API регистрации становится RESTful
1. обзор
В последних нескольких статьяхthe Registration series here on example мы создали большую часть необходимой нам функциональности в стиле MVC.
Теперь мы собираемся перевести некоторые из этих API-интерфейсов на более REST-подход.
2. ОперацияRegister
Начнем с основной операции Register:
@RequestMapping(value = "/user/registration", method = RequestMethod.POST)
@ResponseBody
public GenericResponse registerUserAccount(
@Valid UserDto accountDto, HttpServletRequest request) {
logger.debug("Registering user account with information: {}", accountDto);
User registered = createUserAccount(accountDto);
if (registered == null) {
throw new UserAlreadyExistException();
}
String appUrl = "http://" + request.getServerName() + ":" +
request.getServerPort() + request.getContextPath();
eventPublisher.publishEvent(
new OnRegistrationCompleteEvent(registered, request.getLocale(), appUrl));
return new GenericResponse("success");
}
Итак, как это отличается от оригинальной MVC-ориентированной реализации?
Вот оно:
-
запрос теперь правильно сопоставлен с HTTP POST
-
теперь мы возвращаем правильный DTO и маршалируем его с помощью аннотации@ResponseBody непосредственно в теле ответа
-
мы больше не занимаемся обработкой ошибок в методе
Мы также удаляем старыйshowRegistrationPage() - он не нужен просто для отображения страницы регистрации.
3. registration.html
С этими изменениями нам теперь нужно изменитьregistration.html на:
-
используйте Ajax для отправки регистрационной формы
-
получить результаты операции в формате JSON
Вот оно:
form
4. Обработка исключений
Наряду с более RESTful API логика обработки исключений также станет более зрелой.
Мы используем тот же механизм@ControllerAdvice для чистой обработки исключений, создаваемых приложением - и теперь нам нужен новый тип исключения.
ЭтоBindException, который выдается, когдаUserDto подтвержден (если он недействителен). Мы переопределим методResponseEntityExceptionHandler по умолчаниюhandleBindException(), чтобы добавить ошибки в тело ответа:
@Override
protected ResponseEntity
Нам также нужно будет обработать наш собственныйExceptionUserAlreadyExistException - который выдается, когда пользователь регистрируется с уже существующим адресом электронной почты:
@ExceptionHandler({ UserAlreadyExistException.class })
public ResponseEntity
5. GenericResponse
Нам также необходимо улучшить реализациюGenericResponse, чтобы удерживать эти ошибки проверки:
public class GenericResponse {
public GenericResponse(List fieldErrors, List globalErrors) {
super();
ObjectMapper mapper = new ObjectMapper();
try {
this.message = mapper.writeValueAsString(fieldErrors);
this.error = mapper.writeValueAsString(globalErrors);
} catch (JsonProcessingException e) {
this.message = "";
this.error = "";
}
}
}
6. UI - Поле и глобальные ошибки
Наконец, давайте посмотрим, как обрабатывать как полевые, так и глобальные ошибки с помощью jQuery:
var serverContext = [[function register(){
$(".alert").html("").hide();
var formData= $('form').serialize();
$.post(serverContext + "/user/registration",formData ,function(data){
if(data.message == "success"){
window.location.href = serverContext +"/successRegister.html";
}
})
.fail(function(data) {
if(data.responseJSON.error.indexOf("MailError") > -1)
{
window.location.href = serverContext + "/emailError.html";
}
else if(data.responseJSON.error.indexOf("InternalError") > -1){
window.location.href = serverContext +
"/login.html?message=" + data.responseJSON.message;
}
else if(data.responseJSON.error == "UserAlreadyExist"){
$("#emailError").show().html(data.responseJSON.message);
}
else{
var errors = $.parseJSON(data.responseJSON.message);
$.each( errors, function( index,item ){
$("#"+item.field+"Error").show().html(item.defaultMessage);
});
errors = $.parseJSON(data.responseJSON.error);
$.each( errors, function( index,item ){
$("#globalError").show().append(item.defaultMessage+"
");
});
}
}
Обратите внимание, что:
-
Если есть ошибки проверки - тогда объектmessage содержит ошибки поля, а объектerror содержит глобальные ошибки
-
Мы отображаем каждую ошибку поля рядом с ее полем
-
Мы отображаем все глобальные ошибки в одном месте в конце формы
7. Заключение
Цель этой быстрой статьи - привести API в более RESTful-направлении и показать простой способ работы с этим API в интерфейсе.
Сам интерфейс jQuery не является целью - просто потенциальный клиент, который может быть реализован в любом количестве JS-сред, в то время как API остается точно таким же.
full implementation этого руководства можно найти вthe github project - это проект на основе Eclipse, поэтому его должно быть легко импортировать и запускать как есть.