我们公司现在在做面向巴西市场的APP,需要有葡萄牙语、西班牙语、英语、汉语四种语言今天把我们做的多语言部分独立出来做个demo分享出来
git地址
https://gitee.com/pdh123/spring-internationalization-demo
整个项目非常简单,只有一个springboot,还集成了swagger
只要有JAVA1.8+和maven环境就能跑起来
swagger访问地址:
http://localhost:8080/doc.html
public abstract class BaseException extends RuntimeException {
protected StatusCode statusCode;
public BaseException() {
}
public BaseException(Throwable ex) {
super(ex);
}
public BaseException(String message) {
super(message);
}
public BaseException(StatusCode statusCode) {
this.statusCode = statusCode;
}
public BaseException(StatusCode statusCode, String message) {
super(message);
this.statusCode = statusCode;
}
public BaseException(String message, Throwable ex) {
super(message, ex);
}
public Meta handler() {
Meta meta = new Meta();
meta.setSuccess(false);
meta.setCode(getStatusCode().value());
if (!StringUtils.isEmpty(getMessage())) {
meta.setMsg(getMessage()); // 取系统的错误消息
}else {
meta.setMsg(getStatusCode().msg());
}
return meta;
}
protected abstract StatusCode getStatusCode();
}
精简后的StatusCode ,注意msg()方法,这个方法会根据key获取国际化信息
Resources类在3.3中
/**
* 状态码,主要参考Http状态码,但并不完全对应
* @author amigo
*
*/
public enum StatusCode {
/** 200请求成功 */
OK(200),
/** 400请求参数出错 */
BAD_REQUEST(400),
/** 401没有登录 */
UNAUTHORIZED(401),
/** 500服务器出错 */
INTERNAL_SERVER_ERROR(500),
/** 2000用户异常 */
USER_EXCEPTION(2000),
;
private final Integer value;
StatusCode(Integer value) {
this.value = value;
}
public Integer value() {
return this.value;
}
public String msg() {
return Resources.getMessage("STATUSCODE_" + this.value);
}
public Meta handler() {
Meta meta = new Meta();
if(this.value==200){
meta.setSuccess(true);
}else {
meta.setSuccess(false);
}
meta.setCode(value);
meta.setMsg(msg());
return meta;
}
@Override
public String toString() {
return this.value.toString();
}
}
@SuppressWarnings("serial")
public class DemoException extends BaseException {
public DemoException() {
super();
}
public DemoException(String message) {
super(message);
}
public DemoException(StatusCode statusCode) {
super(statusCode);
}
public DemoException(StatusCode statusCode, String message) {
super(statusCode, message);
}
public DemoException(String message, Throwable ex) {
super(message, ex);
}
@Override
protected StatusCode getStatusCode() {
return super.statusCode != null ? super.statusCode : StatusCode.USER_EXCEPTION;
}
}
@GetMapping("/demo")
public Result demo(){
throw new DemoException(StatusCode.USER_EXCEPTION);
}
@ControllerAdvice
@RestController
@RequestMapping( value = "/error")
@Slf4j
public class ControllerException {
@RequestMapping(value = "/401" ,produces = {"application/json;charset=UTF-8"})
public Result forbidden401(HttpServletResponse response) {
response.setStatus(200);
System.out.println("401");
return Result.error(StatusCode.UNAUTHORIZED);
}
@ExceptionHandler(Exception.class)
@ResponseBody
public Result defaultException(Exception e) {
log.error("系统内部错误", e);
return Result.error(StatusCode.INTERNAL_SERVER_ERROR);
}
/**
* 业务异常.
* @param ex
* @return
*/
@ExceptionHandler(BaseException.class)
@ResponseStatus(HttpStatus.OK)
@ResponseBody
public Result businessException(BaseException ex) {
Meta meta = ex.handler();
log.error("业务异常 => {}", meta.getMsg());
return Result.error(meta);
}
}
个人感觉这里的code做的不是太好,到时候可以自己根据需要将key的规则自行改一下
/**
* 状态码国际化
* @author pangdonghao
* @csdn https://blog.csdn.net/pangdongh
* @version 1.0
* @createDate 2019/08/19 13:52
*/
@PropertySource(value = { "classpath:i18n/messages*.properties" })
public class Resources {
/** 将国际化信息存放在一个map中 */
private static final Map<String, ResourceBundle> MESSAGES = new HashMap<String, ResourceBundle>();
/** 获取国际化信息 */
public static String getMessage(String key, Object... params) {
//获取语言,这个语言是从header中的Accept-Language中获取的,
//会根据Accept-Language的值生成符合规则的locale,如zh、pt、en等
Locale locale = LocaleContextHolder.getLocale();
ResourceBundle message = MESSAGES.get(locale.getLanguage());
if (message == null) {
synchronized (MESSAGES) {
//在这里读取配置信息
message = MESSAGES.get(locale.getLanguage());
if (message == null) {
//注1
message = ResourceBundle.getBundle("i18n/messages", locale);
MESSAGES.put(locale.getLanguage(), message);
}
}
}
//此处获取并返回message
if (params != null) {
return String.format(message.getString(key), params);
}
return message.getString(key);
}
/** 清除国际化信息 */
public static void flushMessage() {
MESSAGES.clear();
}
}
注1:
此处要注意ResourceBundle.getBundle方法,此处如果没有匹配到合适的语言会直接使用系统的语言
源码中是这样写的
for (Locale targetLocale = locale;//这是我们传过去的locale
targetLocale != null;
//如果我们传过去的locale没有用,就会获取候选环境
//
targetLocale = control.getFallbackLocale(baseName, targetLocale)) {
//此处省略获取资源包(ResourceBundle)的代码
}
}
getFallbackLocale方法:
public Locale getFallbackLocale(String baseName, Locale locale) {
if (baseName == null) {
throw new NullPointerException();
}
Locale defaultLocale = Locale.getDefault();
return locale.equals(defaultLocale) ? null : defaultLocale;
}
这个方法主要是调用了Locale.getDefault();
这个方法会根据当前系统的信息返回一个Locale
暂时就这样吧,看不明白的话建议把代码下到本地跑一下,很简单的
如果有问题可以发邮件到 [email protected] 联系我