美文网首页
接口多语言方案

接口多语言方案

作者: 千年的心 | 来源:发表于2020-07-04 12:50 被阅读0次

    需求

    最近接到一个官网需求,官网需要动态展示一些企业信息,并且需要中英文切换。客户会在后台录入中文和英文的数据,由于项目是前后端分离,我这边只负责后端部分,根据需求转换为接口的需求就是:1.未登陆匿名用户,那么接口需要返回用户选择的语言,2.登陆用户(系统只有一个账号来维护信息),那么需要返回中英文两个信息。

    思路

    自定义对象的序列化规则。

    实现

    1. 创建存储值对象

    1.1 基础值对象

    package com.yugioh.api.business.common.model;
    
    import com.yugioh.api.business.common.enums.LanguageEnum;
    import com.yugioh.api.business.util.RequestUtil;
    import io.swagger.annotations.ApiModelProperty;
    import lombok.Data;
    import org.springframework.data.annotation.Transient;
    
    import java.util.Objects;
    
    
    /**
     * 公用多语言值对象
     *
     * @author lieber
     */
    @Data
    public class BaseValueObj<T> {
    
        /**
         * 中文
         */
        @ApiModelProperty("中文")
        T zh;
    
        /**
         * 英文
         */
        @ApiModelProperty("英文")
        T en;
    
        // 如果有其他的依次加
    
        /**
         * 前端使用值,前端展示一次只使用一个对象,不存入数据库,使用get方法判断
         */
        @ApiModelProperty(value = "展示端使用值-增加修改入参时不需要传入")
        @Transient
        T val;
    
        public T getVal() {
            // 根据当前语言环境判断使用哪个值返回
            if (Objects.equals(RequestUtil.getRequest().getHeader(LanguageEnum.HEADER), LanguageEnum.EN.code())) {
                return en;
            }
            return zh;
        }
    }
    
    

    1.2 返回当前所选语言的对象

    package com.yugioh.api.business.common.model;
    
    import com.fasterxml.jackson.annotation.JsonIgnore;
    
    /**
     * 前端值对象,只返回当前语言的
     *
     * @author lieber
     */
    public class ValueObj<T> extends BaseValueObj<T> {
    
        @Override
        @JsonIgnore
        public T getZh() {
            return null;
        }
    
        @Override
        @JsonIgnore
        public T getEn() {
            return null;
        }
    
    }
    

    1.3 返回所有语言的对象

    package com.yugioh.api.business.common.model;
    
    import com.fasterxml.jackson.annotation.JsonIgnore;
    
    /**
     * 所有语言对象
     *
     * @author lieber
     */
    public class ValueObjAll<T> extends BaseValueObj<T> {
    
        @Override
        @JsonIgnore
        public T getVal() {
            return null;
        }
    }
    
    

    2. 增加值对象序列化规则

    2.1 新建规则

    package com.yugioh.api.business.common.model;
    
    import com.fasterxml.jackson.annotation.JsonIgnore;
    import com.fasterxml.jackson.core.JsonGenerator;
    import com.fasterxml.jackson.databind.JsonSerializer;
    import com.fasterxml.jackson.databind.SerializerProvider;
    import com.yugioh.api.business.util.RequestUtil;
    import lombok.extern.slf4j.Slf4j;
    
    import java.beans.PropertyDescriptor;
    import java.io.IOException;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import java.util.*;
    
    
    /**
     * 公用多语言值对象序列化
     *
     * @author lieber
     */
    @Slf4j
    public class BaseValueObjSerializer extends JsonSerializer<BaseValueObj> {
    
        private BaseValueObjSerializer() {
        }
    
        public final static BaseValueObjSerializer instance = new BaseValueObjSerializer();
    
    
        @Override
        public void serialize(BaseValueObj value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
            if (value == null) {
                gen.writeNull();
                return;
            }
            Map<String, Object> fieldMap;
    
            if (this.logon()) {
                fieldMap = this.getWriteInfo(ValueObjAll.class, value);
            } else {
                fieldMap = this.getWriteInfo(ValueObj.class, value);
            }
            gen.writeStartObject();
            for (Map.Entry<String, Object> entry : fieldMap.entrySet()) {
                gen.writeObjectField(entry.getKey(), entry.getValue());
            }
            gen.writeEndObject();
        }
    
        /**
         * 获取输出的字段和值
         *
         * @param clazz 输出的类
         * @param value 值
         * @return 映射
         */
        private Map<String, Object> getWriteInfo(Class<? extends BaseValueObj> clazz, BaseValueObj value) {
            List<Field> fields = new ArrayList<>(4);
            Class tempClass = clazz;
            while (tempClass != null) {
                fields.addAll(Arrays.asList(tempClass.getDeclaredFields()));
                tempClass = tempClass.getSuperclass();
            }
            Map<String, Object> map = new LinkedHashMap<>(fields.size());
            // 此处可优化,字段很少,可以直接填充而不需要使用反射从而提高效率。使用反射只是提高通用性和扩展性
            try {
                for (Field field : fields) {
                    if (field.isAnnotationPresent(JsonIgnore.class)) {
                        continue;
                    }
                    PropertyDescriptor propertyDescriptor = new PropertyDescriptor(field.getName(), clazz);
                    Method readMethod = propertyDescriptor.getReadMethod();
                    if (readMethod.isAnnotationPresent(JsonIgnore.class)) {
                        continue;
                    }
                    map.put(field.getName(), readMethod.invoke(value));
                }
            } catch (Exception e) {
                log.error("获取可返回数据出现异常:", e);
            }
            return map;
        }
        
        // 判断是否登录
        private boolean logon() {
            return Objects.equals(RequestUtil.getRequest().getAttribute(RequestUtil.LOGIN_KEY), true);
        }
    }
    
    

    2.2 注册规则

    package com.yugioh.api.common.core.config;
    
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.databind.module.SimpleModule;
    import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
    import com.yugioh.api.business.common.model.BaseValueObj;
    import com.yugioh.api.business.common.model.BaseValueObjSerializer;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.http.converter.HttpMessageConverter;
    import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
    import org.springframework.stereotype.Component;
    import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    
    import java.util.List;
    
    /**
     * 
     * @author lieber
     */
    @Configuration
    @Component
    public class WebMvcConfig implements WebMvcConfigurer {
    
        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {
            // 配置模板资源路径
            registry.addResourceHandler("/templates/**").addResourceLocations("classpath:/templates/");
            registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
            registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
            registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
        }
    
    
        /**
         * 注册序列化规则
         */
        @Override
        public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
            MappingJackson2HttpMessageConverter jackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
            ObjectMapper objectMapper = new ObjectMapper();
            SimpleModule simpleModule = new SimpleModule();
            // 配置BaseValueObj类的序列化规则
            simpleModule.addSerializer(BaseValueObj.class, BaseValueObjSerializer.instance);
            // 序列换成json时,将所有的long变成string
            // 因为js中得数字类型不能包含所有的java long值
            simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
            simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
            objectMapper.registerModule(simpleModule);
            jackson2HttpMessageConverter.setObjectMapper(objectMapper);
            converters.add(jackson2HttpMessageConverter);
        }
    
    }
    
    

    3. 其它使用到的

    package com.yugioh.api.business.common.enums;
    
    /**
     * 语言枚举
     *
     * @author lieber
     */
    public enum LanguageEnum {
    
        /**
         * 中文
         */
        ZH("zh-cn"),
    
        /**
         * 英文
         */
        EN("en-us");
    
        private String code;
    
        LanguageEnum(String code) {
            this.code = code;
        }
    
        public String code() {
            return code;
        }
    
        public final static String HEADER = "language";
    }
    
    

    4. 使用拓展

    如果需要增加语言,那么需要做的事情是:
    1.BaseValueObj增加对应字段,并在getVal方法中指定规则
    2.ValueObj增加对应getter方法并加上@JsonIgnore
    3.LanguageEnum增加对应语言

    相关文章

      网友评论

          本文标题:接口多语言方案

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