从 Java 中的 URL 读取 JSON 的最简单方法

Posted

技术标签:

【中文标题】从 Java 中的 URL 读取 JSON 的最简单方法【英文标题】:Simplest way to read JSON from a URL in Java 【发布时间】:2011-05-17 13:13:53 【问题描述】:

这可能是一个愚蠢的问题,但是在 Java 中从 URL 读取和解析 JSON 的最简单方法是什么?

在 Groovy 中,只需几行代码即可。我发现 Java 示例非常长(并且有巨大的异常处理块)。

我只想看this link的内容。

【问题讨论】:

异常处理是必需的,因为 java 强制你处理任何声明的异常。异常处理有什么问题? 好吧,“java强迫你”是最大的问题 如果 java 没有强制你处理异常,你认为程序还能运行良好吗?如果我被要求将我的年龄输入到程序中,而我将 snarfleblagger 作为我的输入,该怎么办? java是否应该允许程序毫无问题地执行?如果您不想处理异常,则将它们声明为由它们可能发生的方法抛出,并在某些事情不完全正确时观察您的程序失败。 根本不是一个愚蠢的问题。尤其是来自 php,您可以使用 json_decode(file_get_contents($url)); 完成此操作并完成! 【参考方案1】:

使用 Maven 工件 org.json:json 我得到了以下代码,我认为它很短。不是越短越好,但仍然可以使用。

package so4308554;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.nio.charset.Charset;

import org.json.JSONException;
import org.json.JSONObject;

public class JsonReader 

  private static String readAll(Reader rd) throws IOException 
    StringBuilder sb = new StringBuilder();
    int cp;
    while ((cp = rd.read()) != -1) 
      sb.append((char) cp);
    
    return sb.toString();
  

  public static JSONObject readJsonFromUrl(String url) throws IOException, JSONException 
    InputStream is = new URL(url).openStream();
    try 
      BufferedReader rd = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8")));
      String jsonText = readAll(rd);
      JSONObject json = new JSONObject(jsonText);
      return json;
     finally 
      is.close();
    
  

  public static void main(String[] args) throws IOException, JSONException 
    JSONObject json = readJsonFromUrl("https://graph.facebook.com/19292868552");
    System.out.println(json.toString());
    System.out.println(json.get("id"));
  

【讨论】:

您可以在 BufferedReader 上使用 readLine(),而不是逐个字符地读取。这将减少while循环的迭代次数。 有什么用? readLine 函数将执行循环,我必须连接行而不是字符,这更昂贵。这不会使代码像现在这样简短。此外,在 JSON 表示法中没有“行”的概念,那我为什么要这样读呢? 考虑 Apache commons-io 的 IOUtils.toString(InputStream) 方法。这应该可以为您节省一些线路和责任。 为什么我在 JSONObject json = new JSONObject(jsonText); 行中收到此错误“构造函数 JSONObject(String) 未定义”在“readJsonFromUrl”方法中..? @RolandIllig 对于 GSON、Jackson、Boon、Genson 等,您只需要提供源:要么只是 URL,要么最多 InputStream。虽然上面的代码对于org.json 的用法可能很短,但请确保验证其他可用的库——无需为此任务编写超过 1-3 行的代码。【参考方案2】:

这里有几个带有Jackson 的替代版本(因为您可能想要数据的方式不止一种):

  ObjectMapper mapper = new ObjectMapper(); // just need one
  // Got a Java class that data maps to nicely? If so:
  FacebookGraph graph = mapper.readValue(url, FaceBookGraph.class);
  // Or: if no class (and don't need one), just map to Map.class:
  Map<String,Object> map = mapper.readValue(url, Map.class);

特别是您想要处理 Java 对象的通常 (IMO) 情况,可以做成一个衬里:

FacebookGraph graph = new ObjectMapper().readValue(url, FaceBookGraph.class);

Gson 等其他库也支持单行方法;为什么许多示例显示更长的部分很奇怪。更糟糕的是,许多示例使用过时的 org.json 库;它可能是第一件事,但有六种更好的选择,所以几乎没有理由使用它。

【讨论】:

这里的网址是什么?它是字符串还是 URL 对象还是字节[]? 我在考虑java.net.URL,但其中任何一个都有效,还有很多其他来源(FileInputStreamReaderString)。 应该是上面例子中的java.net.URL,否则它会尝试将字符串'http://....'解析为一个json,这会产生错误 @Zotov 是的。传递 String 将要求内容是 JSON,而不是要使用的 URI/URL 的文本编码。 无法识别的令牌“https”:期待(“真”、“假”或“空”)【参考方案3】:

