一、文件下载
ResponseEntity用于控制器方法的返回值类型,该控制器方法的返回值就是响应到浏览器的响应报文使用ResponseEntity实现下载文件的功能
我们进行下载该文件:
文件资源在本章资源可以找到。
我们在首页index.html进行添加如下所示(其他配置可以查看上面一篇文章:写文章-优快云创作中心):
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>首页</title> </head> <body> <div id="app"> <h1>index.html</h1> <input type="button" value="测试SpringMVC处理ajax" @click="testAjax()"><br> <input type="button" value="使用@RequestBody注解处理json格式的请求参数" @click="testRequestBody()"><br> <a th:href="@{/test/ResponseBody}">测试@ResponseBody注解响应浏览器数据</a><br> <input type="button" value="使用@ResponseBody注解响应json格式的数据" @click="testResponseBody()"> <a th:href="@{/test/down}">下载图片</a> </div> <script type="text/javascript" th:src="@{/js/vue.js}"></script> <script type="text/javascript" th:src="@{js/axios.min.js}"></script> <script type="text/javascript"> /** * axios({ * url:"", //请求路径 * method:"", //请求方式 * //以name=value&name=value的方式发送的请求参数,不管使用的请求方式是get或post,请求参数都会被拼接到请求地址后 * 此种方式的请求参数可以通过request.getParameter()获取 * params:{}, * //以json格式发送的请求参数,请求参数会被保存到请求报文的请求体传输到服务器。 * 此种方式的请求参数不可以通过request.getParameter()获取 * 需要先来读取请求体中的数据,再通过我们当前的一些处理json的jar包,将我们当前获取的请求体中的数据转换为java对象 * data:{} * //then来处理我们当前请求处理ajax请求处理成功之后服务器响应回来的结果的 * }).then(response=>{ * console.log(response.data); * }); */ var vue=new Vue({ el: "#app", methods: { testAjax() { axios.post( "/SpringMVC/test/ajax?id=1001", {username:"admin",password:"123456"} ).then(response=>{ console.log(response.data); }); }, testRequestBody() { //get请求方式没有请求体。且axios方式有键值对,而post方法直接写参数就可以。 axios.post( "/SpringMVC/test/RequestBody/json", {username:"admin",password:"123456",age:23,gender:"男"} ).then(response=>{ console.log(response.data); }); }, testResponseBody() { //get请求方式没有请求体。且axios方式有键值对,而post方法直接写参数就可以。 axios.post( "/SpringMVC/test/ResponseBody/json" ).then(response=>{ console.log(response.data); }); } } }); </script> </body> </html>
ctrl+p进行查看:
我们在controller层里面进行设置如下所示:
package com.rgf.controller; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.util.MultiValueMap; import org.springframework.web.bind.annotation.RequestMapping; import javax.servlet.ServletContext; import javax.servlet.http.HttpSession; import java.io.FileInputStream; import java.io.IOException; /** * ResponseEntity:可以作为控制器方法的返回值,表示响应到浏览器的完整的响应报文 */ @Controller public class FileUpAndDownController { @RequestMapping("/test/down") public void testResponseEntity(HttpSession session) throws IOException{ //获取ServletContext对象 ServletContext servletContext = session.getServletContext(); //获取服务器中文件的真实路径 String realPath =servletContext.getRealPath(""); System.out.println(realPath); } }
此时运行之后出现如下所示:
此时的视图没有找到,控制器方法如果没有设置返回值的话,会把我们当前要处理的请求地址作为逻辑视图,然后进行返回。
我们进行如下示例:
package com.rgf.controller; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.util.MultiValueMap; import org.springframework.web.bind.annotation.RequestMapping; import javax.servlet.ServletContext; import javax.servlet.http.HttpSession; import java.io.FileInputStream; import java.io.IOException; /** * ResponseEntity:可以作为控制器方法的返回值,表示响应到浏览器的完整的响应报文 */ @Controller public class FileUpAndDownController { @RequestMapping("/test/down") public String testResponseEntity(HttpSession session) throws IOException{ //获取ServletContext对象 ServletContext servletContext = session.getServletContext(); //获取服务器中文件的真实路径 String realPath =servletContext.getRealPath(""); System.out.println(realPath); return "success"; } }
重新运行之后如下所示:
![]()
我们查看控制台输出如下所示:如果配置了maven则会读取如下包(如果没有创建maven工程,创建的是一个普通的web工程,则获取的是当前IDEA这个项目里面的out目录下的一个路径)
如果我们设置了地址,则会拼接到如下包的地址的后面:
package com.rgf.controller; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.util.MultiValueMap; import org.springframework.web.bind.annotation.RequestMapping; import javax.servlet.ServletContext; import javax.servlet.http.HttpSession; import java.io.File; import java.io.FileInputStream; import java.io.IOException; /** * ResponseEntity:可以作为控制器方法的返回值,表示响应到浏览器的完整的响应报文 */ @Controller public class FileUpAndDownController { @RequestMapping("/test/down") public String testResponseEntity(HttpSession session) throws IOException{ //获取ServletContext对象 ServletContext servletContext = session.getServletContext(); //获取服务器中文件的真实路径 String realPath =servletContext.getRealPath("img/body1.png"); System.out.println(realPath); return "success"; } }
我们也可以采用如下方式进行拼接:
package com.rgf.controller; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.util.MultiValueMap; import org.springframework.web.bind.annotation.RequestMapping; import javax.servlet.ServletContext; import javax.servlet.http.HttpSession; import java.io.File; import java.io.FileInputStream; import java.io.IOException; /** * ResponseEntity:可以作为控制器方法的返回值,表示响应到浏览器的完整的响应报文 */ @Controller public class FileUpAndDownController { @RequestMapping("/test/down") public String testResponseEntity(HttpSession session) throws IOException{ //获取ServletContext对象 ServletContext servletContext = session.getServletContext(); //获取服务器中文件的真实路径 String realPath =servletContext.getRealPath("img"); //separator(),表示当前文件的分隔符,自动匹配适用于当前不同的系统。 realPath=realPath+ File.separator+"body1.png"; System.out.println(realPath); return "success"; } }
结果如下所示:
如果该目录下没有该文件,可以在maven里面进行clean,然后再重新打包:
我们的代码设置如下所示:FileUpAndDownController.java
package com.rgf.controller; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.util.MultiValueMap; import org.springframework.web.bind.annotation.RequestMapping; import javax.servlet.ServletContext; import javax.servlet.http.HttpSession; import java.io.File; import java.io.FileInputStream; import java.io.IOException; /** * ResponseEntity:可以作为控制器方法的返回值,表示响应到浏览器的完整的响应报文 */ @Controller public class FileUpAndDownController { @RequestMapping("/test/down") public ResponseEntity<byte[]> testResponseEntity(HttpSession session) throws IOException{ //获取ServletContext对象 ServletContext servletContext = session.getServletContext(); //获取服务器中文件的真实路径 String realPath =servletContext.getRealPath("img"); //separator(),表示当前文件的分隔符,自动匹配适用于当前不同的系统。 realPath=realPath+ File.separator+"body1.jpg"; //创建输入流 FileInputStream is = new FileInputStream(realPath); //创建字节数组 //available()获取当前字节输入流所对应的文件所有的字节数 byte[] bytes = new byte[is.available()]; //将流读到字节数组中 is.read(bytes); //响应头本质上都是键值对,MultiValueMap继承了Map //创建HttpHeaders对象设置响应头信息 MultiValueMap<String,String> headers = new HttpHeaders(); //设置要下载方式以及下载文件的名字 //attachment,以附件的形式进行下载。 headers.add("Content-Disposition","attachment;filename=body1.png"); //设置响应状态码 HttpStatus statusCode= HttpStatus.OK; //创建ResponseEntity对象 ResponseEntity<byte[]> responseEntity=new ResponseEntity<>(bytes,headers,statusCode); //关闭输入流 is.close(); return responseEntity; } }
我们进行运行之后如下所示:
我们发现成功下载:
二、文件上传
我们将index.html设置如下,以form表单进行提交:
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>首页</title> </head> <body> <div id="app"> <h1>index.html</h1> <input type="button" value="测试SpringMVC处理ajax" @click="testAjax()"><br> <input type="button" value="使用@RequestBody注解处理json格式的请求参数" @click="testRequestBody()"><br> <a th:href="@{/test/ResponseBody}">测试@ResponseBody注解响应浏览器数据</a><br> <input type="button" value="使用@ResponseBody注解响应json格式的数据" @click="testResponseBody()"><br> <a th:href="@{/test/down}">下载图片</a> //enctype:设置浏览器向服务器传输请求参数的方式,设置为"multipart/form-data",将我们当前表单中的数据以二进制的方式提交到服务器中 <form th:action="@{/test/up}" method="post" enctype="multipart/form-data"> 头像:<input type="file" name="photo"><br> <input type="submit" value="上传"> </form> </div> <script type="text/javascript" th:src="@{/js/vue.js}"></script> <script type="text/javascript" th:src="@{js/axios.min.js}"></script> <script type="text/javascript"> /** * axios({ * url:"", //请求路径 * method:"", //请求方式 * //以name=value&name=value的方式发送的请求参数,不管使用的请求方式是get或post,请求参数都会被拼接到请求地址后 * 此种方式的请求参数可以通过request.getParameter()获取 * params:{}, * //以json格式发送的请求参数,请求参数会被保存到请求报文的请求体传输到服务器。 * 此种方式的请求参数不可以通过request.getParameter()获取 * 需要先来读取请求体中的数据,再通过我们当前的一些处理json的jar包,将我们当前获取的请求体中的数据转换为java对象 * data:{} * //then来处理我们当前请求处理ajax请求处理成功之后服务器响应回来的结果的 * }).then(response=>{ * console.log(response.data); * }); */ var vue=new Vue({ el: "#app", methods: { testAjax() { axios.post( "/SpringMVC/test/ajax?id=1001", {username:"admin",password:"123456"} ).then(response=>{ console.log(response.data); }); }, testRequestBody() { //get请求方式没有请求体。且axios方式有键值对,而post方法直接写参数就可以。 axios.post( "/SpringMVC/test/RequestBody/json", {username:"admin",password:"123456",age:23,gender:"男"} ).then(response=>{ console.log(response.data); }); }, testResponseBody() { //get请求方式没有请求体。且axios方式有键值对,而post方法直接写参数就可以。 axios.post( "/SpringMVC/test/ResponseBody/json" ).then(response=>{ console.log(response.data); }); } } }); </script> </body> </html>
配置文件上传解析器,将我们当前上传的文件转换为MultipartFile:
我们在springmvc.xml配置文件里面进行配置如下所示:
<!--配置文件上传解析器--> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> </bean>
我们在web.xml里面进行配置如下所示:
<dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.1</version> </dependency>
我们将controller层方法设置如下所示:
@RequestMapping("test/up") public String testUp(MultipartFile photo,HttpSession session){ // photo.transferTo(); 将photo所对应的文件直接把他上传到我们所指定的文件(路径)所对应的位置。 // photo.getOriginalFilename();获取所上传的文件的文件名 //获取上传的文件的文件名 String filename = photo.getOriginalFilename(); System.out.println(filename); return "success"; }
我们进行选择文件进行上传:
提交之后如下所示:上传成功
此时控制台输出如下所示:
我们设置方法如下所示:
package com.rgf.controller; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.util.MultiValueMap; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.multipart.MultipartFile; import javax.servlet.ServletContext; import javax.servlet.http.HttpSession; import java.io.File; import java.io.FileInputStream; import java.io.IOException; /** * ResponseEntity:可以作为控制器方法的返回值,表示响应到浏览器的完整的响应报文 * * 文件上传的要求: * 1.form表单的请求方式必须为post * 2.form表单必须设置属性enctype="multipart/form-data" */ @Controller public class FileUpAndDownController { @RequestMapping("test/up") public String testUp(MultipartFile photo,HttpSession session) throws IOException { // photo.transferTo(); 将photo所对应的文件直接把他上传到我们所指定的文件(路径)所对应的位置。 // photo.getOriginalFilename();获取所上传的文件的文件名 //获取上传的文件的文件名 String filename = photo.getOriginalFilename(); //获取ServletContext对象 ServletContext servletContext = session.getServletContext(); //获取当前工程下photo的真实路径 String photoPath = servletContext.getRealPath("photo"); //创建ptotoPath所对应的File对象 File file=new File(photoPath); //判断file所对应目录是否存在 if(!file.exists()){ file.mkdir(); } String finalPath=photoPath+File.separator+filename; //上传文件 photo.transferTo(new File(finalPath)); return "success"; } }
之后,我们点击页面:
此时我们查看目录:
此时成功创建并上传照片成功。
此时图片为:屏幕截图 2023-05-22 082820.png
我们上传名字一致的文件时,会出现如下情况:
此时名字一致,但是图片内容会被覆盖:
这两张图片的名字都是屏幕截图 2023-05-22 082820.png,但是点开之后,图片为第二次上传的内容。
图片内容是进行复制,即先读再写。
我们的代码设置如下所示:
package com.rgf.controller; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.util.MultiValueMap; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.multipart.MultipartFile; import javax.servlet.ServletContext; import javax.servlet.http.HttpSession; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.util.UUID; /** * ResponseEntity:可以作为控制器方法的返回值,表示响应到浏览器的完整的响应报文 * * 文件上传的要求: * 1.form表单的请求方式必须为post * 2.form表单必须设置属性enctype="multipart/form-data" */ @Controller public class FileUpAndDownController { @RequestMapping("test/up") public String testUp(MultipartFile photo,HttpSession session) throws IOException { // photo.transferTo(); 将photo所对应的文件直接把他上传到我们所指定的文件(路径)所对应的位置。 // photo.getOriginalFilename();获取所上传的文件的文件名 //获取上传的文件的文件名 String fileName = photo.getOriginalFilename(); //获取上传的文件的后缀名 String hzName = fileName.substring(fileName.lastIndexOf(".")); //获取uuid String uuid = UUID.randomUUID().toString(); //拼接一个新的文件名 fileName=uuid+hzName; //获取ServletContext对象 ServletContext servletContext = session.getServletContext(); //获取当前工程下photo的真实路径 String photoPath = servletContext.getRealPath("photo"); //创建ptotoPath所对应的File对象 File file=new File(photoPath); //判断file所对应目录是否存在 if(!file.exists()){ file.mkdir(); } String finalPath=photoPath+File.separator+fileName; //FileOutputStream第二个参数默认为不追加而进行覆盖 // FileOutputStream os = new FileOutputStream(); //上传文件 photo.transferTo(new File(finalPath)); return "success"; } }
我们重新部署之后如下所示:
此时我们发现该目录下多了一个文件:
此时上传同样的文件名字之后,服务器所保存的文件名字是不一样的,从而避免被覆盖的情况出现。