改造 2:从响应正文中获取 JSON

Posted

技术标签:

【中文标题】改造 2:从响应正文中获取 JSON【英文标题】:Retrofit 2: Get JSON from Response body 【发布时间】:2017-04-19 19:25:36 【问题描述】:

我想使用改造 2 从我的 api 获取字符串 json,使用改造 1 获取此 json 时我没有问题,但使用改造 2 为我返回 null

这就是我的 json 的样子

"id":1,"Username":"admin","Level":"Administrator"

这是我的 API

@FormUrlEncoded
@POST("/api/level")
Call<ResponseBody> checkLevel(@Field("id") int id);

这就是我的代码的样子

Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(Config.BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        Api api = retrofit.create(Api.class);
        Call<ResponseBody> call = api.checkLevel(1);
        call.enqueue(new Callback<ResponseBody>() 
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) 
                JsonObject post = new JsonObject().get(response.body().toString()).getAsJsonObject();
                    if (post.get("Level").getAsString().contains("Administrator")) 

                    
            

            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) 
            
        );

我是改造 2 的新手,使用上面的代码,它总是让我的应用程序崩溃,因为 response.body().toString() 返回 null。

请指导我如何获取该 json 字符串,以便我可以将其转换为 JsonObject。

【问题讨论】:

看看***.com/questions/21398598/… 您只能访问 response.body.string() 一次,之后它将返回 null。 response.body().toString() 我已经改成 try String result = response.body().string(); catch(异常 e) e.printStackTrace(); 为我工作! 【参考方案1】:

使用此 link 将您的 JSON 转换为 POJO,并使用下图中选择的选项

你会得到一个 POJO 类来作为你的响应

public class Result 

    @SerializedName("id")
    @Expose
    private Integer id;
    @SerializedName("Username")
    @Expose
    private String username;
    @SerializedName("Level")
    @Expose
    private String level;

    /**
    * 
    * @return
    * The id
    */
    public Integer getId() 
        return id;
    

    /**
    * 
    * @param id
    * The id
    */
    public void setId(Integer id) 
        this.id = id;
    

    /**
    * 
    * @return
    * The username
    */
    public String getUsername() 
        return username;
    

    /**
    * 
    * @param username
    * The Username
    */
    public void setUsername(String username) 
        this.username = username;
    

    /**
    * 
    * @return
    * The level
    */
    public String getLevel() 
        return level;
    

    /**
    * 
    * @param level
    * The Level
    */
    public void setLevel(String level) 
        this.level = level;
    


并使用如下界面:

@FormUrlEncoded
@POST("/api/level")
Call<Result> checkLevel(@Field("id") int id);

并像这样调用:

Call<Result> call = api.checkLevel(1);
call.enqueue(new Callback<Result>() 
    @Override
    public void onResponse(Call<Result> call, Response<Result> response)  
     if(response.isSuccessful())
        response.body(); // have your all data
        int id =response.body().getId();
        String userName = response.body().getUsername();
        String level = response.body().getLevel();
        else   Toast.makeText(context,response.errorBody().string(),Toast.LENGTH_SHORT).show(); // this will tell you why your api doesnt work most of time

    

    @Override
    public void onFailure(Call<Result> call, Throwable t) 
     Toast.makeText(context,t.toString(),Toast.LENGTH_SHORT).show(); // ALL NETWORK ERROR HERE

    
);

并在 Gradle 中使用依赖项

compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'com.squareup.retrofit2:converter-gson:2.+'

注意:发生错误是因为您将 JSON 更改为 POJO(在改造中使用 addConverterFactory(GsonConverterFactory.create()))。如果您想要 JSON 格式的响应,请从 Retrofit 中删除 addConverterFactory(GsonConverterFactory.create())。如果没有,则使用上述解决方案

【讨论】:

我一直在寻找的最接近的解决方案,但新版本向我们提供 public void onResponse(retrofit.Response response, Retrofit retrofit) 但我的模型就像hastebin.com/cobezeyoyi.java 和 response.body() .没有给出我的 get 方法... 对于 OP 问题 POJO 是正确的。如果您有类似这样的不同问题,那么您必须创建 getter 和 setter 方法,这在您的 POJO 中不存在。 你将如何创建一个在其他 json 对象中包含 json 对象的 POJO 类? 因为上面的答案包括提供所有 POJO 对象的网站链接。你必须给那个网站 JSON 对象。正如您的评论,创建您的解决方案并不太复杂。在我的 LinkedIn 上与我分享,我会尽力解决您的问题。【参考方案2】:

如果您想获得 JSON 格式的完整响应,请尝试以下操作:

我尝试了一种新方法,无需创建任何模型类即可从服务器获取 JSON 格式的完整响应。 我没有使用任何模型类从服务器获取数据,因为我不知道我会得到什么响应,或者它可能会根据要求而改变。

这是 JSON 响应:

"contacts": [
    
        "id": "c200",
        "name": "sunil",
        "email": "email@gmail.com",
        "address": "xx-xx-xxxx,x - street, x - country",
        "gender" : "male",
        "phone": 
            "mobile": "+91 0000000000",
            "home": "00 000000",
            "office": "00 000000"
        
    ,
    
        "id": "c201",
        "name": "Johnny Depp",
        "email": "johnny_depp@gmail.com",
        "address": "xx-xx-xxxx,x - street, x - country",
        "gender" : "male",
        "phone": 
            "mobile": "+91 0000000000",
            "home": "00 000000",
            "office": "00 000000"
        
    ,
    .
    .
    .
]

    在您的 API 接口中更改参数

    public interface ApiInterface 
    @POST("/index.php/User/login")//your api link 
    @FormUrlEncoded
    Call<Object> getmovies(@Field("user_email_address") String title,
                    @Field("user_password") String body);
    
    

    在您调用它的主要活动中

    ApiInterface apiService =
            ApiClient.getClient().create(ApiInterface.class);
    
    Call call = apiService.getmovies("a@gmail.com","123456");
    call.enqueue(new Callback() 
        @Override
        public void onResponse(Call call, Response response) 
            Log.e("TAG", "response 33: "+new Gson().toJson(response.body()) );
        
    
        @Override
        public void onFailure(Call call, Throwable t) 
            Log.e("TAG", "onFailure: "+t.toString() );
            // Log error here since request failed
        
    );
    

    之后就可以正常使用JSON对象和JSON数组获取参数了

输出

【讨论】:

【参考方案3】:

用它来获取字符串

String res = response.body().string();

而不是

String res = response.body().toString();

在将 responsebody 转换为字符串之前始终检查 null

if(response.body() != null)
     //do your stuff   

【讨论】:

这不起作用...响应正文是一次性值,只能使用一次因此在调试时,检查员会在“幕后”进行调用,并且正文是总是空的。 response.body() 已经为您的改造调用构建了一个 POJO,它不一定有 string() 方法。【参考方案4】:

你可以这样使用它。

 public void onResponse(Call<JsonObject> call, Response<JsonObject> response) 
            if (response.isSuccessful()) 
                try 
                    JSONObject jsonObject = new JSONObject(new Gson().toJson(response.body()));
                    msg = jsonObject.getString("msg");
                    status = jsonObject.getBoolean("status");

                    msg = jsonObject.getString("msg");
                    status = jsonObject.getBoolean("status");
                 catch (JSONException e) 
                    e.printStackTrace();
                

                Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
                Log.e("cvbnop",response.body().toString());
             else 
                Toast.makeText(MainActivity.this, "Some error occurred...", Toast.LENGTH_LONG).show();
            
        

【讨论】:

【参考方案5】:

我发现其他答案的组合有效:

interface ApiInterface 
    @GET("/someurl")
    Call<ResponseBody> getdata()


apiService.getdata().enqueue(object : Callback 
    override fun onResponse(call: Call, response: Response) 
        val rawJsonString = response.body()?.string()
    
)

