java框架之SpringBoot(6)-Restful風格的CRUD示例

準備

環境

  • IDE:Idea
  • SpringBoot版本:1.5.19
  • UI:BootStrap 4
  • 模板引擎:thymeleaf 3
  • 效果:Restful 風格 CRUD 功能的 Demo

依賴

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.19.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.springboot</groupId>
    <artifactId>webdev2</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>webdev2</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <thymeleaf.version>3.0.2.RELEASE</thymeleaf.version>
        <!--佈局功能支持程序,thymeleaf 使用 3.0 版本以上時支持程序要使用 2.0 以上-->
        <thymeleaf-layout-dialect.version>2.1.1</thymeleaf-layout-dialect.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>bootstrap</artifactId>
            <version>4.3.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
pom.xml

靜態文件

html,
body {
  height: 100%;
}

body {
  display: -ms-flexbox;
  display: -webkit-box;
  display: flex;
  -ms-flex-align: center;
  -ms-flex-pack: center;
  -webkit-box-align: center;
  align-items: center;
  -webkit-box-pack: center;
  justify-content: center;
  padding-top: 40px;
  padding-bottom: 40px;
  background-color: #f5f5f5;
}

.form-signin {
  width: 100%;
  max-width: 330px;
  padding: 15px;
  margin: 0 auto;
}
.form-signin .checkbox {
  font-weight: 400;
}
.form-signin .form-control {
  position: relative;
  box-sizing: border-box;
  height: auto;
  padding: 10px;
  font-size: 16px;
}
.form-signin .form-control:focus {
  z-index: 2;
}
.form-signin input[type="email"] {
  margin-bottom: -1px;
  border-bottom-right-radius: 0;
  border-bottom-left-radius: 0;
}
.form-signin input[type="password"] {
  margin-bottom: 10px;
  border-top-left-radius: 0;
  border-top-right-radius: 0;
}
static/css/signin.css

JavaBean

package com.springboot.webdev2.bean;

import java.util.Date;

public class User {
    public User() {
    }

    public User(Integer id,String name, String email, Integer gender, Date birthday) {
        this.id = id;
        this.name = name;
        this.email = email;
        this.gender = gender;
        this.birthday = birthday;
    }

    private  Integer id;
    private  String name;
    private  String email;
    private Integer gender;
    private Date birthday;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public Integer getGender() {
        return gender;
    }

