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-->字符串前:\n" + json.toString());
log.debug("json-->字符串后:\n" + 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字符串格式化前:\n" + json.toString());
log.debug("json字符串格式化后:\n" + 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));

