我在提交表单时收到错误:错误 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()) : "";
}
}
有关属性编辑器支持的更多信息,请访问:验证、数据绑定和类型转换
感谢帮助者