国际化

This commit is contained in:
zjf committed 2026-08-26 14:54:05 +08:00
1 parent 575a8cebe5
commit 60144341ba
16 files changed
+384 -54

No files matched your search

@@ -77,8 +77,8 @@ public abstract class OAuth2ResourceOwnerBaseAuthenticationProvider<T extends OA
this.authorizationService = authorizationService;
this.tokenGenerator = tokenGenerator;
// 国际化配置
this.messages = new MessageSourceAccessor(SpringUtil.getBean("securityMessageSource"), Locale.CHINA);
// 国际化:按当前请求 Locale(Accept-Language)解析
this.messages = new MessageSourceAccessor(SpringUtil.getBean("securityMessageSource"));
}
@Deprecated
@@ -17,10 +17,10 @@
package com.bsd.pjcloud.common.core.config;
import com.bsd.pjcloud.common.core.i18n.Utf8ReloadableResourceBundleMessageSource;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
/**
* @author pjcloud
@@ -33,7 +33,7 @@ public class MessageSourceConfiguration {
@Bean
public MessageSource pjcloudMessageSource() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
Utf8ReloadableResourceBundleMessageSource messageSource = new Utf8ReloadableResourceBundleMessageSource();
messageSource.setBasename("classpath:i18n/messages");
return messageSource;
}
@@ -110,6 +110,55 @@ public interface ErrorCodes {
*/
String APP_USER_USERINFO_EMPTY = "app.user.userInfo.empty";
/** 通用:权限不足 */
String COMMON_ACCESS_DENIED = "common.access.denied";
/** 通用:数据库异常 */
String COMMON_SQL_ERROR = "common.sql.error";
/** 通用:系统繁忙 */
String COMMON_SYSTEM_ERROR = "common.system.error";
/** 用户ID不能为空 */
String SYS_USER_ID_EMPTY = "sys.user.id.empty";
/** 用户名重复(编辑时) */
String SYS_USER_USERNAME_DUPLICATE = "sys.user.username.duplicate";
/** 用户不存在 */
String SYS_USER_NOT_FOUND = "sys.user.not.found";
/** 用户已注销 */
String SYS_USER_CANCELLED = "sys.user.cancelled";
/** 姓名不能为空 */
String SYS_PERSON_NAME_EMPTY = "sys.person.name.empty";
/** 昵称不能为空 */
String SYS_PERSON_NICKNAME_EMPTY = "sys.person.nickname.empty";
/** 姓名格式不合法 */
String SYS_PERSON_NAME_INVALID = "sys.person.name.invalid";
/** 昵称格式不合法 */
String SYS_PERSON_NICKNAME_INVALID = "sys.person.nickname.invalid";
/** 姓名过长 */
String SYS_PERSON_NAME_TOO_LONG = "sys.person.name.too.long";
/** 原密码不能为空 */
String SYS_USER_PASSWORD_OLD_EMPTY = "sys.user.password.old.empty";
/** 新密码不能为空 */
String SYS_USER_PASSWORD_NEW_EMPTY = "sys.user.password.new.empty";
/** 密码长度 */
String SYS_USER_PASSWORD_LENGTH = "sys.user.password.length";
/** 密码字符限制 */
String SYS_USER_PASSWORD_CHARS_ONLY = "sys.user.password.chars.only";
/** 密码需字母+数字 */
String SYS_USER_PASSWORD_LETTER_DIGIT = "sys.user.password.letter.digit";
}
@@ -0,0 +1,26 @@
package com.bsd.pjcloud.common.core.exception;
import com.bsd.pjcloud.common.core.util.MsgUtils;
import lombok.Getter;
/**
* 携带 i18n 错误码的业务异常,由全局异常处理器按当前 Locale 解析文案
*/
@Getter
public class I18nBizException extends RuntimeException {
private final String code;
private final Object[] args;
public I18nBizException(String code, Object... args) {
super(code);
this.code = code;
this.args = args;
}
public String resolveMessage() {
return MsgUtils.getMessage(code, args);
}
}
@@ -0,0 +1,39 @@
package com.bsd.pjcloud.common.core.i18n;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
import java.util.Locale;
/**
* 根据 Accept-Language / LANG 请求头设置当前请求 Locale
*/
public class I18nLocaleFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
Locale locale = resolveLocale(request);
LocaleContextHolder.setLocale(locale);
try {
filterChain.doFilter(request, response);
}
finally {
LocaleContextHolder.resetLocaleContext();
}
}
private Locale resolveLocale(HttpServletRequest request) {
String lang = request.getHeader(I18nLocaleUtils.HEADER_LANG);
if (lang == null || lang.isBlank()) {
lang = request.getHeader(I18nLocaleUtils.HEADER_ACCEPT_LANGUAGE);
}
return I18nLocaleUtils.resolve(lang);
}
}
@@ -0,0 +1,60 @@
package com.bsd.pjcloud.common.core.i18n;
import cn.hutool.core.util.StrUtil;
import java.util.Locale;
/**
* 解析客户端语言(Accept-Language / LANG 请求头)
*/
public final class I18nLocaleUtils {
public static final String HEADER_ACCEPT_LANGUAGE = "Accept-Language";
public static final String HEADER_LANG = "LANG";
private I18nLocaleUtils() {
}
public static Locale resolve(String raw) {
if (StrUtil.isBlank(raw)) {
return Locale.SIMPLIFIED_CHINESE;
}
String lang = raw.trim().toLowerCase();
int comma = lang.indexOf(',');
if (comma > 0) {
lang = lang.substring(0, comma).trim();
}
int semi = lang.indexOf(';');
if (semi > 0) {
lang = lang.substring(0, semi).trim();
}
if (lang.startsWith("en")) {
return Locale.ENGLISH;
}
if (lang.contains("hk") || lang.equals("zh-hk") || lang.equals("zh_hk")) {
return new Locale("zh", "HK");
}
if (lang.contains("hant") || lang.equals("zh-tw") || lang.equals("zh_tw")) {
return new Locale("zh", "HK");
}
return Locale.SIMPLIFIED_CHINESE;
}
public static String toAcceptLanguage(Locale locale) {
if (locale == null) {
return "zh-CN";
}
if (Locale.ENGLISH.equals(locale)) {
return "en";
}
if ("HK".equalsIgnoreCase(locale.getCountry())) {
return "zh-HK";
}
if (Locale.TRADITIONAL_CHINESE.equals(locale)) {
return "zh-HK";
}
return "zh-CN";
}
}
@@ -0,0 +1,36 @@
package com.bsd.pjcloud.common.core.i18n;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.core.io.Resource;
import org.springframework.lang.Nullable;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.util.Properties;
/**
* 强制以 UTF-8 读取 classpath 下 *.properties
*/
public class Utf8ReloadableResourceBundleMessageSource extends ReloadableResourceBundleMessageSource {
public Utf8ReloadableResourceBundleMessageSource() {
setDefaultEncoding(StandardCharsets.UTF_8.name());
}
@Override
protected Properties loadProperties(Resource resource, String filename) throws IOException {
Properties props = newProperties();
try (Reader reader = new InputStreamReader(resource.getInputStream(), StandardCharsets.UTF_8)) {
props.load(reader);
}
return props;
}
@Override
public void setDefaultEncoding(@Nullable String defaultEncoding) {
super.setDefaultEncoding(StandardCharsets.UTF_8.name());
}
}
@@ -2,46 +2,36 @@ package com.bsd.pjcloud.common.core.util;
import lombok.experimental.UtilityClass;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import java.util.Locale;
/**
* i18n 工具类
*
* @author pjcloud
* @date 2022/3/30
*/
@UtilityClass
public class MsgUtils {
/**
* 通过code 获取中文错误信息
* @param code
* @return
*/
public String getMessage(String code) {
MessageSource messageSource = SpringContextHolder.getBean("pjcloudMessageSource");
return messageSource.getMessage(code, null, Locale.CHINA);
return getMessage(code, (Object[]) null);
}
/**
* 通过code 和参数获取中文错误信息
* @param code
* @return
*/
public String getMessage(String code, Object... objects) {
MessageSource messageSource = SpringContextHolder.getBean("pjcloudMessageSource");
return messageSource.getMessage(code, objects, Locale.CHINA);
Locale locale = LocaleContextHolder.getLocale();
if (locale == null) {
locale = Locale.SIMPLIFIED_CHINESE;
}
return messageSource.getMessage(code, objects, locale);
}
/**
* security 通过code 和参数获取中文错误信息
* @param code
* @return
*/
public String getSecurityMessage(String code, Object... objects) {
MessageSource messageSource = SpringContextHolder.getBean("securityMessageSource");
return messageSource.getMessage(code, objects, Locale.CHINA);
Locale locale = LocaleContextHolder.getLocale();
if (locale == null) {
locale = Locale.SIMPLIFIED_CHINESE;
}
return messageSource.getMessage(code, objects, locale);
}
}
@@ -1,6 +1,7 @@
com.bsd.pjcloud.common.core.config.AsyncConfiguration
com.bsd.pjcloud.common.core.config.JacksonConfiguration
com.bsd.pjcloud.common.core.config.MessageSourceConfiguration
com.bsd.pjcloud.common.core.config.I18nLocaleAutoConfiguration
com.bsd.pjcloud.common.core.config.RestTemplateConfiguration
com.bsd.pjcloud.common.core.config.ImmutableConfiguration
com.bsd.pjcloud.common.core.util.SpringContextHolder
@@ -0,0 +1,39 @@
sys.user.update.passwordError=Incorrect old password, update failed
sys.user.query.error=Failed to get current user info
sys.user.import.succeed=Users imported. Default password is mobile number
sys.user.username.existing={0} username already exists
sys.user.phone.existing={0} mobile number already exists
sys.user.userInfo.empty={0} user info is empty
sys.dept.deptName.inexistence={0} department does not exist
sys.post.postName.inexistence={0} post does not exist
sys.post.nameOrCode.existing={0} {1} post name or code already exists
sys.role.roleName.inexistence={0} role does not exist
sys.role.nameOrCode.existing={0} {1} role name or code already exists
sys.param.delete.system=Built-in parameters cannot be deleted
sys.param.config.error={0} system parameter config error
sys.menu.delete.existing=Menu has children and cannot be deleted
sys.app.sms.often=Verification code sent too frequently
sys.app.phone.unregistered={0} mobile number is not registered
sys.dict.delete.system=Built-in dictionary items cannot be deleted
sys.dict.update.system=Built-in dictionary items cannot be modified
sys.connect.cp.dept.sync.error=Failed to fetch WeCom department list
sys.connect.cp.user.sync.error=Failed to fetch WeCom user list
app.user.userInfo.empty={0} user info is empty
common.access.denied=Insufficient permissions
common.sql.error=Database error. Please contact administrator
common.system.error=System busy. Please try again later
sys.user.id.empty=User ID cannot be empty
sys.user.username.duplicate=Username already exists
sys.user.not.found=User does not exist
sys.user.cancelled=Your account has been cancelled
sys.person.name.empty=Name cannot be empty
sys.person.nickname.empty=Nickname cannot be empty
sys.person.name.invalid=Name supports Chinese or English (words may be separated by spaces, e.g. John Smith)
sys.person.nickname.invalid=Nickname supports Chinese or English (words may be separated by spaces, e.g. John Smith)
sys.person.name.too.long=Cannot exceed 32 characters
sys.user.password.old.empty=Old password cannot be empty
sys.user.password.new.empty=New password cannot be empty
sys.user.password.length=Password length must be 6-20 characters
sys.user.password.chars.only=Password can only contain letters and digits
sys.user.password.letter.digit=Password must contain both letters and digits
@@ -1,21 +1,39 @@
sys.user.update.passwordError=\u539F\u5BC6\u7801\u9519\u8BEF\uFF0C\u4FEE\u6539\u5931\u8D25
sys.user.query.error=\u83B7\u53D6\u5F53\u524D\u7528\u6237\u4FE1\u606F\u5931\u8D25
sys.user.import.succeed=\u7528\u6237\u5BFC\u5165\u6210\u529F\uFF0C\u9ED8\u8BA4\u5BC6\u7801\u4E3A\u624B\u673A\u53F7
sys.user.username.existing={0} \u7528\u6237\u540D\u5DF2\u5B58\u5728
sys.user.phone.existing={0} \u624b\u673a\u53f7\u5df2\u5b58\u5728
sys.user.userInfo.empty={0} \u7528\u6237\u4FE1\u606F\u4E3A\u7A7A
sys.dept.deptName.inexistence={0} \u90E8\u95E8\u540D\u79F0\u4E0D\u5B58\u5728
sys.post.postName.inexistence={0} \u5C97\u4F4D\u540D\u79F0\u4E0D\u5B58\u5728
sys.post.nameOrCode.existing={0} {1} \u5C97\u4F4D\u540D\u6216\u5C97\u4F4D\u7F16\u7801\u5DF2\u7ECF\u5B58\u5728
sys.role.roleName.inexistence={0} \u89D2\u8272\u540D\u79F0\u4E0D\u5B58\u5728
sys.role.nameOrCode.existing={0} {1} \u89D2\u8272\u540D\u6216\u89D2\u8272\u7F16\u7801\u5DF2\u7ECF\u5B58\u5728
sys.param.delete.system=\u7CFB\u7EDF\u5185\u7F6E\u53C2\u6570\u4E0D\u80FD\u5220\u9664
sys.param.config.error={0} \u7CFB\u7EDF\u53C2\u6570\u914D\u7F6E\u9519\u8BEF
sys.menu.delete.existing=\u83DC\u5355\u542B\u6709\u4E0B\u7EA7\u4E0D\u80FD\u5220\u9664
sys.app.sms.often=\u9A8C\u8BC1\u7801\u53D1\u9001\u8FC7\u9891\u7E41
sys.app.phone.unregistered={0} \u624B\u673A\u53F7\u672A\u6CE8\u518C
sys.dict.delete.system=\u7CFB\u7EDF\u5185\u7F6E\u5B57\u5178\u9879\u76EE\u4E0D\u80FD\u5220\u9664
sys.dict.update.system=\u7CFB\u7EDF\u5185\u7F6E\u5B57\u5178\u9879\u76EE\u4E0D\u80FD\u4FEE\u6539
sys.connect.cp.dept.sync.error=\u83B7\u53D6\u4F01\u4E1A\u5FAE\u4FE1\u90E8\u95E8\u5217\u8868\u5931\u8D25
sys.connect.cp.user.sync.error=\u83B7\u53D6\u4F01\u4E1A\u5FAE\u4FE1\u7528\u6237\u5217\u8868\u5931\u8D25
app.user.userInfo.empty={0} \u7528\u6237\u4FE1\u606F\u4E3A\u7A7A
sys.user.update.passwordError=原密码错误,修改失败
sys.user.query.error=获取当前用户信息失败
sys.user.import.succeed=用户导入成功,默认密码为手机号
sys.user.username.existing={0} 用户名已存在
sys.user.phone.existing={0} 手机号已存在
sys.user.userInfo.empty={0} 用户信息为空
sys.dept.deptName.inexistence={0} 部门名称不存在
sys.post.postName.inexistence={0} 岗位名称不存在
sys.post.nameOrCode.existing={0} {1} 岗位名或岗位编码已经存在
sys.role.roleName.inexistence={0} 角色名称不存在
sys.role.nameOrCode.existing={0} {1} 角色名或角色编码已经存在
sys.param.delete.system=系统内置参数不能删除
sys.param.config.error={0} 系统参数配置错误
sys.menu.delete.existing=菜单含有下级不能删除
sys.app.sms.often=验证码发送过频繁
sys.app.phone.unregistered={0} 手机号未注册
sys.dict.delete.system=系统内置字典项目不能删除
sys.dict.update.system=系统内置字典项目不能修改
sys.connect.cp.dept.sync.error=获取企业微信部门列表失败
sys.connect.cp.user.sync.error=获取企业微信用户列表失败
app.user.userInfo.empty={0} 用户信息为空
common.access.denied=权限不足,不允许访问
common.sql.error=数据库调用异常,请联系管理员处理
common.system.error=系统繁忙,请稍后再试
sys.user.id.empty=用户ID不能为空
sys.user.username.duplicate=该用户名已存在
sys.user.not.found=用户不存在
sys.user.cancelled=您已注销
sys.person.name.empty=姓名不能为空
sys.person.nickname.empty=昵称不能为空
sys.person.name.invalid=姓名仅支持中文,或英文(单词间可用空格,如 John Smith)
sys.person.nickname.invalid=昵称仅支持中文,或英文(单词间可用空格,如 John Smith)
sys.person.name.too.long=不能超过32个字符
sys.user.password.old.empty=原密码不能为空
sys.user.password.new.empty=新密码不能为空
sys.user.password.length=密码长度需为6-20位
sys.user.password.chars.only=密码只能包含字母和数字
sys.user.password.letter.digit=密码需同时包含字母和数字
@@ -0,0 +1,39 @@
sys.user.update.passwordError=原密碼錯誤,修改失敗
sys.user.query.error=獲取當前用戶資訊失敗
sys.user.import.succeed=用戶導入成功,預設密碼為手機號
sys.user.username.existing={0} 用戶名已存在
sys.user.phone.existing={0} 手機號已存在
sys.user.userInfo.empty={0} 用戶資訊為空
sys.dept.deptName.inexistence={0} 部門名稱不存在
sys.post.postName.inexistence={0} 崗位名稱不存在
sys.post.nameOrCode.existing={0} {1} 崗位名或崗位編碼已經存在
sys.role.roleName.inexistence={0} 角色名稱不存在
sys.role.nameOrCode.existing={0} {1} 角色名或角色編碼已經存在
sys.param.delete.system=系統內置參數不能刪除
sys.param.config.error={0} 系統參數配置錯誤
sys.menu.delete.existing=菜單含有下級不能刪除
sys.app.sms.often=驗證碼發送過頻繁
sys.app.phone.unregistered={0} 手機號未註冊
sys.dict.delete.system=系統內置字典項目不能刪除
sys.dict.update.system=系統內置字典項目不能修改
sys.connect.cp.dept.sync.error=獲取企業微信部門列表失敗
sys.connect.cp.user.sync.error=獲取企業微信用戶列表失敗
app.user.userInfo.empty={0} 用戶資訊為空
common.access.denied=權限不足,不允許訪問
common.sql.error=資料庫調用異常,請聯繫管理員處理
common.system.error=系統繁忙,請稍後再試
sys.user.id.empty=用戶ID不能為空
sys.user.username.duplicate=該用戶名已存在
sys.user.not.found=用戶不存在
sys.user.cancelled=您已註銷
sys.person.name.empty=姓名不能為空
sys.person.nickname.empty=暱稱不能為空
sys.person.name.invalid=姓名僅支援中文,或英文(單詞間可用空格,如 John Smith)
sys.person.nickname.invalid=暱稱僅支援中文,或英文(單詞間可用空格,如 John Smith)
sys.person.name.too.long=不能超過32個字符
sys.user.password.old.empty=原密碼不能為空
sys.user.password.new.empty=新密碼不能為空
sys.user.password.length=密碼長度需為6-20位
sys.user.password.chars.only=密碼只能包含字母和數字
sys.user.password.letter.digit=密碼需同時包含字母和數字
@@ -16,14 +16,12 @@
package com.bsd.pjcloud.common.security.component;
import com.bsd.pjcloud.common.core.i18n.Utf8ReloadableResourceBundleMessageSource;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.Locale;
import static org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type.SERVLET;
/**
@@ -37,9 +35,8 @@ public class PjcloudSecurityMessageSourceConfiguration implements WebMvcConfigur
@Bean
public MessageSource securityMessageSource() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
Utf8ReloadableResourceBundleMessageSource messageSource = new Utf8ReloadableResourceBundleMessageSource();
messageSource.addBasenames("classpath:errors/messages");
messageSource.setDefaultLocale(Locale.CHINA);
return messageSource;
}
@@ -0,0 +1,13 @@
AbstractAccessDecisionManager.accessDenied=Insufficient permissions
AbstractAccessDecisionManager.expireToken=Token expired
AbstractUserDetailsAuthenticationProvider.badCredentials=Incorrect username or password
AbstractUserDetailsAuthenticationProvider.badClientCredentials=Invalid client credentials
AbstractUserDetailsAuthenticationProvider.smsBadCredentials=User does not exist
AbstractUserDetailsAuthenticationProvider.credentialsExpired=Credentials have expired
OAuth2ResourceOwnerBaseAuthenticationProvider.tokenExpired=Credentials have expired
AbstractUserDetailsAuthenticationProvider.disabled=User is not activated
AbstractUserDetailsAuthenticationProvider.locked=User account is locked
AbstractUserDetailsAuthenticationProvider.expired=User account has expired
JdbcDaoImpl.notFound=User {0} not found
UserDetailsService.notFound=User does not exist
RegisteredClient.notFound=Client not found
@@ -0,0 +1,13 @@
AbstractAccessDecisionManager.accessDenied=權限不足,不允許訪問
AbstractAccessDecisionManager.expireToken=Token 已過期
AbstractUserDetailsAuthenticationProvider.badCredentials=帳號或密碼錯誤
AbstractUserDetailsAuthenticationProvider.badClientCredentials=客戶端資訊錯誤
AbstractUserDetailsAuthenticationProvider.smsBadCredentials=用戶不存在,登入失敗
AbstractUserDetailsAuthenticationProvider.credentialsExpired=用戶憑證已過期
OAuth2ResourceOwnerBaseAuthenticationProvider.tokenExpired=用戶憑證已過期
AbstractUserDetailsAuthenticationProvider.disabled=用戶未啟用
AbstractUserDetailsAuthenticationProvider.locked=用戶帳號已鎖定
AbstractUserDetailsAuthenticationProvider.expired=用戶帳號已過期
JdbcDaoImpl.notFound=未找到用戶{0}
UserDetailsService.notFound=用戶不存在
RegisteredClient.notFound=客戶端資訊查詢失敗
@@ -19,6 +19,9 @@ package com.bsd.pjcloud.common.sentinel.handle;
import com.alibaba.csp.sentinel.Tracer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
import com.bsd.pjcloud.common.core.exception.I18nBizException;
import com.bsd.pjcloud.common.core.util.MsgUtils;
import com.bsd.pjcloud.common.core.util.R;
import feign.FeignException;
import lombok.SneakyThrows;
@@ -43,6 +46,13 @@ public class GlobalBizExceptionHandler {
private final ObjectMapper objectMapper = new ObjectMapper();
@ExceptionHandler(I18nBizException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public R handleI18nBizException(I18nBizException e) {
log.warn("业务异常 code={}", e.getCode());
return R.failed(e.resolveMessage());
}
/**
* 全局异常.
*
@@ -70,7 +80,7 @@ public class GlobalBizExceptionHandler {
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public R handleSQLException(SQLException exception) {
log.error("数据库调用异常 ex={}", exception.getMessage(), exception);
return R.failed("数据库调用异常,请联系管理员处理");
return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_SQL_ERROR));
}
@SneakyThrows
@@ -99,7 +109,7 @@ public class GlobalBizExceptionHandler {
@ResponseStatus(HttpStatus.FORBIDDEN)
public R handleAccessDeniedException(AccessDeniedException e) {
log.error("拒绝授权异常信息 ex={}", e.getMessage());
return R.failed("权限不足,不允许访问");
return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_ACCESS_DENIED));
}
/**