使用 Retrofit 我想从 JSON 响应中访问 userId(来自对象内部数组的值)

Using Retrofit i want to access the userId from the JSON Response (a value from an array inside object)

我是第一次使用Retrofit。所以请不要介意愚蠢。 我有 2 个问题:

问题 1. 如何从 API JSON 响应中获取键“userId”的值。 (当 isSuccessful 为真时)以下是来自 API.

的响应

我可以从下面乱七八糟的代码中得到userId,请教我一个更好的方法:

JSONObject jsonObject = new JSONObject(new Gson().toJson(response.body()));
                        JSONArray userInfoObject = jsonObject.getJSONArray("userInfo");
                        JSONObject userIDObject = userInfoObject.getJSONObject(0);
                        Long userId = userIDObject.getLong("userId");

问题二: onResponse 当 isSuccessful 为假时,response.body 显示为空。那么在这种情况下我如何访问 API JSON 响应。但是,在使用 Okhttp 日志记录时,我发现在这种情况下 okhttp 也会记录响应,但是 Retrofit 回调显示 response.body() 为空。

界面Class

public interface UserInfoClient {

@Headers("x-st-diagnostics-callerid: DKAPP-RETROFIT")
@POST("/api/User/")
Call<UserInfoModel> createUser(
        @Header("x-st-diagnostics-correlationid") String uniqueID,
        @Body UserInfoModel userInfo); 

}

DataModel

public class UserInfoModel {


private List userInfo;
private String statusMessage;
private Integer statusCode;
private Long userId;
private String userFullName, userPassword, userName, userEmail, userMobileNumber, userWebsite, userDateOfBirth, userProfileText, userProfileDisplayPhoto, userProfileCoverPhoto;

public UserInfoModel(Long userId, String userFullName, String userPassword, String userName, String userEmail, String userMobileNumber, String userWebsite, String userDateOfBirth, String userProfileText, String userProfileDisplayPhoto, String userProfileCoverPhoto) {
    this.userId = userId;
    this.userFullName = userFullName;
    this.userPassword = userPassword;
    this.userName = userName;
    this.userEmail = userEmail;
    this.userMobileNumber = userMobileNumber;
    this.userWebsite = userWebsite;
    this.userDateOfBirth = userDateOfBirth;
    this.userProfileText = userProfileText;
    this.userProfileDisplayPhoto = userProfileDisplayPhoto;
    this.userProfileCoverPhoto = userProfileCoverPhoto;
}

public Long getUserId() {
    return userId;
}

public List getUserInfo() {
    return userInfo;
}

public Integer getStatusCode() {
    return statusCode;
}

public String getStatusMessage() {
    return statusMessage;
}

}

Activity.java

public class ActivityUserInfo extends AppCompatActivity {

private static final String TAG = "ActivityUserInfo";
private EditText etUserId, etFullName, etPassword, etUsername, etEmail, etMobileNumber, etWebsite, etDob, etProfileTxt, etDispPhoto, etCoverPhoto;
private Button btnUpload;
public static Retrofit retrofit;



@Override
protected void onCreate(Bundle savedInstanceState) {
    Log.d(TAG, "onCreate: begins");
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_user_info);

    etUserId = findViewById(R.id.et_userID);
    etFullName = findViewById(R.id.et_fullName);
    etPassword = findViewById(R.id.et_password);
    etUsername = findViewById(R.id.et_username);
    etEmail = findViewById(R.id.et_email);
    etMobileNumber = findViewById(R.id.et_mobileNumber);
    etWebsite = findViewById(R.id.et_website);
    etDob = findViewById(R.id.et_dob);
    etProfileTxt = findViewById(R.id.et_profileBio);
    etDispPhoto = findViewById(R.id.et_profilePhoto);
    etCoverPhoto = findViewById(R.id.et_coverPhoto);
    btnUpload = findViewById(R.id.btn_uploadUserInfo);

    btnUpload.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            UserInfoModel userInfo = new UserInfoModel(
                    Long.parseLong(etUserId.getText().toString()),
                    etFullName.getText().toString(),
                    etPassword.getText().toString(),
                    etUsername.getText().toString(),
                    etEmail.getText().toString(),
                    etMobileNumber.getText().toString(),
                    etWebsite.getText().toString(),
                    etDob.getText().toString(),
                    etProfileTxt.getText().toString(),
                    etDispPhoto.getText().toString(),
                    etCoverPhoto.getText().toString()
            );

            sendNetworkRequest(userInfo);
        }
    });

}

