1、结构化调整;

This commit is contained in:
2026-03-31 19:58:48 +08:00
parent ebdbdbeb41
commit e78565ea5a
369 changed files with 3790 additions and 1195 deletions

View File

@@ -1,6 +1,6 @@
package com.njcn.msgpush.framework.common.biz.infra.logger;
package com.njcn.msgpush.framework.common.biz.system.logger;
import com.njcn.msgpush.framework.common.biz.infra.logger.dto.ApiAccessLogCreateReqDTO;
import com.njcn.msgpush.framework.common.biz.system.logger.dto.ApiAccessLogCreateReqDTO;
import com.njcn.msgpush.framework.common.enums.RpcConstants;
import com.njcn.msgpush.framework.common.pojo.CommonResult;
import io.swagger.v3.oas.annotations.Operation;
@@ -11,11 +11,11 @@ import org.springframework.scheduling.annotation.Async;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@FeignClient(name = RpcConstants.INFRA_NAME) // TODO 芋艿fallbackFactory =
@FeignClient(name = RpcConstants.SYSTEM_NAME)
@Tag(name = "RPC 服务 - API 访问日志")
public interface ApiAccessLogCommonApi {
String PREFIX = RpcConstants.INFRA_PREFIX + "/api-access-log";
String PREFIX = RpcConstants.SYSTEM_PREFIX + "/api-access-log";
@PostMapping(PREFIX + "/create")
@Operation(summary = "创建 API 访问日志")

View File

@@ -1,6 +1,6 @@
package com.njcn.msgpush.framework.common.biz.infra.logger;
package com.njcn.msgpush.framework.common.biz.system.logger;
import com.njcn.msgpush.framework.common.biz.infra.logger.dto.ApiErrorLogCreateReqDTO;
import com.njcn.msgpush.framework.common.biz.system.logger.dto.ApiErrorLogCreateReqDTO;
import com.njcn.msgpush.framework.common.enums.RpcConstants;
import com.njcn.msgpush.framework.common.pojo.CommonResult;
import io.swagger.v3.oas.annotations.Operation;
@@ -11,11 +11,11 @@ import org.springframework.scheduling.annotation.Async;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@FeignClient(name = RpcConstants.INFRA_NAME) // TODO 芋艿fallbackFactory =
@FeignClient(name = RpcConstants.SYSTEM_NAME)
@Tag(name = "RPC 服务 - API 异常日志")
public interface ApiErrorLogCommonApi {
String PREFIX = RpcConstants.INFRA_PREFIX + "/api-error-log";
String PREFIX = RpcConstants.SYSTEM_PREFIX + "/api-error-log";
@PostMapping(PREFIX + "/create")
@Operation(summary = "创建 API 异常日志")

View File

@@ -1,7 +1,8 @@
package com.njcn.msgpush.framework.common.biz.infra.logger.dto;
package com.njcn.msgpush.framework.common.biz.system.logger.dto;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.experimental.Accessors;
import java.time.LocalDateTime;

View File

@@ -1,4 +1,4 @@
package com.njcn.msgpush.framework.common.biz.infra.logger.dto;
package com.njcn.msgpush.framework.common.biz.system.logger.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;

View File

@@ -0,0 +1,27 @@
package com.njcn.msgpush.module.push.client.factory;
import cn.hutool.core.util.StrUtil;
/**
* 工厂侧通用辅助方法。
*/
public final class ProviderFactorySupport {
private ProviderFactorySupport() {
}
/**
* 只要任一配置值为空白,就认为当前渠道配置不完整。
*/
public static boolean hasBlank(String... values) {
if (values == null || values.length == 0) {
return true;
}
for (String value : values) {
if (StrUtil.isBlank(value)) {
return true;
}
}
return false;
}
}

View File

@@ -0,0 +1,21 @@
package com.njcn.msgpush.module.push.client.sender;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 发送结果大类。
* 这里只描述“主流程该怎么走”,不承载第三方原始错误细节。
*/
@Getter
@AllArgsConstructor
public enum SendOutcome {
SUCCESS("发送成功"),
ACCEPTED("第三方已受理"),
FAILED("发送失败"),
RETRYABLE_FAILED("发送失败,可重试"),
UNSUPPORTED_CHANNEL("当前服务商不支持该发送渠道"),
CONFIG_INVALID("当前服务商渠道配置不完整");
private final String desc;
}

View File

@@ -0,0 +1,109 @@
package com.njcn.msgpush.module.push.client.sender;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
/**
* 统一发送结果。
* outcome 负责主流程分支判断;
* errorCode/message 负责平台内部归类和中文展示;
* retryable 负责决定是否进入重试队列。
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class SendResult {
/**
* 结果分类,供主流程分支判断使用。
*/
private SendOutcome outcome;
/**
* 平台统一错误码。
*/
private String errorCode;
/**
* 中文错误说明。
*/
private String message;
/**
* 服务商原始错误码。
*/
private String providerRawCode;
/**
* 是否允许进入重试队列。
*/
private boolean retryable;
/**
* 第三方消息 ID。
*/
private String thirdPartyId;
/**
* 发送时间。
*/
private LocalDateTime sendTime;
/**
* 耗时,单位毫秒。
*/
private Integer costTime;
/**
* 第三方已明确返回成功。
*/
public static SendResult success(LocalDateTime sendTime, Integer costTime, String thirdPartyId) {
return SendResult.builder()
.outcome(SendOutcome.SUCCESS)
.sendTime(sendTime)
.costTime(costTime)
.thirdPartyId(thirdPartyId)
.build();
}
/**
* 第三方已受理,请等待异步回执或延迟查询更新最终状态。
*/
public static SendResult accepted(LocalDateTime sendTime, Integer costTime, String thirdPartyId) {
return SendResult.builder()
.outcome(SendOutcome.ACCEPTED)
.sendTime(sendTime)
.costTime(costTime)
.thirdPartyId(thirdPartyId)
.build();
}
/**
* 服务商不支持该渠道能力。
*/
public static SendResult unsupported(String message) {
return SendResult.builder()
.outcome(SendOutcome.UNSUPPORTED_CHANNEL)
.errorCode("UNSUPPORTED_CHANNEL")
.message(message)
.retryable(false)
.build();
}
/**
* 服务商理论支持该能力,但当前配置不完整或初始化失败。
*/
public static SendResult configInvalid(String message) {
return SendResult.builder()
.outcome(SendOutcome.CONFIG_INVALID)
.errorCode("CONFIG_INVALID")
.message(message)
.retryable(false)
.build();
}
}

View File

@@ -0,0 +1,30 @@
package com.njcn.msgpush.module.push.client.sender.fallback;
import com.njcn.msgpush.module.push.client.sender.SendOutcome;
import com.njcn.msgpush.module.push.client.sender.SendResult;
/**
* 用于承载“发送前即可确定”的固定结果。
* 例如:当前服务商不支持该渠道,或当前渠道配置不完整。
*/
public abstract class AbstractFixedResultSender {
private final SendOutcome outcome;
private final String message;
protected AbstractFixedResultSender(SendOutcome outcome, String message) {
if (!SendOutcome.UNSUPPORTED_CHANNEL.equals(outcome) && !SendOutcome.CONFIG_INVALID.equals(outcome)) {
throw new IllegalArgumentException("固定结果 sender 仅支持不支持渠道或配置无效场景");
}
this.outcome = outcome;
this.message = message;
}
protected SendResult buildResult() {
if (SendOutcome.UNSUPPORTED_CHANNEL.equals(outcome)) {
return SendResult.unsupported(message);
}
return SendResult.configInvalid(message);
}
}

View File

@@ -0,0 +1,21 @@
package com.njcn.msgpush.module.push.client.sender.fallback;
import com.njcn.msgpush.module.push.client.sender.AppPushSender;
import com.njcn.msgpush.module.push.client.sender.SendOutcome;
import com.njcn.msgpush.module.push.client.sender.SendResult;
import com.njcn.msgpush.module.push.dal.dataobject.message.MessageRecordDO;
/**
* APP 推送渠道固定结果 sender。
*/
public class FixedResultAppPushSender extends AbstractFixedResultSender implements AppPushSender {
public FixedResultAppPushSender(SendOutcome outcome, String message) {
super(outcome, message);
}
@Override
public SendResult appPush(MessageRecordDO messageRecord) {
return this.buildResult();
}
}

View File

@@ -0,0 +1,23 @@
package com.njcn.msgpush.module.push.client.sender.fallback;
import com.njcn.msgpush.module.push.client.sender.EmailSender;
import com.njcn.msgpush.module.push.client.sender.SendOutcome;
import com.njcn.msgpush.module.push.client.sender.SendResult;
import com.njcn.msgpush.module.push.dal.dataobject.message.MessageRecordDO;
import java.util.Map;
/**
* 邮件渠道固定结果 sender。
*/
public class FixedResultEmailSender extends AbstractFixedResultSender implements EmailSender {
public FixedResultEmailSender(SendOutcome outcome, String message) {
super(outcome, message);
}
@Override
public SendResult sendEmail(MessageRecordDO messageRecord, Map<String, Object> params) {
return this.buildResult();
}
}

View File

@@ -0,0 +1,39 @@
package com.njcn.msgpush.module.push.client.sender.fallback;
import com.njcn.msgpush.module.push.client.sender.SendOutcome;
import com.njcn.msgpush.module.push.client.sender.SendResult;
import com.njcn.msgpush.module.push.client.sender.SmsSender;
import com.njcn.msgpush.module.push.dal.dataobject.message.MessageRecordDO;
import java.util.ArrayList;
import java.util.List;
/**
* 短信渠道固定结果 sender。
* 用于替代返回 null让主流程始终拿到可执行对象。
*/
public class FixedResultSmsSender extends AbstractFixedResultSender implements SmsSender {
public FixedResultSmsSender(SendOutcome outcome, String message) {
super(outcome, message);
}
@Override
public SendResult sendSms(MessageRecordDO messageRecord) {
return this.buildResult();
}
@Override
public List<SendResult> sendBatchSms(List<MessageRecordDO> messageList) {
List<SendResult> results = new ArrayList<>(messageList.size());
for (int i = 0; i < messageList.size(); i++) {
results.add(this.buildResult());
}
return results;
}
@Override
public void queryTemplate(String templateIdentifier) {
// 固定结果 sender 不触达第三方,无需查询模板。
}
}

View File

@@ -0,0 +1,101 @@
package com.njcn.msgpush.module.push.client.sender.impl.apppush;
import com.getui.push.v2.sdk.ApiHelper;
import com.getui.push.v2.sdk.GtApiConfiguration;
import com.getui.push.v2.sdk.api.PushApi;
import com.getui.push.v2.sdk.common.ApiResult;
import com.getui.push.v2.sdk.dto.req.Audience;
import com.getui.push.v2.sdk.dto.req.Settings;
import com.getui.push.v2.sdk.dto.req.message.PushDTO;
import com.getui.push.v2.sdk.dto.req.message.PushMessage;
import com.getui.push.v2.sdk.dto.req.message.android.GTNotification;
import com.njcn.msgpush.module.push.client.sender.AppPushSender;
import com.njcn.msgpush.module.push.client.sender.SendResult;
import com.njcn.msgpush.module.push.client.sender.Sender;
import com.njcn.msgpush.module.push.client.setting.impl.UniPushAppPushSetting;
import com.njcn.msgpush.module.push.dal.dataobject.message.MessageRecordDO;
import lombok.extern.slf4j.Slf4j;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Map;
@Slf4j
public class UniPushAppPushSender implements AppPushSender {
private final Sender sender;
private PushApi pushApi;
public UniPushAppPushSender(UniPushAppPushSetting uniPushAppPushSetting, Sender sender) {
this.sender = sender;
try {
GtApiConfiguration gtApiConfiguration = new GtApiConfiguration();
gtApiConfiguration.setAppId(uniPushAppPushSetting.getAppId());
gtApiConfiguration.setAppKey(uniPushAppPushSetting.getAppKey());
gtApiConfiguration.setMasterSecret(uniPushAppPushSetting.getMasterSecret());
gtApiConfiguration.setDomain("https://restapi.getui.com/v2/");
ApiHelper apiHelper = ApiHelper.build(gtApiConfiguration);
this.pushApi = apiHelper.creatApi(PushApi.class);
} catch (Exception e) {
log.error("UniPush 客户端初始化失败", e);
this.pushApi = null;
}
}
@Override
public SendResult appPush(MessageRecordDO message) {
if (pushApi == null) {
return SendResult.configInvalid("当前服务商 APP 推送渠道初始化失败");
}
try {
LocalDateTime now = LocalDateTime.now();
long start = now.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
PushDTO<Audience> pushDTO = this.buildPushDTO(message.getTitle(), message.getContent());
Audience audience = new Audience();
audience.addCid(message.getReceiver());
pushDTO.setAudience(audience);
ApiResult<Map<String, Map<String, String>>> apiResult = pushApi.pushToSingleByCid(pushDTO);
LocalDateTime end = LocalDateTime.now();
int costTime = (int) (end.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() - start);
message.setSendTime(now);
message.setCostTime(costTime);
if (apiResult.isSuccess()) {
// UniPush 同步接口返回成功时,当前平台将其视为已受理。
return SendResult.accepted(now, costTime, null);
}
// 个推原始错误码在这里统一映射为平台错误码和中文错误信息。
return this.sender.buildFailureResult(
message,
String.valueOf(apiResult.getCode()),
apiResult.getMsg(),
"THIRD_PARTY_CALL_FAILED",
"第三方服务调用失败",
false
);
} catch (Exception e) {
log.error("UniPush 推送失败", e);
return this.sender.buildCallFailedResult("第三方服务调用失败");
}
}
private PushDTO<Audience> buildPushDTO(String title, String content) {
PushDTO<Audience> pushDTO = new PushDTO<>();
pushDTO.setRequestId(String.valueOf(System.currentTimeMillis()));
Settings settings = new Settings();
settings.setTtl(3600000);
pushDTO.setSettings(settings);
PushMessage pushMessage = new PushMessage();
GTNotification notification = new GTNotification();
notification.setTitle(title);
notification.setBody(content);
notification.setClickType("startapp");
pushMessage.setNotification(notification);
pushDTO.setPushMessage(pushMessage);
return pushDTO;
}
}

View File

@@ -0,0 +1,110 @@
package com.njcn.msgpush.module.push.client.sender.impl.email;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.dm20151123.Client;
import com.aliyun.dm20151123.models.SingleSendMailRequest;
import com.aliyun.dm20151123.models.SingleSendMailResponse;
import com.aliyun.teaopenapi.models.Config;
import com.aliyun.teautil.models.RuntimeOptions;
import com.njcn.msgpush.module.push.client.sender.EmailSender;
import com.njcn.msgpush.module.push.client.sender.SendResult;
import com.njcn.msgpush.module.push.client.sender.Sender;
import com.njcn.msgpush.module.push.client.setting.impl.AliYunMailSetting;
import com.njcn.msgpush.module.push.dal.dataobject.message.MessageRecordDO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Map;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
@Slf4j
public class AliyunEmailSender implements EmailSender {
private static final String ACCOUNT_NAME = "accountName";
private static final String REPLY_TO_ADDRESS = "replyToAddress";
private static final String FROM_ALIAS = "fromAlias";
private final Sender sender;
private Client emailClient;
public AliyunEmailSender(AliYunMailSetting aliYunMailSetting, Sender sender) {
this.sender = sender;
if (ObjectUtil.isNotNull(aliYunMailSetting)) {
Config config = new Config()
.setAccessKeyId(aliYunMailSetting.getAccessKeyId())
.setAccessKeySecret(aliYunMailSetting.getAccessKeySecret())
.setRegionId(aliYunMailSetting.getRegionId())
.setEndpoint(aliYunMailSetting.getEndpoint());
try {
this.emailClient = new Client(config);
} catch (Exception e) {
log.error("阿里云邮件客户端初始化失败", e);
this.emailClient = null;
}
}
}
@Override
public SendResult sendEmail(MessageRecordDO message, Map<String, Object> params) {
if (emailClient == null) {
return SendResult.configInvalid("当前服务商邮件渠道初始化失败");
}
Future<SendResult> future = this.sender.MSG_PUSH_THREAD_POOL_EXECUTOR.submit(() -> {
RuntimeOptions runtimeOptions = new RuntimeOptions();
runtimeOptions.autoretry = true;
JSONObject jsonObject = JSON.parseObject(message.getExtraInfo());
SingleSendMailRequest request = new SingleSendMailRequest()
.setAccountName(jsonObject.getString(ACCOUNT_NAME))
.setAddressType(1)
.setReplyToAddress(jsonObject.getBooleanValue(REPLY_TO_ADDRESS))
.setToAddress(message.getReceiver())
.setSubject(message.getTitle())
.setHtmlBody(message.getContent())
.setTextBody("")
.setFromAlias(jsonObject.getString(FROM_ALIAS));
try {
LocalDateTime now = LocalDateTime.now();
long start = now.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
SingleSendMailResponse response = this.emailClient.singleSendMailWithOptions(request, runtimeOptions);
LocalDateTime end = LocalDateTime.now();
int costTime = (int) (end.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() - start);
message.setSendTime(now);
message.setCostTime(costTime);
if (HttpStatus.OK.value() == response.getStatusCode()) {
// 邮件接口同步返回成功时,当前平台直接认定本次发送成功。
return SendResult.success(now, costTime, null);
}
// 邮件服务失败同样统一转换为平台错误码和中文错误信息。
return this.sender.buildFailureResult(
message,
String.valueOf(response.getStatusCode()),
null,
"THIRD_PARTY_CALL_FAILED",
"第三方服务调用失败",
false
);
} catch (Exception e) {
log.error("阿里云邮件发送失败", e);
return this.sender.buildCallFailedResult("第三方服务调用失败");
}
});
try {
return future.get(3, TimeUnit.SECONDS);
} catch (Exception e) {
log.error("阿里云邮件发送超时或执行异常", e);
return this.sender.buildTimeoutResult();
}
}
}

View File

@@ -0,0 +1,156 @@
package com.njcn.msgpush.module.push.client.sender.impl.sms;
import cn.hutool.core.util.ObjectUtil;
import com.aliyun.dysmsapi20170525.Client;
import com.aliyun.dysmsapi20170525.models.QuerySendDetailsRequest;
import com.aliyun.dysmsapi20170525.models.QuerySendDetailsResponse;
import com.aliyun.dysmsapi20170525.models.SendSmsRequest;
import com.aliyun.dysmsapi20170525.models.SendSmsResponse;
import com.aliyun.teaopenapi.models.Config;
import com.aliyun.teautil.models.RuntimeOptions;
import com.njcn.msgpush.module.push.client.sender.SendResult;
import com.njcn.msgpush.module.push.client.sender.Sender;
import com.njcn.msgpush.module.push.client.sender.SmsSender;
import com.njcn.msgpush.module.push.client.setting.impl.AliYunMailSetting;
import com.njcn.msgpush.module.push.dal.dataobject.message.MessageRecordDO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
@Slf4j
public class AliyunSmsSender implements SmsSender {
public static final String OK = "OK";
private final Sender sender;
private Client smsClient;
public AliyunSmsSender(AliYunMailSetting aliYunSmsSetting, Sender sender) {
this.sender = sender;
if (ObjectUtil.isNotNull(aliYunSmsSetting)) {
Config config = new Config()
.setAccessKeyId(aliYunSmsSetting.getAccessKeyId())
.setAccessKeySecret(aliYunSmsSetting.getAccessKeySecret())
.setRegionId(aliYunSmsSetting.getRegionId())
.setEndpoint(aliYunSmsSetting.getEndpoint());
try {
this.smsClient = new Client(config);
} catch (Exception e) {
log.error("阿里云短信客户端初始化失败", e);
this.smsClient = null;
}
}
}
@Override
public SendResult sendSms(MessageRecordDO message) {
if (smsClient == null) {
return SendResult.configInvalid("当前服务商短信渠道初始化失败");
}
Future<SendResult> future = this.sender.MSG_PUSH_THREAD_POOL_EXECUTOR.submit(() -> {
RuntimeOptions runtimeOptions = new RuntimeOptions();
runtimeOptions.autoretry = true;
SendSmsRequest request = new SendSmsRequest()
.setPhoneNumbers(message.getReceiver())
.setSignName(message.getTitle())
.setTemplateCode(message.getTemplateCode())
.setTemplateParam(message.getTemplateParams());
try {
LocalDateTime now = LocalDateTime.now();
long start = now.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
SendSmsResponse response = this.smsClient.sendSmsWithOptions(request, runtimeOptions);
LocalDateTime end = LocalDateTime.now();
int costTime = (int) (end.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() - start);
message.setSendTime(now);
message.setCostTime(costTime);
if (HttpStatus.OK.value() == response.getStatusCode() && response.getBody() != null && OK.equals(response.getBody().getCode())) {
String bizId = response.getBody().getBizId();
message.setThirdPartyId(bizId);
// 阿里云短信同步接口只表示“已受理”,最终是否送达依赖后续回执查询。
this.getDownInfo(bizId, message);
return SendResult.accepted(now, costTime, bizId);
}
String providerRawCode = response.getBody() == null ? null : response.getBody().getCode();
String providerRawMessage = response.getBody() == null ? null : response.getBody().getMessage();
// 第三方失败统一在这里映射为平台错误码和中文错误信息。
return this.sender.buildFailureResult(
message,
providerRawCode,
providerRawMessage,
"THIRD_PARTY_CALL_FAILED",
"第三方服务调用失败",
false
);
} catch (Exception e) {
log.error("阿里云短信发送失败", e);
return this.sender.buildCallFailedResult("第三方服务调用失败");
}
});
try {
return future.get(3, TimeUnit.SECONDS);
} catch (Exception e) {
log.error("阿里云短信发送超时或执行异常", e);
return this.sender.buildTimeoutResult();
}
}
@Override
public List<SendResult> sendBatchSms(List<MessageRecordDO> messageList) {
List<SendResult> results = new ArrayList<>();
for (MessageRecordDO message : messageList) {
results.add(this.sendSms(message));
}
return results;
}
@Override
public void queryTemplate(String templateIdentifier) {
}
private void getDownInfo(String bizId, MessageRecordDO message) {
// 回执存在延迟,这里延后查询,避免刚发送完就拿不到最终状态。
this.sender.MSG_CALLBACK_THREAD_POOL_SCHEDULER.schedule(() -> {
QuerySendDetailsRequest request = new QuerySendDetailsRequest()
.setPhoneNumber(message.getReceiver())
.setBizId(bizId)
.setSendDate(message.getSendTime().format(DateTimeFormatter.ofPattern("yyyyMMdd")))
.setCurrentPage(1L)
.setPageSize(10L);
try {
QuerySendDetailsResponse response = this.smsClient.querySendDetails(request);
if (response.getBody() == null || response.getBody().getSmsSendDetailDTOs() == null || response.getBody().getSmsSendDetailDTOs().getSmsSendDetailDTO() == null) {
return;
}
response.getBody().getSmsSendDetailDTOs().getSmsSendDetailDTO().forEach(detail -> {
if (!"DELIVERED".equals(detail.getErrCode())) {
SendResult failedResult = this.sender.buildFailureResult(
message,
detail.getErrCode(),
null,
"THIRD_PARTY_CALLBACK_FAILED",
"短信回执返回失败",
false
);
this.sender.applyCallbackResult(message, failedResult);
} else {
// 送达成功后,统一复用主流程成功状态更新逻辑。
this.sender.applyCallbackResult(
message,
SendResult.success(message.getSendTime(), message.getCostTime(), message.getThirdPartyId())
);
}
});
} catch (Exception e) {
log.error("阿里云短信回执查询失败", e);
}
}, 20, TimeUnit.SECONDS);
}
}

View File

@@ -0,0 +1,225 @@
package com.njcn.msgpush.module.push.client.sender.impl.sms;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.njcn.msgpush.module.push.client.sender.SendResult;
import com.njcn.msgpush.module.push.client.sender.Sender;
import com.njcn.msgpush.module.push.client.sender.SmsSender;
import com.njcn.msgpush.module.push.client.setting.impl.TelecomSmsSetting;
import com.njcn.msgpush.module.push.dal.dataobject.message.MessageRecordDO;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import static com.alibaba.fastjson.JSON.toJSON;
@Data
@Slf4j
public class TelecomSmsSender implements SmsSender {
private static final String CONTENT_TYPE = "application/json;charset=utf-8";
private final TelecomSmsSetting telecomSmsSetting;
private final Sender sender;
@Data
private static class TelecomSmsSendResponse {
private String status;
private Double balance;
private List<TelecomSmsSendDetailRes> list;
}
@Data
private static class TelecomSmsSendDetailRes {
private String mid;
private String mobile;
private Integer result;
}
@Data
private static class TelecomSmsSelectResponse {
private String status;
private Double balance;
private List<TelecomSmsSelectDetailRes> list;
}
@Data
private static class TelecomSmsSelectDetailRes {
private String apmid;
private String apSubmitTime;
private String mobile;
private Integer status;
private String stat;
private String deliverTime;
}
public TelecomSmsSender(TelecomSmsSetting telecomSmsSetting, Sender sender) {
this.telecomSmsSetting = telecomSmsSetting;
this.sender = sender;
}
@Override
public SendResult sendSms(MessageRecordDO message) {
Future<SendResult> future = this.sender.MSG_PUSH_THREAD_POOL_EXECUTOR.submit(() -> {
Map<String, Object> request = new HashMap<>();
boolean isTemplateSend = StrUtil.isNotBlank(message.getTemplateCode());
request.put("account", telecomSmsSetting.getAccount());
request.put("password", telecomSmsSetting.getPassword());
request.put("extno", telecomSmsSetting.getExtno());
if (isTemplateSend) {
request.put("action", "templatep2p");
Map<String, Object> templateJsonMap = new HashMap<>();
templateJsonMap.put("templateID", message.getTemplateCode());
JSONObject jsonObject = JSON.parseObject(message.getTemplateParams());
Map<String, String> variable = new HashMap<>();
variable.put("mobile", message.getReceiver());
jsonObject.forEach((key, value) -> variable.put(key, value.toString()));
templateJsonMap.put("variable", "[" + toJSON(variable) + "]");
request.put("templateJson", toJSON(templateJsonMap));
} else {
request.put("action", "send");
request.put("mobile", message.getReceiver());
request.put("content", message.getContent());
}
HttpHeaders headers = new HttpHeaders();
headers.set("Content-Type", CONTENT_TYPE);
try {
LocalDateTime now = LocalDateTime.now();
long start = now.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
ResponseEntity<String> response = this.sender.restTemplateUtil.post(
telecomSmsSetting.getApiUrl(),
request,
headers,
String.class
);
LocalDateTime end = LocalDateTime.now();
int costTime = (int) (end.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() - start);
message.setSendTime(now);
message.setCostTime(costTime);
TelecomSmsSendResponse sendResponse = JSON.parseObject(response.getBody(), TelecomSmsSendResponse.class);
TelecomSmsSendDetailRes detailRes = sendResponse == null || sendResponse.getList() == null || sendResponse.getList().isEmpty()
? null
: sendResponse.getList().get(0);
if (response.getStatusCode() == HttpStatus.OK && detailRes != null && detailRes.getResult() != null && detailRes.getResult() == 0) {
message.setThirdPartyId(detailRes.getMid());
// 电信短信同步返回成功同样只代表已受理,最终状态以后续回执为准。
this.getDownInfo(detailRes.getMid(), message);
return SendResult.accepted(now, costTime, detailRes.getMid());
}
String providerRawCode = detailRes == null || detailRes.getResult() == null ? null : String.valueOf(detailRes.getResult());
// 电信原始结果码在这里统一映射为平台错误码和中文错误信息。
return this.sender.buildFailureResult(
message,
providerRawCode,
null,
"THIRD_PARTY_CALL_FAILED",
"第三方服务调用失败",
false
);
} catch (Exception e) {
log.error("电信短信发送失败", e);
return this.sender.buildCallFailedResult("第三方服务调用失败");
}
});
try {
return future.get(3, TimeUnit.SECONDS);
} catch (Exception e) {
log.error("电信短信发送超时或执行异常", e);
return this.sender.buildTimeoutResult();
}
}
@Override
public List<SendResult> sendBatchSms(List<MessageRecordDO> messageList) {
List<SendResult> results = new ArrayList<>();
for (MessageRecordDO message : messageList) {
results.add(this.sendSms(message));
}
return results;
}
@Override
public void queryTemplate(String templateIdentifier) {
Map<String, Object> request = new HashMap<>();
request.put("action", "templateSelect");
request.put("account", telecomSmsSetting.getAccount());
request.put("password", telecomSmsSetting.getPassword());
request.put("templateJson", StrUtil.isBlank(templateIdentifier) ? 0 : templateIdentifier);
HttpHeaders headers = new HttpHeaders();
headers.set("Content-Type", CONTENT_TYPE);
this.sender.restTemplateUtil.post(
telecomSmsSetting.getApiUrl(),
request,
headers,
String.class
);
}
private void getDownInfo(String mid, MessageRecordDO message) {
// 回执查询延后执行,给第三方落库和状态变更留出时间。
this.sender.MSG_CALLBACK_THREAD_POOL_SCHEDULER.schedule(() -> {
Map<String, Object> request = new HashMap<>();
request.put("action", "select");
request.put("account", telecomSmsSetting.getAccount());
request.put("password", telecomSmsSetting.getPassword());
request.put("date", message.getSendTime().format(DateTimeFormatter.ofPattern("yyyyMMdd")));
request.put("condition", "APMID");
request.put("valueList", mid);
HttpHeaders headers = new HttpHeaders();
headers.set("Content-Type", CONTENT_TYPE);
try {
ResponseEntity<String> response = this.sender.restTemplateUtil.post(
telecomSmsSetting.getApiUrl(),
request,
headers,
String.class
);
TelecomSmsSelectResponse selectResponse = JSON.parseObject(response.getBody(), TelecomSmsSelectResponse.class);
if (selectResponse == null || selectResponse.getList() == null || selectResponse.getList().isEmpty()) {
return;
}
TelecomSmsSelectDetailRes detailRes = selectResponse.getList().get(0);
if (detailRes.getStatus() == 5) {
SendResult failedResult = this.sender.buildFailureResult(
message,
detailRes.getStat(),
null,
"THIRD_PARTY_CALLBACK_FAILED",
"短信回执返回失败",
false
);
this.sender.applyCallbackResult(message, failedResult);
} else if (detailRes.getStatus() == 4) {
// 回执确认成功后,复用统一成功落库逻辑。
this.sender.applyCallbackResult(
message,
SendResult.success(message.getSendTime(), message.getCostTime(), message.getThirdPartyId())
);
}
} catch (Exception e) {
log.error("电信短信回执查询失败", e);
}
}, 20, TimeUnit.SECONDS);
}
}

View File

@@ -1,14 +1,14 @@
package com.njcn.msgpush.module.infra.api.config;
package com.njcn.msgpush.module.system.api.config;
import com.njcn.msgpush.framework.common.pojo.CommonResult;
import com.njcn.msgpush.module.infra.enums.ApiConstants;
import com.njcn.msgpush.module.system.enums.ApiConstants;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(name = ApiConstants.NAME) // TODO 芋艿fallbackFactory =
@FeignClient(name = ApiConstants.NAME)
@Tag(name = "RPC 服务 - 参数配置")
public interface ConfigApi {

View File

@@ -1,12 +1,12 @@
package com.njcn.msgpush.module.system.api.user;
import cn.hutool.core.convert.Convert;
import com.fhs.core.trans.anno.AutoTrans;
import com.fhs.trans.service.AutoTransable;
import com.njcn.msgpush.framework.common.pojo.CommonResult;
import com.njcn.msgpush.framework.common.util.collection.CollectionUtils;
import com.njcn.msgpush.module.system.api.user.dto.AdminUserRespDTO;
import com.njcn.msgpush.module.system.enums.ApiConstants;
import com.fhs.core.trans.anno.AutoTrans;
import com.fhs.trans.service.AutoTransable;
import feign.FeignIgnore;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
@@ -22,7 +22,7 @@ import java.util.Map;
import static com.njcn.msgpush.module.system.api.user.AdminUserApi.PREFIX;
@FeignClient(name = ApiConstants.NAME) // TODO 芋艿fallbackFactory =
@FeignClient(name = ApiConstants.NAME)
@Tag(name = "RPC 服务 - 管理员用户")
@AutoTrans(namespace = PREFIX, fields = {"nickname"})
public interface AdminUserApi extends AutoTransable<AdminUserRespDTO> {
@@ -34,11 +34,6 @@ public interface AdminUserApi extends AutoTransable<AdminUserRespDTO> {
@Parameter(name = "id", description = "用户编号", example = "1", required = true)
CommonResult<AdminUserRespDTO> getUser(@RequestParam("id") Long id);
@GetMapping(PREFIX + "/list-by-subordinate")
@Operation(summary = "通过用户 ID 查询用户下属")
@Parameter(name = "id", description = "用户编号", example = "1", required = true)
CommonResult<List<AdminUserRespDTO>> getUserListBySubordinate(@RequestParam("id") Long id);
@GetMapping(PREFIX + "/list")
@Operation(summary = "通过用户 ID 查询用户们")
@Parameter(name = "ids", description = "部门编号数组", example = "1,2", required = true)
@@ -66,9 +61,7 @@ public interface AdminUserApi extends AutoTransable<AdminUserRespDTO> {
}
/**
* 校验用户是否有效。如下情况,视为无效:
* 1. 用户编号不存在
* 2. 用户被禁用
* 校验用户是否有效
*
* @param id 用户编号
*/

View File

@@ -0,0 +1,42 @@
package com.njcn.msgpush.module.system.api.websocket;
import com.njcn.msgpush.framework.common.pojo.CommonResult;
import com.njcn.msgpush.framework.common.util.json.JsonUtils;
import com.njcn.msgpush.module.system.api.websocket.dto.WebSocketSendToUsersReqDTO;
import com.njcn.msgpush.module.system.enums.ApiConstants;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.Collection;
@FeignClient(name = ApiConstants.NAME)
@Tag(name = "RPC 服务 - WebSocket 发送器的") // 对 WebSocketMessageSender 进行封装,提供给其它模块使用
public interface WebSocketSenderApi {
String PREFIX = ApiConstants.PREFIX + "/websocket";
@PostMapping(PREFIX + "/send-to-users")
@Operation(summary = "按用户编号集合发送 WebSocket 消息")
CommonResult<Boolean> sendToUsers(@Valid @RequestBody WebSocketSendToUsersReqDTO message);
/**
* 发送消息给指定用户集合
*
* @param userIds 用户编号集合
* @param messageType 消息类型
* @param messageContent 消息内容JSON 格式
*/
default void send(Collection<Long> userIds, String messageType, String messageContent) {
sendToUsers(new WebSocketSendToUsersReqDTO().setUserIds(userIds)
.setMessageType(messageType).setMessageContent(messageContent)).checkError();
}
default void sendObject(Collection<Long> userIds, String messageType, Object messageContent) {
send(userIds, messageType, JsonUtils.toJsonString(messageContent));
}
}

View File

@@ -0,0 +1,27 @@
package com.njcn.msgpush.module.system.api.websocket.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotEmpty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.Collection;
@Schema(description = "RPC 服务 - 按用户编号集合发送 WebSocket 消息 Request DTO")
@Data
@Accessors(chain = true)
public class WebSocketSendToUsersReqDTO {
@Schema(description = "用户编号集合", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1,2,3]")
@NotEmpty(message = "用户编号集合不能为空")
private Collection<Long> userIds;
@Schema(description = "消息类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "notice-push")
@NotEmpty(message = "消息类型不能为空")
private String messageType;
@Schema(description = "消息内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "{\"name\":\"李四\"}")
@NotEmpty(message = "消息内容不能为空")
private String messageContent;
}

View File

@@ -1,4 +1,4 @@
package com.njcn.msgpush.module.infra.enums.config;
package com.njcn.msgpush.module.system.enums.config;
import lombok.AllArgsConstructor;
import lombok.Getter;

View File

@@ -0,0 +1,33 @@
package com.njcn.msgpush.module.system.enums.dept;
import java.util.Arrays;
/**
* 组织节点类型枚举
*/
public enum DeptOrgTypeEnum {
COMPANY("company"),
DEPT("dept"),
DIRECTION("direction"),
TEAM("team");
private final String type;
DeptOrgTypeEnum(String type) {
this.type = type;
}
public String getType() {
return type;
}
public static boolean isValid(String type) {
return Arrays.stream(values()).anyMatch(item -> item.type.equals(type));
}
public static String defaultType() {
return DEPT.type;
}
}

View File

@@ -0,0 +1,28 @@
package com.njcn.msgpush.module.system.enums.dept;
import java.util.Arrays;
/**
* 岗位类型枚举
*/
public enum PostTypeEnum {
MANAGEMENT("management"),
TECHNICAL("technical"),
BUSINESS("business");
private final String type;
PostTypeEnum(String type) {
this.type = type;
}
public String getType() {
return type;
}
public static boolean isValid(String type) {
return Arrays.stream(values()).anyMatch(item -> item.type.equals(type));
}
}

View File

@@ -1,4 +1,4 @@
package com.njcn.msgpush.module.infra.enums.logger;
package com.njcn.msgpush.module.system.enums.logger;
import lombok.AllArgsConstructor;
import lombok.Getter;

View File

@@ -0,0 +1,38 @@
package com.njcn.msgpush.module.system.enums.permission;
import cn.hutool.core.util.StrUtil;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 菜单路由类型枚举
*/
@Getter
@AllArgsConstructor
public enum MenuRouteKindEnum {
DIR("dir"), // 目录路由
VIEW("view"), // 普通页面
SINGLE("single"), // 顶级单页
IFRAME("iframe"), // iframe 页面
EXTERNAL("external"), // 外链页面
REDIRECT("redirect"); // 重定向路由
/**
* 路由类型值
*/
private final String kind;
public static MenuRouteKindEnum valueOfKind(String kind) {
if (StrUtil.isBlank(kind)) {
return null;
}
for (MenuRouteKindEnum value : values()) {
if (StrUtil.equalsIgnoreCase(value.getKind(), StrUtil.trim(kind))) {
return value;
}
}
return null;
}
}

View File

@@ -2,21 +2,20 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.njcn</groupId>
<artifactId>msgpush-module-infra</artifactId>
<artifactId>msgpush-module-system</artifactId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>msgpush-module-infra-server</artifactId>
<packaging>jar</packaging>
<name>${project.artifactId}</name>
<description>
infra 模块,主要提供两块能力:
1. 我们放基础设施的运维与管理,支撑上层的通用与核心业务。 例如说:定时任务的管理、服务器的信息等等
2. 研发工具,提升研发效率与质量。 例如说:代码生成器、接口文档等等
</description>
<artifactId>msgpush-module-system-boot</artifactId>
<description>系统模块功能服务模块</description>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- Spring Cloud 基础 -->
@@ -28,31 +27,28 @@
<!-- 依赖服务 -->
<dependency>
<groupId>com.njcn</groupId>
<artifactId>msgpush-module-infra-api</artifactId>
<artifactId>msgpush-system-api</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>com.njcn</groupId>
<artifactId>msgpush-spring-boot-starter-biz-ip</artifactId>
</dependency>
<!-- Web 相关 -->
<dependency>
<groupId>com.njcn</groupId>
<artifactId>msgpush-spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>com.njcn</groupId>
<artifactId>msgpush-spring-boot-starter-websocket</artifactId>
</dependency>
<!-- DB 相关 -->
<dependency>
<groupId>com.njcn</groupId>
<artifactId>msgpush-spring-boot-starter-mybatis</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId> <!-- 代码生成器,使用它解析表结构 -->
</dependency>
<dependency>
<groupId>com.njcn</groupId>
@@ -77,6 +73,14 @@
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- websocket 配置中心相关 -->
<dependency>
<groupId>com.njcn</groupId>
<artifactId>msgpush-spring-boot-starter-websocket</artifactId>
</dependency>
<!-- 消息队列相关 -->
<dependency>
<groupId>com.njcn</groupId>
@@ -96,15 +100,16 @@
<artifactId>msgpush-spring-boot-starter-excel</artifactId>
</dependency>
<!-- 三方云服务相关 -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId> <!-- 实现代码生成 -->
<groupId>com.anji-plus</groupId>
<artifactId>captcha-spring-boot-starter</artifactId> <!-- 验证码,一般用于登录使用 -->
</dependency>
<!-- <dependency>-->
<!-- <groupId>de.codecentric</groupId>-->
<!-- <artifactId>spring-boot-admin-starter-server</artifactId> &lt;!&ndash; 实现 Spring Boot Admin Server 服务端 &ndash;&gt;-->
<!-- </dependency>-->
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-core</artifactId> <!-- 文件客户端:文件类型的识别 -->
</dependency>
<!-- 三方云服务相关 -->
<dependency>
@@ -120,12 +125,8 @@
<artifactId>s3</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-core</artifactId> <!-- 文件客户端:文件类型的识别 -->
</dependency>
</dependencies>
<build>
<!-- 设置构建的 jar 包名 -->
<finalName>${project.artifactId}</finalName>
@@ -145,5 +146,4 @@
</plugin>
</plugins>
</build>
</project>

View File

@@ -2,7 +2,6 @@ package com.njcn.msgpush.module.system;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
/**
* 项目的启动类

View File

@@ -1,8 +1,9 @@
package com.njcn.msgpush.module.infra.api.config;
package com.njcn.msgpush.module.system.api.config;
import com.njcn.msgpush.framework.common.pojo.CommonResult;
import com.njcn.msgpush.module.infra.dal.dataobject.config.ConfigDO;
import com.njcn.msgpush.module.infra.service.config.ConfigService;
import com.njcn.msgpush.module.system.dal.dataobject.config.ConfigDO;
import com.njcn.msgpush.module.system.service.config.ConfigService;
import io.swagger.v3.oas.annotations.Hidden;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
@@ -11,6 +12,7 @@ import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
@RestController // 提供 RESTful API 接口 Feign 调用
@Validated
@Hidden
public class ConfigApiImpl implements ConfigApi {
@Resource

View File

@@ -5,6 +5,7 @@ import com.njcn.msgpush.framework.common.util.object.BeanUtils;
import com.njcn.msgpush.module.system.api.dept.dto.DeptRespDTO;
import com.njcn.msgpush.module.system.dal.dataobject.dept.DeptDO;
import com.njcn.msgpush.module.system.service.dept.DeptService;
import io.swagger.v3.oas.annotations.Hidden;
import org.springframework.context.annotation.Bean;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
@@ -17,6 +18,7 @@ import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
@RestController // 提供 RESTful API 接口 Feign 调用
@Validated
@Hidden
public class DeptApiImpl implements DeptApi {
@Resource

View File

@@ -5,6 +5,7 @@ import com.njcn.msgpush.framework.common.util.object.BeanUtils;
import com.njcn.msgpush.module.system.api.dept.dto.PostRespDTO;
import com.njcn.msgpush.module.system.dal.dataobject.dept.PostDO;
import com.njcn.msgpush.module.system.service.dept.PostService;
import io.swagger.v3.oas.annotations.Hidden;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
@@ -16,6 +17,7 @@ import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
@RestController // 提供 RESTful API 接口 Feign 调用
@Validated
@Hidden
public class PostApiImpl implements PostApi {
@Resource

View File

@@ -5,6 +5,7 @@ import com.njcn.msgpush.framework.common.util.object.BeanUtils;
import com.njcn.msgpush.framework.common.biz.system.dict.dto.DictDataRespDTO;
import com.njcn.msgpush.module.system.dal.dataobject.dict.DictDataDO;
import com.njcn.msgpush.module.system.service.dict.DictDataService;
import io.swagger.v3.oas.annotations.Hidden;
import org.springframework.context.annotation.Primary;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
@@ -18,6 +19,7 @@ import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
@RestController // 提供 RESTful API 接口 Feign 调用
@Validated
@Primary // 由于 DictDataCommonApi 的存在必须声明为 @Primary Bean
@Hidden
public class DictDataApiImpl implements DictDataApi {
@Resource

View File

@@ -1,18 +1,19 @@
package com.njcn.msgpush.module.infra.api.logger;
package com.njcn.msgpush.module.system.api.logger;
import com.njcn.msgpush.framework.common.biz.infra.logger.ApiAccessLogCommonApi;
import com.njcn.msgpush.framework.common.biz.infra.logger.dto.ApiAccessLogCreateReqDTO;
import com.njcn.msgpush.framework.common.biz.system.logger.ApiAccessLogCommonApi;
import com.njcn.msgpush.framework.common.biz.system.logger.dto.ApiAccessLogCreateReqDTO;
import com.njcn.msgpush.framework.common.pojo.CommonResult;
import com.njcn.msgpush.module.infra.service.logger.ApiAccessLogService;
import com.njcn.msgpush.module.system.service.logger.ApiAccessLogService;
import io.swagger.v3.oas.annotations.Hidden;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
import jakarta.annotation.Resource;
import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
@RestController // 提供 RESTful API 接口 Feign 调用
@Validated
@Hidden
public class ApiAccessLogApiImpl implements ApiAccessLogCommonApi {
@Resource

View File

@@ -1,18 +1,19 @@
package com.njcn.msgpush.module.infra.api.logger;
package com.njcn.msgpush.module.system.api.logger;
import com.njcn.msgpush.framework.common.biz.infra.logger.ApiErrorLogCommonApi;
import com.njcn.msgpush.framework.common.biz.infra.logger.dto.ApiErrorLogCreateReqDTO;
import com.njcn.msgpush.framework.common.biz.system.logger.ApiErrorLogCommonApi;
import com.njcn.msgpush.framework.common.biz.system.logger.dto.ApiErrorLogCreateReqDTO;
import com.njcn.msgpush.framework.common.pojo.CommonResult;
import com.njcn.msgpush.module.infra.service.logger.ApiErrorLogService;
import com.njcn.msgpush.module.system.service.logger.ApiErrorLogService;
import io.swagger.v3.oas.annotations.Hidden;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
import jakarta.annotation.Resource;
import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
@RestController // 提供 RESTful API 接口 Feign 调用
@Validated
@Hidden
public class ApiErrorLogApiImpl implements ApiErrorLogCommonApi {
@Resource

View File

@@ -8,6 +8,7 @@ import com.njcn.msgpush.module.system.api.logger.dto.OperateLogPageReqDTO;
import com.njcn.msgpush.module.system.api.logger.dto.OperateLogRespDTO;
import com.njcn.msgpush.module.system.dal.dataobject.logger.OperateLogDO;
import com.njcn.msgpush.module.system.service.logger.OperateLogService;
import io.swagger.v3.oas.annotations.Hidden;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Primary;
import org.springframework.validation.annotation.Validated;
@@ -18,6 +19,7 @@ import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
@RestController // 提供 RESTful API 接口 Feign 调用
@Validated
@Primary // 由于 OperateLogCommonApi 的存在必须声明为 @Primary Bean
@Hidden
public class OperateLogApiImpl implements OperateLogApi {
@Resource

View File

@@ -1,21 +1,23 @@
package com.njcn.msgpush.module.system.api.oauth2;
import com.njcn.msgpush.framework.common.biz.system.oauth2.OAuth2TokenCommonApi;
import com.njcn.msgpush.framework.common.pojo.CommonResult;
import com.njcn.msgpush.framework.common.util.object.BeanUtils;
import com.njcn.msgpush.framework.common.biz.system.oauth2.dto.OAuth2AccessTokenCheckRespDTO;
import com.njcn.msgpush.framework.common.biz.system.oauth2.dto.OAuth2AccessTokenCreateReqDTO;
import com.njcn.msgpush.framework.common.biz.system.oauth2.dto.OAuth2AccessTokenRespDTO;
import com.njcn.msgpush.framework.common.pojo.CommonResult;
import com.njcn.msgpush.framework.common.util.object.BeanUtils;
import com.njcn.msgpush.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
import com.njcn.msgpush.module.system.service.oauth2.OAuth2TokenService;
import io.swagger.v3.oas.annotations.Hidden;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
@RestController // 提供 RESTful API 接口 Feign 调用
@RestController
@Validated
@Hidden
public class OAuth2TokenApiImpl implements OAuth2TokenCommonApi {
@Resource

View File

@@ -1,8 +1,8 @@
package com.njcn.msgpush.module.system.api.permission;
import com.njcn.msgpush.framework.common.pojo.CommonResult;
import com.njcn.msgpush.framework.common.biz.system.permission.dto.DeptDataPermissionRespDTO;
import com.njcn.msgpush.module.system.service.permission.PermissionService;
import io.swagger.v3.oas.annotations.Hidden;
import org.springframework.context.annotation.Primary;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
@@ -16,6 +16,7 @@ import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
@RestController // 提供 RESTful API 接口 Feign 调用
@Validated
@Primary // 由于 PermissionCommonApi 的存在必须声明为 @Primary Bean
@Hidden
public class PermissionApiImpl implements PermissionApi {
@Resource
@@ -36,9 +37,5 @@ public class PermissionApiImpl implements PermissionApi {
return success(permissionService.hasAnyRoles(userId, roles));
}
@Override
public CommonResult<DeptDataPermissionRespDTO> getDeptDataPermission(Long userId) {
return success(permissionService.getDeptDataPermission(userId));
}
}

View File

@@ -1,34 +1,27 @@
package com.njcn.msgpush.module.system.api.user;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import com.njcn.msgpush.framework.common.pojo.CommonResult;
import com.njcn.msgpush.framework.common.util.object.BeanUtils;
import com.njcn.msgpush.module.system.api.user.dto.AdminUserRespDTO;
import com.njcn.msgpush.module.system.dal.dataobject.dept.DeptDO;
import com.njcn.msgpush.module.system.dal.dataobject.user.AdminUserDO;
import com.njcn.msgpush.module.system.service.dept.DeptService;
import com.njcn.msgpush.module.system.service.user.AdminUserService;
import io.swagger.v3.oas.annotations.Hidden;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
import static com.njcn.msgpush.framework.common.util.collection.CollectionUtils.convertSet;
@RestController // 提供 RESTful API 接口 Feign 调用
@Validated
@Hidden
public class AdminUserApiImpl implements AdminUserApi {
@Resource
private AdminUserService userService;
@Resource
private DeptService deptService;
@Override
public CommonResult<AdminUserRespDTO> getUser(Long id) {
@@ -36,34 +29,6 @@ public class AdminUserApiImpl implements AdminUserApi {
return success(BeanUtils.toBean(user, AdminUserRespDTO.class));
}
@Override
public CommonResult<List<AdminUserRespDTO>> getUserListBySubordinate(Long id) {
// 1.1 获取用户负责的部门
AdminUserDO user = userService.getUser(id);
if (user == null) {
return success(Collections.emptyList());
}
ArrayList<Long> deptIds = new ArrayList<>();
DeptDO dept = deptService.getDept(user.getDeptId());
if (dept == null) {
return success(Collections.emptyList());
}
if (ObjUtil.notEqual(dept.getLeaderUserId(), id)) { // 校验为负责人
return success(Collections.emptyList());
}
deptIds.add(dept.getId());
// 1.2 获取所有子部门
List<DeptDO> childDeptList = deptService.getChildDeptList(dept.getId());
if (CollUtil.isNotEmpty(childDeptList)) {
deptIds.addAll(convertSet(childDeptList, DeptDO::getId));
}
// 2. 获取部门对应的用户信息
List<AdminUserDO> users = userService.getUserListByDeptIds(deptIds);
users.removeIf(item -> ObjUtil.equal(item.getId(), id)); // 排除自己
return success(BeanUtils.toBean(users, AdminUserRespDTO.class));
}
@Override
public CommonResult<List<AdminUserRespDTO>> getUserList(Collection<Long> ids) {
List<AdminUserDO> users = userService.getUserList(ids);

View File

@@ -0,0 +1,35 @@
package com.njcn.msgpush.module.system.api.websocket;
import cn.hutool.core.collection.CollUtil;
import com.njcn.msgpush.framework.common.pojo.CommonResult;
import com.njcn.msgpush.framework.common.enums.UserTypeEnum;
import com.njcn.msgpush.framework.websocket.core.sender.WebSocketMessageSender;
import com.njcn.msgpush.module.system.api.websocket.dto.WebSocketSendToUsersReqDTO;
import io.swagger.v3.oas.annotations.Hidden;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
@RestController // 提供 RESTful API 接口,给 Feign 调用
@Validated
@Hidden
public class WebSocketSenderApiImpl implements WebSocketSenderApi {
private static final Integer SYSTEM_USER_TYPE = UserTypeEnum.ADMIN.getValue();
@Resource
private WebSocketMessageSender webSocketMessageSender;
@Override
public CommonResult<Boolean> sendToUsers(WebSocketSendToUsersReqDTO message) {
if (CollUtil.isNotEmpty(message.getUserIds())) {
message.getUserIds().stream().distinct().forEach(userId ->
webSocketMessageSender.send(SYSTEM_USER_TYPE, userId,
message.getMessageType(), message.getMessageContent()));
}
return success(true);
}
}

View File

@@ -4,9 +4,15 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.njcn.msgpush.framework.common.enums.CommonStatusEnum;
import com.njcn.msgpush.framework.common.pojo.CommonResult;
import com.njcn.msgpush.framework.encrypt.core.annotation.ApiEncrypt;
import com.njcn.msgpush.framework.security.config.SecurityProperties;
import com.njcn.msgpush.framework.security.core.util.SecurityFrameworkUtils;
import com.njcn.msgpush.module.system.controller.admin.auth.vo.*;
import com.njcn.msgpush.module.system.controller.admin.auth.vo.AuthLoginReqVO;
import com.njcn.msgpush.module.system.controller.admin.auth.vo.AuthLoginRespVO;
import com.njcn.msgpush.module.system.controller.admin.auth.vo.AuthPermissionInfoRespVO;
import com.njcn.msgpush.module.system.controller.admin.auth.vo.AuthRegisterReqVO;
import com.njcn.msgpush.module.system.controller.admin.auth.vo.AuthUserRouteRespVO;
import com.njcn.msgpush.module.system.controller.admin.auth.vo.AuthUserInfoRespVO;
import com.njcn.msgpush.module.system.convert.auth.AuthConvert;
import com.njcn.msgpush.module.system.dal.dataobject.permission.MenuDO;
import com.njcn.msgpush.module.system.dal.dataobject.permission.RoleDO;
@@ -26,7 +32,12 @@ import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.Collections;
import java.util.List;
@@ -53,13 +64,13 @@ public class AuthController {
private MenuService menuService;
@Resource
private PermissionService permissionService;
@Resource
private SecurityProperties securityProperties;
@PostMapping("/login")
@PermitAll
@Operation(summary = "使用账号密码登录")
@ApiEncrypt(response = false, requestFields = {"password"})
public CommonResult<AuthLoginRespVO> login(@RequestBody @Valid AuthLoginReqVO reqVO) {
return success(authService.login(reqVO));
}
@@ -84,38 +95,78 @@ public class AuthController {
return success(authService.refreshToken(refreshToken));
}
@GetMapping("/get-permission-info")
@Operation(summary = "获取登录用户的权限信息")
public CommonResult<AuthPermissionInfoRespVO> getPermissionInfo() {
@GetMapping("/get-user-info")
@Operation(summary = "获取登录用户信息")
public CommonResult<AuthUserInfoRespVO> getUserInfo() {
// 1.1 获得用户信息
AdminUserDO user = userService.getUser(getLoginUserId());
if (user == null) {
return success(null);
}
// 1.2 获得角色列表
Set<Long> roleIds = permissionService.getUserRoleIdListByUserId(getLoginUserId());
if (CollUtil.isEmpty(roleIds)) {
// 1.2 获得角色和按钮权限
List<RoleDO> roles = getCurrentUserRoles();
List<MenuDO> menuList = getCurrentUserMenus(roles);
return success(AuthConvert.INSTANCE.convertUserInfo(user, roles, menuList));
}
@GetMapping("/get-user-routes")
@Operation(summary = "获取登录用户路由信息")
public CommonResult<AuthUserRouteRespVO> getUserRoutes() {
AdminUserDO user = userService.getUser(getLoginUserId());
if (user == null) {
return success(null);
}
List<RoleDO> roles = getCurrentUserRoles();
List<MenuDO> menuList = getCurrentUserMenus(roles);
return success(AuthConvert.INSTANCE.convertUserRoutes(menuList));
}
@GetMapping("/get-permission-info")
@Operation(summary = "获取登录用户的权限信息")
public CommonResult<AuthPermissionInfoRespVO> getPermissionInfo() {
AdminUserDO user = userService.getUser(getLoginUserId());
if (user == null) {
return success(null);
}
List<RoleDO> roles = getCurrentUserRoles();
if (CollUtil.isEmpty(roles)) {
return success(AuthConvert.INSTANCE.convert(user, Collections.emptyList(), Collections.emptyList()));
}
List<RoleDO> roles = roleService.getRoleList(roleIds);
roles.removeIf(role -> !CommonStatusEnum.ENABLE.getStatus().equals(role.getStatus())); // 移除禁用的角色
// 1.3 获得菜单列表
Set<Long> menuIds = permissionService.getRoleMenuListByRoleId(convertSet(roles, RoleDO::getId));
List<MenuDO> menuList = menuService.getMenuList(menuIds);
menuList = menuService.filterDisableMenus(menuList);
// 2. 拼接结果返回
List<MenuDO> menuList = getCurrentUserMenus(roles);
return success(AuthConvert.INSTANCE.convert(user, roles, menuList));
}
@PostMapping("/register")
@PermitAll
@Operation(summary = "注册用户")
@ApiEncrypt(response = false, requestFields = {"password"})
public CommonResult<AuthLoginRespVO> register(@RequestBody @Valid AuthRegisterReqVO registerReqVO) {
return success(authService.register(registerReqVO));
}
private List<RoleDO> getCurrentUserRoles() {
Set<Long> roleIds = permissionService.getUserRoleIdListByUserId(getLoginUserId());
if (CollUtil.isEmpty(roleIds)) {
return Collections.emptyList();
}
List<RoleDO> roles = roleService.getRoleList(roleIds);
roles.removeIf(role -> !CommonStatusEnum.ENABLE.getStatus().equals(role.getStatus()));
return roles;
}
private List<MenuDO> getCurrentUserMenus(List<RoleDO> roles) {
if (CollUtil.isEmpty(roles)) {
return Collections.emptyList();
}
Set<Long> menuIds = permissionService.getRoleMenuListByRoleId(convertSet(roles, RoleDO::getId));
List<MenuDO> menuList = menuService.getMenuList(menuIds);
return menuService.filterDisableMenus(menuList);
}
}

View File

@@ -1,18 +1,16 @@
package com.njcn.msgpush.module.system.controller.admin.auth.vo;
import cn.hutool.core.util.StrUtil;
import com.njcn.msgpush.framework.common.validation.InEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.AssertTrue;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.Pattern;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.Length;
@Schema(description = "管理后台 - 账号密码登录 Request VO如果登录并绑定社交用户需要传递 social 开头的参数")
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.Pattern;
@Schema(description = "管理后台 - 账号密码登录 Request VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
@@ -21,8 +19,8 @@ public class AuthLoginReqVO extends CaptchaVerificationReqVO {
@Schema(description = "账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "msgpushyuanma")
@NotEmpty(message = "登录账号不能为空")
@Length(min = 4, max = 16, message = "账号长度为 4-16")
@Pattern(regexp = "^[A-Za-z0-9]+$", message = "账号格式为数字以及字母")
@Length(min = 4, max = 30, message = "账号长度为 4-30")
@Pattern(regexp = "^[a-zA-Z0-9]{4,30}$", message = "账号格式为数字以及字母")
private String username;
@Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "buzhidao")
@@ -30,12 +28,4 @@ public class AuthLoginReqVO extends CaptchaVerificationReqVO {
@Length(min = 4, max = 16, message = "密码长度为 4-16 位")
private String password;
// ========== 绑定社交登录时需要传递如下参数 ==========
@Schema(description = "授权码", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private String socialCode;
@Schema(description = "state", requiredMode = Schema.RequiredMode.REQUIRED, example = "9b2ffbc1-7425-4155-9894-9d5c08541d62")
private String socialState;
}
}

View File

@@ -1,31 +1,39 @@
package com.njcn.msgpush.module.system.controller.admin.auth.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;
import lombok.Data;
import org.hibernate.validator.constraints.Length;
@Schema(description = "管理后台 - Register Request VO")
@Schema(description = "管理后台 - 注册 Request VO")
@Data
public class AuthRegisterReqVO extends CaptchaVerificationReqVO {
@Schema(description = "用户账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "msgpush")
@NotBlank(message = "用户账号不能为空")
@Pattern(regexp = "^[a-zA-Z0-9]{4,30}$", message = "用户账号由 数字、字母 组成")
@Pattern(regexp = "^[a-zA-Z0-9]{4,30}$", message = "用户账号由数字、字母组成")
@Size(min = 4, max = 30, message = "用户账号长度为 4-30 个字符")
private String username;
@Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿")
@Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "awen")
@NotBlank(message = "用户昵称不能为空")
@Size(max = 30, message = "用户昵称长度不能超过 30 个字符")
private String nickname;
@Schema(description = "所属部门编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "所属部门不能为空")
private Long deptId;
@Schema(description = "主岗位编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "主岗位不能为空")
private Long positionId;
@Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456")
@NotEmpty(message = "密码不能为空")
@Length(min = 4, max = 16, message = "密码长度为 4-16 位")
private String password;
}
}

View File

@@ -0,0 +1,46 @@
package com.njcn.msgpush.module.system.controller.admin.auth.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Schema(description = "管理后台 - 用户路由 Meta Response VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class AuthRouteMetaRespVO {
@Schema(description = "菜单或页面标题", requiredMode = Schema.RequiredMode.REQUIRED)
private String title;
@Schema(description = "国际化 key")
private String i18nKey;
@Schema(description = "图标名")
private String icon;
@Schema(description = "本地图标名")
private String localIcon;
@Schema(description = "排序值")
private Integer order;
@Schema(description = "是否缓存")
private Boolean keepAlive;
@Schema(description = "是否在菜单中隐藏")
private Boolean hideInMenu;
@Schema(description = "当前页面高亮的菜单路由名")
private String activeMenu;
@Schema(description = "是否支持多标签页")
private Boolean multiTab;
@Schema(description = "标签页固定位置")
private Integer fixedIndexInTab;
}

View File

@@ -0,0 +1,42 @@
package com.njcn.msgpush.module.system.controller.admin.auth.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Schema(description = "管理后台 - 用户路由节点 Response VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class AuthRouteNodeRespVO {
@Schema(description = "路由节点 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000")
private String id;
@Schema(description = "路由名", requiredMode = Schema.RequiredMode.REQUIRED, example = "system_user")
private String name;
@Schema(description = "完整路由路径", requiredMode = Schema.RequiredMode.REQUIRED, example = "/system/user")
private String path;
@Schema(description = "前端组件白名单 key", example = "view.system_user")
private String component;
@Schema(description = "重定向路径")
private String redirect;
@Schema(description = "路由 props")
private Object props;
@Schema(description = "路由 meta", requiredMode = Schema.RequiredMode.REQUIRED)
private AuthRouteMetaRespVO meta;
@Schema(description = "子路由列表")
private List<AuthRouteNodeRespVO> children;
}

View File

@@ -0,0 +1,31 @@
package com.njcn.msgpush.module.system.controller.admin.auth.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Schema(description = "管理后台 - 登录用户信息 Response VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class AuthUserInfoRespVO {
@Schema(description = "用户 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private String userId;
@Schema(description = "用户账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "admin")
private String userName;
@Schema(description = "角色编码列表", example = "[\"SUPER_ADMIN\"]")
private List<String> roles;
@Schema(description = "按钮权限码列表", requiredMode = Schema.RequiredMode.REQUIRED,
example = "[\"system:user:add\", \"system:user:update\"]")
private List<String> buttons;
}

View File

@@ -0,0 +1,24 @@
package com.njcn.msgpush.module.system.controller.admin.auth.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Schema(description = "管理后台 - 用户路由 Response VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class AuthUserRouteRespVO {
@Schema(description = "用户可访问路由树", requiredMode = Schema.RequiredMode.REQUIRED)
private List<AuthRouteNodeRespVO> routes;
@Schema(description = "默认首页路由名", requiredMode = Schema.RequiredMode.REQUIRED, example = "system_user")
private String home;
}

View File

@@ -27,6 +27,7 @@ public class CaptchaController {
@PostMapping({"/get"})
@Operation(summary = "获得验证码")
@PermitAll
public ResponseModel get(@RequestBody CaptchaVO data, HttpServletRequest request) {
assert request.getRemoteHost() != null;
data.setBrowserInfo(getRemoteId(request));
@@ -36,6 +37,7 @@ public class CaptchaController {
@PostMapping("/check")
@Operation(summary = "校验验证码")
@PermitAll
public ResponseModel check(@RequestBody CaptchaVO data, HttpServletRequest request) {
data.setBrowserInfo(getRemoteId(request));
return captchaService.check(data);

View File

@@ -1,17 +1,17 @@
package com.njcn.msgpush.module.infra.controller.admin.config;
package com.njcn.msgpush.module.system.controller.admin.config;
import com.njcn.msgpush.framework.apilog.core.annotation.ApiAccessLog;
import com.njcn.msgpush.framework.common.pojo.CommonResult;
import com.njcn.msgpush.framework.common.pojo.PageParam;
import com.njcn.msgpush.framework.common.pojo.PageResult;
import com.njcn.msgpush.framework.excel.core.util.ExcelUtils;
import com.njcn.msgpush.module.infra.controller.admin.config.vo.ConfigPageReqVO;
import com.njcn.msgpush.module.infra.controller.admin.config.vo.ConfigRespVO;
import com.njcn.msgpush.module.infra.controller.admin.config.vo.ConfigSaveReqVO;
import com.njcn.msgpush.module.infra.convert.config.ConfigConvert;
import com.njcn.msgpush.module.infra.dal.dataobject.config.ConfigDO;
import com.njcn.msgpush.module.infra.enums.ErrorCodeConstants;
import com.njcn.msgpush.module.infra.service.config.ConfigService;
import com.njcn.msgpush.module.system.controller.admin.config.vo.ConfigPageReqVO;
import com.njcn.msgpush.module.system.controller.admin.config.vo.ConfigRespVO;
import com.njcn.msgpush.module.system.controller.admin.config.vo.ConfigSaveReqVO;
import com.njcn.msgpush.module.system.convert.config.ConfigConvert;
import com.njcn.msgpush.module.system.dal.dataobject.config.ConfigDO;
import com.njcn.msgpush.module.system.enums.ErrorCodeConstants;
import com.njcn.msgpush.module.system.service.config.ConfigService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
@@ -31,7 +31,7 @@ import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 参数配置")
@RestController
@RequestMapping("/infra/config")
@RequestMapping("/system/config")
@Validated
public class ConfigController {
@@ -40,14 +40,14 @@ public class ConfigController {
@PostMapping("/create")
@Operation(summary = "创建参数配置")
@PreAuthorize("@ss.hasPermission('infra:config:create')")
@PreAuthorize("@ss.hasPermission('system:config:create')")
public CommonResult<Long> createConfig(@Valid @RequestBody ConfigSaveReqVO createReqVO) {
return success(configService.createConfig(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "修改参数配置")
@PreAuthorize("@ss.hasPermission('infra:config:update')")
@PreAuthorize("@ss.hasPermission('system:config:update')")
public CommonResult<Boolean> updateConfig(@Valid @RequestBody ConfigSaveReqVO updateReqVO) {
configService.updateConfig(updateReqVO);
return success(true);
@@ -56,7 +56,7 @@ public class ConfigController {
@DeleteMapping("/delete")
@Operation(summary = "删除参数配置")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('infra:config:delete')")
@PreAuthorize("@ss.hasPermission('system:config:delete')")
public CommonResult<Boolean> deleteConfig(@RequestParam("id") Long id) {
configService.deleteConfig(id);
return success(true);
@@ -65,7 +65,7 @@ public class ConfigController {
@DeleteMapping("/delete-list")
@Operation(summary = "批量删除参数配置")
@Parameter(name = "ids", description = "编号列表", required = true)
@PreAuthorize("@ss.hasPermission('infra:config:delete')")
@PreAuthorize("@ss.hasPermission('system:config:delete')")
public CommonResult<Boolean> deleteConfigList(@RequestParam("ids") List<Long> ids) {
configService.deleteConfigList(ids);
return success(true);
@@ -74,7 +74,7 @@ public class ConfigController {
@GetMapping(value = "/get")
@Operation(summary = "获得参数配置")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('infra:config:query')")
@PreAuthorize("@ss.hasPermission('system:config:query')")
public CommonResult<ConfigRespVO> getConfig(@RequestParam("id") Long id) {
return success(ConfigConvert.INSTANCE.convert(configService.getConfig(id)));
}
@@ -95,7 +95,7 @@ public class ConfigController {
@GetMapping("/page")
@Operation(summary = "获取参数配置分页")
@PreAuthorize("@ss.hasPermission('infra:config:query')")
@PreAuthorize("@ss.hasPermission('system:config:query')")
public CommonResult<PageResult<ConfigRespVO>> getConfigPage(@Valid ConfigPageReqVO pageReqVO) {
PageResult<ConfigDO> page = configService.getConfigPage(pageReqVO);
return success(ConfigConvert.INSTANCE.convertPage(page));
@@ -103,7 +103,7 @@ public class ConfigController {
@GetMapping("/export-excel")
@Operation(summary = "导出参数配置")
@PreAuthorize("@ss.hasPermission('infra:config:export')")
@PreAuthorize("@ss.hasPermission('system:config:export')")
@ApiAccessLog(operateType = EXPORT)
public void exportConfig(ConfigPageReqVO exportReqVO,
HttpServletResponse response) throws IOException {
@@ -115,3 +115,4 @@ public class ConfigController {
}
}

View File

@@ -1,4 +1,4 @@
package com.njcn.msgpush.module.infra.controller.admin.config.vo;
package com.njcn.msgpush.module.system.controller.admin.config.vo;
import com.njcn.msgpush.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;

View File

@@ -1,10 +1,10 @@
package com.njcn.msgpush.module.infra.controller.admin.config.vo;
package com.njcn.msgpush.module.system.controller.admin.config.vo;
import com.njcn.msgpush.framework.excel.core.annotations.DictFormat;
import com.njcn.msgpush.framework.excel.core.convert.DictConvert;
import com.njcn.msgpush.module.infra.enums.DictTypeConstants;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import com.njcn.msgpush.framework.excel.core.annotations.DictFormat;
import com.njcn.msgpush.framework.excel.core.convert.DictConvert;
import com.njcn.msgpush.module.system.enums.DictTypeConstants;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

View File

@@ -1,12 +1,11 @@
package com.njcn.msgpush.module.infra.controller.admin.config.vo;
package com.njcn.msgpush.module.system.controller.admin.config.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Data;
@Schema(description = "管理后台 - 参数配置创建/修改 Request VO")
@Data

View File

@@ -0,0 +1,101 @@
package com.njcn.msgpush.module.system.controller.admin.dept;
import com.njcn.msgpush.framework.common.pojo.CommonResult;
import com.njcn.msgpush.framework.common.util.object.BeanUtils;
import com.njcn.msgpush.module.system.controller.admin.dept.vo.orgleader.OrgLeaderRelationRespVO;
import com.njcn.msgpush.module.system.controller.admin.dept.vo.orgleader.OrgLeaderRelationSaveReqVO;
import com.njcn.msgpush.module.system.controller.admin.user.vo.user.UserSimpleRespVO;
import com.njcn.msgpush.module.system.convert.user.UserConvert;
import com.njcn.msgpush.module.system.dal.dataobject.dept.DeptDO;
import com.njcn.msgpush.module.system.dal.dataobject.dept.OrgLeaderRelationDO;
import com.njcn.msgpush.module.system.dal.dataobject.user.AdminUserDO;
import com.njcn.msgpush.module.system.service.dept.DeptService;
import com.njcn.msgpush.module.system.service.dept.OrgLeaderRelationService;
import com.njcn.msgpush.module.system.service.user.AdminUserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Map;
import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
import static com.njcn.msgpush.framework.common.util.collection.CollectionUtils.convertList;
@Tag(name = "管理后台 - 组织负责人关系")
@RestController
@RequestMapping("/system/org-leader")
@Validated
public class OrgLeaderRelationController {
@Resource
private OrgLeaderRelationService orgLeaderRelationService;
@Resource
private DeptService deptService;
@Resource
private AdminUserService adminUserService;
@PostMapping("/create")
@Operation(summary = "创建组织负责人关系")
@PreAuthorize("@ss.hasPermission('system:org-leader:create')")
public CommonResult<Long> createOrgLeaderRelation(@Valid @RequestBody OrgLeaderRelationSaveReqVO createReqVO) {
return success(orgLeaderRelationService.createOrgLeaderRelation(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "修改组织负责人关系")
@PreAuthorize("@ss.hasPermission('system:org-leader:update')")
public CommonResult<Boolean> updateOrgLeaderRelation(@Valid @RequestBody OrgLeaderRelationSaveReqVO updateReqVO) {
orgLeaderRelationService.updateOrgLeaderRelation(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除组织负责人关系")
@Parameter(name = "id", description = "负责人关系编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('system:org-leader:delete')")
public CommonResult<Boolean> deleteOrgLeaderRelation(@RequestParam("id") Long id) {
orgLeaderRelationService.deleteOrgLeaderRelation(id);
return success(true);
}
@GetMapping("/list-by-dept")
@Operation(summary = "查询组织下的负责人关系列表")
@Parameter(name = "deptId", description = "组织节点 ID", required = true, example = "100")
@PreAuthorize("@ss.hasPermission('system:org-leader:query')")
public CommonResult<List<OrgLeaderRelationRespVO>> getOrgLeaderRelationListByDept(@RequestParam("deptId") Long deptId) {
List<OrgLeaderRelationDO> relations = orgLeaderRelationService.getOrgLeaderRelationListByDeptId(deptId);
List<OrgLeaderRelationRespVO> respList = BeanUtils.toBean(relations, OrgLeaderRelationRespVO.class);
Map<Long, AdminUserDO> userMap = adminUserService.getUserMap(convertList(relations, OrgLeaderRelationDO::getUserId));
respList.forEach(respVO -> {
AdminUserDO user = userMap.get(respVO.getUserId());
if (user != null) {
respVO.setUserNickname(user.getNickname());
}
});
return success(respList);
}
@GetMapping("/candidate-users")
@Operation(summary = "查询组织负责人候选用户列表")
@Parameter(name = "deptId", description = "组织节点 ID", required = true, example = "100")
@PreAuthorize("@ss.hasPermission('system:org-leader:query')")
public CommonResult<List<UserSimpleRespVO>> getCandidateUsers(@RequestParam("deptId") Long deptId) {
List<AdminUserDO> users = orgLeaderRelationService.getCandidateUsersByDeptId(deptId);
Map<Long, DeptDO> deptMap = deptService.getDeptMap(convertList(users, AdminUserDO::getDeptId));
return success(UserConvert.INSTANCE.convertSimpleList(users, deptMap));
}
}

View File

@@ -10,6 +10,9 @@ public class DeptListReqVO {
@Schema(description = "部门名称,模糊匹配", example = "灿能")
private String name;
@Schema(description = "组织节点类型", example = "dept")
private String orgType;
@Schema(description = "展示状态,参见 CommonStatusEnum 枚举类", example = "1")
private Integer status;

View File

@@ -12,28 +12,31 @@ public class DeptRespVO {
@Schema(description = "部门编号", example = "1024")
private Long id;
@Schema(description = "部门名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "灿能")
@Schema(description = "部门名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "研发中心")
private String name;
@Schema(description = "父部门 ID", example = "1024")
private Long parentId;
@Schema(description = "组织节点类型", example = "dept")
private String orgType;
@Schema(description = "组织物化路径", example = "/100/101/103/")
private String path;
@Schema(description = "组织层级", example = "3")
private Integer level;
@Schema(description = "组织编码", example = "RD_CENTER")
private String code;
@Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Integer sort;
@Schema(description = "负责人的用户编号", example = "2048")
private Long leaderUserId;
@Schema(description = "联系电话", example = "15601691000")
private String phone;
@Schema(description = "邮箱", example = "msgpush@iocoder.cn")
private String email;
@Schema(description = "状态,见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@Schema(description = "状态,参见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Integer status;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式")
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime;
}

View File

@@ -3,7 +3,6 @@ package com.njcn.msgpush.module.system.controller.admin.dept.vo.dept;
import com.njcn.msgpush.framework.common.enums.CommonStatusEnum;
import com.njcn.msgpush.framework.common.validation.InEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
@@ -16,7 +15,7 @@ public class DeptSaveReqVO {
@Schema(description = "部门编号", example = "1024")
private Long id;
@Schema(description = "部门名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "灿能")
@Schema(description = "部门名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "研发中心")
@NotBlank(message = "部门名称不能为空")
@Size(max = 30, message = "部门名称长度不能超过 30 个字符")
private String name;
@@ -24,23 +23,19 @@ public class DeptSaveReqVO {
@Schema(description = "父部门 ID", example = "1024")
private Long parentId;
@Schema(description = "组织节点类型", example = "dept")
@Size(max = 20, message = "组织节点类型长度不能超过 20 个字符")
private String orgType;
@Schema(description = "组织编码", example = "RD_CENTER")
@Size(max = 64, message = "组织编码长度不能超过 64 个字符")
private String code;
@Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@NotNull(message = "显示顺序不能为空")
private Integer sort;
@Schema(description = "负责人的用户编号", example = "2048")
private Long leaderUserId;
@Schema(description = "联系电话", example = "15601691000")
@Size(max = 11, message = "联系电话长度不能超过11个字符")
private String phone;
@Schema(description = "邮箱", example = "msgpush@iocoder.cn")
@Email(message = "邮箱格式不正确")
@Size(max = 50, message = "邮箱长度不能超过 50 个字符")
private String email;
@Schema(description = "状态,见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@Schema(description = "状态,参见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "状态不能为空")
@InEnum(value = CommonStatusEnum.class, message = "修改状态必须是 {value}")
private Integer status;

View File

@@ -20,4 +20,7 @@ public class DeptSimpleRespVO {
@Schema(description = "父部门 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long parentId;
@Schema(description = "组织节点类型", example = "dept")
private String orgType;
}

View File

@@ -0,0 +1,39 @@
package com.njcn.msgpush.module.system.controller.admin.dept.vo.orgleader;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 组织负责人关系 Response VO")
@Data
public class OrgLeaderRelationRespVO {
@Schema(description = "负责人关系编号", example = "1024")
private Long id;
@Schema(description = "组织节点 ID", example = "100")
private Long deptId;
@Schema(description = "负责人用户 ID", example = "1")
private Long userId;
@Schema(description = "负责人用户昵称", example = "管理员")
private String userNickname;
@Schema(description = "生效开始时间")
private LocalDateTime effectiveFrom;
@Schema(description = "生效结束时间")
private LocalDateTime effectiveUntil;
@Schema(description = "备注", example = "部门负责人")
private String remark;
@Schema(description = "创建时间")
private LocalDateTime createTime;
@Schema(description = "更新时间")
private LocalDateTime updateTime;
}

View File

@@ -0,0 +1,35 @@
package com.njcn.msgpush.module.system.controller.admin.dept.vo.orgleader;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Data;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 组织负责人关系创建/修改 Request VO")
@Data
public class OrgLeaderRelationSaveReqVO {
@Schema(description = "负责人关系编号", example = "1024")
private Long id;
@Schema(description = "组织节点 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
@NotNull(message = "组织节点不能为空")
private Long deptId;
@Schema(description = "负责人用户 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "负责人用户不能为空")
private Long userId;
@Schema(description = "生效开始时间")
private LocalDateTime effectiveFrom;
@Schema(description = "生效结束时间")
private LocalDateTime effectiveUntil;
@Schema(description = "备注", example = "部门负责人")
@Size(max = 500, message = "备注长度不能超过 500 个字符")
private String remark;
}

View File

@@ -16,6 +16,12 @@ public class PostPageReqVO extends PageParam {
@Schema(description = "岗位名称,模糊匹配", example = "灿能")
private String name;
@Schema(description = "岗位类型", example = "technical")
private String postType;
@Schema(description = "岗位级别", example = "8")
private Integer levelRank;
@Schema(description = "展示状态,参见 CommonStatusEnum 枚举类", example = "1")
private Integer status;

View File

@@ -1,10 +1,10 @@
package com.njcn.msgpush.module.system.controller.admin.dept.vo.post;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import com.njcn.msgpush.framework.excel.core.annotations.DictFormat;
import com.njcn.msgpush.framework.excel.core.convert.DictConvert;
import com.njcn.msgpush.module.system.enums.DictTypeConstants;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@@ -19,15 +19,23 @@ public class PostRespVO {
@ExcelProperty("岗位序号")
private Long id;
@Schema(description = "岗位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "小土豆")
@Schema(description = "岗位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "后端开发工程师")
@ExcelProperty("岗位名称")
private String name;
@Schema(description = "岗位编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "msgpush")
@Schema(description = "岗位编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "backend")
@ExcelProperty("岗位编码")
private String code;
@Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@Schema(description = "岗位类型", example = "technical")
@ExcelProperty("岗位类型")
private String postType;
@Schema(description = "岗位级别", example = "8")
@ExcelProperty("岗位级别")
private Integer levelRank;
@Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@ExcelProperty("岗位排序")
private Integer sort;
@@ -36,7 +44,7 @@ public class PostRespVO {
@DictFormat(DictTypeConstants.COMMON_STATUS)
private Integer status;
@Schema(description = "备注", example = "快乐的备注")
@Schema(description = "备注", example = "技术序列岗位")
private String remark;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)

View File

@@ -3,6 +3,7 @@ package com.njcn.msgpush.module.system.controller.admin.dept.vo.post;
import com.njcn.msgpush.framework.common.enums.CommonStatusEnum;
import com.njcn.msgpush.framework.common.validation.InEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
@@ -15,17 +16,25 @@ public class PostSaveReqVO {
@Schema(description = "岗位编号", example = "1024")
private Long id;
@Schema(description = "岗位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "小土豆")
@Schema(description = "岗位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "后端开发工程师")
@NotBlank(message = "岗位名称不能为空")
@Size(max = 50, message = "岗位名称长度不能超过 50 个字符")
private String name;
@Schema(description = "岗位编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "msgpush")
@Schema(description = "岗位编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "backend")
@NotBlank(message = "岗位编码不能为空")
@Size(max = 64, message = "岗位编码长度不能超过64个字符")
@Size(max = 64, message = "岗位编码长度不能超过 64 个字符")
private String code;
@Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@Schema(description = "岗位类型", example = "technical")
@Size(max = 20, message = "岗位类型长度不能超过 20 个字符")
private String postType;
@Schema(description = "岗位级别", example = "8")
@Min(value = 0, message = "岗位级别不能小于 0")
private Integer levelRank;
@Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "显示顺序不能为空")
private Integer sort;
@@ -33,7 +42,7 @@ public class PostSaveReqVO {
@InEnum(CommonStatusEnum.class)
private Integer status;
@Schema(description = "备注", example = "快乐的备注")
@Schema(description = "备注", example = "技术序列岗位")
private String remark;
}
}

View File

@@ -16,4 +16,16 @@ public class PostSimpleRespVO {
@ExcelProperty("岗位名称")
private String name;
@Schema(description = "岗位编码", example = "backend")
private String code;
@Schema(description = "岗位类型", example = "technical")
private String postType;
@Schema(description = "岗位级别", example = "8")
private Integer levelRank;
@Schema(description = "岗位排序", example = "1")
private Integer sort;
}

View File

@@ -75,6 +75,7 @@ public class DictTypeController {
@Operation(summary = "获得字典类型的分页列表")
@PreAuthorize("@ss.hasPermission('system:dict:query')")
public CommonResult<PageResult<DictTypeRespVO>> pageDictTypes(@Valid DictTypePageReqVO pageReqVO) {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
PageResult<DictTypeDO> pageResult = dictTypeService.getDictTypePage(pageReqVO);
return success(BeanUtils.toBean(pageResult, DictTypeRespVO.class));
}

View File

@@ -5,6 +5,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.util.StringUtils;
import jakarta.validation.constraints.Size;
import java.time.LocalDateTime;
@@ -23,6 +24,10 @@ public class DictTypePageReqVO extends PageParam {
@Size(max = 100, message = "字典类型类型长度不能超过100个字符")
private String type;
@Schema(description = "字典类型编码,兼容前端 code 查询参数", example = "sys_common_sex")
@Size(max = 100, message = "字典类型编码长度不能超过100个字符")
private String code;
@Schema(description = "展示状态,参见 CommonStatusEnum 枚举类", example = "1")
private Integer status;
@@ -30,4 +35,8 @@ public class DictTypePageReqVO extends PageParam {
@Schema(description = "创建时间")
private LocalDateTime[] createTime;
public String getTypeKeyword() {
return StringUtils.hasText(code) ? code : type;
}
}

View File

@@ -1,13 +1,13 @@
package com.njcn.msgpush.module.infra.controller.admin.file;
package com.njcn.msgpush.module.system.controller.admin.file;
import com.njcn.msgpush.framework.common.pojo.CommonResult;
import com.njcn.msgpush.framework.common.pojo.PageResult;
import com.njcn.msgpush.framework.common.util.object.BeanUtils;
import com.njcn.msgpush.module.infra.controller.admin.file.vo.config.FileConfigPageReqVO;
import com.njcn.msgpush.module.infra.controller.admin.file.vo.config.FileConfigRespVO;
import com.njcn.msgpush.module.infra.controller.admin.file.vo.config.FileConfigSaveReqVO;
import com.njcn.msgpush.module.infra.dal.dataobject.file.FileConfigDO;
import com.njcn.msgpush.module.infra.service.file.FileConfigService;
import com.njcn.msgpush.module.system.controller.admin.file.vo.config.FileConfigPageReqVO;
import com.njcn.msgpush.module.system.controller.admin.file.vo.config.FileConfigRespVO;
import com.njcn.msgpush.module.system.controller.admin.file.vo.config.FileConfigSaveReqVO;
import com.njcn.msgpush.module.system.dal.dataobject.file.FileConfigDO;
import com.njcn.msgpush.module.system.service.file.FileConfigService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
@@ -23,7 +23,7 @@ import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 文件配置")
@RestController
@RequestMapping("/infra/file-config")
@RequestMapping("/system/file-config")
@Validated
public class FileConfigController {
@@ -32,14 +32,14 @@ public class FileConfigController {
@PostMapping("/create")
@Operation(summary = "创建文件配置")
@PreAuthorize("@ss.hasPermission('infra:file-config:create')")
@PreAuthorize("@ss.hasPermission('system:file-config:create')")
public CommonResult<Long> createFileConfig(@Valid @RequestBody FileConfigSaveReqVO createReqVO) {
return success(fileConfigService.createFileConfig(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新文件配置")
@PreAuthorize("@ss.hasPermission('infra:file-config:update')")
@PreAuthorize("@ss.hasPermission('system:file-config:update')")
public CommonResult<Boolean> updateFileConfig(@Valid @RequestBody FileConfigSaveReqVO updateReqVO) {
fileConfigService.updateFileConfig(updateReqVO);
return success(true);
@@ -47,7 +47,7 @@ public class FileConfigController {
@PutMapping("/update-master")
@Operation(summary = "更新文件配置为 Master")
@PreAuthorize("@ss.hasPermission('infra:file-config:update')")
@PreAuthorize("@ss.hasPermission('system:file-config:update')")
public CommonResult<Boolean> updateFileConfigMaster(@RequestParam("id") Long id) {
fileConfigService.updateFileConfigMaster(id);
return success(true);
@@ -56,7 +56,7 @@ public class FileConfigController {
@DeleteMapping("/delete")
@Operation(summary = "删除文件配置")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('infra:file-config:delete')")
@PreAuthorize("@ss.hasPermission('system:file-config:delete')")
public CommonResult<Boolean> deleteFileConfig(@RequestParam("id") Long id) {
fileConfigService.deleteFileConfig(id);
return success(true);
@@ -65,7 +65,7 @@ public class FileConfigController {
@DeleteMapping("/delete-list")
@Operation(summary = "批量删除文件配置")
@Parameter(name = "ids", description = "编号列表", required = true)
@PreAuthorize("@ss.hasPermission('infra:file-config:delete')")
@PreAuthorize("@ss.hasPermission('system:file-config:delete')")
public CommonResult<Boolean> deleteFileConfigList(@RequestParam("ids") List<Long> ids) {
fileConfigService.deleteFileConfigList(ids);
return success(true);
@@ -74,7 +74,7 @@ public class FileConfigController {
@GetMapping("/get")
@Operation(summary = "获得文件配置")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('infra:file-config:query')")
@PreAuthorize("@ss.hasPermission('system:file-config:query')")
public CommonResult<FileConfigRespVO> getFileConfig(@RequestParam("id") Long id) {
FileConfigDO config = fileConfigService.getFileConfig(id);
return success(BeanUtils.toBean(config, FileConfigRespVO.class));
@@ -82,7 +82,7 @@ public class FileConfigController {
@GetMapping("/page")
@Operation(summary = "获得文件配置分页")
@PreAuthorize("@ss.hasPermission('infra:file-config:query')")
@PreAuthorize("@ss.hasPermission('system:file-config:query')")
public CommonResult<PageResult<FileConfigRespVO>> getFileConfigPage(@Valid FileConfigPageReqVO pageVO) {
PageResult<FileConfigDO> pageResult = fileConfigService.getFileConfigPage(pageVO);
return success(BeanUtils.toBean(pageResult, FileConfigRespVO.class));
@@ -90,9 +90,10 @@ public class FileConfigController {
@GetMapping("/test")
@Operation(summary = "测试文件配置是否正确")
@PreAuthorize("@ss.hasPermission('infra:file-config:query')")
@PreAuthorize("@ss.hasPermission('system:file-config:query')")
public CommonResult<String> testFileConfig(@RequestParam("id") Long id) throws Exception {
String url = fileConfigService.testFileConfig(id);
return success(url);
}
}

View File

@@ -1,4 +1,4 @@
package com.njcn.msgpush.module.infra.controller.admin.file;
package com.njcn.msgpush.module.system.controller.admin.file;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
@@ -6,10 +6,9 @@ import cn.hutool.core.util.URLUtil;
import com.njcn.msgpush.framework.common.pojo.CommonResult;
import com.njcn.msgpush.framework.common.pojo.PageResult;
import com.njcn.msgpush.framework.common.util.object.BeanUtils;
import com.njcn.msgpush.module.infra.controller.admin.file.vo.file.*;
import com.njcn.msgpush.module.infra.dal.dataobject.file.FileDO;
import com.njcn.msgpush.module.infra.service.file.FileService;
import com.njcn.msgpush.module.system.controller.admin.file.vo.file.*;
import com.njcn.msgpush.module.system.dal.dataobject.file.FileDO;
import com.njcn.msgpush.module.system.service.file.FileService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
@@ -31,11 +30,11 @@ import java.nio.charset.StandardCharsets;
import java.util.List;
import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
import static com.njcn.msgpush.module.infra.framework.file.core.utils.FileTypeUtils.writeAttachment;
import static com.njcn.msgpush.module.system.framework.file.core.utils.FileTypeUtils.writeAttachment;
@Tag(name = "管理后台 - 文件存储")
@RestController
@RequestMapping("/infra/file")
@RequestMapping("/system/file")
@Validated
@Slf4j
public class FileController {
@@ -75,7 +74,7 @@ public class FileController {
@GetMapping("/get")
@Operation(summary = "获得文件")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('infra:file:query')")
@PreAuthorize("@ss.hasPermission('system:file:query')")
public CommonResult<FileRespVO> getFile(@RequestParam("id") Long id) {
return success(BeanUtils.toBean(fileService.getFile(id), FileRespVO.class));
}
@@ -83,7 +82,7 @@ public class FileController {
@DeleteMapping("/delete")
@Operation(summary = "删除文件")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('infra:file:delete')")
@PreAuthorize("@ss.hasPermission('system:file:delete')")
public CommonResult<Boolean> deleteFile(@RequestParam("id") Long id) throws Exception {
fileService.deleteFile(id);
return success(true);
@@ -92,7 +91,7 @@ public class FileController {
@DeleteMapping("/delete-list")
@Operation(summary = "批量删除文件")
@Parameter(name = "ids", description = "编号列表", required = true)
@PreAuthorize("@ss.hasPermission('infra:file:delete')")
@PreAuthorize("@ss.hasPermission('system:file:delete')")
public CommonResult<Boolean> deleteFileList(@RequestParam("ids") List<Long> ids) throws Exception {
fileService.deleteFileList(ids);
return success(true);
@@ -100,6 +99,7 @@ public class FileController {
@GetMapping("/{configId}/get/**")
@PermitAll
@Operation(summary = "下载文件")
@Parameter(name = "configId", description = "配置编号", required = true)
public void getFileContent(HttpServletRequest request,
@@ -127,10 +127,11 @@ public class FileController {
@GetMapping("/page")
@Operation(summary = "获得文件分页")
@PreAuthorize("@ss.hasPermission('infra:file:query')")
@PreAuthorize("@ss.hasPermission('system:file:query')")
public CommonResult<PageResult<FileRespVO>> getFilePage(@Valid FilePageReqVO pageVO) {
PageResult<FileDO> pageResult = fileService.getFilePage(pageVO);
return success(BeanUtils.toBean(pageResult, FileRespVO.class));
}
}

View File

@@ -1,4 +1,4 @@
package com.njcn.msgpush.module.infra.controller.admin.file.vo.config;
package com.njcn.msgpush.module.system.controller.admin.file.vo.config;
import com.njcn.msgpush.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;

View File

@@ -1,6 +1,6 @@
package com.njcn.msgpush.module.infra.controller.admin.file.vo.config;
package com.njcn.msgpush.module.system.controller.admin.file.vo.config;
import com.njcn.msgpush.module.infra.framework.file.core.client.FileClientConfig;
import com.njcn.msgpush.module.system.framework.file.core.client.FileClientConfig;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

View File

@@ -1,9 +1,9 @@
package com.njcn.msgpush.module.infra.controller.admin.file.vo.config;
package com.njcn.msgpush.module.system.controller.admin.file.vo.config;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import jakarta.validation.constraints.NotNull;
import java.util.Map;
@Schema(description = "管理后台 - 文件配置创建/修改 Request VO")

View File

@@ -1,4 +1,4 @@
package com.njcn.msgpush.module.infra.controller.admin.file.vo.file;
package com.njcn.msgpush.module.system.controller.admin.file.vo.file;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
@@ -28,6 +28,6 @@ public class FileCreateReqVO {
private String type;
@Schema(description = "文件大小", example = "2048", requiredMode = Schema.RequiredMode.REQUIRED)
private Integer size;
private Long size;
}

View File

@@ -1,4 +1,4 @@
package com.njcn.msgpush.module.infra.controller.admin.file.vo.file;
package com.njcn.msgpush.module.system.controller.admin.file.vo.file;
import com.njcn.msgpush.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;

View File

@@ -1,4 +1,4 @@
package com.njcn.msgpush.module.infra.controller.admin.file.vo.file;
package com.njcn.msgpush.module.system.controller.admin.file.vo.file;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;

View File

@@ -1,4 +1,4 @@
package com.njcn.msgpush.module.infra.controller.admin.file.vo.file;
package com.njcn.msgpush.module.system.controller.admin.file.vo.file;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@@ -28,7 +28,7 @@ public class FileRespVO {
private String type;
@Schema(description = "文件大小", example = "2048", requiredMode = Schema.RequiredMode.REQUIRED)
private Integer size;
private Long size;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime;

View File

@@ -1,4 +1,4 @@
package com.njcn.msgpush.module.infra.controller.admin.file.vo.file;
package com.njcn.msgpush.module.system.controller.admin.file.vo.file;
import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.annotation.JsonIgnore;

View File

@@ -1,4 +1,4 @@
package com.njcn.msgpush.module.infra.controller.admin.logger;
package com.njcn.msgpush.module.system.controller.admin.logger;
import com.njcn.msgpush.framework.apilog.core.annotation.ApiAccessLog;
import com.njcn.msgpush.framework.common.pojo.CommonResult;
@@ -6,10 +6,10 @@ import com.njcn.msgpush.framework.common.pojo.PageParam;
import com.njcn.msgpush.framework.common.pojo.PageResult;
import com.njcn.msgpush.framework.common.util.object.BeanUtils;
import com.njcn.msgpush.framework.excel.core.util.ExcelUtils;
import com.njcn.msgpush.module.infra.controller.admin.logger.vo.apiaccesslog.ApiAccessLogPageReqVO;
import com.njcn.msgpush.module.infra.controller.admin.logger.vo.apiaccesslog.ApiAccessLogRespVO;
import com.njcn.msgpush.module.infra.dal.dataobject.logger.ApiAccessLogDO;
import com.njcn.msgpush.module.infra.service.logger.ApiAccessLogService;
import com.njcn.msgpush.module.system.controller.admin.logger.vo.apiaccesslog.ApiAccessLogPageReqVO;
import com.njcn.msgpush.module.system.controller.admin.logger.vo.apiaccesslog.ApiAccessLogRespVO;
import com.njcn.msgpush.module.system.dal.dataobject.logger.ApiAccessLogDO;
import com.njcn.msgpush.module.system.service.logger.ApiAccessLogService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
@@ -31,7 +31,7 @@ import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - API 访问日志")
@RestController
@RequestMapping("/infra/api-access-log")
@RequestMapping("/system/api-access-log")
@Validated
public class ApiAccessLogController {
@@ -41,7 +41,7 @@ public class ApiAccessLogController {
@GetMapping("/get")
@Operation(summary = "获得 API 访问日志")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('infra:api-access-log:query')")
@PreAuthorize("@ss.hasPermission('system:api-access-log:query')")
public CommonResult<ApiAccessLogRespVO> getApiAccessLog(@RequestParam("id") Long id) {
ApiAccessLogDO apiAccessLog = apiAccessLogService.getApiAccessLog(id);
return success(BeanUtils.toBean(apiAccessLog, ApiAccessLogRespVO.class));
@@ -49,7 +49,7 @@ public class ApiAccessLogController {
@GetMapping("/page")
@Operation(summary = "获得API 访问日志分页")
@PreAuthorize("@ss.hasPermission('infra:api-access-log:query')")
@PreAuthorize("@ss.hasPermission('system:api-access-log:query')")
public CommonResult<PageResult<ApiAccessLogRespVO>> getApiAccessLogPage(@Valid ApiAccessLogPageReqVO pageReqVO) {
PageResult<ApiAccessLogDO> pageResult = apiAccessLogService.getApiAccessLogPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, ApiAccessLogRespVO.class));
@@ -57,7 +57,7 @@ public class ApiAccessLogController {
@GetMapping("/export-excel")
@Operation(summary = "导出API 访问日志 Excel")
@PreAuthorize("@ss.hasPermission('infra:api-access-log:export')")
@PreAuthorize("@ss.hasPermission('system:api-access-log:export')")
@ApiAccessLog(operateType = EXPORT)
public void exportApiAccessLogExcel(@Valid ApiAccessLogPageReqVO exportReqVO,
HttpServletResponse response) throws IOException {
@@ -69,3 +69,4 @@ public class ApiAccessLogController {
}
}

View File

@@ -1,4 +1,4 @@
package com.njcn.msgpush.module.infra.controller.admin.logger;
package com.njcn.msgpush.module.system.controller.admin.logger;
import com.njcn.msgpush.framework.apilog.core.annotation.ApiAccessLog;
import com.njcn.msgpush.framework.common.pojo.CommonResult;
@@ -6,10 +6,10 @@ import com.njcn.msgpush.framework.common.pojo.PageParam;
import com.njcn.msgpush.framework.common.pojo.PageResult;
import com.njcn.msgpush.framework.common.util.object.BeanUtils;
import com.njcn.msgpush.framework.excel.core.util.ExcelUtils;
import com.njcn.msgpush.module.infra.controller.admin.logger.vo.apierrorlog.ApiErrorLogPageReqVO;
import com.njcn.msgpush.module.infra.controller.admin.logger.vo.apierrorlog.ApiErrorLogRespVO;
import com.njcn.msgpush.module.infra.dal.dataobject.logger.ApiErrorLogDO;
import com.njcn.msgpush.module.infra.service.logger.ApiErrorLogService;
import com.njcn.msgpush.module.system.controller.admin.logger.vo.apierrorlog.ApiErrorLogPageReqVO;
import com.njcn.msgpush.module.system.controller.admin.logger.vo.apierrorlog.ApiErrorLogRespVO;
import com.njcn.msgpush.module.system.dal.dataobject.logger.ApiErrorLogDO;
import com.njcn.msgpush.module.system.service.logger.ApiErrorLogService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
@@ -30,7 +30,7 @@ import static com.njcn.msgpush.framework.security.core.util.SecurityFrameworkUti
@Tag(name = "管理后台 - API 错误日志")
@RestController
@RequestMapping("/infra/api-error-log")
@RequestMapping("/system/api-error-log")
@Validated
public class ApiErrorLogController {
@@ -43,7 +43,7 @@ public class ApiErrorLogController {
@Parameter(name = "id", description = "编号", required = true, example = "1024"),
@Parameter(name = "processStatus", description = "处理状态", required = true, example = "1")
})
@PreAuthorize("@ss.hasPermission('infra:api-error-log:update-status')")
@PreAuthorize("@ss.hasPermission('system:api-error-log:update-status')")
public CommonResult<Boolean> updateApiErrorLogProcess(@RequestParam("id") Long id,
@RequestParam("processStatus") Integer processStatus) {
apiErrorLogService.updateApiErrorLogProcess(id, processStatus, getLoginUserId());
@@ -53,7 +53,7 @@ public class ApiErrorLogController {
@GetMapping("/get")
@Operation(summary = "获得 API 错误日志")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('infra:api-error-log:query')")
@PreAuthorize("@ss.hasPermission('system:api-error-log:query')")
public CommonResult<ApiErrorLogRespVO> getApiErrorLog(@RequestParam("id") Long id) {
ApiErrorLogDO apiErrorLog = apiErrorLogService.getApiErrorLog(id);
return success(BeanUtils.toBean(apiErrorLog, ApiErrorLogRespVO.class));
@@ -61,7 +61,7 @@ public class ApiErrorLogController {
@GetMapping("/page")
@Operation(summary = "获得 API 错误日志分页")
@PreAuthorize("@ss.hasPermission('infra:api-error-log:query')")
@PreAuthorize("@ss.hasPermission('system:api-error-log:query')")
public CommonResult<PageResult<ApiErrorLogRespVO>> getApiErrorLogPage(@Valid ApiErrorLogPageReqVO pageReqVO) {
PageResult<ApiErrorLogDO> pageResult = apiErrorLogService.getApiErrorLogPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, ApiErrorLogRespVO.class));
@@ -69,7 +69,7 @@ public class ApiErrorLogController {
@GetMapping("/export-excel")
@Operation(summary = "导出 API 错误日志 Excel")
@PreAuthorize("@ss.hasPermission('infra:api-error-log:export')")
@PreAuthorize("@ss.hasPermission('system:api-error-log:export')")
@ApiAccessLog(operateType = EXPORT)
public void exportApiErrorLogExcel(@Valid ApiErrorLogPageReqVO exportReqVO,
HttpServletResponse response) throws IOException {
@@ -81,3 +81,4 @@ public class ApiErrorLogController {
}
}

View File

@@ -1,4 +1,4 @@
package com.njcn.msgpush.module.infra.controller.admin.logger.vo.apiaccesslog;
package com.njcn.msgpush.module.system.controller.admin.logger.vo.apiaccesslog;
import com.njcn.msgpush.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;

View File

@@ -1,10 +1,10 @@
package com.njcn.msgpush.module.infra.controller.admin.logger.vo.apiaccesslog;
package com.njcn.msgpush.module.system.controller.admin.logger.vo.apiaccesslog;
import com.njcn.msgpush.framework.excel.core.annotations.DictFormat;
import com.njcn.msgpush.framework.excel.core.convert.DictConvert;
import com.njcn.msgpush.module.infra.enums.DictTypeConstants;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import com.njcn.msgpush.framework.excel.core.annotations.DictFormat;
import com.njcn.msgpush.framework.excel.core.convert.DictConvert;
import com.njcn.msgpush.module.system.enums.DictTypeConstants;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@@ -70,7 +70,7 @@ public class ApiAccessLogRespVO {
@Schema(description = "操作分类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@ExcelProperty(value = "操作分类", converter = DictConvert.class)
@DictFormat(com.njcn.msgpush.module.infra.enums.DictTypeConstants.OPERATE_TYPE)
@DictFormat(DictTypeConstants.OPERATE_TYPE)
private Integer operateType;
@Schema(description = "开始请求时间", requiredMode = Schema.RequiredMode.REQUIRED)
@@ -89,7 +89,7 @@ public class ApiAccessLogRespVO {
@ExcelProperty("结果码")
private Integer resultCode;
@Schema(description = "结果提示", example = "灿能源码,牛逼!")
@Schema(description = "结果提示", example = "灿能,牛逼!")
@ExcelProperty("结果提示")
private String resultMsg;

View File

@@ -1,4 +1,4 @@
package com.njcn.msgpush.module.infra.controller.admin.logger.vo.apierrorlog;
package com.njcn.msgpush.module.system.controller.admin.logger.vo.apierrorlog;
import com.njcn.msgpush.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;

View File

@@ -1,10 +1,10 @@
package com.njcn.msgpush.module.infra.controller.admin.logger.vo.apierrorlog;
package com.njcn.msgpush.module.system.controller.admin.logger.vo.apierrorlog;
import com.njcn.msgpush.framework.excel.core.annotations.DictFormat;
import com.njcn.msgpush.framework.excel.core.convert.DictConvert;
import com.njcn.msgpush.module.infra.enums.DictTypeConstants;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import com.njcn.msgpush.framework.excel.core.annotations.DictFormat;
import com.njcn.msgpush.framework.excel.core.convert.DictConvert;
import com.njcn.msgpush.module.system.enums.DictTypeConstants;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

View File

@@ -29,7 +29,7 @@ public class OperateLogRespVO implements VO {
@Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@Trans(type = TransType.SIMPLE, target = AdminUserDO.class, fields = "nickname", ref = "userName")
private Long userId;
@Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿")
@Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "awen")
@ExcelProperty("操作人")
private String userName;

Some files were not shown because too many files have changed in this diff Show More