提交表单时出现错误:错误 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>
所以页面显示得很好但是当我点击提交按钮时我收到错误:错误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 as String 到 AdditionalOption 对象的转换器
所以我将以下绑定添加到我的控制器:
@Autowired
private AdditionalOptionConvertor additionalOptionConvertor;
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(AdditionalOption.class, additionalOptionConvertor);
}
当 AdditionalOptionConvertor 是自动装配的服务时,如下所示:
@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 的更多信息,请访问: 验证、数据绑定和类型转换
感谢帮助者