Spring MVC form data binding and ajax form
Model和View绑定是虽然不是MVC模式的标配,但是Model和View的绑定,为开发者提供的非常方便的方式:视图的数据自动和模型同步并装配完成,避免了繁琐的手工装配过程。Spring MVC提供了复杂的绑定机制和验证机制(前面的一个文章介绍了更复杂的动态列表的绑定)
我们先看看绑定机制:
我们以广告订单为例,在请求创建订单表单的action中,我们添加一个新创建的模型advertiseOrder:
@RequestMapping("/getCreateForm")public ModelAndView getCreateForm(){ModelAndView mav = new ModelAndView(); //add the model which the mav.addObject("advertiseOrder", new AdvertiseOrder()); //other data the form needList<User> sales = userManager.getUsersByType(User.SALE_TYPE);mav.addObject("saleList",sales);List<User> customerAids = userManager.getUsersByType(User.CUSTOMER_AID);mav.addObject("customerAidList",customerAids);mav.setViewName("advertiseOrders/create_order");return mav;}
在表单的页面_order_form.jsp,我们使用spring的form标签,指定commandName为我们在控制器中的名字advertiseOrder,
然后表单的每个数据域的path和模型的字段对应。另外使用form:select的option自动会被选中为value和模型对应字段的值相同的。
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %><form:form commandName="advertiseOrder" id="orderForm" action="${param.actionURL}" method="post"><div class="form"><table cellpadding="0" cellspacing="0" ><tr><th>广告主</th><td><form:hidden class="textbox" path="customerId"/><input class="textbox" id="customerName" type="text" value="${advertiserName}"/><span class="po">广告主名称</span><form:errors class="error" path="customerId"/></td></tr><tr><th><form:label for="name" path="name">订单名称</form:label></th><td><form:hidden path="id"/><form:input class="textbox" path="name"/><span class="po">包含广告主名称,计费类型,业务类型等</span><form:errors class="error" path="name"/></td></tr><tr><th><form:label for="startTime" path="startTime">订单时间</form:label></th><td><div class="qcbox"><div class="labelContainer"></div><div class="boxWrapper"><div class="boxContainer"><div class="sinfo" title=""></div><div class="sicon" id="fromTimeIcon"></div><div style="clear: both;"></div></div></div><form:input path="startTime" class="textbox0"/> </div> <div class="ln">-</div> <div class="qcbox"><div class="labelContainer"></div><div class="boxWrapper"><div class="boxContainer"><div class="sinfo" title=""></div><div class="sicon" id="toTimeIcon"></div><div style="clear: both;"></div></div></div><form:input path="endTime" class="textbox0"/></div><form:errors class="error" path="startTime"/>&nbsp;&nbsp;<form:errors class="error" path="endTime"/></td></tr><tr><th><form:label path="description">订单说明</form:label><td><form:textarea class="textbox" path="description"></form:textarea></td></tr><tr><th><form:label path="saleId">销售人员</form:label></th><td><div class="fg"><div class="list"><form:select class="name" path="saleId" onchange="onSelectOrderSale()"><option value="">选择销售人员</option><form:options items="${saleList}" itemValue="id" itemLabel="usrName"></form:options></form:select><form:hidden path="sale"/></div><form:errors class="error" path="saleId"/></div></td></tr><tr><th><form:label path="customerAidId">客服人员</form:label></th><td><div class="list"><form:select class="name" path="customerAidId" onchange="onSelectOrderCustomerAid()"> <option value="">选择客服人员</option><form:options items="${customerAidList}" itemValue="id" itemLabel="usrName"/></form:select><form:hidden path="customerAid"/></div><form:errors class="error" path="customerAidId"/></td></tr><tr><th></th><td><input class="button"type="submit" value="保 存" /></td></tr></table></div></form:form>
表单提交到创建订单的action:我们使用ModelAttribute的注解绑定表单的对象和@Valid注解需要验证的模型(注:BindingResult参数必须在@ModelAttribute注解参数的下一个):
@RequestMapping("/create")public ModelAndView create(@ModelAttribute("advertiseOrder") @Valid AdvertiseOrder order, BindingResult result,HttpSession session){ModelAndView mav = new ModelAndView();if(result.hasErrors()){mav.setViewName("advertiseOrders/create_order");List<User> sales = userManager.getUsersByType(User.SALE_TYPE);mav.addObject("saleList",sales);List<User> customerAids = userManager.getUsersByType(User.CUSTOMER_AID);mav.addObject("customerAidList",customerAids);mav.addObject("errors", result);mav.addObject("advertiseOrder", order);}else{User user = (User) session.getAttribute("user");order.setOperator(user.getUsrName());advertiseOrderManager.create(order);mav.setViewName("redirect:list");}return mav;}
如果字段的类型需要转换(spring自定默认提供多了很多类型转换,比如String和Integer,Float,Date之间的转换),我们也可以自定义类型转换,比如Timestamp类型,我们需要指定的格式字符串和Timestamp类型的转化的Editor。在执行业务逻辑之前,我们还需要对模型的数据进行验证,也就是表单后台验证,我们只需要在控制器中的使用@InitBinder中注册自定义的类型转换器和添加指定模型验证即可:
@InitBinderpublic void initBinder(WebDataBinder binder, WebRequest request) {if(binder.getTarget() instanceof AdvertiseOrder){binder.setValidator(new AdvertiseOrderValidator()); //自定义字段类型转换的customerEditorbinder.registerCustomEditor(java.sql.Timestamp.class, new TimestampEditor("yyyy-MM-dd", true)); }}
然后写我们验证器代码:
package com.qunar.advertisement.advertiser.vo;import java.sql.Timestamp;import org.springframework.validation.Errors;import org.springframework.validation.ValidationUtils;import org.springframework.validation.Validator;import com.qunar.advertisement.advertiser.model.AdvertiseOrder;public class AdvertiseOrderValidator implements Validator {@Overridepublic boolean supports(Class<?> clazz) {return clazz == AdvertiseOrder.class;}@Overridepublic void validate(Object target, Errors errors) {ValidationUtils.rejectIfEmpty(errors, "customerId", "field.required",new Object[]{"广告主"});ValidationUtils.rejectIfEmpty(errors, "name", "field.required",new Object[]{"订单名称"});ValidationUtils.rejectIfEmpty(errors, "startTime", "field.required",new Object[]{"订单开始时间"});ValidationUtils.rejectIfEmpty(errors, "endTime", "field.required",new Object[]{"订单结束时间"});ValidationUtils.rejectIfEmpty(errors, "saleId", "field.required",new Object[]{"销售人员"});ValidationUtils.rejectIfEmpty(errors, "customerAidId", "field.required",new Object[]{"客服人员"});if(errors.hasErrors())return;AdvertiseOrder order = (AdvertiseOrder)target;Timestamp startTime = order.getStartTime();Timestamp endTime = order.getEndTime();if(endTime.before(startTime)){errors.rejectValue("endTime", "endTime_must_after_startTime");}}}
我们在messages_zh.properties配置要显示的错误信息:
<div class="quote_title">引用
页:
[1]