feat(新增): Redis乱码问题,获取当前登录用户信息,用户退出接口
This commit is contained in:
parent
8cb99adc5e
commit
5bcd1428c2
|
@ -1,6 +1,13 @@
|
|||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="IncorrectHttpHeaderInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="customHeaders">
|
||||
<set>
|
||||
<option value="token" />
|
||||
</set>
|
||||
</option>
|
||||
</inspection_tool>
|
||||
<inspection_tool class="RawUseOfParameterizedType" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="UNCHECKED_WARNING" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
</profile>
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
package com.atguigu.config;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||
import com.fasterxml.jackson.annotation.PropertyAccessor;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.cache.RedisCacheConfiguration;
|
||||
import org.springframework.data.redis.cache.RedisCacheManager;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
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.Jackson2JsonRedisSerializer;
|
||||
import org.springframework.data.redis.serializer.RedisSerializationContext;
|
||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
@Configuration
|
||||
@Slf4j
|
||||
public class RedisConfiguration {
|
||||
/**
|
||||
* 使用StringRedisSerializer序列化为字符串
|
||||
*/
|
||||
@Bean
|
||||
public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory factory) {
|
||||
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
|
||||
redisTemplate.setConnectionFactory(factory);
|
||||
// 设置key序列化为String
|
||||
redisTemplate.setKeySerializer(new StringRedisSerializer());
|
||||
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
|
||||
// 设置value序列化为JSON,使用GenericJackson2JsonRedisSerializer替换默认的序列化
|
||||
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
|
||||
redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
|
||||
return redisTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解决cache(@Cacheable)把数据缓存到redis中的value是乱码问题
|
||||
*/
|
||||
@Bean
|
||||
@SuppressWarnings("all")
|
||||
public CacheManager cacheManager(RedisConnectionFactory factory) {
|
||||
StringRedisSerializer redisSerializer = new StringRedisSerializer();
|
||||
// json序列化
|
||||
Jackson2JsonRedisSerializer<Object> serializer = jsonRedisSerializer();
|
||||
// 配置序列化
|
||||
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
|
||||
RedisCacheConfiguration redisCacheConfiguration = config
|
||||
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
|
||||
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer));
|
||||
|
||||
return RedisCacheManager.builder(factory).cacheDefaults(redisCacheConfiguration).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定的日期模式
|
||||
*/
|
||||
public Jackson2JsonRedisSerializer<Object> jsonRedisSerializer() {
|
||||
// LocalDatetime序列化,默认不兼容jdk8日期序列化
|
||||
JavaTimeModule javaTimeModule = new JavaTimeModule();
|
||||
javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
|
||||
javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
|
||||
javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
||||
javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
// 设置Object访问权限
|
||||
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
|
||||
// 记录序列化之后的数据类型,方便反序列化
|
||||
mapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
|
||||
// 关闭默认的日期格式化方式,默认UTC日期格式 yyyy-MM-dd’T’HH:mm:ss.SSS
|
||||
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
|
||||
mapper.registerModule(javaTimeModule);
|
||||
|
||||
return new Jackson2JsonRedisSerializer<>(mapper, Object.class);
|
||||
}
|
||||
}
|
|
@ -12,4 +12,5 @@ public class EnumException {
|
|||
public static final String CAPTCHA_IS_EMPTY = "提交验证码不能为空";
|
||||
public static final String KEY_IS_EMPTY = "验证码key不能为空";
|
||||
public static final String VERIFICATION_CODE_DOES_NOT_MATCH = "验证码不匹配";
|
||||
public static final String VERIFICATION_CODE_IS_EMPTY = "验证码失效或不存在";
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ public class GlobalExceptionHandler {
|
|||
@ResponseBody
|
||||
public Result<Object> exceptionHandler(RuntimeException exception) {
|
||||
log.error("运行时异常信息:{}", exception.getMessage());
|
||||
return Result.error(500, exception.getMessage());
|
||||
return Result.error(500, "出错了啦");
|
||||
}
|
||||
|
||||
// 捕获系统异常
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -2,10 +2,12 @@ package com.atguigu.spzx.manger;
|
|||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableCaching
|
||||
@EnableScheduling
|
||||
@ComponentScan("com.atguigu")
|
||||
public class MangerApplication {
|
||||
|
|
|
@ -3,8 +3,8 @@ package com.atguigu.spzx.manger.controller;
|
|||
import com.atguigu.spzx.manger.service.SysUserService;
|
||||
import com.atguigu.spzx.manger.service.ValidateCodeService;
|
||||
import com.atguigu.spzx.model.dto.system.LoginDto;
|
||||
import com.atguigu.spzx.model.entity.system.SysUser;
|
||||
import com.atguigu.spzx.model.vo.result.Result;
|
||||
import com.atguigu.spzx.model.vo.result.ResultCodeEnum;
|
||||
import com.atguigu.spzx.model.vo.system.LoginVo;
|
||||
import com.atguigu.spzx.model.vo.system.ValidateCodeVo;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
|
@ -21,17 +21,31 @@ public class IndexController {
|
|||
@Autowired
|
||||
private ValidateCodeService validateCodeService;
|
||||
|
||||
@Operation(summary = "登录请求", description = "登录请求实现")
|
||||
@PostMapping("login")
|
||||
public Result<LoginVo> login(@RequestBody LoginDto loginDto) {
|
||||
LoginVo vo = sysUserService.login(loginDto);
|
||||
return Result.success(vo, ResultCodeEnum.SUCCESS);
|
||||
}
|
||||
|
||||
@Operation(summary = "生成验证码", description = "生成验证码信息")
|
||||
@GetMapping("generateValidateCode")
|
||||
public Result<ValidateCodeVo> generateValidateCode() {
|
||||
ValidateCodeVo vo = validateCodeService.generateValidateCode();
|
||||
return Result.success(vo, ResultCodeEnum.SUCCESS);
|
||||
return Result.success(vo);
|
||||
}
|
||||
|
||||
@Operation(summary = "登录请求", description = "登录请求实现")
|
||||
@PostMapping("login")
|
||||
public Result<LoginVo> login(@RequestBody LoginDto loginDto) {
|
||||
LoginVo vo = sysUserService.login(loginDto);
|
||||
return Result.success(vo);
|
||||
}
|
||||
|
||||
@Operation(summary = "获取登录用户信息", description = "获取当前登录用户信息")
|
||||
@GetMapping("getUserInfo")
|
||||
public Result<SysUser> getUserInfo(@RequestHeader(name = "token") String token) {
|
||||
SysUser sysUser = sysUserService.getUserInfo(token);
|
||||
return Result.success(sysUser);
|
||||
}
|
||||
|
||||
@Operation(summary = "用户退出", description = "用户退出接口")
|
||||
@GetMapping(value = "/logout")
|
||||
public Result logout(@RequestHeader(value = "token") String token) {
|
||||
sysUserService.logout(token);
|
||||
return Result.success();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.atguigu.spzx.manger.service;
|
||||
|
||||
import com.atguigu.spzx.model.dto.system.LoginDto;
|
||||
import com.atguigu.spzx.model.entity.system.SysUser;
|
||||
import com.atguigu.spzx.model.vo.system.LoginVo;
|
||||
|
||||
public interface SysUserService {
|
||||
|
@ -11,4 +12,19 @@ public interface SysUserService {
|
|||
* @return 登录后结果
|
||||
*/
|
||||
LoginVo login(LoginDto loginDto);
|
||||
|
||||
/**
|
||||
* * 获取当前登录用户信息
|
||||
*
|
||||
* @param token token值
|
||||
* @return 用户信息
|
||||
*/
|
||||
SysUser getUserInfo(String token);
|
||||
|
||||
/**
|
||||
* * 用户退出接口
|
||||
*
|
||||
* @param token token值
|
||||
*/
|
||||
void logout(String token);
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ public class SysUserServiceImpl implements SysUserService {
|
|||
@Autowired
|
||||
private SysUserMapper sysUserMapper;
|
||||
@Autowired
|
||||
private RedisTemplate redisTemplate;
|
||||
private RedisTemplate<String, Object> redisTemplate;
|
||||
|
||||
/**
|
||||
* * 登录请求实现
|
||||
|
@ -38,12 +38,14 @@ public class SysUserServiceImpl implements SysUserService {
|
|||
String userName = loginDto.getUserName();
|
||||
String captcha = loginDto.getCaptcha();
|
||||
String key = loginDto.getCodeKey();
|
||||
// 得到Redis中验证码
|
||||
String code = (String) redisTemplate.opsForValue().get(key);
|
||||
stringEmptyUtil.isEmpty(userName, EnumException.USERNAME_IS_EMPTY);
|
||||
stringEmptyUtil.isEmpty(password, EnumException.PASSWORD_IS_EMPTY);
|
||||
stringEmptyUtil.isEmpty(captcha, EnumException.CAPTCHA_IS_EMPTY);
|
||||
stringEmptyUtil.isEmpty(key, EnumException.KEY_IS_EMPTY);
|
||||
// 得到Redis中验证码
|
||||
String code = (String) redisTemplate.opsForValue().get(key);
|
||||
stringEmptyUtil.isEmpty(code, EnumException.VERIFICATION_CODE_IS_EMPTY);
|
||||
|
||||
// 验证码不匹配
|
||||
assert code != null;
|
||||
if ((!Objects.equals(code.toLowerCase(), captcha.toLowerCase()))) {
|
||||
|
@ -63,8 +65,32 @@ public class SysUserServiceImpl implements SysUserService {
|
|||
}
|
||||
// 登录成功
|
||||
String token = UUID.randomUUID().toString().replaceAll("-", "");
|
||||
redisTemplate.opsForValue().set(userName, token, 7, TimeUnit.DAYS);
|
||||
redisTemplate.opsForValue().set(token, userName, 7, TimeUnit.DAYS);
|
||||
// 返回loginVo对象
|
||||
return LoginVo.builder().token(token).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* * 获取当前登录用户信息
|
||||
*
|
||||
* @param token token值
|
||||
* @return 用户信息
|
||||
*/
|
||||
@Override
|
||||
public SysUser getUserInfo(String token) {
|
||||
String username = (String) redisTemplate.opsForValue().get(token);
|
||||
SysUser sysUser = sysUserMapper.selectByUsername(username);
|
||||
sysUser.setPassword("******");
|
||||
return sysUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* * 用户退出接口
|
||||
*
|
||||
* @param token token值
|
||||
*/
|
||||
@Override
|
||||
public void logout(String token) {
|
||||
redisTemplate.delete(token);
|
||||
}
|
||||
}
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -2,31 +2,33 @@ package com.atguigu.spzx.model.entity.system;
|
|||
|
||||
import com.atguigu.spzx.model.entity.base.BaseEntity;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.*;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Schema(description = "系统用户实体类")
|
||||
public class SysUser extends BaseEntity {
|
||||
@Schema(description = "用户名")
|
||||
private String userName;
|
||||
|
||||
@Schema(description = "用户名")
|
||||
private String userName;
|
||||
@Schema(description = "密码")
|
||||
private String password;
|
||||
|
||||
@Schema(description = "密码")
|
||||
private String password;
|
||||
@Schema(description = "昵称")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "昵称")
|
||||
private String name;
|
||||
@Schema(description = "手机号码")
|
||||
private String phone;
|
||||
|
||||
@Schema(description = "手机号码")
|
||||
private String phone;
|
||||
@Schema(description = "图像")
|
||||
private String avatar;
|
||||
|
||||
@Schema(description = "图像")
|
||||
private String avatar;
|
||||
|
||||
@Schema(description = "描述")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "状态(1:正常 0:停用)")
|
||||
private Integer status;
|
||||
@Schema(description = "描述")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "状态(1:正常 0:停用)")
|
||||
private Integer status;
|
||||
}
|
|
@ -64,7 +64,7 @@ public class Result<T> {
|
|||
* @return Result<T>
|
||||
*/
|
||||
public static <T> Result<T> success() {
|
||||
return Result.success(null);
|
||||
return Result.success(null, ResultCodeEnum.SUCCESS);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue