HAP框架实现国际化操作——CacheMessageSource

使用框架:HAP 3.5.6-RELEASE
数据库:mySQL 5.7
说明:这篇文章是为HAP框架编写的。目的是为了分享这个框架的国际化方案,可能还有更好的方法,这里提供一下我的方案:使用框架的 描述维护 功能实现代码内部的国际化(也就是多语言)。

1. 使用MessageSource,配置Bean

Spring Boot、SpringMVC进行i18n国际化支持:使用 MessageSource 。HAP属于SpringMVC,使用的也是MessageSource,但是使用的bean是重新定义的,这个bean的数据源是HAP的基础模块 描述维护
在这里插入图片描述
这里需要配置默认的bean:

<bean id="messageSource" class="com.hand.hap.core.i18n.CacheMessageSource"/>

第一步就完成了。

2. 观察nls()方法

1. 观察 BaseController这个类

在HAP中几乎所有的 Controller 都继承了这个方法,我们发现其中有两个 nls() 方法:

    protected String nls(HttpServletRequest request, String code, Object[] args) {
        Locale locale = RequestContextUtils.getLocale(request);
        return this.messageSource.getMessage(code, args, code, locale);
    }

    protected String nls(HttpServletRequest request, String code) {
        Locale locale = RequestContextUtils.getLocale(request);
        return this.messageSource.getMessage(code, (Object[])null, code, locale);
    }

这两个方法可以用来实现 code 和译文的转换;他们都使用了 String getMessage(String code, Object[] args, String defaultMessage, Locale locale) ;四个参数分别是 code ,要填充的参数,默认描述,和当前语种,这里就不细说了,之所以提到是为了改写这个方法,使得其在 service层 也可以使用,但是这里有一个问题,我们需要传递一个 HttpServletRequest 参数,这样会使得我们的函数使用起来非常不方便。

2. 获取HttpServletRequest

这里提供一种方法:

HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();

这种方式当Bean(这里是当service接口注入时)初始化时,Spring并没有注入一个request对象,而是注入了一个代理(proxy);当Bean中需要使用request对象时,通过该代理获取request对象。这种方式是线程安全的,为了方便使用我们这个方法,我们可以把它放在基类里,这个基类就是BaseServiceImpl

3. 创建nls()方法

我们要创建的 nls() 方法是使用接口的方式,其主要目的是为了在其他功能上取巧,这里不多解释,你也可以像 BaseController 一样设置成 protected 方法,这里用接口的方式;

1. 创建接口

   String nls(String code, Object[] args);
   String nls(String code);

2. 注入 MessageSource

   @Autowired
   private MessageSource messageSource;

3. 创建nls()

    @Override
    public String nls(String code, Object[] args) {
        HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
        Locale locale = RequestContextUtils.getLocale(request);
        return this.messageSource.getMessage(code, args, code, locale);
    }


    @Override
    public String nls(String code) {
        return this.nls(code, null);
    }

4. 测试方法

事先我们定义好一个code:student.studentnumber
在这里插入图片描述
我们的测试类在service里面

    @Override
    public void langTest() {
        System.out.println(nls("student.studentnumber"));
    }

我们在查询页面时调用这个方法:

    @RequestMapping(value = "/student/query")
    @ResponseBody
    public ResponseData query(Student dto, @RequestParam(defaultValue = DEFAULT_PAGE) int page,
                              @RequestParam(defaultValue = DEFAULT_PAGE_SIZE) int pageSize, HttpServletRequest request) 
    {
        IRequest requestContext = createRequestContext(request);
        service.langTest();
        return new ResponseData(service.select(requestContext, dto, page, pageSize));
    }

中文结果

    学号

英文结果

    Student Number

这些说明我们可以通过这样的方式实现后台的国际化,这里还差的就是异常的国际化和统一管理。

4. 异常的国际化和错误提示的统一管理

1. 自定义异常

