SpringMVC 个人总结

目录

SpringMVC

第一章 SpringMVC 概述

1.1 SpringMVC 基本说明

1.2 SpringMVC核心Servlet--DispatcherServlet

1.3 springmvc请求的处理过程

1.4 web开发中配置文件的说明

1.5 SpringMVC内部执行流程

第二章 SpringMVC 注解式开发

2.1 @RequestMapping注解的使用

2.2 接收请求中的参数

2.2.1 逐个接收

2.2.2CharacterEncodingFilter使用:

2.2.3 请求中参数名和形参名不一样,使用@RequestParam

2.2.4 对象接收

2.3 控制器方法的返回值

2.3.1 ModelAndView 数据和视图

2.3.2 String 视图

2.3.3 void 没有数据和视图

2.3.4 Object

2.4 静态资源处理

2.4.1 tomcat的default servlet

2.4.2 中央调度器设置"/"

2.4.3 第一种方式处理静态资源

2.4.4 第二种方式处理静态资源

第三章 SSM整合开发

3.1 SSM 整合思路

3.2 容器的创建

3.3 SSM整合开发步骤

3.4 相对路径

第四章 SpringMVC 核心技术

4.1 forward(转发)、redirect(重定向)

4.2 异常处理

4.3 拦截器

4.3.1 第一个拦截器

4.3.3 拦截器和过滤器的对比


SpringMVC

第一章 SpringMVC 概述

1.1 SpringMVC 基本说明

SpringMVC是基于spring的,是spring中的一个模块,做web开发使用的。springmvc 叫做spring web mvc 说明他是spring的核心技术,做web开发,springmvc内部是使用mvc框架模式

SpringMVC是一个容器,管理对象的,使用IoC核心技术。springmvc管理界面层中的控制器对象

SpringMVC底层也是Servlet,以Servlet为核心,接受请求,处理请求。显示处理结果给用户

处理用户请求:

用户发起请求-----SpringMVC-----Spring-----Mybatis----Mybatis---myssql数据库

springmvc步骤:
1.新建web应用
2.加入web依赖
  spring-webmvc依赖(springmvc框架依赖),servlet依赖javax.servlet-api
​
3.声明springmvc核心对象DispatccherServlet。
  1.DispatcherServlet是一个Servlet对象
  2.DispatcherServlet叫做前端控制器(front controller)
  3.DispatcherServlet作用:
      1.在servlet的init()方法中,创建springmav中的容器
        WebApplicationContext ctx =new ClassPathXmlApplicationContext("applicationContext.xml");
      2.作为servlet,接收请求
​
4.创建一个jsp,发起请求
5.创建一个普通的类,作为控制器使用(代替之前的servlet)
   1.在类的上面加入@Controller注解
   2.在类中定义方法,方法的上面加入@RequestMapping 注解
     方法处理请求的,相当于servlet的doGet,doPost
​
6.创建作为结果的jsp页面
7.创建springmvc的配置文件(spring的配置文件一样)
  1.声明组件扫描器,指定@Controller注解所在的包名
  2.声明视图解析器对象

视图文件受保护:

在WEB-INF根目录下创建一个文件夹将jsp文件放到该文件夹中

1.2 SpringMVC核心Servlet--DispatcherServlet

DispatcherServlet 是框架中的Servlet对象。负责接受请求,相应处理结果

DispatcherServlet 的父类是HttpServlet

DispatcherServlet 也叫做前端控制器 (front controller)

SpringMVC是管理控制器对象,原来没有SpringMVC之前使用Servlet作为控制器对象使用。现在通过SpringMVC容器创建一种叫做控制器的对象,代替Servlet行驶控制器的角色。功能

SpringMVC 主要使用注解的方式。创建控制器对象

<servlet>
  <servlet-name>myweb</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>
  <!--表示服务器tomcat创建对象的顺序,是个整数值,大于等于0
      数值越小,创建对象的时间对象越早-->
  <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
  <servlet-name>myweb</servlet-name>
  <!--url-pattern 作用:把一些请求交给指定的servlet处理
      使用中央调度器(前端调度器DispatcherServlet)
      1.使用扩展名方式,格式 *.xxx,xxx是自定义的扩展名。例如 *.do,*.action,*.mvc 等等,不能使用*.jsp
        例如:http://localhost:8080/myweb/some.do
             http://localhost:8080/myweb/user/list/queryUser.do
​
      2.使用斜杆“/” 例如:/mymvc-->
  <url-pattern>*.do</url-pattern>
</servlet-mapping>

1.3 springmvc请求的处理过程

简单的处理过程:

用户发起请求some.do --->Tomcat接收请求 ---->DispatcherServlet (中央调度器)--->分配MyController(doSome() 返回mv对象) --->mv显示给用户了。

省略tomcat:

用户some.do ------> DispatcherServlet ------> MyController

如果使用Servlet处理请求:

用户发起请求 ----------->Servlet

1.4 web开发中配置文件的说明

  1. web.xml 部署描述文件,给服务器(Tomcat)

    作用:服务器在启动的时候,读取web.xml,根据文件中的声明创建各种对象。

    根据文件的声明 知道 请求和servlet等对象的关系

  2. 框架的配置文件,springmvc的配置文件

    作用:声明框架创建的项目中的各种对象,主要是创建Controller对象的

