SpringMVC

第1章 SpringMVC 概述

SpringMVC 简介

  • SpringMVC 也叫 Spring web mvc。是 Spring 框架的一部分,是在 Spring3.0 后发布的。

SpringMVC 优点

  1. 基于 MVC 架构,功能分工明确,解耦合  

  2. 容易理解,上手快;使用简单。

  3. 作为Spring框架一部分,能够使用Spring的IoC和Aop。方便整合Strtus,MyBatis,Hiberate,JPA 等其他框架。

  4. SpringMVC 强化注解的使用,在控制器,Service,Dao 都可以使用注解。方便灵活。
    使用@Controller 创建处理器对象,@Service 创建业务对象,@Autowired 或者@Resource,在控制器类中注入 Service, Service 类中注入 Dao。

第一个SpringMVC程序

新建maven web项目

pom.xml加入依赖

<dependency>
	<groupId>junit</groupId>
	<artifactId>junit</artifactId>
	<version>4.11</version>
	<scope>test</scope>
</dependency>
<dependency>
	<groupId>javax.servlet</groupId>
	<artifactId>javax.servlet-api</artifactId>
	<version>3.1.0</version>
	<scope>provided</scope>
</dependency>
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-webmvc</artifactId>
	<version>5.2.5.RELEASE</version>
</dependency>

注册中央调度器(DispatcherServlet)

  • springmvc的核心对象DispatcherServlet(本质是一个servlet)需要在tomcat服务器启动后,创建DispatcherServlet对象
    的实例。初始化会执行init()方法,读取springMVC配置文件得到springMVC容器和里面的对象。

    1. 创建容器,读取配置文件
      WebApplicationContext ctx = new ClassPathXmlApplicationContext("springmvc.xml");
    2. 把容器对象放入到ServletContext中

    getServletContext().setAttribute(key, ctx);

  • springmvc创建容器对象时,读取的配置文件默认是/WEB-INF/<servlet-name>-servlet.xml,可以在xml中指定自定义文件的位置

    <web-app>
        <servlet>
          <servlet-name>myweb</servlet-name>
          <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    
          <!--自定义springmvc读取的配置文件的位置-->
          <init-param>
            <!--springmvc的配置文件的位置的属性-->
            <param-name>contextConfigLocation</param-name>
            <!--指定自定义文件的位置-->
            <param-value>classpath:springmvc.xml</param-value>
          </init-param>
    
          <load-on-startup>1</load-on-startup>
        </servlet>
    <!-- load-on-startup:它的值是整数
    当值大于等于 0 时,表示容器在启动时就加载并初始化这个 servlet,数值越小,Servlet的优先级就越高,其被创建的也就越早;
    当值小于 0 或者没有指定时,则表示该 Servlet 在真正被使用时才会去创建。
    当值相同时,容器会自己选择创建顺序。-->
    
  • 使用框架的时候, url-pattern可以使用两种值
    1)使用扩展名方式, 语法 *.xxxx , xxxx是自定义的扩展名。 常用的方式 *.do, *.action, *.mvc等等
    不能使用 *.jsp
    2)使用斜杠 "/"

        <servlet-mapping>
          <servlet-name>myweb</servlet-name>
          <url-pattern>*.do</url-pattern>
        </servlet-mapping>
    </web-app>
    

创建springMVC配置文件

<?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: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 https://www.springframework.org/schema/context/spring-context.xsd">

    <!--声明组件扫描器-->
    <context:component-scan base-package="cn.JInterest.controller" />

    <!--声明 springmvc框架中的视图解析器, 帮助开发人员设置视图文件的路径-->
    <bean  class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--前缀:视图文件的路径-->
        <property name="prefix" value="/WEB-INF/view/" />
        <!--后缀:视图文件的扩展名-->
        <property name="suffix" value=".jsp" />
    </bean>
</beans>

创建处理器

@Controller:

  • 作用:创建控制器(处理器)对象,对象放在springmvc容器中。
  • 位置:在类的上面
    能处理请求的都是控制器(处理器),叫做后端控制器(back controller)