这里一定要使用自定义的异常,并且要实现的是IBaseException接口,当然也可以直接使用这两个异常:BaseExceptionBaseRuntimeExcepiton,为什么要实现这个接口,我们要看 BaseController 里面是如何处理的;

    @ExceptionHandler({Exception.class})
    public Object exceptionHandler(Exception exception, HttpServletRequest request) {
        this.logger.error(exception.getMessage(), exception);
        Throwable thr = this.getRootCause(exception);
        IBaseException be;
        Locale locale;
        String messageKey;
        String message;
        if (!RequestUtil.isAjaxRequest(request) && !RequestUtil.isAPIRequest(request) && !ServletFileUpload.isMultipartContent(request)) {
            ModelAndView view = new ModelAndView("500");
            if (thr instanceof IBaseException) {
                be = (IBaseException)thr;
                locale = RequestContextUtils.getLocale(request);
                messageKey = be.getDescriptionKey();
                message = this.messageSource.getMessage(messageKey, be.getParameters(), messageKey, locale);
                view.addObject("message", message);
            }

            return view;
        } else {
            ResponseData res = new ResponseData(false);
            if (thr instanceof IBaseException) {
                be = (IBaseException)thr;
                locale = RequestContextUtils.getLocale(request);
                messageKey = be.getDescriptionKey();
                message = this.messageSource.getMessage(messageKey, be.getParameters(), messageKey, locale);
                res.setCode(be.getCode());
                res.setMessage(message);
            } else {
                Locale locale1 = new Locale("zh", "CN");
                ResourceBundle resourceBundle = ResourceBundle.getBundle("message",locale1);

                res.setMessage(thr.toString());
            }

            return res;
        }
    }

在这个方法里,我们可以看到,当它捕获到异常是会判断是否实现了IBaseException ,如果实现了,它会将messageKey 转换成译文;
我们这里可以自定义一个异常类:

public class DuplicateException extends RuntimeException implements IBaseException {

    private String code;
    private String descriptionKey;
    private Object[] parameters;

    public DuplicateException() {
    }

    public DuplicateException(String descriptionKey) {
        super(descriptionKey);
        this.code = null;
        this.descriptionKey = descriptionKey;
        this.parameters = null;
    }

    public DuplicateException(String descriptionKey, Object[] parameters) {
        super(descriptionKey);
        this.code = null;
        this.descriptionKey = descriptionKey;
        this.parameters = parameters;
    }

    public DuplicateException(String code, String descriptionKey, Object[] parameters) {
        super(descriptionKey);
        this.code = code;
        this.descriptionKey = descriptionKey;
        this.parameters = parameters;
    }

    @Override
    public String getCode() {
        return this.code;
    }

    @Override
    public String getDescriptionKey() {
        return this.descriptionKey;
    }

    @Override
    public Object[] getParameters() {
        return this.parameters;
    }

    @Override
    public void setCode(String code) {
        this.code = code;
    }

    @Override
    public void setDescriptionKey(String descriptionKey) {
        this.descriptionKey = descriptionKey;
    }

    @Override
    public void setParameters(Object[] parameters) {
        this.parameters = parameters;
    }
}

2. 测试方法修改

    @Override
    public void langTest() {
        throw new DuplicateException("student.studentnumber");
    }

中文结果:
在这里插入图片描述

英文结果:
在这里插入图片描述
这样就实现了;

3.带参数的定义方式

如果想带参数的,可以这样做;
定义描述:
在这里插入图片描述
改写测试方法:

    @Override
    public void langTest() {
        Object[] objects = {"我是参数1", "我是参数2"};
        throw new DuplicateException("test.lang", objects);
    }

运行结果:
在这里插入图片描述
这样就实现了带参数的实现方法了。


到这里就分享完了我关于HAP的国际化方案了,希望对你有帮助,如果有更好的方案也希望能在评论区分享给我谢谢。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章