大概工具类在springboot项目中的结构
除了spring boot自身所需依赖,我们需要加入这两个依赖jar包
<!--json-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.7</version>
</dependency>
<!-- spring aop -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
自定义日志注解:
package com.nz.log;
import java.lang.annotation.*;
/**
* @Author xxs
* @Date 2020/4/21 20:42
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SysLog {
// 定义一个日志注解
}
日志实例缓存:
package com.nz.log;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
/**
* @Author xxs
* @Date 2020/4/21 20:44
*/
public class LoggerCache {
// 定义一个日志实例缓存
/**
* 日志实例记录在内存中
*/
private static HashMap<String, Logger> loggerS = new HashMap<String, Logger>();
/**
* 根据类名获取缓存的日志实例
* @param className 包名加类名 this.getClass().getName();
* @return
*/
public static Logger getLoggerByClassName(String className) {
// 从静态map中获取日志实例
Logger logger = loggerS.get(className);
// 如果没取到
if (logger == null) {
// 创建一个日志实例
logger = LoggerFactory.getLogger(className);
// 加入到静态map中
loggerS.put(className, logger);
}
// 返回
return logger;
}
}
日志注解的具体实现:
package com.nz.log;
import com.alibaba.fastjson.JSON;
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.slf4j.Logger;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.lang.reflect.Method;
/**
* @Author xxs
* @Date 2020/4/21 20:47
*/
@Aspect
@Component
public class SysLogAspect {
@Pointcut("@annotation(com.nz.log.SysLog)")
public void log() {
}
/**
* 加入注解自动记录方法日志
*
* @param joinPoint
* @return
* @throws Throwable
*/
@Around(value = "log()")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
// 获取执行方法的类的名称(包名加类名)
String className = joinPoint.getTarget().getClass().getName();
// 获取实例和方法
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
// 从缓存中获取日志实例
Logger logger = LoggerCache.getLoggerByClassName(className);
// 记录日志
logger.info("---start-------------------------------------------------------------");
logger.info(className + "." + method.getName() + "() 执行");
Object[] args = joinPoint.getArgs();
// if (args != null) {
// try {
// logger.info("Params\t===》\t" + JSON.toJSONString(args));
// } catch (Exception e) {
// logger.info("Params\t===》\t" + args.toString());
// }
// }
Object[] arguments = new Object[args.length];
for (int i = 0; i < args.length; i++) {
if (args[i] instanceof ServletRequest || args[i] instanceof ServletResponse || args[i] instanceof MultipartFile) {
//ServletRequest不能序列化,从入参里排除,否则报异常:java.lang.IllegalStateException: It is illegal to call this method if the current request is not in asynchronous mode (i.e. isAsyncStarted() returns false)
//ServletResponse不能序列化 从入参里排除,否则报异常:java.lang.IllegalStateException: getOutputStream() has already been called for this response
//MultipartFile不能序列化 从入参里排除,否则报异常:ServletRequest一样
continue;
}
arguments[i] = args[i];
}
if (arguments != null) {
try {
logger.info("Params\t===》\t" + JSON.toJSONString(arguments));
} catch (Exception e) {
logger.info("Params\t===》\t" + arguments.toString());
}
}
// 执行方法获取返回值
Object proceed = joinPoint.proceed();
// 记录日志
if (proceed != null) {
logger.info("Returns\t===》\t" + JSON.toJSONString(proceed));
}
logger.info("------end----------------------------------------------------------");
// 返回
return proceed;
}
}
运用日志:
主要示例代码:
/**
* @Author xxs
* @Date 2020/4/17 11:22
*/
@RestController
@ResponseBody
@RequestMapping("/user")
public class UserController {
@Resource
private UserService userService;
// 从缓存中获取日志
Logger LOG = LoggerCache.getLoggerByClassName(this.getClass().getName());
/**
* 登录
* @param account
* @param pwd
* @return
*/
@RequestMapping(value ={"/login"})
@ResponseBody
@SysLog()
public ResponseMess login(String account,String pwd){
User user = userService.selectByAccount(account);
if(user==null){
return new ResponseMess("找不到账号");
}
if (!user.getPwd().equals(pwd)){
return new ResponseMess("密码错误");
}
LOG.info("登陆成功,账号:"+account+" ,密码:"+pwd);
return new ResponseMess(1,"登陆成功");
}
}
运行项目,我们掉登录方法看一下:
2020-04-22 10:55:21.936 INFO 6252 --- [nio-8081-exec-3] com.nz.controller.UserController : ---start-------------------------------------------------------------
2020-04-22 10:55:21.937 INFO 6252 --- [nio-8081-exec-3] com.nz.controller.UserController : com.nz.controller.UserController.login() 执行
2020-04-22 10:55:22.005 INFO 6252 --- [nio-8081-exec-3] com.nz.controller.UserController : Params ===》 ["admin",null]
2020-04-22 10:55:22.080 INFO 6252 --- [nio-8081-exec-3] com.nz.controller.UserController : Returns ===》 {"object":"密码错误","status":0}
2020-04-22 10:55:22.080 INFO 6252 --- [nio-8081-exec-3] com.nz.controller.UserController : ------end----------------------------------------------------------
2020-04-22 11:04:08.529 INFO 6252 --- [nio-8081-exec-1] com.nz.controller.UserController : ---start-------------------------------------------------------------
2020-04-22 11:04:08.529 INFO 6252 --- [nio-8081-exec-1] com.nz.controller.UserController : com.nz.controller.UserController.login() 执行
2020-04-22 11:04:08.529 INFO 6252 --- [nio-8081-exec-1] com.nz.controller.UserController : Params ===》 ["admin","111111"]
2020-04-22 11:04:08.531 INFO 6252 --- [nio-8081-exec-1] com.nz.controller.UserController : 登陆成功,账号:admin ,密码:111111
2020-04-22 11:04:08.531 INFO 6252 --- [nio-8081-exec-1] com.nz.controller.UserController : Returns ===》 {"object":"登陆成功","status":1}
2020-04-22 11:04:08.531 INFO 6252 --- [nio-8081-exec-1] com.nz.controller.UserController : ------end----------------------------------------------------------