springboot 实现记录业务日志和异常业务日志的操作

网友投稿 266 2022-10-09


springboot 实现记录业务日志和异常业务日志的操作

日志记录到redis展现形式

1.基于注解的方式实现日志记录,扫描对应的方法实现日志记录

@Inherited

@Retention(RetentionPolicy.RUNTIME)

@Target({ElementType.METHOD})

public @interface BussinessLog {

/**

* 业务的名称,例如:"修改菜单"

*/

String value() default "";

/**

* 被修改的实体的唯一标识,例如:菜单实体的唯一标识为"id"

*/

String key() default "id";

/**

* 业务类型

*/

String type() default "0";

/**

* 字典(用于查找key的中文名称和字段的中文名称)

*/

Class extends AbstractDictMap> dict() default SystemDict.class;

}

2.扫描的方法,基于注解实现方法扫描并且记录日志

3.基于@Aspect注解,实现日志扫描,并且记录日志

import org.aspectj.lang.ProceedingJoinPoint;

import org.aspectj.lang.Signature;

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.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

import java.util.Map;

/**

* 日志记录

*

*/

@Aspect

@Component

public class LogAop {

private Logger log = LoggerFactory.getLogger(this.getClass());

@Pointcut(value = "@annotation(com.stylefeng.guns.core.common.annotion.BussinessLog)")

public void cutService() {

}

@Around("cutService()")

public Object recordSysLog(ProceedingJoinPoint point) throws Throwable {

//先执行业务

Object result = point.proceed();

try {

handle(point);

} catch (Exception e) {

log.error("日志记录出错!", e);

}

return result;

}

private void handle(ProceedingJoinPoint point) throws Exception {

//获取拦截的方法名

Signature sig = point.getSignature();

MethodSignature msig = null;

if (!(sig instanceof MethodSignature)) {

throw new IllegalArgumentException("该注解只能用于方法");

}

msig = (MethodSignature) sig;

Object target = point.getTarget();

Method currentMethod = target.getClass().getMethod(msig.getName(), msig.getParameterTypes());

String methodName = currentMethod.getName();

//如果当前用户未登录,不做日志

ShiroUser user = ShiroKit.getUser();

if (null == user) {

return;

}

//获取拦截方法的参数

String className = point.getTarget().getClass().getName();

Object[] params = point.getArgs();

//获取操作名称

BussinessLog annotation = currentMethod.getAnnotation(BussinessLog.class);

String bussinessName = annotation.value();

String key = annotation.key();

Class dictClass = annotation.dict();

StringBuilder sb = new StringBuilder();

for (Object param : params) {

sb.append(param);

sb.append(" & ");

}

//如果涉及到修改,比对变化

String msg;

if (bussinessName.contains("修改") || bussinessName.contains("编辑")) {

Object obj1 = LogObjectHolder.me().get();

Map obj2 = HttpContext.getRequestParameters();

msg = Contrast.contrastObj(dictClass, key, obj1, obj2);

} else {

Map parameters = HttpContext.getRequestParameters();

AbstractDictMap dictMap = (AbstractDictMap) dictClass.newInstance();

msg = Contrast.parseMutiKey(dictMap, key, parameters);

}

log.info("[记录日志][RESULT:{}]",user.getId()+bussinessName+className+methodName+msg.toString());

LogManager.me().executeLog(LogTaskFactory.bussinessLog(user.getId(), bussinessName, className, methodName, msg));

}

}

4.比较两个对象的工具类

import java.beans.PropertyDescriptor;

import java.lang.reflect.Field;

import java.lang.reflect.Method;

import java.util.Date;

import java.util.Map;

/**

* 对比两个对象的变化的工具类

*

* @author ...

* @Date 2017/3/31 10:36

*/

