目录
Java SpringBoot 开发学习(狂神说Java)
SpringBoot概述
Spring
-
Spring开源框架(容器),简化开发
-
4种策略:
-
1.基于POJO的轻量级和最小侵入性编程
-
2.通过IOC,依赖注入(DI)和面向接口实现松耦合
-
3.基于切面(AOP)和惯例进行声明式变成
-
4.通过切面和模板减少样式代码
SpringBoot的核心思想:约定大于配置
微服务
-
微服务是一种架构风格。MVC三层架构,MVMM,微服务架构。
-
业务=>模块,把每个功能独立出来,吧独立出来的功能元素动态组合
SpringBoot程序
安装
jdk1.8,maven3.6.1,springboot,IDEA
-
直接官网下载,import
-
IDEA直接创建
测试
-
Application程序主入口,application.properties核心配置文件
-
Application同级目录建立controller进行测试(访问locahost:8080/hello/hello)
- Maven-Lifecycle-package打成jar包,java -jar xxx.jar运行服务
配置文件
-
端口号修改 server.port=8081
-
修改log:配置文件同目录创建banner.txt,从springboot banner等创建粘贴
原理
自动配置
步骤
-
springboot在启动的时候,从类路径下/META-INF/spring.factories获取指定的值
-
将这些自动配置的类导入容器,自动配置就会生效,帮我进行自动配置
-
以前需要自动配置的东西,sprintboot做了
-
整个javaEE,解决方案和自动配置的东西都在sprint-bbot-autoconfigure-version.jar这个包下
-
它会把所有需要导入的组件,以类名的方式返回,这些组件就会被添加到容器
-
容器中也会存在非常多的xxxxAutoConfiguration,就是这些类给容器中导入了这个场景需要的所有组件,并自动配置
-
有了自动配置类,免去了手动编写配置文件的工作
sprintboot所有的自动配置都在启动类种扫描并加载:sprint.factories所有的自动配置类都在这里,但是不一定生效,要判断条件是否成立。只要导入了对应的start,就有对应的启动器了,有了启动器,我们自动装配就会生效,然后就配置成功了。
-
springboot dependecies: 核心依赖在父工程中
-
写或者引入Sprintboot依赖时,不需要指定版本,因为有这些版本仓库
启动器
-
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency>
-
sprintboot将所有功能场景都变成一个个的启动器
-
官网可以寻找需要使用的starter
主程序
-
SpringBootApplication 标注类是一个springboot的应用,启动类下的所有资源被导入
-
SpringApplication.run(SpringbootHelloworldApplication.class, args);
将springboot启动 -
@SprintBootConfiguration: sprintboot配置 @Configuration: sprint配置类 @component: 一个sprint组件 @EnableAutoConfiguration:自动配置 @AutoConfigurationPackage: 自动配置包 @Import(AutoConfigurationPackages.Registrar.class) :自动配置 包注册 @Import(AutoConfigurationImpoSelector.class): 自动配置导入选择
主启动类
SpringApplication
-
1.推断应用的类型时普通的项目还是web项目
-
2.查找并加载所有可用初始化器,设置到initializers属性中
-
3.找出所有的应用程序监听器,设置到listeners属性中
-
4.推断并设置main方法的定义类,找到运行的主类
yaml语法
官方文档:https://docs.spring.io/spring-boot/docs/2.6.11/reference/htmlsingle/#using.build-systems.starters
-
删除默认配置文件,新建application.yaml
-
语法: key: 空格 value
-
server: port: 8081 //2 server: {port: 8081, xxx: yyy} //3 server: - port - xxx
给属性赋值的几种方式
-
@Value("xxx"),测试时用@Autowired自动装配,才能使用private Dog dog;
-
yaml可用直接给实体类赋值,实体类使用@ConfigurationProperties(perfix = "person")。 松散绑定last-name和lastName一样的。 原理是通过set方法实现
person:
name: A1oe
age: 3
lists:
- code
- music
dog:
name: "旺财"
- properties,@propertySource(value = "classpath:A1oe.properties") => @Value("$name") SPEL表达式
JR303校验
-
类上面@Validated
-
属性上面@Email(message="xxx") 等
多环境配置及配置文件位置
springboot 启动会扫描以下位置的application.properties或者application.yml文件作为Spring boot的默认配置文件:(优先级从上到下)
1.当前目录
1.当前目录中的/config子目录
2.当前目录
2.类路径
1.类路径/config直接子目录
2.类路径
多环境切换(yaml使用"---"进行分割)
-
在主配置文件编写的时候,文件名可以是 application-{profile}.properties/yml , 用来指定多个环境版本;如:application-test.yml:代表测试环境配置、application-dev.yml:代表开发环境配置
-
Springboot并不会直接启动这些配置文件,它默认使用application.properties主配置文件,如果没有就会找application.yml。
-
需要通过一个配置来选择需要激活的环境
spring:
profiles:
active: dev #使用开发环境。
SpringBoot Web开发理论
-
xxxAutoConfiguration: 向容器中自动配置文件
-
xxxProperties: 自动配置类,装配配置文件中自定义的一些内容
解决的问题:
-
导入静态资源
-
首页
-
jsp,模板引擎Thymeleaf
-
装配扩展SpringMVC
-
增删改查数据库
-
拦截器
-
国际化
静态资源
-
默认情况下,Spring Boot 从类路径中的/static (或/public 或/resources 或/META-INF/resources)目录或 ServletContext的根目录提供静态内容。
-
优先级:resources>static>public
-
一般static放静态资源,resources放上传的文件,public放公共访问的资源
首页
首页
-
index.html放静态资源下可直接访问,但是一般使用controller跳转
-
在templates目录下的所有页面,只能通过controller来跳转
图标
模板引擎
导入themyleaf依赖,刷新Maven
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
ThymeleafProperties.java查看目录,解析templates下的.html文件
templates目录创建test.html,使用IndexController调用。访问localhost:8080/test,显示页面
package com.example.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class IndexController {
@RequestMapping("/test")
public String test(){
return "test";
}
}
Thymeleaf使用文档:https://www.thymeleaf.org/doc/tutorials/3.1/usingthymeleaf.html
Variable Expressions: ${...}
Selection Variable Expressions: *{...}
Message Expressions: #{...}
Link URL Expressions: @{...}
Fragment Expressions: ~{...}
所有的html元素都可以被thymeleaf替换接管: th:元素名。
在/test路由显示hello springboot
package com.example.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class IndexController {
@RequestMapping("/test")
public String test(Model model){
model.addAttribute("msg","hello springboot");
return "test";
}
}
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div th:text="${msg}"></div>
</body>
</html>
Thymeleaf语法
Thymeleaf使用文档:https://www.thymeleaf.org/doc/tutorials/3.1/usingthymeleaf.html
例子:遍历users,使用each
package com.example.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.Arrays;
@Controller
public class IndexController {
@RequestMapping("/test")
public String test(Model model){
model.addAttribute("msg","hello springboot");
model.addAttribute("users", Arrays.asList("AAA","BBB"));
return "test";
}
}
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h3 th:each="user:${users}" th:text="${user}"></h3>
<h3 th:each="user:${users}">[[ ${user} ]]</h3>
</body>
</html>
MVC配置原理,扩展SpringMVC
Spring Boot官方文档[Web](https://springdoc.cn/spring-boot/web.html#web.servlet.spring-mvc.auto-configuration)
如果你想保留那些Spring Boot MVC定制,并进行更多的 [MVC定制](https://docs.spring.io/spring-framework/docs/6.0.5/reference/html/web.html#mvc)(Interceptor、Formatter、视图控制器和其他功能),你可以添加你自己的
@Configuration 类,类型为
WebMvcConfigurer ,但 **不** 含
@EnableWebMvc。
视图解析
config-MyMvcConfig.java下
package com.example.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;
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
@Bean
public ViewResolver myViewResolver(){
return new MyViewResolver()
}
public static class MyViewResolver implements ViewResolver{
@Override
public View resolveViewName(String viewName, Locale locale) throws Exception {
return null;
}
}
}
视图跳转
addViewControllers,将/a1oe跳转到/test
package com.example.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/a1oe").setViewName("test");
}
}
结论:springboot中,有很多xxxx Configuration 帮助我们进行扩展配置,看见了需要注意。
员工管理系统(基于Spring Boot)
准备工作
BootStrap模板下载:[bootstrap模板 bootstrap模板免费下载](https://sc.chinaz.com/tag_moban/bootstrap.html)
页面放templates,资源放static(静态资源找不到的话可以私信找我要)。
建立部门信息表和员工信息表,需要引入依赖lombok
-
Department.java
-
Employee.java
package com.example.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
//部门表
@Data
@AllArgsConstructor // 有参
@NoArgsConstructor // 无参
public class Department {
private Integer id;
private String departmentName;
}
package com.example.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
//员工表
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Employee {
private Integer id;
private String lastName;
private String email;
private Integer gender; // 0女 1男;
private Department department;
private Date birth;
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.birth = new Date();
}
}
Da层模拟数据库
-
DepartmentDao
-
EmployeeDao
package com.example.dao;
import com.example.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<Integer, Department>(); //创建一个部门表
departments.put(101, new Department(101,"教学部"));
departments.put(102, new Department(102,"市场部"));
departments.put(103, new Department(103,"教研部"));
departments.put(104, new Department(104,"运营部"));
departments.put(105, new Department(105,"后勤部"));
}
//获得所有部门信息
public Collection<Department> getDepartments() {
return departments.values();
}
//通过id得到部门
public Department getDepartmentById(Integer id){
return departments.get(id);
}
}
package com.example.dao;
import com.example.pojo.Department;
import com.example.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<Integer, Employee>(); //创建一个部门表
employees.put(1001,new Employee(1001,"AA","[email protected]",1,new Department(101,"教学部")));
employees.put(1002,new Employee(1002,"BB","[email protected]",0,new Department(102,"市场部")));
employees.put(1003,new Employee(1003,"CC","[email protected]",1,new Department(103,"教研部")));
employees.put(1004,new Employee(1004,"DD","[email protected]",0,new Department(104,"运营部")));
employees.put(1005,new Employee(1005,"EE","[email protected]",1,new Department(105,"后勤部")));
}
//主键自增
private static Integer InitId = 1006;
//增加一个员工
public void save(Employee employee){
if (employee.getId()==null){
employee.setId(InitId++);
}
employee.setDepartment(departmentDao.getDepartmentById(employee.getDepartment().getId()));
employees.put(employee.getId(), employee);
}
//查询全部员工信息
public Collection<Employee> getAll(){
return employees.values();
}
//通过id查询员工
public Employee getEmploeeById(Integer id){
return employees.get(id);
}
//删除员工
public void delete(Integer id){
employees.remove(id);
}
}
首页实现
两种方式
- IndexController,但不建议
@Controller
public class IndexController{
@RequestMapping({"/","/index.html"})
public String index() {
return "index";
}
}
- config目录下的MyMvcConfig,重写addViewControllers接管
package com.example.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
registry.addViewController("/index.html").setViewName("index");
}
}
静态资源加载,修改html文件,使用thymeleaf接管,举例如下:
index.html中
<link th:href="@{/css/bootstrap.min.css}" rel="stylesheet">
<link th:href="@{/css/signin.css}" rel="stylesheet">
404.html,dashboard.html中
<script type="text/javascript" th:src="@{/js/jquery-3.2.1.slim.min.js}"></script>
<script type="text/javascript" th:src="@{/js/popper.min.js}"></script>
<script type="text/javascript" th:src="@{/js/bootstrap.min.js}"></script>
页面国际化
- 确认IDEA设置中FIle Encoding的所有编码为UTF-8
-
resourcces下创建文件夹i18n目录(internationalization缩写),存放国际化配置文件
-
创建配置文件login.properties和中文的login_zh_CN.properties(文件合并,自动创建一个下级目录)
-
再使用新的方法在新的目录这上面去新建一个文件,再添加一个英文的
- 可视化配置,点击Text旁边的Resource Bundle
-
配置message路径,
spring.messages.basename=i18n.login
-
Thymeleaf中使用#号转换国际化消息
- 国际化解析器,LocaleResolver。写一个自己的
LocaleResolver
。思路就是点击中文或English时进行跳转,然后使用组件类进行处理。
<a class="btn btn-sm" th:href="@{/index.html(l='zh_CN')}">中文</a>
<a class="btn btn-sm" th:href="@{/index.html(l='en_US')}">English</a>
package com.example.config;
import org.springframework.web.servlet.LocaleResolver;
import org.thymeleaf.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Locale;
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)){
//zh_CN
String[] split = language.split("_");
//语言,地区
locale = new Locale(split[0], split[1]);
}
return locale;
}
@Override
public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
}
}
为了让我们的类能够生效,需要再配置一下这个组件,在我们自己的MvcConofig
下添加Bean
//自定义国际化生效
@Bean
public LocaleResolver localeResolver() {
return new MyLocaleResolver();
}
登录功能
- 首先需要修改登录页面的表单,修改请求地址、提交的参数和返回信息的输出
<form class="form-signin" th:action="@{/user/login}">
<p style="color: red" th:text="${msg}" th:if="${not #strings.isEmpty({msg})}"></p>
<input type="text" name="username" class="form-control" th:placeholder="#{login.username}" required="" autofocus="">
<input type="password" name="password" class="form-control" th:placeholder="#{login.password}" required="">
- 解决密码泄露问题:加一个main.html映射在MyMvcConfig中,然后再控制器中跳转到main.html
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
registry.addViewController("/index.html").setViewName("index");
registry.addViewController("/main.html").setViewName("dashboard");
}
if (!StringUtils.isEmpty(username) && "123456".equals(password)){
return "redirect:/main.html";
}
登录拦截器
-
只有登录成功才能进main.html
-
需要先给登录拥护session,再LoginController中添加
package com.example.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.thymeleaf.util.StringUtils;
import javax.servlet.http.HttpSession;
@Controller
public class LoginContoller {
@RequestMapping("/user/login")
public String login(@RequestParam("username") String username, @RequestParam("password") String password, Model model
,HttpSession session){
//具体业务
if (!StringUtils.isEmpty(username) && "123456".equals(password)){
session.setAttribute("loginUser",username);
return "redirect:/main.html";
} else {
model.addAttribute("msg","用户名或密码错误");
return "index";
}
}
}
- 然后在config中创建LoginHanlderInterceptor拦截器,实现HandlerInterceptor接口
package com.example.config;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class LoginHandleInterceptor implements HandlerInterceptor {
@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.html").forward(request, response);
return false;
} else{
return true;
}
}
}
- 在MyMvcConfig中重写拦截器方法,添加我们的拦截器(需要排除某些页面和静态资源)
package com.example.config;
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.WebMvcConfigurer;
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
registry.addViewController("/index.html").setViewName("index");
registry.addViewController("/main.html").setViewName("dashboard");
}
//自定义国际化生效
@Bean
public LocaleResolver localeResolver() {
return new MyLocaleResolver();
}
//添加拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 添加拦截路径,排除index.html路径
registry.addInterceptor(new LoginHandleInterceptor()).addPathPatterns("/**").excludePathPatterns("/index.html","/",
"/user/login","/css/*","/js/**","/img/**");
}
}
员工列表展示
- list.html和dashboard.html中修改地址
<li class="nav-item">
<a class="nav-link" th:href="@{/emps}">
- 抽取公共部分代码(不重复造轮子),命名成组件
<!--顶部导航栏-->
<nav class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0" th:fragment="topbar">
<!--...-->
</nav>
<!--侧边栏-->
<nav class="col-md-2 d-none d-md-block bg-light sidebar" th:fragment="sidebar">
<!--...-->
</nav>
- Thymeleaf的插入语法是th:insert="~{}",在list.html中插入公共部分代码
<!--顶部导航栏-->
<div th:insert="~{dashboard::topbar}"></div>
<!--侧边栏-->
<div th:insert="~{dashboard::sidebar}"></div>
- 进一步:将公共部分代码存入commoms文件夹,并创建commons.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<!--头部导航栏-->
<nav class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0" th:fragment="topbar">
···
</nav>
<!--侧边栏-->
<nav class="col-md-2 d-none d-md-block bg-light sidebar" th:fragment="sidebar">
···
</nav>
</html>
- 将dashboard.html和list.html代码的公共部分用commons.html的内容进行插入
<!--顶部导航栏-->
<div th:insert="~{commons/commons::topbar}"></div>
<!--侧边栏-->
<div th:insert="~{commons/commons::sidebar}"></div>
- 侧边栏添加高亮,在dashboard.html和list.html页面侧边栏传参,参数在括号中
<div th:replace="~{commons/commons::sidebar(active='list.html')}"></div>
- 在commons.html中接受并判断是否使用active激活高亮
<a th:class="${active=='main.html'?'nav-link active':'nav-link'}" th:href="@{/main.html}">
-
循环显示th:each,删除list.html原始数据,再加入循环代码
id lastName email gender department birth 操作 -
添加编辑/删除工作
<td>
<button class="btn btn-sm btn-primary">编辑</button>
<button class="btn btn-sm btn-danger">删除</button>
</td>
添加员工
- 按钮提交,跳转到添加页面,添加员工成功,返回首页
<div class="container-fluid">
<div class="row">
<div th:insert="~{common/common::sidebar(active='list.html')}"></div>
- 后台编写,点击添加,跳转到add.html页面
@GetMapping("/emp")
public String toAddpage(Model model){
//查出所有部门信息
Collection<Department> departments = departmentDao.getDepartments();
model.addAttribute("departments", departments);
return "emp/add";
}
- add.html,从bootstarp官网拉一个表单
<main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
<form th:action="@{/emp}" method="post">
<div class="form-group">
<label>LastName</label>
<input type="text" name="lastName" class="form-control" placeholder="A1oe">
</div>
<div class="form-group">
<label>Email</label>
<input type="email" name="email" class="form-control" placeholder="[email protected]">
</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>
<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 class="form-group">
<label>department</label>
<select class="form-control" name="department.id">
<option th:each="dept:${departments}" th:text="${dept.getDepartmentName()}" th:value="${dept.getId()}">1</option>
</select>
</div>
<div class="form-group">
<label>Birth</label>
<input type="text" name="birth" class="form-control" placeholder="2023/05/07 23:00:00">
</div>
<button type="submit" class="btn btn-primary">添加</button>
</form>
</main>
- 后端接收post到/emp的数据
@Autowired
DepartmentDao departmentDao;
@PostMapping("/emp")
public String addEmp(Employee employee) {
//添加的操作
employeeDao.save(employee);
return "redirect:/emps";
}
修改员工信息
- 编辑按钮设置提交
<a class="btn btn-sm btn-primary" th:href="@{/emp/}+${emp.getId()}">编辑</a>
- 后台接收参数,并返回查询出的信息到update.html
//去员工修改页面
@GetMapping("/emp/{id}")
public String toUpdateEmp(@PathVariable("id") Integer id, Model model){
//查出原来的数据
Employee employee = employeeDao.getEmploeeById(id);
model.addAttribute("emp", employee);
//查出所有部门的信息
Collection<Department> department = departmentDao.getDepartments();
model.addAttribute("departments",department);
return "emp/update";
}
- 编写update.html
<main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
<form th:action="@{/updateEmp}" method="post">
<input type="hidden" name="id" th:value="${emp.getId()}">
<div class="form-group">
<label>LastName</label>
<input th:value="${emp.getLastName()}" type="text" name="lastName" class="form-control" placeholder="A1oe">
</div>
<div class="form-group">
<label>Email</label>
<input th:value="${emp.getEmail()}" type="email" name="email" class="form-control" placeholder="[email protected]">
</div>
<div class="form-group">
<label>Gender</label><br>
<div class="form-check form-check-inline">
<input th:checked="${emp.getGender()==1}" class="form-check-input" type="radio" name="gender" value="1">
<label class="form-check-label">男</label>
</div>
</div>
<div class="form-check form-check-inline">
<input th:checked="${emp.getGender()==0}" class="form-check-input" type="radio" name="gender" value="0">
<label class="form-check-label">女</label>
</div>
<div class="form-group">
<label>department</label>
<select class="form-control" name="department.id">
<!--我们在controller接收的是一个Employee,所以我们需要提交的是其中的一个属性-->
<option th:selected="${dept.getId()==emp.getDepartment().getId()}" th:each="dept:${departments}" th:text="${dept.getDepartmentName()}" th:value="${dept.getId()}"></option>
</select>
</div>
<div class="form-group">
<label>Birth</label>
<input th:value="${#dates.format(emp.getBirth(),'yyyy-MM-dd HH:mm:ss')}" type="text" name="birth" class="form-control" placeholder="2020-07-25 00:00:00">
</div>
<button type="submit" class="btn btn-primary">修改</button>
</form>
</main>
- 添加更新路由功能
@PostMapping("/updateEmp")
public String updateEmp(Employee employee) {
employeeDao.save(employee);
return "redirect:/emps";
}