private void sendNetworkRequest(UserInfoModel userInfo){
    Log.d(TAG, "sendNetworkRequest: begins");
    //Create okhttp client
    OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
    //Adding logging interceptor tot he okHttp client
    HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
    //set logging interceptor properties
    logging.setLevel(HttpLoggingInterceptor.Level.BODY);
    //To redact a header from logging
    logging.redactHeader("Content-Type");
    //Disable logging interceptor in mode other than DEBUG.
    if (BuildConfig.DEBUG) {
        //Adding logging interceptor to the okHttpClient using okHttp client builder (conditional for debug only)
        okHttpClientBuilder.addInterceptor(logging);
    }

    //Create Retrofit Instance
    Retrofit.Builder builder = new Retrofit.Builder()
            .baseUrl("http://abc.ett.io")
            .addConverterFactory(GsonConverterFactory.create())
            .client(okHttpClientBuilder.build());

    Retrofit retrofit = builder.build();

    // Get client and call object for the request
    UserInfoClient client  = retrofit.create(UserInfoClient.class);

    String  uniqueID = UUID.randomUUID().toString(); //UUID for the header
    Call<UserInfoModel> call = client.createUser(uniqueID, userInfo);

    call.enqueue(new Callback<UserInfoModel>() {
        @Override
        public void onResponse(Call<UserInfoModel> call, Response<UserInfoModel> response) {
            Log.d(TAG, "1. onResponse: body: " + response.body() + "\n message: " + response.message()
                    + "\n code: " + response.code() + "\n headers: " + response.headers() + " errorBody: " + response.errorBody()
                    + "\n isSuccessful: " + response.isSuccessful() + "\n response: " + response);
                if (response.isSuccessful()) {
                    Toast.makeText(ActivityUserInfo.this, "Upload Successful.", Toast.LENGTH_SHORT).show();
                    try {
                        JSONObject jsonObject = new JSONObject(new Gson().toJson(response.body()));
                        JSONArray userInfoObject = jsonObject.getJSONArray("userInfo");
                        JSONObject userIDObject = userInfoObject.getJSONObject(0);
                        Long userId = userIDObject.getLong("userId");
                        Log.d(TAG, "onResponse: 1.5: " + userId);
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }

                    Log.d(TAG, "2. onResponse: 200: Upload Successful."
                           + " statusCode: " + response.body().getStatusCode()
                           + " statusMessage: " + response.body().getStatusMessage()
                           + " user ID: " + response.body().getUserId()
                           + "\n userInfo: " + response.body().getUserInfo().get(0));
                }
                else{
                    if(response.body() != null){
                        APIError apiError = ErrorUtils.parseError(response);
                        Toast.makeText(ActivityUserInfo.this, "3. Save not successful", Toast.LENGTH_SHORT).show();
                        Log.d(TAG, "3. onResponse: Save not successful"
                                +" ErrorUtils httpStatusCode: " + apiError.getHttpStatusCode()
                                +" ErrorUtils customCode: " + apiError.getCustomCode()
                                +" ErrorUtils message: " + apiError.getMessage());
                    }
                    else{
                        Log.d(TAG, "4. onResponse: response.body() is null");

                    }
                }
        }

        @Override
        public void onFailure(Call<UserInfoModel> call, Throwable t) {
            Log.d(TAG, "4. onFailure: t: " + t + " message: " + t.getMessage() + " toString: " + t.toString()
                    + " getCause: " + t.getCause() + " getStackTrace: " + t.getStackTrace());
            Toast.makeText(ActivityUserInfo.this, "Please check you internet connection.", Toast.LENGTH_SHORT).show();
        }
    });
}

}

感谢您的帮助!

您需要将 UserInfoModel 模型 class 分成两部分:一个 class 代表“外部”对象(userInfostatusCode, statusMessage) 和一个 class 来表示数组中的项目。

public class UserInfoResponse {

    private List<UserInfoItem> userInfo;
    private int statusCode;
    private String statusMessage;

    // ...
}
public class UserInfoItem {

     private String userFullName;
     private String userPassword;
     private String userName;

     // ...
}

您现在将进行 Call<UserInfoResponse> 调用,并像这样访问列表中的项目:

UserInfoResponse response = // ...
String name = response.getUserInfo()[0].getUserName();

1st problem: How to get a value for the key "userId" from the API JSON response.

retrofit 可以自动将 JSON 对象转换为 POJO。所以你只需要让你的模型 classes.
对于 JSON 结果,您需要 2 个模型 classes.

根模型class

data class RootModel (
    var userInfo: mutableList<UserInfoChild> = ArrayList(),
    var statusCode: String = "",
    var statusMessage: String = ""
)  

UserInfoChild class

data class UserInfoChild (
    var userId: Int = 0,
    var userName: String? = "",
    var userPassword: String? = ""
    // add other fields
)  

接下来,将 Call<UserInfoModel> 更改为 Call<RootModel>

最后,在 onResponse 方法中,您可以轻松访问 userId 字段。

val userId = response.body().userInfo[0].userId

2nd problem: status code is 500

在 URL 中使用两个反斜杠可能就是答案。如果你分享你的基地URL,那么解决它会更容易

我的问题有两个问题:问题 1 已由 hassan 和 Ben 解决。 至于问题 2 如何在 isSuccessful 为假的情况下解码响应,我不得不使用 response.errorBody() 而不是 response.body() 因为后者在我的 isSuccessful = false 情况下始终为 null . 以下代码对此 post 有所帮助:

Gson gson = new Gson();
try {
    APIError errorResponse = gson.fromJson(response.errorBody().string(),APIError.class);

    Log.d(TAG, "onResponse: message: " + errorResponse.getMessage()
    + " httpStatusCode: " + errorResponse.getHttpStatusCode()
    + " customCode: " + errorResponse.getCustomCode()
    );
} catch (IOException e) {
    e.printStackTrace();
}

其中 APIError.java 是 class for return 模型以防出错,类似于 hassan 和 Ben 建议的根模型:

public class APIError {
private int httpStatusCode;
private String customCode, message = "Unknown error.";

public APIError() {
}

public int getHttpStatusCode() {
    return httpStatusCode;
}

public String getCustomCode() {
    return customCode;
}

public String getMessage() {
    return message;
}

}