1. 程式人生 > 實用技巧 >SpringBoot-Web開發

SpringBoot-Web開發

SpringBoot Web開發

目錄

1. 自動裝配

SpringBoot到底幫我們配置了什麼? 我們能不能進行修改? 能修改哪些東西? 能不能擴充套件?

  • XXXAutoConfiguration: 向容器中自動裝配的元件
  • XXXProperties: 自動裝配類, 裝配配置檔案中自定義的一些內容!

2. 要解決的問題

  • 匯入靜態資源
  • 首頁
  • 模板引擎: Thymeleaf
  • 裝配擴充套件SpringMVC
  • 增刪改查
  • 攔截器
  • 國際化

3. 靜態資源

靜態資源目錄

預設

  • resources下的 (優先順序由高到低)
    • resources
    • static(預設)
    • public
  • /** (根目錄:localhost:8080/)

自定義靜態資源後, 以上的目錄失效

spring.mvc.static-path-pattern=/hello

4. 首頁如何定製

位置: 靜態資源目錄下的index.html

定製標籤的圖示: 在static目錄下新建favicon.ico即可

5. 模板引擎

1. 匯入依賴

<!--匯入thymeleaf模板引擎依賴, 我們都是基於3.X開發的-->
<dependency>
    <groupId>org.thymeleaf</groupId>
    <artifactId>thymeleaf-spring5</artifactId>
</dependency>
<dependency>
    <groupId>org.thymeleaf.extras</groupId>
    <artifactId>thymeleaf-extras-java8time</artifactId>
</dependency>

2. 使用

在resources下的template目錄下放html頁面即可

@ConfigurationProperties(prefix = "spring.thymeleaf")
public class ThymeleafProperties {

   private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8;

   public static final String DEFAULT_PREFIX = "classpath:/templates/";

   public static final String DEFAULT_SUFFIX = ".html";

controller控制檢視跳轉

package com.wang.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.Arrays;

//在template目錄下的所有頁面, 只能通過controller來跳轉
//這個需要模板引擎的支援
@Controller
public class IndexController {

    @RequestMapping("/test")
    public String index (Model model) {
        model.addAttribute("msg", "Hello, ThymeLeaf!");
        model.addAttribute("htmlMsg", "<h1>Hello, ThymeLeaf!</h1>");
        model.addAttribute("users", Arrays.asList("王", "趙", "李"));
        return "test";
    }
}

3. thymeleaf使用

在html中新增約束

<html xmlns:th="http://www.thymeleaf.org">

Simple expressions:

  • Variable Expressions: ${...}
  • Selection Variable Expressions: *{...}
  • Message Expressions: #{...}
  • Link URL Expressions: @{...}
  • Fragment Expressions: ~{...}
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<!--所有的HTML元素, 都可以被 thymeleaf接管:    th: 元素名-->

<div th:text="${msg}"></div>

<!--轉義html標籤-->
<div th:utext="${htmlMsg}"></div>
<hr>

<!--遍歷 th:each-->
<div th:each="user : ${users}" th:text="${user}"></div>

</body>
</html>

6. 擴充套件裝配MVC

如果我們要擴充套件SpringMVC, 官方建議我們做以下兩步:

  • @Configuration. Java配置類
  • 實現WebMvcConfigurer介面

自己定義一個檢視解析器

package com.wang.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.Locale;

//全面擴充套件SpringMvc
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {

    /*
    public interface ViewResolver
    實現了檢視解析器介面的類, 我們就可以把它看做檢視解析器
     */
    //註冊一個bean, 就相當於我們之前在xml中寫的一bean標籤
    //這個方法的名字就相當於bean標籤中的id屬性
    //這個方法的返回值就相當於bean標籤中的class屬性
    @Bean
    public ViewResolver myViewResolver() {
        //返回值就是要注入到bean中的物件
        return new MyViewResolver();
    }


    //自定義了一個自己的檢視解析器
    public static class MyViewResolver implements ViewResolver{
        @Override
        public View resolveViewName(String s, Locale locale) throws Exception {
            return null;
        }
    }


}

