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的國際化方案了,希望對你有幫助,如果有更好的方案也希望能在評論區分享給我謝謝。

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