使用框架: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接口,當然也可以直接使用這兩個異常:BaseException 和 BaseRuntimeExcepiton,爲什麼要實現這個接口,我們要看 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的國際化方案了,希望對你有幫助,如果有更好的方案也希望能在評論區分享給我謝謝。