基于注解的系统日志

对于一些比较重要的管理系统,操作日志的记录是非常重要,它可以记录下管理人员的任何操作,也便于开发人员在故障中排查问题,可以维护和扩展的日志是尤为重要的。

注解的日志方便和实用,只需要在需要记录的日志方法上加入注解,下面不多说直接上代码

首先创建一个注解和日志实体

@Target({ElementType.METHOD})    
@Retention(RetentionPolicy.RUNTIME)     
@Documented 
public @interface SystemLog {
	
	/** 日志操作类型  */
	OperateTypes type();
	
	/** 日志操作对象  */
	OperateObj object();
	
	/** 日志信息描述  */
	String description()  default "";    
	
	/**
	 * @Description:日志信息描述(支持实体类字段)
	 * 传值方式:根据实体类的字段名获取参数,(参数名与参数值":"分隔,参数之间","分隔)
	 * 如:用户名:userName,姓名:name,手机:phone
	 * @author XPY
	 * @date 2016年7月28日上午10:42:43
	 */
	String descriptionField()  default "";    
	
	/**
	 * @Description:日志信息描述(支持表达式)
	 * 传值方式:{0}表示方法参数内的第一个参数,{1}表示方法参数内的第二个参数,以此类推
	 * 如:科目:{0},课程:{1}
	 * @author XPY
	 * @date 2016年7月28日上午10:42:43
	 */
	String descriptionRex()  default "";  

public class LogEntity{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private Long id;
	/**
	 * 操作人ID
	 */
	private Long userid;
	/**
	 * 操作人名称
	 */
	private String userName;
	/**
	 * 实体名称
	 */
	private String obj;
	/**
	 * 操作类型
	 */
	private String type;
	/**
	 * 日志字符串
	 */
	private String log;
	/**
	 * 日志中记录的操作结果
	 */
	private String result;
	/**
	 * 操作发生的时间戳
	 */
	private Date crtDate;
	/**
	 * 发起请求的IP地址
	 */
	private String requestIP;
	/**
	 * 异常信息
	 */
	private String error;

	public LogEntity() {
		super();
	}

	public Long getId() {
		return id;
	}

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

	public Long getUserid() {
		return userid;
	}

	public void setUserid(Long userid) {
		this.userid = userid;
	}

	public String getUserName() {
		return userName;
	}

	public void setUserName(String userName) {
		this.userName = userName;
	}

	public String getObj() {
		return obj;
	}

	public void setObj(String obj) {
		this.obj = obj;
	}

	public String getType() {
		return type;
	}

	public void setType(String type) {
		this.type = type;
	}

	public String getLog() {
		return log;
	}

	public void setLog(String log) {
		this.log = log;
	}

	public String getResult() {
		return result;
	}

	public void setResult(String result) {
		this.result = result;
	}

	public Date getCrtDate() {
		return crtDate;
	}

	public void setCrtDate(Date crtDate) {
		this.crtDate = crtDate;
	}

	public String getRequestIP() {
		return requestIP;
	}

	public void setRequestIP(String requestIP) {
		this.requestIP = requestIP;
	}

	public String getError() {
		return error;
	}

	public void setError(String error) {
		this.error = error;
	}

然后就是日志的切面类,包括日志的记录以及日志的描述

/**
 * 
 * @Description 日志切入类
 * @author XPY
 * @date 2016年7月25日下午7:32:25
 */
@Aspect
@Component
public class SystemLogAspect {

	private static String splitParaStr = ",";
	private static String splitNameValueStr = ":";

	// 注入Service用于把日志保存数据库
	@Resource
	private LogService logService;
	// 本地异常日志记录对象
	private static final Logger logger = LoggerFactory
			.getLogger(SystemLogAspect.class);

