Ответ 1
Вы можете переопределить этот обмен сообщениями, предоставив реализацию Spring DefaultBindingErrorProcessor
аналогичную тому, что сделано здесь: Пользовательское сообщение об ошибке связи с коллекциями фасоли весной MVC
Я работаю над веб-приложением Spring, и у меня есть объект, который имеет свойство Integer, которое пользователь может заполнить при создании нового объекта с использованием формы JSP. Метод контроллера, вызываемый этой формой, приведен ниже:
@RequestMapping(value = {"/newNursingUnit"}, method = RequestMethod.POST)
public String saveNursingUnit(@Valid NursingUnit nursingUnit, BindingResult result, ModelMap model)
{
boolean hasCustomErrors = validate(result, nursingUnit);
if ((hasCustomErrors) || (result.hasErrors()))
{
List<Facility> facilities = facilityService.findAll();
model.addAttribute("facilities", facilities);
setPermissions(model);
return "nursingUnitDataAccess";
}
nursingUnitService.save(nursingUnit);
session.setAttribute("successMessage", "Successfully added nursing unit \"" + nursingUnit.getName() + "\"!");
return "redirect:/nursingUnits/list";
}
Метод validate просто проверяет, существует ли имя в базе данных, поэтому я не включил его. Моя проблема в том, что, когда я намеренно вводил текст в поле, я хотел бы иметь приятное сообщение, такое как "Время автоматического разряда должно быть числом!". Вместо этого Spring возвращает эту абсолютно ужасную ошибку:
Failed to convert property value of type [java.lang.String] to required type [java.lang.Integer] for property autoDCTime; nested exception is java.lang.NumberFormatException: For input string: "sdf"
Я полностью понимаю, почему это происходит, но я не могу для жизни меня выяснить, как, программно, заменить сообщение об ошибке исключения по умолчанию в формате Spring по умолчанию с моим собственным. Я знаю источники сообщений, которые можно использовать для такого типа вещей, но я действительно хочу добиться этого непосредственно в коде.
РЕДАКТИРОВАТЬ
Как и было предложено, я построил этот метод в своем контроллере, но я все еще получаю сообщение "Не удалось преобразовать значение свойства...":
@ExceptionHandler({NumberFormatException.class})
private String numberError()
{
return "The auto-discharge time must be a number!";
}
OTHER EDIT
Вот код для моего класса сущности:
@Entity
@Table(name="tblNursingUnit")
public class NursingUnit implements Serializable
{
private Integer id;
private String name;
private Integer autoDCTime;
private Facility facility;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
public Integer getId()
{
return id;
}
public void setId(Integer id)
{
this.id = id;
}
@Size(min = 1, max = 15, message = "Name must be between 1 and 15 characters long")
@Column(nullable = false, unique = true, length = 15)
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
@NotNull(message = "The auto-discharge time is required!")
@Column(nullable = false)
public Integer getAutoDCTime()
{
return autoDCTime;
}
public void setAutoDCTime(Integer autoDCTime)
{
this.autoDCTime = autoDCTime;
}
@ManyToOne (fetch=FetchType.EAGER)
@NotNull(message = "The facility is required")
@JoinColumn(name = "id_facility", nullable = false)
public Facility getFacility()
{
return facility;
}
public void setFacility(Facility facility)
{
this.facility = facility;
}
@Override
public boolean equals(Object obj)
{
if (obj instanceof NursingUnit)
{
NursingUnit nursingUnit = (NursingUnit)obj;
if (Objects.equals(id, nursingUnit.getId()))
{
return true;
}
}
return false;
}
@Override
public int hashCode()
{
int hash = 3;
hash = 29 * hash + Objects.hashCode(this.id);
hash = 29 * hash + Objects.hashCode(this.name);
hash = 29 * hash + Objects.hashCode(this.autoDCTime);
hash = 29 * hash + Objects.hashCode(this.facility);
return hash;
}
@Override
public String toString()
{
return name + " (" + facility.getCode() + ")";
}
}
ДАЙТЕ ДРУГОЙ РЕДАКТИРОВАНИЕ
Я могу сделать эту работу, используя файл message.properties в pathpath, содержащий это:
typeMismatch.java.lang.Integer={0} must be a number!
И следующее объявление bean в файле конфигурации:
@Bean
public ResourceBundleMessageSource messageSource()
{
ResourceBundleMessageSource resource = new ResourceBundleMessageSource();
resource.setBasename("message");
return resource;
}
Это дает мне правильное сообщение об ошибке вместо Spring generic TypeMismatchException/NumberFormatException, с которым я могу жить, но все же, я хочу делать все программно, где это возможно, и я ищу альтернативу.
Спасибо за помощь!
Вы можете переопределить этот обмен сообщениями, предоставив реализацию Spring DefaultBindingErrorProcessor
аналогичную тому, что сделано здесь: Пользовательское сообщение об ошибке связи с коллекциями фасоли весной MVC
Вы можете аннотировать метод с помощью:
@ExceptionHandler({NumberFormatException.class})
public String handleError(){
//example
return "Uncorrectly formatted number!";
}
и реализовать все, что вы хотите сделать, в случае исключения этого типа. Данный код будет обрабатывать исключения, которые произошли в текущем контроллере. Для получения дополнительной информации обратитесь к этой ссылке.
Чтобы сделать глобальную обработку ошибок, вы можете использовать @ControllerAdvice
следующим образом:
@ControllerAdvice
public class ServiceExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler({NumberFormatException.class})
public String handleError(){
//example
return "Uncorrectly formatted number!";
}
}
@Martin, я спросил вас о версии, потому что @ControllerAdvice
доступен начиная с версии 3.2.
Я бы рекомендовал вам использовать @ControllerAdvice
, который представляет собой аннотацию, которая позволяет вам писать код, который разделяется между контроллерами (аннотируется с помощью @Controller
и @RestController
), но он также может применяться только к контроллерам в определенных пакетах или конкретных классах.
ControllerAdvice предназначен для использования с @ExceptionHandler
, @InitBinder
или @ModelAttribute
.
Вы устанавливаете целевые классы следующим образом: @ControllerAdvice(assignableTypes = {YourController.class,...})
.
@ControllerAdvice(assignableTypes = {YourController.class, YourOtherController.class})
public class YourExceptionHandler{
//Example with default message
@ExceptionHandler({NumberFormatException.class})
private String numberError(){
return "The auto-discharge time must be a number!";
}
//Example with exception handling
@ExceptionHandler({WhateverException.class})
private String whateverError(WhateverException exception){
//do stuff with the exception
return "Whatever exception message!";
}
@ExceptionHandler({ OtherException.class })
protected String otherException(RuntimeException e, WebRequest request) {
//do stuff with the exception and the webRequest
return "Other exception message!";
}
}
Что нужно иметь в виду, так это то, что если вы не установите цель и вы определите несколько обработчиков исключений для тех же исключений в разных классах @ControllerAdvice
, Spring применит первый обработчик, который он найдет. Если в одном классе @ControllerAdvice
присутствует несколько обработчиков исключений, будет @ControllerAdvice
ошибка.
Обработать NumberFormatException.
try {
boolean hasCustomErrors = validate(result, nursingUnit);
}catch (NumberFormatException nEx){
// do whatever you want
// for example : throw custom Exception with the custom message.
}