From 2d87ebddd81ade58295b8b123c5c7cc4a91d1d1d Mon Sep 17 00:00:00 2001 From: dongzeliang <2746733890@qq.com> Date: Fri, 7 Jun 2024 17:16:03 +0800 Subject: [PATCH 1/3] =?UTF-8?q?fix():=20=E4=BF=AE=E6=94=B9=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE=E7=BC=96=E7=A0=81=E8=A7=84=E8=8C=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/muyu/file/controller/SysFileController.java | 5 +++-- .../main/java/com/muyu/gen/controller/GenController.java | 4 ++-- .../src/main/resources/vm/java/controller.java.vm | 2 +- .../java/com/muyu/job/controller/SysJobController.java | 2 +- .../java/com/muyu/job/controller/SysJobLogController.java | 4 ++-- .../com/muyu/system/controller/SysConfigController.java | 8 ++++---- .../com/muyu/system/controller/SysDeptController.java | 4 ++-- .../com/muyu/system/controller/SysDictDataController.java | 6 +++--- .../com/muyu/system/controller/SysDictTypeController.java | 4 ++-- .../muyu/system/controller/SysLogininforController.java | 2 +- .../com/muyu/system/controller/SysMenuController.java | 2 +- .../com/muyu/system/controller/SysNoticeController.java | 4 ++-- .../com/muyu/system/controller/SysOperlogController.java | 2 +- .../com/muyu/system/controller/SysPostController.java | 4 ++-- .../com/muyu/system/controller/SysRoleController.java | 4 ++-- .../com/muyu/system/controller/SysUserController.java | 2 +- .../muyu/system/controller/SysUserOnlineController.java | 2 +- 17 files changed, 31 insertions(+), 30 deletions(-) diff --git a/cloud-modules/cloud-modules-file/src/main/java/com/muyu/file/controller/SysFileController.java b/cloud-modules/cloud-modules-file/src/main/java/com/muyu/file/controller/SysFileController.java index 5f5ce31..ed04d11 100644 --- a/cloud-modules/cloud-modules-file/src/main/java/com/muyu/file/controller/SysFileController.java +++ b/cloud-modules/cloud-modules-file/src/main/java/com/muyu/file/controller/SysFileController.java @@ -8,6 +8,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestPart; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; @@ -26,8 +27,8 @@ public class SysFileController { /** * 文件上传请求 */ - @PostMapping("upload") - public Result upload (MultipartFile file) { + @PostMapping("/upload") + public Result upload (@RequestPart(value = "file") MultipartFile file) { try { // 上传并返回访问地址 String url = sysFileService.uploadFile(file); diff --git a/cloud-modules/cloud-modules-gen/src/main/java/com/muyu/gen/controller/GenController.java b/cloud-modules/cloud-modules-gen/src/main/java/com/muyu/gen/controller/GenController.java index 92a2117..1dfe039 100644 --- a/cloud-modules/cloud-modules-gen/src/main/java/com/muyu/gen/controller/GenController.java +++ b/cloud-modules/cloud-modules-gen/src/main/java/com/muyu/gen/controller/GenController.java @@ -52,7 +52,7 @@ public class GenController extends BaseController { */ @RequiresPermissions("tool:gen:query") @GetMapping(value = "/{tableId}") - public Result getInfo (@PathVariable Long tableId) { + public Result getInfo (@PathVariable("tableId") Long tableId) { GenTable table = genTableService.selectGenTableById(tableId); List tables = genTableService.selectGenTableAll(); List list = genTableColumnService.selectGenTableColumnListByTableId(tableId); @@ -120,7 +120,7 @@ public class GenController extends BaseController { @RequiresPermissions("tool:gen:remove") @Log(title = "代码生成", businessType = BusinessType.DELETE) @DeleteMapping("/{tableIds}") - public Result remove (@PathVariable Long[] tableIds) { + public Result remove (@PathVariable("tableIds") Long[] tableIds) { genTableService.deleteGenTableByIds(tableIds); return success(); } diff --git a/cloud-modules/cloud-modules-gen/src/main/resources/vm/java/controller.java.vm b/cloud-modules/cloud-modules-gen/src/main/resources/vm/java/controller.java.vm index 8a487d0..1df5be0 100644 --- a/cloud-modules/cloud-modules-gen/src/main/resources/vm/java/controller.java.vm +++ b/cloud-modules/cloud-modules-gen/src/main/resources/vm/java/controller.java.vm @@ -109,7 +109,7 @@ public class ${ClassName}Controller extends BaseController @RequiresPermissions("${permissionPrefix}:remove") @Log(title = "${functionName}", businessType = BusinessType.DELETE) @DeleteMapping("/{${pkColumn.javaField}s}") - public Result remove(@PathVariable ${pkColumn.javaType}[] ${pkColumn.javaField}s) + public Result remove(@PathVariable("${pkColumn.javaField}s") ${pkColumn.javaType}[] ${pkColumn.javaField}s) { return toAjax(${className}Service.delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaField}s)); } diff --git a/cloud-modules/cloud-modules-job/src/main/java/com/muyu/job/controller/SysJobController.java b/cloud-modules/cloud-modules-job/src/main/java/com/muyu/job/controller/SysJobController.java index d01c4b8..2d6d2c9 100644 --- a/cloud-modules/cloud-modules-job/src/main/java/com/muyu/job/controller/SysJobController.java +++ b/cloud-modules/cloud-modules-job/src/main/java/com/muyu/job/controller/SysJobController.java @@ -142,7 +142,7 @@ public class SysJobController extends BaseController { @RequiresPermissions("monitor:job:remove") @Log(title = "定时任务", businessType = BusinessType.DELETE) @DeleteMapping("/{jobIds}") - public Result remove (@PathVariable Long[] jobIds) throws SchedulerException, TaskException { + public Result remove (@PathVariable("jobIds") Long[] jobIds) throws SchedulerException, TaskException { jobService.deleteJobByIds(jobIds); return success(); } diff --git a/cloud-modules/cloud-modules-job/src/main/java/com/muyu/job/controller/SysJobLogController.java b/cloud-modules/cloud-modules-job/src/main/java/com/muyu/job/controller/SysJobLogController.java index f26098b..f8b46e2 100644 --- a/cloud-modules/cloud-modules-job/src/main/java/com/muyu/job/controller/SysJobLogController.java +++ b/cloud-modules/cloud-modules-job/src/main/java/com/muyu/job/controller/SysJobLogController.java @@ -54,7 +54,7 @@ public class SysJobLogController extends BaseController { */ @RequiresPermissions("monitor:job:query") @GetMapping(value = "/{jobLogId}") - public Result getInfo (@PathVariable Long jobLogId) { + public Result getInfo (@PathVariable("jobLogId") Long jobLogId) { return success(jobLogService.selectJobLogById(jobLogId)); } @@ -64,7 +64,7 @@ public class SysJobLogController extends BaseController { @RequiresPermissions("monitor:job:remove") @Log(title = "定时任务调度日志", businessType = BusinessType.DELETE) @DeleteMapping("/{jobLogIds}") - public Result remove (@PathVariable Long[] jobLogIds) { + public Result remove (@PathVariable("jobLogIds") Long[] jobLogIds) { return toAjax(jobLogService.deleteJobLogByIds(jobLogIds)); } diff --git a/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysConfigController.java b/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysConfigController.java index 2e6e905..5d97890 100644 --- a/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysConfigController.java +++ b/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysConfigController.java @@ -26,7 +26,7 @@ import java.util.List; @RestController @RequestMapping("/config") public class SysConfigController extends BaseController { - + @Autowired private SysConfigService configService; @@ -54,7 +54,7 @@ public class SysConfigController extends BaseController { * 根据参数编号获取详细信息 */ @GetMapping(value = "/{configId}") - public Result getInfo (@PathVariable Long configId) { + public Result getInfo (@PathVariable("configId") Long configId) { return success(configService.getById(configId)); } @@ -62,7 +62,7 @@ public class SysConfigController extends BaseController { * 根据参数键名查询参数值 */ @GetMapping(value = "/configKey/{configKey}") - public Result getConfigKey (@PathVariable String configKey) { + public Result getConfigKey (@PathVariable("configKey") String configKey) { return success(configService.selectConfigByKey(configKey)); } @@ -100,7 +100,7 @@ public class SysConfigController extends BaseController { @RequiresPermissions("system:config:remove") @Log(title = "参数管理", businessType = BusinessType.DELETE) @DeleteMapping("/{configIds}") - public Result remove (@PathVariable Long[] configIds) { + public Result remove (@PathVariable("configIds") Long[] configIds) { configService.removeBatchByIds(Arrays.asList(configIds)); return success(); } diff --git a/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysDeptController.java b/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysDeptController.java index f1ed572..37e48fc 100644 --- a/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysDeptController.java +++ b/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysDeptController.java @@ -55,7 +55,7 @@ public class SysDeptController extends BaseController { */ @RequiresPermissions("system:dept:query") @GetMapping(value = "/{deptId}") - public Result getInfo (@PathVariable Long deptId) { + public Result getInfo (@PathVariable("deptId") Long deptId) { deptService.checkDeptDataScope(deptId); return success(deptService.selectDeptById(deptId)); } @@ -100,7 +100,7 @@ public class SysDeptController extends BaseController { @RequiresPermissions("system:dept:remove") @Log(title = "部门管理", businessType = BusinessType.DELETE) @DeleteMapping("/{deptId}") - public Result remove (@PathVariable Long deptId) { + public Result remove (@PathVariable("deptId") Long deptId) { if (deptService.hasChildByDeptId(deptId)) { return warn("存在下级部门,不允许删除"); } diff --git a/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysDictDataController.java b/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysDictDataController.java index 40f77c7..f9862d9 100644 --- a/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysDictDataController.java +++ b/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysDictDataController.java @@ -56,7 +56,7 @@ public class SysDictDataController extends BaseController { */ @RequiresPermissions("system:dict:query") @GetMapping(value = "/{dictCode}") - public Result getInfo (@PathVariable Long dictCode) { + public Result getInfo (@PathVariable("dictCode") Long dictCode) { return success(dictDataService.selectDictDataById(dictCode)); } @@ -64,7 +64,7 @@ public class SysDictDataController extends BaseController { * 根据字典类型查询字典数据信息 */ @GetMapping(value = "/type/{dictType}") - public Result dictType (@PathVariable String dictType) { + public Result dictType (@PathVariable("dictType") String dictType) { List data = dictTypeService.selectDictDataByType(dictType); if (StringUtils.isNull(data)) { data = new ArrayList(); @@ -100,7 +100,7 @@ public class SysDictDataController extends BaseController { @RequiresPermissions("system:dict:remove") @Log(title = "字典类型", businessType = BusinessType.DELETE) @DeleteMapping("/{dictCodes}") - public Result remove (@PathVariable Long[] dictCodes) { + public Result remove (@PathVariable("dictCode") Long[] dictCodes) { dictDataService.deleteDictDataByIds(dictCodes); return success(); } diff --git a/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysDictTypeController.java b/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysDictTypeController.java index 24038ef..c4a7b9f 100644 --- a/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysDictTypeController.java +++ b/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysDictTypeController.java @@ -50,7 +50,7 @@ public class SysDictTypeController extends BaseController { */ @RequiresPermissions("system:dict:query") @GetMapping(value = "/{dictId}") - public Result getInfo (@PathVariable Long dictId) { + public Result getInfo (@PathVariable("dictId") Long dictId) { return success(dictTypeService.selectDictTypeById(dictId)); } @@ -88,7 +88,7 @@ public class SysDictTypeController extends BaseController { @RequiresPermissions("system:dict:remove") @Log(title = "字典类型", businessType = BusinessType.DELETE) @DeleteMapping("/{dictIds}") - public Result remove (@PathVariable Long[] dictIds) { + public Result remove (@PathVariable("dictIds") Long[] dictIds) { dictTypeService.deleteDictTypeByIds(dictIds); return success(); } diff --git a/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysLogininforController.java b/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysLogininforController.java index 8de2fbc..c1e92b7 100644 --- a/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysLogininforController.java +++ b/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysLogininforController.java @@ -52,7 +52,7 @@ public class SysLogininforController extends BaseController { @RequiresPermissions("system:logininfor:remove") @Log(title = "登录日志", businessType = BusinessType.DELETE) @DeleteMapping("/{infoIds}") - public Result remove (@PathVariable Long[] infoIds) { + public Result remove (@PathVariable("infoIds") Long[] infoIds) { return toAjax(logininforService.deleteLogininforByIds(infoIds)); } diff --git a/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysMenuController.java b/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysMenuController.java index c22f798..e5ae348 100644 --- a/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysMenuController.java +++ b/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysMenuController.java @@ -44,7 +44,7 @@ public class SysMenuController extends BaseController { */ @RequiresPermissions("system:menu:query") @GetMapping(value = "/{menuId}") - public Result getInfo (@PathVariable Long menuId) { + public Result getInfo (@PathVariable("menuId") Long menuId) { return success(menuService.selectMenuById(menuId)); } diff --git a/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysNoticeController.java b/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysNoticeController.java index 9706350..e6b9ede 100644 --- a/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysNoticeController.java +++ b/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysNoticeController.java @@ -42,7 +42,7 @@ public class SysNoticeController extends BaseController { */ @RequiresPermissions("system:notice:query") @GetMapping(value = "/{noticeId}") - public Result getInfo (@PathVariable Long noticeId) { + public Result getInfo (@PathVariable("noticeId") Long noticeId) { return success(noticeService.selectNoticeById(noticeId)); } @@ -74,7 +74,7 @@ public class SysNoticeController extends BaseController { @RequiresPermissions("system:notice:remove") @Log(title = "通知公告", businessType = BusinessType.DELETE) @DeleteMapping("/{noticeIds}") - public Result remove (@PathVariable Long[] noticeIds) { + public Result remove (@PathVariable("noticeIds") Long[] noticeIds) { return toAjax(noticeService.deleteNoticeByIds(noticeIds)); } } diff --git a/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysOperlogController.java b/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysOperlogController.java index 35b1506..bb00d1d 100644 --- a/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysOperlogController.java +++ b/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysOperlogController.java @@ -47,7 +47,7 @@ public class SysOperlogController extends BaseController { @Log(title = "操作日志", businessType = BusinessType.DELETE) @RequiresPermissions("system:operlog:remove") @DeleteMapping("/{operIds}") - public Result remove (@PathVariable Long[] operIds) { + public Result remove (@PathVariable("operIds") Long[] operIds) { return toAjax(operLogService.deleteOperLogByIds(operIds)); } diff --git a/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysPostController.java b/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysPostController.java index 230ee8d..79f3f47 100644 --- a/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysPostController.java +++ b/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysPostController.java @@ -53,7 +53,7 @@ public class SysPostController extends BaseController { */ @RequiresPermissions("system:post:query") @GetMapping(value = "/{postId}") - public Result getInfo (@PathVariable Long postId) { + public Result getInfo (@PathVariable("postId") Long postId) { return success(postService.selectPostById(postId)); } @@ -95,7 +95,7 @@ public class SysPostController extends BaseController { @RequiresPermissions("system:post:remove") @Log(title = "岗位管理", businessType = BusinessType.DELETE) @DeleteMapping("/{postIds}") - public Result remove (@PathVariable Long[] postIds) { + public Result remove (@PathVariable("postIds") Long[] postIds) { return toAjax(postService.deletePostByIds(postIds)); } diff --git a/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysRoleController.java b/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysRoleController.java index b96268c..f8b05ad 100644 --- a/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysRoleController.java +++ b/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysRoleController.java @@ -62,7 +62,7 @@ public class SysRoleController extends BaseController { */ @RequiresPermissions("system:role:query") @GetMapping(value = "/{roleId}") - public Result getInfo (@PathVariable Long roleId) { + public Result getInfo (@PathVariable("roleId") Long roleId) { roleService.checkRoleDataScope(roleId); return success(roleService.selectRoleById(roleId)); } @@ -133,7 +133,7 @@ public class SysRoleController extends BaseController { @RequiresPermissions("system:role:remove") @Log(title = "角色管理", businessType = BusinessType.DELETE) @DeleteMapping("/{roleIds}") - public Result remove (@PathVariable Long[] roleIds) { + public Result remove (@PathVariable("roleIds") Long[] roleIds) { return toAjax(roleService.deleteRoleByIds(roleIds)); } diff --git a/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysUserController.java b/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysUserController.java index 5417a01..bc0b5fe 100644 --- a/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysUserController.java +++ b/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysUserController.java @@ -220,7 +220,7 @@ public class SysUserController extends BaseController { @RequiresPermissions("system:user:remove") @Log(title = "用户管理", businessType = BusinessType.DELETE) @DeleteMapping("/{userIds}") - public Result remove (@PathVariable Long[] userIds) { + public Result remove (@PathVariable("userIds") Long[] userIds) { if (ArrayUtils.contains(userIds, SecurityUtils.getUserId())) { return error("当前用户不能删除"); } diff --git a/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysUserOnlineController.java b/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysUserOnlineController.java index 26f7883..5b78721 100644 --- a/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysUserOnlineController.java +++ b/cloud-modules/cloud-modules-system/src/main/java/com/muyu/system/controller/SysUserOnlineController.java @@ -62,7 +62,7 @@ public class SysUserOnlineController extends BaseController { @RequiresPermissions("monitor:online:forceLogout") @Log(title = "在线用户", businessType = BusinessType.FORCE) @DeleteMapping("/{tokenId}") - public Result forceLogout (@PathVariable String tokenId) { + public Result forceLogout (@PathVariable("tokenId") String tokenId) { redisService.deleteObject(CacheConstants.LOGIN_TOKEN_KEY + tokenId); return success(); } From 23b08aaf35fbb6d9d7b8f19d486c93cd967b8faf Mon Sep 17 00:00:00 2001 From: dongzeliang <2746733890@qq.com> Date: Fri, 7 Jun 2024 21:23:05 +0800 Subject: [PATCH 2/3] =?UTF-8?q?fix():=20=E5=A2=9E=E5=8A=A0gateway=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE=E6=97=A5=E5=BF=97=EF=BC=8C=E6=9C=AA=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cloud-common/cloud-common-core/pom.xml | 4 + .../com/muyu/gateway/filter/AuthFilter.java | 1 - .../muyu/gateway/filter/log/AccessLog.java | 122 ++++++++++ .../gateway/filter/log/AccessLogFilter.java | 228 ++++++++++++++++++ .../muyu/gateway/utils/WebFrameworkUtils.java | 113 +++++++++ pom.xml | 7 + 6 files changed, 474 insertions(+), 1 deletion(-) create mode 100644 cloud-gateway/src/main/java/com/muyu/gateway/filter/log/AccessLog.java create mode 100644 cloud-gateway/src/main/java/com/muyu/gateway/filter/log/AccessLogFilter.java create mode 100644 cloud-gateway/src/main/java/com/muyu/gateway/utils/WebFrameworkUtils.java diff --git a/cloud-common/cloud-common-core/pom.xml b/cloud-common/cloud-common-core/pom.xml index 5b49ee4..cd7b8d1 100644 --- a/cloud-common/cloud-common-core/pom.xml +++ b/cloud-common/cloud-common-core/pom.xml @@ -166,6 +166,10 @@ apm-toolkit-logback-1.x + + cn.hutool + hutool-all + diff --git a/cloud-gateway/src/main/java/com/muyu/gateway/filter/AuthFilter.java b/cloud-gateway/src/main/java/com/muyu/gateway/filter/AuthFilter.java index b549a2f..47e073f 100644 --- a/cloud-gateway/src/main/java/com/muyu/gateway/filter/AuthFilter.java +++ b/cloud-gateway/src/main/java/com/muyu/gateway/filter/AuthFilter.java @@ -44,7 +44,6 @@ public class AuthFilter implements GlobalFilter, Ordered { ServerHttpRequest.Builder mutate = request.mutate(); String url = request.getURI().getPath(); - log.info("请求路径:[{}]", url); // 跳过不需要验证的路径 if (StringUtils.matches(url, ignoreWhite.getWhites())) { return chain.filter(exchange); diff --git a/cloud-gateway/src/main/java/com/muyu/gateway/filter/log/AccessLog.java b/cloud-gateway/src/main/java/com/muyu/gateway/filter/log/AccessLog.java new file mode 100644 index 0000000..6eb34af --- /dev/null +++ b/cloud-gateway/src/main/java/com/muyu/gateway/filter/log/AccessLog.java @@ -0,0 +1,122 @@ +package com.muyu.gateway.filter.log; + +import com.alibaba.cloud.commons.io.StringBuilderWriter; +import com.muyu.common.core.utils.StringUtils; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import org.springframework.cloud.gateway.route.Route; +import org.springframework.http.HttpStatus; +import org.springframework.http.HttpStatusCode; +import org.springframework.util.MultiValueMap; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +/** + * 网关的访问日志 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class AccessLog { + + /** + * 链路追踪编号 + */ + private String traceId; + /** + * 用户编号 + */ + private String userId; + + /** + * 路由 + * + * 类似 ApiAccessLogCreateReqDTO 的 applicationName + */ + private Route route; + + /** + * 协议 + */ + private String schema; + /** + * 请求方法名 + */ + private String requestMethod; + /** + * 访问地址 + */ + private String requestUrl; + /** + * 查询参数 + */ + private MultiValueMap queryParams; + /** + * 请求体 + */ + private String requestBody; + /** + * 请求头 + */ + private MultiValueMap requestHeaders; + /** + * 用户 IP + */ + private String userIp; + + /** + * 响应体 + * + * 类似 ApiAccessLogCreateReqDTO 的 resultCode + resultMsg + */ + private String responseBody; + /** + * 响应头 + */ + private MultiValueMap responseHeaders; + /** + * 响应结果 + */ + private HttpStatusCode httpStatus; + + /** + * 开始请求时间 + */ + private LocalDateTime startTime; + /** + * 结束请求时间 + */ + private LocalDateTime endTime; + /** + * 执行时长,单位:毫秒 + */ + private Integer duration; + + @Override + public String toString() { + return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE) + .append("请求简略信息", + StringUtils.format("[{}:{}:{}]-[{{}-{}}:{} ---> {}]",userId, userIp, traceId, schema, requestMethod, requestUrl,httpStatus) + ) + .append("路由", route) + .append("查询参数", queryParams) + .append("请求体", requestBody) + .append("请求头", requestHeaders) + .append("响应体", responseBody) + .append("响应头", responseHeaders) + .append("耗时/时间", + StringUtils.format( + "{}MS-{}-{}", + duration, + startTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")), + endTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))) + ) + .toString(); + } +} diff --git a/cloud-gateway/src/main/java/com/muyu/gateway/filter/log/AccessLogFilter.java b/cloud-gateway/src/main/java/com/muyu/gateway/filter/log/AccessLogFilter.java new file mode 100644 index 0000000..4631190 --- /dev/null +++ b/cloud-gateway/src/main/java/com/muyu/gateway/filter/log/AccessLogFilter.java @@ -0,0 +1,228 @@ +package com.muyu.gateway.filter.log; + +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.json.JSONUtil; +import com.alibaba.fastjson2.JSONObject; +import com.alibaba.nacos.common.utils.StringUtils; +import com.muyu.common.core.constant.SecurityConstants; +import com.muyu.gateway.utils.WebFrameworkUtils; +import lombok.extern.log4j.Log4j2; +import org.reactivestreams.Publisher; +import org.springframework.cloud.gateway.filter.GatewayFilterChain; +import org.springframework.cloud.gateway.filter.GlobalFilter; +import org.springframework.cloud.gateway.filter.factory.rewrite.CachedBodyOutputMessage; +import org.springframework.cloud.gateway.filter.factory.rewrite.ModifyRequestBodyGatewayFilterFactory; +import org.springframework.cloud.gateway.support.BodyInserterContext; +import org.springframework.cloud.gateway.support.ServerWebExchangeUtils; +import org.springframework.core.Ordered; +import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.core.io.buffer.DataBufferFactory; +import org.springframework.core.io.buffer.DataBufferUtils; +import org.springframework.core.io.buffer.DefaultDataBufferFactory; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ReactiveHttpOutputMessage; +import org.springframework.http.codec.HttpMessageReader; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.http.server.reactive.ServerHttpRequestDecorator; +import org.springframework.http.server.reactive.ServerHttpResponse; +import org.springframework.http.server.reactive.ServerHttpResponseDecorator; +import org.springframework.stereotype.Component; +import org.springframework.web.reactive.function.BodyInserter; +import org.springframework.web.reactive.function.BodyInserters; +import org.springframework.web.reactive.function.server.HandlerStrategies; +import org.springframework.web.reactive.function.server.ServerRequest; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.nio.charset.StandardCharsets; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; + + +/** + * 网关的访问日志过滤器 + *

+ *

+ * TODO 如果网关执行异常,不会记录访问日志,后续研究下 https://github.com/Silvmike/webflux-demo/blob/master/tests/src/test/java/ru/hardcoders/demo/webflux/web_handler/filters/logging + */ +@Log4j2 +@Component +public class AccessLogFilter implements GlobalFilter, Ordered { + + private final List> messageReaders = HandlerStrategies.withDefaults().messageReaders(); + + /** + * 打印日志 + * + * @param gatewayLog 网关日志 + */ + private void writeAccessLog(AccessLog gatewayLog) { + log.info("[网关日志:{}]", gatewayLog.toString()); + } + + @Override + public int getOrder() { + return Ordered.HIGHEST_PRECEDENCE; + } + + @Override + public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { + // 将 Request 中可以直接获取到的参数,设置到网关日志 + ServerHttpRequest request = exchange.getRequest(); + // TODO traceId + AccessLog gatewayLog = new AccessLog(); + gatewayLog.setUserId(request.getHeaders().getFirst(SecurityConstants.DETAILS_USER_ID)); + gatewayLog.setRoute(WebFrameworkUtils.getGatewayRoute(exchange)); + gatewayLog.setSchema(request.getURI().getScheme()); + gatewayLog.setRequestMethod(request.getMethod().name()); + gatewayLog.setRequestUrl(request.getURI().getRawPath()); + gatewayLog.setQueryParams(request.getQueryParams()); + gatewayLog.setRequestHeaders(request.getHeaders()); + gatewayLog.setStartTime(LocalDateTime.now()); + gatewayLog.setUserIp(WebFrameworkUtils.getClientIP(exchange)); + + // 继续 filter 过滤 + MediaType mediaType = request.getHeaders().getContentType(); + if (MediaType.APPLICATION_FORM_URLENCODED.isCompatibleWith(mediaType) + || MediaType.APPLICATION_JSON.isCompatibleWith(mediaType)) { // 适合 JSON 和 Form 提交的请求 + return filterWithRequestBody(exchange, chain, gatewayLog); + } + return filterWithoutRequestBody(exchange, chain, gatewayLog); + } + + private Mono filterWithoutRequestBody(ServerWebExchange exchange, GatewayFilterChain chain, AccessLog accessLog) { + // 包装 Response,用于记录 Response Body + ServerHttpResponseDecorator decoratedResponse = recordResponseLog(exchange, accessLog); + return chain.filter(exchange.mutate().response(decoratedResponse).build()) + .then(Mono.fromRunnable(() -> writeAccessLog(accessLog))); // 打印日志 + } + + /** + * 参考 {@link ModifyRequestBodyGatewayFilterFactory} 实现 + *

+ * 差别主要在于使用 modifiedBody 来读取 Request Body 数据 + */ + private Mono filterWithRequestBody(ServerWebExchange exchange, GatewayFilterChain chain, AccessLog gatewayLog) { + // 设置 Request Body 读取时,设置到网关日志 + ServerRequest serverRequest = ServerRequest.create(exchange, messageReaders); + Mono modifiedBody = serverRequest.bodyToMono(String.class).flatMap(body -> { + gatewayLog.setRequestBody(body); + return Mono.just(body); + }); + + // 创建 BodyInserter 对象 + BodyInserter, ReactiveHttpOutputMessage> bodyInserter = BodyInserters.fromPublisher(modifiedBody, String.class); + // 创建 CachedBodyOutputMessage 对象 + HttpHeaders headers = new HttpHeaders(); + headers.putAll(exchange.getRequest().getHeaders()); + // the new content type will be computed by bodyInserter + // and then set in the request decorator + headers.remove(HttpHeaders.CONTENT_LENGTH); // 移除 + CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange, headers); + // 通过 BodyInserter 将 Request Body 写入到 CachedBodyOutputMessage 中 + return bodyInserter.insert(outputMessage, new BodyInserterContext()).then(Mono.defer(() -> { + // 包装 Request,用于缓存 Request Body + ServerHttpRequest decoratedRequest = requestDecorate(exchange, headers, outputMessage); + // 包装 Response,用于记录 Response Body + ServerHttpResponseDecorator decoratedResponse = recordResponseLog(exchange, gatewayLog); + // 记录普通的 + return chain.filter(exchange.mutate().request(decoratedRequest).response(decoratedResponse).build()) + .then(Mono.fromRunnable(() -> writeAccessLog(gatewayLog))); // 打印日志 + + })); + } + + /** + * 记录响应日志 + * 通过 DataBufferFactory 解决响应体分段传输问题。 + */ + private ServerHttpResponseDecorator recordResponseLog(ServerWebExchange exchange, AccessLog gatewayLog) { + ServerHttpResponse response = exchange.getResponse(); + return new ServerHttpResponseDecorator(response) { + + @Override + public Mono writeWith(Publisher body) { + if (body instanceof Flux) { + DataBufferFactory bufferFactory = response.bufferFactory(); + // 计算执行时间 + gatewayLog.setEndTime(LocalDateTime.now()); + gatewayLog.setDuration((int) (LocalDateTimeUtil.between(gatewayLog.getStartTime(), + gatewayLog.getEndTime()).toMillis())); + // 设置其它字段 +// gatewayLog.setUserId(SecurityFrameworkUtils.getLoginUserId(exchange)); + gatewayLog.setResponseHeaders(response.getHeaders()); + gatewayLog.setHttpStatus(response.getStatusCode()); + + // 获取响应类型,如果是 json 就打印 + String originalResponseContentType = exchange.getAttribute(ServerWebExchangeUtils.ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR); + if (StringUtils.isNotBlank(originalResponseContentType) + && originalResponseContentType.contains("application/json")) { + Flux fluxBody = Flux.from(body); + return super.writeWith(fluxBody.buffer().map(dataBuffers -> { + // 设置 response body 到网关日志 + byte[] content = readContent(dataBuffers); + String responseResult = new String(content, StandardCharsets.UTF_8); + gatewayLog.setResponseBody(responseResult); + + // 响应 + return bufferFactory.wrap(content); + })); + } + } + // if body is not a flux. never got there. + return super.writeWith(body); + } + }; + } + + // ========== 参考 ModifyRequestBodyGatewayFilterFactory 中的方法 ========== + + /** + * 请求装饰器,支持重新计算 headers、body 缓存 + * + * @param exchange 请求 + * @param headers 请求头 + * @param outputMessage body 缓存 + * @return 请求装饰器 + */ + private ServerHttpRequestDecorator requestDecorate(ServerWebExchange exchange, HttpHeaders headers, CachedBodyOutputMessage outputMessage) { + return new ServerHttpRequestDecorator(exchange.getRequest()) { + + @Override + public HttpHeaders getHeaders() { + long contentLength = headers.getContentLength(); + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.putAll(super.getHeaders()); + if (contentLength > 0) { + httpHeaders.setContentLength(contentLength); + } else { + httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked"); + } + return httpHeaders; + } + + @Override + public Flux getBody() { + return outputMessage.getBody(); + } + }; + } + + // ========== 参考 ModifyResponseBodyGatewayFilterFactory 中的方法 ========== + + private byte[] readContent(List dataBuffers) { + // 合并多个流集合,解决返回体分段传输 + DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory(); + DataBuffer join = dataBufferFactory.join(dataBuffers); + byte[] content = new byte[join.readableByteCount()]; + join.read(content); + // 释放掉内存 + DataBufferUtils.release(join); + return content; + } + +} diff --git a/cloud-gateway/src/main/java/com/muyu/gateway/utils/WebFrameworkUtils.java b/cloud-gateway/src/main/java/com/muyu/gateway/utils/WebFrameworkUtils.java new file mode 100644 index 0000000..2443e13 --- /dev/null +++ b/cloud-gateway/src/main/java/com/muyu/gateway/utils/WebFrameworkUtils.java @@ -0,0 +1,113 @@ +package com.muyu.gateway.utils; + +import cn.hutool.core.net.NetUtil; +import cn.hutool.core.util.ArrayUtil; +import com.alibaba.fastjson2.JSONObject; +import lombok.extern.log4j.Log4j2; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.cloud.gateway.route.Route; +import org.springframework.cloud.gateway.support.ServerWebExchangeUtils; +import org.springframework.core.io.buffer.DataBufferFactory; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.http.server.reactive.ServerHttpResponse; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Mono; + +/** + * Web 工具类 + * + * + */ +@Log4j2 +public class WebFrameworkUtils { + + private static final String HEADER_TENANT_ID = "tenant-id"; + + private WebFrameworkUtils() {} + + /** + * 将 Gateway 请求中的 header,设置到 HttpHeaders 中 + * + * @param tenantId 租户编号 + * @param httpHeaders WebClient 的请求 + */ + public static void setTenantIdHeader(Long tenantId, HttpHeaders httpHeaders) { + if (tenantId == null) { + return; + } + httpHeaders.set(HEADER_TENANT_ID, String.valueOf(tenantId)); + } + + public static Long getTenantId(ServerWebExchange exchange) { + String tenantId = exchange.getRequest().getHeaders().getFirst(HEADER_TENANT_ID); + return tenantId != null ? Long.parseLong(tenantId) : null; + } + + /** + * 返回 JSON 字符串 + * + * @param exchange 响应 + * @param object 对象,会序列化成 JSON 字符串 + */ + @SuppressWarnings("deprecation") // 必须使用 APPLICATION_JSON_UTF8_VALUE,否则会乱码 + public static Mono writeJSON(ServerWebExchange exchange, Object object) { + // 设置 header + ServerHttpResponse response = exchange.getResponse(); + response.getHeaders().setContentType(MediaType.APPLICATION_JSON_UTF8); + // 设置 body + return response.writeWith(Mono.fromSupplier(() -> { + DataBufferFactory bufferFactory = response.bufferFactory(); + try { + return bufferFactory.wrap(JSONObject.toJSONString(object).getBytes()); + } catch (Exception ex) { + ServerHttpRequest request = exchange.getRequest(); + log.error("[writeJSON][uri({}/{}) 发生异常]", request.getURI(), request.getMethod(), ex); + return bufferFactory.wrap(new byte[0]); + } + })); + } + + /** + * 获得客户端 IP + * + * + * @param exchange 请求 + * @param otherHeaderNames 其它 header 名字的数组 + * @return 客户端 IP + */ + public static String getClientIP(ServerWebExchange exchange, String... otherHeaderNames) { + String[] headers = { "X-Forwarded-For", "X-Real-IP", "Proxy-Client-IP", "WL-Proxy-Client-IP", "HTTP_CLIENT_IP", "HTTP_X_FORWARDED_FOR" }; + if (ArrayUtil.isNotEmpty(otherHeaderNames)) { + headers = ArrayUtil.addAll(headers, otherHeaderNames); + } + // 方式一,通过 header 获取 + String ip; + for (String header : headers) { + ip = exchange.getRequest().getHeaders().getFirst(header); + if (!NetUtil.isUnknown(ip)) { + return NetUtil.getMultistageReverseProxyIp(ip); + } + } + + // 方式二,通过 remoteAddress 获取 + if (exchange.getRequest().getRemoteAddress() == null) { + return null; + } + ip = exchange.getRequest().getRemoteAddress().getHostString(); + return NetUtil.getMultistageReverseProxyIp(ip); + } + + /** + * 获得请求匹配的 Route 路由 + * + * @param exchange 请求 + * @return 路由 + */ + public static Route getGatewayRoute(ServerWebExchange exchange) { + return exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR); + } + +} diff --git a/pom.xml b/pom.xml index 2adcc87..d730315 100644 --- a/pom.xml +++ b/pom.xml @@ -39,6 +39,7 @@ 9.2.0 6.1.0-M2 1.3.2 + 5.8.27 @@ -99,6 +100,12 @@ ${javax.annotation.version} + + cn.hutool + hutool-all + ${hutool.version} + + io.swagger From 68e5411860a664b08488dec03c83830ac3b32a88 Mon Sep 17 00:00:00 2001 From: DongZeLiang <2746733890@qq.com> Date: Fri, 7 Jun 2024 21:45:32 +0800 Subject: [PATCH 3/3] =?UTF-8?q?fix():=E6=9B=B4=E6=96=B0=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E6=A8=A1=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../muyu/gateway/filter/log/AccessLog.java | 2 +- .../gateway/filter/log/AccessLogFilter.java | 37 +++++++++---------- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/cloud-gateway/src/main/java/com/muyu/gateway/filter/log/AccessLog.java b/cloud-gateway/src/main/java/com/muyu/gateway/filter/log/AccessLog.java index 6eb34af..a6bb706 100644 --- a/cloud-gateway/src/main/java/com/muyu/gateway/filter/log/AccessLog.java +++ b/cloud-gateway/src/main/java/com/muyu/gateway/filter/log/AccessLog.java @@ -102,7 +102,7 @@ public class AccessLog { public String toString() { return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE) .append("请求简略信息", - StringUtils.format("[{}:{}:{}]-[{{}-{}}:{} ---> {}]",userId, userIp, traceId, schema, requestMethod, requestUrl,httpStatus) + StringUtils.format("[userId:[{}]-userIp:[{}]-traceId:[{}]] ---结果--- {{}-{}}:{} ---> {}",userId, userIp, traceId, schema, requestMethod, requestUrl,httpStatus) ) .append("路由", route) .append("查询参数", queryParams) diff --git a/cloud-gateway/src/main/java/com/muyu/gateway/filter/log/AccessLogFilter.java b/cloud-gateway/src/main/java/com/muyu/gateway/filter/log/AccessLogFilter.java index 4631190..6307684 100644 --- a/cloud-gateway/src/main/java/com/muyu/gateway/filter/log/AccessLogFilter.java +++ b/cloud-gateway/src/main/java/com/muyu/gateway/filter/log/AccessLogFilter.java @@ -1,9 +1,6 @@ package com.muyu.gateway.filter.log; import cn.hutool.core.date.LocalDateTimeUtil; -import cn.hutool.core.map.MapUtil; -import cn.hutool.json.JSONUtil; -import com.alibaba.fastjson2.JSONObject; import com.alibaba.nacos.common.utils.StringUtils; import com.muyu.common.core.constant.SecurityConstants; import com.muyu.gateway.utils.WebFrameworkUtils; @@ -40,7 +37,6 @@ import reactor.core.publisher.Mono; import java.nio.charset.StandardCharsets; import java.time.LocalDateTime; import java.util.List; -import java.util.Map; /** @@ -66,7 +62,7 @@ public class AccessLogFilter implements GlobalFilter, Ordered { @Override public int getOrder() { - return Ordered.HIGHEST_PRECEDENCE; + return -99; } @Override @@ -74,24 +70,25 @@ public class AccessLogFilter implements GlobalFilter, Ordered { // 将 Request 中可以直接获取到的参数,设置到网关日志 ServerHttpRequest request = exchange.getRequest(); // TODO traceId - AccessLog gatewayLog = new AccessLog(); - gatewayLog.setUserId(request.getHeaders().getFirst(SecurityConstants.DETAILS_USER_ID)); - gatewayLog.setRoute(WebFrameworkUtils.getGatewayRoute(exchange)); - gatewayLog.setSchema(request.getURI().getScheme()); - gatewayLog.setRequestMethod(request.getMethod().name()); - gatewayLog.setRequestUrl(request.getURI().getRawPath()); - gatewayLog.setQueryParams(request.getQueryParams()); - gatewayLog.setRequestHeaders(request.getHeaders()); - gatewayLog.setStartTime(LocalDateTime.now()); - gatewayLog.setUserIp(WebFrameworkUtils.getClientIP(exchange)); + AccessLog accessLog = AccessLog.builder() + .userId(request.getHeaders().getFirst(SecurityConstants.DETAILS_USER_ID)) + .route(WebFrameworkUtils.getGatewayRoute(exchange)) + .schema(request.getURI().getScheme()) + .requestMethod(request.getMethod().name()) + .requestUrl(request.getURI().getRawPath()) + .queryParams(request.getQueryParams()) + .requestHeaders(request.getHeaders()) + .startTime(LocalDateTime.now()) + .userIp(WebFrameworkUtils.getClientIP(exchange)) + .build(); // 继续 filter 过滤 MediaType mediaType = request.getHeaders().getContentType(); - if (MediaType.APPLICATION_FORM_URLENCODED.isCompatibleWith(mediaType) - || MediaType.APPLICATION_JSON.isCompatibleWith(mediaType)) { // 适合 JSON 和 Form 提交的请求 - return filterWithRequestBody(exchange, chain, gatewayLog); - } - return filterWithoutRequestBody(exchange, chain, gatewayLog); + return MediaType.APPLICATION_FORM_URLENCODED.isCompatibleWith(mediaType) || MediaType.APPLICATION_JSON.isCompatibleWith(mediaType) + ? + filterWithRequestBody(exchange, chain, accessLog) + : + filterWithoutRequestBody(exchange, chain, accessLog); } private Mono filterWithoutRequestBody(ServerWebExchange exchange, GatewayFilterChain chain, AccessLog accessLog) {