SpringBoot使用AOP方式记录日志入库

admin 1753 2025-10-08 02:14:09

大概流程

先设计系统操作日志表结构,代码中实现日志实体类和mapper层,

然后自定义日志注解,提取主要属性作为注解属性,例如,操作行为:注册用户 操作类型:新增 ;

定义日志注解的切面类,是处理日志入库的逻辑实现;最后使用注解测试效果。

以最近项目作为简单示例实现这个功能 为保持代码原汁原味,将繁琐的工具类也贴上,

自己作取舍 ,多余就删掉,少了自己想法填 ,各自的系统数据结构不同,需要根据现有逻辑修改 如果代码不全 可以留言 我来补全

项目背景

Springboot 2.5.8 tkMybatis mysql 8.X

0.导入使用到的依赖

org.springframework.boot

spring-boot-starter-aop

1.设计日志表 日志实体类代码

import java.util.Date;

import javax.persistence.*;

import lombok.Getter;

import lombok.Setter;

import lombok.ToString;

@Getter

@Setter

@ToString

@Table(name = "log_user_operate")

public class LogUserOperate {

@Id

@Column(name = "id")

@GeneratedValue(generator = "JDBC")

private Integer id;

/**

* 模块标题

*/

@Column(name = "title")

private String title;

/**

* 业务类型(0其它 1新增 2修改 3删除)

*/

@Column(name = "business_type")

private Integer businessType;

/**

* 方法名称

*/

@Column(name = "`method`")

private String method;

/**

* 操作人

*/

@Column(name = "operate_user")

private String operateUser;

/**

* 操作人姓名

*/

@Column(name = "operate_name")

private String operateName;

/**

* 部门名称

*/

@Column(name = "dept_name")

private String deptName;

/**

* 操作时间

*/

@Column(name = "operate_time")

private Date operateTime;

/**

* 请求URL

*/

@Column(name = "oper_url")

private String operUrl;

/**

* 主机地址

*/

@Column(name = "oper_ip")

private String operIp;

/**

* 请求方式

*/

@Column(name = "request_method")

private String requestMethod;

/**

* 请求参数

*/

@Column(name = "oper_param")

private String operParam;

/**

* 返回结果

*/

@Column(name = "return_value")

private String returnValue;

/**

* 文字描述

*/

@Column(name = "`operation`")

private String operation;

/**

* 操作状态(0正常 1异常)

*/

@Column(name = "`status`")

private Integer status = 0;

/**

* 失败原因

*/

@Column(name = "error_msg")

private String errorMsg;

/**

* 系统名称

*/

@Column(name = "sys_name")

private String sysName = "Device_Manage";

/**

* 响应用时ms

*/

@Column(name = "cost_time")

private Long costTime;

}

2.Mapper持久层

Mapper持久层 插入日志需要调用持久层中的insert方法,将日志记录插入到数据库中。

import com.fri.device_management.model.LogUserOperate;

import tk.mybatis.mapper.common.Mapper;

public interface LogUserOperateMapper extends Mapper {

}

3.自定义日志注解 Log注解的作用仅用于标识

注解的类型是@interface,就是在interface之前加了个@。

添加@Retention(RetentionPolicy.RUNTIME)指定注解运行时生效。

添加@Target(ElementType.METHOD)指定注解作用在方法上。

【其中businessType 使用了枚举类 也可以直接使用123这样的数值】

import com.fri.device_management.common.log.enums.BusinessType;

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

/**

* 自定义操作日志记录注解

* 注解的属性值 就是在使用注解时 可以传的参数

*/

@Target({ ElementType.PARAMETER, ElementType.METHOD })

@Retention(RetentionPolicy.RUNTIME)

public @interface UserLog {

/**

* 模块

*/

public String title() default "";

/**

* 功能

*/

public BusinessType businessType() default BusinessType.OTHER;

/**

* 是否保存请求的参数

*/

public boolean isSaveRequestData() default true;

}

3.1我这边使用到的枚举类 业务操作类型

/**

* 业务操作类型

*

*

*/

public enum BusinessType

{

/**

* 其它

*/

OTHER,

/**

* 新增

*/

INSERT,

/**

* 修改

*/

UPDATE,

/**

* 查询

*/

QUERY,

/**

* 删除

*/

DELETE,

/**

* 授权

*/

GRANT,

/**

* 导出

*/

EXPORT,

/**

* 导入

*/

IMPORT,

/**

* 强退

*/

FORCE,

/**

* 生成代码

*/

GENCODE,

/**

* 清空数据

*/

CLEAN,

}

