feat(新增): Redis乱码问题,获取当前登录用户信息,用户退出接口
This commit is contained in:
parent
8cb99adc5e
commit
5bcd1428c2
|
@ -1,6 +1,13 @@
|
||||||
<component name="InspectionProjectProfileManager">
|
<component name="InspectionProjectProfileManager">
|
||||||
<profile version="1.0">
|
<profile version="1.0">
|
||||||
<option name="myName" value="Project Default" />
|
<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="RawUseOfParameterizedType" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||||
<inspection_tool class="UNCHECKED_WARNING" enabled="false" level="WARNING" enabled_by_default="false" />
|
<inspection_tool class="UNCHECKED_WARNING" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||||
</profile>
|
</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 CAPTCHA_IS_EMPTY = "提交验证码不能为空";
|
||||||
public static final String KEY_IS_EMPTY = "验证码key不能为空";
|
public static final String KEY_IS_EMPTY = "验证码key不能为空";
|
||||||
public static final String VERIFICATION_CODE_DOES_NOT_MATCH = "验证码不匹配";
|
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
|
@ResponseBody
|
||||||
public Result<Object> exceptionHandler(RuntimeException exception) {
|
public Result<Object> exceptionHandler(RuntimeException exception) {
|
||||||
log.error("运行时异常信息:{}", exception.getMessage());
|
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.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.cache.annotation.EnableCaching;
|
||||||
import org.springframework.context.annotation.ComponentScan;
|
import org.springframework.context.annotation.ComponentScan;
|
||||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
|
@EnableCaching
|
||||||
@EnableScheduling
|
@EnableScheduling
|
||||||
@ComponentScan("com.atguigu")
|
@ComponentScan("com.atguigu")
|
||||||
public class MangerApplication {
|
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.SysUserService;
|
||||||
import com.atguigu.spzx.manger.service.ValidateCodeService;
|
import com.atguigu.spzx.manger.service.ValidateCodeService;
|
||||||
import com.atguigu.spzx.model.dto.system.LoginDto;
|
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.Result;
|
||||||
import com.atguigu.spzx.model.vo.result.ResultCodeEnum;
|
|
||||||
import com.atguigu.spzx.model.vo.system.LoginVo;
|
import com.atguigu.spzx.model.vo.system.LoginVo;
|
||||||
import com.atguigu.spzx.model.vo.system.ValidateCodeVo;
|
import com.atguigu.spzx.model.vo.system.ValidateCodeVo;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
@ -21,17 +21,31 @@ public class IndexController {
|
||||||
@Autowired
|
@Autowired
|
||||||
private ValidateCodeService validateCodeService;
|
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 = "生成验证码信息")
|
@Operation(summary = "生成验证码", description = "生成验证码信息")
|
||||||
@GetMapping("generateValidateCode")
|
@GetMapping("generateValidateCode")
|
||||||
public Result<ValidateCodeVo> generateValidateCode() {
|
public Result<ValidateCodeVo> generateValidateCode() {
|
||||||
ValidateCodeVo vo = validateCodeService.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;
|
package com.atguigu.spzx.manger.service;
|
||||||
|
|
||||||
import com.atguigu.spzx.model.dto.system.LoginDto;
|
import com.atguigu.spzx.model.dto.system.LoginDto;
|
||||||
|
import com.atguigu.spzx.model.entity.system.SysUser;
|
||||||
import com.atguigu.spzx.model.vo.system.LoginVo;
|
import com.atguigu.spzx.model.vo.system.LoginVo;
|
||||||
|
|
||||||
public interface SysUserService {
|
public interface SysUserService {
|
||||||
|
@ -11,4 +12,19 @@ public interface SysUserService {
|
||||||
* @return 登录后结果
|
* @return 登录后结果
|
||||||
*/
|
*/
|
||||||
LoginVo login(LoginDto loginDto);
|
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
|
@Autowired
|
||||||
private SysUserMapper sysUserMapper;
|
private SysUserMapper sysUserMapper;
|
||||||
@Autowired
|
@Autowired
|
||||||
private RedisTemplate redisTemplate;
|
private RedisTemplate<String, Object> redisTemplate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* * 登录请求实现
|
* * 登录请求实现
|
||||||
|
@ -38,12 +38,14 @@ public class SysUserServiceImpl implements SysUserService {
|
||||||
String userName = loginDto.getUserName();
|
String userName = loginDto.getUserName();
|
||||||
String captcha = loginDto.getCaptcha();
|
String captcha = loginDto.getCaptcha();
|
||||||
String key = loginDto.getCodeKey();
|
String key = loginDto.getCodeKey();
|
||||||
|
// 得到Redis中验证码
|
||||||
|
String code = (String) redisTemplate.opsForValue().get(key);
|
||||||
stringEmptyUtil.isEmpty(userName, EnumException.USERNAME_IS_EMPTY);
|
stringEmptyUtil.isEmpty(userName, EnumException.USERNAME_IS_EMPTY);
|
||||||
stringEmptyUtil.isEmpty(password, EnumException.PASSWORD_IS_EMPTY);
|
stringEmptyUtil.isEmpty(password, EnumException.PASSWORD_IS_EMPTY);
|
||||||
stringEmptyUtil.isEmpty(captcha, EnumException.CAPTCHA_IS_EMPTY);
|
stringEmptyUtil.isEmpty(captcha, EnumException.CAPTCHA_IS_EMPTY);
|
||||||
stringEmptyUtil.isEmpty(key, EnumException.KEY_IS_EMPTY);
|
stringEmptyUtil.isEmpty(key, EnumException.KEY_IS_EMPTY);
|
||||||
// 得到Redis中验证码
|
stringEmptyUtil.isEmpty(code, EnumException.VERIFICATION_CODE_IS_EMPTY);
|
||||||
String code = (String) redisTemplate.opsForValue().get(key);
|
|
||||||
// 验证码不匹配
|
// 验证码不匹配
|
||||||
assert code != null;
|
assert code != null;
|
||||||
if ((!Objects.equals(code.toLowerCase(), captcha.toLowerCase()))) {
|
if ((!Objects.equals(code.toLowerCase(), captcha.toLowerCase()))) {
|
||||||
|
@ -63,8 +65,32 @@ public class SysUserServiceImpl implements SysUserService {
|
||||||
}
|
}
|
||||||
// 登录成功
|
// 登录成功
|
||||||
String token = UUID.randomUUID().toString().replaceAll("-", "");
|
String token = UUID.randomUUID().toString().replaceAll("-", "");
|
||||||
redisTemplate.opsForValue().set(userName, token, 7, TimeUnit.DAYS);
|
redisTemplate.opsForValue().set(token, userName, 7, TimeUnit.DAYS);
|
||||||
// 返回loginVo对象
|
// 返回loginVo对象
|
||||||
return LoginVo.builder().token(token).build();
|
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 com.atguigu.spzx.model.entity.base.BaseEntity;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.Data;
|
import lombok.*;
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@Data
|
@Data
|
||||||
|
@Builder
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
@Schema(description = "系统用户实体类")
|
@Schema(description = "系统用户实体类")
|
||||||
public class SysUser extends BaseEntity {
|
public class SysUser extends BaseEntity {
|
||||||
|
@Schema(description = "用户名")
|
||||||
|
private String userName;
|
||||||
|
|
||||||
@Schema(description = "用户名")
|
@Schema(description = "密码")
|
||||||
private String userName;
|
private String password;
|
||||||
|
|
||||||
@Schema(description = "密码")
|
@Schema(description = "昵称")
|
||||||
private String password;
|
private String name;
|
||||||
|
|
||||||
@Schema(description = "昵称")
|
@Schema(description = "手机号码")
|
||||||
private String name;
|
private String phone;
|
||||||
|
|
||||||
@Schema(description = "手机号码")
|
@Schema(description = "图像")
|
||||||
private String phone;
|
private String avatar;
|
||||||
|
|
||||||
@Schema(description = "图像")
|
@Schema(description = "描述")
|
||||||
private String avatar;
|
private String description;
|
||||||
|
|
||||||
@Schema(description = "描述")
|
|
||||||
private String description;
|
|
||||||
|
|
||||||
@Schema(description = "状态(1:正常 0:停用)")
|
|
||||||
private Integer status;
|
|
||||||
|
|
||||||
|
@Schema(description = "状态(1:正常 0:停用)")
|
||||||
|
private Integer status;
|
||||||
}
|
}
|
|
@ -64,7 +64,7 @@ public class Result<T> {
|
||||||
* @return Result<T>
|
* @return Result<T>
|
||||||
*/
|
*/
|
||||||
public static <T> Result<T> success() {
|
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