最简单的方法: 使用 gson,google 自己的 goto json 库。 https://code.google.com/p/google-gson/

这是一个示例。我要去这个免费的地理定位器网站并解析 json 并显示我的邮政编码。 (只需将这些东西放在 main 方法中进行测试)

    String sURL = "http://freegeoip.net/json/"; //just a string

    // Connect to the URL using java's native library
    URL url = new URL(sURL);
    URLConnection request = url.openConnection();
    request.connect();

    // Convert to a JSON object to print data
    JsonParser jp = new JsonParser(); //from gson
    JsonElement root = jp.parse(new InputStreamReader((InputStream) request.getContent())); //Convert the input stream to a json element
    JsonObject rootobj = root.getAsJsonObject(); //May be an array, may be an object. 
    String zipcode = rootobj.get("zip_code").getAsString(); //just grab the zipcode

【讨论】:

为什么我收到“NetworkOnMainThreadException”错误?我必须使用 AsyncTask 还是有其他方法?在这个例子中你也得到这个错误吗? 错字,应该是:rootobj.get("zip_code").getAsString(); 如何导入 jsonParser?我总是收到错误:'Error:(69, 9) error: cannot find symbol class JsonParser' 请添加maven依赖com.google.code.gsongson2.8.0 在你的 pom 文件中获取 JsonParse。 可以使用 Gson 以类型安全的方式进行简化和处理,例如:MyResponseObject response = new GsonBuilder().create().fromJson(new InputStreamReader((InputStream) request.getContent()), MyResponseObject.类);【参考方案4】:

如果您不介意使用几个库,可以在一行中完成。

包括 Apache Commons IOUtils 和 json.org 库。

JSONObject json = new JSONObject(IOUtils.toString(new URL("https://graph.facebook.com/me"), Charset.forName("UTF-8")));

Maven 依赖:

<dependency>
  <groupId>commons-io</groupId>
  <artifactId>commons-io</artifactId>
  <version>2.7</version>
</dependency>

【讨论】:

您有任何猜测,为什么将依赖项添加到 gradle 会阻止此应用安装在我的 Google Pixel XL 上? @andrdoiddev - 您应该将其作为一个单独的问题提出。它更适用于 Apache Commons、Gradle 和 android 开发。 这已经很老了,但仍然是一个很好的解决方案,所以以防万一@andrdoiddev 或其他任何人仍然需要 Gradle 依赖项,这些是我正在使用的:compile group: 'org .json',名称:'json',版本:'20180813' 编译组:'commons-io',名称:'commons-io',版本:'2.6' 假设您正在触发多个请求,将 json 响应保存到 JSONArray,然后使用 FileWriter 将 JSONArray 写入文件,那么这个库不会转义双引号。这使得文件很容易被解析回 JSONArray。 感谢@Irregardless,看起来 json.org 重新处理了他们的包。他们的站点上不再有默认的参考 java 实现。我将更新链接以使用他们主页json.org 上的 java 库列表中的第一个 java 项目,因为它应该可以工作并且兼容,因为它是一个参考实现。【参考方案5】:

我已经用最简单的方式完成了 json 解析器,这里是

package com.inzane.shoapp.activity;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONException;
import org.json.JSONObject;

import android.util.Log;

public class JSONParser 

static InputStream is = null;
static JSONObject jObj = null;
static String json = "";

// constructor
public JSONParser() 



public JSONObject getJSONFromUrl(String url) 

    // Making HTTP request
    try 
        // defaultHttpClient
        DefaultHttpClient httpClient = new DefaultHttpClient();
        HttpPost httpPost = new HttpPost(url);

        HttpResponse httpResponse = httpClient.execute(httpPost);
        HttpEntity httpEntity = httpResponse.getEntity();
        is = httpEntity.getContent();

     catch (UnsupportedEncodingException e) 
        e.printStackTrace();
     catch (ClientProtocolException e) 
        e.printStackTrace();
     catch (IOException e) 
        e.printStackTrace();
    

    try 
        BufferedReader reader = new BufferedReader(new InputStreamReader(
                is, "iso-8859-1"), 8);
        StringBuilder sb = new StringBuilder();
        String line = null;
        while ((line = reader.readLine()) != null) 
            sb.append(line + "\n");
            System.out.println(line);
        
        is.close();
        json = sb.toString();

     catch (Exception e) 
        Log.e("Buffer Error", "Error converting result " + e.toString());
    

    // try parse the string to a JSON object
    try 
        jObj = new JSONObject(json);
     catch (JSONException e) 
        Log.e("JSON Parser", "Error parsing data " + e.toString());
        System.out.println("error on parse data in jsonparser.java");
    

    // return JSON String
    return jObj;



