最近需要做一个Java后台的系统日志功能,由于以前从来没有做过,便去网上查阅资料,尝试着做一下
大体思路:
通过AOP在Controller之前进行切面,新建一个自定义注解,然后在AOP配置里面设置当前操作的模块和功能,然后设置进日志的实体类中,最后保存到数据库中即可完成
首先自定义一个注解:
package com.sure.crm.web.config;
import java.lang.annotation.*;
/**
* 系统日志的自定义注解
*
*/
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SystemLog {
String module() default "";
String methods() default "";
}
然后在根据自己的情况去配置AOP
在pom.xml中引入依赖
<!--aop的包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.2.5.RELEASE</version>
</dependency>
<!--切面的一个包(织入)-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.8</version>
</dependency>
在applicationContext-MVC中配置
<!-- aop配置 -->
<aop:aspectj-autoproxy proxy-target-class="true"/>
<!-- 扫描包支持 -->
<bean id="aopLogConfig" class="com.sure.crm.web.config.AopLogConfig">
</bean>
然后写AOP的配置类,在这里对Controller切一下,保存日志
package com.sure.crm.web.config;
import com.sure.crm.domain.Employee;
import com.sure.crm.domain.LogEntity;
import com.sure.crm.service.LogService;
import com.sure.shiro.UserContext;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
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 javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* Aop日志的配置
*
*/
@Component
@Aspect
public class AopLogConfig {
//注入service,用来将日志信息保存在数据库
@Autowired
private LogService logservice;
//配置接入点
@Pointcut("execution(* com.sure.crm.web.controller..*.*(..))")
private void controllerAspect(){}//定义一个切入点
@Around("controllerAspect()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
//日志实体对象
LogEntity log = new LogEntity();
//获取登录用户账户
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
//拿到当前用户,我是通过shiro的主体来取的,各自根据各自情况来进行设置
Employee user = UserContext.getUser();
if (null != user){
//设置当前用户名
String name = user.getName();
log.setUSERID(name);
}
//获取系统时间
String time = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss").format(new Date());
log.setDATA(time);
//获取客户端ip
String ip = request.getRemoteAddr();
log.setIP(ip);
//方法通知前获取时间,来计算模块执行时间的
long start = System.currentTimeMillis();
// 拦截的实体类,就是当前正在执行的controller
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 (NoSuchMethodException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (SecurityException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
System.out.println(method);
if (null != method) {
// 判断是否包含自定义的注解,说明一下这里的SystemLog就是我自己自定义的注解
if (method.isAnnotationPresent(SystemLog.class)) {
SystemLog systemlog = method.getAnnotation(SystemLog.class);
log.setMODULE(systemlog.module());
log.setMETHOD(systemlog.methods());
try {
object = pjp.proceed();
long end = System.currentTimeMillis();
//将计算好的时间保存在实体中
log.setRSPONSE_DATA(""+(end-start));
log.setCOMMITE("执行成功!");
//保存进数据库
logservice.save(log);
/*System.out.println("没切完");*/
} catch (Throwable e) {
// TODO Auto-generated catch block
long end = System.currentTimeMillis();
log.setRSPONSE_DATA(""+(end-start));
log.setCOMMITE("执行失败");
logservice.save(log);
/*System.out.println("切切切");*/
}
} else {//没有包含注解
object = pjp.proceed();
}
} else { //不需要拦截直接执行
object = pjp.proceed();
}
/*System.out.println("切完了");*/
return object;
}
}
数据库中新建一张表,用来存放日志信息,结构如下
当然还需要Domain类,数据库的表都在这了,实体类中一一对应起来写就可以了,然后写增删改查的方法
最后在生成一个查看日志的Controller类
package com.sure.crm.web.controller;
import com.sure.AjaxResult;
import com.sure.PageList;
import com.sure.crm.domain.LogEntity;
import com.sure.crm.query.LogEntityQuery;
import com.sure.crm.service.LogService;
import com.sure.crm.web.config.SystemLog;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
/**
* 配置系统日志的Controller
*/
@CrossOrigin
@Controller
@RequestMapping("/log")
public class AopLogController {
@Autowired
private LogService logService;
@ResponseBody
@RequestMapping(value = "/queryPage",method = RequestMethod.PATCH)
@SystemLog(module = "系统日志",methods = "日志管理-查询日志")
public PageList<LogEntity> findLog(@RequestBody LogEntityQuery query){
//这是我自己封装的一个类,一般不需要,根据各自情况来设置返回值
PageList<LogEntity> pageList = logService.queryPage(query);
return pageList;
}
}
然后前台页面就访问请求,通过表格把数据展示出来即可完成