package com.alatus.config.filter; import com.alatus.constant.Constants; import com.alatus.model.TUser; import com.alatus.result.Result; import com.alatus.service.RedisService; import com.alatus.util.JSONUtils; import com.alatus.util.JWTUtils; import com.alatus.util.ResponseUtils; import com.alatus.result.CodeEnum; import jakarta.annotation.Resource; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import org.springframework.web.filter.OncePerRequestFilter; import java.io.IOException; import java.util.concurrent.TimeUnit; @Component public class TokenVerifyFilter extends OncePerRequestFilter { @Resource private RedisService redisService; // @Resource // // springboot框架提供的线程池,ioc容器内已经存在 // private ThreadPoolTaskExecutor threadPoolTaskExecutor; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { if (request.getRequestURI().equals(Constants.LOGIN_URI)) { //如果是登录请求,此时还没有生成jwt,那不需要对登录请求进行jwt验证 //验证jwt通过了 ,让Filter链继续执行,也就是继续执行下一个Filter filterChain.doFilter(request, response); } else { String token; if(request.getRequestURI().equals(Constants.EXPORT_EXCEL_URI)){ token = request.getParameter(Constants.TOKEN_NAME); } else{ token = request.getHeader(Constants.TOKEN_NAME); } if(!StringUtils.hasText(token)){ // 没拿到token,将失败这个枚举传回去,解析并取出常量拼接 Result result = Result.FAIL(CodeEnum.TOKEN_IS_EMPTY); // 封装 String resultJSON = JSONUtils.toJSON(result); // 返回 ResponseUtils.write(response,resultJSON); return; } // 验证token有没有被篡改过,也是验证token合法性 if (!(JWTUtils.verifyJWT(token))){ // token不合法 Result result = Result.FAIL(CodeEnum.TOKEN_IS_NONE_MATCH); // 封装 String resultJSON = JSONUtils.toJSON(result); // 返回 ResponseUtils.write(response,resultJSON); return; } TUser tUser = JWTUtils.parseUserFromJWT(token); String redisToken = (String) redisService.getValue(Constants.REDIS_JWT_KEY + tUser.getId()); if(!StringUtils.hasText(redisToken)){ // 没有获取到内容说明token过期了 Result fail = Result.FAIL(CodeEnum.TOKEN_IS_EXPIRED); String json = JSONUtils.toJSON(fail); ResponseUtils.write(response,json); return; } if (!redisToken.equals(token)) { // 登陆失败token错误 Result result = Result.FAIL(CodeEnum.TOKEN_IS_ERROR); // 把R对象转为JSON String json = JSONUtils.toJSON(result); ResponseUtils.write(response,json); return; } // jwt验证通过了 UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(tUser,tUser.getLoginPwd(),tUser.getAuthorities()); SecurityContextHolder.getContext().setAuthentication(authenticationToken); // 刷新一下token // 做异步执行 // new Thread(new Runnable() { // @Override // public void run() { 这里刷新token即可 从请求头中获取 // String rememberMe = request.getHeader("rememberMe"); // if (!Boolean.parseBoolean(rememberMe)) { // redisService.expire(Constants.REDIS_JWT_KEY + tUser.getId(), Constants.DEFAULT_EXPIRE_TIME, TimeUnit.SECONDS); // } // } // }).start(); // 最好使用线程池的方式去执行 // threadPoolTaskExecutor.execute(() -> { // 这里刷新token即可 // 从请求头中获取 // String rememberMe = null; // if(StringUtils.hasText(request.getHeader(Constants.REMEMBER_ME))){ // rememberMe = request.getHeader(Constants.REMEMBER_ME); // } // if (!Boolean.parseBoolean(rememberMe)) { // redisService.expire(Constants.REDIS_JWT_KEY + tUser.getId(), Constants.DEFAULT_EXPIRE_TIME, TimeUnit.SECONDS); // } // }); // 验证jwt通过了,让filter链继续执行 // 经过实验,线程池有概率导致请求和我们的service走的线程不是同一个导致请求头里面获取这个rememberMe报错 // 还是不用线程为好,慢点就慢点吧 String rememberMe = null; if(StringUtils.hasText(request.getHeader(Constants.REMEMBER_ME))){ rememberMe = request.getHeader(Constants.REMEMBER_ME); } if (!Boolean.parseBoolean(rememberMe)) { redisService.expire(Constants.REDIS_JWT_KEY + tUser.getId(), Constants.DEFAULT_EXPIRE_TIME, TimeUnit.SECONDS); } filterChain.doFilter(request,response); } } }
package com.alatus.config.filter;
import com.alatus.constant.Constants;
import com.alatus.model.TUser;
import com.alatus.result.Result;
import com.alatus.service.RedisService;
import com.alatus.util.JSONUtils;
import com.alatus.util.JWTUtils;
import com.alatus.util.ResponseUtils;
import com.alatus.result.CodeEnum;
import jakarta.annotation.Resource;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;import java.io.IOException;
import java.util.concurrent.TimeUnit;@Component
public class TokenVerifyFilter extends OncePerRequestFilter {@Resource
private RedisService redisService;
// @Resource
// // springboot框架提供的线程池,ioc容器内已经存在
// private ThreadPoolTaskExecutor threadPoolTaskExecutor;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
if (request.getRequestURI().equals(Constants.LOGIN_URI)) { //如果是登录请求,此时还没有生成jwt,那不需要对登录请求进行jwt验证
//验证jwt通过了 ,让Filter链继续执行,也就是继续执行下一个Filter
filterChain.doFilter(request, response);
} else {
String token;
if(request.getRequestURI().equals(Constants.EXPORT_EXCEL_URI)){
token = request.getParameter(Constants.TOKEN_NAME);
}
else{
token = request.getHeader(Constants.TOKEN_NAME);
}
if(!StringUtils.hasText(token)){
// 没拿到token,将失败这个枚举传回去,解析并取出常量拼接
Result result = Result.FAIL(CodeEnum.TOKEN_IS_EMPTY);
// 封装
String resultJSON = JSONUtils.toJSON(result);
// 返回
ResponseUtils.write(response,resultJSON);
return;
}
// 验证token有没有被篡改过,也是验证token合法性
if (!(JWTUtils.verifyJWT(token))){
// token不合法
Result result = Result.FAIL(CodeEnum.TOKEN_IS_NONE_MATCH);
// 封装
String resultJSON = JSONUtils.toJSON(result);
// 返回
ResponseUtils.write(response,resultJSON);
return;
}
TUser tUser = JWTUtils.parseUserFromJWT(token);
String redisToken = (String) redisService.getValue(Constants.REDIS_JWT_KEY + tUser.getId());
if(!StringUtils.hasText(redisToken)){
// 没有获取到内容说明token过期了
Result fail = Result.FAIL(CodeEnum.TOKEN_IS_EXPIRED);
String json = JSONUtils.toJSON(fail);
ResponseUtils.write(response,json);
return;
}
if (!redisToken.equals(token)) {
// 登陆失败token错误
Result result = Result.FAIL(CodeEnum.TOKEN_IS_ERROR);
// 把R对象转为JSON
String json = JSONUtils.toJSON(result);
ResponseUtils.write(response,json);
return;
}
// jwt验证通过了
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(tUser,tUser.getLoginPwd(),tUser.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
// 刷新一下token
// 做异步执行
// new Thread(new Runnable() {
// @Override
// public void run() {
这里刷新token即可
从请求头中获取
// String rememberMe = request.getHeader("rememberMe");
// if (!Boolean.parseBoolean(rememberMe)) {
// redisService.expire(Constants.REDIS_JWT_KEY + tUser.getId(), Constants.DEFAULT_EXPIRE_TIME, TimeUnit.SECONDS);
// }
// }
// }).start();
// 最好使用线程池的方式去执行
// threadPoolTaskExecutor.execute(() -> {
// 这里刷新token即可
// 从请求头中获取
// String rememberMe = null;
// if(StringUtils.hasText(request.getHeader(Constants.REMEMBER_ME))){
// rememberMe = request.getHeader(Constants.REMEMBER_ME);
// }
// if (!Boolean.parseBoolean(rememberMe)) {
// redisService.expire(Constants.REDIS_JWT_KEY + tUser.getId(), Constants.DEFAULT_EXPIRE_TIME, TimeUnit.SECONDS);
// }
// });
// 验证jwt通过了,让filter链继续执行
// 经过实验,线程池有概率导致请求和我们的service走的线程不是同一个导致请求头里面获取这个rememberMe报错
// 还是不用线程为好,慢点就慢点吧
String rememberMe = null;
if(StringUtils.hasText(request.getHeader(Constants.REMEMBER_ME))){
rememberMe = request.getHeader(Constants.REMEMBER_ME);
}
if (!Boolean.parseBoolean(rememberMe)) {
redisService.expire(Constants.REDIS_JWT_KEY + tUser.getId(), Constants.DEFAULT_EXPIRE_TIME, TimeUnit.SECONDS);
}
filterChain.doFilter(request,response);
}
}
}
package com.alatus.config.listener; import com.alatus.mapper.TClueMapper; import com.alatus.model.TClue; import com.alatus.model.TUser; import com.alatus.util.JSONUtils; import com.alatus.util.JWTUtils; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.read.listener.ReadListener; import com.alibaba.excel.util.ListUtils; import lombok.extern.slf4j.Slf4j; import java.util.Date; import java.util.List; /** * 每读一行Excel的数据,就会触发该监听器中的invoke()方法,Excel读完之后会触发该监听器中的doAfterAllAnalysed()方法 */ @Slf4j public class UploadDataListener implements ReadListener
{ /** * 每隔100条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收 */ private static final int BATCH_COUNT = 100; //缓存List private List cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT); /** * 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。 */ private TClueMapper tClueMapper; private String token; /** * 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来 * */ public UploadDataListener(TClueMapper tClueMapper, String token) { this.tClueMapper = tClueMapper; this.token = token; } /** * 这个每一条数据解析都会来调用 * */ @Override public void invoke(TClue tClue, AnalysisContext context) { log.info("读取到的每一条数据:{}", JSONUtils.toJSON(tClue)); //给读到的clue对象设置创建时间(导入时间)和创建人(导入人) tClue.setCreateTime(new Date()); TUser tUser = JWTUtils.parseUserFromJWT(token); tClue.setCreateBy(tUser.getId()); //每读取一行,就把该数据放入到一个缓存List中 cachedDataList.add(tClue); // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM if (cachedDataList.size() >= BATCH_COUNT) { //把缓存list中的数据写入到数据库 saveData(); //存储完成清空list cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT); } } /** * 所有数据解析完成了 都会来调用 * */ @Override public void doAfterAllAnalysed(AnalysisContext context) { // 这里也要保存数据,确保最后遗留的数据也存储到数据库 saveData(); log.info("所有数据解析完成!"); } /** * 加上存储数据库 */ private void saveData() { log.info("{}条数据,开始存储数据库!", cachedDataList.size()); tClueMapper.saveClue(cachedDataList); log.info("存储数据库成功!"); } }
package com.alatus.config.listener;
import com.alatus.mapper.TClueMapper;
import com.alatus.model.TClue;
import com.alatus.model.TUser;
import com.alatus.util.JSONUtils;
import com.alatus.util.JWTUtils;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.util.ListUtils;
import lombok.extern.slf4j.Slf4j;import java.util.Date;
import java.util.List;/**
* 每读一行Excel的数据,就会触发该监听器中的invoke()方法,Excel读完之后会触发该监听器中的doAfterAllAnalysed()方法
*/
@Slf4j
public class UploadDataListener implements ReadListener{ /**
* 每隔100条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收
*/
private static final int BATCH_COUNT = 100;//缓存List
private ListcachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT); /**
* 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。
*/
private TClueMapper tClueMapper;private String token;
/**
* 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
*
*/
public UploadDataListener(TClueMapper tClueMapper, String token) {
this.tClueMapper = tClueMapper;
this.token = token;
}/**
* 这个每一条数据解析都会来调用
*
*/
@Override
public void invoke(TClue tClue, AnalysisContext context) {
log.info("读取到的每一条数据:{}", JSONUtils.toJSON(tClue));
//给读到的clue对象设置创建时间(导入时间)和创建人(导入人)
tClue.setCreateTime(new Date());
TUser tUser = JWTUtils.parseUserFromJWT(token);
tClue.setCreateBy(tUser.getId());
//每读取一行,就把该数据放入到一个缓存List中
cachedDataList.add(tClue);
// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
if (cachedDataList.size() >= BATCH_COUNT) {
//把缓存list中的数据写入到数据库
saveData();//存储完成清空list
cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
}
}/**
* 所有数据解析完成了 都会来调用
*
*/
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
// 这里也要保存数据,确保最后遗留的数据也存储到数据库
saveData();
log.info("所有数据解析完成!");
}/**
* 加上存储数据库
*/
private void saveData() {
log.info("{}条数据,开始存储数据库!", cachedDataList.size());
tClueMapper.saveClue(cachedDataList);
log.info("存储数据库成功!");
}
}
package com.alatus.config; import com.alatus.config.filter.TokenVerifyFilter; import com.alatus.config.handler.MyAccessDeniedHandler; import com.alatus.config.handler.MyAuthenticationFailureHandler; import com.alatus.config.handler.MyAuthenticationSuccessHandler; import com.alatus.config.handler.MyLogoutSuccessHandler; import com.alatus.constant.Constants; import jakarta.annotation.Resource; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.logout.LogoutFilter; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.CorsConfigurationSource; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import java.util.Arrays; //开启方法级别的权限检查 @EnableMethodSecurity @Configuration public class SecurityConfig { @Resource private MyAuthenticationSuccessHandler myAuthenticationSuccessHandler; @Resource private MyLogoutSuccessHandler myLogoutSuccessHandler; @Resource private TokenVerifyFilter tokenVerifyFilter; // 权限不足 @Resource private MyAccessDeniedHandler myAccessDeniedHandler; // 配置加密器 @Bean public PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } @Resource private MyAuthenticationFailureHandler myAuthenticationFailureHandler; @Bean public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity,CorsConfigurationSource configurationSource) throws Exception{ return httpSecurity .formLogin((formLogin) -> { formLogin.loginProcessingUrl((Constants.LOGIN_URI)) .usernameParameter("loginAct") .passwordParameter("loginPwd") .successHandler(myAuthenticationSuccessHandler) .failureHandler(myAuthenticationFailureHandler); }) // SecurityFilterChain改变了默认行为,不再拦截了,需要手动拦截 .authorizeHttpRequests((authorize) -> { // 对任何请求进行拦截,任何请求都需要登录才可以访问 // /api/login这个请求放开,其他请求正常拦截 authorize.requestMatchers(Constants.LOGIN_URI).permitAll().anyRequest().authenticated(); }) .csrf((csrf) -> { //禁用跨站请求伪造 csrf.disable(); }) //支持跨域请求 .cors((cors)->{ cors.configurationSource(configurationSource); }) .sessionManagement((session) -> { // 让session的创建策略为不创建 session.sessionCreationPolicy(SessionCreationPolicy.STATELESS); }) // 添加我们自定义的filter .addFilterBefore(tokenVerifyFilter, LogoutFilter.class) // 退出登录 .logout((logout) -> { // 退出的地址,这个也不需要我们写controller logout.logoutUrl("/api/logOut").logoutSuccessHandler(myLogoutSuccessHandler); }) //无权限时的处理方法 .exceptionHandling((exceptionHandling) -> { exceptionHandling.accessDeniedHandler(myAccessDeniedHandler); }) .build(); } @Bean public CorsConfigurationSource configurationSource(){ CorsConfiguration corsConfiguration = new CorsConfiguration(); corsConfiguration.setAllowedOrigins(Arrays.asList("*"));//允许任意来源 corsConfiguration.setAllowedMethods(Arrays.asList("*"));//允许任意方法请求 corsConfiguration.setAllowedHeaders(Arrays.asList("*"));//允许请求头任意内容 UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); // 任何路径都按这个来 source.registerCorsConfiguration("/**",corsConfiguration); return source; } }
package com.alatus.config;
import com.alatus.config.filter.TokenVerifyFilter;
import com.alatus.config.handler.MyAccessDeniedHandler;
import com.alatus.config.handler.MyAuthenticationFailureHandler;
import com.alatus.config.handler.MyAuthenticationSuccessHandler;
import com.alatus.config.handler.MyLogoutSuccessHandler;
import com.alatus.constant.Constants;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import java.util.Arrays;//开启方法级别的权限检查
@EnableMethodSecurity
@Configuration
public class SecurityConfig {
@Resource
private MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;
@Resource
private MyLogoutSuccessHandler myLogoutSuccessHandler;
@Resource
private TokenVerifyFilter tokenVerifyFilter;
// 权限不足
@Resource
private MyAccessDeniedHandler myAccessDeniedHandler;// 配置加密器
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Resource
private MyAuthenticationFailureHandler myAuthenticationFailureHandler;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity,CorsConfigurationSource configurationSource) throws Exception{
return httpSecurity
.formLogin((formLogin) -> {
formLogin.loginProcessingUrl((Constants.LOGIN_URI))
.usernameParameter("loginAct")
.passwordParameter("loginPwd")
.successHandler(myAuthenticationSuccessHandler)
.failureHandler(myAuthenticationFailureHandler);
})
// SecurityFilterChain改变了默认行为,不再拦截了,需要手动拦截
.authorizeHttpRequests((authorize) -> {
// 对任何请求进行拦截,任何请求都需要登录才可以访问
// /api/login这个请求放开,其他请求正常拦截
authorize.requestMatchers(Constants.LOGIN_URI).permitAll().anyRequest().authenticated();
})
.csrf((csrf) -> {
//禁用跨站请求伪造
csrf.disable();
})
//支持跨域请求
.cors((cors)->{
cors.configurationSource(configurationSource);
})
.sessionManagement((session) -> {
// 让session的创建策略为不创建
session.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
})
// 添加我们自定义的filter
.addFilterBefore(tokenVerifyFilter, LogoutFilter.class)
// 退出登录
.logout((logout) -> {
// 退出的地址,这个也不需要我们写controller
logout.logoutUrl("/api/logOut").logoutSuccessHandler(myLogoutSuccessHandler);
})
//无权限时的处理方法
.exceptionHandling((exceptionHandling) -> {
exceptionHandling.accessDeniedHandler(myAccessDeniedHandler);
})
.build();
}
@Bean
public CorsConfigurationSource configurationSource(){
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.setAllowedOrigins(Arrays.asList("*"));//允许任意来源
corsConfiguration.setAllowedMethods(Arrays.asList("*"));//允许任意方法请求
corsConfiguration.setAllowedHeaders(Arrays.asList("*"));//允许请求头任意内容
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
// 任何路径都按这个来
source.registerCorsConfiguration("/**",corsConfiguration);
return source;
}
}
package com.alatus.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; @Configuration public class RedisConfig { @Bean public RedisTemplate
redisTemplate(LettuceConnectionFactory lettuceConnectionFactory){ RedisTemplate redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(lettuceConnectionFactory); redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer()); redisTemplate.setHashKeySerializer(new StringRedisSerializer()); redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer()); redisTemplate.afterPropertiesSet(); return redisTemplate; } }
package com.alatus.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;@Configuration
public class RedisConfig
{
@Bean
public RedisTemplateredisTemplate(LettuceConnectionFactory lettuceConnectionFactory){
RedisTemplateredisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(lettuceConnectionFactory);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}