cách đơn giản nhất để đọc json từ một URL trong java


245

Đây có thể là một câu hỏi ngớ ngẩn nhưng cách đơn giản nhất để đọc và phân tích JSON từ URL là gì trong Java là gì?

Trong Groovy, đó là vấn đề của một vài dòng mã. Các ví dụ Java mà tôi tìm thấy dài vô lý (và có khối xử lý ngoại lệ lớn).

Tất cả những gì tôi muốn làm là đọc nội dung của liên kết này .


9
Việc xử lý ngoại lệ là bắt buộc vì java buộc bạn phải xử lý mọi ngoại lệ được khai báo. Có gì sai với xử lý ngoại lệ?
Falmarri

3
tốt, "java buộc bạn" là vấn đề lớn nhất
Jonatan Cloutier

9
Nếu java không buộc bạn xử lý ngoại lệ, bạn có nghĩ rằng các chương trình vẫn chạy và chạy tốt không? Điều gì sẽ xảy ra nếu tôi được yêu cầu nhập tuổi của mình vào một chương trình và tôi đã đưa snarfleblagger làm đầu vào của mình? Java có nên cho phép chương trình chỉ thực hiện mà không có vấn đề gì không? Nếu bạn không muốn xử lý các trường hợp ngoại lệ thì hãy tuyên bố chúng bị ném bởi các phương thức mà chúng có thể xảy ra và xem chương trình của bạn thất bại khi điều gì đó không hoàn toàn đúng.
Richard Barker

2
Không một câu hỏi ngớ ngẩn nào cả. Đặc biệt đến từ PHP nơi bạn có thể làm điều này với json_decode(file_get_contents($url));và được thực hiện!
dtbarne

Câu trả lời:


193

Sử dụng tạo phẩm Maven org.json:jsontôi nhận được mã sau đây, mà tôi nghĩ là khá ngắn. Không ngắn nhất có thể, nhưng vẫn có thể sử dụng.

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"));
  }
}

3
thay vì đọc từng ký tự, bạn có thể sử dụng readLine () trên BufferedReader. Điều này sẽ làm giảm số lần lặp của vòng lặp while.
kdabir

6
Để làm gì? Các readLinechức năng sẽ thực hiện vòng lặp sau đó, và tôi phải nối các đường thay vì các nhân vật, đó là đắt hơn. Điều đó sẽ không giữ mã ngắn như bây giờ. Hơn nữa, trong ký hiệu JSON không có khái niệm về "dòng", vậy tại sao tôi phải đọc chúng như vậy?
Roland Illig

4
Hãy xem xét IOUtils.toString(InputStream)phương pháp commons-io của Apache . Điều đó sẽ giúp bạn tiết kiệm một số dòng và trách nhiệm.
Đánh dấu Tielemans

3
Tại sao tôi gặp lỗi này "Hàm tạo JSONObject (Chuỗi) không xác định" trong dòng JSONObject json = new JSONObject (jsonText); trong phương thức "readJsonFromUrl" ..? @RolandIllig
Karthick pop

2
Với GSON, Jackson, Boon, Genson và những người khác, bạn chỉ cần cung cấp nguồn: chỉ là URL hoặc tối đa InputStream. Mặc dù mã ở trên có thể ngắn để org.jsonsử dụng, hãy đảm bảo xác minh các lib khác có sẵn - không cần phải viết nhiều hơn 1-3 dòng mã cho tác vụ này.
StaxMan

68

Dưới đây là một số phiên bản thay thế với Jackson (vì có nhiều hơn một cách bạn có thể muốn dữ liệu như):

  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);

Và cụ thể là trường hợp (IMO) thông thường mà bạn muốn xử lý các đối tượng Java, có thể được tạo thành một lớp lót:

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

Các lib khác như Gson cũng hỗ trợ các phương thức một dòng; tại sao nhiều ví dụ cho thấy các phần dài hơn là kỳ lạ. Và thậm chí tệ hơn là nhiều ví dụ sử dụng thư viện org.json lỗi thời; nó có thể là điều đầu tiên xung quanh, nhưng có một nửa tá lựa chọn thay thế tốt hơn nên có rất ít lý do để sử dụng nó.


