我正在开发一个Spring Web应用程序,我有一个具有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的默认数字格式异常错误消息。我知道可以用于此类事情的消息源,但我真的想直接在代码中实现这一点。
修改
正如所建议的,我在我的控制器中构建了这个方法,但我仍然得到Spring的“未能转换属性值...”消息:
@ExceptionHandler({NumberFormatException.class})
private String numberError()
{
return "The auto-discharge time must be a number!";
}
其他编辑
以下是我的实体类的代码:
@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文件来完成这项工作:
typeMismatch.java.lang.Integer={0} must be a number!
配置文件中的以下bean声明:
@Bean
public ResourceBundleMessageSource messageSource()
{
ResourceBundleMessageSource resource = new ResourceBundleMessageSource();
resource.setBasename("message");
return resource;
}
这给了我正确的错误消息,而不是我可以使用的Spring泛型TypeMismatchException / NumberFormatException但是,我仍然希望尽可能以编程方式执行所有操作,并且我正在寻找替代方案。
感谢您的帮助!
答案 0 :(得分:3)
您可以通过提供类似于此处所做的Spring DefaultBindingErrorProcessor
的实现来覆盖该消息传递:
Custom Binding Error Message with Collections of Beans in Spring MVC
答案 1 :(得分:2)
您可以使用以下方法注释方法:
@ExceptionHandler({NumberFormatException.class})
public String handleError(){
//example
return "Uncorrectly formatted number!";
}
并实现您想要做的任何事情,以防抛出该类型的异常。给定的代码将处理当前控制器中发生的异常。 如需进一步参考,请参阅this link。
要进行全局错误处理,您可以通过以下方式使用@ControllerAdvice
:
@ControllerAdvice
public class ServiceExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler({NumberFormatException.class})
public String handleError(){
//example
return "Uncorrectly formatted number!";
}
}
答案 2 :(得分:0)
@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
类中存在多个异常处理程序,则会引发错误。
答案 3 :(得分:-1)
处理 NumberFormatException。
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
LayoutInflater inflater = getLayoutInflater().from(this);
View view = inflater.inflate(R.layout.custom_listview, null, false);
menu.setHeaderView(view);
menu.add("Delete");
menu.add("Edit");
}
@Override
public boolean onContextItemSelected(MenuItem item) {
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
int position = info.position;
View v = listView.getChildAt(position);
TextView typeTv = v.findViewById(R.id.custom_listview_type);
TextView userTv = v.findViewById(R.id.custom_listview_user);
TextView passTv = v.findViewById(R.id.custom_listview_password);
if (item.getTitle().equals("Delete")) {
db.execSQL("delete from user_added_accounts where accountType = '" + typeTv.getText().toString() + "' and username = '" + userTv.getText().toString() + "';");
recreate();
}
if (item.getTitle().equals("Edit")) {
update(typeTv.getText().toString(), userTv.getText().toString(), passTv.getText().toString());
}
return true;
}