├── README.md ├── springboot-base-config ├── README.md ├── pom.xml └── src │ ├── main │ ├── .DS_Store │ ├── java │ │ └── com │ │ │ └── love │ │ │ └── example │ │ │ ├── Controller │ │ │ └── Hello.java │ │ │ └── ExampleApplication.java │ └── resources │ │ ├── .DS_Store │ │ ├── application-dev.properties │ │ ├── application-prod.properties │ │ ├── application-test.properties │ │ ├── application.properties │ │ ├── rebel.xml │ │ └── static │ │ ├── .DS_Store │ │ └── images │ │ ├── 1.png │ │ ├── 2.png │ │ ├── 3.png │ │ ├── 4.png │ │ ├── 5.png │ │ ├── 6.png │ │ └── 7.png │ └── test │ └── java │ └── com │ └── love │ └── example │ └── ExampleApplicationTests.java ├── springboot-exception ├── README.md ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── love │ │ │ └── example │ │ │ ├── Config │ │ │ └── WebExceptionHandler.java │ │ │ ├── Controller │ │ │ └── HelloController.java │ │ │ ├── ExampleApplication.java │ │ │ └── Exception │ │ │ ├── HttpResponse.java │ │ │ ├── HttpStatusTypeEnum.java │ │ │ └── ResponseException.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── love │ └── example │ └── ExampleApplicationTests.java ├── springboot-hello-world ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── love │ │ │ └── example │ │ │ ├── Controller │ │ │ └── Hello.java │ │ │ └── ExampleApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── love │ └── example │ └── ExampleApplicationTests.java ├── springboot-jpa ├── README.md ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── love │ │ │ └── example │ │ │ ├── Controller │ │ │ └── UserController.java │ │ │ ├── ExampleApplication.java │ │ │ ├── Model │ │ │ └── User.java │ │ │ ├── Repository │ │ │ └── UserRepository.java │ │ │ └── Service │ │ │ ├── ServiceTemplate │ │ │ └── UserServiceTemplate.java │ │ │ └── UserService.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── love │ └── example │ └── ExampleApplicationTests.java ├── springboot-listener-filter-interceptor ├── README.md ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── love │ │ │ └── example │ │ │ ├── Config │ │ │ ├── CustomListener.java │ │ │ ├── FilterConfig.java │ │ │ ├── InterceptorConfig.java │ │ │ └── ListenerConfig.java │ │ │ ├── Controller │ │ │ └── HelloController.java │ │ │ ├── ExampleApplication.java │ │ │ └── Monitor │ │ │ ├── CustomEvent.java │ │ │ ├── MyFilter1.java │ │ │ ├── MyFilter2.java │ │ │ ├── MyInterceptor.java │ │ │ └── MyListener.java │ └── resources │ │ ├── application.properties │ │ └── rebel.xml │ └── test │ └── java │ └── com │ └── love │ └── example │ └── ExampleApplicationTests.java ├── springboot-mybatis-druid-jta ├── README.md ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── love │ │ │ └── example │ │ │ ├── Config │ │ │ ├── FirstDataSourceConfig.java │ │ │ ├── SecondDataSourceConfig.java │ │ │ └── TransactionManagerConfig.java │ │ │ ├── Controller │ │ │ └── UserController.java │ │ │ ├── ExampleApplication.java │ │ │ ├── Service │ │ │ ├── UserService.java │ │ │ └── template │ │ │ │ └── UserServiceTemplate.java │ │ │ ├── mapper │ │ │ ├── first │ │ │ │ └── FirstMapper.java │ │ │ └── second │ │ │ │ └── SecondMapper.java │ │ │ └── model │ │ │ └── User.java │ └── resources │ │ ├── application.yml │ │ └── mybatis │ │ └── mapper │ │ ├── first │ │ └── FirstMapper.xml │ │ └── second │ │ └── SecondMapper.xml │ └── test │ └── java │ └── com │ └── love │ └── example │ └── ExampleApplicationTests.java ├── springboot-mybatis ├── README.md ├── springboot-mybatis-annotation │ ├── README.md │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── .DS_Store │ │ ├── java │ │ │ ├── .DS_Store │ │ │ └── com │ │ │ │ ├── .DS_Store │ │ │ │ └── love │ │ │ │ ├── .DS_Store │ │ │ │ └── example │ │ │ │ ├── Controller │ │ │ │ └── UserController.java │ │ │ │ ├── ExampleApplication.java │ │ │ │ ├── Service │ │ │ │ ├── UserService.java │ │ │ │ └── UserServiceTemplate.java │ │ │ │ ├── mapper │ │ │ │ └── MyMapper.java │ │ │ │ └── model │ │ │ │ └── User.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── love │ │ └── example │ │ └── ExampleApplicationTests.java └── springboot-mybatis-xml │ ├── pom.xml │ └── src │ ├── main │ ├── .DS_Store │ ├── java │ │ ├── .DS_Store │ │ └── com │ │ │ ├── .DS_Store │ │ │ └── love │ │ │ ├── .DS_Store │ │ │ └── example │ │ │ ├── Controller │ │ │ └── UserController.java │ │ │ ├── ExampleApplication.java │ │ │ ├── Service │ │ │ ├── UserService.java │ │ │ └── UserServiceTemplate.java │ │ │ ├── mapper │ │ │ └── MyMapper.java │ │ │ └── model │ │ │ └── User.java │ └── resources │ │ ├── application.properties │ │ ├── mybatis │ │ ├── mapper │ │ │ └── MyMapper.xml │ │ └── mybatis-config.xml │ │ └── static │ │ └── images │ │ └── 1.png │ └── test │ └── java │ └── com │ └── love │ └── example │ └── ExampleApplicationTests.java └── springboot-swagger ├── README.md ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── love │ │ └── example │ │ ├── Config │ │ └── SwaggerConfig.java │ │ ├── ExampleApplication.java │ │ ├── Model │ │ └── User.java │ │ ├── TestController │ │ └── TestController.java │ │ └── UserController │ │ └── UserController.java └── resources │ ├── application-dev.properties │ ├── application-prod.properties │ ├── application-test.properties │ └── application.properties └── test └── java └── com └── love └── example └── ExampleApplicationTests.java /README.md: -------------------------------------------------------------------------------- 1 | # Spring Boot学习资料 2 | **** 3 | 面包是需要的,牛奶是需要的,Java也是需要的。贫富乃人生常事,进步是致富之本。下面是笔者学习SpringBoot以来总结的经验,分享出来希望对大家有所帮助。笔者是前端出身,最开始对面对Java我是拒绝的,......真香! 4 | 5 | 同时笔者也在同步更新一篇[React Native](https://github.com/zhuqitao/react-native-example)的知识分享,从企业开发的角度分析各种业务场景的实现方案(项目的发布部署与热更新、微信分享/登录/支付实现、如何唤醒APP Store或Android应用商城、IOS和Android的兼容问题...) 6 | 7 | ### Spring Boot 案例 8 | [SpringBoot hello world](https://github.com/zhuqitao/spring-boot-examples/tree/master/springboot-hello-world) 9 | 10 | [SpringBoot 基础配置](https://github.com/zhuqitao/spring-boot-examples/tree/master/springboot-base-config) 11 | 12 | [SpringBoot 整合Swagger2](https://github.com/zhuqitao/spring-boot-examples/tree/master/springboot-swagger) 13 | 14 | [SpringBoot 集成Mybatis](https://github.com/zhuqitao/spring-boot-examples/tree/master/springboot-mybatis) 15 | 16 | [SoringBoot、Mybatis、Druid多数据源JTA分布式事务实现](https://github.com/zhuqitao/spring-boot-examples/tree/master/springboot-mybatis-druid-jta) 17 | 18 | [SpringBoot 监听器、过滤器、拦截器以及自定义事件配置](https://github.com/zhuqitao/spring-boot-examples/tree/master/springboot-listener-filter-interceptor) 19 | 20 | [Spring Boot整合JPA](https://github.com/zhuqitao/spring-boot-examples/tree/master/springboot-jpa) 21 | 22 | [Spring Boot全局异常处理](https://github.com/zhuqitao/spring-boot-examples/tree/master/springboot-exception) -------------------------------------------------------------------------------- /springboot-base-config/README.md: -------------------------------------------------------------------------------- 1 | # Spring Boot 基础配置 2 | ### 全局配置文件 3 | 全局配置文件支持properties和yml两种格式 4 | 5 | 默认在src/main/resources目录下,Spring Boot提供了一个名为application.properties的全局配置文件,可对一些默认配置的配置值进行修改。 6 | #### 优先级 7 | properties优先级大于yml,如果同时存在application.properties和application.yml文件,只有application.properties文件生效 8 | #### properties和yml区别 9 | - yml支持树形结构 10 | - 在properties文件中是以”.”进行分割的, 在yml中是用”:”进行分割 11 | - yml的数据格式是K-V格式,并且通过”:”进行赋值 12 | - yml比properties对中文对支持更友好 13 | 14 | **使用yml注意点** 15 | - key后面的冒号,后面一定要跟一个空格 16 | - 在yml中缩进不要使用TAB 17 | - 把原有的application.properties删掉。然后执行 maven -X clean install 18 | 19 | ```properties 20 | server.port=8081 21 | 22 | spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8 23 | spring.datasource.username=root 24 | spring.datasource.password=root 25 | ``` 26 | 27 | yml 28 | ```yaml 29 | server: 30 | port: 8081 31 | 32 | spring: 33 | datasource: 34 | url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8 35 | username: root 36 | passwoord: root 37 | ``` 38 | 39 | ### 自定义配置文件 40 | 我们开发的服务会部署在不同的环境中,如开发、测试,生产等, 41 | 不同环境需要不同的配置,例如连接不同的 Redis、数据库、第三方服务等等。 42 | Spring Boot 默认的配置文件是 application.properties(或yml)。我们需要根据 43 | 不同的环境配置不同的配置文件。 44 | 45 | 首先在application.properties同级目录下创建以下文件: 46 | - application-dev.properties 开发环境 47 | ```properties 48 | server.port=8081 49 | ``` 50 | - application-test.properties 测试环境 51 | ```properties 52 | server.port=8082 53 | ``` 54 | - application-prod.properties 生产环境 55 | ```properties 56 | server.port=8083 57 | ``` 58 | 59 | 然后在application.properties指定spring.profiles.active使用哪个配置文件 60 | 以下示例指定使用test环境配置文件: 61 | ```properties 62 | spring.profiles.active=test 63 | ``` 64 | 此时项目会在test环境配置文件指定的8082端口运行。 65 | 66 | 熟悉前端开发的同学会比较熟悉webpack配置文件,和webpack的配置文件非常相似, 67 | 通常情况webpack会有一个webpack.base.config.js作为基础配置,然后还有webpack.test.config.js、webpack.prod.config.js, 68 | 在执行npm scripts命令(npm run dev/build)时指定process.env.NODE_ENV环境变量的值, 69 | 在webpack.base.config.js中通过判断process.env.NODE_ENV的值来加载对应的配置文件。 70 | 71 | ### 热加载 72 | 为了提高开发效率,我们需要配置热加载,不然开发速度很鸡肋。 73 | #### 一、使用Jrebel插件 74 | Jrebel是Idea提供的插件,是收费的,网上有许多很简单的破解方法,有条件的同学可以购买正版使用。 75 | ##### 第一步:安装插件,需要重启Idea生效 76 | 77 | ![image](http://q21ledx2j.bkt.clouddn.com/example:springboot-base-config:1.png) 78 | 79 | ##### 第二步:激活 80 | ##### 第三步:设置当前项目为Jrebel热更新 81 | 82 | ![image](http://q21ledx2j.bkt.clouddn.com/example:springboot-base-config:2.png) 83 | 84 | 点击左侧Jrebel小功能按钮,勾选需要Jrebel热更新的项目 85 | 到此就可以使用Jrebel热更新启动项目了 86 | 87 | ![image](http://q21ledx2j.bkt.clouddn.com/example:springboot-base-config:3.png) 88 | 89 | #### 二、devtools实现热加载 90 | ##### 第一步:引入devtools依赖 91 | ```xml 92 | 93 | org.springframework.boot 94 | spring-boot-devtools 95 | true 96 | 97 | ``` 98 | ##### 第二步:设置Idea 99 | 按"Command+Option+Shift+/"选择Registry,选中compiler.automake.allow.when.app.running 100 | ,由于我已经选中,compiler.automake.allow.when.app.running在顶部显示,如果没选中需要下拉寻找 101 | 102 | ![image](http://q21ledx2j.bkt.clouddn.com/example:springboot-base-config:4.png) 103 | 104 | IntelliJ IDEA -> Preferences -> Build,Execution,Deplyment -> Compiler 105 | 选中Build project automatically 106 | 107 | ![image](http://q21ledx2j.bkt.clouddn.com/example:springboot-base-config:5.png) 108 | 109 | ![image](http://q21ledx2j.bkt.clouddn.com/example:springboot-base-config:6.png) 110 | ##### 第三步:application.properties配置 111 | ```properties 112 | #热加载生效 113 | spring.devtools.restart.enabled=true 114 | #额外新增的热加载目录 115 | spring.devtools.restart.additional-paths= src/main/java 116 | #热加载排除目录 117 | #spring.devtools.restart.exclude= 118 | ``` 119 | 120 | ### 常用插件 121 | ##### [Lombok 提高开发效率的插件](https://github.com/mplushnikov/lombok-intellij-plugin) 122 | ##### [GsonFormat 快速的将JSON转换为实体类](https://github.com/zzz40500/GsonFormat) 123 | ##### [Maven Helper 解决Maven插件冲突](http://plugins.jetbrains.com/plugin/7179-maven-helper) 124 | 125 | #### 具体代码可查看[源码地址](https://github.com/zhuqitao/spring-boot-examples/tree/master/springboot-base-config),欢迎star 126 | -------------------------------------------------------------------------------- /springboot-base-config/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.1.RELEASE 9 | 10 | 11 | com.love 12 | example 13 | 0.0.1-SNAPSHOT 14 | example 15 | Demo project for Spring Boot 16 | 17 | 18 | 1.8 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-web 25 | 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-test 30 | test 31 | 32 | 33 | org.junit.vintage 34 | junit-vintage-engine 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | org.springframework.boot 44 | spring-boot-maven-plugin 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /springboot-base-config/src/main/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhuqitao/spring-boot-examples/c42121f57f485c32159fd1b203cdc0d4dae13ee9/springboot-base-config/src/main/.DS_Store -------------------------------------------------------------------------------- /springboot-base-config/src/main/java/com/love/example/Controller/Hello.java: -------------------------------------------------------------------------------- 1 | package com.love.example.Controller; 2 | 3 | import org.springframework.web.bind.annotation.RequestMapping; 4 | import org.springframework.web.bind.annotation.RestController; 5 | 6 | @RestController 7 | public class Hello { 8 | @RequestMapping("/hello") 9 | public String hello() { 10 | return "hello world"; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /springboot-base-config/src/main/java/com/love/example/ExampleApplication.java: -------------------------------------------------------------------------------- 1 | package com.love.example; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class ExampleApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(ExampleApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /springboot-base-config/src/main/resources/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhuqitao/spring-boot-examples/c42121f57f485c32159fd1b203cdc0d4dae13ee9/springboot-base-config/src/main/resources/.DS_Store -------------------------------------------------------------------------------- /springboot-base-config/src/main/resources/application-dev.properties: -------------------------------------------------------------------------------- 1 | server.port=8081 -------------------------------------------------------------------------------- /springboot-base-config/src/main/resources/application-prod.properties: -------------------------------------------------------------------------------- 1 | server.port=8083 -------------------------------------------------------------------------------- /springboot-base-config/src/main/resources/application-test.properties: -------------------------------------------------------------------------------- 1 | server.port=8082 -------------------------------------------------------------------------------- /springboot-base-config/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.profiles.active=test -------------------------------------------------------------------------------- /springboot-base-config/src/main/resources/rebel.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /springboot-base-config/src/main/resources/static/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhuqitao/spring-boot-examples/c42121f57f485c32159fd1b203cdc0d4dae13ee9/springboot-base-config/src/main/resources/static/.DS_Store -------------------------------------------------------------------------------- /springboot-base-config/src/main/resources/static/images/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhuqitao/spring-boot-examples/c42121f57f485c32159fd1b203cdc0d4dae13ee9/springboot-base-config/src/main/resources/static/images/1.png -------------------------------------------------------------------------------- /springboot-base-config/src/main/resources/static/images/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhuqitao/spring-boot-examples/c42121f57f485c32159fd1b203cdc0d4dae13ee9/springboot-base-config/src/main/resources/static/images/2.png -------------------------------------------------------------------------------- /springboot-base-config/src/main/resources/static/images/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhuqitao/spring-boot-examples/c42121f57f485c32159fd1b203cdc0d4dae13ee9/springboot-base-config/src/main/resources/static/images/3.png -------------------------------------------------------------------------------- /springboot-base-config/src/main/resources/static/images/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhuqitao/spring-boot-examples/c42121f57f485c32159fd1b203cdc0d4dae13ee9/springboot-base-config/src/main/resources/static/images/4.png -------------------------------------------------------------------------------- /springboot-base-config/src/main/resources/static/images/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhuqitao/spring-boot-examples/c42121f57f485c32159fd1b203cdc0d4dae13ee9/springboot-base-config/src/main/resources/static/images/5.png -------------------------------------------------------------------------------- /springboot-base-config/src/main/resources/static/images/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhuqitao/spring-boot-examples/c42121f57f485c32159fd1b203cdc0d4dae13ee9/springboot-base-config/src/main/resources/static/images/6.png -------------------------------------------------------------------------------- /springboot-base-config/src/main/resources/static/images/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhuqitao/spring-boot-examples/c42121f57f485c32159fd1b203cdc0d4dae13ee9/springboot-base-config/src/main/resources/static/images/7.png -------------------------------------------------------------------------------- /springboot-base-config/src/test/java/com/love/example/ExampleApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.love.example; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class ExampleApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /springboot-exception/README.md: -------------------------------------------------------------------------------- 1 | # Spring Boot全局异常处理 2 | 开发中我们希望只关心业务核心代码,不希望在每个地方都做相同的异常处理,所以 3 | 需要一个大家都遵守的开发规范和一个全局的异常处理。 4 | 5 | #### 创建响应状态码枚举类HttpStatusTypeEnum 6 | ```java 7 | public enum HttpStatusTypeEnum { 8 | SUCCESS(200, "成功"), 9 | USER_INPUT_ERROR(400, "用户输入异常"), 10 | SYSTEM_ERROR (500,"系统服务异常"), 11 | OTHER_ERROR(-1,"未知异常"); 12 | 13 | private int code; 14 | private String desc; 15 | 16 | HttpStatusTypeEnum(int code, String desc) { 17 | this.code = code; 18 | this.desc = desc; 19 | } 20 | 21 | public int getCode() { 22 | return this.code; 23 | } 24 | 25 | public String getDesc() { 26 | return this.desc; 27 | } 28 | ``` 29 | 定义了4种不用的状态,200:成功;400:用户输入异常;500:系统内部异常;-1:其他未知异常 30 | #### 创建异常类ResponseException 31 | ```java 32 | public class ResponseException extends RuntimeException { 33 | // 异常状态码 34 | private int code; 35 | // 异常信息 36 | private String message; 37 | 38 | public ResponseException() { 39 | super(); 40 | } 41 | public ResponseException(int code, String message) { 42 | super(message); 43 | this.code = code; 44 | this.message = message; 45 | } 46 | 47 | public ResponseException(HttpStatusTypeEnum enmu, String message) { 48 | super(message); 49 | this.code = enmu.getCode(); 50 | this.message = message; 51 | } 52 | 53 | // get和set 54 | } 55 | ``` 56 | 异常类包括异常状态码code和异常信息message,message尽量使用语义化的语言来描述, 57 | 这样返回给浏览器也能根据message迅速定位到异常原因。 58 | 59 | #### 创建响应类HttpResponse 60 | ```java 61 | public class HttpResponse { 62 | // 是否成功 63 | private Boolean success; 64 | // 响应状态码 65 | private int code; 66 | // 成功或失败的提示信息 67 | private String message; 68 | // 响应返回的数据 69 | private Object data; 70 | 71 | // 请求异常处理 72 | public static HttpResponse error(ResponseException e) { 73 | HttpResponse httpResponse = new HttpResponse(); 74 | httpResponse.setSuccess(false); 75 | httpResponse.setCode(e.getCode()); 76 | httpResponse.setMessage(e.getMessage()); 77 | httpResponse.setData(null); 78 | return httpResponse; 79 | } 80 | 81 | // 请求异常处理 82 | public static HttpResponse error(int code, String message) { 83 | HttpResponse httpResponse = new HttpResponse(); 84 | httpResponse.setSuccess(false); 85 | httpResponse.setCode(code); 86 | httpResponse.setMessage(message); 87 | httpResponse.setData(null); 88 | return httpResponse; 89 | } 90 | 91 | // 成功 92 | public static HttpResponse success() { 93 | HttpResponse httpResponse = new HttpResponse(); 94 | httpResponse.setSuccess(true); 95 | httpResponse.setCode(200); 96 | httpResponse.setMessage("success"); 97 | return httpResponse; 98 | } 99 | 100 | // 成功 有data数据 101 | public static HttpResponse success(Object data) { 102 | HttpResponse httpResponse = new HttpResponse(); 103 | httpResponse.setSuccess(true); 104 | httpResponse.setCode(200); 105 | httpResponse.setMessage("success"); 106 | httpResponse.setData(data); 107 | return httpResponse; 108 | } 109 | 110 | public Boolean getSuccess() { 111 | return success; 112 | } 113 | 114 | public void setSuccess(Boolean success) { 115 | this.success = success; 116 | } 117 | 118 | public int getCode() { 119 | return code; 120 | } 121 | 122 | public void setCode(int code) { 123 | this.code = code; 124 | } 125 | 126 | public String getMessage() { 127 | return message; 128 | } 129 | 130 | public void setMessage(String message) { 131 | this.message = message; 132 | } 133 | 134 | public Object getData() { 135 | return data; 136 | } 137 | 138 | public void setData(Object data) { 139 | this.data = data; 140 | } 141 | } 142 | ``` 143 | 统一响应返回类型,主要包括success:是否成功状态;code:状态码; 144 | message:失败或者成功提示信息;data:需要传给浏览器的数据。 145 | 还有success()和error()方法 146 | 147 | #### 创建全局异常处理类WebExceptionHandler 148 | ```java 149 | 150 | @ControllerAdvice 151 | public class WebExceptionHandler { 152 | @ExceptionHandler(ResponseException.class) 153 | @ResponseBody 154 | public HttpResponse responseException(ResponseException e) { 155 | System.out.println("发生业务异常,原因是:" + e.getMessage()); 156 | return HttpResponse.error(e); 157 | } 158 | 159 | // 其他异常 160 | @ExceptionHandler(Exception.class) 161 | @ResponseBody 162 | public HttpResponse exception(Exception e) { 163 | System.out.println("发生未知异常,原因是:" + e); 164 | return HttpResponse.error(HttpStatusTypeEnum.OTHER_ERROR.getCode(), "未知异常"); 165 | } 166 | } 167 | ``` 168 | @ControllerAdvice注解:作用是监听所有的controller,针对Controller抛出的异常进行处理 169 | @ExceptionHandler注解:作用是根据Controller抛出的异常的类型分别处理,不用的异常类型使用不同的处理方法 170 | 171 | 可以根据情况在WebExceptionHandler中继续添加其他类型异常的处理。 172 | 173 | #### 创建控制层HelloConTroller 174 | ```java 175 | @RestController 176 | public class HelloController { 177 | @GetMapping("/normal") 178 | public HttpResponse success() throws ResponseException { 179 | return HttpResponse.success(); 180 | } 181 | @GetMapping("/err/match") 182 | public HttpResponse errMatch(int id) throws ResponseException { 183 | if(id == 0) { 184 | throw new ResponseException(HttpStatusTypeEnum.USER_INPUT_ERROR, "id不符合标准"); 185 | } else { 186 | Map data = new HashMap<>(); 187 | data.put("id", id); 188 | return HttpResponse.success(data); 189 | } 190 | } 191 | @GetMapping("/err/system") 192 | public HttpResponse sysError() throws ResponseException { 193 | try{ 194 | int i = 1/0; 195 | } catch(Exception e) { 196 | throw new ResponseException(HttpStatusTypeEnum.SYSTEM_ERROR.getCode(), "系统异常"); 197 | } 198 | return HttpResponse.success(); 199 | } 200 | } 201 | ``` 202 | 在Controller中写了三个路由,"/normal"是一个正常的路由, 203 | "/err/match"会根据用户传的id的值判断,如果id=0,则认为是一个异常的参数, 204 | "/err/system"会自动抛出一个系统异常。 205 | 206 | 启动项目,浏览器访问[http://localhost:8080/normal](http://localhost:8080/normal) 207 | 会获取正常的响应; 208 | 209 | 访问[http://localhost:8080/err/match?id=0](http://localhost:8080/err/match?id=0) 210 | 会获取"id不符合标准"的异常响应,同时控制台也会打印出异常信息; 211 | 212 | 访问[http://localhost:8080/err/match?id=1](http://localhost:8080/err/match?id=1)则会 213 | 获取正常的响应; 214 | 215 | 访问[http://localhost:8080/err/system](http://localhost:8080/err/system)会获取到 216 | "系统异常"的异常响应。 217 | 218 | -------------------------------------------------------------------------------- /springboot-exception/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.2.RELEASE 9 | 10 | 11 | com.love 12 | example 13 | 0.0.1-SNAPSHOT 14 | example 15 | Demo project for Spring Boot 16 | 17 | 18 | 1.8 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-web 25 | 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-test 30 | test 31 | 32 | 33 | org.junit.vintage 34 | junit-vintage-engine 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | org.springframework.boot 44 | spring-boot-maven-plugin 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /springboot-exception/src/main/java/com/love/example/Config/WebExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package com.love.example.Config; 2 | 3 | import com.love.example.Exception.HttpResponse; 4 | import com.love.example.Exception.HttpStatusTypeEnum; 5 | import com.love.example.Exception.ResponseException; 6 | import org.springframework.web.bind.annotation.ControllerAdvice; 7 | import org.springframework.web.bind.annotation.ExceptionHandler; 8 | import org.springframework.web.bind.annotation.ResponseBody; 9 | 10 | @ControllerAdvice 11 | public class WebExceptionHandler { 12 | @ExceptionHandler(ResponseException.class) 13 | @ResponseBody 14 | public HttpResponse responseException(ResponseException e) { 15 | System.out.println("发生业务异常,原因是:" + e.getMessage()); 16 | return HttpResponse.error(e); 17 | } 18 | 19 | // 其他异常 20 | @ExceptionHandler(Exception.class) 21 | @ResponseBody 22 | public HttpResponse exception(Exception e) { 23 | System.out.println("发生未知异常,原因是:" + e); 24 | return HttpResponse.error(HttpStatusTypeEnum.OTHER_ERROR.getCode(), "未知异常"); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /springboot-exception/src/main/java/com/love/example/Controller/HelloController.java: -------------------------------------------------------------------------------- 1 | package com.love.example.Controller; 2 | 3 | import com.love.example.Exception.HttpResponse; 4 | import com.love.example.Exception.HttpStatusTypeEnum; 5 | import com.love.example.Exception.ResponseException; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.RestController; 8 | 9 | import java.util.HashMap; 10 | import java.util.Map; 11 | 12 | @RestController 13 | public class HelloController { 14 | @GetMapping("/normal") 15 | public HttpResponse success() throws ResponseException { 16 | return HttpResponse.success(); 17 | } 18 | @GetMapping("/err/match") 19 | public HttpResponse errMatch(int id) throws ResponseException { 20 | if(id == 0) { 21 | throw new ResponseException(HttpStatusTypeEnum.USER_INPUT_ERROR, "id不符合标准"); 22 | } else { 23 | Map data = new HashMap<>(); 24 | data.put("id", id); 25 | return HttpResponse.success(data); 26 | } 27 | } 28 | @GetMapping("/err/system") 29 | public HttpResponse sysError() throws ResponseException { 30 | try{ 31 | int i = 1/0; 32 | } catch(Exception e) { 33 | throw new ResponseException(HttpStatusTypeEnum.SYSTEM_ERROR.getCode(), "系统异常"); 34 | } 35 | return HttpResponse.success(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /springboot-exception/src/main/java/com/love/example/ExampleApplication.java: -------------------------------------------------------------------------------- 1 | package com.love.example; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class ExampleApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(ExampleApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /springboot-exception/src/main/java/com/love/example/Exception/HttpResponse.java: -------------------------------------------------------------------------------- 1 | package com.love.example.Exception; 2 | 3 | public class HttpResponse { 4 | // 是否成功 5 | private Boolean success; 6 | // 响应状态码 7 | private int code; 8 | // 成功或失败的提示信息 9 | private String message; 10 | // 响应返回的数据 11 | private Object data; 12 | 13 | // 请求异常处理 14 | public static HttpResponse error(ResponseException e) { 15 | HttpResponse httpResponse = new HttpResponse(); 16 | httpResponse.setSuccess(false); 17 | httpResponse.setCode(e.getCode()); 18 | httpResponse.setMessage(e.getMessage()); 19 | httpResponse.setData(null); 20 | return httpResponse; 21 | } 22 | 23 | // 请求异常处理 24 | public static HttpResponse error(int code, String message) { 25 | HttpResponse httpResponse = new HttpResponse(); 26 | httpResponse.setSuccess(false); 27 | httpResponse.setCode(code); 28 | httpResponse.setMessage(message); 29 | httpResponse.setData(null); 30 | return httpResponse; 31 | } 32 | 33 | // 成功 34 | public static HttpResponse success() { 35 | HttpResponse httpResponse = new HttpResponse(); 36 | httpResponse.setSuccess(true); 37 | httpResponse.setCode(200); 38 | httpResponse.setMessage("success"); 39 | return httpResponse; 40 | } 41 | 42 | // 成功 有data数据 43 | public static HttpResponse success(Object data) { 44 | HttpResponse httpResponse = new HttpResponse(); 45 | httpResponse.setSuccess(true); 46 | httpResponse.setCode(200); 47 | httpResponse.setMessage("success"); 48 | httpResponse.setData(data); 49 | return httpResponse; 50 | } 51 | 52 | 53 | 54 | public Boolean getSuccess() { 55 | return success; 56 | } 57 | 58 | public void setSuccess(Boolean success) { 59 | this.success = success; 60 | } 61 | 62 | public int getCode() { 63 | return code; 64 | } 65 | 66 | public void setCode(int code) { 67 | this.code = code; 68 | } 69 | 70 | public String getMessage() { 71 | return message; 72 | } 73 | 74 | public void setMessage(String message) { 75 | this.message = message; 76 | } 77 | 78 | public Object getData() { 79 | return data; 80 | } 81 | 82 | public void setData(Object data) { 83 | this.data = data; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /springboot-exception/src/main/java/com/love/example/Exception/HttpStatusTypeEnum.java: -------------------------------------------------------------------------------- 1 | package com.love.example.Exception; 2 | 3 | public enum HttpStatusTypeEnum { 4 | SUCCESS(200, "成功"), 5 | USER_INPUT_ERROR(400, "用户输入异常"), 6 | SIGNATURE_NOT_MATCH(401,"请求的数字签名不匹配!"), 7 | SYSTEM_ERROR (500,"系统服务异常"), 8 | OTHER_ERROR(-1,"未知异常"); 9 | 10 | private int code; 11 | private String desc; 12 | 13 | HttpStatusTypeEnum(int code, String desc) { 14 | this.code = code; 15 | this.desc = desc; 16 | } 17 | 18 | public int getCode() { 19 | return this.code; 20 | } 21 | 22 | public String getDesc() { 23 | return this.desc; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /springboot-exception/src/main/java/com/love/example/Exception/ResponseException.java: -------------------------------------------------------------------------------- 1 | package com.love.example.Exception; 2 | 3 | public class ResponseException extends RuntimeException { 4 | // 异常状态码 5 | private int code; 6 | // 异常信息 7 | private String message; 8 | 9 | public ResponseException() { 10 | super(); 11 | } 12 | public ResponseException(int code, String message) { 13 | super(message); 14 | this.code = code; 15 | this.message = message; 16 | } 17 | 18 | public ResponseException(HttpStatusTypeEnum enmu, String message) { 19 | super(message); 20 | this.code = enmu.getCode(); 21 | this.message = message; 22 | } 23 | 24 | public int getCode() { 25 | return code; 26 | } 27 | 28 | public void setCode(int code) { 29 | this.code = code; 30 | } 31 | 32 | @Override 33 | public String getMessage() { 34 | return message; 35 | } 36 | 37 | public void setMessage(String message) { 38 | this.message = message; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /springboot-exception/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /springboot-exception/src/test/java/com/love/example/ExampleApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.love.example; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class ExampleApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /springboot-hello-world/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.1.RELEASE 9 | 10 | 11 | com.love 12 | example 13 | 0.0.1-SNAPSHOT 14 | example 15 | Demo project for Spring Boot 16 | 17 | 18 | 1.8 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-web 25 | 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-test 30 | test 31 | 32 | 33 | org.junit.vintage 34 | junit-vintage-engine 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | org.springframework.boot 44 | spring-boot-maven-plugin 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /springboot-hello-world/src/main/java/com/love/example/Controller/Hello.java: -------------------------------------------------------------------------------- 1 | package com.love.example.Controller; 2 | 3 | import org.springframework.web.bind.annotation.RequestMapping; 4 | import org.springframework.web.bind.annotation.RestController; 5 | 6 | @RestController 7 | public class Hello { 8 | @RequestMapping("/hello") 9 | public String hello() { 10 | return "hello world"; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /springboot-hello-world/src/main/java/com/love/example/ExampleApplication.java: -------------------------------------------------------------------------------- 1 | package com.love.example; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class ExampleApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(ExampleApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /springboot-hello-world/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /springboot-hello-world/src/test/java/com/love/example/ExampleApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.love.example; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class ExampleApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /springboot-jpa/README.md: -------------------------------------------------------------------------------- 1 | # Spring Boot整合JPA 2 | ### 介绍 3 | #### 什么是JPA 4 | JPA(Java Persistence API),也叫Java 持久化 API,是一个 Java 应用程序接口 规范,描述了使用 Java标准版平台(Java SE) 5 | 和 Java企业版平台(Java EE)的应用中的 关系数据 的管理。 6 | 7 | 它的出现主要是为了简化现有的持久化开发工作和整合 ORM 技术,实现 Hibernate,TopLink,JDO 等 ORM 框架大一统局面。 8 | #### 什么是Spring Data Jpa 9 | Spring Data Jpa 是基于ORM框架、Jpa规范封装的一套Jpa应用框架,底层使用了 Hibernate 的 JPA 技术实现, 10 | 它提供了包括增删改查等在内的常用功能,且易于扩展!学习并使用 Spring Data Jpa 可以极大提高开发效率! 11 | 12 | ### Spring Boot继承Spring Data Jpa 13 | #### 数据库 14 | 启动本地MySql,创建数据库jpa_test 15 | #### 添加依赖 16 | ```xml 17 | 18 | mysql 19 | mysql-connector-java 20 | 21 | 22 | org.springframework.boot 23 | spring-boot-starter-data-jpa 24 | 25 | ``` 26 | #### 配置application.properties 27 | ```properties 28 | spring.datasource.url=jdbc:mysql://localhost:3306/jpa_test?useUnicode=true&characterEncoding=UTF-8 29 | spring.datasource.username=root 30 | spring.datasource.password=root 31 | spring.datasource.driver-class-name=com.mysql.jdbc.Driver 32 | 33 | # jpa配置 34 | spring.jpa.database=mysql 35 | # 自动创建|更新|验证数据库表结构的方式 36 | # 其中update是最常用的属性,首次加载hibernate会根据model自动创建表结构,以后再加载hibernate会根据model自动更新表结构 37 | spring.jpa.hibernate.ddl-auto=update 38 | # 输出所有SQL语句到控制台. 39 | spring.jpa.show-sql=true 40 | ``` 41 | 42 | #### 创建实体类User 43 | ```java 44 | @Entity 45 | @Table(name="user") 46 | public class User { 47 | @Id 48 | @GeneratedValue(strategy = GenerationType.IDENTITY) 49 | private Integer id; 50 | 51 | @Column(nullable = false, unique = true, length = 32) 52 | private String name; 53 | @Column(nullable = false) 54 | private String password; 55 | 56 | public User() { 57 | 58 | } 59 | public User(String name, String password) { 60 | this.name = name; 61 | this.password = password; 62 | } 63 | 64 | // get、set和toString方法... 65 | 66 | ``` 67 | - @Entity:表明这是一个接受JPA管理的实体类,对应数据库中一张表,如果没有该表,则会自动创建表 68 | - @Table(name="user"):指明这个实体类对应库中表的名字,如果不使用该注解,则会根据实体类名字与表明 69 | 按照驼峰及下划线规则匹配。 70 | - @Id:指定这个字段为表的主键 71 | - @GeneratedValue(strategy = GenerationType.IDENTITY):指定主键生成方式为自增方式 72 | - GenerationType.TABLE:使用一个特定的数据库表格来保存主键 73 | - GenerationType.SEQUENCE:根据底层数据库的序列来生成主键,条件是数据库支持序列 74 | - GenerationType.IDENTITY:主键由数据库自动生成(主要是自动增长型) 75 | - GenerationType.AUTO:默认值,持久化引擎会根据数据库在以上三种主键生成策略中选择其中一种 76 | - @Column:指定某个属性对应表中哪个字段,nullable=falseb表示字段不能为空,unique=true表示字段唯一不能重复,length=32表示最大长度不能超过32 77 | ### 创建JPA仓库 78 | 继承JpaRepository接口实现数据操作 79 | ```java 80 | public interface UserRepository extends JpaRepository { 81 | 82 | } 83 | ``` 84 | JpaRepositoryT代表实体类,ID是主键id,JpaRepository已经为我们提供了单表的基础操作方法(findById、findAll、save)等方法。 85 | 添加数据和修改数据都是使用save方法,会根据主键id查询是否已经存在实现增加或修改数据。 86 | 87 | #### Service接口 88 | ```java 89 | public interface UserService { 90 | 91 | Optional getUser(Integer id); 92 | 93 | List getAllUser(); 94 | 95 | Boolean addUser(User user); 96 | 97 | Boolean updateUser(Integer id, String name, String password); 98 | 99 | Boolean deleteUser(Integer id); 100 | } 101 | ``` 102 | 103 | #### Service接口实现 104 | ```java 105 | @Service("UserService") 106 | public class UserServiceTemplate implements UserService { 107 | // 注入JPA仓库对象 108 | @Resource 109 | UserRepository userRepository; 110 | 111 | @Override 112 | public Optional getUser(Integer id) { 113 | 114 | return userRepository.findById(id); 115 | } 116 | 117 | @Override 118 | public List getAllUser() { 119 | return userRepository.findAll(); 120 | } 121 | 122 | @Override 123 | public Boolean addUser(User user) { 124 | userRepository.save(user); 125 | return true; 126 | } 127 | 128 | @Override 129 | public Boolean updateUser(Integer id, String name, String password) { 130 | User user = userRepository.findById(id).get(); 131 | user.setName(name); 132 | user.setPassword(password); 133 | userRepository.save(user); 134 | return true; 135 | } 136 | 137 | @Override 138 | public Boolean deleteUser(Integer id) { 139 | userRepository.deleteById(id); 140 | return true; 141 | } 142 | } 143 | ``` 144 | 145 | #### 编写Controller 146 | ```java 147 | @RestController 148 | @RequestMapping("/user") 149 | public class UserController { 150 | @Autowired 151 | UserService userService; 152 | @GetMapping("/add") 153 | public String addUser(String name, String password) { 154 | User user = new User(name, password); 155 | userService.addUser(user); 156 | return "1"; 157 | } 158 | @GetMapping("/get") 159 | public User getUser(Integer id) { 160 | Optional userOptional = userService.getUser(id); 161 | User user = userOptional.orElse(null); 162 | return user; 163 | } 164 | @GetMapping("/getAll") 165 | public List getAllUser() { 166 | return userService.getAllUser(); 167 | } 168 | @GetMapping("/update") 169 | public String updateUser(Integer id, String name, String password) { 170 | userService.updateUser(id, name, password); 171 | return "1"; 172 | } 173 | @GetMapping("/delete") 174 | public String deleteUser(Integer id) { 175 | userService.deleteUser(id); 176 | return "1"; 177 | } 178 | } 179 | ``` 180 | 启动项目,由于在配置文件中设置了spring.jpa.hibernate.ddl-auto=update, 181 | 如果数据库中没有实体类对应的表,则创建表,如果已经存在,则判断实体类结构是否与表结构一致,不一致则更新表结构。 182 | 一切正常情况下,会看到数据库jpa_test多了一张user表,浏览器访问 183 | [http://localhost:8080/user/add?name=test&password=123456](http://localhost:8080/user/add?name=test&password=123456), 184 | 则会往user表中添加一条数据。 185 | 186 | ### 简单自定义查询 187 | 简单自定义查询就是根据方法名字自动生成SQL。比如findByName、findByNameAndPassword. 188 | 189 | 修改UserRepository,添加findByName和findByNameAndPassword方法 190 | ```java 191 | public interface UserRepository extends JpaRepository { 192 | User findByName(String name); 193 | User findByNameAndPassword(String name, String password); 194 | } 195 | ``` 196 | 197 | 修改UserService,添加getUserByName和getUserByNameAndPassword 198 | ```java 199 | public interface UserService { 200 | ... 201 | 202 | User getUserByName(String name); 203 | User getUserByNameAndPassword(String name, String password); 204 | 205 | ... 206 | } 207 | ``` 208 | 修改UserServiceTemplate,添加getUserByName和getUserByNameAndPassword的实现 209 | ```java 210 | @Service("UserService") 211 | public class UserServiceTemplate implements UserService { 212 | ... 213 | 214 | @Override 215 | public User getUserByName(String name) { 216 | return userRepository.findByName(name); 217 | } 218 | 219 | @Override 220 | public User getUserByNameAndPassword(String name, String password) { 221 | return userRepository.findByNameAndPassword(name, password); 222 | } 223 | 224 | ... 225 | } 226 | ``` 227 | 修改UserController,添加"/getUserByName"和"/getUserByNameAndPassword"路由 228 | ```java 229 | @RestController 230 | @RequestMapping("/user") 231 | public class UserController { 232 | ... 233 | 234 | @GetMapping("/getUserByName") 235 | public User getUserByName(String name) { 236 | return userService.getUserByName(name); 237 | } 238 | @GetMapping("/getUserByNameAndPassword") 239 | public User getUserByName(String name, String password) { 240 | return userService.getUserByNameAndPassword(name, password); 241 | } 242 | 243 | ... 244 | } 245 | ``` 246 | 247 | 项目重启,浏览器访问 248 | [http://localhost:8080/user/getUserByName?name=test](http://localhost:8080/user/getUserByName?name=test)或者 249 | [http://localhost:8080/user/getUserByNameAndPassword?name=test&password=123456](http://localhost:8080/user/getUserByNameAndPassword?name=test&password=123456) 250 | 可以查询到之前添加的那条数据。 251 | 252 | 更多关键字查询 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 382 | 383 | 384 |
关键字例子JPQL片段
AndfindByNameAndPassword… where x.name = ?1 and x.password = ?2
OrfindByNameOrPassword… where x.name = ?1 or x.password = ?2
Is,EqualsfindByNameIs,findByNameEquals… where x.name = ?1
BetweenfindByStartDateBetween… where x.startDate between ?1 and ?2
LessThanfindByAgeLessThan… where x.age < ?1
LessThanEqualfindByAgeLessThanEqual… where x.age ⇐ ?1
GreaterThanfindByAgeGreaterThan… where x.age > ?1
GreaterThanEqualfindByAgeGreaterThanEqual… where x.age >= ?1
AfterfindByStartDateAfter… where x.startDate > ?1
BeforefindByStartDateBefore… where x.startDate < ?1
IsNullfindByAgeIsNull… where x.age is null
IsNotNull,NotNullfindByAge(Is)NotNull… where x.age not null
LikefindByNameLike… where x.name like ?1
NotLikefindByNameNotLike… where x.name not like ?1
StartingWithfindByNameStartingWith… where x.name like ?1 (parameter bound with appended %)
EndingWithfindByNameEndingWith… where x.name like ?1 (parameter bound with prepended %)
ContainingfindByNameContaining… where x.name like ?1 (parameter bound wrapped in %)
OrderByfindByAgeOrderByNameDesc… where x.age = ?1 order by x.name desc
NotfindByNameNot… where x.name <> ?1
InfindByAgeIn(Collection ages)… where x.age in ?1
NotInfindByAgeNotIn(Collection age)… where x.age not in ?1
TRUEfindByActiveTrue… where x.active = true
FALSEfindByActiveFalse… where x.active = false
IgnoreCasefindByNameIgnoreCase… where UPPER(x.name) = UPPER(?1) 381 |
385 | 386 | ### 分页排序查询 387 | 分页查询的意义就不多说了,大家都明白,如果确定数据量小的情况可以选择前端分页, 388 | 如果数据量比较大或者数据量一直增加并在未来可能会增加到比较大的数据量(比如用户量),最好还是后端支持分页排序查询。 389 | 390 | Spring Boot Jpa 已经帮我们实现了分页的功能,需要定义一个继承PagingAndSortingRepository的接口,传入参数Pageable就可以实现分页。 391 | 392 | 修改UserRepository 393 | ```java 394 | public interface UserRepository extends PagingAndSortingRepository { 395 | Page findAll(Pageable pageable); 396 | Page findAllByName(String name, Pageable pageable); 397 | } 398 | ``` 399 | 修改UserService 400 | ```java 401 | 402 | public interface UserService { 403 | List getUserPage(Integer pageNumber, Integer pageSize); 404 | List getUserPageBySort(Integer pageNumber, Integer pageSize); 405 | } 406 | ``` 407 | 修改UserServiceTemplate 408 | ```java 409 | @Service("UserService") 410 | public class UserServiceTemplate implements UserService { 411 | // 注入JPA仓库对象 412 | @Resource 413 | UserRepository userRepository; 414 | 415 | @Override 416 | public List getUserPage(Integer pageNumber, Integer pageSize) { 417 | Pageable pageable = PageRequest.of(pageNumber, pageSize); 418 | Page userPage = userRepository.findAll(pageable); 419 | 420 | int totalPage = userPage.getTotalPages(); 421 | Long totalCount = userPage.getTotalElements(); 422 | System.out.println("totalPage" + totalPage); 423 | System.out.println("totalCount" + totalCount); 424 | 425 | List userList = userPage.toList(); 426 | return userList; 427 | } 428 | 429 | @Override 430 | public List getUserPageBySort(Integer pageNumber, Integer pageSize) { 431 | 432 | Order order1 = new Order(Sort.Direction.ASC, "password"); 433 | Order order2 = new Order(Sort.Direction.DESC, "name"); 434 | 435 | List orderList = new ArrayList<>(); 436 | orderList.add(order1); 437 | orderList.add(order2); 438 | 439 | Sort sort = Sort.by(orderList); 440 | Pageable pageable = PageRequest.of(pageNumber, pageSize, sort); 441 | Page userPage = userRepository.findAll(pageable); 442 | List userList = userPage.toList(); 443 | return userList; 444 | } 445 | } 446 | ``` 447 | getUserPage:根据pageNumber和pageSize参数定义一个Pageable对象,Pageable对象 448 | 传给userRepository.findAll,最后使用Page提供的toList方法转为List对象返回Controller, 449 | Page还提供了getTotalPages()方法和getTotalElements()方法,用来获取总页数和总数据条数。 450 | 451 | getUserPageBySort:首先创建了两个Order对象,order1是根据password字段升序排序, 452 | order2根据name字段降序排序,然后分别添加到一个List对象,注意添加顺序,先添加的优先权高, 453 | 最后会先根据order1排序规则然后再根据order2排序规则返回数据。 454 | 455 | 先往数据库user表中添加12条数据,重启项目,浏览器访问 456 | [http://localhost:8080/user/getUserPage?pageNumber=0&pageSize=5](http://localhost:8080/user/getUserPage?pageNumber=0&pageSize=5) 457 | 看到下图没有排序的数据: 458 | ![image](http://q21ledx2j.bkt.clouddn.com/example:springboot-jpa:1.png) 459 | 访问[http://localhost:8080/user/getUserPageBySort?pageNumber=0&pageSize=5](http://localhost:8080/user/getUserPageBySort?pageNumber=0&pageSize=5) 460 | 会看到按照定义好的排序规则排序后的数据: 461 | ![image](http://q21ledx2j.bkt.clouddn.com/example:springboot-jpa:2.png) 462 | 463 | ### 自定义SQL查询 464 | 465 | 修改UserRepository,添加findUserByIdWithQuery方法 466 | ```java 467 | public interface UserRepository extends PagingAndSortingRepository { 468 | Page findAll(Pageable pageable); 469 | Page findAllByName(String name, Pageable pageable); 470 | 471 | @Query("select u from User u where u.id = ?1") 472 | User findUserByIdWithQuery(Integer id); 473 | 474 | @Modifying 475 | @Query("delete from User where id = ?1") 476 | Boolean deleteUserByIdWithQuery(Long id); 477 | } 478 | ``` 479 | 使用@Query可以自定义查询语句,如果涉及到修改和删除数据,还需要再添加@Modifying注解 480 | 481 | 修改UserService,添加getUserByIdWithQuery方法 482 | ```java 483 | public interface UserService { 484 | 485 | List getUserPage(Integer pageNumber, Integer pageSize); 486 | List getUserPageBySort(Integer pageNumber, Integer pageSize); 487 | 488 | User getUserByIdWithQuery(Integer id); 489 | } 490 | ``` 491 | 492 | 修改UserServiceTemplate,添加getUserByIdWithQuery实现 493 | ```java 494 | @Service("UserService") 495 | public class UserServiceTemplate implements UserService { 496 | ... 497 | 498 | @Override 499 | public User getUserByIdWithQuery(Integer id) { 500 | return userRepository.findUserByIdWithQuery(id); 501 | } 502 | } 503 | ``` 504 | 505 | 修改UserController,添加"/getUserByIdWithQuery"路由 506 | ```java 507 | @RestController 508 | @RequestMapping("/user") 509 | public class UserController { 510 | ... 511 | 512 | @GetMapping("/getUserByIdWithQuery") 513 | public User getUserByIdWithQuery(Integer id) { 514 | return userService.getUserByIdWithQuery(id); 515 | } 516 | } 517 | ``` 518 | 519 | 重启项目,浏览器访问[http://localhost:8080/user/getUserByIdWithQuery?id=2](http://localhost:8080/user/getUserByIdWithQuery?id=2), 520 | 看到下图效果: 521 | ![image](http://q21ledx2j.bkt.clouddn.com/example:springboot-jpa:3.png) 522 | 523 | #### 具体代码可查看[源码地址](https://github.com/zhuqitao/spring-boot-examples/tree/master/springboot-jpa),欢迎star 524 | 525 | 526 | -------------------------------------------------------------------------------- /springboot-jpa/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.2.RELEASE 9 | 10 | 11 | com.love 12 | example 13 | 0.0.1-SNAPSHOT 14 | example 15 | Demo project for Spring Boot 16 | 17 | 18 | 1.8 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-web 25 | 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-test 30 | test 31 | 32 | 33 | org.junit.vintage 34 | junit-vintage-engine 35 | 36 | 37 | 38 | 39 | mysql 40 | mysql-connector-java 41 | 42 | 43 | org.springframework.boot 44 | spring-boot-starter-data-jpa 45 | 46 | 47 | 48 | 49 | 50 | 51 | org.springframework.boot 52 | spring-boot-maven-plugin 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /springboot-jpa/src/main/java/com/love/example/Controller/UserController.java: -------------------------------------------------------------------------------- 1 | package com.love.example.Controller; 2 | 3 | import com.love.example.Model.User; 4 | import com.love.example.Service.UserService; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.RestController; 9 | 10 | import java.util.List; 11 | import java.util.Optional; 12 | 13 | //@RestController 14 | //@RequestMapping("/user") 15 | //public class UserController { 16 | // @Autowired 17 | // UserService userService; 18 | // @GetMapping("/add") 19 | // public String addUser(String name, String password) { 20 | // User user = new User(name, password); 21 | // userService.addUser(user); 22 | // return "1"; 23 | // } 24 | // @GetMapping("/get") 25 | // public User getUser(Integer id) { 26 | // Optional userOptional = userService.getUser(id); 27 | // User user = userOptional.orElse(null); 28 | // return user; 29 | // } 30 | // @GetMapping("/getUserByName") 31 | // public User getUserByName(String name) { 32 | // return userService.getUserByName(name); 33 | // } 34 | // @GetMapping("/getUserByNameAndPassword") 35 | // public User getUserByName(String name, String password) { 36 | // return userService.getUserByNameAndPassword(name, password); 37 | // } 38 | // @GetMapping("/getAll") 39 | // public List getAllUser() { 40 | // return userService.getAllUser(); 41 | // } 42 | // @GetMapping("/update") 43 | // public String updateUser(Integer id, String name, String password) { 44 | // userService.updateUser(id, name, password); 45 | // return "1"; 46 | // } 47 | // @GetMapping("/delete") 48 | // public String deleteUser(Integer id) { 49 | // userService.deleteUser(id); 50 | // return "1"; 51 | // } 52 | //} 53 | 54 | @RestController 55 | @RequestMapping("/user") 56 | public class UserController { 57 | @Autowired 58 | UserService userService; 59 | 60 | @GetMapping("/getUserPage") 61 | public List getUserPage(Integer pageNumber, Integer pageSize) { 62 | return userService.getUserPage(pageNumber,pageSize); 63 | } 64 | @GetMapping("/getUserPageBySort") 65 | public List getUserPageBySort(Integer pageNumber, Integer pageSize){ 66 | return userService.getUserPageBySort(pageNumber, pageSize); 67 | } 68 | 69 | @GetMapping("/getUserByIdWithQuery") 70 | public User getUserByIdWithQuery(Integer id) { 71 | return userService.getUserByIdWithQuery(id); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /springboot-jpa/src/main/java/com/love/example/ExampleApplication.java: -------------------------------------------------------------------------------- 1 | package com.love.example; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; 7 | 8 | @SpringBootApplication 9 | //@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class}) 10 | public class ExampleApplication { 11 | 12 | public static void main(String[] args) { 13 | SpringApplication.run(ExampleApplication.class, args); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /springboot-jpa/src/main/java/com/love/example/Model/User.java: -------------------------------------------------------------------------------- 1 | package com.love.example.Model; 2 | 3 | import javax.persistence.*; 4 | 5 | @Entity 6 | @Table(name="user") 7 | public class User { 8 | @Id 9 | @GeneratedValue(strategy = GenerationType.IDENTITY) 10 | private Integer id; 11 | 12 | @Column(nullable = false, unique = true, length = 32) 13 | private String name; 14 | @Column(nullable = false) 15 | private String password; 16 | 17 | public User() { 18 | 19 | } 20 | public User(String name, String password) { 21 | this.name = name; 22 | this.password = password; 23 | } 24 | 25 | public Integer getId() { 26 | return id; 27 | } 28 | 29 | public void setId(Integer id) { 30 | this.id = id; 31 | } 32 | 33 | public String getName() { 34 | return name; 35 | } 36 | 37 | public void setName(String name) { 38 | this.name = name; 39 | } 40 | 41 | public String getPassword() { 42 | return password; 43 | } 44 | 45 | public void setPassword(String password) { 46 | this.password = password; 47 | } 48 | 49 | @Override 50 | public String toString() { 51 | return "User{" + 52 | "id=" + id + 53 | ", name='" + name + '\'' + 54 | ", password='" + password + '\'' + 55 | '}'; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /springboot-jpa/src/main/java/com/love/example/Repository/UserRepository.java: -------------------------------------------------------------------------------- 1 | package com.love.example.Repository; 2 | 3 | import com.love.example.Model.User; 4 | import org.springframework.data.domain.Page; 5 | import org.springframework.data.domain.Pageable; 6 | import org.springframework.data.jpa.repository.JpaRepository; 7 | import org.springframework.data.jpa.repository.Modifying; 8 | import org.springframework.data.jpa.repository.Query; 9 | import org.springframework.data.repository.PagingAndSortingRepository; 10 | 11 | 12 | //public interface UserRepository extends JpaRepository { 13 | // User findByName(String name); 14 | // User findByNameAndPassword(String name, String password); 15 | //} 16 | 17 | public interface UserRepository extends PagingAndSortingRepository { 18 | Page findAll(Pageable pageable); 19 | Page findAllByName(String name, Pageable pageable); 20 | 21 | @Query("select u from User u where u.id = ?1") 22 | User findUserByIdWithQuery(Integer id); 23 | 24 | @Modifying 25 | @Query("delete from User where id = ?1") 26 | Boolean deleteUserByIdWithQuery(Long id); 27 | } 28 | -------------------------------------------------------------------------------- /springboot-jpa/src/main/java/com/love/example/Service/ServiceTemplate/UserServiceTemplate.java: -------------------------------------------------------------------------------- 1 | package com.love.example.Service.ServiceTemplate; 2 | 3 | import com.love.example.Model.User; 4 | import com.love.example.Repository.UserRepository; 5 | import com.love.example.Service.UserService; 6 | import org.springframework.data.domain.Page; 7 | import org.springframework.data.domain.PageRequest; 8 | import org.springframework.data.domain.Pageable; 9 | import org.springframework.data.domain.Sort; 10 | import org.springframework.data.domain.Sort.Order; 11 | import org.springframework.stereotype.Service; 12 | 13 | import javax.annotation.Resource; 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | import java.util.Optional; 17 | 18 | //@Service("UserService") 19 | //public class UserServiceTemplate implements UserService { 20 | // // 注入JPA仓库对象 21 | // @Resource 22 | // UserRepository userRepository; 23 | // 24 | // @Override 25 | // public Optional getUser(Integer id) { 26 | // 27 | // return userRepository.findById(id); 28 | // } 29 | // 30 | // @Override 31 | // public List getAllUser() { 32 | // return userRepository.findAll(); 33 | // } 34 | // 35 | // @Override 36 | // public User getUserByName(String name) { 37 | // return userRepository.findByName(name); 38 | // } 39 | // 40 | // @Override 41 | // public User getUserByNameAndPassword(String name, String password) { 42 | // return userRepository.findByNameAndPassword(name, password); 43 | // } 44 | // 45 | // @Override 46 | // public Boolean addUser(User user) { 47 | // userRepository.save(user); 48 | // return true; 49 | // } 50 | // 51 | // @Override 52 | // public Boolean updateUser(Integer id, String name, String password) { 53 | // User user = userRepository.findById(id).get(); 54 | // user.setName(name); 55 | // user.setPassword(password); 56 | // userRepository.save(user); 57 | // return true; 58 | // } 59 | // 60 | // @Override 61 | // public Boolean deleteUser(Integer id) { 62 | // userRepository.deleteById(id); 63 | // return true; 64 | // } 65 | //} 66 | @Service("UserService") 67 | public class UserServiceTemplate implements UserService { 68 | // 注入JPA仓库对象 69 | @Resource 70 | UserRepository userRepository; 71 | 72 | @Override 73 | public List getUserPage(Integer pageNumber, Integer pageSize) { 74 | Pageable pageable = PageRequest.of(pageNumber, pageSize); 75 | Page userPage = userRepository.findAll(pageable); 76 | int totalPage = userPage.getTotalPages(); 77 | Long totalCount = userPage.getTotalElements(); 78 | System.out.println("totalPage" + totalPage); 79 | System.out.println("totalCount" + totalCount); 80 | List userList = userPage.toList(); 81 | return userList; 82 | } 83 | 84 | @Override 85 | public List getUserPageBySort(Integer pageNumber, Integer pageSize) { 86 | 87 | Order order1 = new Order(Sort.Direction.ASC, "password"); 88 | Order order2 = new Order(Sort.Direction.DESC, "name"); 89 | 90 | List orderList = new ArrayList<>(); 91 | orderList.add(order1); 92 | orderList.add(order2); 93 | 94 | Sort sort = Sort.by(orderList); 95 | Pageable pageable = PageRequest.of(pageNumber, pageSize, sort); 96 | Page userPage = userRepository.findAll(pageable); 97 | List userList = userPage.toList(); 98 | return userList; 99 | } 100 | 101 | @Override 102 | public User getUserByIdWithQuery(Integer id) { 103 | return userRepository.findUserByIdWithQuery(id); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /springboot-jpa/src/main/java/com/love/example/Service/UserService.java: -------------------------------------------------------------------------------- 1 | package com.love.example.Service; 2 | 3 | import com.love.example.Model.User; 4 | import java.util.List; 5 | import java.util.Optional; 6 | 7 | //public interface UserService { 8 | // 9 | // Optional getUser(Integer id); 10 | // 11 | // User getUserByName(String name); 12 | // 13 | // User getUserByNameAndPassword(String name, String password); 14 | // 15 | // List getAllUser(); 16 | // 17 | // Boolean addUser(User user); 18 | // 19 | // Boolean updateUser(Integer id, String name, String password); 20 | // 21 | // Boolean deleteUser(Integer id); 22 | // 23 | //} 24 | 25 | public interface UserService { 26 | 27 | List getUserPage(Integer pageNumber, Integer pageSize); 28 | List getUserPageBySort(Integer pageNumber, Integer pageSize); 29 | 30 | User getUserByIdWithQuery(Integer id); 31 | 32 | } 33 | -------------------------------------------------------------------------------- /springboot-jpa/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | spring.datasource.url=jdbc:mysql://localhost:3306/jpa_test?useUnicode=true&characterEncoding=UTF-8 3 | spring.datasource.username=root 4 | spring.datasource.password=zhuqitao123 5 | spring.datasource.driver-class-name=com.mysql.jdbc.Driver 6 | 7 | # jpa配置 8 | spring.jpa.database=mysql 9 | # 自动创建|更新|验证数据库表结构的方式 10 | # 其中update是最常用的属性,首次加载hibernate会根据model自动创建表结构,以后再加载hibernate会根据model自动更新表结构 11 | spring.jpa.hibernate.ddl-auto=update 12 | # 输出所有SQL语句到控制台. 13 | spring.jpa.show-sql=true 14 | 15 | -------------------------------------------------------------------------------- /springboot-jpa/src/test/java/com/love/example/ExampleApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.love.example; 2 | 3 | //import org.junit.jupiter.api.Test; 4 | //import org.springframework.boot.test.context.SpringBootTest; 5 | // 6 | //@SpringBootTest 7 | //class ExampleApplicationTests { 8 | // 9 | // @Test 10 | // void contextLoads() { 11 | // } 12 | // 13 | //} 14 | -------------------------------------------------------------------------------- /springboot-listener-filter-interceptor/README.md: -------------------------------------------------------------------------------- 1 | # Spring Boot 监听器、过滤器、拦截器以及自定义事件配置 2 | 3 | ## 监听器 4 | 监听器是 Servlet 规范中定义的一种特殊类,用于监听 ServletContext、HttpSession 5 | 和 ServletRequest 等域对象的创建与销毁事件,以及监听这些域对象中属性发生修改的事件。 6 | 监听器具有异步的特性。 7 | - ServletContext: 应用于整个应用,一个应用只有一个ServletContext 8 | - HttpSession: 针对每一个会话,可用于统计会话和在线用户数 9 | - ServletRequest: 针对具体某个请求 10 | #### 实现监听器 11 | spring boot 配置监听器有两种方式,一种是使用@WebListener和@ServletComponentScan注解扫描方式,另一种是借助spring boot 提供的ServletListenerRegistrationBean方法注册。 12 | 13 | 下面以ServletRequest为例实现一个请求监听器 14 | ##### 方式一:@WebListener和@ServletComponentScan注解扫描 15 | 创建MyListener 16 | ``` 17 | @WebListener 18 | public class MyListener implements ServletRequestListener { 19 | @Override 20 | public void requestDestroyed(ServletRequestEvent sre) { 21 | System.out.println("ServletRequestEvent 销毁"); 22 | } 23 | 24 | @Override 25 | public void requestInitialized(ServletRequestEvent sre) { 26 | System.out.println("ServletRequestEvent init"); 27 | } 28 | } 29 | ``` 30 | 在启动类中添加@ServletComponentScan注解 31 | ``` 32 | @SpringBootApplication 33 | @ServletComponentScan 34 | public class ExampleApplication { 35 | 36 | public static void main(String[] args) { 37 | SpringApplication.run(ExampleApplication.class, args); 38 | } 39 | } 40 | ``` 41 | 在启动类添加@ServletComponentScan,spring boot会自动扫描所有使用@WebListener声明的监听器并注册到应用中。 42 | 43 | ##### 方式二:使用ServletListenerRegistrationBean方法注册 44 | 启动类去除@ServletComponentScan注解 45 | 在Config目录创建配置文件ListenerConfig 46 | ``` 47 | @Configuration 48 | public class ListenerConfig { 49 | @Bean 50 | public ServletListenerRegistrationBean myListenerServletListenerRegistrationBean() { 51 | ServletListenerRegistrationBean bean = new ServletListenerRegistrationBean<>(new MyListener()); 52 | return bean; 53 | } 54 | } 55 | ``` 56 | 57 | ## 过滤器 58 | 过滤器在Listener之后以及请求到达servlet之前执行,过滤器可以在请求到达服务器之前,对请求进行预先处理,在响应内容到达客户端之前,对服务器做出的响应进行后置处理。通过过滤器,读取请求携带的cookie判断用户是否登录等。 59 | 60 | #### 过滤器种类 61 | Servlet 3.1 提供的几种常见的过滤器组件: 62 | - 身份验证过滤器:Authentication filters 63 | - 数据压缩过滤器:Data compression Filters 64 | - 加密过滤器:Encryption Filters 65 | - 图片转换过滤器:Image conversion filters 66 | - 日志和安全审计过滤器:Logging and auditing filters 67 | - 词法类过滤器:Tokenizing filters 68 | - 触发资源访问事件过滤器:Filters that trigger resource access events 69 | - XML文件转换过滤器:XSL/T filters that transform XML content 70 | - 缓存类过滤器:Caching filters 71 | - MIME-TYPE 链过滤器:MIME-TYPE Chain Filters 72 | 73 | #### 实现过滤器 74 | 实现过滤器也有两种方式,一种是使用@WebFilter和@ServletComponentScan注解扫描,另一种是借助spring boot 提供的FilterRegistrationBean方法注册。 75 | 76 | ##### 方式一:@WebFilter和@ServletComponentScan注解扫描 77 | 使用@WebFilter这种方式,当有多个过滤器时,可以使用@Order注解指定过滤器优先级来确定他们的执行顺序。 78 | @Order(x) x的值越小,优先级越高,优先执行。 79 | > @Order有时好使有时不好使,如果希望正确的指定过滤器的执行顺序,可以使用第二种方式 80 | 81 | 创建MyFilter1 82 | ``` 83 | @Order(1) 84 | @WebFilter(filterName = "MyFilter1", urlPatterns = {"/*"}) 85 | public class MyFilter1 implements Filter { 86 | @Override 87 | public void init(FilterConfig filterConfig) throws ServletException { 88 | System.out.println("MyFilter1 init"); 89 | } 90 | 91 | @Override 92 | public void destroy() { 93 | System.out.println("MyFilter1 destroy"); 94 | } 95 | 96 | @Override 97 | public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException { 98 | // 在请求到达servlet之前对request、response做一些预处理 比如设置请求编码 99 | System.out.println("MyFilter1 doFilter"); 100 | // 传给下一个过滤器进行处理,如果该过滤器是最后一个过滤器,则直接交给servlet处理 101 | filterChain.doFilter(request, response); 102 | } 103 | } 104 | ``` 105 | 创建MyFilter2 106 | ``` 107 | @Order(2) 108 | @WebFilter(filterName = "MyFilter2", urlPatterns = {"/hello"}) 109 | public class MyFilter2 implements Filter { 110 | @Override 111 | public void init(FilterConfig filterConfig) throws ServletException { 112 | System.out.println("MyFilter2 init"); 113 | } 114 | 115 | @Override 116 | public void destroy() { 117 | System.out.println("MyFilter2 destroy"); 118 | } 119 | 120 | @Override 121 | public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException { 122 | // 在请求到达servlet之前对request、response做一些预处理 比如设置请求编码 123 | System.out.println("MyFilter2 doFilter"); 124 | // 传给下一个过滤器进行处理,如果该过滤器是最后一个过滤器,则直接交给servlet处理 125 | filterChain.doFilter(request, response); 126 | } 127 | } 128 | ``` 129 | 启动类添加@ServletComponentScan注解 130 | ``` 131 | @SpringBootApplication 132 | @ServletComponentScan 133 | public class ExampleApplication { 134 | 135 | public static void main(String[] args) { 136 | SpringApplication.run(ExampleApplication.class, args); 137 | } 138 | } 139 | ``` 140 | 141 | ##### 方式二:使用FilterRegistrationBean方法注册 142 | 启动类去除@ServletComponentScan注解 143 | 在Config目录创建FilterConfig 144 | ``` 145 | @Configuration 146 | public class FilterConfig { 147 | @Bean 148 | public FilterRegistrationBean filterRegistrationBean1() { 149 | FilterRegistrationBean registrationBean = new FilterRegistrationBean(); 150 | registrationBean.setFilter(new MyFilter1()); 151 | registrationBean.setName("MyFilter1"); 152 | registrationBean.addUrlPatterns("/*"); 153 | registrationBean.setOrder(2); 154 | 155 | return registrationBean; 156 | } 157 | 158 | @Bean 159 | public FilterRegistrationBean filterRegistrationBean2() { 160 | FilterRegistrationBean registrationBean = new FilterRegistrationBean(); 161 | registrationBean.setFilter(new MyFilter2()); 162 | registrationBean.setName("MyFilter2"); 163 | registrationBean.addUrlPatterns("/hello"); 164 | registrationBean.setOrder(1); 165 | 166 | return registrationBean; 167 | } 168 | } 169 | ``` 170 | 171 | ## 拦截器 172 | 拦截器(HandlerInterceptor)不是Servlet提供的,而是spring提供的一种基于Java的反射机制进行实现的,它是面向切面编程(AOP)的一种应用,触发时机在请求离开过滤器之后和到达servlet之前,处于过滤器和servlet之间,常用场景:日志记录、计算PV、权限检查、性能监控等。 173 | 174 | #### 实现拦截器 175 | 创建MyInterceptor 176 | ``` 177 | public class MyInterceptor implements HandlerInterceptor { 178 | @Override 179 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { 180 | // 在请求到达controller之前调用 181 | System.out.println("请求之前preHandle"); 182 | // 如果返回false,则会中断执行,不会进入到postHandle和afterCompletion 183 | return true; 184 | } 185 | 186 | @Override 187 | public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { 188 | // 在Controller方法处理完之后DispatcherServlet进行视图的渲染之前,在这里可以对ModelAndView进行操作 189 | System.out.println("请求之后postHandle"); 190 | } 191 | 192 | @Override 193 | public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { 194 | // DispatcherServlet进行视图的渲染之后的回调方法,一般用于资源清理 195 | System.out.println("进行视图的渲染之后回调afterCompletion"); 196 | } 197 | } 198 | ``` 199 | 在Config目录创建InterceptorConfig实现WebMvcConfigurer接口完成拦截器的注册 200 | ``` 201 | @Configuration 202 | public class InterceptorConfig implements WebMvcConfigurer { 203 | MyInterceptor myInterceptor = new MyInterceptor(); 204 | 205 | @Override 206 | public void addInterceptors(InterceptorRegistry registry) { 207 | registry.addInterceptor(myInterceptor).addPathPatterns("/*"); 208 | } 209 | } 210 | ``` 211 | 212 | ## 自定义事件 213 | 实现一个自定义事件,需要三部分 214 | - ApplicationEvent:继承ApplicationEvent编写构造函数实现一个自定义事件 215 | - ApplicationListener:实现ApplicationListener接口onApplicationEvent方法对事件进行监听 216 | - ApplicationEventPublisher:使用ApplicationEventPublisher提供的publishEvent方法发布事件 217 | 218 | #### 实现自定义事件 219 | 创建自定义事件CustomEvent 220 | ``` 221 | public class CustomEvent extends ApplicationEvent { 222 | public CustomEvent(Object source) { 223 | super(source); 224 | } 225 | } 226 | ``` 227 | 监听自定义事件有四种方式: 228 | - **方式一:使用ConfigurableApplicationContext上下文装载自定义事件** 229 | 230 | 创建CustomListener 231 | ``` 232 | public class CustomListener implements ApplicationListener { 233 | @Override 234 | public void onApplicationEvent(CustomEvent customEvent) { 235 | System.out.println("监听到事件:" + CustomListener.class.getName() + customEvent.getSource()); 236 | } 237 | } 238 | ``` 239 | 240 | 然后在启动类中获取ConfigurableApplicationContext上下文,使用addApplicationListener方法进行自定义事件监听 241 | 242 | ``` 243 | @SpringBootApplication 244 | public class ExampleApplication { 245 | 246 | public static void main(String[] args) { 247 | ConfigurableApplicationContext context = SpringApplication.run(ExampleApplication.class, args); 248 | context.addApplicationListener(new CustomListener()); 249 | } 250 | 251 | } 252 | ``` 253 | 254 | - **方式二:在application.properties配置文件中配置监听** 255 | 256 | 创建CustomListener 257 | ``` 258 | public class CustomListener implements ApplicationListener { 259 | @Override 260 | public void onApplicationEvent(CustomEvent customEvent) { 261 | System.out.println("监听到事件:" + CustomListener.class.getName() + customEvent.getSource()); 262 | } 263 | } 264 | ``` 265 | 在application.properties中添加一下配置 266 | ``` 267 | context.listener.classes=com.love.example.Config.CustomListener 268 | ``` 269 | 270 | - **方式三(推荐):使用@Component注解把ApplicationListener注入到spring容器中** 271 | 272 | 创建CustomListener 273 | ``` 274 | @Component 275 | public class CustomListener implements ApplicationListener { 276 | @Override 277 | public void onApplicationEvent(CustomEvent customEvent) { 278 | System.out.println("监听到事件:" + CustomListener.class.getName() + customEvent.getSource()); 279 | } 280 | } 281 | ``` 282 | 283 | - **方式四(推荐): 使用@EventListener注解,无需实现ApplicationListener接口** 284 | 285 | 创建CustomListener 286 | ``` 287 | @Component 288 | public class CustomListener{ 289 | @EventListener 290 | public void listener(CustomEvent customEvent) { 291 | System.out.println("监听到事件:" + CustomListener.class.getName() + customEvent.getSource()); 292 | } 293 | } 294 | ``` 295 | *注意:这种方式仍然需要@Component注解将ApplicationListener注入到spring容器中* 296 | 297 | ##### 发布自定义事件(触发自定义事件) 298 | 在HelloController添加ApplicationContext.publishEvent方法发布自定义事件 299 | ``` 300 | @RestController 301 | public class HelloController { 302 | @Resource private 303 | ApplicationContext applicationContext; 304 | 305 | @GetMapping("/hello") 306 | public String hello() { 307 | 308 | applicationContext.publishEvent(new CustomEvent("测试自定义事件")); 309 | return "hello"; 310 | } 311 | } 312 | ``` 313 | 314 | #### 具体代码可查看[源码地址](https://github.com/zhuqitao/spring-boot-examples/tree/master/springboot-listener-filter-interceptor),欢迎star -------------------------------------------------------------------------------- /springboot-listener-filter-interceptor/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.1.RELEASE 9 | 10 | 11 | com.love 12 | example 13 | 0.0.1-SNAPSHOT 14 | example 15 | Demo project for Spring Boot 16 | 17 | 18 | 1.8 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-web 25 | 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-test 30 | test 31 | 32 | 33 | org.junit.vintage 34 | junit-vintage-engine 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | org.springframework.boot 44 | spring-boot-maven-plugin 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /springboot-listener-filter-interceptor/src/main/java/com/love/example/Config/CustomListener.java: -------------------------------------------------------------------------------- 1 | package com.love.example.Config; 2 | 3 | import com.love.example.Monitor.CustomEvent; 4 | import org.springframework.context.ApplicationListener; 5 | import org.springframework.context.event.EventListener; 6 | import org.springframework.stereotype.Component; 7 | 8 | //@Component 9 | //public class CustomListener implements ApplicationListener { 10 | // @Override 11 | // public void onApplicationEvent(CustomEvent customEvent) { 12 | // System.out.println("监听到事件:" + CustomListener.class.getName() + customEvent.getSource()); 13 | // } 14 | //} 15 | 16 | /** 17 | * ------------------------------------------------------------------------------------------------------------------- 18 | */ 19 | 20 | @Component 21 | public class CustomListener{ 22 | @EventListener 23 | public void listener(CustomEvent customEvent) { 24 | System.out.println("监听到事件:" + CustomListener.class.getName() + customEvent.getSource()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /springboot-listener-filter-interceptor/src/main/java/com/love/example/Config/FilterConfig.java: -------------------------------------------------------------------------------- 1 | package com.love.example.Config; 2 | 3 | import com.love.example.Monitor.MyFilter1; 4 | import com.love.example.Monitor.MyFilter2; 5 | import org.springframework.boot.web.servlet.FilterRegistrationBean; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | 9 | @Configuration 10 | public class FilterConfig { 11 | @Bean 12 | public FilterRegistrationBean filterRegistrationBean1() { 13 | FilterRegistrationBean registrationBean = new FilterRegistrationBean(); 14 | registrationBean.setFilter(new MyFilter1()); 15 | registrationBean.setName("MyFilter1"); 16 | registrationBean.addUrlPatterns("/*"); 17 | registrationBean.setOrder(2); 18 | 19 | return registrationBean; 20 | } 21 | 22 | @Bean 23 | public FilterRegistrationBean filterRegistrationBean2() { 24 | FilterRegistrationBean registrationBean = new FilterRegistrationBean(); 25 | registrationBean.setFilter(new MyFilter2()); 26 | registrationBean.setName("MyFilter2"); 27 | registrationBean.addUrlPatterns("/hello"); 28 | registrationBean.setOrder(1); 29 | 30 | return registrationBean; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /springboot-listener-filter-interceptor/src/main/java/com/love/example/Config/InterceptorConfig.java: -------------------------------------------------------------------------------- 1 | package com.love.example.Config; 2 | 3 | import com.love.example.Monitor.MyInterceptor; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.web.servlet.config.annotation.InterceptorRegistry; 6 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 7 | 8 | @Configuration 9 | public class InterceptorConfig implements WebMvcConfigurer { 10 | MyInterceptor myInterceptor = new MyInterceptor(); 11 | 12 | @Override 13 | public void addInterceptors(InterceptorRegistry registry) { 14 | registry.addInterceptor(myInterceptor).addPathPatterns("/*"); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /springboot-listener-filter-interceptor/src/main/java/com/love/example/Config/ListenerConfig.java: -------------------------------------------------------------------------------- 1 | package com.love.example.Config; 2 | 3 | import com.love.example.Monitor.MyListener; 4 | import org.springframework.boot.web.servlet.ServletListenerRegistrationBean; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | 8 | @Configuration 9 | public class ListenerConfig { 10 | @Bean 11 | public ServletListenerRegistrationBean myListenerServletListenerRegistrationBean() { 12 | ServletListenerRegistrationBean bean = new ServletListenerRegistrationBean<>(new MyListener()); 13 | return bean; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /springboot-listener-filter-interceptor/src/main/java/com/love/example/Controller/HelloController.java: -------------------------------------------------------------------------------- 1 | package com.love.example.Controller; 2 | 3 | import com.love.example.Monitor.CustomEvent; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.context.ApplicationContext; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.RestController; 8 | 9 | import javax.annotation.Resource; 10 | 11 | @RestController 12 | public class HelloController { 13 | @Resource private 14 | ApplicationContext applicationContext; 15 | 16 | @GetMapping("/hello") 17 | public String hello() { 18 | 19 | applicationContext.publishEvent(new CustomEvent("测试自定义事件")); 20 | return "hello"; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /springboot-listener-filter-interceptor/src/main/java/com/love/example/ExampleApplication.java: -------------------------------------------------------------------------------- 1 | package com.love.example; 2 | 3 | import com.love.example.Config.CustomListener; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.boot.web.servlet.ServletComponentScan; 7 | import org.springframework.context.ConfigurableApplicationContext; 8 | 9 | @SpringBootApplication 10 | //@ServletComponentScan 11 | public class ExampleApplication { 12 | 13 | public static void main(String[] args) { 14 | ConfigurableApplicationContext context = SpringApplication.run(ExampleApplication.class, args); 15 | // context.addApplicationListener(new CustomListener()); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /springboot-listener-filter-interceptor/src/main/java/com/love/example/Monitor/CustomEvent.java: -------------------------------------------------------------------------------- 1 | package com.love.example.Monitor; 2 | 3 | import org.springframework.context.ApplicationEvent; 4 | 5 | public class CustomEvent extends ApplicationEvent { 6 | public CustomEvent(Object source) { 7 | super(source); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /springboot-listener-filter-interceptor/src/main/java/com/love/example/Monitor/MyFilter1.java: -------------------------------------------------------------------------------- 1 | package com.love.example.Monitor; 2 | 3 | import org.springframework.core.annotation.Order; 4 | 5 | import javax.servlet.*; 6 | import javax.servlet.annotation.WebFilter; 7 | import java.io.IOException; 8 | 9 | //@Order(1) 10 | //@WebFilter(filterName = "MyFilter1", urlPatterns = {"/*"}) 11 | public class MyFilter1 implements Filter { 12 | @Override 13 | public void init(FilterConfig filterConfig) throws ServletException { 14 | System.out.println("MyFilter1 init"); 15 | } 16 | 17 | @Override 18 | public void destroy() { 19 | System.out.println("MyFilter1 destroy"); 20 | } 21 | 22 | @Override 23 | public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException { 24 | // 在请求到达servlet之前对request、response做一些预处理 比如设置请求编码 25 | System.out.println("MyFilter1 doFilter"); 26 | // 传给下一个过滤器进行处理,如果该过滤器是最后一个过滤器,则直接交给servlet处理 27 | filterChain.doFilter(request, response); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /springboot-listener-filter-interceptor/src/main/java/com/love/example/Monitor/MyFilter2.java: -------------------------------------------------------------------------------- 1 | package com.love.example.Monitor; 2 | 3 | import org.springframework.core.annotation.Order; 4 | 5 | import javax.servlet.*; 6 | import javax.servlet.annotation.WebFilter; 7 | import java.io.IOException; 8 | 9 | //@Order(2) 10 | //@WebFilter(filterName = "MyFilter2", urlPatterns = {"/hello"}) 11 | public class MyFilter2 implements Filter { 12 | @Override 13 | public void init(FilterConfig filterConfig) throws ServletException { 14 | System.out.println("MyFilter2 init"); 15 | } 16 | 17 | @Override 18 | public void destroy() { 19 | System.out.println("MyFilter2 destroy"); 20 | } 21 | 22 | @Override 23 | public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException { 24 | // 在请求到达servlet之前对request、response做一些预处理 比如设置请求编码 25 | System.out.println("MyFilter2 doFilter"); 26 | // 传给下一个过滤器进行处理,如果该过滤器是最后一个过滤器,则直接交给servlet处理 27 | filterChain.doFilter(request, response); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /springboot-listener-filter-interceptor/src/main/java/com/love/example/Monitor/MyInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.love.example.Monitor; 2 | 3 | import org.springframework.web.servlet.HandlerInterceptor; 4 | import org.springframework.web.servlet.ModelAndView; 5 | 6 | import javax.servlet.http.HttpServletRequest; 7 | import javax.servlet.http.HttpServletResponse; 8 | 9 | public class MyInterceptor implements HandlerInterceptor { 10 | @Override 11 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { 12 | // 在请求到达controller之前调用 13 | System.out.println("请求之前preHandle"); 14 | // 如果返回false,则会中断执行,不会进入到postHandle和afterCompletion 15 | return true; 16 | } 17 | 18 | @Override 19 | public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { 20 | // 在Controller方法处理完之后DispatcherServlet进行视图的渲染之前,在这里可以对ModelAndView进行操作 21 | System.out.println("请求之后postHandle"); 22 | } 23 | 24 | @Override 25 | public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { 26 | // DispatcherServlet进行视图的渲染之后的回调方法,一般用于资源清理 27 | System.out.println("进行视图的渲染之后回调afterCompletion"); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /springboot-listener-filter-interceptor/src/main/java/com/love/example/Monitor/MyListener.java: -------------------------------------------------------------------------------- 1 | package com.love.example.Monitor; 2 | 3 | import javax.servlet.ServletContextEvent; 4 | import javax.servlet.ServletRequestEvent; 5 | import javax.servlet.ServletRequestListener; 6 | import javax.servlet.annotation.WebListener; 7 | 8 | //@WebListener 9 | public class MyListener implements ServletRequestListener { 10 | @Override 11 | public void requestDestroyed(ServletRequestEvent sre) { 12 | System.out.println("ServletRequestEvent 销毁"); 13 | } 14 | 15 | @Override 16 | public void requestInitialized(ServletRequestEvent sre) { 17 | System.out.println("ServletRequestEvent init"); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /springboot-listener-filter-interceptor/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | #context.listener.classes=com.love.example.Config.CustomListener 2 | -------------------------------------------------------------------------------- /springboot-listener-filter-interceptor/src/main/resources/rebel.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /springboot-listener-filter-interceptor/src/test/java/com/love/example/ExampleApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.love.example; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class ExampleApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /springboot-mybatis-druid-jta/README.md: -------------------------------------------------------------------------------- 1 | # SoringBoot、Mybatis、Druid多数据源JTA分布式事务实现 2 | 随着需求不断的增加,业务逐渐的增强,项目越来越复杂,有时候单数据源无法满足我们的开发, 3 | 就需要多个数据源来实现业务需求。本章内容就是搭建一个多数据源分布式事务配置的服务。 4 | 5 | 下面先来弄清楚几个概念。 6 | ### 什么是Druid 7 | 官方原文: 阿里巴巴数据库事业部出品,为监控而生的数据库连接池。Druid是Java语言中最好的数据库连接池。Druid能够提供强大的监控和扩展功能。 8 | 9 | [Druid官方github地址](https://github.com/alibaba/druid) 10 | 11 | ### 为什么需要分布式事务 12 | Java事务API(Java Transaction API,简称JTA ) 是一个Java企业版 的应用程序接口,在Java环境中,允许完成跨越多个XA资源的分布式事务。JTA是在Java社区过程下制定的规范,编号JSR 907。 13 | 14 | 与JDBC的区别,通俗的讲,JTA是多库的事务 JDBC是单库的事务,也就是说JTA可以管理多个数据源。 15 | 16 | 比如一个货物管理的项目连接了两个数据源,一个用来管理出售订单source1,一个用来管理库存余量source2, 17 | 客户下单就要在管理出售订单的库中添加一条订单数据,同时也要设置管理库存余量的库,正常来讲, 18 | 这两个操作要么一起成功,要么一起失败,假如现在下单成功了,但是在修改库存余量时发生了错误未能成功修改数据源, 19 | 就需要管理出售订单的数据源回滚,而正好JTA可以帮我们管理这些数据源。 20 | 21 | ### 开始配置 22 | #### 创建两个数据库 23 | 创建两个数据库test1、test2 24 | #### 添加依赖 25 | ```xml 26 | 27 | mysql 28 | mysql-connector-java 29 | 5.1.46 30 | 31 | 32 | com.alibaba 33 | druid-spring-boot-starter 34 | 1.1.10 35 | 36 | ``` 37 | **注意** 38 | mysql-connector-java使用的是5.1.46版本,JTA暂时不支持Mysql8 39 | 40 | #### application.yml多数据源配置 41 | ```yaml 42 | datasource: 43 | druid: 44 | first: 45 | unique-resource-name: firstDataSource 46 | xa-data-source-class-name: com.alibaba.druid.pool.xa.DruidXADataSource 47 | driver-class-name: com.mysql.jdbc.Driver 48 | # 连接池配置 49 | initial-size: 5 50 | min-idle: 5 51 | max-active: 20 52 | # 连接等待超时时间 53 | max-wait: 30000 54 | # 配置检测可以关闭的空闲连接间隔时间 55 | time-between-eviction-runs-millis: 60000 56 | # 配置连接在池中的最小生存时间 57 | min-evictable-idle-time-millis: 300000 58 | validation-query: select '1' from dual 59 | test-while-idle: true 60 | test-on-borrow: false 61 | test-on-return: false 62 | # 打开PSCache,并且指定每个连接上PSCache的大小 63 | pool-prepared-statements: true 64 | max-open-prepared-statements: 20 65 | max-pool-prepared-statement-per-connection-size: 20 66 | # 配置监控统计拦截的filters, 去掉后监控界面sql无法统计, 'wall'用于防火墙 67 | filters: stat,wall 68 | aop-patterns: com.springboot.servie.* 69 | xa-properties: 70 | url: jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=UTF-8&useSSL=false 71 | username: root 72 | password: zhuqitao123 73 | second: 74 | unique-resource-name: secondDataSource 75 | xa-data-source-class-name: com.alibaba.druid.pool.xa.DruidXADataSource 76 | driver-class-name: com.mysql.jdbc.Driver 77 | # 连接池配置 78 | initial-size: 5 79 | min-idle: 5 80 | max-active: 20 81 | # 连接等待超时时间 82 | max-wait: 30000 83 | # 配置检测可以关闭的空闲连接间隔时间 84 | time-between-eviction-runs-millis: 60000 85 | # 配置连接在池中的最小生存时间 86 | min-evictable-idle-time-millis: 300000 87 | validation-query: select '1' from dual 88 | test-while-idle: true 89 | test-on-borrow: false 90 | test-on-return: false 91 | # 打开PSCache,并且指定每个连接上PSCache的大小 92 | pool-prepared-statements: true 93 | max-open-prepared-statements: 20 94 | max-pool-prepared-statement-per-connection-size: 20 95 | # 配置监控统计拦截的filters, 去掉后监控界面sql无法统计, 'wall'用于防火墙 96 | filters: stat,wall 97 | # Spring监控AOP切入点,如x.y.z.service.*,配置多个英文逗号分隔 98 | aop-patterns: com.springboot.servie.* 99 | xa-properties: 100 | url: jdbc:mysql://localhost:3306/test2?useUnicode=true&characterEncoding=UTF-8&useSSL=false 101 | username: root 102 | password: zhuqitao123 103 | ``` 104 | 105 | 106 | #### 数据源配置类 107 | FirstDataSourceConfig: 108 | 多个数据源需要指定主数据源,使用@Primary注解指定主数据源。 109 | ```java 110 | package com.love.example.Config; 111 | 112 | import com.alibaba.druid.support.http.StatViewServlet; 113 | import com.atomikos.jdbc.AtomikosDataSourceBean; 114 | import org.apache.ibatis.session.SqlSessionFactory; 115 | import org.mybatis.spring.SqlSessionFactoryBean; 116 | import org.mybatis.spring.SqlSessionTemplate; 117 | import org.mybatis.spring.annotation.MapperScan; 118 | import org.springframework.beans.factory.annotation.Qualifier; 119 | import org.springframework.boot.context.properties.ConfigurationProperties; 120 | import org.springframework.boot.web.servlet.ServletRegistrationBean; 121 | import org.springframework.context.annotation.Bean; 122 | import org.springframework.context.annotation.Configuration; 123 | import org.springframework.context.annotation.Primary; 124 | import org.springframework.core.env.Environment; 125 | import org.springframework.core.io.support.PathMatchingResourcePatternResolver; 126 | import org.springframework.core.io.support.ResourcePatternResolver; 127 | import org.springframework.jdbc.datasource.DataSourceTransactionManager; 128 | 129 | import javax.sql.DataSource; 130 | 131 | @Configuration 132 | @MapperScan(basePackages = "com.love.example.mapper.first", sqlSessionTemplateRef="firstSqlSessionTemplate") 133 | public class FirstDataSourceConfig { 134 | @Bean(name = "firstDataSource") 135 | @Primary 136 | @ConfigurationProperties(prefix = "spring.datasource.druid.first") 137 | public DataSource firstDataSource(Environment env) { 138 | return new AtomikosDataSourceBean(); 139 | } 140 | 141 | @Bean(name = "firstTransactionManager") 142 | @Primary 143 | public DataSourceTransactionManager firstTransactionManager(@Qualifier("firstDataSource") DataSource dataSource) { 144 | return new DataSourceTransactionManager(dataSource); 145 | } 146 | 147 | @Bean(name = "firstSqlSessionFactory") 148 | @Primary 149 | public SqlSessionFactory firstSqlSessionFactory(@Qualifier("firstDataSource") DataSource dataSource) throws Exception{ 150 | SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean(); 151 | sessionFactory.setDataSource(dataSource); 152 | ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); 153 | sessionFactory.setMapperLocations(resolver.getResources("classpath:mybatis/mapper/first/*.xml")); 154 | return sessionFactory.getObject(); 155 | } 156 | 157 | @Bean(name = "firstSqlSessionTemplate") 158 | @Primary 159 | public SqlSessionTemplate firstSqlSessionTemplate(@Qualifier("firstSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception { 160 | return new SqlSessionTemplate(sqlSessionFactory); 161 | } 162 | 163 | @Bean 164 | @Primary 165 | public ServletRegistrationBean druidServlet() { 166 | ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*"); 167 | 168 | //控制台管理用户,进入druid后台(localhost:{port}/druid)需要登录 169 | servletRegistrationBean.addInitParameter("loginUsername", "admin"); 170 | servletRegistrationBean.addInitParameter("loginPassword", "admin"); 171 | return servletRegistrationBean; 172 | } 173 | 174 | } 175 | ``` 176 | 177 | SecondDataSourceConfig: 178 | ```java 179 | package com.love.example.Config; 180 | 181 | import com.atomikos.jdbc.AtomikosDataSourceBean; 182 | import org.apache.ibatis.session.SqlSessionFactory; 183 | import org.mybatis.spring.SqlSessionFactoryBean; 184 | import org.mybatis.spring.SqlSessionTemplate; 185 | import org.mybatis.spring.annotation.MapperScan; 186 | import org.springframework.beans.factory.annotation.Qualifier; 187 | import org.springframework.boot.context.properties.ConfigurationProperties; 188 | import org.springframework.context.annotation.Bean; 189 | import org.springframework.context.annotation.Configuration; 190 | import org.springframework.core.io.support.PathMatchingResourcePatternResolver; 191 | import org.springframework.core.io.support.ResourcePatternResolver; 192 | import org.springframework.jdbc.datasource.DataSourceTransactionManager; 193 | import javax.sql.DataSource; 194 | 195 | @Configuration 196 | @MapperScan(basePackages = "com.love.example.mapper.second", sqlSessionTemplateRef="secondSqlSessionTemplate") 197 | public class SecondDataSourceConfig { 198 | @Bean(name = "secondDataSource") 199 | @ConfigurationProperties(prefix = "spring.datasource.druid.second") 200 | public DataSource firstDataSource() { 201 | return new AtomikosDataSourceBean(); 202 | } 203 | 204 | @Bean(name = "secondTransactionManager") 205 | public DataSourceTransactionManager secondTransactionManager(@Qualifier("secondDataSource") DataSource dataSource) { 206 | return new DataSourceTransactionManager(dataSource); 207 | } 208 | 209 | @Bean(name = "secondSqlSessionFactory") 210 | public SqlSessionFactory secondSqlSessionFactory(@Qualifier("secondDataSource") DataSource dataSource) throws Exception{ 211 | SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean(); 212 | sessionFactory.setDataSource(dataSource); 213 | ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); 214 | sessionFactory.setMapperLocations(resolver.getResources("classpath:mybatis/mapper/second/*.xml")); 215 | return sessionFactory.getObject(); 216 | } 217 | 218 | @Bean(name = "secondSqlSessionTemplate") 219 | public SqlSessionTemplate firstSqlSessionTemplate(@Qualifier("secondSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception{ 220 | return new SqlSessionTemplate(sqlSessionFactory); 221 | } 222 | } 223 | ``` 224 | 225 | #### 事务管理配置 226 | 227 | TransactionManagerConfig: 228 | ```java 229 | package com.love.example.Config; 230 | 231 | import org.springframework.context.annotation.Bean; 232 | import com.atomikos.icatch.jta.UserTransactionImp; 233 | import com.atomikos.icatch.jta.UserTransactionManager; 234 | import org.springframework.context.annotation.Configuration; 235 | import org.springframework.context.annotation.DependsOn; 236 | import org.springframework.transaction.PlatformTransactionManager; 237 | import org.springframework.transaction.jta.JtaTransactionManager; 238 | import javax.transaction.TransactionManager; 239 | import javax.transaction.UserTransaction; 240 | 241 | @Configuration 242 | public class TransactionManagerConfig { 243 | @Bean 244 | public UserTransaction userTransaction() throws Throwable { 245 | UserTransactionImp userTransactionImp = new UserTransactionImp(); 246 | userTransactionImp.setTransactionTimeout(10000); 247 | return userTransactionImp; 248 | } 249 | 250 | @Bean 251 | public TransactionManager atomikosTransactionManager() throws Throwable { 252 | UserTransactionManager userTransactionManager = new UserTransactionManager(); 253 | userTransactionManager.setForceShutdown(false); 254 | return userTransactionManager; 255 | } 256 | 257 | @Bean(name = "transactionManager") 258 | @DependsOn({ "userTransaction", "atomikosTransactionManager" }) 259 | public PlatformTransactionManager transactionManager() throws Throwable { 260 | JtaTransactionManager manager = new JtaTransactionManager(userTransaction(), atomikosTransactionManager()); 261 | return manager; 262 | } 263 | } 264 | 265 | ``` 266 | 267 | #### 创建model 268 | Model实体类 269 | 270 | User: 271 | ```java 272 | package com.love.example.model; 273 | 274 | public class User { 275 | private Long id; 276 | private String userName; 277 | private String passWord; 278 | 279 | public User(){ 280 | super(); 281 | } 282 | public User(String userName, String passWord) { 283 | this.userName = userName; 284 | this.passWord = passWord; 285 | } 286 | 287 | public Long getId() { 288 | return id; 289 | } 290 | 291 | public void setId(Long id) { 292 | this.id = id; 293 | } 294 | 295 | public String getUserName() { 296 | return userName; 297 | } 298 | 299 | public void setUserName(String userName) { 300 | this.userName = userName; 301 | } 302 | 303 | public String getPassword() { 304 | return passWord; 305 | } 306 | 307 | public void setPassword(String password) { 308 | this.passWord = password; 309 | } 310 | 311 | @Override 312 | public String toString() { 313 | return "User{" + 314 | "id=" + id + 315 | ", userName='" + userName + '\'' + 316 | ", password='" + passWord + '\'' + 317 | '}'; 318 | } 319 | } 320 | ``` 321 | 322 | #### 分别在不同的目录下创建mapper及SQL映射xml文件 323 | firstMapper: 324 | ```java 325 | package com.love.example.mapper.first; 326 | 327 | import com.love.example.model.User; 328 | import org.apache.ibatis.annotations.Mapper; 329 | import org.springframework.stereotype.Component; 330 | 331 | @Component 332 | @Mapper 333 | public interface FirstMapper { 334 | User getUser(Long id); 335 | int addUser(User user); 336 | } 337 | ``` 338 | 创建firstMapper的SQL映射xml文件,注意namespace指向FirstMapper 339 | 340 | firstMapper.xml: 341 | ```xml 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | id, user_name, password 353 | 354 | 355 | 361 | 362 | 363 | INSERT INTO 364 | users 365 | (user_name,password) 366 | VALUES 367 | (#{userName}, #{passWord}) 368 | 369 | 370 | 371 | ``` 372 | 373 | secondMapper 374 | ```java 375 | package com.love.example.mapper.second; 376 | 377 | import com.love.example.model.User; 378 | import org.apache.ibatis.annotations.Mapper; 379 | import org.springframework.stereotype.Component; 380 | 381 | @Component 382 | @Mapper 383 | public interface SecondMapper { 384 | User getUser(Long id); 385 | int addUser(User user); 386 | } 387 | ``` 388 | 389 | 创建secondMapper的SQL映射xml文件,注意namespace指向SecondMapper 390 | 391 | secondMapper.xml: 392 | ```xml 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | id, user_name, password 404 | 405 | 406 | 412 | 413 | 414 | INSERT INTO 415 | users 416 | (user_name,password) 417 | VALUES 418 | (#{userName}, #{passWord}) 419 | 420 | 421 | 422 | ``` 423 | 424 | #### Service层测试 425 | 定义service接口 426 | 427 | UserService: 428 | ```java 429 | package com.love.example.Service; 430 | 431 | import com.love.example.model.User; 432 | 433 | public interface UserService { 434 | User getFirstUser(Long id); 435 | void addFirstUser(User user); 436 | User getSecondUser(Long id); 437 | void addSecondUser(User user); 438 | 439 | void addAllUser(User user); 440 | } 441 | ``` 442 | service接口实现类 443 | 444 | UserServiceTemplate: 445 | ```java 446 | package com.love.example.Service.template; 447 | 448 | import com.love.example.Service.UserService; 449 | import com.love.example.mapper.first.FirstMapper; 450 | import com.love.example.mapper.second.SecondMapper; 451 | import com.love.example.model.User; 452 | import org.springframework.beans.factory.annotation.Autowired; 453 | import org.springframework.stereotype.Service; 454 | import org.springframework.transaction.annotation.Transactional; 455 | 456 | @Service("UserService") 457 | @Transactional("transactionManager") 458 | public class UserServiceTemplate implements UserService { 459 | @Autowired 460 | private FirstMapper firstMapper; 461 | 462 | @Autowired 463 | private SecondMapper secondMapper; 464 | 465 | @Override 466 | public User getFirstUser(Long id) { 467 | return this.firstMapper.getUser(id); 468 | } 469 | 470 | @Override 471 | public void addFirstUser(User user) { 472 | this.firstMapper.addUser(user); 473 | } 474 | 475 | @Override 476 | public User getSecondUser(Long id) { 477 | return this.secondMapper.getUser(id); 478 | } 479 | 480 | @Override 481 | public void addSecondUser(User user) { 482 | this.secondMapper.addUser(user); 483 | } 484 | 485 | @Override 486 | public void addAllUser(User user) { 487 | this.firstMapper.addUser(user); 488 | // 创造错误 489 | int a = 2/0; 490 | this.secondMapper.addUser(user); 491 | } 492 | } 493 | 494 | ``` 495 | UserServiceTemplate使用@Transactional("transactionManager")注入分布式事务管理。 496 | 497 | 注意在addAllUser方法中添加了一行"int a = 2/0;"用来模拟开发中异常现象。 498 | 499 | 如果在UserServiceTemplate中使用了@Transactional("transactionManager") 500 | 注入分布式管理器,调用addAllUser方法时,两个数据库都不会插入数据,如果去除@Transactional("transactionManager"), 501 | 再调用addAllUser方法时,会发现first库成功插入了数据,second没有插入数据。 502 | 503 | 504 | #### 编写Controller 505 | 506 | UserController: 507 | ```java 508 | package com.love.example.Controller; 509 | 510 | import com.love.example.Service.UserService; 511 | import com.love.example.model.User; 512 | import org.springframework.beans.factory.annotation.Autowired; 513 | import org.springframework.web.bind.annotation.GetMapping; 514 | import org.springframework.web.bind.annotation.RestController; 515 | 516 | @RestController 517 | public class UserController { 518 | @Autowired 519 | private UserService userService; 520 | 521 | @GetMapping("/getfirstuser") 522 | public User getFirstUser(Long id) { 523 | return this.userService.getFirstUser(id); 524 | } 525 | @GetMapping("/addfirstuser") 526 | public String addFirstUser(String userName, String password) { 527 | User user = new User(userName, password); 528 | this.userService.addFirstUser(user); 529 | return "true"; 530 | } 531 | 532 | @GetMapping("/getseconduser") 533 | public User getSecondUser(Long id) { 534 | return this.userService.getSecondUser(id); 535 | } 536 | @GetMapping("/addseconduser") 537 | public String addSecondUser(String userName, String password) { 538 | User user = new User(userName, password); 539 | this.userService.addSecondUser(user); 540 | return "true"; 541 | } 542 | 543 | @GetMapping("/addalluser") 544 | public String addAllUser(String userName, String password) { 545 | User user = new User(userName, password); 546 | this.userService.addAllUser(user); 547 | return "true"; 548 | } 549 | 550 | } 551 | ``` 552 | 553 | #### 测试 554 | 到此就完成了配置,启动项目,在浏览器访问[http://localhost:8083/addalluser?userName=test_name&password=123456](http://localhost:8083/addalluser?userName=test_name&password=123456), 555 | 会抛出异常,查看数据库会发现test1库和test2库两个数据源都没有插入数据,如果在UserServiceTemplate中去除@Transactional("transactionManager"), 556 | 刷新浏览器重新发出请求,同样会抛出异常,查看两个数据源first库成功插入了数据,second库没有插入数据。 557 | 558 | 如果出现上述效果,说明配置成功了。 559 | 560 | ##### 具体代码可查看[源码地址](https://github.com/zhuqitao/spring-boot-examples/tree/master/springboot-mybatis-druid-jta),欢迎star -------------------------------------------------------------------------------- /springboot-mybatis-druid-jta/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.1.RELEASE 9 | 10 | 11 | com.love 12 | example 13 | 0.0.1-SNAPSHOT 14 | example 15 | Demo project for Spring Boot 16 | 17 | 18 | 1.8 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-web 25 | 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-test 30 | test 31 | 32 | 33 | org.junit.vintage 34 | junit-vintage-engine 35 | 36 | 37 | 38 | 39 | org.mybatis 40 | mybatis 41 | 3.5.0 42 | 43 | 44 | org.xmlunit 45 | xmlunit-core 46 | 47 | 48 | 49 | org.mybatis.spring.boot 50 | mybatis-spring-boot-starter 51 | 1.3.1 52 | 53 | 54 | mysql 55 | mysql-connector-java 56 | 5.1.46 57 | 58 | 59 | com.alibaba 60 | druid-spring-boot-starter 61 | 1.1.10 62 | 63 | 64 | com.atomikos 65 | transactions-jdbc 66 | 4.0.6 67 | 68 | 69 | javax.transaction 70 | javax.transaction-api 71 | 1.2 72 | 73 | 74 | 75 | 76 | 77 | 78 | org.springframework.boot 79 | spring-boot-maven-plugin 80 | 81 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /springboot-mybatis-druid-jta/src/main/java/com/love/example/Config/FirstDataSourceConfig.java: -------------------------------------------------------------------------------- 1 | package com.love.example.Config; 2 | 3 | import com.alibaba.druid.support.http.StatViewServlet; 4 | import com.atomikos.jdbc.AtomikosDataSourceBean; 5 | import org.apache.ibatis.session.SqlSessionFactory; 6 | import org.mybatis.spring.SqlSessionFactoryBean; 7 | import org.mybatis.spring.SqlSessionTemplate; 8 | import org.mybatis.spring.annotation.MapperScan; 9 | import org.springframework.beans.factory.annotation.Qualifier; 10 | import org.springframework.boot.context.properties.ConfigurationProperties; 11 | import org.springframework.boot.web.servlet.ServletRegistrationBean; 12 | import org.springframework.context.annotation.Bean; 13 | import org.springframework.context.annotation.Configuration; 14 | import org.springframework.context.annotation.Primary; 15 | import org.springframework.core.env.Environment; 16 | import org.springframework.core.io.support.PathMatchingResourcePatternResolver; 17 | import org.springframework.core.io.support.ResourcePatternResolver; 18 | import org.springframework.jdbc.datasource.DataSourceTransactionManager; 19 | 20 | import javax.sql.DataSource; 21 | 22 | @Configuration 23 | @MapperScan(basePackages = "com.love.example.mapper.first", sqlSessionTemplateRef="firstSqlSessionTemplate") 24 | public class FirstDataSourceConfig { 25 | @Bean(name = "firstDataSource") 26 | @Primary 27 | @ConfigurationProperties(prefix = "spring.datasource.druid.first") 28 | public DataSource firstDataSource(Environment env) { 29 | return new AtomikosDataSourceBean(); 30 | } 31 | 32 | @Bean(name = "firstTransactionManager") 33 | @Primary 34 | public DataSourceTransactionManager firstTransactionManager(@Qualifier("firstDataSource") DataSource dataSource) { 35 | return new DataSourceTransactionManager(dataSource); 36 | } 37 | 38 | @Bean(name = "firstSqlSessionFactory") 39 | @Primary 40 | public SqlSessionFactory firstSqlSessionFactory(@Qualifier("firstDataSource") DataSource dataSource) throws Exception{ 41 | SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean(); 42 | sessionFactory.setDataSource(dataSource); 43 | ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); 44 | sessionFactory.setMapperLocations(resolver.getResources("classpath:mybatis/mapper/first/*.xml")); 45 | return sessionFactory.getObject(); 46 | } 47 | 48 | @Bean(name = "firstSqlSessionTemplate") 49 | @Primary 50 | public SqlSessionTemplate firstSqlSessionTemplate(@Qualifier("firstSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception { 51 | return new SqlSessionTemplate(sqlSessionFactory); 52 | } 53 | 54 | @Bean 55 | @Primary 56 | public ServletRegistrationBean druidServlet() { 57 | ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*"); 58 | 59 | //控制台管理用户,进入druid后台(localhost:{port}/druid)需要登录 60 | servletRegistrationBean.addInitParameter("loginUsername", "admin"); 61 | servletRegistrationBean.addInitParameter("loginPassword", "admin"); 62 | return servletRegistrationBean; 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /springboot-mybatis-druid-jta/src/main/java/com/love/example/Config/SecondDataSourceConfig.java: -------------------------------------------------------------------------------- 1 | package com.love.example.Config; 2 | 3 | import com.atomikos.jdbc.AtomikosDataSourceBean; 4 | import org.apache.ibatis.session.SqlSessionFactory; 5 | import org.mybatis.spring.SqlSessionFactoryBean; 6 | import org.mybatis.spring.SqlSessionTemplate; 7 | import org.mybatis.spring.annotation.MapperScan; 8 | import org.springframework.beans.factory.annotation.Qualifier; 9 | import org.springframework.boot.context.properties.ConfigurationProperties; 10 | import org.springframework.context.annotation.Bean; 11 | import org.springframework.context.annotation.Configuration; 12 | import org.springframework.core.io.support.PathMatchingResourcePatternResolver; 13 | import org.springframework.core.io.support.ResourcePatternResolver; 14 | import org.springframework.jdbc.datasource.DataSourceTransactionManager; 15 | import javax.sql.DataSource; 16 | 17 | @Configuration 18 | @MapperScan(basePackages = "com.love.example.mapper.second", sqlSessionTemplateRef="secondSqlSessionTemplate") 19 | public class SecondDataSourceConfig { 20 | @Bean(name = "secondDataSource") 21 | @ConfigurationProperties(prefix = "spring.datasource.druid.second") 22 | public DataSource firstDataSource() { 23 | return new AtomikosDataSourceBean(); 24 | } 25 | 26 | @Bean(name = "secondTransactionManager") 27 | public DataSourceTransactionManager secondTransactionManager(@Qualifier("secondDataSource") DataSource dataSource) { 28 | return new DataSourceTransactionManager(dataSource); 29 | } 30 | 31 | @Bean(name = "secondSqlSessionFactory") 32 | public SqlSessionFactory secondSqlSessionFactory(@Qualifier("secondDataSource") DataSource dataSource) throws Exception{ 33 | SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean(); 34 | sessionFactory.setDataSource(dataSource); 35 | ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); 36 | sessionFactory.setMapperLocations(resolver.getResources("classpath:mybatis/mapper/second/*.xml")); 37 | return sessionFactory.getObject(); 38 | } 39 | 40 | @Bean(name = "secondSqlSessionTemplate") 41 | public SqlSessionTemplate firstSqlSessionTemplate(@Qualifier("secondSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception{ 42 | return new SqlSessionTemplate(sqlSessionFactory); 43 | } 44 | } 45 | 46 | -------------------------------------------------------------------------------- /springboot-mybatis-druid-jta/src/main/java/com/love/example/Config/TransactionManagerConfig.java: -------------------------------------------------------------------------------- 1 | package com.love.example.Config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import com.atomikos.icatch.jta.UserTransactionImp; 5 | import com.atomikos.icatch.jta.UserTransactionManager; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.context.annotation.DependsOn; 8 | import org.springframework.transaction.PlatformTransactionManager; 9 | import org.springframework.transaction.jta.JtaTransactionManager; 10 | import javax.transaction.TransactionManager; 11 | import javax.transaction.UserTransaction; 12 | 13 | @Configuration 14 | public class TransactionManagerConfig { 15 | @Bean 16 | public UserTransaction userTransaction() throws Throwable { 17 | UserTransactionImp userTransactionImp = new UserTransactionImp(); 18 | userTransactionImp.setTransactionTimeout(10000); 19 | return userTransactionImp; 20 | } 21 | 22 | @Bean 23 | public TransactionManager atomikosTransactionManager() throws Throwable { 24 | UserTransactionManager userTransactionManager = new UserTransactionManager(); 25 | userTransactionManager.setForceShutdown(false); 26 | return userTransactionManager; 27 | } 28 | 29 | @Bean(name = "transactionManager") 30 | @DependsOn({ "userTransaction", "atomikosTransactionManager" }) 31 | public PlatformTransactionManager transactionManager() throws Throwable { 32 | JtaTransactionManager manager = new JtaTransactionManager(userTransaction(), atomikosTransactionManager()); 33 | return manager; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /springboot-mybatis-druid-jta/src/main/java/com/love/example/Controller/UserController.java: -------------------------------------------------------------------------------- 1 | package com.love.example.Controller; 2 | 3 | import com.love.example.Service.UserService; 4 | import com.love.example.model.User; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.RestController; 8 | 9 | @RestController 10 | public class UserController { 11 | @Autowired 12 | private UserService userService; 13 | 14 | @GetMapping("/getfirstuser") 15 | public User getFirstUser(Long id) { 16 | return this.userService.getFirstUser(id); 17 | } 18 | @GetMapping("/addfirstuser") 19 | public String addFirstUser(String userName, String password) { 20 | User user = new User(userName, password); 21 | this.userService.addFirstUser(user); 22 | return "true"; 23 | } 24 | 25 | @GetMapping("/getseconduser") 26 | public User getSecondUser(Long id) { 27 | return this.userService.getSecondUser(id); 28 | } 29 | @GetMapping("/addseconduser") 30 | public String addSecondUser(String userName, String password) { 31 | User user = new User(userName, password); 32 | this.userService.addSecondUser(user); 33 | return "true"; 34 | } 35 | 36 | @GetMapping("/addalluser") 37 | public String addAllUser(String userName, String password) { 38 | User user = new User(userName, password); 39 | this.userService.addAllUser(user); 40 | return "true"; 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /springboot-mybatis-druid-jta/src/main/java/com/love/example/ExampleApplication.java: -------------------------------------------------------------------------------- 1 | package com.love.example; 2 | 3 | import com.love.example.Config.FirstDataSourceConfig; 4 | import org.mybatis.spring.annotation.MapperScan; 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | import org.springframework.context.annotation.Import; 8 | import org.springframework.transaction.annotation.EnableTransactionManagement; 9 | 10 | //@MapperScan("com.love.example.mapper") 11 | @SpringBootApplication 12 | 13 | @EnableTransactionManagement(proxyTargetClass = true) 14 | @Import(FirstDataSourceConfig.class) 15 | public class ExampleApplication { 16 | 17 | public static void main(String[] args) { 18 | SpringApplication.run(ExampleApplication.class, args); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /springboot-mybatis-druid-jta/src/main/java/com/love/example/Service/UserService.java: -------------------------------------------------------------------------------- 1 | package com.love.example.Service; 2 | 3 | import com.love.example.model.User; 4 | 5 | public interface UserService { 6 | User getFirstUser(Long id); 7 | void addFirstUser(User user); 8 | User getSecondUser(Long id); 9 | void addSecondUser(User user); 10 | 11 | void addAllUser(User user); 12 | } 13 | -------------------------------------------------------------------------------- /springboot-mybatis-druid-jta/src/main/java/com/love/example/Service/template/UserServiceTemplate.java: -------------------------------------------------------------------------------- 1 | package com.love.example.Service.template; 2 | 3 | import com.love.example.Service.UserService; 4 | import com.love.example.mapper.first.FirstMapper; 5 | import com.love.example.mapper.second.SecondMapper; 6 | import com.love.example.model.User; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.stereotype.Service; 9 | import org.springframework.transaction.annotation.Transactional; 10 | 11 | @Service("UserService") 12 | @Transactional("transactionManager") 13 | public class UserServiceTemplate implements UserService { 14 | @Autowired 15 | private FirstMapper firstMapper; 16 | 17 | @Autowired 18 | private SecondMapper secondMapper; 19 | 20 | @Override 21 | public User getFirstUser(Long id) { 22 | return this.firstMapper.getUser(id); 23 | } 24 | 25 | @Override 26 | public void addFirstUser(User user) { 27 | this.firstMapper.addUser(user); 28 | } 29 | 30 | @Override 31 | public User getSecondUser(Long id) { 32 | return this.secondMapper.getUser(id); 33 | } 34 | 35 | @Override 36 | public void addSecondUser(User user) { 37 | this.secondMapper.addUser(user); 38 | } 39 | 40 | @Override 41 | public void addAllUser(User user) { 42 | this.firstMapper.addUser(user); 43 | // 创造错误 44 | int a = 2/0; 45 | this.secondMapper.addUser(user); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /springboot-mybatis-druid-jta/src/main/java/com/love/example/mapper/first/FirstMapper.java: -------------------------------------------------------------------------------- 1 | package com.love.example.mapper.first; 2 | 3 | import com.love.example.model.User; 4 | import org.apache.ibatis.annotations.Mapper; 5 | import org.springframework.stereotype.Component; 6 | 7 | @Component 8 | @Mapper 9 | public interface FirstMapper { 10 | User getUser(Long id); 11 | int addUser(User user); 12 | } -------------------------------------------------------------------------------- /springboot-mybatis-druid-jta/src/main/java/com/love/example/mapper/second/SecondMapper.java: -------------------------------------------------------------------------------- 1 | package com.love.example.mapper.second; 2 | 3 | import com.love.example.model.User; 4 | import org.apache.ibatis.annotations.Mapper; 5 | import org.springframework.stereotype.Component; 6 | 7 | @Component 8 | @Mapper 9 | public interface SecondMapper { 10 | User getUser(Long id); 11 | int addUser(User user); 12 | } 13 | -------------------------------------------------------------------------------- /springboot-mybatis-druid-jta/src/main/java/com/love/example/model/User.java: -------------------------------------------------------------------------------- 1 | package com.love.example.model; 2 | 3 | public class User { 4 | private Long id; 5 | private String userName; 6 | private String passWord; 7 | 8 | public User(){ 9 | super(); 10 | } 11 | public User(String userName, String passWord) { 12 | this.userName = userName; 13 | this.passWord = passWord; 14 | } 15 | 16 | public Long getId() { 17 | return id; 18 | } 19 | 20 | public void setId(Long id) { 21 | this.id = id; 22 | } 23 | 24 | public String getUserName() { 25 | return userName; 26 | } 27 | 28 | public void setUserName(String userName) { 29 | this.userName = userName; 30 | } 31 | 32 | public String getPassword() { 33 | return passWord; 34 | } 35 | 36 | public void setPassword(String password) { 37 | this.passWord = password; 38 | } 39 | 40 | @Override 41 | public String toString() { 42 | return "User{" + 43 | "id=" + id + 44 | ", userName='" + userName + '\'' + 45 | ", password='" + passWord + '\'' + 46 | '}'; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /springboot-mybatis-druid-jta/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8083 3 | spring: 4 | jta: 5 | enabled: true 6 | datasource: 7 | druid: 8 | first: 9 | unique-resource-name: firstDataSource 10 | xa-data-source-class-name: com.alibaba.druid.pool.xa.DruidXADataSource 11 | driver-class-name: com.mysql.jdbc.Driver 12 | # 连接池配置 13 | initial-size: 5 14 | min-idle: 5 15 | max-active: 20 16 | # 连接等待超时时间 17 | max-wait: 30000 18 | # 配置检测可以关闭的空闲连接间隔时间 19 | time-between-eviction-runs-millis: 60000 20 | # 配置连接在池中的最小生存时间 21 | min-evictable-idle-time-millis: 300000 22 | validation-query: select '1' from dual 23 | test-while-idle: true 24 | test-on-borrow: false 25 | test-on-return: false 26 | # 打开PSCache,并且指定每个连接上PSCache的大小 27 | pool-prepared-statements: true 28 | max-open-prepared-statements: 20 29 | max-pool-prepared-statement-per-connection-size: 20 30 | # 配置监控统计拦截的filters, 去掉后监控界面sql无法统计, 'wall'用于防火墙 31 | filters: stat,wall 32 | aop-patterns: com.springboot.servie.* 33 | xa-properties: 34 | url: jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=UTF-8&useSSL=false 35 | username: root 36 | password: zhuqitao123 37 | second: 38 | unique-resource-name: secondDataSource 39 | xa-data-source-class-name: com.alibaba.druid.pool.xa.DruidXADataSource 40 | driver-class-name: com.mysql.jdbc.Driver 41 | # 连接池配置 42 | initial-size: 5 43 | min-idle: 5 44 | max-active: 20 45 | # 连接等待超时时间 46 | max-wait: 30000 47 | # 配置检测可以关闭的空闲连接间隔时间 48 | time-between-eviction-runs-millis: 60000 49 | # 配置连接在池中的最小生存时间 50 | min-evictable-idle-time-millis: 300000 51 | validation-query: select '1' from dual 52 | test-while-idle: true 53 | test-on-borrow: false 54 | test-on-return: false 55 | # 打开PSCache,并且指定每个连接上PSCache的大小 56 | pool-prepared-statements: true 57 | max-open-prepared-statements: 20 58 | max-pool-prepared-statement-per-connection-size: 20 59 | # 配置监控统计拦截的filters, 去掉后监控界面sql无法统计, 'wall'用于防火墙 60 | filters: stat,wall 61 | # Spring监控AOP切入点,如x.y.z.service.*,配置多个英文逗号分隔 62 | aop-patterns: com.springboot.servie.* 63 | xa-properties: 64 | url: jdbc:mysql://localhost:3306/test2?useUnicode=true&characterEncoding=UTF-8&useSSL=false 65 | username: root 66 | password: zhuqitao123 67 | #mybatis: 68 | # mapper-locations: classpath:mybatis/mapper/*.xml -------------------------------------------------------------------------------- /springboot-mybatis-druid-jta/src/main/resources/mybatis/mapper/first/FirstMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | id, user_name, password 12 | 13 | 14 | 20 | 21 | 22 | INSERT INTO 23 | users 24 | (user_name,password) 25 | VALUES 26 | (#{userName}, #{passWord}) 27 | 28 | 29 | -------------------------------------------------------------------------------- /springboot-mybatis-druid-jta/src/main/resources/mybatis/mapper/second/SecondMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | id, user_name, password 12 | 13 | 14 | 20 | 21 | 22 | INSERT INTO 23 | users 24 | (user_name,password) 25 | VALUES 26 | (#{userName}, #{passWord}) 27 | 28 | 29 | -------------------------------------------------------------------------------- /springboot-mybatis-druid-jta/src/test/java/com/love/example/ExampleApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.love.example; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class ExampleApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /springboot-mybatis/README.md: -------------------------------------------------------------------------------- 1 | # Spring Boot集成Mybatis 2 | springboot集成Mybatis和MySQL 3 | ### 添加依赖 4 | ``` 5 | 6 | org.mybatis.spring.boot 7 | mybatis-spring-boot-starter 8 | 1.3.1 9 | 10 | 11 | mysql 12 | mysql-connector-java 13 | 8.0.17 14 | 15 | ``` 16 | 最好指定mysql版本,根据项目运行环境安装的MySQL版本填写对应的版本 17 | ### 配置application.properties 18 | ``` 19 | mybatis.type-aliases-package=com.love.example.model 20 | 21 | spring.datasource.url=jdbc:mysql://localhost:3306/blog?useUnicode=true&characterEncoding=UTF-8 22 | spring.datasource.username=root 23 | spring.datasource.password=root 24 | spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver 25 | ``` 26 | ***注意:*** 27 | Mysql6.x之前的版本需要指定spring.datasource.driver-class-name=com.mysql.jdbc.Driver 28 | 29 | Mysql6.x及以上版本需要指定spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver 30 | 31 | 这就是为什么添加mysql依赖时为什么要指定版本的原因了,开始的版本mysql驱动器使用的是com.mysql.jdbc.Driver,之后的版本换成了新的驱动器 com.mysql.cj.jdbc.Driver 32 | 33 | ### 添加mapper包配置 34 | - 使用@Mapper注解 35 | 36 | @Mapper指明这是一个Mapper, Mybatis 会有一个拦截器,会自动的把 @Mapper 注解的接口生成动态代理类 37 | ``` 38 | @Mapper 39 | public interface MyMapper { 40 | ... 41 | } 42 | ``` 43 | - 使用@MapperScan注解 44 | @Mapper需要每个mapper类都添加@Mapper注解比较繁琐,为了方便@MapperScan就出现了,@MapperScan配置一个或多个包路径,自动的扫描这些包路径下的类,自动的为它们生成代理类。 45 | 46 | 在启动类中添加@MapperScan 47 | ``` 48 | @SpringBootApplication 49 | @MapperScan("com.love.example.mapper") 50 | public class ExampleApplication { 51 | public static void main(String[] args) { 52 | SpringApplication.run(ExampleApplication.class, args); 53 | } 54 | } 55 | ``` 56 | 57 | ### 配置Mybatis两种方式: 使用注解和使用xml配置文件 58 | 59 | 配置Mybatis有两种方式,一种是使用注解,就是所有的都由注解来搞定,还有一种是使用xml配置文件。 60 | 61 | 注解方式特点: 62 | - 注解方式简洁,不需要写额外大量的xml配置文件 63 | - 注解方式灵活性低,但后期可维护型差 64 | - 注解方式对于小型项目可以提高开发效率 65 | - 注解相对于XML的另一个好处是类型安全的,XML只能在运行期才能发现问题。 66 | 67 | xml方式特点 68 | - XML配置起来有时候冗长 69 | - 灵活性和可扩展性高,后期维护方便 70 | 两种方式都有各自适用的场景,还有一种方案是约定大于配置,在某些场景这个方案可能是最优的,但无法满足非常复杂的业务场景。由于企业业务变化需求大,方便维护起见,现在企业大部分使用的是xml方式。 71 | 72 | #### 注解方式: 73 | 注解方式其实就是借助@Select、@Results、@Result、@Insert等注解,把操作数据库的方法和mapper接口写在一块实现对数据库的增删改查等操作。 74 | ##### 一、定义mapper接口 75 | ``` 76 | @Component 77 | @Mapper 78 | public interface MyMapper { 79 | @Select("SELECT * FROM users WHERE id = #{id}") 80 | @Results({ 81 | 82 | @Result(property = "passWord", column = "password"), 83 | @Result(property = "userName", column = "user_name") 84 | }) 85 | User getUser(Long id); 86 | 87 | @Insert("INSERT INTO users(user_name,password) VALUES(#{userName}, #{passWord})") 88 | int addUser(User user); 89 | 90 | @Update("UPDATE users SET user_name=#{userName},password=#{passWord}, WHERE id =#{id}") 91 | int setUser(User user); 92 | 93 | @Delete("DELETE FROM users WHERE id =#{id}") 94 | int removeUser(Long id); 95 | 96 | } 97 | ``` 98 | 了解@Select、@Results、@Result、@Insert等注解使用方法请查看[这里](https://mybatis.org/mybatis-3/zh/java-api.html) 99 | 100 | ##### 二、使用Mapper 101 | - 定义service接口 102 | ``` 103 | public interface UserService { 104 | User getUser(Long id); 105 | int addUser(User user); 106 | int setUser(User user); 107 | int removeUser(Long id); 108 | } 109 | ``` 110 | - 实现service接口 111 | ``` 112 | @Service("UserService") 113 | public class UserServiceTemplate implements UserService { 114 | @Autowired 115 | private MyMapper myMapper; 116 | 117 | @Override 118 | public User getUser(Long id) { 119 | return this.myMapper.getUser(id); 120 | } 121 | @Override 122 | public int addUser(User user) { 123 | return this.myMapper.addUser(user); 124 | } 125 | @Override 126 | public int setUser(User user) { 127 | return this.myMapper.setUser(user); 128 | } 129 | @Override 130 | public int removeUser(Long id) { 131 | return this.myMapper.removeUser(id); 132 | } 133 | } 134 | ``` 135 | - 定义controller 136 | ``` 137 | @RestController 138 | public class UserController { 139 | @Autowired 140 | private UserService userService; 141 | @GetMapping("/getUser") 142 | public User getUser(Long id) { 143 | return this.userService.getUser(id); 144 | } 145 | @GetMapping("/addUser") 146 | public int addUser(User user) { 147 | User user1 = new User("test", "123456"); 148 | return this.userService.addUser(user1); 149 | } 150 | 151 | @PostMapping("/setUser") 152 | public int setUser(User user) { 153 | return this.userService.setUser(user); 154 | } 155 | @PostMapping("/removeUser") 156 | public int removeUser(Long id) { 157 | return this.userService.removeUser(id); 158 | } 159 | } 160 | ``` 161 | 162 | 到此项目就配置完成了,配置本地MySQL数据库,新建一个users表,启动项目,在浏览器中输入[http://localhost:8080/addUser](http://localhost:8080/addUser),就可以添加一条User数据,刷新自己本地数据库,查看是否添加一条数据,然后访问[http://localhost:8080/getUser?id=1](http://localhost:8080/getUser?id=1)(id为刚才添加的User的id),如果一切正常显示说明Mybatis配置成功了。 163 | 164 | #### xml方式: 165 | mapper只定义接口方法,并没有对数据库的操作,对数据库的操作写在xml文件,根据mapper的方法名与xml文件中标签的id匹配。 166 | 167 | 和注解方式的不同主要也是体现在这里,注解是把数据库操作和mapper接口写在一起。 168 | ##### 一、 定义mapper和xml映射文件 169 | MyMapper: 170 | ``` 171 | public interface MyMapper { 172 | User getUser(Long id); 173 | int addUser(User user); 174 | int setUser(User user); 175 | int removeUser(Long id); 176 | } 177 | ``` 178 | 在resources下创建mybatis/mapper目录,并创建MyMapper.xml文件 179 | ``` 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | id, user_name, password 190 | 191 | 197 | 198 | INSERT INTO 199 | users 200 | (userName,passWord) 201 | VALUES 202 | (#{userName}, #{passWord}) 203 | 204 | 205 | UPDATE 206 | users 207 | SET 208 | userName = #{userName}, 209 | passWord = #{passWord}, 210 | WHERE 211 | id = #{id} 212 | 213 | 214 | DELETE FROM 215 | users 216 | WHERE 217 | id =#{id} 218 | 219 | 220 | ``` 221 | ##### 二、 application.properties配置 222 | 现在MyMapper.java接口文件在main/java/com/love/example/mapper/目录下,而MyMapper.xml文件在resources/mybatis/mapper目录下,怎么让这两个文件一起工作呢? 223 | 224 | 这就需要在application.properties添加以下配置 225 | ``` 226 | mybatis.config-location=classpath:mybatis/mybatis-config.xml 227 | mybatis.mapper-locations=classpath:mybatis/mapper/*.xml 228 | ``` 229 | mybatis.mapper-locations=classpath:mybatis/mapper/*.xml是为了让程序去扫描该目录下的所有xml文件,需要注意Mapper接口文件和xml文件名字要相同,他们是根据相同名字匹配。 230 | 231 | 到此配置完成,配置本地数据库,启动项目,和上面看到一样的效果说明Mybatis的xml配置方式配置成功。 232 | 233 | ##### 具体代码可查看[源码地址](https://github.com/zhuqitao/spring-boot-examples/tree/master/springboot-mybatis),欢迎star 234 | -------------------------------------------------------------------------------- /springboot-mybatis/springboot-mybatis-annotation/README.md: -------------------------------------------------------------------------------- 1 | # SpringBoot整合Mybatis、Mysql 2 | spring boot集成Mybatis有两种方式,一种是注解版,不需要xml配置文件, 3 | 另一种是xml配置版 4 | ### 注解版 5 | #### 第一步 引入依赖包 6 | 在pom.xml添加: 7 | ```xml 8 | 9 | org.mybatis.spring.boot 10 | mybatis-spring-boot-starter 11 | 12 | 13 | mysql 14 | mysql-connector-java 15 | 8.0.17 16 | 17 | 18 | ``` 19 | 最好指明Mysql版本,实际根据项目运行环境安装的Mysql版本为准, 20 | 笔者使用的Mysql版本为8.0.17版本。 21 | #### 第二步 配置application.properties 22 | ```properties 23 | mybatis.type-aliases-package=com.neo.model 24 | 25 | spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8 26 | spring.datasource.username=root 27 | spring.datasource.password=root 28 | spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver 29 | ``` 30 | 31 | 32 | -------------------------------------------------------------------------------- /springboot-mybatis/springboot-mybatis-annotation/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.1.RELEASE 9 | 10 | 11 | com.love 12 | example 13 | 0.0.1-SNAPSHOT 14 | example 15 | Demo project for Spring Boot 16 | 17 | 18 | 1.8 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-web 25 | 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-test 30 | test 31 | 32 | 33 | org.junit.vintage 34 | junit-vintage-engine 35 | 36 | 37 | 38 | 39 | 40 | org.mybatis.spring.boot 41 | mybatis-spring-boot-starter 42 | 1.3.1 43 | 44 | 45 | mysql 46 | mysql-connector-java 47 | 8.0.17 48 | 49 | 50 | 51 | 52 | 53 | 54 | org.springframework.boot 55 | spring-boot-maven-plugin 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /springboot-mybatis/springboot-mybatis-annotation/src/main/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhuqitao/spring-boot-examples/c42121f57f485c32159fd1b203cdc0d4dae13ee9/springboot-mybatis/springboot-mybatis-annotation/src/main/.DS_Store -------------------------------------------------------------------------------- /springboot-mybatis/springboot-mybatis-annotation/src/main/java/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhuqitao/spring-boot-examples/c42121f57f485c32159fd1b203cdc0d4dae13ee9/springboot-mybatis/springboot-mybatis-annotation/src/main/java/.DS_Store -------------------------------------------------------------------------------- /springboot-mybatis/springboot-mybatis-annotation/src/main/java/com/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhuqitao/spring-boot-examples/c42121f57f485c32159fd1b203cdc0d4dae13ee9/springboot-mybatis/springboot-mybatis-annotation/src/main/java/com/.DS_Store -------------------------------------------------------------------------------- /springboot-mybatis/springboot-mybatis-annotation/src/main/java/com/love/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhuqitao/spring-boot-examples/c42121f57f485c32159fd1b203cdc0d4dae13ee9/springboot-mybatis/springboot-mybatis-annotation/src/main/java/com/love/.DS_Store -------------------------------------------------------------------------------- /springboot-mybatis/springboot-mybatis-annotation/src/main/java/com/love/example/Controller/UserController.java: -------------------------------------------------------------------------------- 1 | package com.love.example.Controller; 2 | 3 | import com.love.example.Service.UserService; 4 | import com.love.example.model.User; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.PostMapping; 8 | import org.springframework.web.bind.annotation.RestController; 9 | 10 | @RestController 11 | public class UserController { 12 | @Autowired 13 | private UserService userService; 14 | @GetMapping("/getUser") 15 | public User getUser(Long id) { 16 | return this.userService.getUser(id); 17 | } 18 | @GetMapping("/addUser") 19 | public int addUser(User user) { 20 | User user1 = new User("test", "123456"); 21 | return this.userService.addUser(user1); 22 | } 23 | 24 | @PostMapping("/setUser") 25 | public int setUser(User user) { 26 | return this.userService.setUser(user); 27 | } 28 | @PostMapping("/removeUser") 29 | public int removeUser(Long id) { 30 | return this.userService.removeUser(id); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /springboot-mybatis/springboot-mybatis-annotation/src/main/java/com/love/example/ExampleApplication.java: -------------------------------------------------------------------------------- 1 | package com.love.example; 2 | 3 | import org.mybatis.spring.annotation.MapperScan; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | 7 | @SpringBootApplication 8 | @MapperScan("com.love.example.mapper") 9 | public class ExampleApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(ExampleApplication.class, args); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /springboot-mybatis/springboot-mybatis-annotation/src/main/java/com/love/example/Service/UserService.java: -------------------------------------------------------------------------------- 1 | package com.love.example.Service; 2 | 3 | import com.love.example.model.User; 4 | 5 | public interface UserService { 6 | User getUser(Long id); 7 | int addUser(User user); 8 | int setUser(User user); 9 | int removeUser(Long id); 10 | } 11 | -------------------------------------------------------------------------------- /springboot-mybatis/springboot-mybatis-annotation/src/main/java/com/love/example/Service/UserServiceTemplate.java: -------------------------------------------------------------------------------- 1 | package com.love.example.Service; 2 | 3 | import com.love.example.mapper.MyMapper; 4 | import com.love.example.model.User; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.stereotype.Service; 7 | 8 | @Service("UserService") 9 | public class UserServiceTemplate implements UserService { 10 | @Autowired 11 | private MyMapper myMapper; 12 | 13 | @Override 14 | public User getUser(Long id) { 15 | return this.myMapper.getUser(id); 16 | } 17 | @Override 18 | public int addUser(User user) { 19 | return this.myMapper.addUser(user); 20 | } 21 | @Override 22 | public int setUser(User user) { 23 | return this.myMapper.setUser(user); 24 | } 25 | @Override 26 | public int removeUser(Long id) { 27 | return this.myMapper.removeUser(id); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /springboot-mybatis/springboot-mybatis-annotation/src/main/java/com/love/example/mapper/MyMapper.java: -------------------------------------------------------------------------------- 1 | package com.love.example.mapper; 2 | 3 | import com.love.example.model.User; 4 | import org.apache.ibatis.annotations.*; 5 | import org.springframework.stereotype.Component; 6 | import org.springframework.stereotype.Repository; 7 | 8 | @Component 9 | //@Mapper 10 | public interface MyMapper { 11 | @Select("SELECT * FROM users WHERE id = #{id}") 12 | @Results({ 13 | 14 | @Result(property = "passWord", column = "password"), 15 | @Result(property = "userName", column = "user_name") 16 | }) 17 | User getUser(Long id); 18 | 19 | @Insert("INSERT INTO users(user_name,password) VALUES(#{userName}, #{passWord})") 20 | int addUser(User user); 21 | 22 | @Update("UPDATE users SET user_name=#{userName},password=#{passWord}, WHERE id =#{id}") 23 | int setUser(User user); 24 | 25 | @Delete("DELETE FROM users WHERE id =#{id}") 26 | int removeUser(Long id); 27 | 28 | } 29 | -------------------------------------------------------------------------------- /springboot-mybatis/springboot-mybatis-annotation/src/main/java/com/love/example/model/User.java: -------------------------------------------------------------------------------- 1 | package com.love.example.model; 2 | 3 | public class User { 4 | private Long id; 5 | private String userName; 6 | private String passWord; 7 | 8 | public User(){ 9 | super(); 10 | } 11 | public User(String userName, String passWord) { 12 | this.userName = userName; 13 | this.passWord = passWord; 14 | } 15 | 16 | public Long getId() { 17 | return id; 18 | } 19 | 20 | public void setId(Long id) { 21 | this.id = id; 22 | } 23 | 24 | public String getUserName() { 25 | return userName; 26 | } 27 | 28 | public void setUserName(String userName) { 29 | this.userName = userName; 30 | } 31 | 32 | public String getPassword() { 33 | return passWord; 34 | } 35 | 36 | public void setPassword(String password) { 37 | this.passWord = password; 38 | } 39 | 40 | @Override 41 | public String toString() { 42 | return "User{" + 43 | "id=" + id + 44 | ", userName='" + userName + '\'' + 45 | ", password='" + passWord + '\'' + 46 | '}'; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /springboot-mybatis/springboot-mybatis-annotation/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | mybatis.type-aliases-package=com.love.example.model 2 | 3 | spring.datasource.url=jdbc:mysql://localhost:3306/blog?useUnicode=true&characterEncoding=UTF-8 4 | spring.datasource.username=root 5 | spring.datasource.password=zhuqitao123 6 | spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver 7 | -------------------------------------------------------------------------------- /springboot-mybatis/springboot-mybatis-annotation/src/test/java/com/love/example/ExampleApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.love.example; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class ExampleApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /springboot-mybatis/springboot-mybatis-xml/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.1.RELEASE 9 | 10 | 11 | com.love 12 | example 13 | 0.0.1-SNAPSHOT 14 | example 15 | Demo project for Spring Boot 16 | 17 | 18 | 1.8 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-web 25 | 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-test 30 | test 31 | 32 | 33 | org.junit.vintage 34 | junit-vintage-engine 35 | 36 | 37 | 38 | 39 | 40 | org.mybatis.spring.boot 41 | mybatis-spring-boot-starter 42 | 1.3.1 43 | 44 | 45 | mysql 46 | mysql-connector-java 47 | 8.0.17 48 | 49 | 50 | 51 | 52 | 53 | 54 | org.springframework.boot 55 | spring-boot-maven-plugin 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /springboot-mybatis/springboot-mybatis-xml/src/main/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhuqitao/spring-boot-examples/c42121f57f485c32159fd1b203cdc0d4dae13ee9/springboot-mybatis/springboot-mybatis-xml/src/main/.DS_Store -------------------------------------------------------------------------------- /springboot-mybatis/springboot-mybatis-xml/src/main/java/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhuqitao/spring-boot-examples/c42121f57f485c32159fd1b203cdc0d4dae13ee9/springboot-mybatis/springboot-mybatis-xml/src/main/java/.DS_Store -------------------------------------------------------------------------------- /springboot-mybatis/springboot-mybatis-xml/src/main/java/com/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhuqitao/spring-boot-examples/c42121f57f485c32159fd1b203cdc0d4dae13ee9/springboot-mybatis/springboot-mybatis-xml/src/main/java/com/.DS_Store -------------------------------------------------------------------------------- /springboot-mybatis/springboot-mybatis-xml/src/main/java/com/love/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhuqitao/spring-boot-examples/c42121f57f485c32159fd1b203cdc0d4dae13ee9/springboot-mybatis/springboot-mybatis-xml/src/main/java/com/love/.DS_Store -------------------------------------------------------------------------------- /springboot-mybatis/springboot-mybatis-xml/src/main/java/com/love/example/Controller/UserController.java: -------------------------------------------------------------------------------- 1 | package com.love.example.Controller; 2 | 3 | import com.love.example.Service.UserService; 4 | import com.love.example.model.User; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.PostMapping; 8 | import org.springframework.web.bind.annotation.RestController; 9 | 10 | @RestController 11 | public class UserController { 12 | @Autowired 13 | private UserService userService; 14 | @GetMapping("/getUser") 15 | public User getUser(Long id) { 16 | return this.userService.getUser(id); 17 | } 18 | @GetMapping("/addUser") 19 | public int addUser(User user) { 20 | User user1 = new User("test", "123456"); 21 | return this.userService.addUser(user1); 22 | } 23 | 24 | @PostMapping("/setUser") 25 | public int setUser(User user) { 26 | return this.userService.setUser(user); 27 | } 28 | @PostMapping("/removeUser") 29 | public int removeUser(Long id) { 30 | return this.userService.removeUser(id); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /springboot-mybatis/springboot-mybatis-xml/src/main/java/com/love/example/ExampleApplication.java: -------------------------------------------------------------------------------- 1 | package com.love.example; 2 | 3 | import org.mybatis.spring.annotation.MapperScan; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | 7 | @SpringBootApplication 8 | @MapperScan("com.love.example.mapper") 9 | public class ExampleApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(ExampleApplication.class, args); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /springboot-mybatis/springboot-mybatis-xml/src/main/java/com/love/example/Service/UserService.java: -------------------------------------------------------------------------------- 1 | package com.love.example.Service; 2 | 3 | import com.love.example.model.User; 4 | 5 | public interface UserService { 6 | User getUser(Long id); 7 | int addUser(User user); 8 | int setUser(User user); 9 | int removeUser(Long id); 10 | } 11 | -------------------------------------------------------------------------------- /springboot-mybatis/springboot-mybatis-xml/src/main/java/com/love/example/Service/UserServiceTemplate.java: -------------------------------------------------------------------------------- 1 | package com.love.example.Service; 2 | 3 | import com.love.example.mapper.MyMapper; 4 | import com.love.example.model.User; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.stereotype.Service; 7 | 8 | @Service("UserService") 9 | public class UserServiceTemplate implements UserService { 10 | @Autowired 11 | private MyMapper myMapper; 12 | 13 | @Override 14 | public User getUser(Long id) { 15 | return this.myMapper.getUser(id); 16 | } 17 | @Override 18 | public int addUser(User user) { 19 | return this.myMapper.addUser(user); 20 | } 21 | @Override 22 | public int setUser(User user) { 23 | return this.myMapper.setUser(user); 24 | } 25 | @Override 26 | public int removeUser(Long id) { 27 | return this.myMapper.removeUser(id); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /springboot-mybatis/springboot-mybatis-xml/src/main/java/com/love/example/mapper/MyMapper.java: -------------------------------------------------------------------------------- 1 | package com.love.example.mapper; 2 | 3 | import com.love.example.model.User; 4 | import org.springframework.stereotype.Component; 5 | 6 | //@Component 7 | //@Mapper 8 | public interface MyMapper { 9 | User getUser(Long id); 10 | int addUser(User user); 11 | int setUser(User user); 12 | int removeUser(Long id); 13 | } 14 | -------------------------------------------------------------------------------- /springboot-mybatis/springboot-mybatis-xml/src/main/java/com/love/example/model/User.java: -------------------------------------------------------------------------------- 1 | package com.love.example.model; 2 | 3 | public class User { 4 | private Long id; 5 | private String userName; 6 | private String passWord; 7 | 8 | public User(){ 9 | super(); 10 | } 11 | public User(String userName, String passWord) { 12 | this.userName = userName; 13 | this.passWord = passWord; 14 | } 15 | 16 | public Long getId() { 17 | return id; 18 | } 19 | 20 | public void setId(Long id) { 21 | this.id = id; 22 | } 23 | 24 | public String getUserName() { 25 | return userName; 26 | } 27 | 28 | public void setUserName(String userName) { 29 | this.userName = userName; 30 | } 31 | 32 | public String getPassword() { 33 | return passWord; 34 | } 35 | 36 | public void setPassword(String password) { 37 | this.passWord = password; 38 | } 39 | 40 | @Override 41 | public String toString() { 42 | return "User{" + 43 | "id=" + id + 44 | ", userName='" + userName + '\'' + 45 | ", password='" + passWord + '\'' + 46 | '}'; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /springboot-mybatis/springboot-mybatis-xml/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | mybatis.type-aliases-package=com.love.example.model 3 | mybatis.config-location=classpath:mybatis/mybatis-config.xml 4 | mybatis.mapper-locations=classpath:mybatis/mapper/*.xml 5 | 6 | spring.datasource.url=jdbc:mysql://localhost:3306/blog?useUnicode=true&characterEncoding=UTF-8 7 | spring.datasource.username=root 8 | spring.datasource.password=zhuqitao123 9 | spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver 10 | -------------------------------------------------------------------------------- /springboot-mybatis/springboot-mybatis-xml/src/main/resources/mybatis/mapper/MyMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | id, user_name, password 12 | 13 | 14 | 20 | 21 | 22 | INSERT INTO 23 | users 24 | (userName,passWord) 25 | VALUES 26 | (#{userName}, #{passWord}) 27 | 28 | 29 | 30 | UPDATE 31 | users 32 | SET 33 | userName = #{userName}, 34 | passWord = #{passWord}, 35 | WHERE 36 | id = #{id} 37 | 38 | 39 | 40 | DELETE FROM 41 | users 42 | WHERE 43 | id =#{id} 44 | 45 | 46 | -------------------------------------------------------------------------------- /springboot-mybatis/springboot-mybatis-xml/src/main/resources/mybatis/mybatis-config.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /springboot-mybatis/springboot-mybatis-xml/src/main/resources/static/images/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhuqitao/spring-boot-examples/c42121f57f485c32159fd1b203cdc0d4dae13ee9/springboot-mybatis/springboot-mybatis-xml/src/main/resources/static/images/1.png -------------------------------------------------------------------------------- /springboot-mybatis/springboot-mybatis-xml/src/test/java/com/love/example/ExampleApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.love.example; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class ExampleApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /springboot-swagger/README.md: -------------------------------------------------------------------------------- 1 | # Spring Boot 整合Swagger2 2 | 前后端分离开发模式已成大势,一份可读性强、简单易用、实时性强的API文档对于提高开发效率显得尤为重要。相比后端人员手写word作为API文档,要想保证API文档实时有效性,后端人员修改接口,必须同时找到对应的API文档并对其修改,无形中增加了后端人员开发工作量。Swagger 给我们提供了一个全新的维护 API 文档的方式。 3 | 4 | ### 引入依赖 5 | ``` 6 | 7 | io.springfox 8 | springfox-swagger2 9 | 2.6.1 10 | 11 | 12 | 13 | io.springfox 14 | springfox-swagger-ui 15 | 2.6.1 16 | 17 | ``` 18 | ### 创建User实体类 19 | ``` 20 | public class User { 21 | private String name; 22 | private String password; 23 | // 省略get、set、构造方法... 24 | } 25 | ``` 26 | ### 创建Controller类,编写接口 27 | 创建UserCoontroller和TestController 28 | ``` 29 | @RestController 30 | @RequestMapping("/user") 31 | public class UserController { 32 | @GetMapping("/get") 33 | public User getUserByName(@RequestParam String name) { 34 | return new User(name, "123456"); 35 | } 36 | @PostMapping("/add") 37 | public Boolean addUser(@RequestBody User user) { 38 | return true; 39 | } 40 | @PutMapping("/update") 41 | public Boolean updateUser(@RequestBody User user) { 42 | return true; 43 | } 44 | @DeleteMapping("/delete") 45 | public Boolean deleteUserByName(@RequestParam String name) { 46 | return true; 47 | } 48 | } 49 | ``` 50 | ``` 51 | @RestController 52 | public class TestController { 53 | @GetMapping("/test") 54 | public String test() { 55 | return "Only for test controller"; 56 | } 57 | } 58 | ``` 59 | 60 | ### 添加Swagger配置 61 | Springfox 提供了一个 Docket 对象,让我们可以灵活的配置 Swagger 的各项属性。 62 | 创建SwaggerConfig 63 | ``` 64 | @Configuration 65 | @EnableSwagger2 66 | public class SwaggerConfig { 67 | @Bean 68 | public Docket myApi() { 69 | return new Docket(DocumentationType.SWAGGER_2) 70 | .select() 71 | .apis(RequestHandlerSelectors.basePackage("com.love.example")) 72 | .paths(PathSelectors.any()) 73 | .build(); 74 | } 75 | } 76 | ``` 77 | 启动服务,访问[http://localhost:8080/swagger-ui.html](http://localhost:8080/swagger-ui.html),可以看到下图效果: 78 | ![image](http://q21ledx2j.bkt.clouddn.com/example:springboot-swagger:1.png) 79 | 80 | ### 添加文档相关配置 81 | 82 | (1)给整个文档添加配置信息,支持文档的版本号、联系人邮箱、网站、版权、开源协议等等信息 83 | 修改SwaggerConfig 84 | ``` 85 | @Configuration 86 | @EnableSwagger2 87 | public class SwaggerConfig { 88 | @Bean 89 | public Docket myApi() { 90 | return new Docket(DocumentationType.SWAGGER_2) 91 | .apiInfo(apiInfo()) 92 | .select() 93 | .apis(RequestHandlerSelectors.basePackage("com.love.example")) 94 | .paths(PathSelectors.any()) 95 | .build(); 96 | } 97 | 98 | private ApiInfo apiInfo() { 99 | return new ApiInfoBuilder() 100 | .title("spring boot集成Swagger2实例") 101 | .description("简约Restful风格接口文档") 102 | .version("1.1.0") 103 | .build(); 104 | } 105 | } 106 | ``` 107 | (2)@Api 和@ApiOperation注解给 Controller和接口方法 添加描述信息 108 | 修改UserController 109 | ``` 110 | @RestController 111 | @Api(tags = "用户相关接口", description = "用户的增删改查") 112 | @RequestMapping("/user") 113 | public class UserController { 114 | @ApiOperation("获取用户") 115 | @GetMapping("/get") 116 | public User getUserByName(@RequestParam String name) { 117 | return new User(name, "123456"); 118 | } 119 | @ApiOperation("添加用户") 120 | @PostMapping("/add") 121 | public Boolean addUser(@RequestBody User user) { 122 | return true; 123 | } 124 | @ApiOperation("修改用户") 125 | @PutMapping("/update") 126 | public Boolean updateUser(@RequestBody User user) { 127 | return true; 128 | } 129 | @ApiOperation("删除用户") 130 | @DeleteMapping("/delete") 131 | public Boolean deleteUserByName(@RequestParam String name) { 132 | return true; 133 | } 134 | } 135 | ``` 136 | 137 | (3) @ApiModel 和 @ApiModelProperty注解给实体类Model和实体类属性添加配置信息 138 | 修改实体类User 139 | ``` 140 | @ApiModel("用户实体类") 141 | public class User { 142 | @ApiModelProperty("用户名字") 143 | private String name; 144 | @ApiModelProperty("用户密码") 145 | private String password; 146 | // 省略get、set、构造方法... 147 | } 148 | ``` 149 | 150 | 重新启动项目,访问[http://localhost:8080/swagger-ui.html](http://localhost:8080/swagger-ui.html)可看到下图效果: 151 | 152 | ![image](http://q21ledx2j.bkt.clouddn.com/example:springboot-swagger:2.png) 153 | 可以看到我们添加的配置说明信息都已经显示。 154 | 155 | ### 接口过滤 156 | 有时候某些敏感接口或者后端开发内部测试使用接口不想暴露在Swagger文档,swagger提供了两种过滤接口的方法。 157 | #### 方式一:使用@ApiIgnore 注解 158 | 直接在想要屏蔽的接口方法添加@ApiIgnore 注解就可以屏蔽掉该接口。 159 | 修改UserController 160 | ``` 161 | @RestController 162 | @Api(tags = "用户相关接口", description = "用户的增删改查") 163 | @RequestMapping("/user") 164 | public class UserController { 165 | @ApiOperation("获取用户") 166 | @GetMapping("/get") 167 | public User getUserByName(@RequestParam String name) { 168 | return new User(name, "123456"); 169 | } 170 | @ApiOperation("添加用户") 171 | @PostMapping("/add") 172 | public Boolean addUser(@RequestBody User user) { 173 | return true; 174 | } 175 | @ApiOperation("修改用户") 176 | @PutMapping("/update") 177 | public Boolean updateUser(@RequestBody User user) { 178 | return true; 179 | } 180 | 181 | @ApiIgnore 182 | @ApiOperation("删除用户") 183 | @DeleteMapping("/delete") 184 | public Boolean deleteUserByName(@RequestParam String name) { 185 | return true; 186 | } 187 | } 188 | ``` 189 | 上述代码就在swagger屏蔽了删除用户的方法 190 | 191 | #### 方式二:在 Docket 上增加筛选 192 | Docket 类提供了 apis() 和 paths()两 个方法过滤接口。 193 | - apis():指定包名,Swagger只扫描指定包下的接口 194 | - paths():通过匹配URL路径规则进行过滤 195 | 196 | 修改SwaggerConfig 197 | ``` 198 | @Configuration 199 | @EnableSwagger2 200 | public class SwaggerConfig { 201 | @Bean 202 | public Docket myApi() { 203 | return new Docket(DocumentationType.SWAGGER_2) 204 | .apiInfo(apiInfo()) 205 | .select() 206 | .apis(RequestHandlerSelectors.basePackage("com.love.example.UserController")) 207 | .paths(PathSelectors.regex("/user/.*")) 208 | .build(); 209 | } 210 | 211 | private ApiInfo apiInfo() { 212 | return new ApiInfoBuilder() 213 | .title("spring boot集成Swagger2实例") 214 | .description("简约Restful风格接口文档") 215 | .version("1.1.0") 216 | .build(); 217 | } 218 | } 219 | ``` 220 | 重新启动项目,访问[http://localhost:8080/swagger-ui.html](http://localhost:8080/swagger-ui.html)可看到下图效果: 221 | 222 | ![image](http://q21ledx2j.bkt.clouddn.com/example:springboot-swagger:3.png) 223 | 224 | 可以看到过滤掉了TestController所有接口,UserController类下的删除用户接口也过滤掉了 225 | 226 | ### 最佳实践方式 227 | 最好的实现方式就是不写@Api、@ApiOperation、@ApiModel、@ApiModelProperty等各种说明注解,团队严格遵循RESTful接口的设计原则和统一的交互规范,尽量采用语义化英文名词,这样前端人员在看接口文档时,根据语义就能知道每个接口的作用。 228 | 229 | ### 生产环境下禁用swagger 230 | #### 方式一:使用@@Profile注解 231 | 创建application-dev.properties 232 | ``` 233 | server.port=8081 234 | ``` 235 | 创建application-test.properties 236 | ``` 237 | server.port=8081 238 | ``` 239 | 创建application-prod.properties 240 | ``` 241 | server.port=8082 242 | ``` 243 | 244 | 修改SwaggerConfig, 添加@Profile({"dev","test"}),指明只在开发和测试环境才启用swagger 245 | ``` 246 | @Configuration 247 | @EnableSwagger2 248 | @Profile({"dev","test"}) 249 | public class SwaggerConfig { 250 | @Bean 251 | public Docket myApi() { 252 | return new Docket(DocumentationType.SWAGGER_2) 253 | .apiInfo(apiInfo()) 254 | .select() 255 | .apis(RequestHandlerSelectors.basePackage("com.love.example.UserController")) 256 | .paths(PathSelectors.regex("/user/.*")) 257 | .build(); 258 | } 259 | 260 | private ApiInfo apiInfo() { 261 | return new ApiInfoBuilder() 262 | .title("spring boot集成Swagger2实例") 263 | .description("简约Restful风格接口文档") 264 | .version("1.1.0") 265 | .build(); 266 | } 267 | } 268 | ``` 269 | 270 | 修改application.properties 271 | ``` 272 | spring.profiles.active=dev 273 | # 或者 spring.profiles.active=test 274 | ``` 275 | 开发或者测试环境启动项目,浏览器访问[http://localhost:8081/swagger-ui.html](http://localhost:8081/swagger-ui.html),依然可以看到swagger接口文档 276 | 277 | 再次修改修改application.properties 278 | ``` 279 | spring.profiles.active=prod 280 | ``` 281 | 生产环境再次重启项目,浏览器访问[http://localhost:8082/swagger-ui.html](http://localhost:8082/swagger-ui.html),发现浏览器可以正常访问,但是看不到任何文档: 282 | ![image](http://q21ledx2j.bkt.clouddn.com/example:springboot-swagger:4.png) 283 | 284 | #### 方式二: 使用注解@ConditionalOnProperty 285 | 修改application-dev.properties 286 | ``` 287 | server.port=8081 288 | swagger.enable=true 289 | ``` 290 | 修改application-test.properties 291 | ``` 292 | server.port=8081 293 | swagger.enable=true 294 | ``` 295 | 修改application-prod.properties 296 | ``` 297 | server.port=8082 298 | swagger.enable=false 299 | ``` 300 | 301 | 修改SwaggerConfig,去除@Profile({"dev","test"}),添加@ConditionalOnProperty(name = "swagger.enable", havingValue = "true") 302 | 303 | 修改application.properties,如果spring.profiles.active=dev或者spring.profiles.active=test,重启项目,浏览器访问[http://localhost:8081/swagger-ui.html](http://localhost:8081/swagger-ui.html),可以看到swagger接口文档,如果修改spring.profiles.active=prod,重启项目,浏览器访问[http://localhost:8082/swagger-ui.html](http://localhost:8082/swagger-ui.html),则看不到任何接口文档。 304 | 305 | ### 方式三:使用@Value和Docket提供的enable方法 306 | application-dev.properties、application-test.properties、application-prod.properties这三个文件与方式二中保持一致 307 | 308 | 修改SwaggerConfig 309 | 310 | ``` 311 | @Configuration 312 | @EnableSwagger2 313 | 314 | public class SwaggerConfig { 315 | 316 | @Value("${swagger.enable}") 317 | private Boolean enable; 318 | 319 | @Bean 320 | public Docket myApi() { 321 | return new Docket(DocumentationType.SWAGGER_2) 322 | .enable(enable) 323 | .apiInfo(apiInfo()) 324 | .select() 325 | .apis(RequestHandlerSelectors.basePackage("com.love.example.UserController")) 326 | .paths(PathSelectors.regex("/user/.*")) 327 | .build(); 328 | } 329 | 330 | private ApiInfo apiInfo() { 331 | return new ApiInfoBuilder() 332 | .title("spring boot集成Swagger2实例") 333 | .description("简约Restful风格接口文档") 334 | .version("1.1.0") 335 | .build(); 336 | } 337 | } 338 | ``` 339 | 340 | 修改application.properties,如果spring.profiles.active=dev或者spring.profiles.active=test,重启项目,浏览器访问[http://localhost:8081/swagger-ui.html](http://localhost:8081/swagger-ui.html),可以看到swagger接口文档,如果修改spring.profiles.active=prod,重启项目,浏览器访问[http://localhost:8082/swagger-ui.html](http://localhost:8082/swagger-ui.html),则看不到任何接口文档。 341 | 342 | #### 具体代码可查看[源码地址](https://github.com/zhuqitao/spring-boot-examples/tree/master/springboot-swagger),欢迎star -------------------------------------------------------------------------------- /springboot-swagger/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.1.RELEASE 9 | 10 | 11 | com.love 12 | example 13 | 0.0.1-SNAPSHOT 14 | example 15 | Demo project for Spring Boot 16 | 17 | 18 | 1.8 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-web 25 | 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-test 30 | test 31 | 32 | 33 | org.junit.vintage 34 | junit-vintage-engine 35 | 36 | 37 | 38 | 39 | 40 | io.springfox 41 | springfox-swagger2 42 | 2.6.1 43 | 44 | 45 | 46 | io.springfox 47 | springfox-swagger-ui 48 | 2.6.1 49 | 50 | 51 | 52 | 53 | 54 | 55 | org.springframework.boot 56 | spring-boot-maven-plugin 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /springboot-swagger/src/main/java/com/love/example/Config/SwaggerConfig.java: -------------------------------------------------------------------------------- 1 | package com.love.example.Config; 2 | 3 | import org.springframework.beans.factory.annotation.Value; 4 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.context.annotation.Profile; 8 | import springfox.documentation.builders.ApiInfoBuilder; 9 | import springfox.documentation.builders.PathSelectors; 10 | import springfox.documentation.builders.RequestHandlerSelectors; 11 | import springfox.documentation.service.ApiInfo; 12 | import springfox.documentation.spi.DocumentationType; 13 | import springfox.documentation.spring.web.plugins.Docket; 14 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 15 | 16 | @Configuration 17 | @EnableSwagger2 18 | //@Profile({"dev","test"}) 19 | //@ConditionalOnProperty(name = "swagger.enable", havingValue = "true") 20 | 21 | public class SwaggerConfig { 22 | 23 | @Value("${swagger.enable}") 24 | private Boolean enable; 25 | 26 | @Bean 27 | public Docket myApi() { 28 | return new Docket(DocumentationType.SWAGGER_2) 29 | .enable(enable) 30 | .apiInfo(apiInfo()) 31 | .select() 32 | .apis(RequestHandlerSelectors.basePackage("com.love.example.UserController")) 33 | .paths(PathSelectors.regex("/user/.*")) 34 | .build(); 35 | } 36 | 37 | private ApiInfo apiInfo() { 38 | return new ApiInfoBuilder() 39 | .title("spring boot集成Swagger2实例") 40 | .description("简约Restful风格接口文档") 41 | .version("1.1.0") 42 | .build(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /springboot-swagger/src/main/java/com/love/example/ExampleApplication.java: -------------------------------------------------------------------------------- 1 | package com.love.example; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class ExampleApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(ExampleApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /springboot-swagger/src/main/java/com/love/example/Model/User.java: -------------------------------------------------------------------------------- 1 | package com.love.example.Model; 2 | 3 | import io.swagger.annotations.ApiModel; 4 | import io.swagger.annotations.ApiModelProperty; 5 | 6 | @ApiModel("用户实体类") 7 | public class User { 8 | @ApiModelProperty("用户名字") 9 | private String name; 10 | @ApiModelProperty("用户密码") 11 | private String password; 12 | 13 | public User() { 14 | 15 | } 16 | public User(String name, String password) { 17 | this.name = name; 18 | this.password = password; 19 | } 20 | 21 | public String getName() { 22 | return name; 23 | } 24 | 25 | public void setName(String name) { 26 | this.name = name; 27 | } 28 | 29 | public String getPassword() { 30 | return password; 31 | } 32 | 33 | public void setPassword(String password) { 34 | this.password = password; 35 | } 36 | 37 | @Override 38 | public String toString() { 39 | return "User{" + 40 | "name='" + name + '\'' + 41 | ", password='" + password + '\'' + 42 | '}'; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /springboot-swagger/src/main/java/com/love/example/TestController/TestController.java: -------------------------------------------------------------------------------- 1 | package com.love.example.TestController; 2 | 3 | import org.springframework.web.bind.annotation.GetMapping; 4 | import org.springframework.web.bind.annotation.RestController; 5 | 6 | @RestController 7 | public class TestController { 8 | @GetMapping("/test") 9 | public String test() { 10 | return "Only for test controller"; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /springboot-swagger/src/main/java/com/love/example/UserController/UserController.java: -------------------------------------------------------------------------------- 1 | package com.love.example.UserController; 2 | 3 | import com.love.example.Model.User; 4 | import io.swagger.annotations.Api; 5 | import io.swagger.annotations.ApiOperation; 6 | import org.springframework.web.bind.annotation.*; 7 | import springfox.documentation.annotations.ApiIgnore; 8 | 9 | @RestController 10 | @Api(tags = "用户相关接口", description = "用户的增删改查") 11 | @RequestMapping("/user") 12 | public class UserController { 13 | @ApiOperation("获取用户") 14 | @GetMapping("/get") 15 | public User getUserByName(@RequestParam String name) { 16 | return new User(name, "123456"); 17 | } 18 | @ApiOperation("添加用户") 19 | @PostMapping("/add") 20 | public Boolean addUser(@RequestBody User user) { 21 | return true; 22 | } 23 | @ApiOperation("修改用户") 24 | @PutMapping("/update") 25 | public Boolean updateUser(@RequestBody User user) { 26 | return true; 27 | } 28 | 29 | @ApiIgnore 30 | @ApiOperation("删除用户") 31 | @DeleteMapping("/delete") 32 | public Boolean deleteUserByName(@RequestParam String name) { 33 | return true; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /springboot-swagger/src/main/resources/application-dev.properties: -------------------------------------------------------------------------------- 1 | server.port=8081 2 | swagger.enable=true -------------------------------------------------------------------------------- /springboot-swagger/src/main/resources/application-prod.properties: -------------------------------------------------------------------------------- 1 | server.port=8082 2 | swagger.enable=false -------------------------------------------------------------------------------- /springboot-swagger/src/main/resources/application-test.properties: -------------------------------------------------------------------------------- 1 | server.port=8081 2 | swagger.enable=true -------------------------------------------------------------------------------- /springboot-swagger/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.profiles.active=dev -------------------------------------------------------------------------------- /springboot-swagger/src/test/java/com/love/example/ExampleApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.love.example; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class ExampleApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | --------------------------------------------------------------------------------