SpringMVC笔记
SpringMVC重要组件
-
DispatcherServlet:前端控制器,用于接收所有请求,整个流程控制的中心,控制其它组件执行,统一调度,降低组件之间的耦合性,提高每个组件的扩展性。
-
HandlerMapping:解析请求格式的.判断希望要执行哪个具体的方法
-
HandlerAdapter:负责调用具体的方法.
-
ViewResovler:视图解析器.解析结果,准备跳转到具体的物理视图
SpringMVC 运行原理图
Spring 容器和 SpringMVC 容器的关系
Spring 容器和 SpringMVC 容器是父子容器,SpringMVC 容器中能够调用 Spring 容器的所有内容
在 web.xml 中配置前端控制器 DispatcherServlet
<!--由tomcat实例化springMVC拦截器 load-on-startup为1时启动即实例化 否则请求时候才进行实例化--> <servlet> <servlet-name>Spring</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-mvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Spring</servlet-name> <!--为/而不是/*--> <url-pattern>/</url-pattern> </servlet-mapping>
注释:如果不配置会在/WEB-INF/(servlet-name)-servlet.xml
在 src 下新建 springmvc.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!-- 默认的注解映射的支持,自动注册DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter --> <mvc:annotation-driven/> <!-- 自动扫描注解的controller包名 --> <context:component-scan base-package="com.ym.*"/> <!-- 视图解释类 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/jsp/"/> <property name="suffix" value=".jsp"/> </bean> <mvc:resources mapping="/image/**" location="/image/"/> <mvc:resources mapping="/css/**" location="/css/"/> <mvc:resources mapping="/js/**" location="/js/"/> </beans>
编写控制器类
@Controller public class myController { @RequestMapping("demo") public String demo(HttpServletRequest req, HttpServletResponse resp) throws UnsupportedEncodingException { System.out.println("开始"); return "index"; } @RequestMapping("demo1") public String demo1(int id,String name){ System.out.println("开始"+id+" "+name); return "main"; } }
字符编码过滤器
在 web.xml 中配置 Filter
<!--字符编码过滤器--> <filter> <filter-name>encoding</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>encoding</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
传递参数
- 把内容写到方法(HandlerMethod)参数中,SpringMVC 只要有这个内 容,注入内容.
- 基本数据类型参数,默认保证参数名称和请求中传递的参数名相同
- 如果请求参数名和方法参数名不对应使用@RequestParam()赋值
@RequestMapping("demo1") public String demo1(@RequestParam("id1") int id,@RequestParam("name1") String name){ System.out.println("开始"+id+" "+name); return "main"; }
- 如果方法参数是基本数据类型(不是封装类)可以通过 @RequestParam 设置默认值.防止没有参数的时候报错500
@RequestMapping("demo1") public String demo1(@RequestParam(defaultValue = "1" ,name="id1") int id,@RequestParam(defaultValue = "1",name="name1") String name){ System.out.println("开始"+id+" "+name); return "main"; }
- 如果强制要求必须有某个参数
@RequestMapping("demo2") public String demo2(@RequestParam(required=true) String name){ System.out.println("name 是 SQL 的查询条件,必须要传递 name 参数"+name); return "main"; }
- HandlerMethod 中参数是对象类型
@RequestMapping("demo2") public String demo2(People people,int id,String name){ System.out.println("开始"+people+" "+id+" "+name); return "main"; }
- 请求参数中包含多个同名参数的获取方式,复选框传递的参数就是多个同名参数
@RequestMapping("demo5") public String demo5(@RequestParam("hover")List<String> abc){ System.out.println(abc); return "main"; }
- 请求参数中对象.属性格式,在对象外面在封装一层对象,并且传递参数为外层新封装的对象
- restful 传值方式.简化 jsp 中参数编写格式,在 jsp 中设定特定的格式
<a href="/demo4/12/1212">restful测试</a>
@RequestMapping("demo4/{id}/{name}") public String demo3(@PathVariable int id,@PathVariable String name){ System.out.println("开始"+id+" "+name); return "main"; }
跳转方式
默认跳转方式为请求转发
设置返回值字符串内容,以改变跳转方式
添加forward:或者不添加 为请求转发-- 携带数据
添加redirect: 为重定向
视图解析器
SpringMVC 会提供默认视图解析器
自定义视图解析器
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/jsp/"/> <property name="suffix" value=".jsp"/> </bean>
如果希望不执行自定义视图解析器,在方法返回值前面添加 forward:或 redirect:
@ResponseBody
在方法上只有@RequestMapping 时,无论方法返回值是什么认为需 要跳转
在方法上添加@ResponseBody(恒不跳转)---依赖Jackson
如果返回值满足 key-value 形式(对象或 map)把响应头设置为 application/json;charset=utf-8 把转换后的内容输出流的形式响应给客户端.
如果返回值不满足 key-value,例如返回值为 String 把相应头设置为 text/html 把方法返回值以流的形式直接输出
如果返回值包含中文,出现中文乱码 produces 表示响应头中 Content-Type 取值 @RequestMapping(value="demo12",produces="text/html; charset=utf-8")
JSP九大内置对象四大作用域
名称 | 类型 | 含义 | 获取方式 |
request | HttpServletRequest | 封装所有请求信息 | 方法参数 |
response | HttpServletResponse | 封装所有响应信息 | 方法参数 |
session | HttpSession | 封装所有会话信息 | req.getSession() |
application | ServletContext | 所有信息 |
getServletContext() request.getServletContext() |
exception | PrintWriter | 输出对象 | response.getWriter() |
out | Exception | 异常对象 | |
page | Object | 当前页面对象 | |
pageCoontext | pageContext | 获取其他对象 | |
config | ServletConfig | 配置信息 |
作用域
page
在当前页面不会被重新实例化
request
在一次请求中为同一对象,下一次请求重新实例化一个对象
session
在一次会话中为同一对象.
只要Cookie中传递的Jsessionid不变,则Session不会被重新实例化(不超过默认时间)
有效时间:浏览器关闭,Cookie失效 默认时间 在范围内无任何交互,在tomcat的web.xml中配置 其中30为超时时间30分钟
<session-config> <session-timeout>30</session-timeout> </session-config>
application
只有在tomcat启动项目的时候才进行实例化,关闭tomcat的时候销毁
SpringMVC 作用域传值的几种方式
使用原生 Servlet
在Controller方法的参数中添加作用域对象
@RequestMapping("demo7") public String demo7(HttpServletRequest req, HttpSession session1){ //request作用域 req.setAttribute("req","req的值"); //session作用域两种方式获取 HttpSession session=req.getSession(); session.setAttribute("session","session的值"); session1.setAttribute("session1","session1的值"); //application作用域 ServletContext application=req.getServletContext(); application.setAttribute("application","application的值"); return "index"; }
使用Map集合
放在request作用域中
map被org.springframework.validation.support.BindingAwareModelMap实例化
@RequestMapping("demo8") public String demo8(Map<String,Object> map){ map.put("map","map的值"); //map被org.springframework.validation.support.BindingAwareModelMap实例化 System.out.println(map.getClass()); return "index"; }
使用 SpringMVC 中 Model 接口
把内容最终放入到 request 作用域中
@RequestMapping("demo9") public String demo9(Model model){ model.addAttribute("model","model的值"); return "index"; }
使用 SpringMVC 中 ModelAndView 类
把内容最终放入到 request 作用域中
@RequestMapping("demo10") public ModelAndView demo10(){ ModelAndView mav=new ModelAndView("index"); mav.addObject("mav","mav的值"); return mav; }
文件下载
访问资源时相应头如果没有设置 Content-Disposition,浏览器默认按 照 inline 值进行处理
只需要修改相应头中 Context-Disposition=”attachment;filename=文件名
attachment 下载,以附件形式下载
filename=值就是下载时显示的下载文件名
@RequestMapping("download") public void download(HttpServletResponse resp,String fileName,HttpServletRequest req) throws IOException { //设置响应头为下载 resp.setHeader("Content-Disposition","attachment;filename="+fileName); //获取文件夹在服务端的真实路径 String path=req.getServletContext().getRealPath("files"); System.out.println(path); File file=new File(path,fileName); //common-io中的方法,将文件转换为字节数组 byte[] bytes= FileUtils.readFileToByteArray(file); //字节流需要输出流发送到浏览器 ServletOutputStream os = resp.getOutputStream(); os.write(bytes); os.flush(); os.close(); }
文件上传
基于 apache 的 commons-fileupload.jar 完成文件上传
MultipartResovler 作用:把客户端上传的文件流转换成 MutipartFile 封装类. 通过 MutipartFile 封装类获取到文件流
表单数据类型分类:在表单的 enctype 属性控制表单类型
默认值 application/x-www-form-urlencoded,普通表单数据.(少 量文字信息)
text/plain 大文字量时使用的类型.邮件,论文
multipart/form-data 表单中包含二进制文件内容
编写JSP页面
<form action="/upload" method="post" enctype="multipart/form-data"> <input type="file" name="file"> <input type="submit" value="上传"> </form>
配置MultipartResolver解析器和异常解析器
其中5000为字节
<!--MultipartResolver解析器,文件上传自动转换为字节对象--> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="maxUploadSize" value="5000"/> </bean> <!--异常解析器--> <bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="exceptionMappings"> <props> <prop key="Exception">main</prop> </props> </property> </bean>
编写控制类
MultipartFile 对象名必须和input的name属性值相同
@RequestMapping("upload") public String upload(MultipartFile file,HttpServletRequest req) throws IOException { //上传文件的真实名字 String fileName=file.getOriginalFilename(); //截取后缀 String suffix=fileName.substring(fileName.lastIndexOf(".")); //判断文件类型 if(suffix.equalsIgnoreCase(".png")){ //随机文件名,防止重名文件覆盖 String uuid= UUID.randomUUID().toString(); File path = new File(req.getServletContext().getRealPath("image") +"/"+ uuid + suffix); System.out.println(path); FileUtils.copyInputStreamToFile(file.getInputStream(), path); return "index"; }else{ return "error"; } }
自定义拦截器
发送请求时被拦截器拦截,在控制器的前后添加额外功能.
跟 AOP 区分开.AOP 在特定方法前后扩充(对 ServiceImpl)
拦截器,请求的拦截.针对点是控制器方法.(对 Controller)
SpringMVC 拦截器和 Filter 的区别
拦截器只能拦截Controller 而Filter能拦截所有请求
实现步骤
自定义拦截器类,需要实现HandlerInterceptor接口,重写方法
preHandle方法 在进入控制器之前执行,如果返回false,则不进入控制器,用来编写控制代码
postHandle方法 在控制器执行完成后,进入jsp文件前执行,多用于日志记录但不包含异常信息,也可敏感词语过滤
afterCompletion方法 jsp执行完成后执行,多用于日志记录(包含异常信息)
在springMVC配置文件中,注册拦截器
拦截所有控制器
<mvc:interceptors> <bean class="com.ym.interceptor.MyInterceptor"/> </mvc:interceptors>
拦截指定控制器
<mvc:interceptors> <mvc:interceptor> <mvc:mapping path="demo"/> <mvc:mapping path="demo2"/> <bean class="com.ym.interceptor.MyInterceptor"/> </mvc:interceptor> </mvc:interceptors>
拦截器栈
多个拦截器组成了拦截器栈
执行顺序:先进后出
执行顺序和在springMVC配置文件中的顺序有关
设置先配置拦截器 A 在配置拦截器 B 执行顺序为:
preHandle(A) --> preHandle(B) --> 控制器方法 --> postHandle(B) --> postHanle(A) --> JSP --> afterCompletion(B) --> afterCompletion(A)
运行原理
如果在 web.xml 中设置 DispatcherServlet 的为/时,当用户 发 起 请 求 , 请 求 一 个 控 制 器 , 首 先 会 执 行 DispatcherServlet. 由 DispatcherServlet 调 用 HandlerMapping 的 DefaultAnnotationHandlerMapping 解 析 URL, 解 析 后 调 用 HandlerAdatper 组 件 的 AnnotationMethodHandlerAdapter 调 用 Controller 中的 HandlerMethod.当 HandlerMethod 执行完成后会返回 View,会被 ViewResovler 进行视图解析,解析后调用 jsp 对应的.class 文 件并运行,最终把运行.class 文件的结果响应给客户端.