diff --git a/file-common/src/main/java/com/qiwenshare/common/cbb/CollectUtil.java b/file-common/src/main/java/com/qiwenshare/common/cbb/CollectUtil.java new file mode 100644 index 0000000..a127ef6 --- /dev/null +++ b/file-common/src/main/java/com/qiwenshare/common/cbb/CollectUtil.java @@ -0,0 +1,61 @@ +package com.qiwenshare.common.cbb; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.http.HttpServletRequest; +import java.net.InetAddress; +import java.net.UnknownHostException; + +/** + * 通信工具类 + * + * @author ma116 + */ +public class CollectUtil { + + private static final Logger LOG = LoggerFactory.getLogger(CollectUtil.class); + + /** + * java 后台获取访问客户端ip地址 + * + * @param request HttpServletRequest请求 + * @return IP地址 + */ + public String getClientIpAddress(HttpServletRequest request) { + String clientIp = request.getHeader("x-forwarded-for"); + if (clientIp == null || clientIp.length() == 0 + || "unknown".equalsIgnoreCase(clientIp)) { + clientIp = request.getHeader("Proxy-Client-IP"); + } + if (clientIp == null || clientIp.length() == 0 + || "unknown".equalsIgnoreCase(clientIp)) { + clientIp = request.getHeader("WL-Proxy-Client-IP"); + } + if (clientIp == null || clientIp.length() == 0 + || "unknown".equalsIgnoreCase(clientIp)) { + clientIp = request.getRemoteAddr(); + } + return clientIp; + } + + /** + * 获取本地IP + * + * @return IP地址 + */ + public String getLocalIp() { + InetAddress addr = null; + String ip = ""; + try { + addr = InetAddress.getLocalHost(); + } catch (UnknownHostException e) { + LOG.error("获取本地IP失败"); + } + if (addr != null) { + ip = addr.getHostAddress().toString(); + } + return ip; + } + +} diff --git a/file-web/src/main/java/com/qiwenshare/file/anno/MyLog.java b/file-web/src/main/java/com/qiwenshare/file/anno/MyLog.java new file mode 100644 index 0000000..239e4cf --- /dev/null +++ b/file-web/src/main/java/com/qiwenshare/file/anno/MyLog.java @@ -0,0 +1,19 @@ +package com.qiwenshare.file.anno; + +import java.lang.annotation.*; + +/** + * 自定义注解类 + */ +@Target(ElementType.METHOD) //注解放置的目标位置,METHOD是可注解在方法级别上 +@Retention(RetentionPolicy.RUNTIME) //注解在哪个阶段执行 +@Documented //生成文档 +public @interface MyLog { + String module() default ""; + + String operation() default ""; + + String type() default "operation"; + + String level() default "0"; //0-低,1-中,2-高 +} \ No newline at end of file diff --git a/file-web/src/main/java/com/qiwenshare/file/aop/WebLogAcpect.java b/file-web/src/main/java/com/qiwenshare/file/aop/WebLogAcpect.java new file mode 100644 index 0000000..db2ce2d --- /dev/null +++ b/file-web/src/main/java/com/qiwenshare/file/aop/WebLogAcpect.java @@ -0,0 +1,116 @@ +package com.qiwenshare.file.aop; + +import com.qiwenshare.common.cbb.RestResult; +import com.qiwenshare.file.anno.MyLog; +import com.qiwenshare.file.api.IOperationLogService; +import com.qiwenshare.file.api.IUserService; +import com.qiwenshare.file.domain.UserBean; +import com.qiwenshare.file.util.OperationLogUtil; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.AfterReturning; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.CodeSignature; +import org.aspectj.lang.reflect.MethodSignature; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +/** + * 操作日志切面 + */ +@Aspect +@Component +public class WebLogAcpect { + @Resource + IOperationLogService operationLogService; + @Resource + IUserService userService; + + private String operation = ""; + private String module = ""; + private String token = ""; + private HttpServletRequest request; + + private Logger logger = LoggerFactory.getLogger(WebLogAcpect.class); + + /** + * 定义切入点,切入点为com.example.aop下的所有函数 + */ + @Pointcut("@annotation(com.qiwenshare.file.anno.MyLog)") + public void webLog() { + } + + /** + * 前置通知:在连接点之前执行的通知 + * + * @param joinPoint 切入点 + */ + @Before("webLog()") + public void doBefore(JoinPoint joinPoint) { + //从切面织入点处通过反射机制获取织入点处的方法 + MethodSignature signature = (MethodSignature) joinPoint.getSignature(); + //获取切入点所在的方法 + Method method = signature.getMethod(); + Map map = getNameAndValue(joinPoint); + + //获取操作 + MyLog myLog = method.getAnnotation(MyLog.class); + + if (myLog != null) { + operation = myLog.operation(); + module = myLog.module(); + token = (String) map.get("token"); + } + + // 接收到请求,记录请求内容 + ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); + request = attributes.getRequest(); + + + } + + @AfterReturning(returning = "ret", pointcut = "webLog()") + public void doAfterReturning(Object ret) throws Throwable { + + if (ret instanceof RestResult) { + boolean isSuccess = ((RestResult) ret).getSuccess(); + String errorMessage = ((RestResult) ret).getMessage(); + UserBean sessionUserBean = userService.getUserBeanByToken(token); + if (isSuccess) { + + operationLogService.insertOperationLog( + OperationLogUtil.getOperationLogObj(request,sessionUserBean, "成功", module, operation, "操作成功")); + } else { + operationLogService.insertOperationLog( + OperationLogUtil.getOperationLogObj(request,sessionUserBean, "失败", module, operation, errorMessage)); + } + } + + + } + + /** + * 获取参数Map集合 + * @param joinPoint + * @return + */ + Map getNameAndValue(JoinPoint joinPoint) { + Map param = new HashMap<>(); + Object[] paramValues = joinPoint.getArgs(); + String[] paramNames = ((CodeSignature)joinPoint.getSignature()).getParameterNames(); + for (int i = 0; i < paramNames.length; i++) { + param.put(paramNames[i], paramValues[i]); + } + return param; + } +} \ No newline at end of file diff --git a/file-web/src/main/java/com/qiwenshare/file/api/IOperationLogService.java b/file-web/src/main/java/com/qiwenshare/file/api/IOperationLogService.java new file mode 100644 index 0000000..4840ba0 --- /dev/null +++ b/file-web/src/main/java/com/qiwenshare/file/api/IOperationLogService.java @@ -0,0 +1,17 @@ +package com.qiwenshare.file.api; + + + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import com.qiwenshare.file.domain.OperationLogBean; + +import java.util.List; + +public interface IOperationLogService extends IService { + IPage selectOperationLogPage(Integer current, Integer size); + + List selectOperationLog(); + + void insertOperationLog(OperationLogBean operationlogBean); +} diff --git a/file-web/src/main/java/com/qiwenshare/file/controller/FileController.java b/file-web/src/main/java/com/qiwenshare/file/controller/FileController.java index fa155b3..19c9a66 100644 --- a/file-web/src/main/java/com/qiwenshare/file/controller/FileController.java +++ b/file-web/src/main/java/com/qiwenshare/file/controller/FileController.java @@ -10,6 +10,7 @@ import com.qiwenshare.common.operation.FileOperation; import com.qiwenshare.common.oss.AliyunOSSRename; import com.qiwenshare.common.util.FileUtil; import com.qiwenshare.common.util.PathUtil; +import com.qiwenshare.file.anno.MyLog; import com.qiwenshare.file.api.IFileService; import com.qiwenshare.file.api.IRecoveryFileService; import com.qiwenshare.file.api.IUserFileService; @@ -50,6 +51,8 @@ public class FileController { QiwenFileConfig qiwenFileConfig; public static Executor executor = Executors.newFixedThreadPool(20); + public static final String CURRENT_MODULE = "文件接口"; + public static int COMPLETE_COUNT = 0; public static long treeid = 0; @@ -57,6 +60,7 @@ public class FileController { @Operation(summary = "创建文件", description = "目录(文件夹)的创建", tags = {"file"}) @RequestMapping(value = "/createfile", method = RequestMethod.POST) + @MyLog(operation = "创建文件", module = CURRENT_MODULE) @ResponseBody public RestResult createFile(@RequestBody CreateFileDTO createFileDto, @RequestHeader("token") String token) { if (!operationCheck(token).getSuccess()){ @@ -84,6 +88,7 @@ public class FileController { @Operation(summary = "文件重命名", description = "文件重命名", tags = {"file"}) @RequestMapping(value = "/renamefile", method = RequestMethod.POST) + @MyLog(operation = "文件重命名", module = CURRENT_MODULE) @ResponseBody public RestResult renameFile(@RequestBody RenameFileDTO renameFileDto, @RequestHeader("token") String token) { RestResult restResult = new RestResult<>(); @@ -190,6 +195,7 @@ public class FileController { @Operation(summary = "批量删除文件", description = "批量删除文件", tags = {"file"}) @RequestMapping(value = "/batchdeletefile", method = RequestMethod.POST) + @MyLog(operation = "批量删除文件", module = CURRENT_MODULE) @ResponseBody public RestResult deleteImageByIds(@RequestBody BatchDeleteFileDTO batchDeleteFileDto, @RequestHeader("token") String token) { @@ -216,6 +222,7 @@ public class FileController { @Operation(summary = "删除文件", description = "可以删除文件或者目录", tags = {"file"}) @RequestMapping(value = "/deletefile", method = RequestMethod.POST) + @MyLog(operation = "删除文件", module = CURRENT_MODULE) @ResponseBody public RestResult deleteFile(@RequestBody DeleteFileDTO deleteFileDto, @RequestHeader("token") String token) { @@ -243,6 +250,7 @@ public class FileController { @Operation(summary = "解压文件", description = "压缩功能为体验功能,目前持续优化中。", tags = {"file"}) @RequestMapping(value = "/unzipfile", method = RequestMethod.POST) + @MyLog(operation = "解压文件", module = CURRENT_MODULE) @ResponseBody public RestResult unzipFile(@RequestBody UnzipFileDTO unzipFileDto, @RequestHeader("token") String token) { @@ -326,6 +334,7 @@ public class FileController { @Operation(summary = "文件移动", description = "可以移动文件或者目录", tags = {"file"}) @RequestMapping(value = "/movefile", method = RequestMethod.POST) + @MyLog(operation = "文件移动", module = CURRENT_MODULE) @ResponseBody public RestResult moveFile(@RequestBody MoveFileDTO moveFileDto, @RequestHeader("token") String token) { @@ -344,6 +353,7 @@ public class FileController { @Operation(summary = "批量移动文件", description = "可以同时选择移动多个文件或者目录", tags = {"file"}) @RequestMapping(value = "/batchmovefile", method = RequestMethod.POST) + @MyLog(operation = "批量移动文件", module = CURRENT_MODULE) @ResponseBody public RestResult batchMoveFile(@RequestBody BatchMoveFileDTO batchMoveFileDto, @RequestHeader("token") String token) { diff --git a/file-web/src/main/java/com/qiwenshare/file/controller/FiletransferController.java b/file-web/src/main/java/com/qiwenshare/file/controller/FiletransferController.java index 2d220f0..7aa52c6 100644 --- a/file-web/src/main/java/com/qiwenshare/file/controller/FiletransferController.java +++ b/file-web/src/main/java/com/qiwenshare/file/controller/FiletransferController.java @@ -3,6 +3,7 @@ package com.qiwenshare.file.controller; import com.qiwenshare.common.cbb.DateUtil; import com.qiwenshare.common.util.FileUtil; import com.qiwenshare.common.cbb.RestResult; +import com.qiwenshare.file.anno.MyLog; import com.qiwenshare.file.api.IFileService; import com.qiwenshare.file.api.IFiletransferService; import com.qiwenshare.file.api.IUserFileService; @@ -44,9 +45,11 @@ public class FiletransferController { IUserService userService; @Resource IUserFileService userFileService; + public static final String CURRENT_MODULE = "文件传输接口"; @Operation(summary = "极速上传", description = "校验文件MD5判断文件是否存在,如果存在直接上传成功并返回skipUpload=true,如果不存在返回skipUpload=false需要再次调用该接口的POST方法", tags = {"filetransfer"}) @RequestMapping(value = "/uploadfile", method = RequestMethod.GET) + @MyLog(operation = "极速上传", module = CURRENT_MODULE) @ResponseBody public RestResult uploadFileSpeed(HttpServletRequest request, UploadFileDTO uploadFileDto, @RequestHeader("token") String token) { RestResult restResult = new RestResult(); @@ -103,6 +106,7 @@ public class FiletransferController { */ @Operation(summary = "上传文件", description = "真正的上次文件接口", tags = {"filetransfer"}) @RequestMapping(value = "/uploadfile", method = RequestMethod.POST) + @MyLog(operation = "上传文件", module = CURRENT_MODULE) @ResponseBody public RestResult uploadFile(HttpServletRequest request, UploadFileDTO uploadFileDto, @RequestHeader("token") String token) { RestResult restResult = new RestResult<>(); diff --git a/file-web/src/main/java/com/qiwenshare/file/controller/RecoveryFileController.java b/file-web/src/main/java/com/qiwenshare/file/controller/RecoveryFileController.java index 73a6d1f..3151758 100644 --- a/file-web/src/main/java/com/qiwenshare/file/controller/RecoveryFileController.java +++ b/file-web/src/main/java/com/qiwenshare/file/controller/RecoveryFileController.java @@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.qiwenshare.common.cbb.DateUtil; import com.qiwenshare.common.cbb.RestResult; import com.qiwenshare.common.util.PathUtil; +import com.qiwenshare.file.anno.MyLog; import com.qiwenshare.file.api.IRecoveryFileService; import com.qiwenshare.file.api.IUserFileService; import com.qiwenshare.file.api.IUserService; @@ -35,9 +36,10 @@ public class RecoveryFileController { IUserFileService userFileService; @Resource IUserService userService; - + public static final String CURRENT_MODULE = "回收站文件接口"; @Operation(summary = "删除回收文件", description = "删除回收文件", tags = {"recoveryfile"}) + @MyLog(operation = "删除回收文件", module = CURRENT_MODULE) @RequestMapping(value = "/deleterecoveryfile", method = RequestMethod.POST) @ResponseBody public RestResult deleteRecoveryFile(@RequestBody DeleteRecoveryFileDTO deleteRecoveryFileDTO, @RequestHeader("token") String token) { @@ -55,6 +57,7 @@ public class RecoveryFileController { @Operation(summary = "批量删除回收文件", description = "批量删除回收文件", tags = {"recoveryfile"}) @RequestMapping(value = "/batchdelete", method = RequestMethod.POST) + @MyLog(operation = "批量删除回收文件", module = CURRENT_MODULE) @ResponseBody public RestResult batchDeleteRecoveryFile(@RequestBody BatchDeleteRecoveryFileDTO batchDeleteRecoveryFileDTO, @RequestHeader("token") String token) { RestResult restResult = new RestResult(); @@ -86,6 +89,7 @@ public class RecoveryFileController { @Operation(summary = "还原文件", description = "还原文件", tags = {"recoveryfile"}) @RequestMapping(value = "/restorefile", method = RequestMethod.POST) + @MyLog(operation = "还原文件", module = CURRENT_MODULE) @ResponseBody public RestResult restoreFile(RestoreFileDto restoreFileDto, @RequestHeader("token") String token) { UserBean sessionUserBean = userService.getUserBeanByToken(token); diff --git a/file-web/src/main/java/com/qiwenshare/file/controller/UserController.java b/file-web/src/main/java/com/qiwenshare/file/controller/UserController.java index 8fae50b..f101fab 100644 --- a/file-web/src/main/java/com/qiwenshare/file/controller/UserController.java +++ b/file-web/src/main/java/com/qiwenshare/file/controller/UserController.java @@ -5,6 +5,7 @@ import com.alibaba.fastjson.JSON; import com.qiwenshare.common.cbb.RestResult; import com.qiwenshare.common.domain.AliyunOSS; import com.qiwenshare.common.util.JjwtUtil; +import com.qiwenshare.file.anno.MyLog; import com.qiwenshare.file.api.IUserService; import com.qiwenshare.file.config.QiwenFileConfig; import com.qiwenshare.file.domain.UserBean; @@ -52,6 +53,7 @@ public class UserController { @Operation(summary = "用户注册", description = "注册账号", tags = {"user"}) @PostMapping(value = "/register") + @MyLog(operation = "用户注册", module = CURRENT_MODULE) @ResponseBody public RestResult addUser(@RequestBody RegisterDTO registerDTO) { RestResult restResult = null; @@ -64,6 +66,7 @@ public class UserController { @Operation(summary = "用户登录", description = "用户登录认证后才能进入系统", tags = {"user"}) @GetMapping("/login") + @MyLog(operation = "用户登录", module = CURRENT_MODULE) @ResponseBody public RestResult userLogin( @Parameter(description = "登录用户名") String username, diff --git a/file-web/src/main/java/com/qiwenshare/file/domain/OperationLogBean.java b/file-web/src/main/java/com/qiwenshare/file/domain/OperationLogBean.java new file mode 100644 index 0000000..5de8b25 --- /dev/null +++ b/file-web/src/main/java/com/qiwenshare/file/domain/OperationLogBean.java @@ -0,0 +1,73 @@ +package com.qiwenshare.file.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import javax.persistence.*; + +/** + * 操作日志基础信息类 + * + * @author ma116 + */ +@Data +@Table(name = "operationlog") +@Entity +@TableName("operationlog") +public class OperationLogBean { + /** + * 操作日志id + */ + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @TableId(type = IdType.AUTO) + private long operationLogId; + + /** + * 用户id + */ + private long userId; + + /** + * 操作 + */ + private String operation; + + /** + * 操作对象 + */ + private String operationObj; + + /** + * 终端IP + */ + private String terminal; + + /** + * 操作结果 + */ + private String result; + + /** + * 操作详情 + */ + private String detail; + + /** + * 操作源 + */ + private String source; + + /** + * 时间 + */ + private String time; + + /** + * 日志级别 + */ + private String logLevel; + +} diff --git a/file-web/src/main/java/com/qiwenshare/file/mapper/OperationLogMapper.java b/file-web/src/main/java/com/qiwenshare/file/mapper/OperationLogMapper.java new file mode 100644 index 0000000..adc2fdb --- /dev/null +++ b/file-web/src/main/java/com/qiwenshare/file/mapper/OperationLogMapper.java @@ -0,0 +1,14 @@ +package com.qiwenshare.file.mapper; + + + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.qiwenshare.file.domain.OperationLogBean; + +import java.util.List; + +public interface OperationLogMapper extends BaseMapper { + List selectOperationLog(); + + void insertOperationLog(OperationLogBean operationlogBean); +} diff --git a/file-web/src/main/java/com/qiwenshare/file/service/OperationLogService.java b/file-web/src/main/java/com/qiwenshare/file/service/OperationLogService.java new file mode 100644 index 0000000..b35a082 --- /dev/null +++ b/file-web/src/main/java/com/qiwenshare/file/service/OperationLogService.java @@ -0,0 +1,42 @@ +package com.qiwenshare.file.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; + +import com.qiwenshare.file.api.IOperationLogService; +import com.qiwenshare.file.domain.OperationLogBean; +import com.qiwenshare.file.mapper.OperationLogMapper; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.List; + + +@Service +public class OperationLogService extends ServiceImpl implements IOperationLogService { + + @Resource + OperationLogMapper operationLogMapper; + + @Override + public IPage selectOperationLogPage(Integer current, Integer size) { + IPage page = new Page<>(current, size); + IPage list = operationLogMapper.selectPage(page, null); + return list; + } + + @Override + public List selectOperationLog() { + List result = operationLogMapper.selectOperationLog(); + return result; + } + + @Override + public void insertOperationLog(OperationLogBean operationlogBean) { + operationLogMapper.insertOperationLog(operationlogBean); + + } + + +} diff --git a/file-web/src/main/java/com/qiwenshare/file/util/OperationLogUtil.java b/file-web/src/main/java/com/qiwenshare/file/util/OperationLogUtil.java new file mode 100644 index 0000000..ebc6dcb --- /dev/null +++ b/file-web/src/main/java/com/qiwenshare/file/util/OperationLogUtil.java @@ -0,0 +1,43 @@ +package com.qiwenshare.file.util; + +import com.qiwenshare.common.cbb.CollectUtil; +import com.qiwenshare.common.cbb.DateUtil; +import com.qiwenshare.file.domain.OperationLogBean; +import com.qiwenshare.file.domain.UserBean; +import org.apache.shiro.SecurityUtils; + +import javax.servlet.http.HttpServletRequest; + +public class OperationLogUtil { + + /** + * 构造操作日志参数 + * + * @param request 请求 + * @param isSuccess 操作是否成功(成功/失败) + * @param source 操作源模块 + * @param operation 执行操作 + * @param detail 详细信息 + * @return 操作日志参数 + */ + public static OperationLogBean getOperationLogObj(HttpServletRequest request, UserBean sessionUserBean, String isSuccess, String source, String operation, String detail) { + +// UserBean sessionUserBean = (UserBean) SecurityUtils.getSubject().getPrincipal(); + //用户需要登录才能进行的操作,需要记录操作日志 + long userId = 1; + if (sessionUserBean != null) { + userId = sessionUserBean.getUserId(); + } + OperationLogBean operationLogBean = new OperationLogBean(); + operationLogBean.setUserId(userId); + operationLogBean.setTime(DateUtil.getCurrentTime()); + operationLogBean.setTerminal(new CollectUtil().getClientIpAddress(request)); + operationLogBean.setSource(source); + operationLogBean.setResult(isSuccess); + operationLogBean.setOperation(operation); + operationLogBean.setDetail(detail); + + return operationLogBean; + } + +} diff --git a/file-web/src/main/resources/mybatis/mapper/OperationLogMapper.xml b/file-web/src/main/resources/mybatis/mapper/OperationLogMapper.xml new file mode 100644 index 0000000..b55c7eb --- /dev/null +++ b/file-web/src/main/resources/mybatis/mapper/OperationLogMapper.xml @@ -0,0 +1,19 @@ + + + + + + + + + + INSERT INTO operationLog (operation, userId, terminal, result, detail, source, time, logLevel) + VALUES (#{operation}, #{userId}, #{terminal}, #{result}, #{detail}, #{source}, #{time}, #{logLevel}); + + + \ No newline at end of file