前言

本篇文章中,所使用的架构是前后端半分离,采用 SpringMVC + JSP + JS 实现视图层,三者的分工,如下:

SpringMVC :1. JSP 模版绑定;2. 数据提交及返回;

JSP : 前台页面展示;

JS :1. 数据提交/接收;2. 数据渲染;3. 网页效果。

业务场景

工作中,经常出现:JSON 格式的字符串与 Java 对象互相转换的情形。如果我们使用 SpringMVC 框架,就可以用 :

@ResponseBody 返回 JSON 数据

@RequestBody 接收 JSON 数据

但这种方式只能用于 Controller 的接收及返回,无法应用在其它场景。比如:

拦截器中,对某些非法参数进行拦截,并返回错误信息。这时候就要重写 HttpResponse,再返回 JSON 格式。

单点登陆,将“用户信息”保存到 redis 时,Java 对象要转成 JSON 字符串;从 redis 取出“用户信息”后,要将 JSON 字符串转成 Java 对象。

在上述这两种情景中,我们需要一个工具类,来实现:JSON 字符串及 Java 对象的互转。

基本设计

这个工具类,我们命名为:JsonMapper,有 2 个核心方法:

JSON 字符串转 Java 对象;

Java 对象转 JSON 字符串;

功能实现

这个工具类已经用在实际工作上,完全适合作为“轮子”,供大家在日常工作中使用,“源码地址”放在文末。

这里,我们为了更清晰地解释代码的作用及设计思路,会把分析写在“代码注释”上。所以,大家如果想比较深入的理解代码及知识点,可以认真阅读下面的“代码注释”及“知识点介绍”。

1. 引用 Maven 依赖

我们需要在Maven中,引用 1 个工具包,

org.codehaus.jackson
jackson-mapper-asl
1.9.12
2. 定义、配置 ObjectMapper
这里,我们需要新建 JsonMapper 类,代码如下:
public class JsonMapper {
// 日志
private static Logger log = LoggerFactory.getLogger(JsonMapper.class);
// 用于 Java 对象的序列化及反序列化
private static ObjectMapper objectMapper = new ObjectMapper();
// objectMapper 配置
static {
// 对象的所有字段全部列入
objectMapper.setSerializationInclusion(Inclusion.ALWAYS);
// 取消默认转换 timestamps
objectMapper.configure(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS, false);
// 忽略空bean转 JSON 的错误
objectMapper.configure(SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS, false);
// 所有日期格式都统一为:yyyy-MM-dd HH:mm:ss
objectMapper.setDateFormat(new SimpleDateFormat(DateTimeUtil.STANDARD_FORMAT));
// 忽略 JSON 字符串存在,但 Java 对象中不存在对应属性的情况,防止错误
objectMapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}
}
3. Java 对象序列化为 JSON 字符串
/**
* 对象转换json字符串
* @param obj 任意对象
* @param 将此方法声明为泛型方法,可传入任何对象
* @return json字符串
*/
public static String obj2String(T obj) {
if (obj == null) {
return null;
}
// 如果是String,则返回原对象,否则执行对象转json
try {
return obj instanceof String ? (String) obj : objectMapper.writeValueAsString(obj);
} catch (Exception e) {
log.warn("Parse Object to String error:", e);
return null;
}
}
/**
* 对象转换json字符串,并返回格式化好的json字符串
* @param obj 任意对象
* @param 将此方法声明为泛型方法,可传入任何对象
* @return json字符串
*/
public static String obj2StringPretty(T obj) {
if (obj == null) {
return null;
}
// 如果是String,则返回原对象,否则执行对象转json
try {
return obj instanceof String ? (String) obj : objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
} catch (Exception e) {
log.warn("Parse Object to String error:", e);
return null;
}
}
4. JSON 字符串反序列化为 Java 对象
/**
* json字符串转换对象
* @param str json字符串
* @param clazz 转换目标对象
* @param 将此方法声明为泛型方法,可传入任何对象
* @return 目标对象
*/
public static T string2Obj(String str, Class clazz) {
if (StringUtils.isEmpty(str) || clazz == null) {
return null;
}
try {
return clazz.equals(String.class) ? (T) str : objectMapper.readValue(str, clazz);
} catch (IOException e) {
log.warn("Parse String to Object error:", e);
return null;
}
}
/**
* json字符串转换对象
* @param str json字符串
* @param typeReference 转换目标对象
* @param 将此方法声明为泛型方法,可传入任何对象
* @return 目标对象的集合
*/
public static T string2Obj(String str, TypeReference typeReference) {
if (StringUtils.isEmpty(str) || typeReference == null) {
return null;
}
try {
return (T) (typeReference.getType().equals(String.class) ? str : objectMapper.readValue(str, typeReference));
} catch (IOException e) {
log.warn("Parse String to Object error:", e);
return null;
}
}
/**
* json 字符串转换成“集合对象”
* @param str json字符串
* @param collectionClass 集合类型
* @param elementClass Java对象
* @param 将此方法声明为泛型方法,可传入任何对象
* @return 目标对象的集合
*/
public static T string2Obj(String str, Class> collectionClass, Class>... elementClass) {
JavaType javaType = objectMapper.getTypeFactory().constructParametricType(collectionClass, elementClass);
try {
return objectMapper.readValue(str, javaType);
} catch (IOException e) {
log.warn("Parse String to Object error:", e);
return null;
}
}