成都网站建设 致尚,wordpress域名 文件,大气建站工作室网站源码,免费企业管理培训课程视频文章目录 【实战教程】SpringBoot全面指南#xff1a;快速上手到项目实战(SpringBoot)1. SpringBoot介绍1.1 SpringBoot简介1.2系统要求1.3 SpringBoot和SpringMVC区别1.4 SpringBoot和SpringCloud区别 2.快速入门3. Web开发3.1 静态资源访问3.2 渲染Web页面3.3 YML与Properti… 文章目录 【实战教程】SpringBoot全面指南快速上手到项目实战(SpringBoot)1. SpringBoot介绍1.1 SpringBoot简介1.2系统要求1.3 SpringBoot和SpringMVC区别1.4 SpringBoot和SpringCloud区别 2.快速入门3. Web开发3.1 静态资源访问3.2 渲染Web页面3.3 YML与Properties用法3.4使用Freemarker模板引擎渲染web视图3.5 使用thymeleaf渲染Web页面 4.数据库访问4.1 springboot整合使用JdbcTemplate4.2 springboot整合使用mybatis4.3 springboot整合多数据源 5.事务管理5.1 Springboot整合事务管理5.2 SpringBoot分布式事务管理 6.整合热部署6.1 Spring Boot集成lombok让代码更简洁6.2 Spring Boot整合热部署框架 7.整合配置文件7.1使用value注解和ConfigurationProperties注解7.2配置文件占位符7.3多环境配置和核心配置 8.日志管理8.1使用logback记录日志8.2使用log4j记录日志8.3使用AOP统一处理Web请求日志 9.其他内容9.1使用Scheduled创建定时任务9.2使用Async实现异步调用9.3全局捕获异常9.4发布打包 【实战教程】SpringBoot全面指南快速上手到项目实战(SpringBoot)
1. SpringBoot介绍
1.1 SpringBoot简介
SpringBoot 是一个快速开发的框架, 封装了Maven常用依赖、能够快速的整合第三方框架简化XML配置全部采用注解形式内置Tomcat、Jetty、Undertow帮助开发者能够实现快速开发SpringBoot的Web组件 默认集成的是SpringMVC框架。 SpringBoot原理介绍
能够帮助开发者实现快速整合第三方框架 原理Maven依赖封装去除xml配置 完全采用注解化 原理Spring体系中内置注解方式无需外部Tomcat、内部实现服务器原理Java语言支持内嵌入Tomcat服务器
1.2系统要求
Java1.8及以上 Spring Framework 5.0及以上 本课程采用Java1.8版本、SpringBoot2.1.8版本
1.3 SpringBoot和SpringMVC区别
SpringBoot 是一个快速开发的框架,能够快速的整合第三方框架简化XML配置全部采用注解形式内置Tomcat容器,帮助开发者能够实现快速开发SpringBoot的Web组件默认集成的是SpringMVC框架。 SpringMVC是控制层。
1.4 SpringBoot和SpringCloud区别
SpringBoot 是一个快速开发的框架,能够快速的整合第三方框架简化XML配置全部采用注解形式内置Tomcat容器,帮助开发者能够实现快速开发SpringBoot的Web组件 默认集成的是SpringMVC框架。 SpringMVC是控制层。 SpringCloud依赖与SpringBoot组件使用SpringMVC编写Http协议接口同时SpringCloud是一套完整的微服务解决框架。 2.快速入门
2.1创建一个Maven工程
2.2 pom文件引入依赖
parentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion2.1.8.RELEASE/version
/parent
dependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependency
/dependenciesspring-boot-starter-parent作用 在pom.xml中引入spring-boot-start-parentspring官方的解释叫什么stater poms,它可以提供dependency management,也就是说依赖管理引入以后在申明其它dependency的时候就不需要version了后面可以看到。 spring-boot-starter-web作用 springweb 核心组件
2.3 RestController RestController 是由 Controller(控制层注解)ResponBody(数据传输格式为 json 格式)组合而成的 Rest 微服务接口开发中 rest 风格的数据传输格式为 json 格式采用HTTP协议 在上加上RestController 表示修饰该Controller所有的方法返回JSON格式,直接可以编写 Restful接口 注意该注解是(RestController )SpringMVC提供的哦
2.4EnableAutoConfiguration 该注解:作用在于让 Spring Boot 根据应用所声明的依赖来对 Spring 框架进行自动配置 这个注解告诉Spring Boot根据添加的jar依赖猜测你想如何配置Spring。由于spring-boot-starter-web添加了Tomcat和Spring MVC所以auto-configuration将假定你正在开发一个web应用并相应地对Spring进行设置。
2.5 SpringBoot的3种启动方式 方式一
package com.zhaoli.service;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;RestController
EnableAutoConfiguration
public class HelloworldService {RequestMapping(/hello)public String hello() {return Hello World!;}public static void main(String[] args) {SpringApplication.run(HelloworldService.class, args);}
}可以请求本类中的 url 启动主程序打开浏览器访问http://127.0.0.1:8080/hello可以看到页面输出Hello World
方式二
package com.zhaoli.service;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;ComponentScan(com.zhaoli.service)//扫包范围
EnableAutoConfiguration
public class App {public static void main(String[] args) {SpringApplication.run(App.class, args);}
}package com.zhaoli.service;import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;RestController
public class HellowordService {RequestMapping(/hello02)public String hello02() {return Hello 赵立;}
}可以启动扫包范围下的所有类中的 url
方式三推荐使用 在启动类上直接加上SpringBootApplication即可 SpringBootApplication 被 Configuration、EnableAutoConfiguration、ComponentScan 注解所修饰换言之 Springboot 提供了统一的注解来替代以上三个注解 扫包范围在启动类上加上SpringBootApplication注解,当前包下或者子包下所有的类都可以扫到。
package com.zhaoli.service;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;SpringBootApplication
public class App {public static void main(String[] args) {SpringApplication.run(App.class, args);}
}3. Web开发
3.1 静态资源访问
在我们开发Web应用的时候需要引用大量的js、css、图片等静态资源。 默认配置 Spring Boot默认提供静态资源目录位置需置于classpath下目录名需符合如下规则
/static
/public
/resources
/META-INF/resources举例我们可以在src/main/resources/目录下创建static在该位置放置一个图片文件。启动程序后尝试访问http://localhost:8080/one.png。如能显示图片配置成功。
微服务项目 前后端分离 前端----vue----前端工程师 后端—springboot–后端工程师
动静分离 部署cdn上 cdn 减少带宽距离传输 减少自己服务器带宽
3.2 渲染Web页面
com.zhaoli.controller—视图层 渲染我们页面 com.zhaoli.service—业务逻辑层 com.zhaoli.dao—数据库访问层
渲染Web页面 在之前的示例中我们都是通过RestController来处理请求所以返回的内容为json对象。那么如果需要渲染html页面的时候要如何实现呢 模板引擎 能够非常好的帮助seo搜索到该网页 在动态HTML实现上Spring Boot依然可以完美胜任并且提供了多种模板引擎的默认配置支持所以在推荐的模板引擎下我们可以很快的上手开发动态网站。 Spring Boot提供了默认配置的模板引擎主要有以下几种
ThymeleafFreeMarkerVelocityGroovyMustache Spring Boot建议使用这些模板引擎避免使用JSP若一定要使用JSP将无法实现Spring Boot的多种特性具体可见后文支持JSP的配置 当你使用上述模板引擎中的任何一个它们默认的模板配置路径为src/main/resources/templates。当然也可以修改这个路径具体如何修改可在后续各模板引擎的配置属性中查询并修改。
3.3 YML与Properties用法
SpringBoot支持两种配置方式,一种是properties文件,一种是yml。(都是在resources目录下) 使用yml可以减少配置文件的重复性。 例如application.properties配置
test.namezhaoli
test.age21例如application.yml配置
test:name: zhaoliage: 20在企业中application.yml方式用的是比较多的
package com.zhaoli.service;import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;RestController
public class MayiktPropertiesService {Value(${mayikt.name})private String name;Value(${mayikt.age})private String age;RequestMapping(/getProperties)public String getProperties(){return name---------age;}
}3.4使用Freemarker模板引擎渲染web视图
1.Maven依赖
!-- 引入freeMarker的依赖包. --
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-freemarker/artifactId
/dependency2.后端代码
package com.zhaoli.controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;import java.util.Map;Controller
public class FreemarkerIndexController {RequestMapping(/freemarkerIndex)public String freemarkerIndex(MapString,String result){//转发到页面展示数据result.put(name,赵立);return freemarkerIndex;}
}3.前端代码
在src/main/resources/创建一个templates文件夹,用来存 *.ftl
!DOCTYPE html
html
head langenmeta charsetUTF-8/title/title
/head
body
${name}
/body
/html4.Freemarker其他用法 Freemarker配置 新建application.yml文件 (加粗提示对应的配置可以进行修改)
spring:
##Freemarker配置http:encoding:force: true### 模版引擎编码为UTF-8charset: UTF-8freemarker:allow-request-override: falsecache: falsecheck-template-location: truecharset: UTF-8content-type: text/html; charsetutf-8expose-request-attributes: falseexpose-session-attributes: falseexpose-spring-macro-helpers: false## 模版文件结尾.ftlsuffix: .ftl## 模版文件目录template-loader-path: classpath:/templates*.ftl 文件中使用符号替换方法
符号替换为条件判断gt 或者 #if(xy)gte 或者 #if(xy)lt 或者 #if(xy)lte 或者 #if(xy)
判断条件用法 com.zhaoli.controller.FreemarkerIndexController
RequestMapping(/freemarkerIndex02)
public String freemarkerIndex02(MapString, Object result) {//转发到页面展示数据result.put(name, 赵立);//0为男 1为女result.put(sex, 0);result.put(age, 21);return freemarkerIndex02;
}freemarkerIndex02.ftl
!DOCTYPE html
html
head langenmeta charsetUTF-8/title/title
/head
body
${name}
#if sex0男
#elseif sex1女
#else 其他
/#if
#if age gt 17已经成年了
#else 没成年
/#if
/body
/htmllist集合 com.zhaoli.controller.FreemarkerIndexController
RequestMapping(/freemarkerIndex03)
public String freemarkerIndex03(MapString, Object result) {//转发到页面展示数据ListString userLists new ArrayList();userLists.add(zl);userLists.add(fj);userLists.add(lfc);userLists.add(ywq);result.put(userList,userLists);return freemarkerIndex03;freemarkerIndex03.ftl
!DOCTYPE html
html
head langenmeta charsetUTF-8/title/title
/head
body
#list userList as user${user}
/#list
/body
/html3.5 使用thymeleaf渲染Web页面
1 .什么是thymeleaf thymeleaf是一款用于渲染XML/XHTML/HTML5内容的模板引擎类似JSPVelocityFreeMaker等它也可以轻易的与Spring MVC等Web框架进行集成作为Web应用的模板引擎。
2.Maven依赖
!--引入thymeleaf的依赖--
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-thymeleaf/artifactId
/dependency3.配置文件新增 新建application.yml文件
###ThymeLeaf配置
spring:thymeleaf:#prefix指定模板所在的目录prefix: classpath:/templates/#check-tempate-location: 检查模板路径是否存在check-template-location: true#cache: 是否缓存开发模式下设置为false避免改了模板还要重启服务器线上设置为true可以提高性能。cache: truesuffix: .htmlencoding: UTF-8mode: HTML54.案例代码 com.zhaoli.entity.UserEntity
package com.zhaoli.entity;public class UserEntity {private String userName;
private Integer age;
}com.zhaoli.controller.ThymeleafController
package com.zhaoli.controller;import com.zhaoli.entity.UserEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;import java.util.Map;Controller
public class ThymeleafController {RequestMapping(/thymeleaf)public String thymeleaf(MapString, Object result) {result.put(user, new UserEntity(赵立, 20));return thymeleaf;}
}在src/main/resources/创建一个templates文件夹,用来存 *html
!DOCTYPE html
!--需要在HTML文件中加入以下语句 --
html langen xmlns:thhttp://www.thymeleaf.orgheadmeta charsetUTF-8titleShow User/title/headbodytable姓名:span th:text${user.userName}/span年龄:span th:text${user.age}/span/table/body
/html5.高级写法 循环语句 com.zhaoli.entity.UserEntity 同上 com.zhaoli.controller.ThymeleafController
RequestMapping(/thymeleaf02)public String thymeleaf02(MapString, Object result) {ListUserEntity userLists new ArrayList();userLists.add(new UserEntity(赵立, 21));userLists.add(new UserEntity(fj, 20));result.put(userList, userLists);return thymeleaf02;
}thymeleaf02.html
!DOCTYPE html
!--需要在HTML文件中加入以下语句 --
html langen xmlns:thhttp://www.thymeleaf.org
headmeta charsetUTF-8titleShow User/title
/head
body
tableul th:eachuser:${userList}li th:text${user.userName}/lili th:text${user.age}/li/ul
/table
/body
/htmlIf判断
span th:if${user.age17}已经成年啦/span
span th:if${user.age17}未成年/span详细可以更多语法可以查看https://www.thymeleaf.org/documentation.html 4.数据库访问
4.1 springboot整合使用JdbcTemplate
1.pom文件引入
parentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion2.1.8.RELEASE/version
/parent
dependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependency!-- 引入freeMarker的依赖包. --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-freemarker/artifactId/dependency!--引入thymeleaf的依赖--dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-thymeleaf/artifactId/dependency!-- SpringBoot 整合 jdbc 模板框架--dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-jdbc/artifactId/dependency!-- SpringBoot 整合 mysql 驱动类 --dependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactIdversion5.1.21/version/dependency
/dependencies2.application.yml新增配置 ##springboot整合使用JdbcTemplatedatasource:url: jdbc:mysql://localhost:3306/mayikt_springboot?serverTimezoneUTCuseSSLfalseusername: rootpassword: 20020806driver-class-name: com.mysql.jdbc.Driver3.数据库表结构
CREATE TABLE users (id int(11) NOT NULL AUTO_INCREMENT,name varchar(32) NOT NULL COMMENT 用户名称,age int(11) DEFAULT NULL,PRIMARY KEY (id)
) ENGINEInnoDB AUTO_INCREMENT3 DEFAULT CHARSETutf8;4.案例代码 com.zhaoli.entity.UserEntity
public class MayiktUserEntity {private Integer id;private String userName;
private Integer age;
}com.zhaoli.service.UserService
package com.zhaoli.service;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;RestController
public class UserService {Autowiredprivate JdbcTemplate jdbcTemplate;/*** 插入数据到 users 表*/RequestMapping(/inserUser)public String inserUser(String userName, Integer age) {int update jdbcTemplate.update(INSERT INTO users VALUES(null,?,?);, userName, age);return update 0 ? success : fail;}
}com.zhaoli.App App类
package com.zhaoli;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;SpringBootApplication
public class App {public static void main(String[] args) {SpringApplication.run(App.class, args);}
}4.2 springboot整合使用mybatis
1.pom文件引入
!-- springboot 整合mybatis --
dependencygroupIdorg.mybatis.spring.boot/groupIdartifactIdmybatis-spring-boot-starter/artifactIdversion1.1.1/version
/dependency2.application.yml 新增配置 ##springboot整合使用mybatisdatasource:url: jdbc:mysql://localhost:3306/mayikt_springboot?serverTimezoneUTCuseSSLfalseusername: rootpassword: 20020806driver-class-name: com.mysql.jdbc.Driver3.案例代码 数据库表结构同上 com.zhaoli.entity.UserEntity 同上 com.zhaoli.mapper.UserMapper 接口
package com.zhaoli.mapper;import com.zhaoli.entity.MayiktUserEntity;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;public interface UserMapper {Insert(INSERT INTO users VALUES(null,#{userName},#{age});)int insertUser(Param(userName) String userName, Param(age)Integer age);Select(SELECT id,name AS userName,age FROM users WHERE id#{id};)MayiktUserEntity selectByUserId(Param(id)Integer id);
}com.zhaoli.service.UserService
package com.zhaoli.service;import com.zhaoli.entity.MayiktUserEntity;
import com.zhaoli.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;RestController
public class UserService {Autowiredprivate UserMapper userMapper;/*** mybatis 查询*/RequestMapping(/mybatisfinbyId)public MayiktUserEntity mybatisfinbyId(Integer id){return userMapper.selectByUserId(id);}/*** mybatis 插入*/RequestMapping(/mybatisInser)public String mybatisInser(String userName, Integer age) {int inser userMapper.insertUser(userName, age);return inser 0 ? success : fail;}
}com.zhaoli.App App类
package com.zhaoli;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;SpringBootApplication
MapperScan(com.zhaoli.mapper)//将 mapper 包下的类、接口注入到ioc 容器中
public class App {public static void main(String[] args) {SpringApplication.run(App.class, args);}
}4.3 springboot整合多数据源
1.Maven相关依赖
parentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion2.1.8.RELEASE/version
/parent
dependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependency!-- springboot 整合mybatis --dependencygroupIdorg.mybatis.spring.boot/groupIdartifactIdmybatis-spring-boot-starter/artifactIdversion1.1.1/version/dependency!-- SpringBoot 整合 mysql 驱动类 --dependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactIdversion8.0.18/version/dependency
/dependencies2.数据库表结构
CREATE TABLE users (id int(11) NOT NULL AUTO_INCREMENT,name varchar(32) NOT NULL COMMENT 用户名称,age int(11) DEFAULT NULL,PRIMARY KEY (id)
) ENGINEInnoDB AUTO_INCREMENT5 DEFAULT CHARSETutf8;
CREATE TABLE order_number (id int(11) NOT NULL AUTO_INCREMENT,order_name varchar(255) DEFAULT NULL,PRIMARY KEY (id)
) ENGINEInnoDB AUTO_INCREMENT5 DEFAULT CHARSETutf8;3.配置文件中新增两个数据源
resources.application.yml
spring:datasource:###会员数据库member:jdbc-url: jdbc:mysql://localhost:3306/user?serverTimezoneUTCuseSSLfalseusername: rootpassword: rootdriver-class-name: com.mysql.jdbc.Driver###订单数据库order:jdbc-url: jdbc:mysql://localhost:3306/order?serverTimezoneUTCuseSSLfalseusername: rootpassword: rootdriver-class-name: com.mysql.jdbc.Driver备注如果是SpringBoot2配置多数据源 报如下错误 jdbcUrl is required with driverClassName.或者Cause: java.lang.IllegalArgumentException: dataSource or dataSourceClassName or jdbcUrl is required.] with root cause 解决方案 spring.datasource.url 和spring.datasource.driverClassName换成 spring.datasource.jdbc-url和spring.datasource.driver-class-name
4.数据库数据源相关配置 会员数据源
Configuration
MapperScan(basePackages com.zhaoli.member.mapper, sqlSessionFactoryRef memberSqlSessionFactory)
public class MemberDataSourceConfig {/*** 将会员db注册到容器中** return*/Bean(name memberDataSource)ConfigurationProperties(prefix spring.datasource.member)public DataSource memberDataSource() {return DataSourceBuilder.create().build();}/*** 将会员SqlSessionFactory注册到容器中** param dataSource* return* throws Exception*/Bean(name memberSqlSessionFactory)public SqlSessionFactory memberSqlSessionFactory(Qualifier(memberDataSource) DataSource dataSource) throws Exception {SqlSessionFactoryBean sqlSessionFactoryBean new SqlSessionFactoryBean();sqlSessionFactoryBean.setDataSource(memberDataSource());return sqlSessionFactoryBean.getObject();}/*** 创建会员管理器** param dataSource* return*/Bean(name memberTransactionManager)public DataSourceTransactionManager memberTransactionManager(Qualifier(memberDataSource) DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}/*** 创建订单sqlSesion模版** param sqlSessionFactory* return* throws Exception*/Bean(name memberSqlSessionTemplate)public SqlSessionTemplate menberSqlSessionTemplate(Qualifier(memberSqlSessionFactory) SqlSessionFactory sqlSessionFactory) throws Exception {return new SqlSessionTemplate(sqlSessionFactory);}
}订单数据源
Configuration
MapperScan(basePackages com.zhaoli.order.mapper, sqlSessionFactoryRef orderSqlSessionFactory)
public class OrderDataSourceConfig {/*** 将订单db注册到容器中** return*/Bean(name orderDataSource)ConfigurationProperties(prefix spring.datasource.order)public DataSource orderDataSource() {return DataSourceBuilder.create().build();}/*** 将订单SqlSessionFactory注册到容器中** param dataSource* return* throws Exception*/Bean(name orderSqlSessionFactory)public SqlSessionFactory orderSqlSessionFactory(Qualifier(orderDataSource) DataSource dataSource) throws Exception {SqlSessionFactoryBean sqlSessionFactoryBean new SqlSessionFactoryBean();sqlSessionFactoryBean.setDataSource(orderDataSource());return sqlSessionFactoryBean.getObject();}/*** 创建订单管理器** param dataSource* return*/Bean(name orderTransactionManager)public DataSourceTransactionManager orderTransactionManager(Qualifier(orderDataSource) DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}/*** 创建订单sqlSesion模版** param sqlSessionFactory* return* throws Exception*/Bean(name orderSqlSessionTemplate)public SqlSessionTemplate menberSqlSessionTemplate(Qualifier(orderSqlSessionFactory) SqlSessionFactory sqlSessionFactory) throws Exception {return new SqlSessionTemplate(sqlSessionFactory);}
}5.创建分包Mapper 会员mapper
public interface MemberMapper {Insert(insert into users values(null,#{name},#{age});)public int addUser(Param(name) String name, Param(age) Integer age);
}订单mapper
public interface OrderMapper {Insert(insert into order_number values(null,#{number});)int inserOrder(Param(number) String number);
}6.启动项目
SpringBootApplication
public class App{public static void main(String[] args) {SpringApplication.run(App.class);}
}5.事务管理
5.1 Springboot整合事务管理
springboot默认集成事务,只主要在方法上加上Transactional即可
5.2 SpringBoot分布式事务管理
使用springbootjtaatomikos 分布式事物Transactional管理
1.多数据源分布式事务案例
Service
public class MemberService {Autowiredprivate MemberMapper memberMapper;Autowiredprivate OrderMapper orderMapper;Transactional(transactionManager memberTransactionManager)public int addUser(String userName, Integer age) {int result memberMapper.addUser(userName, age);orderMapper.inserOrder(userName);int j 1 / age;return result;}
}2.Maven相关依赖
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-jta-atomikos/artifactId
/dependency3.新增配置文件信息
spring:datasource:###会员数据库member:url: jdbc:mysql://localhost:3306/user?serverTimezoneUTCuseSSLfalseusername: rootpassword: rootborrowConnectionTimeout: 30loginTimeout: 30maintenanceInterval: 60maxIdleTime: 60maxLifetime: 20000maxPoolSize: 25minPoolSize: 3uniqueResourceName: orderDatasource###订单数据库order:url: jdbc:mysql://localhost:3306/order?serverTimezoneUTCuseSSLfalseusername: rootpassword: rootborrowConnectionTimeout: 30loginTimeout: 30maintenanceInterval: 60maxIdleTime: 60maxLifetime: 20000maxPoolSize: 25minPoolSize: 3uniqueResourceName: memberDatasource4.读取配置文件信息
ConfigurationProperties(prefix spring.datasource.member)
Data
public class MemberConfig {private String url;private String userName;private String passWord;private int minPoolSize;private int maxPoolSize;private int maxLifetime;private int borrowConnectionTimeout;private int loginTimeout;private int maintenanceInterval;private int maxIdleTime;private String testQuery;private String uniqueResourceName;
}ConfigurationProperties(prefix spring.datasource.order)
Data
public class OrderConfig {private String url;private String userName;private String passWord;private int minPoolSize;private int maxPoolSize;private int maxLifetime;private int borrowConnectionTimeout;private int loginTimeout;private int maintenanceInterval;private int maxIdleTime;private String testQuery;private String uniqueResourceName;
}5.创建多数据源
Configuration
MapperScan(basePackages com.zhaoli.member.mapper, sqlSessionTemplateRef memberSqlSessionTemplate)
public class MemberDataSourceConfig {//Configuration xml MemberDataSourceConfig.xml/*** 创建我们的DataSource*/Bean(memberDataSource)public DataSource memberDataSource(MemberConfig memberConfig) throws SQLException {// 1.创建MysqlXADataSourceMysqlXADataSource mysqlXaDataSource new MysqlXADataSource();mysqlXaDataSource.setUrl(memberConfig.getUrl());mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);mysqlXaDataSource.setPassword(memberConfig.getPassWord());mysqlXaDataSource.setUser(memberConfig.getUserName());mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);// 2.将本地事务注册到创 Atomikos全局事务AtomikosDataSourceBean xaDataSource new AtomikosDataSourceBean();xaDataSource.setXaDataSource(mysqlXaDataSource);xaDataSource.setUniqueResourceName(memberConfig.getUniqueResourceName());xaDataSource.setMinPoolSize(memberConfig.getMinPoolSize());xaDataSource.setMaxPoolSize(memberConfig.getMaxPoolSize());xaDataSource.setMaxLifetime(memberConfig.getMaxLifetime());xaDataSource.setBorrowConnectionTimeout(memberConfig.getBorrowConnectionTimeout());xaDataSource.setLoginTimeout(memberConfig.getLoginTimeout());xaDataSource.setMaintenanceInterval(memberConfig.getMaintenanceInterval());xaDataSource.setMaxIdleTime(memberConfig.getMaxIdleTime());xaDataSource.setTestQuery(memberConfig.getTestQuery());return xaDataSource;}/*** 创建我们的SqlSessionFactory*/Bean(name memberSqlSessionFactory)public SqlSessionFactory memberSqlSessionFactory(Qualifier(memberDataSource) DataSource dataSource) throws Exception {SqlSessionFactoryBean sqlSessionFactoryBean new SqlSessionFactoryBean();sqlSessionFactoryBean.setDataSource(dataSource);return sqlSessionFactoryBean.getObject();}/*** 创建订单sqlSesion模版*/Bean(name memberSqlSessionTemplate)public SqlSessionTemplate memberSqlSessionTemplate(Qualifier(memberSqlSessionFactory) SqlSessionFactory sqlSessionFactory) throws Exception {return new SqlSessionTemplate(sqlSessionFactory);}
}Configuration
MapperScan(basePackages com.zhaoli.order.mapper, sqlSessionTemplateRef orderSqlSessionTemplate)
public class OrderDataSourceConfig {//Configuration xml orderDataSourceConfig.xml/*** 创建我们的DataSource*/Bean(orderDataSource)public DataSource orderDataSource(OrderConfig orderConfig) throws SQLException {// 1.创建MysqlXADataSourceMysqlXADataSource mysqlXaDataSource new MysqlXADataSource();mysqlXaDataSource.setUrl(orderConfig.getUrl());mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);mysqlXaDataSource.setPassword(orderConfig.getPassWord());mysqlXaDataSource.setUser(orderConfig.getUserName());mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);// 2.将本地事务注册到创 Atomikos全局事务AtomikosDataSourceBean xaDataSource new AtomikosDataSourceBean();xaDataSource.setXaDataSource(mysqlXaDataSource);xaDataSource.setUniqueResourceName(orderConfig.getUniqueResourceName());xaDataSource.setMinPoolSize(orderConfig.getMinPoolSize());xaDataSource.setMaxPoolSize(orderConfig.getMaxPoolSize());xaDataSource.setMaxLifetime(orderConfig.getMaxLifetime());xaDataSource.setBorrowConnectionTimeout(orderConfig.getBorrowConnectionTimeout());xaDataSource.setLoginTimeout(orderConfig.getLoginTimeout());xaDataSource.setMaintenanceInterval(orderConfig.getMaintenanceInterval());xaDataSource.setMaxIdleTime(orderConfig.getMaxIdleTime());xaDataSource.setTestQuery(orderConfig.getTestQuery());return xaDataSource;}/*** 创建我们的SqlSessionFactory*/Bean(name orderSqlSessionFactory)public SqlSessionFactory orderSqlSessionFactory(Qualifier(orderDataSource) DataSource dataSource) throws Exception {SqlSessionFactoryBean sqlSessionFactoryBean new SqlSessionFactoryBean();sqlSessionFactoryBean.setDataSource(dataSource);return sqlSessionFactoryBean.getObject();}
//
// /**
// * 创建会员管理器
// */
// Bean(name orderTransactionManager)
// public DataSourceTransactionManager orderTransactionManager(Qualifier(orderDataSource) DataSource dataSource) {
// return new DataSourceTransactionManager(dataSource);
// }/*** 创建订单sqlSesion模版*/Bean(name orderSqlSessionTemplate)public SqlSessionTemplate orderSqlSessionTemplate(Qualifier(orderSqlSessionFactory) SqlSessionFactory sqlSessionFactory) throws Exception {return new SqlSessionTemplate(sqlSessionFactory);}
}如果多数据源使用事务报错的话 cted single matching bean but found 2: memberTransactionManager,orderTransactionManager Transactional(transactionManager memberTransactionManager) 明确指定使用那个事务管理器即可
6.启动加载配置 EnableConfigurationProperties({OrderConfig.class, MemberConfig.class}) 6.整合热部署
6.1 Spring Boot集成lombok让代码更简洁
1.需要安装Idea整合 整合Lombok插件
2.搜索Lombok插件即可
3.点击install然后安装成功之后点击 重启idea 即可。
整合lombok注意事项
需要在idea中安装lombok插件-----没有做引入到lombok依赖 加上了注解根本就没有生成get和set方法。
原理 实际上在开发写代码的时候 是不需要写get和set方法但是在编译class文件中帮你自动生成好这样get和set方法 放入到class文件中。
4.添加lombok依赖
dependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactId
/dependency5.打印日志 //App 是类的名称在那个类中用就写那个类 private static Logger log Logger.getLogger(App.class); 直接在类上加上Slf4j 就不用写上面这行代码
6.其他特性
注解描述Data自动生成getter/setter方法toString()方法equals()方法hashCode()方法不带参数的构造方法。NonNull避免NullPointerException确保非空对象引用。CleanUp自动管理需要关闭的资源无需手动在finally块中调用close()方法。Setter自动生成setter方法。Getter自动生成getter方法。ToString自动生成toString()方法。EqualsAndHashCode从对象的字段生成hashCode()和equals()方法的实现。NoArgsConstructor自动生成无参构造方法。RequiredArgsConstructor根据final或NotNull修饰的属性自动生成构造方法。AllArgsConstructor自动生成包含所有属性的构造方法。Value用于注解不可变的final类。Builder自动生成复杂对象的构造器API。SneakyThrows捕获并隐藏检查型异常需谨慎使用。Synchronized将方法或代码块标记为同步的保证线程安全。Getter(lazytrue)延迟加载属性值仅适用于Java 8及以上版本。Log支持不同的日志框架例如使用Log4j注解引入Log4j日志对象。
6.2 Spring Boot整合热部署框架
1.什么是热部署 修改java类或页面或者静态文件不需要手动重启 原理类加载器 适合于本地开发环境
2. Maven依赖
!--SpringBoot热部署配置 --
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-devtools/artifactIdscoperuntime/scopeoptionaltrue/optional
/dependency3. Idea工具设置 “File” - “Settings” - “Build,Execution,Deplyment” - “Compiler”选中打勾 “Build project automatically” 组合键“ShiftCtrlAlt/” 选择 “Registry” 选中打勾 “compiler.automake.allow.when.app.running”
新版本的IDEA在这里设置
4.效果演示 按住保存键自动帮我实现重启项目 7.整合配置文件
1. 在springboot整合配置文件分成两大类 application.properties application.yml 或者是 Bootstrap.properties Bootstrap.yml 相对于来说yml文件格式写法更加精简减少配置文件的冗余性。
2. 加载顺序 bootstrap.yml 先加载 application.yml后加载 bootstrap.yml 用于应用程序上下文的引导阶段。 bootstrap.yml 由父Spring ApplicationContext加载。 3.区别 bootstrap.yml 和 application.yml 都可以用来配置参数。 bootstrap.yml 用来程序引导时执行应用于更加早期配置信息读取。可以理解成系统级别的一些参数配置这些参数一般是不会变动的。一旦bootStrap.yml 被加载则内容不会被覆盖。 application.yml 可以用来定义应用级别的 应用程序特有配置信息可以用来配置后续各个模块中需使用的公共参数等。 分布式配置中心
Properties在线转换yml格式网址https://www.toyaml.com/index.html
7.1使用value注解和ConfigurationProperties注解
value注解
Value(${test.name})//可以获取到配置文件中对应的值
private String name; ConfigurationProperties注解 Maven依赖
!--导入配置文件处理器配置文件进行绑定就会有提示--
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-configuration-processor/artifactIdoptionaltrue/optional
/dependencycom.zhaoli.entity
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;Component
ConfigurationProperties(prefix test)
public class TestUserEntity {private String addres;private String age;private String name;//省略了get set toString
}配置文件
test:addres: www.zhaoli.comage: 22name: testcom.zhaoli.service
Autowired
private TestUserEntity userEntity;RequestMapping(/getNameAndAgeAddres)
public String getNameAndAgeAddres() {return userEntity.toString();
}7.2配置文件占位符
在SpringBoot的配置文件中我们可以使用SpringBoot提供的的一些随机数 ${random.value}、${random.int}、${random.long} ${random.int(10)}表示获取10以内的随机数、${random.int[1024,65536]} -${app.name:默认值} 来制定找不到属性时的默认值
7.3多环境配置和核心配置
resources.templates.application.yml 里面指定读取文件的名称
spring:profiles:active: dev或者test或者prdapplication-dev.yml开发环境 application-test.yml测试环境 application-prd.yml生产环境
核心配置
server:
## 设定端口号port: 8081servlet:
## 设置 springboot 项目访问路径context-path: /mayikt
Springboot 默认的情况下整合tomcat容器8.日志管理
8.1使用logback记录日志
Springboot 已经默认帮你整合好了logback 日志输出文件在当前项目路径log文件夹下 1.Maven依赖
!-- 添加lombok依赖 --
dependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactId
/dependency2.在resources包下新建一个log包在包下建 logback.xml 在里面进行配置(拷贝到里面即可)
configuration!--本文主要输出日志为控制台日志系统日志sql日志异常日志--!-- %m输出的信息,%p日志级别,%t线程名,%d日期,%c类的全名,,,, --!--控制台--appender nameconsole classch.qos.logback.core.ConsoleAppenderencoderpattern%d %p (%file:%line\)- %m%n/patterncharsetUTF-8/charset/encoder/appender!--系统info级别日志--!--File 日志目录没有会自动创建--!--rollingPolicy日志策略每天简历一个日志文件或者当天日志文件超过64MB时--!--encoder 日志编码及输出格式--appender namefileLogclassch.qos.logback.core.rolling.RollingFileAppenderFilelog/file/fileLog.log/FilerollingPolicy classch.qos.logback.core.rolling.TimeBasedRollingPolicyfileNamePatternlog/file/fileLog.log.%d.%i/fileNamePatterntimeBasedFileNamingAndTriggeringPolicy classch.qos.logback.core.rolling.SizeAndTimeBasedFNATP!-- or whenever the file size reaches 64 MB --maxFileSize64 MB/maxFileSize/timeBasedFileNamingAndTriggeringPolicy/rollingPolicyencoderpattern%d %p (%file:%line\)- %m%n/patterncharsetUTF-8/charset!-- 此处设置字符集 --/encoder/appender!--sql日志--appender namesqlFileclassch.qos.logback.core.rolling.RollingFileAppenderFilelog/sql/sqlFile.log/FilerollingPolicy classch.qos.logback.core.rolling.TimeBasedRollingPolicyfileNamePatternlog/sql/sqlFile.log.%d.%i/fileNamePatterntimeBasedFileNamingAndTriggeringPolicy classch.qos.logback.core.rolling.SizeAndTimeBasedFNATP!-- or whenever the file size reaches 64 MB --maxFileSize64 MB/maxFileSize/timeBasedFileNamingAndTriggeringPolicy/rollingPolicy!--对记录事件进行格式化。负责两件事一是把日志信息转换成字节数组二是把字节数组写入到输出流。--encoder!--用来设置日志的输入格式--pattern%d %p (%file:%line\)- %m%n/patterncharsetUTF-8/charset!-- 此处设置字符集 --/encoder/appender!--异常日志--appender nameerrorFileclassch.qos.logback.core.rolling.RollingFileAppenderFilelog/error/errorFile.log/FilerollingPolicy classch.qos.logback.core.rolling.TimeBasedRollingPolicyfileNamePatternlog/error/errorFile.%d.log.%i/fileNamePatterntimeBasedFileNamingAndTriggeringPolicy classch.qos.logback.core.rolling.SizeAndTimeBasedFNATP!-- or whenever the file size reaches 64 MB --maxFileSize64 MB/maxFileSize/timeBasedFileNamingAndTriggeringPolicy/rollingPolicy!--对记录事件进行格式化。负责两件事一是把日志信息转换成字节数组二是把字节数组写入到输出流。--encoder!--用来设置日志的输入格式--pattern%d %p (%file:%line\)- %m%n/patterncharsetUTF-8/charset!-- 此处设置字符集 --/encoder!--日志都在这里 过滤出 error使用 try {}catch (Exception e){} 的话异常无法写入日志可以在catch里用logger.error()方法手动写入日志--filter classch.qos.logback.classic.filter.LevelFilterlevelERROR/levelonMatchACCEPT/onMatchonMismatchDENY/onMismatch/filter/appender!-- 日志输出级别 --!--All\DEBUG\INFO\WARN\ERROR\FATAL\OFF--!--打印info级别日志分别在控制台fileLogerrorFile输出异常日志在上面由过滤器过滤出ERROR日志打印--root levelINFOappender-ref reffileLog /appender-ref refconsole /appender-ref referrorFile //root!--打印sql至sqlFile文件日志--logger namecom.dolphin.mapper levelDEBUG additivityfalseappender-ref refconsole /appender-ref refsqlFile //logger
/configuration3.在 resources 目录下的 application.yml 文件内新增 application 配置
###指定读取logback配置文件
logging:config: classpath:log/logback.xml4.测试案例
RestController
Slf4j
public class MyIndexService {/*** 演示打印日志*/RequestMapping(/getNameAndAge)public String getNameAndAge(String name,Integer age){log.info(name:{},age:{},name,age);return name,age;}
}5.日志级别 ALL 最低等级的用于打开所有日志记录。 TRACE designates finer-grained informational events than the DEBUG.Since:1.2.12很低的日志级别一般不会使用。 DEBUG 指出细粒度信息事件对调试应用程序是非常有帮助的主要用于开发过程中打印一些运行信息。 INFO 消息在粗粒度级别上突出强调应用程序的运行过程。打印一些你感兴趣的或者重要的信息这个可以用于生产环境中输出程序运行的一些重要信息但是不能滥用避免打印过多的日志。 WARN 表明会出现潜在错误的情形有些信息不是错误信息但是也要给程序员的一些提示 ERROR 指出虽然发生错误事件但仍然不影响系统的继续运行。打印错误和异常信息如果不想输出太多的日志可以使用这个级别。 FATAL 指出每个严重的错误事件将会导致应用程序的退出。这个级别比较高了。重大错误这种级别你可以直接停止程序了。 OFF 最高等级的用于关闭所有日志记录。
6.日志目录
8.2使用log4j记录日志
日志级别描述输出源格式TRACE追踪程序每推进一步可以写入一个TRACE级别的日志通常用于非常详细的执行流程跟踪。CONSOLESimpleLayoutDEBUG调试用于记录调试信息通常是最低级别帮助开发者理解程序运行情况。FILEHTMLLayoutINFO重要信息用于记录应用程序运行的关键信息是使用较为频繁的日志级别。PatternLayoutWARN警告记录可能需要注意的信息这些信息虽然不是错误但可能会导致问题或需要注意的情况。ERROR错误记录应用程序中的错误信息这类信息表明应用程序中出现了问题。CONSOLEFATAL致命错误记录非常严重的错误信息通常指应用程序无法继续运行下去的情况。FILE机制如果一条日志信息的级别大于等于配置文件的级别则记录这条日志信息。输出源日志可以输出到控制台(CONSOLE)或文件(FILE)。格式日志输出的格式可以是简单的(SimpleLayout)HTML表格形式(HTMLLayout)或者自定义格式(PatternLayout)。
1.Maven依赖
!-- spring boot start --
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter/artifactIdexclusions!-- 排除自带的logback依赖 --exclusiongroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-logging/artifactId/exclusion/exclusions
/dependency!-- springboot-log4j --
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-log4j/artifactIdversion1.3.8.RELEASE/version
/dependency!-- spring boot start -- 这段代码是使用Maven构建项目时添加spring-boot-starter依赖的一种方式并且通过exclusions排除了其中的logback依赖。 当你使用类似的配置时spring-boot-starter依赖会被添加到项目中并且排除了 spring-boot-starter-logging。这样你可以根据自己的需求选择适合的日志框架进行使用 这个排除logback依赖的操作可以用来替换其他的日志框架或者使用自定义的日志框架进行日志的输出
2.新建log4j配置文件 在 resources 目录下新建文件log4j.properties 记得根据自己的项目修改里面的日志输出路径
#log4j.rootLoggerCONSOLE,info,error,DEBUG
log4j.rootLoggerDEBUG,error,CONSOLE,info
log4j.appender.CONSOLEorg.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layoutorg.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern%d{yyyy-MM-dd-HH-mm} [%t] [%c] [%p] - %m%n log4j.logger.infoinfo
log4j.appender.infoorg.apache.log4j.DailyRollingFileAppender
log4j.appender.info.layoutorg.apache.log4j.PatternLayout
log4j.appender.info.layout.ConversionPattern%d{yyyy-MM-dd-HH-mm} [%t] [%c] [%p] - %m%n
log4j.appender.info.datePattern.yyyy-MM-dd
log4j.appender.info.Threshold info
log4j.appender.info.appendtrue
log4j.appender.info.FileE:/code/log/info.loglog4j.logger.errorerror
log4j.appender.errororg.apache.log4j.DailyRollingFileAppender
log4j.appender.error.layoutorg.apache.log4j.PatternLayout
log4j.appender.error.layout.ConversionPattern%d{yyyy-MM-dd-HH-mm} [%t] [%c] [%p] - %m%n
log4j.appender.error.datePattern.yyyy-MM-dd
log4j.appender.error.Threshold error
log4j.appender.error.appendtrue
log4j.appender.error.FileE:/code/log/error.loglog4j.logger.DEBUGDEBUG
log4j.appender.DEBUGorg.apache.log4j.DailyRollingFileAppender
log4j.appender.DEBUG.layoutorg.apache.log4j.PatternLayout
log4j.appender.DEBUG.layout.ConversionPattern%d{yyyy-MM-dd-HH-mm} [%t] [%c] [%p] - %m%n
log4j.appender.DEBUG.datePattern.yyyy-MM-dd
log4j.appender.DEBUG.Threshold DEBUG
log4j.appender.DEBUG.appendtrue
log4j.appender.DEBUG.FileE:/code/log/dubug.loglog4j代码 private static final Logger logger LoggerFactory.getLogger(IndexController.class);
3.application
# 指定log4j.properties配置文件路径
logging:config: classpath:log4j.properties8.3使用AOP统一处理Web请求日志
一般项目都是基于AOP实现 或者elk实现的 它可以在我们的方法的前后实现拦截 减少打印日志代码的冗余性的问题 1.Maven依赖
!-- springboot-aop --
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-aop/artifactId
/dependency2.AOP切面相关配置(直接拷贝即可)
package com.zhaoli.aop;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;Aspect
Component
Slf4j
public class WebLogAspect {// private static final Logger logger LoggerFactory.getLogger(WebLogAspect.class);/*** 切入点* com.zhaoli.controller.* 拦截该包下的所有类* com.zhaoli.controller.*.* 拦截该包下的所有类中的所有方法* (..)所有的方法参数*/Pointcut(execution(public * com.zhaoli.controller.*.*(..)))public void webLog() {}/*** 前置通知 请求方法之前做拦截*/Before(webLog())public void doBefore(JoinPoint joinPoint) throws Throwable {// 接收到请求记录请求内容ServletRequestAttributes attributes (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();HttpServletRequest request attributes.getRequest();// 记录下请求内容log.info(URL : request.getRequestURL().toString());log.info(HTTP_METHOD : request.getMethod());log.info(IP : request.getRemoteAddr());EnumerationString enu request.getParameterNames();while (enu.hasMoreElements()) {String name (String) enu.nextElement();log.info(name:{},value:{}, name, request.getParameter(name));}}/*** 目标方法请求之后 打印(响应)信息*/AfterReturning(returning ret, pointcut webLog())public void doAfterReturning(Object ret) throws Throwable {// 处理完请求返回内容log.info(RESPONSE : ret);}
}9.其他内容
9.1使用Scheduled创建定时任务
在Spring Boot的主类(App类即启动类)中加入EnableScheduling注解启用定时任务的配置 package com.zhaoli.task;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;Component
Slf4j
public class ScheduledTasks {/*** 每隔三秒执行到 taskService()*/Scheduled(fixedRate 3000)public void taskService(){log.info(定时任务执行System.currentTimeMillis());}
}加粗部分一般使用Scheduled(cron 0/2 * * * * *) 写法 https://www.bejson.com/othertools/cron/ 可以在此网站中查找双引号中的使用规范
9.2使用Async实现异步调用
在 Spring Boot 应用的主类(App类即启动类)上添加 EnableAsync 注解用于启用 Spring 的异步执行功能。 需要执行异步方法上加入 Async
具体来说Async 注解用于告诉 Spring 框架将被注解的方法放入一个任务执行器Task Executor中执行而不是使用调用线程进行同步执行。任务执行器负责管理执行异步任务的线程池或者其他执行策略。 异步应用场景 Async实际就是多线程封装的 异步线程执行方法有可能会非常消耗cpu的资源所以大的项目建议使用 Mq异步实现。
整合线程池 异步注解配置类 com.zhaoli.config.ThreadPoolConfig (配置线程池可直接拷贝)
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import java.util.concurrent.ThreadPoolExecutor;Configuration
EnableAsync
public class ThreadPoolConfig {/*** 每秒需要多少个线程处理?* tasks/(1/taskcost)*/private int corePoolSize 3;/*** 线程池维护线程的最大数量* (max(tasks)- queueCapacity)/(1/taskcost)*/private int maxPoolSize 3;/*** 缓存队列* (coreSizePool/taskcost)*responsetime*/private int queueCapacity 10;/*** 允许的空闲时间* 默认为60*/private int keepAlive 100;Beanpublic TaskExecutor taskExecutor() {ThreadPoolTaskExecutor executor new ThreadPoolTaskExecutor();// 设置核心线程数executor.setCorePoolSize(corePoolSize);// 设置最大线程数executor.setMaxPoolSize(maxPoolSize);// 设置队列容量executor.setQueueCapacity(queueCapacity);// 设置允许的空闲时间秒//executor.setKeepAliveSeconds(keepAlive);// 设置默认线程名称executor.setThreadNamePrefix(thread-);// 设置拒绝策略rejection-policy当pool已经达到max size的时候如何处理新任务// CALLER_RUNS不在新线程中执行任务而是有调用者所在的线程来执行executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());// 等待所有任务结束后再关闭线程池executor.setWaitForTasksToCompleteOnShutdown(true);return executor;}
}代码案例 Async(taskExecutor) 是一个Spring框架中的注解用于将方法标记为异步执行的方法。
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;Slf4j
Component
public class MemberServiceAsync {Async(taskExecutor) //指定线程池名称public String smsAsync() {log.info(02);try {log.info(正在发送短信..);Thread.sleep(3000);} catch (Exception e) {}log.info(03);return 短信发送完成!;}
}注意失效问题 注意如果异步注解写当前自己类有可能aop会失效无法拦截注解最终导致异步注解失效需要经过代理类调用接口 所以需要将异步的代码单独抽取成一个类调用接口。
9.3全局捕获异常
ExceptionHandler 表示拦截异常 ControllerAdvice 是 controller 的一个辅助类最常用的就是作为全局异常处理的切面类 ControllerAdvice 可以指定扫描范围 ControllerAdvice 约定了几种可行的返回值如果是直接返回 model 类的话需要使用 ResponseBody 进行 json 转换
返回 String表示跳到某个 view返回 modelAndView返回 model ResponseBody
全局捕获异常配置类
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;import java.util.HashMap;
import java.util.Map;ControllerAdvice
public class MayiktExceptionHandler {/*** 拦截运行异常出现的错误~~~*/ExceptionHandler(RuntimeException.class)ResponseBodypublic MapObject, Object exceptionHandler() {MapObject, Object map new HashMap();map.put(error, 500);map.put(msg, 系统出现错误~);return map;}
}没使用之前
给用户显示这个页面很不友好 使用全局捕获异常配置类之后的页面
9.4发布打包
使用mvn package 打包 进入到项目所在目录 输入 mvn clean package 进行打包等待打包完成
显示这个即打包完成
在项目的目录中的 target 包下生成一个java-jar包
使用java –jar 包的全路径地址
如果报错没有主清单在pom文件中新增
!-- 设置打包主清单属性 --
buildpluginsplugingroupIdorg.springframework.boot/groupIdartifactIdspring-boot-maven-plugin/artifactIdexecutionsexecutiongoalsgoalrepackage/goal/goals/execution/executionsconfiguration!-- 启动类 --mainClasscom.zhaoli.App/mainClassexcludesexcludegroupIdjunit/groupIdartifactIdjunit/artifactId/excludeexcludegroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactId/exclude/excludes/configuration/plugin/plugins
/build重新打包再运行 启动
成功运行