需求
最近接到一个官网需求,官网需要动态展示一些企业信息,并且需要中英文切换。客户会在后台录入中文和英文的数据,由于项目是前后端分离,我这边只负责后端部分,根据需求转换为接口的需求就是: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增加对应语言
网友评论