SpringMVC框架笔记02

mac2022-06-30  22

目录

第1章 高级参数的绑定 1.1 参数的分类1.2 数组类型的参数的绑定1.3 集合类型的参数的绑定第2章 @RequestMapping的用法 2.1 URL路径映射2.2 请求方法限定2.3 窄化请求映射第3章 Controller方法的返回类型 3.1 返回ModelAndView3.2 返回void3.3 返回类型为String 3.3.1 逻辑视图名3.3.2 重定向3.3.3 转发第4章 文件上传【重要】 4.1 文件上传页面三要素4.2 SpringMVC上传文件注意点4.3 开始上传 4.3.1 场景设计4.3.2 导入文件上传的jar包4.3.3 修改页面的jsp代码4.3.4 配置文件 解析器4.3.5 编写Controller修改商品的方法,其中包括文件上传4.3.6 测试4.3.7 注意第5章 异常处理器 5.1 异常处理的思路5.2 自定义异常处理器的举例 5.2.1 场景描述5.2.2 自定义异常处理器5.2.3 编写错误页面5.2.4 配置异常处理器5.2.5 模拟异常5.2.6 测试第6章 JSON数据交互 6.1 场景设计6.2 在修改页面引入JS支持6.3 修改提交方式6.4 编写save函数和ajax代码6.5 在Controller中编写updateitemAjax方法6.6 测试第7章 RESTful支持 7.1 什么是restful风格7.2 案例:实现对商品访问页的restful风格支持 7.2.1 实现思路7.2.2 修改前端控制器配置7.2.3 修改Controller方法的@RequestMapping:URL模板映射7.2.4 处理静态资源访问第8章 拦截器 8.1 SpringMVC的拦截器8.2 拦截器的定义8.3 拦截器配置 8.3.1 针对所有mapping配置全局拦截器8.3.2 针对某种mapping配置拦截器8.4 测试8.5 拦截器的应用 8.5.1 用户身份认证8.5.2 用户登录Controller

第1章 高级参数的绑定

1.1 参数的分类

默认参数绑定:request、response、session、model基础数据类型POJO自定义参数绑定【比如定义转换器Converter】包装的POJO数组:可以绑定到形参上,可以绑定到包装的POJO中集合:只能保定在包装的POJO上

1.2 数组类型的参数的绑定

场景描述:在商品列表页选中多个商品,然后删除。

需求分析:此功能要求列表页中的每个商品前有一个checkbox,选中多个商品点击删除按钮,把此商品的id传递给Controller,根据商品的id删除商品信息。

JSP中的实现

程序运行后生成的html代码如下:

Controller方法中可以使用String[]接收,或者pojo的String[]属性接收。两种方式任选一种即可。方式一:直接绑定到形参上 @RequestMapping("/queryitem") public String queryItem(QueryVo queryVo, String[] ids) { System.out.println(queryVo.getItems().getName()); System.out.println(queryVo.getItems().getPrice()); System.out.println(ids.toString()); return null; } 方式二:绑定到包装的pojo中

查看结果

1.3 集合类型的参数的绑定

场景描述:实现商品数据的批量修改。需求分析:要想实现商品数据的批量删除,需要在商品列表中可以对商品进行修改,并且可以批量提交修改后的商品数据。这时需要将表单的数据绑定到List。List中存放对象,并将定义的List放在包装类中,使用包装的pojo对象接收。接收商品列表的pojo如下:

JSP改造

Name属性必须是包装pojo的list属性+下标+元素属性。Jsp做如下改造:

varStatus属性常用参数总结下: ${status.index}      输出行号,从0开始。 ${status.count}      输出行号,从1开始。 ${status.current}   当前这次迭代的(集合中的)项 ${status.first}  判断当前项是否为集合中的第一项,返回值为true或false ${status.last}   判断当前项是否为集合中的最后一项,返回值为true或false begin、end、step分别表示:起始序号,结束序号,跳跃步伐。 Controller @RequestMapping("/queryitem") public String queryItem(QueryVo queryVo, String[] ids) { System.out.println(queryVo.getItems().getName()); System.out.println(queryVo.getItems().getPrice()); System.out.println(ids.toString()); return null; } 接收List类型的数据必须是pojo的属性,方法的形参为List类型无法正确接收到数据。

第2章 @RequestMapping的用法

