接入缓存功能、登录退出功能完善、业务逻辑判断完善

wxpay
LI-CCONG\李聪聪 8 months ago
parent eeba3f1613
commit 849e4149ac

@ -12,6 +12,7 @@ import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.Objects;
/**
@ -23,24 +24,24 @@ import java.util.Objects;
@Slf4j
public class JudgeUserAspect {
@Pointcut( "@annotation(UserTypeAnnotation)" )
@Pointcut( "@annotation(UserTypeAnnotation) || @within(UserTypeAnnotation)" )
public void catCut(){}
@Before( "catCut()" )
public void judgeCurrentUser(JoinPoint joinPoint) {
// 获取方法信息
try {
MethodSignature methodSignature = (MethodSignature)joinPoint.getSignature();
UserTypeAnnotation annotation = methodSignature.getMethod().getAnnotation(UserTypeAnnotation.class);
UserTypeEnum typeEnum = annotation.value();
UserDTO currentUser = UserContext.getUser();
log.info("请求控制器: {}, 当前用户信息: {}", methodSignature, currentUser);
if (currentUser == null || !Objects.equals(currentUser.getUserType(), typeEnum.getCode())) {
throw new UnauthorizedException("非法请求!");
}
} catch (Exception exception) {
throw new RuntimeException("非法请求!");
MethodSignature methodSignature = (MethodSignature)joinPoint.getSignature();
Method method = methodSignature.getMethod();
UserTypeAnnotation annotation = method.getAnnotation(UserTypeAnnotation.class);
if (annotation == null) {
annotation = method.getDeclaringClass().getAnnotation(UserTypeAnnotation.class);
}
UserTypeEnum typeEnum = annotation.value();
UserDTO currentUser = UserContext.getUser();
log.info("请求控制器: {}, 当前用户信息: {}", methodSignature, currentUser);
if (currentUser == null || !Objects.equals(currentUser.getUserType(), typeEnum)) {
throw new UnauthorizedException("非法请求!");
}
}
}

@ -7,7 +7,7 @@ import java.lang.annotation.*;
@Documented
@Target({ElementType.METHOD})
@Target({ElementType.METHOD, ElementType.TYPE})
@Inherited
//注解会在class字节码文件中存在在运行时可以通过反射获取到
@Retention(RetentionPolicy.RUNTIME)

@ -0,0 +1,107 @@
package cc.yunxi.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
* redis bean
*/
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
@Bean
@ConditionalOnClass(ObjectMapper.class)
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
// 连接配置工厂
redisTemplate.setConnectionFactory(redisConnectionFactory);
//使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值默认使用JDK的序列化方式
Jackson2JsonRedisSerializer jacksonSeial = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
// 指定要序列化的域field,get和set,以及修饰符范围ANY是都有包括private和public
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// 指定序列化输入的类型类必须是非final修饰的final修饰的类比如String,Integer等会跑出异常
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jacksonSeial.setObjectMapper(om);
// value值采用json序列化
redisTemplate.setValueSerializer(jacksonSeial);
//使用StringRedisSerializer来序列化和反序列化redis的key值
redisTemplate.setKeySerializer(new StringRedisSerializer());
// 设置hash key 和value序列化模式
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(jacksonSeial);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
/**
* hash
*
* @param redisTemplate
* @return
*/
@Bean
public HashOperations<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForHash();
}
/**
* redis
*
* @param redisTemplate
* @return
*/
@Bean
public ValueOperations<String, Object> valueOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForValue();
}
/**
*
*
* @param redisTemplate
* @return
*/
@Bean
public ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForList();
}
/**
*
*
* @param redisTemplate
* @return
*/
@Bean
public SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForSet();
}
/**
*
*
* @param redisTemplate
* @return
*/
@Bean
public ZSetOperations<String, Object> zSetOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForZSet();
}
}

