java - 客户端发送的请求在语法上不正确,列表为复选框

标签 java spring hibernate jsp tomcat7

我在提交表单时遇到错误: ERROR 400:客户端发送的请求语法不正确

我在带有 servlet 3.0 的 Tomcat 7 中使用 Hibernate 4、Spring 3 和 JSP 页面

我得到了一个扩展 BaseEntity 的 Order 类(BaseEntity 得到了自动生成的 uuid 成员):

@Entity
@Table (name = "orders")
public class Order extends BaseEntity {

    @ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinTable(name = "orders_additional_options", joinColumns = { 
            @JoinColumn(name = "orders_uuid", nullable = false, updatable = false) }, 
            inverseJoinColumns = { @JoinColumn(name = "additionalOptions_uuid", 
                    nullable = false, updatable = false) })
    protected Set<AdditionalOption> selectedAdditionalOptions = new HashSet<AdditionalOption>();

    /**
     * Constructor
     */
    public Order() {
        super("");
    }


    /**
     * @return the selectedAdditionalOptions
     */
    public Set<AdditionalOption> getSelectedAdditionalOptions() {
        return selectedAdditionalOptions;
    }

    /**
     * @param selectedAdditionalOptions the selectedAdditionalOptions to set
     */
    public void setSelectedAdditionalOptions(
            Set<AdditionalOption> selectedAdditionalOptions) {
        this.selectedAdditionalOptions = selectedAdditionalOptions;
    }



}

为了获得AdditionalOption 的列表,AdditionalOption 类如下所示:

@Entity
@Table (name = "additional_options")
public class AdditionalOption extends BaseEntity {

    @Column (nullable = false)
    protected String name;

    @ManyToMany(fetch = FetchType.EAGER, mappedBy = "selectedAdditionalOptions")
    private Set<Order> orders = new HashSet<Order>();

    /**
     * Constructor
     */
    public AdditionalOption()
    {
        super("");
    }

    /**
     * @return the name
     */
    public String getName() {
        return name;
    }

    /**
     * @param name the name to set
     */
    public void setName(String name) {
        this.name = name;
    }
}

我创建了一个 JSP 页面,其中包含一个新订单表单,我希望用户通过附加选项列表中的复选框进行选择。

所以代码如下所示:(uuid 来自 BaseEntity,availableAdditionalOptions 来自 AdditionalOptions 表上的全选查询)

 <form:form modelAttribute="order" action="/menuapp/order/create" method="POST">
<table>
    <tr>
        <td>Additional Options:</td>
        <td><form:checkboxes items="${availableAdditionalOptions}" path="selectedAdditionalOptions" itemLabel="name" itemValue="uuid"/></td>
    </tr>
    <tr>
        <input value="Order" type="submit">
    </tr>
  </table>
</form:form>

所以页面显示良好,但是当我单击提交按钮时,出现错误: ERROR 400:客户端发送的请求语法不正确

处理提交的 Controller 如下所示:

@RequestMapping(value = "/create", method = RequestMethod.POST)
        public String save(Model model, @ModelAttribute Order order) {
        orderService.saveOrUpdate(order);
            model.addAttribute("saved", "success");
            return "order";
        }

但它永远不会到达那里......

我用wireshark检查了HTML POST请求中发送的内容并得到了这个:

 selectedAdditionalOptions=ae396f42-843c-454d-a573-85e71c36709d&selectedAdditionalOptions=962e0766-5e56-4490-bc50-d4f41272c77e&_selectedAdditionalOptions=on

我在 log4j 文件中发现以下错误:

013-11-04 20:46:56 DEBUG DispatcherServlet:823 - DispatcherServlet with name 'appServlet' processing POST request for [/menuapp/order/create]
2013-11-04 20:46:56 DEBUG RequestMappingHandlerMapping:220 - Looking up handler method for path /order/create
2013-11-04 20:46:56 DEBUG RequestMappingHandlerMapping:227 - Returning handler method [public java.lang.String com.openu.menuapp.controller.OrderController.save(org.springframework.ui.Model,com.openu.menuapp.entity.Order)]
2013-11-04 20:46:56 DEBUG DefaultListableBeanFactory:246 - Returning cached instance of singleton bean 'orderController'
2013-11-04 20:46:56 DEBUG BeanUtils:443 - No property editor [com.openu.menuapp.entity.AdditionalOptionEditor] found for type com.openu.menuapp.entity.AdditionalOption according to 'Editor' suffix convention
2013-11-04 20:46:56 DEBUG ExceptionHandlerExceptionResolver:132 - Resolving exception from handler [public java.lang.String com.openu.menuapp.controller.OrderController.save(org.springframework.ui.Model,com.openu.menuapp.entity.Order)]: org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors
Field error in object 'order' on field 'selectedAdditionalOptions': rejected value [962e0766-5e56-4490-bc50-d4f41272c77e]; codes [typeMismatch.order.selectedAdditionalOptions,typeMismatch.selectedAdditionalOptions,typeMismatch.java.util.Set,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [order.selectedAdditionalOptions,selectedAdditionalOptions]; arguments []; default message [selectedAdditionalOptions]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'java.util.Set' for property 'selectedAdditionalOptions'; nested exception is java.lang.IllegalStateException: Cannot convert value of type [java.lang.String] to required type [com.openu.menuapp.entity.AdditionalOption] for property 'selectedAdditionalOptions[0]': no matching editors or conversion strategy found]
2013-11-04 20:46:56 DEBUG ResponseStatusExceptionResolver:132 - Resolving exception from handler [public java.lang.String com.openu.menuapp.controller.OrderController.save(org.springframework.ui.Model,com.openu.menuapp.entity.Order)]: org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors
Field error in object 'order' on field 'selectedAdditionalOptions': rejected value [962e0766-5e56-4490-bc50-d4f41272c77e]; codes [typeMismatch.order.selectedAdditionalOptions,typeMismatch.selectedAdditionalOptions,typeMismatch.java.util.Set,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [order.selectedAdditionalOptions,selectedAdditionalOptions]; arguments []; default message [selectedAdditionalOptions]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'java.util.Set' for property 'selectedAdditionalOptions'; nested exception is java.lang.IllegalStateException: Cannot convert value of type [java.lang.String] to required type [com.openu.menuapp.entity.AdditionalOption] for property 'selectedAdditionalOptions[0]': no matching editors or conversion strategy found]
2013-11-04 20:46:56 DEBUG DefaultHandlerExceptionResolver:132 - Resolving exception from handler [public java.lang.String com.openu.menuapp.controller.OrderController.save(org.springframework.ui.Model,com.openu.menuapp.entity.Order)]: org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors
Field error in object 'order' on field 'selectedAdditionalOptions': rejected value [962e0766-5e56-4490-bc50-d4f41272c77e]; codes [typeMismatch.order.selectedAdditionalOptions,typeMismatch.selectedAdditionalOptions,typeMismatch.java.util.Set,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [order.selectedAdditionalOptions,selectedAdditionalOptions]; arguments []; default message [selectedAdditionalOptions]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'java.util.Set' for property 'selectedAdditionalOptions'; nested exception is java.lang.IllegalStateException: Cannot convert value of type [java.lang.String] to required type [com.openu.menuapp.entity.AdditionalOption] for property 'selectedAdditionalOptions[0]': no matching editors or conversion strategy found]
2013-11-04 20:46:56 DEBUG DispatcherServlet:999 - Null ModelAndView returned to DispatcherServlet with name 'appServlet': assuming HandlerAdapter completed request handling
2013-11-04 20:46:56 DEBUG DispatcherServlet:966 - Successfully completed request

我无法回答自己的问题,所以我在这里写下答案:

好吧,问题是从 Uuid 作为字符串到AdditionalOption 对象的转换器

