package cn.ibizlab.util.aspect; import lombok.SneakyThrows; import cn.ibizlab.util.annotation.VersionCheck; import cn.ibizlab.util.domain.EntityBase; import cn.ibizlab.util.errors.BadRequestAlertException; import cn.ibizlab.util.helper.RuleUtils; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.core.annotation.Order; import org.springframework.expression.EvaluationContext; import org.springframework.expression.Expression; 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 org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; import java.lang.reflect.Field; import java.sql.Timestamp; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Map; /** * 数据库版本检查 */ @Aspect @Order(50) @Component public class VersionCheckAspect { private final ExpressionParser parser = new SpelExpressionParser(); private final String IgnoreField="ignoreversioncheck"; @SneakyThrows @Before("execution(* cn.ibizlab.*.rest.*.update(..)) && @annotation(versionCheck)") public void BeforeUpdate(JoinPoint point, VersionCheck versionCheck){ Object[] args = point.getArgs(); Object id=args[0]; Object dto=args[1]; if(ObjectUtils.isEmpty(id) || ObjectUtils.isEmpty(dto)) return; String versionField=versionCheck.versionfield(); if(StringUtils.isEmpty(versionField)) return; versionCheck(versionCheck,point.getTarget(),dto,id); } @SneakyThrows @Before("execution(* cn.ibizlab.*.rest.*.updateBy*(..)) && @annotation(versionCheck)") public void BeforeUpdateBy(JoinPoint point, VersionCheck versionCheck){ Object[] args = point.getArgs(); if(args.length>=2){ Object id=args[args.length-2]; Object dto=args[args.length-1]; if(ObjectUtils.isEmpty(id) || ObjectUtils.isEmpty(dto)) return; String versionField=versionCheck.versionfield(); if(StringUtils.isEmpty(versionField)) return; versionCheck(versionCheck,point.getTarget(),dto,id); } } private void versionCheck(VersionCheck versionCheck,Object resource,Object dto,Object id ){ EvaluationContext context = new StandardEvaluationContext(); context.setVariable("dto",dto); //忽略版本检查 Expression dtoParamsExp = parser.parseExpression("#dto.extensionparams"); Map dtoParam=dtoParamsExp.getValue(context, Map.class); if(!ObjectUtils.isEmpty(dtoParam) && !ObjectUtils.isEmpty(dtoParam.get(IgnoreField)) && dtoParam.get(IgnoreField).equals(1)) return; Expression newExp = parser.parseExpression(String.format("#dto.%s",versionCheck.versionfield())); Object newVersion=newExp.getValue(context); if(ObjectUtils.isEmpty(newVersion)) return; //进行版本检查 Object oldVersion =getDBVersion(versionCheck,getService(resource,versionCheck.entity()),id); if(!ObjectUtils.isEmpty(oldVersion)){ if(RuleUtils.gt(newVersion,oldVersion)) throw new BadRequestAlertException("数据已变更,可能后台数据已被修改,请重新加载数据","VersionCheckAspect","versionCheck"); } } /** * 获取实体服务对象 * @param resource * @param entity * @return */ @SneakyThrows private Object getService(Object resource,String entity){ Object service = null; Field[] fields= resource.getClass().getDeclaredFields(); for(Field field : fields){ if(field.getModifiers()==1 && field.getName().equalsIgnoreCase(String.format("%sService",entity))){ service=field.get(resource); break; } } return service; } /** * 获取数据库版本 * @param versionCheck * @param service * @param id * @return */ @SneakyThrows private Object getDBVersion(VersionCheck versionCheck,Object service,Object id){ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Timestamp dbVersion=null; String versionField=versionCheck.versionfield(); if(!ObjectUtils.isEmpty(service)){ EvaluationContext oldContext = new StandardEvaluationContext(); oldContext.setVariable("service",service); oldContext.setVariable("id",id); Expression oldExp = parser.parseExpression("#service.get(#id)"); EntityBase oldEntity =oldExp.getValue(oldContext, EntityBase.class); Object oldDate=oldEntity.get(versionField); if(oldDate!=null && oldDate instanceof Timestamp){ Timestamp db_time= (Timestamp) oldDate; Date db_date = sdf.parse(sdf.format(db_time)); dbVersion=new Timestamp(db_date.getTime()); } } return dbVersion; } }