1. 程式人生 > >ThreadLocal 在記錄操作日誌中的應用

ThreadLocal 在記錄操作日誌中的應用

boolean bsp cti @override long med span 字段 中文

  ThreadLocal,很多地方叫做線程本地變量,也有些地方叫做線程本地存儲,其實意思差不多。可能很多朋友都知道ThreadLocal為變量在每個線程中都創建了一個副本,那麽每個線程可以訪問自己內部的副本變量

  在HandlerInterceptor的preHandle 中可以截取crud等操作的一些url

 

public class PlatformLogInterceptor implements HandlerInterceptor {
    private Logger log = LoggerFactory.getLogger(this.getClass());

    @Autowired
    UserService userService;

    @Autowired
    PlatformLogService platformLogService;

    @Autowired
    FunctionService functionService;
    @Override
    
public boolean preHandle(HttpServletRequest httpRequest, HttpServletResponse response, Object handler) throws Exception { try{ String types = httpRequest.getHeader("Accept"); String uri = httpRequest.getRequestURI();//請求uri PlatformLog platformLog = new PlatformLog();
if(uri.toLowerCase().matches("[\\s\\S]*((del)|(update)|(insert)|(add)|(publish)|(export)|(import)|(upload)|(create)|(process)|(audit))[\\s\\S]*")) { Function function = getFunction(uri); //獲取uri對應功能詳情 String userId =(String) httpRequest.getAttribute("token_userId");//userId
String ipAddr = getIpAddr(httpRequest);// 用戶ip地址 User user = userService.findByUesrId(Long.valueOf(""+userId)); /*************************設置日誌項**************************/ platformLog.setParamJson(JSONObject.fromObject(httpRequest.getParameterMap()).toString()); if(function!=null){ platformLog.setMethodName(function.getFuncName()); }else{ platformLog.setMethodName(uri); } platformLog.setOptionIp(ipAddr); platformLog.setOptionTime(new Date()); platformLog.setOptionUser(Long.valueOf(userId)); platformLog.setOptionUserGroupName(user.getGroupName()); platformLog.setOptionUserName(user.getName()); platformLog.setRelatedId(user.getUserId()); platformLog.setTenantId(user.getTenantId()); platformLog.setOrgId(user.getGroupId()); PlatformLog.setPlatformLog(platformLog);// put it into threadLocal } return true; }catch (Exception e){ PlatformLog.removePlatformLog(); return true; } } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { // do nothing } @Override public void afterCompletion(HttpServletRequest req, HttpServletResponse res, Object handler, Exception ex) throws Exception { // do nothing } private String getIpAddr(HttpServletRequest request) { String ip = request.getHeader("X-Forwarded-For"); if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("WL-Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("HTTP_CLIENT_IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("HTTP_X_FORWARDED_FOR"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getRemoteAddr(); } return ip; } private Function getFunction(String funcURl){ try { List<Function> functions = functionService.findAll(); for(Function f:functions){ if(f.getFuncURl().equals(funcURl)){ return f; } } } catch (Exception e) { // e.printStackTrace(); return null; } return null; }

 spring配置

<bean id="wsLogInterceptor" class="。。。。。。.interceptor.PlatformLogInterceptor"/>
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <ref bean="wsLogInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>

在這裏不能直接去記錄操作的platformLog 定義的platformlog 將要記錄的日誌放入ThreadLocal中 ThreadLocal調用get方法前 必須調用set方法

public class PlatformLog implements Serializable {
    
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    private static final ThreadLocal<PlatformLog> PLATFORM_LOG_THREAD_LOCAL = new ThreadLocal<>();
    private Integer id;
    private String methodName;//方法名
    private String paramJson;//參數json
    private String resultJson;//修改後的對象json
    private Long   relatedId;//相關ID
    private String relatedChar;//相關字符
    private Long   optionUser;//操作用戶
    private String   optionIp;//操作Ip
    private String dataCode;//返回的code碼
    private Date   optionTime;//操作時間
    private Long tenantId;//日誌租戶(獲取操作用戶)
    private Long orgId;//orgId
    
    private String   optionUserName;//操作用戶名
    private String   optionUserGroupName;//操作用戶組
    private List<Object> thParamName=new ArrayList<Object>();//表頭名稱
    private List<Object> tdParamData=new ArrayList<Object>();//
    private List<Object> thResultName=new ArrayList<Object>();
    private List<Object> tdResulData=new ArrayList<Object>();//
    private List<LogValue> logValues=new ArrayList<LogValue>();//
    public String getOptionIp() {
        return optionIp;
    }
    public void setOptionIp(String optionIp) {
        this.optionIp = optionIp;
    }
    
    public String getOptionUserName() {
        return optionUserName;
    }
    public void setOptionUserName(String optionUserName) {
        this.optionUserName = optionUserName;
    }
    public String getOptionUserGroupName() {
        return optionUserGroupName;
    }
    public void setOptionUserGroupName(String optionUserGroupName) {
        this.optionUserGroupName = optionUserGroupName;
    }
    public List<LogValue> getLogValues() {
        return logValues;
    }
    public void setLogValues(List<LogValue> logValues) {
        this.logValues = logValues;
    }
    public List<Object> getThParamName() {
        return thParamName;
    }
    public void setThParamName(List<Object> thParamName) {
        this.thParamName = thParamName;
    }
    public List<Object> getThResultName() {
        return thResultName;
    }
    public void setThResultName(List<Object> thResultName) {
        this.thResultName = thResultName;
    }
    public List<Object> getTdParamData() {
        return tdParamData;
    }
    public void setTdParamData(List<Object> tdParamData) {
        this.tdParamData = tdParamData;
    }
    public List<Object> getTdResulData() {
        return tdResulData;
    }
    public void setTdResulData(List<Object> tdResulData) {
        this.tdResulData = tdResulData;
    }
    public Long getRelatedId() {
        return relatedId;
    }
    public void setRelatedId(Long relatedId) {
        this.relatedId = relatedId;
    }
    public String getRelatedChar() {
        return relatedChar;
    }
    public void setRelatedChar(String relatedChar) {
        this.relatedChar = relatedChar;
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }

    public String getMethodName() {
        return methodName;
    }
    public void setMethodName(String methodName) {
        this.methodName = methodName;
    }
    public String getParamJson() {
        try {
            if(StringUtils.isEmpty(this.paramJson)&&this.logValues.size()>0){
                ObjectMapper mapper = new ObjectMapper();
                this.paramJson=mapper.writeValueAsString(this.logValues);
            }
        } catch (JsonProcessingException e) {
            Logger logger = LoggerFactory.getLogger(this.getClass());
            logger.error("method {} execute error,param:{} Exception:{}","setTranslationParam",logValues,e);
    
        }
        return paramJson;
    }
    
    public String getResultJson() {
        return resultJson;
    }
    
    /**
     * 該方法不提供對外調用,只提供數據庫封裝回調,要設置日誌保存參數使用
     * setTranslationParam,setUpdateParam方法
     * @param paramJson
     */
    @SuppressWarnings("unchecked")
    public void setParamJson(String paramJson) {
        try {
            
            if(StringUtils.isEmpty(paramJson)){
                return;
            }
            ObjectMapper mapper = new ObjectMapper();
            JavaType type = mapper.getTypeFactory().constructParametricType(ArrayList.class,
                    LogValue.class);
            List<LogValue>    logValues = (List<LogValue>) mapper.readValue(paramJson, type);
            for (LogValue logValue : logValues) {
                this.thParamName.add(logValue.getName());
                this.tdParamData.add(logValue.getValue());
            }
        } catch (Exception e) {
            Logger logger = LoggerFactory.getLogger(this.getClass());
            logger.error("method {} execute error,param:{} Exception:{}","setParamJson",paramJson,e);
            this.paramJson = paramJson;
        }
        this.paramJson = paramJson;
    }
    /**
     * 該方法不提供對外調用,只提供數據庫封裝回調,要設置日誌保存參數使用
     * setTranslationParam,setUpdateParam方法
     * @param paramJson
     */
    public void setResultJson(String resultJson) {
        try {
            if(StringUtils.isEmpty(resultJson)){
                return;
            }
            ObjectMapper mapper = new ObjectMapper();
            JavaType type = mapper.getTypeFactory().constructParametricType(ArrayList.class,
                    LogValue.class);
            List<LogValue>    logValues = (List<LogValue>) mapper.readValue(resultJson, type);
            for (LogValue logValue : logValues) {
                this.thResultName.add(logValue.getName());
                this.tdResulData.add(logValue.getValue());
            }
        } catch (Exception e) {
            Logger logger = LoggerFactory.getLogger(this.getClass());
            logger.error("method {} execute error,param:{} Exception:{}","setParamJson",paramJson,e);
            this.resultJson = resultJson;
        }
        this.resultJson = resultJson;
    }
    public Long getOptionUser() {
        return optionUser;
    }
    public void setOptionUser(Long optionUser) {
        this.optionUser = optionUser;
    }
    public String getDataCode() {
        return dataCode;
    }
    /**
     * 該方法回調使用
     * 設置日誌回調結果用
     * setOptionResult
     * @param dataCode
     */
    public void setDataCode(String dataCode) {
        this.dataCode = dataCode;
    }
    public Date getOptionTime() {
        return optionTime;
    }
    public void setOptionTime(Date optionTime) {
        this.optionTime = optionTime;
    }
    public Long getTenantId() {
        return tenantId;
    }
    public void setTenantId(Long tenantId) {
        this.tenantId = tenantId;
    }
    
    /**
     * 除去修改刪除以外設置調用參數的時候都是調用這個方法
     * @param atribute 屬性字段
     * @param name     屬性名稱中文
     * @param value    屬性值
     */
    public void setTranslationParam(String atribute,String name,Object value){
            LogValue logValue=new LogValue();
            logValue.setAtribute(atribute);
            logValue.setName(name);
            logValue.setValue(value);
            logValues.add(logValue);
    }
    /**
     * 修改或者刪除操作需要保留日誌的對象
     * old 和news對象的屬性獲取方法一定要設置名稱註解
     * {@link Excel}
     * @param old 修改刪除前的對象
     * @param news 修改後的對象,刪除是設置為null
     */
    public void setUpdateParam(Object old,Object news){
        try {
            ObjectMapper mapper = new ObjectMapper();
            if(old!=null){
                this.paramJson=mapper.writeValueAsString(ClassObjectValueUtile.getFiledName(old));
            }
            if(news!=null){
                this.resultJson=mapper.writeValueAsString(ClassObjectValueUtile.getFiledName(news));
            }
            
        } catch (JsonProcessingException e) {
            Logger logger = LoggerFactory.getLogger(this.getClass());
            logger.error("method {} execute error,old:{} news:{} Exception:{}","setUpdateParam",old,news,e);

        }
    }
    /**
     * 設置操作日誌的返回結果
     * 
     * @param code
     */
  public void setOptionResult(Integer code){
      String codeName =PlatformErrorCode.codes.get(code);
      if(StringUtils.isEmpty(codeName)){
          codeName ="請求失敗";
      }
      this.dataCode=PlatformErrorCode.codes.get(code);
  }
    /**
     * @return the orgId
     */
    public Long getOrgId() {
        return orgId;
    }
    /**
     * @param orgId the orgId to set
     */
    public void setOrgId(Long orgId) {
        this.orgId = orgId;
    }

    public static PlatformLog getPlatformLog(){
        return PLATFORM_LOG_THREAD_LOCAL.get();
    }
    public static void setPlatformLog(PlatformLog platformLog){
        PLATFORM_LOG_THREAD_LOCAL.set(platformLog);
    }
    public  static void removePlatformLog(){
        PLATFORM_LOG_THREAD_LOCAL.remove();
    }
}

最後在ResponseBodyAdvice 的實現類中記錄操作日誌

public class LogResponseBodyAdvice implements ResponseBodyAdvice<ResultDTO> {
    private Logger log = LoggerFactory.getLogger(this.getClass());
    @Autowired
    PlatformLogService platformLogService;
    static ObjectMapper mapper = new ObjectMapper();
    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        return true;//do nothing
    }

    @Override
    public ResultDTO beforeBodyWrite(ResultDTO body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        PlatformLog platformLog = PlatformLog.getPlatformLog();
        if (platformLog==null){
            return body;
        }
        try {
            platformLog.setResultJson(mapper.writeValueAsString(body));
            platformLog.setDataCode(""+body.getCode());
            PlatformLog.removePlatformLog();
            platformLogService.insert(platformLog);
        } catch (Exception e) {
            e.printStackTrace();
            PlatformLog.removePlatformLog();
            log.error("err method: wsLogResponseBodyAdvice.beforeBodyWrite, Exception ", e);
            return body;
        }
        return body;
    }
}

就這樣吧 第一次寫 好渣

ThreadLocal 在記錄操作日誌中的應用