@RequestMapping:请求映射

  • 作用:把一个请求地址和一个方法绑定在一起。一个请求指定一个方法处理。
  • 属性
    1)value 是一个String,表示请求的uri地址的(some.do)。value值必须是唯一,在使用时,推荐地址以“/”开始
    2)method 表示请求的方式。 它的值RequestMethod类枚举值。例如表示get请求方式, RequestMethod.GET。不写表示可以接受get和post
  • 位置
    1)在方法的上面,常用的。
    2)在类的上面 ,value=所有请求地址的公共部分,叫做模块名称
  • 说明
    使用RequestMapping修饰的方法叫做处理器方法或者控制器方法,是可以处理请求的,类似Servlet中的doGet, doPost
  • 返回值
    ModelAndView 表示本次请求的处理结果
    Model: 数据,请求处理完成后,要显示给用户的数据 View: 视图, 比如jsp等等。
/*
   处理用户提交的请求,springmvc中是使用方法来处理的。
   方法是自定义的, 可以有多种返回值, 多种参数,方法名称自定义
*/
@Controller
public class MyController {

    @RequestMapping(value = {"/some.do","/first.do"})
    public ModelAndView doSome(){  
        //service调用...
        //处理some.do请求。

        ModelAndView mv  = new ModelAndView();
        //添加数据, 框架在请求的最后把数据放入到request作用域。
        //request.setAttribute("msg","欢迎使用springmvc做web开发");
        mv.addObject("msg","欢迎使用springmvc做web开发");
        mv.addObject("fun","执行的是doSome方法");

        //指定视图, 指定视图的完整路径
        //框架默认对视图执行的forward操作, request.getRequestDispather("/show.jsp).forward(...)
        //mv.setViewName("/show.jsp");
		//放入WEB-INF/下受保护
        //mv.setViewName("/WEB-INF/view/show.jsp");
		//当配置了视图解析器后,可以使用逻辑名称(文件名),指定视图
        //框架会使用视图解析器的前缀 + 逻辑名称 + 后缀 组成完成路径, 这里就是字符连接操作
        ///WEB-INF/view/ + show + .jsp
        mv.setViewName("show");

        //返回mv
        return mv;
    }
    @RequestMapping(value = {"/other.do","/second.do"})
    public ModelAndView doOther(){
        ModelAndView mv  = new ModelAndView();
        mv.addObject("msg","====欢迎使用springmvc做web开发====");
        mv.addObject("fun","执行的是doOther方法");
        mv.setViewName("other");
        return mv;
    }

}

定义请求页面和目标页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>Title</title>
    </head>
    <body>
        <p>第一个springmvc项目</p>
        <p><a href="some.do">发起some.do的请求</a> </p>
        <p><a href="other.do">发起other.do的请求</a> </p>
    </body>
</html>

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page  isELIgnored="false"%>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h3>/WEB-INF/view/show.jsp从request作用域获取数据</h3><br/>
    <h3>msg数据: ${msg} </h3><br/>
    <h3>fun数据: ${fun} </h3>
</body>
</html>

SpringMVC执行流程(理解)

流程图

执行流程简单分析

(1)浏览器提交请求到中央调度器
(2)中央调度器直接将请求转给处理器映射器。
(3)处理器映射器会根据请求,找到处理该请求的处理器,并将其封装为处理器执行链后返回给中央调度器。
(4)中央调度器根据处理器执行链中的处理器,找到能够执行该处理器的处理器适配器。
(5)处理器适配器调用执行处理器。
(6)处理器将处理结果及要跳转的视图封装到一个对象 ModelAndView 中,并将其返回给处理器适配器。
(7)处理器适配器直接将结果返回给中央调度器。
(8)中央调度器调用视图解析器,将 ModelAndView 中的视图名称封装为视图对象。
(9)视图解析器将封装了的视图对象返回给中央调度器
(10)中央调度器调用视图对象,让其自己进行渲染,即进行数据填充,形成响应对象。
(11)中央调度器响应浏览器

第2章 SpringMVC的核心技术

请求重定向和转发

  • 请求处理完毕的两种跳转方式。
    求重定向和转发
    SpringMVC 框架把原来 Servlet 中的请求转发和重定向操作进行了封装。现在可以使用简单的方式实现转发和重定向。
  • forward:表示转发,实现 request.getRequestDispatcher("xx.jsp").forward()
  • redirect:表示重定向,实现 response.sendRedirect("xxx.jsp")
  • forward和redirect都是关键字, 共同的特点:不和视图解析器一同工作
  • 处理器方法可以返回ModelAndView, String , void 都可以使用forward,redirect
  • 语法:setViewName("redirect/forword:视图完整路径")

