Spring Conversion Service,将表单绑定到嵌套对象

时间:2013-11-16 13:22:11

标签: java java-ee spring-mvc

我无法将弹簧形式值绑定到支持对象。 以下是代码的相关部分。

这是来自page.jsp

<form:form method="post" commandName="building" action="addBuilding">
        <div>
            <div>
                <form:label path="buildingName">Building Name:</form:label>
                <form:input path="buildingName" />
                <form:errors path="buildingName"></form:errors>
            </div>
            <div>
                <form:label path="buildingType">Building Type:</form:label>
                <form:select path="buildingType">
                    <form:option value="none">--Select One--</form:option>
                    <form:options items="${buildingTypeList}" itemValue="id" itemLabel="typeName"/>
                </form:select>
                <form:errors path="buildingType"></form:errors>
            </div>
        </div>
</form:form>

我想绑定的模型类如下。为了完整起见,我添加了这些

@Entity
@Table(name="tablename")
class Building {

    @Column
    private buildingName;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "buildingType", referencedColumnName = "id", nullable = false)
    private BuildingType buildingType;

    //other fields, getters and setters etc.
}

@Entity
@Table(name="tablename")
class BuildingType {

    @Id
    @Column
    private int id;

    @Column
    private String typeName;

    //getters, setters
}

此时我可以在组合框中看到建筑类型名称(在GET请求中)。发布表单时会出现问题。来自组合框的Itemvalue是int,我想将它绑定到Building模型中的buildingType字段。代码会更好地解释我猜。相关的控制器功能:

@RequestMapping(value = "addBuilding", method = RequestMethod.GET)
public String addBuildingPage(Model model) {

    Building building = new Building();
    model.addAttribute("building", building);

    List<BuildingType> buildingTypeList = buildingTypeDao.findAll();

    model.addAttribute("buildingTypeList", buildingTypeList);
    return "addBuilding";
}

@RequestMapping(value = "addBuilding", method = RequestMethod.POST)
public String submitNewBuilding(@ModelAttribute(value = "building") @Valid Building building,
        BindingResult result, Model model) {

    if (result.hasErrors()) {
        return "addBuilding";
    }

    model.addAttribute("building", building);

    return "addBuilding";
}

我得到一个无法将int强制转换为BuildingType异常,经过一些搜索后我跟着写了here的博客文章。所以我决定编写一个自定义格式化程序并使用ConversionService。 这是格式化程序类

@Component
public class BuildingTypeFormatter implements Formatter<BuildingType> {

    @Autowired
    private BuildingTypeDao buildingTypeDao;

    @Override
    public String print(BuildingType buildingType, Locale arg1) {
    return buildingType.getName();
    }

    @Override
    public BuildingTypeDBO parse(String id, Locale arg1) throws ParseException {
    return buildingTypeDao.findOne(Long.parseLong(id));
    }
}

这是spring配置类。 (我不使用xml配置。)

@EnableWebMvc
@Configuration
@ComponentScan({ "my.packages" })
public class MvcConfig extends WebMvcConfigurerAdapter {

    @Autowired
    private BuildingTypeDBOFormatter formatter;

    public MvcConfig() {
        super();
    }

    @Bean(name = "conversionService")
    public FormattingConversionServiceFactoryBean conversionService() {
        FormattingConversionServiceFactoryBean bean = new FormattingConversionServiceFactoryBean();
        Set<Formatter<?>> formatters = new HashSet<Formatter<?>>();
        formatters.add(formatter);
        bean.setFormatters(formatters);

        return bean;
    }

我认为我需要注册转换服务,如博客文章中所述。像我这样在我的控制器中使用和初始化绑定器。

@Autowired
ConversionService conversionService;

@InitBinder
public void initBinder(WebDataBinder binder) {
    binder.setConversionService(conversionService);
}

问题是我在使用setConversionException时遇到以下异常。当我调试它时,我看到使用默认的conversionService初始化了绑定器。

java.lang.IllegalStateException: DataBinder is already initialized with ConversionService
at org.springframework.util.Assert.state(Assert.java:385)
at org.springframework.validation.DataBinder.setConversionService(DataBinder.java:562)
at my.package.controller.MyController.initBinder(MyController.java:138)

我遇到了许多建议setConversionService的答案,但它不起作用,我该如何解决这个问题? (PS:很抱歉很长的帖子,但我认为可能有几种方法可以解决这个问题,所以我更愿意发布整篇文章。)

1 个答案:

答案 0 :(得分:0)

您可以尝试在控制器中添加自定义属性编辑器

@InitBinder
public void initBinder(ServletRequestDataBinder binder) {

    binder.registerCustomEditor(BuildingType.class, "buildingType", new PropertyEditorSupport() {

        public void setAsText(String text) {
            Long buildingTypeId = Long.parseLong(text);
            BuildingType buildingType = (BuildingType) buildingTypeDao.findOne(buildingTypeId);
            setValue(buildingType);               
        }
    });

}