Spring AOP+Annotation切面式注解实现自定义系统日志

写在前面:此实现感谢我大杰哥

后期我大杰哥会有针对此日志实现的优化,包括注入LogUserService 的懒加载问题

切面编程和自定义注解的技术博客自行研究

【SpringBoot笔记8】Spring AOP 面向切面编程(应用篇)
自定义注解详细介绍

目标:

实现用户操作、操作方法、执行结果的一站式记录

思路:

1. 使用切面编程的方式处理用户操作中系统调用方法的环绕通知式记录,包括调用前获得用户及传参参数,执行方法的处理内容,执行方法结束后状态返回值等。

2. 使用注解的方式实现自定义方法体的指向性日志记录,通过自定义注解,自定义日志等级,操作类型,数据库操作类型等。设定自定义传参格式,可获取方法传参,切面变成的方式存储入库。

3. 设置切面变成的切入点为注解。

使用方式

在这里插入图片描述

实现过程:

Spring AOP+Annotation切面式注解实现自定义系统日志_第1张图片

1. 自定义注解OperationLogDetail

  • 使用@interface关键字定义注解
  • @Documented是被用来指定自定义注解是否能随着被定义的java文件生成到JavaDoc文档当中
  • @Target表示注解的可作用类型,枚举类型ElementType.METHOD表示作用指向方法,枚举类型中还定义了其他作用类型,自行研究学习。
  • @Retention表示注解的生命周期,RetentionPolicy.RUNTIME表示作用到被加载到CLASS中,程序运行阶段可以通过反射得到这个注解。开发常用配置。
注解类,定义操作细节、日志等级、操作类型、操作对象四个属性。

源码:

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import com.XXXX.enums.OperationType;

@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface OperationLogDetail {

    /**
     * 方法描述,可使用占位符获取参数:{{id}}
     */
    String detail() default "";

    /**
     * 日志等级:自己定,此处分为1-9
     */
    int level() default 0;

    /**
     * 操作类型(enum):主要是select,insert,update,delete
     */
    OperationType operationType() default OperationType.UNKNOWN;

    /**
     * 被操作的对象(此处使用enum):可以是任何对象,如表名(user),或者是工具(redis)
     */
    String operationUnit() default "";
}


2. 定义切面类,处理切面业务逻辑

  • @Aspect声明一个切面,被其注释的类都会被Spring AOP框架自动发现并加载为一个Aspect切面,此切面类可以有成员变量和方法,也可以包含切入点和通知。
  • @Component声明切面的注解并不能在Spring上下文中注册这个bean,需要添加此注释注册bean,否则此切面不会生效。
在这里我们定义了我们的切面切入点为自定义注解

切入点包含两个要素:

  • 切入点表达式@Pointcut("@annotation(com.sinog2c.annotation.OperationLogDetail)")
  • 切入点签名public void operationLog(){}
选用Around Advice环绕通知处理业务
  • 我们需要执行前记录操作用户,操作类型等信息,执行结束后记录操作结果信息。
  • 自定义参数获取{{param}}类型获取方法getDetail,文本替换。
  • 设定注解方法时,通过文本设定,如用户{{userId}}执行对编号{{id}}数据进行了删除操作
  • 定义对请求request的ip地址获取方法。
  • 由SystemLogService类处理汇总数据的入库工作,使用mongodb存储日志。
  • 懒加载因为logAspect创建时logUserService这个bean还没有创建

源码:

package com.xxxx.aop;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;

import org.aspectj.lang.ProceedingJoinPoint;
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.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.xxxx.annotation.OperationLogDetail;
import com.xxxx.config.LogUserService;
import com.xxxx.model.LogUser;
import com.xxxx.model.OperationLog;
import com.xxxx.service.SystemLogService;
import com.xxxx.util.JsonUtils;
import com.xxxx.util.StringUtil;

@Aspect
@Component
public class LogAspect {

	@Autowired
	private SystemLogService systemLogService;
	@Autowired
	@Lazy
	private LogUserService logUserService;
	private static final String SUCCESS = "SUCCESS";
	private static final String ERROR = "ERROR";
	private static final String SYSTEM_ID = "system";
	private static final String SYSTEM_NAME = "系统";

	/**
	 * 此处的切点是注解的方式,也可以用包名的方式达到相同的效果
	 * '@Pointcut("execution(* com.wwj.springboot.service.impl.*.*(..))")'
	 */
	@Pointcut("@annotation(com.sinog2c.annotation.OperationLogDetail)")
	public void operationLog(){}