这个类从url返回json对象

当你想要 json 对象时,你只需调用这个类和 Activity 类中的方法

我的代码在这里

String url = "your url";
JSONParser jsonParser = new JSONParser();
JSONObject object = jsonParser.getJSONFromUrl(url);
String content=object.getString("json key");

这里的“json key”表示你的json文件中的key

这是一个简单的 json 文件示例


    "json":"hi"

这里“json”是key,“hi”是value

这会将您的 json 值转换为字符串内容。

【讨论】:

我认为这不是“最简单的方法” 这有点复杂【参考方案6】:

使用HttpClient 获取URL 的内容。然后使用来自json.org 的库来解析 JSON。我在很多项目中都使用过这两个库,它们功能强大且易于使用。

除此之外,您还可以尝试使用 Facebook API Java 库。我在这方面没有任何经验,但是有一个与using a Facebook API in java 相关的堆栈溢出问题。您可能希望将 RestFB 作为库使用的不错选择。

【讨论】:

【参考方案7】:

我发现这是迄今为止最简单的方法。

使用这个方法:

public static String getJSON(String url) 
        HttpsURLConnection con = null;
        try 
            URL u = new URL(url);
            con = (HttpsURLConnection) u.openConnection();

            con.connect();


            BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream()));
            StringBuilder sb = new StringBuilder();
            String line;
            while ((line = br.readLine()) != null) 
                sb.append(line + "\n");
            
            br.close();
            return sb.toString();


         catch (MalformedURLException ex) 
            ex.printStackTrace();
         catch (IOException ex) 
            ex.printStackTrace();
         finally 
            if (con != null) 
                try 
                    con.disconnect();
                 catch (Exception ex) 
                    ex.printStackTrace();
                
            
        
        return null;
    

并像这样使用它:

String json = getJSON(url);
JSONObject obj;
   try 
         obj = new JSONObject(json);
         JSONArray results_arr = obj.getJSONArray("results");
         final int n = results_arr.length();
            for (int i = 0; i < n; ++i) 
                // get the place id of each object in JSON (Google Search API)
                String place_id = results_arr.getJSONObject(i).getString("place_id");
            


   

【讨论】:

那里有一个 ClassCastException 异常。更改行 URL u = new URL(url);到这个 URL u = new URL(null, url, new sun.net.www.protocol.https.Handler());让这段代码工作【参考方案8】:

很简单,使用 jersey-client,只需要包含这个 maven 依赖:

<dependency>
  <groupId>org.glassfish.jersey.core</groupId>
  <artifactId>jersey-client</artifactId>
  <version>2.25.1</version>
</dependency>

然后使用这个例子调用它:

String json = ClientBuilder.newClient().target("http://api.coindesk.com/v1/bpi/currentprice.json").request().accept(MediaType.APPLICATION_JSON).get(String.class);

然后使用谷歌的Gson解析JSON:

Gson gson = new Gson();
Type gm = new TypeToken<CoinDeskMessage>() .getType();
CoinDeskMessage cdm = gson.fromJson(json, gm);

【讨论】:

没有什么不符合答案的,但是 jersey-client 包有这么多问题......这是一堆错误。 我没有遇到任何问题。你能指出一些细节和/或替代方案吗? 我发现的问题与 classnotfound 错误有关,并不确定原因,因为我没有设法修复它。【参考方案9】:

我不确定这是否有效,但这是可能的方法之一:

使用url.openStream()从url读取json并将内容读入字符串。

用这个字符串构造一个 JSON 对象(更多信息在json.org)

JSONObject(java.lang.String source)
      Construct a JSONObject from a source JSON text string.

【讨论】:

【参考方案10】:

这里是如何解析 Json 内容的完整示例。该示例采用 Android 版本统计信息(来自 Android Studio 源代码here,链接到here)。

将从那里获得的“distributions.json”文件复制到 res/raw 中,作为备用。

