package com.awj.mall.core.aop;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import com.awj.mall.core.base.tips.SuccessTip;
import com.awj.mall.core.common.annotion.DistributedLock;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;
/**
* @author ljj
*/
@Slf4j
@Aspect
@Component
public class RedisLockAop {
private ExpressionParser parser = new SpelExpressionParser();
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Pointcut("@annotation(com.awj.mall.core.common.annotion.DistributedLock)")
public void pointCut() {
}
@Around("pointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
String className = point.getTarget().getClass().getName();
Object[] args = point.getArgs();
String[] paramNames = signature.getParameterNames();
//参数写入SpringEl域中
EvaluationContext context = new StandardEvaluationContext();
for (int i = 0; i < args.length; i++) {
context.setVariable(paramNames[i], args[i]);
}
//获取切面注解
DistributedLock lock = method.getAnnotation(DistributedLock.class);
TimeUnit timeUnit = lock.timeUnit();
//redis key过期时间
long expire = lock.expire();
//key为空时锁方法,否则按SpringEl表达式取值
String param = StringUtils.isEmpty(lock.key()) ? method.getName() : parser.parseExpression(lock.key()).getValue
(context, String.class);
//作用域为空时取className
String lockName = StringUtils.isEmpty(lock.lockName()) ? className : lock.lockName();
//构造redisKey
String redisKey = lockName + "#" + param;
try {
ValueOperations valueOperations = stringRedisTemplate.opsForValue();
Boolean cacheRes = valueOperations.setIfAbsent(redisKey, param);
if (!cacheRes) {
return new SuccessTip("系统繁忙,请稍后重试!");
}
stringRedisTemplate.expire(redisKey, expire, timeUnit);
} catch (Exception e) {
this.log.error("获取分布式锁失败", e);
}
log.info("获取分布式锁失败,class={},method={},key={}", className, method, redisKey);
Object proceed = point.proceed();
return proceed;
}
}
package com.awj.mall.core.common.annotion;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.concurrent.TimeUnit;
/**
* @author ljj
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DistributedLock {
/**
* 过期时间 时间按时间单位换算
*
* @return
*/
long expire() default 30L;
/**
* 时间单位 默认为秒
*
* @return
*/
TimeUnit timeUnit() default TimeUnit.SECONDS;
/**
* springEl表达式 为空时取方法名称锁方法
*
* @return
*/
String key() default "";
/**
* 定义lock作用域,避免key重复 为空时取类完整包名
*
* @return
*/
String lockName() default "";
}
/**
* 回访完成
*
* @author zjk
* @version 创建时间:2018年9月14日 下午3:40:10
* @param
* @return
*/
@RequestMapping("/visit")
@ResponseBody
@Transactional
@DistributedLock(key = "#id")
public Object visit(Integer id, Integer serviceUserId, Model model) {
Date date = new Date();
Integer userId = ShiroKit.getUser().getId();
// 判断是否完成了财务审核,如果invoice_info表里面没有status为3的记录就是没有完成审核
WorkOrderInvoiceInfo have = WorkOrderInvoiceInfoServiceImpl.selectOne(new EntityWrapper<WorkOrderInvoiceInfo>()
.eq("work_order_id", id).eq("is_deleted", 0).eq("is_enable", 1).eq("status", 3));
if (have == null) {
return new SuccessTip("此工单不能完成回访,请先交由财务审核处理!");
}
// TODO:借助Redis的原子操作实现分布式锁-对共享操作-资源进行控制
// ValueOperations valueOperations = stringRedisTemplate.opsForValue();
// final String key = new
// StringBuffer().append(have.getWorkOrderNo()).append("-RedisLock").toString();
// Boolean cacheRes = valueOperations.setIfAbsent(key, have.getWorkOrderNo());
// if (cacheRes) {
UserServiceWorkOrderInfo content = this.iUserServiceWorkOrderInfoService.selectById(id);
if (content != null) {
if (content.getWorkOrderStatus() != 11) {
return new SuccessTip("只有已财务核对的工单才能回访!");
}
// stringRedisTemplate.expire(key, 30, TimeUnit.SECONDS);
content.setId(id);
content.setWorkOrderStatus(5);
content.setModifier(userId);
content.setModified(date);
content.setVisitDate(date);
iUserServiceWorkOrderInfoService.updateById(content);
// 将服务工单账单明细表的状态改为1(可提现)
UserServiceWorkOrderBill bill = userServiceWorkOrderBillServiceImpl.selectOne(
new EntityWrapper<UserServiceWorkOrderBill>().eq("work_order_id", id).eq("is_deleted", 0));
if (bill != null) {
bill.setType(1);
bill.setModified(date);
bill.setModifier(userId);
bill.setUserPrice(have.getUserPrice());
userServiceWorkOrderBillServiceImpl.updateById(bill);
// 增加可提现服务费,减去未结算服务费
UserBaseInfo info = iUserBaseInfoService.selectById(bill.getUserId());
if (info != null) {
info.setCouldWithdrawcashMoney(add(info.getCouldWithdrawcashMoney(), have.getUserPrice(), 2));
info.setUnliquidatedWithdrawcashMoney(
subtract(info.getUnliquidatedWithdrawcashMoney(), have.getUserPrice(), 2));
info.setModifier(userId);
info.setModified(date);
iUserBaseInfoService.updateById(info);
}
}
// 逻辑删除服务商与工单关系表记录
EntityWrapper<UserServiceWorkOrderRel> myWrapper1 = new EntityWrapper<>();
Wrapper<UserServiceWorkOrderRel> wrapper1 = myWrapper1.eq("user_id", serviceUserId).eq("work_order_id", id)
.eq("is_deleted", 0);
UserServiceWorkOrderRel userServiceWorkOrderRel = userServiceWorkOrderRelServiceImpl.selectOne(wrapper1);
if (userServiceWorkOrderRel != null) {
userServiceWorkOrderRel.setIsDeleted(1);
userServiceWorkOrderRel.setIsEnable(0);
userServiceWorkOrderRel.setModified(date);
userServiceWorkOrderRel.setModifier(userId);
userServiceWorkOrderRelServiceImpl.updateById(userServiceWorkOrderRel);
}
// 插入日志表
UserServiceWorkOrderLog log = new UserServiceWorkOrderLog();
SysUser sysUser = sysUserServiceImpl.selectById(userId);
log.setWorkOrderId(id);
log.setServiceUserId(serviceUserId);
log.setStatus(6);
log.setDetail("回访完成,操作员是" + sysUser.getAccount());
log.setCreator(userId);
log.setCreated(date);
log.setModifier(userId);
log.setModified(date);
iUserServiceWorkOrderLogService.insert(log);
// if (have.getWorkOrderNo().equals(valueOperations.get(key).toString())) {
// stringRedisTemplate.delete(key);
// }
}
// } else {
// return new SuccessTip("系统繁忙,请稍后重试!");
// }
return SUCCESS_TIP;
}
package com.awj.mall.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
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.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
* redis配置类
* @author SHF
* @version 创建时间:2019年1月15日 上午9:31:51
*/
@Configuration
@EnableCaching//开启注解
public class RedisConfig {
@Autowired
private RedisConnectionFactory redisConnectionFactory;
/*@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
//使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class);
template.setValueSerializer(serializer);
//使用StringRedisSerializer来序列化和反序列化redis的key值
template.setKeySerializer(new StringRedisSerializer());
template.afterPropertiesSet();
return template;
}*/
@Bean
public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
RedisTemplate<String,Object> template=new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer=new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper=new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
StringRedisSerializer stringRedisSerializer=new StringRedisSerializer();
template.setKeySerializer(stringRedisSerializer);
template.setHashKeySerializer(stringRedisSerializer);
template.setValueSerializer(jackson2JsonRedisSerializer);
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
@Bean
public StringRedisTemplate stringRedisTemplate(){
StringRedisTemplate stringRedisTemplate=new StringRedisTemplate();
stringRedisTemplate.setConnectionFactory(redisConnectionFactory);
return stringRedisTemplate;
}
}