    public void setGender(Integer gender) {
        this.gender = gender;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
}
com.springboot.webdev2.bean.User

模擬數據層

package com.springboot.webdev2.dao;

import com.springboot.webdev2.bean.User;
import org.springframework.stereotype.Repository;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;

@Repository
public class UserDao {
    private static List<User> userList;
    private static int id = 3;
    static {
        /**
         * 模擬 db 數據
         */
        userList = new ArrayList<>();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        try {
            userList.add(new User(1,"張三", "asda@qq.com", 1, simpleDateFormat.parse("2019-1-1")));
            userList.add(new User(2,"李四", "32432@qq.com", 0, simpleDateFormat.parse("2014-3-11")));
            userList.add(new User(3,"王五", "dae@qq.com", 1, simpleDateFormat.parse("2012-1-1")));
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }

    public List<User> listAll(){
        return userList;
    }

    public void save(User user){
        user.setId(++id);
        userList.add(user);
    }

    public void delete(Integer id){
        userList.removeIf(p -> p.getId() == id);
    }

    public User getById(Integer id){
        for (User user : userList) {
            if (user.getId() == id) {
                return user;
            }
        }
        return null;
    }

    public void update(User user){
        User dbUser = getById(user.getId());
        dbUser.setName(user.getName());
        dbUser.setBirthday(user.getBirthday());
        dbUser.setEmail(user.getEmail());
        dbUser.setGender(user.getGender());
    }

}
com.springboot.webdev2.dao.UserDao

編碼

引入BootStrap-WebJars使用

以前咱們經過 Maven 引入的依賴 jar 中大多都是類文件,其實經過 Maven 還能夠引入靜態文件,好比咱們下面要用的 BootStrap,咱們只須要添加以下依賴:css

<dependency>
    <groupId>org.webjars</groupId>
    <artifactId>bootstrap</artifactId>
    <version>4.3.1</version>
</dependency>

若是要引入其它靜態資源依賴可參考 webjars.orghtml

原理:經過以前的學習咱們已經瞭解了靜態資源映射,只要將靜態資源放在 classpath:/META-INF/resources/webjars/ 下,咱們就能夠經過 /webjars/** 請求訪問到對應靜態資源。java

登陸頁-國際化

下面以登陸頁面作國際化爲示例。jquery

一、首先要建立國際化使用的資源文件:web

login.password=密碼
login.please=請登陸
login.rememberMe=記住我
login.signin=登陸
login.username=用戶名
login.properties
login.password=password
login.please=please login
login.rememberMe=Remember Me
login.signin=Sing In
login.username=UserName
login_en_US.properties

二、配置國際化資源目錄:spring

# 若是有多個目錄能夠 , 分隔,起始目錄爲 classpath
spring.messages.basename=i18n.login
application.properties

三、編寫登陸模板頁面,引用 BootStrap,使用 #{屬性名} 引入國際化資源屬性:apache

<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="description" content="">
    <meta name="author" content="">
    <title>[[#{login.please}]]</title>

    <link th:href="@{/webjars/bootstrap/4.3.1/css/bootstrap.css}" rel="stylesheet">

    <link th:href="@{/css/signin.css}" rel="stylesheet">
</head>

<body class="text-center">
<form class="form-signin" th:action="@{/login}" method="post">
    <h1 class="h3 mb-3 font-weight-normal">[[#{login.please}]]</h1>
    <label for="inputEmail" th:text="#{login.username}" class="sr-only"></label>
    <input type="text" id="inputEmail"  th:name="username" class="form-control" th:placeholder="#{login.username}" required autofocus>
    <label for="inputPassword" th:text="#{login.password}" class="sr-only"></label>
    <input type="password" id="inputPassword"  th:name="password" class="form-control" th:placeholder="#{login.password}" required>
    <div class="checkbox mb-3">
        <label>
            <input type="checkbox" value="remember-me">[[#{login.rememberMe}]]
        </label>
    </div>
    <button class="btn btn-lg btn-primary btn-block" th:text="#{login.signin}" type="submit"></button>
    <span th:if="${msg!=null}" style="color:red;">[[${msg}]]</span>
    <p class="mt-5 mb-3 text-muted">&copy; 2019-2020</p>
</form>
</body>
</html>
templates/login.html

四、作完上述步驟其實已經完成了登陸頁面國際化,但 SpringBoot 默認配置的國際化解析器是根據客戶端請求頭來返回對應語言資源的。若是咱們想要定製本身的國際化規則,能夠自定義國際化解析器以下:bootstrap

package com.springboot.webdev2.component;

import org.springframework.util.StringUtils;
import org.springframework.web.servlet.LocaleResolver;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Locale;

/**
 * 自定義國際化解析器
 *      做用:
 *          若是客戶端請求攜帶了語言參數,則根據語言參數返回相應資源
 *          若是客戶端未攜帶語言參數,則根據語言請求頭返回相應資源
 */
public class MyLocaleResolver implements LocaleResolver {
    @Override
    public Locale resolveLocale(HttpServletRequest httpServletRequest) {
        // 獲取請求語言參數
        String langCode = httpServletRequest.getParameter("langCode");
        Locale locale = Locale.getDefault();
        // 若是沒有傳遞請求參數
        if (StringUtils.isEmpty(langCode)) {
            // 獲取語言請求頭
            String languageHeader = httpServletRequest.getHeader("Accept-Language");
            String[] langInfo = languageHeader.split(";");
            if (langInfo != null && langInfo.length != 0) {
                String langsStr = langInfo[0];
                String[] langArr = langsStr.split(",");
                langCode = langArr[0];
            }
        }
        String[] strs = langCode.split("-");
        locale = new Locale(strs[0], strs[1]);
        return locale;
    }

