AOP日志组件 多次获取post参数
AOP日志组件 多次获取post参数
- 需求:新增接口日志组件。通过拦截器对接口URL进行拦截处理,然后将接口post请求的参数与结果,写入日志表。
- 问题:POST方法的参数是存储在request.getInputStream中,只能读一次,不能多次读取。从中读取post请求参数,只能读取一次。在filter中获取之后,controller无法获取post请求参数。
- 解决办法:继承HttpServletRequest,先获取到请求参数,再加参数重新set到inputStream。
1.拦截器记录日志
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest)request;
        String requestPath  = httpRequest.getServletPath().split("\\?")[0];
        if(request  == null){
            chain.doFilter(request, response);
            return ;
        }
         for (String noFilter : NO_FILETER_LIST) {
             if(requestPath.toLowerCase().contains(noFilter)){
                 chain.doFilter(request, response);
                 return ;
             }
         }
         Pattern pattern = Pattern.compile(".*[api|interface].*");
         Matcher matcher = pattern.matcher(requestPath);
         if(matcher.matches()){
             LoggerManager loggerManager = SpringLoadListener.getBean("loggerManager",LoggerManager.class);
             //扩展request,防止字符注入等
             XssSqlHttpServletRequestWrapper xssRequest = new XssSqlHttpServletRequestWrapper((HttpServletRequest)request);
             ResponseWrapper wrapResponse = new ResponseWrapper((HttpServletResponse)response);
             //继续请求处理类
             chain.doFilter(xssRequest, wrapResponse);
             //获取URL的参数 get请求
             Map<Object, Object> urlParam = xssRequest.getParameterMap();
             //获取post参数
             String param = xssRequest.getRequestParams();
             JSONObject jObject = JSONObject.fromObject(urlParam);
             jObject.put("postParam", param.toString());
             String params = jObject.toString();
             //获取接口处理类返回结果
             byte[] data = wrapResponse.getResponseData();
              String result = new String(data,"UTF-8");
              //保存日志
              loggerManager.operateInterfaceLogger("", params, requestPath, result);
              ServletOutputStream out = response.getOutputStream();
              out.write(data);
              out.flush();
         }else{
             chain.doFilter(request, response);
         }
    }2.处理request请求,先获取inputStream,将请求参数复制给其他方法,同时再将获取的inputStream赋值回request中。
public class XssSqlHttpServletRequestWrapper extends HttpServletRequestWrapper
 {
         HttpServletRequest orgRequest = null;
         private byte[] bytes;
         private WrappedServletInputStream  wrappedServletInputStream;
   public XssSqlHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
           super(request);
           this.orgRequest = request;
           //读取输入流的请求参数,保存到bytes中
           bytes = IOUtils.toByteArray(request.getInputStream());
           ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
           this.wrappedServletInputStream = new WrappedServletInputStream(byteArrayInputStream);
           //把post参数重新写入请求流
           reWriteInputStream();
   }
   /**
    * 把参数重新写进请求里
    */
    public void reWriteInputStream() {
       wrappedServletInputStream.setStream(new ByteArrayInputStream(bytes != null ? bytes : new byte[0]));
   }
    @Override
    public ServletInputStream getInputStream() throws IOException {
        return wrappedServletInputStream;
    }
    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(wrappedServletInputStream));
    }
    /**
     * 获取post参数
     */
    public String getRequestParams() throws IOException {
        return new String(bytes, this.getCharacterEncoding());
    }
   //清洗参数,防止xss注入
   public String[] getParameterValues(String parameter)
   {
           String[] values = super.getParameterValues(parameter);
           if (values == null) {
             return null;
     }
           int count = values.length;
           String[] encodedValues = new String[count];
           for (int i = 0; i < count; i++) {
             encodedValues[i] = xssEncode(values[i]);
     }
           return encodedValues;
   }
   public String getParameter(String name)
   {
           String value = super.getParameter(xssEncode(name));
           if (value != null) {
             value = xssEncode(value);
     }
           return value;
   }
   public String getHeader(String name)
   {
           String value = super.getHeader(xssEncode(name));
           if (value != null) {
             value = xssEncode(value);
     }
           return value;
   }
   private static String xssEncode(String s)
   {
           return StringUtil.xssEncode(s);
   }
   public HttpServletRequest getOrgRequest()
   {
           return this.orgRequest;
   }
   public static HttpServletRequest getOrgRequest(HttpServletRequest req)
   {
           if ((req instanceof XssSqlHttpServletRequestWrapper)) {
             return ((XssSqlHttpServletRequestWrapper)req).getOrgRequest();
     }
         return req;
   }
   private class WrappedServletInputStream extends ServletInputStream {
       public void setStream(InputStream stream) {
           this.stream = stream;
       }
       private InputStream stream;
       public WrappedServletInputStream(InputStream stream) {
           this.stream = stream;
       }
       public int read() throws IOException {
           return stream.read();
       }
       public boolean isFinished() {
           return true;
       }
       public boolean isReady() {
           return true;
       }
       public void setReadListener(ReadListener readListener) {
       }
   }
 }3.Manager保存日志记录。对LoggerAnnotation自定义注解,实现AOP日志保存。
