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);
}
}