    @Override
    public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {

    }
}
com.springboot.webdev2.component.MyLocaleResolver

五、接下來咱們就能夠配置頁面映射,還須要注意的是,編寫完國際化解析器後還須要將其註冊到容器中才會生效:springboot

package com.springboot.webdev2.config;

import com.springboot.webdev2.component.MyLocaleResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

/**
 * SpringMVC 擴展配置類
 */
@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter {

    @Bean
    public WebMvcConfigurerAdapter webMvcConfigurerAdapter(){
        WebMvcConfigurerAdapter webMvcConfigurerAdapter = new WebMvcConfigurerAdapter(){
            @Override
            public void addViewControllers(ViewControllerRegistry registry) {
                // 配置首頁映射爲登陸頁
                registry.addViewController("/").setViewName("login");
                registry.addViewController("/index.html").setViewName("login");
            }
        };
        return webMvcConfigurerAdapter;
    }

    /**
     * 註冊國際化解析器到容器
     */
    @Bean
    public LocaleResolver localeResolver(){
        return new MyLocaleResolver();
    }
}
com.springboot.webdev2.config.MyMvcConfig

六、測試:session

不指定語言參數,請求 localhost:8080


指定語言參數,請求 localhost:8080?langCode=en-US

test

Spring Boot 自動配置好了國際化資源文件的組件,對應類爲:

