14.SSM框架集~SpringMVC文件上传下载
本文是上一篇文章的后续,详情点击该链接
SpringMVC中使用作用域对象完成数据的流转
名称 | 作用域 |
application | 在所有应用程序中有效 |
session | 在当前会话中有效 |
request | 在当前请求中有效 |
page | 在当前页面中有效 |
SpringMVC中使用作用域对象流转数据
使用request对象作为请求转发数据流转的载体
作用域范围:一次请求内。
作用: 解决了一次请求内的资源的数据共享问题
使用方式和原有Servlet中使用方式完全一致,只不过现在需要在单元方法中来使用。
@Controller
public class MyController {
@RequestMapping("/requestA")
public String RequestScope(HttpServletRequest request){
request.setAttribute("msg","request");
return "forward:/scope.jsp";
}
}
使用session对象作为同一个用户的不同请求的数据流转的载体
作用域范围:一次会话内有效。
说明:浏览器不关闭,并且后台的session不失效,在任意请求中都可以获取到同一个session对象。
作用:解决了一个用户不同请求的数据共享问题。
使用方式和原有Servlet中使用方式完全一致,只不过现在需要在单元方法中来使用,在单元方法的形参上直接声明session即可。
@RequestMapping("/sessionA")
public String sessionSope(HttpSession session){
session.setAttribute("msg","session值");
return "redirect:/scope.jsp";
}
使用application对象作用项目公共数据的载体。
作用域范围:整个项目内有效。
特点:一个项目只有一个,在服务器启动的时候即完成初始化创建无论如何获取都是同一个项目。
作用:解决了不同用户的数据共享问题。
application对象的获取,只能我们自己在单元方法中获取,不能使用形参的方式,让DispatcherServlet帮我们获取。
@RequestMapping("/applicationA")
public String ApplicationScope(HttpServletRequest request){
//获得applicationContext
ServletContext servletContext = request.getServletContext();
servletContext.setAttribute("msg","application值");
return "redirect:/scope.jsp";
}
SpringMVC的Model对象的使用
作为数据流转的载体,SpringMVC官方提供的一个对象,在单元方法上声明Model类型的形参即可。
Model对象是由DispatcherServlet创建并作为实参传递给单元方法使用。
请求转发:model对象中存储的数据,相当于存储到了request对象中我们在jsp中直接按照request对象作用域取值的方式来获取数据即可。
重定向:在重定向中,会将第一次请求中model对象的数据作为第二次请求的请求数据携带,第一次请求的model对象销毁。只能携带基本类型的数据。
请求转发中使用Model对象作为数据流转的载体
@RequestMapping("/modelScopeA")
public String modelScopeA(Model model){
model.addAttribute("msg","model值");
return "forward:/scope.jsp";
}
这个值会被request接收
重定向中使用Model对象作为数据流转的载体
@RequestMapping("/modelScopeB")
public String modelScopeB(Model model){
model.addAttribute("msg","model值");
return "redirect:/scope.jsp";
}
SpringMVC的自定义视图解析器
我们在SpringMVC的响应中,直接在单元方法中返回字符串数据来表明请求转发或者重定向的资源,DispatcherServlet的底层默认使用ModelAndView来完成视图资源的解析和跳转。
ModelAndView这个视图 解析器比较死板ModelAndView会将单元方法返回的字符串,根据关键拆分后来完成资源的跳转,比如:”forward:/index.jsp”,那么ModelAndView就会直接请求转发index.jsp资源。
我们在实际生产环境中往往会有很多特殊的需求,这样ModelAndView就无法满足了,比如,我们在项目下创建一个A文件夹,在A文件夹下创建B子文件夹,在B下创建一个C子文件夹,然后将项目的页面资源全部放到C文件夹下,这样我们如果在单元方法中请求转发C文件夹中的资源,返回值路径:
”forward:/A/B/C/index.jsp”
”forward:/A/B/C/page.jsp”
“forward:/A/B/C/sel.jsp”
后期一旦资源路径的文件夹名字发生变更,修改起来也会非常的麻烦。
使用自定义视图解析器,我们自定义的视图解析器除了可以让我们根据需求配置一些路径上的常量参数以外,还需具备ModelAndView的逻辑。所以,我们自己需要从头创建一个新的视图解析器,在我们自己创建的视图解析器中声明ModelAndView中的原有逻辑代码,以及我们自己需要的部分常量参数。但是ModelAndView的逻辑我们是不知道的,那么能不能让SpringMVC官方提供一个支持部分数据自定义的视图解析器呢,答案是可以的。我们可以通过配置文件来配置一些我们在视图解析器中的常量数据。
InternalResourceViewResolver可以让我们通过配置文件来设置一些常量参数,所以我们将该视图解析器称为自定义视图解析器。
配置xml
<!-- 自定义视图解析器 -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 前缀 -->
<property name="prefix" value="/WEB-INF/"></property>
<!-- 后缀 -->
<property name="suffix" value=".jsp"></property>
</bean>
这个时候我们只需要返回名字就可以了
@RequestMapping("/Show")
public String show(){
return "main";
}
SpringMVC的上传
添加依赖
<!--文件上传组件的依赖 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
配置文件上传表单组件对象
<!-- 配置文件上传表单组件对象 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> </bean>
前台实现
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<base href="<%=request.getContextPath()+"/"%>">
<script type="text/javascript" src="js/jquery-1.12.3.min.js"></script>
<script type="text/javascript">
$(function () {
$("#upload1").click(function () {
//发送ajax请求进行文件上传
//选择文件的对象信息
var f=$("#fi")[0].files[0];
//创建文件上传的载体对象
var formdata=new FormData();
formdata.append("photo",f);
$.ajax({
type:"post",
url:"fileUpload",
data:formdata,
processData:false,
contentType:false,
success:function (result) {
alert(result);
}
})
})
})
</script>
</head>
<body>
<p>
<input type="file" id="fi" /> <a href="javascript:void(0)" id="upload1">立即上传</a>
</p>
</body>
</html>
后台实现
@RequestMapping("/fileUpload")
@ResponseBody
public String fileUpload(MultipartFile photo) throws IOException {
//上传到桌面
photo.transferTo(new File("C:\\Users\\36961\\Desktop\\" + photo.getOriginalFilename()));
return "OK!";
}
MultipartFile 接收前台文件的类型
photo 和前台传递的name名称保持一致
photo.getOriginalFilename() 原始的文件名称
很显然,这种上传方式是非常简陋的,我们会遇到很多问题。常见的问题如下:
上传图片时名字出现中文乱码
解决:
<!-- 配置文件上传表单组件对象 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="UTF-8"></property>
</bean>
上传的文件夹名称必须要给出
解决:
//自动创建文件目录
File file = new File("C:\\Users\\36961\\Desktop\\New");
//判断是否存在
if(!file.exists()){
//创建
file.mkdirs();
}
上传图不到当前的服务器路径中
解决:
//获得服务器的目录
String realPath = request.getServletContext().getRealPath("/upload");
System.out.println(realPath);
//自动创建文件目录
File file = new File(realPath);
相同的图片名称会覆盖
解决:
//重置上传文件的名称
String uuid = UUID.randomUUID().toString();
//获得原始文件名最后一个.的下标开始截取
String substring = photo.getOriginalFilename().substring(photo.getOriginalFilename().lastIndexOf("."));
//完整的文件名称, 名称 + 后缀
String fileName = uuid + substring;
无法指定上传图片的大小
解决一:判断
//约束上传文件的大小
if(photo.getSize() > 20 * 1024){
return "Error Size";
}
解决二:约束大小
<!-- 约束文件大小 -->
<property name="maxUploadSize" value="1024"></property>
<!-- 配置异常解析器 -->
<bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<!-- key:异常的全路径,指定的异常是Spring种异常 -->
<prop key="org.springframework.web.multipart.MaxUploadSizeExceededException">
redirect:/error.jsp
</prop>
</props>
</property>
</bean>
无法指定上传文件的类型
解决:
//约束文件的类型
if(".jpg".equals(substring) || "zip".equals(substring)){
return "Error Type";
}
完整代码如下:
springMvc.xml配置
<?xml version="1.0" encoding="UTF8"?>
<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:aop="http://www.springframework.org/schema/aop"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://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/aop
https://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--@Controller-->
<context:component-scan base-package="com.alvin.controller"></context:component-scan>
<!--@RequestMapping-->
<mvc:annotation-driven></mvc:annotation-driven>
<!-- 自定义视图解析器 -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 前缀 -->
<property name="prefix" value="/WEB-INF/"></property>
<!-- 后缀 -->
<property name="suffix" value=".jsp"></property>
</bean>
<!-- 配置文件上传表单组件对象 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="UTF-8"></property>
<!-- 约束文件大小 -->
<property name="maxUploadSize" value="1024"></property>
</bean>
<!-- 配置异常解析器 -->
<bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<!-- key:异常的全路径,指定的异常是Spring种异常 -->
<prop key="org.springframework.web.multipart.MaxUploadSizeExceededException">
redirect:/error.jsp
</prop>
</props>
</property>
</bean>
<!--静态资源放行标签-->
<!--mapping:代表的是网络中访问的路径 location:代表本地放行的文件位置-->
<mvc:resources mapping="/img/**" location="/img/"></mvc:resources>
<mvc:resources mapping="/css/**" location="/css/"></mvc:resources>
<mvc:resources mapping="/js/**" location="/js/"></mvc:resources>
</beans>
Java
@Controller
public class MyController {
@RequestMapping("/fileUpload")
@ResponseBody
public String fileUpload(MultipartFile photo,HttpServletRequest request) throws IOException {
/*
//约束上传文件的大小
if(photo.getSize() > 20 * 1024){
return "Error Size";
}*/
//重置上传文件的名称
String uuid = UUID.randomUUID().toString();
//获得原始文件名最后一个.的下标开始截取
String substring = photo.getOriginalFilename().substring(photo.getOriginalFilename().lastIndexOf("."));
//完整的文件名称, 名称 + 后缀
String fileName = uuid + substring;
//获得服务器的目录
String realPath = request.getServletContext().getRealPath("/upload");
System.out.println(realPath);
//自动创建文件目录
File file = new File(realPath);
//判断是否存在
if(!file.exists()){
//创建
file.mkdirs();
}
photo.transferTo(new File(file,fileName));
//约束文件的类型
if(".jpg".equals(substring) || "zip".equals(substring)){
return "Error Type";
}
return "OK!";
}
}
jsp不变,那么接下来,我们来讲讲SpringMVC跨服务器方式的文件上传
SpringMVC跨服务器方式的文件上传
分服务器
数据库服务器:运行我们的数据库
缓存和消息服务器:负责处理大并发访问的缓存和消息
文件服务器:负责存储用户上传文件的服务器。
应用服务器:负责部署我们的应用
在实际开发中我们会运用很多功能不同的服务器,分服务器处理的目的是让服务器各司其职,从而提高我们项目的运行效率。
服务器工作示意图
代码实现
添加依赖
<!-- 跨服务器文件访问依赖 -->
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>1.19</version>
</dependency>
@Controller
public class MyControllerPlus {
public static final String FILESERVERURL = "http://localhost:8080/Servlet/uploads/";
/**
* 文件上传,保存文件到不同服务器
*/
@RequestMapping("/fileUpload")
public String testResponseJson(String picname, MultipartFile uploadFile) throws Exception{
//定义文件名
String fileName = "";
//获取原始文件名
String uploadFileName = uploadFile.getOriginalFilename();
//截取文件扩展名
String extendName = uploadFileName.substring(uploadFileName.lastIndexOf(".")+1,
uploadFileName.length());
//把文件加上随机数,防止文件重复
String uuid = UUID.randomUUID().toString();
//文件名
fileName = uuid+"."+extendName;
System.out.println(fileName);
//创建 sun 公司提供的 jersey 包中的 Client 对象
Client client = Client.create();
//指定上传文件的地址,该地址是 web 路径
WebResource resource = client.resource(FILESERVERURL+fileName);
//实现上传
String result = resource.put(String.class,uploadFile.getBytes());
System.out.println(result);
return "success";
}
}
Spring MVC下载
文件的上传是将用户本地的资源发送到服务器,让服务器存储到其硬盘中的过程。而下载和上传正好是相反的过程。下载是用户发起请求,请求要下载的资源。服务器根据请求,将其硬盘中的文件资源发送给浏览器的过程。
代码实现
@Controller
public class MyControllerPlusPro {
//声明单元方法:处理下载请求
@RequestMapping("downFile")
public void downFile(String filename, HttpServletResponse response, HttpServletRequest request) throws IOException, IOException {
//设置下载资源的MIME类型?
//设置响应头,告诉浏览器下载的资源需要存储到客户端的硬盘中,而不是解析打开。
response.setHeader("Content-Disposition", "attachment;filename="+filename);
//获取要下载的资源的流对象
//获取文件的绝对路径
String path=request.getServletContext().getRealPath("/upload");
//获取文件的二进制数据
byte[] bytes = FileUtils.readFileToByteArray(new File(path, filename));
//2.响应浏览器
//获取输出流对象
ServletOutputStream outputStream = response.getOutputStream();
//响应资源
outputStream.write(bytes);
}
}