value={"/list","/list2","/itemList"}多个请求地址可以同时指向同一个方法method=RequestMethod.GET限制请求方式@RequestMapping可以写到Controller上 ,窄化请求映射

2.1 URL路径映射

@RequestMapping(value="/item")或@RequestMapping("/item)。value的值是数组,可以将多个url映射到同一个方法。例如:

2.2 请求方法限定

限定GET方式请求:只能以GET方式访问才能通过 @RequestMapping(method = RequestMethod.GET) //如果通过Post访问则报错: //HTTP Status 405 - Request method 'POST' not supported //例如: @RequestMapping(value="/editItem",method=RequestMethod.GET) 限定POST方法 @RequestMapping(method = RequestMethod.POST) GET和POST都可以都可以访问 @RequestMapping(method={RequestMethod.GET,RequestMethod.POST})

2.3 窄化请求映射

在class上添加@RequestMapping(url)指定通用请求前缀, 限制此类下的所有方法请求url必须以请求前缀开头,通过此方法对url进行分类管理。例如: @Controller @RequestMapping("/items/") public class ItemsController { @Autowired private ItemService itemService ; @RequestMapping(value={"/list","/list2","/itemList"},method={RequestMethod.GET,RequestMethod.POST}) public ModelAndView showList(QueryVo queryVo,int[] ids){ List<Items> list = itemService.findAll(); ModelAndView modelAndView = new ModelAndView(); modelAndView.addObject("itemList", list); modelAndView.setViewName("itemList"); return modelAndView; } 访问的地址为:/items/list

第3章 Controller方法的返回类型

Controller方法的返回值类型有三种: ModelAndViewStringvoid

3.1 返回ModelAndView

controller方法中定义ModelAndView对象并返回,对象中可添加model数据、指定view。

3.2 返回void

当Controller方法的返回值类型为void时,可以在controller方法形参上定义request和response,使用request和response指定响应结果。使用request转向页面: request.getRequestDispatcher("页面路径").forward(request, response); 使用response页面重定向 response.sendRedirect("url")

3.3 返回类型为String

3.3.1 逻辑视图名

controller方法返回字符串可以指定逻辑视图名,通过视图解析器解析为物理视图地址。 //指定逻辑视图名,经过视图解析器解析为jsp物理路径: /WEB-INF/jsp/item/editItem.jsp return "item/editItem";

3.3.2 重定向

Contrller方法返回结果重定向到一个url地址,如下商品修改提交后重定向到商品查询方法,参数无法带到商品查询方法中。 //重定向到list.action地址,request无法带过去 return "redirect:list.action";

redirect方式相当于response.sendRedirect(),转发后浏览器的地址栏变为重定向后的地址,因为重定向即执行了一个新的request和response。

由于新发起一个request原来的参数在转发时就不能传递到下一个url,如果要传参数可以/item/list.action后边加参数,如下:

/item/list?...&…..

3.3.3 转发

controller方法执行后继续执行另一个controller方法,如下商品修改提交后转向到商品修改页面,修改商品的id参数可以带到商品修改方法中。 //结果转发到editItem.action,request可以带过去 return "forward:editItem.action"; forward方式相当于request.getRequestDispatcher().forward(request,response),转发后浏览器地址栏还是原来的地址。转发并没有执行新的request和response,而是和转发前的请求共用一个request和response。所以转发前请求的参数在转发后仍然可以读取到。

第4章 文件上传【重要】

4.1 文件上传页面三要素

表单的提交方式method一定是post表单enctype的值一定是multipart/form-data文件上传项input的类型一定是file

4.2 SpringMVC上传文件注意点

需要添加两个jar:commons-io.jar和commons-fileupload.jar。在SpringMVC容器中配置文件解析器绑定参数类型是MultipartFile,参数的名称要和页面input属性值保持一致。

4.3 开始上传

4.3.1 场景设计

在商品展示页面单击修改按钮后跳转到修改页面

修改页面

4.3.2 导入文件上传的jar包

4.3.3 修改页面的jsp代码

WebContent/jsp/editItem.jsp <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>修改商品信息</title> </head> <body> <!-- 上传图片是需要指定属性 enctype="multipart/form-data" --> <!-- <form id="itemForm" action="" method="post" enctype="multipart/form-data"> --> <form id="itemForm" action="${pageContext.request.contextPath }/updateitem.action" enctype="multipart/form-data" method="post"> <input type="hidden" name="id" value="${item.id }" /> 修改商品信息: <table width="100%" border=1> <tr> <td>商品名称</td> <td><input type="text" name="name" value="${item.name }" /></td> </tr> <tr> <td>商品价格</td> <td><input type="text" name="price" value="${item.price }" /></td> </tr> <%-- <tr> <td>商品生产日期</td> <td><input type="text" name="createtime" value="<fmt:formatDate value="${item.createtime}" pattern="yyyy-MM-dd HH:mm:ss"/>" /></td> </tr> --%> <tr> <td>商品图片</td> <td> <c:if test="${item.pic !=null}"> <img src="/pic/${item.pic}" width=100 height=100/> <br/> </c:if> <input type="file" name="pictureFile"/> </td> </tr> <tr> <td>商品简介</td> <td><textarea rows="3" cols="30" name="detail">${item.detail }</textarea> </td> </tr> <tr> <td colspan="2" align="center"><input type="submit" value="提交" /> </td> </tr> </table> </form> </body> </html>

4.3.4 配置文件 解析器

在springmvc.xml中添加如下配置: <!-- 文件上传 --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!-- 设置上传文件的最大尺寸为5MB --> <property name="maxUploadSize"> <value>5242880</value> </property> </bean>

4.3.5 编写Controller修改商品的方法,其中包括文件上传

// 商品修改 @RequestMapping("updateitem") public String updateitem(Items item, MultipartFile pictureFile, Model model) throws IllegalStateException, IOException { // 获取上传文件的完整名称(带扩展名) String originalFilename = pictureFile.getOriginalFilename(); String fileName = UUID.randomUUID().toString(); // 创建一个随机数,作为即将保存图片的名字 // 获取文件的扩展名 String ext = originalFilename.substring(originalFilename.lastIndexOf(".")); pictureFile.transferTo(new File("d:\\upload\\"+fileName+ext)); // 文件保存 item.setPic(fileName+ext); itemService.update(item); return "redirect:list.action"; }

4.3.6 测试

在修改页面填写修改信息,点击提交后页面跳转到商品展示页。上传的图片保存到了磁盘上,数据库中对应的记录更新。

4.3.7 注意

file的name与controller的形参保持一致form添加enctype="multipart/form-data"文件上传的目录需要提前创建好需要在springmvc.xml中配置文件解析器

第5章 异常处理器

5.1 异常处理的思路

Web工程中一般都是三层结构,如果系统中无论那一层发送异常都可以直接向上抛出,而不用处理。如下图所示,系统的dao、service、controller出现异常后都通过throws Exception向上抛出,最后由springmvc前端控制器交由异常处理器进行异常处理。

5.2 自定义异常处理器的举例

5.2.1 场景描述

在商品展示修改页面,当用户访问到id不存在的路径时出现异常。

5.2.2 自定义异常处理器

com.itzhouq.ssm.exception.MyHandlerExceptionResolver package com.itzhouq.ssm.exception; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.HandlerExceptionResolver; import org.springframework.web.servlet.ModelAndView; /** * 自定义异常处理器 * @author itzhouq * */ public class MyHandlerExceptionResolver implements HandlerExceptionResolver { @Override public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object method, Exception exception) { // 跳转到错误页面 ModelAndView modelAndView = new ModelAndView(); modelAndView.addObject("errorMessage", exception.getMessage()); modelAndView.setViewName("error"); return modelAndView; } }

5.2.3 编写错误页面

WebContent/jsp/error.jsp <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <h1>由于您的操作造成系统异常,错误信息如下,请转告开发工程师:<br/></h1> ${errorMessage } </body> </html>

5.2.4 配置异常处理器

在springmvc.xml中添加以下配置: <!-- 异常处理器 --> <bean id="handlerExceptionResolver" class="com.itzhouq.ssm.exception.MyHandlerExceptionResolver"/>

5.2.5 模拟异常

com.itzhouq.ssm.controller.ItemsController // 展示修改页面 @RequestMapping("/itemEdit") public String itemEdit(@RequestParam(value="id",required=false,defaultValue="1")int itemId,HttpServletRequest request, HttpServletResponse response,Model model){ Items items = itemService.findById(itemId); // 模拟异常 if(items == null) { int i = 1 / 0; } model.addAttribute("item", items); // 逻辑视图:jsp的路径 return "editItem"; }

5.2.6 测试

访问http://localhost/Spring-mybatis-test/itemEdit.action?id=9,id=9是不存在的。

第6章 JSON数据交互

6.1 场景设计

商品修改页面,修改商品信息后,如果需要使用Ajax的异步提交方式,需要和json交互。

6.2 在修改页面引入JS支持

在WebContent/jsp/editItem.jsp引入js <script type="text/javascript" src="${pageContext.request.contextPath }/js/jquery-1.4.4.min.js"></script>

6.3 修改提交方式

<input type="button" onclick="save()" value="提交" />

6.4 编写save函数和ajax代码

$("#itemForm").serialize()可以将表单数据序列化,将数据封装成对象 <script type="text/javascript"> function save(){ // ajax异步提交 // alert($("#itemForm").serialize()); $.ajax({ url:'${pageContext.request.contextPath }/updateitemAjax.action', type:'post', data:$("#itemForm").serialize(), dataType:'json', success:function(data){ // data :{"success":true|false,"message":"操作成功"|“操作失败”} if(data.success){ location.href="${pageContext.request.contextPath }/list.action"; }else{ alert(data.message); } } }) } </script>

6.5 在Controller中编写updateitemAjax方法

// 使用Ajax异步提交方式的修改 @RequestMapping("/updateitemAjax") @ResponseBody // 作用:把即将返回的对象转化json字符串并且写道浏览器 public Map updateitemAjax(Items item) { // data :{"success":true|false,"message":"操作成功"|“操作失败”} Map<String,Object> map = new HashMap<String,Object>(); try { itemService.update(item); map.put("success", true); map.put("message", "操作成功"); } catch (Exception e) { map.put("success", false); map.put("message", "操作失败"); // e.printStackTrace(); } return map; } @ResponseBody // 作用:把即将返回的对象转化json字符串并且写道浏览器,这个注解需要引入jar包

6.6 测试

访问http://localhost/Spring-mybatis-test/list.action点击修改按钮后,修改信息,提交后页面跳转,后台数据map中保存了信息{success=true, message=操作成功}。

第7章 RESTful支持

7.1 什么是restful风格

Restful就是一个资源定位及资源操作的风格。不是标准也不是协议,只是一种风格,是对hhtp协议的诠释。可以简单理解为精简的url地址:比如http://localhost/Spring-mybatis-test/itemEdit.action?id=2可以访问商品修改页,我现在想让访问的路径精简为http://localhost/Spring-mybatis-test/itemEdit/2。

7.2 案例:实现对商品访问页的restful风格支持

7.2.1 实现思路

修改web.xml中前端控制器<url-pattern>/</url-pattern>的配置修改方法的@RequestMapping处理静态资源

7.2.2 修改前端控制器配置

之前的前端控制器的配置如下: <!-- 前端控制器 --> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>*.action</url-pattern> </servlet-mapping> 也就说请求的url必须是*.action这样的格式,才会进入前端控制器。需要修改为: <servlet-mapping> <servlet-name>springmvc</servlet-name> <!-- / 不包含jsp --> <!-- /* 包含jsp --> <url-pattern>/</url-pattern> </servlet-mapping>

7.2.3 修改Controller方法的@RequestMapping:URL模板映射

com.itzhouq.ssm.controller.ItemsController // 展示修改页面 @RequestMapping("/itemEdit/{id}") public String itemEdit(@PathVariable("id")int itemId,HttpServletRequest request, HttpServletResponse response,Model model){ Items items = itemService.findById(itemId); model.addAttribute("item", items); // 逻辑视图:jsp的路径 return "editItem"; } 到了这一步就可以通过精简的路径访问了。

但是控制台提示找不到js。这是由于我们配置前端控制的时候<url-pattern>/</url-pattern>使用的是/,也就是除jsp外的所有请求都会进入springmvc容器中,进而去控制器中寻找响应的方法,但是没有方法映射静态资源,所以就报404。所以现在要处理静态资源,让静态资源去Webcontent下寻找资源而不是进入springmvc容器中。

7.2.4 处理静态资源访问

在springmvc.xml中配置 <!-- 配置静态资源 --> <!-- location:请求地址 mapping:映射的位置 --> <mvc:resources location="/js/" mapping="/js/**"></mvc:resources>

第8章 拦截器

8.1 SpringMVC的拦截器

SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。

8.2 拦截器的定义

定义拦截器要实现接口HandlerInterceptor

com.itzhouq.ssm.interceptor.MyHandlerInterceptor1

public class MyHandlerInterceptor1 implements HandlerInterceptor { /** * controller执行前调用此方法 * 返回true表示继续执行,返回false中止执行 * 这里可以加入登录校验、权限拦截等 */ @Override public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception { System.out.println("执行了MyHandlerInterceptor1的前置方法"); return true; } /** * controller执行后但未返回视图前调用此方法 * 这里可在返回用户前对模型数据进行加工处理,比如这里加入公用信息以便页面显示 */ @Override public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3) throws Exception { System.out.println("执行了MyHandlerInterceptor1的执行方法"); } /** * controller执行后且视图返回后调用此方法 * 这里可得到执行controller时的异常信息 * 这里可记录操作日志,资源清理等 */ @Override public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) throws Exception { System.out.println("执行了MyHandlerInterceptor1的后置方法"); } } com.itzhouq.ssm.interceptor.MyHandlerInterceptor2 public class MyHandlerInterceptor2 implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception { System.out.println("执行了MyHandlerInterceptor2的前置方法"); return true; } @Override public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3) throws Exception { System.out.println("执行了MyHandlerInterceptor2的执行方法"); } @Override public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) throws Exception { System.out.println("执行了MyHandlerInterceptor2的后置方法"); } }