框架对重定向的操作:

  1. 框架会把Model中的简单类型的数据,转为string使用,作为hello.jsp的get请求参数使用。目的是在
    doRedirect.do 和 hello.jsp 两次请求之间传递数据

  2. 在目标hello.jsp页面可以使用参数集合对象 $获取请求参数值 ${param.myname}

  3. 重定向不能访问/WEB-INF资源

异常处理

  • springmvc框架采用的是统一,全局的异常处理。
    把controller中的所有异常处理都集中到一个地方。采用的是aop的思想。把业务逻辑和异常处理代码分开,解耦合。
  • 处理异常的方法和控制器方法的定义一样, 可以有多个参数,可以有ModelAndView,String, void,对象类型的返回值

@ControllerAdvice

  • 控制器增强(也就是说给控制器类增加功能--异常处理功能)
    位置:在类的上面。
    特点:必须让框架知道这个注解所在的包名,需要在springmvc配置文件声明组件扫描器。指定@ControllerAdvice所在的包名

@ExceptionHandler

  • value: 指定异常,表示此异常发生时执行所在方法。
    value没有值表示除指定外的异常执行所在的方法,只能有一个。
  • 形参:Exception,表示Controller中抛出的异常对象。通过形参可以获取发生的异常信息。
  • 异常发生处理逻辑:
    1)需要把异常记录下来, 记录到数据库,日志文件。记录日志发生的时间,哪个方法发生的,异常错误内容。
    2)发送通知,把异常的信息通过邮件,短信,微信发送给相关人员。
    1. 给用户友好的提示。

代码

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(value = NameException.class)
    public ModelAndView doNameException(Exception exception){

        ModelAndView mv = new ModelAndView();
        mv.addObject("msg","姓名必须是zs,其它用户不能访问");
        mv.addObject("ex",exception);
        mv.setViewName("nameError");
        return mv;
    }

    //处理AgeException
    @ExceptionHandler(value = AgeException.class)
    public ModelAndView doAgeException(Exception exception){
	
        ModelAndView mv = new ModelAndView();
        mv.addObject("msg","你的年龄不能大于80");
        mv.addObject("ex",exception);
        mv.setViewName("ageError");
        return mv;
    }

    //处理其它异常, NameException, AgeException以外,不知类型的异常
    @ExceptionHandler
    public ModelAndView doOtherException(Exception exception){
        //处理其它异常
        ModelAndView mv = new ModelAndView();
        mv.addObject("msg","你的年龄不能大于80");
        mv.addObject("ex",exception);
        mv.setViewName("defaultError");
        return mv;
    }
}
jsp--${ex.message}

拦截器

  1. 拦截器是springmvc中的一种,需要实现HandlerInterceptor接口。
  2. 拦截器和过滤器类似,功能方向侧重点不同。 过滤器是用来过滤器请求参数,设置编码字符集等工作。
    拦截器是拦截用户的请求,做请求做判断处理的。
  3. 拦截器是全局的,可以对多个Controller做拦截。
    一个项目中可以有0个或多个拦截器, 他们在一起拦截用户的请求。
  • 拦截器常用在:用户登录处理,权限检查, 记录日志。
  • 拦截器:看做是多个Controller中公用的功能,集中到拦截器统一处理。使用的aop的思想

