1. 程式人生 > >spring mvc記錄各個controller訪問開始結束時間,以及耗時時間 執行緒安全

spring mvc記錄各個controller訪問開始結束時間,以及耗時時間 執行緒安全

package cn.test.web.interceptor;  
public class StopWatchHandlerInterceptor extends HandlerInterceptorAdapter {  
    private NamedThreadLocal<Long>  startTimeThreadLocal =   
new NamedThreadLocal<Long>("StopWatch-StartTime");  
    @Override  
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,   
Object handler) throws Exception {  
        long beginTime = System.currentTimeMillis();//1、開始時間  
        startTimeThreadLocal.set(beginTime);//執行緒繫結變數(該資料只有當前請求的執行緒可見)  
        return true;//繼續流程  
    }  
      
    @Override  
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,   
Object handler, Exception ex) throws Exception {  
        long endTime = System.currentTimeMillis();//2、結束時間  
        long beginTime = startTimeThreadLocal.get();//得到執行緒繫結的區域性變數(開始時間)  
        long consumeTime = endTime - beginTime;//3、消耗的時間  
        if(consumeTime > 500) {//此處認為處理時間超過500毫秒的請求為慢請求  
            //TODO 記錄到日誌檔案  
            System.out.println(  
String.format("%s consume %d millis", request.getRequestURI(), consumeTime));  
        }          
    }  
}  
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.aspectj.lang.ProceedingJoinPoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.NamedThreadLocal;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import com.common.interceptor
/**
 *攔截所有使用者的操作,記錄操作日誌
 * 
 * @author 
 * @version 1.00.00
 *
 */
public class UserActionLogInterceptor extends HandlerInterceptorAdapter{
    private static final Logger logger = LoggerFactory.getLogger(UserActionLogInterceptor.class.getName());
    
    private NamedThreadLocal<Long> startTimeThreadLocal=new NamedThreadLocal<Long>("StartTime-EndTime");
    
    @Autowired
    private JdbcTemplate jdbcTemplate;
    
    @Override
    public boolean preHandle(HttpServletRequest request, 
    HttpServletResponse response, Object handler) throws Exception {
    String url=request.getRequestURI();
    String reqId=UUID.randomUUID().toString();
    //前段如果已經傳入請求標識,則繼續沿用
    if(request.getParameter("reqId")==null){    

    request.setAttribute("reqId", reqId);
    }else{
    reqId=request.getParameter("reqId");
    //encode一次,防止前段sql注入
    reqId=URLEncoder.encode(reqId, reqId);
    request.setAttribute("reqId", reqId);
    }     

    logger.debug("進了Web端的logger interceptor,請求Url:"+url+"  請求標識為:" + reqId+"  開始處理請求Start");
    Long startTime=System.currentTimeMillis();
    startTimeThreadLocal.set(startTime);    

    return true;
    }
    
    @Override
    public void afterCompletion(HttpServletRequest request, 
    HttpServletResponse response, Object handler, Exception ex) throws Exception {
    
    String url=request.getRequestURI();    
    Long startTime=startTimeThreadLocal.get();
    Long endTime  =System.currentTimeMillis();
    String reqId=(String)request.getAttribute("reqId");    

    User user = SecurityUtils.getSessionUser();    

    if(user!=null){  
    String loginid=user.getLoginId();
    String ip     =request.getRemoteAddr();
    String loginType=user.getLoginType();
    logger.debug("UserActionLogInterceptor:使用者名稱:"+loginid+",  IP:"+ip);
    if(handler instanceof HandlerMethod){
    HandlerMethod method=(HandlerMethod)handler;
    String className=method.getBean().getClass().getSimpleName();
    String methodName=method.getMethod().getName();
    //記錄日誌-//xxhCommonController 不做日誌記錄
    if(!"xxhCommonController".equals(className)&&!"MenuHintsController".equals(className)){    

        
String msg=ex==null?"操作成功":"操作失敗:"+ex.getMessage();
        
if(msg.length()>512){//資料庫長度為1536,全部為漢字時是512個字元
        
msg=msg.substring(0, 512);
        
}
        
if(reqId.length()>96){
        
msg=msg.substring(0, 95);
        
}
        
UserActionLogger logBean=new UserActionLogger();
    logBean.setUserId(loginid);
    logBean.setPostClassId(className);
    logBean.setPostAction(methodName);
    logBean.setLogType(loginType);
    logBean.setClientIP(ip);
    logBean.setProcessTime(endTime-startTime);
    logBean.setObjId(reqId);
    logBean.setBookId(user.getCurrentSetsOfBooksId());
    logBean.setDetail(msg);
    log2DB(logBean);
    }else{
    logger.debug("UserActionLogInterceptor:請求來自xxhCommonController,MenuHintsController,無需記錄日誌");
    }
    }else{
    logger.debug("UserActionLogInterceptor:非業務處理類的controller,無需記錄日誌");
    }
    }else{
    logger.debug("UserActionLogInterceptor:未登入使用者,無法獲取使用者資訊");
    }
    if(ex!=null){
    logger.debug("UserActionLogInterceptor攔截到來自controller的異常資訊", ex);
    }
    logger.debug("進了Web端的logger interceptor,請求Url:"+url+",  請求標識為:" + reqId+"  結束End");
    
    }  
    
    private void log2DB(UserActionLogger logInfo){
    String insertSql=" insert into xxh_opt_log "+
    " (syslogid, "+
    " logtime, "+
    " logtype, "+
    " postclassid, "+
    " postaction, "+
    " objid, "+
    " userid, "+
    " clientip, "+
    " bookid, "+
    " detail, "+
    " processtime) "+
    " values "+
    " ("
    + " SQ_xxh_OPT_LOG.Nextval, "+
    " sysdate, "+
    " '"+logInfo.getLogType()+"', "+
    " '"+logInfo.getPostClassId()+"', "+
    " '"+logInfo.getPostAction()+"', "+
    " '"+logInfo.getObjId()+"', "+
    " '"+logInfo.getUserId()+"', "+
    " '"+logInfo.getClientIP()+"', "+
    " "+logInfo.getBookId()+", "+
    " '"+logInfo.getDetail()+"', "+
    " "+logInfo.getProcessTime()+""
    +")";
    try {jdbcTemplate.execute(insertSql);} catch (Exception e) {logger.error("UserActionLogInterceptor_logInDB_error",e);}
    }
}

XML 配置:

   <mvc:interceptors>   
      
        <mvc:interceptor>    
            <!-- 匹配的是url路徑, 如果不配置或/**,將攔截所有的Controller -->  
            <mvc:mapping path="/**" /> 
            <bean class="com.common.interceptor.UserActionLogInterceptor"></bean>    <!-- 自定義攔截器路徑 -->
        </mvc:interceptor>  
        <!-- 當設定多個攔截器時,先按順序呼叫preHandle方法,然後逆序呼叫每個攔截器的postHandle和afterCompletion方法 -->  
    </mvc:interceptors>