public class Contrast {

//记录每个修改字段的分隔符

public static final String separator = ";;;";

/**

* 比较两个对象,并返回不一致的信息

*

* @author ...

* @Date 2017/5/9 19:34

*/

public static String contrastObj(Object pojo1, Object pojo2) {

String str = "";

try {

Class clazz = pojo1.getClass();

Field[] fields = pojo1.getClass().getDeclaredFields();

int i = 1;

for (Field field : fields) {

if ("serialVersionUID".equals(field.getName())) {

continue;

}

PropertyDescriptor pd = new PropertyDescriptor(field.getName(), clazz);

Method getMethod = pd.getReadMethod();

Object o1 = getMethod.invoke(pojo1);

Object o2 = getMethod.invoke(pojo2);

if (o1 == null || o2 == null) {

continue;

}

if (o1 instanceof Date) {

o1 = DateUtil.getDay((Date) o1);

}

if (!o1.toString().equals(o2.toString())) {

if (i != 1) {

str += separator;

}

str += "字段名称" + field.getName() + ",旧值:" + o1 + ",新值:" + o2;

i++;

}

}

} catch (Exception e) {

e.printStackTrace();

}

return str;

}

/**

* 比较两个对象pojo1和pojo2,并输出不一致信息

*

* @author ...

* @Date 2017/5/9 19:34

*/

public static String contrastObj(Class dictClass, String key, Object pojo1, Map pojo2) throws IllegalAccessException, InstantiationException {

AbstractDictMap dictMap = (AbstractDictMap) dictClass.newInstance();

String str = parseMutiKey(dictMap, key, pojo2) + separator;

try {

Class clazz = pojo1.getClass();

Field[] fields = pojo1.getClass().getDeclaredFields();

int i = 1;

for (Field field : fields) {

if ("serialVersionUID".equals(field.getName())) {

continue;

}

PropertyDescriptor pd = new PropertyDescriptor(field.getName(), clazz);

Method getMethod = pd.getReadMethod();

Object o1 = getMethod.invoke(pojo1);

Object o2 = pojo2.get(StrKit.firstCharToLowerCase(getMethod.getName().substring(3)));

if (o1 == null || o2 == null) {

continue;

}

if (o1 instanceof Date) {

o1 = DateUtil.getDay((Date) o1);

} else if (o1 instanceof Integer) {

o2 = Integer.parseInt(o2.toString());

}

if (!o1.toString().equals(o2.toString())) {

if (i != 1) {

str += separator;

}

String fieldName = dictMap.get(field.getName());

String fieldWarpperMethodName = dictMap.getFieldWarpperMethodName(field.getName());

if (fieldWarpperMethodName != null) {

Object o1Warpper = DictFieldWarpperFactory.createFieldWarpper(o1, fieldWarpperMethodName);

Object o2Warpper = DictFieldWarpperFactory.createFieldWarpper(o2, fieldWarpperMethodName);

str += "字段名称:" + fieldName + ",旧值:" + o1Warpper + ",新值:" + o2Warpper;

} else {

str += "字段名称:" + fieldName + ",旧值:" + o1 + ",新值:" + o2;

}

i++;

}

}

} catch (Exception e) {

e.printStackTrace();

}

return str;

}

/**

* 比较两个对象pojo1和pojo2,并输出不一致信息

*

* @author ...

* @Date 2017/5/9 19:34

*/

public static String contrastObjByName(Class dictClass, String key, Object pojo1, Map pojo2) throws IllegalAccessException, InstantiationException {

AbstractDictMap dictMap = (AbstractDictMap) dictClass.newInstance();

String str = parseMutiKey(dictMap, key, pojo2) + separator;

try {

Class clazz = pojo1.getClass();

Field[] fields = pojo1.getClass().getDeclaredFields();

int i = 1;

for (Field field : fields) {

if ("serialVersionUID".equals(field.getName())) {

continue;

}

String prefix = "get";

int prefixLength = 3;

if (field.getType().getName().equals("java.lang.Boolean")) {

prefix = "is";

prefixLength = 2;

}

Method getMethod = null;

try {

getMethod = clazz.getDeclaredMethod(prefix + StrKit.firstCharToUpperCase(field.getName()));

} catch (NoSuchMethodException e) {

System.err.println("this className:" + clazz.getName() + " is not methodName: " + e.getMessage());

continue;

}

Object o1 = getMethod.invoke(pojo1);

Object o2 = pojo2.get(StrKit.firstCharToLowerCase(getMethod.getName().substring(prefixLength)));

if (o1 == null || o2 == null) {

continue;

}

if (o1 instanceof Date) {

o1 = DateUtil.getDay((Date) o1);

} else if (o1 instanceof Integer) {

o2 = Integer.parseInt(o2.toString());

}

if (!o1.toString().equals(o2.toString())) {

if (i != 1) {

str += separator;

}

String fieldName = dictMap.get(field.getName());

String fieldWarpperMethodName = dictMap.getFieldWarpperMethodName(field.getName());

if (fieldWarpperMethodName != null) {

Object o1Warpper = DictFieldWarpperFactory.createFieldWarpper(o1, fieldWarpperMethodName);

Object o2Warpper = DictFieldWarpperFactory.createFieldWarpper(o2, fieldWarpperMethodName);

str += "字段名称:" + fieldName + ",旧值:" + o1Warpper + ",新值:" + o2Warpper;

} else {

str += "字段名称:" + fieldName + ",旧值:" + o1 + ",新值:" + o2;

}

i++;

}

}

} catch (Exception e) {

e.printStackTrace();

}

return str;

}

/**

* 解析多个key(逗号隔开的)

*

* @author ...

* @Date 2017/5/16 22:19

*/

public static String parseMutiKey(AbstractDictMap dictMap, String key, Map requests) {

StringBuilder sb = new StringBuilder();

if (key.indexOf(",") != -1) {

String[] keys = key.split(",");

for (String item : keys) {

String fieldWarpperMethodName = dictMap.getFieldWarpperMethodName(item);

String value = requests.get(item);

if (fieldWarpperMethodName != null) {

Object valueWarpper = DictFieldWarpperFactory.createFieldWarpper(value, fieldWarpperMethodName);

sb.append(dictMap.get(item) + "=" + valueWarpper + ",");

} else {

sb.append(dictMap.get(item) + "=" + value + ",");

}

}

return StrKit.removeSuffix(sb.toString(), ",");

} else {

String fieldWarpperMethodName = dictMap.getFieldWarpperMethodName(key);

String value = requests.get(key);

if (fieldWarpperMethodName != null) {

Object valueWarpper = DictFieldWarpperFactory.createFieldWarpper(value, fieldWarpperMethodName);

sb.append(dictMap.get(key) + "=" + valueWarpper);

} else {

sb.append(dictMap.get(key) + "=" + value);

}

return sb.toString();

}

}

}

