Table of Contents
3.1.1:用於上傳文件的Form表單,需要設置enctype屬性。
1:什麼是mvc
- MVC是一個框架型設計模式
- 本身沒有實際的代碼(功能)
- 它只是說明頁面、數據處理如何擺放。
1.1:Model---邏輯處理
- 封裝應用狀態(封裝應用數據)
- 響應狀態查詢(對數據進行增刪改查)
- 暴露應用的功能(暴露接口<public>)
1.2:Controller---控制頁面跳轉
- 驗證HTTP請求的數據(收集組織數據)
- 將用戶數據與模型的更新相映射(調用邏輯層)
- 選擇用於響應的視圖(選擇下一個界面)
1.3:View ---演示數據
- 產生HTML響應(展示數據),如jsp,html等
- 請求模型的更新(人機交互)
- 提供HTML form用於用戶請求(收集參數,調用邏輯層api)
1.4:MVC的優缺點
1.4.1:MVC的優點:
低耦合性:視圖層和業務層分離
高重用性和可適用性
可維護性
有利於軟件工程化管理
提高軟件的健壯性
1.4.2: MVC的缺點:
工作量大,增加工作的複雜性,MVC不適合小型甚至中等規模的應用程序
將狀態查詢封裝在Model中,使Model過於臃腫。
2:定製錯誤頁面
聲明方式:
使用部署描述符爲特定情況(HTTP錯誤或Java異常)聲明錯誤頁面,並由Web容器將處理轉發到這些頁面
編程方式:
直接在servlet代碼中處理Java異常,並將HTTP請求轉發到所選定的錯誤頁面
2.1:聲明錯誤頁面
使用error-page元素聲明一個給定HTTP狀態碼的處理器:
<error-page>
<error-code>404</error-code>
<location>/error/404.html</location>
</error-page>
可以聲明任意數量的錯誤頁面,但一個給定的狀態碼只能對應一個頁面。
- 使用exception-type元素聲明給定Java異常的處理器
<error-page>
<exception-type>
java.lang.ArithmeticException
</exception-type>
<location>/error/ExceptionPage</location>
</error-page>
可以聲明任意數量的錯誤頁面,但一個給定的異常類型只對應一個頁面。
不能使用父類捕獲多種異常。
2.2:容器處理異常:
一個servlet可拋出ServletException指明有異常產生
所有檢查到的異常必須被捕獲,並封裝在ServletException中
編寫錯誤處理Servlet
- 應同時覆蓋doGet和doPost方法
兩個預定義的請求屬性:
- javax.servlet.error.exception :包含原始(被包裝)的異常
- javax.servlet.error.request_uri:包含原始客戶請求的URI
可編寫自己的servlet代碼捕獲所有異常並自己處理,而不是讓容器處理
使用此技術只可以處理Java異常,而非HTTP異常
步驟:
- 對可能產生異常的所有代碼使用一個 try-catch塊
- 在catch塊中使用RequestDispatcher將異常轉發到一個servlet異常處理器
- (可選)可以設置特定的請求屬性
聲明servlet異常處理器,但不提供URL映射
<servlet>
<servlet-name>ExceptionHandler</servlet-name>
<servlet-class>sl314.web.ExceptionDisplay</servlet-class>
</servlet>
使用servlet名獲得RequestDispatcher
ServletContext context = getServletContext();
RequestDispatcher errorPage= context.getNamedDispatcher("ExceptionHandler");
request.setAttribute("javax.servlet.error.exception", e);
request.setAttribute("javax.servlet.error.request_uri",
request.getRequestURI());
errorPage.forward(request, response);
3:文件上傳下載
3.1:文件上傳
在Servlet2.5中,我們要實現文件上傳功能時,一般都需要藉助第三方開源組件,例如Apache的commons-fileupload組件,在Servlet3.0中提供了對文件上傳的原生支持,我們不需要藉助任何第三方上傳組件,直接使用Servlet3.0提供的API就能夠實現文件上傳功能了。
3.1.1:用於上傳文件的Form表單,需要設置enctype屬性。
<form action="UploadServlet.do" method="post" enctype= "multipart/form-data">
</form>
3.1.2:開發支持文件上傳的Servlet
在Servlet類的聲明上,使用註解@MultipartConfig可以設置Servlet支持文件上傳。
@MultipartConfig
public class UploadServlet extends HttpServlet {
}
3.1.3:part類
Part是Java EE6.0新增的接口,Servlet3.0將multipart/form-data的部分POST請求封裝成Part,通過Part對上傳的文件進行操作。
//通過name獲得上傳文件對象Part
Part part=request.getPart("file");
//獲取上傳的文件集合
Collection<Part> parts = request.getParts();
3.2:單文件上傳
3.2.1:html頁面
上傳單個文件
<form action="UploadServlet.do" method="post" enctype="multipart/form-data">
上傳文件:
<input type="file" name="file">
<br>
<input type="submit" value="上傳">
</form>
3.2.2:Servlet
protected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
// 存儲路徑
String savePath = request.getServletContext().getRealPath("/uploadFile");
// 通過name獲得上傳文件對象Part
Part part = request.getPart("file");
// Servlet3沒有提供直接獲取文件名的方法,需要從請求頭中解析出來
// 獲取請求頭,請求頭的格式:form-data; name="file"; filename="snmp4j--api.zip"
String header = part.getHeader("content-disposition");
// 獲取文件名
String fileName = getFileName(header);
// 把文件寫到指定路徑
part.write(savePath + File.separator + fileName);
PrintWriter out = response.getWriter();
out.println("上傳成功");
out.flush();
out.close();
}
獲取文件名的方法:
/**
* 根據請求頭解析出文件名 請求頭的格式:
* 火狐和google瀏覽器下:form-data;name="file";filename="AmazeUI-2.7.2.zip"
* IE瀏覽器下:form-data; name="file";filename="E:\AmazeUI-2.7.2.zip"
* @param header 請求頭
* @return 文件名
*/
public String getFileName(String header) {
String[] tempArr1 = header.split(";");
/**
* 火狐或者google瀏覽器下:tempArr2={filename,"AmazeUI-2.7.2.zip"}
* IE瀏覽器下:tempArr2={filename,"E:\AmazeUI-2.7.2.zip"}
*/
String[] tempArr2 = tempArr1[2].split("=");
// 獲取文件名,兼容各種瀏覽器的寫法
String fileName = tempArr2[1].substring(tempArr2[1].lastIndexOf("\\") + 1).replaceAll("\"", "");
return fileName;
}
3.3:文件下載
在Servlet中實現文件的下載,第一需要通過HttpServletResponse的setContentType方法設置ContentType頭信息的值,這樣設置之後瀏覽器纔會以下載的方式來響應。第二需要使用IO流來讀取文件內容,將字節輸出在響應流中。
3.3.1:Servlet
@WebServlet("/downloadServlet.do")
public class DownloadServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 處理請求
// 根據根路徑得到絕對路徑
String path = this.getServletContext().getRealPath("/uploadFile/AmazeUI-2.7.2.zip");
// 讀取要下載的文件
File f = new File(path);
if (f.exists()) {
//需要注意:源文件的名稱是《AmazeUI-2.7.2.zip》,下載後的文件名稱是《妹子UI.zip》
// 解決中文文件名下載後亂碼的問題,將gbk編碼轉換成ISO8859_1編碼
String filename = new String("妹子UI.zip".getBytes("GBK"),"ISO8859-1");
response.setHeader("Content-Disposition", "attachment;filename=" + filename + "");
// 獲取要下載的文件輸入流
FileInputStream fis = new FileInputStream(f);
int len = 0;
// 創建數據緩衝區
byte[] buffer = new byte[1024*16];
// 通過response對象獲取OutputStream流
OutputStream out = response.getOutputStream();
// 將FileInputStream流寫入到buffer緩衝區
while ((len = fis.read(buffer)) > 0) {
//使用OutputStream將緩衝區的數據輸出到客戶端瀏覽器
out.write(buffer, 0, len);
out.flush();
}
out.close();
}
}
}
public Response downUpload(String id) {
InputStream in = null;
ByteArrayOutputStream bos = null;
try {
String fileName = "";
in = UploadIn.downloadFile(id);
bos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while((len = in.read(buffer)) != -1) {
bos.write(buffer, 0, len);
}
return Response.ok(bos.toByteArray())
.header("Content-disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"))
.header("Cache-Control", "no-cache").build();
}catch (Exception e){
System.out.println(""+e);
}finally {
try {
if(in != null)
in.close();
if(bos != null)
bos.close();
}catch (IOException e){
System.out.println(""+e);
}
}
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
}
3.3.2:Html頁面
<a href="downloadServlet.do">下載</a>
3.3.3:設置contentType
調用HttpServletResponse接口的setContentType方法,可以設置響應內容的類型,也叫MIME類型。它的作用是使客戶端瀏覽器可以區分不同類型的數據,並根據不同的MIME類型調用瀏覽器內不同的程序嵌入模塊來處理相應的數據。
例如web瀏覽器就是通過MIME類型來判斷文件是word。
// 根據根路徑得到絕對路徑
String path = this.getServletContext()
.getRealPath("/uploadFile/[匯才同飛教育]預科班教程_V1.6.docx");
// 讀取要下載的文件
File f = new File(path);
String filename =
new String(f.getName().getBytes("GBK"),"ISO8859-1");
response.setHeader("Content-Disposition",
"attachment;filename=" + filename + "");
//設置響應類型是word
response.setContentType("application/x-msdownload");
3.3.4:常用ContentType
文件擴展名 |
Content-Type(Mime-Type) |
.*(二進制流,不知道文件類型) |
application/octet-stream |
.tif |
image/tiff |
.awf |
application/vnd.adobe.workflow |
.avi |
video/avi |
.bmp |
application/x-bmp |
.doc |
application/msword |
.class |
java/* |
.css |
text/css |
.exe |
application/x-msdownload |
.excel |
application/vnd.ms-excel |
.gif |
image/gif |
.htm |
text/html |
.html |
text/html |
.ico |
image/x-icon |
.img |
application/x-img |
.java |
java/* |
.jpe |
image/jpeg |
.jpeg |
image/jpeg |
.jpg |
image/jpeg |
.jsp |
text/html |
.mp3 |
audio/mp3 |
.mp4 |
video/mpeg4 |
.mpeg |
video/mpg |
.odc |
text/x-ms-odc |
|
application/pdf |
.png |
image/png |
.ppt |
application/vnd.ms-powerpoint |
rar |
application/octet-stream |
.rmvb |
application/vnd.rn-realmedia-vbr |
.swf |
application/x-shockwave-flash |
.torrent |
application/x-bittorrent |
.txt |
text/plain |
.xml |
text/xml |
.zip |
application/x-zip-compressed |