SpringBoot使用Aop自定义注解展示日志信息,军事网络技术基础


package com.qycq.server.enums;

import io.swagger.annotations.ApiModel;

import lombok.extern.slf4j.Slf4j;

/**

  • @author 七月初七

  • @version 1.0

  • @date 2021/7/19 23:11

*/

@ApiModel(value = “日志操作类型”)

@Slf4j

public enum LogEnum {

LOGIN(“登录操作!”),

LOGOUT(“退出操作!”),

SELECT(“查询操作”),

DELETE(“删除操作”),

UPDATE(“更新操作!”),

CALCULATION(“计算操作!”),

INSERT(“增加操作”);

/**

  • 操作类型

*/

private final String type;

LogEnum(final String type) {

this.type = type;

}

public String getType() {

return this.type;

}

}

5:@Log自定义注解


package com.qycq.server.annotations;

import com.qycq.server.enums.LogEnum;

import io.swagger.annotations.ApiModel;

import java.lang.annotation.*;

/**

  • @author 七月初七

  • @version 1.0

  • @date 2021/7/19 22:50

*/

@Documented

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.METHOD)

@ApiModel(value = “日志注解”)

public @interface Log {

/**

  • 日志描述

  • @return

*/

LogEnum[] type() default {};

}

6:切面类


package com.qycq.server.aspect;

import com.fasterxml.jackson.databind.ObjectMapper;

import com.qycq.server.encapsulation.ResultBean;

import com.qycq.server.enums.LogEnum;

import com.qycq.server.exception.GlobalException;

import com.qycq.server.pojo.Errorlog;

import com.qycq.server.pojo.Log;

import com.qycq.server.service.ErrorlogService;

import com.qycq.server.service.LogService;

import com.qycq.server.utils.HttpServletRequestUtil;

import com.qycq.server.utils.IpUtil;

import com.qycq.server.utils.StringUtil;

import io.swagger.annotations.ApiModel;

import io.swagger.annotations.ApiOperation;

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.*;

import org.aspectj.lang.reflect.MethodSignature;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.context.annotation.Configuration;

import org.springframework.core.annotation.Order;

import org.springframework.security.authentication.AnonymousAuthenticationToken;

import org.springframework.security.core.Authentication;

import org.springframework.security.core.context.SecurityContextHolder;

import org.springframework.web.bind.annotation.RequestBody;

import org.springframework.web.bind.annotation.RequestParam;

import javax.servlet.http.HttpServletRequest;

import java.lang.reflect.Method;

import java.lang.reflect.Parameter;

import java.text.SimpleDateFormat;

import java.util.*;

/**

  • @author 七月初七

  • @version 1.0

  • @date 2021/7/19 23:17

*/

@ApiModel(value = “日志注解切面类”)

@Slf4j

@Configuration

@Aspect

@Order(1)

public class LogAspectImpl {

private static final Logger LOGGER = LoggerFactory.getLogger(LogAspectImpl.class);

@Autowired

private ObjectMapper objectMapper;

@Autowired

private LogService logService;

@Autowired

private ErrorlogService errorlogService;

private final SimpleDateFormat simpleDateFormat = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”);

/**

  • 切点

*/

@Pointcut("@annotation(com.qycq.server.annotations.Log)")

public void pointcut() {

}

/**

  • 前置增强

  • @param joinPoint

*/

@Before(“pointcut()”)

public void before(JoinPoint joinPoint) {

LOGGER.info("========= 前置增强 start… =========");

}

/**

  • 环绕增强

  • @param proceedingJoinPoint

  • @return

*/

@Around(“pointcut()”)

