引入:在实际开发中,控制层需要接收从浏览器提交的数据,通过该数据调用服务层去处理。那么,其是如何实现的呢?
1.SrpingMvc的参数绑定
理解:当浏览器选择提交(GET/POST等)方式,究竟提交的是哪些东西?
1)GET方式提交
GET /day09/testMethod.html?name=eric&password=123456 HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-cn,en-us;q=0.8,zh;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://localhost:8080/day09/testMethod.html
Connection: keep-alive
- a)地址栏(URI)会跟上参数数据。以?开头,多个参数之间以&分割。
- b)GET提交参数数据有限制,不超过1KB。
- c)GET方式不适合提交敏感密码。
- d)注意: 浏览器直接访问的请求,默认提交方式是GET方式
2)POST方式提交
POST /day09/testMethod.html HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-cn,en-us;q=0.8,zh;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://localhost:8080/day09/testMethod.html
Connection: keep-alive
name=eric&password=123456
- a)参数不会跟着URI后面。参数而是跟在请求的实体内容中。没有?开头,多个参数之间以&分割。
- b)POST提交的参数数据没有限制。
- c)POST方式提交敏感数据。
1.1基本参数类型(int,double,Integer,String…)
1.可以使用request获取参数
- View对象可以使用String返回值代替
- 【ModelMap:使用效果与Model相同,是Model接口的实现类,如果使用的是Model,springmvc会将其实例化】
- 【不管是Model还是ModelAndView,其本质都是使用Request对象向jsp传递数据】
@RequestMapping("itemEdit")
public String queryItemById(HttpServletRequest request,Model model){
Integer id = Integer.parseInt(request.getParameter("id"));
Item item = itemService.queryItemById(id);
//将商品数据放在模型中
model.addAttribute("item", item);
//要返回的视图对象(返回到哪一个jsp页面)
return "itemEdit";
}
但是我们一直使用request获取麻烦了,当请求参数名称与处理器形参参数名称一致时,将会请求参数进行绑定
- (参数绑定)接收简单的参数传递(每次都从Request获取比较麻烦)
- 其他基本类型 String Integer Double Float。。
- 说明:对于布尔类型的参数,请求的参数值为true或false。或者1/0
- 请求url:
http://localhost:8080/xxx.action?id=2&status=false
- 处理器方法:
public String editItem(Model model,Integer id,Boolean status)
- 【注:必须要求处理器形参与表单中的提交name字段名称相同】后面介绍不同如何处理
@RequestMapping("itemEdit")
public String queryItemById(int id,Model model){
Item item = itemService.queryItemById(id);
//将商品数据放在模型中
model.addAttribute("item", item);
//要返回的视图对象(返回到哪一个jsp页面)
return "itemEdit";
}
那么问题来了,当我们处理器形参参数与请求参数不一致时咋办呢?
- @RequestParam
- value:参数名字,需要与表单提交的名字相同
<a href="${pageContext.request.contextPath }/itemEdit.action?id123=${item.id}">
- required:默认true,Request请求中一定要有相应的参数,找不到将报错400
- defaultValue:默认值,如果找不到给其一个默认值
@RequestMapping("itemEdit")
public String queryItemById(@RequestParam(value="id123",required=true,defaultValue="1")int ids,Model model){
Item item = itemService.queryItemById(ids);
//将商品数据放在模型中
model.addAttribute("item", item);
//要返回的视图对象(返回到哪一个jsp页面)
return "itemEdit";
}
1.2 POJO类型(对象类型)
如果我们一次性提交的参数很多,我们可以使用一个对象来接收
要求:pojo对象的属性名与表单中的input的name一致
- 需求:将页面修改后的商品保存在数据库中
- 请求url:/updateItem.action
- 响应内容:给一个更新成功的提示
@RequestMapping("/updateItem.action")
public String queryItemById(Model model,Item item){
itemService.update(item);
//将商品数据放在模型中
model.addAttribute("item", item);
//返回一个成功的信息
model.addAttribute("msg", "商品信息更新成功");
//要返回的视图对象(返回到哪一个jsp页面)
return "itemEdit";
}
1.3封装的POJO(自定义实体类)
封装类:
public class QueryVo {
private Item item;
private String message;
private List<Item> items;
.
.
.get/set方法...
- 通过成员.属性来访问
- 需要更改表单的传递形式
@RequestMapping("/queryItem")
public String queryItem(Model model,QueryVo item){
//直接输出返回的封装对象的值
System.out.println(item.getItem().getName());
System.out.println(item.getItem().getPrice());
System.out.println(item.getMessage());
List<Item> list = itemService.queryItemList();
model.addAttribute("itemList", list);
return "itemList";
}
对应的表单:
<c:forEach items="${itemList }" var="item">
<tr>
<td>${item.name }</td>
<td>${item.price }</td>
<td><fmt:formatDate value="${item.createtime}"pattern="yyyy-MM-dd HH:mm:ss" /></td>
<td>${item.detail }</td>
<td><a href="${pageContext.request.contextPath }/itemEdit.action?id=${item.id}">修改</a></td>
</tr>
</c:forEach>
1.4数组
情景:列表中每个商品前有一个checkbook,选中多个商品后点击删除按钮,把商品id传递给Controller,得到一个ids[]
- 可以直接接收或使用pojo属性接收,前者相当于是用一个数组接收了多个ids(JSP里的name属性),后者是直接对应pojo的属性
@RequestMapping("/queryItem")
public String queryItem(Model model,int[]ids,QueryVo vo){
if(vo.getItem()!=null){
System.out.println(vo);
}
//问题:checkbox如果不选,则返回空指针异常,不知道咋整
//直接输出返回的封装对象的值
if(ids.length>0 && ids!=null){
for (Integer integer : ids) {
System.out.println(integer);
}
}
List<Item> list = itemService.queryItemList();
model.addAttribute("itemList", list);
return "itemList";
}
1.5List、Map类型
场景需求:在类表中实现批量修改提交后的商品数据
- 定义pojo
public class QueryVo {
private Item item;
private String message;
private List<Item> items;
...
- 修改jsp
name属性必须是list属性名+下表+元素属性
注:此处日期类型无妨自动绑定,需要自定义参数绑定日期类型
<c:forEach items="${itemList }" var="item" varStatus="s">
<tr>
<td><input type="checkbox" name="ids" value="${item.id }" /></td>
<td><input type="text" name="items[${s.index}].name"value="${item.name }" /></td>
<td><input type="text" name="items[${s.index}].price" value="${item.price }" /></td>
<td><input type="text" name="items[${s.index}].createtime"value='<fmt:formatDate value="${item.createtime}" pattern="yyyy-MM-dd HH:mm:ss" />' /></td>
<td><input type="text" name="items[${s.index}].detail" value="${item.detail }" /></td>
<td><a href="${pageContext.request.contextPath }/itemEdit.action?id=${item.id}">修改</a></td>
</tr>
</c:forEach>
返回的是一个List的集合,在jsp显示中,需要先将单个对象取出,故需要加下标访问。
@RequestMapping(value="/queryItem",method={RequestMethod.POST})
public String queryItem(Model model,QueryVo vo){
List<Item> items = vo.getItems();
//注意:如果进行更新操作,那么需要更改jsp,把id传给vo中的item,不然没有主键无法更新
for (Item item : items) {
itemService.update(item);
System.out.println(item);
}
List<Item> itemList = itemService.queryItemList();
model.addAttribute("itemList", itemList);
//这个return是跳转到/WEB-INF/下面的jsp页面,而不是跳转到控制器的URL因是个很
return "itemList";
}
2.@RequestMapping
作用:通过@RequestMapping注解可以定义不同的处理器映射规则
- URL路径映射
value的值是数组,将多个url映射到同一个方法上
@RequestMapping(value={"/itemList","/itemList2"})
- 添加在类上
作用:指定通用请求前缀,可对url进行分类管理
此时访问地址为:http://localhost:8080/item/itemList.action
@RequestMapping("/item")
public class ItemController {
//绑定请求地址
@RequestMapping(value={"/itemList","/itemList2"})
public ModelAndView queryItemList(){
- 限定请求方法
@RequestMapping(value="/queryItem",method={RequestMethod.POST})
3.Controller的返回值
3.1返回ModelAndView
@RequestMapping("/itemList")
public ModelAndView queryItemList(){
List<Item> list = itemService.queryItemList();
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("itemList",list);
//设置逻辑视图,告诉要返回到哪一个jsp
modelAndView.setViewName("itemList");
return modelAndView;
}
3.2返回void
- request
不经过视图解析器的,返回路径必须是全路径
@RequestMapping("/itemReturn1")
public void MyReturn1(HttpServletRequest request,HttpServletResponse response) throws Exception{
//通过request请求转发,不会改变URL的地址栏
request.getRequestDispatcher("/WEB-INF/jsp/itemList.jsp").forward(request, response);
}
-
response
- 通过response请求重定向
- 【注:】response.sendRedirect("");
- 参数是URL,即浏览器中的地址
response是响应,而Model返回,经过视图解析器,springmvc已经帮我们解码了,区别:一个是直接找到jsp,另外一个是找到一个控制类/
@RequestMapping("/itemReturn1")
public void MyReturn1(HttpServletRequest request,HttpServletResponse response) throws Exception{
response.sendRedirect("/itemList.action");
}
3.3返回String
- 返回视图名字(逻辑视图名)
返回的通过视图解析器解析为物理视图地址
/WEB-INF/jsp/itemList.jsp
return “itemList”
-
- Model传递数据(向jsp)
- View对象可以使用String返回值代替
- ModelMap:使用效果与Model相同,是Model接口的实现类,如果使用的是Model,springmvc会将其实例化
- 不管是Model还是ModelAndView,其本质都是使用Request对象向jsp传递数据】
@RequestMapping("itemEdit")
public String queryItemById(HttpServletRequest request,Model model){
Integer id = Integer.parseInt(request.getParameter("id"));
Item item = itemService.queryItemById(id);
//将商品数据放在模型中
model.addAttribute("item", item);
//要返回的视图对象(返回到哪一个jsp页面)
return "itemEdit";
}
- redirect与forward
实现从一个控制器跳转到另外一个控制器
@RequestMapping("/itemReturn2")
public String MyReturn2(){
//相当于走的视图解析器,直接访问jsp页面
//return "itemList";
//相当于走的视图解析器,直接访问jsp页面
//return "forward:/WEB-INF/jsp/itemList.jsp";
/**
* 这种形式是直接跳转到另外控制器Controller
*/
return "forward:/itemList2.action";//请求地址不会变
//return "redirect:/itemList2.action";
}