Jeecg中通过Spring_AOP+注解方式实现日志的管理

一、设计思路

通过spring的aop切面功能,拦截到请求的所有的符合切面表达式的方法,判断是否含有注解标志,生成日志对象,然后通过aop的后置通知进行日志的持久化。

二、代码实现

1、工程结构:

2、pom.xml增加aop依赖:

org.springframework

spring-aop

4.1.7.RELEASE

aspectj

aspectjrt

1.5.3

org.aspectj

aspectjweaver

1.8.4

aopalliance

aopalliance

1.0

cglib

cglib

3.2.4

3、定义我们的Log实体对象

package aop;

import java.util.Date;

import javax.persistence.Column;

import javax.persistence.Entity;

import javax.persistence.GeneratedValue;

import javax.persistence.Id;

import javax.persistence.Table;

import org.hibernate.annotations.DynamicInsert;

import org.hibernate.annotations.DynamicUpdate;

import org.hibernate.annotations.GenericGenerator;

import org.jeecgframework.core.common.entity.IdEntity;

@Entity

@Table(name="assess_log_test")

@DynamicInsert(true)

@DynamicUpdate(true)

@SuppressWarnings("serial")

public class Log implements java.io.Serializable{

/**

* 日志id

*/

private String id;

/**

* 当前操作人id

*/

private String loginAccount;

/**

* 当前操作人ip

*/

private String loginIp;

/**

* 操作请求的链接

*/

private String actionUrl;

/**

* 执行的模块

*/

private String module;

/**

* 执行的方法

*/

private String method;

/**

* 执行操作时间

*/

private Long actionTime;

/**

* 描述

*/

private String description;

/**

* 执行的时间

*/

private Date gmtCreate;

/**

* 该操作状态,1表示成功,-1表示失败!

*/

private Short state;

@Id

@GeneratedValue(generator = "paymentableGenerator")

@GenericGenerator(name="paymentableGenerator",strategy="uuid")

@Column(name="id",nullable=false,length=32)

public String getId() {

return id;

}

@Column(name="login_account",length=32)

public String getLoginAccount() {

return loginAccount;

}

@Column(name="login_ip",length=32)

public String getLoginIp() {

return loginIp;

}

@Column(name="action_url",length=100)

public String getActionUrl() {

return actionUrl;

}

@Column(name="module",length=32)

public String getModule() {

return module;

}

@Column(name="method",length=32)

public String getMethod() {

return method;

}

@Column(name="action_time")

public Long getActionTime() {

return actionTime;

}

@Column(name="description",length=200)

public String getDescription() {

return description;

}

@Column(name="gmt_create")

public Date getGmtCreate() {

return gmtCreate;

}

@Column(name="state")

public Short getState() {

return state;

}

public void setId(String id) {

this.id = id;

}

public void setLoginAccount(String loginAccount) {

this.loginAccount = loginAccount;

}

public void setLoginIp(String loginIp) {

this.loginIp = loginIp;

}

public void setActionUrl(String actionUrl) {

this.actionUrl = actionUrl;

}

public void setModule(String module) {

this.module = module;

}

public void setMethod(String method) {

this.method = method;

}

public void setActionTime(Long actionTime) {

this.actionTime = actionTime;

}

public void setDescription(String description) {

this.description = description;

}

public void setGmtCreate(Date gmtCreate) {

this.gmtCreate = gmtCreate;

}

public void setState(Short state) {

this.state = state;

}

@Override

public String toString() {

return "Log [id=" + id + ", loginAccount=" + loginAccount

+ ", loginIp=" + loginIp + ", actionUrl=" + actionUrl

+ ", module=" + module + ", method=" + method + ", actionTime="

+ actionTime + ", description=" + description + ", gmtCreate="

+ gmtCreate + ", state=" + state + "]";

}

}

4.定义注解对象

package aop;

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;

