知识回顾
springmvc框架
用户请求url到DispatcherServlet前端控制器,相当于中央调度器,降低系统各组件之间的耦合度。
DispatcherServlet前端控制器通过HandlerMapping处理器映射器根据url找到Handler。
DispatcherServlet前端控制器通过HandlerAdapter处理器适配器执行Handler。
DispatcherServlet前端控制器得到Handler返回的ModelAndView通过视图解析器ViewResolver进行视图解析。
视图解析:将程序中写的逻辑视图名,转成真正的视图(springmvc通过view表示各个类型不同的视图)。DispatcherServlet前端控制器调用View的渲染方法进行视图渲染(将ModelAndView中的model放到request域)
重点:SpringMVC的注解开发,企业中常用springmvc的注解开发
使用专门注解处理器映射器(RequestMappingHandlerMapping)和处理器适配器(RequestMappingHandlerAdapter)
注意:使用<mvc:annotation-driven/>可以替代上边的注解处理器映射器和注解处理器适配器的配置。
在Handler(controller)中定义很多的方法,一个方法通过@RequestMapping对url进行映射。
方法返回值:ModelAndView、String(jsp的逻辑视图名)、void(通过response将数据输出成json)。
方法输入参数(形参):springmvc需要将请求的key/value(串,id=001&id=002)、解析绑定到Handler(controller)中方法的形参上。
springmvc默认支持多类型的参数绑定。
默认支持的类型:HttpServletRequest、HttpServletResponse、HttpSession、Model(用于将数据填充到request域)。
@RequestParam注解:用于绑定单个请求参数,常用于简单类型参数(Integer、String、Float......)绑定。
不使用@ReuestParam要求请求参数的名称和方法形参名一致方可进行绑定。
对于简单类型参数中的日期型,建议使用自定义参数绑定,对日期类型数据个性化定义日期的格式。
自定义参数绑定:建议使用Converter进行参数绑定。
还可以绑定pojo、包装的pojo.
高级知识清单
注解开发:
数据回显:表单提交错误,重新回到表单,用户重新填写数据,刚才提交的参数在页面上回显。
集合类型(String[]、List<>、Map)的参数绑定
springmvc上传图片(重点)
json数据交互(提交json数据、响应json数据)(重点)
Validation(springmvc使用校验方式: 使用Hibernate Validator(和Hibernate的ORM没有任何关系) )
拦截器(用于权限控制)
数据回显
需求
表单提交出现错误,重新回到表单,用户重新填写数据,刚才提交的数据在页面上显示。
对简单类型的数据回显
对商品修改数据回显:
注意在进入修改页面的controller方法中和提交修改商品信息方法model.addAttribute方法设置key一致。
修改商品显示方法:
@RequestMapping(value="/editItems",method={RequestMethod.GET})
public String editItems(Model model,Integer id) throws Exception{
// 将id传递到页面
model.addAttribute("id",id);
// 调用Service查询商品信息
ItemsCustom itemsCustom = itemsService.findItemsById(id); //将模型数据传到jsp
model.addAttribute("item",itemsCustom);
//return "editItem_2";
return "editItem";
}
修改页面
<form id="itemForm" action="${pageContext.request.contextPath }/items/editItemSubmit.action" method="post" >
<input type="hidden" name="id" value="${id }"/>
修改商品信息:
<table width="100%" border=1>
<tr>
<td>商品名称</td>
<td><input type="text" name="name" value="${item.name }"/></td>
</tr>
......
修改商品提交方法
@RequestMapping("/editItemSubmit")
public String editItemSubmit(Model model,Integer id, ItemsCustom itemsCustom) throws Exception {
// 调用Service接口更新商品信息
itemsService.updateItems(id, itemsCustom);
// 进行数据回显
model.addAttribute("id", id);
// 提交后回到修改页面
return "editItem";
}
提交后查看网页源码
可以发现只有id回显到了修改页面
其过程原理是这样的:
第一次点击修改跳转到修改页面,从request域取值为name的id的属性赋值。
点击提交后将name的值(请求参数)提交到提交方法中为形参id赋值。
然后在提交方法内将id存入request域,再跳转到编辑页面,进行回显。
pojo数据类型回显
回显方法1:
使用model.addAttribute方法进行数据回显
@RequestMapping("/editItemSubmit")
public String editItemSubmit(Model model,Integer id, ItemsCustom itemsCustom) throws Exception {
// 调用Service接口更新商品信息
itemsService.updateItems(id, itemsCustom);
// 进行数据回显
model.addAttribute("id", id);
model.addAttribute("item",itemsCustom);
// 提交后回到修改页面
return "editItem";
}
过程就是:提交后表单数据传入到提交方法的形参id和itemsCustom中。
然后将形参存入到request域,属性命名保持与编辑页面取数据的名称一致。
跳转到编辑页面即可从request取值 进行回显。
回显方法2:
使用@ModelAttribute, 作用于将请求pojo数据放到Model中回显到页面
public String editItemSubmit(Model model,Integer id, @ModelAttribute(value="item")ItemsCustom itemsCustom) throws Exception {
在@ModelAttribute方法指定的名称就是要填充到Model中的key,在页面上就要通过key取数据。
@ModelAttribute将方法返回值传到页面
需求:商品类别信息在商品信息页面展示// 单独将商品类型的方法提出来,将方法返回值填充到request,在页面显示
@ModelAttribute("itemsType")
public Map<String, String> getItemsType() throws Exception{
HashMap<String, String> itemsType = new HashMap<String, String>();
itemsType.put("001", "数码");
itemsType.put("002", "服装");
return itemsType;
}
页面
商品类别:
<select>
<c:forEach items="${itemsType }" var="item">
<option value="${item.key }">${item.value }</option>
</c:forEach>
</select>
使用@ModelAttribute将公用的取数据的方法返回值传递到页面,不用在controller的每一个方法中通过Model将数据传到页面。
参数绑定集合类型
绑定数组
需求:在商品查询列表页面,用户选择要删除的商品,批量删除商品。
在controller方法中如何将批量提交的数据绑定成数组类型。
页面定义
<td><input type="checkbox" name="delete_id" value="${item.id }"/></td>
controller方法定义
// 删除商品
@RequestMapping("/deleteItems")
public String deleteItems(Integer[] delete_id) throws Exception{
System.out.println(delete_id);
return "success";
}
运行结果:
绑定List<Object>
先进入批量修改商品页面,填写信息,点击提交
页面定义
<c:forEach items="${itemsList }" var="item" varStatus="s">
<tr>
<td><input type="text" name="itemsList[${s.index }].name" value="${item.name }"/></td>
<td><input type="text" name="itemsList[${s.index }].price" value="${item.price }"/></td>
......
</tr>
注释:name值中的itemList
itemsList:controller方法形参包装类型中list的属性名
itemsList[0]或itemsList[0]......[]中是序号,从0开始
itemsList[index].name就是controller方法形参包装类型中list中pojo的属性名。
Controller方法定义
使用包装类型接收页面批量提交的数据,绑定成list
public class ItemsQueryVo {
// 商品信息
private ItemsCustom itemsCustom;
// 定义一个List
private List<ItemsCustom> itemsList;
......
}
使用包装类型作为形参 接收参数
// 批量修改商品提交
@RequestMapping("/editItemsListSubmit")
public String editItemsListSubmit(ItemsQueryVo itemsQueryVo){
return "success";
}
springmvc和struts的区别
SpringMVC是通过方法的形参接受参数,在使用时可以以单例方式使用,建议使用单例。
Struts是通过成员变量接收参数,在使用时必须以多例方式使用。
SpringMVC是基于方法开发,Struts是基于类开发。
SpringMVC将一个请求的Method和Handler进行关联绑定,一个method对应一个Handler。
SpringMVC开发是以方法为单位进行开发,方法更贴近Service(业务方法)。
经过实际测试,发现Struts标签解析速度比较慢,建议在实际开发中使用jstl。
商品图片上传
需求
在商品修改页面,增加图片上传的功能。
操作流程:
用户进入商品修改页面
上传图片
点击提交(提交的是图片和商品的信息)
再次进入修改页面,图片在商品修改页面展示
图片存储的问题
切记:不要将图片上传到工程目录,不方便进行工程维护。
实际电商项目中使用专门的图片服务器(比如Apache、Tomcat)
在Tomcat中进行虚拟目录的设置
设置方法如下:
<Context path="/虚拟目录名" docBase="目标目录位置" debug="0" reloadable="true" ></Context>
虚拟目录名:浏览器访问的地址
目标目录位置:项目所在目录的绝对路径
reloadable="true" :服务器配置动态加载
测试:拖进目录中一张图片,启动服务器进行测试:
注意:图片目录中尽量进行目录分级存储,提高IO的访问速度。
配置图片上传解析器
springmvc使用commons-fileupload进行图片上传
commons-fileupload对应的springmvc的图片上传解析器:org.springframework.web.multipart.commons.CommonsMultipartResolver
在springmvc.xml中配置如下:
<!-- 文件上传 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 设置上传文件的最大尺寸为5MB -->
<property name="maxUploadSize">
<value>5242880</value>
</property>
</bean>
加入commons-fileupload的jar包
编写上传图片的页面
表单属性的enctype要设置为multipart/form-data
<form id="itemForm" action="${pageContext.request.contextPath }/items/editItemSubmit.action" method="post" enctype="multipart/form-data">
添加图片上传组件<input type="file" name=""> 其中name的属性值要与控制器中接收图片的方法中的形参一致。
<td>商品图片</td>
<td>
<c:if test="${item.pic != null }">
<img src="/pic/${item.pic}" width="100px" height="100px"/>
<br/>
</c:if>
<input type="file" name="pictureFile"/>
</td>
编写控制器方法
@RequestMapping("/editItemSubmit")
// public String editItemSubmit(Integer id,ItemsCustom
// itemsCustom,ItemsQueryVo itemsQueryVo) throws Exception{
public String editItemSubmit(Model model,Integer id,
@ModelAttribute(value="item")ItemsCustom itemsCustom,
// 上传图片
MultipartFile pictureFile
) throws Exception {
// 进行数据回显
model.addAttribute("id", id);
//model.addAttribute("item",itemsCustom);
//进行图片上传
if (pictureFile!=null && pictureFile.getOriginalFilename()!=null && pictureFile.getOriginalFilename().trim().length()>0) {
// 图片上传成功后,将图片的地址写到数据库
String filePath = "/Users/liuxun/Desktop/pictures";
// 上传文件原始名称
String originFileName = pictureFile.getOriginalFilename();
// 新的图片的名称
String newFileName = UUID.randomUUID()+originFileName.substring(originFileName.lastIndexOf("."));
// 新文件
File file = new File(filePath+File.separator+newFileName);
// 将内存中的文件写入磁盘
pictureFile.transferTo(file);
// 图片上传成功,将图片地址写入数据库
itemsCustom.setPic(newFileName);
}
// 调用Service接口更新商品信息
itemsService.updateItems(id, itemsCustom);
// 提交后回到修改页面
return "editItem";
// 请求重定向
//return "redirect:queryItems.action";
// 转发
// return "forward:queryItems.action";
}
提交后页面效果如下
json数据交互
需求
json数据格式是比较简单和容易理解的,json数据格式常用于远程接口传输,http传输json数据,非常方便页面进行 提交/请求结果解析,对json数据的解析。SpringMVC解析json加入json解析包
springmvc默认采用MappingJacksonHttpMessageConverter对json数据进行转换,需要加入jackson的包如下所示:
在处理器适配器中注入MappingJacksonHttpMessageConverter
让处理器适配器支持json数据解析,需要注入MappingJacksonHttpMessageConverter
<!-- 注解适配器 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<!-- 在webBindingInitializer中注入自定义属性编辑器,自定义转换器 -->
<property name="webBindingInitializer" ref="customBinder"/>
<!-- 加入json数据的消息转换器 MappingJacksonHttpMessageConverter依赖的Jackson包 -->
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/>
</list>
</property>
</bean>
需要将支持json数据解析