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)


相关推荐

  • isnotempty和isnotnull_likely与possible和probable的区别

    isnotempty和isnotnull_likely与possible和probable的区别前两天因为用到isBlank,上网查了下,顺便放在CSDN上,希望能帮助到更多的人!!!isNotEmpty将空格也作为参数,isNotBlank则排除空格参数参考StringUtils方法的操作对象是java.lang.String类型的对象,是JDK提供的String类型操作方法的补充,并且是null安全的(即如果输入参数String为null则不会抛出NullPointerException…

  • 软件工厂简介「建议收藏」

    软件工厂简介「建议收藏」摘要:简要介绍Microsoft开发软件工厂这种方法的动机。所谓软件工厂就是指为了支持某种特定应用程序的快速开发而配置的开发环境。软件工厂从逻辑上讲就是软件开发方法和实践的下一个发展阶段。然而,通过引入产业化模式,软件工厂势必会改变软件行业的现状。扩大软件开发的规模从目前的情况来看,软件开发的速度缓慢、代价高昂而又极易出错,常常会生产出存在大量缺陷的产品,在可用性、可靠性、性能、安全

  • 用激活码怎么永久激活idea_一键无痕视频教程

    用激活码怎么永久激活idea_一键无痕视频教程Idea激活码最新破解教程,Mac版激活至2299年,Idea激活码2021.3.3

  • 域名解析 dns_一区新增风险区

    域名解析 dns_一区新增风险区1、DNSDNS(DomainNameSystem)是域名系统的英文缩写,是一种组织成域层次结构的计算机和网络服务命名系统,用于TCP/IP网络。2、域名系统DNS的作用通常我们有两种方式识别主机:通过主机名或者IP地址。人们喜欢便于记忆的主机名表示,而路由器则喜欢定长的、有着层次结构的IP地址。为了满足这些不同的偏好,我们就需要一种能够进行主机名到IP地址转换的目录服务,域名系统作为将域名和IP地址相互映射的一个分布式数据库,能够使人更方便地访问互联网。因此,即使不使用域名

  • CollectGarbage 垃圾回收

    在IE中,调用window.CollectGarbage()方法会立即执行垃圾收集,在Opera7及更高版本中,调用window.opera.collect()也会启动垃圾收集例程。转载于:https://www.cnblogs.com/wujidns/p/5462372.html…

  • js解决页面后退

    js解决页面后退在a链接加上下面属性href=”javascript:history.go(-1);”

发表回复

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

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