3.2我这边使用到的枚举类 操作状态类型

/**

* 操作状态

*/

public enum BusinessStatus

{

/**

* 成功

*/

SUCCESS,

/**

* 失败

*/

FAIL,

}

4.切入面处理逻辑 这里是重点 通读这块代码 自己想怎么实现都成

如果不需要记录那么多信息 就用不到这些工具类 其中获取当前登录用户信息,返回数据结果需要根据自己的项目中适配

import com.alibaba.fastjson.JSON;

import com.alibaba.fastjson.JSONObject;

import com.fri.device_management.common.log.annotation.UserLog;

import com.fri.device_management.common.log.enums.BusinessStatus;

import com.fri.device_management.common.utils.IpUtils;

import com.fri.device_management.common.utils.ServletUtils;

import com.fri.device_management.common.utils.StringUtils;

import com.fri.device_management.mapper.LogUserOperateMapper;

import com.fri.device_management.mapper.UserMapper;

import com.fri.device_management.model.LogUserOperate;

import com.fri.device_management.model.User;

import lombok.extern.slf4j.Slf4j;

import org.aspectj.lang.JoinPoint;

import org.aspectj.lang.ProceedingJoinPoint;

import org.aspectj.lang.Signature;

import org.aspectj.lang.annotation.AfterReturning;

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.http.HttpMethod;

import org.springframework.stereotype.Component;

import org.springframework.web.multipart.MultipartFile;

import org.springframework.web.servlet.HandlerMapping;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import java.lang.reflect.Method;

import java.util.Arrays;

import java.util.Map;

/**

*

* 切面类

* 操作日志记录处理详细罗杰

*

* 一个切面 对应一个 注解标记切入点

*

* 连接点:JoinPoint,可以被AOP控制的方法(暗含方法执行时的相关信息)

* 通知:Advice,指哪些重复的逻辑,也就是共性功能(最终体现为一个方法)

* 切入点:PointCut,匹配连接点的条件,通知仅会在切入点方法执行时被应用

* 切面:Aspect,描述通知与切入点的对应关系(通知+切入点)

* 目标对象:Target,通知所应用的对象

*

*

*/

@Aspect

@Component

@Slf4j

public class UserLogAspect {

@Autowired

private HttpServletRequest request;

// 日志入库的mapper

@Autowired

private LogUserOperateMapper logUserOperateMapper;

// 通过请求内的信息,获取当前登录用户的个人信息 补充日志的内容

@Autowired

private UserMapper userMapper;

/**

* 配置切入点 自定义注解的包路径

*/

@Pointcut("@annotation(com.fri.device_management.common.log.annotation.UserLog)")

public void logPointCut()

{

}

/**

* 处理完请求后执行

*

* @param proceedingJoinPoint 切点

*/

@AfterReturning(pointcut = "logPointCut()", returning = "jsonResult")

public void doAfterReturning(JoinPoint proceedingJoinPoint, Object jsonResult)

{

handleLog(proceedingJoinPoint, null, jsonResult);

}

protected void handleLog(final JoinPoint joinPoint, final Exception e, Object jsonResult)

{

try

{

// 获得注解

UserLog controllerLog = getAnnotationLog(joinPoint);

if (controllerLog == null)

{

return;

}

// 获取当前的登录用户

String token = request.getHeader("Authorization");

User loginUser = userMapper.selectByToken(token);

// *========数据库日志=========*//

// SysOperLog operLog = new SysOperLog();

LogUserOperate operateLog = new LogUserOperate();

operateLog.setSysName("Device-Manage");

operateLog.setStatus(BusinessStatus.SUCCESS.ordinal());

operateLog.setDeptName(loginUser.getDepartmentName());

operateLog.setOperateName(loginUser.getRealName());

// 请求的地址

String ip = IpUtils.getIpAddr(ServletUtils.getRequest());

operateLog.setOperIp(ip);

// 返回参数

operateLog.setReturnValue(JSON.toJSONString(jsonResult));

operateLog.setOperUrl(ServletUtils.getRequest().getRequestURI());

if (e != null)

{

operateLog.setStatus(BusinessStatus.FAIL.ordinal());

operateLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000));

}

// 设置方法名称

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

String methodName = joinPoint.getSignature().getName();

operateLog.setMethod(className + "." + methodName + "()");

// 设置请求方式

operateLog.setRequestMethod(ServletUtils.getRequest().getMethod());

// 处理设置注解上的参数

getControllerMethodDescription(joinPoint, controllerLog, operateLog);

// 保存数据库

logUserOperateMapper.insertSelective(operateLog);

}

