springmvc中aop对controller切面编程

1.导入当前JDK版本支持的apectjwever.jar和spring-aspects.jar

        我当前的版本是JDK1.6、aspectjweaver-1.6.9.jar、spring-aspects-3.2.8.RELEASE.jar

2.数据库中创建表sys_oper_log

CREATE TABLE `sys_oper_log` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '日志主键',
  `title` varchar(50) DEFAULT '' COMMENT '模块标题',
  `content` varchar(100) DEFAULT NULL COMMENT '日志内容',
  `method` varchar(100) DEFAULT '' COMMENT '方法名称',
  `requestMethod` varchar(10) DEFAULT '' COMMENT '请求方式',
  `operName` varchar(100) DEFAULT '' COMMENT '操作人员',
  `requestUrl` varchar(255) DEFAULT '' COMMENT '请求URL',
  `ip` varchar(128) DEFAULT '' COMMENT '请求IP地址',
  `iplocation` varchar(255) DEFAULT '' COMMENT 'IP归属地',
  `requestparam` varchar(2000) DEFAULT '' COMMENT '请求参数',
  `responseResult` varchar(2000) DEFAULT '' COMMENT '方法响应参数',
  `status` int(1) DEFAULT NULL COMMENT '操作状态(0正常 1异常)',
  `errormsg` varchar(5000) DEFAULT NULL COMMENT '错误消息',
  `operTime` datetime DEFAULT NULL COMMENT '操作时间',
  `takeTime` bigint(20) DEFAULT NULL COMMENT '方法执行耗时(单位:毫秒)',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8 COMMENT='操作日志记录';

3.日志实体类OperLog

package com.go.annotation;

import java.util.Date;

public class OperLog {
	private String id;
	private String title;
	private String content;
	private String method;
	private String requestMethod;
	private String requestParam;
	private String responseResult;
	private String operName;
	private String ip;
	private String ipLocation;
	private String requestUrl;
	private Date operTime;
	private Integer status;
	private String ErrorMsg;
	private Long TakeTime;

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getContent() {
		return content;
	}

	public void setContent(String content) {
		this.content = content;
	}

	public String getMethod() {
		return method;
	}

	public void setMethod(String method) {
		this.method = method;
	}

	public String getRequestMethod() {
		return requestMethod;
	}

	public void setRequestMethod(String requestMethod) {
		this.requestMethod = requestMethod;
	}

	public String getRequestParam() {
		return requestParam;
	}

	public void setRequestParam(String requestParam) {
		this.requestParam = requestParam;
	}

	public String getResponseResult() {
		return responseResult;
	}

	public void setResponseResult(String responseResult) {
		this.responseResult = responseResult;
	}

	public String getOperName() {
		return operName;
	}

	public void setOperName(String operName) {
		this.operName = operName;
	}

	public String getIp() {
		return ip;
	}

	public void setIp(String ip) {
		this.ip = ip;
	}

	public String getIpLocation() {
		return ipLocation;
	}

	public void setIpLocation(String ipLocation) {
		this.ipLocation = ipLocation;
	}

	public String getRequestUrl() {
		return requestUrl;
	}

	public void setRequestUrl(String requestUrl) {
		this.requestUrl = requestUrl;
	}

	public Date getOperTime() {
		return operTime;
	}

	public void setOperTime(Date operTime) {
		this.operTime = operTime;
	}

	public Integer getStatus() {
		return status;
	}

	public void setStatus(Integer status) {
		this.status = status;
	}

	public String getErrorMsg() {
		return ErrorMsg;
	}

	public void setErrorMsg(String errorMsg) {
		ErrorMsg = errorMsg;
	}

	public Long getTakeTime() {
		return TakeTime;
	}

	public void setTakeTime(Long takeTime) {
		TakeTime = takeTime;
	}

}

4.然后就是OperLogService和OperLog.xml(我这里直接省略了)

5.切面处理类OperLogAspect

package com.go.aop;

import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
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.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import com.alibaba.fastjson.JSON;
import com.go.annotation.OperLog;
import com.go.common.util.SysUtil;
import com.go.service.base.IOperLogService;

/**
 * 切面处理类,记录操作日志到数据库
 */
@Aspect
@Component
public class OperLogAspect {

	@Autowired
	private IOperLogService operLogService;

	private Date nowDate;

