一.简介

  1. SpringMVC是一个基于MVC模式的WEB/表现层框架,它解决WEB开发中常见的问题:参数接收、文件上传/下载、表单验证、国际化(时间处理)等等;
  2. SpringMVC需要的jar包:
    • spring-webmvc-4.1.2.RELEASE.jar SpringMVC核心包
    • spring-web-4.1.2.RELEASE.jar Spring对Web项目项目的支持

二. 核心控制器

  1. SpringMVC中使用的是DispatcherServlet为核心控制器. DispatcherServlet核心控制器会拦截匹配的请求,把拦截下来的请求,依据相应的规则分发到目标Controller来处理;

  2. Spring的相关jar包:地址https://gitee.com/coderyeah/layui-module/tree/master/lib/spring%E7%9A%84jar

    Ø com.springsource.org.apache.commons.logging-1.1.1.jar

    Ø spring-beans-4.1.2.RELEASE.jar

    Ø spring-context-4.1.2.RELEASE.jar

    Ø spring-core-4.1.2.RELEASE.jar

    Ø spring-expression-4.1.2.RELEASE.jar

    Ø spring-aop-4.1.2.RELEASE.jar — Spring测试需要导入此包

  3. 在web.xml配置核心控制器(容器启动时就创建sevlet实例对象,并加载classpath下的一个名为spring-mvc.xml文件)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    <!-- 配置前端控制器   -->
    <servlet>
    <servlet-name>dispatcherServlet</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>
    <!-- 默认的是第一次访问加载配置文件,这里设置tomcat启动时就加载配置文件 提高访问效率 -->
    <!-- 数字表示访问级别 正整数值越低级别越高 -->
    <load-on-startup>1</load-on-startup>
    </servlet>
    <!-- 拦截所有请求给 dispatcherServlet处理 -->
    <servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <!-- /*会拦截所有; /会放行jsp -->
    <url-pattern>/</url-pattern>
    <!-- <url-pattern>/*</url-pattern>-->
    </servlet-mapping>
  4. 配置文件模板

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    <?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
    http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- 组件扫描 -->
    <context:component-scan base-package="com.lqs.controller" />

    <!-- 开启spring对springmvc的注解支持 -->
    <mvc:annotation-driven />

    <!-- 对于静态资源(图片,css,js,html)进行放行 -->
    <mvc:default-servlet-handler />

    <!-- 设置视图路径的前后缀,该配置可以让我们写视图路径的时候更简单。 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <!--前缀: jsp在当前工程文件夹的路径 -->
    <property name="prefix" value="/WEB-INF/jsp/" />
    <!--后缀:扩展名 -->
    <property name="suffix" value=".jsp" />
    </bean>

    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <!-- 设置上传文件的最大尺寸为1MB -->
    <!-- 设置上传文件的最大尺寸为5MB -->
    <property name="maxUploadSize" value="#{1024*1024*5}"/>
    </bean>
    </beans>

三. 注解

  1. 指定请求方法:@RequestMapping(value = “/upload”, method = RequestMethod.GET)

  2. 实例化bean注解:

    1. 指定一个包路径,Spring会自动扫描该包及其子包所有类,当发现类定义前有特定的注解标记时,就将该类的对象实例化并纳入到Spring容器中,等价于原有XML配置中定义功能;
    2. 组件扫描可以替代大量XML配置的定义;
    3. 需要在XML配置中指定扫描路径:;容器在实例化对象时会自动扫描com.lqs.controller包及其子包下所有类,如果有多个包可以再写一条
  3. 注解标记

    img

四. 注入注解

  1. 具有依赖关系的Bean对象,利用此注解可以实现关系注入:@Autowired、@Resource;
  2. 这些注解标记可以用在字段定义或setter方法定义前面,一般用于注入容器中对象,该注解可以直接写在字段上,那么就不需要setter方法了;
  3. 注意:使用该注解之前,一定要确保容器中是否有该类型的对象,否则注入失败。

五. 参数传递

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

@Controller
@RequestMapping("/login")
public class LoginController {
@RequestMapping("/form1")
@ResponseBody
public String form1(HttpServletRequest req) {
final String name = req.getParameter("name");
final String pwd = req.getParameter("pwd");
System.out.println(name + " : " + pwd);
return name + " - " + pwd;
}

@RequestMapping("/form2")
@ResponseBody
public String form1(String name, String pwd) {
System.out.println(name + " : " + pwd);
return name + " - " + pwd;
}

@RequestMapping("/form3")
@ResponseBody
public String form1(User user) {
System.out.println(user.getName() + " : " + user.getName());
return user.getName() + " : " + user.getPwd();
}

@RequestMapping("/form4/{id}/{name}")
@ResponseBody
public String form4(@PathVariable("id") String id, @PathVariable("name") String name) {
System.out.println(id);
return id + " " + name;
}

//给页面传值
@RequestMapping("/form5")
public String form5(HttpServletRequest req) {
req.setAttribute("message5", "coderyeah爱喝水水");
return "model2";
}

@RequestMapping("/form6")
public String form5(Model model) {
model.addAttribute("message6", "我是我滴神");
return "model2";
}

@RequestMapping("/form7")
public ModelAndView form7(ModelAndView mav) {
mav.addObject("message7", "springmvc的宝贝");
mav.setViewName("model2");
return mav;
}


}

六. 解决乱码

  1. 自定义Filter

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    package com.lqs.filter;


    import javax.servlet.*;
    import java.io.IOException;

    public class MyFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    System.out.println("过滤器初始化。。。。。");
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain filterChain) throws IOException, ServletException {
    System.out.println("filter被执行了。。。。");
    //过滤器在servlet之前执行 拦截所有请求
    req.setCharacterEncoding("UTF-8");
    resp.setCharacterEncoding("UTF-8");
    resp.setContentType("text/html;charset=utf-8");
    //放行
    filterChain.doFilter(req, resp);
    }

    @Override
    public void destroy() {
    System.out.println("filter被销毁了");
    }
    }

  2. springmvc的过滤配置(web.xml)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
     <!-- 配置过滤器   -->
    <!-- <filter>
    <filter-name>myFilter</filter-name>
    <filter-class>com.lqs.filter.MyFilter</filter-class>
    </filter>
    <filter-mapping>
    <filter-name>myFilter</filter-name>
    &lt;!&ndash; 过滤所有请求 &ndash;&gt;
    <url-pattern>/*</url-pattern>
    </filter-mapping>-->


    <!-- 支持UTF-8编码 -->
    <filter>
    <filter-name>characterEncoding</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>
    <!--强制指定字符编码,即使request或response设置了字符编码,也会强制使用当前设置的,任何情况下强制使用此编码-->
    <init-param>
    <param-name>forceEncoding</param-name>
    <param-value>true</param-value>
    </init-param>
    </filter>
    <filter-mapping>
    <filter-name>characterEncoding</filter-name>
    <url-pattern>/*</url-pattern>
    </filter-mapping>
  3. 返回前端中文乱码解决

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @Autowired
    private XXXService xxxService;

    @RequestMapping(value = "test", produces = "application/json;charset=utf-8")//解决相应乱码
    @ResponseBody
    public String test() {
    xxxService.test();
    return "test被执行了哦";
    }

七. 自定义请求转发和自定义重定向

  1. forward

    1
    2
    3
    4
    5
    6
    @RequestMapping("/index")
    public String index(Model model) {
    model.addAttribute("msg", "121212");
    //自定义请求转发
    return "forward:/index.jsp";
    }
  2. redirect

    1
    2
    3
    4
    5
    6
    @RequestMapping("/index2")
    public String index2(Model model) {
    model.addAttribute("msg", "1212地方法规12");
    //自定义重定向 不能共享数据哦
    return "redirect:/index.jsp";
    }
  3. 编码和解码

    1
    2
    3
    4
    5
    public static void main(String[] args) throws UnsupportedEncodingException {
    //编码和解码
    System.out.println(URLEncoder.encode("1212叫阿三的12", "UTF-8"));
    System.out.println(URLDecoder.decode("1212%E5%8F%AB%E9%98%BF%E4%B8%89%E7%9A%8412", "UTF-8"));
    }

八. Java对象转换成json格式数据

  1. 需要jar包

    image-20220804174631507

  2. @ResponseBody注解

    • 返回值是通过json流的方式输出,springmvc获取返回值,把对象自动转换位json,然后通过resp.getWrite().print(jsonString)返回json数据。
    • 将返回的数据自动转换成json格式的数据,而且是用了@ResponseBody,不会经过视图解析器
  3. Json中对日期格式的特殊处理

    image-20220805110611265

    • 默认返回的日期格式为时间戳,而在前台我们希望显示出指定规则的日期字符串:

      1
      2
      3
      4
      5
      6
      7
      8
      @Data
      @AllArgsConstructor
      public class User {
      private Long id;
      private String name;
      private String pwd;
      @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
      private Date birthday;//返回给前端时时间戳毫秒数 所以需要指定格式

九. 文件上传

  1. 需要jar包

  2. 配置上传解析器

    • SpringMVC使用MultipartFile来进行文件上传,所以我们首先要配置MultipartResolver,用于处理表单中的file;

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
        <!-- 设置视图路径的前后缀,该配置可以让我们写视图路径的时候更简单。 -->
      <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
      <!--前缀: jsp在当前工程文件夹的路径 -->
      <property name="prefix" value="/jsp/"/>
      <!--后缀:扩展名 -->
      <property name="suffix" value=".jsp"/>
      </bean>

      <!-- 文件上传解析器 将文件的所有信息封装到MultipartFile对象中
      然后就可以从MultipartFile对象获取文件信息
      -->
      <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
      <!-- &lt;!&ndash; 设置上传文件的最大尺寸 &ndash;&gt;-->
      <!-- 1024字节->1kb->100M=1024*1024*100 -->
      <property name="maxUploadSize" value="104857600"/>
      <!-- <property name="maxUploadSize" value="#{1024*1024*5}"/>-->
      <property name="defaultEncoding" value="utf-8"/>
      </bean>
    • 后台实现文件上传

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      //    @RequestMapping("upload")
      public String upload(String name, MultipartFile photo, Model model, HttpServletRequest req) throws IOException {
      System.out.println("photo:" + photo);
      System.out.println("文件名称:" + photo.getOriginalFilename());//back.jpeg 文件名称
      System.out.println("filename:" + photo.getName());//photo
      System.out.println("size:" + photo.getSize());//获取文件大小
      System.out.println("type:" + photo.getContentType());//image/jpeg 文件类型

      //判断文件是否为空
      if (photo == null || photo.getSize() <= 0) {
      model.addAttribute("error", "请选择文件!!!");
      return "upload";
      }

      //复制文件
      //获取字节输入流 读取文件
      final InputStream in = photo.getInputStream();
      //获取文件后缀
      final String filename = photo.getOriginalFilename();
      final String suffix = filename.substring(filename.lastIndexOf("."));//后缀 .png .jpg
      // 给定不重复文件名
      //1.时间戳
      String newFilename = System.currentTimeMillis() + suffix;
      //2.UUID
      // String newFilename = UUID.randomUUID().toString().replaceAll("-", "");//36位
      //获取上下文路径
      final ServletContext context = req.getServletContext();
      //获取upload文件夹的真实路径
      final String realPath = context.getRealPath("/upload");
      System.out.println("contextPath:" + context.getContextPath());
      System.out.println("realPath:" + realPath);
      //判断文件对象是否存在
      final File file = new File(realPath);
      if (!file.exists()) {
      //不存在创建文件夹
      file.mkdirs();//创建文件夹
      // file.createNewFile();//创建文件
      }
      //创建字节输出流
      final FileOutputStream os = new FileOutputStream(new File(realPath, newFilename));
      //调用工具类复制图片
      IOUtils.copy(in, os);
      //关流
      os.close();
      in.close();
      model.addAttribute("error", "success!");
      return "upload";
      }
  3. 封装文件上传工具类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    package com.lqs.util;

    import org.apache.commons.io.IOUtils;
    import org.springframework.web.multipart.MultipartFile;

    import java.io.*;

    public class UploadUtils {

    /**
    * 用于上传文件
    *
    * @param uploadPath 指定文件上传路径
    * @param file 需要上传的文件
    * @return 返回文件名称
    */
    public static String uploadFile(String uploadPath, MultipartFile file) {
    final File fileItem = new File(uploadPath);
    if (!fileItem.exists()) {
    fileItem.mkdirs();
    }
    if (file == null || file.getSize() <= 0) {
    return null;
    }
    final String filename = file.getOriginalFilename();
    final String suffix = filename.substring(filename.lastIndexOf("."));
    String newFilename = System.currentTimeMillis() + suffix;
    try (InputStream in = file.getInputStream();
    OutputStream os = new FileOutputStream(new File(uploadPath, newFilename));
    ) {
    IOUtils.copy(in, os);
    return newFilename;
    } catch (IOException e) {
    e.printStackTrace();
    }
    return null;
    }
    }

