Spring MVC原理、基于Spring MVC的文件上传与下载

Spring MVC框架教程

学习的目标:

  • Servlet开发步骤及问题
  • SpringMVC框架入门案例
  • SpringMVC的注解
  • 页面数据参数传递封装给后台
  • SpringMVC原理
  • RestFul风格的数据传输

复习回顾

1 SpringMVC框架简介

1.Servlet非常麻烦,每一个模块都需要去创建对应的Servlet组件,在和视图层进行配合开发需要大量的配置。

2.SpringMVC前端控制器,可以和客户端进行数据的通信(请求处理、响应数据)。

2 SpringMVC开发步骤

1.导入SpringMVC的依赖:spring-webmvc依赖。

2.在web.xml配置文件中添加DispatcherServlet配置(前端控制器)。

3.编写一个控制器类:必须实现Controller接口(ModelAndView)。定义请求处理业务方法,同时可以将请求发送给目标指定的视图页面。

4.在SpringMVC核心配置文件中完成组件的配置(springmvc-servlet.xml)。配置4个组件:

  • 配置控制器类:自定义的Controller。
  • 配置处理器映射器类:HandlerMapping。
  • 配置处理器适配器类:HandlerAdapter。
  • 配置视图解析器类:ViewResolver。

5.分析了SpringMVC执行流程。

1 Spring MVC简介

1.1 Servlet开发缺点

1.每一个Servlet都需要在web.xml文件中配置,如果很多个Servlet,就会导致web.xml文件内容过于繁重。

2.Servlet具有容器的依赖性,Tomcat如果没有启动,则无法进行功能测试的。

3.Servlet处理请求局限性大。

4…

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O7Gu6SyT-1666541197549)(images/001.png)]

1.2 Spring MVC简介

Spring MVC是是一个前端控制器框架(负责前端的请求和响应-控制者),主要负责来和客户端进行后台数据的通信。Spring家族中非常多框架,其中SpringMVC是极为重要一个组件,可以和Spring框架完美整合在一起。

1.3 Spring MVC开发Web项目流程

应用程序分层:

分层名称描述
Model模型层。即表示业务模型,负责完成业务中数据通信处理,对应项目中service和dao层。
View视图层。渲染数据,生成页面,对应项目中的JSP、Vue…
Controller控制层。直接对接请求,控制MVC执行流程,调度模型层和视图层,对应项目中Servlet、Spring MVC

Spring MVC开发Web应用程序项目一个设计架构。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T5ZRaiYy-1666541197550)(images/002.png)]

1.4 SpringMVC入门案例

1.SpringMVC的开发步骤

1.在项目中导入SpringMVC相关的依赖spring-web、spring-webmvc。

2.编写SpringMVC的控制层。

3.需要配置SpringMVC的核心配置文件: spring-servlet.xml。

4.配置url映射。

2.SpringMVC的开发实现

1.导入相关依赖。

<!-- 导入SpringMVC的webmvc模块 -->
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-webmvc</artifactId>
  <version>5.3.22</version>
</dependency>
<!-- Spring Web模块 -->
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-web</artifactId>
  <version>5.3.22</version>
</dependency>
<!-- Spring框架 -->
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>5.3.22</version>
</dependency>

2.配置什么请求可以提交给Spring MVC前端控制器。在web.xml文件中配置。

<?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">
    <!-- 配置Spring MVC的前端控制器:DispatcherServlet,作用是可以处理哪些请求 -->
    <!-- 1.注册Servlet -->
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- 表示给当前的Servlet配置初始化参数信息-->
        <init-param>
            <!-- contextConfigLocation: 表示给上下文配置核心文件 -->
            <param-name>contextConfigLocation</param-name>
            <!-- 表示核心文件的位置 -->
            <param-value>/WEB-INF/spring-servlet.xml</param-value>
        </init-param>
    </servlet>
    <!-- 2.配置Servlet映射 -->
    <servlet-mapping>
        <!--servlet的名称上下需保持一致-->
        <servlet-name>springmvc</servlet-name>
        <!-- url映射路径。"/"表示所有的请求都可以拦截到当前的Servlet中 -->
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