在doDispatch方法打斷點, 訪問localhost:8080

發現自己的檢視解析器被載入了

結論:

如果想要定製化一些功能, 只需要寫這個元件, 然後將它交給SpringBoot(利用註解註冊Bean), 然後他就會被自動裝配!

7. 員工管理

1. 建立實體類

package com.wang.pojo;

import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;
//員工表
@Data
@NoArgsConstructor
public class Employee {
    private Integer id;
    private String lastName;
    private String email;
    private Integer gender; //0: 女, 1:  男

    private Department department;
    private Date date;

    public Employee(Integer id, String lastName, String email, Integer gender, Department department) {
        this.id = id;
        this.lastName = lastName;
        this.email = email;
        this.gender = gender;
        this.department = department;
        //預設的建立日期
        this.date = new Date();
    }
}
package com.wang.pojo;
//部門表

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Department {
    private Integer id;
    private String departmentName;
}

2. 模擬資料庫, 建立Dao

package com.wang.dao;

import com.wang.pojo.Department;
import org.springframework.stereotype.Repository;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

//部門Dao
@Repository
public class DepartmentDao {
    //模擬資料庫中的資料
    private static Map<Integer, Department> departments = null;
    static {
        departments = new HashMap<>();      //建立一個部門表

        departments.put(101, new Department(101, "教學部"));
        departments.put(101, new Department(102, "市場部"));
        departments.put(101, new Department(103, "教研部"));
        departments.put(101, new Department(104, "運營部"));
        departments.put(101, new Department(105, "後勤部"));
    }

    //獲得所有部門的資訊
    public Collection<Department> getDepartments() {
        return departments.values();
    }

    //通過id獲得部門
    public Department getDepartmentById(Integer id) {
        return departments.get(id);
    }

}
package com.wang.dao;

import com.wang.pojo.Department;
import com.wang.pojo.Employee;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

//員工Dao
@Repository
public class EmployeeDao {
    //模擬資料庫中的資料
    private static Map<Integer, Employee> employees = null;
    //員工所屬部門
    @Autowired
    private DepartmentDao departmentDao;
    static {
        employees = new HashMap<>();    //建立一個部門表

        employees.put(1001, new Employee(1001, "AA", "[email protected]", 0, new Department(101, "教學部")));
        employees.put(1002, new Employee(1002, "BB", "[email protected]", 1, new Department(102, "市場部")));
        employees.put(1003, new Employee(1003, "CC", "[email protected]", 0, new Department(103, "教研部")));
        employees.put(1004, new Employee(1004, "DD", "[email protected]", 1, new Department(104, "運營部")));
        employees.put(1005, new Employee(1005, "EE", "[email protected]", 0, new Department(105, "後勤部")));
    }

    //主鍵自增!
    private static Integer initId = 1006;
    //增加 一個員工
    public void save(Employee employee) {
        //如果沒有id, 主鍵自增
        if (employee.getId() == null) {
            employee.setId(initId++);
        }

        //如果部門name錯誤, 通過部門ID可以取到正確的值
        employee.setDepartment(departmentDao.getDepartmentById(employee.getDepartment().getId()));

        employees.put(employee.getId(), employee);
    }

    //查詢全部員工的資訊
    public Collection<Employee> getAll() {
        return employees.values();
    }

    //通過ID查詢員工
    public Employee getEmployeeByID (Integer id) {
        return employees.get(id);
    }

    //通過ID刪除員工
    public void deleteEmployeeById (Integer id) {
        employees.remove(id);
    }


}

3. 可以在controller中控制檢視跳轉

package com.wang.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class IndexController {

    //訪問首頁和/index都會跳轉
    @RequestMapping({"/", "/index"})
    public String index() {
        return "index";
    }
}