Url ở đây là gì? Đây có phải là một chuỗi hoặc đối tượng URL hoặc byte [] không?
Dinesh

1
Tôi đã nghĩ đến java.net.URLnhưng một trong hai tác phẩm, cũng như rất nhiều các nguồn khác ( File, InputStream, Reader, String).
StaxMan

4
phải là java.net.URL trong ví dụ trên, nếu không, nó sẽ cố phân tích chuỗi 'http: // ....' dưới dạng json, điều này sẽ gây ra lỗi
zbstof

@Zotov Vâng. Việc vượt qua Stringsẽ yêu cầu nội dung phải là JSON và không được mã hóa văn bản của URI / URL để sử dụng.
Staxman

2
Mã thông báo không được nhận dạng 'https': đang mong đợi ('đúng', 'sai' hoặc 'null')
Damir Olejar

60

Cách dễ nhất: Sử dụng gson, thư viện goto json của google. https://code.google.com.vn/p/google-gson/

Đây là một mẫu. Tôi đang truy cập trang web định vị địa lý miễn phí này và phân tích cú pháp và hiển thị mã zip của tôi. (chỉ cần đặt công cụ này trong một phương thức chính để kiểm tra)

    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

1
Tại sao tôi gặp lỗi 'NetworkOnMainThreadException'? Tôi phải sử dụng AsyncTask hoặc có cách nào khác không? Trong ví dụ này bạn có nhận được lỗi này không?
Benetz

Typo, nên là:rootobj.get("zip_code").getAsString();
loopasam

Làm cách nào để nhập jsonParser? Tôi luôn gặp lỗi: 'Lỗi: (69, 9) lỗi: không thể tìm thấy lớp ký hiệu JsonParser'
MAESTRO_DE

1
Vui lòng thêm phụ thuộc maven <phụ thuộc> <groupId> com.google.code.gson </ groupId> <artifactId> gson </ artifactId> <version> 2.8.0 </ version> </ Depencies> để lấy JsonPude trong pom của bạn tập tin.
sashikanta

có thể được đơn giản hóa và xử lý theo cách an toàn với Gson như: MyResponseObject answer = new GsonBuilder (). created (). fromJson (new InputStreamReader ((InputStream) request.getContent ()), MyResponseObject. class);
Gregor

42

Nếu bạn không phiền khi sử dụng một vài thư viện, nó có thể được thực hiện trong một dòng duy nhất.

Bao gồm các thư viện Apache Commons IOUtils & json.org .

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

Bạn có đoán được tại sao việc thêm phụ thuộc vào lớp sẽ ngăn ứng dụng này cài đặt trên Google Pixel XL của tôi không?
andrdoiddev

@andrdoiddev - Bạn nên hỏi như một câu hỏi riêng biệt. Nó là khái quát hơn cho Apache Commons, Gradle và Android Development.
ezwrighter

1
Điều này khá cũ, nhưng vẫn là một giải pháp tốt, vì vậy trong trường hợp @andrdoiddev hoặc bất kỳ ai khác vẫn cần phụ thuộc Gradle, đây là những giải pháp tôi đang sử dụng: nhóm biên dịch: 'org.json', tên: 'json ', phiên bản:' 20180813 'nhóm biên dịch:' commons-io ', tên:' commons-io ', phiên bản:' 2.6 '
r02

Giả sử bạn đang thực hiện nhiều yêu cầu, lưu các phản hồi json vào một JSONArray và sau đó viết JSONArray vào một tệp bằng FileWriter, sau đó thư viện này KHÔNG ESCAPE trích dẫn kép. Điều này làm cho tệp dễ dàng được phân tích cú pháp trở lại JSONArray.
Gh0sT

6

Sử dụng HttpClient để lấy nội dung của URL. Và sau đó sử dụng thư viện từ json.org để phân tích JSON. Tôi đã sử dụng hai thư viện này trên nhiều dự án và chúng rất mạnh mẽ và đơn giản để sử dụng.