3.编写一个HelloController类,控制器类,将来和一个url地址进行映射,当访问这个url地址会自动触发此控制器。

注意:需要使用一个接口Controller接口。

package com.qf.springmvc01introduction.controller;


import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 控制器:SpringMVC框架提供了一个接口Controller,实现该接口的类,就是SpringMVC的控制器
 */
public class HelloController implements Controller {
    /**
     * 请求url找到对应的Controller类之后,回去执行handleRequest方法
     * @param request 请求对象,打包有请求客户端过来数据
     * @param response 响应对象,打包有响应客户端的数据
     * @return 模型和视图,数据和展示页面
     * @throws Exception 会抛出异常
     */
    @Override
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        /**
         * 请求:/hello请求发送给后台,响应一个数据"Spring MVC"给到前端。
         */
        // 创建一个ModelAndView的对象,然后绑定数据到这个对象,绑定页面(视图)
        ModelAndView modelAndView = new ModelAndView();
        // 1.绑定数据到ModelAndView对象:key:value键值对形式来绑定
        modelAndView.addObject("msg", "Hello Spring MVC!!!");
        // 2.绑定跳转指定的页面:如何跳转到hello.jsp。可以设置视图名称,ModelAndView就知道往哪个页面跳转了
        modelAndView.setViewName("hello"); // 文件名:hello.jsp, 视图名:hello
        // 3.返回ModelAndView对象
        return modelAndView;
    }
}

4.配置spring-servlet.xml文件。

  • 处理器映射器:将请求的url地址和bean对象(Controller)进行绑定。
  • 处理器适配器:根据访问的请求,来调用对应的处理方法(addUser()方法)。
  • 视图解析器:根据配置的文件前缀和后缀找到数据渲染的视图文件,将数据渲染在页面上。
  • 注册控制器:需要由一个url地址映射一个Controller控制器,对应请求触发这个控制器。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 1.注册处理器映射器:
         作用:处理器映射器会根据请求的url与Spring容器中定义的bean的名称进行匹配,从而Spring容器中找到对应的bean.
         说明:不需要手动定义一个id,id规则:包名.类名#数字 -->
    <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>

    <!-- 2.注册处理器:
         name: 表示对应一个前端的请求,name属性的取值必须以"/"开头
         class: 表示对应请求从后台处理的类是谁 -->
    <bean name="/hello" class="com.qf.springmvc01introduction.controller.HelloController"></bean>

    <!-- 3.配置处理器适配器:
         作用:根据处理器映射器返回的Controller,执行哪一个方法 -->
    <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>

    <!-- 4.配置视图解析器:
         作用:根据路径的前缀和后缀来找到匹配的jsp页面,然后执行页面数据的渲染操作 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!-- 1.配置路径的前缀,其中prefix属性表示视图文件的前缀:/WEB-INF/目录下 -->
        <property name="prefix" value="/WEB-INF/"></property>
        <!-- 2.配置路径后缀:.jsp -->
        <property name="suffix" value=".jsp"></property>
    </bean>
</beans>
1.2 SpringMVC执行流程

核心组件:

  • DispatcherServlet:前端控制器
  • HandlerMapping: 处理器映射器
  • HandlerAdapter:处理器适配器
  • ViewResolver:视图解析器

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h7ZLrOIk-1666541197550)(images/003.png)]

1.4 HandlerMapping

1.4.1 BeanNameUrlHandlerMapping

如果想多个url绑定在同一个Controller,需要将控制器的标签进行多次定义,将name属性的制作为url的访问地址进行映射。

<!-- 1.注册处理器映射器:
     作用:处理器映射器会根据请求的url与Spring容器中定义的bean的名称进行匹配,从而Spring容器中找到对应的bean.
     说明:不需要手动定义一个id,id规则:包名.类名#数字 -->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>

<!-- 2.注册处理器:
     name: 表示对应一个前端的请求,name属性的取值必须以"/"开头
     class: 表示对应请求从后台处理的类是谁 -->