@LoggerAnnotation(type="INTERFACE", name="#name", params="#params", desc="#pageLink")
public String operateInterfaceLogger(String name, String params, String pageLink, String result)
{
    return result;
}
 @Component
 @Aspect
 @Async
 public class LoggerOperationAop
 {
   private static final Logger logger = LoggerFactory.getLogger(LoggerOperationAop.class);
   @Autowired
   private LoggerManager loggerManager;
   @Autowired
   private UserManager userManager;
   @Autowired
   private JdbcTemplateImpl jdbcTemplate;
   public LoggerOperationAop() {}
   @Pointcut("@annotation(LoggerAnnotation)")
   private void serviceAspect(LoggerAnnotation LoggerAnnotation) {}
   @Around("serviceAspect(LoggerAnnotation)")
   public Object process(ProceedingJoinPoint point, LoggerAnnotation LoggerAnnotation)
     throws Throwable
   {
     String targetName = point.getTarget().getClass().getName();
     String methodName = point.getSignature().getName();
     Object[] arguments = point.getArgs();
     String operationType = LoggerAnnotation.type();
     String message = LoggerAnnotation.desc();
     String params = LoggerAnnotation.params();
     String name = LoggerAnnotation.name();
     String id = LoggerAnnotation.id();
     String[] paramNames = ReflectParamNames.getNames(targetName, methodName);
     if ((StringUtil.isNotBlank(name)) && (name.startsWith("#"))) {
       String value = SpelParser.getKey(name, "", paramNames, arguments);
       if (StringUtil.isNotBlank(value)) {
         targetName = value;
       }
     }
     String methodParams = "";
     if ((StringUtil.isNotBlank(params)) && (params.startsWith("#"))) {
       methodParams = SpelParser.getKey(params, "", paramNames, arguments);
     }
     if ((StringUtil.isNotBlank(message)) && (message.startsWith("#"))) {
       String value = SpelParser.getKey(message, "", paramNames, arguments);
       if (StringUtil.isNotBlank(value)) {
         message = value;
       }
     }
     String userId = null;
     String userName = "游客";
     try {
         Subject currentSubject = SecurityUtils.getSubject();
         if (currentSubject != null) {
           Object tmpObj = currentSubject.getSession().getAttribute("authorizeUser");
           if ((tmpObj != null) && ("INTERFACE".equals(operationType))) {
             userName = StringUtil.parseAny2String(tmpObj);
           } else if (currentSubject.getPrincipal() != null) {
             ShiroDbRealm.ShiroUser shiroUser = (ShiroDbRealm.ShiroUser)currentSubject.getPrincipal();
             userId = shiroUser.getUserId();
             userName = shiroUser.getLoginName();
           }
         }
       } catch (Exception e) {
         logger.info("不支持shiro技术框架");
         logger.error("异常信息:{}", e.getMessage());
       }
     Object target = point.proceed();
     try
     {
       String extName = DateUtil.getYearMonth(new Date());
       String sql = " INSERT INTO T_E4S_DB_LOG_MESSAGE_" + extName +
         " (USER_ID,USER_NAME,CLASS_NAME,METHOD_NAME,METHOD_PARAMS,LOG_DATE,LOG_MESSAGE,OPERATION_TYPE,REMARK) " +
         " VALUES(?,?,?,?,?,?,?,?,?) ";
       Object[] object = { userId, userName, targetName, methodName, methodParams,
         new Date(), message, operationType, target };
       this.jdbcTemplate.beginTranstaion();
       this.jdbcTemplate.update(sql, object);
       this.jdbcTemplate.commit();
     }
     catch (Exception ex) {
       logger.error("==异常通知异常==");
       logger.error("异常信息:{}", ex.getMessage());
       this.jdbcTemplate.rollback();
     }
     return target;
   }
 }