注意:

  • 跳轉多個路徑, 用{ , }

4. 也可以在自定義config中設定檢視跳轉

package com.wang.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

//全面擴充套件SpringMvc
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {

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

重寫addViewController方法, 同樣可以跳轉多個路徑

在SpringBoot中, 檢視跳轉的返回值自動被設定了字首(templates)和字尾(.html), 直接寫頁面檔名即可

5. 修改模板為thymeleaf

修改頁面後不生效, 在配置檔案中關閉模板引擎的快取

#關閉模板引擎的快取
spring.thymeleaf.cache=false

修改url, 在標籤前加th:表示被模板引擎接管了

  • Link URL Expressions: @{...}

注意, 路徑直接從靜態資源目錄找, 即直接寫靜態資源下的路徑就可以了

修改的時候, 只修改位於本地的資源即可

所有頁面的靜態資源都要用thymeleaf接管!

6. 頁面的國際化

1. 配置i18n

在resource目錄下建立i18n, 分別建立login.properties, login_en_US.properties, login_zn_CN.properties, 可以使用Resource Bundle方便寫對應的配置檔案

2. 需要在專案中進行按鈕切換, 需要自定義元件

package com.wang.config;

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;

//實現了LocaleResolver就是一個國際化解析器
public class MyLocaleResolver implements LocaleResolver {

    //解析請求
    @Override
    public Locale resolveLocale(HttpServletRequest request) {
        //獲取請求中的引數 l
        String language = request.getParameter("l");

        //如果沒有, 就使用預設的
        Locale locale = Locale.getDefault();

        //如果請求的連結攜帶了國際化的引數
        if (!StringUtils.isEmpty(language)) {
            String[] split = language.split("_");
            //國家, 地區
            locale = new Locale(split[0], split[1]);
        }

        return locale;
    }

    @Override
    public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {

    }
}

3. 記得將自己寫的元件配置到Spring容器中

用@Bean註冊為bean, 注意方法的名字必須寫對, 因為這是bean的id!, 返回值為bean的value

package com.wang.config;

import org.apache.tomcat.util.descriptor.LocalResolver;
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.WebMvcConfigurer;

//全面擴充套件SpringMvc
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {

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

    //在這裡註冊自己寫的配置檔案, 這樣自定義國際化元件就生效了!
    @Bean
    public LocaleResolver localeResolver() {
        return new MyLocaleResolver();
    }
}

4. 前端頁面用#{}配置訊息, @{}配置url, ()直接傳參

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta http-equiv="Content-Type" content="text/html; 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>Signin Template for Bootstrap</title>
    <!-- Bootstrap core CSS -->
    <link th:href="@{/css/bootstrap.min.css}" rel="stylesheet">
    <!-- Custom styles for this template -->
    <link th:href="@{css/signin.css}" rel="stylesheet">
</head>

<body class="text-center">
<form class="form-signin" action="dashboard.html">
    <img class="mb-4" th:src="@{/img/bootstrap-solid.svg}" alt="" width="72" height="72">
    <h1 class="h3 mb-3 font-weight-normal" th:text="#{login.tip}"></h1>
    <label class="sr-only" th:text="#{login.username}">Username</label>
    <input type="text" class="form-control" th:placeholder="#{login.username}" required="" autofocus="">
    <label class="sr-only" th:text="#{login.password}">Password</label>
    <input type="password" class="form-control" th:placeholder="#{login.password}" required="">
    <div class="checkbox mb-3">
        <label>
            <input type="checkbox" value="remember-me" th:text=" #{login.remember}">
        </label>
    </div>
    <button class="btn btn-lg btn-primary btn-block" type="submit" th:text="#{login.btn}">Sign in</button>
    <p class="mt-5 mb-3 text-muted">© 2017-2018</p>
    <a class="btn btn-sm" th:href="@{/index(l='zh_CN')}">中文</a>
    <a class="btn btn-sm" th:href="@{/index(l='en_US')}">English</a>
</form>

</body>

</html>

7. 登陸功能實現

1. controller

package com.wang.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class LoginController {

    @RequestMapping("/user/login")
    public String login(@RequestParam("username") String username, @RequestParam("password") String password, Model model) {
        //具體的業務
        if (!StringUtils.isEmpty(username) && "123456".equals(password)) {
            //重定向
            return "redirect:/main";
        } else {
            //提示使用者,登入失敗
            model.addAttribute("msg", "使用者名稱或密碼錯誤!");
            //返回登入頁
            return "index";
        }
    }
}

注意

  • 可以直接取到前端中name屬性對應的值, 但推薦使用@RequestParam註釋進行繫結
  • 如果要返回前端一些資訊, 使用Model並用addAttribute(name, value)

2. 修改前端顯示資訊

可以使用模板引擎提供的一些工具類進行判斷是否顯示資訊

<!--如果msg的結果為空, 則不顯示訊息-->
<p th:text="${msg}" style="color: red" th:if="${not #strings.isEmpty(msg)}"></p>

3. 在自定義配置類中新增檢視控制

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

8. 登入攔截器

1. 編寫攔截器

package com.wang.config;

import org.springframework.web.servlet.HandlerInterceptor;

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

//實現了HandlerInterceptor介面就是一個攔截器
public class LoginHandlerIntercepter implements HandlerInterceptor {
    //return true就是放行
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        //登入成功之後, 應該有使用者的session
        Object loginUser = request.getSession().getAttribute("loginUser");

        if (loginUser == null) {
            //沒有登入
            request.setAttribute("msg", "沒有許可權, 請先登入");
            request.getRequestDispatcher("/index").forward(request, response);
            //不放行
            return false;
        } else {
            return true;
        }
    }
}

