mysql sub-table spring interceptor for log collection

Requirements: All operations of the system are required to be logged

The sub-table rules are for reference only:

It adopts a business-based model: forcing users to be unable to skip page queries, what does it mean, that users can only click on the next page or the previous page to browse, the specific method is to query the number of records while recording the current unique The maximum value of the id value, and then add the where condition when querying again...Let’s start from the beginning: the first query pageNum=1,pageSize=10,maxId=0->sql:select * from db_x where id>0 limit 10 ; Then distribute to the table of the corresponding library, merge the obtained 4*10 pieces of data, and then parse and sort them in the memory, take the first 10 pieces of data, and take out the id=maxId of the 10th piece of data separately and render it to the front end Save it on the page, so when you click the next page, the maxId=10 is also submitted, and the sql becomes select * from db_x where id>10 limit 10, and then continue to parse and continue to save... the data returned in this way All are stable and the data is coherent (sorted)

mysql table

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='日志记录用于查询操作记录';

Entity class:



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;
    }
}

Interceptor collecting logs

id is generated by redis, you can use others

The new sentence will not be posted here

Put a table for the following operation query

Others put a table

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;
    }
}

 The following operations are used to query

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);
    }
}

The maxId and minId of the controller here are stored in the front-end. The first query is empty, and all will be queried.

Then sort 10 items each for merge and paging. After the first query, the merged maximum id and minimum id will be saved to the front end, etc. The second time the previous or next page is clicked, it will be passed in.

When the next page is clicked, minId is passed in. When the previous page is clicked, maxId is passed in. Because it is desc sorting, only one can be passed in. Click on the previous page or the next page.

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);
        }
    }

}

 

Guess you like

Origin blog.csdn.net/qq_39313596/article/details/106780770