5.根据输入方法获取数据字典的数据

import java.lang.reflect.Method;

public class DictFieldWarpperFactory {

public static Object createFieldWarpper(Object parameter, String methodName) {

IConstantFactory constantFactory = ConstantFactory.me();

try {

Method method = IConstantFactory.class.getMethod(methodName, parameter.getClass());

return method.invoke(constantFactory, parameter);

} catch (Exception e) {

try {

Method method = IConstantFactory.class.getMethod(methodName, Integer.class);

return method.invoke(constantFactory, Integer.parseInt(parameter.toString()));

} catch (Exception e1) {

throw new RuntimeException("BizExceptionEnum.ERROR_WRAPPER_FIELD");

}

}

}

}

6.对应获取数据字典的方法

public interface IConstantFactory {

/**

* 获取状态

*/

String getWordStatus(Integer DATA_STATUS);

}

import com.qihoinfo.dev.log.util.SpringContextHolder;

import org.anyJtbuQline.service.AnylineService;

import org.springframework.context.annotation.DependsOn;

import org.springframework.stereotype.Component;

@Component

@DependsOn("springContextHolder")

public class ConstantFactory implements IConstantFactory {

private AnylineService anylineService = SpringContextHolder.getBean(AnylineService.class);

public static IConstantFactory me() {

return SpringContextHolder.getBean("constantFactory");

}

@Override

public String getWordStatus(Integer DATA_STATUS) {

if ("1".equals(DATA_STATUS.toString())) {

return "启用";

} else {

return "停用";

}

}

}

7.spring根据方法名获取对应容器中的对象

import org.springframework.beans.BeansException;

import org.springframework.context.ApplicationContext;

import org.springframework.context.ApplicationContextAware;

import org.springframework.stereotype.Component;

/**

* Spring的ApplicationContext的持有者,可以用静态方法的方式获取spring容器中的bean

*/

@Component

public class SpringContextHolder implements ApplicationContextAware {

private static ApplicationContext applicationContext;

@Override

public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

SpringContextHolder.applicationContext = applicationContext;

}

public static ApplicationContext getApplicationContext() {

assertApplicationContext();

return applicationContext;

}

@SuppressWarnings("unchecked")

public static T getBean(String beanName) {

assertApplicationContext();

return (TJtbuQ) applicationContext.getBean(beanName);

}

public static T getBean(Class requiredType) {

assertApplicationContext();

return applicationContext.getBean(requiredType);

}

private static void assertApplicationContext() {

if (SpringContextHolder.applicationContext == null) {

throw new RuntimeException("applicaitonContext属性为null,请检查是否注入了SpringContextHolder!");

}

}

}

8.字符串工具类

/**

* 字符串工具类

*/