重要的部分是响应类型应该是ResponseBody 并使用response.body()?.string() 来获取原始字符串。

https://***.com/a/33286112/860488

【讨论】:

【参考方案6】:

为改造2添加依赖项

compile 'com.google.code.gson:gson:2.6.2'
compile 'com.squareup.retrofit2:retrofit:2.0.2'
compile 'com.squareup.retrofit2:converter-gson:2.0.2'

为基础 url 创建类

public class ApiClient     

public static final String BASE_URL = "base_url";

private static Retrofit retrofit = null;

public static Retrofit getClient() 
    if (retrofit==null) 
        retrofit = new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
    
    return retrofit;



然后创建类模型以获取价值

public class ApprovalModel 

@SerializedName("key_parameter")
private String approvalName;
public String getApprovalName() 
    return approvalName;


创建接口类

public interface ApiInterface  
@GET("append_url")
Call<CompanyDetailsResponse> getCompanyDetails();

在主类之后

 if(Connectivity.isConnected(mContext))
            final ProgressDialog mProgressDialog = new ProgressDialog(mContext);
            mProgressDialog.setIndeterminate(true);
            mProgressDialog.setMessage("Loading...");
            mProgressDialog.show();

            ApiInterface apiService =
                    ApiClient.getClient().create(ApiInterface.class);

            Call<CompanyDetailsResponse> call = apiService.getCompanyDetails();
            call.enqueue(new Callback<CompanyDetailsResponse>() 
                @Override
                public void onResponse(Call<CompanyDetailsResponse>call, Response<CompanyDetailsResponse> response) 
                    mProgressDialog.dismiss();
                    if(response!=null && response.isSuccessful()) 
                        List<CompanyDetails> companyList = response.body().getCompanyDetailsList();

                        if (companyList != null&&companyList.size()>0) 
                            for (int i = 0; i < companyList.size(); i++) 
                                Log.d(TAG, "" + companyList.get(i));
                            
                         //get values
                        else
                            //show alert not get value
                        
                    else
                        //show error message

                    
                

                @Override
                public void onFailure(Call<CompanyDetailsResponse>call, Throwable t) 
                    // Log error here since request failed
                    Log.e(TAG, t.toString());
                    mProgressDialog.dismiss();
                
            );
        else
            //network error alert box

        

【讨论】:

【参考方案7】:

更好的方法是让 Retrofit 从 json 中为你生成 POJO(使用 gson)。首先是在创建Retrofit 实例时添加.addConverterFactory(GsonConverterFactory.create())。例如,如果您有一个与您的 json 对应的 User java 类(如下所示),那么您的改造 api 可以返回 Call&lt;User&gt;

class User 
    private String id;
    private String Username;
    private String Level;
    ...
    

【讨论】:

很抱歉不同意,但 Retrofit 不会从 json 生成 POJO,而只会生成基于先前声明的 POJO 的对象。 是的,这就是我的意思......“生成 POJO 实例”我同意会更清楚 请注意:您需要将 'com.squareup.retrofit2:converter-gson:' 添加到依赖项中才能使用此类转换器。【参考方案8】:
try                                                                            
    JSONObject jsonObject = new JSONObject(response.body().string());           
    System.out.println(jsonObject);                                             
 catch (JSONException | IOException e )                                       
    e.printStackTrace();                                                        

【讨论】:

【参考方案9】:

所以,这是交易:

制作时

Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(Config.BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build();

您在此处传递 GsonConverterFactory.create()。如果你这样做,Gson 会自动将你得到的 json 对象转换为你的对象&lt;ResponseBody&gt;。在这里你可以传递所有其他的转换器如Jackson等...

【讨论】:

【参考方案10】:

如果您不知道 API 的响应可能是什么。按照步骤将 responsebody 响应值转换为字节并以 String 格式打印您可以在控制台中打印出整个响应。

然后你就可以轻松地将字符串转换为 JSONObject。

      apiService.getFeeds(headerMap, map).enqueue(object : Callback, retrofit2.Callback<ResponseBody> 
            override fun onFailure(call: Call<ResponseBody>?, t: Throwable?) 
            

            override fun onResponse(call: Call<ResponseBody>?, response: Response<ResponseBody>?) 
                val bytes = (response!!.body()!!.bytes())
                Log.d("Retrofit Success : ", ""+ String(bytes))
            
        )

【讨论】:

【参考方案11】:

如果您需要 json 字符串响应,您可以使用下面给出的代码更改您的界面..

@FormUrlEncoded
@POST("/api/level")
Call<JsonObject> checkLevel(@Field("id") int id);  

并使用此功能进行改造

Call<JsonObject> call = api.checkLevel(1);
    call.enqueue(new Callback<JsonObject>() 
        @Override
        public void onResponse(Call<JsonObject> call, Response<JsonObject> response) 
            Log.d("res", response.body().toString());
        

        @Override
        public void onFailure(Call<JsonObject> call, Throwable t) 
            Log.d("error",t.getMessage());
        
    );

【讨论】:

【参考方案12】:

你可以像下面这样的用户...

    API接口

    public interface Api 
    
     @POST("app-api/user-login")
     Call<RegistrationResponseModel> doLogin( @Body RegistrationModel userModel);
    
    
    

    ApiService

    public class ApiService 
    
        Gson gson = new GsonBuilder()
                .setLenient()
                .create();
    
        public static final String BASE_URL = "your api url";
    
        Api api = new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.create(gson))           
                .build().create(Api.class);
    
    
    
        public Call<RegistrationResponseModel> doLogin(RegistrationModel model) 
            return api.doLogin(model);
        
    
    

    请求模型

    public class RegistrationModel 
        String fullName="";
        String eamil="";
        String phone="";
        String password="";
        int id = 0;
        //getter or setter
       
    

    响应模型

       public class RegistrationResponseModel 
            private String outMessage;
            private String outCode;
           //getter setter
         
    

    通话活动

        private void doLogin()
    
            ApiService apiService = new ApiService();
            RegistrationModel model = new RegistrationModel();
    
            model.setPhone("0192144444");
            model.setPassword("123");
            model.setId(3);
    
            Call<RegistrationResponseModel> call = apiService.doLogin(model);
            call.enqueue(new Callback<RegistrationResponseModel>() 
                @Override
                public void onResponse(Call<RegistrationResponseModel> call, Response<RegistrationResponseModel> response) 
    
                
    
                @Override
                public void onFailure(Call<RegistrationResponseModel> call, Throwable t) 
    
                
            );
        
    

    别忘了添加下面的库

    implementation 'com.squareup.retrofit2:retrofit:2.5.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
    implementation 'com.squareup.retrofit2:converter-scalars:2.3.0'
    

    添加工具:在应用程序下的清单文件中替换。清单文件看起来像..

        <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        package="your package">
    
        <uses-permission android:name="android.permission.INTERNET" />
    
        <application
            ......
            tools:replace="android:icon" >
    
        </application>
    
    </manifest>
    

好好享受吧……

【讨论】:

【参考方案13】:

您可以从原始对象获取 json 响应 正如你所做的那样,你从 api 获得 ResponseBody

Call<ResponseBody>

在内部回调中,您可以获得您的 json 响应

json = response.raw().toString();

【讨论】:

【参考方案14】:

使用这个

response.body().get(0).getUsername().toString();

【讨论】:

以上是关于改造 2:从响应正文中获取 JSON的主要内容,如果未能解决你的问题,请参考以下文章

改造 - 在将其解析为 json 之前从响应正文中删除一些无效字符

Java Selenium 获取 JSON 响应正文

如何从片段中的 JSON 响应中的对象获取数据

在进行改造 2 发布请求时,响应正文为空

如何从包含其他参数的响应中获取 JSON 对象列表

如何通过改造解析 JSON 响应