第三个基础框架 — springMVC — 更新完毕
阅读原文时间:2023年07月08日阅读:4

  • 唯一有用的信息:springMVC就是spring的一部分

  • 我来说一下:

    • springMVC本质就是前面说过的servlet,所以它的职责还是和servlet的一样 ———— 获取请求,解析请求,实现页面跳转,只是对servlet做了比较深的封装,使我们编写代码变得轻松了而已

      • 因此:玩springMVC就和servlet差不多,做的事情都一样,什么请求转发、重定向、文件上传、文件下载、过滤器、拦截器……

      • 因此:学springMVC之前,玩一下servlet的请求转发( 只玩请求转发即可,有利于理解springMVC的流程 )

    • 既然是springMVC,那MVC指的是什么?

      • M 即:model 模型:提供要进行展示的数据
      • V 即:view 试图:负责进行模型的展示嘛
      • C 即:controller 控制层:接受请求,委托给模型进行处理
    • MVC的主要作用: 降低视图和业务层之间的双向耦合,MVC是一种架构模式,典型的就是:jsp+servlet+entity

    • springMVC的中央大脑:DispacherServlet

    • 先上springMVC的执行原理

  • 1)、准备工作:创建maven项目( 可以直接选择maven的webapp模板【 这种方式版本很老,需要手动把web.xml进行更新 [ 这在我的servlet博客内容中安装maven已说明 ] 】,也可以选择创建单纯的maven项目,然后转web项目,这种方式生成的web.xml是对应java版本最新的 ———— 我自己使用的是这样方式 )

  • 导入依赖

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.2.12.RELEASE</version>
        </dependency>
    &lt;dependency&gt;
        &lt;groupId&gt;javax.servlet&lt;/groupId&gt;
        &lt;artifactId&gt;javax.servlet-api&lt;/artifactId&gt;
        &lt;version&gt;3.1.0&lt;/version&gt;
    &lt;/dependency&gt;
    
    &lt;dependency&gt;
        &lt;groupId&gt;javax.servlet.jsp&lt;/groupId&gt;
        &lt;artifactId&gt;javax.servlet.jsp-api&lt;/artifactId&gt;
        &lt;version&gt;2.2.1&lt;/version&gt;
    &lt;/dependency&gt;
    
    &lt;dependency&gt;
        &lt;groupId&gt;junit&lt;/groupId&gt;
        &lt;artifactId&gt;junit&lt;/artifactId&gt;
        &lt;version&gt;4.12&lt;/version&gt;
        &lt;scope&gt;test&lt;/scope&gt;
    &lt;/dependency&gt;
    
    &lt;dependency&gt;
        &lt;groupId&gt;javax.servlet.jsp.jstl&lt;/groupId&gt;
        &lt;artifactId&gt;jstl&lt;/artifactId&gt;
        &lt;version&gt;1.2&lt;/version&gt;
    &lt;/dependency&gt;</code></pre></li>
  • 2)、跟着流程图来玩一玩

    • (1)、配置springMVC的中央大脑,即:前端控制器DispacherServlet


    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>springmvc</servlet-name> 这里的springmvc名字乱取都可以,只要自己和别人看得懂就行
        DispatcherServlet 就是springMVC的中央大脑 所有的请求都会经过它
        由这个中央大脑来分配这个请求的流程是怎么样的
     --&gt;
    &lt;servlet-name&gt;springmvc&lt;/servlet-name&gt;
    &lt;servlet-class&gt;org.springframework.web.servlet.DispatcherServlet&lt;/servlet-class&gt;
    
    &lt;!--  把springMVC的配置文件集成过来
            为什么需要把springMVC集成到这里到?
                这个web.xml其实也算一个容器,这个容器处理的是后端的程序,这个需要知道servlet的执行原理 和 这个web.xml
                及tomcat中的web.xml的关系才能理解
    
            就当补充知识点吧,在我的servlet中只讲了这个web.xml和Tomcat中的web.xml的关系,其他的没讲
            因此:为了这里面话别太多影响内容,待会儿完了之后再补充servlet的执行原理,这里就这么配置就行了
    
            注:&lt;param-value&gt;classpath:springmvc.xml&lt;/param-value&gt;中的springmvc.xml就是要配置的springMVC文件名
      --&gt;
    &lt;init-param&gt;
        &lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;
        &lt;param-value&gt;classpath:springmvc.xml&lt;/param-value&gt;
    &lt;/init-param&gt;
    
    &lt;!-- 这个这个在servlet中说明过,这个值只要大于 -1 即可,就是servlet加载的优先级
            这里简单粗暴理解可以认为是:单例模式的懒汉式加载( 虽然不对,但是用这个想法来理解也算对 )
      --&gt;
    &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;
    </servlet> <!-- 这里的springmvc名字必须和前面说的乱取的<servlet-name>springmvc</servlet-name>名字保持一致 <url-pattern>/</url-pattern> 这里面必须用 / 不能用其他的 千万注意:这里不用用成 /*
    / 和 /*的区别
         / 不会匹配到.jsp, 只针对我们编写的请求;即:.jsp 不会进入spring的 DispatcherServlet类
        /*  会匹配 *.jsp,会出现返回 jsp视图 时再次进入spring的DispatcherServlet 类,
            导致找不到对应的controller,从而报404错误
    --> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>

(2)、配置springMVC文件( 一是刚刚的web.xml中加进去了,但是还没写,二是配置映射器、适配器和视图解析器

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--    添加处理器映射器   就是原理图中的映射器 HandlerMapping-->
    <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>

    <!--    添加处理器适配器   就是原理图中的适配器HandlerAdapter-->
    <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>

    <!--    添加视图解析器
            这个的本质就是把controller中返回的视图名进行拼接,从而找到相应的视图xxxx,jsp而已
    -->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!-- prefix 要展示的视图的前缀 这里是/  是因为一:我的视图就放在web目录下的,要是加了另外的目录,那就再拼接
                    如:/WEB-INF/jsp/     二是:在浏览器中发起请求的时候,对应的url路径名其实是/xxxx.jsp涩
                                               而这里的xxxx就是待会儿controller中返回回来的那个名字
        -->
        <property name="prefix" value="/"/>
        <!-- suffix 要展示的视图的后缀 -->
        <property name="suffix" value=".jsp"/>
    </bean>

</beans>

(3)、编写controller

(4)、把这个controller中的类托管到springMVC.xml这个容器中、以及编写要跳转的视图

(5)、配置Tomcat,启动项目

(6)、会报404的情况

  • 1、检查自己的控制台,看报的错是什么,或者看它是不是报了少了什么jar,少了就看是不是自己漏了

  • 2、**最常见的一种:IDEA的bug,控制台没有报任何错误,但是一请求路径,就报404,在浏览器

    F12控制台抓包看就是报的请求路径找不到**

    • 解决办法:

      • 提示:弄完lib之后,记得把maven使用clean工具清除一下( 有时idea会开小差,没clean好,clean好了就是那个target目录没了 ),然后重启tomcat就可以了

  • 3、额外原因导致报404 ———— 这种是自己粗心代码导致的,一般为以下情况:

    • 前后缀哪里配错了

    • handler配错了,严格来说是:那个id值搞错了

    • 以上两种情况属于:not mapping for get 的404情况

  • 玩完了上面的流程之后,试着自己多写几次其他的页面展示,然后结合servlet的转发,这个springMVC的执行原理就理解的差不多了( 流程图也就到自己脑海中去了 )

  • web.xml和tomcat中web.xml的联系已在我的servlet博客内容中说明过:项目中的web.xml处理的是后端的代码;tomcat中的web.xml处理的是前端的代码,并把他们通过流的形式给到了后台,同时转成了一个servlet( tomcat的web.xml中有一个servlet配置是default )

  • servlet的执行原理:

    • 当客户端发起一个请求之后,tomcat会帮我们开启一个容器( 即:我在servlet中说明过的全局域servletContext ),请求能够精准找到tomcat就是因为客户端的那个url地址中有ip和端口号( localhost:8080 )

    • 这个容器怎么去加载另外的东西才是关键点

      • 请求进来要找servlet,而servlet是一个接口,不能做事,因此又创建GenericServlet,而这是一个抽象类 ( 对servlet做了简单的实现而已 ),因此还不能做事,所以继续创建HttpServlet ———— 这才是我们用的那个servlet

      • HttpServlet根据http协议接收了客户端的请求,为什么能够接收请求?

        • 因为:GenericServlet还是serializeable的抽象类 ———— serializeable序列化嘛,流技术咯

    • HttpServlet要去找我们编写的servlet在哪里,怎么找?

      • 注解版是使用了@webServlet,xml版是在web.xml中配了一个servlet,里面的那个servlet-class就是指向的我们编写的servlet,这样就找到了我们编写的servlet在哪里
    • 找到我们自己编写的servlet之后,我们编写的servlet里面需要用到HttpServlet涩( 重写了doGet和doPost方法嘛)

      • 因此:这里才有的servlet的生命周期:即创建 ———— 使用构造器创建的、初始化init()、服务service() ———— 我们重写了这里面的两个方法doGet和doPost、销毁destroy()
    • 到了我们自己编写的servlet之后,把编写的东西( 响应信息 )通过HttpResponse对象把响应信息返回给客户端

      • 它怎么知道返回到哪个url路径去?

        • 注解版@webServlet()这个()里面有一个请求路径、xml版中web.xml中有一个servlet-mapping,这个mapping下面有一个url-pattern路径,这就是HttpResponse应该把信息返回到的地方
  • 前面在springMVC项目中,为什么那个web.xml中需要配置:

       <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>

这是一个初始化参数嘛,别忘了GenericServlet还是servletConfig的实现类,因此:servletConfig的功能它也有,相应的HttpServlet也有,作用就是为了读取初始化参数嘛 ———— 获取初始化参数在我的servlet说明servletContext获取初始化参数时已经说明了,原理就是一样的,servletContext这里面的东西在我们编写的任何一个servlet中都可以拿到,因此:这里web.xml中加入了springMVC的参数路径,也就把springMVC的xml配置文件在请求进来时也加载出来了( 这也是我说的哪个load-on-start大于-1可以理解为:单例模式的懒汉式加载的原因 ,因为:相对于servlet本身来说,这个springMVC的配置文件确实是后面controller中用时才加载的,只是那个数字大小也关系到多个servlet的加载时的先后顺序而已 )

1)、基本类型

2)、对象类型 ———— 重点中的重点

3)、什么数组、集合….自行了解,这里不做说明

注:无法出现跳转的情况:

另外出现404的情况:结合前面xml版来分析

老规矩:百度百科一手

提取一下上面的就是下面的话:

  • 1)、RESTful风格是一种设计风格和开发方式
  • 2)、是一组架构约束条件和原则
  • 3)、有四种方式:post、delete、put、get

*_看了上面这些介绍,还是不太很明白RESTfule风格到底是个什么东西,那就来看一组对比图_

对比链接如下:

https://baike.baidu.com/item/马化腾    // 这就是RESTful风格的一种特征

http://localhost:8080/test/getBaseType?name=紫邪情age=24    // 而这种就是原生的URI方式

注:URI、URL、URN到底是什么意思,自行百度,这里不做说明

(1)、通过上面的对比之后,我将RESTful的一种特征归纳为:安全性更高

  • 在我们原生的开发中,前台和后台传送参数时,是直接使用 : 参数名 = 值 , 而RESTful风格,是直接传递参数值( 这种也叫:路径收参:这种方式很重要,是一种前后台传递参数值的小技巧,有时很有用 ),演示如下:

这样我只传递一个参数值,然后后台通过请求搭配要获取的参数名、以及注解就可以得到想要的参数值了,因此:这样别人看URI路径时,并不能猜到我后台的参数名是什么,也就可以预防:别人猜出数据库字段的字段名的情况了,所以:RESTful风格的一个特征就是:让数据更安全

  • 注意:有多个路径参数时,后台要给每一个参数名搭配一个 @PathVariable注解,另外:URI中的参数对应的顺序不可以打乱( 如:刚刚的 /1/紫邪情 不可以弄成 /紫邪情/1 ),不然和后台的参数名对不上

(2)、继续来说明RESTful风格,另一种特征,我归纳为:请求方式的细分

  • 刚刚在前面百度百科的时候,说到了4种方式:post、delete、put、get,其他两个不熟,但是:post和get绝对熟悉,哟西~没错,就是心里的那个苗头,只是可能还无法表达出来而已,看下图:

通过上图可以得知:只要前台的请求是去数据库中做那些对应的操作,那么就用对应的请求方式

那么问题来了:前台请求方式我想都可以理解过来,就是method换成对应的名字即可,那么后台在controller层时,怎么用对应的方式接收?

  • 简单得很。就几个注解

  • @PostMapping

  • @DeleteMapping

  • @PutMapping

  • @GetMapping

**说明一下:@RequestMapping这个注解和上面四个的区别:

@RequestMapping可以认为是上面这些注解的老爹,因此这个@RequestMapping注解,可以接收上面的这四种方式的请求,即:post、delete、put、get请求方式,@RequestMapping都可以接收到,而如果在后台声明的是@PostMapping方式接收请求,那么:如果前台传递的是@DeleteMapping,后台就无法接收,注意:请求方式不对,会报:405**

  • 这里还牵扯到协议相关,即:http / https,建议:有兴趣的自行找资源,把协议相关的看一下,能够懂得怎么自定义协议的程度最好

补充:只有这几种请求方式吗?当然不是,这只是最常用的,而这4个最常用的里面又是post和get最常用,另外请求方式如下:

(3)、我将RESTful风格的另一个特征归纳为:后台请求路径的编写原则

  • 来看一下图就明白了

运行效果如下:

从控制台乱码就可以得出结论:这个乱码在浏览器传给后台的时候就已经乱码了

解决乱码如下:

1)、设置前台页面的编码格式为utf-8

2)、设置浏览器的编码格式为utf-8,不同浏览器的设置方式不一样,自行百度百科搜索自己浏览器对应的设置方式

3)、设置tomcat的编码(注:这种是只对get请求有效)

4)、设置编辑器的编码( 如:我的idea )

5)、给springmvc设置编码( 即:过滤器 )

  • 在web.xml中加入如下内容

    <filter>
        <filter-name>encoding</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    &lt;init-param&gt;
        &lt;param-name&gt;encoding&lt;/param-name&gt;
        &lt;param-value&gt;UTF-8&lt;/param-value&gt;
    &lt;/init-param&gt;
    </filter> <filter-mapping> <filter-name>encoding</filter-name> <url-pattern>/*</url-pattern> <!-- 注意:这里一定得是 /* , 即:过滤所有请求 原理和servlet的过滤器是一样的 springmvc本质就是servlet --> </filter-mapping>

因此:以后写springmvc时,第一时间除了编写这个web.xml中的DispatcherServlet之外,还需要写上这个过滤器

另外:这个过滤器才是主要要写的东西,前面说的那几个设置,只是建议改好。在java的web开发中需要设置如下的这些为utf-8

  • 浏览器

  • 编辑器,如:idea

  • 过滤器

  • jsp / html

  • tomcat

    • 这个有两个地方要改

  • 数据库连接池,有一个url,哪里要跟一个参数characterEncoding=utf-8

  • 建数据库 和 数据库表时选择utf-8

  • 电脑的操作系统改为unicode编码,utf-8格式( 不同的操作系统设置方法不一样,自行百度百科 )

解决之后,运行效果如下:

1)、model ———— 重要、使用频率最高的一个

  • 这个其实已经很熟悉了,因为用过modelAndView嘛,modelAndView是老爹,model是儿子( 即:相比modelAndView方法变少了 )

  • 没什么好玩的,不玩了 (注:以后存值就用这个)

2)、modelAndView

  • 这个前面一直在用,所以更不玩了

1)、给web.xml中的servlet-mapping的url-pattern添加请求后缀 ———— 了解即可

2)、在springmvc.xml中使用<mvc:default-servlet-handler/>

  • 这种方式在前面一直使用,这个的原理就是请求进来,现在服务器中找对应要跳转的视图( 如:hello.html ),但是:我们做的配置是.jsp结尾的,因此找不到这个hello.html静态资源,所以:单独加了<mvc:default-servlet-handler/>这个处理器之后,就是让服务器去默认的servlet中去处理这个请求( 即:tomcat的那个web.xml ,正好这样就可以找到hello.html这个视图了。 注:这种方式的优先级最低,也就是先在服务器找一遍之后,找不到才去默认处理器中进行处理

3)、在springmvc.xml中使用<mvc:resources mapping="" location=""/>

  • 1)、jackson ———— 了解即可,但是也要掌握,用的最多的是:fastjson,但是:springmvc的默认json处理方式是jackson

  • (1)、准备工作:导入依赖

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.8</version>
        </dependency>
  • (2)、@responseBody 和 @restController注解

  • (3)、@requestBody注解

    • 这个注解一样的原理,就是表明:后台接收前台的数据格式为json字符串
  • (4)、另外的注解:一般在实体类中使用

  • 2)、fastjson,这种json比jackson传输效率更快 ———— 重要

    • (1)、准备工作:导入依赖

      <dependency>
          <groupId>com.alibaba</groupId>
          <artifactId>fastjson</artifactId>
          <version>1.2.75</version>
      </dependency>

(2)、配置json转换器

    <mvc:annotation-driven>
        <mvc:message-converters>    <!--alibaba的json转换器-->
            <bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
                <property name="supportedMediaTypes">
                    <list>
                        <value>application/json</value>
                    </list>
                </property>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>

(3)、使用的注解

  • @requestBody

  • @responseBody

  • @restController

    使用方法都不变

  • 使用在实体类上的注解

    • @JSONField
    • 就这一个注解:可以做前面jackjson的所有事情,不做演示了
  • 作用:为了方便管理handler处理器抛出的异常( 即:controller层中抛出来的异常,含service、mapper层中抛到controller中的 ),即:把这些异常都统一抛到一个地方去进行处理

  • (1)、编写异常解析器

    package cn.xiegongzi.util.resolver;

    import org.springframework.web.servlet.HandlerExceptionResolver;
    import org.springframework.web.servlet.ModelAndView;

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

    public class MyResolver implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {

        ModelAndView mv = new ModelAndView();
    mv.setViewName("error");        // 这里就是出现异常之后,就调到同一个页面去,如:error内容为:服务器开小差 / 一个很大的404页面 。 这里也可以分类啊,如:出现空指针那跳到什么页面去,出现栈溢出又跳到什么页面去等等.....
    
    return mv;
    }

    }

  • (2)、注册异常解析器

    <!--  注册异常解析器  即:就是刚刚自己写的异常解析器 -->
    <bean class="cn.xiegongzi.util.resolver.MyResolver"/>

最后:编写异常页面error.html就可以了,这样出现异常了,前台自然会跳到这个error.html页面中去

  • 作用:抽取handler的冗余代码,说白一点:就是handler处理器处理请求之前改干什么、处理了请求之后该干什么、渲染完页面之后该干什么

  • (1)、自定义拦截器

    package cn.xiegongzi.util.interceptor;

    import org.springframework.lang.Nullable;
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;

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

    public class MyHandlerInterceptor implements HandlerInterceptor {

    // 注意:下面的三个方法其实都是HandlerInterceptor接口下的方法,但是:底层是用了default修改的,所以不会提示重写
    //      因此:进入HandlerInterceptor的源码,复制出来,然后把default改为public即可
    
    // 这个方法是handler处理请求之前做的事情
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    return true;    // 这个return true 在这里是放行的意思,和servlet中的filter中最后放行是一样的原理,让后续的拦截器 或 处理器handler可以继续执行
    } // 这个是handler处理请求之后做的事情 public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception { } // 这个是页面渲染完之后做的事情 public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception { }

    }

  • (2)、配置拦截项并注册

    <!--  配置拦截器的拦截项  -->
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="*"/>         <!-- 即:拦截所有的请求,也可以根据自己的需求来配置 这里面还有其他属性
                                                    如:不拦截哪些请求,如:select/**    即:select下任意路径都不拦截
                                             -->
            <!-- 注册拦截器 -->
            <bean class="cn.xiegongzi.util.interceptor.MyHandlerInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>
  • 1)、文件上传 ———— 这个在我的servlet中玩过文件上传,差球不多的

    • (1)、导入依赖

      <dependency>
          <groupId>commons-io</groupId>
          <artifactId>commons-io</artifactId>
          <version>2.4</version>
      </dependency>
      
      <dependency>
          <groupId>commons-fileupload</groupId>
          <artifactId>commons-fileupload</artifactId>
          <version>1.3.3</version>
          <!-- 注意:commons-fileupload这里面本身就有servlet,
                  因此需要通过如下方式把这里面本身所带的servlet剔除掉
                  但是:maven本身就有解决jar冲突的能力,
                  因此:我自己使用的使用并没有加入下面这一项
           -->
          <exclusions>
              <exclusion>
                  <groupId>javax.servlet</groupId>
                  <artifactId>servlet-api</artifactId>
              </exclusion>
          </exclusions>
      </dependency>

(2)、配置文件上传解析器

(3)、编写页面测试一下

(4)、编写controller层,对文件进行处理

  • package cn.xiegongzi.controller;

    import org.apache.commons.io.FilenameUtils;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.multipart.MultipartFile;

    @Controller
    public class FileUpload {

    @PostMapping("/file/upload")
    public String fileUpload( MultipartFile source ) {
    // 和在servlet玩的一样的,获取文件名 ———— 但是:浏览器不同,这个值不同
    String filePathName = source.getOriginalFilename();
    
    System.out.println(filePathName);
    
    // 因此:获取文件的后缀名
    String fileSufName = FilenameUtils.getExtension(filePathName);
    
    System.out.println(fileSufName);    // 能够获取到文件名和其后缀名了,那后面的事情就很简单了,自行发挥即可
    
    // 重新起一个名字 可以使用时间戳( 最low的一种 ) 、 也可以使用UUID
    
    // 文件保存到什么地方,自定义文件夹即可,和servlet中我玩过的文件上传流程差球不多了
    // source getContentType() 可以获取这个文件的类型,从而判断去放到什么地方去比较好( 归类嘛 )
    
    // 保存的方法,source.transferTo( new file( fileName ) )
    return null;
    }

    }

效果如下:

  • 2)、文件下载,其实这个和我在servlet中玩的差不多

    • 前台:我给她指定要下载的文件地址

    下载

    // name=Koala.jpg 这个是可以换的啊,甚至还可以玩的深一点,自行发挥

后台

@PostMapping("/file/download")
public void fileDownload( String name, HttpSession session, HttpServletResponse response ){

    System.out.println("要上传的文件名为::" + name);

    // 获得要下载文件的绝对路径
    String path = session.getServletContext().getRealPath("/upload_file");

    // 文件的完整路径
    String real_path = path+"\\"+name;

    // 设置响应头 即:让浏览器支持文件下载 还是一样的,URLEncoder防止中文名文件乱码嘛
    response.setHeader( "content-disposition","attachment;filename=" + URLEncoder.encode(name) );

    // 读取目标文件,响应( 写 )给客户端
    IOUtils.copy(new FileInputStream(real_path), response.getOutputStream());

}