2. 在配置類中配置攔截器

//配置攔截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(new LoginHandlerIntercepter())
            .addPathPatterns("/**")
            .excludePathPatterns("/index", "/", "/user/login", "/static/**");
}

注意

  • 重寫addInterceptors方法
  • addPathPatterns寫要攔截的url
  • excludePathPatterns寫要放行的資源, 注意要將靜態資源放行!
  • / 和 /* 的區別**
    • / 是攔截所有的資料夾,不包含子資料夾*
    • / 是攔截所有的資料夾及裡面的子資料夾**

3. 在前端頁面從session中取出結果

<a class="navbar-brand col-sm-3 col-md-2 mr-0" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">[[${session.loginUser}]]</a>

使用[[${}]]即可取出, session用session.欄位 即可取出對應欄位在session中存放的值!

9. 展示員工列表

1. 利用thymeleaf抽取模板

<nav class="col-md-2 d-none d-md-block bg-light sidebar" th:fragment="sidebar">

th:fragment="" 抽取模板

<div th:insert="~{dashboard::sidebar}"></div>

th:insert="~{}"使用模板

花括號中的內容為 檔名::模板名

可以將公用的模板放在一個html中

通過 () 可以傳遞一些值, 接收判斷即可

<div th:insert="~{commons/commons::sidebar(active='list')}"></div>

這樣可以實現對一些標籤的兩種狀態的切換

<a th:class="${active=='list'?'nav-link active':'nav-link'}" th:href="@{/employees}">

2. 列表迴圈展示

<table class="table table-striped table-sm">
    <thead>
    <tr>
        <th>id</th>
        <th>lastName</th>
        <th>email</th>
        <th>gender</th>
        <th>department</th>
        <th>birth</th>
        <th>操作</th>
    </tr>
    </thead>
    <tbody>
        <tr th:each="employee:${employees}">
            <td th:text="${employee.getId()}"></td>
            <td th:text="${employee.getLastName()}"></td>
            <td th:text="${employee.getEmail()}"></td>
            <td th:text="${employee.getGender() == 0 ? '女' : '男'}"></td>
            <td th:text="${employee.getDepartment().getDepartmentName()}"></td>
            <td th:text="${#dates.format(employee.getDate(), 'yyyy-MM-dd HH:mm:ss')}"></td>
            <td>
                <button class="btn btn-sm btn-primary">編輯</button>
                <button class="btn btn-sm btn-danger">刪除</button>
            </td>
        </tr>
    </tbody>
</table>

用 th:each="" 遍歷, 用 th:text="${}" 展示其中的元素

10. 新增員工

SpringBoot預設的date格式為 / 分隔

我們為了實現輸入日期用 - 分隔, 在配置檔案中設定日期格式

spring.mvc.format.date=yyyy-MM-dd

1. 按鈕提交

main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
    <h2>
        <a class="btn btn-sm btn-success" th:href="@{/addEmployee}">新增員工</a>
    </h2>

a標籤預設的提交方式為get請求

2. 跳轉到新增頁面

//只能用get方式獲得請求, 前端請求新增員工, 這裡進行頁面的跳轉
@GetMapping("/addEmployee")
public String toAddPage(Model model) {
    //查出所有部門的資訊
    Collection<Department> departments = departmentDao.getDepartments();
    model.addAttribute("departments", departments);

    return "employees/add";
}
<main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">

    <form th:action="@{/addEmployee}" method="post">
        <div class="form-group">
            <label>LastName</label>
            <input type="text" name="lastName" class="form-control" placeholder="請輸入姓氏">
        </div>
        <div class="form-group">
            <label>Email</label>
            <input type="email" name="email" class="form-control" placeholder="請輸入郵箱">
        </div>
        <div class="form-group">
            <label>Gender</label><br>
            <div class="form-check form-check-inline">
                <input class="form-check-input" type="radio" 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" name="gender" value="0">
                <label class="form-check-label">女</label>
            </div>
        </div>
        <div class="form-group">
            <label>department</label>
            <!--由於我們在controller中接收的是一個department物件, 而我們提交的是其中的一個屬性, 因此要寫成name="department.id"-->
            <select class="form-control" name="department.id">
                <!--這裡提交的是value-->
                <option th:each="department:${departments}" th:text="${department.getDepartmentName()}"
                        th:value="${department.getId()}"></option>
            </select>
        </div>
        <div class="form-group">
            <label>Birth</label>
            <input type="text" name="date" class="form-control" placeholder="請輸入出生日期">
        </div>
        <button type="submit" class="btn btn-primary">新增</button>
    </form>


</main>

這裡使用post請求提交

表單的name屬性要與pojo中的屬性一一對應, 這樣才能取到自動裝配後對應的值

3. 新增員工成功

//只能用post方式獲得請求, 與上面的get方式的url一致, 是RestFul風格
@PostMapping("/addEmployee")
public String addEmployee(Employee employee) {
    //新增的操作
    //呼叫底層業務方法, 儲存員工資訊
    employeeDao.save(employee);
    return "redirect:/employees";
}

新增成功後跳轉到員工展示頁面, 從map中遍歷並展示

11. 修改員工

1. 新增修改按鈕

<a class="btn btn-sm btn-primary" th:href="@{/employee/}+${employee.getId()}">編輯</a>

利用url傳遞引數, 將當前選中的物件的id傳到後端

2. 跳轉到修改頁面

//去員工的修改頁面
@GetMapping("/employee/{id}")
public String toUpdateEmployee(@PathVariable("id")Integer id, Model model) {
    //查出原來的資料
    Employee employee = employeeDao.getEmployeeByID(id);
    model.addAttribute("employee", employee);
    Collection<Department> departments = departmentDao.getDepartments();
    model.addAttribute("departments", departments);
    return "employees/update";
}

@PathVariable 註解,讓方法引數的值對應繫結到一個URI模板變數上 ( RestFul風格, 路徑格式為 /XXX/{XX} )

這裡由於我們要顯示departmentId對應的名字, 要把department物件也傳遞到前端

3. 設計修改頁面

注意前端的name要與屬性一致!

由於我們設計了主鍵自增, 而修改頁面無需讓使用者看到自己的id, 因此利用隱藏域傳遞id, 防止建立新的使用者

要顯示選中使用者的屬性值, 用value

date格式很重要, 我們可以指定顯示的日期格式: th:value="${#dates.format(employee.getDate(), 'yyyy-MM-dd')}"

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

    <form th:action="@{/updateEmployee}" method="post">
        <!--利用隱藏域傳遞id, 從而實現修改當前使用者的功能-->
        <input type="hidden" name="id" th:value="${employee.getId()}">
        <div class="form-group">
            <label>LastName</label>
            <input type="text" name="lastName" class="form-control" placeholder="請輸入姓氏"
                   th:value="${employee.getLastName()}">
        </div>
        <div class="form-group">
            <label>Email</label>
            <input type="email" name="email" class="form-control" placeholder="請輸入郵箱"
                   th:value="${employee.getEmail()}">
        </div>
        <div class="form-group">
            <label>Gender</label><br>
            <div class="form-check form-check-inline">
                <input class="form-check-input" type="radio" name="gender" value="1"
                       th:checked="${employee.getGender()==1}">
                <label class="form-check-label">男</label>
            </div>
            <div class="form-check form-check-inline">
                <input class="form-check-input" type="radio" name="gender" value="0"
                       th:checked="${employee.getGender()==0}">
                <label class="form-check-label">女</label>
            </div>
        </div>
        <div class="form-group">
            <label>department</label>
            <!--由於我們在controller中接收的是一個department物件, 而我們提交的是其中的一個屬性, 因此要寫成name="department.id"-->
            <select class="form-control" name="department.id">
                <!--這裡提交的是value, 所以要得到id-->
                <!--選擇與修改員工的部門一致的id, 遍歷, 一致則為true, 選中-->
                <option th:each="department:${departments}" th:text="${department.getDepartmentName()}"
                        th:selected="${department.getId()==employee.getDepartment().getId()}"
                        th:value="${department.getId()}"></option>
            </select>
        </div>
        <div class="form-group">
            <label>Birth</label>
            <input type="text" name="date" class="form-control" placeholder="請輸入出生日期"
                   th:value="${#dates.format(employee.getDate(), 'yyyy-MM-dd')}">
        </div>
        <button type="submit" class="btn btn-primary">修改</button>
    </form>


</main>

4. 儲存修改結果

將修改頁面的值讀到employee物件中, 儲存

@PostMapping("/updateEmployee")
public String updateEmployee(Employee employee) {
    employeeDao.save(employee);
    return "redirect:/employees";
}

12. 刪除員工

1. 新增刪除按鈕

<a class="btn btn-sm btn-danger" th:href="@{/deleteEmployee/}+${employee.getId()}">刪除</a>

此處為a標籤, 使用了btn的樣子

如果為button, 要繫結onclick

2. 在controller中刪除

將前端傳遞的id在後端刪除對應的employee

由於刪除不需要額外的資訊提供, 因此不用跳轉到專門的刪除頁面

//刪除員工
@GetMapping("/deleteEmployee/{id}")
public String deleteEmployee(@PathVariable("id")Integer id) {
    employeeDao.deleteEmployeeById(id);
    return "redirect:/employees";
}

13. 404處理

在template下新建error資料夾, 在其中新建404.html即可

其他錯誤與404類似, 修改名字即可

14. 登出

1. 設定登出按鈕

<a class="nav-link" th:href="@{/user/logout}">登出</a>

2. 根據url設計controller

package com.wang.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpSession;

@Controller
public class LogoutController {

    //移除loginUser欄位
    @RequestMapping("/user/logout")
    public String logout(HttpSession session) {
        session.removeAttribute("loginUser");
        return "redirect:/index";
    }
}