最近项目中有个需求:
需要从后台系统页面勾选标题头根据勾选的标题头导出,项目里面用到了导出的注解和导出工具类(可以根据注解属性来判断是否让这个字段加入导出),抓住这个点我往下探索。
这个需求出来的时候我琢磨着是用第三方api导出时动态修改注解属性还是用AOP的拦截修改注解属性,最终采用了AOP方式原因有以下
1.低代码的耦合性 极大的减免了对代码的侵入,提高了程序复用性(要不然每个导出方法都得改动)
2.让Spring 管理 也遵守了ioc原则
先看下后端代码
1.导出注解
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Excel { /* * 是否忽略 */ boolean isIgnore() default true; /** * 导出到Excel中的名字. */ String name() default ""; /** * 日期格式, 如: yyyy-MM-dd */ String dateFormat() default ""; }
2.后端统一导出工具类
关键核心代码
Field field = fields.get(i); Excel attr = field.getAnnotation(Excel.class); if (attr.isIgnore()) { continue; }
3.然后是导出的切面类
这个 request.getParameter("exportTitle"); 就是获取前端传来的字段头参数拼接
然后根据参数循环遍历拦截导出方法的list参数来判断是否需要忽略
Aspect @Component public class ExportAspect { private static final Logger log = LoggerFactory.getLogger(ExportAspect.class); // 配置织入点 @Pointcut("execution(* com.huadu.system.utils.ExcelUtil.exportExcel(..))") public void excelPointCut() { } /** * 导出前添加需要导出的字段头 */ @Before("excelPointCut()") public void before(JoinPoint joinPoint) throws NoSuchFieldException, IllegalAccessException { RequestAttributes ra = RequestContextHolder.getRequestAttributes(); ServletRequestAttributes sra = (ServletRequestAttributes) ra; HttpServletRequest request = sra.getRequest(); String exportTitle = request.getParameter("exportTitle"); if (StringUtils.isBlank(exportTitle)) { return; } List<String> exportTitles = Arrays.asList(exportTitle.split(",")); //获取目标方法的参数信息 Object[] obj = joinPoint.getArgs(); for (Object argItem : obj) { if (argItem instanceof List) { List<?> list = (ArrayList) argItem; for (Object o : list) { //获取属性 Field[] declaredFields = o.getClass().getDeclaredFields(); List<Field> fieldList = Arrays.asList(declaredFields); for (Field field : fieldList) { Excel annotation = field.getAnnotation(Excel.class); if (null != annotation) { InvocationHandler handler = Proxy.getInvocationHandler(annotation); Field annotationField = handler.getClass().getDeclaredField("memberValues"); annotationField.setAccessible(true); Map meberValues = (Map) annotationField.get(handler); if (exportTitles.contains(field.getName())) { meberValues.put("isIgnore", false); } else { meberValues.put("isIgnore", true); } } } } } } } }
这个是我自己的导出工具方法 我定义的aop拦截的切入点方法
public byte[] exportExcel(List<T> list, String sheetName, Class<T> clazz) { this.clazz = clazz; return exportExcel(list, sheetName, true); }
最后需要注意的点
aop拦截的类必须被spring管理 可以通过 @Service或@Component等注解