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



我在提交表单时收到错误:错误 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;
    }

}

为了我得到一个 ExtraalOption 的列表,ExtraalOption 类看起来像这样:

@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>

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

处理提交的控制器如下所示:

@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 作为字符串到附加选项对象的转换器

因此,我将以下绑定添加到我的控制器:

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

当 ExtraalOptionConvertor 是一个自动连线的服务时,如下所示:

@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()) : "";
    }   
}

有关属性编辑器支持的更多信息,请访问:验证、数据绑定和类型转换

感谢帮助者

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

因此,我将以下绑定添加到我的控制器:

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

当 ExtraalOptionConvertor 是一个自动连线的服务时,如下所示:

@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()) : "";
    }   
}

有关属性编辑器支持的更多信息,请访问:验证、数据绑定和类型转换

感谢帮助者

最新更新