@ -35,15 +35,11 @@ public class CommonController {
private final CommonService commonService;
@Resource
private JwtTool jwtTool;
@ApiOperation("回收员登录")
@PostMapping("/hsylogin")
public CommonResult<UserDTO> hsyLogin(@Valid @RequestBody WxLoginDTO wxLoginDTO) {
UserDTO userDTO = commonService.loginByRecycler(wxLoginDTO);
String token = jwtTool.createToken(userDTO);
userDTO.setToken(token);
return CommonResult.success(userDTO);
}
@ -52,17 +48,15 @@ public class CommonController {
public CommonResult<UserDTO> shLogin(@Valid @RequestBody WxLoginDTO wxLoginDTO) {
// 散户端登录业务
UserDTO userDTO = commonService.loginByClient(wxLoginDTO);
String token = jwtTool.createToken(userDTO);
userDTO.setToken(token);
return CommonResult.success(userDTO);
}
@ApiOperation("退出")
@GetMapping("/logout")
public CommonResult<String> logout() {
// todo
return CommonResult.success("login success");
public CommonResult<Boolean> logout(@RequestHeader("authorization") String token) {
commonService.logout(token);
return CommonResult.success(true);
}

@ -1,5 +1,6 @@
package cc.yunxi.controller;
import cc.yunxi.aspect.UserTypeAnnotation;
import cc.yunxi.common.domain.CommonResult;
import cc.yunxi.common.domain.PageDTO;
import cc.yunxi.common.utils.BeanUtils;
@ -8,6 +9,7 @@ import cc.yunxi.domain.po.Recycler;
import cc.yunxi.domain.query.RecyclerQuery;
import cc.yunxi.domain.vo.recycler.RecyclerRespVO;
import cc.yunxi.domain.vo.recycler.RecyclerUpdateVO;
import cc.yunxi.enums.UserTypeEnum;
import cc.yunxi.service.IRecyclerService;
import cc.yunxi.utils.UserContext;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@ -20,6 +22,7 @@ import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/recycler")
@RequiredArgsConstructor
@UserTypeAnnotation(UserTypeEnum.RECYCLER)
public class RecyclerController {
private final IRecyclerService recyclerService;
@ -40,7 +43,7 @@ public class RecyclerController {
public CommonResult<RecyclerRespVO> getRecyclerInfo() {
// 获取当前用户信息
UserDTO userDTO = UserContext.getUser();
Recycler recycler = recyclerService.getById(userDTO.getId());
Recycler recycler = recyclerService.getRecyclerById(userDTO.getId());
RecyclerRespVO recyclerDTO = BeanUtils.copyBean(recycler, RecyclerRespVO.class);
return CommonResult.success(recyclerDTO);
}

@ -30,6 +30,9 @@ public class UserDTO {
@ApiModelProperty(value = "openid", required = true)
private String openid;
@ApiModelProperty(value = "有效时长(s)", required = true)
private Long timeExpire;
@ApiModelProperty(value = "访问token", required = false)
private String token; // 返回时有用

@ -1,8 +1,12 @@
package cc.yunxi.interceptor;
import cc.yunxi.common.exception.BizIllegalException;
import cc.yunxi.domain.dto.UserDTO;
import cc.yunxi.service.impl.CommonService;
import cc.yunxi.utils.JwtTool;
import cc.yunxi.utils.RedisTool;
import cc.yunxi.utils.UserContext;
import cn.hutool.core.util.ObjectUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@ -18,11 +22,19 @@ public class LoginInterceptor implements HandlerInterceptor {
private final JwtTool jwtTool;
private final RedisTool redisTool;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 1.获取请求头中的 token
String token = request.getHeader("authorization");
// 2.校验token
// 2.缓存中读取token信息
boolean existsKey = redisTool.existsKey(CommonService.TOKEN_KEY + token);
if (!existsKey) {
throw new BizIllegalException("token已过期");
}
// 这里userInfo可以来自缓存 todo
// 3.校验token
UserDTO userInfo = jwtTool.parseToken(token);
log.info("当前用户信息: 【{}】", userInfo);
// 3.存入上下文

@ -11,8 +11,8 @@ public interface ICommonService {
/**
*
* @param userJson
* @param openid
* @param wxLoginDTO
* @return UserDTO
* @return
*/
UserDTO loginByRecycler(WxLoginDTO wxLoginDTO);
@ -20,9 +20,15 @@ public interface ICommonService {
/**
*
* @param userJson
* @param openid
* @return
* @param wxLoginDTO
* @return UserDTO
*/
UserDTO loginByClient(WxLoginDTO wxLoginDTO);
/**
* 退
* @param token
*/
void logout(String token);
}

@ -5,6 +5,7 @@ import cc.yunxi.common.exception.DbException;
import cc.yunxi.common.utils.BeanUtils;
import cc.yunxi.domain.dto.UserDTO;
import cc.yunxi.domain.po.Client;
import cc.yunxi.domain.po.RecycleOrder;
import cc.yunxi.domain.po.Recycler;
import cc.yunxi.domain.query.ClientQuery;
import cc.yunxi.domain.query.RecyclerQuery;
@ -48,7 +49,14 @@ public class ClientServiceImpl extends ServiceImpl<ClientMapper, Client> impleme
@Override
public Client getClientById(String id) {
return this.getById(id);
if (StrUtil.isEmpty(id)) {
throw new BizIllegalException("请求参数缺失");
}
Client client = this.getById(id);
if (client == null) {
throw new BizIllegalException("散户不存在");
}
return client;
}
@Override
@ -85,7 +93,7 @@ public class ClientServiceImpl extends ServiceImpl<ClientMapper, Client> impleme
// 校验散户是否存在
private void validateClientExists(String id) {
if (this.getClientById(id) == null) {
throw new DbException("散户不存在");
throw new BizIllegalException("散户不存在");
}
}
}

@ -12,6 +12,7 @@ import cc.yunxi.service.IClientService;
import cc.yunxi.service.ICommonService;
import cc.yunxi.service.IRecyclerService;
import cc.yunxi.utils.JwtTool;
import cc.yunxi.utils.RedisTool;
import cc.yunxi.utils.WeChatUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
@ -22,12 +23,15 @@ import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Date;
/**
*
*/
@Service
@Slf4j
//@CacheConfig(cacheNames = "AUTH_TOKEN")
public class CommonService implements ICommonService {
@Resource
@ -36,15 +40,23 @@ public class CommonService implements ICommonService {
@Resource
private IClientService clientService;
@Resource
private RedisTool redisTool;
@Resource
private WxHsyProperties wxHsyProperties;
@Resource
private WxShProperties wxShProperties;
@Resource
private JwtTool jwtTool;
private static final String code2SessionUrl = "https://api.weixin.qq.com/sns/jscode2session";
public static final String TOKEN_KEY = "AUTH_TOKEN_";
private UserDTO wxAuthentication(WxLoginDTO wxLoginDTO) {
log.info("login request body{}", wxLoginDTO);
// String url = code2SessionUrl +"?appid=" + wxHsyProperties.getAppId() +
@ -92,6 +104,7 @@ public class CommonService implements ICommonService {
userDTO.setStationId(recycler.getStationId());
userDTO.setUserType(UserTypeEnum.RECYCLER);
userDTO.setUsername(recycler.getStaffsName());
userDTO.setToken(this.createToken(userDTO));
return userDTO;
}
@ -106,6 +119,34 @@ public class CommonService implements ICommonService {
userDTO.setId(client.getId());
userDTO.setUserType(UserTypeEnum.CLIENT);
userDTO.setUsername(client.getNickName());
userDTO.setToken(this.createToken(userDTO));
return userDTO;
}
@Override
public void logout(String token) {
removeToken(token);
}
/**
* token
* @param userDTO
* @return token
*/
private String createToken(UserDTO userDTO) {
String token = jwtTool.createToken(userDTO);
userDTO.setToken(token);
// 缓存token
redisTool.setValue(TOKEN_KEY + token, userDTO, userDTO.getTimeExpire());
return token;
}
/**
* token
*/
public void removeToken(String token) {
redisTool.expireKeyAt(TOKEN_KEY + token, new Date());
}
}

@ -78,7 +78,11 @@ public class RecycleOrderServiceImpl extends ServiceImpl<RecycleOrderMapper, Rec
if (StrUtil.isEmpty(id)) {
throw new BizIllegalException("请求参数缺失");
}
return this.getById(id);
RecycleOrder recycleOrder = this.getById(id);
if (recycleOrder == null) {
throw new BizIllegalException("回收订单不存在");
}
return recycleOrder;
}
@ -128,7 +132,7 @@ public class RecycleOrderServiceImpl extends ServiceImpl<RecycleOrderMapper, Rec
// 校验订单是否存在
private void validateOrderExists(String id) {
if (this.getOrderById(id) == null) {
throw new DbException("回收订单不存在");
throw new BizIllegalException("回收订单不存在");
}
}

@ -48,7 +48,11 @@ public class RecycleStationServiceImpl extends ServiceImpl<RecycleStationMapper,
if (StrUtil.isEmpty(id)) {
throw new BizIllegalException("请求参数缺失");
}
return recycleStationMapper.selectById(id);
RecycleStation recycleStation = recycleStationMapper.selectById(id);
if (recycleStation == null) {
throw new BizIllegalException("回收站点不存在");
}
return recycleStation;
}
}

@ -47,7 +47,14 @@ public class RecyclerServiceImpl extends ServiceImpl<RecyclerMapper, Recycler> i
@Override
public Recycler getRecyclerById(String id) {
return this.getById(id);
if (StrUtil.isEmpty(id)) {
throw new BizIllegalException("请求参数缺失");
}
Recycler recycler = this.getById(id);
if (recycler == null) {
throw new BizIllegalException("回收员不存在");
}
return recycler;
}
@ -86,7 +93,7 @@ public class RecyclerServiceImpl extends ServiceImpl<RecyclerMapper, Recycler> i
// 校验散户是否存在
private void validateRecyclerExists(String id) {
if (this.getRecyclerById(id) == null) {
throw new DbException("散户不存在");
throw new BizIllegalException("回收员不存在");
}
}
}

@ -17,6 +17,10 @@ import org.springframework.stereotype.Component;
import java.security.KeyPair;
import java.util.Date;
/**
* Jwt Bean
*/
@Component
public class JwtTool {
private final JWTSigner jwtSigner;
@ -36,6 +40,7 @@ public class JwtTool {
* @return access-token
*/
public String createToken(UserDTO userDTO) {
userDTO.setTimeExpire(jwtProperties.getTokenTTL().toMillis());
// 1.生成jws
return JWT.create()
.setPayload("user", userDTO)

@ -0,0 +1,157 @@
package cc.yunxi.utils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import java.time.Duration;
import java.util.Collection;
import java.util.Date;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* redis Bean
*/
@Component
public class RedisTool {
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Autowired
private ValueOperations<String, Object> valueOperations;
/**
*
*/
public static final long DEFAULT_EXPIRE = 60 * 60 * 24;
/**
*
*/
public static final long NOT_EXPIRE = -1;
/**
* key-value
* @param key
* @return boolean
*/
public boolean setValue(String key, Object value, Long expire) {
return Boolean.TRUE.equals(valueOperations.setIfAbsent(key, value, expire, TimeUnit.MILLISECONDS));
}
/**
* value
* @param key
* @return Object
*/
public Object getValue(String key) {
return valueOperations.get(key);
}
/**
* key
* @param key
* @return boolean
*/
public boolean existsKey(String key) {
return redisTemplate.hasKey(key);
}
/**
* keynewKeynewKey
*
* @param oldKey
* @param newKey
*/
public void renameKey(String oldKey, String newKey) {
redisTemplate.rename(oldKey, newKey);
}
/**
* newKey
*
* @param oldKey
* @param newKey
* @return true
*/
public boolean renameKeyNotExist(String oldKey, String newKey) {
return redisTemplate.renameIfAbsent(oldKey, newKey);
}
/**
* key
*
* @param key
*/
public void deleteKey(String key) {
redisTemplate.delete(key);
}
/**
* key
*
* @param keys
*/
public void deleteKey(String... keys) {
Set<String> kSet = Stream.of(keys).map(k -> k).collect(Collectors.toSet());
redisTemplate.delete(kSet);
}
/**
* Key
*
* @param keys
*/
public void deleteKey(Collection<String> keys) {
Set<String> kSet = keys.stream().map(k -> k).collect(Collectors.toSet());
redisTemplate.delete(kSet);
}
/**
* key
*
* @param key
* @param time
* @param timeUnit
*/
public void expireKey(String key, long time, TimeUnit timeUnit) {
redisTemplate.expire(key, time, timeUnit);
}
/**
* key
*
* @param key
* @param date
*/
public void expireKeyAt(String key, Date date) {
redisTemplate.expireAt(key, date);
}
/**
* key
*
* @param key
* @param timeUnit
* @return
*/
public long getKeyExpire(String key, TimeUnit timeUnit) {
return redisTemplate.getExpire(key, timeUnit);
}
/**
* key
*
* @param key
*/
public void persistKey(String key) {
redisTemplate.persist(key);
}
}

@ -16,7 +16,7 @@ spring:
database: 1 #缓存库编号
host: 127.0.0.1
port: 6379
password: 123456 # 密码为空时,请将本行注释
# password: 123456 # 密码为空时,请将本行注释
timeout: 3000 #超时时间(单位:秒)
lettuce: #Lettuce为Redis的Java驱动包
pool:

Loading…
Cancel
Save