package com.ruoyi.framework.aspectj; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.IService; import com.ruoyi.common.annotation.UniqueCheck; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.spring.SpringUtils; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.List; /** * 唯一性校验切面 * 用于在新增操作前进行字段唯一性检查 * * @author ruoyi */ @Aspect @Order(2) @Component public class UniqueCheckAspect { protected Logger logger = LoggerFactory.getLogger(getClass()); @Pointcut("@annotation(com.ruoyi.common.annotation.UniqueCheck)") public void uniqueCheckPointCut() { } @Before("uniqueCheckPointCut()") public void doBefore(JoinPoint point) throws Throwable { handleUniqueCheck(point); } protected void handleUniqueCheck(JoinPoint joinPoint) throws Exception { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); UniqueCheck uniqueCheck = method.getAnnotation(UniqueCheck.class); if (uniqueCheck == null) { return; } // 获取方法参数 Object[] args = joinPoint.getArgs(); if (args == null || args.length == 0) { return; } // 获取第一个参数(通常是实体对象) Object entity = args[0]; if (entity == null) { return; } // 校验实体类型 Class entityClass = uniqueCheck.entityClass(); if (!entityClass.isInstance(entity)) { logger.warn("实体类型不匹配, 期望: {}, 实际: {}", entityClass.getName(), entity.getClass().getName()); return; } // 获取Service实例 Class serviceClass = uniqueCheck.serviceClass(); IService service = (IService) SpringUtils.getBean(serviceClass); // 获取需要检查的字段 String[] fields = uniqueCheck.fields(); if (fields == null || fields.length == 0) { throw new ServiceException("UniqueCheck注解的fields属性不能为空"); } // 构建查询条件 QueryWrapper queryWrapper = Wrappers.query(); StringBuilder messageBuilder = new StringBuilder(); boolean hasCondition = false; for (int i = 0; i < fields.length; i++) { String fieldName = fields[i]; Object fieldValue = getFieldValue(entity, fieldName); // 只有字段值不为空时才添加查询条件 if (fieldValue != null && !"".equals(fieldValue)) { // 使用字符串字段名,MyBatis-Plus会自动转换为数据库列名 queryWrapper.eq(StringUtils.toUnderScoreCase(fieldName), fieldValue); hasCondition = true; if (messageBuilder.length() > 0) { messageBuilder.append(","); } messageBuilder.append(fieldValue); } } // 如果没有有效的查询条件,直接返回 if (!hasCondition) { return; } // 执行查询 List list = service.list(queryWrapper); if (list != null && !list.isEmpty()) { String message = uniqueCheck.message(); // 简单的消息格式化 if (message.contains("{value0}")) { message = message.replace("{value0}", messageBuilder.toString()); } logger.warn("唯一性校验失败: {}", message); throw new ServiceException(message); } } /** * 通过反射获取实体字段值 */ private Object getFieldValue(Object entity, String fieldName) throws Exception { Class clazz = entity.getClass(); // 尝试获取字段 Field field = null; while (clazz != null && field == null) { try { field = clazz.getDeclaredField(fieldName); } catch (NoSuchFieldException e) { clazz = clazz.getSuperclass(); } } if (field == null) { throw new ServiceException("实体类中不存在字段: " + fieldName); } field.setAccessible(true); return field.get(entity); } }