วิธีที่ง่ายที่สุดในการอ่าน json จาก URL ใน java


245

นี่อาจเป็นคำถามที่โง่ แต่วิธีที่ง่ายที่สุดในการอ่านและแยกJSONจากURLในJavaคืออะไร

ใน Groovy มันเป็นเรื่องของรหัสไม่กี่บรรทัด ตัวอย่าง Java ที่ฉันค้นหามีความยาวน่าขัน (และมีบล็อกการจัดการข้อยกเว้นขนาดใหญ่)

สิ่งที่ฉันต้องการทำคืออ่านเนื้อหาของลิงค์นี้


9
จำเป็นต้องมีการจัดการข้อยกเว้นเนื่องจาก java บังคับให้คุณจัดการกับข้อยกเว้นใด ๆ ที่ประกาศไว้ เกิดอะไรขึ้นกับการจัดการข้อยกเว้น?
Falmarri

3
ดี "จาวาบังคับคุณ" เป็นปัญหาที่ใหญ่ที่สุด
Jonatan Cloutier

9
หาก java ไม่ได้บังคับให้คุณจัดการกับข้อยกเว้นคุณคิดว่าโปรแกรมจะยังทำงานและรันได้ดีหรือไม่? ถ้าฉันถูกขอให้ป้อนอายุของฉันลงในโปรแกรมและฉันให้ snarfleblagger เป็นข้อมูลของฉัน java ควรอนุญาตให้โปรแกรมรันโดยไม่มีปัญหาหรือไม่? หากคุณไม่ต้องการจัดการข้อยกเว้นให้ประกาศว่าพวกเขาถูกโยนด้วยวิธีการที่พวกเขาอาจเกิดขึ้นและดูโปรแกรมของคุณล้มเหลวเมื่อมีบางอย่างไม่ถูกต้องสมบูรณ์
Richard Barker

2
ไม่ใช่คำถามที่โง่เลย โดยเฉพาะอย่างยิ่งมาจาก PHP ที่คุณสามารถทำได้json_decode(file_get_contents($url));และต้องทำ!
dtbarne

คำตอบ:


193

การใช้สิ่งประดิษฐ์ 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"));
  }
}

3
แทนที่จะอ่านตัวอักษรตามตัวอักษรคุณสามารถใช้ readLine () บน BufferedReader วิธีนี้จะลดจำนวนการวนซ้ำของ while loop
kdabir

6
เพื่ออะไร? readLineฟังก์ชั่นจะทำวงแล้วและฉันต้องเชื่อมสายแทนของตัวละครซึ่งมีราคาแพงมากขึ้น ที่จะไม่เก็บรหัสสั้น ๆ เหมือนตอนนี้ นอกจากนี้ในสัญกรณ์ JSON ไม่มีแนวคิดของ "บรรทัด" ดังนั้นทำไมฉันควรอ่านพวกเขาเช่น
Roland Illig

4
พิจารณาIOUtils.toString(InputStream)วิธีการของ Apache commons-io สิ่งนี้จะช่วยให้คุณประหยัดความรับผิดชอบ
Mark Tielemans

3
ทำไมฉันได้รับข้อผิดพลาดนี้ "ตัวสร้าง JSONObject (สตริง) ไม่ได้กำหนด" ในบรรทัดของ JSONObject json = ใหม่ JSONObject (jsonText); ในวิธี "readJsonFromUrl" .. ? @RolandIllig
Karthick pop

2
ด้วย GSON แจ็คสันบุญ Genson และคนอื่น ๆ ที่คุณจะต้องกินอาหารที่มา: ทั้งเพียง URL InputStreamหรือที่มากที่สุด แม้ว่ารหัสข้างต้นอาจสั้นสำหรับorg.jsonการใช้งานตรวจสอบให้แน่ใจเพื่อตรวจสอบ libs อื่น ๆ ที่มีอยู่ - ไม่จำเป็นต้องเขียนโค้ดมากกว่า 1-3 บรรทัดสำหรับงานนี้
StaxMan

68

ต่อไปนี้เป็นทางเลือกสองรุ่นที่มีแจ็คสัน (เนื่องจากมีหลายวิธีที่คุณอาจต้องการข้อมูล)

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

และโดยเฉพาะอย่างยิ่งกรณีปกติ (IMO) ที่คุณต้องการจัดการกับวัตถุ Java สามารถทำหนึ่งซับ:

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

libs อื่น ๆ เช่น Gson ยังสนับสนุนวิธีการหนึ่งบรรทัด; เหตุใดหลายตัวอย่างจึงแสดงส่วนที่ยาวกว่านั้นแปลก และยิ่งแย่ลงคือตัวอย่างจำนวนมากใช้ไลบรารี org.json ที่ล้าสมัย อาจเป็นสิ่งแรกที่อยู่รอบ ๆ แต่มีทางเลือกที่ดีกว่าครึ่งโหลดังนั้นจึงมีเหตุผลน้อยมากที่จะใช้มัน