catch (Exception exp)

{

// 记录本地异常日志

log.error("==前置通知异常==");

log.error("异常信息:{}", exp.getMessage());

exp.printStackTrace();

}

}

/**

* 获取注解中对方法的描述信息 用于Controller层注解

*

* @param log 日志

* @param operLog 操作日志

* @throws Exception

*/

public void getControllerMethodDescription(JoinPoint joinPoint, UserLog log, LogUserOperate operLog) throws Exception

{

// 设置action动作

operLog.setBusinessType(log.businessType().ordinal());

// 设置标题

operLog.setTitle(log.title());

// 是否需要保存request,参数和值

if (log.isSaveRequestData())

{

// 获取参数的信息,传入到数据库中。

setRequestValue(joinPoint, operLog);

}

}

/**

* 获取请求的参数,放到log中

*

* @param operLog 操作日志

* @throws Exception 异常

*/

private void setRequestValue(JoinPoint joinPoint, LogUserOperate operLog) throws Exception

{

String requestMethod = operLog.getRequestMethod();

if (HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod))

{

String params = argsArrayToString(joinPoint.getArgs());

operLog.setOperParam(StringUtils.substring(params, 0, 2000));

}

else

{

Map paramsMap = (Map) ServletUtils.getRequest().getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);

operLog.setOperParam(StringUtils.substring(paramsMap.toString(), 0, 2000));

}

}

/**

* 是否存在注解,如果存在就获取

*/

private UserLog getAnnotationLog(JoinPoint joinPoint) throws Exception

{

Signature signature = joinPoint.getSignature();

MethodSignature methodSignature = (MethodSignature) signature;

Method method = methodSignature.getMethod();

if (method != null)

{

return method.getAnnotation(UserLog.class);

}

return null;

}

/**

* 参数拼装

*/

private String argsArrayToString(Object[] paramsArray)

{

String params = "";

if (paramsArray != null && paramsArray.length > 0)

{

for (int i = 0; i < paramsArray.length; i++)

{

if (!isFilterObject(paramsArray[i]))

{

Object jsonObj = JSON.toJSON(paramsArray[i]);

params += jsonObj.toString() + " ";

}

}

}

return params.trim();

}

/**

* 判断是否需要过滤的对象。

*

* @param o 对象信息。

* @return 如果是需要过滤的对象,则返回true;否则返回false。

*/

public boolean isFilterObject(final Object o)

{

return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse;

}

}

4.1用到的工具类IpUtils

import org.springframework.util.StringUtils;

import java.net.InetAddress;

import java.net.UnknownHostException;

import javax.servlet.http.HttpServletRequest;

/**

* 获取IP方法

*

*

*/

public class IpUtils

{

public static String getIpAddr(HttpServletRequest request)

{

if (request == null)

{

return "unknown";

}

String ip = request.getHeader("x-forwarded-for");

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("X-Forwarded-For");

}

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("X-Real-IP");

}

if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))

{

ip = request.getRemoteAddr();

}

return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;

}

public static boolean internalIp(String ip)

{

byte[] addr = textToNumericFormatV4(ip);

return internalIp(addr) || "127.0.0.1".equals(ip);

}

private static boolean internalIp(byte[] addr)

{

if (addr == null || addr.length < 2)

{

return true;

}

final byte b0 = addr[0];

final byte b1 = addr[1];

// 10.x.x.x/8

final byte SECTION_1 = 0x0A;

// 172.16.x.x/12

final byte SECTION_2 = (byte) 0xAC;

final byte SECTION_3 = (byte) 0x10;

final byte SECTION_4 = (byte) 0x1F;

// 192.168.x.x/16

final byte SECTION_5 = (byte) 0xC0;

final byte SECTION_6 = (byte) 0xA8;

switch (b0)

{

case SECTION_1:

return true;

case SECTION_2:

if (b1 >= SECTION_3 && b1 <= SECTION_4)

{

return true;

}

case SECTION_5:

switch (b1)

{

case SECTION_6:

return true;

}

default:

return false;

}

}

