Как правильно использовать и загружать данные JSON в Spring Boot по запросу Android Volley? - PullRequest
0 голосов
/ 24 января 2019

Я не уверен, как правильно отправлять и получать запросы как со стороны Android, так и со стороны сервера.

Допустим, например, во время регистрации я хочу проверить, существует ли пользователь, проверив его адрес электронной почты в БД.

Мое текущее понимание того, как это реализовать, будет следующим:

Код запроса Android:

    @Override
    public void onClick(View v) { //Assume this request is performed on a button click

    JSONObject registrationRequestDetails = new JSONObject(); //Creating a JSON object to be sent to the server
    try {
      registrationRequestDetails.put("email", emailBox.getText().toString());
    } catch (JSONException e) {
      Log.e("Couldn't create JSON: ", e.toString());
    }

    JsonObjectRequest loginRequest = new JsonObjectRequest(Request.Method.POST,
        URL,
        loginRequestDetails,
        new Response.Listener<JSONObject>() {
          @Override
          public void onResponse(JSONObject response) {
            try {
              if (response.get("result").equals("registered")) {
                //Assuming a JSON object is returned here, something akin to "result":"registered" if the email does exist - do something
              } else {
                //Email doesn't exist
              }
            } catch (JSONException e) {
              e.printStackTrace();
            }
          }
        }, new Response.ErrorListener() {
      @Override
      public void onErrorResponse(VolleyError error) {
        Log.e("Something: ", error.toString());
      }
    });
    loginRequestQueue.add(loginRequest);
  }
});

Код сервера Spring Boot:

UserController.java

@RequestMapping(value = "/register", method = RequestMethod.POST, consumes = "application/json", produces = "application/json") //Want to accept JSON & return JSON
//I return a Map below because I do not understand if this is the correct way to return JSON format - what is the correct way??
public Map<String, String> registerNewUser(@RequestBody final Map<String, String> details) {
    return registrationService.checkIfUserAlreadyExists(details);
}

RegistrationService.java

//Assume repo is injected that checks if email exists

public Map<String, String> checkIfUserAlreadyExists(Map<String, String> user) { //Should I be returning response status instead of JSON?
    Map<String, String> resultMap = new HashMap<>();
    if (usersRepository.existsByEmailAddress(user.get("email_address"))) {
        resultMap.put("result", "error");
        return resultMap;
    } else {
        //Save email if not registered
        resultMap.put("result", "registered");
        return resultMap;
    }
}

В настоящее время это работает.Но я не уверен, что это правильный путь.Может кто-нибудь объяснить, как правильно принимать и возвращать данные JSON?

Кроме того, например, во время процесса регистрации, что на самом деле должно быть возвращено при успешной (или нет) регистрации с сервера?

Ответы [ 3 ]

0 голосов
/ 24 января 2019

Забудьте о залпе, используйте Retrofit. Retrofit автоматически преобразует ответ json в объекты Java, используя Volley, для этого вам потребуется дополнительная работа. И я объясню часть rest-api тоже. Если вы построите свою структуру так, как я объясняю ниже, вы будете обрабатывать масштабирование и добавлять дополнительные конечные точки в свое приложение, как профи :)

---------------------------- ANDROID --------------- ----------------

Модифицированные

Добавить эти зависимости в android

implementation 'com.squareup.okhttp:okhttp:2.7.2'
implementation 'com.squareup.retrofit2:retrofit:2.4.0'
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'

Теперь нам нужен интерфейс, который будет имитировать наш rest-apis в клиенте Android

public interface APIUser { 

    @POST("/registr")
    Call<GenericResponse<User>> register(@Body User user);

}

Это для регистрации. Здесь у нас есть 2 класса, GenericResponse и User.

GenericResponse является универсальным типом класса, и мы используем его как для данных ответа, так и для ошибок (если они происходят). Это универсальный тип, потому что мы хотим использовать его для всех наших ответов, которые могут быть разных типов.

Пользователь просто java-класс содержит пользовательские поля.

CustomError содержит ответное сообщение и код.

GenericResponse