 1 @Configuration
 2 @ConditionalOnMissingBean(value = MessageSource.class, search = SearchStrategy.CURRENT)
 3 @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
 4 @Conditional(ResourceBundleCondition.class)
 5 @EnableConfigurationProperties
 6 // 與 spring.messages 下屬性綁定
 7 @ConfigurationProperties(prefix = " spring.messages")
 8 public class MessageSourceAutoConfiguration {
 9 
10     private static final Resource[] NO_RESOURCES = {};
11 
12     /*
13     國際化資源文件的默認基礎名爲 messages
14     因此咱們國際化屬性能夠直接定義在 classpath 下 messages.properties 文件中
15     */
16     private String basename = "messages";  
17 
18     private Charset encoding = Charset.forName("UTF-8");
19 
20     private int cacheSeconds = -1;
21 
22     private boolean fallbackToSystemLocale = true;
23 
24     private boolean alwaysUseMessageFormat = false;
25 
26     @Bean
27     public MessageSource messageSource() {
28         ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
29         if (StringUtils.hasText(this.basename)) {
30             // 設置國際化資源文件的基礎名(如:login_zh_CN、login_en_US 的基礎名就爲 login)
31             messageSource.setBasenames(StringUtils.commaDelimitedListToStringArray(
32                     StringUtils.trimAllWhitespace(this.basename)));
33         }
34         if (this.encoding != null) {
35             messageSource.setDefaultEncoding(this.encoding.name());
36         }
37         messageSource.setFallbackToSystemLocale(this.fallbackToSystemLocale);
38         messageSource.setCacheSeconds(this.cacheSeconds);
39         messageSource.setAlwaysUseMessageFormat(this.alwaysUseMessageFormat);
40         return messageSource;
41     }
42 
43     public String getBasename() {
44         return this.basename;
45     }
46 
47     public void setBasename(String basename) {
48         this.basename = basename;
49     }
50 
51     public Charset getEncoding() {
52         return this.encoding;
53     }
54 
55     public void setEncoding(Charset encoding) {
56         this.encoding = encoding;
57     }
58 
59     public int getCacheSeconds() {
60         return this.cacheSeconds;
61     }
62 
63     public void setCacheSeconds(int cacheSeconds) {
64         this.cacheSeconds = cacheSeconds;
65     }
66 
67     public boolean isFallbackToSystemLocale() {
68         return this.fallbackToSystemLocale;
69     }
70 
71     public void setFallbackToSystemLocale(boolean fallbackToSystemLocale) {
72         this.fallbackToSystemLocale = fallbackToSystemLocale;
73     }
74 
75     public boolean isAlwaysUseMessageFormat() {
76         return this.alwaysUseMessageFormat;
77     }
78 
79     public void setAlwaysUseMessageFormat(boolean alwaysUseMessageFormat) {
80         this.alwaysUseMessageFormat = alwaysUseMessageFormat;
81     }
82 
83 }
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration
而在 SpringMVC 的自動配置類中配置了默認的國際化解析器:
 1 @Bean
 2 @ConditionalOnMissingBean  // 當容器中沒有國際化解析器時才使用註冊以下解析器,即若是咱們本身在容器中註冊了國際化解析器 SpringMVC 就會使用咱們本身的國際化解析器
 3 @ConditionalOnProperty(prefix = "spring.mvc", name = "locale")
 4 public LocaleResolver localeResolver() {
 5     if (this.mvcProperties
 6             .getLocaleResolver() == WebMvcProperties.LocaleResolver.FIXED) {
 7         return new FixedLocaleResolver(this.mvcProperties.getLocale());
 8     }
 9     AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
10     localeResolver.setDefaultLocale(this.mvcProperties.getLocale());
11     return localeResolver;
12 }
org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration.WebMvcAutoConfigurationAdapter#localeResolver

抽取公共頁-thymeleaf佈局

一、頂部欄:

<nav class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0">
    <a class="navbar-brand col-sm-3 col-md-2 mr-0" href="#">[[${#session.getAttribute('loginUser')}]]</a>
    <input class="form-control form-control-dark w-100" type="text" placeholder="Search" aria-label="Search">
    <ul class="navbar-nav px-3">
        <li class="nav-item text-nowrap">
            <a class="nav-link" href="#">Sign out</a>
        </li>
    </ul>
</nav>
templates/fragment/topbar.html

二、抽取左邊菜單欄,動態高亮:

<nav class="col-md-2 d-none d-md-block bg-light sidebar" xmlns:th="http://www.thymeleaf.org">
    <div class="sidebar-sticky">
        <ul class="nav flex-column" th:with="activeURI=${#request.getRequestURI()}">
            <li class="nav-item">
                <a th:class="${activeURI}==@{/} or ${acitveURI}==@{/index.html} ?'nav-link active':'nav-link'"
                   th:href="@{/}">
                    <span data-feather="home"></span>
                    首頁
                </a>
            </li>
            <li class="nav-item">
                <a th:class="${activeURI}==@{/users}?'nav-link active':'nav-link'" th:href="@{/users}">
                    <span data-feather="file"></span>
                    用戶列表
                </a>
            </li>
        </ul>
    </div>
</nav>
<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script>window.jQuery || document.write('<script src="../../../../assets/js/vendor/jquery-slim.min.js"><\/script>')</script>

<!-- Icons -->
<script src="https://unpkg.com/feather-icons/dist/feather.min.js"></script>
<script>
    feather.replace()
</script>
templates/fragment/leftmenu.html

三、首頁引用公共頁:

<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="description" content="">
    <meta name="author" content="">

    <title>首頁</title>

    <link th:href="@{/webjars/bootstrap/4.3.1/css/bootstrap.css}" rel="stylesheet">
    <link th:href="@{/css/index.css}" rel="stylesheet">
</head>

<body>
<nav th:replace="fragment/topbar :: nav"/>
<div class="container-fluid">
    <div class="row">
        <nav th:replace="fragment/leftmenu"/>

        <main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">

            <h2>首頁</h2>
        </main>
    </div>
</div>
</body>
</html>
templates/index.html

登陸功能-攔截器

一、編寫登陸控制器:

package com.springboot.webdev2.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

import javax.servlet.http.HttpSession;

@Controller
public class LoginController {

    @GetMapping("/login")
    public String loginView(){
        return "login";
    }

    @PostMapping("/login")
    public String login(String username, String password, HttpSession session, Model model){
        if(!StringUtils.isEmpty(username)&&"123456".equals(password)){
            session.setAttribute("loginUser",username);
            return "redirect:/index.html";
        }
        model.addAttribute("msg", "用戶名或密碼錯誤");
        return "/login";
    }
}
com.springboot.webdev2.controller.LoginController

二、編寫登陸攔截器:

package com.springboot.webdev2.component;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
        Object loginUser = httpServletRequest.getSession().getAttribute("loginUser");
        if (loginUser==null){
            httpServletResponse.sendRedirect("/login");
            return false;
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {

    }
}
com.springboot.webdev2.component.LoginInterceptor

三、註冊攔截器:

package com.springboot.webdev2.config;

import com.springboot.webdev2.component.LoginInterceptor;
import com.springboot.webdev2.component.MyLocaleResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

/**
 * SpringMVC 擴展配置類
 */
@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter {

    @Bean
    public WebMvcConfigurerAdapter webMvcConfigurerAdapter(){
        WebMvcConfigurerAdapter webMvcConfigurerAdapter = new WebMvcConfigurerAdapter(){
            @Override
            public void addInterceptors(InterceptorRegistry registry) {
                // 註冊攔截器,不攔截 /login 請求
                registry.addInterceptor(new LoginInterceptor()).excludePathPatterns("/login");
            }

            @Override
            public void addViewControllers(ViewControllerRegistry registry) {
                registry.addViewController("/").setViewName("index");
                registry.addViewController("/index.html").setViewName("index");
            }
        };


        return webMvcConfigurerAdapter;
    }

    /**
     * 註冊國際化解析器到容器
     */
    @Bean
    public LocaleResolver localeResolver(){
        return new MyLocaleResolver();
    }
}
com.springboot.webdev2.config.MyMvcConfig

CRUD功能實現

一、編寫 User 控制器:

package com.springboot.webdev2.controller;

import com.springboot.webdev2.bean.User;
import com.springboot.webdev2.dao.UserDao;
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;

@Controller
public class UserController {

    @Autowired
    private UserDao userDao;

    @GetMapping("/users")
    public String listAll(Model model) {
        List<User> users = userDao.listAll();
        model.addAttribute("userList", users);
        return "users";
    }

    @GetMapping("/user/{id}")
    public String updateView(@PathVariable Integer id, Model model) {
        User user = userDao.getById(id);
        model.addAttribute("user", user);
        return "user";
    }

    @GetMapping("/user")
    public String addView(Model model) {
        // 由於頁面使用了 th:object ,若是 user 爲 null 會異常
        model.addAttribute("user", new User());
        return "user";
    }

    @PostMapping("/user")
    public String save(User user) {
        userDao.save(user);
        return "redirect:/users";
    }

    @PutMapping("/user")
    public String update(User user) {
        userDao.update(user);
        return "redirect:/users";
    }

    @DeleteMapping("/user/{id}")
    public String delete(@PathVariable Integer id) {
        userDao.delete(id);
        return "redirect:/users";
    }
}
com.springboot.webdev2.controller.UserController

二、編寫列表頁:

<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="description" content="">
    <meta name="author" content="">

    <title>用戶列表</title>

    <link th:href="@{/webjars/bootstrap/4.3.1/css/bootstrap.css}" rel="stylesheet">
    <link th:href="@{/css/index.css}" rel="stylesheet">
  </head>

  <body>
  <nav th:replace="fragment/topbar :: nav"/>
  <div class="container-fluid">
    <div class="row">
      <nav th:replace="fragment/leftmenu"/>

      <main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">

        <h2>用戶列表</h2>
        <button th:onclick="|window.location.href='@{/user}'|" class="btn btn-sm btn-success">添加</button>
        <div class="table-responsive">
          <table class="table table-striped table-sm">
            <thead>
            <tr>
              <th>編號</th>
              <th>姓名</th>
              <th>郵箱</th>
              <th>性別</th>
              <th>生日</th>
              <th>操做</th>
            </tr>
            </thead>
            <tbody>
            <tr th:each="user : ${userList}">
              <td th:text="${user.id}"/>
              <td th:text="${user.name}"/>
              <td th:text="${user.email}"/>
              <td th:text="${user.gender}==0?'女':'男'"/>
              <td th:text="${#dates.format(user.birthday,'yyyy-MM-dd')}"/>
              <td>
                <form th:action="@{/user/}+${user.id}" method="post">
                  <input type="button" th:onclick="|window.location.href='@{/}user/${user.id}'|" class="btn btn-sm btn-info" value="編輯"/>
                  <input type="hidden" name="_method" value="delete">
                  <input type="submit" value="刪除" class="btn btn-sm btn-danger"/>
                </form>
              </td>
            </tr>
            </tbody>
          </table>
        </div>
      </main>
    </div>
  </div>
  </body>
</html>
templates/users.html

三、編寫編輯頁:

<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="description" content="">
    <meta name="author" content="">

    <title>[[${user.id==null?'添加':'編輯'}]]</title>

    <link th:href="@{/webjars/bootstrap/4.3.1/css/bootstrap.css}" rel="stylesheet">
    <link th:href="@{/css/index.css}" rel="stylesheet">
  </head>

  <body>
  <nav th:replace="fragment/topbar :: nav"/>
  <div class="container-fluid">
    <div class="row">
      <nav th:replace="fragment/leftmenu"/>

      <main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">

        <h2>用戶[[${user.id==null?'添加':'編輯'}]]</h2>
        <form th:action="@{/user}" method="post" th:object="${user}">
          <input type="hidden" name="id" th:value="*{id}">
            <input type="hidden" name="_method" value="put" th:unless="${user.id==null}">
          <div class="form-group">
            <lable>姓名:</lable>
            <input type="text" name="name" th:value="*{name}" class="form-control" placeholder="姓名"/>
          </div>
          <div class="form-group">
            <lable>郵箱:</lable>
            <input type="email" name="email" th:value="*{email}" class="form-control" placeholder="郵箱"/>
          </div>
          <div class="form-group">
            <lable>性別:</lable>
            <br>
            <div class="form-check form-check-inline">
              <input class="form-check-input" type="radio" th:checked="*{gender}==1" name="gender" value="1"/>
              <label class="form-check-label"></label>
            </div>
            <div class="form-check form-check-inline">
              <input class="form-check-input" type="radio" th:checked="*{gender}==0" name="gender" value="0"/>
              <label class="form-check-label"></label>
            </div>
          </div>
          <div class="form-group">
            <label>生日:</label>
            <input type="text" name="birthday" th:value="*{#dates.format(birthday,'yyyy-MM-dd')}" class="form-control" placeholder="生日"/>
          </div>

          <button class="btn btn-lg btn-primary btn-block" th:text="提交" type="submit"></button>
          <span th:if="${msg!=null}" style="color:red;">[[${msg}]]</span>
          <p class="mt-5 mb-3 text-muted">&copy; 2019-2020</p>
        </form>
      </main>
    </div>
  </div>
  </body>
</html>
templates/user.html

四、效果:

實現了 Restful 風格的 CRUD
列表頁:


新增:


編輯:

test
須要注意的地方:
  • 在添加和修改時有提交日期類型數據,須要在配置文件中配置日期格式化規則 spring.mvc.date-format=yyyy-MM-dd 。
  • 修改和刪除操做提交時咱們須要使用特殊請求( PUT 和 DELETE ),但表單自己又是不支持特殊請求的,SpringMVC 自己是給咱們提供了一個 HTTP 方法過濾器(HiddenHttpMethodFilter),該過濾器的做用就是讓 SpringMVC 將咱們的普通請求當作特殊請求來處理,而且 SpringBoot 已經幫咱們配置好了這個過濾器。使用該功能咱們須要作一些額外的操做告知 SpringMVC 咱們的請求是複雜請求:a、表單的請求方法必須爲 POST,b、咱們須要在表單中提供一個隱藏域,且該隱藏域 name 需指定爲 "_method"(可修改配置),value 則爲咱們要使用的請求方式。
    1 @Bean
    2 @ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
    3 public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
    4   return new OrderedHiddenHttpMethodFilter();
    5 }
    org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration#hiddenHttpMethodFilter : SpringBoot 自動配置的 HTTP 方法過濾器
相關文章
相關標籤/搜索