/**

* 将IPv4地址转换成字节

*

* @param text IPv4地址

* @return byte 字节

*/

public static byte[] textToNumericFormatV4(String text)

{

if (text.length() == 0)

{

return null;

}

byte[] bytes = new byte[4];

String[] elements = text.split("\\.", -1);

try

{

long l;

int i;

switch (elements.length)

{

case 1:

l = Long.parseLong(elements[0]);

if ((l < 0L) || (l > 4294967295L))

return null;

bytes[0] = (byte) (int) (l >> 24 & 0xFF);

bytes[1] = (byte) (int) ((l & 0xFFFFFF) >> 16 & 0xFF);

bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);

bytes[3] = (byte) (int) (l & 0xFF);

break;

case 2:

l = Integer.parseInt(elements[0]);

if ((l < 0L) || (l > 255L))

return null;

bytes[0] = (byte) (int) (l & 0xFF);

l = Integer.parseInt(elements[1]);

if ((l < 0L) || (l > 16777215L))

return null;

bytes[1] = (byte) (int) (l >> 16 & 0xFF);

bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);

bytes[3] = (byte) (int) (l & 0xFF);

break;

case 3:

for (i = 0; i < 2; ++i)

{

l = Integer.parseInt(elements[i]);

if ((l < 0L) || (l > 255L))

return null;

bytes[i] = (byte) (int) (l & 0xFF);

}

l = Integer.parseInt(elements[2]);

if ((l < 0L) || (l > 65535L))

return null;

bytes[2] = (byte) (int) (l >> 8 & 0xFF);

bytes[3] = (byte) (int) (l & 0xFF);

break;

case 4:

for (i = 0; i < 4; ++i)

{

l = Integer.parseInt(elements[i]);

if ((l < 0L) || (l > 255L))

return null;

bytes[i] = (byte) (int) (l & 0xFF);

}

break;

default:

return null;

}

}

catch (NumberFormatException e)

{

return null;

}

return bytes;

}

public static String getHostIp()

{

try

{

return InetAddress.getLocalHost().getHostAddress();

}

catch (UnknownHostException e)

{

}

return "127.0.0.1";

}

public static String getHostName()

{

try

{

return InetAddress.getLocalHost().getHostName();

}

catch (UnknownHostException e)

{

}

return "未知";

}

}

4.2 用到的工具类ServletUtils

import java.io.IOException;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import javax.servlet.http.HttpSession;

import cn.hutool.core.convert.Convert;

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

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

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

/**

* 客户端工具类

*

*

*/

public class ServletUtils {

/**

* 获取String参数

*/

public static String getParameter(String name) {

return getRequest().getParameter(name);

}

/**

* 获取String参数

*/

public static String getParameter(String name, String defaultValue) {

return Convert.toStr(getRequest().getParameter(name), defaultValue);

}

/**

* 获取Integer参数

*/

public static Integer getParameterToInt(String name) {

return Convert.toInt(getRequest().getParameter(name));

}

/**

* 获取Integer参数

*/

public static Integer getParameterToInt(String name, Integer defaultValue) {

return Convert.toInt(getRequest().getParameter(name), defaultValue);

}

/**

* 获取request

*/

public static HttpServletRequest getRequest() {

return getRequestAttributes().getRequest();

}

/**

* 获取response

*/

public static HttpServletResponse getResponse() {

return getRequestAttributes().getResponse();

}

/**

* 获取session

*/

public static HttpSession getSession() {

return getRequest().getSession();

}

public static ServletRequestAttributes getRequestAttributes() {

RequestAttributes attributes = RequestContextHolder.getRequestAttributes();

return (ServletRequestAttributes) attributes;

}

/**

* 将字符串渲染到客户端

*

* @param response 渲染对象

* @param string 待渲染的字符串

* @return null

*/

public static String renderString(HttpServletResponse response, String string) {

try {

response.setStatus(200);

response.setContentType("application/json");

response.setCharacterEncoding("utf-8");

response.getWriter().print(string);

} catch (IOException e) {

e.printStackTrace();

}

return null;

}

/**

* 是否是Ajax异步请求

*

* @param request

*/

public static boolean isAjaxRequest(HttpServletRequest request) {

String accept = request.getHeader("accept");

if (accept != null && accept.indexOf("application/json") != -1) {

return true;

}

String xRequestedWith = request.getHeader("X-Requested-With");

if (xRequestedWith != null && xRequestedWith.indexOf("XMLHttpRequest") != -1) {

return true;

}

String uri = request.getRequestURI();

if (StringUtils.inStringIgnoreCase(uri, ".json", ".xml")) {

return true;

}

String ajax = request.getParameter("__ajax");

if (StringUtils.inStringIgnoreCase(ajax, "json", "xml")) {

return true;

}

return false;

}

}