public Object result(ProceedingJoinPoint proceedingJoinPoint) {

LOGGER.info("========= 环绕增强 start… =========");

//获取开始时间

long startTime = System.currentTimeMillis();

HttpServletRequest httpServletRequest = HttpServletRequestUtil.getHttpServletRequest();

Log log = new Log();

Object proceed = null;

try {

//返回结果

proceed = proceedingJoinPoint.proceed();

Signature signature = proceedingJoinPoint.getSignature();

MethodSignature methodSignature = (MethodSignature) signature;

Method method = methodSignature.getMethod();

if (method.isAnnotationPresent(ApiOperation.class)) {

//获取方法描述

ApiOperation annotation = method.getAnnotation(ApiOperation.class);

log.setComment(annotation.value());

LOGGER.info(annotation.value());

}

if (method.isAnnotationPresent(com.qycq.server.annotations.Log.class)) {

//获取操作类型

com.qycq.server.annotations.Log annotation = method.getAnnotation(com.qycq.server.annotations.Log.class);

for (LogEnum logEnum : annotation.type()) {

log.setRequestType(logEnum.getType());

LOGGER.info(logEnum.getType());

}

}

//获取登录用户名

Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

if (!(authentication instanceof AnonymousAuthenticationToken)) {

log.setUsername(authentication.getName());

LOGGER.info(authentication.getName());

}

//获取JSON数据耗时

long endDate = System.currentTimeMillis();

//获取方法类型(get,post…)

String methodType = httpServletRequest.getMethod();

String requestURL = httpServletRequest.getRequestURL().toString();

String requestURI = httpServletRequest.getRequestURI();

String className = proceedingJoinPoint.getTarget().getClass().getName() + “.” + proceedingJoinPoint.getSignature().getName();

String requestIp = IpUtil.getIpAddr(httpServletRequest);

Object params = getParams(method, proceedingJoinPoint.getArgs());

log.setRequestMethod(methodType);

log.setRequestURL(requestURL);

log.setRequestURI(requestURI);

log.setClassName(className);

log.setRequestIp(IpUtil.getIpAddr(httpServletRequest));

log.setRequestParams(objectMapper.writeValueAsString(params));

log.setStartTime(simpleDateFormat.format(new Date(startTime)));

log.setEndDate(System.currentTimeMillis() - endDate);

log.setRequestMethodName(proceedingJoinPoint.getSignature().getName());

log.setResult(objectMapper.writeValueAsString(proceed));

// 打印日志信息输出到控制台

LOGGER.info(“methodType:{}”, methodType);

LOGGER.info(“requestMethodName:{}”, proceedingJoinPoint.getSignature().getName());

LOGGER.info(“requestURL:{}”, requestURL);

LOGGER.info(“requestURI:{}”, requestURI);

LOGGER.info(“className:{}”, className);

LOGGER.info(“requestIp:{}”, requestIp);

LOGGER.info(“params:{}”, objectMapper.writeValueAsString(params));

LOGGER.info(“startDate:{}”, simpleDateFormat.format(new Date(startTime)));

LOGGER.info(“endDate:{}”, startTime - endDate);

LOGGER.info(“result:{}”, objectMapper.writeValueAsString(proceed));

//保存日志

boolean save = logService.save(log);

if (save) {

LOGGER.info(“日志保存成功!”);

}

} catch (Throwable throwable) {

throwable.printStackTrace();

LOGGER.error(“日志保存失败:{” + throwable.getMessage() + “}”);

}

return proceed;

}

/**

  • 后置增强

  • @param joinPoint

*/

@AfterReturning(“pointcut()”)

public void afterReturning(JoinPoint joinPoint) {

LOGGER.info("========== 进入后置增强… ==========");

}

/**

  • 异常增强

  • @param joinPoint

  • @param error

*/

@AfterThrowing(value = “pointcut()”, throwing = “error”)

public void afterThrowing(JoinPoint joinPoint, Throwable error) {

Errorlog errorlog = new Errorlog();

HttpServletRequest httpServletRequest = HttpServletRequestUtil.getHttpServletRequest();

try {

//获取代理方法

Signature signature = joinPoint.getSignature();

MethodSignature methodSignature = (MethodSignature) signature;

//获取方法名称

Method method = methodSignature.getMethod();

if (method.isAnnotationPresent(ApiOperation.class)) {

//获取方法描述

ApiOperation annotation = method.getAnnotation(ApiOperation.class);

errorlog.setComment(annotation.value());

LOGGER.info(annotation.value());

}

if (method.isAnnotationPresent(com.qycq.server.annotations.Log.class)) {

//获取操作类型

com.qycq.server.annotations.Log annotation = method.getAnnotation(com.qycq.server.annotations.Log.class);

for (LogEnum logEnum : annotation.type()) {

errorlog.setRequestType(logEnum.getType());

LOGGER.info(logEnum.getType());

}

}

//获取完整类路径名

String classMethodName = method + “”;

errorlog.setClassName(classMethodName);

//获取请求地址

String ipAddr = IpUtil.getIpAddr(httpServletRequest);

errorlog.setRequestIp(ipAddr);

//获取参数

Object args = getParams(method, joinPoint.getArgs());

errorlog.setRequestParams(objectMapper.writeValueAsString(args));

//获取异常名称

String errorName = error.getClass().getName();

errorlog.setErrorName(errorName);

//获取请求方法类型

String methodType = httpServletRequest.getMethod();

errorlog.setRequestMethod(methodType);

//获取相对方法名称

String simpleName = joinPoint.getTarget().getClass().getSimpleName();

errorlog.setRequestMethodName(simpleName);

//获取方法的url

String requestURL = httpServletRequest.getRequestURL().toString();

errorlog.setRequestURL(requestURL);

//相对路径

String requestURI = httpServletRequest.getRequestURI();

errorlog.setRequestURI(requestURI);

//返回堆栈跟踪元素

String errorMessage = this.stackTraceToString(errorName, error.getMessage(), error.getStackTrace());

errorlog.setErrorMessage(errorMessage);

LOGGER.info(“方法:{}”, classMethodName);

LOGGER.info(“入参:{}”, args);

LOGGER.info(“uri:{}”, requestURI);

LOGGER.info(“url:{}”, requestURL);

LOGGER.info(“methodType:{}”, methodType);

LOGGER.info(“ipAddr:{}”, ipAddr);

LOGGER.error(“异常信息:{}”, errorMessage);

boolean save = errorlogService.save(errorlog);

if (save) {

LOGGER.info(“错误日志保存成功!”);

}

// LOGGER.error(“方法:{}, 入参:{}, uri:{}, 请求ip:{}, 异常信息:{}”, classMethodName, args, requestURI, ipAddr, errorMessage);

} catch (Throwable throwable) {

log.error("{}", throwable.getMessage(), throwable);

}

}