配置文件的加载顺序和功能

  1. tomcat服务器启动,读取web.xml,根据web.xml文件中的说明,创建对象。

    <servlet>
      <servlet-name>myweb</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>
      <!--表示服务器tomcat创建对象的顺序,是个整数值,大于等于0
          数值越小,创建对象的时间对象越早-->
      <load-on-startup>1</load-on-startup>
    </servlet>

    创建DispatcherServlet的对象,会执行init()方法。在init()方法中会执行springmvc容器对象创建

    WebApplicationContext ctx = new ClassPathApplicationContext() 读取springmvc的配置文件

  2. Springmvc框架,new ClassPathXmlApplicationContext() 读取springmvc的配置文件

    <!--springmvc的配置文件-->
    <!--声明组件扫描器 ,使用注解就需要-->
    <context:component-scan base-package="com.zd.controller"/>
    ​
    <!--声明视图解析器:帮助处理视图-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--前缀:指定视图文件的路径-->
        <property name="prefix" value="/WEB-INF/view/"/>
        <!--后缀:视图文件的扩展名-->
        <property name="suffix" value=".jsp"/>
    </bean>

    使用组件扫描器 <context:component-scan base-package="com.zd.controller"/> ,遍历controller包中的所有类,MyController类,找到这个类中的@Controller,@Requestmapping注解,就能创建MyController对象。知道some.do的请求是执行doSome()方法

    以上1,2都是项目启动的过程,没有执行任何的用户请求

  3. 用户发起请求some.do --->DispatcherServlet

    DispatcherServlet 里面有WebApplicationContext。WebApplicationContext 里面有MyContorller对象。

    请求some.do ,DispatcherServlet 就知道是 MyContrller处理的

1.5 SpringMVC内部执行流程

springmvc内部请求的处理过程:

  1. 用户发起请求给DispatcherServlet

  2. DispatcherServlet把请求(request)交给了处理器映射器

    处理器映射器:springmvc框架中的对象,需要实现HandlerMappering接口。

    映射器作用:从springmvc容器中,获取控制器对象(MyController),把找到的控制器和拦截器对象都放到处理器执行链对象中,保存,并返回给中央调度器。

    (Mycontroller controller=ApplicationContext.getBean())

  3. DispatcherServlet把获取到的处理器执行链中的控制器对象,交给处理器适配器

    处理器适配器:是springmvc框架中的对象,实现HandlerAdspter接口

    适配器作用:执行控制器的方法,也就是执行MyController.doSome()方法。得到结果ModelAndView

  4. DispatcherServlet把控制器执行结果mv交给了 视图解析器

    视图解析器:springmvc中的对象,需要实现ViewResolver接口

    视图解析器作用:处理视图的完整路径。能创建View类型的对象

  5. DispatcherServlet调用View类中的方法,把Model中的数据放入到request作用域。执行request.setAttribute(),对视图执行forward()转发行为,request.getRequestDispather("/shou.jsp").forward(request,response)

第二章 SpringMVC 注解式开发

2.1 @RequestMapping注解的使用

http://localhost:8888/ch02_requestmappering/test/some.do

http://localhost:8888/ch02_requestmappering/test/second.do

@RequestMapping: 请求映射 属性: value 请求中的uri地址,唯一值,以"/"为开头 位置:1.在方法的上面(必须) 2,在类定义的上面(可选) 作用:把指定的请求,交给指定的方法处理,等同于url-pattern

属性 method请求的方式,使用RequestMethod类的枚举,表示请求方式

