简体   繁体   中英

How to Consume Spring-Boot REST API using Retrofit 2 in Android app

I had created REST API on Spring Boot for my Android application, when I try to hit the API it works well in Postman but not in my application kindly help me out by looking to my code I shall be very thankful to the community members.

SPRING UserController.java

@RestController
@RequestMapping(value = USER_URL)
public class UserController {
    private final UserService userService;
    //email service
    @Autowired
    private EmailServiceImpl emailServiceImpl;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    @PostMapping(value = LOGIN, consumes = MediaType.ALL_VALUE)
    public ResponseEntity<Object> authenticateUser(@RequestParam(EMAIL) String email,
                                                   @RequestParam(PASSWORD) String password) {

        if (userService.authenticateUser(email, password).size() > 0) {
            //generating auth token
            String token;
            try {
                token = MD5.getMD5Hex(email + DateTime.getCurrentTime(Constants.DATETIME.formatyyyyMMddHHmmss));
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
                return ResponseHandler.negativeResponse(
                        HttpStatus.INTERNAL_SERVER_ERROR,
                        HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase(),
                        "error generating auth token");
            }

            //adding authToken to users Entity
            userService.updateUserAuthToken(email, token);
            //sending response
            return ResponseHandler.positiveResponse(
                    HttpStatus.OK,
                    HttpStatus.OK.getReasonPhrase(),
                    SUCCESS,
                    userService.authenticateUser(email, password).iterator().next(),
                    USER);

        } else
            return ResponseHandler.negativeResponse(
                    HttpStatus.NOT_FOUND,
                    HttpStatus.NOT_FOUND.getReasonPhrase(),
                    EMAIL_PASS_NOT_MATCH);
    }

SPRING pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.spring-app</groupId>
    <artifactId>spring-app</artifactId>
    <version>0.2.5</version>
    <packaging>jar</packaging>

    <name>spring-app</name>

    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
            <version>2.3.0.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>groupid</groupId>
            <artifactId>artifiactId</artifactId>
            <version>1.0</version>
            <scope>system</scope>
            <systemPath>${java.home}/lib/rt.jar</systemPath>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.5.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <compilerArgs>
                        <arg>-XDignore.symbol.file</arg>
                        <arg>-parameters</arg>
                    </compilerArgs>
                    <fork>true</fork>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

ANDROID Model User.java

import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;

public class User {

    @SerializedName("id")
    @Expose
    private int id;
    @SerializedName("full_name")
    @Expose
    private String fullName;
    @SerializedName("email")
    @Expose
    private String email;
    @SerializedName("phone")
    @Expose
    private String phone;
    @SerializedName("role")
    @Expose
    private String role;
    @SerializedName("created_at")
    @Expose
    private String createdAt;
    @SerializedName("auth_token")
    @Expose
    private String authToken;
    @SerializedName("password")
    @Expose
    private String password;
    @SerializedName("image")
    @Expose
    private String image;

    public User(Integer id, String fullName, String email, String phone, String role, String createdAt, String authToken, String password, String image) {
        this.id = id;
        this.fullName = fullName;
        this.email = email;
        this.phone = phone;
        this.role = role;
        this.createdAt = createdAt;
        this.authToken = authToken;
        this.password = password;
        this.image = image;
    }

    public User(int id, String fullName, String email, String phone, String role, String createdAt, String authToken, String image) {
        this.id = id;
        this.fullName = fullName;
        this.email = email;
        this.phone = phone;
        this.role = role;
        this.createdAt = createdAt;
        this.authToken = authToken;
        this.image = image;
    }

    public User() {
    }

    public int getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getFullName() {
        return fullName;
    }

    public void setFullName(String fullName) {
        this.fullName = fullName;
    }

    public String getEmail() {
        return email;
    }

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

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public String getRole() {
        return role;
    }

    public void setRole(String role) {
        this.role = role;
    }

    public String getCreatedAt() {
        return createdAt;
    }

    public void setCreatedAt(String createdAt) {
        this.createdAt = createdAt;
    }

    public String getAuthToken() {
        return authToken;
    }

    public void setAuthToken(String authToken) {
        this.authToken = authToken;
    }

    public String getPassword() {
        return password;
    }

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

    public String getImage() {
        return image;
    }

