SpringBoot项⽬实战总结
⽬录
1 项⽬信息
1.1 项⽬模板地址
2.特殊功能与实
2.1 ⽇志记录功能
看过⽹上很多的SpringBoot项⽬记录⽇志的功能,使⽤SysLog注解,同时将⽇志写⼊数据库,写⼊数据库字段名如下:
即是记录什么⽤户,什么时间,什么ip,操作了什么接⼝,耗时多长,请求的什么参数,其实我也是这样记录的,但是这⾥存在⼀个问题,请求的参数多数情况下是⼀个 主键id,如删除⽤户接⼝是⼀个userId
@ApiOperation("删除⽤户")
@DeleteMapping(value = "/delete")
@SysLog(msg = "删除⽤户")
public ResponseEntity<ResponseMessage> deleteUser(Integer userId) {
ResponseMessage response = sysUserService.deleteUser(userId);
return ResponseEntity.Status()).body(response);
}
最后记录参数时记录的是userId,这样导致前端使⽤时不知道对应的⽤户名是谁,不⽅便展⽰:
在将改进前,我们先回顾⼀下原始⽇志代码实现流程
步骤⼀:新建SysLog注解类,⽤于Controller的接⼝上
package com.swt.agy.annotation;
import com.swt.agy.aspect.ServiceEnum;
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;
/**
* 系统⽇志注解,从⽅法上中提取参数,⽤于查、增、改操作
*
* @author Bleeth
* @version 1.0
* @date 2020-01-08 16:12
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SysLog {
String msg() default "";
}
步骤⼆:Controller接⼝上添加SysLog注解
@ApiOperation("⽤户登陆")
@PostMapping(value = "/login")
@SysLog(msg = "⽤户登陆")
public ResponseEntity<ResponseMessage> login(@RequestBody SysLoginForm form) {        ResponseMessage response = sysLoginService.login(form);
return ResponseEntity.Status()).body(response);
}
步骤三:AOP进⾏处理SysLog的注解(此代码仅供参考,有修改)
package com.swt.agy.aspect;
import onvert.Convert;
import date.DateTime;
import date.DateUtil;
import util.NumberUtil;
import util.StrUtil;
import cn.hutool.json.JSONObject;
import sion.service.IService;
import com.swt.agy.annotation.SysLog;
import com.fig.ResponseBean;
import com.fig.ResponseMessage;
springboot aopimport com.ity.SysLogEntity;
import com.dule.sys.service.SysLogService;
import com.dule.sys.service.SysMsgService;
import com.dule.sys.service.SysUserService;
import com.swt.agy.shiro.ShiroUtils;
import com.swt.agy.util.IpUtil;
import com.swt.agy.util.RedisUtil;
import com.swt.agy.util.SpringContextUtil;
slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import LocalVariableTableParameterNameDiscoverer;
import pression.ExpressionParser;
import pression.spel.standard.SpelExpressionParser;
import pression.spel.support.StandardEvaluationContext;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.t.request.RequestContextHolder;
import org.t.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import flect.Method;
import java.util.HashMap;
import java.util.Map;
/**
* 系统⽇志,切⾯处理类
*
* @author Bleeth
* @version 1.0
* @date 2020-01-08 16:12
*/
@Slf4j
@Aspect
@Component
public class SysLogAspect {
@Autowired
private SysLogService sysLogService;
@Autowired
private SysMsgService sysMsgService;
@Autowired
private SysUserService sysUserService;
@Pointcut("@annotation(com.swt.agy.annotation.SysLog)")
public void logPointCut() {
}
@Around("logPointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
String methodParam = null;
String methodMsg = null;
DateTime current = DateUtil.date();
HttpServletRequest request = ((ServletRequestAttributes) RequestAttributes()).getRequest();        Method method = getMethod(point);
String methodName = Name();
//想办法获取参数
SysLog sysLog = Annotation(SysLog.class);
methodParam = parseKey(paramField, method, Args());
methodMsg = sysLog.msg();
long beginTime = System.currentTimeMillis();
//执⾏⽅法
//执⾏⽅法
Object result = point.proceed();
//执⾏时长(毫秒)
long time = System.currentTimeMillis() - beginTime;
Integer userId = UserId();
if (userId == null) {
return result;
}
SysLogEntity entity = new SysLogEntity();
entity.setUserId(userId);
entity.setParams(methodParam);
entity.setCreatedTime(current);
entity.IpAddr(request));
entity.setMethod(methodName);
entity.setTime(time);
entity.setOperation(methodMsg);
entity.setRemark("");
if (result instanceof ResponseEntity) {
ResponseEntity responseEntity = (ResponseEntity) result;
Object body = Body();
if (body instanceof ResponseMessage) {
ResponseMessage responseMessage = (ResponseMessage) body;
entity.Message());
}
if (body instanceof ResponseBean) {
ResponseBean responseBean = (ResponseBean) body;
entity.Message());
}
}
sysLogService.save(entity);
return result;
}
/**
* 获取被拦截⽅法对象
* <p>
* Method() 获取的是顶层接⼝或者⽗类的⽅法对象
* ⽽缓存的注解在实现类的⽅法上
* 所以应该使⽤反射获取当前对象的⽅法对象
*/
public Method getMethod(ProceedingJoinPoint point) {
//获取参数的类型
Object[] args = Args();
Class[] argTypes = new Args().length];
for (int i = 0; i < args.length; i++) {
argTypes[i] = args[i].getClass();
}
Method method = null;
try {
method = Target().getClass().Signature().getName(), argTypes);        } catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
return method;
}
private String parseKey(String key, Method method, Object[] args) {
//获取被拦截⽅法参数名列表(使⽤Spring⽀持类库)
LocalVariableTableParameterNameDiscoverer u =
LocalVariableTableParameterNameDiscoverer u =
new LocalVariableTableParameterNameDiscoverer();
String[] paraNameArr = u.getParameterNames(method);
//使⽤SPEL进⾏key的解析
ExpressionParser parser = new SpelExpressionParser();
/
/SPEL上下⽂
StandardEvaluationContext context = new StandardEvaluationContext();
//把⽅法参数放⼊SPEL上下⽂中
for (int i = 0; i < paraNameArr.length; i++) {
context.setVariable(paraNameArr[i], args[i]);
}
String value = parser.parseExpression(key).getValue(context, String.class);
return value;
}
}
改进思路:针对Controller中接⼝的参数形式,我们得知⼤概⼏种情况
1.增,改接⼝⼀般都会对应表中实体的名称,此时可以从参数列表中获取我们需要的参数,如创建⽤户,我们关注的是创建的⽤户名是什么,此时可以从form表单中获取得到,同类,修改⽤户接⼝可从修改表单中获取
@ApiOperation("创建⽤户")
@PostMapping(value = "/create")
@SysLog(msg = "创建⽤户", field = "#form.username")
public ResponseEntity<ResponseBean> createUser(AddUserForm form) {
ResponseBean response = ateUser(form);
return ResponseEntity.Status()).body(response);
}
2.删除接⼝都是提供对应实体的id,此时需要从数据库中查询记录实体名是什么,如删除⽤户,我们需要⽤SysUserService查询userId得到SysUserEntity,后获取username,如下
@ApiOperation("删除⽤户")
@DeleteMapping(value = "/delete")
@SysLog(msg = "删除⽤户", field = "#userId",serviceEnum = ServiceEnum.SYS_USER,queryKey = "username")
public ResponseEntity<ResponseMessage> deleteUser(Integer userId) {
ResponseMessage response = sysUserService.deleteUser(userId);
return ResponseEntity.Status()).body(response);
}
SysLog 中 field 记录的是主键id,serviceEnum 是⽤哪个Service进⾏查询(配合Mybatis使⽤Service中的selectById⽅法),queryKey 指查询后需要获取哪个字段的值
步骤说明如下:
步骤⼀:扩展SysLog注解类,⽤于Controller的接⼝上

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。