什么是参数绑定 ?
在Controller使用方法参数接收值,就是把web端的值给接收到Controller中处理,这个过程就叫做参数绑定。
springmvc所支持参数绑定
默认支持参数类型
Controller默认支持的参数类型有四个,足以满足开发需求
- HttpServletRequest 通过request对象获取请求信息
- HttpServletResponse 通过response处理响应信息
- HttpSession 通过session对象得到session中存放的对象
- Model/ ModelMap 将模型数据填充到request域 model是一个接口modelMap是一个接口实现
1.简单数据类型绑定,整型、字符串、日期...
·只要保证request请求的参数名和形参名称一致,自动绑定成功。
·如果request请求的参数名和形参名称不一致,可以使用@RequestParam(指定request请求的参数名),@RequestParam加在形参的前边。
2. 支持pojo类型绑定
只要保证request请求的参数名称和pojo中的属性名一致,自动将request请求的参数设置到pojo的属性中。(注意:形参中即有pojo类型又有简单类型,参数绑定互不影响。)
3. 集合类型绑定
通常在需要批量提交数据时,将提交的数据通过集合绑定完成数据提交
- 数组绑定
- list绑定
- map绑定
4. 自定义参数绑定
例:日期类型绑定自定义:定义Converter<源类型,目标类型>接口实现类,比如:Converter<String,Date>表示:将请求的日期数据串转成java中的日期类型。(注意:要转换的目标类型一定和接收的pojo中的属性类型一致。将定义的Converter实现类注入到处理器适配器中。)
参数绑定过程
从客户端请求key/value数据,经过参数绑定,将key/value数据绑定到controller方法的形参上。
springmvc中,接收页面提交的数据是通过方法形参来接收。而不是在controller类定义成员变更接收!
图源:《阿里云》
在本次介绍中,以下4种绑定方法统一运用默认使用支持参数HttpServletRequest类型绑定。直接在controller方法形参上定义下边类型的对象,就可以使用这些对象。其他默认参数绑定类型与其类似。
简单数据类型绑定
通过@RequestParam对简单类型的参数进行绑定。
1.不使用@RequestParam,要求request传入参数名称和controller方法的形参名称一致,方可绑定成功。
2.使用@RequestParam,不用限制request传入参数名称和controller方法的形参名称一致。
- 指定request返回参数名称与controller形参名称绑定
- required,指定参数必须传入
- defaultValue,指定默认参数
itemsList.jsp
<td><a href="${PageContext.request.ContextPath }/items/editItems.action?id=${item.id}">修改</a></td>
Controller
/**
*
* @Description: 商品信息修改页面
* @param @param request 通过request对象获取请求信息
* @param @param id 商品信息id
* @param @return 返回修改页面
* @param @throws Exception
* @return ModelAndView
* @throws
* @author XHChen
* @date 2018年10月26日 上午10:16:06
*/
// 1.Integer id,要求request返回参数名称与controller形参名称一致
// [email protected]对简单类型的参数进行绑定
// [email protected],指定request返回参数名称与controller形参名称绑定
// b.required,指定参数必须传入
// c.defaultValue,id默认参数
@RequestMapping("/editItems.action")
public ModelAndView editItems(
HttpServletRequest request,
@RequestParam(value = "id", required = true, defaultValue = "id") Integer id)
throws Exception {
// 调用itemsService接口,查询商品信息
ItemsCustomer itemsCustomer = itemsService.findItemsById(id);
// 创建ModelAndView
ModelAndView modelAndView = new ModelAndView();
// 返回数据到页面
modelAndView.addObject("itemsCustomer", itemsCustomer);
// 指定视图
// 路径前缀和后缀已由springmvc.xml配置
modelAndView.setViewName("items/editItems");
// 返回指定视图
return modelAndView;
}
ItemsService.java
/**
*
* @Description: 找到修改商品信息
* @param @param id 查询商品的id
* @param @return
* @param @throws Exception
* @return ItemsCustomer
* @throws
* @author XHChen
* @date 2018年10月20日 下午8:23:06
*/
public ItemsCustomer findItemsById(Integer id) throws Exception;
ItemsServiceImpl.java
@Override
/**
* 根据id查询商品信息
*/
public ItemsCustomer findItemsById(Integer id) throws Exception {
// 根据id查询商品信息
Items items = itemsMapper.findItemsById(id);
// 创建ItemsCustomer对象
ItemsCustomer itemsCustomer = new ItemsCustomer();
// 把商品信息items复制到itemsCustomer
BeanUtils.copyProperties(items, itemsCustomer);
// 返回拓展类ItemsCustomer
return itemsCustomer;
}
itemsMapper.java
// 通过id查询
public Items findItemsById(int id) throws Exception;
itemsMapper.xml
<!-- 通过id查询 -->
<select id="findItemsById" parameterType="java.lang.Integer" resultType="cn.ssm.xhchen.po.Items">
<!-- 插入查询语句 -->
select * from items where id=#{id}
</select>
自定义参数绑定
对于controller形参中pojo对象,如果属性中有日期类型,需要自定义参数绑定。
将请求日期数据串传成日期类型,要转换的日期类型和pojo中日期属性的类型保持一致(下文的Converter<String, Date>接口)。
pojo对象
private Date items_creattime; // 商品生产时间
itemsList.jsp
<td><fmt:formatDate value="${item.items_creattime }" pattern="yyyy:MM:dd HH:mm:ss"/></td>
自定义日期类型绑定
在cn.ssm.xhchen.controller.converter下创建CustomerDateConverter.java并实现Converter<String, Date>接口
package cn.ssm.xhchen.controller.converter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.core.convert.converter.Converter;
/**
*
* ClassName: CustomerDateConverter
*
* @Description: 日期转换器
* @author XHChen
* @date 2018年10月21日 上午11:56:35
*/
public class CustomerDateConverter implements Converter<String, Date> {
@Override
public Date convert(String source) {
// 把日期串转换成yyyy:MM:dd HH:mm:ss格式
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss");
// 根据需求格式转换
try {
return simpleDateFormat.parse(source);
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
}
配置方式
自动注册DefaultAnnotationHandlerMapping与AnnotationMethodHandlerAdapte两个bean
<!-- 自动注册DefaultAnnotationHandlerMapping与AnnotationMethodHandlerAdapte两个bean,
是spring MVC为@Controllers分发请求所必须的 -->
<mvc:annotation-driven conversion-service="conversionService" />
<!-- 自定义参数绑定 -->
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<!-- 转换器 -->
<property name="converters">
<list>
<!-- 日期类型转换 -->
<bean class="cn.ssm.xhchen.controller.converter.CustomerDateConverter" />
</list>
</property>
</bean>
pojo类型绑定
页面中input的name和controller的pojo形参中的属性名称一致,将页面中数据绑定到pojo。
controller的pojo形参的定义
// 系统拓展性,对原始po进行拓展
private ItemsCustomer itemsCustomer;
itemsList.jsp
<td><input type="text" name="itemsCustomer.items_name"></td>
<td><input type="button" value="搜索商品" onclick="queryItems()"></td>
function queryItems() {
document.itemsForm.action="${PageContext.request.ContextPath }/items/queryItems.action";
document.itemsForm.submit();
}
Controller
/**
*
* @Description: 查询商品信息,pojo绑定
* @param @param itemsQueryVo pojo绑定
* @param @return 返回商品列表
* @param @throws Exception
* @return ModelAndView
* @throws
* @author XHChen
* @date 2018年10月26日 上午10:23:36
*/
@RequestMapping("/queryItems.action")
public ModelAndView queryItems(HttpServletRequest request, ItemsQueryVo itemsQueryVo)
throws Exception {
// 调用service方法查询数据库
List<ItemsCustomer> itemsList = itemsService.findItemsList(itemsQueryVo);
// 遍历结果
for (ItemsCustomer itemsCustomer2 : itemsList) {
System.out.println(itemsCustomer2);
}
System.out.println(itemsList.size());
// 返回ModelAndView
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("itemsList", itemsList);
// 指定视图
// 路径前缀和后缀已由springmvc.xml配置
modelAndView.setViewName("items/itemsList");
return modelAndView;
}
ItemsService.java
/**
*
* @Description: 商品列表查询
* @param @param itemsQueryVo 封装商品信息的类
* @param @return
* @param @throws Exception
* @return List<ItemsCustomer> 数据库返回的值映射到ItemsCustomer
* @throws
* @author XHChen
* @date 2018年10月20日 下午8:23:28
*/
public List<ItemsCustomer> findItemsList(ItemsQueryVo itemsQueryVo) throws Exception;
ItemsServiceImpl.java
@Override
/**
* 通过itemsQueryVo查询商品信息
*/
public List<ItemsCustomer> findItemsList(ItemsQueryVo itemsQueryVo) throws Exception {
// 通过ItemsMapperCustomer查询数据库
return itemsMapperCustomer.findItemsList(itemsQueryVo);
}
ItemsMapperCustomer.java
// 商品列表查询
public List<ItemsCustomer> findItemsList(ItemsQueryVo itemsQueryVo) throws Exception;
ItemsMapperCustomer.xml
<!-- ItemsMapper的拓展mapper -->
<mapper namespace="cn.ssm.xhchen.mapper.ItemsMapperCustomer">
<!-- sql片段 -->
<sql id="where_query_Items">
<!-- 使用动态sql,满足条件进行sql拼接 -->
<!-- 商品信息通过 ItemsQueryVo包装类中的ItemsCustomer传递 -->
<if test="itemsCustomer != null">
<if test="itemsCustomer.items_name != null and itemsCustomer.items_name != ''">
items_name like '%${itemsCustomer.items_name}%';
</if>
</if>
</sql>
<!-- 商品列表查询
parameterType:商品信息包装类
resultType:商品信息po拓展类
-->
<select id="findItemsList" parameterType="cn.ssm.xhchen.po.ItemsQueryVo" resultType="cn.ssm.xhchen.po.ItemsCustomer">
select * from items
<where>
<include refid="where_query_Items"></include>
</where>
</select>
集合类型绑定
数组绑定
需求:商品批量删除,用户在页面选择多个商品,批量删除。
原理:
将页面选择(多选)的商品id,传到controller方法的形参,方法形参使用数组接收页面请求的多个商品id。
定义数组有两种方式(下文采用第二种)
- 在Controller方法定义形参, 不使用@RequestParam简单绑定获得ids
- 在ItemsQueryVo定义数组属性,通过get获得ids
itemsList.jsp
checkbox
<td><input type="checkbox" name="items_ids" value="${item.id }"></td>
input
<td><input type="button" value="批量删除" onclick="deleteItems()"></td>
javascript
function deleteItems() {
document.itemsForm.action="${PageContext.request.ContextPath }/items/deleteItems.action";
document.itemsForm.submit();
}
ItemsQueryVo.java
// 接收数组,属性名要和页面name保持一致
private Integer[] items_ids;
实现方式可以分为两种(建议后者)
- 逐一删除数组里的商品信息(不断请求数据库)
- 一次删除数组里的商品信息,需要sql拼接
Controller.java
/**
*
* @Description: 批量删除商品
* @param @param items_id 与页面checkbox的名称保持一致
* @param @return 返回商品列表
* @return String
* @throws Exception
* @throws
* @author XHChen
* @date 2018年10月26日 上午9:57:26
*/
@RequestMapping("/deleteItems.action")
public ModelAndView deleteItems(HttpServletRequest requests, ItemsQueryVo itemsQueryVo) throws Exception {
// 调用itemsService方法
// 逐一删除商品信息
// itemsService.deleteItemsArray(itemsQueryVo.getItems_ids());
// 一次删除商品信息,需要sql拼接
itemsService.deleteItemsArrayAllIn(itemsQueryVo.getItems_ids());
// 重新查询商品信息
List<ItemsCustomer> itemsList = itemsService.findItemsList(itemsQueryVo);
// 返回ModelAndView
ModelAndView modelAndView = new ModelAndView();
// 返回参数到页面
modelAndView.addObject("itemsList", itemsList);
// 指定视图
modelAndView.setViewName("items/itemsList");
// 返回指定视图
return modelAndView;
}
itemsService.java
/**
*
* @Description: 逐次删除数组商品信息
* @param @param items_id 商品id
* @return void
* @throws
* @author XHChen
* @date 2018年10月26日 上午11:22:56
*/
public void deleteItemsArray(Integer[] items_id) throws Exception;
/**
*
* @Description: 一次性删除商品信息
* @param @param items_ids
* @param @throws Exception
* @return void
* @throws
* @author XHChen
* @date 2018年10月27日 上午11:33:32
*/
public void deleteItemsArrayAllIn(Integer[] items_ids) throws Exception;
ItemsServiceImpl.java
@Override
/**
* 单个删除数组商品信息
*/
public void deleteItemsArray(Integer[] items_ids) throws Exception {
// 每次传一个id值删除
try {
for (Integer id : items_ids) {
// 调用itemsMapper接口方法
itemsMapper.deleteItems(id);
}
} catch (Exception e) {
// 输出错误日志
System.out.println(e.getMessage());
}
}
@Override
/**
* 一次性删除商品信息
*/
public void deleteItemsArrayAllIn(Integer[] items_ids) throws Exception {
// 调用itemsMapperCustomer接口方法
itemsMapperCustomer.deleteItemsArrayAllIn(items_ids);
}
ItemsMapper.xml
<!-- 删除数据 -->
<delete id="deleteItems" parameterType="cn.ssm.xhchen.po.Items">
<!-- 插入删除语句 -->
delete from items where id=#{id}
</delete>
ItemsMapper.java
// 删除
public void deleteItems(int id) throws Exception;
ItemsMapperCustomer.xml
<!-- 批量删除数组商品信息
collection: 传入单参数的参数类型
index: 每次迭代到的位置
item: 每一个元素进行迭代时的别名
open: 以什么开始
separator: 每次进行迭代之间以什么符号作为分隔 符
close: 以什么结束
-->
<delete id="deleteItemsArrayAllIn" parameterType="java.util.List">
delete from items where id in
<foreach collection="list" index="index" item="items_id" open="(" separator="," close=")">
#{items_id}
</foreach>
</delete>
ItemsMapperCustomer.java
// 一次性删除商品信息
public void deleteItemsArrayAllIn(Integer[] items_ids) throws Exception;
List绑定
需求:批量商品修改,在页面输入多个商品信息,将多个商品信息提交到controller方法中。
原理:
- 进入批量商品修改页面(页面样式参考商品列表实现)
- 批量修改商品提交,使用List接收页面提交的批量数据,通过包装pojo接收,在包装pojo中定义list<pojo>属性, 并添加get/set方法
Pojo定义
// 接受list集合,批量商品信息
private List<ItemsCustomer> itemsList;
editItemsQuery.jsp
<c:forEach items="${itemsList}" var="item" varStatus="status">
<tr>
<td>
<input type="text" name="itemsList[${status.index }].items_name" value="${item.items_name }">
</td>
<td>
<input type="text" name="itemsList[${status.index }].items_price" value="${item.items_price }">
</td>
<td>
<input type="text" name="itemsList[${status.index }].items_creattime" value="<fmt:formatDate value="${item.items_creattime }" pattern="yyyy:MM:dd HH:mm:ss"/>">
</td>
<td>
<input type="text" name="itemsList[${status.index }].items_detail" value="${item.items_detail }">
</td>
</tr>
</c:forEach>
实现方式可以分为两种(建议后者)
- 逐条提交批量修改商品信息(不断请求数据库)
- 一次性提交批量修改商品信息,需要sql拼接
Controller
/**
*
* @Description: 批量修改商品信息页面 ,list绑定
* @param @param request 通过request对象获取请求信息
* @param @param itemsQueryVo pojo绑定
* @param @return 返回批量修改商品信息页面
* @param @throws Exception
* @return ModelAndView
* @throws
* @author XHChen
* @date 2018年10月26日 下午9:14:40
*/
@RequestMapping("/editItemsQuery.action")
public ModelAndView editItemsQuery(HttpServletRequest request, ItemsQueryVo itemsQueryVo)
throws Exception {
// 查询所有商品信息
List<ItemsCustomer> itemsList = itemsService.findItemsList(itemsQueryVo);
// 返回ModelAndView
ModelAndView modelAndView = new ModelAndView();
// 向页面传递数据
modelAndView.addObject("itemsList", itemsList);
// 指定视图
modelAndView.setViewName("items/editItemsQuery");
// 返回指定视图
return modelAndView;
}
/**
*
* @Description: 提交批量修改商品信息
* 绑定原理:通过ItemsQueryVo批量提交商品信息,将商品信息存储在ItemsQueryVo的itemsList属性中
* @param @param request 通过request对象获取请求信息
* @param @param itemsQueryVo pojo绑定
* @param @return 返回商品信息页面
* @param @throws Exception
* @return ModelAndView
* @throws
* @author XHChen
* @date 2018年10月26日 下午9:30:23
*/
@RequestMapping("/editItemsAllSubmit.action")
public ModelAndView editItemsAllSubmit(HttpServletRequest request, ItemsQueryVo itemsQueryVo)
throws Exception {
// 调用itemsService接口方法
// 逐条提交批量修改商品信息
// itemsService.updateAllItems(itemsQueryVo.getItemsList());
// 一次性提交批量修改商品信息,需要sql拼接
itemsService.updateAllItemsSubmit(itemsQueryVo.getItemsList());
// 重新查询所有商品信息
List<ItemsCustomer> itemsList = itemsService.findItemsList(itemsQueryVo);
// 返回ModelAndView
ModelAndView modelAndView = new ModelAndView();
// 向页面传递数据
modelAndView.addObject("itemsList", itemsList);
// 指定视图
modelAndView.setViewName("items/itemsList");
// 返回指定视图
return modelAndView;
}
itemsService.java
/**
*
* @Description:逐次提交批量修改商品信息
* @param @param itemsList
* @return void
* @throws
* @author XHChen
* @date 2018年10月27日 上午10:16:57
*/
public void updateAllItems(List<ItemsCustomer> itemsList) throws Exception;
/**
*
* @Description: 一次性提交批量修改商品信息
* @param @param itemsList
* @return void
* @throws
* @author XHChen
* @date 2018年10月27日 上午10:47:18
*/
public void updateAllItemsSubmit(List<ItemsCustomer> itemsList) throws Exception;
ItemsServiceImpl.java
@Override
/**
* 逐条提交批量修改商品信息
*/
public void updateAllItems(List<ItemsCustomer> itemsList) throws Exception {
try {
for (ItemsCustomer itemsCustomer : itemsList) {
// 调用itemsMapper接口方法
itemsMapper.updateItems(itemsCustomer);
}
} catch (Exception e) {
// 输出错误日志
System.out.println(e.getMessage());
}
}
@Override
/**
* 一次性提交批量修改商品信息
*/
public void updateAllItemsSubmit(List<ItemsCustomer> itemsList) throws Exception {
// 调用itemsMapperCustomer接口方法
itemsMapperCustomer.updateAllItemsSubmit(itemsList);
}
ItemsMapper.xml
<!-- 修改数据 -->
<update id="updateItems" parameterType="cn.ssm.xhchen.po.Items">
<!-- 插入修改sql语句 -->
update items set items_name=#{items_name}, items_detail=#{items_detail}, items_price=#{items_price} where id=#{id}
</update>
ItemsMapper.java
// 修改
public void updateItems(Items items) throws Exception;
ItemsMapperCustomer.xml
<!-- 提交批量修改商品信息
collection: 传入单参数的参数类型
index: 每次迭代到的位置
item: 每一个元素进行迭代时的别名
open: 以什么开始
separator: 每次进行迭代之间以什么符号作为分隔 符
close: 以什么结束
-->
<update id="updateAllItemsSubmit" parameterType="java.util.List">
update items set status =
<foreach collection="list" index="index" item="itemsList" open="case ID" separator=" " close="end">
when #{itemsList.id} then #{itemsList.status}
</foreach>
where id in
<foreach collection="list" index="index" item="itemsList" open="(" separator="," close=")">
#{itemsList.id,jdbcType=INT}
</foreach>
</update>
以上mybatis相当于如下mysql的批量更新
UPDATE xianyu2.Items
SET items_name = CASE id
WHEN 2 THEN '小米8'
WHEN 3 THEN '苹果10'
END,
items_price = CASE id
WHEN 2 THEN 3499.79
WHEN 3 THEN 5099.69
END
WHERE id IN (2,3)
ItemsMapperCustomer.java
// 一次性提交批量修改商品信息
public void updateAllItemsSubmit(List<ItemsCustomer> itemsList) throws Exception;
Map绑定(不做详细介绍,与list绑定类似)
也通过在包装pojo中定义map类型属性。
原理:在包装类中定义Map对象,并添加get/set方法,action使用包装对象接收。
包装类中定义Map对象
Public class ItemsQueryVo {
private Map<String, Object> itemInfo = new HashMap<String, Object>();
//get/set方法..
}
页面定义
<tr>
<td>学生信息:</td>
<td>
姓名:<inputtype="text"name="itemInfo['name']"/>
年龄:<inputtype="text"name="itemInfo['price']"/>
.. .. ..
</td>
</tr>
Controller
public String useraddsubmit(Model model,QueryVo queryVo)throws Exception{
System.out.println(queryVo.getStudentinfo());
}