SpringMVC——高级参数绑定(数组、集合),@RequestMapper 的使用,Controller方法的三种返回值类型,异常处理器,上传图片,JSON数据交互,配置拦截器
一.高级参数绑定
1、将前端传来的参数绑定数组/集合中
1)数组直接接收
@RequestMapping(value = "/arrayTest.action") public void arrayTest(Integer[] ids){ System.out.println(Arrays.toString(ids)); }
2)POJO中的数组接收
@RequestMapping(value = "/arrayTest.action") public void arrayTest(QueryVo vo){ System.out.println(Arrays.toString(vo.getIds())); }
3)集合直接接收(报错,无法直接接收)
@RequestMapping(value = "/arrayTest.action") public void arrayTest(List<Integer> ids){ System.out.println(ids); }
4)POJO中的集合接收
@RequestMapping(value = "/arrayTest.action") public void arrayTest(QueryVo vo){ System.out.println(vo.getIds()); }
2、将前端传来的所有参数保存到集合中
JSP页面样式
<form action="${pageContext.request.contextPath }/arrayTest.action" method="post"> 商品列表: <table width="100%" border=1> <tr> <td>选择</td> <td>商品名称</td> <td>商品价格</td> <td>生产日期</td> <td>商品描述</td> <td>操作</td> </tr> <c:forEach items="${itemList }" var="item" varStatus="s"> <tr> <td><input type="checkbox" name="ids" value="${item.id }"></td> <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> <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> </table> <input type="submit"/> </form>
QueryVO.java
public class QueryVo { List<Item> itemsList; public List<Item> getItemsList() { return itemsList; } public void setItemsList(List<Item> itemsList) { this.itemsList = itemsList; } }
测试类
@RequestMapping(value = "/arrayTest.action") public void arrayTest(QueryVo vo){ System.out.println(vo.getItemsList()); }
二.@RequestMapper
1、URL路由映射
@RequestMapping(value = "/xxx.action")
2、在类上加
// 简化请求路径 /itemList ==> /item/itemList
@RequestMapping("/item")
public class ItemsController {
3、方法限定
限定GET方法:@RequestMapping(method = RequestMethod.GET)
限定POST方法:@RequestMapping(method = RequestMethod.POST)
GET和POST都可以:@RequestMapping(method = {RequestMethod.GET,RequestMethod.POST})
4、多个URL映射到同一方法
@RequestMapping(value = "{/itemList.action,/item123.action}")
三.Controller方法返回值
1、返回ModelAndView
controller方法中定义ModelAndView对象并返回,对象中可添加model数据、指定view。(一般用于异常处理器中)
// 配置请求的url @RequestMapping(value = "/itemList.action") public ModelAndView queryItemList(){ // 创建页面需要显示的商品数据 List<Item> items = itemService.selectItemsList(); ModelAndView modelAndView = new ModelAndView(); // 放到request域中 modelAndView.addObject("itemList",items); //modelAndView.setViewName("/WEB-INF/jsp/itemList.jsp"); modelAndView.setViewName("itemList"); return modelAndView; }
2、返回String
优点:解耦,返回视图路径,model带数据,官方推荐此种方式。解耦,数据,视图,分离,MVC 。
// 配置请求的url @RequestMapping(value = "/itemList.action") public String queryItemList(Model model){ // 创建页面需要显示的商品数据 List<Item> items = itemService.selectItemsList(); // 放到request域中 model.addAttribute("itemList",items); //return "itemList"; // 直接返回一个视图文件(jsp) //return "redirect:/itemEdit.action?itemId=1"; // 重定向到其他URL return "forward: /itemEdit.action?itemId=1"; // 转发到其他URL }
3、返回Void(常用于ajax)
/ 配置请求的url @RequestMapping(value = "/itemList.action") public void queryItemList(HttpServletRequest request, HttpServletResponse response, HttpSession session, Model model,...其他自定义的类) throws ServletException, IOException { // 创建页面需要显示的商品数据 List<Item> items = itemService.selectItemsList(); request.setAttribute("itemList",items); // 请求转发 request.getRequestDispatcher("/WEB-INF/jsp/itemList.jsp").forward(request,response); }
四.异常处理器
springmvc在处理请求过程中出现异常信息交由异常处理器进行处理,自定义异常处理器可以实现一个系统的异常处理逻辑。
系统中异常包括两类:预期异常和运行时异常RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试通过手段减少运行时异常的发生。
系统的dao、service、controller出现都通过throws Exception向上抛出,最后由springmvc前端控制器交由异常处理器进行异常处理,如下图:
自定义异常处理器
1)自定义一个异常MyException.java
public class MyException extends Exception { private String msg; public MyException(String msg) { this.msg = msg; } public MyException() { } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } }
2)在程序中手动抛出这个异常
// 配置请求的url @RequestMapping(value = "/itemList.action") public void queryItemList(HttpServletRequest request, HttpServletResponse response, HttpSession session, Model model) throws Exception { if (1==1) { throw new MyException("啦啦啦"); } // 创建页面需要显示的商品数据 List<Item> items = itemService.selectItemsList(); request.setAttribute("itemList",items); // 请求转发 request.getRequestDispatcher("/WEB-INF/jsp/itemList.jsp").forward(request,response); }
3)在applicationContext.xml中配置全局异常处理器
<!-- *****************配置全局异常处理器***************** --> <bean class="cn.x5456.exception.CustomExceptionResolver"/>
4)书写异常处理器
import org.springframework.web.servlet.HandlerExceptionResolver; // 别导错包 public class CustomExceptionResolver implements HandlerExceptionResolver { @Override public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, // 发生异常的地方 Serivce层 方法 包名+类名+方法名(形参) 字符串 Exception e) { ModelAndView mav = new ModelAndView(); String msg = "未知异常"; if (e instanceof MyException){ MyException myex = (MyException) e; msg = myex.getMsg(); } mav.addObject("msg",msg); mav.setViewName("error"); return mav; } }
五.上传图片
1)配置上传文件夹的url访问路径
2)配置applicationContext.xml
<!-- *************配置文件上传的实现类,id必须设置为multipartResolver*************--> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!-- 设置文件上传大小 --> <property name="maxUploadSize" value="5000000" /> </bean>
<!-- 文件上传 --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!-- 设置上传文件的最大尺寸位30M --> <property name="maxUploadSize" value="31457280" /> <property name="defaultEncoding" value="UTF-8" /> <!-- 是否延迟加载,在需要的时候才进行上传文件的解析 --> <property name="resolveLazily" value="true" /> <!-- 文件上传的临时路径,文件上传完成后,临时目录中的临时文件会被自动清除 --> <property name="uploadTempDir" value="upload/temp" /> </bean>
3)修改form标签
<form id="itemForm" action="${pageContext.request.contextPath }/updateitem.action" method="post" enctype="multipart/form-data">
4)书写Controller
@RequestMapping(value = "/updateitem.action") public String arrayTest(Item itemPOJO, MultipartFile pictureFile) throws IOException { // 接收前端传来的pic文件对象 // 1.保存图片 // 为避免重复,使用uuid String picName = UUID.randomUUID().toString().replaceAll("-", ""); // 获取文件名的后缀 String ext = FilenameUtils.getExtension(pictureFile.getOriginalFilename()); // 保存文件 pictureFile.transferTo(new File("D:\\upload\\"+picName+"."+ext)); // 2.更新商品信息 itemPOJO.setPic(picName+"."+ext); itemService.updateItem(itemPOJO); return "redict:/itemEdit.action?id="+itemPOJO.getId(); }
六.JSON数据交互
前端
<script type="text/javascript" src="${pageContext.request.contextPath }/js/jquery-1.4.4.min.js"></script> <script type="text/javascript"> $(function () { // 不能使用 // $.post(url,params, // function(data){ // 回调 // }, // "json"); 因为这个jasn指的是响应是json格式的数据 var params = '{"id": 1,"name": "测试商品","price": 99.9,"detail": "测试商品描述","pic": "123456.jpg"}'; // 字典+引号==json字符串 $.ajax({ url : "${pageContext.request.contextPath }/json.action", data : params, contentType : "application/json;charset=UTF-8",//发送数据的格式 type : "post", dataType : "json",//回调 success : function(data){ alert(data.name); } }) }) </script>
后端
@RequestMapping(value = "/json.action") public @ResponseBody Item jsonTest(@RequestBody Item item){ System.out.println(item); return item; }
七.拦截器
Spring Web MVC 的处理器拦截器类似于Servlet 开发中的过滤器Filter,用于对处理器进行预处理和后处理。
配置拦截器
applicationContext.xml
<!-- *************配置拦截器************* --> <mvc:interceptors> <mvc:interceptor> <!-- 所有的请求都进入拦截器 --> <mvc:mapping path="/**" /> <!-- 配置具体的拦截器 --> <bean class="cn.x5456.interceptor.HandlerInterceptor1" /> </mvc:interceptor> <mvc:interceptor> <!-- 所有的请求都进入拦截器 --> <mvc:mapping path="/**" /> <!-- 配置具体的拦截器 --> <bean class="cn.x5456.interceptor.HandlerInterceptor2" /> </mvc:interceptor> </mvc:interceptors>
HandlerInterceptor1.java
package cn.x5456.interceptor; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.portlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class HandlerInterceptor1 implements HandlerInterceptor { // controller执行后且视图返回后调用此方法 // 这里可得到执行controller时的异常信息 // 这里可记录操作日志 @Override public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) throws Exception { System.out.println("HandlerInterceptor1....afterCompletion"); } // controller执行后但未返回视图前调用此方法 // 这里可在返回用户前对模型数据进行加工处理,比如这里加入公用信息以便页面显示 @Override public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, org.springframework.web.servlet.ModelAndView modelAndView) throws Exception { System.out.println("HandlerInterceptor1....postHandle"); } // Controller执行前调用此方法 // 返回true表示继续执行,返回false中止执行 // 这里可以加入登录校验、权限拦截等 @Override public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception { // 获取session // HttpSession session =request.getSession(); System.out.println("HandlerInterceptor1....preHandle"); // 设置为true,测试使用 return true; } }
结果
控制台打印:
HandlerInterceptor1..preHandle..
HandlerInterceptor2..preHandle..
HandlerInterceptor2..postHandle..
HandlerInterceptor1..postHandle..
HandlerInterceptor2..afterCompletion..
HandlerInterceptor1..afterCompletion..
处理流程
preHandle按拦截器定义顺序调用
postHandler按拦截器定义逆序调用
- postHandler在拦截器链内所有拦截器返成功调用
afterCompletion按拦截器定义逆序调用
- afterCompletion只有preHandle返回true才调用
SpringMVC与Struts2拦截器的区别
他们的拦截器都是继承servlet的filter;且都能传递了request和response作用域。spring过滤后是去找controller,struts过滤后是去struts的配置文件找action。
// 获取应用的url
request.getScheme() +"://" + request.getServerName() + ":" +request.getServerPort() +request.getContextPath();
// 获取应用的绝对路径
request.getServletContext().getRealPath("/")