十. 文件下载

  1. 下载页面

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
    <title>下载文件</title>
    </head>
    <body>
    <h2>下载功能</h2>
    <ul>
    <li><a href="${pageContext.request.contextPath}/download?filename=star.mp4">star.mp4</a></li>
    <li><a href="${pageContext.request.contextPath}/download?filename=suiji.zip">suiji.zip</a></li>
    <li><a href="${pageContext.request.contextPath}/download?filename=words.txt">words.txt</a></li>
    <li><a href='${pageContext.request.contextPath}/download?filename=<%=URLEncoder.encode("女孩.jpg","utf-8")%>'>女孩.jpg</a></li>
    </ul>

    </body>
    </html>
  2. 后台代码 user–agent:这个请求头是指用户代理的意思,告诉服务器使什么浏览器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    /*
    * 下载文件
    */
    @RequestMapping("download")
    public String download(String filename, HttpServletRequest req, HttpServletResponse resp) throws Exception {
    //E:\javabase\spring_demo\out\artifacts\spring_demo_war_exploded\download 这是编译路径
    final String realPath = req.getServletContext().getRealPath("/download");
    System.out.println(realPath);
    //判断需要下载的文件是否还存在
    final File file = new File(realPath, filename);
    if (file.exists()) {//文件存在
    //获取输入流
    final FileInputStream in = new FileInputStream(file);
    //区分浏览器 解决中文乱码
    if (req.getHeader("User-Agent").toUpperCase().contains("TRIDENT")) {
    filename = URLEncoder.encode(filename, "utf-8");
    //电脑自带edge【edʒ】浏览器
    } else if (req.getHeader("User-Agent").toUpperCase().contains("EDGE")) {
    filename = URLEncoder.encode(filename, "utf-8");
    } else {//其他浏览器
    filename = new String(filename.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);//转码的方式
    }
    //设置文件下载的名字 -- 附件表示做下载或上传操作,浏览器就不会将文件的内容直接显示出来了
    resp.setHeader("Content-Disposition", "attachment; filename=" + filename);
    //获取输出流
    final ServletOutputStream os = resp.getOutputStream();
    //实现下载
    IOUtils.copy(in, os);
    //关流
    os.close();
    in.close();
    }
    return "redirect:/jsp/download.jsp";
    }