4.3 用到的工具类StringUtils

import java.util.ArrayList;

import java.util.Collection;

import java.util.HashSet;

import java.util.List;

import java.util.Map;

import java.util.Set;

/**

* 字符串工具类

*

*

*/

public class StringUtils extends org.apache.commons.lang3.StringUtils

{

/** 空字符串 */

private static final String NULLSTR = "";

/** 下划线 */

private static final char SEPARATOR = '_';

/**

* 获取参数不为空值

*

* @param value defaultValue 要判断的value

* @return value 返回值

*/

public static T nvl(T value, T defaultValue)

{

return value != null ? value : defaultValue;

}

/**

* * 判断一个Collection是否为空, 包含List,Set,Queue

*

* @param coll 要判断的Collection

* @return true:为空 false:非空

*/

public static boolean isEmpty(Collection coll)

{

return isNull(coll) || coll.isEmpty();

}

/**

* * 判断一个Collection是否非空,包含List,Set,Queue

*

* @param coll 要判断的Collection

* @return true:非空 false:空

*/

public static boolean isNotEmpty(Collection coll)

{

return !isEmpty(coll);

}

/**

* * 判断一个对象数组是否为空

*

* @param objects 要判断的对象数组

** @return true:为空 false:非空

*/

public static boolean isEmpty(Object[] objects)

{

return isNull(objects) || (objects.length == 0);

}

/**

* * 判断一个对象数组是否非空

*

* @param objects 要判断的对象数组

* @return true:非空 false:空

*/

public static boolean isNotEmpty(Object[] objects)

{

return !isEmpty(objects);

}

/**

* * 判断一个Map是否为空

*

* @param map 要判断的Map

* @return true:为空 false:非空

*/

public static boolean isEmpty(Map map)

{

return isNull(map) || map.isEmpty();

}

/**

* * 判断一个Map是否为空

*

* @param map 要判断的Map

* @return true:非空 false:空

*/

public static boolean isNotEmpty(Map map)

{

return !isEmpty(map);

}

/**

* * 判断一个字符串是否为空串

*

* @param str String

* @return true:为空 false:非空

*/

public static boolean isEmpty(String str)

{

return isNull(str) || NULLSTR.equals(str.trim());

}

/**

* * 判断一个字符串是否为非空串

*

* @param str String

* @return true:非空串 false:空串

*/

public static boolean isNotEmpty(String str)

{

return !isEmpty(str);

}

/**

* * 判断一个对象是否为空

*

* @param object Object

* @return true:为空 false:非空

*/

public static boolean isNull(Object object)

{

return object == null;

}

/**

* * 判断一个对象是否非空

*

* @param object Object

* @return true:非空 false:空

*/

public static boolean isNotNull(Object object)

{

return !isNull(object);

}

/**

* * 判断一个对象是否是数组类型(Java基本型别的数组)

*

* @param object 对象

* @return true:是数组 false:不是数组

*/

public static boolean isArray(Object object)

{

return isNotNull(object) && object.getClass().isArray();

}

/**

* 去空格

*/

public static String trim(String str)

{

return (str == null ? "" : str.trim());

}

/**

* 截取字符串

*

* @param str 字符串

* @param start 开始

* @return 结果

*/

public static String substring(final String str, int start)

{

if (str == null)

{

return NULLSTR;

}

if (start < 0)

{

start = str.length() + start;

}

if (start < 0)

{

start = 0;

}

if (start > str.length())

{

return NULLSTR;

}

return str.substring(start);

}

/**

* 截取字符串

*

* @param str 字符串

* @param start 开始

* @param end 结束

* @return 结果

*/

public static String substring(final String str, int start, int end)

{

if (str == null)

{

return NULLSTR;

}

if (end < 0)

{

end = str.length() + end;

}

if (start < 0)

{

start = str.length() + start;

}

if (end > str.length())

{

end = str.length();

}

if (start > end)

{

return NULLSTR;

}

if (start < 0)

{

start = 0;

}

if (end < 0)

{

end = 0;

}

return str.substring(start, end);

}

/**

* 字符串转set

*

* @param str 字符串

* @param sep 分隔符

* @return set集合

*/

public static final Set str2Set(String str, String sep)

{

return new HashSet(str2List(str, sep, true, false));

}

/**

* 字符串转list

*

* @param str 字符串

* @param sep 分隔符

* @param filterBlank 过滤纯空白

* @param trim 去掉首尾空白

* @return list集合

*/

public static final List str2List(String str, String sep, boolean filterBlank, boolean trim)

{

List list = new ArrayList();

if (StringUtils.isEmpty(str))

{

return list;

}

// 过滤空白字符串

if (filterBlank && StringUtils.isBlank(str))

{

return list;

}

String[] split = str.split(sep);

for (String string : split)

{

if (filterBlank && StringUtils.isBlank(string))

{

continue;

}

if (trim)

{

string = string.trim();

}

list.add(string);

}

return list;

}

/**

* 下划线转驼峰命名

*/

public static String toUnderScoreCase(String str)

{

if (str == null)

{

return null;

}

StringBuilder sb = new StringBuilder();

// 前置字符是否大写

boolean preCharIsUpperCase = true;

// 当前字符是否大写

boolean curreCharIsUpperCase = true;

// 下一字符是否大写

boolean nexteCharIsUpperCase = true;

for (int i = 0; i < str.length(); i++)

{

char c = str.charAt(i);

if (i > 0)

{

preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1));

}

else

{

preCharIsUpperCase = false;

}

curreCharIsUpperCase = Character.isUpperCase(c);

if (i < (str.length() - 1))

{

nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1));

}