Ngoài ra, bạn có thể thử sử dụng thư viện java API của Facebook. Tôi không có bất kỳ kinh nghiệm nào trong lĩnh vực này, nhưng có một câu hỏi về tràn ngăn xếp liên quan đến việc sử dụng API Facebook trong java . Bạn có thể muốn xem RestFB là một lựa chọn tốt cho thư viện sử dụng.


5

Tôi đã thực hiện trình phân tích cú pháp json theo cách đơn giản nhất, đây là

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;

}
}

lớp này trả về đối tượng json từ url

và khi bạn muốn đối tượng json, bạn chỉ cần gọi lớp này và phương thức trong lớp Activity của bạn

mã của tôi ở đây

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

ở đây "khóa json" được biểu thị là khóa trong tệp json của bạn

đây là một ví dụ tập tin json đơn giản

{
    "json":"hi"
}

Ở đây "json" là chìa khóa và "hi" là giá trị

Điều này sẽ nhận được giá trị json của bạn cho chuỗi nội dung.


1
Tôi nghĩ đó không phải là "cách đơn giản nhất"
độc lập

3

Thật dễ dàng, sử dụng jersey-client, chỉ cần bao gồm phụ thuộc maven này:

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

Sau đó gọi nó bằng ví dụ này:

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

Sau đó, sử dụng Google Gson để phân tích JSON:

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

Không có gì chống lại câu trả lời, nhưng rất nhiều vấn đề với gói jersey-client ... đó là một mớ lỗi.
Johnny Bigoode

tôi chưa gặp phải vấn đề gì với nó bạn có thể chỉ ra một số chi tiết cụ thể và / hoặc lựa chọn thay thế?
dùng3892260

Các vấn đề tôi tìm thấy có liên quan đến lỗi classnotfound, không chắc chắn chính xác về nguyên nhân, vì tôi đã không quản lý để khắc phục nó.
Johnny Bigoode

3

Tôi đã tìm thấy điều này là cách dễ nhất cho đến nay.

Sử dụng phương pháp này:

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;
    }

Và sử dụng nó như thế này:

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");
            }


   }

Bạn đã có một ngoại lệ ClassCastException ngồi ở đó. Thay đổi URL dòng u = URL mới (url); đến URL này u = URL mới (null, url, sun.net.www.protatio.https.Handler ()); để mã này hoạt động
nắng arya

2

Tôi không chắc chắn nếu điều này là hiệu quả, nhưng đây là một trong những cách có thể:

Đọc json từ việc sử dụng url url.openStream()và đọc nội dung thành một chuỗi.

xây dựng một đối tượng JSON với chuỗi này (thêm tại json.org )

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

0

Tôi muốn thêm một câu trả lời được cập nhật ở đây vì (phần nào) các bản cập nhật gần đây cho JDK đã giúp việc đọc nội dung của URL HTTP dễ dàng hơn một chút. Giống như những người khác đã nói, bạn vẫn sẽ cần sử dụng thư viện JSON để thực hiện phân tích cú pháp, vì JDK hiện không chứa một thư viện. Dưới đây là một vài thư viện JSON được sử dụng phổ biến nhất cho Java:

Để lấy JSON từ một URL, đây dường như là cách đơn giản nhất bằng cách sử dụng các lớp JDK nghiêm ngặt (nhưng có lẽ không phải là thứ bạn muốn làm cho tải trọng lớn), Java 9 đã giới thiệu: 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());
}

Ví dụ, để phân tích JSON bằng thư viện GSON

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

0

Đây là một mẫu đầy đủ về cách phân tích nội dung Json. Ví dụ lấy số liệu thống kê phiên bản Android (được tìm thấy từ mã nguồn Android Studio tại đây , liên kết đến đây ).

Sao chép tệp "distribut.json" mà bạn nhận được từ đó vào res / raw, dưới dạng dự phòng.

xây dựng. nâng cấp

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

rõ ràng

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

ChínhActivity.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)}%")
            }
        }
    }
}

Thay thế cho phụ thuộc, bạn cũng có thể sử dụng thay thế này:

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

và dự phòng:

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

Kết quả của việc chạy này:

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%
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.