在需要調用第三方 HTTP 接口獲取 JSON 數據的場景中,Java 開發者常面臨:HTTP 請求封裝、流轉字符串、JSON 解析三大步驟。本文提供一套完整的工具類封裝(HttpUtil、InputStreamUtil、JsonUtil),基於 JDK 原生 HttpURLConnection 與官方 org.json 庫,並通過實際測試類演示調用笑話接口的全流程。最後對比 Gson,指出官方庫的復雜性痛點。
package com.dragon.java.jsonwebdata;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
public class HttpUtil {
public static InputStream getInputStreamByPost(String url, String parms) {
try {
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
conn.setReadTimeout(5000);
conn.setConnectTimeout(5000);
conn.setRequestMethod("POST");
conn.setDoOutput(true);
try (OutputStream os = conn.getOutputStream()) {
os.write(parms.getBytes("UTF-8"));
}
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
return conn.getInputStream();
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
改進點: 顯式指定 getBytes("UTF-8") 避免中文亂碼;使用 try-with-resources 關閉流。
package com.dragon.java.jsonwebdata;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class InputStreamUtil {
public static String inputStreamToString(InputStream is) {
StringBuilder sb = new StringBuilder();
try (BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8"))) {
String line;
while ((line = br.readLine()) != null) {
sb.append(line);
}
} catch (IOException e) {
e.printStackTrace();
}
return sb.toString();
}
}
注意: 原代碼 return line 只讀第一行,已修正為拼接完整響應體。
package com.dragon.java.jsonwebdata;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
public class JsonUtil {
public static void jsonParse(String json) {
List<Detail> details = new ArrayList<>();
try {
JSONObject root = new JSONObject(json);
if ("000000".equals(root.optString("status"))) {
// 假設 detail 為數組
JSONArray array = root.optJSONArray("detail");
if (array != null) {
for (int i = 0; i < array.length(); i++) {
JSONObject obj = array.getJSONObject(i);
Detail d = new Detail(
obj.getInt("id"),
obj.getInt("xhid"),
obj.getString("author"),
obj.getString("content"),
obj.getString("picUrl"),
obj.getString("status")
);
details.add(d);
}
}
details.forEach(System.out::println);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
// 數據實體類
class Detail {
int id, xhid;
String author, content, picUrl, status;
public Detail(int id, int xhid, String author, String content, String picUrl, String status) {
this.id = id; this.xhid = xhid; this.author = author; this.content = content; this.picUrl = picUrl; this.status = status;
}
@Override public String toString() {
return "Detail{id=" + id + ", author='" + author + "', content='" + content + "'}";
}
}
package com.dragon.java.jsonwebdata;
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("請輸入頁數: ");
int currentPage = scanner.nextInt();
System.out.print("請輸入每頁笑話數: ");
int size = scanner.nextInt();
String url = "https://api.1-blog.com/biz/bizserver/xiaohua/list.do";
String parms = "currentPage=" + currentPage + "&size=" + size;
String json = InputStreamUtil.inputStreamToString(
HttpUtil.getInputStreamByPost(url, parms)
);
JsonUtil.jsonParse(json);
}
}
| 維度 | org.json (官方) | Gson (Google) |
|---|---|---|
| 依賴體積 | 極小(單文件) | 約 200KB |
| 對象映射 | 手動 getInt/getString 構造對象 | gson.fromJson(json, Detail.class) 一行搞定 |
| 泛型支持 | 無 TypeToken 機制,List<T> 需手動循環 | 完美支持 new TypeToken<List<Detail>>(){}.getType() |
| 空值/異常處理 | 易拋 JSONException,需大量 try-catch | 優雅處理 null,可配置序列化策略 |
| 性能 | 一般 | 優秀(流式解析 + 緩存) |
OkHttp、Apache HttpClient 5 或 Spring RestTemplate/WebClient,支持連接池、重試、攔截器等企業級特性。ApiInvokeException),上層統一處理降級/告警。本文演示了從 HTTP 請求到 JSON 解析的完整鏈路代碼。雖然官方 org.json 庫零依賴、輕量,但其繁瑣的手動映射極大降低了開發效率。現代 Java 開發中,Gson/Jackson + OkHttp/HttpClient 是處理 REST API 的黃金組合,請根據項目約束合理選型。