    public void setImage(String image) {
        this.image = image;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", fullName='" + fullName + '\'' +
                ", email='" + email + '\'' +
                ", phone='" + phone + '\'' +
                ", role='" + role + '\'' +
                ", createdAt='" + createdAt + '\'' +
                ", authToken='" + authToken + '\'' +
                ", password='" + password + '\'' +
                ", image='" + image + '\'' +
                '}';
    }
}

ANDROID Model GenericResponse.java

import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;

public class GenericResponse  {
    @SerializedName("error")
    @Expose
    private String error;
    @SerializedName("message")
    @Expose
    private String message;
    @SerializedName("user")
    @Expose
    private User user;
    @SerializedName("timestamp")
    @Expose
    private String timestamp;
    @SerializedName("status")
    @Expose
    private int status;

    public String getError() {
        return error;
    }

    public void setError(String error) {
        this.error = error;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public String getTimestamp() {
        return timestamp;
    }

    public void setTimestamp(String timestamp) {
        this.timestamp = timestamp;
    }

    public int getStatus() {
        return status;
    }

    public void setStatus(Integer status) {
        this.status = status;
    }

}

ANDROID RestApiInterface.java

  public interface RestApiInterface {

        //login
        @Multipart
        @POST(USER_URL + LOGIN)
     Call<GenericResponse> signInRequest(@Part("email") RequestBody email,
                                        @Part("password") RequestBody password);
 }

ANDROID RestApiManager.java

public class RestApiManager {
    public static Retrofit retrofit = null;

    //
    public static Retrofit getClient() {
        if (retrofit == null) {
            retrofit = new Retrofit.Builder()

                    .baseUrl(BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
        }
        return retrofit;
    }

    private static OkHttpClient getClientt() {
        OkHttpClient client = new OkHttpClient.Builder()
                .connectTimeout(5, TimeUnit.MINUTES)
                .readTimeout(5, TimeUnit.MINUTES)
                .addInterceptor(new Interceptor() {
                    @Override
                    public Response intercept(Chain chain) throws IOException {
                        Request original = chain.request();
                        Request request = original.newBuilder()

                                .header(AUTH_KEY_ATTRIBUTE, AUTH_KEY_VALUE)
                                .method(original.method(), original.body())
                                .build();

                        return chain.proceed(request);
                    }
                })
                .build();
        return client;
    }
}

ANDROID Method SendSignInRequestToServer()

 /*Network Calls for sign in*/
    public void sendSignInRequestToServer(String email, String password) {

        RestApiInterface restService = RestApiManager.getClient().create(RestApiInterface.class);
        RequestBody email_ = RequestBody.create(MediaType.parse("text/plain"), email);
        RequestBody password_ = RequestBody.create(MediaType.parse("text/plain"), password);

        Call<GenericResponse> connection = restService.signInRequest(email_, password_);
        connection.enqueue(new Callback<GenericResponse>() {
            @Override
            public void onResponse(Call<GenericResponse> call, retrofit2.Response<GenericResponse> response) {
                progressDialog.dismiss();
                if (response.body() != null) {
                    if (response.body().getStatus() == 200) {
                        ((AuthenticationActivity) getActivity()).goToHomeActivity();
                    } else {
                        new CustomToast().Show_Toast(getActivity(), mainView, response.body().getMessage());
                        ll_signIn.startAnimation(shakeAnimation);
                    }
                }
            }

            @Override
            public void onFailure(Call<GenericResponse> call, Throwable t) {
                if (t instanceof IOException) {
                    Toast.makeText(getActivity(), "this is an actual network failure :( inform the user and possibly retry", Toast.LENGTH_SHORT).show();
                }
                else {
                    Toast.makeText(getActivity(), "conversion issue! big problems :(", Toast.LENGTH_SHORT).show();
                    // todo log to some central bug tracking service
                }
            }
        });
    }

POSTMAN response

{
    "error": "OK",
    "message": "success",
    "user": {
        "role": "admin",
        "image": "",
        "email": "sultan@gmail.com",
        "phone": "11223344",
        "created_at": "23:40:49",
        "full_name": "sultan",
        "auth_token": "c7cec6c452f645af1e3a7368aee1b364",
        "id": 4
    },
    "timestamp": "2020-06-04T03:28:59.710+0000",
    "status": 200
}

ERROR on application side It always hit onFailure I don't know what I'm doing wrong kindly help me out thanks

I had found that on android x you need to define network security configuration for this, you need to create an XML file in res->xml->network-security-config.xml here and mention this in your manifest

 android:networkSecurityConfig="@xml/network-security-config"

network-security-config.xml

    <?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config cleartextTrafficPermitted="true">
    <domain includeSubdomains="true">EXAMPLE.COM/API etc</domain>
    </domain-config>
</network-security-config>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM