najprostszy sposób na odczyt Json z adresu URL w Javie


245

To może być głupie pytanie, ale jaki jest najprostszy sposób na odczyt i analizę JSON z adresu URL w Javie ?

W Groovy jest to kwestia kilku linii kodu. Przykłady Java, które znalazłem, są absurdalnie długie (i mają ogromny blok obsługi wyjątków).

Chcę tylko przeczytać treść tego linku .


9
Obsługa wyjątków jest wymagana, ponieważ Java wymusza obsługę wszelkich zadeklarowanych wyjątków. Co jest nie tak z obsługą wyjątków?
Falmarri

3
Cóż, „java force you” jest największym problemem
Jonatan Cloutier

9
Jeśli java nie zmusiła cię do obsługi wyjątków, czy uważasz, że programy nadal działałyby i działałyby dobrze? Co się stanie, jeśli poproszę Cię o podanie mojego wieku do programu, a jako dane wejściowe podałem Snarfleblagger? Czy Java powinna pozwolić, aby program po prostu działał bez żadnych problemów? Jeśli nie chcesz obsługiwać wyjątków, zadeklaruj je jako rzucane przez metody, w których mogą wystąpić, i obserwuj, jak Twój program się nie udaje, gdy coś jest nie tak.
Richard Barker,

2
Wcale nie głupie pytanie. Zwłaszcza pochodzący z PHP, w którym możesz to zrobić json_decode(file_get_contents($url));i gotowe!
dtbarne

Odpowiedzi:


193

Używając artefaktu Maven org.json:jsonotrzymałem następujący kod, który moim zdaniem jest dość krótki. Nie tak krótki, jak to możliwe, ale nadal użyteczny.

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
zamiast czytać znak po znaku, możesz użyć readLine () na BufferedReader. Spowoduje to zmniejszenie liczby iteracji pętli while.
kdabir,

6
Po co? readLineFunkcja wykona pętlę czasu, a mam do łączenia linii zamiast znaków, który jest droższy. To nie oznaczałoby, że kod jest tak krótki, jak teraz. Co więcej, w notacji JSON nie ma pojęcia „linii”, więc dlaczego miałbym je czytać?
Roland Illig,

4
Rozważ IOUtils.toString(InputStream)metodę Apache commons-io . To powinno zaoszczędzić ci trochę linii i odpowiedzialności.
Mark Tielemans,

3
Dlaczego otrzymuję ten błąd „Konstruktor JSONObject (String) jest niezdefiniowany” w linii JSONObject json = new JSONObject (jsonText); w metodzie „readJsonFromUrl” ..? @RolandIllig
pop

2
W przypadku GSON, Jackson, Boon, Genson i innych musisz tylko podać źródło: albo URL, albo co najwyżej InputStream. Chociaż powyższy kod może być krótki org.json, należy sprawdzić inne dostępne biblioteki - nie trzeba pisać więcej niż 1-3 wierszy kodu dla tego zadania.
StaxMan

68

Oto kilka alternatywnych wersji z Jacksonem (ponieważ istnieje więcej niż jeden sposób, w jaki możesz chcieć danych jako):

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

A konkretnie zwykły przypadek (IMO), w którym chcesz zajmować się obiektami Java, może być utworzony z jednej linijki:

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

Inne biblioteki, takie jak Gson, obsługują również metody jednowierszowe; dlaczego wiele przykładów pokazuje, że dłuższe sekcje są dziwne. Co gorsza, wiele przykładów korzysta z przestarzałej biblioteki org.json; być może była to pierwsza rzecz, ale istnieje pół tuzina lepszych alternatyw, więc nie ma powodu, aby z niego korzystać.


Co to jest tutaj adres URL? Czy jest to ciąg znaków, obiekt URL lub bajt []?
Dinesh

1
Myślałam o java.net.URLale albo ktoś pracuje, a także mnóstwo innych źródeł ( File, InputStream, Reader, String).
StaxMan

4
To powinno być java.net.URL w powyższym przykładzie, w przeciwnym razie będzie próbować analizować ciąg „http: // ....” jako JSON, który przyniesie błąd
zbstof

@Zotov Tak. Przekazywanie Stringwymagałoby treści JSON, a nie tekstowego kodowania URI / URL do użycia.
StaxMan

2
Nierozpoznany token „https”: oczekiwał („prawda”, „fałsz” lub „zero”)
Damir Olejar

60

Najprostszy sposób: skorzystaj z gson, własnej biblioteki goto json firmy Google. https://code.google.com/p/google-gson/

Oto próbka. Idę na tę darmową stronę geolocatora, analizuję plik Json i wyświetlam mój kod pocztowy. (po prostu umieść to w głównej metodzie, aby to przetestować)

    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
Dlaczego pojawia się błąd „NetworkOnMainThreadException”? Muszę użyć AsyncTask lub istnieje inny sposób? Czy w tym przykładzie wystąpił również ten błąd?
Benetz

Literówka, powinna być:rootobj.get("zip_code").getAsString();
loopasam

Jak zaimportować jsonParser? Zawsze pojawia się błąd: „Błąd: (69, 9) błąd: nie można znaleźć klasy symboli JsonParser”
MAESTRO_DE,

1
Dodaj zależność maven <dependency> <groupId> com.google.code.gson </groupId> <artifactId> gson </artifactId> <version> 2.8.0 </version> </dependency>, aby uzyskać JsonParse w pom plik.
sashikanta

