머리말
이 회사는 프로젝트를 Struts2에서 SpringMVC로 이전했습니다. 회사의 사업은 해외 서비스이므로 국제 기능에 대한 수요는 매우 높습니다. Struts2의 국제화 기능은 SpringMVC보다 완벽하지만 Spring의 큰 특징은 사용자 정의 가능하고 맞춤화되므로 회사 프로젝트가 SpringMVC로 이식 될 때 국제화 기능이 추가됩니다. 나는 기록을 편집하고 여기에서 개선했습니다.
이 기사에서 구현 된 주요 기능 :
폴더에서 여러 국제 파일을 직접로드하십시오. 배경 설정 프론트 엔드 페이지에는 국제 정보가 표시됩니다. 국제 정보를 표시하는 파일은 인터셉터 및 주석을 사용하여 자동으로 설정됩니다. 프론트 엔드 페이지에 국제 정보를 표시하는 파일에는 국제 정보가 표시됩니다.
참고 :이 기사는 국제화, 지역 파서 등을 구성하는 방법을 자세히 소개하지 않습니다.
성취하다
국제 프로젝트 초기화
먼저 기본 Spring-Boot+Thymeleaf+국제화 정보 (Message.Properties) 프로젝트를 만듭니다. 필요한 경우 내 github에서 다운로드 할 수 있습니다.
프로젝트의 디렉토리와 파일을 간단히 살펴보십시오.
그중, i18napplication.java는 쿠키를 사용하여 국제 언어를 제어하는 CookieLocaleResolver 설정합니다. 또한 국제 언어의 변화를 가로 채기 위해 LocaleChangeInterceptor 인터셉터를 설정합니다.
@springbootApplication@configurationPublic Class i18Napplication {public static void main (String [] args) {springApplication.run (i18napplication.class, args); } @bean public localeresolver localeresolver () {cookielocaleresolver slr = 새로운 cookielocaleresolver (); SLR.SETCOOKIEMAXAGE (3600); slr.setcookiename ( "Language"); // 저장된 쿠키의 이름을 언어 리턴 SLR로 설정합니다. } @bean public webmvcconfigurer webmvcconfigurer () {return new return new webmvcconfigurer () {// interceptor @intercread public void addinterceptors (interceptorregistry registry) {registry.addinterceptor (new localechangeinterceptor ()). addpathpatterns ( "/**"); }}; }}hello.html로 작성된 내용을 살펴 보겠습니다.
<! docType html> <html xmlns = "http://www.w3.org/1999/xhtml"xmlns : th = "http://www.thymeleaf.org"> <head> <title> </title> <body> <h1 Th : text = "#{i18n_page}"> </h1> <h3 Th : text = "#{hello}"> </h3> </body> </html> 이제 프로젝트를 시작하고 http://localhost:9090/hello 방문하십시오 (포트를 Application.Properties에서 9090으로 설정).
브라우저의 기본 언어는 중국어이므로 Messages_ZH_CN.Properties에서 검색하는 것이 기본값이며, 그렇지 않은 경우 국제화 된 단어에 대한 메시지에서 검색됩니다.
그런 다음 브라우저에 http://localhost:9090/hello?locale=en_US 입력하면 언어가 영어로 잘립니다. 마찬가지로 URL 이후의 매개 변수가 locale=zh_CH 로 설정되면 언어는 중국어로 절단됩니다.
폴더에서 여러 국제 파일을 직접로드하십시오
hello.html 페이지에는 두 가지 국제 정보 'i18n_page'와 'hello'가 있습니다. 그러나 실제 프로젝트에서는 몇 가지 국제 정보만큼 작지 않을 것입니다. 그런 다음 messages.properties 포함 된 파일에 너무 많은 국제 정보를 넣어서는 안되며 일반적으로 국제 정보는 여러 파일로 분류되고 저장됩니다. 그러나 프로젝트가 커지면 이러한 국제 파일은 점점 더 많아 질 것입니다. 현재이 파일을 application.properties 파일에서 하나씩 구성하는 것은 불편합니다. 이제 우리는 공식 디렉토리에 모든 국제 파일을 자동으로로드하는 기능을 구현합니다.
ResourceBundEssagesSource를 상속합니다
ResourceBundleMessageSource 또는 ReloadableResourceBundleMessageSource 상속받을 수있는 프로젝트에서 클래스를 작성하고 MessageResourceExtension 의 이름을 지정하십시오. 그리고 그것을 콩에 주입하고 messageSource 라는 이름을 지정합니다.
@Component ( "MessessOURCE") Public Class MessagerESourceExtension Extends ResourceBundleMessagesSource {} ApplicationContext 초기화 할 때 'MessageSource'라는 Bean이있는 Bean이 조회되기 때문에 구성 요소 이름은 'MessageSource'여야합니다. 이 프로세스는 AbstractApplicationContext.java 에 있습니다. 소스 코드를 살펴 보겠습니다
/*** MessageSource를 초기화하십시오.*이 맥락에서 정의되지 않은 경우 부모를 사용하십시오.*/Protected void initMessagesSource () {configurableIstableBeanFactory beanFactory = getBeanCactory (); if (beanfactory.containslocalbean (message_source_bean_name)) {this.messagesource = beanfactory.getBean (message_source_bean_name, messageSource.class); ...}} ... 이 MessageSource를 초기화하는이 방법에서, BeanFactory는 MESSAGE_SOURCE_BEAN_NAME(messageSource) 이름으로 주입 된 Bean을 찾습니다. 찾지 못하면 부모 수업에 이름이있는 콩이 있는지 여부를 찾습니다.
파일로드를 구현합니다
이제 방금 만든 MessageResourceExtension 시작할 수 있습니다
파일을로드하는 메소드가 작성되었습니다.
@Component ( "MessageSource") 공개 클래스 MessagerESourceExtension 확장 resourceBundLemessagesSource {private final static logger = loggerfactory.getLogger (MessagerEsourceExtension.class); / *** 지정된 국제화 파일 디렉토리*/ value (value = "$ {spring.messages.basefolder : i18n}") private String basefolder; / *** 부모 메시지로 지정된 국제화 파일*/ @Value (value = "$ {spring.messages.baseName : message}") 개인 문자열 basename; @PostConstruct public void init () {logger.info ( "init messageresourceextension ..."); if (! stringUtils.isempty (basefolder)) {try {this.setbasenames (getallbasenames (basefolder)); } catch (ioException e) {logger.error (e.getMessage ()); }} // 상위 메시지 설정 자료 ResourceBundleMessagesOURCE Parent = New ResourceBundleMessagesSource (); parent.setbaseName (basename); this.SetParentMessagesOURCE (부모); } / ** * 폴더에서 모든 국제 파일 이름을 가져옵니다 * * @param 폴더 이름 파일 이름 * @return * @throws ioException * / private String [] getAllBasEnames (String FolderName)는 ioException {resource resource = new ClassPathResource (folderName); 파일 = resource.getFile (); list <string> basenames = new ArrayList <> (); if (file.exists () && file.isdirectory ()) {this.getallfile (basenames, file, ""); } else {logger.error ( "지정된 BaseFile이 존재하지 않거나 폴더가 아님"); } return basenames.toArray (새 문자열 [basenames.size ()]; } / ** * 모든 파일을 가로 지르십시오 * * @param basenames * @param 폴더 * @param path * / private void getAllFile (list <string> basenames, 파일 폴더, 문자열 path) {if (folder.isdirectory ()) {for (파일 파일 : folder.listfiles ()) {thistallfile (vase, poat, path.getname). file.separator); }} else {String i18name = this.geti18filename (path + folder.getName ()); if (! basenames.contains (i18name)) {basenames.add (i18name); }}} / ** * 일반 파일 이름을 국제 파일 이름으로 변환 * * @param filename * @return * / private String geti18filename (string filename) {filename = filename.replace ( ". Properties", ""); for (int i = 0; i <2; i ++) {int index = filename.lastIndexof ( "_"); if (index! = -1) {filename = filename.substring (0, index); }} 리턴 파일 이름; }}차례로 몇 가지 방법을 설명하십시오.
init() 메소드에는 @PostConstruct 주석이 있으며 MessagerESourceExtension 클래스가 인스턴스화 된 후 init() 메소드를 자동으로 호출합니다. 이 방법은 baseFolder 디렉토리의 모든 국제화 파일을 가져 와서 basenameSet 로 설정합니다. 그리고 국제 정보를 찾을 수 없을 때 ParentMessageSource 설정하여 ParentMessagesOURCE를 설정하여 국제 정보를 찾을 수 없을 때 국제 정보를 찾으십시오.getAllBaseNames() 메소드는 baseFolder 로의 경로를 가져온 다음 getAllFile() 메소드를 호출하여 디렉토리에서 모든 국제 파일의 파일 이름을 가져옵니다.getAllFile() 디렉토리를 가로 지르며, 폴더 인 경우 파일 인 경우 getI18FileName() 호출하여 파일 이름을 'i18n/basename/'형식으로 국제 리소스 이름으로 변환합니다. 간단히 말해서, MessageResourceExtension 인스턴스화 된 후에 간단히 말하면 'i18n'폴더의 리소스 파일의 이름이 Basenames 에로드됩니다. 이제 효과를 보겠습니다.
먼저, spring.messages.baseFolder=i18n application.properties 파일에 추가하여 MessageResourceExtension 의 baseFolder 에 'i18n'을 할당합니다.
시작한 후, init 정보가 콘솔에 인쇄되어 @PostConstruct 에 의해 주석이 달린 init () 메소드가 실행되었음을 나타냅니다.
그런 다음 '대시 보드'와 '판매자'라는 두 가지 국제 정보 파일 세트를 만듭니다. 여기에는 각각 'Dashboard.Hello'및 'Merchant.Hello'라는 하나의 국제 정보 만 있습니다.
그런 다음 hello.html 파일을 수정 한 다음 hello 페이지를 방문하십시오.
... <body> <h1> 국제화 페이지! </h1> <p th : text = "#{hello}"> </p> <p th : text = "#{merchant.hello}"> </p> <p th : text = "#{dashboard.hello.hello.hello.1"> </p> </body> ...'Message', 'Dashboard'및 'Merchant'의 국제화 정보가 웹 페이지에로드되어 'I18N'폴더 아래에 파일을 한 번에로드했음을 나타냅니다.
배경 설정의 프론트 엔드 페이지에 국제 정보를 표시하는 파일
이전 섹션에서는 여러 국제화 파일을 성공적으로로드하고 국제화 정보를 표시했습니다. 그러나 'Dashboard.Properties'의 국제화 정보는 'Dashboard.Hello'및 'Merchant.Properties'는 'Merchant.hello'입니다. 따라서 각각에 대한 접두사를 작성하는 것은 매우 번거 롭습니다. 이제 '대시 보드'와 '판매자'의 국제화 파일에만 'Hello'를 쓰고 싶지만 '대시 보드'또는 '판매자'의 국제화 정보가 표시됩니다.
MessageResourceExtension 에서 resolveCodeWithoutArguments 메소드를 다시 작성하십시오 (문자 형식이 필요한 경우 resolveCode 다시 작성).
@component ( "messageSource") public class messageresourceextension resourceBundLemessagesSource {... public static string i18n_attribute = "i18n_attribute"; @override Protected String resolveCodeWithOutArguments (문자열 코드, 로케일 로케일) {// 요청에 지정된 국제 파일 이름을 가져옵니다. servletRequestAttributes attr = (servletRequestAttributes) requestContexTholder.currentRequestattributes (); 최종 문자열 i18file = (string) attr.getAttribute (i18n_attribute, requestAttributes.scope_request); if (! stringUtils.isempty (i18file))) {// Basenameset String basename = getBasenameset () .filter (이름 -> stringUtils.endswitHignoreCase (name, i18file)) .FANDFIRST (). ORELSE (NULL); if (! stringUtils.isempty (basename)) {// 지정된 국제 파일 리소스 리소스 자원 자원 자원을 가져옵니다. if (bundle! = null) {return getStringornull (번들, 코드); }}} // 지정된 i18 폴더에 국제화 필드가없는 경우 NULL을 반환하면 부모님이 null을 찾을 수 있습니다. } ...} resolveCodeWithoutArguments 메소드에서 우리가 다시 작성한 httpservletRequest (이것을 설정할 위치에 대해 이야기 할 것임)에서 'i18n_attribute'를 받으십시오. 그런 다음 BasenameSet 에서 파일을 찾은 다음 getResourceBundle 통해 리소스를 얻고 마침내 getStringOrNull 통해 해당 국제 정보를 얻습니다.
이제 HelloController 에 두 가지 방법을 추가합시다.
@ControllerPublic 클래스 HelloController {@getMapping ( "/hello") public String index (httpservletRequest request) {request.setAttribute (MessagerESourceExtension.i18n_attribute, "hello"); "System/Hello"를 반환합니다. } @getMapping ( "/dashboard") public String dashboard (httpservletrequest request) {request.setAttribute (MessagerEsourceExtension.i18n_attribute, "dashboard"); "대시 보드"를 반환합니다. } @getMapping ( "/merchant") public String 판매자 (httpservletrequest request) {request.setAttribute (MessagerEsourceExtension.i18n_attribute, "merchant"); "상인"을 반환합니다. }} 각 방법에서 해당 'I18N_ATTRIBUTE'을 설정하여 각 요청에서 해당 국제화 파일을 설정 한 다음 MessageResourceExtension 에서 가져옵니다.
현재 국제화 파일을보고 모든 키워드가 'Hello'임을 알 수 있지만 정보는 다릅니다.
동시에, 두 개의 새로운 HTML 파일은 'Dashboard.html'및 'merchant.html'이며, 'Hello'에 대한 국제 정보와 구별을위한 제목 만 있습니다.
<!-이것은 hello.html-> <body> <h1> 국제화 페이지입니다! </h1> <p th : text = "#{hello}"> </p> </body> <!-이것은 dashboard.html-> <body> <h1> 국제화 페이지 (대시 보드)! </h1> <p th : text = "#{hello}"> </p> </body>입니다 <!-이것은 Merchant.html-> <body> <h1> 국제화 페이지 (Merchant)! </h1> <p th : text = "#{hello}"> </p> </body>입니다현재 프로젝트를 시작하고 살펴 보겠습니다.
각 페이지의 국제화 단어는 'Hello'이지만 해당 페이지에 표시하려는 정보를 표시합니다.
인터셉터 및 주석을 사용하여 프론트 엔드 페이지에 국제 정보를 표시하는 파일을 자동으로 설정하십시오.
해당 국제화 정보를 지정할 수 있지만 각 컨트롤러의 HTTPSERVletRequest에서 국제화 파일을 설정하기에는 너무 번거 롭기 때문에 이제 해당 파일을 표시하기 위해 자동 판단을 구현합니다.
먼저 클래스 또는 메소드에 배치 할 수있는 주석을 만듭니다.
@TARGET ({ElementType.type, elementType.Method}) @retention (retentionPolicy.runtime) public @Interface i18n { / *** 국제화 된 파일 이름* / string value ();} 그런 다음 현재 컨트롤러 메소드에 생성 된 I18n 주석을 넣었습니다. 그 효과를 표시하기 위해 ShopController 및 UserController 생성하고 해당 '상점'및 '사용자'국제 파일도 생성하며 콘텐츠도 'Hello'입니다.
@ControllerPublic 클래스 HelloController {@getMapping ( "/hello") public String index () {return "System/Hello"; } @i18n ( "대시 보드") @getMapping ( "/dashboard") public String dashboard () {return "dashboard"; } @i18n ( "merchant") @getMapping ( "/merchant") public String merchant () {return "merchant"; }} @i18n ( "shop") @ControllerPublic Class ShopController {@getMapping ( "Shop") public String Shop () {return "shop"; }} @ControllerPublic Class UserController {@getMapping ( "user") public String user () {return "user"; }} 우리는 I18n 주석을 dashboard 및 merchant 메소드 아래에 HelloController 와 ShopController 클래스에 각각 배치합니다. 원래 dashboard 및 merchant 메소드에서 'i18n_attribute'를 설정하는 진술이 제거됩니다.
준비는 모두 완료되며 이제 이러한 주석을 기반으로 국제화 파일을 자동으로 지정하는 방법을 확인하십시오.
공개 클래스 MessagerEsourceinterceptor는 핸들러 인터셉터를 구현합니다 {@override public void posthandle (httpservletrequest req, httpservletresponse rep, 객체 핸들러, modelandview modelandview) {// if (null! = req.getattribute. i18netttterbute.i18nettterbute; } handlermethod method = (handlermethod) 핸들러; // 방법 i18 i18n i18nmethod = method.getMethodannotation (i18n.class)에 대한 주석; if (null! = i18nmethod) {req.setattribute (messageresourceextension.i18n_attribute, i18nmethod.value ()); 반품; } // 컨트롤러의 주석은 i18n i18ncontroller = method.getBeantype (). getAnnotation (i18n.class); if (null! = i18ncontroller) {req.setattribute (messageresourceextension.i18n_attribute, i18ncontroller.value ()); 반품; } // set i18 string controller = method.getBeanType (). getName (); int index = controller.lastIndexof ( "."); if (index! = -1) {controller = controller.substring (index + 1, controller.length ()); } index = controller.toupperCase (). indexof ( "컨트롤러"); if (index! = -1) {controller = controller.substring (index + 1, controller.length ()); } index = controller.toupperCase (). indexof ( "컨트롤러"); if (index! = -1) {controller = controller.substring (0, index); } req.setAttribute (MessagerEsourceextension.i18n_attribute, 컨트롤러); } @override public boolean prehandle (httpservletrequest req, httpservletrepronse rep, object handler) {//이 메소드로 점프 할 때 먼저 요청 req.removeattrube (messageresourceextension.i18n_attribute); 진실을 반환하십시오. }}이 인터셉터를 간단히 설명하겠습니다.
먼저, 요청에 이미 'i18n_attribute'가있는 경우 설정이 컨트롤러 메소드에 지정되어 있고 더 이상 판단이 이루어지지 않음을 의미합니다.
그런 다음 인터셉터로 들어가는 방법에 I18n 주석이 있는지 확인하십시오. 있으면 'i18n_attribute'를 요청으로 설정하고 인터셉터를 종료하십시오. 없으면 계속하십시오.
그런 다음 절편에 들어간 클래스에 I18n 주석이 있는지 확인하십시오. 있으면 'i18n_attribute'를 요청으로 설정하고 인터셉터를 종료하십시오. 없으면 계속하십시오.
마지막으로, 메소드 및 클래스에 I18n 주석이 없으면 컨트롤러 이름에 따라 지정된 국제화 파일을 자동으로 설정할 수 있습니다. 예를 들어 'UserController'는 '사용자'국제화 파일을 찾습니다.
이제 효과를 확인하고 각 링크에 표시된 해당 국제 정보의 내용을 확인하겠습니다.
마침내
방금 전체 국제화 향상의 기본 기능을 완료했습니다. 마지막으로, 모든 코드와 통합 된 부트 스트랩4를 정렬하여 기능의 구현 효과를 보여줍니다.
자세한 코드는 Github의 Spring-Boot-I18N-Pro 코드를 참조하십시오.
위는이 기사의 모든 내용입니다. 모든 사람의 학습에 도움이되기를 바랍니다. 모든 사람이 wulin.com을 더 지원하기를 바랍니다.