diff --git a/common/src/main/java/com/storeroom/utils/ThrowableUtil.java b/common/src/main/java/com/storeroom/utils/ThrowableUtil.java
new file mode 100644
index 0000000..d59cbf5
--- /dev/null
+++ b/common/src/main/java/com/storeroom/utils/ThrowableUtil.java
@@ -0,0 +1,18 @@
+package com.storeroom.utils;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+public class ThrowableUtil {
+
+ /**
+ * 获取堆栈信息
+ */
+ public static String getStackTrace(Throwable throwable){
+ StringWriter sw = new StringWriter();
+ try (PrintWriter pw = new PrintWriter(sw)) {
+ throwable.printStackTrace(pw);
+ return sw.toString();
+ }
+ }
+}
diff --git a/logging/pom.xml b/logging/pom.xml
new file mode 100644
index 0000000..91d754f
--- /dev/null
+++ b/logging/pom.xml
@@ -0,0 +1,29 @@
+
+
+
+ yxk_StoreroomSystem
+ com.storeroom
+ 1.0
+
+ 4.0.0
+
+ logging
+ 日志模块
+
+
+ 17
+ 17
+
+
+
+
+
+ com.storeroom
+ common
+ 1.0
+
+
+
+
\ No newline at end of file
diff --git a/logging/src/main/java/com/storeroom/annotation/Log.java b/logging/src/main/java/com/storeroom/annotation/Log.java
new file mode 100644
index 0000000..3266944
--- /dev/null
+++ b/logging/src/main/java/com/storeroom/annotation/Log.java
@@ -0,0 +1,13 @@
+package com.storeroom.annotation;
+
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Log {
+ String value() default "";
+}
diff --git a/logging/src/main/java/com/storeroom/aspect/LogAspect.java b/logging/src/main/java/com/storeroom/aspect/LogAspect.java
new file mode 100644
index 0000000..c91c67b
--- /dev/null
+++ b/logging/src/main/java/com/storeroom/aspect/LogAspect.java
@@ -0,0 +1,82 @@
+package com.storeroom.aspect;
+
+
+import com.storeroom.domain.Log;
+import com.storeroom.service.LogService;
+import com.storeroom.utils.RequestHolder;
+import com.storeroom.utils.SecurityUtils;
+import com.storeroom.utils.StringUtils;
+import com.storeroom.utils.ThrowableUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.AfterThrowing;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.http.HttpServletRequest;
+
+@Component
+@Aspect
+@Slf4j
+public class LogAspect {
+
+
+ private final LogService logService;
+
+ ThreadLocal currentTime = new ThreadLocal<>();
+
+ public LogAspect(LogService logService) {
+ this.logService = logService;
+ }
+
+ /**
+ * 配置切入点
+ */
+ @Pointcut("@annotation(com.storeroom.annotation.Log)")
+ public void logPointcut() {
+ // 该方法无方法体,主要为了让同类中其他方法使用此切入点
+ }
+
+ /**
+ * 配置环绕通知,使用在方法logPointcut()上注册的切入点
+ *
+ * @param joinPoint join point for advice
+ */
+ @Around("logPointcut()")
+ public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
+ Object result;
+ currentTime.set(System.currentTimeMillis());
+ result = joinPoint.proceed();
+ Log log = new Log("INFO",System.currentTimeMillis() - currentTime.get());
+ currentTime.remove();
+ HttpServletRequest request = RequestHolder.getHttpServletRequest();
+ logService.save(getUsername(), StringUtils.getBrowser(request), StringUtils.getIp(request),joinPoint, log);
+ return result;
+ }
+
+ /**
+ * 配置异常通知
+ *
+ * @param joinPoint join point for advice
+ * @param e exception
+ */
+ @AfterThrowing(pointcut = "logPointcut()", throwing = "e")
+ public void logAfterThrowing(JoinPoint joinPoint, Throwable e) {
+ Log log = new Log("ERROR",System.currentTimeMillis() - currentTime.get());
+ currentTime.remove();
+ log.setExceptionDetail(ThrowableUtil.getStackTrace(e).getBytes());
+ HttpServletRequest request = RequestHolder.getHttpServletRequest();
+ logService.save(getUsername(), StringUtils.getBrowser(request), StringUtils.getIp(request), (ProceedingJoinPoint)joinPoint, log);
+ }
+
+ public String getUsername() {
+ try {
+ return SecurityUtils.getCurrentUsername();
+ }catch (Exception e){
+ return "";
+ }
+ }
+}
diff --git a/logging/src/main/java/com/storeroom/controller/LogController.java b/logging/src/main/java/com/storeroom/controller/LogController.java
new file mode 100644
index 0000000..f20d7b3
--- /dev/null
+++ b/logging/src/main/java/com/storeroom/controller/LogController.java
@@ -0,0 +1,93 @@
+package com.storeroom.controller;
+
+
+import com.storeroom.annotation.Log;
+import com.storeroom.service.LogService;
+import com.storeroom.service.dto.LogQueryCriteria;
+import com.storeroom.utils.SecurityUtils;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import org.springframework.data.domain.Pageable;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/api/logs")
+@Api(tags = "系统:日志管理")
+public class LogController {
+
+ private final LogService logService;
+
+
+ @Log("导出数据")
+ @ApiOperation("导出数据")
+ @GetMapping(value = "/download")
+ @PreAuthorize("@ys.check()")
+ public void exportLog(HttpServletResponse response, LogQueryCriteria criteria) throws IOException {
+ criteria.setLogType("INFO");
+ logService.download(logService.queryAll(criteria), response);
+ }
+
+ @Log("导出错误数据")
+ @ApiOperation("导出错误数据")
+ @GetMapping(value = "/error/download")
+ @PreAuthorize("@ys.check()")
+ public void exportErrorLog(HttpServletResponse response, LogQueryCriteria criteria) throws IOException {
+ criteria.setLogType("ERROR");
+ logService.download(logService.queryAll(criteria), response);
+ }
+ @GetMapping
+ @ApiOperation("日志查询")
+ @PreAuthorize("@ys.check()")
+ public ResponseEntity