/**

  • 组装异常信息

  • @param errorName

  • @param errorMessage

  • @param stackTrace

  • @return

*/

private String stackTraceToString(String errorName, String errorMessage, StackTraceElement[] stackTrace) {

StringBuilder stringBuffer = new StringBuilder();

for (StackTraceElement traceElement : stackTrace) {

stringBuffer.append(traceElement).append("\n");

}

return errorName + “:” + errorMessage + “\n\t” + stringBuffer.toString();

}

/**

  • 获取参数

  • @param method 当前方法

  • @param args 当前参数

  • @return

*/

private Object getParams(Method method, Object[] args) {

List paramsList = new ArrayList<>();

//拿到当前方法的参数数组

Parameter[] parameters = method.getParameters();

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

//获取RequestBody注解修饰的参数

if (parameters[i].isAnnotationPresent(RequestBody.class)) {

RequestBody requestBody = parameters[i].getAnnotation(RequestBody.class);

if (requestBody != null) {

paramsList.add(args[i]);

}

}

//获取RequestParam注解修饰的参数

if (parameters[i].isAnnotationPresent(RequestParam.class)) {

RequestParam requestParam = parameters[i].getAnnotation(RequestParam.class);

Map map = new HashMap<>(16);

//获取的形参名称作为key

String key = parameters[i].getName();

System.out.println("key = " + key);

if (StringUtil.isNotEmpty(requestParam.value())) {

key = requestParam.value();

}

map.put(key, args[i]);

paramsList.add(map);

}

}

if (paramsList.size() == 0) {

return null;

} else if (paramsList.size() == 1) {

return paramsList.get(0);

} else {

return paramsList;

}

}

}

7:mybatisPlus代码生成器pom


UTF-8

1.8

1.8

org.springframework.boot

spring-boot-starter-web

mysql

mysql-connector-java

runtime

com.baomidou

mybatis-plus-boot-starter

3.3.1.tmp

org.apache.velocity

velocity-engine-core

2.0

com.baomidou

mybatis-plus-generator

3.3.1.tmp

compile

8:直接运行下面代码即可生成对应的pojo、service、mapper、mapper.xml、serviceImpl、controller,我这里就不一一去截图了。注意修改你的项目路径


《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》

【docs.qq.com/doc/DSmxTbFJ1cmN1R2dB】 完整内容开源分享


package com.qycq.generator;

import com.baomidou.mybatisplus.annotation.DbType;

import com.baomidou.mybatisplus.generator.AutoGenerator;

import com.baomidou.mybatisplus.generator.config.DataSourceConfig;

import com.baomidou.mybatisplus.generator.config.GlobalConfig;

import com.baomidou.mybatisplus.generator.config.PackageConfig;

import com.baomidou.mybatisplus.generator.config.StrategyConfig;

import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;

/**

  • @author 七月初七

  • @version 1.0

  • @date 2021/7/10 15:51

*/