można uprościć i obsługiwać w sposób bezpieczny z Gson, na przykład: MyResponseObject response = new GsonBuilder (). create (). fromJson (new InputStreamReader ((InputStream) request.getContent ()), MyResponseObject.class);
Gregor,

42

Jeśli nie masz nic przeciwko użyciu kilku bibliotek, możesz to zrobić w jednym wierszu.

Uwzględnij biblioteki Apache Commons IOUtils i json.org .

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

Czy wiesz, dlaczego dodanie zależności do stopnia uniemożliwiłoby zainstalowanie tej aplikacji na moim Google Pixel XL?
andrdoiddev

@andrdoiddev - Powinieneś zadać to jako osobne pytanie. Jest bardziej ogólny dla Apache Commons, Gradle i Android Development.
ezwrighter

1
To jest już dość stare, ale nadal jest dobrym rozwiązaniem, więc na wypadek, gdyby @andrdoiddev lub ktokolwiek inny nadal potrzebował zależności Gradle, używam tych: kompilacja grupy: „org.json”, nazwa: „json ”, wersja:„ 20180813 ”grupa kompilacji:„ commons-io ”, nazwa:„ commons-io ”, wersja:„ 2.6 ”
r02

Załóżmy, że uruchamiasz wiele żądań, zapisujesz odpowiedzi JSON na tablicy JSONArray, a następnie zapisujesz JSONArray do pliku przy użyciu FileWriter, a następnie ta biblioteka NIE WYKRYWA podwójnych cudzysłowów. Dzięki temu plik można łatwo przeanalizować z powrotem do JSONArray.
Gh0sT

6

Użyj HttpClient, aby pobrać zawartość adresu URL. A następnie skorzystaj z biblioteki z json.org do parsowania JSON. Korzystałem z tych dwóch bibliotek w wielu projektach, które były niezawodne i łatwe w użyciu.

Poza tym możesz spróbować użyć biblioteki Java API Facebooka. Nie mam doświadczenia w tej dziedzinie, ale pojawia się pytanie o przepełnienie stosu związane z używaniem interfejsu API Facebooka w java . Możesz spojrzeć na RestFB jako dobry wybór dla biblioteki.


5

Zrobiłem parser json w najprostszy sposób, oto jest

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;

}
}

ta klasa zwraca obiekt json z adresu URL

a kiedy chcesz obiekt json, po prostu wywołujesz tę klasę i metodę w klasie Activity

mój kod jest tutaj

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

tutaj „klucz json” oznacza ten klucz w pliku json

jest to prosty przykład pliku json

{
    "json":"hi"
}

Tutaj „json” jest kluczem, a „cześć” jest wartością

Spowoduje to, że twoja wartość json zostanie dodana do ciągu.


1
Myślę, że to nie jest „najprostszy sposób”
samodzielny

3

To bardzo proste, używając klienta Jersey, po prostu uwzględnij tę zależność od maven:

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

Następnie wywołaj go za pomocą tego przykładu:

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

Następnie użyj Google Gson, aby przeanalizować JSON:

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

Nic wbrew odpowiedzi, ale tyle problemów z pakietem jersey-client ... to bałagan błędów.
Johnny Bigoode

nie spotkałem z tym żadnych problemów. czy możesz wskazać niektóre szczegóły i / lub alternatywy?
user3892260,

Znalezione przeze mnie problemy były związane z błędem znalezionym przez klasę, nie byłem do końca pewien przyczyny, ponieważ nie udało mi się go naprawić.
Johnny Bigoode

3

Jak dotąd uważam, że jest to najłatwiejszy sposób.

Użyj tej metody:

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

I użyj tego w ten sposób:

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


   }

Masz wyjątek ClassCastException. Zmień wiersz adresu URL u = nowy adres URL (url); do tego adresu URL u = nowy adres URL (null, url, new sun.net.www.protocol.https.Handler ()); aby ten kod zadziałał
słoneczna arya

2

Nie jestem pewien, czy jest to skuteczne, ale jest to jeden z możliwych sposobów:

Odczytaj json z adresu URL url.openStream()i wczytaj zawartość do łańcucha.

zbuduj obiekt JSON z tym ciągiem (więcej na json.org )

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

0

Chciałem tutaj dodać zaktualizowaną odpowiedź, ponieważ (nieco) ostatnie aktualizacje JDK ułatwiły nieco czytanie zawartości adresu URL HTTP. Jak powiedzieli inni, nadal będziesz musiał użyć biblioteki JSON do parsowania, ponieważ JDK obecnie jej nie zawiera. Oto kilka najczęściej używanych bibliotek JSON dla Java:

Aby pobrać JSON z adresu URL, wydaje się to najprostszym sposobem przy użyciu ściśle klas JDK (ale prawdopodobnie nie jest to coś, co chciałbyś zrobić dla dużych ładunków), Java 9 wprowadziła: 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());
}

Aby na przykład przeanalizować JSON przy użyciu biblioteki GSON

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

0

Oto pełna próbka sposobu analizowania zawartości Json. Przykład pobiera statystyki wersji Androida (znalezione tutaj w kodzie źródłowym Android Studio , który prowadzi tutaj) ).

Skopiuj pobrany plik stamtąd.json do res / raw, jako kopię zapasową.

build.gradle

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

oczywisty

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

Zamiast zależności można także użyć tego:

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

i awaryjne:

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

Wynik uruchomienia tego:

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%
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.