1.情景展示
如上图所示,这一个标准的json字符串,双引号需要使用反斜杠进行转义,
一般情况下,我们是用不到这种json字符串的,在java中,json字符串的通常表现形式是这种:
其本质还是json对象,并不是真正意义上的json字符串(即使将json对象转字符串),哪里会用到上面那种带转义符的json字符串?(下面示例)
完整请求参数:
后台用实体类接收,且Person用的是字符串String来接收的
一般情况下,是不会出现这种变态需求的,明明是json对象,却用字符串接收,我们通常通过java后台发送http请求时,往往传送的数据格式是这样的:
而我们一旦使用这种标准的json数据格式发送请求,对方服务器在接收到数据后往Person里塞数据时,将会报错:大致信息是-需要的是字符串,提供的却是json对象。
↓↓↓如果是想在json对象里嵌套json字符串,直接看最后↓↓↓
如何生成这种格式的数据?
2.具体实践
准备工作:
JSON对象常用的有两种:一种是net.sf.json.JSONObject,另一种是com.alibaba.fastjson.JSONObect
错误示例一:调用原生的toString()方法
这是java形式的json字符串,无论是net的toString()还是ali的toString()、toJSONString()方法,里面存的还是对象,并不是我们想要的结果
错误示例二:使用FackJson
import com.fasterxml.jacks on.core.io.JsonStringEncoder;
这种是javascript形式的json字符串,虽然离目标近了,但还是不是我们想要的结果
错误示例三:使用StringEscapeUtils
import org.apache.commons.lang.StringEscapeUtils
还是不行,生成的也是JavaScript形式的json字符串
3.解决方案
方式一:通过Jackson实现
所需jar包:
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.10</version> </dependency>
导入:
import com.fasterxml.jackson.core.io.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper;
代码实现:
/* * json转字符串(带转义符且两边带双引号) * @attention: 与 当formatJson()的入参为json字符串 实现的效果一致 * @date: 2020年10月24日 0024 10:01 * @param: json JSONObject/JSONArray * @return: java.lang.String 字符串(带转义符) */ public static String toJsonString(Object json) { if (null == json) return ""; String jsonStr = ""; // JSONObject,JSONArray 都实现了JSON接口 if (json instanceof net.sf.json.JSONObject || json instanceof net.sf.json.JSONArray || json instanceof com.alibaba.fastjson.JSONObject || json instanceof com.alibaba.fastjson.JSONArray) { Map<String, String> map = new HashMap<>(1); ObjectMapper om = new ObjectMapper(); map.put("JSON", json.toString()); try { jsonStr = om.writeValueAsString(map.get("JSON")); } catch (JsonProcessingException e) { log.error(e.getMessage()); e.printStackTrace(); return ""; } log.debug("json-->字符串前: " + json.toString()); log.debug("json-->字符串后: " + jsonStr); } else { log.error("不是json格式数据"); } return jsonStr; }
方式二:通过谷歌的Gson实现
所需jar包:
<dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.8.6</version> </dependency>
导包:
import com.google.gson.Gson; import com.google.gson.GsonBuilder;
代码实现:
/* * json对象转格式化后的json字符串 * @attention: 入参格式不同,返回结果不同 * @date: 2020年11月12日 0012 15:32 * @param: json * 如果参数是json对象,返回的将是:格式化后的json字符串(小于号>会被转码成u003c,大于号>会被转码成u003e,且替换无效); * 如果参数是json字符串,返回的将是:带转义符且两边带双引号的json字符串; * 当参数是json字符串时,实现的效果与toJsonString()方法一样 * @return: java.lang.String */ public static String formatJson(Object json) { // 非空校验 if (null == json) return ""; GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.setPrettyPrinting(); Gson gson = gsonBuilder.create(); String jsonStr = gson.toJson(json); // 替换无效 // jsonStr = jsonStr.replaceAll("\u003c","<").replaceAll("\u003e", ">"); log.debug("json字符串格式化前: " + json.toString()); log.debug("json字符串格式化后: " + jsonStr); return jsonStr; }
4.测试
测试一:
上面的这两种方式,会在生成的json字符串两边加上双引号
测试二:
方式一:
public static void main(String[] args) { JSONObject jo = new JSONObject(); jo.put("name","Marydon"); jo.put("age",18); JSONObject params = new JSONObject(); params.put("Person", toJsonString(jo)); params.put("Time", "2020-11-12"); System.out.println(params.toString().replace("\\", "")); }
方式二:
public static void main(String[] args) { JSONObject jo = new JSONObject(); jo.put("name","Marydon"); jo.put("age",18); JSONObject params = new JSONObject(); params.put("Person", formatJson(jo.toString())); params.put("Time", "2020-11-12"); System.out.println(params.toString().replace("\\", "")); }
方式三:
<dependency> <groupId>commons-lang</groupId> <artifactId>commons-lang</artifactId> <version>2.3</version> </dependency>
方式四:Jackson核心包
如果是json对象嵌套json字符串,则上面4种方式都可以实现(但不一定能用,未测试)。
5.json对象嵌套json字符串
已知这种数据
需要转成这种数据
public static void main(String[] args) { JSONObject jo = new JSONObject(); jo.put("name","Marydon"); jo.put("age",18); // 需要转成json字符串,外层必须使用Map组装数据(不能用json) Map<String,String> params = new HashMap<>(); params.put("Person", jo.toString()); params.put("Time", "2020-11-12"); try { System.out.println(params); // 由Jackson将map转成json字符串,再转成json对象 JSONObject json = JSONObject.fromObject(new ObjectMapper().writeValueAsString(params)); System.out.println(json); } catch (JsonProcessingException e) { e.printStackTrace(); } }
2021-06-11
我发现了一个诡异的情况,那就是:
Map转Json,当Map的Value带有闭合标签时,转化成json后,会被强制添加转义符"",一起来看下:
Map<String, Object> map = new HashMap<>(2); map.put("name", "<Name>Marydon</name>"); map.put("website", "<Blog>https://www.cnblogs.com/Marydon20170307/</Blog>");
使用net.sf.json将map转json
System.out.println(JSONObject.fromObject(map));
被强制添加了转义符
解决办法:
使用com.alibaba.fastjson
System.out.println(JSONObject.toJSONString(map));