public class StrKit {

/**

* 首字母变小写

*/

public static String firstCharToLowerCase(String str) {

char firstChar = str.charAt(0);

if (firstChar >= 'A' && firstChar <= 'Z') {

char[] arr = str.toCharArray();

arr[0] += ('a' - 'A');

return new String(arr);

}

return str;

}

/**

* 首字母变大写

*/

public static String firstCharToUpperCase(String str) {

char firstChar = str.charAt(0);

if (firstChar >= 'a' && firstChar <= 'z') {

char[] arr = str.toCharArray();

arr[0] -= ('a' - 'A');

return new String(arr);

}

return str;

}

/**

* 去掉指定后缀

*/

public static String removeSuffix(String str, String suffix) {

if (isEmpty(str) || isEmpty(suffix)) {

return str;

}

if (str.endsWith(suffix)) {

return str.substring(0, str.length() - suffix.length());

}

return str;

}

/**

* 字符串是否为空,空的定义如下 1、为null

* 2、为""

*/

public static boolean isEmpty(String str) {

return str == null || str.length() == 0;

}

}

import java.io.IOException;

import java.io.PrintWriter;

import java.io.StringWriter;

public class ToolUtil {

public static final int SALT_LENGTH = 6;

public ToolUtil() {

}

public static String getExceptionMsg(Throwable e) {

StringWriter sw = new StringWriter();

try {

e.printStackTrace(new PrintWriter(sw));

} finally {

try {

sw.close();

} catch (IOException var8) {

var8.printStackTrace();

}

}

return sw.getBuffer().toString().replaceAll("\\$", "T");

}

}

9.获取数据字典的类

import java.util.HashMap;

public abstract class AbstractDictMap {

protected HashMap dictory = new HashMap<>();

protected HashMap fieldWarpperDictory = new HashMap<>();

public AbstractDictMap() {

put("ID", "主键ID");

init();

initBeWrapped();

}

public abstract void init();

protected abstract void initBeWrapped();

public String get(String key) {

return this.dictory.get(key);

}

public void put(String key, String value) {

this.dictory.put(key, value);

}

public String getFieldWarpperMethodName(String key) {

return this.fieldWarpperDictory.get(key);

}

public void putFieldWrapperMethodName(String key, String methodName) {

this.fieldWarpperDictory.put(key, methodName);

}

}

public class SystemDict extends AbstractDictMap {

@Override

public void init() {

}

@Override

protected void initBeWrapped() {

}

}

public class WordMap extends AbstractDictMap {

@Override

public void init() {

put("EN", "英文");

put("CN", "中文");

put("SHORT", "简称");

put("REMARK", "备注");

put("DATA_STATUS", "状态");

}

@Override

protected void initBeWrapped() {

putFieldWrapperMethodName("DATA_STATUS","getWordStatusJtbuQ");

}

}

10.获取缓存对象的bean

import org.springframework.context.annotation.Scope;

import org.springframework.stereotype.Component;

import org.springframework.web.context.WebApplicationContext;

import java.io.Serializable;

@Component

@Scope(scopeName = WebApplicationContext.SCOPE_SESSION)

public class LogObjectHolder implements Serializable{

private Object object = null;

public void set(Object obj) {

this.object = obj;

}

public Object get() {

return object;

}

public static LogObjectHolder me(){

LogObjectHolder bean = SpringContextHolder.getBean(LogObjectHolder.class);

return bean;

}

}

11.运行时异常的获取

@ControllerAdvice

public class GlobalExceptionHandler extends BasicMemberjsONController {

private Logger log = LoggerFactory.getLogger(this.getClass());

@ExceptionHandler(RuntimeException.class)

@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)

@ResponseBody

public String notFount(RuntimeException e) {

String userName = curManage().get("USERNAME").toString();

LogManager.me().executeLog(LogTaskFactory.exceptionLog(userName, e));

log.error("运行时异常:", e);

return fail();

}

}

12.使用线程池创建操作日志

import java.util.Date;

public class LogFactory {

/**

* 创建操作日志

*/

public static DataRow createOperationLog(LogType logType, String userName, String bussinessName, String clazzName, String methodName, String msg, LogSucceed succeed) {

DataRow operationLog = new DataRow();

operationLog.put("log_type", logType.getMessage());

operationLog.put("USER_NAME", userName);

operationLog.put("log_name", bussinessName);

operationLog.put("CLASS_NAME", clazzName);

operationLog.put("METHOD", methodName);

operationLog.put("CREATE_TIME", new Date());

operationLog.put("SUCCEED", succeed.getMessage());

if (msg.length() > 800) {

msg = msg.substring(0, 800);

operationLog.put("MESSAGE", msg);

} else {

operationLog.put("MESSAGE", msg);

}

return operationLog;

}

}

import java.util.TimerTask;

