Thymeleaf-demo

中餐厅Demo嘉宾:黄晓明 秦海璐 林述巍 王俊凯(走) 杨紫 仝卓 王鹤棣
1)嘉宾展示列表;
2)增加、删除嘉宾 更改角色(店长、财务、大堂经理、主厨、帮厨。。。)

交互设计:
1)首先展示列表页,页面中有多个按钮,每一行上面有更改和删除按钮,列表下方有增加按钮。
2)点击增加时,出现新的页面,页面需要填入名字和角色两个基本信息,填好提交返回列表页。
3)点击删除时,列表页更新。
4)点击更改时,出现新的编辑页面,名字不可改,角色可修改,修改提交后返回列表页。

系统设计:
1)实体类Guest name role
2)操作Model的方式GuestDao 初始化的数据、数据的增删改查处理
3)业务控制逻辑GuestController 接收请求,逻辑处理,返回相应的页面
4)逻辑处理GuestService去调用相应的GuestDao

接口设计
1) /guest/list 查询列表 无查询参数 返回结果:List
2)/guest/toAdd 点击增加按钮 返回add.html页面 需填写名字和角色 /guest/add 增加操作 传参为Guest 返回结果:跳转到list页面3)/guest/toUpdate 点击修改按钮 传参Guest name 返回update.html页面 名字固定 角色可改 /guest/update 修改操作 传参Guest 返回结果:跳转到list页面
4)/guest/delete 删除操作 传参Guest name 返回结果:跳转到list页面

list.html

  1. <!DOCTYPE html>
  2. <html lang="en" xmlns:th="http://www.thymeleaf.org">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. <link rel="stylesheet" th:href="@{/bootstrap.css}">
  7. </head>
  8. <body>
  9. <h2>中餐厅嘉宾列表</h2><br>
  10. <table class="table table-hover">
  11. <thead>
  12. <tr>
  13. <th>名字</th>
  14. <th>角色</th>
  15. </tr>
  16. </thead>
  17. <tbody>
  18. <tr th:each="guest:${guestList}">
  19. <td th:text="${guest.name}">name</td>
  20. <td th:text="${guest.role}">role</td>
  21. <td>
  22. <a th:href="@{/guest/toUpdate(name=${guest.name})}">修改角色</a>
  23. </td>
  24. <td>
  25. <a th:href="@{/guest/delete(name=${guest.name})}">删除嘉宾</a>
  26. </td>
  27. </tr>
  28. </tbody>
  29. </table>
  30. <div class="form-group">
  31. <div class="col-sm-2 control-lable" >
  32. <a href="/guest/toAdd" th:href="@{/guest/toAdd}"
  33. class="btn btn-info">add</a>
  34. </div>
  35. </div>
  36. </body>
  37. </html>

update.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>修改嘉宾角色</title>
    <link rel="stylesheet" th:href="@{/bootstrap.css}">
</head>
<body>
<form th:action="@{/guest/update}" th:object="${guest}" method="post">

    名字:<input type="text" id="name" name="name"
                   th:value="*{name}" readonly>
    角色:<input type="text" id="role" name="role"
                   th:value="*{role}">
    <input type="submit" value="提交">
</form>

</body>
</html>

add.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>添加嘉宾</title>
    <link rel="stylesheet" th:href="@{/bootstrap.css}">
</head>
<body>
<form th:action="@{/guest/add}" method="post">
    嘉宾名字<input type="text" id="name" name="name">
    嘉宾角色<input type="text" id="role" name="role">
    <input type="submit" value="提交">
</form>

</body>
</html>

controller

package com.duing.controller;

import com.duing.bean.Guest;
import com.duing.service.GuestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.List;

@Controller
public class GuestController {

    @Autowired
    private GuestService guestService;

    @RequestMapping("/guest/list")
    public String list(Model model){
        List<Guest> guestList= guestService.list();
        model.addAttribute("guestList",guestList);
        return "list";
    }

    @RequestMapping("/guest/add")
    public String add(String name,String role,Model model){
        Guest guest=new Guest(name, role);
        model.addAttribute("guest",guest);
        guestService.add(guest);
        return "redirect:/guest/list";
    }