	/**
	 * 环绕通知(Around advice) :包围一个连接点的通知,类似Web中Servlet规范中的Filter的doFilter方法。可以在方法的调用前后完成自定义的行为,也可以选择不执行。
	 * @param joinPoint
	 * @return
	 * @throws Throwable
	 */
	@Around("operationLog()")
	public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
		// 1.方法执行前的处理,相当于前置通知
		long time = System.currentTimeMillis();
		// 获取方法签名
		MethodSignature signature = (MethodSignature) joinPoint.getSignature();
		// 获取方法
		Method method = signature.getMethod();
		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
		LogUser user = logUserService.getLogUser(request);
		// 创建一个日志对象(准备记录日志)
		OperationLog operationLog = new OperationLog();
		if(null == user){
			user.setUserId(SYSTEM_ID);
			user.setUserName(SYSTEM_NAME);
			user.setData(0);
		}
		operationLog.setId(StringUtil.getUUID());//设置id
		operationLog.setMethod(signature.getDeclaringTypeName() + "." + signature.getName());//设置方法名
		operationLog.setIp(getIpAddress(request));//设置ip
		operationLog.setUserId(user.getUserId());// 设置操作人账号
		operationLog.setSource(user.getData().toString());
		operationLog.setUserName(user.getUserName());// 设置操作人姓名
		Object[] obj = joinPoint.getArgs();
		String args = "";
		if(obj != null && obj.length > 0) {
			for(int i=0; i<obj.length; i++) {
				args += obj[i] + ",";
			}
			operationLog.setArgs(args.substring(0, args.lastIndexOf(",")));//入参
		}

		// 获取方法上面的注解
		OperationLogDetail annotation = method.getAnnotation(OperationLogDetail.class);
		if(null != annotation){
			operationLog.setLogLevel(annotation.level());
			operationLog.setOperationType(annotation.operationType().getValue());
			operationLog.setOperationUnit(annotation.operationUnit());
			operationLog.setLogDescribe(getDetail(signature, obj, annotation, user));//操作说明
		}
		Object result = null;
		try {
			//让代理方法执行
			result = joinPoint.proceed();
			time = System.currentTimeMillis() - time;
			// 2.相当于后置通知(方法成功执行之后走这里)
			operationLog.setRunTime(time);
			operationLog.setResult(SUCCESS);// 设置操作结果
			operationLog.setReturnValue(JSON.toJSONString(result));//设置出参
		} catch (Exception e) {
			// 3.相当于异常通知部分
			operationLog.setResult(ERROR);// 设置操作结果
			operationLog.setErrorInfo(getExceptionAllinformation(e));// 设置错误信息
		} finally {
			// 4.相当于最终通知
			operationLog.setCreateTime(new Date());// 设置操作时间
			systemLogService.addLogInfo(operationLog);
		}
		return result;
	}

	/**
	 * 获取Exception详情
	 * @param ex
	 * @return
	 */
	public String getExceptionAllinformation(Exception ex){
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		PrintStream pout = new PrintStream(out);
		ex.printStackTrace(pout);
		String ret = new String(out.toByteArray());
		try {
			pout.close();
		} catch (Exception e) {
		}
		try {
			out.close();
		} catch (Exception e) {
		}
		return ret;
	}

	/**
	 * 对当前登录用户和占位符处理
	 * @param argNames 方法参数名称数组
	 * @param args 方法参数数组
	 * @param annotation 注解信息
	 * @return 返回处理后的描述
	 */
	private String getDetail(MethodSignature methodSignature, Object[] args, OperationLogDetail annotation, LogUser user){
		Class[] clas = methodSignature.getParameterTypes();
		String[] argNames = methodSignature.getParameterNames();
		JSONObject json = new JSONObject();
		for(int i = 0;i < argNames.length;i++){
			if(!"java.lang.String".equals(clas[i].getName())) {
				JSONObject jsonObject = JsonUtils.objectToJson(args[i]);
				Set<String> keys = jsonObject.keySet();
				for(String key : keys){
					json.put(key, jsonObject.get(key));
				}
			}else {
				json.put(argNames[i],args[i]);
			}
		}

		String detail = annotation.detail();
		try {
			detail = "" + user.getUserName() + "=》" + annotation.detail();
			for (String key : json.keySet()) {
				Object value = json.get(key);
				detail = detail.replace("{{" + key + "}}", JSON.toJSONString(value));
			}
		}catch (Exception e){
			e.printStackTrace();
		}
		return detail;
	}

	/**
	 * 获取请求注解的ip地址
	 * @Title: getIpAddress 
	 * @Description: TODO
	 * @param: @param request
	 * @param: @return
	 * @param: @throws IOException 
	 * @return: String 
	 * @throws
	 */
	public final static String getIpAddress(HttpServletRequest request)throws IOException {
		// 获取请求主机IP地址,如果通过代理进来,则透过防火墙获取真实IP地址
		String ip = request.getHeader("X-Forwarded-For");

		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(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.getHeader("HTTP_CLIENT_IP");
			}
			if (ip == null || ip.length() == 0
					|| "unknown".equalsIgnoreCase(ip)) {
				ip = request.getHeader("HTTP_X_FORWARDED_FOR");
			}
			if (ip == null || ip.length() == 0
					|| "unknown".equalsIgnoreCase(ip)) {
				ip = request.getRemoteAddr();
			}
		} else if (ip.length() > 15) {
			String[] ips = ip.split(",");
			for (int index = 0; index < ips.length; index++) {
				String strIp = (String) ips[index];
				if (!("unknown".equalsIgnoreCase(strIp))) {
					ip = strIp;
					break;
				}
			}
		}
		return ip;
	}
	
}

