é£è¼è¨äºãSpringBoot ã¢ããªéçºããèªã¿é²ããã¨ããµã³ãã«ã® Webã¢ããªãå¶ä½ãããã¨ãã§ãã¾ãã
ä»åã¯ãHTMLã¨JavaScriptã使ãã¦ããã¾ãã
é£è¼è¨äº
SpringBoot ã¢ããªéçºã®é£è¼è¨äºã¯ä»¥ä¸ã®éãã§ãã
- æ¦è¦ã»ä½¿ç¨ãããã¯ã
- ããã¸ã§ã¯ã使ã»SQL使
- ã¢ãã«ã»ãªãã¸ããªã®ä½æ
- ã³ã³ããã¼ã©ã¼ã»ã¡ã¤ã³ã®ä½æ
- HTMLã»JavaScriptã®ä½æï¼ä»åã®è¨äºï¼
- CSSã»ç»åã®ä½æ
- ãã¹ãã»åä½ç¢ºèª
ç®æ¬¡
- HTMLã®ä½æ
- JavaScriptã®ä½æ
1. HTMLã®ä½æ
以ä¸ã®HTMLã使ãã¾ãã
src/main/resources/static/index.html
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>ã¤ã¶ããã¢ããª</title> <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.min.css"> <link href="css/tweet.css" rel="stylesheet"> </head> <body> <header> <div class="d-flex justify-content-center"> <img src="img/logo.png"> </div> </header> <main> <div class="container"> <div class="row"> <div class="col-md-8 offset-md-2 col-lg-6 offset-lg-3"> <div id="tweet-form"> <textarea class="form-control" id="txt" rows="3" placeholder="ã¡ãã»ã¼ã¸"></textarea> <div class="d-flex justify-content-end"> <button type="button" id="create" class="btn btn-success">ãã¤ã¼ã</button> </div> </div><!-- tweet-form --> <div id="tweet-list"></div> </div><!-- .col-* --> </div><!-- .row --> </div> </main> <script id="tweet-template" type="x-tmpl-mustache"> {{#tweet}} <div class="tweet" data-id="{{id}}"> <div class="txt"><p>{{txt}}</p></div> <div class="d-flex justify-content-start"> <button type="button" class="btn edit"> <i class="bi-pencil"></i> ç·¨é </button> <button type="button" class="btn delete"> <i class="bi-trash3"></i> åé¤ </button> <div class="date">{{createTime}}</div> </div> </div> {{/tweet}} </script> <div class="modal fade" id="modal" tabindex="-1" aria-labelledby="modal-label" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <h1 class="modal-title fs-5" id="modal-label">ç·¨é</h1> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body"> <form> <div class="form-group"> <textarea class="form-control" rows="3" id="modal-txt"></textarea> </div> </form> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">ãã£ã³ã»ã«</button> <button type="button" id="modal-update" class="btn btn-success">æ´æ°</button> </div> </div> </div> </div> <script src="https://code.jquery.com/jquery-3.7.1.min.js" integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js" integrity="sha384-fbbOQedDUMZZ5KreZpsbe1LCZPVmfTnH7ois6mU1QK+m14rQ1l2bGBq41eYeM/fS" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/4.1.0/mustache.min.js" integrity="sha512-HYiNpwSxYuji84SQbCU5m9kHEsRqwWypXgJMBtbRSumlx1iBB6QaxgEBZHSHEGM+fKyCX/3Kb5V5jeVXm0OglQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> <script src="js/tweet.js"></script> </body> </html>
bodyã¯ä»¥ä¸ã®å 容ã«åé¡ã§ãã¾ãã
- ãããã¼
- ã¡ã¤ã³
- Mustacheãã³ãã¬ã¼ã
- Bootstrapã¢ã¼ãã«
ãããã¼ã¯ãã´ãã¡ã¤ã³ã¯ãã¤ã¼ãã表示ããã¾ãããã³ãã¬ã¼ãã¯ãã¤ã¼ãã表示ããéã«ãã¢ã¼ãã«ã¯ãã¤ã¼ããç·¨éããéã«å©ç¨ããã¾ãã
2. JavaScriptã®ä½æ
以ä¸ã®JavaScriptã使ãã¾ãã
src/main/resources/static/js/tweet.js
$(function() { // mustache template. const template = $('#tweet-template').html(); Mustache.parse(template); // utilities. function render(tweet) { let rendered = Mustache.render(template, tweet); $('#tweet-list').prepend(rendered); } function deleteSec(dateString) { return dateString.substring(0, 16); } // onload. $('#txt').focus(); $.ajax({ url: '/tweet', method: 'get', cache: false }).then(function(data, status, jqxhr) { render(data); $('.date').each(function(index, e) { $(e).html(deleteSec($(e).html())); }) }); // create. $('#create').click(function() { let txt = $('#txt').val(); if (txt === '') return; $.ajax({ url: '/tweet', data: JSON.stringify({'txt':txt}), contentType: 'application/json', method: 'post', cache: false }).then(function(data, status, jqxhr) { render(data); let $date = $('.tweet:first').find('.date'); $date.html(deleteSec($date.html())); $('#txt').val('').focus(); }); }); // update. let $tweet; const modal = new bootstrap.Modal( document.getElementById('modal') ); $('body').on('click', '.edit', function() { $tweet = $(this).closest('.tweet'); $('#modal-txt').val($tweet.find('.txt p').html()); modal.show(); }); $('#modal-update').click(function() { let txt = $('#modal-txt').val(); let url = '/tweet/' + $tweet.data('id'); $.ajax({ url: url, data: {'txt':txt}, method: 'put', cache: false }).then(function(data, status, jqxhr) { $('#modal').modal('hide'); $tweet.find('.txt p').html(txt); }); }); // delete. $('body').on('click', '.delete', function() { if (!confirm("åé¤ãã¾ããï¼")) return; let $tweet = $(this).closest('.tweet'); let url = '/tweet/' + $tweet.data('id'); $.ajax({ url: url, method: 'delete', cache: false }).then(function(data, status, jqxhr) { $tweet.remove(); }); }); });
JavaScriptã®å 容ã§ããã主ã«ãµã¼ãã¼ãµã¤ãã®å¦çãå¼ã³åºããã®ã¨ãªã£ã¦ãã¾ãã
ä¾ãã°ããªã³ãã¼ãæã¯ãµã¼ããµã¤ãã®å¦çãå¼ã³åºãã¦ãã¤ã¼ããåå¾ãã¾ããããããMustacheãã³ãã¬ã¼ãã使ã£ã¦ãç»é¢ã«ãã¤ã¼ãã表示ãã¦ãã¾ãã
GitHubãªãã¸ããª
ã¢ããªã®ã³ã¼ãã¯ã以ä¸ã®ãªãã¸ããªã«ãããã¾ãã