	// 基于注解的切入点,service层及controller层都可使用
	@Pointcut("@annotation(com.noah.system.log.annotation.SystemLog)")
	public void serviceAspect() {
	}

	
/*	  @Around("serviceAspect()") 
	  public Object process(ProceedingJoinPoint point) throws Throwable { 
		  System.out.println("@Around:执行目标方法之前...");
		  //访问目标方法的参数: 
		  Object[] args = point.getArgs(); //用改变后的参数执行目标方法 Object
		  Object returnValue = point.proceed(args);
		  returnValue = point.proceed(args);
		  System.out.println("@Around:执行目标方法之后...");
		  System.out.println("@Around:被织入的目标对象为:" + point.getTarget()); 
		  return "原返回值:" + returnValue + ",这是返回结果的后缀"; 
		  }*/


	/**
	 * 正常返回通知 用于拦截Service层记录用户的操作
	 * 
	 * @param joinPoint
	 *            切点
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	@AfterReturning(pointcut = "serviceAspect()")
	public void doAfter(JoinPoint joinPoint) {
		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
				.getRequestAttributes()).getRequest();
		// 读取session中的用户
		User user = (User) LiveUtils.getCurrentUser();
		if (user == null) {
			logger.info("=====读取用户信息失败=====");
			return;
		}
		// 请求的IP
		String ip = IpUtil.getIpAddress(request);
		// 获取用户请求方法的参数并序列化为JSON格式字符串
/*		String params = "";
		if (joinPoint.getArgs() != null && joinPoint.getArgs().length > 0) {
			for (int i = 0; i < joinPoint.getArgs().length; i++) {
				params += JSON.toJSONString(joinPoint.getArgs()[i]) + ";";
			}
		}*/
		try {
			// *========控制台输出=========*//
			logger.info("=====正常返回通知开始=====");
			logger.info("请求方法:"
					+ (joinPoint.getTarget().getClass().getName() + "."
							+ joinPoint.getSignature().getName() + "()"));
			logger.info("方法描述:" + getServiceMethod(joinPoint).getLog());
			logger.info("请求人:" + user.getName());
			logger.info("请求IP:" + ip);
			// *========数据库日志=========*//
			Object[] param = joinPoint.getArgs();
			Class[] parameterTypes = ((MethodSignature) joinPoint
					.getSignature()).getMethod().getParameterTypes();
			Method method = null;
			String methodName = joinPoint.getSignature().getName();
			Class targetClass = joinPoint.getTarget().getClass();
			method = targetClass.getMethod(methodName, parameterTypes);
			if (method != null) {
			SystemLog ann = method.getAnnotation(SystemLog.class);
			LogEntity log = (LogEntity) SpringBeanUtil.getBean("logEntity");
			log.setType(getServiceMethod(joinPoint).getType());
			log.setObj(getServiceMethod(joinPoint).getObj());
			log.setRequestIP(ip);
			log.setResult(Constants.SUCCESS);
			log.setUserid(user.getId());
			log.setUserName(user.getUserName());
			log.setCrtDate(new Date());
			log.setError("");
			if (getServiceMethod(joinPoint).getLog().isEmpty()) {
				log.setLog(getParamsRemark(ann, param));
			}else{
				log.setLog(getServiceMethod(joinPoint).getLog());
			}
			// 保存数据库
			logService.add(log);
			}
			logger.info("=====正常返回通知结束=====");
		} catch (Exception e) {
			// 记录本地异常日志
			logger.error("==正常返回通知异常==");
			logger.error("异常信息:{}", e.getMessage());
		}
	}