URL ที่นี่คืออะไร มันเป็นวัตถุสตริงหรือ URL หรือไบต์ []?
Dinesh

1
ฉันคิดของjava.net.URLแต่อย่างใดอย่างหนึ่งในการทำงานเช่นเดียวกับความอุดมสมบูรณ์ของแหล่งข้อมูลอื่น ๆ ( File, InputStream, Reader, String)
StaxMan

4
มันควรเป็น java.net.URL ในตัวอย่างด้านบนมิฉะนั้นจะพยายามแยกสตริง 'http: // .... ' เป็น json ซึ่งจะทำให้เกิดข้อผิดพลาด
zbstof

@Zotov ใช่ การส่งผ่านStringจะต้องมีเนื้อหาเป็น JSON และไม่ใช่การเข้ารหัสแบบข้อความของ URI / URL ที่จะใช้
StaxMan

2
โทเค็นที่ไม่รู้จัก 'https': คาดหวังว่า ('จริง', 'เท็จ' หรือ 'โมฆะ')
Damir Olejar

60

วิธีที่ง่ายที่สุด: ใช้ gson ซึ่งเป็นไลบรารี goto json ของ Google https://code.google.com/p/google-gson/

นี่คือตัวอย่าง ฉันจะไปที่เว็บไซต์ geolocator ฟรีและแยก json และแสดงรหัสไปรษณีย์ของฉัน (เพียงใส่สิ่งนี้ในวิธีการหลักในการทดสอบ)

    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
ทำไมฉันถึงได้รับข้อผิดพลาด 'NetworkOnMainThreadException' ฉันต้องเป็นผู้ใช้ AsyncTask หรือมีวิธีอื่นไหม ในตัวอย่างนี้คุณได้รับข้อผิดพลาดนี้ด้วยหรือไม่
Benetz

พิมพ์ผิดควรเป็น:rootobj.get("zip_code").getAsString();
loopasam

ฉันจะนำเข้า jsonParser ได้อย่างไร ฉันได้รับข้อผิดพลาดเสมอ: 'ข้อผิดพลาด: (69, 9) ข้อผิดพลาด: ไม่พบคลาสสัญลักษณ์ JsonParser'
MAESTRO_DE

1
โปรดเพิ่มการพึ่งพา Maven <dependency> <groupId> com.google.code.gson </groupId> <artifactId> gson </artifactId> <version> 2.8.0 </version> </dependency> เพื่อรับ JsonParse ใน pom ของคุณ ไฟล์.
sashikanta

สามารถทำให้ง่ายขึ้นและจัดการในแบบ typesafe ด้วย Gson เช่น: MyResponseObject response = new GsonBuilder (). create (). fromJson (InputStreamReader ใหม่ (InputStream) Request.getContent ()), MyResponseObject.class
Gregor

42

หากคุณไม่รังเกียจการใช้ห้องสมุดคู่ก็สามารถทำได้ในบรรทัดเดียว

รวมApache Commons IOUtils & json.orgไลบรารี

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

คุณมีเดาว่าทำไมการเพิ่มการอ้างอิงไปยัง gradle จะป้องกันไม่ให้แอพนี้ติดตั้งบน Google Pixel XL ของฉัน?
andrdoiddev

@andrdoiddev - คุณควรถามเป็นคำถามแยกต่างหาก เป็นเรื่องทั่วไปสำหรับ Apache Commons, Gradle และ Android
ezwrighter

1
นี่ค่อนข้างเก่าแล้ว แต่ก็ยังเป็นทางออกที่ดีดังนั้นในกรณีที่ @andrdoiddev หรือใครก็ตามที่ยังต้องการการพึ่งพา Gradle สิ่งเหล่านี้คือสิ่งที่ฉันใช้: คอมไพล์กลุ่ม: 'org.json', ชื่อ: 'json ', รุ่น:' 20180813 'กลุ่มคอมไพล์:' commons-io ', ชื่อ:' commons-io ', เวอร์ชัน:' 2.6 '
r02

สมมติว่าคุณกำลังยิงคำขอหลายคำขอบันทึกการตอบสนอง json ไปยัง JSONArray แล้วเขียน JSONArray ไปยังไฟล์โดยใช้ FileWriter จากนั้นไลบรารีนี้จะไม่อัญประกาศคู่ สิ่งนี้ทำให้แยกไฟล์ได้อย่างง่ายดายกลับไปที่ JSONArray
Gh0sT

6