3.AOP基础bean:LogBean

spring在IOC初始化的时候,一般的bean都是直接调用构造方法,如果该bean实现了FactroyBean接口,则会调用该bean的getObject方法获取bean,这也是Spring使用此接口构造AOP的原因,在IOC调用此方法时返回一个代理,完成AOP代理的创建

import org.springframework.beans.factory.FactoryBean;

import com.xxxx.service.SystemLogService;

public class LogBean implements FactoryBean<SystemLogService> {

	@Override
	public SystemLogService getObject() throws Exception {
		return new SystemLogService();
	}

	@Override
	public Class<SystemLogService> getObjectType() {
		return SystemLogService.class;
	}

	@Override
	public boolean isSingleton() {
		return true;
	}

}

4.登陆用户接口LogUserService

用户定义获取登陆用户信息
import javax.servlet.http.HttpServletRequest;

import com.sinog2c.model.LogUser;

public interface LogUserService {
	
	public LogUser getLogUser(HttpServletRequest request);

}

5.应用上下文环境

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class MyApplicationContext<T> implements ApplicationContextAware {
	
	private T t;
	
	//Spring应用上下文环境
	private static ApplicationContext applicationContext;
	
	public MyApplicationContext(T t) {
		this.t = t;
	}

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

		DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();

		LogUserService logUserService = (LogUserService) t;
		//创建bean信息
		BeanDefinitionBuilder beanDefinitionBuilder =BeanDefinitionBuilder.genericBeanDefinition(logUserService.getClass());
		//动态注册bean
		defaultListableBeanFactory.registerBeanDefinition("logUserService",beanDefinitionBuilder.getBeanDefinition());
		MyApplicationContext.applicationContext = applicationContext;
	}

	/**
	 * 获取对象
	 * @param name
	 * @return Object 一个以类型
	 * @throws BeansException
	 */

	public static Object getBean(Class requiredType) throws BeansException {
		return applicationContext.getBean(requiredType);
	}

	/**
	 * 获取对象
	 * @param name
	 * @return Object 一个以所给名字注册的bean的实例
	 * @throws BeansException
	 */
	public static Object getBean(String name) throws BeansException {
		return applicationContext.getBean(name);
	}

	/**
	 * 获取类型为requiredType的对象
	 * 如果bean不能被类型转换,相应的异常将会被抛出(BeanNotOfRequiredTypeException)
	 * @param name       bean注册名
	 * @param requiredType 返回对象类型
	 * @return Object 返回requiredType类型对象
	 * @throws BeansException
	 */
	public static Object getBean(String name, Class requireType) throws BeansException{
		return applicationContext.getBean(name, requireType);
	}

	/**
	 * 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true
	 * @param name
	 * @return boolean
	 */
	public static boolean containsBean(String name){
		return applicationContext.containsBean(name);
	}

	/**
	 * 判断以给定名字注册的bean定义是一个singleton还是一个prototype。
	 * 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException)
	 * @param name
	 * @return boolean
	 * @throws NoSuchBeanDefinitionException
	 */
	public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
		return applicationContext.isSingleton(name);
	}

	/**
	 * @param name
	 * @return Class 注册对象的类型
	 * @throws NoSuchBeanDefinitionException
	 */
	public static Class getType(String name) throws NoSuchBeanDefinitionException {
		return applicationContext.getType(name);
	}

	/**
	 * 如果给定的bean名字在bean定义中有别名,则返回这些别名
	 * @param name
	 * @return
	 * @throws NoSuchBeanDefinitionException
	 */
	public static String[] getAliases(String name) throws NoSuchBeanDefinitionException {
		return applicationContext.getAliases(name);
	}

}

