单点日志

This commit is contained in:
zjf committed 2026-08-10 00:39:46 +08:00
1 parent e260c015ab
commit 287e8134db
5 files changed
+51 -37

No files matched your search

@@ -3,12 +3,10 @@ package com.bsd.pjcloud.app.controller;
import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bsd.pjcloud.app.api.constant.menu.AppMenuPlatformEnum; import com.bsd.pjcloud.app.api.constant.menu.AppMenuPlatformEnum;
import com.bsd.pjcloud.app.api.constant.menu.AppMenuTypeEnum; import com.bsd.pjcloud.app.api.constant.menu.AppMenuTypeEnum;
import com.bsd.pjcloud.app.api.dto.AppMenuDto;
import com.bsd.pjcloud.app.api.entity.AppMenuEntity; import com.bsd.pjcloud.app.api.entity.AppMenuEntity;
import com.bsd.pjcloud.common.core.constant.enums.YesNoEnum; import com.bsd.pjcloud.common.core.constant.enums.YesNoEnum;
import com.bsd.pjcloud.common.core.util.R; import com.bsd.pjcloud.common.core.util.R;
@@ -23,6 +21,7 @@ import org.springframework.http.HttpHeaders;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.util.List; import java.util.List;
@@ -30,6 +29,7 @@ import java.util.List;
/** /**
* 菜单管理 * 菜单管理
*/ */
@Slf4j
@RestController @RestController
@RequiredArgsConstructor @RequiredArgsConstructor
@RequestMapping("/app-menu") @RequestMapping("/app-menu")
@@ -42,12 +42,14 @@ public class AppMenuController {
/* ************************************* start app start ************************************* */ /* ************************************* start app start ************************************* */
/** /**
* 列表差 * App 端菜单列表(显式接收 enum,与 Feign 一致,避免 ParameterObject 继承 Entity 绑参歧义)
*/ */
@Operation(summary = "分页查询", description = "分页查询") @Operation(summary = "App菜单列表", description = "按平台/类型查询可见菜单")
@GetMapping("/app/list") @GetMapping("/app/list")
public R<List<AppMenuEntity>> appList(@ParameterObject AppMenuDto dto) { public R<List<AppMenuEntity>> appList(
return listVisibleAppMenus(dto); @RequestParam(value = "typeEnum", required = false) AppMenuTypeEnum typeEnum,
@RequestParam(value = "platformEnum", required = false) AppMenuPlatformEnum platformEnum) {
return listVisibleAppMenus(typeEnum, platformEnum);
} }
/** /**
@@ -56,19 +58,32 @@ public class AppMenuController {
@Inner(value = true) @Inner(value = true)
@Operation(summary = "内部-App菜单列表", description = "供 integrated 等经 Feign 拉取,与 /app-menu/app/list 一致") @Operation(summary = "内部-App菜单列表", description = "供 integrated 等经 Feign 拉取,与 /app-menu/app/list 一致")
@GetMapping("/inner/app/list") @GetMapping("/inner/app/list")
public R<List<AppMenuEntity>> innerAppList(@ParameterObject AppMenuDto dto) { public R<List<AppMenuEntity>> innerAppList(
return listVisibleAppMenus(dto); @RequestParam(value = "typeEnum", required = false) AppMenuTypeEnum typeEnum,
@RequestParam(value = "platformEnum", required = false) AppMenuPlatformEnum platformEnum) {
return listVisibleAppMenus(typeEnum, platformEnum);
} }
private R<List<AppMenuEntity>> listVisibleAppMenus(AppMenuDto dto) { /**
dto.setVisible(YesNoEnum.YES.getCode()); * 仅按 platform/type/visible 查询,使用干净 Entity,避免 DTO 脏字段污染条件。
if (ObjectUtil.isNotEmpty(dto.getPlatformEnum())) { */
dto.setPlatform(dto.getPlatformEnum().getType()); private R<List<AppMenuEntity>> listVisibleAppMenus(AppMenuTypeEnum typeEnum, AppMenuPlatformEnum platformEnum) {
AppMenuEntity query = new AppMenuEntity();
query.setVisible(YesNoEnum.YES.getCode());
if (ObjectUtil.isNotEmpty(platformEnum)) {
query.setPlatform(platformEnum.getType());
} }
if (ObjectUtil.isNotEmpty(dto.getTypeEnum())) { if (ObjectUtil.isNotEmpty(typeEnum)) {
dto.setType(dto.getTypeEnum().getType()); query.setType(typeEnum.getType());
} }
return R.ok(appMenuService.scopeList(dto, null)); List<AppMenuEntity> list = appMenuService.scopeList(query, null);
log.info("[app-menu/list] platformEnum={} platform={} typeEnum={} type={} size={}",
platformEnum,
query.getPlatform(),
typeEnum,
query.getType(),
list == null ? 0 : list.size());
return R.ok(list);
} }
/* ************************************* end app end ************************************* */ /* ************************************* end app end ************************************* */
@@ -19,7 +19,8 @@ public interface AppMenuMapper extends PjcloudBaseMapper<AppMenuEntity> {
.eq(ObjectUtil.isNotEmpty(dto.getPlatform()), AppMenuEntity::getPlatform, dto.getPlatform()) .eq(ObjectUtil.isNotEmpty(dto.getPlatform()), AppMenuEntity::getPlatform, dto.getPlatform())
.eq(ObjectUtil.isNotEmpty(dto.getType()), AppMenuEntity::getType, dto.getType()) .eq(ObjectUtil.isNotEmpty(dto.getType()), AppMenuEntity::getType, dto.getType())
.eq(ObjectUtil.isNotEmpty(dto.getVisible()), AppMenuEntity::getVisible, dto.getVisible()) .eq(ObjectUtil.isNotEmpty(dto.getVisible()), AppMenuEntity::getVisible, dto.getVisible())
.orderByAsc(AppMenuEntity::getSort) // 后台文案:排序越大越靠前
.orderByDesc(AppMenuEntity::getSort)
.orderByDesc(AppMenuEntity::getCreateTime); .orderByDesc(AppMenuEntity::getCreateTime);
return wrapper; return wrapper;
} }
@@ -12,6 +12,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestHeader;
@@ -24,6 +25,7 @@ import java.util.List;
/** /**
* App 端菜单:开放路径凭 X-App-Id/Secret;已登录路径与 {@code /app-menu/app/list} 数据一致,经 Feign 调 app-server(租户头随 Feign 传递)。 * App 端菜单:开放路径凭 X-App-Id/Secret;已登录路径与 {@code /app-menu/app/list} 数据一致,经 Feign 调 app-server(租户头随 Feign 传递)。
*/ */
@Slf4j
@RestController @RestController
@RequiredArgsConstructor @RequiredArgsConstructor
@RequestMapping("/appMenu") @RequestMapping("/appMenu")
@@ -43,7 +45,12 @@ public class AppMenuOpenController {
public R<List<AppMenuEntity>> appList( public R<List<AppMenuEntity>> appList(
@RequestParam(value = "typeEnum", required = false) AppMenuTypeEnum typeEnum, @RequestParam(value = "typeEnum", required = false) AppMenuTypeEnum typeEnum,
@RequestParam(value = "platformEnum", required = false) AppMenuPlatformEnum platformEnum) { @RequestParam(value = "platformEnum", required = false) AppMenuPlatformEnum platformEnum) {
return remoteAppMenuService.innerAppList(typeEnum, platformEnum); log.info("[appMenu/app/list] typeEnum={} platformEnum={}", typeEnum, platformEnum);
R<List<AppMenuEntity>> r = remoteAppMenuService.innerAppList(typeEnum, platformEnum);
log.info("[appMenu/app/list] resultCode={} size={}",
r == null ? null : r.getCode(),
r == null || r.getData() == null ? 0 : r.getData().size());
return r;
} }
@Operation(summary = "开放-App菜单列表", description = "凭应用凭证访问,与 app-server /app-menu/app/list 数据一致") @Operation(summary = "开放-App菜单列表", description = "凭应用凭证访问,与 app-server /app-menu/app/list 数据一致")
@@ -57,8 +64,13 @@ public class AppMenuOpenController {
if (!isValidAppCredentials(appId, appSecret)) { if (!isValidAppCredentials(appId, appSecret)) {
return R.failed("无效的应用ID或密钥"); return R.failed("无效的应用ID或密钥");
} }
// 按前端 platformEnum 区分:WECHAT(10) / ZZD(30) / SHPJ(40),勿写死浙政钉 // 按前端 platformEnum 区分:WECHAT(10) / ZZD(30) / SHPJ(40),勿写死浙政钉、勿合并平台
return remoteAppMenuService.innerAppList(typeEnum, platformEnum); log.info("[appMenu/open/app/list] typeEnum={} platformEnum={}", typeEnum, platformEnum);
R<List<AppMenuEntity>> r = remoteAppMenuService.innerAppList(typeEnum, platformEnum);
log.info("[appMenu/open/app/list] resultCode={} size={}",
r == null ? null : r.getCode(),
r == null || r.getData() == null ? 0 : r.getData().size());
return r;
} }
private boolean isValidAppCredentials(String appId, String appSecret) { private boolean isValidAppCredentials(String appId, String appSecret) {
@@ -845,31 +845,18 @@ public class ThirdPartyOAuth2Service {
} }
/** /**
* 诗画浦江单点:直连诗画开放接口获取用户,不再经对方 /login/shpj 中转。 * 诗画浦江单点:直连诗画开放接口获取用户。
* HTTP 原始请求/响应由 {@link com.bsd.pjcloud.thirdparty.shpj.ShpjUserClient} 写入单点日志。 * 成功/失败汇总日志由 Controller 统一记一条;openapi HTTP/业务失败由 ShpjUserClient 记。
*/ */
public ZZDUserDTO shjnsso(String accountId, String sessionId) { public ZZDUserDTO shjnsso(String accountId, String sessionId) {
String reqLog = "accountId=" + accountId + ",sessionId=" + sessionId + ",time=" + System.currentTimeMillis();
ShpjOpenapiUser openapiUser = shpjUserClient.getUserInfo(accountId, sessionId); ShpjOpenapiUser openapiUser = shpjUserClient.getUserInfo(accountId, sessionId);
if (openapiUser == null || openapiUser.getIsLogin() != 1) { if (openapiUser == null || openapiUser.getIsLogin() != 1) {
recordSsoLog(UserTypeEnum.SH_OPEN_USER.getDescription() + "-失败",
"/openapi/v2/{accountId}/detail", reqLog, JSON.toJSONString(openapiUser),
"FAIL", "SHPJ_NOT_LOGIN", "请先登录诗画客户端");
throw new ThirdPartyException("请先登录诗画客户端", "SHPJ_NOT_LOGIN"); throw new ThirdPartyException("请先登录诗画客户端", "SHPJ_NOT_LOGIN");
} }
if (!StringUtils.hasText(openapiUser.getMobile())) { if (!StringUtils.hasText(openapiUser.getMobile())) {
recordSsoLog(UserTypeEnum.SH_OPEN_USER.getDescription() + "-失败",
"/openapi/v2/{accountId}/detail", reqLog, JSON.toJSONString(openapiUser),
"FAIL", "SHPJ_MOBILE_EMPTY", "诗画用户手机号为空");
throw new ThirdPartyException("诗画用户手机号为空", "SHPJ_MOBILE_EMPTY"); throw new ThirdPartyException("诗画用户手机号为空", "SHPJ_MOBILE_EMPTY");
} }
ZZDUserDTO dto = mapShpjOpenapiUserToZzdDto(openapiUser); return mapShpjOpenapiUserToZzdDto(openapiUser);
com.alibaba.fastjson.JSONObject okBody = new com.alibaba.fastjson.JSONObject();
okBody.put("mappedUser", JSON.toJSON(dto));
recordSsoLog(UserTypeEnum.SH_SSO.getDescription() + "-换用户成功",
"/thirdPartyOAth2/shjnsso", reqLog, okBody.toJSONString(),
"OK", "0", null);
return dto;
} }
private static ZZDUserDTO mapShpjOpenapiUserToZzdDto(ShpjOpenapiUser user) { private static ZZDUserDTO mapShpjOpenapiUserToZzdDto(ShpjOpenapiUser user) {
@@ -88,8 +88,7 @@ public class ShpjUserClient {
"SHPJ_BIZ_" + resp.getCode(), resp.getMessage()); "SHPJ_BIZ_" + resp.getCode(), resp.getMessage());
throw new ThirdPartyException("诗画浦江接口调用失败:" + resp.getMessage(), "SHPJ_BIZ_" + resp.getCode()); throw new ThirdPartyException("诗画浦江接口调用失败:" + resp.getMessage(), "SHPJ_BIZ_" + resp.getCode());
} }
thirdPartyLogService.recordSsoLog(UserTypeEnum.SH_OPEN_USER.getDescription() + "-成功", // 成功不落库:由 /shjnsso 控制器记一条汇总日志,避免一次登录多条成功记录
apiUrl, reqLog, body, "OK", "0", null);
return resp.getData(); return resp.getData();
} catch (ThirdPartyException e) { } catch (ThirdPartyException e) {
throw e; throw e;