zoukankan      html  css  js  c++  java
  • spring AOP自定义注解方式实现日志管理

    在applicationContext-mvc.xml中要添加的

         <mvc:annotation-driven />
         <!-- 激活组件扫描功能,在包com.gcx及其子包下面自动扫描通过注解配置的组件 -->
         <context:component-scan base-package="com.gcx" />

      

         <!-- 启动对@AspectJ注解的支持 --> 
         <!-- proxy-target-class等于true是强制使用cglib代理,proxy-target-class默认是false,如果你的类实现了接口 就走JDK代理,如果没有,走cglib代理  -->
         <!-- 注:对于单利模式建议使用cglib代理,虽然JDK动态代理比cglib代理速度快,但性能不如cglib -->

         <!--如果不写proxy-target-class="true"这句话也没问题-->
         <aop:aspectj-autoproxy proxy-target-class="true"/>

         <!--切面-->
         <bean id="systemLogAspect" class="com.gcx.annotation.SystemLogAspect"></bean>

    接下来开始编写代码。

         创建日志类实体

    public class SystemLog {
    private String id;

    private String description;

    private String method;

    private Long logType;

    private String requestIp;

    private String exceptioncode;

    private String exceptionDetail;

    private String params;

    private String createBy;

    private Date createDate;

    public String getId() {
    return id;
    }

    public void setId(String id) {
    this.id = id == null ? null : id.trim();
    }

    public String getDescription() {
    return description;
    }

    public void setDescription(String description) {
    this.description = description == null ? null : description.trim();
    }

    public String getMethod() {
    return method;
    }

    public void setMethod(String method) {
    this.method = method == null ? null : method.trim();
    }

    public Long getLogType() {
    return logType;
    }

    public void setLogType(Long logType) {
    this.logType = logType;
    }

    public String getRequestIp() {
    return requestIp;
    }

    public void setRequestIp(String requestIp) {
    this.requestIp = requestIp == null ? null : requestIp.trim();
    }

    public String getExceptioncode() {
    return exceptioncode;
    }

    public void setExceptioncode(String exceptioncode) {
    this.exceptioncode = exceptioncode == null ? null : exceptioncode.trim();
    }

    public String getExceptionDetail() {
    return exceptionDetail;
    }

    public void setExceptionDetail(String exceptionDetail) {
    this.exceptionDetail = exceptionDetail == null ? null : exceptionDetail.trim();
    }

    public String getParams() {
    return params;
    }

    public void setParams(String params) {
    this.params = params == null ? null : params.trim();
    }

    public String getCreateBy() {
    return createBy;
    }

    public void setCreateBy(String createBy) {
    this.createBy = createBy == null ? null : createBy.trim();
    }

    public Date getCreateDate() {
    return createDate;
    }

    public void setCreateDate(Date createDate) {
    this.createDate = createDate;
    }
    }

       编写dao接口

    package com.gcx.dao;

    import com.gcx.entity.SystemLog;

    public interface SystemLogMapper {
    int deleteByPrimaryKey(String id);

    int insert(SystemLog record);

    int insertSelective(SystemLog record);

    SystemLog selectByPrimaryKey(String id);

    int updateByPrimaryKeySelective(SystemLog record);

    int updateByPrimaryKey(SystemLog record);
    }

    编写service层

    package com.gcx.service;

    import com.gcx.entity.SystemLog;

    public interface SystemLogService {

    int deleteSystemLog(String id);

    int insert(SystemLog record);

    int insertTest(SystemLog record);

    SystemLog selectSystemLog(String id);

    int updateSystemLog(SystemLog record);
    }

    编写service实现类serviceImpl

    package com.gcx.service.impl;

    import javax.annotation.Resource;

    import org.springframework.stereotype.Service;

    import com.gcx.annotation.Log;
    import com.gcx.dao.SystemLogMapper;
    import com.gcx.entity.SystemLog;
    import com.gcx.service.SystemLogService;

    @Service("systemLogService")
    public class SystemLogServiceImpl implements SystemLogService {

    @Resource
    private SystemLogMapper systemLogMapper;

    @Override
    public int deleteSystemLog(String id) {

    return systemLogMapper.deleteByPrimaryKey(id);
    }

    @Override

    public int insert(SystemLog record) {

    return systemLogMapper.insertSelective(record);
    }

    @Override
    public SystemLog selectSystemLog(String id) {

    return systemLogMapper.selectByPrimaryKey(id);
    }

    @Override
    public int updateSystemLog(SystemLog record) {

    return systemLogMapper.updateByPrimaryKeySelective(record);
    }

    @Override
    public int insertTest(SystemLog record) {

    return systemLogMapper.insert(record);
    }

    }

    到这里基本程序编写完毕,下面开始自定义注解

    package com.gcx.annotation;

    import java.lang.annotation.*;

    @Target({ElementType.PARAMETER, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Log {

    /** 要执行的操作类型比如:add操作 **/
    public String operationType() default "";

    /** 要执行的具体操作比如:添加用户 **/
    public String operationName() default "";
    }

    下面编写切面

    package com.gcx.annotation;

    import java.lang.reflect.Method;
    import java.util.Date;
    import java.util.UUID;

    import javax.annotation.Resource;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpSession;

    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.After;
    import org.aspectj.lang.annotation.AfterReturning;
    import org.aspectj.lang.annotation.AfterThrowing;
    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.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;

    import com.gcx.entity.SystemLog;
    import com.gcx.entity.User;
    import com.gcx.service.SystemLogService;
    import com.gcx.util.JsonUtil;

    /**
    * @author 杨建
    * @E-mail: email
    * @version 创建时间:2015-10-19 下午4:29:05
    * @desc 切点类
    */

    @Aspect
    @Component
    public class SystemLogAspect {

    //注入Service用于把日志保存数据库
    @Resource //这里我用resource注解,一般用的是@Autowired,他们的区别如有时间我会在后面的博客中来写
    private SystemLogService systemLogService;

    private static final Logger logger = LoggerFactory.getLogger(SystemLogAspect. class);

    //Controller层切点
    @Pointcut("execution (* com.gcx.controller..*.*(..))")
    public void controllerAspect() {
    }

    /**
    * 前置通知 用于拦截Controller层记录用户的操作
    *
    * @param joinPoint 切点
    */
    @Before("controllerAspect()")
    public void doBefore(JoinPoint joinPoint) {
    System.out.println("==========执行controller前置通知===============");
    if(logger.isInfoEnabled()){
    logger.info("before " + joinPoint);
    }
    }

    //配置controller环绕通知,使用在方法aspect()上注册的切入点
    @Around("controllerAspect()")
    public void around(JoinPoint joinPoint){
    System.out.println("==========开始执行controller环绕通知===============");
    long start = System.currentTimeMillis();
    try {
    ((ProceedingJoinPoint) joinPoint).proceed();
    long end = System.currentTimeMillis();
    if(logger.isInfoEnabled()){
    logger.info("around " + joinPoint + " Use time : " + (end - start) + " ms!");
    }
    System.out.println("==========结束执行controller环绕通知===============");
    } catch (Throwable e) {
    long end = System.currentTimeMillis();
    if(logger.isInfoEnabled()){
    logger.info("around " + joinPoint + " Use time : " + (end - start) + " ms with exception : " + e.getMessage());
    }
    }
    }

    /**
    * 后置通知 用于拦截Controller层记录用户的操作
    *
    * @param joinPoint 切点
    */
    @After("controllerAspect()")
    public void after(JoinPoint joinPoint) {

    /* HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
    HttpSession session = request.getSession(); */
    //读取session中的用户
    // User user = (User) session.getAttribute("user");
    //请求的IP
    //String ip = request.getRemoteAddr();
    User user = new User();
    user.setId(1);
    user.setName("张三");
    String ip = "127.0.0.1";
    try {

    String targetName = joinPoint.getTarget().getClass().getName();
    String methodName = joinPoint.getSignature().getName();
    Object[] arguments = joinPoint.getArgs();
    Class targetClass = Class.forName(targetName);
    Method[] methods = targetClass.getMethods();
    String operationType = "";
    String operationName = "";
    for (Method method : methods) {
    if (method.getName().equals(methodName)) {
    Class[] clazzs = method.getParameterTypes();
    if (clazzs.length == arguments.length) {
    operationType = method.getAnnotation(Log.class).operationType();
    operationName = method.getAnnotation(Log.class).operationName();
    break;
    }
    }
    }
    //*========控制台输出=========*//
    System.out.println("=====controller后置通知开始=====");
    System.out.println("请求方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()")+"."+operationType);
    System.out.println("方法描述:" + operationName);
    System.out.println("请求人:" + user.getName());
    System.out.println("请求IP:" + ip);
    //*========数据库日志=========*//
    SystemLog log = new SystemLog();
    log.setId(UUID.randomUUID().toString());
    log.setDescription(operationName);
    log.setMethod((joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()")+"."+operationType);
    log.setLogType((long)0);
    log.setRequestIp(ip);
    log.setExceptioncode( null);
    log.setExceptionDetail( null);
    log.setParams( null);
    log.setCreateBy(user.getName());
    log.setCreateDate(new Date());
    //保存数据库
    systemLogService.insert(log);
    System.out.println("=====controller后置通知结束=====");
    } catch (Exception e) {
    //记录本地异常日志
    logger.error("==后置通知异常==");
    logger.error("异常信息:{}", e.getMessage());
    }
    }

    //配置后置返回通知,使用在方法aspect()上注册的切入点
    @AfterReturning("controllerAspect()")
    public void afterReturn(JoinPoint joinPoint){
    System.out.println("=====执行controller后置返回通知=====");
    if(logger.isInfoEnabled()){
    logger.info("afterReturn " + joinPoint);
    }
    }

    /**
    * 异常通知 用于拦截记录异常日志
    *
    * @param joinPoint
    * @param e
    */
    @AfterThrowing(pointcut = "controllerAspect()", throwing="e")
    public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {
    /*HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
    HttpSession session = request.getSession();
    //读取session中的用户
    User user = (User) session.getAttribute(WebConstants.CURRENT_USER);
    //获取请求ip
    String ip = request.getRemoteAddr(); */
    //获取用户请求方法的参数并序列化为JSON格式字符串

    User user = new User();
    user.setId(1);
    user.setName("张三");
    String ip = "127.0.0.1";

    String params = "";
    if (joinPoint.getArgs() != null && joinPoint.getArgs().length > 0) {
    for ( int i = 0; i < joinPoint.getArgs().length; i++) {
    params += JsonUtil.getJsonStr(joinPoint.getArgs()[i]) + ";";
    }
    }
    try {

    String targetName = joinPoint.getTarget().getClass().getName();
    String methodName = joinPoint.getSignature().getName();
    Object[] arguments = joinPoint.getArgs();
    Class targetClass = Class.forName(targetName);
    Method[] methods = targetClass.getMethods();
    String operationType = "";
    String operationName = "";
    for (Method method : methods) {
    if (method.getName().equals(methodName)) {
    Class[] clazzs = method.getParameterTypes();
    if (clazzs.length == arguments.length) {
    operationType = method.getAnnotation(Log.class).operationType();
    operationName = method.getAnnotation(Log.class).operationName();
    break;
    }
    }
    }
    /*========控制台输出=========*/
    System.out.println("=====异常通知开始=====");
    System.out.println("异常代码:" + e.getClass().getName());
    System.out.println("异常信息:" + e.getMessage());
    System.out.println("异常方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()")+"."+operationType);
    System.out.println("方法描述:" + operationName);
    System.out.println("请求人:" + user.getName());
    System.out.println("请求IP:" + ip);
    System.out.println("请求参数:" + params);
    /*==========数据库日志=========*/
    SystemLog log = new SystemLog();
    log.setId(UUID.randomUUID().toString());
    log.setDescription(operationName);
    log.setExceptioncode(e.getClass().getName());
    log.setLogType((long)1);
    log.setExceptionDetail(e.getMessage());
    log.setMethod((joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));
    log.setParams(params);
    log.setCreateBy(user.getName());
    log.setCreateDate(new Date());
    log.setRequestIp(ip);
    //保存数据库
    systemLogService.insert(log);
    System.out.println("=====异常通知结束=====");
    } catch (Exception ex) {
    //记录本地异常日志
    logger.error("==异常通知异常==");
    logger.error("异常信息:{}", ex.getMessage());
    }
    /*==========记录本地异常日志==========*/
    logger.error("异常方法:{}异常代码:{}异常信息:{}参数:{}", joinPoint.getTarget().getClass().getName() + joinPoint.getSignature().getName(), e.getClass().getName(), e.getMessage(), params);

    }

    }

     我这里写的比较全,前置通知,环绕通知,后置通知,异常通知,后置饭后通知,都写上了,在我们实际编写中不写全也没事,我习惯上把记录日志的逻辑写在后置通知里面,我看网上也有些在前置通知里面的,但我感觉写在后置通知里比较好。

    下面开始在controller中加入自定义的注解!!

    package com.gcx.controller;

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;

    import com.gcx.annotation.Log;
    import com.gcx.service.UserService;

    @Controller
    @RequestMapping("userController")
    public class UserController {

    @Autowired
    private UserService userService;

    @RequestMapping("testAOP")
    @Log(operationType="add操作:",operationName="添加用户")
    public void testAOP(String userName,String password){
    userService.addUser(userName, password);
    }
    }

    下面编写测试类

    @Test
    public void testAOP1(){
    //启动Spring容器
    ApplicationContext ctx = new ClassPathXmlApplicationContext(new String[]{"classpath:applicationContext-mvc.xml","classpath:applicationContext-dataSource.xml"});
    //获取service或controller组件
    UserController userController = (UserController) ctx.getBean("userController");
    userController.testAOP("zhangsan", "123456");
    }

  • 相关阅读:
    二叉树基本操作(二)
    二叉树基本操作(一)
    数组的方式实现--栈 数制转换
    数据的插入与删除
    链表 创建 插入 删除 查找 合并
    ACM3 求最值
    ACM2 斐波那契数列
    ACM_1 大数求和
    简单二维码生成及解码代码:
    ORM中去除反射,添加Expression
  • 原文地址:https://www.cnblogs.com/vofill/p/6835779.html
Copyright © 2011-2022 走看看