如何在spring 3.2 mvc中接收复杂对象?

codeday· 2019-11-11
本文来自 codeday ,作者 codeday
如何在弹簧3.2 mvc中接收复杂物体?

在下面的简单示例中,我有两个模型类,具有多对一关系.添加新的Employee对象时,我想使用html选择来选择它的部门.

当我发布添加新的员工时,我收到以下错误:

Failed to convert property value of type java.lang.String to required type hu.pikk.model.Department for property department; nested exception is java.lang.IllegalStateException: Cannot convert value of type [java.lang.String] to required type [hu.pikk.model.Department] for property department: no matching editors or conversion strategy found

我该如何实施编辑器或转换策略?是否应该注意最佳做法或陷阱?

我已经阅读了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>
最佳答案
问题是,当控制器收到POST时,它不知道如何将id字符串转换为Department对象.
我发现基本上有三种方法可以解决这个问题:

>不使用spring表单jstl,而是使用自定义名称的简单html选择,并在Controller中使用@RequestParam读取它,访问数据库并填充它.
>实现Converter接口,并将其注册为bean.
>实现PropertyEditor接口.通过扩展PropertyEditorSupport类,可以更轻松地完成此操作.

我是第三种选择. (稍后当我有时间的时候,我会用探索的前两个选项编辑这个答案.)

2.实现转换器< String,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>

3.扩展PropertyEditorSupport类

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));
    }