使用 Retrofit with Field 传递参数

Posted

技术标签:

【中文标题】使用 Retrofit with Field 传递参数【英文标题】:Pass parameters with Retrofit with Field 【发布时间】:2020-04-08 09:14:30 【问题描述】:

我正在学习一个改造课程,在该课程中我创建了一个带有 api 的小型后端,其中我有一个 POST 方法来执行教师的登录。在课程中,他所做的是创建一个教师,并使用 set 方法将电子邮件和密码传递给他,这是该方法在 API 中接收的内容。

我希望在调用 Retrofit 时直接传递此电子邮件和密码,我已通过以下方式完成此操作:

public class LoginActivity extends AppCompatActivity 

    private EditText etPasswordLogin, etEmailLogin;
    private Button btLogin;
    private TextView tvSignUp;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);

        setupView();
    

    private void setupView() 

        etPasswordLogin = findViewById(R.id.loginEditTextPassword);
        etEmailLogin = findViewById(R.id.loginEditTextEmail);
        btLogin = findViewById(R.id.buttonSignUp);
        tvSignUp = findViewById(R.id.textViewSignUp);

        btLogin.setOnClickListener(v -> userSignUp());
        tvSignUp.setOnClickListener(v -> startActivity(new Intent(getApplicationContext(), SignUpActivity.class)));
    

    private void userSignUp() 

        String email = etEmailLogin.getText().toString().trim();
        String password = etPasswordLogin.getText().toString().trim();

        if (email.isEmpty()) 

            etEmailLogin.setError(getResources().getString(R.string.email_error));
            etEmailLogin.requestFocus();
            return;
        

        if (!Patterns.EMAIL_ADDRESS.matcher(email).matches()) 

            etEmailLogin.setError(getResources().getString(R.string.email_doesnt_match));
            etEmailLogin.requestFocus();
            return;
        

        if (password.isEmpty()) 

            etPasswordLogin.setError(getResources().getString(R.string.password_error));
            etPasswordLogin.requestFocus();
            return;
        

        if (password.length() < 4) 

            etPasswordLogin.setError(getResources().getString(R.string.password_error_less_than));
            etPasswordLogin.requestFocus();
            return;
        

        login(email, password);
    

    private void login(String email, String password) 

        String BASE_URL = "http://10.0.2.2:8040";

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

        WebServiceApi api = retrofit.create(WebServiceApi.class);
        Call<List<Profesor>> call = api.login(email, password);

        call.enqueue(new Callback<List<Profesor>>() 
            @Override
            public void onResponse(Call<List<Profesor>> call, Response<List<Profesor>> response) 
                if (response.code() == 200) 
                    Log.d("TAG1", "Profesor logeado");
                 else if (response.code() == 404) 
                    Log.d("TAG1", "Profesor no existe");
                 else 
                    Log.d("TAG1", "Error desconocido");
                
            

            @Override
            public void onFailure(Call<List<Profesor>> call, Throwable t) 
                Log.d("TAG Error: ", Objects.requireNonNull(t.getMessage()));
            
        );

    

这将是我的模范老师:

public class Profesor 

    @SerializedName("id")
    private Long id;
    @SerializedName("nombre")
    private String nombre;
    @SerializedName("email")
    private String email;
    @SerializedName("password")
    private String password;
    @SerializedName("foto")
    private String photo;

    public Profesor()

    public Profesor(Long id, String nombre, String email, String photo) 
        this.id = id;
        this.nombre = nombre;
        this.email = email;
        this.photo = photo;
    

    public Profesor(String email, String password)
        this.email = email;
        this.password = password;
    

    public Long getId() 
        return id;
    

    public void setId(Long id) 
        this.id = id;
    

    public String getNombre() 
        return nombre;
    

    public void setNombre(String nombre) 
        this.nombre = nombre;
    

    public String getEmail() 
        return email;
    

    public void setEmail(String email) 
        this.email = email;
    

    public String getPassword() 
        return password;
    

    public void setPassword(String password) 
        this.password = password;
    

    public String getPhoto() 
        return photo;
    

    public void setPhoto(String photo) 
        this.photo = photo;
    

最后,我对 Retrofit 的调用如下:

@FormUrlEncoded
@POST("api/login")
Call<List<Profesor>> login(@Field("email") String email, @Field("password") String password);

但是,当我运行应用程序并通过表单传递电子邮件和密码时,在日志中我返回“Error desconocido”,但是在邮递员中给了我没有问题的答案:

知道我做错了什么吗?

【问题讨论】:

【参考方案1】:

您的邮递员请求不是格式编码的,而是原始的。 您需要发送 json 作为请求,而不是字段。因此,要解决此问题,您可以更改 API,处理表单 urlencoded 请求,或以这种方式更改 android 代码。

public class LoginCredentials 
    @SerializedName("email")
    private String email;
    @SerializedName("password")
    private String password;

    public LoginCredentials(String email, String password) 
        this.email = email;
        this.password = password;
    

然后改变这个

@FormUrlEncoded
@POST("api/login")
Call<List<Profesor>> login(@Field("email") String email, @Field("password") String password);

到这里

@POST("api/login")
Call<List<Profesor>> login(@Body LoginCredentials credentials);

希望这会有所帮助。

【讨论】:

所以我无法以这种方式传递请求的问题是我正在使用的 API 没有为它配置? 没错,你可以阅读这个问题了解更多详情***.com/questions/26723467/… 嗯,好吧,创建带有要发送的字段的新模型类或创建带有电子邮件和密码字段的教师生成器之间有什么区别?我不知道这样更有效还是一样。 其实还有其他区别。我删除了@FormUrlEncoded 注释,用 Body 替换了 Field 注释。在这种情况下,请求参数将不是“key”:“value”对,而是一个 json 对象。对于登录,我建议更改 API,接受 x-www-form-urlencoded 请求,而不是更改 Android 代码。 很遗憾,我是一名安卓开发者,无法在后端提供更多建议:) 感谢您接受答案。

以上是关于使用 Retrofit with Field 传递参数的主要内容,如果未能解决你的问题,请参考以下文章

我可以同时发布 Retrofit @Path 和 @Field 吗?

Retrofit实现PUT网络请求,并修改Content-Type

Retrofit Url 配置

post request with retrofit get response a s bad request in android

retrofit使用随记

使用 Retrofit 发送 POST 请求并接收 Json 响应无法使用响应数据我需要将其传递给另一个活动