我们公司的springboot国际化(多语言)解决方案,有demo,

2 篇文章 0 订阅
1 篇文章 0 订阅

我们公司现在在做面向巴西市场的APP,需要有葡萄牙语、西班牙语、英语、汉语四种语言今天把我们做的多语言部分独立出来做个demo分享出来

1.git地址及使用说明:

git地址
https://gitee.com/ayezs/spring-internationalization-demo
整个项目非常简单,只有一个springboot,还集成了swagger
只要有JAVA1.8+和maven环境就能跑起来
swagger访问地址:
http://localhost:8080/doc.html
在这里插入图片描述

2.Demo基础逻辑

2.1 首先,所有的正常的请求都有前台的APP管理

2.2 我们写了一个基础的异常类,异常类中有一个StatusCode,StatusCode是一个enum,存放了多语言返回值的key


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();
    }
}

2.3 所有的业务异常都继承了这个基础的异常类,如:


@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;
    }
}

2.4 如果有异常用自己的业务异常封装一下,将StatusCode传进去然后抛出来,如:

@GetMapping("/demo")
    public Result demo(){
        throw new DemoException(StatusCode.USER_EXCEPTION);
    }

2.5 配置一个全局异常处理程序


@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);
    }
}

3.最重要的多语言部分

3.1首先在resources目录下加入i18n文件夹,文件夹下存放多语言配置文件,如图:

多语言配置文件
为避免误会在贴一张win10下的目录()

在这里插入图片描述

3.2文件内容示例:

文件内容示例

个人感觉这里的code做的不是太好,到时候可以自己根据需要将key的规则自行改一下

3.3根据语言和返回值的key获取返回值的message


/**
 * 状态码国际化
 * @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

结语

暂时就这样吧,看不明白的话建议把代码下到本地跑一下,很简单的

如果有问题可以发邮件到 pangdonghao@foxmail.com 联系我

  • 7
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
【2021年,将Spring全家桶的课程进行Review,确保不再有课程的顺序错乱,从而导致学员看不懂。进入2022年,将Spring的课程进行整理,整理为案例精讲的系列课程,并开始加入高阶Spring Security等内容,一步步手把手教你从零开始学会应用Spring,课件将逐步进行上传,敬请期待!】 本课程是Spring全家桶系列课程的第三部分Spring Boot,Spring案例精讲课程以真实场景、项目实战为导向,循序渐进,深入浅出的讲解Java网络编程,助力您在技术工作中更进一步。 本课程聚焦Spring Boot核心知识点:整合Web(如:JSP、Thymeleaf、freemarker等的整合)的开发、全局异常处理、配置文件的配置访问、多环境的配置文件设置、日志Logback及slf4j的使用、国际化设置及使用, 并在最后以一个贯穿前后台的Spring Boot整合Mybatis的案例为终奖,使大家快速掌握Spring的核心知识,快速上手,为面试、工作都做好充足的准备。 由于本课程聚焦于案例,即直接上手操作,对于Spring的原理等不会做过多介绍,希望了解原理等内容的需要通过其他视频或者书籍去了解,建议按照该案例课程一步步做下来,之后再去进一步回顾原理,这样能够促进大家对原理有更好的理解。 【通过Spring全家桶,我们保证你能收获到以下几点】 1、掌握Spring全家桶主要部分的开发、实现2、可以使用Spring MVC、Spring Boot、Spring Cloud及Spring Data进行大部分的Spring开发3、初步了解使用微服务、了解使用Spring进行微服务的设计实现4、奠定扎实的Spring技术,具备了一定的独立开发的能力  【实力讲师】 毕业于清华大学软件学院软件工程专业,曾在Accenture、IBM等知名外企任管理及架构职位,近15年的JavaEE经验,近8年的Spring经验,一直致力于架构、设计、开发及管理工作,在电商、零售、制造业等有丰富的项目实施经验  【本课程适用人群】如果你是一定不要错过!  适合于有JavaEE基础的,如:JSP、JSTL、Java基础等的学习者没有基础的学习者跟着课程可以学习,但是需要补充相关基础知识后,才能很好的参与到相关的工作中。 【Spring全家桶课程共包含如下几门】 
在创建SpringBoot项目时,通常会有一个名为DemoApplication的主类,该类使用了注解@SpringBootApplication来开启SpringBoot的自动配置。这个主类是项目的入口点,我们可以直接运行该类的main方法来启动整个项目。至于demo文件,通常会在创建SpringBoot项目的过程中生成一个示例文件,用于演示项目的基本功能和结构。这个示例文件通常包含了一些基本的业务逻辑和配置。但是具体是否有demo文件还要根据你使用的开发工具和创建项目的方式来确定。例如,使用IntelliJ的社区版可以安装spring boot helper插件来创建SpringBoot项目,并在其中生成demo文件。另外,有时在创建项目时可能会发生一些问题,比如报错"无效的源发行版17",这可能是因为选择了不兼容的SpringBoot版本,导致项目的Java版本不匹配。需要检查pom.xml文件中的java version是否正确设置为所需的版本。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [SpringBoot(一)使用itelliJ社区版创建SpringBoot项目](https://blog.csdn.net/qq_21154101/article/details/131415849)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值