拦截器的使用步骤:

  1. 定义类实现HandlerInterceptor接口

    public class MyInterceptor implements HandlerInterceptor {
    
  2. 在springmvc配置文件中,声明拦截器, 让框架知道拦截器的存在。

<mvc:interceptors>
        <!--声明第一个拦截器-->
        <mvc:interceptor>
            <!--指定拦截的请求uri地址
                path:就是uri地址,可以使用通配符 **
                      ** : 表示任意的字符,文件或者多级目录和目录中的文件
            -->
            <mvc:mapping path="/**"/>
            <!--声明拦截器对象-->
            <bean class="cn.JInterest.handler.MyInterceptor" />
        </mvc:interceptor>
</mvc:interceptors>

拦截器的执行时间:

  1. 在请求处理之前, 也就是controller类中的方法执行之前先被拦截。
  2. 在控制器方法执行之后也会执行拦截器。
  3. 在请求处理完成后也会执行拦截器。

拦截器实现的三个方法

preHandle()--预处理方法

  • 重要:是整个项目的入口,门户。
    当preHandle返回true 请求可以被处理。
    preHandle返回false,请求到此方法就截止。

  • 参数:
    Object handler :被拦截的控制器对象

  • 返回值boolean

    true:请求是通过了拦截器的验证,可以执行处理器方法。
    false:请求没有通过拦截器的验证,请求到达拦截器就截止了。 请求没有被处理拦截器的MyInterceptor的preHandle()

  • 特点:

    1. 方法在控制器方法(MyController的doSome)之前先执行的。用户的请求首先到达此方法
    2. 在这个 方法中可以获取请求的信息, 验证请求是否符合要求。
      可以验证用户是否登录, 验证用户是否有权限访问某个连接地址(url)。
      如果验证失败,可以截断请求,请求不能被处理。
      如果验证成功,可以放行请求,此时控制器方法才能执行。

postHandle()--后处理方法

  • 参数:
    Object handler:被拦截的处理器对象MyController
    ModelAndView mv:处理器方法的返回值

  • 特点:

    1. 在处理器方法之后执行的(MyController.doSome())
    2. 能够获取到处理器方法的返回值ModelAndView,可以修改ModelAndView中的数据和视图,可以影响到最后的执行结果。
    3. 主要是对原来的执行结果做二次修正,

afterCompletion()--最后执行的方法

  • 参数
    Object handler:被拦截器的处理器对象
    Exception ex:程序中发生的异常

  • 特点:

    1. 在请求处理完成后执行的。框架中规定是当你的视图处理完成后,对视图执行了forward。就认为请求处理完成。
      此时对 ModelAndView 再操作也对响应无济于事。
    2. 一般做资源回收工作的, 程序请求过程中创建了一些对象,在这里可以删除,把占用的内存回收。
    3. 当 preHandle()方法返回 true 时,会将该方法放到专门的方法栈中,等到对请求进行响应的所有工作完成之后才执行该方法。

多个拦截器

  • 多个拦截器中方法与处理器方法的执行顺序如下图:

    从图中可以看出,只要有一个 preHandle()方法返回 false,则上部的执行链将被断开,其后续的处理器方法
    与 postHandle()方法将无法执行。但,无论执行链执行情况怎样,只要方法栈中有方法,即执行链中只要有
    preHandle()方法返回 true,就会执行方法栈中的afterCompletion()方法。最终都会给出响应。

拦截器和过滤器的区别

  1. 过滤器是servlet中的对象, 拦截器是框架中的对象
  2. 过滤器实现Filter接口的对象, 拦截器是实现HandlerInterceptor
  3. 过滤器是用来设置request,response的参数,属性的,侧重对数据过滤的。
    拦截器是用来验证请求的,能截断请求。
  4. 过滤器是在拦截器之前先执行的。
  5. 过滤器是tomcat服务器创建的对象
    拦截器是springmvc容器中创建的对象
  6. 过滤器是一个执行时间点。
    拦截器有三个执行时间点
  7. 过滤器可以处理jsp,js,html等等
    拦截器是侧重拦截对Controller的对象。 如果你的请求不能被DispatcherServlet接收, 这个请求不会执行拦截器内容
  8. 拦截器拦截普通类方法执行,过滤器过滤servlet请求响应

第3章 处理器方法补充

处理器方法的参数

处理器方法可以包含以下四类参数,这些参数会在系统调用时由系统自动赋值,即程序员可在方法内直接使用。
➢ HttpServletRequest
➢ HttpServletResponse
➢ HttpSession
➢ 请求中所携带的请求参数

逐个参数接收

逐个接收请求参数:
要求: 处理器(控制器)方法的形参名和请求中参数名必须一致。同名的请求参数赋值给同名的形参框架接收请求参数

  1. 使用request对象接收请求参数
    String strName = request.getParameter("name");
    String strAge = request.getParameter("age");

  2. springmvc框架通过 DispatcherServlet 调用 MyController的doSome()方法调用方法时,按名称对应,把接收的参数赋值给形参
    doSome(strName,Integer.valueOf(strAge))
    框架会提供类型转换的功能,能把String转为 int ,long , float, double等类型。

  • 出现400客户端错误,是因为提交请求参数过程中,发生了问题。例如int类型接收了一个null。

对象参数接收

  • 创建一个vo类,作为处理器方法形参,类的属性是请求中的参数名
  • 请求过程中框架会创建java对象, 给属性赋值。 请求中的参数是name,框架会调用setName()

请求参数中文乱码问题

  • 在 web.xml 中注册字符集过滤器,即可解决 Spring 的请求参数的中文乱码问题。不过,
    最好将该过滤器注册在其它过滤器之前。因为过滤器的执行是按照其注册顺序进行的。
    <!--注册声明过滤器,解决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>
        <!--强制请求对象(HttpServletRequest)使用encoding编码的值-->
        <init-param>
            <param-name>forceRequestEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
        <!--强制应答对象(HttpServletResponse)使用encoding编码的值-->
        <init-param>
            <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>

处理器方法的返回值

@Controller
public class MyController {
    /**
     * 处理器方法返回String--表示逻辑视图名称,需要配置视图解析器
     */
    @RequestMapping(value = "/returnString-view.do")
    public String doReturnView(HttpServletRequest request, String name, Integer age){
        System.out.println("doReturnView, name="+name+"   age="+age);
        //可以自己手工添加数据到request作用域
        request.setAttribute("myName",name);
        request.setAttribute("myAge",age);
        // show : 逻辑视图名称,项目中配置了视图解析器
        // 框架对视图执行forward转发操作
        return "show";
    }

    //处理器方法返回String,表示完整视图路径的时候, 此时不能配置视图解析器
    @RequestMapping(value = "/returnString-view2.do")
    public String doReturnView2(HttpServletRequest request,String name, Integer age){
        System.out.println("===doReturnView2====, name="+name+"   age="+age);
        //可以自己手工添加数据到request作用域
        request.setAttribute("myName",name);
        request.setAttribute("myAge",age);
        // 完整视图路径,项目中不能配置视图解析器
        // 框架对视图执行forward转发操作
        // /WEB-INF/view//WEB-INF/view/show.jsp.jsp
        return "/WEB-INF/view/show.jsp";
    }

    //处理器方法返回void, 响应ajax请求
    //手工实现ajax,json数据: 代码有重复的 1. java对象转为json; 2. 通过HttpServletResponse输出json数据
    @RequestMapping(value = "/returnVoid-ajax.do")
    public void doReturnVoidAjax(HttpServletResponse response, String name, Integer age) throws IOException {
        System.out.println("===doReturnVoidAjax====, name="+name+"   age="+age);
        //处理ajax, 使用json做数据的格式
        //service调用完成了, 使用Student表示处理结果
        Student student  = new Student();
        student.setName("张飞同学");
        student.setAge(28);

        String json = "";
        //把结果的对象转为json格式的数据
        if( student != null){
            ObjectMapper om  = new ObjectMapper();
            json  = om.writeValueAsString(student);
            System.out.println("student转换的json===="+json);
        }

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

    }


    /**
     * 处理器方法返回一个Student,通过框架转为json,响应ajax请求
     * @ResponseBody:
     *    作用:把处理器方法返回对象转为json后,通过HttpServletResponse输出给浏览器。
     *    位置:方法的定义上面。 和其它注解没有顺序的关系。
     * 返回对象框架的处理流程:
     *  1. 框架会把返回Student类型,调用框架的中ArrayList<HttpMessageConverter>中每个类的canWrite()方法
     *     检查那个HttpMessageConverter接口的实现类能处理Student类型的数据--MappingJackson2HttpMessageConverter
     *
     *  2.框架会调用实现类的write(), MappingJackson2HttpMessageConverter的write()方法
     *    把李四同学的student对象转为json, 调用Jackson的ObjectMapper实现转为json
     *    contentType: application/json;charset=utf-8
     *
     *  3.框架会调用@ResponseBody把2的结果数据输出到浏览器, ajax请求处理完成
     */
    @RequestMapping(value = "/returnStudentJson.do")
    @ResponseBody
    public Student doStudentJsonObject(String name, Integer age) {
        //调用service,获取请求结果数据 , Student对象表示结果数据
        Student student = new Student();
        student.setName("李四同学");
        student.setAge(20);
        return student; // 会被框架转为json

    }

    /**
     *  处理器方法返回List<Student>
     * 返回对象框架的处理流程:
     *  1. 框架会把返回List<Student>类型,调用框架的中ArrayList<HttpMessageConverter>中每个类的canWrite()方法
     *     检查那个HttpMessageConverter接口的实现类能处理Student类型的数据--MappingJackson2HttpMessageConverter
     *
     *  2.框架会调用实现类的write(), MappingJackson2HttpMessageConverter的write()方法
     *    把李四同学的student对象转为json, 调用Jackson的ObjectMapper实现转为json array
     *    contentType: application/json;charset=utf-8
     *
     *  3.框架会调用@ResponseBody把2的结果数据输出到浏览器, ajax请求处理完成
     */
    @RequestMapping(value = "/returnStudentJsonArray.do")
    @ResponseBody
    public List<Student> doStudentJsonObjectArray(String name, Integer age) {

        List<Student> list = new ArrayList<>();
        //调用service,获取请求结果数据 , Student对象表示结果数据
        Student student = new Student();
        student.setName("李四同学");
        student.setAge(20);
        list.add(student);

        student = new Student();
        student.setName("张三");
        student.setAge(28);
        list.add(student);


        return list;

    }

    /**
     * 处理器方法返回的是String , String表示数据的,不是视图。
     * 区分返回值String是数据,还是视图,看有没有@ResponseBody注解
     * 如果有@ResponseBody注解,返回String就是数据,反之就是视图
     *
     * 默认使用“text/plain;charset=ISO-8859-1”作为contentType,导致中文有乱码,
     * 解决方案:给RequestMapping增加一个属性 produces, 使用这个属性指定新的contentType.
     * 返回对象框架的处理流程:
     *  1. 框架会把返回String类型,调用框架的中ArrayList<HttpMessageConverter>中每个类的canWrite()方法
     *     检查那个HttpMessageConverter接口的实现类能处理String类型的数据--StringHttpMessageConverter
     *
     *  2.框架会调用实现类的write(), StringHttpMessageConverter的write()方法
     *    把字符按照指定的编码处理 text/plain;charset=utf-8
     *
     *  3.框架会调用@ResponseBody把2的结果数据输出到浏览器, ajax请求处理完成
     */
    @RequestMapping(value = "/returnStringData.do",produces = "text/plain;charset=utf-8")
    @ResponseBody
    public String doStringData(String name,Integer age){
        return "Hello SpringMVC 返回对象,表示数据成功";
    }

}

  • 加入注解驱动<mvc:annotation-driven/>后适配器类的 messageConverters 属性值

静态资源的处理

  • 在没有特殊要求的情况下,SpringMVC 的中央调度器 DispatcherServlet 的<url-pattern/>
    常使用后辍匹配方式,如写为*.do 或者*.action, *.mvc 等。
    当使用/时 DispatcherServlet 会将向静态资源的获取请求,当作是一个普通的 Controller 请求。中央调度器会调用处理器映射器为其查找相应的处理器。
    当然也是找不到的,所以在这种情况下,所有的静态资源获取请求也均会报 404 错误。
    解决方法
  1. 使用<mvc:default-servlet-handler/> 注册tomcat的默认servlet
    tomcat的web.xml文件有一个servlet名称是default ,在服务器启动时创建的,这个servlet能处理静态资源的访问
  2. 使用<mvc:resources/>(掌握)
    当服务器不是tomcat没有默认的servlet时,可以载springmvc配置文件中加入<mvc:resources/>专门用于处理静态资源访问请求
    <mvc:resources mapping="/static/" location="/static/** "/>
    • location 表示静态资源所在目录。当然,目录不要使用/WEB-INF/及其子目录。
    • mapping 表 示 对 该 资 源 的 请 求 ( 以 /static/开 始 的 请 求 , 如/static/beauty.jpg , /static/car.png 等)。注意,后面是两个星号**
  3. 声明注解驱动
  • 有静态资源访问就要加<mvc:annotation-driven />

path

  • 动态设置当前页面的所有链接规定默认地址或默认目标

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <%
        String basePath = request.getScheme() + "://" +
                request.getServerName() + ":" + request.getServerPort() +
                request.getContextPath() + "/";
    %>
    <html>
    	    <head>
    	    <title>Title</title>
    	    <base href="<%=basePath%>" />
    	</head>
    	<body>
    	     <p>第一个springmvc项目</p>
    	     <p><a href="user/some.do">发起user/some.do的get请求</a> </p>
    	     <br/>
    	</body>
    	</html>
    

第4章 SSM整合

  • SSM:SpringMVC 、 Spring 、 MyBatis.

  • SpringMVC: 视图层,界面层,负责接收请求,显示处理结果的。
    Spring:业务层,管理service,dao,工具类对象的。
    MyBatis:持久层, 访问数据库的

    • 用户发起请求--SpringMVC接收--Spring中的Service对象--MyBatis处理数据

    • SSM整合也叫做SSI (IBatis也就是mybatis的前身), 整合中有容器。

      1. 第一个容器SpringMVC容器, 管理Controller控制器对象的。
    1. 第二个容器Spring容器,管理Service,Dao,工具类对象的。
  • 我们要做的把使用的对象交给合适的容器创建,管理。

    1. 把Controller还有web开发的相关对象交给springmvc容器,这些web用的对象写在springmvc配置文件中

    2. service,dao对象定义在spring的配置文件中,让spring管理这些对象。

    springmvc容器是spring容器的子容器, 类似java中的继承。 子可以访问父的内容在子容器中的
    Controller可以访问父容器中的Service对象, 就可以实现controller使用service对象

实现步骤

  1. 准备数据库表
  2. 新建maven web项目
  3. 加入依赖
    • springmvc,spring,mybatis三个框架的依赖,jackson依赖,mysql驱动,druid连接池,jsp,servlet依赖
   <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>jsp-api</artifactId>
      <version>2.2.1-b03</version>
      <scope>provided</scope>
    </dependency>
    <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>
    <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>
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>1.3.1</version>
    </dependency>
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.1</version>
    </dependency>
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.9</version>
    </dependency>
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.1.12</version>
    </dependency>

写web.xml

  1. 注册DispatcherServlet ,目的:
    1)创建springmvc容器对象,才能创建Controller类对象。
    2)创建的是Servlet,才能接受用户的请求。

  2. 注册spring的监听器:ContextLoaderListener,目的: 创建spring的容器对象,才能创建service,dao等对象。

  3. 注册字符集过滤器,解决post请求乱码的问题

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
          version="4.0">
        <!--注册中央调度器-->
      <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:conf/dispatcherServlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
      </servlet>
      <servlet-mapping>
        <servlet-name>myweb</servlet-name>
        <url-pattern>*.do</url-pattern>
      </servlet-mapping>
    
      <!--注册spring的监听器-->
      <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:conf/applicationContext.xml</param-value>
      </context-param>
      <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
      </listener>
    
      <!--注册字符集过滤器-->
      <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>
          <param-name>forceRequestEncoding</param-name>
          <param-value>true</param-value>
        </init-param>
        <init-param>
          <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>
    
    </web-app>
    
  4. 创建包, Controller包, service ,dao,实体类包名创建好

    1. 写springmvc,spring,mybatis的配置文件

      • springmvc配置文件

        <?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:context="http://www.springframework.org/schema/context"
               xmlns:mvc="http://www.springframework.org/schema/mvc"
               xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
        
            <!--springmvc配置文件, 声明controller和其它web相关的对象-->
            <context:component-scan base-package="cn.JInterest.controller" />
        
            <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
                <property name="prefix" value="/WEB-INF/jsp/" />
                <property name="suffix" value=".jsp" />
            </bean>
        
            <mvc:annotation-driven />
            <!--
              1. 响应ajax请求,返回json
              2. 解决静态资源访问问题。
            -->
        </beans>
        
      • spring配置文件

        <?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: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 https://www.springframework.org/schema/context/spring-context.xsd">
        
         <!--spring配置文件: 声明service,dao,工具类等对象-->
        
         <context:property-placeholder location="classpath:conf/jdbc.properties" />
        
         <!--声明数据源,连接数据库-->
         <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
               init-method="init" destroy-method="close">
             <property name="url" value="${jdbc.url}" />
             <property name="username" value="${jdbc.username}" />
             <property name="password" value="${jdbc.passwd}" />
         </bean>
        
         <!--SqlSessionFactoryBean创建SqlSessionFactory-->
         <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
             <property name="dataSource" ref="dataSource" />
             <property name="configLocation"  value="classpath:conf/mybatis.xml" />
         </bean>
        
         <!--声明mybatis的扫描器,创建dao对象-->
         <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
             <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
             <property name="basePackage" value="cn.JInterest.dao" />
         </bean>
        
         <!--声明service的注解@Service所在的包名位置-->
         <context:component-scan base-package="cn.JInterest.service" />
        
         <!--事务配置:注解的配置, aspectj的配置-->
        </beans>
        
      • mybatis主配置文件

        <?xml version="1.0" encoding="UTF-8" ?>
        <!DOCTYPE configuration
                PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
                "http://mybatis.org/dtd/mybatis-3-config.dtd">
        <configuration>
            <!--settings:控制mybatis全局行为-->
            <!-- <settings>
                &lt;!&ndash;设置mybatis输出日志&ndash;&gt;
                <setting name="logImpl" value="STDOUT_LOGGING"/>
            </settings>-->
            <!--设置别名-->
            <typeAliases>
                <!--name:实体类所在的包名(不是实体类的包名也可以)-->
                <package name="cn.JInterest.domain"/>
            </typeAliases>
            <!-- sql mapper(sql映射文件)的位置-->
            <mappers>
                <!--
                  name:是包名, 这个包中的所有mapper.xml一次都能加载
                  使用package的要求:
                   1. mapper文件名称和dao接口名必须完全一样,包括大小写
                   2. mapper文件和dao接口必须在同一目录
                -->
                <package name="cn.JInterest.dao"/>
            </mappers>
        </configuration>
        
  5. 数据库的属性配置文件