<bean name="/hello" class="com.qf.springmvc01introduction.controller.HelloController"></bean>
<bean name="/world" class="com.qf.springmvc01introduction.controller.HelloController"></bean>

缺点:

  • Controller配置显得极为冗余。
  • 在标签的属性设置上,容易产生歧义。
1.4.2 SimpleUrlHandlerMapping

可以将url请求和对应的处理器的配置分离开来完成,可以多个url地址抽离出来,放在一个独立的标签中,然后通过其他配置完成映射。

<!--配置处理器映射器类:-->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
  <!--mappings属性:表示给当前的处理器映射器配置访问的url地址 -->
  <!--
        <property name="mappings">
             props用来声明一组url地址
             prop标签:表示一个url地址的映射,key表示具体的url
            <props>
                <prop key="/hello">helloController</prop>
                <prop key="/world">helloController</prop>
            </props>
        </property>
        -->
  <!-- urlMap表示给指定的控制器配置多个url地址映射 -->
  <property name="urlMap">
    <map>
      <!-- entry表示配置一组url映射 -->
      <entry key="/hello" value="helloController" />
      <entry key="/world" value="helloController" />
    </map>
  </property>
</bean>
<!-- 配置处理器类 -->
<bean id="helloController" class="com.qf.springmvc01introduction.controller.HelloController"></bean>

2 Spring MVC注解

2.1 SpringMVC注解项目分析

1.Spring框架注解:创建的Bean注解、DI依赖注入的注解(@AutoWride)。

2.SpringMVC注解:

  • @RequestMapping:表示给当前方法添加一个请求url映射,在访问固定请求的时候,可以出发此方法。可以处理get和post请求。
  • @GetMapping: 表示只有get类型的请求才可以触发被标记的方法。
  • @PostMappiint: 表示只有post类型的请求才可以出发被标记的方法。

2.1 SpringMVC注解开发步骤

1.导入依赖:spring-webmvc。

2.在web.xml配置前端控制器:DispacherServlet。

3.定义控制器:Controller。通过SpringMVC的注解和处理请求的方法完成映射。

4.在springmvc-servlet.xml文件中配置视图解析器。

3 SpringMVC用户注册

3.1 SpringMVC请求类型

1.精确匹配

<url-pattern>/hello</url-pattern>

2.通配符匹配:可以使用“*”来表示多个任意的字符

