mysql分表spring攔截器進行日誌採集

需求: 要求對系統的所有操作進行日誌記錄

分表規則 僅供參考:

採取的是基於業務的模式:迫使用戶無法進行跳頁查詢,什麼意思呢,就是用戶只能點擊下一頁或者上一頁的方式瀏覽,具體的做法在於查詢得到記錄數的同時記錄下當前唯一id值的最大值,然後再次查詢的時候添加where 條件…讓我們從頭開始捋: 第一次查詢pageNum=1,pageSize=10 ,maxId=0->sql:select * from db_x where id>0 limit 10; 然後分發到對應的庫的表中,將得到的4*10條數據合併,再在內存中進行解析排序,取前10條數據,同時將第10條數據的id=maxId單獨取出渲染到前端頁面上保存,這樣當點擊下一頁的時候,這個maxId=10也提交上去了,sql 變成了select * from db_x where id>10 limit 10,然後繼續解析,繼續保存…這種方式返回的數據都是穩定的並且數據是連貫的(排序)

mysql表

CREATE TABLE `tb_logging` (
  `id` int(64) NOT NULL COMMENT 'id',
  `class_name` varchar(64) DEFAULT NULL COMMENT '類名',
  `method_name` varchar(64) DEFAULT NULL COMMENT '方法名',
  `param` varchar(3000) DEFAULT NULL COMMENT '參數',
  `url` varchar(512) DEFAULT NULL COMMENT '訪問的url',
  `ip` varchar(64) DEFAULT NULL COMMENT '操作人ip',
  `create_user_id` varchar(64) DEFAULT NULL COMMENT '創建人id',
  `create_time` datetime DEFAULT NULL COMMENT '創建時間',
  `state_time` datetime DEFAULT NULL COMMENT '執行開始時間',
  `end_time` datetime DEFAULT NULL COMMENT '執行結束時間',
  `long_time` varchar(64) DEFAULT NULL COMMENT '耗時',
  `method` varchar(32) DEFAULT NULL COMMENT '請求方式GET、POST...',
  `module_name` varchar(512) DEFAULT NULL COMMENT '操作模塊描述',
  `return_value` varchar(521) DEFAULT NULL COMMENT '返回值',
  `browser` varchar(128) DEFAULT NULL COMMENT '當前操作的瀏覽器',
  `is_delete` tinyint(1) DEFAULT '0' COMMENT '是否刪除 0、未刪除 1、刪除',
  `state` varchar(32) DEFAULT NULL COMMENT '返回狀態碼',
  PRIMARY KEY (`id`),
  KEY `log_Joint_idx` (`is_delete`,`class_name`,`method_name`,`create_time`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='日誌記錄 用於新增修改刪除等操作記錄';

CREATE TABLE `tb_logging_select` (
  `id` int(64) NOT NULL COMMENT 'id',
  `class_name` varchar(64) DEFAULT NULL COMMENT '類名',
  `method_name` varchar(64) DEFAULT NULL COMMENT '方法名',
  `param` varchar(3000) DEFAULT NULL COMMENT '參數',
  `url` varchar(512) DEFAULT NULL COMMENT '訪問的url',
  `ip` varchar(64) DEFAULT NULL COMMENT '操作人ip',
  `create_user_id` varchar(64) DEFAULT NULL COMMENT '創建人id',
  `create_time` datetime DEFAULT NULL COMMENT '創建時間',
  `state_time` datetime DEFAULT NULL COMMENT '執行開始時間',
  `end_time` datetime DEFAULT NULL COMMENT '執行結束時間',
  `long_time` varchar(64) DEFAULT NULL COMMENT '耗時',
  `method` varchar(32) DEFAULT NULL COMMENT '請求方式GET、POST...',
  `module_name` varchar(512) DEFAULT NULL COMMENT '操作模塊描述',
  `return_value` varchar(521) DEFAULT NULL COMMENT '返回值',
  `browser` varchar(128) DEFAULT NULL COMMENT '當前操作的瀏覽器',
  `is_delete` tinyint(1) DEFAULT '0' COMMENT '是否刪除 0、未刪除 1、刪除',
  `state` varchar(32) DEFAULT NULL COMMENT '返回狀態碼',
  PRIMARY KEY (`id`),
  KEY `log_Joint_idx` (`is_delete`,`class_name`,`method_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='日誌記錄用於查詢操作記錄';

實體類:



import lombok.Data;

import java.util.Date;


/**
 * 項目名稱:
 * 類 名 稱:TbLogging
 * 類 描 述:TODO
 * 創建時間:2020/6/11 19:30
 * 創 建 人:heng
 */
@Data
public class TbLogging {
    //id
    private java.lang.Integer id;//id
    //類名
    private java.lang.String class_name;//類名
    //方法名
    private java.lang.String method_name;//方法名
    //參數
    private java.lang.String param;//參數
    //訪問的url
    private java.lang.String url;//訪問的url
    //操作人ip
    private java.lang.String ip;//操作人ip
    //創建人id
    private java.lang.String create_user_id;//創建人id
    //創建時間
    private Date create_time;//創建時間
    //執行開始時間
    private Date state_time;//執行開始時間
    //執行結束時間
    private Date end_time;//執行結束時間
    //耗時
    private java.lang.String long_time;//耗時
    //請求方式GET、POST...
    private java.lang.String method;//請求方式GET、POST...
    //操作模塊描述
    private java.lang.String module_name;//操作模塊描述 //操作模塊描述
    //返回值
    private java.lang.String return_value;//返回值
    //當前操作的瀏覽器
    private java.lang.String browser;//當前操作的瀏覽器
    //是否刪除 0、未刪除 1、刪除
    private java.lang.Integer is_delete;//是否刪除 0、未刪除 1、刪除
    private java.lang.String state;//操作模塊描述

    public Date getCreate_time() {
        return create_time;
    }

    public void setCreate_time(Date create_time) {
        this.create_time = create_time;
    }

    public Date getState_time() {
        return state_time;
    }

    public void setState_time(Date state_time) {
        this.state_time = state_time;
    }

    public Date getEnd_time() {
        return end_time;
    }

    public void setEnd_time(Date end_time) {
        this.end_time = end_time;
    }
}


import lombok.Data;

import java.util.Date;

/**
 * 項目名稱:
 * 類 名 稱:TbLoggingSelect 
 * 類 描 述:TODO
 * 創建時間:2020/6/11 19:30
 * 創 建 人:heng
 */
@Data
public class TbLoggingSelect {
    //id
    private Integer id;//id
    //類名
    private String class_name;//類名
    //方法名
    private String method_name;//方法名
    //參數
    private String param;//參數
    //訪問的url
    private String url;//訪問的url
    //操作人ip
    private String ip;//操作人ip
    //創建人id
    private String create_user_id;//創建人id
    //創建時間
    private Date create_time;//創建時間
    //執行開始時間
    private Date state_time;//執行開始時間
    //執行結束時間
    private Date end_time;//執行結束時間
    //耗時
    private String long_time;//耗時
    //請求方式GET、POST...
    private String method;//請求方式GET、POST...
    //操作模塊描述
    private String module_name;//操作模塊描述 //操作模塊描述
    //返回值
    private String return_value;//返回值
    //當前操作的瀏覽器
    private String browser;//當前操作的瀏覽器
    //是否刪除 0、未刪除 1、刪除
    private Integer is_delete;//是否刪除 0、未刪除 1、刪除
    private String state;//操作模塊描述

    public Date getCreate_time() {
        return create_time;
    }

    public void setCreate_time(Date create_time) {
        this.create_time = create_time;
    }

    public Date getState_time() {
        return state_time;
    }

    public void setState_time(Date state_time) {
        this.state_time = state_time;
    }

    public Date getEnd_time() {
        return end_time;
    }

    public void setEnd_time(Date end_time) {
        this.end_time = end_time;
    }
}

攔截器採集日誌

id是用redis生成的小夥伴可以用別的

新增語句這裏就不貼出來了

以下操作查詢的放一個表

其他放一張表

package com.web.common.intercept;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.web.common.controller.BaseController;
import com.web.entity.TbLogging;
import com.web.entity.TbLoggingSelect;
import nl.bitwalker.useragentutils.UserAgent;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import redis.clients.jedis.Jedis;
import web.dao.hsdao.TbLoggingMapper;
import web.dao.hsdao.TbLoggingSelectMapper;
import web.util.JedisUtil;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;

/**
 * @ClassName SginAop
 * @Description
 * @Author heng
 * @Date 2020/4/26 10:41
 * @Version 1.0
 */

public class LogInterceptor extends HandlerInterceptorAdapter {
  

    private final String redisKey = "LOG:LOGGING_KEY";
    private final static Logger LOGGER = LoggerFactory.getLogger(LogInterceptor.class);
    //請求開始時間標識
    private static final String LOGGER_SEND_TIME = "_send_time";
    //請求日誌實體標識
    private static final String LOGGER_ENTITY = "_logger_entity";

    @Autowired
    private TbLoggingSelectMapper tbLoggingSelectMapper;

    @Autowired
    private TbLoggingMapper tbLoggingMapper;
  public Long incr(String key) {
        Jedis jedis =JedisUtil.getJedis();
        try {
            return jedis.incr(key);
        } finally {
            if (null != jedis) {
                jedis.close();
            }
        }
    }
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (handler.getClass().isAssignableFrom(HandlerMethod.class)) {
            try {

                TbLogging tbLogging = new TbLogging();
                Long start_long_time = System.currentTimeMillis();
                tbLogging.setState_time(DateUtil.date(start_long_time));
                //獲取ip
                tbLogging.setIp(getRemoteHost(request));

                //獲取控制器的名字
                tbLogging.setClass_name(((HandlerMethod) handler).getBean().getClass().getName());
                //獲取方法名
                tbLogging.setMethod_name(((HandlerMethod) handler).getMethod().getName());
                //獲取請求參數信息
                String param = JSON.toJSONString(request.getParameterMap(),
                        SerializerFeature.DisableCircularReferenceDetect,
                        SerializerFeature.WriteMapNullValue);
                tbLogging.setParam(param);
                try {
                    tbLogging.setCreate_user_id(new BaseController().obtainLoginUserId(request));
                }catch (Exception ex){
                    LOGGER.info("拿到當前登錄人失敗");
                }
                //請求方法
                tbLogging.setMethod(request.getMethod());
                //請求url到後端的url
                tbLogging.setUrl(request.getRequestURI());
                //瀏覽器
                //獲取瀏覽器信息
                String ua = request.getHeader("User-Agent");
               //轉成UserAgent對象
                UserAgent userAgent = UserAgent.parseUserAgentString(ua);
                tbLogging.setBrowser(userAgent.toString());
                //獲取返回值
                //tbLogging.setReturn_value(response.getWriter().toString());
                //設置請求開始時間
                request.setAttribute(LOGGER_SEND_TIME, start_long_time);

                //設置請求實體到request內,方便afterCompletion方法調用
                request.setAttribute(LOGGER_ENTITY, tbLogging);

            } catch (Exception e) {
                LOGGER.info("日誌添加失敗");
            }

        }
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        try {

        String uri = request.getRequestURI();
        String contextPath = request.getContextPath();

        if (StringUtils.length(contextPath) > 0) {
            contextPath = StringUtils.substring(uri, contextPath.length());
        }
        TbLogging tbLogging = (TbLogging) request.getAttribute(LOGGER_ENTITY);

        //獲取請求錯誤碼
        int status = response.getStatus();

        //當前時間
        long currentTime = System.currentTimeMillis();

        //請求開始時間
        long time = Long.valueOf(request.getAttribute(LOGGER_SEND_TIME).toString());

        //獲取本次請求日誌實體

        tbLogging.setState(status+"");

        //設置請求時間差
        tbLogging.setLong_time((currentTime - time)+"");
        tbLogging.setEnd_time(DateUtil.date(currentTime));
        tbLogging.setCreate_time(DateUtil.date(currentTime));
           // Long longId =  IdUtil.createSnowflake(1, 1).nextId();
            Long longId = incr(redisKey);
            tbLogging.setId(longId.intValue());
            if(tbLogging.getClass_name().indexOf("TbLoggingController") == -1){
        if (contextPath.indexOf("search_") == -1
                && !tbLogging.getMethod_name().startsWith("search")
                && !tbLogging.getMethod_name().startsWith("get")
                && !tbLogging.getMethod_name().startsWith("query")
                && !tbLogging.getMethod_name().startsWith("find")
                && !tbLogging.getMethod_name().startsWith("select")
                &&  !tbLogging.getMethod_name().equals("index")) {
        //執行將日誌寫入數據庫,可以根據實際需求進行保存
        // sysLogRepo.save(sysLog);
            tbLoggingMapper.insertTbLogging(tbLogging);
        }else {
            TbLoggingSelect select = new TbLoggingSelect();
            //把tbLogging的值給select

            BeanUtils.copyProperties(select,tbLogging);
            tbLoggingSelectMapper.insertTbLoggingSelect(select);
         }
     }
        }catch (Exception e){
            LOGGER.info("日誌添加失敗");
        }
    }

    public int difference(Date nowDate, String decrypted){
        return Math.abs((int)(nowDate.getTime()-Long.valueOf(decrypted))/1000);
    }


    /**
     * @Title: getRemoteHost
     * @Description: 獲取Ip地址
     * @return: String
     * @version V1.0
     */
    public String getRemoteHost(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.equals("0:0:0:0:0:0:0:1") ? "127.0.0.1" : ip;
    }
}

 以下操作用於查詢

mapper.xml

  /**
     * 用於分表分頁查詢
     * @param map
     * @return
     */
    List<TbLogging> pageListTbLoggingSelectByObj(Map<String,Object> map);
    int pageListTbLoggingSelectByObjCount(Map<String,Object> map);





 <select id="pageListTbLoggingSelectByObj" parameterType="map" resultMap="BaseResultMap2">
        SELECT <include refid="Base_Column_List" />
        FROM tb_logging_select
        <where>
            is_delete = 0
            <if test ='null != create_time and create_time != ""'>
                AND  date_format(create_time,'%Y-%m-%d') =  #{create_time}
            </if>
            <if test ='null != maxId and maxId != "" '>
                AND  id  &gt; #{maxId}
            </if>
            <if test ='null != minId and minId != ""'>
                AND  id  &lt; #{minId}
            </if>
        </where>
        <if test ='null != maxId and maxId != "" '>
             order by id asc
        </if>
        <if test ='null != minId and minId != ""'>
              order by id desc
        </if>
        <if test ='(minId == null or minId == "") and (maxId == "" or maxId ==null) '>
            order by id desc
        </if>
        LIMIT #{pageSize}
    </select>
    <select id="pageListTbLoggingSelectByObjCount" parameterType="map" resultType="int">
        SELECT count(1)
        FROM tb_logging_select
        <where>
            is_delete = 0
            <if test ='null != create_time and create_time != ""'>
                AND  date_format(create_time,'%Y-%m-%d') =  #{create_time}
            </if>
        </where>
    </select>
   /**
     * 用於分表分頁查詢
     * @param map
     * @return
     */
    List<TbLogging> pageListTbLoggingByObj(Map<String,Object> map);
    int pageListTbLoggingByObjCount(Map<String,Object> map);




    <select id="pageListTbLoggingByObj" parameterType="map" resultMap="BaseResultMap2">
        SELECT <include refid="Base_Column_List" />
        FROM tb_logging
        <where>
            is_delete = 0
            <if test ='null != create_time and create_time != "" '>
                AND  date_format(create_time,'%Y-%m-%d') =  #{create_time}
            </if>
            <if test ='null != maxId and maxId != "" '>
                AND  id  &gt; #{maxId}
            </if>
            <if test ='null != minId and minId != ""'>
                AND  id  &lt; #{minId}
            </if>
        </where>
        <if test ='null != maxId and maxId != "" '>
            order by id asc
        </if>
        <if test ='null != minId and minId != ""'>
            order by id desc
        </if>
        <if test ='minId == "" and maxId == ""'>
            order by id desc
        </if>
        LIMIT #{pageSize}
    </select>
    <select id="pageListTbLoggingByObjCount" parameterType="map" resultType="int">
        SELECT count(1)
        FROM tb_logging
        <where>
            is_delete = 0
            <if test ='null != create_time and create_time != "" '>
                AND  date_format(create_time,'%Y-%m-%d') =  #{create_time}
            </if>
        </where>
    </select>

 

 

service

package web.service.logging;

import com.web.common.util.PropertyValueChangeUtil;
import com.web.common.util.web.BeanRefUtil;
import com.web.entity.TbLogging;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import web.dao.hsdao.TbLoggingMapper;
import web.dao.hsdao.TbLoggingSelectMapper;
import web.util.ResultUtils;

import java.util.*;

/**
 * 項目名稱:
 * 類 名 稱:TbLoggingService
 * 類 描 述:TODO
 * 創建時間:2020/6/12 17:25
 * 創 建 人:heng
 */
@Service
public class TbLoggingService {
    @Autowired
    private TbLoggingMapper tbLoggingMapper;
    @Autowired
    private TbLoggingSelectMapper tbLoggingSelectMapper;

    public ResultUtils findLoging(Map<String,Object> map){
      Integer pageSize =  Integer.valueOf( map.get("pageSize").toString());
      List<TbLogging> tbLoggings = tbLoggingMapper.pageListTbLoggingByObj(map);
      List<TbLogging> tbLoggingSelects = tbLoggingSelectMapper.pageListTbLoggingSelectByObj(map);
     int count1 = tbLoggingMapper.pageListTbLoggingByObjCount(map);
     int count2 = tbLoggingSelectMapper.pageListTbLoggingSelectByObjCount(map);
      tbLoggings.addAll(tbLoggingSelects);
        List<TbLogging> list = new ArrayList<>();
      if (map.get("maxId") != null){
          Collections.sort(tbLoggings, new Comparator<TbLogging>() {
              @Override
              public int compare(TbLogging o1, TbLogging o2) {
                  if (o1.getId()> o2.getId()){
                      return  1;
                  }
                  if(o1.getId()< o2.getId()){

                      return  -1;
                  }
                  return 0;
              }
          });
          if (tbLoggings.size() >= pageSize){
              list = tbLoggings.subList(0,pageSize);
          }else {
              list = tbLoggings;
          }
          Collections.sort(list, new Comparator<TbLogging>() {
              @Override
              public int compare(TbLogging o1, TbLogging o2) {
                  if (o1.getId()< o2.getId()){
                      return  1;
                  }
                  if(o1.getId()> o2.getId()){

                      return  -1;
                  }
                  return 0;
              }
          });
      }else{
          Collections.sort(tbLoggings, new Comparator<TbLogging>() {
              @Override
              public int compare(TbLogging o1, TbLogging o2) {
                  if (o1.getId()< o2.getId()){
                      return  1;
                  }
                  if(o1.getId()> o2.getId()){

                      return  -1;
                  }
                  return 0;
              }
          });
          if (tbLoggings.size() >= pageSize){
              list = tbLoggings.subList(0,pageSize);
          }else {
              list = tbLoggings;
          }

      }


        List<Map> mapRows = new ArrayList<Map>();
        for (TbLogging d : list) {
            BeanRefUtil beanRefUtil = new BeanRefUtil();
            Map map1 = beanRefUtil.transBean2Map(d);
            // 2.自定義按鈕設置在此處
            map1.put("maxId",list.get(0).getId());
            map1.put("minId",list.get(list.size()-1).getId());
            //下面的方法是將對象中的枚舉值改爲枚舉描述。如stat爲0時表示無效。則將map中的stat的值從0改爲0-無效,方便前端顯示,但是該方法需要完善Dto的PropertyEnum方法
            PropertyValueChangeUtil.dateValue2Desc(map1 );
            mapRows.add(map1);
        }
        return new ResultUtils(mapRows,count1+count2);
    }
}

controller 這裏的maxId和minId是存前端傳來的第一次查詢爲空會查詢全部的

然後排序各取10條進行合併分頁  第一次查詢後會把合併後的最大id和最小id存到前端等第二次點上一頁或者下一頁的時候傳入

點下一頁的時候傳入 minId 點上一頁的時候傳入maxId因爲是desc排序原因 只能傳入一個 點上一頁或者下一頁傳入

package com.web.controller;

import com.web.common.controller.BaseController;
import com.web.common.exception.BusinessException;
import com.web.common.util.ConstantValue;
import com.web.common.util.web.PagingObject;
import com.web.common.util.web.PangingUtils;
import org.apache.commons.collections.map.HashedMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import web.service.logging.TbLoggingService;
import web.util.ResultUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;

/**
 * 項目名稱:
 * 類 名 稱:TbLoggingController
 * 類 描 述:TODO
 * 創建時間:2020/6/12 17:15
 * 創 建 人:heng
 */
@Controller
@RequestMapping("logging")
public class TbLoggingController {
    @Autowired
    TbLoggingService tbLoggingService;
    /***
     * 查詢實體TbLoggingDto的分頁列表
     * @return
     * @throws Exception
     */
    @ResponseBody
    @RequestMapping(value="/search_TbLogging.do")
    public ResultUtils getListData(HttpServletRequest request , HttpServletResponse response)throws Exception {
        try {

            PagingObject init_pg = PangingUtils.getPagingObjectFormRequest(request);
            Map<String,Object> map = new HashedMap();
            map.put("create_time",request.getParameter("create_time"));
            map.put("maxId",request.getParameter("maxId"));
            map.put("minId",request.getParameter("minId"));
            map.put("pageSize",10);
            return tbLoggingService.findLoging(map);
        } catch (Exception ex) {
            logger.error("操作錯誤",ex);
            ex.printStackTrace();
            throw new BusinessException(ConstantValue.SYSTEM_ERROR_CODE,ConstantValue.SYSTEM_EROR_MESSAGE);
        }
    }

}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章