if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase)

{

sb.append(SEPARATOR);

}

else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase)

{

sb.append(SEPARATOR);

}

sb.append(Character.toLowerCase(c));

}

return sb.toString();

}

/**

* 是否包含字符串

*

* @param str 验证字符串

* @param strs 字符串组

* @return 包含返回true

*/

public static boolean inStringIgnoreCase(String str, String... strs)

{

if (str != null && strs != null)

{

for (String s : strs)

{

if (str.equalsIgnoreCase(trim(s)))

{

return true;

}

}

}

return false;

}

/**

* 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 例如:HELLO_WORLD->HelloWorld

*

* @param name 转换前的下划线大写方式命名的字符串

* @return 转换后的驼峰式命名的字符串

*/

public static String convertToCamelCase(String name)

{

StringBuilder result = new StringBuilder();

// 快速检查

if (name == null || name.isEmpty())

{

// 没必要转换

return "";

}

else if (!name.contains("_"))

{

// 不含下划线,仅将首字母大写

return name.substring(0, 1).toUpperCase() + name.substring(1);

}

// 用下划线将原始字符串分割

String[] camels = name.split("_");

for (String camel : camels)

{

// 跳过原始字符串中开头、结尾的下换线或双重下划线

if (camel.isEmpty())

{

continue;

}

// 首字母大写

result.append(camel.substring(0, 1).toUpperCase());

result.append(camel.substring(1).toLowerCase());

}

return result.toString();

}

/**

* 驼峰式命名法 例如:user_name->userName

*/

public static String toCamelCase(String s)

{

if (s == null)

{

return null;

}

s = s.toLowerCase();

StringBuilder sb = new StringBuilder(s.length());

boolean upperCase = false;

for (int i = 0; i < s.length(); i++)

{

char c = s.charAt(i);

if (c == SEPARATOR)

{

upperCase = true;

}

else if (upperCase)

{

sb.append(Character.toUpperCase(c));

upperCase = false;

}

else

{

sb.append(c);

}

}

return sb.toString();

}

}

5.在Controller使用实例 @UserLog

@UserLog(title = "新增设备",businessType = BusinessType.INSERT)

@PostMapping("add")

public Result insertVehicle( Device device) {

Result resultJson = new Result();

try {

resultJson.setSuccessCode().setData(deviceService.insertDevice(device));

}catch (Exception e){

e.printStackTrace();

resultJson.setErrorCode().setMessage(e.getMessage());

}

return resultJson;

}

耐心通读代码,写出你想要的日志存储机制

上一篇
下一篇
相关文章