@RequestMapping(value = {"/other.do"},method = RequestMethod.POST)
public ModelAndView doother(){
    
@RequestMapping(value={"/some.do"})
public ModelAndView doSome(){
  
  

返回值ModelAndView:表示本次请求的处理结果(数据和视图) Model:表示视图 View:表示视图

位置:在类的上面时

属性 value:表示所有请求地址的公共前缀,相当于是模块名称 位置:在类的上面

2.2 接收请求中的参数

对应HttpServletRequest,HttpServletResponse,HttpSession 只需要在控制器方法的形参列表中,定义就可以了。框架会给参数赋值。在控制器方法内部可以直接使用request,response,session参数。

400: http status,表示客户端异常。主要是发生在用户提交参数过程中。

接收请求中的参数,逐个接收,对象接收

2.2.1 逐个接收

逐个接收:请求中的参数名和控制器方法的形参名一样。按照名称对象接收参数

index.jsp

<p>逐个接收请求参数</p>
<form action="receive-property.do" method="post">
     姓名:<input  type="text" name="name"><br/>
     年龄:<input type="text" name="age"><br/>
     <input type="submit" value="post请求">
</form>

Conntroller接收参数

@RequestMapping(value={"/receive-property.do"})
public ModelAndView doPropertyParam(String name,Integer age)  {
  
  

接收参数的问题:

  1. 参数最好使用包装类型。例如Integer,能接收空值情况,接收的是null

  2. 框架可以实现String到int,log,float,double等类型转换

  3. post请求中有乱码的问题,使用字符集过滤器

2.2.2CharacterEncodingFilter使用:

在web.xml 声明过滤器
 <!--声明过滤器,框架提供的,解决post请求乱码-->
  <filter>
    <filter-name>characterEncodingFilter</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>
    <init-param>
      <!--强制请求(request)对象使用encoding的编码方式-->
      <param-name>forceRequestEncoding</param-name>
      <param-value>true</param-value>
    </init-param>
    <init-param>
      <!--强制应答(response)对象使用encoding的编码方式-->
      <param-name>forceResponseEncoding</param-name>
      <param-value>true</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>characterEncodingFilter</filter-name>
    <!--强制所有请求,先经过过滤器处理-->
    <url-pattern>/*</url-pattern>
  </filter-mapping>

2.2.3 请求中参数名和形参名不一样,使用@RequestParam

/**
 * 逐个接收请求参数,请求中参数名和形参名不一样
 * @RequestParm : 解决名称不一样的问题
 *     属性 : value 请求中的参数名称
 *            required: boolean类型的,默认是true
 *                      true:请求中必须有此参数。没有就报错-400
 *                      false:请求中可以没有此参数。
 *     位置:  在形参定义的前面
 */
@RequestMapping(value={"/receive-param.do"})
public ModelAndView doReceiveParam(
       @RequestParam(value = "rname",required = false) String name,
       @RequestParam(value = "rage",required = false) Integer age)  {}

2.2.4 对象接收

对象接收:在控制器方法的形参是java对象,使用java对象的属性接收请求中参数值。

要求:java对象的属性名和请求中参数名一样。

例子:

Student类:

public class Student {
    //属性名和请求中的参数名一样
    private String name;
    private int age;
    
    set、get方法
    toString方法

Controller类:

/**
 * 使用对象接收请求中的参数
 * 要求:参数名和java对象的属性名一样‘
 *      java类需要一个无参数构造方法,属性有set方法
 *
 * 框架的处理:
 *    1.调用Student的无参构造方法,创建对象
 *    2.调用对象set方法,同名的参数,调用对应的set方法。
 *       参数是name,调用setName(参数值)
 */
@RequestMapping(value = "receive-object.do")
 public ModelAndView doReceiveObject(Student student){
    System.out.println("MyController的方法doReceiveObject="+student);
    ModelAndView mv =new ModelAndView();
    mv.addObject("myname",student.getName());
    mv.addObject("myage",student.getAge());
    mv.setViewName("show");
    return mv;
 }

2.3 控制器方法的返回值

控制器方法的返回值表示本次请求的处理结果,返回值有ModelAndView,spring,void,Object

请求的处理结果包含:数据和视图

2.3.1 ModelAndView 数据和视图

请求的结果又有数据和视图,使用ModelAndView最方便

数据:存放request作用域

视图:执行forward转发操作

2.3.2 String 视图

框架对返回值是String,执行的是forward转发操作。

视图可以表示为完整视图路径,或者视图的逻辑名称

/**
 * 控制器方法返回String ,表示逻辑名称,需要项目中配置视图解析器
 */
@RequestMapping(value={"/return-string-view.do"})
public String doRequestStringView1(HttpServletRequest request,String name, Integer age)  {
    System.out.println("执行了doRequestStringView1的方法name="+name+",age="+age);

    //处理数据,
    request.setAttribute("myname",name);
    request.setAttribute("myage",age);
    //返回结果,forward,转发到show.jsp
    return "show";
}

/**
 * 控制器方法返回String ,表示完整视图路径,项目中不能配置视图解析器
 */
@RequestMapping(value={"/return-string-view2.do"})
public String doRequestStringView2(HttpServletRequest request,String name, Integer age)  {

    System.out.println("执行了doRequestStringView2的方法name="+name+",age="+age);

    //处理数据,
    request.setAttribute("myname",name);
    request.setAttribute("myage",age);
    //返回结果,forward,转发到show.jsp
    //使用视图解析器 :/WEB-INF/view/ WEB-INF/view/show.jsp .jsp
    return "/WEB-INF/view/show.jsp";
}

2.3.3 void 没有数据和视图

void:没有数据和视图,可以使用HttpServletResponse对象输出数据,响应ajax请求

Controller类:

/**
 * 控制器方法返回是void,响应ajax请求,使用HttpServletResponse输出数据
 */
@RequestMapping(value = "/return-void-ajax.do")
public void returnVoidAjax1(HttpServletResponse response,String name, Integer age) throws IOException {
    System.out.println("处理void返回类型,name"+name+",age="+age);
    //调用service得到结果对象
    Student student =new Student();
    student.setName(name+"同学");
    student.setAge(age);

    //把对象转为json
    ObjectMapper om =new ObjectMapper();
    String json=om.writeValueAsString(student);
    System.out.println("服务器端对象转为json==="+json);

    //输出json,响应ajax
    response.setContentType("application/json;charset=utf-8");
    PrintWriter pw =response.getWriter();
    pw.println(json);
    pw.flush();
    pw.close();

}

index.jsp:

<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
    <title>请求方式</title>
    <script type="text/javascript" src="js/jquery-3.4.1.js"></script>
    <script type="text/javascript">
        $(function(){
            //绑定事件
            $("#btnAjax").on("click",function (){
                $.ajax({
                    url:"return-void-ajax.do",
                    data:{
                        name:"lisi",
                        age:20
                    },
                    dataType:"json",
                    success:function (resp){
                        //resp=XMLHttpResquest.responseText;
                        alert("resp==="+resp.name+"===="+resp.age);
                    }
                })
            })
        })
    </script>
</head>
<body>
      <button id="btnAjax" >发起ajax请求</button>
<br/>
</body>
</html>

2.3.4 Object

返回Student 表示数据。ajax要的是数据,所以控制器方法返回对象Object,用来响应ajax请求。

返回对象Object,可以是List,Student,Map,String,Integer。。。。这些都是数据。在ajax请求中,一般需要从服务器返回的是json格式的数据,经常要处理java对象到json转换,而且还需要输出数据响应ajax请求。框架提供了处理java对象到json转换,还是数据输出工作。

2.3.4.1 HttpMessageConverter 消息转换器

HttpMessageConverter 接口,作用是 1.实现请求的数据转为java对象,2.把控制器方法返回对象转为json,xml,text,二进制等不同格式的数据

public interface HttpMessageConverter<T> {

    /**
        canRead作用:检查class这个类型的对象,能否转为 mediaType表示的数据格式
             如果能转为mediaType表示的类型,返回true,返回true调用read()
    */
   boolean canRead(Class<?> clazz, @Nullable MediaType mediaType);

    /**
       read 作用:接收请求中的数据,把数据转为class表示的对象
    */
    T read(Class<? extends T> clazz, HttpInputMessage inputMessage)
         throws IOException, HttpMessageNotReadableException;

    /**
      canWrite 作用:检查class这种数据类型,能否转为mediaType表示的数据
    */
   boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType);
    
    /**
      write 作用:把t对象,按照contentType说明的格式,把对象转为json或者xml
      t:控制器方法的返回值
    */
   void write(T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage)
         throws IOException, HttpMessageNotWritableException;
    
    	
}

MediaType:媒体类型,表示互联网中数据的格式。例如application/json,text/html,image/gif

HttpMessageConverter 接口的实现类:
MappingJackson2HttpMessageConverter :使用jackson工具库的ObjectMapper把java对象转为json数据格式
StringHttpMessageConverter :把字符串类型的数据,进行格式转换和编码

使用实现类:

框架根据控制器的方法的返回类型,自动查找使用的实现类

@RequestMapping(value = "receive-object.do")
 public Student doReceiveObject(String name,Integer age){
    System.out.println("MyController的方法doReceiveObject=");
    Student student =new Student();
    student.setName("lisi");
    student.setAge(20);
    return student;
 }

默认情况下:springmvc使用了HttpMessageConveter接口的4个实现类,包括了StringHttpMessageConverter

需要在springmvc的配置文件,加入注解驱动的标签 mvc:annotation-drivern。加入这个标签后,springmvc项目启动后,会创建HttpMessageConveter接口的7个实现类对象,包括StringHttpMessageConverter和MappingJackson2HttpMessageConverter 。

springmvc.xml:

<mvc:annotation-driven/> 

MappingJackson2HttpMessageConverter 完成的工作例如:

//把对象转为json
    ObjectMapper om =new ObjectMapper();
    String json=om.writeValueAsString(student);
    System.out.println("服务器端对象转为json==="+json);

2.3.4.2 @ResponseBody

@ResponseBody注解的作用,就是把student转换后的json通过HttpServletResponse对象输出给浏览器。

@ResponseBody完成的工作例如:

 //输出json,响应ajax
    response.setContentType("application/json;charset=utf-8");
    PrintWriter pw =response.getWriter();
    pw.println(json);
    pw.flush();
    pw.close();

2.3.4.3 控制器方法返回对象转为json的步骤

  1. pom.xml加入jackson依赖,springmvc依赖,默认处理json就是jackson

  2. 在springmvc的配置文件中,加入注解驱动的标签mvc:annotation-driven

  3. 在控制器的方法上面加入@ResponseBody注解,表示返回值是数据输出到浏览器

注意:

返回值是String类型,会有中文乱码,

Controller类:

/**
 * 控制器方法返回String -- 数据
 *
 * 区分返回值是数据还是视图
 * 1.方法上面有@ResponseBody注解就是数据
 * 2.方法上面没有@ResponseBody注解就是视图
 *
 * 页面默认content-type:text/plain;charset=ISO-8859-1 没走过滤器
 * 解决中文,需要使用@RequestMapping的produces属性
 * produces属性: 指定content-type的值
 *
 * 框架处理String返回值
 * 1.框架使用的是StringHttpMessageConverter
 * 2.StringHttpMessageConverter使用的是text/plan;charset=ISO-8859-1
 */
@RequestMapping(value = "/doStringData.do",produces = "text/plan;charset=utf-8")
@ResponseBody
public String doStringData(String name,Integer age){
    System.out.println("控制器方法返回String,是数据");
    return "Hello SpringMVC注解式开发";
}

index.jsp:

dataType:"text",

2.4 静态资源处理

访问地址:

当web.xml中DispatcherServlet的url-pattern是*.do

http://localhost:8888/ch05_url_pattern/index.jsp tomcat

http://localhost:8888/ch05_url_pattern/js/jQuery-3.4.1.js tomcat

http://localhost:8888/ch05_url_pattern/images/p1.png tomcat

http://localhost:8888/ch05_url_pattern/html/test.html tomcat

http://localhost:8888/ch05_url_pattern/some.do DispatcherServlet(springmvc框架)

2.4.1 tomcat的default servlet

tomcat安装目录/conf/web.xml

<servlet>
    <servlet-name>default</servlet-name>
    <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
    <init-param>
        <param-name>debug</param-name>
        <param-value>0</param-value>
    </init-param>
    <init-param>
        <param-name>listings</param-name>
        <param-value>false</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>/</url-pattern>
</servlet-mapping>


default 叫做默认servlet,作用:
1.它提供静态资源的处理
2.它处理所有未映射到其他请求的请求处理

2.4.2 中央调度器设置"/"

<servlet-mapping>
  <servlet-name>myweb</servlet-name>
  <!--url-pattern 作用:把一些请求交给指定的servlet处理
     使用中央调度器(前端调度器DispatcherServlet)
     1.使用扩展名方式,格式 *.xxx,xxx是自定义的扩展名。例如 *.do,*.action,*.mvc 等等,不能使用*.jsp
       例如:http://localhost:8080/myweb/some.do
            http://localhost:8080/myweb/user/list/queryUser.do

     2.使用斜杆“/” 例如:/mymvc-->
  <url-pattern>/</url-pattern>
</servlet-mapping>

http://localhost:8888/ch05_url_pattern/index.jsp tomcat成功访问

http://localhost:8888/ch05_url_pattern/js/jQuery-3.4.1.js 404 因为没有对应的控制器对象

http://localhost:8888/ch05_url_pattern/images/p1.png 404 因为没有对应的控制器对象

http://localhost:8888/ch05_url_pattern/html/test.html 404 因为没有对应的控制器对象

http://localhost:8888/ch05_url_pattern/some.do 200 有对应的控制器对象

              使用斜杆“/” ,导致中央调度器成为了默认的default servlet
              需要处理其他静态资源和其他的未映射的请求。
              默认中央调度器没有处理静态资源的控制器对象,所以静态资源都是404.
              some.do这个请求有MyController对象,所以能访问

              如果项目中,中央调度器设置了"/",动态资源能访问,静态资源不能访问
              需要处理静态资源的访问工作,

2.4.3 第一种方式处理静态资源

在springmvc的配置文件加入mvc:default-servlet-handler标签,springmvc框架会在项目运行时,加入DefauletServletHttpRequestHandler对象,让这个对象处理静态资源的访问

springmvc.xml:

<!--声明注解驱动(annotation-driven),1.创建HttpMessageConverter(消息转换器)接口的7个实现类对象

    2.default-servlet-handler和@RequestMapping使用有冲突
    解决冲突是加入annotation-driven
    DefaultServletHttpRequestHandler把接收的静态资源的地址,转发给了tomcat的defualt
    优点:解决tomcat服务器提供的能力 缺点:依赖tomcat提供的能力-->
<mvc:annotation-driven/>

<!--声明静态资源的第一种处理方式-->
<mvc:default-servlet-handler/>

2.4.4 第二种方式处理静态资源

在springmvc配置文件中加入一个mvc:resources标签,框架会创建ResourcesHttpRequestHandle控制器对象,使用这个对象处理静态资源的访问,不依赖于tomcat服务器,推荐使用

springmvc.xml:

<!--声明注解驱动(annotation-driven),1.创建HttpMessageConverter(消息转换器)接口的7个实现类对象

    2.resources和@RequestMapping使用有冲突
    解决冲突是加入annotation-driven
    -->
<mvc:annotation-driven/>

<!--声明静态资源的第二种处理方式
    mapping:访问静态资源的uri地址,可以使用通配符(**)
             **:表示任意的目录和目录和资源名称
    location:静态资源在项目中的资源,不要使用/WEB-INF目录-->
<mvc:resources mapping="/images/**" location="/images/"/>
<mvc:resources mapping="/html/**" location="/html/"/>
<mvc:resources mapping="/js/**" location="/js/"/>
<!--或者一句话设置静态资源,将所有的静态文件放到一个文件夹中
    <mvc:resources mapping="/static/**" location="/static/"/>
    -->

第三章 SSM整合开发

3.1 SSM 整合思路

SSM思路:SpringMVC+Spring+Mybatis(IBatis) ,所以有人叫做SSI整合。SSM整合是使用三个框架的优势功能。三个框架对应的三层架构的三层。SpringMVC是视图层,Spring是业务层,Mybatis是持久层。

SSM整合,需要把对象交给容器管理,让容器去创建项目中要使用的java对象。现在有两个容器。第一个是Spring容器:Spring容器是管理service和dao等对象的,是业务层对象的容器。

第二个是SpringMVC容器:管理控制器对象的,是视图层对象的。

SSM整合就是把对象交给容器管理。两个容器共存。各自负责管理不同的对象。把对象声明到配置文件中,让两个容器创建对象。spring创建service,dao;springmvc创建controller。

3.2 容器的创建

Spring容器创建:在web.xml声明了监听器ContextLoaderListener,这个功能框架写好了。功能是创建spring的容器对象 WebApplicationContext。在创建WebApplicationContext对象时,读取spring的配置文件,读取文件的时候,遇到bean标签获知注解是,就能创建service,dao等对象,放到容器中。

SpringMVC容器:在web.xml声明了中央调度器DispatcherServlet。在这个servlet的init()方法中,创建了容器对象 WebApplicationContext。在创建WebApplicationContext对象,读取springmvc的配置文件,读取文件的时候,遇到@Controller注解,创建控制器controller对象,放到容器中。

内存中,创建对象

webApplicationContext spring= new WebApplicationContext(); //spring-map(service,dao)

webApplicationContext springmvc= new webApplicationContext(); //springmvc-map(controller)

SpringMVC容器和Spring容器的关系:设计上SpringMVC容器对象是Spring容器的子容器。

Spring是父容器。SpringMVC是子容器。相当于java中的继承关系。

用户发起请求 some.do ----> controller -----> service ----->dao

3.3 SSM整合开发步骤

  1. 使用的springdb中的student表(id,name,age)

  2. 创建maven web项目

  3. 修改pom.xml加入依赖:spring,springmvc,mybatis,mybatis-spring,mysql驱动,druid,jackson

  4. 写web.xml:声明容器对象

    1. 声明spring的监听器ControllerLoaderListener:创建spring的容器对象,创建service,dao对象

    2. 声明springmvc的中央调度器DispatcherServlet:创建springmvc容器对象,创建controller对象

    3. 声明字符集的过滤器 CharacterEncodingFilter,解决post请求乱码的问题

  5. 创建程序中的包,dao,service,controller,entity

  6. 写spring,springmvc,mybatis配置文件

  7. 写java代码,实体类,dao接口和mapper文件,service类,controller类,使用注解声明对象和赋值

  8. 创建视图文件,各种jsp

pom.xml依赖:

<dependencies>
  <!--单元测试依赖-->
  <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.11</version>
    <scope>test</scope>
  </dependency>

  <!--servlet依赖-->
  <dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.1.0</version>
    <scope>provided</scope>
  </dependency>

  <!--jsp依赖-->
  <dependency>
    <groupId>javax.servlet.jsp</groupId>
    <artifactId>jsp-api</artifactId>
    <version>2.2.1-b03</version>
    <scope>provided</scope>
  </dependency>

  <!--springmvc-->
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.2.5.RELEASE</version>
  </dependency>

  <!--事务-->
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>5.2.5.RELEASE</version>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.2.5.RELEASE</version>
  </dependency>

  <!--jackson依赖-->
  <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.9.0</version>
  </dependency>
  <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.0</version>
  </dependency>

  <!--mybatis,spring整合依赖-->
  <dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>1.3.1</version>
  </dependency>

  <!--mybatis依赖-->
  <dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.1</version>
  </dependency>

  <!--mysql驱动依赖-->
  <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.28</version>
  </dependency>

  <!--阿里连接池依赖 JDBC的一个组件-->
  <dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.12</version>
  </dependency>
</dependencies>


<build>
  <finalName>ch06-SSM</finalName>

  <!--资源插件:处理src/main/java目录中的xml-->
  <resources>
    <resource>
      <directory>src/main/java</directory><!--所在的目录-->
      <includes><!--包括目录下的.properties,.xml 文件都会扫描到-->
        <include>**/*.properties</include>
        <include>**/*.xml</include>
      </includes>
      <filtering>false</filtering>
    </resource>
  </resources>
</build>

3.4 相对路径

在页面中,有路径的问题,访问路径有"/"开头的,还有没有"/"开头的

<a href="test/some.do">没有斜杠开头</a>
<a href="/test/some.do">有斜杠开头</a>
<a href="http://www.baidu.com">有协议开头的地址</a>

地址的区别,现在看的都是在页面中的地址。

  1. 有协议开头的例如百度一下,你就知道,称为绝对地址。地址是唯一的,能够直接访问

  2. 没有协议开头的,例如test/some.do, /test/some.do称为相对地址,相对地址单独使用不能表示某个资源,不能访问。相对地址必须有参考地址在一起

参考地址:有"/"和没有 "/" 参考地址不同的

  1. 没有斜杠开头的地址,参考地址:当前资源的访问路径

    当前访问的地址:http://localhost:8888/ch07_path/index.jsp
    
    资源名称:index.jsp
    
    资源路径:http://localhost:8888/ch07_path

    在index.jsp有访问地址 a href="test/some.do"

    点击some.do后,地址变为http://localhost:8888/ch07_path/test/some.do

    此时:http://localhost:8888/ch07_path/test/some.do
    资源名称:some.do
    资源路径:http://localhost:8888/ch07_path/test/
    
    再次点击test/some.do 地址:http://localhost:8888/ch07_path/test/test/some.do

    没有斜杠开头的地址:参考地址+当前的相对地址组合在一起是最后的访问地址

    解决方式:

    1.使用${pageContext.request.contextPath}/。表示访问项目的路径(上下文件 context path)
    <a href="${pageContext.request.contextPath}/test/some.do">发起请求test/some.do</a>
    优点:好理解
    缺点:每个链接地址,都需要加el表达式
    
    2.固定当前页面中的 没有"/"开头地址的 参考地址
    使用html中base标签
    <head>
        <base href="http://localhost:8888/ch07_path/">
    </head>
        
    jsp可以定义一个变量
    <%
       String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+request.getContextPath()+"/";
       
       %>  
    <head>
        <title>请求方式</title>
        <base href=<%=basePath%>>
    </head>
  2. 有斜杠开头的地址

    <a href="/test/some.do">

    访问的地址:http://localhost:8888/ch07_path/index.jsp
    在index.jsp有 相对地址  <a href="/test/some.do">/test/some.do</a> 
    点击链接后,地址:http://localhost:8888/test/some.do
    
    使用"/"开头的地址,参考地址是服务器地址,也就是从协议开始到端口号位置 http://localhost:8888/
    使用参考地址 http://localhost:8888 + 相对地址 /test/some.do 最后就是
    地址组成:http://localhost:8888/test/some.do
    地址缺少项目访问路径:ch07_path

    解决问题的方式:在路径前面加入el表达示 ${pageContext.request.contextPath}

<a href="${pageContext.request.contextPath}/test/some.do">发起请求/test/some.do</a>

第四章 SpringMVC 核心技术

4.1 forward(转发)、redirect(重定向)

forward:

/**
 * 控制器方法返回是ModeAndView实现转发forward
 * 语法: mv.setViewName("forward:视图完整路径")
 *
 * forward特点:不和视图解析器一同工作的,就当项目中没有视图解析器
 */
@RequestMapping(value={"/doForward.do"},method = RequestMethod.GET)
public ModelAndView doSome(){
    System.out.println("执行了MyController的doForward方法");
    //使用这个方法处理请求,能处理请求的方法叫做控制器方法
    //调用service对象,处理请求,返回数据
    ModelAndView mv =new ModelAndView();

    //添加数据
    mv.addObject("msg","处理了some.do请求");
    mv.addObject("fun","执行了doSome方法");
    //显示使用forward指定转发操作
    //mv.setViewName("forward:/WEB-INF/view/show.jsp");
    //hello不在/WEB-INF/view下 ,要访问视图解析器用不了,可以用forward
    mv.setViewName("forward:/hello.jsp");
    return mv;
}

redirect:

 /**
     * 当控制器方法返回ModeAndView实现重定向
     * 语法: mv.setViewName("redirect:视图完成路径")
     * redirect特点:不和视图解析器一同工作,就当项目中没有视图解析器
     * redirect(重定向)不能访问受保护的目录 ,不能访问/WEB-INF/目录
     *
     * 框架提供的重定向的功能
     * 1.框架可以实现两次请求之间的数据传递,把第一个请求中的Model里面
     *   简单类型的数据,转为字符串,附加到目标页面的后面,做get参数传递。
     *   可以在目标页面中获取参数值使用
     *
     * 2.在目标页面中,可以使用${param.参数名}或<%=request.getParameter("参数名")%> 获取参数值
     */
    @RequestMapping(value = "/doRedirect.do")
    public ModelAndView doRedirect(String name,Integer age){
        System.out.println("doRedirect,name="+name+",age="+age);
        ModelAndView mv = new ModelAndView();
        mv.addObject("myname",name);
        mv.addObject("myage",age);
        mv.setViewName("redirect:/redirect.jsp");
        //http://localhost:8888/ch08_forward_redirect/redirect.jsp?myname=lisi&myage=22

        return mv;
    }
<h3>获取get请求中的参数的两种方式:<%=request.getParameter("myname")%></h3>
<h3>myname数据:${param.myname}</h3>

4.2 异常处理

框架使用的是集中的异常处理,把各个Controller中抛出的异常集中到一个地方处理。处理异常的叫异常处理器。

框架使用两个注解完成异常的集中处理,这样每个controller不用单独处理异常了。注解是:

  1. @ExceptionHandler:放在方法的上面,表示此方法可以处理某个类型的异常。当异常发生时,执行这个方法。

  2. @ControllerAdvice:放在类的上面,表示这个类中有异常的处理方法。相当于aop中的Aspect

    @ControllerAdvice可以看作是 控制器增强,就是给Controller类增加异常(切面)的处理功能。

步骤:

需求:用户发起一个请求,springmvc接收请求,显示请求的处理结果

servlet的实现方式:
          jsp发起----servlet----jsp显示结果

springmvc步骤:
1.新建web应用
2.加入web依赖
  spring-webmvc依赖(springmvc框架依赖),servlet依赖

3.声明springmvc核心对象DispatccherServlet。
  1.DispatcherServlet是一个Servlet对象
  2.DispatcherServlet叫做前端控制器(front controller)
  3.DispatcherServlet作用:
      1.在servlet的init()方法中,创建springmav中的容器
        WebApplicationContext ctx =new ClassPathXmlApplicationContext("applicationContext.xml");
      2.作为servlet,接收请求

4.创建一个jsp,发起请求 有参数name,age
5.创建异常类MyUserException,
  子类 NameException,AgeException
6.创建一个普通的类,作为控制器使用(代替之前的servlet)
   1.在类的上面加入@Controller注解
   2.在类中定义方法,方法的上面加入@RequestMapping 注解
     方法处理请求的,根据请求的参数name,age的值抛出NameException,AgeException


7.创建作为结果的jsp页面

8.创建一个普通类,作为异常的处理类
  1.在类的上面加入@ControllerAdvice
  2.在类中定义方法,每个方法处理对应的异常。方法的上面加入@ExceptionHandler注解

9.创建处理异常的jsp页面

10.创建springmvc的配置文件(spring的配置文件一样)
  1.声明组件扫描器,指定@Controller注解所在的包名
  2.声明视图解析器对象

  3.声明组件扫描器,找到@ControllerAdvice注解包名
  4.声明注解驱动

4.3 拦截器

拦截器:是springmvc框架中的一种对象,需要实现接口HandlerInterceptor,拦截用户的请求,拦截到controller的请求

作用:拦截用户的请求,可以预先对请求做处理。根据处理结果,决定是否执行controller。也可以把多个controller中共有的功能定义到拦截器。比如说可以做登录检查,统计数据------

特点:

  1. 拦截器可以分为系统拦截器和自定义拦截器。

  2. 一个项目中可以有多个拦截器,也可以没有

  3. 拦截器侧重拦截用户的请求。

  4. 拦截器是在请求处理之前先执行的。

拦截器的定义:

  1. 创建类实现拦截器接口HandlerInterceptor,实现接口中的方法(3个)

  2. 在springmvc配置文件中,声明拦截对象,并指定拦截的uri地址

4.3.1 第一个拦截器

/**
 *  拦截器
 */
public class MyInterceptor implements HandlerInterceptor {
    /**
     * preHandle:预先处理请求的方法  总开关
     *     参数:
     *         Object handler: 被拦截的控制器对象(MyController)
     *     返回值: boolean
     *      true:请求是正确的,可以被controller执行
     *        ====MyInterceptor拦截器preHandle====
     *        执行了MyController的doSome方法
     *        ====MyInterceptor拦截器postHandle====
     *        ====MyInterceptor拦截器afterCompletion====
     *      false:请求不能被处理,控制器方法不会执行。请求到此截至
     *        ====MyInterceptor拦截器preHandle====
     *   特点:
     *   1.预处理方法的执行时间,控制器方法执行之前先执行
     *   2.可以对请求做处理,可以做登录验证,权限的判断,统计数据等等
     *   3.决定请求是否执行
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("====MyInterceptor拦截器preHandle====");
        //提示
        //request.getRequestDispatcher("/tips.jsp").forward(request,response);
        return true;
    }

    /**
     * postHandle 后处理方法
     *  参数:
     *     Object handler: 被拦截的控制器对象(MyController)
     *     ModelAndView mv: 控制器方法的返回值(请求的执行结果)
     *
     *   特点:
     *      1.后处理方法的执行时间,控制器方法执行之后执行
     *      2.能获取到控制器方法的执行结果,可以修改原来的执行结果
     *        可以修改数据,也可以修改视图
     *      3.可以做对请求的二次处理
     *
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView mv) throws Exception {
        System.out.println("====MyInterceptor拦截器postHandle====");
        //对请求做二次处理
        if(mv!=null){
           mv.addObject("mydate",new Date());
           //修改视图
            mv.setViewName("other");
        }
    }

    /**
     * afterCompletion 最后执行的方法
     *  参数:
     *     Object handler: 被拦截的控制器对象(MyController)
     *     Exception ex: 异常对象
     *
     *   特点:
     *      1.请求处理完成后执行的,
     *       请求处理完成的标志是 视图处理完成,对视图执行forword操作后
     *      2.可以做程序最后要做的工作,释放内存,清理临时变量。
     *      3.方法执行的条件:
     *         1.当前拦截器的preHandle()方法必须执行。
     *         2.preHandle()必须返回true。
     *
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("====MyInterceptor拦截器afterCompletion====");

        //获取数据
        HttpSession session =request.getSession();
        Object attr=session.getAttribute("attr");
        System.out.println("attr=="+attr);

        //删除数据
        session.removeAttribute("attr");

        //确定数据是否删除
        attr = session.getAttribute("attr");
        System.out.println("删除后,再次检查数据=="+attr);

        /*
         * ====MyInterceptor拦截器preHandle====
           执行了MyController的doSome方法
           ====MyInterceptor拦截器postHandle====
           ====MyInterceptor拦截器afterCompletion====
           attr==在controller中增加的临时数据
           删除后,再次检查数据==null
         */
    }
}

springmvc配置文件:

<!--声明拦截器-->
<mvc:interceptors>
    <!--声明第一个拦截器-->
    <mvc:interceptor>
        <!--指定拦截器的拦截地址
        path:拦截的uri地址,可以使用 ** 通配符
              例如: path="/user/**"-->
        <mvc:mapping path="/**"/>
        <!--<mvc:exclude-mapping path=""/> 指定不拦截的地址-->
        <!--指定使用的拦截器-->
        <bean class="com.zd.handler.MyInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

MyController类:

@Controller
public class MyController {

    @RequestMapping(value={"/some.do"})
    public ModelAndView doSome(HttpSession session,String name,Integer age) {
        System.out.println("执行了MyController的doSome方法");

        //添加一个临时数据
        session.setAttribute("attr","在controller中增加的临时数据");

        ModelAndView mv =new ModelAndView();
        //添加数据
        mv.addObject("myname",name);
        mv.addObject("myage",age);
        

        mv.setViewName("show");
        return mv;
    }
}

当preHandle返回true,执行结果:

====MyInterceptor拦截器preHandle====
执行了MyController的doSome方法
====MyInterceptor拦截器postHandle====
====MyInterceptor拦截器afterCompletion====

请求的执行顺序:
用户some.do--->preHandle---->controller(doSome)---->postHandle---->afterComplietion

当preHandle返回false,执行结果:

====MyInterceptor拦截器preHandle====

4.3.2 多个拦截器

使用两个拦截器,主要看拦截器的执行顺序,以及哪个方法控制请求的执行

  1. 两个拦截器,第一个preHandle=true,第二个拦截器preHandle=true

====MyInterceptor1111111拦截器preHandle====
====MyInterceptor222222拦截器preHandle====
执行了MyController的doSome方法
====MyInterceptor222222拦截器postHandle====
====MyInterceptor1111111拦截器postHandle====
====MyInterceptor222222拦截器afterCompletion====
====MyInterceptor1111111拦截器afterCompletion====

请求的执行顺序:

用户some.do--->拦截器1的preHandle--->拦截器2的preHandle--->controller(doSome)--->控制器doSome--->拦截器2的postHandle--->拦截器1的postHandle--->拦截器2的afterCompletion--->拦截器1的afterCompletion.

  1. 两个拦截器,第一个preHandle=true,第二个拦截器preHandle=false

    ====MyInterceptor1111111拦截器preHandle====
    ====MyInterceptor222222拦截器preHandle====
    ====MyInterceptor1111111拦截器afterCompletion====
    

    请求的执行顺序:

    用户some.do--->拦截器1的preHandle--->拦截器2的preHandle--->controller(doSome)--->拦截器1的afterCompletion。

  2. 两个拦截器,第一个preHandle=true,第二个拦截器preHandle=true|false

    ====MyInterceptor1111111拦截器preHandle====

    请求的执行顺序:

    用户some.do--->拦截器1的preHandle

  3. 为什么要使用多个拦截器?

    1. 把验证功能分散到独立的拦截器,每个拦截器做单一的验证处理。

    2. 组合多个拦截器。

  4. 总结:

    多个拦截器,串在一个链条上的。多个拦截器和一个控制器对象在一个链条上,框架使用HandlerExecutionChain(处理器执行链),表示这个执行的链条

    public class HandlerExecutionChain {
    
        private final Object handler; //存放控制器对象的,MyController
        @Nullable
        private HandlerInterceptor[] interceptors; //存放拦截器对象的,MyInterceptor 1,2....
        @Nullable
        private List<HandlerInterceptor> interceptorList;
    }

    拦截器怎么实现1,2,2,1,2,1的执行顺序,遍历HandlerInterceptor[] interceptors 数组

    //1-2
    HandlerInterceptor[] interceptors ={MyInterceptor1,MyInterceptor2};
    //使用循环调用的方法
    for(int i=0;i<interceptors.length;i++){
        HandlerInterceptor obj=interceptors][i];
        obj.preHandle();
    }
    Mycontroller.doSome();
    
    //2-1
    for(int i=interceptors.length-1;i>=0;i--){
        HandlerInterceptor obj =interceptors[i];
        obj.postHandle;
    }

4.3.3 拦截器和过滤器的对比

  1. 拦截器是springmvc框架中的对象,过滤器是servlet中的对象

  2. 拦截器对象是框架容器创建的,过滤器对象是tomcat创建的对象

  3. 拦截器是侧重对请求做判断的,处理的,可以截断请求。过滤器是侧重对request,response对象的属性,参数设置值的。例如request.setCharacterEncoding("utf-8");

  4. 拦截器执行的时间有三个,控制方法之前,之后,请求完成后,过滤器是在请求之前。

  5. 拦截器是拦截对controller,动态资源请求的。过滤器可以过滤所有请求动态的和静态的。

  6. 拦截器和过滤器一起执行的话,先执行过滤器,后是中央调度器,后是拦截器,最后面是控制器方法

猜你喜欢

转载自blog.csdn.net/weixin_53630942/article/details/124000780