8.3 拦截器配置

8.3.1 针对所有mapping配置全局拦截器

在springmvc.xml中添加配置 <!-- 针对所有mapping配置全局拦截器 /**表示所有的拦截器都可以进入 --> <mvc:interceptors> <!-- 多个拦截器按照顺序执行 --> <mvc:interceptor> <mvc:mapping path="/**"/> <bean class="com.itzhouq.ssm.interceptor.MyHandlerInterceptor1"/> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/**"/> <bean class="com.itzhouq.ssm.interceptor.MyHandlerInterceptor2"/> </mvc:interceptor> </mvc:interceptors>

8.3.2 针对某种mapping配置拦截器

参考代码 <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"> <property name="interceptors"> <list> <ref bean="handlerInterceptor1"/> <ref bean="handlerInterceptor2"/> </list> </property> </bean> <bean id="handlerInterceptor1" class="springmvc.intercapter.HandlerInterceptor1"/> <bean id="handlerInterceptor2" class="springmvc.intercapter.HandlerInterceptor2"/>

8.4 测试

访问http://localhost/Spring-mybatis-test/itemEdit/2,查看后台拦截器的执行顺序 执行了MyHandlerInterceptor1的前置方法 执行了MyHandlerInterceptor2的前置方法 执行了MyHandlerInterceptor2的执行方法 执行了MyHandlerInterceptor1的执行方法 执行了MyHandlerInterceptor2的后置方法 执行了MyHandlerInterceptor1的后置方法 总结: preHandle按拦截器定义顺序调用 postHandler按拦截器定义逆序调用 afterCompletion按拦截器定义逆序调用 postHandler在拦截器链内所有拦截器返成功调用 afterCompletion只有preHandle返回true才调用

8.5 拦截器的应用

8.5.1 用户身份认证

Public class LoginInterceptor implements HandlerInterceptor{ @Override Public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //如果是登录页面则放行 if(request.getRequestURI().indexOf("login.action")>=0){ return true; } HttpSession session = request.getSession(); //如果用户已登录也放行 if(session.getAttribute("user")!=null){ return true; } //用户没有登录挑战到登录页面 request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response); return false; } }

8.5.2 用户登录Controller

//登陆页面 @RequestMapping("/login") public String login(Model model)throws Exception{ return "login"; } //登陆提交 //userid:用户账号,pwd:密码 @RequestMapping("/loginsubmit") public String loginsubmit(HttpSession session,String userid,String pwd)throws Exception{ //向session记录用户身份信息 session.setAttribute("activeUser", userid); return "redirect:item/queryItem.action"; } //退出 @RequestMapping("/logout") public String logout(HttpSession session)throws Exception{ //session过期 session.invalidate(); return "redirect:item/queryItem.action"; }

转载于:https://www.cnblogs.com/itzhouq/p/springmvc2.html

最新回复(0)