最近系统在做安全测评,要求所有数据操作都要保留操作痕迹,于是PM要求所有接口按照增加、修改、查询、删除、导出、导入、审批、文件上传下载删除这几大操作类型统一增加日志。这一需求的典型实现方法是给Controller层的接口加上自定义注解,通过AOP拦截所有方法来实现。我实现的这个自定义注解传入的参数有menu菜单名、title操作数据说明及操作类型,记录格式一般是:用户名+操作类型+菜单+操作数据说明+获取的参数信息。下面简单说一下其中的逻辑。

  • 1.增加:单条新增数据的方法统一返回新增记录id,根据拦截到的方法返回值获取id记录
  • 2.删除:循环request中的参数获取到id并记录
Enumeration enu=request.getParameterNames();
    while(enu.hasMoreElements()){
    String paraName=(String)enu.nextElement();
    Object paramVal1 = request.getParameter(paraName); 
    if(paramVal1 != null && !"".equals(paramVal1.toString())){     
        sb.append(paraName+"为"+paramVal1+";");  
    }}
  • 3.查询:一般是GET请求也是循环request中的参数获取查询条件,这里注意参数有的放在request里,有的是如queryXXX/id 这种直接放在请求路径上的
String paraName=(String)enu.nextElement();
    // 解析查询路径传参的情况,如 url/id
    if ("_".equals(paraName)){
        Map pathVariables = (Map) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);   
        String idInPath = (String) pathVariables.get("id"); 
        if (idInPath != null) {        
            sb.append("id为"+idInPath+";");    
        }
    }
  • 4.修改/导出操作:默认也是根据request获取信息,但是我的POST请求类型是通过joinPoint.getArgs()获取的
StringBuffer exportStr = new StringBuffer();
    String title = operLog.getTitle();
    // 统计报表专用(因为所有统计报表公用一个导出接口)
    Object[] args = joinPoint.getArgs();
    if ("统计报表".equals(controllerLog.menu()) && args.length>0){   
        Map arguMap = (Map) args[0]; 
        title = arguMap.get("reportName")+"穿透";  
        exportStr.append("tn为").append(arguMap.get("tn"))          
        .append("exportMode为").append(arguMap.get("exportMode"));
    }
  • 5.文件上传、下载、删除
    我的文件上传是通过WebUploader组件实现的,上传文件记录了文件名,而下载和删除文件都只记录了文件id。注意这里有个小坑,Controller中获取文件名是直接将HttpServletRequest请求映射为MultipartHttpRequest实现的:
    MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
    通过反射获取到request之后再这样写就报错:cannot be cast to org.springframeworkweb.multipart.MultipartHttpServletRequest
    于是查了一下发现需要通过MultipartResolver转一下:
MultipartResolver resolver = new StandardServletMultipartResolver();
    MultipartHttpServletRequest multiRequest = resolver.resolveMultipart(request);
这个具体原理大家可以查询,其他方式实现的文件上传不一定适用此方法。感兴趣的朋友可以留言跟我要相关代码及数据表。