LoggerFilter里一个实现了XssSqlHttpServletRequestWrapper类,其构造器自动读取了servletRequest里的输入流,并把数据保存了下来,最后又把数据重新写入servletRequest里,在filter中可以读取post请求参数,cotroller也可以再次从request里读取到post请求参数。
AOP日志组件 多次获取post参数的更多相关文章
- Performance Counter的使用——获取各类组件性能,获取CPU参数等
		一 PerformanceCounter 基本介绍1 简单介绍表示 Windows NT 性能计数器组件 命名空间:System.Diagnostics程序集:System(在 system.dll ... 
- 08 SSM整合案例(企业权限管理系统):11.AOP日志
		04.AdminLTE的基本介绍 05.SSM整合案例的基本介绍 06.产品操作 07.订单操作 08.权限控制 09.用户和角色操作 10.权限关联 11.AOP日志 11.AOP日志 1.数据库与 ... 
- vue-router2.0 组件之间传参及获取动态参数
		<li v-for=" el in hotLins" > <router-link :to="{path:'details',query: {id:el ... 
- [js开源组件开发]query组件,获取url参数和form表单json格式
		query组件,获取url参数和form表单json格式 距离上次的组件[js开源组件开发]ajax分页组件一转眼过去了近二十天,或许我一周一组件的承诺有了质疑声,但其实我一直在做,只是没人看到……, ... 
- 我心中的核心组件(可插拔的AOP)~第十五回 我的日志组件Logger.Core(策略,模版方法,工厂,单例等模式的使用)
		回到目录 之前的讲过两篇关于日志组件的文章,分别是<第一回 日志记录组件之自主的Vlog>和<第三回 日志记录组件之log4net>,而今天主要说一下我自己开发的另一种日志 ... 
- java日志组件介绍(common-logging,log4j,slf4j,logback )
		转自:http://www.blogjava.net/daiyongzhi/archive/2014/04/13/412364.html common-logging是apache提供的一个通用的日志 ... 
- 你的日志组件记录够清晰嘛?--自己开发日志组件 Logger
		现在现成的日志组件实在是太多太多,为什么我还需要自己实现呢????? 需求来源于java的log4j, [07-31 16:40:00:557:WARN : com.game.engine.threa ... 
- 转:java日志组件介绍(common-logging,log4j,slf4j,logback )
		原网址:http://www.blogjava.net/daiyongzhi/archive/2014/04/13/412364.html common-logging common-logging是 ... 
- 日志组件logback的介绍及配置使用方法
		一.logback的介绍 Logback是由log4j创始人设计的又一个开源日志组件.logback当前分成三个模块:logback-core,logback- classic和logback-acc ... 
随机推荐
- 解决element 照片墙上传时回显问题
			1.先看看样式: <el-upload class="imgList" action="1165165" list-type="picture- ... 
- hyperledger fabric 1.0.5 分布式部署 (六)
			如何在相同的peer 节点上创建多个 channel 作者在hyperledger fabric 1.0.5 分布式部署 (五)已经向读者们介绍了一个简单的fabric 的部署流程,那么根据上一篇博客 ... 
- 最简大数据Spark-2.1.0
			0.0 前言 本文主要基于最新的Spark 2.1.0版本.阅读本文可以对Spark 2.1.0的学习过程,运行流程,关键组件,原理有所了解.文章有点长,你也可以直接阅读感兴趣的部分,但是还是建议全面 ... 
- GPDB外部表创建示例
			创建以|为分隔符的外部表CREATE EXTERNAL TABLE ext_expenses ( name text,date date, amount float4, category text, ... 
- 一篇文章彻底弄懂CAS实现SSO单点登录原理
			1. CAS 简介 1.1. What is CAS ? CAS ( Central Authentication Service ) 是 Yale 大学发起的一个企业级的.开源的项目,旨在为 Web ... 
- Codeforces Round #396 (Div. 2) C
			Mahmoud wrote a message s of length n. He wants to send it as a birthday present to his friend Moaz ... 
- memcpy/memmove?快速乘?
			memcpy?memmove? //#pragma GCC optimize(2) #include<bits/stdc++.h> using namespace std; ; ],b[n ... 
- dubbo-springboot
			一.服务提供者boot-user-service-provider 服务提供者boot-user-service-provider代码结构如下: 1.服务提供者boot-user-service-pr ... 
- C++ Sort类成员的传递
			C++模板中提供了sort方法,一般有两种方法:传递函数,传递一个对象. 第一种方法:函数 bool compare(const string &strLeft, const string & ... 
- “玲珑杯”ACM比赛 Round #4 E -- array DP
			http://www.ifrog.cc/acm/problem/1050?contest=1006&no=4 DP[val]表示以val这个值结尾的等差数列有多少个 DP[val] += DP ... 