    @RequestMapping("/guest/toAdd")
    public String toAdd(){
        return "add";
    }

    @RequestMapping("/guest/toUpdate")
    public String toUpdate(Model model,String name){
        Guest guest= guestService.get(name);
        model.addAttribute("guest",guest);
        return "update";
    }

    @RequestMapping("/guest/update")
    public String update(Guest guest,Model model){
        guestService.update(guest);
        return "redirect:/guest/list";
    }

    @RequestMapping("/guest/delete")
    public String delete(String name,Model model){
        guestService.delete(name);
        return "redirect:/guest/list";
    }

}

service

package com.duing.service;

import com.duing.bean.Guest;
import com.duing.dao.GuestDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class GuestServiceImpl implements GuestService{

    @Autowired
    private GuestDao guestDao;

    @Override
    public List<Guest> list() {
        return guestDao.list();
    }

    @Override
    public void add(Guest guest) {
        guestDao.add(guest);
    }

    @Override
    public void update(Guest guest) {
        guestDao.update(guest);
    }

    @Override
    public void delete(String name) {
        guestDao.delete(name);
    }

    @Override
    public Guest get(String name) {
        return guestDao.get(guestDao.getIndex(name));
    }

}

dao

package com.duing.dao;

import com.duing.bean.Guest;
import org.springframework.stereotype.Repository;

import java.util.ArrayList;
import java.util.List;

@Repository
public class GuestDao {

    static List<Guest> guestList = new ArrayList<>();
    static {
        guestList.add(new Guest("黄晓明","店长"));
        guestList.add(new Guest("秦海璐","财务"));
        guestList.add(new Guest("林述巍","总厨"));
        guestList.add(new Guest("王俊凯","经理"));
        guestList.add(new Guest("杨紫","前台"));
    }

    public List<Guest> list(){
        return guestList;
    }

    public void add(Guest guest){
        guestList.add(guest);
    }

    public int getIndex(String name){
        for(int i=0;i< guestList.size();i++){
            if (name.equals(guestList.get(i).getName())) {
                return i;
            }
        }
        return -1;
    }

    public Guest get(int i){
        return guestList.get(i);
    }

    public void update(Guest guest){
        guestList.get(getIndex(guest.getName())).setRole(guest.getRole());
    }

    public void delete(String name){
        int i=getIndex(name);
        guestList.remove(i);
    }

}


RESTful API设计

image.png

一句话理解:看url就知道要什么,看http method就知道要做什么(增删改查),看http status code就知道哪里有问题
以上面中餐厅为例


传统API RESTful API
查询 /guest/list /guest
to添加 /guest/toAdd /guest/toAdd
添加 /guest/add?guest={guest} /guest
to编辑 /guest/toUpdate?name={name} /guest/toUpdate/{name}
编辑 /guest/update?guest={guest} /guest
删除 /guest/delete?name={name} /guest/{name}

编辑功能的更改有几点注意事项:
1)form表单原生只支持get和post方法,可以通过隐藏属性值,实现put以及delete的提交方式。

 <input type="hidden" name="_method" value="put">
  1. /guest/toUpdate/{name}路径的属性接收和以往不同。
    通过注解 @PathVariable(“name”)映射到方法的属性中,直译的意思就是 从路径中获取name的值
    @GetMapping("/toUpdate/{name}")
    public String toUpdate(Model model,@PathVariable("name") String name){
        Guest guest = guestService.get(name);
        model.addAttribute("guest",guest);
        return "update";
    }

删除功能的更改有几点注意事项:

1) 通过webjars引入jquery
pom.xml

        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>jquery</artifactId>
            <version>3.4.1</version>
        </dependency>

list.html

<script type="text/javascript" th:src="@{/webjars/jquery/3.4.1/jquery.js}"></script>


  1. 如何通过delete的方法提交按钮? 借助form表单


<!--声明删除按钮-->
<button th:attr="del_url=@{/guest/}+${guest.name}" name="del_button">删除</button>

<!--声明删除按钮借助的表单-->
<form method="post" id="del_form">
    <input type="hidden" name="_method" value="delete">
</form>

