目录结构
具体代码
config 配置类
DefaultControllerAdvice.java
package com.stu.manage.demo.config;
import com.stu.manage.demo.result.Result;
import com.stu.manage.demo.result.ResultEnum;
import com.stu.manage.demo.result.ResultUtil;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* 捕获Control层抛出的异常 做统一通知处理
*/
/*@ControllerAdvice
@ResponseBody
public class DefaultControllerAdvice {
@ExceptionHandler(Exception.class)
public Result exceptionHandler() {
return ResultUtil.error(ResultEnum.UNKNOWN_ERROR.getCode(),ResultEnum.UNKNOWN_ERROR.getMsg());
}
}*/
MybatisPlusConfig.java
package com.stu.manage.demo.config;
import javax.annotation.Resource;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.TransactionManagementConfigurer;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
// 配置类
// 如果这里使用 @MapperScan 则 在启动类 SpingbootTestApplication@MapperScan可以不用写
//@MapperScan("com.lomonkey.mapper")
@Configuration
@EnableTransactionManagement // 开启注解事务管理,等同于xml配置文件中的 <tx:annotation-driven />
public class MybatisPlusConfig implements TransactionManagementConfigurer {
@Resource(name="txManager1")
private PlatformTransactionManager txManager1;
/**
* 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false
* 避免缓存出现问题(该属性会在旧插件移除后一同移除)
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
// 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求 默认false
paginationInnerInterceptor.setOverflow(true);
// 设置最大单页限制数量,默认 500 条,-1 不受限制
paginationInnerInterceptor.setMaxLimit(50L);
// 开启 count 的 join 优化,只针对部分 left join
//paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
// paginationInnerInterceptor.setDialect();
// 添加分页拦截器插件
interceptor.addInnerInterceptor(paginationInnerInterceptor);
// 添加乐观锁配置
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
@Bean
public ConfigurationCustomizer configurationCustomizer() {
return configuration -> configuration.setUseDeprecatedExecutor(false);
}
/*// 注册乐观锁插件
@Bean
public OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor() {
return new OptimisticLockerInnerInterceptor();
}*/
// 创建事务管理器1 其中DataSource会自动注入
//在Spring容器中,我们手工注解@Bean 将被优先加载,框架不会重新实例化其他的 PlatformTransactionManager 实现类。
// 关于事务管理器,不管是JPA还是JDBC等都实现自接口 PlatformTransactionManager
// 如果你添加的是 spring-boot-starter-jdbc 依赖,框架会默认注入 DataSourceTransactionManager 实例。
// 如果你添加的是 spring-boot-starter-data-jpa 依赖,框架会默认注入 JpaTransactionManager 实例。
@Bean(name = "txManager1")
public PlatformTransactionManager txManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
// 创建事务管理器2
/*@Bean(name = "txManager2")
public PlatformTransactionManager txManager2(EntityManagerFactory factory) {
return new JpaTransactionManager(factory);
}*/
// 实现接口 TransactionManagementConfigurer 方法,其返回值代表在拥有多个事务管理器的情况下默认使用的事务管理器
@Override
public PlatformTransactionManager annotationDrivenTransactionManager() {
return txManager1;
}
}
MyMetaObjectHandler
package com.stu.manage.demo.config;
import java.util.Date;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Component //一定不要忘记吧处理器加到IOC容器中
public class MyMetaObjectHandler implements MetaObjectHandler {
//插入时候的填充策略
@Override
public void insertFill(MetaObject metaObject) {
//设置字段的值(String fieldName字段名,Object fieldVal要传递的值,MetaObject metaObject)
this.setFieldValByName("createTime",new Date(),metaObject);
this.strictInsertFill(metaObject, "modifyTime", Date.class, new Date()); // 起始版本 3.3.0(推荐使用)
}
//更新时间的填充策略
@Override
public void updateFill(MetaObject metaObject) {
this.strictUpdateFill(metaObject, "modifyTime", Date.class, new Date()); // 起始版本 3.3.0(推荐使用)
}
}
SecurityConfiguration.java
package com.stu.manage.demo.config;
import java.util.Arrays;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import com.stu.manage.demo.config.service.UserDetailsServiceImpl;
import com.stu.manage.demo.constants.SecurityConstants;
import com.stu.manage.demo.exception.JwtAccessDeniedHandler;
import com.stu.manage.demo.exception.JwtAuthenticationEntryPoint;
import com.stu.manage.demo.filter.JWTAuthenticationFilter;
import com.stu.manage.demo.filter.JwtAuthorizationFilter;
import static java.util.Collections.singletonList;
import static org.springframework.security.config.Customizer.withDefaults;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private final StringRedisTemplate stringRedisTemplate;
@Autowired
private JwtAccessDeniedHandler jwtAccessDeniedHandler;
@Autowired
private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
public SecurityConfiguration(StringRedisTemplate stringRedisTemplate) {
this.stringRedisTemplate = stringRedisTemplate;
}
/**
* 密码编码器
*/
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
@Override
protected UserDetailsService userDetailsService() {
return new UserDetailsServiceImpl();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// 设置自定义的userDetailsService以及密码编码器
auth.userDetailsService(userDetailsService()).passwordEncoder(bCryptPasswordEncoder());
}
/*@Bean
public JwtAuthorizationFilter jwtAuthorizationFilter() throws Exception {
JwtAuthorizationFilter filter = new JwtAuthorizationFilter(authenticationManager(), stringRedisTemplate);
return filter;
}*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors(withDefaults())
.csrf().disable() // 禁用 CSRF 禁用自带的跨域策略
.authorizeRequests()
// 指定的接口直接放行
.antMatchers(SecurityConstants.SWAGGER_WHITELIST).permitAll() // swagger
//.antMatchers(HttpMethod.GET, SecurityConstants.SYSTEM).permitAll()
.antMatchers(HttpMethod.POST, SecurityConstants.AUTH_LOGIN_URL).permitAll()
//.antMatchers(SecurityConstants.HAS_AUTH).hasAuthority("SystemUserUpdate")
//.antMatchers("student/insert/*").hasAuthority("SystemUserInsert")
.anyRequest().authenticated() // 其他的接口都需要认证后才能请求
.and()
//添加自定义Filter
.addFilter(new JWTAuthenticationFilter(authenticationManager(), stringRedisTemplate))
.addFilter(new JwtAuthorizationFilter(authenticationManager(), stringRedisTemplate))
// 不需要session(不创建会话)
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
// 授权异常处理
.exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint)
.accessDeniedHandler(jwtAccessDeniedHandler);
// 防止H2 web 页面的Frame 被拦截
http.headers().frameOptions().disable();
/*http
.csrf().disable()
.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
.sessionManagement()
.and()
.logout()
.and()
.httpBasic();*/
}
/**
* Cors配置优化
**/
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(singletonList("*"));
// configuration.setAllowedOriginPatterns(singletonList("*"));
configuration.setAllowedHeaders(singletonList("*"));
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "DELETE", "PUT", "OPTIONS"));
configuration.setExposedHeaders(singletonList(SecurityConstants.TOKEN_HEADER));
configuration.setAllowCredentials(false);
configuration.setMaxAge(3600L);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
SwaggerConfig
package com.stu.manage.demo.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("com.stu.manage.demo.controller")).build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()