SpringMVC笔记

SpringMVC重要组件

  1. DispatcherServlet:前端控制器,用于接收所有请求,整个流程控制的中心,控制其它组件执行,统一调度,降低组件之间的耦合性,提高每个组件的扩展性。

  2. HandlerMapping:解析请求格式的.判断希望要执行哪个具体的方法

  3. HandlerAdapter:负责调用具体的方法.

  4. 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>

传递参数

  1. 把内容写到方法(HandlerMethod)参数中,SpringMVC 只要有这个内 容,注入内容.
  2. 基本数据类型参数,默认保证参数名称和请求中传递的参数名相同
  3. 如果请求参数名和方法参数名不对应使用@RequestParam()赋值
    @RequestMapping("demo1")
        public String demo1(@RequestParam("id1") int id,@RequestParam("name1") String name){
            System.out.println("开始"+id+"  "+name);
            return "main";
        }
  4. 如果方法参数是基本数据类型(不是封装类)可以通过 @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";
        }
  5. 如果强制要求必须有某个参数
    @RequestMapping("demo2")
    public String demo2(@RequestParam(required=true) String name){
      System.out.println("name 是 SQL 的查询条件,必须要传递 name 参数"+name);
      return "main";
    }
  6. HandlerMethod 中参数是对象类型
    @RequestMapping("demo2")
        public String demo2(People people,int id,String name){
            System.out.println("开始"+people+"  "+id+"  "+name);
            return "main";
        }
  7. 请求参数中包含多个同名参数的获取方式,复选框传递的参数就是多个同名参数
    @RequestMapping("demo5")
    public String demo5(@RequestParam("hover")List<String> abc){
        System.out.println(abc);
        return "main";
    }    
  8. 请求参数中对象.属性格式,在对象外面在封装一层对象,并且传递参数为外层新封装的对象
  9. 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 文件的结果响应给客户端.

原文地址:https://www.cnblogs.com/yuming2018/p/11338298.html