在基於 Spring MVC 的項目中,直接將對象/集合序列化為 JSON 字符串再放入響應對象,常導致雙重序列化產生 \\ 轉義字符。本文提供「Map 封裝 + JSONArray 顯式轉換」標準模式,確保輸出純淨 JSON,並給出完整 Controller 實現代碼。
// 錯誤示範
String json = JSONObject.fromObject(userList).toString(); // 產生 "[{\"name\":\"A\"}]"
returnMsg.setMsg(json); // 再次序列化 → "{\"msg\":\"[{\\\"name\\\":\\\"A\\\"}]\"}"
雙層 toString() 導致反斜杠轉義,前端需 JSON.parse 兩次,極易出錯。
@RequestMapping("/dept/users")
public void deptUsers(HttpServletResponse response, @RequestParam Long deptId) throws IOException {
List<User> userList = accountManager.findDeptUser(deptId);
// 1. 配置 JsonConfig:排除循環引用、忽略字段
JsonConfig jsonConfig = new JsonConfig();
jsonConfig.setExcludes(new String[]{"role"});
jsonConfig.setIgnoreDefaultExcludes(true);
jsonConfig.setCycleDetectionStrategy(CycleDetectionStrategy.LENIENT);
// 2. 顯式轉為 JSONArray(非字符串)
JSONArray jsonArray = JSONArray.fromObject(userList, jsonConfig);
// 3. 構建響應 Map
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("success", true);
resultMap.put("msg", jsonArray); // 直接放 JSONArray 對象
resultMap.put("errmsg", "");
// 4. 統一輸出:再次用 JSONArray.fromObject(Map) 確保頂層也是標準 JSON
response.setHeader("Cache-Control", "no-cache");
response.setContentType("application/json; charset=UTF-8");
response.setCharacterEncoding("UTF-8");
try (PrintWriter out = response.getWriter()) {
out.print(JSONArray.fromObject(resultMap).toString());
out.flush();
}
}
setExcludes 過濾敏感/循環字段;LENIENT 策略遇到循環引用輸出 null 而非拋異常。JSONArray.fromObject(map) 序列化一次,保證輸出合法 JSON 對象 {...}。application/json + UTF-8,防止中文亂碼;no-cache 避免瀏覽器緩存舊數據。若專案已引入 Spring Boot / Jackson,強烈建議遷移:
@RestController
@RequestMapping("/api/dept")
public class DeptController {
@GetMapping("/{deptId}/users")
public Result<List<UserDTO>> deptUsers(@PathVariable Long deptId) {
List<User> users = accountManager.findDeptUser(deptId);
List<UserDTO> dtos = users.stream().map(this::convert).collect(toList());
return Result.success(dtos);
}
}
// 統一響應封裝
@Data
class Result<T> {
private boolean success;
private T data;
private String errmsg;
public static <T> Result<T> success(T data) {
Result<T> r = new Result<>(); r.setSuccess(true); r.setData(data); return r;
}
}
@JsonIgnore、@JsonView 精細控制字段輸出。舊項目維護期:用 Map + JSONArray 模式快速修復轉義問題;新項目/重構期:全面擁抱 Spring Boot + Jackson + @RestController,享受聲明式 JSON 開發體驗。核心原則:對象進、對象出,框架負責序列化,業務碼零觸碰 JSON 字符串。