jdbc.url=jdbc:mysql://localhost:3306/springdb?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT
jdbc.username=
jdbc.passwd=

写代码, dao接口和mapper文件, service和实现类,controller, 实体类。

写jsp页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    String basePath = request.getScheme() + "://" +
            request.getServerName() + ":" + request.getServerPort() +
            request.getContextPath() + "/";
%>
<html>
<head>
    <title>查询学生ajax</title>
    <base href="<%=basePath%>" />
    <script type="text/javascript" src="js/jquery-3.4.1.js"></script>
    <script type="text/javascript">
        $(function(){
            //在当前页面dom对象加载后,执行loadStudentData()
            loadStudentData();
            $("#btnLoader").click(function () {
                loadStudentData();
            });
        })

        function loadStudentData(){
            $.ajax({
                url:"student/queryStudent.do",
                type:"get",
                dataType:"json",
                success:function(data){
                    //清除旧的数据
                    $("#info").html("");
                    //增加新的数据
                    $.each(data,function(i,n){
                        $("#info").append("<tr>")
                            .append("<td>"+n.id+"</td>")
                            .append("<td>"+n.name+"</td>")
                            .append("<td>"+n.email+"</td>")
                            .append("<td>"+n.age+"</td>")
                            .append("</tr>")
                    })
                }
            })
        }
    </script>
</head>
<body>
    <div align="center">
        <table border="1">
            <thead>
             <tr>
                 <td>学号</td>
                 <td>姓名</td>
                 <td>邮箱</td>
                 <td>年龄</td>
             </tr>
            </thead>
            <tbody id="info">
            </tbody>
        </table>
        <input type="button" id="btnLoader" value="刷新数据">
    </div>
</body>
</html>

更新时间:2020-09-25 12:34:08

本文由 阿俊 创作,如果您觉得本文不错,请随意赞赏
采用 知识共享署名4.0 国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
原文链接:https://jinterest.cn/archives/springmvc
最后更新:2020-09-25 12:34:08

评论

Your browser is out of date!

Update your browser to view this website correctly. Update my browser now

×