1. 程式人生 > >ssm引數繫結(簡單,陣列,list,map)

ssm引數繫結(簡單,陣列,list,map)

什麼是引數繫結 ?

在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。

定義陣列有兩種方式(下文采用第二種)

  1. 在Controller方法定義形參, 不使用@RequestParam簡單繫結獲得ids
  2. 在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;

實現方式可以分為兩種(建議後者)

  1.  逐一刪除數組裡的商品資訊(不斷請求資料庫)
  2.  一次刪除數組裡的商品資訊,需要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方法中。

原理:

  1. 進入批量商品修改頁面(頁面樣式參考商品列表實現)
  2. 批量修改商品提交,使用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>

實現方式可以分為兩種(建議後者)

  1.  逐條提交批量修改商品資訊(不斷請求資料庫)
  2.  一次性提交批量修改商品資訊,需要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());
}