6.操作类型枚举类

public enum OperationType {
	/**
	 * 操作类型
	 */
	UNKNOWN("unknown"),
	DELETE("delete"),
	SELECT("select"),
	UPDATE("update"),
	INSERT("insert");

	private String value;

	public String getValue() {
		return value;
	}

	public void setValue(String value) {
		this.value = value;
	}

	OperationType(String s) {
		this.value = s;
	}
}

7.用户Model

import java.io.Serializable;

public class LogUser implements Serializable {
	
	private static final long serialVersionUID = -6520588712998125186L;

	private String userId;
	
	private String userName;
	
	private Object data;

	public String getUserId() {
		return userId;
	}

	public void setUserId(String userId) {
		this.userId = userId;
	}

	public String getUserName() {
		return userName;
	}

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

	public Object getData() {
		return data;
	}

	public void setData(Object data) {
		this.data = data;
	}

}

8.日志Model

import java.io.Serializable;
import java.util.Date;

import com.fasterxml.jackson.annotation.JsonFormat;

public class OperationLog implements Serializable {
	private static final long serialVersionUID = 5581824747183716437L;
	
	private String id;
	@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
    private Date createTime;
	/**
	 * ip地址
	 */
	private String ip;
    /**
     * 日志等级
     */
    private Integer logLevel;
    /**
     * 被操作的对象
     */
    private String operationUnit;
    /**
     * 方法名
     */
    private String method;
    /**
     * 参数
     */
    private String args;
    /**
     * 操作人id
     */
    private String userId;
    /**
     * 操作人
     */
    private String userName;
    /**
     * 日志描述
     */
    private String logDescribe;
    /**
     * 操作类型
     */
    private String operationType;
    /**
     * 方法运行时间
     */
    private Long runTime;
    /**
     * 方法返回值
     */
    private String returnValue;
    /**
     * 日志来源
     */
    private String source;
    
    private String result;
    
    private String errorInfo;
    
	public String getId() {
		return id;
	}


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


	public Date getCreateTime() {
		return createTime;
	}


	public void setCreateTime(Date createTime) {
		this.createTime = createTime;
	}


	public String getIp() {
		return ip;
	}


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


	public Integer getLogLevel() {
		return logLevel;
	}


	public void setLogLevel(Integer logLevel) {
		this.logLevel = logLevel;
	}


	public String getOperationUnit() {
		return operationUnit;
	}


	public void setOperationUnit(String operationUnit) {
		this.operationUnit = operationUnit;
	}


	public String getMethod() {
		return method;
	}


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


	public String getArgs() {
		return args;
	}


	public void setArgs(String args) {
		this.args = args;
	}


	public String getUserId() {
		return userId;
	}


	public void setUserId(String userId) {
		this.userId = userId;
	}


	public String getUserName() {
		return userName;
	}


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


	public String getLogDescribe() {
		return logDescribe;
	}


	public void setLogDescribe(String logDescribe) {
		this.logDescribe = logDescribe;
	}


	public String getOperationType() {
		return operationType;
	}


	public void setOperationType(String operationType) {
		this.operationType = operationType;
	}


	public Long getRunTime() {
		return runTime;
	}


	public void setRunTime(Long runTime) {
		this.runTime = runTime;
	}


	public String getReturnValue() {
		return returnValue;
	}


	public void setReturnValue(String returnValue) {
		this.returnValue = returnValue;
	}


	public String getSource() {
		return source;
	}


	public void setSource(String source) {
		this.source = source;
	}


	public String getResult() {
		return result;
	}


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


	public String getErrorInfo() {
		return errorInfo;
	}


	public void setErrorInfo(String errorInfo) {
		this.errorInfo = errorInfo;
	}


	@Override
	public String toString() {
		return "OperationLog [id=" + id + ", createTime=" + createTime + ", ip=" + ip + ", logLevel=" + logLevel
				+ ", operationUnit=" + operationUnit + ", method=" + method + ", args=" + args + ", userId=" + userId
				+ ", userName=" + userName + ", logDescribe=" + logDescribe + ", operationType=" + operationType
				+ ", runTime=" + runTime + ", returnValue=" + returnValue + ", source=" + source + ", result=" + result
				+ ", errorInfo=" + errorInfo + "]";
	}

}