	/**
	 * 异常通知 用于拦截service层记录异常日志
	 * 
	 * @param joinPoint
	 * @param e
	 * @throws Throwable
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	@AfterThrowing(pointcut = "serviceAspect()", throwing = "e")
	public void doAfterThrowing(JoinPoint joinPoint, Throwable e)
			throws Throwable {
		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
				.getRequestAttributes()).getRequest();
		// 读取session中的用户
		User user = (User) LiveUtils.getCurrentUser();
		// 请求的IP
		String ip = IpUtil.getIpAddress(request);
		// 获取用户请求方法的参数并序列化为JSON格式字符串
		String params = "";
		if (joinPoint.getArgs() != null && joinPoint.getArgs().length > 0) {
			for (int i = 0; i < joinPoint.getArgs().length; i++) {
				params += JSON.toJSONString(joinPoint.getArgs()[i]) + ";";
			}
		}
		try {
			/* ========控制台输出========= */
			logger.info("=====异常通知开始=====");
			logger.info("异常代码:" + e.getClass().getName());
			logger.info("异常信息:" + e.getMessage());
			logger.info("异常方法:"
					+ (joinPoint.getTarget().getClass().getSimpleName() + "."
							+ joinPoint.getSignature().getName() + "()"));
			logger.info("方法描述:" + getServiceMethod(joinPoint).getLog());
			logger.info("请求人:" + user.getName());
			logger.info("请求IP:" + ip);
			logger.info("请求参数:" + params);
			/* ==========数据库日志========= */
			Object[] param = joinPoint.getArgs();
			Class[] parameterTypes = ((MethodSignature) joinPoint
					.getSignature()).getMethod().getParameterTypes();
			Method method = null;
			String methodName = joinPoint.getSignature().getName();
			Class targetClass = joinPoint.getTarget().getClass();
			method = targetClass.getMethod(methodName, parameterTypes);
			if (method != null) {
			SystemLog ann = method.getAnnotation(SystemLog.class);
			LogEntity log = (LogEntity) SpringBeanUtil.getBean("logEntity");
			log.setType(getServiceMethod(joinPoint).getType());
			log.setObj(getServiceMethod(joinPoint).getObj());
			log.setRequestIP(ip);
			log.setResult(Constants.FAILTURE);
			log.setUserid(user.getId());
			log.setUserName(user.getUserName());
			log.setCrtDate(new Date());
			log.setError("异常代码:" + e.getClass().getName()+"异常信息:" + e.getMessage());
			if (getServiceMethod(joinPoint).getLog().isEmpty()) {
				log.setLog(getParamsRemark(ann, param));
			}else{
				log.setLog(getServiceMethod(joinPoint).getLog());
			}
			// 保存数据库
			logService.add(log);
			logger.info("=====异常通知结束=====");
			}
		} catch (Exception ex) {
			// 记录本地异常日志
			logger.error("==异常通知异常==");
			logger.error("异常信息:{}", ex.getMessage());
		}
		/* ==========记录本地异常日志========== */
		logger.error("异常方法:{}异常代码:{}异常信息:{}参数:{}", joinPoint.getTarget()
				.getClass().getName()
				+ joinPoint.getSignature().getName(), e.getClass().getName(),
				e.getMessage(), params);

	}

	/**
	 * 获取注解中对方法的描述信息 用于service层注解
	 * 
	 * @param joinPoint
	 *            切点
	 * @return 方法描述
	 * @throws Exception
	 */
	@SuppressWarnings("rawtypes")
	public static LogEntity getServiceMethod(JoinPoint joinPoint)
			throws Exception {
		String targetName = joinPoint.getTarget().getClass().getName();
		String methodName = joinPoint.getSignature().getName();
		Object[] arguments = joinPoint.getArgs();
		Class<?> targetClass = Class.forName(targetName);
		Method[] methods = targetClass.getMethods();
		LogEntity logEntity = new LogEntity();
		for (Method method : methods) {
			if (method.getName().equals(methodName)) {
				Class[] clazzs = method.getParameterTypes();
				if (clazzs.length == arguments.length) {
					String type = method.getAnnotation(SystemLog.class).type().type;
					String obj = method.getAnnotation(SystemLog.class).object().type;
					String description = method.getAnnotation(SystemLog.class)
							.description();
					logEntity.setType(type);
					logEntity.setObj(obj);
					logEntity.setLog(description);
					break;
				}
			}
		}
		return logEntity;
	}

	/**
	 * 通过java反射来从传入的参数object里取出我们需要记录的字段等属性
	 * @param obj 参数实体
	 * @param param 参数字段
	 * @return 参数字段的值
	 */
	private String getID(Object obj, String param) {
		if (obj instanceof String) {
			return obj.toString();
		}
		PropertyDescriptor pd = null;
		Method method = null;
		String v = "";
		try {
			pd = new PropertyDescriptor(param, obj.getClass());
			method = pd.getReadMethod();
			v = String.valueOf(method.invoke(obj));
		} catch (Exception e) {
			e.printStackTrace();
		}
		return v;
	}

	/**
	 * 通过反射调用bean的get方法或{1}这样的表达式生成描述信息
	 * {0}为第一位参数的值,{1}为第二位参数的值
	 * 如果参数为bean的情况可以"用户名:userName"这样的方式获取参数值
	 * @param param 所有参数
	 * @return 描述信息
	 */
	private String getParamsRemark(SystemLog annotation, Object[] param) {
		String propertys = annotation.descriptionField();
		String params = annotation.descriptionRex();
		StringBuffer sb = new StringBuffer();
		String desc1 = "";
		String desc2 = "";
		if (null != propertys && !"".equals(propertys)) {
			String[] propertysRemark = annotation.descriptionField().split(
					splitParaStr);
			for (String property : propertysRemark) {// 按参数对象属性,取参数值
				String name = property.split(splitNameValueStr)[0];
				String value = property.split(splitNameValueStr)[1];
				sb.append(name + splitNameValueStr + getID(param[0], value)
						+ splitParaStr).append(",");
			}
			desc1 = sb.toString().substring(0, sb.length() - 1);
		} 
		if(null != params && !"".equals(params)) {
			List<String> list = StringUtil.getList("\\{(.*?)\\}", params);// 按参数位置取参数值
			for (int i = 0; i < list.size(); i++) {
				String str = list.get(i);
				Object obj = param[Integer.parseInt(str)];
				params = StringUtil.replease("\\{" + Integer.parseInt(str)
						+ "\\}", params, obj.toString())+",";
			}
			desc2 =  params;
		}
		return desc1+desc2;
	}
}


