目录
二、SpringBoot整合MybatisPlus
2.1 MybatisPlus介绍
MybatisPlus官网:简介 | MyBatis-Plus
MyBatis-Plus (opens new window)(简称 MP)是一个 MyBatis (opens new window)的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
特性:
-
无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
-
损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
-
强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
-
支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
-
支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
-
支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
-
支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
-
内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
-
内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
-
分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
-
内置性能分析插件:可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
-
内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作
2.2 MybatisPlus整合SpringBoot
2.2.1 集成SpringBoot
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>
2.2.2 配置数据信息
application.properties文件里面的配置信息
#配置数据源
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=密码
#转换时间格式
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8
spring.jackson.serialization.write-date-keys-as-timestamps=false
#输出日志
#logging.level.com.baomidou.ant.test.dao=debug
#mybatis-plus 第一个是 将_转换为下一个字母大写 第二个是输出日志
mybatis-plus.configuration.map-underscore-to-camel-case=true
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
#mybatis-plus.configuration.log-impl= 设置mapper文件所在的位置
mybatis-plus.mapper-locations=classpath:/mapper/*.xml
#逻辑删除 0代表逻辑删除之前 1代表逻辑删除之后
mybatis-plus.global-config.db-config.logic-not-delete-value=0
mybatis-plus.global-config.db-config.logic-delete-value=1
#设置端口号
server.port=8888
# 设置上下文的路径 :必须以/为开头
server.servlet.context-path=/test2
2.2.3 BaseMapper实现基本的增删改查
public interface BaseMapper<T> {
/**
* <p>
* 插入一条记录
* </p>
*
* @param entity 实体对象
*/
Integer insert(T entity);
/**
* <p>
* 根据 ID 删除
* </p>
*
* @param id 主键ID
*/
Integer deleteById(Serializable id);
/**
* <p>
* 根据 columnMap 条件,删除记录
* </p>
*
* @param columnMap 表字段 map 对象
*/
Integer deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
/**
* <p>
* 根据 entity 条件,删除记录
* </p>
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
Integer delete(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
* <p>
* 删除(根据ID 批量删除)
* </p>
*
* @param idList 主键ID列表(不能为 null 以及 empty)
*/
Integer deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
/**
* <p>
* 根据 ID 修改
* </p>
*
* @param entity 实体对象
*/
Integer updateById(@Param(Constants.ENTITY) T entity);
/**
* <p>
* 根据 whereEntity 条件,更新记录
* </p>
*
* @param entity 实体对象 (set 条件值,不能为 null)
* @param updateWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)
*/
Integer update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T> updateWrapper);
/**
* <p>
* 根据 ID 查询
* </p>
*
* @param id 主键ID
*/
T selectById(Serializable id);
/**
* <p>
* 查询(根据ID 批量查询)
* </p>
*
* @param idList 主键ID列表(不能为 null 以及 empty)
*/
List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
/**
* <p>
* 查询(根据 columnMap 条件)
* </p>
*
* @param columnMap 表字段 map 对象
*/
List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
/**
* <p>
* 根据 entity 条件,查询一条记录
* </p>
*
* @param queryWrapper 实体对象
*/
T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
* <p>
* 根据 Wrapper 条件,查询总记录数
* </p>
*
* @param queryWrapper 实体对象
*/
Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
* <p>
* 根据 entity 条件,查询全部记录
* </p>
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
* <p>
* 根据 Wrapper 条件,查询全部记录
* </p>
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
* <p>
* 根据 Wrapper 条件,查询全部记录
* 注意: 只返回第一个字段的值
* </p>
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
* <p>
* 根据 entity 条件,查询全部记录(并翻页)
* </p>
*
* @param page 分页查询条件(可以为 RowBounds.DEFAULT)
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
IPage<T> selectPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
* <p>
* 根据 Wrapper 条件,查询全部记录(并翻页)
* </p>
*
* @param page 分页查询条件
* @param queryWrapper 实体对象封装操作类
*/
IPage<Map<String, Object>> selectMapsPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
}
2.2.4 service的方法介绍
public interface IService<T> {
/**
* <p>
* 插入一条记录(选择字段,策略插入)
* </p>
*
* @param entity 实体对象
*/
boolean save(T entity);
/**
* <p>
* 插入(批量)
* </p>
*
* @param entityList 实体对象集合
*/
default boolean saveBatch(Collection<T> entityList) {
return saveBatch(entityList, 1000);
}
/**
* <p>
* 插入(批量)
* </p>
*
* @param entityList 实体对象集合
* @param batchSize 插入批次数量
*/
boolean saveBatch(Collection<T> entityList, int batchSize);
/**
* <p>
* 批量修改插入
* </p>
*
* @param entityList 实体对象集合
*/
default boolean saveOrUpdateBatch(Collection<T> entityList) {
return saveOrUpdateBatch(entityList, 1000);
}
/**
* <p>
* 批量修改插入
* </p>
*
* @param entityList 实体对象集合
* @param batchSize 每次的数量
*/
boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize);
/**
* <p>
* 根据 ID 删除
* </p>
*
* @param id 主键ID
*/
boolean removeById(Serializable id);
/**
* <p>
* 根据 columnMap 条件,删除记录
* </p>
*
* @param columnMap 表字段 map 对象
*/
boolean removeByMap(Map<String, Object> columnMap);
/**
* <p>
* 根据 entity 条件,删除记录
* </p>
*
* @param queryWrapper 实体包装类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
*/
boolean remove(Wrapper<T> queryWrapper);
/**
* <p>
* 删除(根据ID 批量删除)
* </p>
*
* @param idList 主键ID列表
*/
boolean removeByIds(Collection<? extends Serializable> idList);
/**
* <p>
* 根据 ID 选择修改
* </p>
*
* @param entity 实体对象
*/
boolean updateById(T entity);
/**
* <p>
* 根据 whereEntity 条件,更新记录
* </p>
*
* @param entity 实体对象
* @param updateWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper}
*/
boolean update(T entity, Wrapper<T> updateWrapper);
/**
* <p>
* 根据ID 批量更新
* </p>
*
* @param entityList 实体对象集合
*/
default boolean updateBatchById(Collection<T> entityList) {
return updateBatchById(entityList, 1000);
}
/**
* <p>
* 根据ID 批量更新
* </p>
*
* @param entityList 实体对象集合
* @param batchSize 更新批次数量
*/
boolean updateBatchById(Collection<T> entityList, int batchSize);
/**
* <p>
* TableId 注解存在更新记录,否插入一条记录
* </p>
*
* @param entity 实体对象
*/
boolean saveOrUpdate(T entity);
/**
* <p>
* 根据 ID 查询
* </p>
*
* @param id 主键ID
*/
T getById(Serializable id);
/**
* <p>
* 查询(根据ID 批量查询)
* </p>
*
* @param idList 主键ID列表
*/
Collection<T> listByIds(Collection<? extends Serializable> idList);
/**
* <p>
* 查询(根据 columnMap 条件)
* </p>
*
* @param columnMap 表字段 map 对象
*/
Collection<T> listByMap(Map<String, Object> columnMap);
/**
* <p>
* 根据 Wrapper,查询一条记录
* </p>
*
* @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
*/
default T getOne(Wrapper<T> queryWrapper) {
return getOne(queryWrapper, false);
}
/**
* <p>
* 根据 Wrapper,查询一条记录
* </p>
*
* @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
* @param throwEx 有多个 result 是否抛出异常
*/
T getOne(Wrapper<T> queryWrapper, boolean throwEx);
/**
* <p>
* 根据 Wrapper,查询一条记录
* </p>
*
* @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
*/
Map<String, Object> getMap(Wrapper<T> queryWrapper);
/**
* <p>
* 根据 Wrapper,查询一条记录
* </p>
*
* @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
* @param mapper 转换函数
*/
default <V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper) {
return SqlHelper.getObject(listObjs(queryWrapper, mapper));
}
/**
* <p>
* 根据 Wrapper 条件,查询总记录数
* </p>
*
* @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
*/
int count(Wrapper<T> queryWrapper);
/**
* <p>
* 查询总记录数
* </p>
*
* @see Wrappers#emptyWrapper()
*/
default int count() {
return count(Wrappers.emptyWrapper());
}
/**
* <p>
* 查询列表
* </p>
*
* @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
*/
List<T> list(Wrapper<T> queryWrapper);
/**
* <p>
* 查询所有
* </p>
*
* @see Wrappers#emptyWrapper()
*/
default List<T> list() {
return list(Wrappers.emptyWrapper());
}
/**
* <p>
* 翻页查询
* </p>
*
* @param page 翻页对象
* @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
*/
IPage<T> page(IPage<T> page, Wrapper<T> queryWrapper);
/**
* <p>
* 无条件翻页查询
* </p>
*
* @param page 翻页对象
* @see Wrappers#emptyWrapper()
*/
default IPage<T> page(IPage<T> page) {
return page(page, Wrappers.emptyWrapper());
}
/**
* <p>
* 查询列表
* </p>
*
* @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
*/
List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper);
/**
* <p>
* 查询所有列表
* </p>
*
* @see Wrappers#emptyWrapper()
*/
default List<Map<String, Object>> listMaps() {
return listMaps(Wrappers.emptyWrapper());
}
/**
* <p>
* 查询全部记录
* </p>
*/
default List<Object> listObjs() {
return listObjs(Function.identity());
}
/**
* <p>
* 查询全部记录
* </p>
*
* @param mapper 转换函数
*/
default <V> List<V> listObjs(Function<? super Object, V> mapper) {
return listObjs(Wrappers.emptyWrapper(), mapper);
}
/**
* <p>
* 根据 Wrapper 条件,查询全部记录
* </p>
*
* @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
*/
default List<Object> listObjs(Wrapper<T> queryWrapper) {
return listObjs(Wrappers.emptyWrapper(), Function.identity());
}
/**
* <p>
* 根据 Wrapper 条件,查询全部记录
* </p>
*
* @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
* @param mapper 转换函数
*/
<V> List<V> listObjs(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);
/**
* <p>
* 翻页查询
* </p>
*
* @param page 翻页对象
* @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
*/
IPage<Map<String, Object>> pageMaps(IPage<T> page, Wrapper<T> queryWrapper);
/**
* <p>
* 无条件翻页查询
* </p>
*
* @param page 翻页对象
* @see Wrappers#emptyWrapper()
*/
default IPage<Map<String, Object>> pageMaps(IPage<T> page) {
return pageMaps(page, Wrappers.emptyWrapper());
}
}
2.3 MybatisPlus的自动生成
2.3.1 导入pom的依赖
<!--MybatisPlus持久层操作-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>
<!--根据数据库表自动生成代码-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.4.1</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.2</version>
</dependency>
2.3.2 添加自动生成的类
这个类可以放在任何地方
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import org.junit.platform.commons.util.StringUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class GenerateTest {
/**
* <p>
* 读取控制台内容
* </p>
*/
public static String scanner(String tip) {
Scanner scanner = new Scanner(System.in);
StringBuilder help = new StringBuilder();
help.append("请输入" + tip + ":");
System.out.println(help.toString());
if (scanner.hasNext()) {
String ipt = scanner.next();
if (StringUtils.isNotBlank(ipt)) {
return ipt;
}
}
throw new MybatisPlusException("请输入正确的" + tip + "!");
}
public static void main(String[] args) {
// 代码生成器
AutoGenerator mpg = new AutoGenerator();
// 全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
gc.setOutputDir(projectPath + "/src/main/java");//代码生成位置
gc.setAuthor("L");//设置作者
gc.setOpen(false);
// gc.setSwagger2(true); 实体属性 Swagger2 注解
mpg.setGlobalConfig(gc);//是否设置为全局配置
// 数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/test_zzz_test?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true");
// dsc.setSchemaName("public");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("密码");
mpg.setDataSource(dsc);
// 包配置
PackageConfig pc = new PackageConfig();
//pc.setModuleName(scanner("模块名"));
pc.setParent("com.example.springbootdemo");//设置代码存放的包名
//pc.setXml("");
pc.setEntity("entity");//实体的包
pc.setMapper("dao");//dao的包
pc.setService("service");//service的包
pc.setServiceImpl("service.impl");//实现类的包
mpg.setPackageInfo(pc);
// 自定义配置
InjectionConfig cfg = new InjectionConfig() {
@Override
public void initMap() {
// to do nothing
}
};
// 如果模板引擎是 freemarker
// String templatePath = "/templates/mapper.xml.ftl";
// 如果模板引擎是 velocity
String templatePath = "/templates/mapper.xml.vm";
// 自定义输出配置
List<FileOutConfig> focList = new ArrayList<>();
// 自定义配置会被优先输出
focList.add(new FileOutConfig(templatePath) {
@Override
public String outputFile(TableInfo tableInfo) {
// 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
return projectPath + "/src/main/resources/mapper/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
}
});
cfg.setFileOutConfigList(focList);
mpg.setCfg(cfg);
// 配置模板
//不在java文件夹下面写入mapper文件
TemplateConfig templateConfig = new TemplateConfig();
templateConfig.setXml(null);
mpg.setTemplate(templateConfig);
// 策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setNaming(NamingStrategy.underline_to_camel);//设置将字段中的_省略,自动将下一个字母转换为大写字母
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
strategy.setEntityLombokModel(true);
strategy.setRestControllerStyle(true);
// 公共父类
// 写于父类中的公共字段
// strategy.setSuperEntityColumns("id");//设置是否有公共的父类主键为id字段,不写这一句时,会给主键为id的字段一个@TableId注解
strategy.setInclude(scanner("表名,多个英文逗号分割").split(","));//输出仅需要的表名
strategy.setControllerMappingHyphenStyle(true);
strategy.setTablePrefix(pc.getModuleName() + "_");
mpg.setStrategy(strategy);
mpg.execute();
}
}
2.4 MybatisPlus的分页插件
插件主体:插件主体 | MyBatis-Plus
@Configuration
//分页插件可以放在启动类中,也可以放在单独一个类中
//如果是放在单独一个类中,那这个类和启动类只需要有一个类写MapperScan注解即可
@MapperScan("scan.your.mapper.package")
public class MybatisPlusConfig {
/**
* 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除)
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
return interceptor;
}
@Bean
public ConfigurationCustomizer configurationCustomizer() {
return configuration -> configuration.setUseDeprecatedExecutor(false);
}
}
分页插件测试:
@Test
public void testPage() {
IPage<Dept> dept=new Page<>(1,2);
IPage<Dept> page = deptService.page(dept);
}
或者是:
controller层:
@GetMapping
public Result getAll(HtUser user, Page page){
return new Result(htUserService.listByNameAndSex(user,page));
}
service层:
public interface IHtUserService extends IService<HtUser> {
Page listByNameAndSex(HtUser user, Page page);
}
service实现:
@Service
public class HtUserServiceImpl extends ServiceImpl<HtUserMapper, HtUser> implements IHtUserService {
@Override
public Page listByNameAndSex(HtUser user, Page page) {
QueryWrapper queryWrapper = new QueryWrapper();
if (StringUtils.isNotBlank(user.getUsername())){
queryWrapper.like("username",user.getUsername());
}
if (StringUtils.isNotBlank(user.getSex())){
queryWrapper.like("sex",user.getSex());
}
Page page1 = this.page(page, queryWrapper);
// 返回当前字节里面的一个查询条件的结果
return page1;
}
}
2.5 逻辑删除
数据库表中有一个status(状态)字段
在这个数据库表对应的实体类中,在status列上加上注解@TableLogic
@TableLogic
private Integer status;
对应的配置文件中规定了什么是禁用/什么是启用
#MybatisPlus的逻辑删除
# 1 代表逻辑删除之前
mybatis-plus.global-config.db-config.logic-not-delete-value=1
# 2 代表逻辑删除之后
mybatis-plus.global-config.db-config.logic-delete-value=2
测试逻辑删除:
/**
* 根据id删除对用户进行逻辑删除
*/
@DeleteMapping("delUser/{id}")
public Result delRole(@PathVariable Integer id){
boolean b = userService.removeById(id);
return new Result(b);
}
/**
*逻辑删除其实是一个修改语句
*逻辑删除的结果就是将status值为1改为值为2
*查询的时候MybatisPlus会自动添加status=1的条件
*/
2.6 多表查询忽略字段
当多表查询时 用于实体类中
/**
* @TableFiled的值默认为true,当修改为false,单表查询时不会将此字段当做当前字段的列
*/
@TableField(exist = false)
private List<HtUser> htUsers;
2.7 统一返回结果格式
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Result<T> {
private Integer code = 200;
private String msg = "操作成功";
private T t;
public Result(T t) {
this.code=200;
this.msg="操作成功";
this.t = t;
}
}
2.8 全局跨域请求
/**
*全局跨域请求和局部跨域请求写一个即可
*全局跨域请求可以写在启动类中,也可以单独写一个类
*如果是单独写一个类,那么启动类和跨域请求类 只需要写一个@MapperScan注解
*/
@Bean
public CorsFilter corsFilter() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
final CorsConfiguration corsConfiguration = new CorsConfiguration();
// corsConfiguration.setAllowCredentials(true);
corsConfiguration.addAllowedHeader("*");// 允许所有的头
corsConfiguration.addAllowedOrigin("*");// 允许所有源发出的请求
corsConfiguration.addAllowedMethod("*");// 允许所有的方法 如果不写的话默认是允许GET POST
source.registerCorsConfiguration("/**", corsConfiguration);// 所有的路径,这里写完就不用再Controller中写跨域请求
return new CorsFilter(source);
}