<url-pattern>/*</url-pattern>

<url-pattern>/hello/*</url-pattern>

3.后缀匹配

<url-pattern>*.do</url-pattern>
<url-pattern>*.action</url-pattern>
3.2 SpringMVC用户注册实现

1.导入依赖:spring-webmvc。

2.在web.xml配置前端控制器:DispacherServlet。

3.定义控制器:Controller。通过SpringMVC的注解和处理请求的方法完成映射。

4.在springmvc-servlet.xml文件中配置视图解析器。

5.在项目添加了一个新的表单页面:addUser.jsp页面。

6.将表单中的数据在后台处理请求的方法上进行数据解析:

- HttpServletRequest: 如果请求的数据会自动打包在request对象上,需要在request上获取数据(getParamater("name值")方法);
- Model: 如果数据要向视图页面传递,需要将数据绑定在Model上,在页面上通过${属性名称}来获取到绑定的数据。
3.3 SpringMVC中文乱码处理

1.在web.xml配置文件中添加一个过滤器,设置编码为画utf-8。

<!-- 配置过滤器:配置解决中文乱码的问题 -->
<!-- 1.注册过滤器 -->
<filter>
  <filter-name>encodingFilter</filter-name>
  <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
  <!-- 设置编码:ISO-8895-1 -->
  <init-param>
    <param-name>encoding</param-name>
    <param-value>utf-8</param-value>
  </init-param>
</filter>
<!-- 2.添加过滤器映射:将请求配置到过滤器上,当前的过滤器可以处理什么样的请求 -->
<filter-mapping>
  <filter-name>encodingFilter</filter-name>
  <!-- "/*"不会忽略JSP文件 -->
  <url-pattern>/*</url-pattern>
</filter-mapping>

2.常见BUG问题分析:

  • 在配置SpringMVC前端控制器的时候,如果要拦截所有的请求“/”。
  • 编辑Tomcat - Depenment选项 - 【+】 - Artifact选项 - 选择带有war explord类型的。把最新的项目加载到Tomcat中。

3.4 前后端数据通信

后端接收前端数据常见有三种方式:

  • HttServletRequst:需要大量的调用request.getParameter()方法,代码冗余。
  • 参数名称和表单name属性值保持一致,自动进行注入。如果表单的参数过多,那么方法的参数列表需要定义大量的参数来接受。
  • 封装的pojo实体类来接收表单中的数据,适合处理数据比较多的情况,需要保证表单的name属性值和实体类的属性名相同。

3.5 SpringMVC日期类型转化

原因:前端表单在进行date控件数据传输的时候,当给到后台,SpringMVC无法解析表单类型的date。

解决:需要自定义一种日期类型的映射,来解决时间转化的问题。

  • @InitBinder:SpringMVC提供的,被此注解标记的方法表示是SpringMVC的初始化方法,执行早于请求处理方法。

  • CustomDateEditor:表示创建一个自定义的日期编辑器对象。

  • ServletRequestDataBinder:表示Servlet请求中绑定的数据。通过此对象格式化日期转化的类型(Date.class)。

     @InitBinder
        public void initBinder(ServletRequestDataBinder binder) {
    
            //创建时间编辑器,并指定格式
            CustomDateEditor editor = new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), true);
            //将转化的日期绑定到servlet上
            binder.registerCustomEditor(Date.class, editor);
    
        }
    

4 RestFul风格

4.1 RestFul风格

这通过key=value的形式和后端进行数据交互时,get请求数据的体量在2KB左右,将导致无法在有限的数据限制内,发送更多的数据给到后台服务器进行处理。

http://localhost:8080/reg?username=tom&pwd=123456&age=20&gender=M

可以使用RestFul风格的url请求来传递数据。语法格式:

客户端:http://localhost:port/服务器程序名称/请求/参数值1/参数值2/参数值3/....
服务器:http://localhost:port/服务器程序名称/请求/{参数名1}/{参数名2}/{参数名3}/....

举例:
客户端:http://localhost:port/springmvc-reg/reg/tom/123456/24/....
服务器:http://localhost:port/springmvc-reg/reg/{username}/{pwd}/{age}/....

4.2 RestFul案例

需求:

http://localhost:port/程序名/userInfo/Jack/24

5 Spring MVC文件上传

5.1 文件上传接口介绍

1.MultipartFile接口

接口中常用的API:

方法功能描述
String getOriginalFilename()获取上传文件的原始文件名,即该文件在客户端中的文件名
boolean isEmpty()判断上传的文件是否为空,当没有选择文件就直接上传,或者选中的文件是0字节的空文件时,返回true,否则返回false
long getSize()获取上传的文件大小,以字节为单位
String getContentType()根据所上传的文件的扩展名决定该文件的MIME类型,例如上传.jpg格式的图片,将返回image/jpeg
InputStream getInputStream()获取上传文件的输入字节流,通常用于自定义读取所上传的文件的过程,该方法与transferTo()方法不可以同时使用
void transferTo(File dest)保存上传的文件,该方法与getInputStream()方法不可以同时使用

2.MultipartResolver接口

将文件解析成多不部件(MultipartFile)。

在xm核心配置文件中来完成MultipartResolver解析器的配置,后台完成文件数据的解析。

5.2 SpringMVC文件上传案例

  1. 导入依赖:

     <!--文件上传-->
            <dependency>
                <groupId>org.apache.commons</groupId>
                <artifactId>commons-io</artifactId>
                <version>1.3.2</version>
            </dependency>
            <dependency>
                <groupId>commons-fileupload</groupId>
                <artifactId>commons-fileupload</artifactId>
                <version>1.3.2</version>
            </dependency>
    
  2. 在web.xml文件中配置前端控制器与乱码过滤器

    <?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>mvc</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>classpath:spring-servlet.xml</param-value>
            </init-param>
            <load-on-startup>1</load-on-startup>
        </servlet>
        <servlet-mapping>
            <servlet-name>mvc</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>
    
        <!--中文乱码过滤器-->
        <filter>
            <filter-name>chatset</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>chatset</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    </web-app>
    
  3. 在springmvc.xml文件中配置包扫描和MultipartResolver解析器。

      <!--配置注解申明-->
        <aop:aspectj-autoproxy/>
        <!--包扫描 内置注解驱动-->
        <context:component-scan base-package="com.lty"/>
    
        <!--文件解析器-->
        <bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" id="multipartResolver">
            <!--最大上传文件的大小-->
           <!-- <property name="maxUploadSize" value="1048567"/>-->
        </bean>
    
  4. 前端页面:

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
    <form method="post" action="${pageContext.request.contextPath}/user/file" enctype="multipart/form-data">
        文件:<input type="file" name="file">
        <input type="submit" value="upload">
    </form>
    </body>
    </html>
    
    
  5. 编写请求处理类,就是将客户端的文件数据转移到目标文件中(底层使用的是IO技术来完成数据的输出到目标文件中)。

@Controller
@RequestMapping("/user")
public class UserController {
     @RequestMapping("/toUpload")
    public String toUpload() {
        return "upload";
    }

    @RequestMapping(value = "/file",produces = "text/html;charset=utf-8")//produces 防止中文乱码
    @ResponseBody
    public String upload(HttpServletRequest request, MultipartFile file) {
        //获取源文件的文件名
        String originalFilename = file.getOriginalFilename();
        System.out.println(originalFilename);
        //得到该文件的后缀名,也可以找到最后一个.利用字符串的截取获取
        String endName = FilenameUtils.getExtension(originalFilename);

        System.out.println(endName);
        //生成新文件的文件名
        //目标文件的名称:1666535390435.docx
       /* String desc = Calendar.getInstance().getTimeInMillis() +"."+ endName;*/

        //目标文件的名称:QQ录屏202210231727041666535690345.mp4
        String desc=originalFilename.substring(0,originalFilename.lastIndexOf("."))+System.currentTimeMillis()+originalFilename.substring(originalFilename.lastIndexOf("."));

        System.out.println("目标文件的名称:" + desc);
        //获取上下文路径找文件夹”upload“
        String realPath = request.getServletContext().getRealPath("upload");
        System.out.println("upload的路径+" + realPath);
        //判断该目录是否存在,不存在就创建
        File dir = new File(realPath);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        //生成目标文件
        File descFileName = new File(dir, desc);
        System.out.println("目标目录:"+descFileName);
        //向此文件中写入
        try {
            file.transferTo(descFileName);
            return "成功";
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}

image-20221023225346402

image-20221023225402798

image-20221023225431326

6 Spring MVC文件下载

文件下载案例:

  1. jsp页面:

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
    
    <%--filename:源文件的文件名
        下载路径在浏览器中设置--%>
    <a href="${pageContext.request.contextPath}/download?filename=de356aa6-18a6-483c-b605-67d155e2690f.docx">下载</a>
    
    </body>
    </html>
    
  2. Controller层实现:

    @Controller
    public class DownloadController {
    
        @RequestMapping("/toDownLoad")
        public String toDownload() {
            return "download";
        }
    
        @RequestMapping(value = "/download",produces = "text/html;charset=utf-8")
        public void downLoad(String filename, HttpServletResponse response, HttpSession session) throws IOException {
            //设置响应头,以附件的形式进行下载
            response.setHeader("content-disposition", "attachment;filename=" + filename);
    
            String realPath=session.getServletContext().getRealPath("/upload");
            //源文件的路径
            String file=realPath+"\\"+filename;
    
            //以流的形式对外输出,输出服务器指定的file
            IOUtils.copy(new FileInputStream(file),response.getOutputStream());
        }
    }
    

    image-20221024000425678

image-20221024000437845

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值