public class MyBatisPlusGenerator {

/**

  • 数据库链接

*/

private static final String DRIVER_NAME = “com.mysql.cj.jdbc.Driver”;

/**

  • 用户名

*/

private static final String USERNAME = “root”;

/**

  • 密码

*/

private static final String PASSWORD = “2829”;

/**

  • 链接的url

*/

private static final String JDBC_URL = “jdbc:mysql://localhost:3306/yeb?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8”;

/**

  • 项目的绝对路径

*/

private static final String PATH = “E:\Project\qycq\yeb-server”;

// private static final String PATH = “E:\Project\qycq”;

/**

  • 作者

*/

private static final String AUTHOR = “七月初七”;

/**

  • 包名

*/

private static final String PACKAGE = “com.qycq.server”;

/**

  • 实体类

*/

private static final String ENTITY = “pojo”;

/**

  • mapper

*/

private static final String MAPPER = “mapper”;

/**

  • controller

*/

private static final String CONTROLLER = “controller”;

/**

  • service

*/

private static final String SERVICE = “service”;

/**

  • serviceImpl

*/

private static final String SERVICE_IMPL = “service.impl”;

/**

  • 根据表名生成多个模块代码

*/

private static final String[] TABLE_NAME = {“t_log”,“t_errorLog”};

public static void main(String[] args) {

//代码生成器

AutoGenerator autoGenerator = new AutoGenerator();

//数据源配置

DataSourceConfig dataSourceConfig = new DataSourceConfig();

dataSourceConfig.setDbType(DbType.MYSQL);//指定数据库类型

dataSourceConfig.setDriverName(DRIVER_NAME);

dataSourceConfig.setUsername(USERNAME);

dataSourceConfig.setPassword(PASSWORD);

dataSourceConfig.setUrl(JDBC_URL);

autoGenerator.setDataSource(dataSourceConfig);

//全局配置

GlobalConfig globalConfig = new GlobalConfig();

globalConfig.setOpen(false);

globalConfig.setFileOverride(false); //重新生成时文件是否覆盖

globalConfig.setBaseResultMap(true);

//xml 开启BaseColumnList

globalConfig.setBaseColumnList(true);

// 实体属性 Swagger2 注解

globalConfig.setSwagger2(true);

//输出路径

globalConfig.setOutputDir(PATH + “/src/main/java”);

//设置作者名字

globalConfig.setAuthor(AUTHOR);

//去掉service的I前缀,一般只需要设置service就行

globalConfig.setServiceImplName("%sServiceImpl");

globalConfig.setServiceName("%sService");

autoGenerator.setGlobalConfig(globalConfig);

//包配置

PackageConfig packageConfig = new PackageConfig();

packageConfig.setParent(PACKAGE);//自定义包的路径

packageConfig.setEntity(ENTITY);

packageConfig.setMapper(MAPPER);

packageConfig.setController(CONTROLLER);

packageConfig.setService(SERVICE);

packageConfig.setServiceImpl(SERVICE_IMPL);

autoGenerator.setPackageInfo(packageConfig);

//策略配置

StrategyConfig strategyConfig = new StrategyConfig();

//是否使用Lombok

strategyConfig.setEntityLombokModel(true);

//生成RestController

strategyConfig.setRestControllerStyle(true);

//根据表名生成模块

strategyConfig.setInclude(TABLE_NAME);

//去掉表前缀

strategyConfig.setTablePrefix(“t_”);

autoGenerator.setStrategy(strategyConfig);

//数据库表映射到实体的命名策略

strategyConfig.setNaming(NamingStrategy.underline_to_camel);

//数据库表字段映射到实体的命名策略

strategyConfig.setColumnNaming(NamingStrategy.no_change);

//执行

autoGenerator.execute();

}

}

9:yml文件


yml文件必须注意缩进

端口号

server:

port: 9091

数据源

spring:

数据源配置

datasource:

type: com.alibaba.druid.pool.DruidDataSource

url: jdbc:mysql://localhost:3306/xxx?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8

username: root

password: 2829

hikari:

连接池名

pool-name: DateHikariCP

最小空闲连接数

minimum-idle: 5

空闲连接存活最大时间,默认600000(10分钟)

idle-timeout: 180000

最大连接数,默认10

maximum-pool-size: 10

从连接池返回的连接的自动提交

auto-commit: true

连接最大存活时间,0表示永久存活,默认1800000(30分钟)

max-lifetime: 1800000

连接超时时间,默认30000(30秒)

connection-timeout: 30000

测试连接是否可用的查询语句

connection-test-query: SELECT 1

#redis

redis:

host: 127.0.0.1

port: 6379

database: 0

timeout: 10000ms #超时时间

password: 2829

lettuce:

pool:

max-active: 1024 #最大连接数

max-wait: 10000ms #最大等待时间

你可能感兴趣的:(程序员,面试,java,后端)