/**

* 日志记录

*

* @author mgj

*@date 2017-8-11 上午10:53:19

*/

@Target({ElementType.PARAMETER,ElementType.METHOD})

@Retention(RetentionPolicy.RUNTIME)

@Documented

public @interface SystemLog {

String module() default "";

String methods() default "";

}

5.定义aop界面拦截方法

package aop;

import java.lang.reflect.Method;

import java.util.Date;

import javax.servlet.http.HttpServletRequest;

import org.aspectj.lang.ProceedingJoinPoint;

import org.aspectj.lang.Signature;

import org.aspectj.lang.annotation.After;

import org.aspectj.lang.annotation.AfterReturning;

import org.aspectj.lang.annotation.Around;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Before;

import org.aspectj.lang.annotation.Pointcut;

import org.aspectj.lang.reflect.MethodSignature;

import org.jeecgframework.core.util.ResourceUtil;

import org.jeecgframework.core.util.StringUtil;

import org.jeecgframework.web.system.pojo.base.TSUser;

import org.jeecgframework.web.system.service.SystemService;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Component;

import org.springframework.web.context.request.RequestContextHolder;

import org.springframework.web.context.request.ServletRequestAttributes;

import antlr.StringUtils;

@Component

@Aspect

public class LogAopAction {

private long BEGIN_TIME;

private long END_TIME;

private Log log = new Log();

@Autowired

private SystemService systemService;

//@Pointcut("execution(* vote.backmanage.teachermanage.controller.AssessTeacherInfoController.*(..))")

//@Pointcut("execution(* vote.backmanage.teachermanage.controller.*.*(..))")

//@Pointcut("execution(* vote.backmanage.teachermanage.controller..*.*(..))")

@Pointcut("execution(* vote.backmanage.teachermanage.controller..*.*(..))")

public void controllerAspect(){}

@Before("controllerAspect()")

public void doBefore(){

BEGIN_TIME = new Date().getTime();

}

@AfterReturning("controllerAspect()")

public void doAfter(){

if (log.getState() == 1 || log.getState() == -1) {

log.setActionTime(END_TIME - BEGIN_TIME);

log.setGmtCreate(new Date(BEGIN_TIME));

System.out.println(log);

System.out.println("存入到数据库");

systemService.save(log);

}else {

System.out.println(log);

System.out.println("不存到数据库里");

}

}

@After("controllerAspect()")

public void after(){

END_TIME = new Date().getTime();

}

@Around("controllerAspect()")

public Object around(ProceedingJoinPoint pjp) throws Throwable{

HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes())

.getRequest();

//获得当前用户

TSUser user = ResourceUtil.getSessionUserName();

String name = user.getRealName();

log.setLoginAccount(name);

//拦截的实体类

Object target = pjp.getTarget();

//拦截的方法名

String methodName = pjp.getSignature().getName();

//拦截的方法参数

Object[] args = pjp.getArgs();

//拦截的放参数类型

Signature sig = pjp.getSignature();

MethodSignature msig = null;

if (!(sig instanceof MethodSignature)) {

throw new IllegalArgumentException("该注解只能用于方法");

}

msig = (MethodSignature)sig;

Class[] parameterTypes = msig.getMethod().getParameterTypes();

Object object = null;

Method method = null;

try{

method = target.getClass().getMethod(methodName, parameterTypes);

}catch (Exception e) {

e.printStackTrace();

}

if (null != method) {

if (method.isAnnotationPresent(SystemLog.class)) {//判断是否包含我们自定义的注解

SystemLog systemlog = method.getAnnotation(SystemLog.class);

log.setModule(systemlog.module());

log.setMethod(systemlog.methods());

log.setLoginIp(getIp(request));

log.setActionUrl(request.getRequestURI());

try {

object = pjp.proceed();

log.setDescription("执行成功");

log.setState((short)1);

} catch (Exception e) {

log.setDescription("执行失败");

log.setState((short)-1);

e.printStackTrace();

}

}else {//不包自定义注解

object = pjp.proceed();

log.setDescription("此操作不包含注解");

log.setState((short)0);

}

}else {//不需要拦截

object = pjp.proceed();

log.setDescription("不需要拦截直接运行");

log.setState((short)0);

}

return object;

}