<!--增加按钮的点击监听,给表单的action赋值,然后提交-->
<script>
    $(function () {
        $("button[name='del_button']").click(function () {
            $("#del_form").prop("action",$(this).attr("del_url")).submit();
        });
    });
</script>

相较于之前的代码,改变的部分
controller

package com.duing.controller;

import com.duing.bean.Guest;
import com.duing.service.GuestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * @RequestMapping("/guest")
 * 放在类的上面,表示类里面的方法都是以 /guest 开头的
 */
@Controller
@RequestMapping("/guest")
public class GuestController {

    @Autowired
    private GuestService guestService;

    //@RequestMapping(method = RequestMethod.GET)
    //等价于下面的注解
    @GetMapping
    public String list(Model model){
        List<Guest> guestList= guestService.list();
        model.addAttribute("guestList",guestList);
        return "list";
    }

    @PostMapping
    public String add(String name,String role,Model model){
        Guest guest=new Guest(name, role);
        model.addAttribute("guest",guest);
        guestService.add(guest);
        return "redirect:/guest";
    }

    @GetMapping("/toAdd")
    public String toAdd(){
        return "add";
    }

    /**
     * 将/guest/toUpdate/{name}格式的url映射到此方法
     * 其中的name属性值通过注解@PathVariable映射到方法的属性中
     */
    @GetMapping("/toUpdate/{name}")
    public String toUpdate(Model model,@PathVariable("name") String name){
        Guest guest= guestService.get(name);
        model.addAttribute("guest",guest);
        return "update";
    }

    @PutMapping
    public String update(Guest guest,Model model){
        guestService.update(guest);
        return "redirect:/guest";
    }

    @DeleteMapping("/{name}")
    public String delete(@PathVariable("name") String name,Model model){
        guestService.delete(name);
        return "redirect:/guest";
    }

}

list.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" th:href="@{/bootstrap.css}">

    <script type="text/javascript" th:src="@{/webjars/jquery/3.4.1/jquery.js}"></script>

</head>
<body>
    <h2>中餐厅嘉宾列表</h2><br>
    <table class="table table-hover">
        <thead>
            <tr>
                <th>名字</th>
                <th>角色</th>
            </tr>
        </thead>
        <tbody>
            <tr th:each="guest:${guestList}">
                <td th:text="${guest.name}">name</td>
                <td th:text="${guest.role}">role</td>


                <td>
                    <a th:href="@{/guest/toUpdate/}+${guest.name}">修改角色</a>
                </td>
                <td>
<!--                    <a th:href="@{/guest/delete(name=${guest.name})}">删除嘉宾</a>-->
                    <!--声明删除按钮-->
                    <button th:attr="del_url=@{/guest/}+${guest.name}" name="del_button">删除嘉宾</button>
                </td>


          </tr>
        </tbody>
    </table>

    <div class="form-group">
        <div class="col-sm-2 control-lable" >
            <a href="/guest/toAdd" th:href="@{/guest/toAdd}"
            class="btn btn-info">add</a>
        </div>
    </div>

    <!--删除按钮借助的表单-->
    <form method="post" id="del_form">
        <input type="hidden" name="_method" value="delete">
    </form>

    <script>
        $(function () {
            $("button[name='del_button']").click(function () {
                $("#del_form").prop("action",$(this).attr("del_url")).submit();
            });
        });
    </script>
</body>
</html>

add.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>添加嘉宾</title>
    <link rel="stylesheet" th:href="@{/bootstrap.css}">
</head>
<body>

<form th:action="@{/guest}" method="post">

    嘉宾名字<input type="text" id="name" name="name">
    嘉宾角色<input type="text" id="role" name="role">
    <input type="submit" value="提交">
</form>

</body>
</html>

update.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>修改嘉宾角色</title>
    <link rel="stylesheet" th:href="@{/bootstrap.css}">
</head>
<body>


<form th:action="@{/guest}" th:object="${guest}" method="post">

<!--    form表单只提供post和get,隐式传递method使之为put-->
    <input type="hidden" name="_method" value="put">



    名字:<input type="text" id="name" name="name"
                   th:value="*{name}" readonly>
    角色:<input type="text" id="role" name="role"
                   th:value="*{role}">
    <input type="submit" value="提交">
</form>

</body>
</html>