需要通过代理方式来增强AOP
public interface BeanSelfAware {
	//AOP增强后的代理对象 
	public void setSelf(Object proxyBean);
}
/**
 * @Description 动态注入代理类
 * @author XPY
 * @date 2016年7月28日下午2:08:25
 */
public class InjectBeanSelfProcessor implements BeanPostProcessor  
{  
   
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException  
    {  
        if(bean instanceof BeanSelfAware)  
        {  
            System.out.println("inject proxy:" + bean.getClass());  
            BeanSelfAware proxyBean = (BeanSelfAware)bean;  
            proxyBean.setSelf(bean);  
            return proxyBean;  
        }  
        return bean;  
    }  
   
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException  
    {  
        return bean;  
    }  
}  

最终的使用方式,在方法加入注解即可

@SystemLog(type=OperateTypes.login,object=OperateObj.SysUser,description="登录系统")
	public ModelAndView login(HttpServletRequest request,HttpSession session,ModelMap model) {}




  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: 基于Spring Boot开发系统文档,是指使用Spring Boot框架来开发和管理系统文档。 首先,Spring Boot是一种基于Spring Framework的快速开发框架,它简化了Spring应用的配置和部署过程。通过使用Spring Boot,可以快速搭建一个可运行的、自包含的应用程序。 在开发系统文档时,可以使用Spring Boot的特性和功能来简化开发过程。首先,可以使用Spring Boot的自动配置功能,根据项目的依赖和配置文件,自动配置系统文档所需的环境和依赖项。这样可以减少开发人员的工作量,提高开发效率。 其次,Spring Boot还提供了一组开发工具和插件,可以帮助开发人员快速生成文档。例如,可以使用Springfox库来生成API文档,该库可以根据代码注解和配置文件自动生成API接口的文档。此外,还可以使用Swagger UI来展示和测试API文档,使开发人员可以方便地查看和验证API接口的正确性。 另外,基于Spring Boot开发的系统文档还可以利用Spring Boot的监控和管理功能。通过集成Spring Boot Actuator,可以获取系统的运行状态、性能指标和日志信息等。这些信息对于系统的运维和排错非常有价值。 总之,基于Spring Boot开发系统文档可以简化开发过程,提高开发效率。通过利用Spring Boot的特性和功能,可以自动配置文档所需的环境和依赖项,快速生成API文档,并方便地监控和管理系统的运行状态。这样可以帮助开发人员更好地编写和维护系统文档。 ### 回答2: 基于Spring Boot开发系统文档是一种将系统开发过程中的各个模块、功能、接口、代码等信息进行记录和汇总的手段。系统文档的编写可以使开发团队成员之间更好地了解系统的整体架构、模块划分、接口设计等,从而提高团队的协作效率。 在基于Spring Boot开发系统文档时,可以根据项目的具体需求来确定文档的内容和格式。常见的文档类型包括需求文档、设计文档、接口文档、用户手册等。 需求文档主要描述系统开发的目标和功能需求,包括系统的使用场景、用户角色、功能模块、业务流程等。在编写需求文档时,可以使用UML图、流程图等图形化工具来更好地展示系统的功能和流程。 设计文档主要描述系统的架构和模块划分,包括系统的分层结构、模块之间的关系、数据库设计等。在编写设计文档时,可以使用UML图、类图、时序图等来表示系统的结构和流程。 接口文档主要描述系统的各个接口,包括接口名称、参数、响应等。在编写接口文档时,可以使用Swagger等工具来自动生成接口文档,以提高文档的准确性和一致性。 用户手册主要面向系统的最终用户,描述系统的使用方法和注意事项。在编写用户手册时,应尽量简明扼要地描述系统的操作步骤和功能说明,避免使用过于专业的术语。 总之,基于Spring Boot开发系统文档是系统开发过程中必不可少的一环,它能够帮助团队成员更好地理解系统的架构和功能,提高开发效率和协作效果。 ### 回答3: 基于Spring Boot开发系统文档是指在使用Spring Boot框架开发一个系统时编写的相关文档。这些文档旨在记录开发过程的各个阶段,包括需求分析、设计、开发、测试和部署等环节。系统文档的编写有助于团队成员之间的沟通和配合,提高开发效率和质量。 开发系统文档的基本步骤包括以下几个方面: 1. 需求分析:首先要明确系统的功能需求和非功能需求,包括用户需求、系统约束、用例场景等内容。在这一阶段,可以编写需求规格说明书和用例文档等。 2. 设计阶段:根据需求分析的结果,进行系统的整体架构设计和详细设计。在这一阶段,可以编写设计文档,包括系统架构图、数据库设计、接口设计等。 3. 开发阶段:根据设计文档,进行具体的编码实现。在开发过程中,可以编写代码注释、API文档等。 4. 测试阶段:对开发完成的代码进行单元测试、集成测试和系统测试等,确保系统的正确性和稳定性。在这一阶段,可以编写测试用例和测试报告等。 5. 部署阶段:将开发完成的系统部署到生产环境,并进行性能测试和安全测试。在这一阶段,可以编写部署文档和运维手册等。 在整个开发过程中,系统文档起到了记录和沟通的作用。它可以帮助团队成员了解整个系统的结构和实现细节,方便开发和维护。同时,系统文档也可以作为项目的重要交付物,提供给客户或参与者了解系统的功能和特点。 总而言之,基于Spring Boot开发系统文档是非常重要的一环。它可以提供开发过程的指导和帮助,促进项目的顺利进行和成功交付。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值