build.gradle

    implementation 'com.google.code.gson:gson:2.8.6'

清单

  <uses-permission android:name="android.permission.INTERNET" />

MainActivity.kt

class MainActivity : AppCompatActivity() 
    override fun onCreate(savedInstanceState: Bundle?) 
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        if (savedInstanceState != null)
            return
        thread 
            // https://cs.android.com/android/platform/superproject/+/studio-master-dev:tools/adt/idea/android/src/com/android/tools/idea/stats/DistributionService.java
            var root: JsonArray
            Log.d("AppLog", "loading...")
            try 
                HttpURLConnection.setFollowRedirects(true)
                val statsUrl = "https://dl.google.com/android/studio/metadata/distributions.json" //just a string
                val url = URL(statsUrl)
                val request: HttpURLConnection = url.openConnection() as HttpURLConnection
                request.connectTimeout = 3000
                request.connect()
                InputStreamReader(request.content as InputStream).use 
                    root = JsonParser.parseReader(it).asJsonArray
                
             catch (e: Exception) 
                Log.d("AppLog", "error while loading from Internet, so using fallback")
                e.printStackTrace()
                InputStreamReader(resources.openRawResource(R.raw.distributions)).use 
                    root = JsonParser.parseReader(it).asJsonArray
                
            
            val decimalFormat = DecimalFormat("0.00")
            Log.d("AppLog", "result:")

            root.forEach 
                val androidVersionInfo = it.asJsonObject
                val versionNickName = androidVersionInfo.get("name").asString
                val versionName = androidVersionInfo.get("version").asString
                val versionApiLevel = androidVersionInfo.get("apiLevel").asInt
                val marketSharePercentage = androidVersionInfo.get("distributionPercentage").asFloat * 100f
                Log.d("AppLog", "\"$versionNickName\" - $versionName - API$versionApiLevel - $decimalFormat.format(marketSharePercentage)%")
            
        
    

作为依赖的替代方案,您也可以使用它来代替:

InputStreamReader(request.content as InputStream).use 
    val jsonArray = JSONArray(it.readText())

和后备:

InputStreamReader(resources.openRawResource(R.raw.distributions)).use 
    val jsonArray = JSONArray(it.readText())

运行结果:

loading...
result:
"Ice Cream Sandwich" - 4.0 - API15 - 0.20%
"Jelly Bean" - 4.1 - API16 - 0.60%
"Jelly Bean" - 4.2 - API17 - 0.80%
"Jelly Bean" - 4.3 - API18 - 0.30%
"KitKat" - 4.4 - API19 - 4.00%
"Lollipop" - 5.0 - API21 - 1.80%
"Lollipop" - 5.1 - API22 - 7.40%
"Marshmallow" - 6.0 - API23 - 11.20%
"Nougat" - 7.0 - API24 - 7.50%
"Nougat" - 7.1 - API25 - 5.40%
"Oreo" - 8.0 - API26 - 7.30%
"Oreo" - 8.1 - API27 - 14.00%
"Pie" - 9.0 - API28 - 31.30%
"Android 10" - 10.0 - API29 - 8.20%

【讨论】:

【参考方案11】:

我想在这里添加一个更新的答案,因为(在某种程度上)最近对 JDK 的更新使得阅读 HTTP URL 的内容变得更容易一些。 就像其他人所说的那样,您仍然需要使用 JSON 库来进行解析,因为 JDK 目前不包含一个。 以下是一些最常用的 Java JSON 库:

org.JSON FasterXML Jackson GSON

要从 URL 中检索 JSON,这似乎是使用严格的 JDK 类的最简单方法(但对于大型有效负载,您可能不想这样做),Java 9 引入:https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/io/InputStream.html#readAllBytes()

try(java.io.InputStream is = new java.net.URL("https://graph.facebook.com/me").openStream()) 
    String contents = new String(is.readAllBytes());

以使用 GSON 库解析 JSON 为例

com.google.gson.JsonElement element = com.google.gson.JsonParser.parseString(contents); //from 'com.google.code.gson:gson:2.8.6'

【讨论】:

以上是关于从 Java 中的 URL 读取 JSON 的最简单方法的主要内容,如果未能解决你的问题,请参考以下文章

Base封装--我的最简MVP架构

Flink学习笔记:Flink的最简安装

禅道的最简使用

Flink学习笔记:Flink的最简安装

在 .NET 中从 URL 读取到字符串的最简单方法

从API读取JSON数据