package com.bc.exam.aspect;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.bc.exam.core.annon.Dict;
import com.bc.exam.core.api.ApiRest;
import com.bc.exam.core.utils.Reflections;
import com.bc.exam.modules.system.service.SysDictService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* 数据字典翻译AOP切面
*
* 拦截所有Controller方法的返回结果,自动将带有@Dict注解的字段从字典编码翻译为可读文本。
* 翻译后的文本以"字段名_dictText"的形式追加到返回的JSON对象中。
* 同时处理Date类型字段的格式化输出。
*
*
* 支持的数据结构:
* - 单个对象:直接遍历字段进行翻译
* - 列表(List):遍历每个元素进行翻译
* - 分页结果(IPage):遍历分页记录进行翻译
* - 嵌套List字段:递归处理子列表中的字典翻译
*
*
* 注意:当前@Component注解被注释,如需启用字典翻译功能需取消注释或通过其他方式注册为Spring Bean。
*
*
* @Description 描述:数据字典AOP类,处理数据字典值
* @Author C薛涵艺034244315
* @Date 20260616
*/
@Aspect
//@Component
@Slf4j
public class DictAspect {
/** 字典服务,用于根据字典编码查询对应的可读文本 */
@Autowired
private SysDictService sysDictService;
/**
* 环绕通知:切入所有Controller方法执行前后
*
* 切点表达式匹配com.bc.exam包下所有Controller类的public方法,
* 在方法执行完成后对返回结果进行字典翻译处理。
*
* @param pjp 连接点对象,封装了目标方法的执行信息
* @return 经过字典翻译处理后的返回结果
* @throws Throwable 目标方法执行过程中抛出的异常
*/
@Around("execution(public * com.bc.exam..*.*Controller.*(..))")
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
return this.translate(pjp);
}
/**
* 执行目标方法并对返回结果进行字典翻译
*
* 调用前必须确保SysDictService已正确配置并注入。
*
* @param pjp 连接点对象
* @return 翻译处理后的返回结果
* @throws Throwable 目标方法执行异常
*/
public Object translate(ProceedingJoinPoint pjp) throws Throwable {
// 先执行目标方法获取返回结果,再对结果进行字典翻译处理
return this.parseAllDictText(pjp.proceed());
}
/**
* 转换全部数据字典
*
* 仅对ApiRest类型的返回值进行字典翻译处理,其他类型直接透传。
*
* @param result Controller方法的返回结果
* @return 处理后的返回结果(ApiRest类型会被翻译,其他类型原样返回)
*/
private Object parseAllDictText(Object result) {
// 仅ApiRest统一响应格式才进行字典翻译,非ApiRest类型直接返回不做处理
if (result instanceof ApiRest) {
parseFullDictText(result);
}
return result;
}
/**
* 解析并翻译ApiRest响应体中的所有数据字典字段
*
* 根据data字段的实际类型分三种情况处理:
* 1. 分页对象(IPage):遍历分页记录逐条翻译
* 2. 列表对象(List):遍历列表元素逐条翻译
* 3. 单个对象:直接进行字段翻译
* 基本数据类型和null值不做处理。
*
* @param result ApiRest统一响应对象
*/
private void parseFullDictText(Object result) {
try {
// 从ApiRest中提取实际业务数据
Object rest = ((ApiRest) result).getData();
// null值或基本数据类型(String、Integer等)无需字典翻译,直接跳过
if (rest == null || this.isBaseType(rest.getClass())) {
return;
}
// 处理分页查询结果:遍历分页记录(records)逐条翻译字典字段
if (rest instanceof IPage) {
List