SpringBoot-03-开发Web项目
5 SpringBoot开发web项目
5.1 静态资源映射
静态资源映射规则
-
在开发一个web项目中,我们不可避免的要使用到许多静态资源,如CSS、JS等,那么SpringBoot是怎么处理这些资源的呢?
-
官方文档
-
官方文档告诉了我们SpringBoot中默认存放静态资源的几个位置,
/static
、/public
、/resources
、/META-INF/resources
。或者是配置文件中指定的位置 -
除了这些常规手段之外,还提到了一种特殊的静态资源
webjars
,所有的webjars
会被映射到路径/webjars/**
上-
什么是
webjars
?- 按照
jar
的格式进行打包的静态资源文件。这种格式的文件管理和方便,只需要引入依赖即可使用。
- 按照
-
示例
-
引入maven依赖
<dependency> <groupId>org.webjars</groupId> <artifactId>jquery</artifactId> <version>3.5.1</version> </dependency>
-
访问测试
红色框出来的文件都会被映射到url
/webjars
下
-
-
5.2 首页处理
-
官方文档给出的说明是,SpringBoot会在静态资源的目录下查找一个叫
index.html
的文件,将它作为首页。如果这个找不到的话,就会在模板中找index
的模板 -
使用循序
index.html
>index
模板
5.3 ThymeLeaf
模板引擎
-
Web开发的模板引擎是为了使用户界面与业务数据(内容)分离而产生的,它可以生成特定格式的文档,用于网站的模板引擎就会生成一个标准的HTML文档。
-
我们之前使用的jsp就是一种模板引擎,不过他已经过时了,我们就不在使用它了。
-
这张图可以告诉你模板引擎怎么工作的
-
SpringBoot原生支持的模板引擎:FreeMaker、Groovy、Thymeleaf、Mustache,其中官方建议我们使用Thymeleaf
Thymeleaf简介
-
Thymeleaf是用来开发Web和独立环境项目的服务器端的Java模版引擎
-
Thymeleaf与SpringMVC的视图技术,及SpringBoot的自动化配置集成非常完美,几乎没有任何成本,你只用关注Thymeleaf的语法即可。
-
优点
- 动静结合:Thymeleaf 在有网络和无网络的环境下皆可运行,即它可以让美工在浏览器查看页面的静态效果,也可以让程序员在服务器查看带数据的动态页面效果。这是由于它支持 html 原型,然后在 html 标签里增加额外的属性来达到模板+数据的展示方式。浏览器解释 html 时会忽略未定义的标签属性,所以 thymeleaf 的模板可以静态地运行;当有数据返回到页面时,Thymeleaf 标签会动态地替换掉静态内容,使页面动态显示。
- 开箱即用:它提供标准和spring标准两种方言,可以直接套用模板实现JSTL、 OGNL表达式效果,避免每套模板、改jstl、改标签的困扰。同时开发人员也可以扩展和创建自定义的方言。
- 多方言支持:Thymeleaf 提供spring标准方言和一个与 SpringMVC 完美集成的可选模块,可以快速的实现表单绑定、属性编辑器、国际化等功能。
- SpringBoot完美整合,SpringBoot提供了Thymeleaf的默认配置,并且为Thymeleaf设置了视图解析器,我们可以像以前操作jsp一样来操作Thymeleaf。代码几乎没有任何区别,就是在模板语法上有区别
-
如何使用
-
导入Thymeleaf启动器
<!--thymeleaf--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>
-
把模板文件放到template文件夹下
-
语法
参考:https://www.cnblogs.com/jiangbei/p/8462294.html
-
创建HTML,这样的话才能在上下文中使用
th
标签<html xmlns:th="http://www.thymeleaf.org">
-
变量
${variable}
,*{...}
<p th:text="'Hello!, '+${name}+'!'">World</p> <div th:object="${session.user}"> <p>Name: <span th:text="*{firstName}">Sebastian</span>.</p> <p>Surname: <span th:text="*{lastName}">Pepper</span>.</p> <p>Nationality: <span th:text="*{nationality}">Saturn</span>.</p> </div> <!--等价于--> <div> <p>Name: <span th:text="${session.user.firstName}">Sebastian</span>.</p> <p>Surname: <span th:text="${session.user.lastName}">Pepper</span>.</p> <p>Nationality: <span th:text="${session.user.nationality}">Saturn</span>.</p> </div>
-
链接表达式
@{…}
<a href="details.html" th:href="@{http://localhost:8080/gtvg/order/details(orderId=${o.id})}">view</a>
-
文本替换,在替换时不能进行条件判断
<span th:text="'Welcome to our application, ' + ${user.name} + '!'"/>
-
运算符
- 算数运算符:
+
,-
,*
,/
,%
- 逻辑运算符:
>
,<
,>=
,<=
,==
,!=
- 条件运算符:
- If-then: (if) ? (then)
- If-then-else: (if) ? (then) : (else)
- Default: (value) ?: (defaultvalue)
- 算数运算符:
-
条件选择
th:if
,th:unless
,th:switch
<a th:href="@{/login}" th:if=${session.user == null}>Login</a> <a th:href="@{/login}" th:unless=${session.user != null}>Login</a> <div th:switch="${user.role}"> <p th:case="'admin'">User is an administrator</p> <p th:case="#{roles.manager}">User is a manager</p> <p th:case="*">User is some other thing</p> </div>
-
循环
th:each
<table> <tr> <th>ID</th> <th>NAME</th> <th>AGE</th> </tr> <tr th:each="emp : ${empList}"> <td th:text="${emp.id}">1</td> <td th:text="${emp.name}">海</td> <td th:text="${emp.age}">18</td> </tr> </table>
5.4 配置SpringMVC
默认配置下的SpringMVC
- 包含
ContentNegotiatingViewResolver
和BeanNameViewResolver
- 映射了静态资源路径,包括支持了
Webjars
- 自动注册了一些类型转换器和格式转化器
- 支持 Http 消息转换和 错误代码定制
- 支持静态首页
- 初始化数据绑定器(自动绑定数据到JavaBean上)
如何扩展SpringMVC
-
官方文档
-
翻译
- 如果你在默认的配置上增加额外的配置,实现接口
WebMvcConfigurer
,只给这个类加上@Configuration
注解,千万别用@EnableWebMvc
` - 如果想定制一些组件,就实现
WebMvcRegistrations
接口 - 如果想全面接管SpringMVC,就给你的配置类同时加上
@Configuration
和@EnableWebMvc
- 如果你在默认的配置上增加额外的配置,实现接口
-
源码分析
-
我们找到
WebMvcAutoConfiguration
,这个是SpringMVC的自动配置类。可以看到这个类的有这么一个生效条件@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
,这个注解的意思是,当不存在WebMvcConfigurationSupport
这个类的时候,默认配置才会生效 -
下面我们再来看
@EnableWebMvc
的源码,可以看见他引入了一个叫DelegatingWebMvcConfiguration
的类。字面意思就是托管WebMVC的自动配置。 -
再深入查看源码之后,这个
DelegatingWebMvcConfiguration
实际上继承了WebMvcConfigurationSupport
,这也就是说为什么我们在扩展SpringMVC的时候,不要加上@EnableWebMvc
` 的注解
-
5.5 i18n国际化
-
SpringBoot支持本地化消息用于迎合不同用户的语言需求
-
默认情况下,SpringBoot会在
classpath
下查找消息资源包,也可以通过配置文件指定位置 -
示例
-
在
resources
目录下创建i18n
文件夹,IDEA会自动识别这个文件夹为国际化的文件 -
在SpringBoot中配置国际化资源路径
spring: messages: basename: i18n.message
-
创建中文的配置文件和英文的配置文件
-
zh_CN
alert=请登录 loginBtn=登录 password=密码 remember=记住密码(不建议在公共电脑上勾选) username=用户名
-
en_US
alert=Please sign in loginBtn=SIGN IN password=Password remember=Remember Me (not recommended to set on public computers) username=username
-
-
在首页中使用
-
效果展示
-
-
源码分析
-
在
WebMvcAutoConfiguration
中有关于选择 本地资源的内容,具体逻辑如下- 先判断是否总是使用配置的语言环境
- 如果不是的话,则根据请求头中的
Accept-Language
解析使用什么样的语言资源
-
5.6 上手操作
准备工作
-
把前端模板放到该放的地方
-
导入Maven依赖
<dependencies> <!--web--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--数据库--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.4</version> </dependency> <!--配置工具--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
-
实体类
@Data @AllArgsConstructor @NoArgsConstructor @Repository public class Department { private int id; private String name; }
@Data @AllArgsConstructor @NoArgsConstructor @Repository public class Employee { private int id; private String name; private String email; private int gender; private Department department; private Date birth; }
-
配置数据库连接信息
spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver username: root password: 123456 url: jdbc:mysql://localhost:3306/springboot?serverTimezone=GMT%2B8&useSSL=true&useUnicode=true&characterEncoding=utf8
MyBatis整合
-
配置MyBatis
mybatis: mapper-locations: classpath:mybatis/mapper/*.xml type-aliases-package: com.pbx.pojo
-
mapper
-
DepartmentMapper.java
@Mapper @Repository public interface DepartmentMapper { List<Department> getDepartmentList(); Department getDepartmentById(@Param("departmentID") int id); int countByDepartmentId(@Param("departmentID")int id); int updateDepartment(Department department); int deleteDepartment(@Param("departmentID") int id); int insertDepartment(Department department); }
-
DepartmentMapper.xml
<mapper namespace="com.pbx.mapper.DepartmentMapper"> <select id="getDepartmentList" resultType="com.pbx.pojo.Department"> select * from springboot.department </select> <select id="getDepartmentById" resultType="com.pbx.pojo.Department"> select * from springboot.department where id = #{departmentID} </select> <select id="countByDepartmentId" resultType="java.lang.Integer"> SELECT COUNT(id) num FROM springboot.employee WHERE department = #{departmentID} </select> <update id="updateDepartment" parameterType="com.pbx.pojo.Department"> update springboot.department set name = #{name} where id = #{id}; </update> <delete id="deleteDepartment"> delete from springboot.department where id = #{departmentID}; </delete> <insert id="insertDepartment" parameterType="com.pbx.pojo.Department"> insert into springboot.department (id, name) values (#{id}, #{name}) </insert> </mapper>
-
EmployeeMapper.java
@Mapper @Repository public interface EmployeeMapper { List<Employee> getEmployeeList(); Employee getOneById(@Param("employeeID") int id); int addEmployee(Employee employee); int updateEmployee(Employee employee); int deleteEmployee(int id); }
-
EmployeeMapper.xml
<mapper namespace="com.pbx.mapper.EmployeeMapper"> <!--因为实体类的字段和数据库的字段不一致,所以要配置这resultMap和parameterMap--> <resultMap id="resultMap" type="com.pbx.pojo.Employee"> <!--有association之后就要配置所有属性的映射--> <result property="id" column="id"/> <result property="name" column="last_name"/> <result property="email" column="email"/> <result property="gender" column="gender"/> <result property="birth" column="birth"/> <association property="department" javaType="com.pbx.pojo.Department"> <result property="id" column="did"/> <result property="name" column="dname"/> </association> </resultMap> <select id="getEmployeeList" resultMap="resultMap"> select e.id, e.last_name, e.email, e.gender, e.department, e.birth, d.id did, d.name dname from springboot.employee e, springboot.department d where e.department = d.id </select> <select id="getOneById" resultMap="resultMap"> select e.id, e.last_name, e.email, e.gender, e.department, e.birth, d.id did, d.name dname from springboot.employee e, springboot.department d where e.id = #{employeeID} and e.department = d.id </select> <insert id="addEmployee" parameterType="com.pbx.pojo.Employee"> insert into springboot.employee(last_name, email, gender, department, birth) values (#{name}, #{email}, #{gender}, #{department.id}, #{birth}) </insert> <update id="updateEmployee" parameterType="com.pbx.pojo.Employee"> update springboot.employee set last_name = #{name}, email=#{email}, gender=#{gender}, department=#{department.id} where id = #{id} </update> <delete id="deleteEmployee"> delete from springboot.employee where id = #{id} </delete> </mapper>
-
-
测试
@Test public void DepartmentTest() { DMapper.insertDepartment(new Department(106, "干饭部门")); showDepartment(); DMapper.updateDepartment(new Department(106, "打工部")); showDepartment(); DMapper.deleteDepartment(106); showDepartment(); } public void showDepartment() { for (Department department : DMapper.getDepartmentList()) { System.out.println(department); } System.out.println("===================="); }
@Test public void EmployeeTest() { EMapper.addEmployee(new Employee(1, "布鲁斯儿", "123@qq.com", 1, DMapper.getDepartmentById(101), new Date())); showEmployee(); Map<String, Object> map = new HashMap<>(); map.put("id", 1); map.put("name", "里卡呆"); EMapper.updateEmployee(map); showEmployee(); EMapper.deleteEmployee(1); showEmployee(); } public void showEmployee() { for (Employee employee : EMapper.getEmployeeList()) { System.out.println(employee); } System.out.println("============="); }
首页
-
在配置类中给首页添加几个映射
@Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/").setViewName("index"); registry.addViewController("/index.html").setViewName("index"); registry.addViewController("/index").setViewName("index"); }
-
这样的话,访问上述任一路径都可以到达我们的首页,同时为了保证所有的静态资源能被正确引用到,这里我们要用
Thymeleaf
管理所有的静态资源-
具体表现为用
Thymeleaf
来引用<!-- 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">
-
i18n 国际化
-
在SpringBoot中配置国际化资源路径
spring: messages: basename: i18n.message
-
创建中文的配置文件和英文的配置文件
-
zh_CN
alert=请登录 loginBtn=登录 password=密码 remember=记住密码(不建议在公共电脑上勾选) username=用户名
-
en_US
alert=Please sign in loginBtn=SIGN IN password=Password remember=Remember Me (not recommended to set on public computers) username=username
-
-
在首页中使用
-
实现中英文切换
-
给两个链接添加地址
<a class="btn btn-sm" th:href="@{/zh/index}">中文</a> <a class="btn btn-sm" th:href="@{/en/index}">English</a>
-
配置Controller
@GetMapping("/{s}/index") public String changeLanguage(@PathVariable String s, HttpSession session) { // 为了保证语言信息能跟着一起走,所有要放到session里面 session.setAttribute("language", s); return "index"; }
-
重新配置Locale
public class LanguageConfig implements LocaleResolver { @Override public Locale resolveLocale(HttpServletRequest request) { String language = (String) request.getSession().getAttribute("language"); if ("zh".equals(language)) { return new Locale("zh", "CN"); } else if ("en".equals(language)) { return new Locale("en", "US"); } return request.getLocale(); } @Override public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) { } }
-
在MVC配置类中注入
@Bean public LocaleResolver localeResolver() { return new LanguageConfig(); }
-
-
效果展示
登录
-
修改index.html中的相应元素,使其能将登录表单提交到相应的位置
-
User实体类
@Data @AllArgsConstructor @NoArgsConstructor @Repository public class User { private int id; private String username; private String password; }
-
mapper接口和xml
@Mapper @Repository public interface UserMapper { User getUser(Map<String, String> map); }
<mapper namespace="com.pbx.mapper.UserMapper"> <select id="getUser" parameterType="map" resultType="com.pbx.pojo.User"> select * from springboot.user where username = #{username} and password = #{password} </select> </mapper>
-
登录服务
@Service public class LoginService { @Autowired private UserMapper mapper; public void setMapper(UserMapper mapper) { this.mapper = mapper; } public boolean login(Map<String, String> map) { return mapper.getUser(map) != null; } }
-
Controller设置
@Autowired private LoginService loginService; @PostMapping("/login") public String login(@RequestParam String username, @RequestParam String password) { Map<String, String> map = new HashMap<>(2); map.put("username", username); map.put("password", password); if (loginService.login(map)) { session.setAttribute("user", username); session.setAttribute("login", true); return "redirect:/dashboard"; } return "index"; }
-
测试
登录拦截器
-
现在我们的主页可以在没有登录的情况下直接访问,那么我们就需要使用拦截器去拦截所有的未登录情况下的所有请求,这也就是在登录的时候给session加了一个状态的原因
-
自定义拦截器
public class LoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { Object login = request.getSession().getAttribute("login"); if (login == null || login == Boolean.FALSE) { request.getRequestDispatcher("/index").forward(request, response); return false; } else { return true; } } }
-
注册拦截器
@Override public void addInterceptors(InterceptorRegistry registry) { String[] exclude = {"/", "/index","/index.html","/login","/jss/**","/css/**","/js/**","/*/index"}; registry.addInterceptor(new LoginInterceptor()).excludePathPatterns(exclude); }
主页
-
抽取公共组件,简化模板文件结构,提高代码复用,同时完成链接跳转功能
<!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"> <a class="navbar-brand col-sm-3 col-md-2 mr-0" style="color:white;" th:text="${session.user}"></a> <ul class="navbar-nav px-3"> <li class="nav-item text-nowrap"> <a class="nav-link" th:href="@{/quit}" th:text="#{main.signout}"></a> </li> </ul> </nav> <nav class="col-md-2 d-none d-md-block bg-light sidebar" th:fragment="sidebar"> <div class="sidebar-sticky"> <ul class="nav flex-column"> <li class="nav-item"> <a th:class="${current=='main' ? 'nav-link active' : 'nav-link'}" th:href="@{/main}" th:text="#{main.main}"> </a> </li> <li class="nav-item"> <a th:class="${current=='employee' ? 'nav-link active' : 'nav-link'}" th:href="@{/employee}" th:text="#{main.employee}"> </a> </li> <li class="nav-item"> <a th:class="${current=='department' ? 'nav-link active' : 'nav-link'}" th:href="@{/department}" th:text="#{main.department}"> </a> </li> </ul> </div> </nav> </html>
-
主页页面
<body> <div th:replace="~{component/part::topbar}"></div> <div class="container-fluid"> <div class="row"> <div th:replace="~{component/part::sidebar}"></div> <main class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4" role="main"> <h1 th:text="'Hello ' + ${session.user}"></h1> </main> </div> </div> </body>
-
主页Controller
@RequestMapping({"/dashboard", "/main"}) public String mainPage(Model model) { model.addAttribute("current", "main"); return "detail/main"; } @RequestMapping("/quit") public String quit(HttpSession session) { session.invalidate(); return "index"; }
-
效果展示
部门信息展示
-
页面
<body> <div th:replace="~{component/part::topbar}"></div> <div class="container-fluid"> <div class="row"> <div th:replace="~{component/part::sidebar}"></div> <main class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4" role="main"> <h1 th:text="#{main.department.title}">Department</h1> <div class="table-responsive"> <table class="table table-striped table-sm"> <thead> <tr> <th th:text="#{main.department.id}"></th> <th th:text="#{main.department.name}"></th> <th th:text="#{main.department.nums}"></th> </tr> </thead> <tbody> <tr th:each="k:${map}"> <td th:text="${k.getKey().getId()}"></td> <td th:text="${k.getKey().getName()}"></td> <td th:text="${map.get(k.getKey())}"></td> </tr> </tbody> </table> </div> </main> </div> </div> </body>
-
mapper
-
接口
@Mapper @Repository public interface DepartmentMapper { List<Department> getDepartmentList(); int countByDepartmentId(@Param("departmentID")int id); }
-
映射文件
<mapper namespace="com.pbx.mapper.DepartmentMapper"> <select id="getDepartmentList" resultType="com.pbx.pojo.Department"> select * from springboot.department </select> <select id="countByDepartmentId" resultType="java.lang.Integer"> SELECT COUNT(id) num FROM springboot.employee WHERE department = #{departmentID} </select> </mapper>
-
-
Service
@Service public class DepartmentService { @Autowired private DepartmentMapper mapper; private List<Department> getDepartment() { return mapper.getDepartmentList(); } public Map<Department, Integer> countDepartment() { Map<Department, Integer> map = new LinkedHashMap<>(); List<Department> departmentList = getDepartment(); for (Department department : departmentList) { map.put(department, mapper.countByDepartmentId(department.getId())); } System.out.println(map); return map; } }
-
Controller
@GetMapping("/department") public String department(Model model) { model.addAttribute("current", "department"); Map<Department, Integer> map = departmentService.countDepartment(); model.addAttribute("map", map); return "detail/department"; }
-
效果
员工信息展示
-
页面
<body> <div th:replace="~{component/part::topbar}"></div> <div class="container-fluid"> <div class="row"> <div th:replace="~{component/part::sidebar}"></div> <main class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4" role="main"> <h2 th:text="#{main.employee.title}"></h2> <div class="table-responsive"> <table class="table table-striped table-sm"> <thead> <tr> <th th:text="#{main.employee.id}"></th> <th th:text="#{main.employee.name}"></th> <th th:text="#{main.employee.email}"></th> <th th:text="#{main.employee.gender}"></th> <th th:text="#{main.employee.department}"></th> <th th:text="#{main.employee.birth}"></th> <th th:text="#{main.employee.action}"></th> </tr> </thead> <tbody> <tr th:each="l:${list}"> <td th:text="${l.getId()}"></td> <td th:text="${l.getName()}"></td> <td th:text="${l.getEmail()}"></td> <td th:text="${l.getGender()==0 ? '女' : '男'}"></td> <td th:text="${l.getDepartment().getName()}"></td> <td th:text="${l.getBirth()}"></td> <td> <button class="btn btn-sm btn-primary" th:text="#{main.employee.edit}"></button> <button class="btn btn-sm btn-danger" th:text="#{main.employee.delete}"></button> </td> </tr> </tbody> </table> </div> </main> </div> </div> </body>
-
mapper
-
接口
@Mapper @Repository public interface EmployeeMapper { List<Employee> getEmployeeList(); Employee getOneById(@Param("employeeID") int id); int addEmployee(Employee employee); int updateEmployee(Map<String, Object> map); int deleteEmployee(int id); }
-
映射文件
<mapper namespace="com.pbx.mapper.EmployeeMapper"> <!--因为实体类的字段和数据库的字段不一致,所以要配置这resultMap和parameterMap--> <resultMap id="resultMap" type="com.pbx.pojo.Employee"> <!--有association之后就要配置所有属性的映射--> <result property="id" column="id"/> <result property="name" column="last_name"/> <result property="email" column="email"/> <result property="gender" column="gender"/> <result property="birth" column="birth"/> <association property="department" javaType="com.pbx.pojo.Department"> <result property="id" column="did"/> <result property="name" column="dname"/> </association> </resultMap> <select id="getEmployeeList" resultMap="resultMap"> select e.id, e.last_name, e.email, e.gender, e.department, e.birth, d.id did, d.name dname from springboot.employee e, springboot.department d where e.department = d.id </select> <select id="getOneById" resultMap="resultMap"> select * from springboot.employee where id = #{employeeID} </select> <insert id="addEmployee" parameterType="com.pbx.pojo.Employee"> insert into springboot.employee(id, last_name, email, gender, department, birth) values (#{id}, #{name}, #{email}, #{gender}, #{department.id}, #{birth}) </insert> <update id="updateEmployee" parameterType="map"> update springboot.employee <set> <if test="name != null"> last_name = #{name} </if> <if test="email != null"> email = #{email} </if> <if test="gender != null"> gender = #{gender} </if> <if test="department != null"> department = #{department} </if> <if test="birth != null"> birth = #{birth} </if> </set> where id = #{id} </update> <delete id="deleteEmployee"> delete from springboot.employee where id = #{id} </delete> </mapper>
-
-
Service
@Service public class EmployeeService { @Autowired private EmployeeMapper mapper; public List<Employee> getEmployList() { return mapper.getEmployeeList(); } }
-
Controller
@GetMapping("/employee") public String employee(Model model) { model.addAttribute("current", "employee"); model.addAttribute("list", employeeService.getEmployList()); return "detail/employee"; }
-
展示
增、删、改员工
增加
-
跳转链接
<a th:href="@{/delete/}+${l.getId()}"><button class="btn btn-sm btn-danger" th:text="#{main.employee.delete}"></button></a>
-
页面
<body> <div th:replace="~{component/part::topbar}"></div> <div class="container-fluid"> <div class="row"> <div th:replace="~{component/part::sidebar}"></div> <main class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4" role="main"> <form action="/add" method="post"> <div class="form-group"> <label for="name">姓名</label> <input type="text" class="form-control" id="name" placeholder="姓名" name="name"> </div> <div class="form-group"> <label for="email">邮箱</label> <input type="email" class="form-control" id="email" placeholder="邮箱" name="email"> </div> <div class="form-group"> <label>性别</label> <div class="form-check"> <input class="form-check-inline" type="radio" name="gender" value="0"> <label class="form-check-label">男</label> </div> <div class="form-check"> <input class="form-check-inline" type="radio" name="gender" value="1"> <label class="form-check-label">女</label> </div> </div> <div class="form-group"> <label for="department">部门</label> <select class="form-control" id="department" name="department.id"> <option th:each="dept:${list}" th:text="${dept.getName()}" th:value="${dept.getId()}"></option> </select> </div> <div class="form-group"> <label for="birth">出生日期</label> <input type="date" class="form-control" id="birth" placeholder="出生日期" name="birth"> </div> <button type="submit" class="btn btn-default">提交</button> </form> </main> </div> </div> </body>
-
Controller
@GetMapping("/add") public String toAdd(Model model) { model.addAttribute("list", departmentService.getDepartment()); return "detail/add"; } @PostMapping("/add") public String add(Employee employee) { System.out.println(employee); employeeService.addEmployee(employee); return "redirect:/employee"; }
-
展示
-
注意点:
-
日期格式的Formatter要记得设置
spring: mvc: format: date: yyyy-mm-dd
-
修改
-
跳转链接
<a th:href="@{/edit/}+${l.getId()}"><button class="btn btn-sm btn-primary" th:text="#{main.employee.edit}"></button></a>
-
页面
<body> <div th:replace="~{component/part::topbar}"></div> <div class="container-fluid"> <div class="row"> <div th:replace="~{component/part::sidebar}"></div> <main class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4" role="main"> <form th:action="@{/edit/}+${employee.getId()}" method="post"> <div class="form-group"> <label for="name">姓名</label> <input type="text" class="form-control" id="name" th:value="${employee.getName()}" th:name="${'name'}"> </div> <div class="form-group"> <label for="email">邮箱</label> <input type="email" class="form-control" id="email" th:value="${employee.getEmail()}" name="email"> </div> <div class="form-group"> <label>性别</label> <div class="form-check"> <input th:checked="${employee.getGender()==0}" class="form-check-inline" type="radio" name="gender" value="0"> <label class="form-check-label">男</label> </div> <div class="form-check"> <input th:checked="${employee.getGender()==1}" class="form-check-inline" type="radio" name="gender" value="1"> <label class="form-check-label">女</label> </div> </div> <div class="form-group"> <label for="department">部门</label> <select class="form-control" id="department" name="department.id"> <option th:selected="${dept.getId()==employee.getDepartment().getId()}" th:each="dept:${list}" th:text="${dept.getName()}" th:value="${dept.getId()}"></option> </select> </div> <div class="form-group"> <label for="birth">出生日期</label> <input type="date" class="form-control" id="birth" th:value="${#dates.format(employee.getBirth(),'yyyy-mm-dd')}" name="birth"> </div> <button type="submit" class="btn btn-default">提交</button> </form> </main> </div> </div> </body>
-
Controller
@GetMapping("/edit/{id}") public String toUpdate(@PathVariable int id, Model model) { Employee employee = employeeService.getOneByID(id); System.out.println(employee); model.addAttribute("employee", employee); model.addAttribute("list", departmentService.getDepartment()); return "detail/edit"; } @PostMapping("/edit/{id}") public String udate(@PathVariable int id, Employee employee) { System.out.println(id); System.out.println(employee); employeeService.updateEmployee(employee); return "redirect:/employee"; }
-
展示
删除
-
跳转链接
<a th:href="@{/delete/}+${l.getId()}"><button class="btn btn-sm btn-danger" th:text="#{main.employee.delete}"></button></a>
-
Controller
@GetMapping("/delete/{id}") public String delete(@PathVariable int id) { employeeService.deleteEmployee(id); return "redirect:/employee"; }
-
演示
![image-20201224220948227](https://gitee.com/primabrucexu/image/raw/main/image/20201224220948.png)
![image-20201224220954612](https://gitee.com/primabrucexu/image/raw/main/image/20201224220954.png)