08_SpringBoot_整合PageHelper(掌握)
PageHelper插件
我们在正常的查询业务之中,只需要加上一行代码就可以实现分页的数据的封装处理
实现原理
PageHelper方法使用了静态的ThreadLocal参数,分页参数和线程是绑定的。内部流程是ThreadLocal中设置了分页参数(pageIndex,pageSize),之后在查询执行的时候,获取当线程中的分页参数,执行查询的时候通过拦截器在sql语句中添加分页参数,之后实现分页查询,查询结束后在 finally 语句中清除ThreadLocal中的查询参数
使用方法
1.调用PageHelper方法:PageHelper.startPage(pageNum, pageSize)
2. MyBatis 查询方法
注意:只要你可以保证在PageHelper方法调用后紧跟 MyBatis 查询方法,这就是安全的。因为PageHelper在finally代码段中自动清除了ThreadLocal存储的对象。
MyBatis整合PageHelper插件,自行阅读即可
mybatis中pageHelper的配置使用_铛铛响的博客-CSDN博客
添加PageHelper启动器依赖
1. <dependency>
2. <groupId>com.github.pagehelper</groupId>
3. <artifactId>pagehelper-spring-boot-starter</artifactId>
4. <version>1.2.12</version>
5. </dependency>
EmpController
1. package com.msb.controller;
2.
3. import com.msb.pojo.Emp;
4. import com.msb.service.EmpService;
5. import org.springframework.beans.factory.annotation.Autowired;
6. import org.springframework.stereotype.Controller;
7. import org.springframework.web.bind.annotation.PathVariable;
8. import org.springframework.web.bind.annotation.RequestMapping;
9. import org.springframework.web.bind.annotation.ResponseBody;
10.
11. import java.util.List;
12.
13. /**
14. * @Author: Ma HaiYang
15. * @Description: MircoMessage:Mark_7001
16. */
17. @Controller
18. @RequestMapping("/emp")
19. public class EmpController {
20.
21. @Autowired
22. private EmpService empService;
23.
24. @RequestMapping("/findByPage/{pageNum}/{pageSize}")
25. @ResponseBody
26. public List<Emp> findByPage(@PathVariable("pageNum") Integer pageNum,@PathVariable("pageSize") Integer pageSize){
27. return empService.findByPage(pageNum,pageSize);
28. }
29. }
30.
Service层代码编写
1. package com.msb.service.impl;
2.
3. import com.github.pagehelper.Page;
4. import com.github.pagehelper.PageHelper;
5. import com.github.pagehelper.PageInfo;
6. import com.msb.mapper.EmpMapper;
7. import com.msb.pojo.Emp;
8. import com.msb.service.EmpService;
9. import org.springframework.beans.factory.annotation.Autowired;
10. import org.springframework.stereotype.Service;
11.
12. import java.util.List;
13.
14. /**
15. * @Author: Ma HaiYang
16. * @Description: MircoMessage:Mark_7001
17. */
18. @Service
19. public class EmpServiceImpl implements EmpService {
20. @Autowired
21. private EmpMapper empMapper;
22. @Override
23. public List<Emp> findByPage(Integer pageNum, Integer pageSize) {
24. Page<Emp> page = PageHelper.startPage(pageNum, pageSize);
25. List<Emp> list =empMapper.findAll();
26.
27. // 方式1
28. System.out.println("当前页:"+page.getPageNum());
29. System.out.println("总页数"+page.getPages());
30. System.out.println("页大小:"+page.getPageSize());
31. System.out.println("总记录数:"+page.getTotal());
32. System.out.println("当前页数据"+page.getResult());
33.
34. // 方式2
35. PageInfo<Emp> pi =new PageInfo<>(list);
36. System.out.println("当前页"+pi.getPageNum());
37. System.out.println("总页数"+pi.getPages());
38. System.out.println("页大小"+pi.getSize());
39. System.out.println("总记录数"+pi.getTotal());
40. System.out.println("当前页数据"+pi.getList());
41.
42. return list;
43. }
44. }
PageInfo对象和Page对象的区别
Page和PageInfo_程序员^晓洋的博客-CSDN博客_page和pageinfo
?
?
09_SpringBoot_整合Druid((掌握)
Druid是由阿里巴巴推出的数据库连接池。它结合了C3P0、DBCP、PROXOOL等数据库连接池的优点。之所以从众多数据库连接池中脱颖而出,还有一个重要的原因就是它包含控制台,很方便的帮助我们实现对于sql执行的监控。
添加依赖
<dependency>
2. <groupId>com.alibaba</groupId>
3. <artifactId>druid-spring-boot-starter</artifactId>
4. <version>1.1.10</version>
5. </dependency>
修改配置文件application.yml
1. spring:
2. datasource:
3. # 使用阿里的Druid连接池
4. type: com.alibaba.druid.pool.DruidDataSource
5. driver-class-name: com.mysql.cj.jdbc.Driver
6. # 填写你数据库的url、登录名、密码和数据库名
7. url: jdbc:mysql://127.0.0.1:3306/mydb?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
8. username: root
9. password: root
10. druid:
11. # 连接池的配置信息
12. # 初始化大小,最小,最大
13. initial-size: 5
14. min-idle: 5
15. maxActive: 20
16. # 配置获取连接等待超时的时间
17. maxWait: 60000
18. # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
19. timeBetweenEvictionRunsMillis: 60000
20. # 配置一个连接在池中最小生存的时间,单位是毫秒
21. minEvictableIdleTimeMillis: 300000
22. validationQuery: SELECT 1
23. testWhileIdle: true
24. testOnBorrow: false
25. testOnReturn: false
26. # 打开PSCache,并且指定每个连接上PSCache的大小
27. poolPreparedStatements: true
28. maxPoolPreparedStatementPerConnectionSize: 20
29. # 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
30. filters: stat,wall,slf4j
31. # 通过connectProperties属性来打开mergeSql功能;慢SQL记录
32. connectionProperties: druid.stat.mergeSql\=true;druid.stat.slowSqlMillis\=5000
33. # 配置DruidStatFilter
34. web-stat-filter:
35. enabled: true
36. url-pattern: "/*"
37. exclusions: "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*"
38. # 配置DruidStatViewServlet
39. stat-view-servlet:
40. url-pattern: "/druid/*"
41. # IP白名单(没有配置或者为空,则允许所有访问)
42. allow: 127.0.0.1,192.168.8.109
43. # IP黑名单 (存在共同时,deny优先于allow)
44. deny: 192.168.1.188
45. # 禁用HTML页面上的“Reset All”功能
46. reset-enable: false
47. # 登录名
48. login-username: admin
49. # 登录密码
50. login-password: 123456
代码测试
?
?访问监控页面
?
10_SpringBoot_整合JSP(了解)
添加依赖
<!--JSP依赖-->
2. <dependency>
3. <groupId>org.apache.tomcat.embed</groupId>
4. <artifactId>tomcat-embed-jasper</artifactId>
5. <scope>provided</scope>
6. </dependency>
添加webapps目录并设置目录
?
??
设置工作目录,如果在IDEA中项目结构为聚合工程。那么在运行jsp是需要指定路径。如果项目结构为独立项目则不需要。 ?
?
?在 yml配置文件中配置视图解析器参数
?
?在控制类中声明单元方法请求转发jsp资源
1. package com.msb.controller;
2.
3. import org.springframework.stereotype.Controller;
4. import org.springframework.web.bind.annotation.PathVariable;
5. import org.springframework.web.bind.annotation.RequestMapping;
6.
7. /**
8. * @Author: Ma HaiYang
9. * @Description: MircoMessage:Mark_7001
10. */
11. @Controller
12. public class PageController {
13. @RequestMapping("/{uri}")
14. public String getPage(@PathVariable("uri") String uri){
15. return uri;
16. }
17. }
11_SpringBoot_整合FreeMarker(熟悉)
1FreeMarker的简介
? ? FreeMarker是一款模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML网页、电子邮件、配置文件、源代码等)的通用工具。 它不是面向最终用户的,而是一个Java类库,是一款程序员可以嵌入他们所开发产品的组件。
? ? FreeMarker是免费的,基于Apache许可证2.0版本发布。其模板编写为FreeMarker Template Language(FTL),属于简单、专用的语言。需要准备数据在真实编程语言中来显示,比如数据库查询和业务运算, 之后模板显示已经准备好的数据。在模板中,主要用于如何展现数据, 而在模板之外注意于要展示什么数据。
常用的java模板引擎还有哪些?
Jsp、Freemarker、Thymeleaf 、Velocity 等。
模板+数据模型=输出
freemarker并不关心数据的来源,只是根据模板的内容,将数据模型在模板中显示并输出文件(通常为html,也可以生成其它格式的文本文件)
freemarker作为springmvc一种视图格式,默认情况下SpringMVC支持freemarker视图格式。 需要创建Spring Boot+Freemarker工程用于测试模板。
2FreeMarker初次使用
导入依赖
<!--freeMaker依赖-->
2. <dependency>
3. <groupId>org.springframework.boot</groupId>
4. <artifactId>spring-boot-starter-freemarker</artifactId>
5. </dependency>
创建controller
@RequestMapping("/freemarker")
2. @Controller
3. public class FreemarkerController {
4. @RequestMapping("/show")
5. public String freemarker(Map<String, Object> map){
6. map.put("name","msb");
7. //返回模板文件名称
8. return "show";
9. }
10. }
通过查阅配置信息发现,默认前缀为 '' ,后缀为.ftlh,默认路径为templates
templates目录下创建模板文件
?
1. <!DOCTYPE html>
2. <html lang="en">
3. <head>
4. <meta charset="UTF-8">
5. <title>Title</title>
6. </head>
7. <body>
8. this is showftlh
9. <br/>
10. ${name}
11. <img src="img/a.jpg"></img>
12. </body>
13. </html>
3FreeMarker常用指令
A遍历List集合
1、注释,即<#‐‐和‐‐>,介于其之间的内容会被freemarker忽略
2、插值(Interpolation):即${..}部分,freemarker会用真实的值代替${..}
3、FTL指令:和HTML标记类似,名字前加#予以区分,Freemarker会解析标签中的表达式或逻辑。
4、文本,仅文本信息,这些不是freemarker的注释、插值、FTL指令的内容会被freemarker忽略解析,直接输出内容。
1. @Controller
2. public class FreemarkerController {
3. @Autowired
4. private EmpService empService;
5.
6. @RequestMapping("/showEmp")
7. public ModelAndView testList(){
8. ModelAndView mv =new ModelAndView();
9. List<Emp> list =empService.findAll();
10. mv.addObject("empList", list);
11. mv.setViewName("showEmp");
12. return mv;
13. }
14. }
15.
页面代码
1. <!DOCTYPE html>
2. <html lang="en">
3. <head>
4. <meta charset="UTF-8">
5. <title>Title</title>
6. <style type="text/css">
7. #empTable{
8. width: 80%;
9. border: 1px solid blue;
10. margin: 0px auto;
11. }
12. #empTable th,td{
13. border: 1px solid green;
14. text-align: center;
15. }
16.
17. </style>
18. </head>
19. <body>
20.
21. <table id="empTable" cellpadding="0px" cellspacing="0px">
22. <tr>
23. <th>索引</th>
24. <th>工号</th>
25. <th>姓名</th>
26. <th>岗位</th>
27. <th>薪资</th>
28. <th>部门号</th>
29. </tr>
30. <#list empList as emp>
31. <tr>
32. <td>${emp_index}</td>
33. <td>${emp.empno}</td>
34. <td>${emp.ename}</td>
35. <td>${emp.job}</td>
36. <td>${emp.sal}</td>
37. <td>${emp.deptno}</td>
38. </tr>
39. </#list>
40.
41.
42. </table>
43.
44. </body>
45. </html>
说明: _index:得到循环的下标,使用方法是在stu后边加"_index",它的值是从0开始?
B遍历Map数据
遍历输出指定内容
controller
1. @Controller
2. public class FreemarkerController {
3. @Autowired
4. private EmpService empService;
5.
6. @RequestMapping("/showEmpMap")
7. public ModelAndView testMap(){
8. ModelAndView mv =new ModelAndView();
9. List<Emp> list =empService.findAll();
10. Map<String,Emp> empMap =new HashMap<>();
11. for (Emp emp : list) {
12. empMap.put(emp.getEmpno().toString(), emp);
13. }
14.
15. mv.addObject("empMap", empMap);
16. mv.setViewName("showEmpMap");
17. return mv;
18. }
页面
1. <!DOCTYPE html>
2. <html lang="en">
3. <head>
4. <meta charset="UTF-8">
5. <title>Title</title>
6. <style type="text/css">
7. #empTable{
8. width: 80%;
9. border: 1px solid blue;
10. margin: 0px auto;
11. }
12. #empTable th,td{
13. border: 1px solid green;
14. text-align: center;
15. }
16.
17. </style>
18. </head>
19. <body>
20.
21. 输出7521员工信息:<br/>
22. 工号:${empMap['7521'].empno}<br/>
23. 姓名:${empMap['7521'].ename}<br/>
24. 岗位:${empMap['7521'].job}<br/>
25. 薪资:${empMap['7521'].sal}<br/>
26. 部门号:${empMap['7521'].deptno}<br/>
27. <br/>
28. 遍历EmpMap
29.
30. <table id="empTable" cellpadding="0px" cellspacing="0px">
31. <tr>
32. <th>索引</th>
33. <th>工号</th>
34. <th>姓名</th>
35. <th>岗位</th>
36. <th>薪资</th>
37. <th>部门号</th>
38. </tr>
39. <#list empMap?keys as k>
40. <tr>
41. <td>${k_index}</td>
42. <td>${k}</td>
43. <td>${empMap[k].ename}</td>
44. <td>${empMap[k].job}</td>
45. <td>${empMap[k].sal}</td>
46. <td>${empMap[k].deptno}</td>
47. </tr>
48. </#list>
49.
50.
51. </table>
52.
53. </body>
54. </html>
FreeMarker在遍历map集合是,key必须是String
C ?if指令
if 指令即判断指令,是常用的FTL指令,freemarker在解析时遇到if会进行判断,条件为真则输出if中间的内容,否 则跳过内容不再输出。
if中支持的运算符
? ? a算数运算符 FreeMarker表达式中完全支持算术运算,FreeMarker支持的算术运算符包括:+, - , * , / , %
? ? b逻辑运算符有如下几个: 逻辑与:&& 逻辑或:|| 逻辑非:! 逻辑运算符只能作用于布尔值,否则将产生错误
? ? c比较运算符有如下几个:
? ? ? ? ① =或者==:判断两个值是否相等.
? ? ? ? ② !=:判断两个值是否不等.
? ? ? ? ③ > 或者gt:判断左边值是否大于右边值
? ? ? ? ④ >=或者gte:判断左边值是否大于等于右边值
? ? ? ? ⑤ <或者lt:判断左边值是否小于右边值
? ? ? ? ⑥ <=或者lte:判断左边值是否小于等于右边值
注意:?=和!=可以用于字符串,数值和日期来比较是否相等,但=和!=两边必须是相同类型的值,否则会产生错误,而且FreeMarker是精确比较,"x","x ","X"是不等的.其它的运行符可以作用于数字和日期,但不能作用于字符串,大部分的时候,使用gt等字母运算符代替>会有更好的效果,因为 FreeMarker会把>解释成FTL标签的结束字符,当然,也可以使用括号来避免这种情况,如:<#if (x>y)>
如何判断空值
1、判断某变量是否存在使用 “??” 用法为:variable??,如果该变量存在,返回true,否则返回false 例:为防止stus为空报错可以加上判断如下
2、缺失变量默认值使用 “!” 使用!要以指定一个默认值,当变量为空时显示默认值。例: ${name!''}表示如果name为空显示空字符串。如果是嵌套对象则建议使用()括起来。
<#if empList??>
2. <#list empList as emp>
3. <tr <#if emp_index%2 ==0 > style="background-color: gray" </#if>>
4. <td>${emp_index}</td>
5. <td>${emp.empno}</td>
6. <td <#if emp.ename == 'KING'> style="color: aqua" </#if>>${emp.ename}</td>
7. <td>${emp.job}</td>
8. <td>${emp.mgr!'无'}</td>
9. <td <#if emp.sal gte 2000.0> style="color: red" </#if>>${emp.sal}</td>
10. <td>${emp.comm!'0'}</td>
11. <td>${emp.deptno}</td>
12. </tr>
13. </#list>
14. </#if>
4 内置函数
内建函数语法格式: 变量+?+函数名称
1、内建函数获取某个集合的大小
${集合名?size}
2、内建函数日期格式化
显示年月日: ? ? ? ? ${today?date}
显示时分秒: ? ? ?${today?time}
显示日期+时间:${today?datetime}
自定义格式化: ? ${today?string("yyyy年MM月")}
3、内建函数将json字符串转成对象
1. <#assign text="{'bank':'工商银行','account':'10101920201920212'}" />
2. <#assign data=text?eval />
3. 开户行:${data.bank} 账号:${data.account}
其中用到了 assign标签,assign的作用是定义一个变量。
页面
1. 员工人数:${empList?size}
2. <table id="empTable" cellpadding="0px" cellspacing="0px">
3. <tr>
4. <th>索引</th>
5. <th>工号</th>
6. <th>姓名</th>
7. <th>岗位</th>
8. <th>上级</th>
9. <th>入职日期a</th>
10. <th>入职日期b</th>
11. <th>入职日期c</th>
12. <th>入职日期d</th>
13. <th>薪资</th>
14. <th>补助</th>
15. <th>部门号</th>
16. </tr>
17. <#if empList??>
18. <#list empList as emp>
19. <tr <#if emp_index%2 ==0 > style="background-color: gray" </#if>>
20. <td>${emp_index}</td>
21. <td>${emp.empno}</td>
22. <td <#if emp.ename == 'KING'> style="color: aqua" </#if>>${emp.ename}</td>
23. <td>${emp.job}</td>
24. <td>${emp.mgr!'无'}</td>
25. <td>${emp.hiredate?date}</td>
26. <td>${emp.hiredate?time}</td>
27. <td>${emp.hiredate?datetime}</td>
28. <td>${emp.hiredate?string("yyyy年MM月dd日")}</td>
29. <td <#if emp.sal gte 2000.0> style="color: red" </#if>>${emp.sal}</td>
30. <td>${emp.comm!'0'}</td>
31. <td>${emp.deptno}</td>
32. </tr>
33. </#list>
34. </#if>
35.
36. </table>
更多内置函数FreeMarker内置函数的用法_WO木子的博客-CSDN博客_freemarker lower_case?
12_SpringBoot_整合Thymeleaf(掌握)
Thymeleaf的主要目标是将优雅的自然模板带到开发工作流程中,并将HTML在浏览器中正确显示,并且可以作为静态原型,让开发团队能更容易地协作。Thymeleaf能够处理HTML,XML,JavaScript,CSS甚至纯文本。
? ? 长期以来,jsp在视图领域有非常重要的地位,随着时间的变迁,出现了一位新的挑战者:Thymeleaf,Thymeleaf是原生的,不依赖于标签库.它能够在接受原始HTML的地方进行编辑和渲染.因为它没有与Servelet规范耦合,因此Thymeleaf模板能进入jsp所无法涉足的领域。
? ? Thymeleaf在Spring Boot项目中放入到resources/templates中。这个文件夹中的内容是无法通过浏览器URL直接访问的(和WEB-INF效果一样),所有Thymeleaf页面必须先走控制器。
创建项目,准备配置文件及各层级代码
项目中添加依赖
1. <dependencies>
2. <dependency>
3. <groupId>org.springframework.boot</groupId>
4. <artifactId>spring-boot-starter-web</artifactId>
5. </dependency>
6.
7. <dependency>
8. <groupId>org.springframework.boot</groupId>
9. <artifactId>spring-boot-starter-test</artifactId>
10. <scope>test</scope>
11. </dependency>
12.
13. <dependency>
14. <groupId>org.mybatis.spring.boot</groupId>
15. <artifactId>mybatis-spring-boot-starter</artifactId>
16. <version>2.1.3</version>
17. </dependency>
18. <dependency>
19. <groupId>mysql</groupId>
20. <artifactId>mysql-connector-java</artifactId>
21. <version>8.0.21</version>
22. </dependency>
23.
24. <dependency>
25. <groupId>org.projectlombok</groupId>
26. <artifactId>lombok</artifactId>
27. <version>1.18.12</version>
28. <scope>provided</scope>
29. </dependency>
30.
31.
32. <dependency>
33. <groupId>com.alibaba</groupId>
34. <artifactId>druid-spring-boot-starter</artifactId>
35. <version>1.1.10</version>
36. </dependency>
37.
38.
39. <dependency>
40. <groupId>com.github.pagehelper</groupId>
41. <artifactId>pagehelper-spring-boot-starter</artifactId>
42. <version>1.2.12</version>
43. </dependency>
44.
45. <dependency>
46. <groupId>org.springframework.boot</groupId>
47. <artifactId>spring-boot-starter-thymeleaf</artifactId>
48. <version>2.4.5</version>
49. </dependency>
50.
51. </dependencies>
关于Thymeleaf默认配置
?
?在resources下新建templates文件夹。新建index.html
新建控制器
1. package com.msb.controller;
2.
3. import org.springframework.stereotype.Controller;
4. import org.springframework.web.bind.annotation.RequestMapping;
5.
6. /**
7. * @Author: Ma HaiYang
8. * @Description: MircoMessage:Mark_7001
9. */
10. @Controller
11. public class ThymeleafController {
12. @RequestMapping("showIndex")
13. public String showIndex(){
14. return "index";
15. }
16. }
13_SpringBoot_Thymeleaf基础语法(掌握)
Thymeleaf通过标准变量表达式完成数据的展示和处理
1 标准变量表达式必须依赖标签,不能独立使用
2 标准变量表达式一般在开始标签中,以 th开头
3 语法为: <tag th:***="${key}" ? ></tag>
4 表达式中可以通过${}取出域中的值并放入标签的指定位置
5 ${}在这里不能单独使用,必须在 th:后面的双引号里使用
为了有提示,修改html页面中<html>标签为
1. <html xmlns:th="http://www.thymeleaf.org" >
举例
1. <input th:type="" th:text="${}" th:style="" th:id="" th:class="" ... ... >
th:text属性
向HTML标签内部输出信息。
处理器 Controller
@RequestMapping("showIndex")
2. public String showIndex(Map<String,Object> map){
3. map.put("msg", "testMessage");
4. return "index";
5. }
页面代码
<!--向span双标签内部添加文本-->
2. <span th:text="pageMessage"></span> <br/>
3. <!--从域中根据参数名取出参数值放在双标签中-->
4. <span th:text="${msg}"></span> <br/>
th:value
表单元素,设置HTML标签中表单元素value属性时使用。
<!--向input标签中的value属性赋值-->
2. <input type="text" th:value="pageMessage"/>
3. <!--从域中根据参数名取出参数值 向input标签中的value属性赋值-->
4. <input type="text" th:value="${msg}"/>
th:if
1. <span th:if="${name}!='张三'">会显示</span>
循环遍历.th:each
示例中u为迭代遍历。
th:each="u,i :${list}"?其中i表示迭代状态。
1,index:当前迭代器的索引 从0开始
2,count:当前迭代对象的计数 从1开始
3,size:被迭代对象的长度
4,even/odd:布尔值,当前循环是否是偶数/奇数 从0开始
5,first:布尔值,当前循环的是否是第一条,如果是返回true否则返回false
6,last:布尔值,当前循环的是否是最后一条,如果是则返回true否则返回false
controller代码
1. @Controller
2. public class ThymeleafController {
3.
4. @Autowired
5. private EmpService empService;
6.
7. @RequestMapping("/showEmp")
8. public String showEmp(Map<String, Object> map) {
9. List<Emp> empList = empService.findAll();
10. map.put("empList", empList);
11. map.put("emp", empList.get(0));
12. return "showEmp";
13. }
页面模板代码
1. <!DOCTYPE html>
2. <html lang="en" xmlns:th="http://www.thymeleaf.org">
3. <head>
4. <meta charset="UTF-8">
5. <title>Title</title>
6. <style type="text/css">
7. #empTable{
8. width: 80%;
9. border: 1px solid blue;
10. margin: 0px auto;
11. }
12. #empTable th,td{
13. border: 1px solid green;
14. text-align: center;
15. }
16. </style>
17. </head>
18. <body>
19. 展示单个员工信息:
20. <span th:if="${emp}!=null">
21. 工号:<span th:text="${emp.empno}"></span><br/>
22. 姓名:<span th:text="${emp.ename}"></span><br/>
23. 职务:<span th:text="${emp.job}"></span><br/>
24. 上级:<span th:text="${emp.mgr}"></span><br/>
25. 入职日期:<span th:text="${emp.hiredate}"></span><br/>
26. 工资:<span th:text="${emp.sal}"></span><br/>
27. 补助:<span th:text="${emp.comm}"></span><br/>
28. 部门号:<span th:text="${emp.deptno}"></span><br/>
29. </span>
30. <hr/>
31. <span th:if="${empList}!=null">
32. <span th:if="${empList.size()} ne 0">
33. 工号:<span th:text="${empList[0].empno}"></span><br/>
34. 姓名:<span th:text="${empList[0].ename}"></span><br/>
35. 职务:<span th:text="${empList[0].job}"></span><br/>
36. 上级:<span th:text="${empList[0].mgr}"></span><br/>
37. 入职日期:<span th:text="${empList[0].hiredate}"></span><br/>
38. 工资:<span th:text="${empList[0].sal}"></span><br/>
39. 补助:<span th:text="${empList[0].comm}"></span><br/>
40. 部门号:<span th:text="${empList[0].deptno}"></span><br/>
41. </span>
42. </span>
43. <table id="empTable" cellpadding="0px" cellspacing="0px">
44. <tr>
45. <th>索引</th>
46. <th>序号</th>
47. <th>总人数</th>
48. <th>偶数索引?</th>
49. <th>奇数索引?</th>
50. <th>第一?</th>
51. <th>最后?</th>
52. <th>工号</th>
53. <th>姓名</th>
54. <th>职务</th>
55. <th>上级</th>
56. <th>入职日期</th>
57. <th>工资</th>
58. <th>补助</th>
59. <th>部门号</th>
60. </tr>
61. <tr th:each="emp,i:${empList}">
62. <td th:text="${i.index}"></td>
63. <td th:text="${i.count}"></td>
64. <td th:text="${i.size}"></td>
65. <td th:text="${i.odd}"></td>
66. <td th:text="${i.even}"></td>
67. <td th:text="${i.first}"></td>
68. <td th:text="${i.last}"></td>
69. <td th:text="${emp.empno}"></td>
70. <td th:text="${emp.ename}"></td>
71. <td th:text="${emp.job}"></td>
72. <td th:text="${emp.mgr}"></td>
73. <td th:text="${emp.hiredate}"></td>
74. <td th:text="${emp.sal}"></td>
75. <td th:text="${emp.comm}"></td>
76. <td th:text="${emp.deptno}"></td>
77. </tr>
78.
79. </table>
80.
81. </body>
82. </html>
页面效果
标准变量表达式运算符支持
标准变量表达式支持的运算符
算数运算符
算术运算:+ , - , * , / , %
1. <span th:text="1+1"></span>
2. <span th:text="'1'+1"></span>
3. <span th:text="${emp.empno}+1"></span>
4. <span th:text="${emp.empno+1}"></span>
关系运算符
gt: great than(大于)>
2 ge: great equal(大于等于)>=
3 eq: equal(等于)==
4 lt: less than(小于)<
5 le: less equal(小于等于)<=
6 ne: not equal(不等于)!=
逻辑运算符
&&? 或 and:? ?表示并且
||? 或? or? : 表示或者
1. <div th:text="1>0 and 2<3"></div>
2. <div th:text="1>0 and 2>3"></div>
3. <div th:text="1>0 or 2<3"></div>
4. <div th:text="1>0 or 2>3"></div>
5. <hr/>
6. <div th:text="${emp.sal ge 800}"></div>
7. <div th:text="${emp.sal } ge 800"></div>
8. <div th:text="${emp.sal ge 800} and ${emp.deptno eq 20}"></div>
9. <div th:text="(${emp.sal }ge 800) or (${emp.deptno } ne 20)"></div>
10. <div th:text="${emp.sal ge 800 or emp.deptno ne 20 }"></div>
在早期的thymeleaf模板引擎框架中 逻辑运算符要写在${}的外边,目前我们2.4.5版本中,可以写在${}里面
三目运算符
1. <tr th:each="emp,i:${empList}" th:class="${i.odd}?a:b">
对空值作出处理
<tr th:each="emp,i:${empList}" th:class="${i.odd}?a:b">
2. <td th:text="${i.index}"></td>
3. <td th:text="${i.count}"></td>
4. <td th:text="${i.size}"></td>
5. <td th:text="${i.odd}"></td>
6. <td th:text="${i.even}"></td>
7. <td th:text="${i.first}"></td>
8. <td th:text="${i.last}"></td>
9. <td th:text="${emp.empno}"></td>
10. <td th:text="${emp.ename}"></td>
11. <td th:text="${emp.job}"></td>
12. <td th:text="${emp.mgr} eq null ?老板:${emp.mgr}"></td>
13. <td th:text="${emp.hiredate}"></td>
14. <td th:text="${emp.sal}"></td>
15. <td th:text="${emp.comm} eq null ?0:${emp.comm}"></td>
16. <td th:text="${emp.deptno}"></td>
17. </tr>
th:href
设置href属性的。取值使用@{}取值
1. <a th:href="@{/getParam(id=1,name='msb')}" >跳转</a>
2. <!-- 获取作用域值-->
3. <a th:href="@{/getParam(name=${stu.name},age=${stu.age})}">跳转二</a>
页面代码
<tr th:each="emp,i:${empList}" th:class="${i.odd}?a:b">
2. <td th:text="${i.index}"></td>
3. <td th:text="${i.count}"></td>
4. <td th:text="${i.size}"></td>
5. <td th:text="${i.odd}"></td>
6. <td th:text="${i.even}"></td>
7. <td th:text="${i.first}"></td>
8. <td th:text="${i.last}"></td>
9. <td th:text="${emp.empno}"></td>
10. <td th:text="${emp.ename}"></td>
11. <td th:text="${emp.job}"></td>
12. <td th:text="${emp.mgr} eq null ?老板:${emp.mgr}"></td>
13. <td th:text="${emp.hiredate}"></td>
14. <td th:text="${emp.sal}"></td>
15. <td th:text="${emp.comm} eq null ?0:${emp.comm}"></td>
16. <td th:text="${emp.deptno}"></td>
17. <td>
18. <a th:href="@{/removeEmp(empno=${emp.empno},ename=${emp.ename})}">删除</a>
19. </td>
20. </tr>
后台controller处理器
1. @Controller
2. public class ThymeleafController {
3.
4. @Autowired
5. private EmpService empService;
6.
7. @RequestMapping("/showAllEmp")
8. public String showEmp(Map<String, Object> map) {
9. List<Emp> empList = empService.findAll();
10. map.put("empList", empList);
11. map.put("emp", empList.get(0));
12. return "showEmp";
13. }
14.
15. @RequestMapping("/removeEmp")
16. public String removeEmp(Integer empno,String ename){
17. boolean success =empService.removeEmp(empno,ename);
18. return "redirect:showAllEmp";
19. }
20. }
?service和mapper 略
th:onclick?
给元素绑定事件,单击事件并传递参数
写法1:仅仅支持数字和布尔类型参数的传递,字符串不支
1. <a href="javascript:viod(0)" th:onclick="'del('+${emp.empno}+')'">删除</a>
写法2:支持数字和文本类型的参数传递
1. <a href="javascript:void(0)" th:onclick="delEmp([[${emp.empno}]],[[${emp.ename}]])">删除</a>
前端代码
1. <table id="empTable" cellpadding="0px" cellspacing="0px">
2. <tr>
3. <th>索引</th>
4. <th>序号</th>
5. <th>总人数</th>
6. <th>偶数索引?</th>
7. <th>奇数索引?</th>
8. <th>第一?</th>
9. <th>最后?</th>
10. <th>工号</th>
11. <th>姓名</th>
12. <th>职务</th>
13. <th>上级</th>
14. <th>入职日期</th>
15. <th>工资</th>
16. <th>补助</th>
17. <th>部门号</th>
18. <th>操作</th>
19. </tr>
20. <tr th:each="emp,i:${empList}" th:class="${i.odd}?a:b">
21. <td th:text="${i.index}"></td>
22. <td th:text="${i.count}"></td>
23. <td th:text="${i.size}"></td>
24. <td th:text="${i.odd}"></td>
25. <td th:text="${i.even}"></td>
26. <td th:text="${i.first}"></td>
27. <td th:text="${i.last}"></td>
28. <td th:text="${emp.empno}"></td>
29. <td th:text="${emp.ename}"></td>
30. <td th:text="${emp.job}"></td>
31. <td th:text="${emp.mgr} eq null ?老板:${emp.mgr}"></td>
32. <td th:text="${emp.hiredate}"></td>
33. <td th:text="${emp.sal}"></td>
34. <td th:text="${emp.comm} eq null ?0:${emp.comm}"></td>
35. <td th:text="${emp.deptno}"></td>
36. <td>
37. <a href="javascript:void(0)" th:onclick="removeEmp([[${emp.empno}]],[[${emp.ename}]])">删除</a>
38. </td>
39. </tr>
40.
41. </table>
42. <script>
43. function removeEmp(empno,ename){
44. var resulet =confirm("确定要删除编号为"+empno+"的"+ename);
45. if(resulet){
46. window.location.href="removeEmp?empno="+empno+"&ename="+ename;
47. }
48. }
49.
50. </script>
14_SpringBoot_Thymeleaf内置对象(掌握)
Thymeleaf提供了一些内置对象,内置对象可直接在模板中使用。这些对象是以#引用的。
使用内置对象的语法
1引用内置对象需要使用#
2大部分内置对象的名称都以s结尾。如:strings、numbers、dates 3常见内置对象如下
#arrays:数组操作的工具;
#aggregates:操作数组或集合的工具;
#bools:判断boolean类型的工具;
#calendars:类似于#dates,但是是java.util.Calendar类的方法;
#ctx:上下文对象,可以从中获取所有的thymeleaf内置对象;
#dates:日期格式化内置对象,具体方法可以参照java.util.Date;
#numbers: 数字格式化;#strings:字符串格式化,具体方法可以参照String,如startsWith、contains等;
#objects:参照java.lang.Object;
#lists:列表操作的工具,参照java.util.List;
#sets:Set操作工具,参照java.util.Set;#maps:Map操作工具,参照java.util.Map;
#messages:操作消息的工具。
更多
??
这里我们着重学习 ?strings dates numbers和域对象
strings对象 ?
??
dates对象
??
#numbers
#numbers.formatDecimal(numbwe,整数位,整数位千分位标识符,小数位,小数位表示符)
${#numbers.formatDecimal(num,1,'COMMA',2,'POINT')}
显示:99,999,999.99
1:表示整数位至少一位,不足以0补齐,如:num = 0.00,
${#numbers.formatDecimal(num,0,'COMMA',2,'POINT')}则显示 .00
${#numbers.formatDecimal(num,1,'COMMA',2,'POINT')}则显示 0.00
COMMA:','
POINT:‘.’
域对象
??
更多内置 对象:?Tutorial: Using Thymeleaf
?controller
@RequestMapping("showIndex")
2. public String showIndex(Map<String,Object> map, HttpServletRequest req, HttpSession session){
3. // 向request域放数据
4. req.setAttribute("msg", "requestMessage");
5. // 向session域放数据
6. session.setAttribute("msg", "sessionMessage");
7. // 向application域放数据
8. req.getServletContext().setAttribute("msg", "applicationMessage");
9.
10. // 对象List集合数据
11. List<Emp> empList = empService.findAll();
12. map.put("empList", empList);
13. return "index";
14. }
页面
1. <!DOCTYPE html>
2. <html lang="en" xmlns:th="http://www.thymeleaf.org">
3. <head>
4. <meta charset="UTF-8">
5. <title>Title</title>
6. <style type="text/css">
7. #empTable{
8. width: 80%;
9. border: 1px solid blue;
10. margin: 0px auto;
11. }
12. #empTable th,td{
13. border: 1px solid green;
14. text-align: center;
15. }
16. .a{
17. background-color: antiquewhite;
18. }
19. .b{
20. background-color: gray;
21. }
22. </style>
23. </head>
24. <body>
25. <table id="empTable" cellpadding="0px" cellspacing="0px">
26. <tr>
27. <th>索引</th>
28. <th>序号</th>
29. <th>总人数</th>
30. <th>偶数索引?</th>
31. <th>奇数索引?</th>
32. <th>第一?</th>
33. <th>最后?</th>
34. <th>工号</th>
35. <th>姓名</th>
36. <th>职务</th>
37. <th>上级</th>
38. <th>入职日期</th>
39. <th>入职年</th>
40. <th>入职月</th>
41. <th>入职日</th>
42. <th>工资</th>
43. <th>补助</th>
44. <th>部门号</th>
45. <th>操作</th>
46. </tr>
47. <tr th:each="emp,i:${empList}" th:class="${i.odd}?a:b">
48. <td th:text="${i.index}"></td>
49. <td th:text="${i.count}"></td>
50. <td th:text="${i.size}"></td>
51. <td th:text="${i.odd}"></td>
52. <td th:text="${i.even}"></td>
53. <td th:text="${i.first}"></td>
54. <td th:text="${i.last}"></td>
55. <td th:text="${emp.empno}"></td>
56. <td th:text="${emp.ename}"></td>
57. <td th:text="${emp.job}"></td>
58. <td th:text="${#strings.isEmpty(emp.mgr)}?老板:${emp.mgr}"></td>
59. <td th:text="${#dates.format(emp.hiredate,'yyyy-MM-dd HH:mm:ss')}"></td>
60. <td th:text="${#dates.year(emp.hiredate)}"></td>
61. <td th:text="${#dates.month(emp.hiredate)}"></td>
62. <td th:text="${#dates.day(emp.hiredate)}"></td>
63. <td th:text="${#numbers.formatDecimal(emp.sal,7,'COMMA',2,'POINT')}"></td>
64. <td th:text="${#strings.isEmpty(emp.comm)}?0:${#numbers.formatDecimal(emp.sal,7,'COMMA',2,'POINT')}"></td>
65. <td th:text="${emp.deptno}"></td>
66. <td>
67. <a href="javascript:void(0)" th:onclick="removeEmp([[${emp.empno}]],[[${emp.ename}]])">删除</a>
68. </td>
69. </tr>
70.
71. </table>
72. <script>
73. function removeEmp(empno,ename){
74. var resulet =confirm("确定要删除编号为"+empno+"的"+ename);
75. if(resulet){
76. window.location.href="removeEmp?empno="+empno+"&ename="+ename;
77. }
78. }
79.
80. </script>
81.
82. <hr/>
83. request:<br/>
84. <span th:text="${#httpServletRequest.getAttribute('msg')}"></span><br/>
85. <span th:text="${#request.getAttribute('msg')}"></span><br/>
86. <span th:text="${msg}"></span><br/>
87.
88. session:<br/>
89. <span th:text="${#httpSession.getAttribute('msg')}"></span><br/>
90. <span th:text="${#session.getAttribute('msg')}"></span><br/>
91. <span th:text="${session.msg}"></span><br/>
92.
93. application:<br/>
94. <span th:text="${#servletContext.getAttribute('msg')}"></span><br/>
95. <span th:text="${application.msg}"></span><br/>
96.
97. </body>
98. </html>
15_SpringBoot_模板引擎总结(了解)
jsp
优点:
1、功能强大,可以写java代码
2、支持jsp标签(jsp tag)
3、支持表达式语言(el)
4、官方标准,用户群广,丰富的第三方jsp标签库
缺点:
性能问题。不支持前后端分离
freemarker
FreeMarker是一个用Java语言编写的模板引擎,它基于模板来生成文本输出。FreeMarker与Web容器无关,即在Web运行时,它并不知道Servlet或HTTP。它不仅可以用作表现层的实现技术,而且还可以用于生成XML,JSP或Java 等。
目前企业中:主要用Freemarker做静态页面或是页面展示
优点:
1、不能编写java代码,可以实现严格的mvc分离
2、性能非常不错
3、对jsp标签支持良好
4、内置大量常用功能,使用非常方便
5、宏定义(类似jsp标签)非常方便
6、使用表达式语言
缺点:
1、不是官方标准
2、用户群体和第三方标签库没有jsp多
Thymeleaf
Thymeleaf是个XML/XHTML/HTML5模板引擎,可以用于Web与非Web应用。
Thymeleaf的主要目标在于提供一种可被浏览器正确显示的、格式良好的模板创建方式,因此也可以用作静态建模。你可以使用它创建经过验证的XML与HTML模板。相对于编写逻辑或代码,开发者只需将标签属性添加到模板中即可。接下来,这些标签属性就会在DOM(文档对象模型)上执行预先制定好的逻辑。Thymeleaf的可扩展性也非常棒。你可以使用它定义自己的模板属性集合,这样就可以计算自定义表达式并使用自定义逻辑。这意味着Thymeleaf还可以作为模板引擎框架。
优点:静态html嵌入标签属性,浏览器可以直接打开模板文件,便于前后端联调。springboot官方推荐方案。
缺点:模板必须符合xml规范
VUE: 前后端分离,最多,未来趋势
16_SpringBoot_开发者工具(了解)
使用开发者工具包不需要重启。监听内容改变。
1导入依赖
<dependency>
2. <groupId>org.springframework.boot</groupId>
3. <artifactId>spring-boot-devtools</artifactId>
4. <version>2.4.5</version>
5. <optional>true</optional>
6. </dependency>
1修改idea自动编译
??
2修改Reigstry
Ctrl+Shift+Alt+/ 点击弹出框中Registry...
??
??
17_SpringBoot_项目打包部署(熟练)
SpringBoot项目可以是jar类型的maven项目,也可以是一个war类型的maven项目,取决于我们要不要整合jsp使用。但是不管是哪种项目类型,已经不是我们传统意义上的项目结构了
在本地使用SpringBoot的启动器即可访问我们开发的项目。如果我们将项目功能开发完成后,需要使用SpringBoot的打包功能来将项目进行打包。
SpringBoot项目打包在linux服务器中运行:
? ? ①jar类型项目会打成jar包:
? ? jar类型项目使用SpringBoot打包插件打包时,会在打成的jar中内置一个tomcat的jar。所以我们可以使用jdk直接运行该jar项目可,jar项目中有一个功能,将功能代码放到其内置的tomcat中运行。我们直接使用浏览器访问即可。
? ? ②war类型项目会打成war包:
? ? 在打包时需要将内置的tomcat插件排除,配置servlet的依赖。将war正常的放到tomcat服务器中运行即可。
导入springboot打包插件
1. <build>
2. <plugins>
3. <plugin>
4. <groupId>org.springframework.boot</groupId>
5. <artifactId>spring-boot-maven-plugin</artifactId>
6. <configuration>
7. <fork>true</fork>
8. </configuration>
9. </plugin>
10. </plugins>
11. </build>
将项目导出成jar包并运行
项目类型为jar
??
使用maven ?package指令打包即可
?
打成包后,可以通过dos ?java -jar指令直接启动运行 ??
??
将项目导出war包并运行
项目打包成war之后,要放在一个Tomcat上运行
如果我们当前的maven项目本身就是war类型的项目,直接打包即可,但是如果我们当前的maven项目是jar类型的项目,我们需要将项目修改为war类型,修改项目的pom文件,使用packaging标签设置值为war.并且需要在项目中创建webapp文件夹,并设置为资源文件夹。
??
webapp文件夹可加可不加
??
排除项目中自带的所有的Tomcat插件和jsp servlet 依赖,因为这里要将项目放到一个Tomcat上运行
1. <!--配置SpringBoot的web启动器-->
2. <dependency>
3. <groupId>org.springframework.boot</groupId>
4. <artifactId>spring-boot-starter-web</artifactId>
5. <!--排除web启动中自动依赖的tomcat插件-->
6. <exclusions>
7. <exclusion>
8. <groupId>org.springframework.boot</groupId>
9. <artifactId>spring-boot-starter-tomcat</artifactId>
10. </exclusion>
11. </exclusions>
12. </dependency>
13. <!--
14. 手动依赖tomcat插件,但是表明项目打包时该依赖不会被打进去,目的主要是保证开发阶段本地SpringBoot
15. 项目可以正常运行
16. -->
17. <dependency>
18. <groupId>org.springframework.boot</groupId>
19. <artifactId>spring-boot-starter-tomcat</artifactId>
20. <!--打包的时候可以不用包进去,别的设施会提供。事实上该依赖理论上可以参与编译,测试,运行等周期。
21. 相当于compile,但是打包阶段做了exclude操作-->
22. <scope>provided</scope>
23. </dependency>
24.
SpringBoot的启动类继承SpringBootServletInitializer,并重写configure
1. @SpringBootApplication
2. public class MyApplication extends SpringBootServletInitializer {
3. //重写配置方法
4. @Override
5. protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
6. return application.sources(MyApplication.class);
7. }
8. public static void main(String[] args) {
9. //启动SpringBoot
10. SpringApplication.run(MyApplication.class,args);
11. }
12. }
13.
使用install命令打包项目,并将war包放到tomcat下的webapps下,启动tomcat即可。
??
??
如果我们使用的是tomcat7则需要将javax.el-api-3.0.0.jar包放到tomcat下? ? ? ? 的lib目录中。
18_SpringBoot_异常处理(掌握)
??
默认情况,Spring Boot项目错误页面如下。当项目实际上线,如果给用户显示这个页面就不是很友好。当系统出现异常时应该给用户显示更加友好的错误页面。
1设置具体的状态码页面
在templates/下新建error文件夹,在error中新建:状态码.html的页面。例如当出现500时显示的页面为500.html
2使用x进行模糊匹配
当出现5开头状态码的错误时,显示页面可以命名为5xx.html
当出现50开头状态码的错误时,显示页面可以命名为50x.html
3统一错误显示页面
在templates下新建error.html。如果项目中不存在具体状态码的页面或没有使用x成功匹配的页面时,显示error.html作为错误显示页面。
SpringMVC异常简介
系统中异常包括两类:预期异常(检查型异常)和运行时异常 RuntimeException,前者通过捕获异常从而获取异常信息, 后者主要通过规范代码开发、测试通过手段减少运行时异常的发生。
系统的 dao、service、controller 出现都通过 throws Exception 向上抛出,最后由 springmvc 前端控制器交由异常处理器进行异常处理,如下图
??
异常处理具体实现
1使用@ExceptionHandler注解处理异常 缺点:只能处理当前Controller中的异常。
1. @Controller
2. public class ControllerDemo1 {
3. @RequestMapping("test1.action")
4. public String test1(){
5. int i = 1/0;
6. return "success";
7. }
8. @RequestMapping("test2.action")
9. public String test2(){
10. String s =null;
11. System.out.println(s.length());
12. return "success";
13. }
14. @ExceptionHandler(value ={ArithmeticException.class,NullPointerException.class} )
15. public ModelAndView handelException(){
16. ModelAndView mv =new ModelAndView();
17. mv.setViewName("error1");
18. return mv;
19. }
20. }
2使用:@ControllerAdvice+@ExceptionHandler
此处优先级低于局部异常处理器
1. package com.msb.exceptionhandler;
2.
3. import org.springframework.web.bind.annotation.ControllerAdvice;
4. import org.springframework.web.bind.annotation.ExceptionHandler;
5. import org.springframework.web.servlet.ModelAndView;
6.
7. /**
8. * @Author: Ma HaiYang
9. * @Description: MircoMessage:Mark_7001
10. */
11. @ControllerAdvice
12. public class GloableExceptionHandler1 {
13. @ExceptionHandler(value ={ArithmeticException.class,NullPointerException.class} )
14. public ModelAndView handelException(){
15. ModelAndView mv =new ModelAndView();
16. mv.setViewName("error1");
17. return mv;
18. }
19. }
20.
3使用:SimpleMappingExceptionResolver
xml配置
配置类配置
1. /**
2.
3. * 全局异常
4.
5. */
6.
7. @Configuration
8.
9. public class GloableException2 {
10.
11. @Bean
12.
13. public SimpleMappingExceptionResolver getSimpleMappingExceptionResolver(){
14.
15. SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();
16.
17. Properties prop = new Properties();
18.
19. prop.put("java.lang.NullPointerException","error1");
20.
21. prop.put("java.lang.ArithmeticException","error2");
22.
23. resolver.setExceptionMappings(prop);
24.
25. return resolver;
26.
27. }
28.
29. }
4自定义的HandlerExceptionResolver
1. /**
2.
3. * 全局异常
4.
5. * HandlerExceptionResolve
6.
7. */
8.
9. @Configuration
10.
11. public class GloableException3 implements HandlerExceptionResolver {
12.
13. @Override
14.
15. public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
16.
17. ModelAndView mv = new ModelAndView();
18.
19. if(e instanceof NullPointerException){
20.
21. mv.setViewName("error1");
22.
23. }
24.
25. if(e instanceof ArithmeticException){
26.
27. mv.setViewName("error2");
28.
29. }
30.
31. mv.addObject("msg",e);
32.
33. return mv;
34.
35. }}
19_SpringBoot_单元测试支持(了解)
在src/main/test里面新建com.msb.项目上下文
注意:
1. 测试类不能叫做Test,会和注解同名
2. 测试方法必须是public
3. 测试方法返回值必须是void
4. 测试方法必须没有参数
1. package com.msb;
2.
3. import com.msb.pojo.Emp;
4. import com.msb.service.EmpService;
5. import org.junit.jupiter.api.Test;
6. import org.springframework.beans.factory.annotation.Autowired;
7. import org.springframework.boot.test.context.SpringBootTest;
8.
9. import java.util.List;
10.
11. @SpringBootTest(classes = Springboot03Application.class)
12. class Springboot03AppliactionTests {
13. @Autowired
14. private EmpService empService;
15. @Test
16. public void testFindAll() {
17. List<Emp> list = empService.findAll();
18. list.forEach(System.out::println);
19. }
20.
21. }
22.
20_SpringBoot_bean管理(了解)
Spring Boot中Bean管理
Spring Boot 由于没有XML文件,所以所有的Bean管理都放入在一个配置类中实现。
配置类就是类上具有@Configuration的类。这个类就相当于之前的applicationContext.xml
1 新建配置类
com.msb.config.MyConfig , 规范都是放入到config文件夹中。
注意:配置类要有@Configuration,方法要有@Bean
1. @Configuration
2. public class MyConfig {
3. //访问权限修饰符没有强制要求,一般是protected
4. //返回值就是注入到Spring容器中实例类型。
5. // 方法名没有强制要求,相当于<bean >中id属性。
6. @Bean
7. protected User getUser(){
8. User user = new User();
9. user.setId(1L);
10. user.setName("张三");
11. return user;
12. }
13. //自定义bean名称
14. @Bean("user2")
15. protected User getUser2(){
16. User user = new User();
17. user.setId(2L);
18. user.setName("李四");
19. return user;
20. }
21. }
如果Spring容器中存在同类型的Bean通过Bean的名称获取到Bean对象。或结合@Qualifier使用
1. @SpringBootTest
2. public class TestGetBean {
3. @Autowired
4. @Qualifier("user2")
5. private User user;
6. @Test
7. public void testGetUser(){
8. System.out.println(user);
9. }
10. }
11.
在配置类的方法中通过方法参数让Spring容器把对象注入。
1. //自定义bean名称
2. @Bean("user1")
3. public User getUser(){
4. User user = new User();
5. user.setId(2L);
6. user.setName("李四");
7. return user;
8. }
9.
10. @Bean
11. //可以直接从方法参数中取到。
12. public People getPeople(User user1){
13. People p = new People();
14. p.setUser(user1);
15. return p;
16. }
17.
18.
22_SpringBoot其他拓展
01_SpringBoot_注解拓展
springboot默认已经帮助我们整合好了SpringMVC,同时也给我们默认配置了DispathcerServlet 和编码过滤器,同时也给我们配置好了WEB项目开发的常见组件
查看容器中的所有组件
@SpringBootApplication
1. /*
2. * 默认扫描启动类所在包下的所有层级的子包
3. * 可以通过scanBasePackages属性指定扫描路径
4. * SpringBootApplication是一个合成注解,可以拆分为以下三个注解
5. * @SpringBootConfiguration
6. * @EnableAutoConfiguration
7. * @ComponentScan(basePackages = "com.msb")
8. *
9. *
10. * */
11. @SpringBootApplication
12. public class Springboot04Application {
13. public static void main(String[] args) {
14. //返回一个spring容器
15. ConfigurableApplicationContext context = SpringApplication.run(Springboot04Application.class, args);
16. // 查看所有组件的名
17. String[] names = context.getBeanDefinitionNames();
18. for (String name : names) {
19. System.out.println(name);
20. }
21. }
22. }
@Configuration?
1. package com.msb.config;
2.
3. import com.msb.pojo.User;
4. import org.springframework.context.annotation.Bean;
5. import org.springframework.context.annotation.Configuration;
6.
7. /**
8. * @Author: Ma HaiYang
9. * @Description: MircoMessage:Mark_7001
10. * MyConfig配置类本身也是一个spring容器中的bean
11. * proxyBeanMethods=true 属性,给MyConfig对象产生一个代理对象
12. * 通过代理对象控制反复调用MyConfig里面的方法返回的是容器中的一个单实例
13. * 如果proxyBeanMethods=false 那么我们拿到的MyConfig对象就不是一个代理对象
14. * 那么这个时候反复调用MyConfig中的方法返回的就是多实例
15. *
16. * proxyBeanMethods=false 称之为Lite模式 特点启动快
17. * proxyBeanMethods=true 称之为Full模式 特点依赖spring容器控制bean单例
18. *
19. */
20. @Configuration(proxyBeanMethods = true)
21. public class MyConfig {
22.
23. /*<bean id = "user1" class ="com.msb.pojo.User">... ...</bean>*/
24. @Bean // 向容器中添加一个Bean,以方法名作为Bean的id,返回值类型作为组件的类型
25. public User user1(){
26. return new User("zhangsan", 10);
27. }
28.
29. /*<bean id = "user2" class ="com.msb.pojo.User">... ...</bean>*/
30. @Bean("user2") // 向容器中添加一个Bean,手动指定Bean的name属性,返回值类型作为组件的类型
31. public User getUser(){
32. return new User("lisi", 11);
33. }
34. }
测试代码
1. package com.msb;
2.
3. import com.msb.config.MyConfig;
4. import com.msb.pojo.User;
5. import org.springframework.boot.SpringApplication;
6. import org.springframework.boot.SpringBootConfiguration;
7. import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
8. import org.springframework.boot.autoconfigure.SpringBootApplication;
9. import org.springframework.context.ConfigurableApplicationContext;
10. import org.springframework.context.annotation.ComponentScan;
11.
12.
13. @SpringBootApplication(scanBasePackages = "com.msb")
14. public class Springboot04Application {
15. public static void main(String[] args) {
16. //返回一个spring容器
17. ConfigurableApplicationContext context = SpringApplication.run(Springboot04Application.class, args);
18.
19.
20. System.out.println(context.getBean("user1"));
21. System.out.println(context.getBean("user2"));
22. User usera = context.getBean(MyConfig.class).getUser();
23. User userb = context.getBean(MyConfig.class).getUser();
24. System.out.println(usera==userb);
25. }
26. }
@Import
1. package com.msb.config;
2.
3. import com.msb.pojo.User;
4. import org.springframework.context.annotation.Bean;
5. import org.springframework.context.annotation.Configuration;
6. import org.springframework.context.annotation.Import;
7.
8.
9. /*
10. * @Import({User.class}) 在容器中自动创建Bean的注解
11. * 通过传入字节码,默认调用bean的无参构造器,向容器中存放一个Bean
12. * 默认组件的名字就是类的全路径名
13. * @Import只要放到可以被扫描到的类之上就可以,不必非得是配置类或者Controller
14. * */
15. @Import({User.class})
16. @Configuration(proxyBeanMethods = true)
17. public class MyConfig {
18.
19. }
1. @SpringBootApplication(scanBasePackages = "com.msb")
2. public class Springboot04Application {
3. public static void main(String[] args) {
4. //启动SpringBoot, 返回一个spring容器
5. ConfigurableApplicationContext context = SpringApplication.run(Springboot04Application.class, args);
6. // 根据类型获取Bean
7. User bean = context.getBean(User.class);
8. System.out.println(bean);
9. // 获取属性User类的所有bean的name
10. String[] beanNamesForType = context.getBeanNamesForType(User.class);
11. for (String s : beanNamesForType) {
12. System.out.println(s);
13. }
14. }
15. }
@Conditional 条件装配
满足Conditional指定的条件,则进行组件注入
@Conditional下还有很多子注解
??
1. package com.msb.config;
2.
3. import com.msb.pojo.Emp;
4. import com.msb.pojo.User;
5. import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
6. import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
7. import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
8. import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
9. import org.springframework.context.annotation.Bean;
10. import org.springframework.context.annotation.Conditional;
11. import org.springframework.context.annotation.Configuration;
12. import org.springframework.context.annotation.Import;
13.
14.
15. @Configuration
16. /*
17. * 当配置中存在一个aaa.b的配置并且值为x的时候,当前配置中所有的配置才会生效
18. * */
19. //@ConditionalOnProperty( name = "aaa.b",havingValue = "x")
20. public class MyConfig {
21. /*
22. * 当配置中存在一个aaa.b的配置并且值为x的时候,容器才会初始化user1
23. * */
24. @ConditionalOnProperty( name = "aaa.b",havingValue = "x")
25. @Bean
26. public User user1(){
27. return new User("zhangsan", 10);
28. }
29. }
??
@ImportResource
原生配置文件引入,允许我们自己定义xml配置文件,在文件中配置bean
resources目录下准备一个xml配置文件
???
配置类中加载该配置文件
1. package com.msb.config;
2.
3. import org.springframework.context.annotation.*;
4.
5. @Configuration
6. @ImportResource("classpath:beans.xml")
7. public class MyConfig {
8. }
9.
从容器中获取beans.xml中配置的bean
1. @SpringBootApplication
2. public class Springboot04Application {
3. public static void main(String[] args) {
4. //启动SpringBoot, 返回一个spring容器
5. ConfigurableApplicationContext context = SpringApplication.run(Springboot04Application.class, args);
6. System.out.println(context.getBean("userx"));
7.
8. }
9. }
@ConfigurationProperties
读取application.properties配置文件中的内容,读取进入bean
1. /*prefix前缀,为配置文件中对应的前缀
2. * 通过前缀找到对应的配置信息后,在根据属性名去注入匹配的数据*/
3. @ConfigurationProperties( prefix = "user")
4. @Component
5. public class User {
6. private String uname;
7. private int age;
8. }
?配置类代码
1. package com.msb.config;
2.
3. import com.msb.pojo.User;
4. import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
5. import org.springframework.boot.context.properties.EnableConfigurationProperties;
6. import org.springframework.context.annotation.Configuration;
7.
8. /**
9. * @Author: Ma HaiYang
10. * @Description: MircoMessage:Mark_7001
11. */
12. @Configuration
13. /*开启了User的属性自动配置功能并把User自动注册到容器中
14. * 这个时候,我们的User上就不用加@Component注解了
15. * 适用于Bean来自于第三方JAR场景
16. * */
17. @EnableConfigurationProperties(User.class)
18. public class MyConfig {
19. }
测试代码
1. package com.msb;
2.
3. import com.msb.pojo.User;
4. import org.springframework.boot.SpringApplication;
5. import org.springframework.boot.autoconfigure.SpringBootApplication;
6. import org.springframework.context.ConfigurableApplicationContext;
7.
8. @SpringBootApplication
9. public class Springboot04Application {
10. public static void main(String[] args) {
11. //启动SpringBoot, 返回一个spring容器
12. ConfigurableApplicationContext context = SpringApplication.run(Springboot04Application.class, args);
13. System.out.println(context.getBean(User.class));
14.
15. }
16. }
02_SpringBoot_静态资源
静态资源默认存放位置
resources 目录下,static/public目录是我们的静态资源目录,直接访问该目录下的资源的映射路径不需要携带/public或者/static,直接访问即可
?
如果controller的映射路径和静态资源路径冲突,会发生什么事情呢?
?
1. package com.msb.controller;
2.
3. import org.springframework.stereotype.Controller;
4. import org.springframework.web.bind.annotation.RequestMapping;
5. import org.springframework.web.bind.annotation.ResponseBody;
6.
7. /**
8. * @Author: Ma HaiYang
9. * @Description: MircoMessage:Mark_7001
10. */
11. @Controller
12. public class MyController {
13. @RequestMapping("/logo.png")
14. @ResponseBody
15. public String logo(){
16. return "controller logo";
17. }
18. }
19.
请求进来,先去看Controller中有没有对应的资源,如果有则,执行controller资源,如果没有,就交给静态资源处理器,静态资源处理器也没有找到,则返回404
静态资源访问前缀
默认无前缀,如果想指定静态资源前缀,可以 通过spring.mvc.static-path-pattern配置
yml配置如下
?
?请求路径上通过 项目上下文路径+静态资源前缀+静态资源名的方式访问
?
指定静态资源位置
静态资源默认存放的路径为static content from a directory called /static (or /public or /resources or /META-INF/resources)
可以通过
?
static-locations 指定专门的静态资源路径
?
springboot还支持静态资源webjars 的处理方式,就是将静态资源打成jar导入
WebJars - Web Libraries in Jars? ??
?
项目中导入jQuery依赖
?
1. <dependency>
2. <groupId>org.webjars</groupId>
3. <artifactId>jquery</artifactId>
4. <version>3.6.0</version>
5. </dependency>
导入后,自动映射
http://localhost:8080/springboot-static-content/res/webjars/jquery/3.6.0/jquery.js
或者
http://localhost:8080/springboot-static-content/webjars/jquery/3.6.0/jquery.js
?
欢迎页功能 ?
方式1 支持静态资源欢迎页, index.html ?注意此时不能配置静态资源前缀,否则不生效
静态资源位置
?
方式2 通过controller ,定义 / 和/index映射 路径 ?
@RequestMapping(path={"/","/index"})
2. public String welcome(){
3. return "welcome";
4. }
导入thymeleaf
<dependency>
2. <groupId>org.springframework.boot</groupId>
3. <artifactId>spring-boot-starter-thymeleaf</artifactId>
4. <version>2.4.5</version>
5. </dependency>
定义Favicon
static目录下准备一个favicon.ico的一个图片即可
浏览器默认访问favicon.ico的路径为 ?协议://ip:端口号/favicon.ico,所以这里不要设置项目的上下文路径
拦截器静态资源放行
定义一个登陆页面
?
1. <!DOCTYPE html>
2. <html lang="en">
3. <head>
4. <meta charset="UTF-8">
5. <title>Title</title>
6. <link type="text/css" href="css/mycss.css">
7. <script src="js/myjs.js"></script>
8. </head>
9. <body>
10. <img src="img/logo.png">
11. <form action="login">
12. <input type="text" name="username" >
13. <input type="submit">
14. </form>
15.
16. </body>
17. </html>
?定义一个登陆controller
?
1. package com.msb.controller;
2.
3. import org.springframework.stereotype.Controller;
4. import org.springframework.web.bind.annotation.RequestMapping;
5.
6. import javax.servlet.http.HttpServletRequest;
7.
8. /**
9. * @Author: Ma HaiYang
10. * @Description: MircoMessage:Mark_7001
11. */
12. @Controller
13. public class LoginController {
14.
15. @RequestMapping("/login")
16. public String login(String username, HttpServletRequest request){
17. if(null != username&&!"".equals(username)){
18. request.getSession().setAttribute("username", username);
19. return "main";
20. }
21. return "redirect:/login.html";
22. }
23. }
定义一个登陆拦截器
1. package com.msb.interceptor;
2.
3. import org.springframework.stereotype.Component;
4. import org.springframework.web.servlet.HandlerInterceptor;
5.
6. import javax.servlet.http.HttpServletRequest;
7. import javax.servlet.http.HttpServletResponse;
8.
9. /**
10. * @Author: Ma HaiYang
11. * @Description: MircoMessage:Mark_7001
12. */
13. @Component
14. public class LoginInterceptor implements HandlerInterceptor {
15. @Override
16. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
17. Object username = request.getSession().getAttribute("username");
18. // 如果登录过,那么就放行
19. if(null != username){
20. return true;
21. }
22. // 如果没登陆过,那么就回到登录页,重定向
23. response.sendRedirect("login.html");
24. return false;
25. }
26. }
27.
配置拦截器
1. package com.msb.config;
2.
3. import com.msb.interceptor.LoginInterceptor;
4. import org.springframework.beans.factory.annotation.Autowired;
5. import org.springframework.context.annotation.Configuration;
6. import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
7. import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
8.
9. /**
10. * @Author: Ma HaiYang
11. * @Description: MircoMessage:Mark_7001
12. */
13. @Configuration
14. public class MyInterceptorRegist implements WebMvcConfigurer {
15. @Autowired
16. private LoginInterceptor loginInterceptor;
17. //配置拦截器的映射
18. @Override
19. public void addInterceptors(InterceptorRegistry registry) {
20. registry.addInterceptor(loginInterceptor).addPathPatterns("/**").excludePathPatterns("/login","/login.html","/css/**","/js/**","/img/**","/font/**");
21. }
22. }
template下的main.html
1. <!DOCTYPE html>
2. <html lang="en">
3. <head>
4. <meta charset="UTF-8">
5. <title>Title</title>
6. </head>
7. <body>
8.
9. this is main... ...
10.
11.
12. </body>
13. </html>
03_SpringBoot_文件上传
创建项目:略
启动文件上传服务器:略
导入依赖
1. <dependency>
2. <groupId>com.sun.jersey</groupId>
3. <artifactId>jersey-client</artifactId>
4. <version>1.19</version>
5. </dependency>
页面代码
1. <html>
2. <head>
3. <meta charset="UTF-8">
4. <title>Title</title>
5. <style>
6. .progress {
7. width: 200px;
8. height: 10px;
9. border: 1px solid #ccc;
10. border-radius: 10px;
11. margin: 10px 0px;
12. overflow: hidden;
13. }
14. /* 初始状态设置进度条宽度为0px */
15. .progress > div {
16. width: 0px;
17. height: 100%;
18. background-color: yellowgreen;
19. transition: all .3s ease;
20. }
21. </style>
22. <script type="text/javascript" src="js/jquery.min.js"></script>
23. <script type="text/javascript">
24. $(function(){
25. $("#uploadFile").click(function(){
26. // 获取要上传的文件
27. var photoFile =$("#photo")[0].files[0]
28. if(photoFile==undefined){
29. alert("您还未选中文件")
30. return;
31. }
32. // 将文件装入FormData对象
33. var formData =new FormData();
34. formData.append("headPhoto",photoFile)
35. // ajax向后台发送文件
36. $.ajax({
37. type:"post",
38. data:formData,
39. url:"file/upload",
40. processData:false,
41. contentType:false,
42. success:function(result){
43. // 接收后台响应的信息
44. alert(result.message)
45. // 图片回显
46. $("#headImg").attr("src",result.newFileName);
47. },
48. xhr: function() {
49. var xhr = new XMLHttpRequest();
50. //使用XMLHttpRequest.upload监听上传过程,注册progress事件,打印回调函数中的event事件
51. xhr.upload.addEventListener('progress', function (e) {
52. //loaded代表上传了多少
53. //total代表总数为多少
54. var progressRate = (e.loaded / e.total) * 100 + '%';
55. //通过设置进度条的宽度达到效果
56. $('.progress > div').css('width', progressRate);
57. })
58. return xhr;
59. }
60. })
61. })
62. })
63. </script>
64. </head>
65. <body>
66. <form action="addPlayer" method="get">
67. <p>账号<input type="text" name="name"></p>
68. <p>密码<input type="text" name="password"></p>
69. <p>昵称<input type="text" name="nickname"></p>
70. <p>头像:
71. <br/>
72. <input id="photo" type="file">
73. <br/>
74. <img id="headImg" style="width: 200px;height: 200px" alt="你还未上传图片">
75. <br/>
76. <div class="progress">
77. <div></div>
78. </div>
79. <a id="uploadFile" href="javascript:void(0)">立即上传</a>
80. </p>
81. <p><input type="submit" value="注册"></p>
82. </form>
83. </body>
84. </html>
Controller代码
1. package com.msb.controller;
2.
3. import com.sun.jersey.api.client.Client;
4. import com.sun.jersey.api.client.WebResource;
5. import org.springframework.stereotype.Controller;
6. import org.springframework.web.bind.annotation.RequestMapping;
7. import org.springframework.web.bind.annotation.ResponseBody;
8. import org.springframework.web.multipart.MultipartFile;
9.
10. import javax.servlet.http.HttpServletRequest;
11. import java.io.File;
12. import java.io.IOException;
13. import java.util.HashMap;
14. import java.util.Map;
15. import java.util.UUID;
16.
17. /**
18. * @Author: Ma HaiYang
19. * @Description: MircoMessage:Mark_7001
20. */
21. @Controller
22. @RequestMapping("/file")
23. public class FileController {
24.
25. // 文件存储位置
26. private final static String FILESERVER="http://127.0.0.1:8090/upload/";
27.
28. @RequestMapping("/upload")
29. @ResponseBody
30. public Map<String,String> upload(MultipartFile headPhoto, HttpServletRequest req) throws IOException {
31. Map<String,String> map=new HashMap<>();
32.
33. // 指定文件存储目录为我们项目部署环境下的upload目录
34. String realPath = req.getServletContext().getRealPath("/upload");
35. File dir = new File(realPath);
36. // 如果不存在则创建目录
37. if(!dir.exists()){
38. dir.mkdirs();
39. }
40. // 获取文件名
41. String originalFilename = headPhoto.getOriginalFilename();
42. // 避免文件名冲突,使用UUID替换文件名
43. String uuid = UUID.randomUUID().toString();
44. // 获取拓展名
45. String extendsName = originalFilename.substring(originalFilename.lastIndexOf("."));
46. // 新的文件名
47. String newFileName=uuid.concat(extendsName);
48. // 创建 sun公司提供的jersey包中的client对象
49. Client client=Client.create();
50. WebResource resource = client.resource(FILESERVER + newFileName);
51. // 文件保存到另一个服务器上去了
52. resource.put(String.class, headPhoto.getBytes());
53. // 上传成功之后,把文件的名字和文件的类型返回给浏览器
54. map.put("message", "上传成功");
55. map.put("newFileName", FILESERVER+newFileName);
56. map.put("filetype", headPhoto.getContentType());
57. return map;
58. }
59. }
yml中配置文件大小限制
1. spring:
2. servlet:
3. multipart:
4. max-file-size: 10MB
5. max-request-size: 100MB
多文件同步上传处理方式
页面代码
1. <form action="file/upload" method="post" enctype="multipart/form-data">
2. <p>账号<input type="text" name="name"></p>
3. <p>密码<input type="text" name="password"></p>
4. <p>昵称<input type="text" name="nickname"></p>
5. <p>头像:
6. <br/>
7. <input id="photo" name="photo" type="file">
8. <input id="photos" name="photos" type="file" multiple>
9. <br/>
10. <img id="headImg" style="width: 200px;height: 200px" alt="你还未上传图片">
11. <br/>
12. <div class="progress">
13. <div></div>
14. </div>
15. <a id="uploadFile" href="javascript:void(0)">立即上传</a>
16. </p>
17. <p><input type="submit" value="注册"></p>
18. </form>
后台接收的处理单元参数处理
public Map<String,String> upload(String name,
2. String password,
3. String nickname,
4. @RequestPart("photo") MultipartFile photo,
5. @RequestPart("photos") MultipartFile[] photos, HttpServletRequest req)
04_SpringBoot_MyBatis-Plus
Redirect?
MyBatis-plus是mybatis的增强工具,在MyBatis 上只做增强,不做改变,为简化开发,提高效率而生
?
MyBatis-plus和mybatis就像是魂斗罗中的两个兄弟 ?
安装MyBatisX插件
创建项目
略
导入依赖
?
1. <dependency>
2. <groupId>org.springframework.boot</groupId>
3. <artifactId>spring-boot-starter-web</artifactId>
4. </dependency>
5.
6. <dependency>
7. <groupId>org.projectlombok</groupId>
8. <artifactId>lombok</artifactId>
9. <optional>true</optional>
10. </dependency>
11. <dependency>
12. <groupId>org.springframework.boot</groupId>
13. <artifactId>spring-boot-starter-test</artifactId>
14. <scope>test</scope>
15. </dependency>
16.
17.
18. <dependency>
19. <groupId>mysql</groupId>
20. <artifactId>mysql-connector-java</artifactId>
21. <version>8.0.21</version>
22. </dependency>
23.
24. <dependency>
25. <groupId>com.alibaba</groupId>
26. <artifactId>druid-spring-boot-starter</artifactId>
27. <version>1.1.10</version>
28. </dependency>
29.
30. <dependency>
31. <groupId>com.baomidou</groupId>
32. <artifactId>mybatis-plus-boot-starter</artifactId>
33. <version>3.4.2</version>
34. </dependency>
35.
自动配置的内容
MyBatis PlusAutoConfiguration配置类,MyBatisPlusProperties配置项前缀 mybatis-plus: ***就是对mybatis-plus的参数的设置
SQLSessionFactory已经配置好
mapperlocations 自动配置好的,默认值是classpath*:/mapper/**/*.xml ?意为任意包路径下所有的mapper包下的xml文件
@Mapper建议替换成MapperScan
配置mybatisplus
1.
2. spring:
3. datasource:
4. type: com.alibaba.druid.pool.DruidDataSource
5. driver-class-name: com.mysql.cj.jdbc.Driver
6. url: jdbc:mysql://127.0.0.1:3306/mydb?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
7. username: root
8. password: root
9. druid:
10. initial-size: 5
11. min-idle: 5
12. maxActive: 20
13. maxWait: 60000
14. timeBetweenEvictionRunsMillis: 60000
15. minEvictableIdleTimeMillis: 300000
16. validationQuery: SELECT 1
17. testWhileIdle: true
18. testOnBorrow: false
19. testOnReturn: false
20. poolPreparedStatements: true
21. maxPoolPreparedStatementPerConnectionSize: 20
22. filters: stat,wall,slf4j
23. connectionProperties: druid.stat.mergeSql\=true;druid.stat.slowSqlMillis\=5000
24. web-stat-filter:
25. enabled: true
26. url-pattern: "/*"
27. exclusions: "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*"
28. stat-view-servlet:
29. url-pattern: "/druid/*"
30. allow: 127.0.0.1,192.168.8.109
31. deny: 192.168.1.188
32. reset-enable: false
33. login-username: admin
34. login-password: 123456
35.
36. mybatis-plus:
37. type-aliases-package: com.msb.pojo
实体类
1. @AllArgsConstructor
2. @NoArgsConstructor
3. @Data
4. @TableName("dept")
5. public class Dept implements Serializable {
6. /*@TableField(exist = false)
7. private String aaa;*/
8. @TableField("deptno")
9. private Integer deptno;
10. private String dname;
11. private String loc;
12. }
mapper
1. public interface DeptMapper extends BaseMapper<Dept> {
2.
3. }
service
接口
1. public interface DeptService extends IService<Dept> {
2. }
实现类
1. @Service
2. public class DeptServiceImpl extends ServiceImpl<DeptMapper, Dept> implements DeptService {
3. }
测试代码CURD
1. package com.msb;
2.
3. import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
4. import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
5. import com.msb.mapper.DeptMapper;
6. import com.msb.pojo.Dept;
7. import com.msb.service.DeptService;
8. import lombok.AllArgsConstructor;
9. import org.junit.jupiter.api.Test;
10. import org.springframework.beans.factory.annotation.Autowired;
11. import org.springframework.boot.test.context.SpringBootTest;
12.
13. import java.util.List;
14.
15. @SpringBootTest
16. class SpringbootMybatisplusApplicationTests {
17.
18.
19. @Autowired
20. DeptService deptService;
21.
22.
23. @Test
24. public void testFindAll(){
25. List<Dept> list = deptService.list();
26. for (Dept dept : list) {
27. System.out.println(dept);
28. }
29. }
30. // 查询集合
31. @Test
32. public void testQueryWrapper(){
33. // 部门号》=20
34. // QueryWrapper 作用就是在原本的SQL语句后面拼接where条件
35. // selec * from where delete from dept where update dept set ... where ....
36. QueryWrapper<Dept> queryWrapper=new QueryWrapper<>();
37. //queryWrapper.ge("deptno", 20).eq("dname", "ACCOUNTING").likeRight("dname", "A");
38. //queryWrapper.likeRight("dname", "A");
39. List<Dept> list = deptService.list(queryWrapper);
40. for (Dept dept : list) {
41. System.out.println(dept);
42. }
43.
44.
45. }
46. // 查询单个
47. @Test
48. public void testQueryWrapper2(){
49. QueryWrapper<Dept> queryWrapper=new QueryWrapper<>();
50. queryWrapper.eq("deptno", 20);
51. Dept dept = deptService.getOne(queryWrapper);
52. System.out.println(dept);
53.
54. }
55.
56. // 增加
57. @Test
58. public void testAdd(){
59. boolean save = deptService.save(new Dept(null, "aaa", "bbb"));
60. System.out.println(save);
61. }
62.
63. // 修改
64. @Test
65. public void testUpdate(){
66. // 要更新的数据
67. Dept dept =new Dept();
68. dept.setDname("xxx");
69. dept.setLoc("yyy");
70. // 更新的条件
71. QueryWrapper<Dept> queryWrapper=new QueryWrapper<>();
72. queryWrapper.eq("deptno", 41);
73. boolean update = deptService.update(dept, queryWrapper);
74. System.out.println(update);
75. }
76. // 删除
77. @Test
78. public void testRemove(){
79. QueryWrapper<Dept> queryWrapper=new QueryWrapper<>();
80. queryWrapper.eq("deptno", 41);
81. boolean remove = deptService.remove(queryWrapper);
82. System.out.println(remove);
83. }
84.
85.
86.
87. }
分页插件的使用
配置分页插件
1. package com.msb.config;
2.
3. import com.baomidou.mybatisplus.annotation.DbType;
4. import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
5. import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
6. import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
7. import com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize;
8. import org.springframework.context.annotation.Bean;
9. import org.springframework.context.annotation.Configuration;
10.
11. /**
12. * @Author: Ma HaiYang
13. * @Description: MircoMessage:Mark_7001
14. */
15. @Configuration
16. public class MyBatisPlusConfig {
17. @Bean
18. public MybatisPlusInterceptor mybatisPlusInterceptor() {
19. MybatisPlusInterceptor mybatisPlusInterceptor =new MybatisPlusInterceptor();
20. PaginationInnerInterceptor paginationInnerInterceptor =new PaginationInnerInterceptor();
21. // 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求 默认false
22. //paginationInnerInterceptor.setOverflow(false);
23. // 设置最大单页限制数量,默认 500 条,-1 不受限制
24. //paginationInnerInterceptor.setMaxLimit(500L);
25. // 设置数据库类型
26. paginationInnerInterceptor.setDbType(DbType.MYSQL);
27. mybatisPlusInterceptor.addInnerInterceptor(paginationInnerInterceptor);
28. return mybatisPlusInterceptor;
29. }
30. }
测试分页插件
@Test
2. public void testPage(){
3. // 当前页 页大小
4. QueryWrapper<Dept> queryWrapper=new QueryWrapper<>();
5. //queryWrapper.likeRight("dname", "A");
6. Page<Dept> page = deptService.page(new Page<>(1, 2), queryWrapper);
7. // 当前页数据 总页数 总记录数 当前页 页大小 ... ..
8. List<Dept> list = page.getRecords();
9. list.forEach(System.out::println);
10. System.out.println("总页数:"+page.getPages());
11. System.out.println("总记录数:"+page.getTotal());
12. System.out.println("当前页:"+page.getCurrent());
13. System.out.println("页大小:"+page.getSize());
14. }
05_SpringBoot_Junit5
springboot 2.2.0开始引入Junit5作为单元测试的默认库
JUnit5和之前的版本有很大的不同,由单个子项目的几个不同模块组成
JUnit Platform ,是在JVM上启动测试框架的技术,不仅支持Junit自己的测试引擎,其他的测试引擎也可以
JUnit Jupiter,提供了Junit5的最新的编程模型,是Junit5 的核心,内部包含了一个测试引擎,用于在Junit Platform上运行
JUnit Vintager: 提供了兼容Junit4/3 的测试引擎
Junit5 =?JUnit Platform+?JUnit Jupiter+JUnit Vintager
?
Junit支持Spring中的注解,测试起来比较方便, @Autowired @Transactional 等
1. package com.msb;
2.
3. import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
4. import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
5. import com.msb.mapper.DeptMapper;
6. import com.msb.pojo.Dept;
7. import com.msb.service.DeptService;
8. import org.junit.jupiter.api.*;
9. import org.junit.jupiter.api.extension.ExtendWith;
10. import org.junit.platform.commons.annotation.Testable;
11. import org.springframework.beans.factory.annotation.Autowired;
12. import org.springframework.boot.test.context.SpringBootTest;
13. import org.springframework.boot.test.context.SpringBootTestContextBootstrapper;
14. import org.springframework.test.context.BootstrapWith;
15. import org.springframework.test.context.junit.jupiter.SpringExtension;
16.
17. import java.util.List;
18. import java.util.concurrent.TimeUnit;
19.
20. @SpringBootTest // 使用springboot的容器功能
21. /*@BootstrapWith(SpringBootTestContextBootstrapper.class)
22. @ExtendWith({SpringExtension.class})*/
23. @DisplayName("Junit5测试类")// 测试类描述
24. class SpringbootMybatisplusApplicationTests2 {
25.
26. @Autowired
27. private DeptMapper deptMapper;
28.
29.
30. @BeforeEach
31. public void testForeach(){
32. System.out.println("beforeach");
33. }
34.
35. @AfterEach
36. public void testAftereach(){
37. System.out.println("aferEach");
38. }
39.
40. @BeforeAll
41. public static void beforeAll(){
42. System.out.println("beforall");
43. }
44.
45. @AfterAll
46. public static void aferAll(){
47. System.out.println("afterAll");
48. }
49. @RepeatedTest(3)// 重复测试3次
50. @Timeout(value = 10000,unit = TimeUnit.MILLISECONDS)// 超时时间设置
51. @DisplayName("Junit测试方法1")
52. @Test
53. public void test1(){
54. System.out.println("a");
55. System.out.println(deptMapper);
56. }
57.
58.
59. @Disabled// 设置不可用
60. @DisplayName("Junit测试方法2") // 方法描述
61. @Test
62. public void test2(){
63. System.out.println("b");
64. }
65.
66.
67.
68. }
?
断言机制
断定某件事情,一定会发生,如果没有发生,那就是出现了问题,所欲的测试运行结束后,会有一个详细的断言报告
用来对测试需要满足的条件进行验证,这些断言方法都是org.junit.jupiter.api.Assertions中的静态方法,
简单断言
?
1. package com.msb;
2.
3.
4. import org.junit.jupiter.api.Assertions;
5. import org.junit.jupiter.api.DisplayName;
6. import org.junit.jupiter.api.Test;
7. import org.springframework.boot.test.context.SpringBootTest;
8.
9. import java.time.Duration;
10. import java.util.concurrent.TimeUnit;
11.
12. @SpringBootTest
13. @DisplayName("Junit5断言测试类")
14. class SpringbootMybatisplusApplicationTests3 {
15.
16. @DisplayName("简单断言1")
17. @Test
18. public void testAssertions1(){
19. int add = add(1, 2);
20. Assertions.assertEquals(6,add,"add结果计算错误");
21. }
22. public int add(int a,int b){
23. return a+b;
24. }
25.
26. @DisplayName("简单断言2")
27. @Test
28. public void testAssertions2(){
29. String s =new String("xxx");
30. String s2=new String("abc");
31. Assertions.assertEquals(s,s2,"String对象不一样");
32. }
33.
34. // 组合断言
35. @DisplayName("组合断言")
36. @Test
37. public void testAssertAll(){
38. Assertions.assertAll("AssertAll",
39. ()-> Assertions.assertTrue(true&& false),
40. ()-> Assertions.assertEquals(1,2));
41. }
42.
43. // 异常断言 认为应该会出现异常
44. @DisplayName("异常断言")
45. @Test
46. public void testAssertException(){
47. Assertions.assertThrows(ArithmeticException.class, ()->{ int i=1/0;}, "没有抛出异常");
48. }
49.
50.
51.
52. // 超时断言 判断有没有超时
53. @DisplayName("超时断言")
54. @Test
55. public void testAssertTimeOut(){
56. Assertions.assertTimeout(Duration.ofMillis(1000),()-> Thread.sleep(5000));
57. }
58.
59. // 快速失败
60. @DisplayName("快速失败")
61. @Test
62. public void testFail(){
63. if(true){
64. Assertions.fail("测试 失败");
65. }
66. }
67. }
前置条件(assumptions假设)
类似于断言,不同在于,不满足断言回事方法测试失败,而不满足的前置条件会使得的是方法的执行中止,前置条件可以看成是测试方法执行的前提,当条件不满足时,就没有继续执行的必要
1. package com.msb;
2.
3.
4. import org.junit.jupiter.api.Assertions;
5. import org.junit.jupiter.api.Assumptions;
6. import org.junit.jupiter.api.DisplayName;
7. import org.junit.jupiter.api.Test;
8. import org.springframework.boot.test.context.SpringBootTest;
9.
10. import java.time.Duration;
11.
12. @SpringBootTest
13. @DisplayName("Junit5测试前置条件")
14. class SpringbootMybatisplusApplicationTests4 {
15.
16. @DisplayName("测试前提条件")
17. @Test
18. public void testAssumptions(){
19. // 假设为true,才会执行
20. Assumptions.assumeTrue(false,"结果不是true");
21. System.out.println("后面的测试代码前提条件");
22. }
23.
24. @DisplayName("简单断言1")
25. @Test
26. public void testAssertions1(){
27. int add =10;
28. Assertions.assertEquals(6,add,"add结果计算错误");
29. System.out.println("后面的测试代码简单断言");
30. }
31.
32.
33. }
34.
嵌套测试
1. package com.msb;
2.
3.
4. import org.junit.jupiter.api.*;
5. import static org.junit.jupiter.api.Assertions.*;
6.
7. import java.util.EmptyStackException;
8. import java.util.Stack;
9.
10.
11.
12. @DisplayName("嵌套测试")
13. class SpringbootMybatisplusApplicationTests5 {
14.
15. Stack<Object> stack;
16.
17. @Test
18. @DisplayName("is instantiated with new Stack()")
19. void isInstantiatedWithNew() {
20. new Stack<>();
21. // 外层的测试不能驱动内层的测试方法
22. assertNull(stack);
23. }
24.
25. @Nested
26. @DisplayName("when new")
27. class WhenNew {
28.
29. @BeforeEach
30. void createNewStack() {
31. stack = new Stack<>();
32. }
33.
34. @Test
35. @DisplayName("is empty")
36. void isEmpty() {
37. assertTrue(stack.isEmpty());
38. }
39.
40. @Test
41. @DisplayName("throws EmptyStackException when popped")
42. void throwsExceptionWhenPopped() {
43. assertThrows(EmptyStackException.class, stack::pop);
44. }
45.
46. @Test
47. @DisplayName("throws EmptyStackException when peeked")
48. void throwsExceptionWhenPeeked() {
49. assertThrows(EmptyStackException.class, stack::peek);
50. }
51.
52. @Nested
53. @DisplayName("after pushing an element")
54. class AfterPushing {
55.
56. String anElement = "an element";
57.
58. @BeforeEach // 内层Test可以驱动外层的BeforeEach
59. void pushAnElement() {
60. stack.push(anElement);
61. }
62.
63. @Test
64. @DisplayName("it is no longer empty")
65. void isNotEmpty() {
66.
67. assertFalse(stack.isEmpty());
68. }
69.
70. @Test
71. @DisplayName("returns the element when popped and is empty")
72. void returnElementWhenPopped() {
73. assertEquals(anElement, stack.pop());
74. assertTrue(stack.isEmpty());
75. }
76.
77. @Test
78. @DisplayName("returns the element when peeked but remains not empty")
79. void returnElementWhenPeeked() {
80. assertEquals(anElement, stack.peek());
81. assertFalse(stack.isEmpty());
82. }
83. }
84. }
85. }
参数化测试
1. package com.msb;
2.
3.
4. import org.junit.jupiter.api.BeforeEach;
5. import org.junit.jupiter.api.DisplayName;
6. import org.junit.jupiter.api.Nested;
7. import org.junit.jupiter.api.Test;
8. import org.junit.jupiter.params.ParameterizedTest;
9. import org.junit.jupiter.params.provider.MethodSource;
10. import org.junit.jupiter.params.provider.ValueSource;
11.
12. import java.util.EmptyStackException;
13. import java.util.Stack;
14. import java.util.stream.Stream;
15.
16. import static org.junit.jupiter.api.Assertions.*;
17.
18.
19. @DisplayName("参数化测试")
20. class SpringbootMybatisplusApplicationTests6 {
21.
22.
23. @ParameterizedTest
24. @ValueSource(ints = { 1, 2, 3 })
25. void testWithValueSource(int argument) {
26. System.out.println(argument);
27. assertTrue(argument > 0 && argument < 4);
28. }
29.
30.
31.
32. @ParameterizedTest
33. @MethodSource("stringProvider")
34. void testWithExplicitLocalMethodSource(String argument) {
35. assertNotNull(argument);
36. }
37.
38. static Stream<String> stringProvider() {
39. return Stream.of("apple", "banana");
40. }
41.
42.
43.
44.
45. }
?
|