	/**
	 * 
	 * 
	 * 
	 * @Pointcut("execution(public * com.go.controller..*.*(..))")
	 */
	@Pointcut("execution(public * com.go.controller..*.*save.*(..))")
	// 从controller切入
	public void operLogPoinCut() {
	}

	@Before("operLogPoinCut()")
	public void beforMethod(JoinPoint point) {

		nowDate = new Date();
	}

	/**
	 * 设置操作异常切入点记录异常日志 扫描所有包下操作
	 */
	@Pointcut("execution(public * com.go..*.*(..))")
	public void operExceptionLogPoinCut() {
	}

	/**
	 * 正常返回通知,拦截用户操作日志,连接点正常执行完成后执行, 如果连接点抛出异常,则不会执行
	 * 
	 * @param joinPoint
	 *            切入点
	 * @param result
	 *            返回结果
	 */
	@AfterReturning(value = "operLogPoinCut()", returning = "result")
	public void saveOperLog(JoinPoint joinPoint, Object result) {
		// 获取RequestAttributes
		RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
		// 从获取RequestAttributes中获取HttpServletRequest的信息
		HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
		try {
			// 从切面织入点处通过反射机制获取织入点处的方法
			MethodSignature signature = (MethodSignature) joinPoint.getSignature();
			// 获取切入点所在的方法
			Method method = signature.getMethod();
			// 获取操作

			OperLog operlog = new OperLog();
			operlog.setTitle("");// 设置模块名称
			operlog.setContent("");// 设置日志内容

			// 将入参转换成json
			String params = argsArrayToString(joinPoint.getArgs());
			// 获取请求的类名
			String className = joinPoint.getTarget().getClass().getName();
			// 获取请求的方法名
			String methodName = method.getName();
			methodName = className + "." + methodName + "()";
			operlog.setMethod(methodName); // 设置请求方法
			operlog.setRequestMethod(request.getMethod());// 设置请求方式
			operlog.setRequestParam(params); // 请求参数
			operlog.setResponseResult(JSON.toJSONString(result)); // 返回结果
			Map<String, Object> user = SysUtil.getSessionUsr(request, "user");// 当前用户
			if (null != user) {
				operlog.setOperName("{ id : " + user.get("id") + ", name : " + user.get("text").toString() + " }"); // 获取用户名(真实环境中,肯定有工具类获取当前登录者的账号或ID的,或者从token中解析而来)
			}
			operlog.setIp(getIp(request)); // IP地址
			operlog.setIpLocation(""); // IP归属地(真是环境中可以调用第三方API根据IP地址,查询归属地)
			operlog.setRequestUrl(request.getRequestURL().toString()); // 请求URI
			operlog.setOperTime(new Date()); // 时间
			operlog.setStatus(0);// 操作状态(0正常 1异常)
			Long takeTime = System.currentTimeMillis() - nowDate.getTime();// 记录方法执行耗时时间(单位:毫秒)
			operlog.setTakeTime(takeTime);
			// 插入数据库
			operLogService.insert(operlog);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 异常返回通知,用于拦截异常日志信息 连接点抛出异常后执行
	 */
	@AfterThrowing(pointcut = "operExceptionLogPoinCut()", throwing = "e")
	public void saveExceptionLog(JoinPoint joinPoint, Throwable e) {
		// 获取RequestAttributes
		RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
		// 从获取RequestAttributes中获取HttpServletRequest的信息
		HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);

		OperLog operlog = new OperLog();
		try {
			// 从切面织入点处通过反射机制获取织入点处的方法
			MethodSignature signature = (MethodSignature) joinPoint.getSignature();
			// 获取切入点所在的方法
			Method method = signature.getMethod();
			// 获取请求的类名
			String className = joinPoint.getTarget().getClass().getName();
			// 获取请求的方法名
			String methodName = method.getName();
			methodName = className + "." + methodName + "()";
			// 获取操作

			operlog.setTitle("");// 设置模块名称
			operlog.setContent("");// 设置日志内容
			// 将入参转换成json
			String params = argsArrayToString(joinPoint.getArgs());
			operlog.setMethod(methodName); // 设置请求方法
			operlog.setRequestMethod(request.getMethod());// 设置请求方式
			operlog.setRequestParam(params); // 请求参数
			Map<String, Object> user = SysUtil.getSessionUsr(request, "user");// 当前用户
			if (null != user) {
				operlog.setOperName("{ id : " + user.get("id") + ", name : " + user.get("text").toString() + " }"); // 获取用户名(真实环境中,肯定有工具类获取当前登录者的账号或ID的,或者从token中解析而来)
			}
			operlog.setIp(getIp(request)); // IP地址
			operlog.setIpLocation(""); // IP归属地(真是环境中可以调用第三方API根据IP地址,查询归属地)
			operlog.setRequestUrl(request.getRequestURI()); // 请求URI
			operlog.setOperTime(new Date()); // 时间
			operlog.setStatus(1);// 操作状态(0正常 1异常)
			operlog.setErrorMsg(stackTraceToString(e.getClass().getName(), e.getMessage(), e.getStackTrace()));// 记录异常信息
			// 插入数据库
			operLogService.insert(operlog);
		} catch (Exception e2) {
			e2.printStackTrace();
		}
	}

	/**
	 * 转换异常信息为字符串
	 */
	public String stackTraceToString(String exceptionName, String exceptionMessage, StackTraceElement[] elements) {
		StringBuffer strbuff = new StringBuffer();
		for (StackTraceElement stet : elements) {
			strbuff.append(stet + "\n");
		}
		String message = exceptionName + ":" + exceptionMessage + "\n\t" + strbuff.toString();
		message = substring(message, 0, 2000);
		return message;
	}

	/**
	 * 参数拼装
	 */
	private String argsArrayToString(Object[] paramsArray) {
		String params = "";
		if (paramsArray != null && paramsArray.length > 0) {
			for (Object o : paramsArray) {
				if (o != null) {
					try {
						if (o instanceof HttpServletRequest) {
							HttpServletRequest request = (HttpServletRequest) o;
							Map map = (Map) request.getParameterMap();
							Object jsonObj = JSON.toJSON(map);
							params += jsonObj.toString() + " ";
						} else if (o instanceof HttpServletResponse) {
							HttpServletResponse response = (HttpServletResponse) o;
						}

					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}
		}
		return params.trim();
	}

	// 字符串截取
	public static String substring(String str, int start, int end) {
		if (str == null) {
			return null;
		} else {
			if (end < 0) {
				end += str.length();
			}

			if (start < 0) {
				start += str.length();
			}

			if (end > str.length()) {
				end = str.length();
			}

			if (start > end) {
				return "";
			} else {
				if (start < 0) {
					start = 0;
				}

				if (end < 0) {
					end = 0;
				}
				return str.substring(start, end);
			}
		}
	}

	/**
	 * 转换request 请求参数
	 * 
	 * @param paramMap
	 *            request获取的参数数组
	 */
	public Map<String, String> converMap(Map<String, String[]> paramMap) {
		Map<String, String> returnMap = new HashMap<String, String>();
		for (String key : paramMap.keySet()) {
			returnMap.put(key, paramMap.get(key)[0]);
		}
		return returnMap;
	}

	// 根据HttpServletRequest获取访问者的IP地址
	public static String getIp(HttpServletRequest request) {
		String unknown = "unknown";

		String ip0 = request.getHeader("x-forwarded-for");
		String ip = request.getHeader("X-Real-IP");

		if (ip == null || ip.length() == 0 || unknown.equalsIgnoreCase(ip)) {
			ip = request.getHeader("Proxy-Client-IP");
		}

		if (ip == null || ip.length() == 0 || unknown.equalsIgnoreCase(ip)) {
			ip = request.getHeader("WL-Proxy-Client-IP");
		}

		if (ip == null || ip.length() == 0 || unknown.equalsIgnoreCase(ip)) {
			ip = request.getRemoteAddr();
		}

		return ip;
	}
}

6.spring-mvc.xml 配置扫描包时,不要包含Service的注解, 并且配置proxy-target-class为true。

    <!-- 默认的注解映射的支持 -->
    <mvc:annotation-driven />

    <!-- 自动扫描该包 -->
    <context:component-scan base-package="com.test">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>
    </context:component-scan>

    <!-- 配置使Spring采用CGLIB代理 -->
    <aop:aspectj-autoproxy proxy-target-class="true" /> 

7.applicationContext.xml 配置扫描包时,不要包含controller的注解

    <context:component-scan base-package="com.test">           
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值