Java'daki bir URL'den json'u okumanın en kolay yolu


245

Bu aptalca bir soru olabilir ama okumak ve ayrıştırmak için en basit yolu nedir JSON dan URL'ye içinde Java ?

Groovy'de bu birkaç satır kod meselesidir. Bulduğum Java örnekleri gülünç derecede uzun (ve büyük istisna işleme bloğu var).

Tek yapmak istediğim bu bağlantının içeriğini okumak .


9
Java sizi bildirilen istisnaları işlemeye zorladığı için kural dışı durum işleme gerekir. İstisna yönetimi ile ilgili sorun nedir?
Kasım'da Falmarri

3
Peki, "java force you" en büyük problem
Jonatan Cloutier

9
Java sizi istisnaları işlemeye zorlamıyorsa, programların hala iyi çalışıp çalışmayacağını düşünüyor musunuz? Yaşımı bir programa girmem istendi ve girdim olarak snarfleblagger verirsem ne olur? Java, programın herhangi bir sorun olmadan yürütülmesine izin vermeli mi? İstisnaları ele almak istemiyorsanız, bunların meydana gelebilecek yöntemlerle atıldığını beyan edin ve bir şey mükemmel değilse programınızın başarısız olduğunu izleyin.
Richard Barker

2
Hiç de aptalca bir soru değil. Özellikle PHP ile geliyor ve bunu yapabilir json_decode(file_get_contents($url));ve yapılabilir!
dtbarne

Yanıtlar:


193

Maven eserini kullanarak org.json:jsonoldukça kısa olduğunu düşündüğüm aşağıdaki kodu aldım. Mümkün olduğunca kısa değil, ama yine de kullanılabilir.

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
karakter karakter okumak yerine BufferedReader üzerinde readLine () kullanabilirsiniz. Bu, while döngüsünün yineleme sayısını azaltacaktır.
kdabir

6
Ne için? readLineFonksiyon sonra döngü yapacak ve ben daha pahalı olan Karakterler yerine hatları bağlamak gerekir. Bu, kodu şu anda olduğu kadar kısa tutmaz. Dahası, JSON notasyonunda "satır" kavramı yoktur, o zaman neden bu şekilde okumalıyım?
Roland Illig

4
Apache commons-io'nun IOUtils.toString(InputStream)yöntemini düşünün . Bu size bazı çizgiler ve sorumluluk kazandırmalıdır.
Mark Tielemans

3
Neden bu hatayı JSONObject satırında "yapıcı JSONObject (String) tanımsız" alıyorum json = new JSONObject (jsonText); "readJsonFromUrl" yönteminde ..? @RolandIllig
Karthick pop

2
GSON, Jackson, Boon, Genson ve diğerleriyle, kaynağı beslemeniz yeterlidir: sadece URL veya en fazla InputStream. Yukarıdaki kod org.jsonkullanım için kısa olsa da , kullanılabilir diğer kütüphaneleri doğruladığınızdan emin olun - bu görev için 1-3 satırdan fazla kod yazmanıza gerek yoktur.
StaxMan

68

İşte Jackson ile birkaç alternatif versiyon (veri olarak isteyebileceğiniz birden fazla yol olduğu için):

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

Ve özellikle Java nesneleri ile uğraşmak istediğiniz her zamanki (IMO) durum, bir astar yapılabilir:

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

Gson gibi diğer kütüphaneler de tek hat yöntemlerini destekler; neden birçok örnek çok daha uzun bölümleri tuhaf gösteriyor. Ve daha da kötüsü, birçok örnek eski org.json kütüphanesini kullanıyor; ilk şey olmuş olabilir, ama yarım düzine daha iyi alternatif var, bu yüzden kullanmak için çok az neden var.


Burada url nedir? Bir dize mi yoksa URL nesnesi mi yoksa byte [] mı?
Dinesh

1
Ben düşünüyordum java.net.URLbiri eser, hem de diğer kaynaklardan bol ama ya ( File, InputStream, Reader, String).
StaxMan

4
Bu gerektiğini aksi takdirde ayrıştırma dizeye çalışacağız, yukarıdaki örnekte java.net.URL olmak 'http: // ....' hata verirler bir json olarak
zbstof

@Zotov Evet. Geçme String, içeriğin JSON olmasını gerektirir ve kullanılacak URI / URL'nin metinsel kodlamasını gerektirmez.
StaxMan

2
Tanınmayan jeton 'https': bekliyordum ('doğru', 'yanlış' veya 'boş')
Damir Olejar

60

En kolay yol: Google'ın kendi goto json kütüphanesi olan gson'u kullanın. https://code.google.com/p/google-gson/

İşte bir örnek. Bu ücretsiz geolocator web sitesine gidiyorum ve json ayrıştırma ve posta kodumu görüntüleme. (test etmek için bu şeyleri ana bir yönteme koyun)

    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
Neden 'NetworkOnMainThreadException' hatası alıyorum? Bir AsyncTask kullanıcı gerekir veya başka bir yolu var mı? Bu örnekte de bu hatayı aldınız mı?
Benetz

rootobj.get("zip_code").getAsString();
Yazım hatası

JsonParser'ı nasıl alabilirim? Her zaman hatayı alıyorum: 'Hata: (69, 9) hatası: JsonParser sembol sınıfını bulamıyorum'
MAESTRO_DE

1
Pom'nıza JsonParse almak için lütfen maven bağımlılığı <dependency> <groupId> com.google.code.gson </groupId> <artifactId> gson </artifactId> <version> 2.8.0 </version> </dependency> ekleyin. dosya.
sashikanta