ใช้HttpClientเพื่อจับเนื้อหาของ URL จากนั้นใช้ไลบรารีจากjson.orgเพื่อวิเคราะห์ JSON ฉันใช้ไลบรารี่ทั้งสองนี้ในหลาย ๆ โปรเจกต์และมีประสิทธิภาพและใช้งานง่าย

นอกเหนือจากนั้นคุณสามารถลองใช้ห้องสมุด Java API API ผมไม่ได้มีประสบการณ์ใด ๆ ในพื้นที่นี้ แต่มีคำถามในกองล้นที่เกี่ยวข้องกับการใช้ API ของ Facebook ใน java คุณอาจต้องการดูRestFBเป็นทางเลือกที่ดีสำหรับห้องสมุดที่จะใช้


5

ฉันทำ json parser ด้วยวิธีที่ง่ายที่สุดแล้วนี่คือ

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;

}
}

คลาสนี้ส่งคืนอ็อบเจ็กต์ json จาก url

และเมื่อคุณต้องการวัตถุ json คุณเพียงเรียกคลาสนี้และเมธอดในคลาสกิจกรรมของคุณ

รหัสของฉันอยู่ที่นี่

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

นี่คือ "json key" จะแสดงว่าสำคัญในไฟล์ json ของคุณ

นี่เป็นตัวอย่างไฟล์ json อย่างง่าย

{
    "json":"hi"
}

นี่ "json" เป็นกุญแจสำคัญและ "hi" คือค่า

นี่จะทำให้ค่า json ของคุณเป็นเนื้อหาของสตริง


1
ฉันคิดว่ามันไม่ใช่ "วิธีที่ง่ายที่สุด"
ยืนอยู่คนเดียว

3

มันง่ายมากที่ใช้ 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 ของ Google เพื่อวิเคราะห์ JSON:

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

ไม่มีสิ่งใดเทียบกับคำตอบ แต่มีปัญหามากมายเกี่ยวกับแพ็คเกจไคลเอนต์ Jersey ... มันเป็นข้อผิดพลาด
Johnny Bigoode

ฉันไม่ได้พบปัญหาใด ๆ กับมัน คุณสามารถชี้เฉพาะเจาะจงและ / หรือทางเลือกได้ไหม?
user3892260

ปัญหาที่ฉันพบมีความเกี่ยวข้องกับข้อผิดพลาด classnotfound ไม่แน่ใจเกี่ยวกับสาเหตุเพราะฉันไม่ได้จัดการเพื่อแก้ไข
Johnny Bigoode

3

ฉันพบว่านี่เป็นวิธีที่ง่ายที่สุดในตอนนี้

ใช้วิธีนี้:

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 = URL ใหม่ (null, url, sun.net.www.protocol.https.Handler ใหม่) () เพื่อให้โค้ดนี้ทำงาน
sunny arya

2

ฉันไม่แน่ใจว่าสิ่งนี้มีประสิทธิภาพหรือไม่ แต่นี่เป็นวิธีหนึ่งที่เป็นไปได้:

อ่าน json จาก url use url.openStream()และอ่านเนื้อหาลงในสายอักขระ

สร้างวัตถุ JSON ด้วยสายนี้ (เพิ่มเติมที่json.org )

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

0

ฉันต้องการเพิ่มคำตอบที่อัปเดตที่นี่เนื่องจากการอัปเดตล่าสุดของ JDK ทำให้การอ่านเนื้อหาของ URL HTTP นั้นง่ายขึ้น เช่นเดียวกับที่คนอื่นพูดคุณจะยังคงต้องใช้ไลบรารี JSON เพื่อแยกวิเคราะห์เนื่องจาก JDK ไม่ได้มีอยู่ในขณะนี้ นี่เป็นตัวอย่างของไลบรารี JSON ที่ใช้บ่อยที่สุดสำหรับ Java:

ในการเรียก JSON จาก URL สิ่งนี้ดูเหมือนจะเป็นวิธีที่ง่ายที่สุดในการใช้คลาส JDK อย่างเคร่งครัด (แต่อาจไม่ใช่สิ่งที่คุณต้องการจะทำสำหรับเพย์โหลดขนาดใหญ่) แนะนำให้ใช้ Java 9: https://docs.oracle.com/en/ java / javase / 11 / เอกสาร / 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());
}

หากต้องการวิเคราะห์ JSON โดยใช้ไลบรารี GSON ตัวอย่างเช่น

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

0

นี่คือตัวอย่างเต็มรูปแบบของวิธีการแยกเนื้อหา Json ตัวอย่างใช้สถิติเวอร์ชั่น Android (พบได้จากซอร์สโค้ด Android Studio ที่นี่ซึ่งลิงก์ไปที่นี่ )

คัดลอกไฟล์ "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%
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.