/**

*获得ip地址

* @param request

* @return

* @author mgj

*@date 2017-8-11 下午2:19:51

*/

private String getIp(HttpServletRequest request){

if (request.getHeader("x-forwarded-for") == null) {

return request.getRemoteAddr();

}

return request.getHeader("x-forwarded-for");

}

}

6.增加aop自动扫描配置

(1)打开spring-mvc.xml文件,增加aop上下文

如下:

xmlns:mvc="http://www.springframework.org/schema/mvc"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:p="http://www.springframework.org/schema/p"

xmlns:context="http://www.springframework.org/schema/context"

xmlns:aop="http://www.springframework.org/schema/aop"

xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-3.0.xsd

http://www.springframework.org/schema/context

http://www.springframework.org/schema/context/spring-context-3.0.xsd

http://www.springframework.org/schema/mvc

http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd

http://www.springframework.org/schema/aop

http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">

(2)增加aop自动扫描并实例化bean

7.持久化Log实体的xml配置,使用自动扫描class的形式进行配置。打开spring-mvc-hibernate.xml文件,增加aop.

class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">

${hibernate.dialect}

${hibernate.hbm2ddl.auto}

true

false

false

org.jeecgframework.web.system.pojo.*

org.jeecgframework.web.demo.entity.*

org.jeecgframework.web.test.entity.*

org.jeecgframework.web.cgform.entity.*

org.jeecgframework.web.cgreport.entity.*

aop.

8.使用注解方式,配置日志,在访问的controller方法上,增加@SystemLog(module="区教师库登录",methods="区教师库的assessTeacherInfo()方法")配置

/**

* 教师库管理列表 页面跳转

*

* @return

*/

@RequestMapping(params = "assessTeacherInfo")

@SystemLog(module="区教师库登录",methods="区教师库的assessTeacherInfo()方法")

public ModelAndView assessTeacherInfo(HttpServletRequest request) {

return new ModelAndView("vote/backmanage/teachermanage/assessTeacherInfoList");

}

9.效果

三、注意事项

1.增加aop自动扫描包时,必须写到spring-mvc.xml内,不可写到spring-mvc-aop.xml文件中。因为spring-mvc.xml会比spring-mvc-aop.xml文先执行。

2.持久化Log实体,使用自动扫描class的形式进行配置时,规则如下

(1)aop.,会解析为aop/*.class 或者 aop/xxx/*.class。即aop的包以及子包下的所有class。

(2)aop,会解析为aop/*.class 。即aop的包下的所有class。

(3)aop.*,会解析为 aop/xxx/*.class。即aop的子包下的所有class。

四、思考

1.需要深刻理解spring_mvc.xml文件的执行顺序。

2.需要深刻理解使用自动扫描class的形式的配置规则。

---------------------------------------------------------------------------

附录:

Log实体创建的mysql脚本:

drop table if exists assess_log_test;

create table assess_log_test (

id varchar(32) not null COMMENT '主键id',

login_account varchar(32) default null comment '当前操作人',

login_ip varchar(32) default null comment '登录ip',

action_url varchar(100) default null comment '请求url',

module varchar(32) default null comment '执行模块',

method varchar(32) default null comment '执行方法',

action_time bigint default 0 comment '执行操作时间',

description varchar(200)default null comment '描述',

gmt_create datetime default null comment '执行时间',

state smallint(6) default null comment '操作状态',

primary key (id)

)engine=innodb default charset=utf8 comment '操作日志表';

转自:https://blog.csdn.net/ma451152002/article/details/77234236

更多推荐