Gson ile aşağıdaki gibi basit bir şekilde basitleştirilebilir ve işlenebilir: MyResponseObject response = new GsonBuilder (). create (). fromJson (new InputStreamReader ((InputStream) request.getContent ()), MyResponseObject.class);
Gregor

42

Eğer birkaç kütüphane kullanmak sakıncası yoksa tek bir satırda yapılabilir.

Apache Commons IOUtils & json.org kitaplıklarını ekleyin .

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

Dereceye bağımlılık eklemenin neden bu uygulamanın Google Pixel XL'ime yüklenmesini engelleyeceğine dair bir tahmininiz var mı?
andrdoiddev

@andrdoiddev - Bunu ayrı bir soru olarak sormalısınız. Apache Commons, Gradle ve Android Development için daha geneldir.
ezwrighter

1
Bu şimdi oldukça eski, ama yine de iyi bir çözüm, bu yüzden @andrdoiddev veya başkalarının hala Gradle bağımlılıklarına ihtiyacı varsa, bunlar kullanıyorum: compile group: 'org.json', name: 'json ', sürüm:' 20180813 'derleme grubu:' commons-io ', ad:' commons-io ', sürüm:' 2.6 '
r02

Birden fazla istek ateşlediğinizi, json yanıtlarını bir JSONArray'e kaydettiğinizi ve ardından JSONArray'ı FileWriter kullanarak bir dosyaya yazdığınızı varsayalım, bu kitaplık çift tırnak KAÇIRMAZ. Bu, dosyanın JSONArray'e kolayca ayrıştırılmasını sağlar.
Gh0sT

6

URL'nin içeriğini almak için HttpClient kullanın . Ve sonra JSON ayrıştırmak için json.org kütüphanesini kullanın . Bu iki kütüphaneyi birçok projede kullandım ve sağlam ve kullanımı basitti.

Bunun dışında bir Facebook API java kütüphanesi kullanmayı deneyebilirsiniz. Bu alanda herhangi bir deneyimim yok, ancak java'da bir Facebook API kullanımı ile ilgili yığın taşması hakkında bir soru var . RestFB'ye bir kütüphanenin kullanması için iyi bir seçim olarak bakmak isteyebilirsiniz .


5

Json ayrıştırıcısını en basit şekilde yaptım, işte burada

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;

}
}

bu sınıf json nesnesini url'den döndürür

json nesnesini istediğinizde bu sınıfı ve Activity sınıfınızdaki yöntemi çağırmanız yeterlidir.

kodum burada

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

burada "json anahtarı" json dosyanızdaki anahtarın

bu basit bir json dosyası örneğidir

{
    "json":"hi"
}

Burada "json" anahtar ve "hi" değer

Bu, json değerinizi dize içeriğine alır.


1
Ben "basit yolu" olmadığını düşünüyorum
tek başına

3

Forma-istemci kullanarak çok kolay, sadece bu maven bağımlılığını ekleyin:

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

Ardından bu örneği kullanarak çağırın:

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

Ardından JSON'u ayrıştırmak için Google'ın Gson'unu kullanın:

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

Cevaba karşı bir şey yok, ancak forma-istemci paketi ile ilgili birçok sorun ... bu bir hatalar karmaşası.
Johnny Bigoode

onunla herhangi bir sorunla karşılaşmadım. bazı özellikleri ve / veya alternatifleri gösterebilir misiniz?
user3892260

Bulduğum sorunlar classnotfound hatasıyla ilgili, nedenini tam olarak bilmiyordum, çünkü düzeltmeyi başaramadım.
Johnny Bigoode

3

Bunu şimdiye kadarki en kolay yol olarak buldum.

Bu yöntemi kullanın:

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

Ve şu şekilde kullanın:

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


   }

Orada bir ClassCastException istisnası var. Satır URL'sini değiştirin u = yeni URL (url); bu URL'ye u = yeni URL (null, url, yeni sun.net.www.protocol.https.Handler ()); kod çalışması için
güneşli arya

2

Bunun etkili olup olmadığından emin değilim, ancak bu olası yollardan biri:

Url kullanımından json'u okuyun url.openStream()ve içeriği bir dizeye okuyun.

bu dizeyle bir JSON nesnesi oluşturun (daha fazlası json.org'da )

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

0

JDK'ya yapılan son güncellemeler (biraz) bir HTTP URL'sinin içeriğini okumayı biraz daha kolaylaştırdığı için burada güncellenmiş bir cevap eklemek istedim. Diğerlerinin söylediği gibi, JDK şu anda bir tane içermediğinden ayrıştırma yapmak için yine de bir JSON kütüphanesi kullanmanız gerekecektir. Java için en sık kullanılan JSON kitaplıklarından bazıları:

Bir URL'den JSON almak için, bu kesinlikle JDK sınıflarını kullanmanın en basit yolu gibi görünüyor (ancak büyük yükler için yapmak isteyeceğiniz bir şey değil), Java 9 tanıtıldı: https://docs.oracle.com/tr/ 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 kütüphanesini kullanarak JSON'i ayrıştırmak için, örneğin

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

0

Json içeriğinin nasıl ayrıştırılacağına dair tam bir örnek. Örnek (Android Studio kaynak kodundan bulunan Android sürümü, istatistik alır burada üzere, bağlantılar burada ).

Oradan aldığınız "distributionutions.json" dosyasını bir yedek olarak res / raw dosyasına kopyalayın.

build.gradle

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

belirgin

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

Bağımlılığa alternatif olarak, bunun yerine şunu da kullanabilirsiniz:

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

ve yedek:

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

Bunu çalıştırmanın sonucu:

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%
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.