所以我将以下绑定(bind)添加到我的 Controller :

@Autowired
private AdditionalOptionConvertor additionalOptionConvertor;

@InitBinder
public void initBinder(WebDataBinder binder) {
     binder.registerCustomEditor(AdditionalOption.class, additionalOptionConvertor);
}

当AdditionalOptionConvertor是一个获得Autowired的服务时,如下所示:

@Service("additionalOptionConvertor")
public class AdditionalOptionConvertor extends BaseConvertor<AdditionalOption>
{
    @Autowired
    protected AdditionalOptionService service;

    @Override
    public void setAsText(String text) throws IllegalArgumentException
    {
        baseService = service;
        super.setAsText(text);
    }

}

我还添加了 BaseConvertor 类,因为我的所有对象共享 Uuid 成员,并且所有服务都获得返回 BaseEntity 对象的 findByUuid 所以 BaseConvertor 看起来像这样:

public abstract class BaseConvertor<T extends BaseEntity> extends PropertyEditorSupport
{

    protected BaseEntityService baseService;

    @Override
    public void setAsText(String text) throws IllegalArgumentException
    {
        T value =  baseService.findByUUID(text);
        setValue(value);
    }

    @SuppressWarnings("unchecked")
    @Override
    public String getAsText()
    {
        T d = (T) getValue();
        return d != null ? String.valueOf(d.getUuid()) : "";
    }   
}

有关 PropertyEditorSupport 的更多信息,请访问: Validation, Data Binding, and Type Conversion

感谢各位的帮助

最佳答案

好吧,问题是从 Uuid 作为字符串到AdditionalOption 对象的转换器

所以我将以下绑定(bind)添加到我的 Controller :

@Autowired
private AdditionalOptionConvertor additionalOptionConvertor;

@InitBinder
public void initBinder(WebDataBinder binder) {
     binder.registerCustomEditor(AdditionalOption.class, additionalOptionConvertor);
}

当AdditionalOptionConvertor是一个获得Autowired的服务时,如下所示:

@Service("additionalOptionConvertor")
public class AdditionalOptionConvertor extends BaseConvertor<AdditionalOption>
{
    @Autowired
    protected AdditionalOptionService service;

    @Override
    public void setAsText(String text) throws IllegalArgumentException
    {
        baseService = service;
        super.setAsText(text);
    }

}

我还添加了 BaseConvertor 类,因为我的所有对象共享 Uuid 成员,并且所有服务都获得返回 BaseEntity 对象的 findByUuid 所以 BaseConvertor 看起来像这样:

public abstract class BaseConvertor<T extends BaseEntity> extends PropertyEditorSupport
{

    protected BaseEntityService baseService;

    @Override
    public void setAsText(String text) throws IllegalArgumentException
    {
        T value =  baseService.findByUUID(text);
        setValue(value);
    }

    @SuppressWarnings("unchecked")
    @Override
    public String getAsText()
    {
        T d = (T) getValue();
        return d != null ? String.valueOf(d.getUuid()) : "";
    }   
}

有关 PropertyEditorSupport 的更多信息,请访问: Validation, Data Binding, and Type Conversion

感谢各位的帮助

关于java - 客户端发送的请求在语法上不正确,列表为复选框,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19775175/

相关文章:

java - 如何在 Hibernate 中保存时增加版本字段,无论是否脏?

java - Java中的多值哈希表

java - FXMLLoader 如何加载 FXML 的 Controller ?

java - 使用键值返回映射中的条目集

java - 解析特殊键字符串以获得KeyCode

java - 使用 spring mvc 设置日志记录,只想将跟踪/调试限制到我的代码

java - 项目的异常 Spring Hibernate Jndi Tomcat

java - Hibernate 在插入子对象时插入重复的父对象

java - 在@Transactional 服务方法中捕获 DataIntegrityViolationException

java - Spring XD 使用自定义 TCP 序列化器