• Spring Boot进阶系列二


    上一篇文章,主要分析了怎么建立一个Restful web service,系列二主要创建一个H5静态页面使用ajax请求数据,功能主要有添加一本书,请求所有书并且按照Id降序排列,以及查看,删除一本书。

    1.   示例结构以及用到的技术点

    1.1 项目逻辑架构

    1.2 项目的技术选型

    • Spring-Data-JPA
    • H5
    • Bootstrap
    • jQuery + ajax

    2.  后端服务

    2.1  pom.xml依赖的jar包和系列一中结构完全一样,省略不表。

    2.2  book表结构,book类定义和系列一中定义完全一样,此处省略1000+英文字母。

    2.3 在com.example.demo.store包中的BooRepository定义如下,

    public interface BookRepository extends JpaRepository<Book,Integer> {
    
        @Query(value = "SELECT * FROM book order by Id desc", nativeQuery = true)
        List<Book> findBooks();
    }

    2.4 因为项目简单的缘故,没有建立service包,在control中直接调用数据访问层接口。

    @Controller
    @RequestMapping(path = "/book")
    public class BookController {
    
        @Autowired
        private BookRepository bookRepository;
    
        @Value("${upload.path}")
        private String filePath;
    
        @PostMapping(path = "/save")
        public @ResponseBody String save(HttpServletRequest request, @RequestParam("poster") MultipartFile poster) {
    
            String tempPath = filePath;
            String name = request.getParameter("name");
            String category = request.getParameter("category");
            Double price = Double.valueOf(request.getParameter("price"));
            // Give today as a default date
            Date publishDate = new Date();
            String temp = request.getParameter("publishDate");
            DateFormat formatDate = new SimpleDateFormat("yyyy-MM-dd");
            try {
                publishDate = formatDate.parse(temp);
            } catch (ParseException e2) {
                // TODO Auto-generated catch block
                e2.printStackTrace();
            }
            // Handle uploading picture
            String fileName = poster.getOriginalFilename();
            String suffixName = fileName.substring(fileName.lastIndexOf('.'));
            fileName = UUID.randomUUID() + suffixName;
            String posterPath = "image/" + fileName;
            Book book = new Book();
            book.setId(0);
            book.setName(name);
            book.setCategory(category);
            book.setPrice(price);
            book.setPublish_date(publishDate);
            book.setPoster(posterPath);
    
            tempPath += fileName;
            try {
                poster.transferTo(new File(tempPath));
                bookRepository.save(book);
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return "Add new book successfully";
        }
    
        @GetMapping(path = "/one/{id}")
        public @ResponseBody Book findOne(@PathVariable("id") Integer id) throws NotFoundException {
    
            Optional<Book> book = this.bookRepository.findById(id);
            if (book.isPresent()) {
                return book.get();
            } else {
                throw new NotFoundException("Not found " + id);
            }
        }
    
        @GetMapping(path = "/all")
        public @ResponseBody Iterable<Book> findAll() {
            return bookRepository.findBooks();
        }
    
        @DeleteMapping(path = "/del/{id}")
        public @ResponseBody String deleteBook(@PathVariable("id") Integer id) {
            bookRepository.deleteById(id);
            return String.format("Delete book (%d) successfully!", id);
        }
    }

    2.5 新建WebConfig文件,解决 springboot上传图片不能马上访问显示的问题

    @Configuration
    public class WebConfig implements WebMvcConfigurer {
    
        @Value("${upload.path}")
        private String filePath;
    
        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {
            // 映射图片保存地址
            registry.addResourceHandler("/image/**").addResourceLocations("file:" + filePath);
        }
    } 

     // JSONWebConfig.java 详见系列一,完全一样,此处省略。

    2.6 Application.properties内容如下:

    值得一提的是连接MySQL数据库的url里面的时区用的是东八区的时间。

    # DB connection configuration
    spring.datasource.url=jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8 
    spring.datasource.username=root
    spring.datasource.password=Home2019
    
    # JPA configuration
    spring.jpa.hibernate.ddl-auto=none
    spring.jpa.show-sql=true
    
    upload.path=D:/eclipse-workspace/ProductApp3/src/main/resources/static/image/

    3.  前端H5

    3.1 在public文件夹里面添加index.html

      1 <!doctype html>
      2 <html lang="en">
      3 <head>
      4 <!-- Required meta tags -->
      5 <meta charset="utf-8"></meta>
      6 <meta name="viewport"
      7     content="width=device-width, initial-scale=1, shrink-to-fit=no"></meta>
      8 
      9 <!-- Bootstrap CSS -->
     10 <link rel="stylesheet"
     11     href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
     12     integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T"
     13     crossorigin="anonymous"></link>
     14 
     15 <title>Index Page</title>
     16 </head>
     17 <body>
     18     <div class="container">
     19         <h1>Springboot进阶系列二</h1>
     20         
     21         <!-- Content here -->
     22         <div class="table-responsive">
     23             <table class="table table-striped table-sm" id="books">
     24                 <thead>
     25                     <tr>
     26                         <th>ID</th>
     27                         <th>Name</th>
     28                         <th>Category</th>
     29                         <th>Price</th>
     30                         <th>Operation</th>
     31                     </tr>
     32                 </thead>
     33                 <tbody></tbody>
     34             </table>
     35         </div>
     36         
     37         <button type="button" class="btn btn-outline-secondary" data-toggle="modal" data-target="#addModal">Add Book</button>
     38         
     39         <!-- Add Model -->
     40         <div class="modal fade" id="addModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
     41             <div class="modal-dialog" role="document">
     42                 <div class="modal-content">
     43                     <div class="modal-header">
     44                         <h5 class="modal-title" id="exampleModalLabel">Add Book</h5>
     45                     </div>
     46                     <div class="modal-body">
     47                         <div class="form-group row">
     48                             <label for="inputName" class="col-sm-2 col-form-label">Name</label>
     49                             <div class="col-sm-10">
     50                                 <input type="text" class="form-control" id="inputName" placeholder="Name">
     51                             </div>
     52                         </div>
     53                         <div class="form-group row">
     54                             <label for="categorySelect" class="col-sm-2 col-form-label">Category</label>
     55                             <div class="col-sm-10">
     56                                 <select class="form-control" id="categorySelect">
     57                                     <option>武侠</option>
     58                                     <option>历史</option>
     59                                     <option>军事</option>
     60                                     <option>国学</option>
     61                                     <option>投资</option>
     62                                     <option>管理</option>
     63                                     <option>传记</option>
     64                                 </select>
     65                             </div>
     66                         </div>
     67                         <div class="form-group row">
     68                             <label for="inputPrice" class="col-sm-2 col-form-label">Price</label>
     69                             <div class="col-sm-10">
     70                                 <input type="text" class="form-control" id="inputPrice" placeholder="Price">
     71                             </div>
     72                         </div>
     73                         <div class="form-group row">
     74                             <label for="inputDate" class="col-sm-2 col-form-label">Publish Date</label>
     75                             <div class="col-sm-10">
     76                                 <input type="date" class="form-control" id="inputDate" />
     77                             </div>
     78                         </div>
     79                         <div class="form-group row">
     80                             <label for="inputPoster" class="col-sm-2 col-form-label">Poster</label>
     81                             <div class="col-sm-10">
     82                                 <input type="file" class="form-control" id="inputPoster" />
     83                             </div>
     84                         </div>
     85                     </div>
     86 
     87                     <div class="modal-footer">
     88                         <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
     89                         <button type="button" class="btn btn-primary" id="saveBook">Save</button>
     90                     </div>
     91                 </div>
     92             </div>
     93         </div>
     94         
     95         <!-- View Model -->
     96         <div class="modal fade" id="viewModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
     97             <div class="modal-dialog" role="document">
     98                 <div class="modal-content" style="768px">
     99                     <div class="modal-header">
    100                         <h5 class="modal-title" id="exampleModalLabel">View Book</h5>
    101                     </div>
    102                     <div class="modal-body">
    103                         <div class="form-group row">
    104                             <label for="nameView" class="col-sm-2 col-form-label">Name</label>
    105                             <div class="col-sm-10">
    106                                 <input type="text" class="form-control" id="nameView" readonly>
    107                             </div>
    108                         </div>
    109                         <div class="form-group row">
    110                             <label for="categoryView" class="col-sm-2 col-form-label">Category</label>
    111                             <div class="col-sm-10">
    112                                 <select class="form-control" id="categoryView" disabled>
    113                                     <option>武侠</option>
    114                                     <option>历史</option>
    115                                     <option>军事</option>
    116                                     <option>国学</option>
    117                                     <option>投资</option>
    118                                     <option>管理</option>
    119                                     <option>传记</option>
    120                                 </select>
    121                             </div>
    122                         </div>
    123                         <div class="form-group row">
    124                             <label for="priceView" class="col-sm-2 col-form-label">Price</label>
    125                             <div class="col-sm-10">
    126                                 <input type="text" class="form-control" id="priceView" readonly>
    127                             </div>
    128                         </div>
    129                         <div class="form-group row">
    130                             <label for="dateView" class="col-sm-2 col-form-label">Publish Date</label>
    131                             <div class="col-sm-10">
    132                                 <input type="text" class="form-control" id="dateView" readonly>
    133                             </div>
    134                         </div>
    135                         <div class="form-group row">
    136                             <label for="posterView" class="col-sm-2 col-form-label">Poster</label>
    137                             <div class="col-sm-10">
    138                                 <img src="..." alt="Poster" id="posterView">
    139                             </div>
    140                         </div>
    141                     </div>
    142 
    143                     <div class="modal-footer">
    144                         <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
    145                     </div>
    146                 </div>
    147             </div>
    148         </div>
    149     </div>
    150 
    151 
    152     <!-- Optional JavaScript -->
    153     <!-- jQuery first, then Popper.js, then Bootstrap JS -->
    154     <script src="js/jquery-3.4.1.js"></script>
    155     <script src="js/book.js"></script>
    156     <script
    157         src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"
    158         integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1"
    159         crossorigin="anonymous"></script>
    160     <script
    161         src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"
    162         integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM"
    163         crossorigin="anonymous"></script>
    164 </body>
    165 </html>

    3.2 在static/js文件夹里面添加book.js

     

      1 $(document).ready(function() {
      2     $.ajax({
      3         url: "/greeting"
      4     }).then(function(data) {
      5        $('#greeting-content').append(data.id + '---');
      6        $('#greeting-content').append(data.content);
      7     });
      8     
      9     // Clean table
     10     $('#books tr:not(:first)').empty();
     11 
     12     $.getJSON('book/all').done(function (data) {
     13         $.each(data, function (key, item) {
     14             if (item != null) {
     15                 var tmp = JSON.stringify(item);
     16                 row = "<tr><td>" + item.id + "</td><td>" + item.name + "</td><td>" + item.category + "</td><td>" + item.price + "</td><td>" + '<button type="button" class="btn btn-outline-secondary" data-toggle="modal" data-target="#viewModal" onclick="viewBook('+item.id+')">View</button> <button type="button" class="btn btn-outline-secondary">Edit</button> <button type="button" class="btn btn-outline-secondary" onclick="delBook('+item.id+')">Delete</button>' + "</td><tr>";
     17                 $('#books tr:last').after(row);
     18             }
     19         });
     20     });
     21 });
     22 
     23 
     24 $('#saveBook').on('click', function () {
     25     // 处理图片上传
     26     var fd = new FormData();
     27     fd.append('name', $('#inputName').val());
     28     fd.append('category', $('#categorySelect').val());
     29     fd.append('price', $('#inputPrice').val());
     30     fd.append('publishDate', $('#inputDate').val());
     31     fd.append('poster', $('#inputPoster').get(0).files[0]);
     32 
     33     $.ajax({
     34         url: 'book/save',
     35         type: 'POST',
     36         data: fd,
     37         cache: false,
     38         processData: false,
     39         contentType: false,
     40         success: function () {
     41             alert('Add new book successfully!');
     42             // 刷新父窗口
     43             $('#addModel').modal('hide');
     44             window.location.reload();
     45         },
     46         error: function (xhr,status,errorThrown) {
     47             alert('Failed to add new book.Error :' + errorThrown);
     48         }
     49     });
     50 });
     51 
     52 
     53 function viewBook(id) {
     54     $.ajax({
     55         url: '/book/one/' + id, 
     56         // Whether this is a POST or GET request
     57         type: "GET", 
     58         // The type of data we expect back
     59         dataType : "json"
     60     })
     61       // Code to run if the request succeeds (is done);
     62       // The response is passed to the function
     63       .done(function(data) {
     64          $('#viewModel').modal('show');
     65          $('#nameView').val(data.name);
     66          $('#categoryView').val(data.category);
     67          $('#priceView').val(data.price);
     68          $('#dateView').val(data.publish_date);
     69          $('#posterView').attr('src',data.poster);
     70       })
     71       // Code to run if the request fails; the raw request and
     72       // status codes are passed to the function
     73       .fail(function( xhr, status, errorThrown ) {
     74         alert( "Sorry, there was a problem!" );
     75         console.log( "Error: " + errorThrown );
     76         console.log( "Status: " + status );
     77         console.dir( xhr );
     78       })
     79       // Code to run regardless of success or failure;
     80       .always(function( xhr, status ) {
     81         //alert( "The request is complete!" );
     82       });
     83 }
     84 
     85 
     86 function delBook(id) {
     87     if(true == confirm("Are you sure to delete it?")) {
     88         $.ajax({
     89             url:'book/del/' + id,
     90             type:'DELETE',
     91             // The type of data we expect back
     92             dataType : "json"
     93         })
     94           // Code to run if the request succeeds (is done);
     95           // The response is passed to the function
     96           .done(function(data) {
     97               alert(data);
     98               window.location.reload();      
     99           })
    100           // Code to run if the request fails; the raw request and
    101           // status codes are passed to the function
    102           .fail(function( xhr, status, errorThrown ) {
    103             alert( "Sorry, there was a problem!" );
    104             console.log( "Error: " + errorThrown );
    105             console.log( "Status: " + status );
    106             console.dir( xhr );
    107           })
    108           // Code to run regardless of success or failure;
    109           .always(function( xhr, status ) {
    110             //alert( "The request is complete!" );
    111           });
    112     }
    113 }

    4.  运行程序

    浏览器中输入http://localhost:8080/index.html,程序默认输出所有记录,按Id大小降序排列。

    程序最终实现了添加,查看,删除功能。

     

  • 相关阅读:
    mock数据
    关于适配各种浏览器的图片预览。
    闭包
    兼容性 适配
    递归 使用callee
    webservice的model层命名空间不同的问题
    删除右键菜单中的Git
    windows server core 设置shell 及切换
    设置共享用户名密码
    Windows Remote Shell(WinRM)使用介绍
  • 原文地址:https://www.cnblogs.com/sankt/p/11489146.html
Copyright © 2020-2023  润新知