import java.util.concurrent.ScheduledThreadPoolExecutor;

import java.util.concurrent.TimeUnit;

public class LogManager {

//日志记录操作延时

private final int OPERATE_DELAY_TIME = 10;

//异步操作记录日志的线程池

private ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(10);

private LogManager() {

}

public static LogManager logManager = new LogManager();

public static LogManager me() {

return logManager;

}

public void executeLog(TimerTask task) {

executor.schedule(task, OPERATE_DELAY_TIME, TimeUnit.MILLISECONDS);

}

}

public enum LogSucceed {

SUCCESS("成功"),

FAIL("失败");

String message;

LogSucceed(String message) {

this.message = message;

}

public String getMessage() {

return message;

}

public void setMessage(String message) {

this.message = message;

}

}

import com.qihoinfo.dev.log.annotation.RedisDb;

import com.qihoinfo.dev.log.util.ToolUtil;

import org.anyline.entity.DataRow;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.context.annotation.DependsOn;

import org.springframework.data.redis.core.StringRedisTemplate;

import org.springframework.stereotype.Component;

import java.util.TimerTask;

@Component

@DependsOn("springContextHolder")

public class LogTaskFactory {

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

private static StringRedisTemplate redisTemplate = RedisDb.getMapper(StringRedisTemplate.class);

public static TimerTask bussinessLog(final String userName, final String bussinessName, final String clazzName, final String methodName, final String msg) {

return new TimerTask() {

@Override

public void run() {

DataRow operationLog = LogFactory.createOperationLog(

LogType.BUSSINESS, userName, bussinessName, clazzName, methodName, msg, LogSucceed.SUCCESS);

try {

redisTemplate.opsForList().rightPush("sys_operation_log", operationLog.getJson());

} catch (Exception e) {

logger.error("创建业务日志异常!", e);

}

}

};

}

public static TimerTask exceptionLog(final String userName, final Exception exception) {

return new TimerTask() {

@Override

public void run() {

String msg = ToolUtil.getExceptionMsg(exception);

DataRow operationLog = LogFactory.createOperationLog(

LogType.EXCEPTION, userName, "", null, null, msg, LogSucceed.FAIL);

try {

redisTemplate.opsForList().rightPush("sys_operation_log", operationLog.getJson());

} catch (Exception e) {

logger.error("创建异常日志异常!", e);

}

}

};

}

}

public enum LogType {

EXCEPTION("异常日志"),

BUSSINESS("业务日志");

String message;

LogType(String message) {

this.message = message;

}

public String getMessage() {

return message;

}

public void setMessage(String message) {

this.message = message;

}

}

13.将日志记录到redis数据库

package com.qihoinfo.dev.log.annotation;

import com.qihoinfo.dev.log.util.SpringContextHolder;

import org.springframework.data.redis.core.StringRedisTemplate;

public class RedisDb {

private Class clazz;

private StringRedisTemplate baseMapper;

private RedisDb(Class clazz) {

this.clazz = clazz;

this.baseMapper = (StringRedisTemplate) SpringContextHolder.getBean(clazz);

}

public static RedisDb create(Class clazz) {

return new RedisDb(clazz);

}

public StringRedisTemplate getMapper() {

return this.baseMapper;

}

public static T getMapper(Class clazz) {

return SpringContextHolder.getBean(clazz);

}

}

import org.springframework.web.context.request.RequestContextHolder;

import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import java.util.Enumeration;

import java.util.HashMap;

import java.util.Map;

/**

* @Description:

* @Auther: wj

* @Date: 2019/5/28 13:56

*/

public class HttpContext {

public HttpContext() {

}

public static String getIp() {

HttpServletRequest request = getRequest();

return request == null ? "127.0.0.1" : request.getRemoteHost();

}

public static HttpServletRequest getRequest() {

ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

return requestAttributes == null ? null : requestAttributes.getRequest();

}

public static HttpServletResponse getResponse() {

ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

return requestAttributes == null ? null : requestAttributes.getResponse();

}

public static Map getRequestParameters() {

HashMap values = new HashMap();

HttpServletRequest request = getRequest();

if (request == null) {

return values;

} else {

Enumeration enums = request.getParameterNames();

while (enums.hasMoreElements()) {

String paramName = (String) enums.nextElement();

String paramValue = request.getParameter(paramName);

values.put(paramName, paramValue);

}

return values;

}

}

}


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:HTTP协议(9)Python requests模块的使用
下一篇:第二十三章 SHELL脚本-CENTOS7.5知识
相关文章

 发表评论

暂时没有评论,来抢沙发吧~