十一. SpringMVC拦截器

  1. 实现\HandlerInterceptor** 接口

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    public class MyInterceptor implements HandlerInterceptor {

    //preHandle()方法在业务处理器处理请求之前被调用
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
    throws Exception {
    System.out.println("进入拦截器了....");
    //这里可以判断用户是否登录
    //没有登录可以使用 request/response跳转回登录页面

    //注:如果不继续执行返回false,否则返回true
    return false;
    }

    // postHandle()方法在业务处理器处理请求之后被调用
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
    ModelAndView modelAndView) throws Exception {
    }

    // afterCompletion()方法在DispatcherServlet完全处理完请求后被调用
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
    throws Exception {
    }
    }
  2. 配置拦截器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <!--  配置拦截器组  -->
    <mvc:interceptors>
    <!-- 配置拦截器 -->
    <mvc:interceptor>
    <!-- 要拦截的配置,该配置必须写在不拦截的上面,/*拦截一级请求,/**拦截多级请求 -->
    <mvc:mapping path="/**"/>
    <!-- 设置不拦截的配置 -->
    <mvc:exclude-mapping path="/user/list"/>
    <!--配置拦截器-->
    <bean class="com.lqs.interceptor.MyInterceptor"/>
    </mvc:interceptor>
    </mvc:interceptors>

十二. SpringMVC执行流程

spring-mvc - 副本

1、用户发送请求到前端控制器(DispatcherServlet)。
2、前端控制器请求处理器映射器(HandlerMapping)去查找处理器(Handler)。
3、找到以后处理器映射器(HandlerMappering)向前端控制器返回执行链(HandlerExecutionChain)。
4、前端控制器(DispatcherServlet)调用处理器适配器(HandlerAdapter)去执行处理器(Handler)。
5、处理器适配器去执行Handler。
6、处理器执行完给处理器适配器返回ModelAndView。
7、处理器适配器向前端控制器返回ModelAndView。
8、前端控制器请求视图解析器(ViewResolver)去进行视图解析。
9、视图解析器向前端控制器返回View。
10、前端控制器对视图进行渲染。
11、前端控制器向用户响应结果。

十三. SpringMVC接口

  • Spring MVC 涉及到的组件有 DispatcherServlet(前端控制器)、HandlerMapping(处理器映射器)、HandlerAdapter(处理器适配器)、Handler(处理器)、ViewResolver(视图解析器)和 View(视图)。
  1. DispatcherServlet

    Spring MVC 的所有请求都要经过 DispatcherServlet 来统一分发。DispatcherServlet 相当于一个转发器或中央处理器,控制整个流程的执行,对各个组件进行统一调度,以降低组件之间的耦合性,有利于组件之间的拓展。

  2. HandlerMapping

    HandlerMapping 是处理器映射器,其作用是根据请求的 URL 路径,通过注解或者 XML 配置,寻找匹配的处理器(Handler)信息。

  3. HandlerAdapter

    HandlerAdapter 是处理器适配器,其作用是根据映射器找到的处理器(Handler)信息,按照特定规则执行相关的处理器(Handler)。

  4. Handler

    Handler 是处理器,和 Java Servlet扮演的角色一致。其作用是执行相关的请求处理逻辑,并返回相应的数据和视图信息,将其封装至 ModelAndView 对象中。

  5. View Resolver

    View Resolver 是视图解析器,其作用是进行解析操作,通过 ModelAndView 对象中的 View 信息将逻辑视图名解析成真正的视图 View(如通过一个 JSP 路径返回一个真正的 JSP 页面)。

  6. View

    View 是视图,其本身是一个接口,实现类支持不同的 View 类型(JSP、FreeMarker、Excel 等)。

十四. 拦截器和过滤器的区别

  1. 过滤器Filter属于Servlet级别,拦截器Interceptor属于SpringMVC级别;
  2. 过滤器先执行,拦截器后执行;
  3. 过滤器基于函数回调方式实现,拦截器是基于反射方式实现。

image-20220805182430631

十五. 流程

  1. 用户向服务器发送请求,请求会统一交给SpringMVC前端控制DispatcherServlet处理;

  2. DispatcherServlet通过请求HandlerMapping(处理器映射管理对象)找到该请求对应的Handler对象(包括控制器以及Handler对象对应的拦截器) 和HandlerExecutionChain对象(包含:控制器+2个拦截器);

  3. DispatcherServlet请求HandlerAdapter,选择一个合适的HandlerAdapter去处理Handler。(附注:如果成功获得HandlerAdapter后,此时将开始执行拦截器的preHandler(…)方法);

  4. 提取request中的模型数据,填充Handler入参,开始执行Handler(Controller)。 在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:

Ø HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息

Ø 数据转换:对请求消息进行数据转换。如String转换成Integer、Double等

Ø 数据格式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等

Ø 数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中

  1. Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象;

  2. 根据返回的ModelAndView,选择一个适合的ViewResolver(必须是已经注册到Spring容器中的ViewResolver)返回给DispatcherServlet;

  3. ViewResolver 结合Model和View,来渲染视图(Model+View合成)

  4. 将渲染结果返回给客户端;

十六. 简易版:

  1. 客户端将请求统一提交到DispatcherServlet;

  2. DispatcherServlet会将请求交给HandlerMapping进行请求映射,匹配该请求的Handler;

  3. DispatcherServlet再请求HandlerAdapter调用相应的Handler处理请求,并向前端控制器返回一个ModelAndView对象;

  4. DispatcherServlet将ModelAndView对象交给ViewResoler视图解析器处理,返回指定的视图View;

  5. DispatcherServlet 对 View 进行渲染(即将模型数据填充至视图中);

  6. DispatcherServlet 将页面响应给用户。

十七. SSM整合

  1. applicationContext.xml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    <?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:tx="http://www.springframework.org/schema/tx"
    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
    http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <!-- 配置资源文件路径
    system-properties-mode:表示配置文件使用username不会报错,否则会将username当初系统名称
    -->
    <context:property-placeholder location="classpath:db.properties" system-properties-mode="NEVER"/>
    <context:component-scan base-package="com.lqs"/>

    <!-- 管理连接池对象 -->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName" value="${driverClassName}"/>
    <property name="url" value="${url}"/>
    <property name="username" value="${username}"/>
    <property name="password" value="${password}"/>
    <property name="maxActive" value="${dbcp.maxActive}"/>
    <property name="maxIdle" value="${dbcp.maxIdle}"/>
    <property name="minIdle" value="${dbcp.minIdle}"/>
    <property name="minEvictableIdleTimeMillis" value="${dbcp.minEvictableIdleTimeMillis}"/>
    </bean>

    <!-- 配置SqlSessionFactory对象 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <!-- XML方式注入连接池对象 -->
    <property name="dataSource" ref="dataSource"/>
    <!-- 配置别名包 -->
    <property name="typeAliasesPackage" value="com.lqs.domain"/>
    <!-- 加载sql映射文件 -->
    <property name="mapperLocations" value="classpath:/mapper/*.xml"/>
    </bean>

    <!-- 管理mapper的代理对象 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <!--
    扫描mapper接口的包,Spring会自动根据这个配置去扫描这个包下的所有mapper接口
    生成代理对象,交给spring管理
    -->
    <property name="basePackage" value="com.lqs.mapper"/>
    </bean>
    <!-- 定义事务管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
    </bean>
    <!-- 7. 注解驱动,启动事务注解 -->
    <tx:annotation-driven transaction-manager="transactionManager"/>
    </beans>
  2. db.properties

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    driverClassName=com.mysql.jdbc.Driver
    url=jdbc:mysql://127.0.0.1:3306/ssm
    username=root
    password=123456
    #DBCP
    dbcp.initialSize=1
    dbcp.maxIdle=20
    dbcp.maxActive=20
    dbcp.minIdle=5
    dbcp.maxWaitMillis=1000
    dbcp.timeBetweenEvictionRunsMillis=6000
    dbcp.numTestsPerEvictionRun=10
    dbcp.minEvictableIdleTimeMillis=30000
    dbcp.validationQuery = SELECT 1
    dbcp.testWhileIdle = true
    dbcp.testOnBorrow = true
    dbcp.removeAbandonedTimeout=180
  3. spring-mvc.xml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    <?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
    http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <!-- 组件扫描-->
    <context:component-scan base-package="com.lqs.controller"/>
    <!-- 开启RequestMapping 注解支持 -->
    <mvc:annotation-driven/>
    <!-- 静态资源放行 -->
    <mvc:default-servlet-handler/>
    <!-- 视图解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/views/"/>
    <property name="suffix" value=".jsp"/>
    </bean>

    <!-- 文件上传解析器 -->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="maxUploadSize" value="#{1024*1024*3}"/>
    <property name="defaultEncoding" value="UTF-8"/>
    </bean>

    </beans>
  4. log4j.properties

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #控制台输出+自定义布局
    log4j.rootLogger=DEBUG,my
    #指定输出器
    log4j.appender.my=org.apache.log4j.ConsoleAppender
    #指定布局器(自定义布局)
    #指定布局为自定义布局
    log4j.appender.my.layout=org.apache.log4j.PatternLayout
    #指定在自定义布局的格式,%d -- 表示当前系统时间,%t -- 执行该业务的线程名称,%p -- 日记器的级别,-5 -- 5表示输出字符的个数,符号表示右对齐
    #%c -- 表示指定业务所在的类的完全限定名(包名.类名),%m -- 输出额外信息,%n -- 表示换行
    log4j.appender.my.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
    #设置package(可以是自定义的包也可以是api的包)输出级别
    log4j.logger.org.springframework=info
    log4j.logger.com.lqs=debug
  5. spring测试

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:applicationContext.xml")
    public class MyTest {
    // DI依赖注入
    @Autowired
    private BasicDataSource dataSource;
    @Autowired
    private SqlSessionFactoryBean factoryBean;
    @Autowired
    private MapperScannerConfigurer mapperScannerConfigurer;

    @Autowired
    private EmpMapper empMapper;

    @Test
    public void test1() {
    System.out.println(dataSource.getUrl());
    System.out.println(dataSource.getUsername());

    System.out.println("------------------");
    System.out.println(factoryBean);
    System.out.println(factoryBean.getDatabaseIdProvider());

    System.out.println("-------------");
    System.out.println(mapperScannerConfigurer);
    }

    @Test
    public void testQueryAll() {
    // empMapper.queryAll().forEach(System.out::println);
    System.out.println(empMapper.queryById(1));
    }
    }
  6. spring整合mybatis所需jar

    image-20220806180924417