美文网首页Java 杂谈技能图谱
SpringBoot系列之服务端解析客户端国际化请求

SpringBoot系列之服务端解析客户端国际化请求

作者: 西召 | 来源:发表于2019-03-27 17:50 被阅读0次

    国际化方案

    前后端分离的国际化方案,如果每个接口都增加参数,代码量和测试量会很大,最好把语言变量加到请求头并通过拦截器解析。

    i18n

    具体过程如下:

    1. 客户端增加请求头 Accept-Language;
    2. 服务端增加拦截器,解析请求头Accept-Language中的语言值,并通过LanguageUtil设置到当前线程的语言环境中;
    3. 服务端需要返回多语言结果的地方,通过LanguageUtil获取当前请求客户端的语言。

    除了请求头,也可以通过cookie实现,但是有些客户端不支持cookie,而且cookie存在被篡改的危险,因此更建议使用标准的请求头。

    实现代码

    通过 SpringMVC 的RequestContextUtilsjava.util.Local,可以很轻松地解析请求头中的语言标识。

    SpringMVC提供了多种国际化的实现方式。

    i18n3

    下面一步步讲解代码实现。

    pom.xml

    使用SpringBoot搭建项目,并且引入Lombok用于简化JavaBean。

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.1.3.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <groupId>net.ijiangtao.tech.framework.spring.ispringboot.demo</groupId>
        <artifactId>demo-i18n</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>demo-i18n</name>
        <description>Demo  Spring Boot  project for i18n</description>
    
        <properties>
            <java.version>1.8</java.version>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
    </project>
    
    

    application.properties

    配置当前服务的端口。

    server.port=8303
    

    LanguageUtil.java

    使用ThreadLocal保存当前线程的环境语言。

    /**
     * @author ijiangtao.net
     */
    public class LanguageUtil {
    
        public static final String ZH_CN = "zh_CN";
    
        public static final String EN_US = "en_US";
    
        public static final String DEFAULT_LANGUAGE = ZH_CN;
    
        private String lang;
    
        private static final ThreadLocal<LanguageUtil> context = new ThreadLocal<LanguageUtil>() {
            @Override
            protected LanguageUtil initialValue() {
                return new LanguageUtil();
            }
        };
    
        public LanguageUtil() {
            lang = DEFAULT_LANGUAGE;
        }
    
        public static LanguageUtil getCurrentContext() {
            return (LanguageUtil) context.get();
        }
    
        public static String getCurrentLang() {
            return getCurrentContext().lang;
        }
    
        public static void setCurrentLang(String lang) {
            getCurrentContext().lang = lang;
        }
    
        public static void remove() {
            context.remove();
        }
    }
    

    LanguageInterceptor.java

    实现HandlerInterceptor接口,拦截并解析请求头中的环境语言,并设置到LanguageUtil中。

    import lombok.extern.slf4j.Slf4j;
    import net.ijiangtao.tech.framework.spring.ispringboot.demo.i18n.util.LanguageUtil;
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.LocaleResolver;
    import org.springframework.web.servlet.ModelAndView;
    import org.springframework.web.servlet.support.RequestContextUtils;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.util.Locale;
    
    @Slf4j
    public class LanguageInterceptor implements HandlerInterceptor {
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
                throws Exception {
            log.info("preHandle:请求前调用");
    
            //请求头 当前语言
            // Accept-Language: zh-CN
            // Accept-Language: en-US
            LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(request);
            Locale local= localeResolver.resolveLocale(request);
    
            log.info("local={} , localDisplayName={}",local.toString(),local.getDisplayName());
    
            LanguageUtil.setCurrentLang(local.toString());
            log.info("LanguageUtil.getCurrentLang() = {}",LanguageUtil.getCurrentLang());
    
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                               ModelAndView modelAndView) throws Exception {
            log.info("postHandle:请求后调用");
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
                throws Exception {
            log.info("afterCompletion:请求调用完成后回调方法,即在视图渲染完成后回调");
        }
    
    }
    
    

    InterceptorConfig.java

    配置拦截器并使之生效。

    
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
    
    @Configuration
    public class InterceptorConfig extends WebMvcConfigurationSupport {
    
        @Override
        public void addInterceptors(InterceptorRegistry registry){
            registry.addInterceptor(new LanguageInterceptor())
                    .addPathPatterns("/**")
                    .excludePathPatterns("/noi18n")
                    .excludePathPatterns("/onelang");
        }
    
    }
    
    

    LanguageController.java

    从LanguageController中获取当前线程设置的环境语言,测试效果。

    
    import net.ijiangtao.tech.framework.spring.ispringboot.demo.i18n.util.LanguageUtil;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    /**
     *
     * @author ijiangtao.net
     */
    @Controller
    public class LanguageController {
    
        @GetMapping("/lang/current")
        @ResponseBody
        public String currentLanguage(){
            return LanguageUtil.getCurrentLang();
        }
    }
    
    

    测试

    使用IDEA的Rest Client发起请求

    使用IDEA的Rest Client发起请求

    测试请求的response

    en_US
    

    总结

    本教程介绍了如何通过客户端的请求头设置服务端的语言环境,从而实现服务端响应内容的国际化。

    希望对你有所帮助。

    Links

    相关文章

      网友评论

        本文标题:SpringBoot系列之服务端解析客户端国际化请求

        本文链接:https://www.haomeiwen.com/subject/owrtbqtx.html