public class GenericResponse<T> {
    public CustomError error;
    public T data;
}

Пользователь

   public class User  {
    public String email; 
}

CustomError

public class CustomError implements Serializable {

    private Integer code;
    private String message;

}

Как использовать его для отправки запроса

Вы вводите этот регистрационный код там, где хотите, чтобы он был.

            User user = new User();
            user.setEmail(email);

            OkHttpClient client = getOkHttpClient(context);
            Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl("http://yourDomainOrIpAddress/endpoint")
                    .addConverterFactory(GsonConverterFactory.create())
                    .client(client)
                    .build();
            apiDicts = retrofit.create(APIDicts.class);


            apiDicts.register()
            .enqueue(new Callback<GenericResponse<User>>() {
                @Override
                public void onResponse(Call<GenericResponse<User>> call, retrofit2.Response<GenericResponse<User>> response) {
                    if(response.body().error==null){
                     // you can do someting with response.body().error.code and response.body().error.message. Or simple show them with toast
                    } else if(response.body().data!=null){
                       User user = response.body().data;
                       // you got your user object back after successfull registration
                    } else {
                      /// log something went really bad
                    } 
                }

                @Override
                public void onFailure(Call<GenericResponse<User>> call, Throwable t) {
                   //something is wrong with server/api
                }
            });
}

------------------------------------------- API -----------------------------------------

GenericResponse , CustomError и Пользователь - это тот же класс, который мы используем как в клиенте Android, так и в веб-сервисе.

PS. GenericResponse здесь не является универсальным. Простой класс.

public class GenericResponse {
    private CustomError error;
    private Object data;
}

Класс RestController

@PostMapping("/register") 
public GenericResponse registerNewUser(@RequestBody User user) {
    return registrationService.checkIfUserAlreadyExists(user);
}

В классе обслуживания

public GenericResponse  checkIfUserAlreadyExists(User user) { 
    GenericResponse genRes = new GenericResponse();
    if (usersRepository.existsByEmailAddress(user.getEmail())) {
        genRes.setError(new CustomError(1001, "User email already exists"))
        return genRes;
    } else {
         user = dao.registerUser(user);
         genRes.setUser(user);
        return genRes;
    }
}

Последние слова.

Несмотря на сообщение об ошибке, которое вы отправляете, используйте пользовательские коды ошибок, такие как 1001 для пользователя не найден, 1002 для уже зарегистрированного

0 голосов
/ 25 января 2019

Чтобы ответить на ваш вопрос, я постараюсь решить вашу проблему, используя свой личный опыт регистрации пользователей. Лучше всего использовать сериализатор, такой как Джексон (пример ниже) или GSON. Это позволит вам удобно создавать Java POJO из данных JSON и создавать JSON из Java POJO. Обратите внимание, что я использую метод Builder, это еще один удобный способ для вас построить свои модели для модульных тестов, интеграционных тестов или в целом, как показано ниже.

Также ознакомьтесь с техниками Spring Security, чтобы вы могли правильно закодировать пароль пользователя и т. Д. Следующим будет хороший ресурс.

https://www.baeldung.com/spring-security-registration

UserController.java

    @PostMapping(value="/register", produces = "application/json", consumes = "application/json")
    public ResponseEntity<?> signUp(@RequestBody @Validated User user, BindingResult bindingResult, UriComponentsBuilder uri) {
        if (bindingResult.hasErrors()) {
            return BadRequest.of(bindingResult).asResponseEntity();
        }

        if (userService.userAlreadyExists(user.getUsername())) {
            return BadRequest.ofAlreadyExists(USER_USERNAME, "User already exists. Please sign in with different username.").asResponseEntity();
        }

        user = User.builder()
                .from(user)
                .build();

        return userService.save(user, uri);
    }

User.java

@JsonDeserialize(builder = User.Builder.class)
@JsonSerialize
public class User {

    @Id
    private UUID id;

    @NotNull
    private String firstName;

    @NotNull
    private String lastName;

    @NotNull
    private String username;

    @NotNull
    private String password;

    @NotNull
    private Integer role;

