diff --git a/build.gradle b/build.gradle index c758391..171821a 100644 --- a/build.gradle +++ b/build.gradle @@ -15,8 +15,10 @@ repositories { dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.boot:spring-boot-starter-aop' developmentOnly 'org.springframework.boot:spring-boot-devtools' runtimeOnly 'mysql:mysql-connector-java' + testImplementation('org.springframework.boot:spring-boot-starter-test') { exclude group: 'org.junit.vintage', module: 'junit-vintage-engine' } @@ -25,10 +27,12 @@ dependencies { annotationProcessor 'org.projectlombok:lombok' compile group: 'com.baomidou', name: 'mybatis-plus-boot-starter', version: '3.3.2' compile group: 'com.gitee.sunchenbin.mybatis.actable', name: 'mybatis-enhance-actable', version: '1.2.1.RELEASE' + // compile group: 'com.github.xiaoymin', name: 'knife4j-spring-boot-starter', version: '2.0.4' // implementation 'com.github.xiaoymin:knife4j-spring-boot-starter:2.0.2' compile group: 'io.springfox', name: 'springfox-boot-starter', version: '3.0.0' + compile group: 'com.alibaba', name: 'fastjson', version: '1.2.73' } diff --git a/src/main/java/com/aiprose/mbp/annotation/OperLog.java b/src/main/java/com/aiprose/mbp/annotation/OperLog.java new file mode 100644 index 0000000..5227a70 --- /dev/null +++ b/src/main/java/com/aiprose/mbp/annotation/OperLog.java @@ -0,0 +1,19 @@ +package com.aiprose.mbp.annotation; +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 nelson + */ +@Target(ElementType.METHOD) //注解放置的目标位置,METHOD是可注解在方法级别上 +@Retention(RetentionPolicy.RUNTIME) //注解在哪个阶段执行 +@Documented +public @interface OperLog { + String operModul() default ""; // 操作模块 + String operType() default ""; // 操作类型 + String operDesc() default ""; // 操作说明 +} \ No newline at end of file diff --git a/src/main/java/com/aiprose/mbp/aop/OperLogAspect.java b/src/main/java/com/aiprose/mbp/aop/OperLogAspect.java new file mode 100644 index 0000000..6899692 --- /dev/null +++ b/src/main/java/com/aiprose/mbp/aop/OperLogAspect.java @@ -0,0 +1,186 @@ +package com.aiprose.mbp.aop; + +import com.aiprose.mbp.annotation.OperLog; +import com.aiprose.mbp.entity.ExceptionLog; +import com.aiprose.mbp.entity.SysLog; +import com.aiprose.mbp.service.ExceptionLogService; +import com.aiprose.mbp.service.SysLogService; +import com.aiprose.mbp.util.IPUtil; +import com.alibaba.fastjson.JSON; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.AfterReturning; +import org.aspectj.lang.annotation.AfterThrowing; +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.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.RequestContextHolder; + +import javax.servlet.http.HttpServletRequest; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +@Aspect +@Component +public class OperLogAspect { + + @Value("${version}") + private String operVer; + + @Autowired + private SysLogService sysLogService; + + @Autowired + private ExceptionLogService excService; + + /** + * 设置操作日志切入点 记录操作日志 在注解的位置切入代码 + */ + @Pointcut("@annotation(com.aiprose.mbp.annotation.OperLog)") + public void syslogPoinCut() { + } + + /** + * 设置操作异常切入点记录异常日志 扫描所有controller包下操作 + */ + @Pointcut("execution(* com.aiprose.mbp.controller..*.*(..))") + public void operExceptionLogPoinCut() { + } + + + /** + * 正常返回通知,拦截用户操作日志,连接点正常执行完成后执行, 如果连接点抛出异常,则不会执行 + * @param joinPoint 切入点 + * @param keys 返回结果 + */ + @AfterReturning(value = "syslogPoinCut()", returning = "keys") + public void savesyslog(JoinPoint joinPoint, Object keys) { + // 获取RequestAttributes + RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); + // 从获取RequestAttributes中获取HttpServletRequest的信息 + HttpServletRequest request = (HttpServletRequest) requestAttributes + .resolveReference(RequestAttributes.REFERENCE_REQUEST); + + SysLog syslog = new SysLog(); + try { + + // 从切面织入点处通过反射机制获取织入点处的方法 + MethodSignature signature = (MethodSignature) joinPoint.getSignature(); + // 获取切入点所在的方法 + Method method = signature.getMethod(); + // 获取操作 + OperLog opLog = method.getAnnotation(OperLog.class); + if (opLog != null) { + String operModul = opLog.operModul(); + String operType = opLog.operType(); + String operDesc = opLog.operDesc(); + syslog.setOperModul(operModul); // 操作模块 + syslog.setOperType(operType); // 操作类型 + syslog.setOperDesc(operDesc); // 操作描述 + } + // 获取请求的类名 + String className = joinPoint.getTarget().getClass().getName(); + // 获取请求的方法名 + String methodName = method.getName(); + methodName = className + "." + methodName; + + syslog.setOperMethod(methodName); // 请求方法 + + // 请求的参数 + Map rtnMap = converMap(request.getParameterMap()); + // 将参数所在的数组转换成json + String params = JSON.toJSONString(rtnMap); + + syslog.setOperRequParam(params); // 请求参数 + syslog.setOperRespParam(JSON.toJSONString(keys)); // 返回结果 + syslog.setOperUserId(1l); // 请求用户ID + syslog.setOperUserName("nelson"); // 请求用户名称 + syslog.setOperIp(IPUtil.getIpAddr(request)); // 请求IP + syslog.setOperUri(request.getRequestURI()); // 请求URI + syslog.setOperVersion(operVer); // 操作版本 + sysLogService.save(syslog); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 异常返回通知,用于拦截异常日志信息 连接点抛出异常后执行 + * + * @param joinPoint 切入点 + * @param e 异常信息 + */ + @AfterThrowing(pointcut = "operExceptionLogPoinCut()", throwing = "e") + public void saveExceptionLog(JoinPoint joinPoint, Throwable e) { + // 获取RequestAttributes + RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); + // 从获取RequestAttributes中获取HttpServletRequest的信息 + HttpServletRequest request = (HttpServletRequest) requestAttributes + .resolveReference(RequestAttributes.REFERENCE_REQUEST); + + ExceptionLog excepLog = new ExceptionLog(); + try { + // 从切面织入点处通过反射机制获取织入点处的方法 + MethodSignature signature = (MethodSignature) joinPoint.getSignature(); + // 获取切入点所在的方法 + Method method = signature.getMethod(); + // 获取请求的类名 + String className = joinPoint.getTarget().getClass().getName(); + // 获取请求的方法名 + String methodName = method.getName(); + methodName = className + "." + methodName; + // 请求的参数 + Map rtnMap = converMap(request.getParameterMap()); + // 将参数所在的数组转换成json + String params = JSON.toJSONString(rtnMap); + excepLog.setExcRequParam(params); // 请求参数 + excepLog.setOperMethod(methodName); // 请求方法名 + excepLog.setExcName(e.getClass().getName()); // 异常名称 + excepLog.setExcMsg(stackTraceToString(e.getClass().getName(), e.getMessage(), e.getStackTrace())); // 异常信息 + excepLog.setOperUserId(1l); // 请求用户ID + excepLog.setOperUserName("nelson"); // 请求用户名称 + excepLog.setOperUri(request.getRequestURI()); // 操作URI + excepLog.setOperIp(IPUtil.getIpAddr(request)); // 操作员IP + excepLog.setOperVersion(operVer); // 操作版本号 + + excService.save(excepLog); + + } catch (Exception e2) { + e2.printStackTrace(); + } + + } + + /** + * 转换request 请求参数 + * + * @param paramMap request获取的参数数组 + */ + public Map converMap(Map paramMap) { + Map rtnMap = new HashMap(); + for (String key : paramMap.keySet()) { + rtnMap.put(key, paramMap.get(key)[0]); + } + return rtnMap; + } + + /** + * 转换异常信息为字符串 + * + * @param exceptionName 异常名称 + * @param exceptionMessage 异常信息 + * @param elements 堆栈信息 + */ + public String stackTraceToString(String exceptionName, String exceptionMessage, StackTraceElement[] elements) { + StringBuffer strbuff = new StringBuffer(); + for (StackTraceElement stet : elements) { + strbuff.append(stet + "\n"); + } + String message = exceptionName + ":" + exceptionMessage + "\n\t" + strbuff.toString(); + return message; + } +} diff --git a/src/main/java/com/aiprose/mbp/controller/UserController.java b/src/main/java/com/aiprose/mbp/controller/UserController.java index 510d8f5..a40f749 100644 --- a/src/main/java/com/aiprose/mbp/controller/UserController.java +++ b/src/main/java/com/aiprose/mbp/controller/UserController.java @@ -1,5 +1,6 @@ package com.aiprose.mbp.controller; +import com.aiprose.mbp.annotation.OperLog; import com.aiprose.mbp.entity.User; import com.aiprose.mbp.service.UserService; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; @@ -7,6 +8,7 @@ import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.util.List; @@ -36,7 +38,8 @@ public class UserController { @ApiOperation(value = "分页") @GetMapping("page") - public Page page() { - return userService.page(); + @OperLog(operModul = "用户列表分页",operType = "分页") + public Page page(@RequestParam Integer pageNum,@RequestParam Integer pageSize) { + return userService.page(pageNum,pageSize); } } diff --git a/src/main/java/com/aiprose/mbp/entity/ExceptionLog.java b/src/main/java/com/aiprose/mbp/entity/ExceptionLog.java new file mode 100644 index 0000000..94aa86b --- /dev/null +++ b/src/main/java/com/aiprose/mbp/entity/ExceptionLog.java @@ -0,0 +1,39 @@ +package com.aiprose.mbp.entity; +import com.baomidou.mybatisplus.annotation.TableName; +import com.gitee.sunchenbin.mybatis.actable.annotation.Column; +import com.gitee.sunchenbin.mybatis.actable.annotation.Table; +import com.gitee.sunchenbin.mybatis.actable.constants.MySqlTypeConstant; +import lombok.Data; + +@Data +@Table(name="mbp_exception_log") +@TableName("mbp_exception_log") +public class ExceptionLog extends SuperEntity{ + + @Column(name = "oper_user_id",comment = "操作用户id") + private Long operUserId; + + @Column(name = "oper_user_name",comment = "操作用户名") + private String operUserName; + + @Column(name = "exc_requ_param",comment = "请求参数",type = MySqlTypeConstant.TEXT) + private String excRequParam; + + @Column(name = "oper_method",comment = "操作方法") + private String operMethod; + + @Column(name = "oper_uri",comment = "请求uri") + private String operUri; + + @Column(name = "oper_ip",comment = "请求ip") + private String operIp; + + @Column(name = "oper_version",comment = "版本号") + private String operVersion; + + @Column(name = "exc_name",comment = "异常名称") + private String excName; + + @Column(name = "exc_msg",comment = "异常信息",type = MySqlTypeConstant.TEXT) + private String excMsg; +} diff --git a/src/main/java/com/aiprose/mbp/entity/SysLog.java b/src/main/java/com/aiprose/mbp/entity/SysLog.java new file mode 100644 index 0000000..528ef92 --- /dev/null +++ b/src/main/java/com/aiprose/mbp/entity/SysLog.java @@ -0,0 +1,45 @@ +package com.aiprose.mbp.entity; +import com.baomidou.mybatisplus.annotation.TableName; +import com.gitee.sunchenbin.mybatis.actable.annotation.Column; +import com.gitee.sunchenbin.mybatis.actable.annotation.Table; +import com.gitee.sunchenbin.mybatis.actable.constants.MySqlTypeConstant; +import lombok.Data; + +@Data +@Table(name="mbp_syslog") +@TableName("mbp_syslog") +public class SysLog extends SuperEntity{ + + @Column(name = "oper_user_id",comment = "操作用户id") + private Long operUserId; + + @Column(name = "oper_user_name",comment = "操作用户名") + private String operUserName; + + @Column(name = "oper_modul",comment = "功能模块") + private String operModul; + + @Column(name = "oper_type",comment = "操作类型") + private String operType; + + @Column(name = "oper_desc",comment = "操作描述") + private String operDesc; + + @Column(name = "oper_requ_param",comment = "请求参数",type = MySqlTypeConstant.TEXT) + private String operRequParam; + + @Column(name = "oper_resp_param",comment = "返回参数",type = MySqlTypeConstant.TEXT) + private String operRespParam; + + @Column(name = "oper_method",comment = "操作方法") + private String operMethod; + + @Column(name = "oper_uri",comment = "请求uri") + private String operUri; + + @Column(name = "oper_ip",comment = "请求ip") + private String operIp; + + @Column(name = "oper_version",comment = "版本号") + private String operVersion; +} diff --git a/src/main/java/com/aiprose/mbp/mapper/ExceptionLogMapper.java b/src/main/java/com/aiprose/mbp/mapper/ExceptionLogMapper.java new file mode 100644 index 0000000..74e21ca --- /dev/null +++ b/src/main/java/com/aiprose/mbp/mapper/ExceptionLogMapper.java @@ -0,0 +1,10 @@ +package com.aiprose.mbp.mapper; + +import com.aiprose.mbp.entity.ExceptionLog; +import com.aiprose.mbp.entity.SysLog; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface ExceptionLogMapper extends BaseMapper { +} diff --git a/src/main/java/com/aiprose/mbp/mapper/SysLogMapper.java b/src/main/java/com/aiprose/mbp/mapper/SysLogMapper.java new file mode 100644 index 0000000..9306243 --- /dev/null +++ b/src/main/java/com/aiprose/mbp/mapper/SysLogMapper.java @@ -0,0 +1,9 @@ +package com.aiprose.mbp.mapper; + +import com.aiprose.mbp.entity.SysLog; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface SysLogMapper extends BaseMapper { +} diff --git a/src/main/java/com/aiprose/mbp/service/ExceptionLogService.java b/src/main/java/com/aiprose/mbp/service/ExceptionLogService.java new file mode 100644 index 0000000..bd114d2 --- /dev/null +++ b/src/main/java/com/aiprose/mbp/service/ExceptionLogService.java @@ -0,0 +1,13 @@ +package com.aiprose.mbp.service; + +import com.aiprose.mbp.entity.ExceptionLog; +import com.aiprose.mbp.entity.SysLog; +import com.aiprose.mbp.mapper.ExceptionLogMapper; +import com.aiprose.mbp.mapper.SysLogMapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; + +@Service +public class ExceptionLogService extends ServiceImpl { + +} diff --git a/src/main/java/com/aiprose/mbp/service/SysLogService.java b/src/main/java/com/aiprose/mbp/service/SysLogService.java new file mode 100644 index 0000000..462af06 --- /dev/null +++ b/src/main/java/com/aiprose/mbp/service/SysLogService.java @@ -0,0 +1,18 @@ +package com.aiprose.mbp.service; + +import com.aiprose.mbp.entity.SysLog; +import com.aiprose.mbp.entity.User; +import com.aiprose.mbp.mapper.SysLogMapper; +import com.aiprose.mbp.mapper.UserMapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class SysLogService extends ServiceImpl { + +} diff --git a/src/main/java/com/aiprose/mbp/service/UserService.java b/src/main/java/com/aiprose/mbp/service/UserService.java index 3d39d0b..64d5c9f 100644 --- a/src/main/java/com/aiprose/mbp/service/UserService.java +++ b/src/main/java/com/aiprose/mbp/service/UserService.java @@ -6,33 +6,28 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; +import org.springframework.web.bind.annotation.RequestParam; import java.util.List; @Service public class UserService extends ServiceImpl { - @Autowired - private UserMapper userMapper; - - public List list(){ - List userList1 = userMapper.queryList(); - List userList = userMapper.selectList(new QueryWrapper().lambda().eq(User::getName,"nelson")); + List userList1 = baseMapper.queryList(); + List userList = baseMapper.selectList(new QueryWrapper().lambda().eq(User::getName,"nelson")); return userList; } - public List fingByName(String name,Integer age){ - List userList = userMapper.selectByName(name,age); + List userList = baseMapper.selectByName(name,age); return userList; } - - public Page page(){ - Page page = userMapper.selectPage(new Page(1, 2), new QueryWrapper().eq("name","nelson")); + public Page page(Integer pageNum,Integer pageSize){ + Page page = baseMapper.selectPage(new Page(pageNum, pageSize), new QueryWrapper().eq("name","nelson")); return page; } - } diff --git a/src/main/java/com/aiprose/mbp/util/IPUtil.java b/src/main/java/com/aiprose/mbp/util/IPUtil.java new file mode 100644 index 0000000..cd1aa88 --- /dev/null +++ b/src/main/java/com/aiprose/mbp/util/IPUtil.java @@ -0,0 +1,26 @@ +package com.aiprose.mbp.util; + +import javax.servlet.http.HttpServletRequest; + +public class IPUtil { + /** + * 获取IP地址 + * + * 使用Nginx等反向代理软件, 则不能通过request.getRemoteAddr()获取IP地址 + * 如果使用了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP地址,X-Forwarded-For中第一个非unknown的有效IP字符串,则为真实IP地址 + */ + public static String getIpAddr(HttpServletRequest request) { + + 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("WL-Proxy-Client-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; + } +} \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 774522d..3ec5356 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,3 +1,4 @@ +version: v0.1 server: port: 8200 spring: