Spring MVC通过AOP切面编程 来拦截controller 实现日志的写入
首选需要参考的是:【参考】http://www.cnblogs.com/guokai870510826/p/5977948.html
http://www.cnblogs.com/guokai870510826/p/5981015.html
1:首先定义maven
<!--配置aop切面编程需要引入的包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.5.3</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.4</version>
</dependency>
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.4</version>
</dependency>
2:在拦截controller之前 需要自定义一个注解
package com.cdms.aop; import java.lang.annotation.*; /**
* Created by 草帽boy on 2017/2/21.
*/ @Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SystemLog {
String module() default "";
String methods() default "";
}
其目的是 如图:
三:配置spring-web.xml
<!--Aop切面编程的配置-->
<aop:aspectj-autoproxy expose-proxy="true"></aop:aspectj-autoproxy>
<bean id="logAopAction" class="com.cdms.aop.LogAopAction"></bean>
四:aop的实现类中处理记录日志的逻辑
package com.cdms.aop; import com.cdms.dto.User;
import com.cdms.entity.Log;
import com.cdms.util.SessionUtil; import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import java.lang.reflect.Method; import javax.servlet.http.HttpServletRequest;
import java.util.Date; /**
* Created by 草帽boy on 2017/2/21.
*/
@Aspect
public class LogAopAction {
//获取开始时间
private long BEGIN_TIME ; //获取结束时间
private long END_TIME; //定义本次log实体
private Log log = new Log(); @Pointcut("execution(* com.cdms.controller..*.*(..))")
private void controllerAspect(){} /**
* 方法开始执行
*/
@Before("controllerAspect()")
public void doBefore(){
BEGIN_TIME = new Date().getTime();
System.out.println("开始");
} /**
* 方法结束执行
*/
@After("controllerAspect()")
public void after(){
END_TIME = new Date().getTime();
System.out.println("结束");
} /**
* 方法结束执行后的操作
*/
@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(">>>>>>>>>>存入到数据库");
}else {
System.out.println(log);
System.out.println(">>>>>>>>不存入到数据库");
}
} /**
* 方法有异常时的操作
*/
@AfterThrowing("controllerAspect()")
public void doAfterThrow(){
System.out.println("例外通知-----------------------------------");
} /**
* 方法执行
* @param pjp
* @return
* @throws Throwable
*/
@Around("controllerAspect()")
public Object around(ProceedingJoinPoint pjp) throws Throwable{
//日志实体对象
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
//获取当前登陆用户信息
User loginUser = SessionUtil.getLoginSession(request);
if(loginUser==null){
log.setLoginAccount("—— ——");
}else{
log.setLoginAccount(loginUser.getUserAuth().getIdentity());
} // 拦截的实体类,就是当前正在执行的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();
} if (null != method) {
// 判断是否包含自定义的注解,说明一下这里的SystemLog就是我自己自定义的注解
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 (Throwable e) {
// TODO Auto-generated catch block
log.setDescription("执行失败");
log.setState((short)-1);
}
} 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
*/
private String getIp(HttpServletRequest request){
if (request.getHeader("x-forwarded-for") == null) {
return request.getRemoteAddr();
}
return request.getHeader("x-forwarded-for");
}
}
其中我的Log实体类如下图所示
/**
* 日志id
*/
private Integer 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;
四:我们在看一下 controller中的注解怎么写
/**
* 登陆消息验证
* @param userAuth 用户登陆信息
* @param request http协议请求
* @return 一个带参数的json数据
*/
@RequestMapping(value = "/toLogin",method = RequestMethod.POST,
produces = {"application/json;charset=UTF-8"})
@ResponseBody
@SystemLog(methods = "用户管理",module = "用户登陆")
public JSONObject toLogin(UserAuth userAuth, HttpServletRequest request){
JSONObject loginJson = userService.userLogin(userAuth);
//表示登陆成功
if(loginJson.get("key").equals("success")){
//放入到session中
SessionUtil.setLoginSession(request,loginJson.get("data"));
return JSONOperation.successMessage("登陆成功!");
}
return loginJson;
}
在控制台的打印结果是:
开始
结束
Log{id=null, loginAccount='919132691@qq.com', loginIp='127.0.0.1', actionUrl='/user/toLogin', module='用户登陆', method='用户管理', actionTime=0, description='执行成功', gmtCreate=Tue Feb 21 18:56:15 CST 2017, state=1}
>>>>>>>>>>存入到数据库
Spring MVC通过AOP切面编程 来拦截controller 实现日志的写入的更多相关文章
- spring AOP 之五:Spring MVC通过AOP切面编程来拦截controller
示例1:通过包路径及类名规则为应用增加切面 该示例是通过拦截所有com.dxz.web.aop包下的以Controller结尾的所有类的所有方法,在方法执行前后打印和记录日志到数据库. 新建一个spr ...
- spring boot使用AOP切面编程
spring boot使用AOP 1.在pom文件中添加依赖: <!--spring boot aop切面--> <dependency> <groupId>org ...
- Spring框架系列(4) - 深入浅出Spring核心之面向切面编程(AOP)
在Spring基础 - Spring简单例子引入Spring的核心中向你展示了AOP的基础含义,同时以此发散了一些AOP相关知识点; 本节将在此基础上进一步解读AOP的含义以及AOP的使用方式.@pd ...
- Spring AOP 切面编程记录日志和接口执行时间
最近客户现在提出系统访问非常慢,需要优化提升访问速度,在排查了nginx.tomcat内存和服务器负载之后,判断是数据库查询速度慢,进一步排查发现是因为部分视图和表查询特别慢导致了整个系统的响应时间特 ...
- SpringBoot2.0 基础案例(11):配置AOP切面编程,解决日志记录业务
本文源码 GitHub地址:知了一笑 https://github.com/cicadasmile/spring-boot-base 一.AOP切面编程 1.什么是AOP编程 在软件业,AOP为Asp ...
- 十:SpringBoot-配置AOP切面编程,解决日志记录业务
SpringBoot-配置AOP切面编程,解决日志记录业务 1.AOP切面编程 1.1 AOP编程特点 1.2 AOP中术语和图解 2.SpringBoot整合AOP 2.1 核心依赖 2.2 编写日 ...
- springMVC+MyBatis+Spring 整合(4) ---解决Spring MVC 对AOP不起作用的问题
解决Spring MVC 对AOP不起作用的问题 分类: SpringMVC3x+Spring3x+MyBatis3x myibaits spring J2EE2013-11-21 11:22 640 ...
- AOP切面编程在android上的应用
代码地址如下:http://www.demodashi.com/demo/12563.html 前言 切面编程一直是一个热点的话题,这篇文章讲讲一个第三方aop库在android上的应用.第三方AOP ...
- 注解与AOP切面编程实现redis缓存与数据库查询的解耦
一般缓存与数据库的配合使用是这样的. 1.查询缓存中是否有数据. 2.缓存中无数据,查询数据库. 3.把数据库数据插入到缓存中. 其实我们发现 1,3 都是固定的套路,只有2 是真正的业务代码.我们可 ...
随机推荐
- linux下nginx【反向代理】配置【负载均衡】配置
nginx 可以配置多个端口: 1.10088端口 配置反向代理,消除跨域问题. 2.10087端口 配置ip_hash模式的负载均衡,ip_hash可以绕开解决session共享的问题. nginx ...
- Linux运维第二课----Linux发展史、环境准备
一.Linux的发展 1.1969年在贝尔实验室诞生Unix,是开源免费的,之后逐渐转变为收费系统. 2.1986年谭邦宁研发mini Unix,但主要用来教学. 3.斯托曼创建FSF(自由软件基金会 ...
- ext当表单中的输入项为必填时,输入项label后显示红色的*
form表单里,当输入项为必填项时,需要将对应item的allowblank属性设置为true,如果item的label后面自带红色的*,表单中哪些输入项是“必填”,哪些输入项是“非必填”,一眼望去清 ...
- 数据库原理 - 序列4 - 事务是如何实现的? - Redo Log解析(续)
> 本文节选自<软件架构设计:大型网站技术架构与业务架构融合之道>第6.4章节. 作者微信公众号:> 架构之道与术.进入后,可以加入书友群,与作者和其他读者进行深入讨论.也可以 ...
- C# 获取当前服务器域名
"http://"是协议名 "www.test.com"是域名 "aaa"是站点名 "bbb.aspx"是页面名(文件名 ...
- 抽象,接口和Object类
在面向对象的概念中, 所有的对象都是通过类来表述的, 但并不是所有的类都是用来描绘对象的, 如果一个类中么有包含足够的信息来描绘一类具体的对象, 这样的类就是抽象类. 抽象类往往用来表征对问题领域进行 ...
- Linux学习历程——SUID、SGID、SBIT简介
一.SUID.SGID.SBIT简介 SUID:对一个可执行文件,不是以发起者身份来获取资源,而是以可执行文件的属主身份来执行.SGID:对一个可执行文件,不是以发起者身份来获取资源,而是以可执行文件 ...
- 爬虫技术实现空间相册采集器V.0.0.1版本
一. 功能需求分析: 在很多时候我们需要做这样一个事情:我们想把我们QQ空间上的相册高清图像下载下来,怎么做?到网上找软件?答案是否定的,理由之一:网上很多软件不知有没有病毒,第二它有可能捆了很 ...
- RobotFramework第一篇之环境搭建
定义:是一款python编写的功能自动化测试框架,具备良好的扩展性,可以进行分布性测试 1:对编程能力要求低,容易上手 2:关键字调用方式,已经定义好的功能,只需要去调用它,一个关键字实现了一个功能, ...
- LINQ 之 GroupBy
声明:本文为www.cnc6.cn原创,转载时请注明出处,谢谢! 本文作者文采欠佳,文字表达等方面不是很好,但实际的代码例子是非常实用的,请作参考. 一.先准备要使用的类: 1.Person类: cl ...