    @NotNull
    @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
    private LocalDateTime createdDateTime;

    @NotNull
    @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
    private LocalDateTime lastModifiedDateTime;

    public User(Builder builder ) {
        this.id = builder.id;
        this.firstName = builder.firstName;
        this.lastName = builder.lastName;
        this.username = builder.username;
        this.password = builder.password;
        this.role = builder.role;
        this.createdDateTime = builder.createdDateTime;
        this.lastModifiedDateTime = builder.lastModifiedDateTime;
    }

    public static Builder builder() {
        return new Builder();
    }

    @JsonIgnoreProperties(ignoreUnknown = true)
    @JsonPOJOBuilder(withPrefix = "")
    public static final class Builder {
        private UUID id;
        private String firstName;
        private String lastName;
        private String username;
        private String password;
        private Integer role;
        private LocalDateTime createdDateTime;
        private LocalDateTime lastModifiedDateTime;

        public Builder from(User user) {
            return this.id(user.id)
                .firstName(user.firstName)
                .lastName(user.lastName)
                .username(user.username)
                .password(user.password)
                .role(user.role)
                .createdDateTime(user.createdDateTime)
                .lastModifiedDateTime(user.lastModifiedDateTime);
        }

        public Builder id(UUID id) {
            this.id = id;
            return this;
        }

        public Builder firstName(String firstName) {
            this.firstName = firstName;
            return this;
        }

        public Builder lastName(String lastName) {
            this.lastName = lastName;
            return this;
        }

        public Builder username(String username) {
            this.username = username;
            return this;
        }

        public Builder password(String password) {
            this.password = password;
            return this;
        }

        public Builder role(Integer role) {
            this.role = role;
            return this;
        }

        public Builder createdDateTime(LocalDateTime createdDateTime) {
            this.createdDateTime = createdDateTime;
            return this;
        }

        public Builder lastModifiedDateTime(LocalDateTime lastModifiedDateTime) {
            this.lastModifiedDateTime = lastModifiedDateTime;
            return this;
        }

        public Builder applyDefaults() {
            if (this.id == null) {
                this.id = UUID.randomUUID();
            }
            if (this.createdDateTime == null) {
                 createdDateTime = LocalDateTime.now();
            }
            if (this.lastModifiedDateTime == null) {
                lastModifiedDateTime = LocalDateTime.now();
            }
            return this;
        }

        public User build() {
            return new User(applyDefaults());
        }

        public UUID getId() {
            return id;
        }

        public String getFirstName() {
            return firstName;
        }

        public String getLastName() {
            return lastName;
        }

        public String getUsername() {
            return username;
        }

        public String getPassword() {
            return password;
        }

        public Integer getRole() {
            return role;
        }

        public LocalDateTime getCreatedDateTime() {
            return createdDateTime;
        }

        public LocalDateTime getLastModifiedDateTime() {
            return lastModifiedDateTime;
        }
    }

    public UUID getId() {
        return id;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public String getUsername() {
        return username;
    }

    public String getPassword() {
        return password;
    }

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

    public Integer getRole() {
        return role;
    }

    public LocalDateTime getCreatedDateTime() {
        return createdDateTime;
    }

    public LocalDateTime getLastModifiedDateTime() {
        return lastModifiedDateTime;
    }
}
0 голосов
/ 24 января 2019

В программировании нет правильного или неправильного решения.Однако, если вы хотите упростить свою работу с json, я рекомендую вам использовать API для сериализации json, например GSON.эта ссылка является руководством по интеграции и использованию Gson: https://medium.com/quick-code/parsing-json-on-android-using-gson-and-volley-83d6715776f8

эта ссылка является github для зависимости: https://github.com/google/gson

Также не стесняйтесь искать в другой библиотеке для сериализации.

ОБНОВЛЕНИЕ: хорошим ответом на стороне сервера для регистрации будет пользователь с его автоматически сгенерированным идентификатором или логическое значение.При первом решении - пользователь с автоматически сгенерированным идентификатором - нулевой ответ означает сбой, а завершенный пользователь - успех.Со второй скважиной это логическое значение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...