java 项目日志管理设计方案[通俗易懂]

java 项目日志管理设计方案[通俗易懂]java项目日志管理设计方案因项目需要记录整个系统的操作记录,考虑到系统操作日志的数据量,单表很容易达到瓶颈,导致查询效率低下,顾使用分表方案,减小数据库的负担,缩短查询时间。目前对于分表的解决方案有很多,但本篇博文主要讲解博主自行实现的日志管理的解决方案1创建日志表1.1日志表Sql语句如下具体表设计随项目情况而变化表创建SQL语句CREATETABLE`sys_user

大家好,又见面了,我是你们的朋友全栈君。

java 项目日志管理设计方案

因项目需要记录整个系统的操作记录,考虑到系统操作日志的数据量,单表很容易达到瓶颈,导致查询效率低下,顾使用分表方案,减小数据库的负担,缩短查询时间。目前对于分表的解决方案有很多,本博文主要讲解博主自行实现的日志管理的解决方案,如有遗漏或错误的请各位大佬多多包涵
鉴于总是有人私信要demo,这里将以前搭的一个简易的项目贴出来:https://gitee.com/jiangliuhong/syslog.git


1 创建日志表

1.1 日志表Sql语句如下

具体表设计随项目情况而变化

表创建SQL语句

CREATE TABLE `sys_user_log` (
  `log_id` varchar(32) NOT NULL COMMENT '日志表id,uuid',
  `user_id` varchar(32) DEFAULT NULL COMMENT '用户id,记录操作用户',
  `module_name` varchar(225) NOT NULL COMMENT '模块名称',
  `operate` varchar(225) NOT NULL COMMENT '操作名称',
  `time` datetime NOT NULL COMMENT '操作时间',
  `class_name` varchar(225) NOT NULL COMMENT '类名称',
  `method_name` varchar(225) NOT NULL COMMENT '方法名称',
  `params` longtext COMMENT '传入参数',
  `ip` varchar(225) NOT NULL COMMENT '操作ip',
  PRIMARY KEY (`log_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

1.2 日志表创建

因考虑到项目情况,顾为每月创建一个日志表

1.2.1 表创建方法

创建service、dao方法

DbMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.carfi.vrcp.dao.SysDbMapper">
    <update id="createUserLogTable" parameterType="java.lang.String">
    	create table #{name,jdbcType=VARCHAR} like sys_user_log
    </update>
</mapper>

DbMapper.java

public interface SysDbMapper {
    /**
     *  创建数据表
     * @param name 表名
     */
    void createUserLogTable(String name);
}

DbService.java

public interface SysDbService {
    /**
     * 创建数据表
     *
     * @param preName   名称前缀
     * @param isSufTime 是否显示 时间后缀
     */
    void createTable(String preName, Boolean isSufTime);
}

DbServiceImpl.java


@Service("dbService")
public class DbServiceimpl implements DbService {

    @Autowired
    private DbMapper dbMapper;

    @Override
    public void createTable(String preName, Boolean sufTime) {
        if (sufTime) {
            dbMapper.createTable(preName + "_" + getSufName());
        } else {
            dbMapper.createTable(preName);
        }
    }
    
    /**
     * 获取名称后缀<br>
     * 格式: 20170301
     *
     * @return
     */
    private String getSufName() {
        Date d = new Date();
        String s = DateUtil.date2String(d, false);
        return s.replace("-", "");
    }
}

1.2.2 创建定时任务(每月第一天凌晨执行)

BaseQuartz.java


/**
 * 报警定时任务接口
 * 
 */
public interface BaseQuartz {

	/**
	 * 定时任务执行方法
	 */
	public void work();
}

DbQuartz.java


public class DbQuartz implements BaseQuartz {
    
    private static final Logger log = LoggerFactory.getLogger(DbQuartz.class);
    /**
     * 默认表名
     */
    private static String tableName = "sys_user_log";

    @Override
    public void work() {
        try {
            //创建表
            DbService dbService = (SysDbService) SpringUtil.getBean("sysDbService");
            dbService.createTable(tableName, true);
            log.info("创建表" + tableName + "成功");
            //更新系统用户日志表表缓存
            SysCacheUtil.flushSysUserLogTableName();
        } catch (Exception e) {
            log.error("创建表" + tableName + "失败");
            work();
        }
    }
    
}

quartz配置文件:spring-quartz.xml


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:tx="http://www.springframework.org/schema/tx" xmlns:cache="http://www.springframework.org/schema/cache"
	xsi:schemaLocation="  
       http://www.springframework.org/schema/context  
       http://www.springframework.org/schema/context/spring-context.xsd  
       http://www.springframework.org/schema/beans  
       http://www.springframework.org/schema/beans/spring-beans.xsd  
       http://www.springframework.org/schema/tx  
       http://www.springframework.org/schema/tx/spring-tx.xsd  
       http://www.springframework.org/schema/aop  
       http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/cache  
       http://www.springframework.org/schema/cache/spring-cache-3.2.xsd
     ">
     
     <!-- 工作的bean -->
	<!-- 数据库定时任务 开始 -->
	<bean id="dbQuartz" class="com.carfi.vrcp.quartz.DbQuartz" />
	<bean id="dbQuartzJobDetail"
		class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
		<property name="targetObject">
			<ref bean="dbQuartz" />
		</property>
		<property name="targetMethod">
			<value>work</value>
		</property>
	</bean>
	<!-- 定义触发器 -->
	<bean id="dbQuartzJobTrigger"
		class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
		<property name="jobDetail">
			<ref bean="dbQuartzJobDetail" />
		</property>
		<property name="cronExpression">
			<!-- 每月第一天凌晨执行 -->
			<value>0 0 0 1 * ?</value>
		</property>
	</bean>
	
	<!-- 启动触发器的配置开始 -->
	<bean name="startQuertz" lazy-init="false" autowire="no"
		class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
		<property name="triggers">
			<list>
				<ref bean="dbQuartzJobTrigger" />
			</list>
		</property>
	</bean>
	
</beans>  

到止为止日志表自动创建逻辑完成

2 日志表数据插入查询

因考虑查询速度,采用根据传入的时间进行联合查询,规定只能查询连续3个月的日志数据,即前台传入 20170301,20170525 则联合表sys_user_log20170301,sys_user_log20170401,sys_user_log20170501三表进行联合查询。

2.1 日志相关类源代码

主要代码包括,日志实体类,日志查询类,日志表相关的dao、service 类

SysUserLog.java


import java.io.Serializable;
import java.util.Date;

import com.fasterxml.jackson.annotation.JsonFormat;

/**
 * 系统用户日志
 */
public class SysUserLog implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	/**日志id*/
	private String logId;
	/**用户id*/
	private String userId;
	/**模块名称*/
	private String moduleName;
	/**操作*/
	private String operate;
	/**时间*/
	private Date time;
	/**类名*/
	private String className;
	/**方法名*/
	private String methodName;
	/**传入参数*/
	private String params;
	/**操作ip*/
	private String ip;
	
	public String getLogId() {
		return logId;
	}
	public void setLogId(String logId) {
		this.logId = logId;
	}
	public String getUserId() {
		return userId;
	}
	public void setUserId(String userId) {
		this.userId = userId;
	}
	public String getModuleName() {
		return moduleName;
	}
	public void setModuleName(String moduleName) {
		this.moduleName = moduleName;
	}
	public String getOperate() {
		return operate;
	}
	public void setOperate(String operate) {
		this.operate = operate;
	}
	
	@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
	public Date getTime() {
		return time;
	}
	public void setTime(Date time) {
		this.time = time;
	}
	
	public String getClassName() {
		return className;
	}
	public void setClassName(String className) {
		this.className = className;
	}
	public String getMethodName() {
		return methodName;
	}
	public void setMethodName(String methodName) {
		this.methodName = methodName;
	}
	public String getParams() {
		return params;
	}
	public void setParams(String params) {
		this.params = params;
	}
	public String getIp() {
		return ip;
	}
	public void setIp(String ip) {
		this.ip = ip;
	}
	//扩展字段
	/**用户账号*/
	private String username;
	/**组织名称*/
	private String organizationName;

	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getOrganizationName() {
		return organizationName;
	}
	public void setOrganizationName(String organizationName) {
		this.organizationName = organizationName;
	}
	

SysUserLogMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.carfi.vrcp.dao.SysUserLogMapper" >
  <resultMap id="BaseResultMap" type="com.carfi.vrcp.pojo.SysUserLog" >
    <id column="log_id" property="logId" jdbcType="VARCHAR" />
    <result column="user_id" property="userId" jdbcType="VARCHAR" />
    <result column="module_name" property="moduleName" jdbcType="VARCHAR" />
    <result column="operate" property="operate" jdbcType="VARCHAR" />
    <result column="time" property="time" jdbcType="TIMESTAMP" />
    <result column="class_name" property="className" jdbcType="VARCHAR" />
    <result column="method_name" property="methodName" jdbcType="VARCHAR" />
    <result column="params" property="params" jdbcType="VARCHAR" />
    <result column="ip" property="ip" jdbcType="VARCHAR" />
  </resultMap>
  <resultMap type="com.carfi.vrcp.pojo.SysUserLog" id="BaseResultMapExt" extends="BaseResultMap">
  	<result column="username" property="username" jdbcType="VARCHAR" />
    <result column="full_name" property="organizationName" jdbcType="VARCHAR" />
  </resultMap>
  <sql id="BaseColumn">
  	log_id, user_id, module_name, operate, time, class_name, method_name, params, ip
  </sql>
  <insert id="insertToTable">
  	insert into ${tableName}
  	(log_id, user_id, module_name, operate, time, class_name, method_name, params, ip)
  	values
  	(
  	#{log.logId,jdbcType=VARCHAR},
  	#{log.userId,jdbcType=VARCHAR},
  	#{log.moduleName,jdbcType=VARCHAR},
  	#{log.operate,jdbcType=VARCHAR},
  	#{log.time,jdbcType=TIMESTAMP},
  	#{log.className,jdbcType=VARCHAR},
  	#{log.methodName,jdbcType=VARCHAR},
  	#{log.params,jdbcType=VARCHAR},
  	#{log.ip,jdbcType=VARCHAR}
  	)
  </insert>
  <insert id="insert" parameterType="com.carfi.vrcp.pojo.SysUserLog" >
  	insert into sys_user_log 
  	(log_id, user_id, module_name, operate, time, class_name, method_name, params, ip)
  	values
  	(
  	#{logId,jdbcType=VARCHAR},
  	#{userId,jdbcType=VARCHAR},
  	#{moduleName,jdbcType=VARCHAR},
  	#{operate,jdbcType=VARCHAR},
  	#{time,jdbcType=TIMESTAMP},
  	#{className,jdbcType=VARCHAR},
  	#{methodName,jdbcType=VARCHAR},
  	#{params,jdbcType=VARCHAR},
  	#{ip,jdbcType=VARCHAR}
  	)
  </insert>
  <!-- <select id="selectAll" resultMap="BaseResultMap">
  	select 
  	<include refid="BaseColumn"/>
  	from sys_user_log
  </select> -->
   <select id="selectAll" resultMap="BaseResultMapExt" parameterType="com.carfi.vrcp.query.SysUserLogQuery">
  	SELECT
	U.USERNAME,
	O.FULL_NAME,
	UL.LOG_ID,
	UL.USER_ID,
	UL.MODULE_NAME,
	UL.OPERATE,
	UL.TIME,
	UL.CLASS_NAME,
	UL.METHOD_NAME,
	UL.PARAMS,
	UL.IP
	FROM
		V_USER_LOG UL
	INNER JOIN SYS_USER U ON U.USER_ID = UL.USER_ID
	INNER JOIN SYS_ORGANIZATION O ON O.ORGANIZATION_ID = U.ORGANIZATION_ID
	<where>
		<if test="organizationId != null and organizationId != ''">
			AND O.ORGANIZATION_ID = #{organizationId,jdbcType=VARCHAR}
		</if>
		<if test="organizationIds != null">
			AND O.ORGANIZATION_ID IN 
			<foreach collection="organizationIds" item="oid" open="(" separator="," close=")">
				#{oid,jdbcType=VARCHAR}
			</foreach>
		</if>
		<if test="username != null and username != ''">
			AND UL.USER_ID LIKE CONCAT('%',#{username,jdbcType=VARCHAR},'%')
		</if>
		<if test="moduleName != null and moduleName != ''">
			AND UL.MODULE_NAME LIKE CONCAT('%',#{moduleName,jdbcType=VARCHAR},'%')
		</if>
	</where>
	ORDER BY UL.TIME DESC 
  </select>
  <select id="selectAllByTables" resultMap="BaseResultMapExt">
  	SELECT
	U.USERNAME,
	O.FULL_NAME,
	UL.LOG_ID,
	UL.USER_ID,
	UL.MODULE_NAME,
	UL.OPERATE,
	UL.TIME,
	UL.CLASS_NAME,
	UL.METHOD_NAME,
	UL.PARAMS,
	UL.IP
	FROM
		${table} UL
	INNER JOIN SYS_USER U ON U.USER_ID = UL.USER_ID
	INNER JOIN SYS_ORGANIZATION O ON O.ORGANIZATION_ID = U.ORGANIZATION_ID
	<where>
		<if test="query.organizationId != null and query.organizationId != ''">
			AND O.ORGANIZATION_ID = #{query.organizationId,jdbcType=VARCHAR}
		</if>
		<if test="query.organizationIds != null">
			AND O.ORGANIZATION_ID IN 
			<foreach collection="query.organizationIds" item="oid" open="(" separator="," close=")">
				#{oid,jdbcType=VARCHAR}
			</foreach>
		</if>
		<if test="query.username != null and query.username != ''">
			AND U.USERNAME LIKE CONCAT('%',#{query.username,jdbcType=VARCHAR},'%')
		</if>
		<if test="query.moduleName != null and query.moduleName != ''">
			AND UL.MODULE_NAME LIKE CONCAT('%',#{query.moduleName,jdbcType=VARCHAR},'%')
		</if>
		<if test="query.startTime != null and query.endTime != null">
			AND UL.TIME BETWEEN #{query.startTime,jdbcType=TIMESTAMP} AND #{query.endTime,jdbcType=TIMESTAMP}
		</if>
	</where>
	ORDER BY UL.TIME DESC 
  </select>
</mapper>

SysUserLogMapper.java

public interface SysUserLogMapper {

	/**
	 * 新增日志记录
	 * @param sysUserLog
	 * @return
	 */
	int insert(SysUserLog sysUserLog);
	/**
	 * 添加日志到指定数据库
	 * @param tableName
	 * @param sysUserLog
	 * @return
	 */
	int insertToTable(@Param("tableName") String tableName,@Param("log") SysUserLog sysUserLog);
	/**
	 * 查询所有
	 * @return
	 */
	List<SysUserLog> selectAll(SysUserLogQuery query);
	
	
	List<SysUserLog> selectAllByTables(@Param("table") String table,@Param("query") SysUserLogQuery query);
}

SysUserLogService.java

PageInfo 为Mybatis分页插件“PageHelp”中的分页辅助类

public interface SysUserLogService {

    /**
     * 添加系统用户日志
     *
     * @param sysUserLog 日志信息
     */
    void addUserLog(SysUserLog sysUserLog);

    /**
     * 分页获取日志列表
     *
     * @param query  查询参数
     * @param start  页数
     * @param length 每页个数
     * @return
     */
    PageInfo queryPage(SysUserLogQuery query, Integer start, Integer length) throws Exception;

SysUserLogServiceImpl.java

SysCacheUtil:项目中集成了EhCahe缓存,而后根据项目的缓存规则封装的缓存工具类。在该日志查询、存储方案中将根据数据库中的日志表进行操作,顾将日志数据表名存入缓存。查询系统数据库中日志数据表表名的sql语句如下:
SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE=‘BASE TABLE’ AND TABLE_SCHEMA = ‘数据库名称’ AND TABLE_NAME LIKE CONCAT (‘sys_user_log’,’%’);


/**
 * 用户日志管理业务实现
 *
 * @author jiangliuhong
 * @CREATEDATE 2017年2月13日
 */
@Service("sysUserLogService")
public class SysUserLogServiceImpl implements SysUserLogService {

    @Autowired
    private SysUserLogMapper userLogMapper;
    @Autowired
    private DbService dbService;

    /**
     * sys_user_log
     */
    private static String preTableName = "sys_user_log";

    @Override
    public void addUserLog(SysUserLog sysUserLog) {
        try {
            userLogMapper.insertToTable(getUserLogTableName(), sysUserLog);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public PageInfo queryPage(SysUserLogQuery query, Integer start, Integer length) throws Exception {
        // 判断开始结束日期是否为空
        if (query.getStartTime() == null || query.getEndTime() == null) {
            throw new CustomerException("开始、结束时间不能为空");
        }
		// 从缓存中读取系统数据库中的日志表表名
        List<String> userLogTableName = (List<String>) SysCacheUtil.getSysUserLogTableName();
        // 检查系统用户日志表名缓存是否存在,不存在则查询
        if (userLogTableName == null) {
            userLogTableName = dbService.queryUserLogTableName();
        }
        String logTable = "";
        if (userLogTableName == null ? true : userLogTableName.size() > 0) {
            // 标记是否比较开始时间
            Boolean isStart = true;
            for (int i = 0; i < userLogTableName.size(); i++) {
                if (isStart) {
                    // 如果表创建时间与开始时间时间同年同月 则使循环体往下执行
                    if (DateUtil.equals(changeToDate(userLogTableName.get(i)), query.getStartTime())
                            || DateUtil.countSecond(changeToDate(userLogTableName.get(i)), query.getStartTime()) >= 0) {
                        logTable = " ( select * from " + preTableName;
                        isStart = false;
                    } else {
                        continue;
                    }
                }
                logTable = logTable + " union all " + " select * from " + userLogTableName.get(i);
                // 如果表创建时间与结束时间同年同月 则跳出循环
                if (DateUtil.equals(changeToDate(userLogTableName.get(i)), query.getEndTime())) {
                    break;
                }
            }
            if (!isStart) {
                logTable = logTable + " ) ";
            } else {
                logTable = preTableName;
            }
        } else {
            logTable = preTableName;
        }
        // 分页计算
        start = start / length + 1;
        PageHelper.startPage(start, length);
        // List<SysUserLog> userLogs = userLogMapper.selectAll(query);
        List<SysUserLog> userLogs = userLogMapper.selectAllByTables(logTable, query);
        PageInfo pageInfo = new PageInfo(userLogs);
        return pageInfo;
    }

    /**
     * 获取最新的日志表表名
     *
     * @return
     */
    private String getUserLogTableName() {
        //取用户日志表名集合
        List<String> userLogTableName = SysCacheUtil.getSysUserLogTableName();
        // 判断最新表名是否与该月同月,不同月则创建该月日志表
        if (userLogTableName == null ? true : userLogTableName.size() <= 0) {
            dbService.createTable("sys_user_log", true);
            userLogTableName = SysCacheUtil.flushSysUserLogTableName();
        } else {
            // userLogTableName.size() > 0
            String tableName = userLogTableName.get(userLogTableName.size() - 1);
            if (!DateUtil.equals(changeToDate(tableName), new Date(System.currentTimeMillis()))) {
                // 不同月,则创建该月表,并更新日志缓存
                dbService.createTable("sys_user_log", true);
                userLogTableName = SysCacheUtil.flushSysUserLogTableName();
            }
        }
        if (userLogTableName == null ? true : userLogTableName.size() <= 0) {
            return preTableName;
        }

        // 更新缓存
        SysCacheUtil.setSysUserLogTableName(userLogTableName);
        return userLogTableName.get(userLogTableName.size() - 1);
    }

    /**
     * 获取名称后缀<br>
     * 格式: 20170301
     *
     * @return
     */
    @SuppressWarnings("unused")
    private String getSufName() {
        Date d = new Date();
        String s = DateUtil.date2String(d, false);
        s = s.replace("-", "");
        s = s.substring(0, s.length() - 2);
        s = s + "01";
        return s;
    }

    /**
     * 计算日志表时间
     *
     * @param tabelName 表名
     * @return
     */
    private Date changeToDate(String tabelName) {
        int lastIndexOf = tabelName.lastIndexOf('_');
        if (lastIndexOf >= 0) {
            tabelName = tabelName.substring(lastIndexOf + 1);
            String strDate = tabelName.substring(0, 4) + "-" + tabelName.substring(4, 6) + "-"
                    + tabelName.substring(6, 8);
            return DateUtil.string2Date(strDate);
        } else {
            return null;
        }
    }
}

SysUserLogQuery.java

该类为日志表辅助查询类,具体查询条件根据项目实际情况而定

import java.util.Date;
import java.util.List;

/**
 * 日志查询类
 */
public class SysUserLogQuery {

	/**组织id*/
	private String organizationId;
	/**组织集合*/
	private List<String> organizationIds;
	/**开始时间*/
	private Date startTime;
	/**结束时间*/
	private Date endTime;
	/**用户名*/
	private String username;
	/**模块名称*/
	private String moduleName;
	public String getOrganizationId() {
		return organizationId;
	}
	public void setOrganizationId(String organizationId) {
		this.organizationId = organizationId;
	}
	public List<String> getOrganizationIds() {
		return organizationIds;
	}
	public void setOrganizationIds(List<String> organizationIds) {
		this.organizationIds = organizationIds;
	}
	public Date getStartTime() {
		return startTime;
	}
	public void setStartTime(Date startTime) {
		this.startTime = startTime;
	}
	public Date getEndTime() {
		return endTime;
	}
	public void setEndTime(Date endTime) {
		this.endTime = endTime;
	}
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getModuleName() {
		return moduleName;
	}
	public void setModuleName(String moduleName) {
		this.moduleName = moduleName;
	}
	
}

DateUtil.java

该类为自行封装的时间处理工具类,代码如下:

import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

public class DateUtil {

    public static Date string2Date(String time) {
        try {
            Date date = new Date();
            DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            if (time.length() <= 10) {
                time = time + " 00:00:00";
            }
            date = sdf.parse(time);
            return date;
        } catch (ParseException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * @param date 时间对象
     * @param hms  是否显示时分秒
     * @return
     */
    public static String date2String(Date date, Boolean hms) {
        DateFormat sdf;
        if (hms) {
            sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        } else {
            sdf = new SimpleDateFormat("yyyy-MM-dd");
        }
        String time = sdf.format(date);
        return time;
    }

    public static Timestamp string2Timestamp(String time) {
        Timestamp ts = new Timestamp(System.currentTimeMillis());
        if (time.length() <= 10) {
            time = time + " 00:00:00";
        }
        ts = Timestamp.valueOf(time);
        return ts;
    }

    /**
     * @param ts  时间戳对象
     * @param hms 是否显示时分秒
     * @return
     */
    public static String timestamp2String(Timestamp ts, Boolean hms) {
        DateFormat sdf;
        if (hms) {
            sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        } else {
            sdf = new SimpleDateFormat("yyyy-MM-dd");
        }
        String tsStr = "";
        tsStr = sdf.format(ts);
        return tsStr;
    }

    public static Date timestamp2Date(Timestamp ts) {
        Date date = new Date();
        date = ts;
        return date;
    }

    public static Timestamp date2Timestamp(Date date) {
        String time = "";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        time = sdf.format(date);
        Timestamp ts = Timestamp.valueOf(time);
        return ts;
    }

    /**
     * 计算两个时间之间的小时差<br>
     * start - stop
     *
     * @param start 开始时间
     * @param stop  结束时间
     * @return
     */
    public static Long countHour(Date start, Date stop) {
        long diff = start.getTime() - stop.getTime();
        long hour = diff / (60 * 60 * 1000);
        return hour;
    }

    /**
     * 计算两个时间之间的分钟数差 <br>
     * start - stop
     *
     * @param start 开始时间
     * @param stop  结束时间
     * @return
     */
    public static Long countMinute(Date start, Date stop) {
        long diff = start.getTime() - stop.getTime();
        long min = diff / (60 * 1000);
        return min;
    }

    /**
     * 计算两个时间之间的秒数差<br>
     * start - stop
     *
     * @param start 开始时间
     * @param stop  结束时间
     * @return
     */
    public static Long countSecond(Date start, Date stop) {
        long diff = start.getTime() - stop.getTime();
        long sec = diff / 1000;
        return sec;
    }

    /**
     * 按天增加或减时间
     *
     * @param date
     * @param days  增减的天数
     * @param hms   是否显示时分秒
     * @param isAdd 加减标识,false 是减,true是加
     * @return
     */
    public static String addOrMinusDate(Date date, int days, Boolean hms, Boolean isAdd) {
        long d = (long) days;
        SimpleDateFormat df = null;
        if (hms) {
            df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        } else {
            df = new SimpleDateFormat("yyyy-MM-dd");
        }
        if (!isAdd) {
            return df.format(new Date(date.getTime() - (d * 24 * 60 * 60 * 1000)));
        } else {
            return df.format(new Date(date.getTime() + (d * 24 * 60 * 60 * 1000)));
        }
    }

    /**
     * 判断两个日期是否同年同月
     *
     * @param date1 时间1
     * @param date2 时间2
     * @return
     */
    public static boolean equals(Date date1, Date date2) {
        Calendar calendar1 = Calendar.getInstance();
        calendar1.setTime(date1);
        Calendar calendar2 = Calendar.getInstance();
        calendar2.setTime(date2);
        return calendar1.get(Calendar.YEAR) == calendar2.get(Calendar.YEAR)
                && calendar1.get(Calendar.MONTH) == calendar2.get(Calendar.MONTH);
    }

2.2 用户日志的记录

用户日志的记录,主要通过自定义java注解,通过在service方法标记注解,使用spring aop进行日志存储

2.2.1 自定义java注解

自定义注解主要包括模块名称、操作内容两个内容,其使用方式为:@LogAnnotation(moduleName = “角色管理”, operate = “新增角色”)
如果需要其他内容,可根据以下源码进行扩展

LogAnnotation.java

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 自定义日志注解
 */
@Retention(RetentionPolicy.RUNTIME)  
@Target({ElementType.METHOD})  
@Documented
public @interface LogAnnotation {
	
	/**模块名称*/
    String moduleName() default "";  
    /**操作内容*/
    String operate() default "";  
	
}

注解使用:

@LogAnnotation(moduleName = "角色管理", operate = "新增角色")
@Override
public void saveRole(SysRole role, String[] perIds) {

2.2.2 切面配置

aop配置

	<aop:config>
	    <aop:pointcut id="pc" expression="execution(* com.carfi.vrcp.service.*.*.*(..))"/> 
	    <!--把事务控制在Service层-->
   <aop:advisor pointcut-ref="pc" advice-ref="txAdvice" />
  </aop:config>
  <bean id="logInterceptor" class="XXXX.XXXX.XXX.LogInterceptor"></bean>
  <aop:config>  
    <aop:aspect id="logAop" ref="logInterceptor" >
    	<aop:pointcut expression="execution(* com.carfi.vrcp.service.*.*.*(..))" id="logPoint"/>
    	<aop:after-returning method="afterReturning" pointcut-ref="logPoint" />
    </aop:aspect>
  </aop:config>

LogInterceptor.java

定义拦截器,重写afterReturning方法,在调用service方法完成之后触发该方法实现日志写入

/**
 * 日志拦截器
 * 
 */
public class LogInterceptor {
	/**
	 * 方法正常完成后执行方法
	 * @param point
	 */
	@SuppressWarnings("rawtypes")
	public void afterReturning(JoinPoint point) {
        try {
        	Subject subject = null ;
        	try {
				subject = CarfiUserUtil.getSubject();
			} catch (Exception e) {
				e.printStackTrace();
				//发生异常则不进行
				return ;
			}
        	SysUserLog userLog = new SysUserLog();
        	String targetName = point.getTarget().getClass().getName();
			Class targetClass = Class.forName(targetName);
			String methodName = point.getSignature().getName();
			Method[] method = targetClass.getMethods();
			Object[] params = point.getArgs(); // 获得参数列表
			for (Method m : method) {
				if (m.getName().equals(methodName)) {
					Class[] tmpCs = m.getParameterTypes();
					if (tmpCs.length == params.length) {
						// 获取注解内容
						LogAnnotation logAnnotation = m.getAnnotation(LogAnnotation.class);
						if(logAnnotation != null){
							//写入参数
							if(params.length>0){
								// 使用json转换工具 将参数转为json串,以便存入数据库
								String jsonStr = JsonUtil.toJSONStr(params);
								userLog.setParams(jsonStr);
							}
							//获取模块名称
							String moduleName = logAnnotation.moduleName();
							//获取操作名称
							String operate = logAnnotation.operate();
							userLog.setModuleName(moduleName);
							userLog.setOperate(operate);
							userLog.setClassName(targetName);
							userLog.setMethodName(methodName);
							userLog.setLogId(CommonUtil.generatePrimaryKey());
							userLog.setTime(new Date());
							HttpServletRequest request = (HttpServletRequest)((WebSubject)subject).getServletRequest();
							userLog.setIp(CommonUtil.getIpAddr(request));
							userLog.setUserId(CarfiUserUtil.getSysUser().getUserId());
							SysUserLogService userLogService = (SysUserLogService) SpringUtil.getBean ("sysUserLogService");
							userLogService.addUserLog(userLog);
							break;
						}
					}
				}
			}
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
}

3 SpringUtil.java 解释

SpringUtil的作用为在非Spring IOC容器下获取Spring IOC容器的上下文环境中的类,比如获取某个bean,最常见的如本文中的多次出现的“SysUserLogService userLogService = (SysUserLogService) SpringUtil.getBean (“sysUserLogService”);”通过SpringUtil得到service

3.1 SpringUtil 配置详解

SpringUtil.java

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

/**
 * Spring工具类
 */
public class SpringUtil implements ApplicationContextAware {

	/** 上下文 */
	private static ApplicationContext applicationContext;

	public static ApplicationContext getApplicationContext() {
		return applicationContext;
	}

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		SpringUtil.applicationContext = applicationContext;
	}

	/**
	 * 根据Bean ID获取Bean
	 * 
	 * @param beanId
	 * @return
	 */
	public static Object getBean(String beanId) {
		if(applicationContext == null){
			return null;
		}
		return applicationContext.getBean(beanId);
	}
}

spring 配置文件(application.xml)中配置相应的bean,在配置文件中注册的SpringUtil bean 应在spring扫描配置之前

 <bean id="springUtil" class="XXX.XXXX.SpringUtil"></bean>

 <context:component-scan base-package="XXX.XXX.service"></context:component-scan>
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/144027.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 广州有哪些好点的软件外包公司或者软件开发公司呀?听说广州碧软还不错,还有其他靠谱的软件外包公司?

    广州有哪些好点的软件外包公司或者软件开发公司呀?听说广州碧软还不错,还有其他靠谱的软件外包公司?广州有哪些好点的软件外包公司或者软件开发公司呀?听说广州碧软还不错,还有其他靠谱的软件外包公司?广州碧软,做软件开发与外包还不错,我们和他们一直合作了好几年,不比那些超大型软件外包公司差,因为超大的软件外包公司公司他们也仅仅是一个分公司小部门来给你做项目,店大欺客啊,碧软他们规模中等,但用心,把该交付的东西做好很重要。…

  • sublime text 3 激活码【2022免费激活】[通俗易懂]

    (sublime text 3 激活码)2021最新分享一个能用的的激活码出来,希望能帮到需要激活的朋友。目前这个是能用的,但是用的人多了之后也会失效,会不定时更新的,大家持续关注此网站~https://javaforall.cn/100143.htmlIntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,上面是详细链接哦~40…

  • 数据库设计 Step by Step (8)——视图集成

    数据库设计 Step by Step (8)——视图集成

  • django插件大全_裸缸用什么过滤器

    django插件大全_裸缸用什么过滤器前言如果需要满足前端各种筛选条件查询,我们使用drf自带的会比较麻烦,比如查询书名中包含“国”字,日期大于“2020-1-1”等等诸如此类的请求,Django-filter这个组件就是要解决这样的问

  • 链表排序最优算法_链表算法题

    链表排序最优算法_链表算法题链表排序算法总结概述问题描述:给定一个链表,请将这个链表升序排列。节点定义:structListNode{intval;ListNode*next;ListNode(intx):val(x),next(NULL){}};1链表插入排序题目描述:Leetcode0147链表进行插入排序分析因为头结点可能会改变,因此需要设置一个虚拟头结点dummy。我们从前向后遍历整个链表,假设当前考察节点为p,我们需要从

    2022年10月10日
  • Java strictfp[通俗易懂]

    Java strictfp[通俗易懂]Javastrictfp关键字的作用strictfp关键字可以应用于方法,类和接口。strictfp关键字的非法代码Javastrictfp关键字确保您将在每个平台上获得相同的结果,如果在浮点变量中执行操作。不同平台的精度可能不同,这就是为什么java编程语言提供了strictfp关键字,它用于在每个平台上获得相同的结果。所以,现在我们就可以更好的控制浮点数据类型运算了。strictf…

    2022年10月21日

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号