如何在spring 3.2 mvc中接收复杂对象?
在下面的简单示例中,我有两个模型类,具有多对一关系。添加新的Employee对象时,我想使用html select来选择它的部门。
当我发帖添加新的员工时,我收到以下错误:
无法将java.lang.String类型的属性值转换为属性部门所需类型hu.pikk.model.Department;嵌套异常是java.lang.IllegalStateException:无法将类型[java.lang.String]的值转换为属性部门所需的类型[hu.pikk.model.Department]:找不到匹配的编辑器或转换策略
我应该如何实施编辑器或转换策略?是否应该注意最佳做法或陷阱?
我已经阅读了spring mvc文档,以及一些文章和stackoverflow问题,但说实话,我发现它们有点令人困惑,而且很多时候太短,太过分了。
型号:
@Entity
public class Employee {
@Id
@GeneratedValue
private int employeeId;
@NotEmpty
private String name;
@ManyToOne
@JoinColumn(name="department_id")
private Department department;
//getters,setters
}
@Entity
public class Department {
@Id
@GeneratedValue
private int departmentId;
@Column
private String departmentName;
@OneToMany
@JoinColumn(name = "department_id")
private List<Employee> employees;
//getters,setters
}
在我的控制器类中:
@RequestMapping(value = "/add", method = RequestMethod.GET)
private String addNew(ModelMap model) {
Employee newEmployee = new Employee();
model.addAttribute("employee", newEmployee);
model.addAttribute("departments", departmentDao.getAllDepartments());
return "employee/add";
}
@RequestMapping(value = "/add", method = RequestMethod.POST)
private String addNewHandle(@Valid Employee employee, BindingResult bindingResult, ModelMap model, RedirectAttributes redirectAttributes) {
if (bindingResult.hasErrors()) {
model.addAttribute("departments", departmentDao.getAllDepartments());
return "employee/add";
}
employeeDao.persist(employee);
redirectAttributes.addFlashAttribute("added_employee", employee.getName());
redirectAttributes.addFlashAttribute("message", "employee added...");
return "redirect:list";
}
在add.jsp中:
<f:form commandName="employee" action="${pageContext.request.contextPath}/employee/add" method="POST">
<table>
<tr>
<td><f:label path="name">Name:</f:label></td>
<td><f:input path="name" /></td>
<td><f:errors path="name" class="error" /></td>
</tr>
<tr>
<td><f:label path="department">Department:</f:label></td>
<td><f:select path="department">
<f:option value="${null}" label="NO DEPARTMENT" />
<f:options items="${departments}" itemLabel="departmentName" itemValue="departmentId" />
</f:select></td>
<td><f:errors path="department" class="error" /></td>
</tr>
</table>
<input type="submit" value="Add Employee">
</f:form>
答案 0 :(得分:3)
问题是,当控制器收到POST时,它不知道如何将id字符串转换为Department对象。 我发现基本上有三种方法可以解决这个问题:
我选择了第三种选择。 (稍后当我将有一些时间时,我将使用探索的前两个选项编辑此答案。)
@Component
public class DepartmentConverter implements Converter<String,Department>{
@Autowired
private DepartmentDao departmentDao;
@Override
public Department convert(String id){
Department department = null;
try {
Integer id = Integer.parseInt(text);
department = departmentDao.getById(id);
System.out.println("Department name:" + department.getDepartmentName());
} catch (NumberFormatException ex) {
System.out.println("Department will be null");
}
return department;
}
}
在spring beans配置文件中:
<mvc:annotation-driven conversion-service="conversionService"/>
<bean id="conversionService"
class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="package.DepartmentConverter"/>
</list>
</property>
</bean>
public class SimpleDepartmentEditor extends PropertyEditorSupport {
private DepartmentDao departmentDao;
public SimpleDepartmentEditor(DepartmentDao departmentDao){
this.departmentDao = departmentDao;
}
@Override
public void setAsText(String text) throws IllegalArgumentException {
Department department = null;
try {
Integer id = Integer.parseInt(text);
department = departmentDao.getById(id);
System.out.println("Department name:" + department.getDepartmentName());
} catch (NumberFormatException ex) {
System.out.println("Department will be null");
}
setValue(department);
}
}
在Controller内部,我需要添加一个@InitBinder:
@InitBinder
protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) {
binder.registerCustomEditor(Department.class, new SimpleDepartmentEditor(departmentDao));
}
答案 1 :(得分:0)
我认为你在这里遇到了下一个情况。当Spring尝试反序列化在Employee
中收到的addNewHandle
实体时,它找到了String类型的属性department
,但在目标实体中它有Department
类型,那么,因为你有没有转换为这种转换注册,它失败了。因此,要解决此问题,您可以实现自己的转换器(Converter),它获取String并返回Department
并在conversionService
中注册它,或者您可以通过覆盖{{3}来实现自己的JSON反序列化策略使用department
注释@JsonDeserialize(using=<your Jacson custom deserializer>.class)
属性。希望这会有所帮助。