init local code

This commit is contained in:
chenxing
2026-08-24 17:37:10 +08:00
commit 40dd7fadea
71 changed files with 5597 additions and 0 deletions
@@ -0,0 +1,55 @@
package com.yunhai.notice.common;
import com.yunhai.platform.apistd.ApiResponse;
import com.yunhai.platform.utils.exception.ErrorCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.validation.ConstraintViolationException;
/**
* 全局异常处理器:将业务异常转为统一响应 {@link ApiResponse}(code/msg/data)。
*/
@RestControllerAdvice
public class GlobalExceptionHandler {
private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
@ExceptionHandler(NoticeException.class)
@ResponseStatus(HttpStatus.OK)
public ApiResponse<Object> handleNoticeException(NoticeException ex) {
log.warn("[NoticeException] {}", ex.getMessage());
String msg = ex.getMessage() == null ? "业务异常" : ex.getMessage();
return ApiResponse.fail(5, msg);
}
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.OK)
public ApiResponse<Object> handleValidException(MethodArgumentNotValidException ex) {
String msg = ex.getBindingResult().getFieldError() != null
? ex.getBindingResult().getFieldError().getDefaultMessage()
: "参数校验失败";
log.warn("[Validation] {}", msg);
return ApiResponse.fail(ErrorCode.PARAM_ERROR, msg);
}
@ExceptionHandler(ConstraintViolationException.class)
@ResponseStatus(HttpStatus.OK)
public ApiResponse<Object> handleConstraintViolation(ConstraintViolationException ex) {
log.warn("[ConstraintViolation] {}", ex.getMessage());
return ApiResponse.fail(ErrorCode.PARAM_ERROR, ex.getMessage());
}
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.OK)
public ApiResponse<Object> handleException(Exception ex) {
log.error("[UnhandledException] ", ex);
String msg = ex.getMessage() == null ? ex.getClass().getSimpleName() : ex.getMessage();
return ApiResponse.fail(ErrorCode.INTERNAL_SERVER_ERROR.getCode(), "服务器内部错误:" + msg);
}
}
@@ -0,0 +1,15 @@
package com.yunhai.notice.common;
/**
* 业务异常。等价于 UserBase 的 com.bestsch.utils.DException,统一以 RuntimeException 抛出。
*/
public class NoticeException extends RuntimeException {
public NoticeException(String message) {
super(message);
}
public NoticeException(String message, Throwable cause) {
super(message, cause);
}
}
@@ -0,0 +1,32 @@
package com.yunhai.notice.common.context;
/**
* 当前登录用户上下文(ThreadLocal)。<br>
* 由 {@link com.yunhai.notice.common.interceptor.CurrentUserInterceptor} 在请求入口写入,
* 供 JPA 审计监听器与业务层取用发布人/读者身份。<br><br>
* 身份取自 CAS 写入的 {@code request.getRemoteUser()},本地未接入 CAS 时回退到
* application.yml 的 dev.default-user 或请求头 X-Login-Account,便于本地联调。
*/
public class NoticeContext {
private static final ThreadLocal<String> ACCOUNT = new ThreadLocal<>();
private static final ThreadLocal<String> NAME = new ThreadLocal<>();
public static void set(String account, String name) {
ACCOUNT.set(account);
NAME.set(name);
}
public static String getAccount() {
return ACCOUNT.get();
}
public static String getName() {
return NAME.get();
}
public static void clear() {
ACCOUNT.remove();
NAME.remove();
}
}
@@ -0,0 +1,32 @@
package com.yunhai.notice.common.event;
import java.util.List;
/**
* 通知发布事件。在通知状态从草稿变更为已发布时发布,
* 由 {@code MessageService} 监听并在事务提交后异步推送消息(短信/App/角标等)。
*/
public class NoticePublishedEvent {
private final Integer noticeId;
private final String title;
private final List<String> receiverAccounts;
public NoticePublishedEvent(Integer noticeId, String title, List<String> receiverAccounts) {
this.noticeId = noticeId;
this.title = title;
this.receiverAccounts = receiverAccounts;
}
public Integer getNoticeId() {
return noticeId;
}
public String getTitle() {
return title;
}
public List<String> getReceiverAccounts() {
return receiverAccounts;
}
}
@@ -0,0 +1,52 @@
package com.yunhai.notice.common.interceptor;
import com.yunhai.notice.common.context.NoticeContext;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 当前登录用户拦截器:优先取 CAS 写入的 {@code getRemoteUser()},
* 其次取请求头 X-Login-Account / X-Login-Name(本地联调用),最后回退到 dev.default-user。
* 写入 {@link NoticeContext} 供业务层与 JPA 审计监听器使用。
*/
@Component
public class CurrentUserInterceptor implements HandlerInterceptor {
@Value("${dev.default-user.account:admin}")
private String devAccount;
@Value("${dev.default-user.name:管理员}")
private String devName;
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) {
String account = request.getRemoteUser();
String name = null;
if (account == null) {
account = request.getHeader("X-Login-Account");
name = request.getHeader("X-Login-Name");
}
if (account == null) {
account = devAccount;
name = devName;
}
if (name == null) {
name = account;
}
NoticeContext.set(account, name);
return true;
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler, Exception ex) {
NoticeContext.clear();
}
}
@@ -0,0 +1,40 @@
package com.yunhai.notice.common.listener;
import com.yunhai.notice.common.context.NoticeContext;
import com.yunhai.notice.entity.BaseEntity;
import org.springframework.stereotype.Component;
import javax.persistence.PrePersist;
import javax.persistence.PreUpdate;
import java.time.LocalDateTime;
/**
* JPA 审计监听器:在实体持久化/更新前自动填充创建人/更新人(登录账号)与时间戳。
* 对应 {@link BaseEntity} 的 createBy / updateBy / createTime / updateTime 字段。
*/
@Component
public class NoticeAuditListener {
@PrePersist
public void prePersist(BaseEntity entity) {
LocalDateTime now = LocalDateTime.now();
entity.setCreateTime(now);
entity.setUpdateTime(now);
String account = NoticeContext.getAccount();
if (account != null) {
if (entity.getCreateBy() == null) {
entity.setCreateBy(account);
}
entity.setUpdateBy(account);
}
}
@PreUpdate
public void preUpdate(BaseEntity entity) {
entity.setUpdateTime(LocalDateTime.now());
String account = NoticeContext.getAccount();
if (account != null) {
entity.setUpdateBy(account);
}
}
}