9. 日志处理类

处理日志信息的入库操作,及列表查询详细查询方法。

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.domain.Sort.Order;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;

import com.xxxx.model.OperationLog;

public class SystemLogService {

	@Autowired
	private MongoTemplate mongoTemplate;
	/**
	 * 添加日志
	 * @param operationLog
	 * @throws Exception
	 */
	public void addLogInfo(OperationLog operationLog) throws Exception {
		mongoTemplate.save(operationLog);// 添加日志记录
	}

	/**
	 * 分页查询日志
	 * @param param
	 * @return
	 * @throws Exception
	 */
	public Map<String, Object> getOperationLogByMap(Map<String, Object> param) throws Exception {
		Map<String, Object> result = new HashMap<String, Object>();
		Criteria criteria = new Criteria();
		if(param.get("key") != null && !"".equals(param.get("key"))) {
			criteria.and("userId").in(param.get("key")).orOperator(criteria.and("userName").in(param.get("key")));
		}
		if(param.get("opType") != null && !"".equals(param.get("opType"))) {
			criteria.and("operationType").is(param.get("opType"));
		}
		if(param.get("source") != null && !"".equals(param.get("source"))) {
			criteria.and("source").is(param.get("source"));
		}
		Query query = new Query(criteria);
		long count = mongoTemplate.count(query, OperationLog.class);
		
		List<Order> orders = new ArrayList<Order>();  //排序
		if(!"".equals(param.get("sortField"))) {
			if("desc".equals(param.get("sortOrder").toString().toLowerCase())) {
				orders.add(new Order(Direction.DESC, param.get("sortField").toString()));
			} else {
				orders.add(new Order(Direction.ASC, param.get("sortField").toString()));
			}
		} 
		orders.add(new Order(Direction.DESC, "create_time"));
		Sort sort = Sort.by(orders);
		
		Object pageIndex = param.get("pageIndex");
		Integer pageStart = 0;
		Integer pageSize = 20;
		if(pageIndex != null) {
			pageStart = Integer.valueOf(pageIndex.toString());
			pageSize = Integer.valueOf(param.get("pageSize") == null ? "20" : param.get("pageSize").toString());
		}
		Pageable pageable = PageRequest.of(pageStart, pageSize, sort);
		List<OperationLog> list = mongoTemplate.find(query.with(pageable), OperationLog.class);
		result.put("total", count);
		result.put("data", list);
		return result;
	}
	/**
	 * 根据日志id查询日志详情
	 * @param id
	 * @return
	 * @throws Exception
	 */
	public OperationLog getOperationLogById(String id) throws Exception {
		if(null != id && !"".equals(id)) {
			return mongoTemplate.findById(id, OperationLog.class);
		}
		return null;
	}
	
}

10.Json工具类

import java.util.List;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;

public class JsonUtils {

	// 定义jackson对象
    private static final ObjectMapper MAPPER = new ObjectMapper();
 
    /**
     * 将对象转换成json字符串。
     * 

Title: pojoToJson

*

Description:

* @param data * @return */
public static String objectToJsonStr(Object data) { try { String string = MAPPER.writeValueAsString(data); return string; } catch (JsonProcessingException e) { e.printStackTrace(); } return null; } public static JSONObject objectToJson(Object data) { String jsonStr = objectToJsonStr(data); JSONObject jsonObject = JSONObject.parseObject(jsonStr); return jsonObject; } /** * 将json结果集转化为对象 * * @param jsonData json数据 * @param clazz 对象中的object类型 * @return */ public static <T> T jsonToPojo(String jsonData, Class<T> beanType) { try { T t = MAPPER.readValue(jsonData, beanType); return t; } catch (Exception e) { e.printStackTrace(); } return null; } /** * 将json数据转换成pojo对象list *

Title: jsonToList

*

Description:

* @param jsonData * @param beanType * @return */
public static <T>List<T> jsonToList(String jsonData, Class<T> beanType) { JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, beanType); try { List<T> list = MAPPER.readValue(jsonData, javaType); return list; } catch (Exception e) { e.printStackTrace(); } return null; } }

11.UUID工具类String

import java.util.UUID;

public class StringUtil {
	
	public static String getUUID(){
		return UUID.randomUUID().toString().replaceAll("-", "");
	}

}

你可能感兴趣的:(AOP,SpringBoot,annotation,aop,java,annotations)