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

2022-08-31 11:13:26 浏览数 (2)

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

java 项目日志管理设计方案

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


1 创建日志表

1.1 日志表Sql语句如下

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

表创建SQL语句

代码语言:javascript复制
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

代码语言:javascript复制
<?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

代码语言:javascript复制
public interface SysDbMapper {
    /**
     *  创建数据表
     * @param name 表名
     */
    void createUserLogTable(String name);
}

DbService.java

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

DbServiceImpl.java

代码语言:javascript复制
@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

代码语言:javascript复制
/**
 * 报警定时任务接口
 * 
 */
public interface BaseQuartz {

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

DbQuartz.java

代码语言:javascript复制
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

代码语言:javascript复制
<?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

代码语言:javascript复制
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

代码语言:javascript复制
<?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

代码语言:javascript复制
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”中的分页辅助类

代码语言:javascript复制
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’,’%’);

代码语言:javascript复制
/**
 * 用户日志管理业务实现
 *
 * @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

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

代码语言:javascript复制
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

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

代码语言:javascript复制
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

代码语言:javascript复制
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 "";  
	
}

注解使用:

代码语言:javascript复制
@LogAnnotation(moduleName = "角色管理", operate = "新增角色")
@Override
public void saveRole(SysRole role, String[] perIds) {
2.2.2 切面配置

aop配置

代码语言:javascript复制
	<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方法完成之后触发该方法实现日志写入

代码语言:javascript复制
/**
 * 日志拦截器
 * 
 */
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

代码语言:javascript复制
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扫描配置之前

代码语言:javascript复制
 <bean id="springUtil" class="XXX.XXXX.SpringUtil"></bean>

 <context:component-scan base-package="XXX.XXX.service"></context:component-scan>

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

0 人点赞