mirror of
https://github.com/continew-org/continew-starter.git
synced 2025-09-11 16:57:14 +08:00
feat: 新增国际化及全局异常码配置
This commit is contained in:
@@ -124,6 +124,11 @@ public class PropertiesConstants {
|
|||||||
*/
|
*/
|
||||||
public static final String MESSAGING_WEBSOCKET = MESSAGING + StringConstants.DOT + "websocket";
|
public static final String MESSAGING_WEBSOCKET = MESSAGING + StringConstants.DOT + "websocket";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 国际化配置
|
||||||
|
*/
|
||||||
|
public static final String I18N = WEB + StringConstants.DOT + "i18n";
|
||||||
|
|
||||||
private PropertiesConstants() {
|
private PropertiesConstants() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package top.continew.starter.core.exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 统一错误码异常
|
||||||
|
*
|
||||||
|
* @author Jasmine
|
||||||
|
* @since 2.2.0
|
||||||
|
*/
|
||||||
|
public class GlobalException extends Exception {
|
||||||
|
|
||||||
|
private ResultInfoInterface resultInfo;
|
||||||
|
|
||||||
|
public GlobalException() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public GlobalException(ResultInfoInterface resultInfo) {
|
||||||
|
this.resultInfo = resultInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResultInfoInterface getResultInfo() {
|
||||||
|
return this.resultInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setResultInfo(ResultInfoInterface resultInfo) {
|
||||||
|
this.resultInfo = resultInfo;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package top.continew.starter.core.exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 接口返回码 所有业务异常都要继承该接口
|
||||||
|
*
|
||||||
|
* @author Jasmine
|
||||||
|
* @since 2.2.0
|
||||||
|
*/
|
||||||
|
public enum GlobalResultInfoEnum implements ResultInfoInterface {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作成功
|
||||||
|
*/
|
||||||
|
SUCCESS(200, "操作成功"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作失败
|
||||||
|
*/
|
||||||
|
FAILED(500, "操作失败");
|
||||||
|
|
||||||
|
private int code;
|
||||||
|
private String messageKey;
|
||||||
|
private String defaultMessage;
|
||||||
|
|
||||||
|
GlobalResultInfoEnum(int code, String defaultMessage) {
|
||||||
|
this.code = code;
|
||||||
|
this.defaultMessage = defaultMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
GlobalResultInfoEnum(int code, String messageKey, String defaultMessage) {
|
||||||
|
this.code = code;
|
||||||
|
this.messageKey = messageKey;
|
||||||
|
this.defaultMessage = defaultMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCode() {
|
||||||
|
return this.code;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMessageKey() {
|
||||||
|
return this.messageKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDefaultMessage() {
|
||||||
|
return this.defaultMessage;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package top.continew.starter.core.exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 接口返回码与消息 所有业务异常都要继承该接口
|
||||||
|
*
|
||||||
|
* @author Jasmine
|
||||||
|
* @since 2.2.0
|
||||||
|
*/
|
||||||
|
public interface ResultInfoInterface {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取编码
|
||||||
|
*
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
int getCode();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 国际化消息key
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
default String getMessageKey() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取默认消息 若从国际化文件里没有获取到值,就取默认值
|
||||||
|
*
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
String getDefaultMessage();
|
||||||
|
}
|
@@ -19,6 +19,8 @@ package top.continew.starter.web.autoconfigure.exception;
|
|||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.util.NumberUtil;
|
import cn.hutool.core.util.NumberUtil;
|
||||||
import cn.hutool.core.text.CharSequenceUtil;
|
import cn.hutool.core.text.CharSequenceUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.validation.ConstraintViolation;
|
import jakarta.validation.ConstraintViolation;
|
||||||
import jakarta.validation.ConstraintViolationException;
|
import jakarta.validation.ConstraintViolationException;
|
||||||
@@ -36,7 +38,11 @@ import org.springframework.web.multipart.MultipartException;
|
|||||||
import top.continew.starter.core.constant.StringConstants;
|
import top.continew.starter.core.constant.StringConstants;
|
||||||
import top.continew.starter.core.exception.BadRequestException;
|
import top.continew.starter.core.exception.BadRequestException;
|
||||||
import top.continew.starter.core.exception.BusinessException;
|
import top.continew.starter.core.exception.BusinessException;
|
||||||
|
import top.continew.starter.core.exception.GlobalException;
|
||||||
|
import top.continew.starter.core.exception.ResultInfoInterface;
|
||||||
|
import top.continew.starter.web.autoconfigure.i18n.I18nProperties;
|
||||||
import top.continew.starter.web.model.R;
|
import top.continew.starter.web.model.R;
|
||||||
|
import top.continew.starter.web.util.MessageSourceUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 全局异常处理器
|
* 全局异常处理器
|
||||||
@@ -49,6 +55,8 @@ public class GlobalExceptionHandler {
|
|||||||
private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
|
private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
|
||||||
|
|
||||||
private static final String PARAM_FAILED = "请求地址 [{}],参数验证失败。";
|
private static final String PARAM_FAILED = "请求地址 [{}],参数验证失败。";
|
||||||
|
@Resource
|
||||||
|
private I18nProperties i18nProperties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 拦截自定义验证异常-错误请求
|
* 拦截自定义验证异常-错误请求
|
||||||
@@ -153,6 +161,23 @@ public class GlobalExceptionHandler {
|
|||||||
return R.fail(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage());
|
return R.fail(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 拦截全局应用异常
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(GlobalException.class)
|
||||||
|
public R<Void> handleGlobalException(GlobalException e, HttpServletRequest request) {
|
||||||
|
log.error("请求地址 [{}],发生业务异常。", request.getRequestURI(), e);
|
||||||
|
ResultInfoInterface resultInfo = e.getResultInfo();
|
||||||
|
// 未开启,直接返回
|
||||||
|
if (!i18nProperties.getEnabled()) {
|
||||||
|
return R.fail(resultInfo.getCode(), resultInfo.getDefaultMessage());
|
||||||
|
}
|
||||||
|
// 以用户自定的messageKey优先,否则枚举当messageKey
|
||||||
|
String messageKey = StrUtil.blankToDefault(resultInfo.getMessageKey(), resultInfo.toString());
|
||||||
|
String message = MessageSourceUtils.getMessage(messageKey, resultInfo.getDefaultMessage());
|
||||||
|
return R.fail(resultInfo.getCode(), message);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 拦截未知的运行时异常
|
* 拦截未知的运行时异常
|
||||||
*/
|
*/
|
||||||
|
@@ -26,10 +26,12 @@ import org.slf4j.LoggerFactory;
|
|||||||
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
|
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
import org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController;
|
import org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController;
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
import org.springframework.validation.beanvalidation.SpringConstraintValidatorFactory;
|
import org.springframework.validation.beanvalidation.SpringConstraintValidatorFactory;
|
||||||
|
import top.continew.starter.web.autoconfigure.i18n.I18nProperties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 全局异常处理器自动配置
|
* 全局异常处理器自动配置
|
||||||
@@ -40,6 +42,7 @@ import org.springframework.validation.beanvalidation.SpringConstraintValidatorFa
|
|||||||
@Configuration(proxyBeanMethods = false)
|
@Configuration(proxyBeanMethods = false)
|
||||||
@ConditionalOnMissingBean(BasicErrorController.class)
|
@ConditionalOnMissingBean(BasicErrorController.class)
|
||||||
@Import({GlobalExceptionHandler.class, GlobalErrorHandler.class})
|
@Import({GlobalExceptionHandler.class, GlobalErrorHandler.class})
|
||||||
|
@EnableConfigurationProperties(I18nProperties.class)
|
||||||
public class GlobalExceptionHandlerAutoConfiguration {
|
public class GlobalExceptionHandlerAutoConfiguration {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandlerAutoConfiguration.class);
|
private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandlerAutoConfiguration.class);
|
||||||
|
@@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package top.continew.starter.web.autoconfigure.i18n;
|
||||||
|
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import top.continew.starter.core.constant.PropertiesConstants;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 国际化 配置属性
|
||||||
|
*
|
||||||
|
* @author Jasmine
|
||||||
|
* @since 2.2.0
|
||||||
|
*/
|
||||||
|
@ConfigurationProperties(prefix = PropertiesConstants.I18N)
|
||||||
|
public class I18nProperties {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 国际化开启 true-开启, false-关闭
|
||||||
|
*/
|
||||||
|
private Boolean enabled;
|
||||||
|
|
||||||
|
public Boolean getEnabled() {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnabled(Boolean enabled) {
|
||||||
|
this.enabled = enabled;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package top.continew.starter.web.util;
|
||||||
|
|
||||||
|
import cn.hutool.extra.spring.SpringUtil;
|
||||||
|
import org.springframework.context.MessageSource;
|
||||||
|
import org.springframework.context.i18n.LocaleContextHolder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Jasmine
|
||||||
|
* @since 2.2.0
|
||||||
|
*/
|
||||||
|
public class MessageSourceUtils {
|
||||||
|
|
||||||
|
private static final MessageSource messageSource = SpringUtil.getBean(MessageSource.class);
|
||||||
|
|
||||||
|
private static final Object[] emptyArray = new Object[] {};
|
||||||
|
|
||||||
|
public static String getMessage(String key) {
|
||||||
|
return getMessage(key, emptyArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getMessage(String key, String defaultMessage) {
|
||||||
|
return getMessage(key, defaultMessage, emptyArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getMessage(String msgKey, Object... args) {
|
||||||
|
return getMessage(msgKey, msgKey, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getMessage(String msgKey, String defaultMessage, Object... args) {
|
||||||
|
try {
|
||||||
|
return messageSource.getMessage(msgKey, args, LocaleContextHolder.getLocale());
|
||||||
|
} catch (Exception e) {
|
||||||
|
return defaultMessage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Reference in New Issue
Block a user