[ASP.net/JSP] ASP.net和JSP互相上傳多檔案、ASP.net使用HttpWebRequest上傳檔案到JSP
題外話
早上到[Java] 使用過的Library 要找JSP的上傳檔案套件時,發現內容怎麼變成另一篇文章?
以前紀錄用過的套件全沒了就跟之前Windows Live ID被盜一樣讓我痛風差點發作Orz
=======
回歸正題
此篇文章點子來源:请问 jsp form 可以上传文件到asp.net 网站上么?
兩個不同語言的網站是可以互相上傳檔案的
寫此篇順便紀錄幾個重點
1. ASP.net WebForm不透過FileUpload控制項的SaveAs()方法來實現多檔案上傳(到ASP.net Server端)
2. JSP(Java)的Oreilly MultiPartRequest如何做到上傳檔案重新命名
3. 自我練習ASP.net HttpWebRequest執行上傳檔案
準備工作:
要上傳檔案的話
1. <form>屬性一定要有enctype="multipart/form-data"
如果使用ASP.net WebForm的FileUpload控制項,.net會自動加上去
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" Debug="true" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server" >
<%--顯示上傳結果--%>
<asp:Literal id="li_showResult" runat="server" />
<br />
<asp:FileUpload runat="server" ID="FileUpload1" /><br />
<asp:FileUpload runat="server" ID="FileUpload2" />
<asp:Button Text="上傳" ID="mySubmit" runat="server" />
</form>
</body>
</html>
執行畫面檢視原始碼:
如果是自己手寫<input type=”file”name=”fileData” />則一定要加上name名稱
並且<form>的method確保是post
如此才能上傳成功
2.
ASP.net的程式網址:http://localhost:4815/test/Default.aspx
JSP則分成兩支
一為Servlet版:http://localhost:8084/WebApplication1/UploadServlet
另一為使用Oreilly上傳套件的.jsp:http://localhost:8084/WebApplication1/UploadFile.jsp
3.
準備兩個要上傳的檔案
測試1.txt、測試2.txt的內容分別是
開始寫程式
先看從ASP.net => JSP(Servlet)
Default.aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" Debug="true" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<%--ASP.net WebForm執行起來表單自己會加method="post"--%>
<%--因為設計畫面有放FileUpload,所以執行結來form會自動被加enctype="multipart/form-data"--%>
<%--action為JSP的Servlet位置--%>
<form id="form1" runat="server" action="http://localhost:8084/WebApplication1/UploadServlet" >
<%--顯示上傳結果--%>
<asp:Literal id="li_showResult" runat="server" />
<br />
<asp:FileUpload runat="server" ID="FileUpload1" /><br />
<asp:FileUpload runat="server" ID="FileUpload2" />
<asp:Button Text="上傳" ID="mySubmit" runat="server" />
</form>
</body>
</html>
Default.aspx.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using System.IO;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Wordprocessing;
using System.Text;
using System.Security.Principal;
using System.Data;
using System.Collections;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!string.IsNullOrEmpty(Request.QueryString["result"]))
{
/*ASP.net上傳檔案到JSP,上傳完成並導回此頁顯示上傳結果*/
li_showResult.Text = Request.QueryString["result"];
}
}
}
JSP的UploadServlet.java
import java.io.IOException; import java.io.PrintWriter; import java.net.URLEncoder; import java.util.UUID; import javax.servlet.ServletException; import javax.servlet.annotation.MultipartConfig; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.Part; @WebServlet(name = "UploadServlet", urlPatterns = {"/UploadServlet"}) @MultipartConfig/*此annotation必加*/ public class UploadServlet extends HttpServlet { protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); request.setCharacterEncoding("UTF-8"); PrintWriter out = response.getWriter(); try { /*要在ASP.net顯示的上傳結果訊息*/ String result = ""; /*如果post過來的表單有加enctype="multipart/form-data"屬性,則JSP要用getPart來抓取*/ for(Part part:request.getParts()) { if (!"mySubmit".equalsIgnoreCase(part.getName()) && !"__VIEWSTATE".equalsIgnoreCase(part.getName()) && !"__EVENTVALIDATION".equalsIgnoreCase(part.getName()) ) { //排除submit按鈕,因為ASP.net WebForm會自動產生name為__VIEWSTATE和__EVENTVALIDATION的hidden,這個也要排除 String header = part.getHeader("Content-Disposition"); /*原始檔名*/ String filename = header.substring( header.indexOf("filename=\"") + 10, header.lastIndexOf("\"")); /*取得副檔名*/ String fileExtensionName = filename.substring(filename.lastIndexOf(".")); /*拼出不重覆的檔名*/ filename = UUID.randomUUID().toString() + fileExtensionName; /*存檔在JSP網站根目錄下*/ part.write(request.getRealPath("/") + filename); } }//End foreach //導回ASP.net頁面,並傳遞QueryString response.sendRedirect("http://localhost:4815/test/Default.aspx?result="+ URLEncoder.encode("上傳完成!", "UTF-8")); } catch(Exception ex) { //導回ASP.net頁面,並傳遞QueryString response.sendRedirect("http://localhost:4815/test/Default.aspx?result="+ URLEncoder.encode("上傳失敗!", "UTF-8")); }finally { out.close(); } } @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } @Override public String getServletInfo() { return "Short description"; } }
執行結果:
在ASP.net選取檔案
按下「上傳」
到JSP的網站根目錄查看
確實兩個檔案都進來了
接著把ASP.net的Default.aspx的 action改一下位置
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" Debug="true" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<%--ASP.net WebForm執行起來表單會自己加method="post"--%>
<%--因為設計畫面有放FileUpload,所以執行結來form會自動被加enctype="multipart/form-data"--%>
<%--action為.jsp檔--%>
<form id="form1" runat="server" action="http://localhost:8084/WebApplication1/UploadFile.jsp" >
<%--顯示上傳結果--%>
<asp:Literal id="li_showResult" runat="server" />
<br />
<asp:FileUpload runat="server" ID="FileUpload1" /><br />
<asp:FileUpload runat="server" ID="FileUpload2" />
<asp:Button Text="上傳" ID="mySubmit" runat="server" />
</form>
</body>
</html>
JSP的UploadFile.jsp使用Oreilly MultipartRequest上傳檔案寫法
<%@page import="java.net.URLEncoder"%>
<%@page import="java.io.File"%>
<%@page import="com.oreilly.servlet.multipart.DefaultFileRenamePolicy"%>
<%@page import="com.oreilly.servlet.multipart.FileRenamePolicy"%>
<%@page import="java.util.Enumeration"%>
<%@page import="java.util.Iterator"%>
<%@page import="java.io.OutputStream"%>
<%@page import="java.util.UUID"%>
<%@page import="java.io.FileOutputStream"%>
<%@page import="java.io.InputStream"%>
<%@page import="com.oreilly.servlet.MultipartRequest" %>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%
/*網站根目錄(檔案總管路徑)*/
String saveDirectory = request.getRealPath("/");
// 限制上傳之檔案大小為 10 MB
int maxPostSize = 10 * 1024 * 1024 ;
/*override檔案命名規則物件*/
FileRenamePolicy policy = new DefaultFileRenamePolicy(){
@Override
public File rename(File file) {
String fileExtension = file.getName().substring(file.getName().lastIndexOf("."));
String fileSaveName = UUID.randomUUID().toString() + fileExtension;
File result = new File(file.getParentFile(), fileSaveName);
return result;
}
};
/*上傳檔案完成*/
MultipartRequest multi = new MultipartRequest(request , saveDirectory , maxPostSize, "UTF-8",policy);
//導回ASP.net頁面,並傳遞QueryString
response.sendRedirect("http://localhost:4815/test/Default.aspx?result="+ URLEncoder.encode("上傳成功!", "UTF-8"));
/*Enumeration names = multi.getFileNames();
while(names.hasMoreElements()) {
String name = (String) names.nextElement();
out.print("接到file參數:" +name+",已儲存檔名:"+ multi.getFile(name).getName()+"<hr/>");
}
*/
%>
再執行ASP.net的Default.aspx
確定action為JSP的UploadFile.jsp
按下「上傳」
接著到JSP的網站根目錄查看
再上傳兩個檔案確實變成四個檔案
ASP.net => JSP看完後
接著看
JSP => ASP.net
JSP(index.jsp)選擇檔案要上傳的畫面原始碼
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>JSP Page</title>
</head>
<body>
<%--action為ASP.net的Url--%>
<form name="form1" method="post" action="http://localhost:4815/test/Default.aspx" enctype="multipart/form-data">
<input type="file" name="fileData1" /><br />
<input type="file" name="fileData2" />
<input type="submit" name="mySubmit" value="提交"/>
<%
String result = request.getParameter("result")!=null?(String)request.getParameter("result"):"";
if(!"".equals(result))
{
out.print("<hr/>" +result);
}
%>
</form>
</body>
</html>
ASP.net(Default.aspx) 稍微改寫一下程式
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" Debug="true" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server" >
</form>
</body>
</html>
Default.aspx.cs
這裡該注意多檔案上傳的寫法,其實跟ASP.net MVC是一樣的,就算畫面上有FileUpload控制項,也可以用此方式做多檔案上傳
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using System.IO;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Wordprocessing;
using System.Text;
using System.Security.Principal;
using System.Data;
using System.Collections;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
/*從JSP Post過來的<input type='file' />*/
if (Request.Files.Count > 0)
{
for (int i = 0; i < Request.Files.Count; i++)
{
//檔名不為空字串才儲存
if (!string.IsNullOrEmpty(Request.Files[i].FileName))
{
HttpPostedFile file = Request.Files[i];
/*產生不重覆的檔名*/
string fileName = Guid.NewGuid().ToString() + Path.GetExtension(file.FileName);
/*儲存檔案*/
file.SaveAs(Server.MapPath("~/upload/") + fileName);
}
}
/*上傳完成,導回JSP頁面*/
Response.Redirect("http://localhost:8084/WebApplication1/index.jsp?result=" + HttpUtility.UrlEncode("上傳完成", Encoding.UTF8));
}
}
}
接下來從JSP執行index.jsp選擇要上傳的檔案
按下「提交」
到ASP.net的upload資料夾底下查看
確實兩個檔案都進到ASP.net網站了
===========================
最後要試試
ASP.net => JSP
然後不依賴<form>的action,ASP.net要用HttpWebRequest物件實現上傳檔案到JSP網站
再改寫一下Default.aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" Debug="true" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server" >
<asp:FileUpload runat="server" ID="FileUpload1" /><br />
<asp:FileUpload runat="server" ID="FileUpload2" />
<asp:Button Text="上傳檔案到JSP" ID="btn_Go" runat="server"
onclick="btn_Go_Click" />
</form>
</body>
</html>
Default.aspx.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using System.IO;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Wordprocessing;
using System.Text;
using System.Security.Principal;
using System.Data;
using System.Collections;
using System.Net;
using System.Collections.Specialized;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
/*JSP儲存檔案網址*/
string url = @"http://localhost:8084/WebApplication1/UploadFile.jsp";
//送出Button Click事件
protected void btn_Go_Click(object sender, EventArgs e)
{
//走訪<input type="file" />控制項
for (int i = 0; i < Request.Files.Count; i++)
{
//檔名不為空(FileUpload有選擇檔案)的,才丟到JSP
if (!string.IsNullOrEmpty(Request.Files[i].FileName))
{
this.uploadFile(this.url, Request.Files[i]);
}
}
}
//上傳一個檔案給url對象
private void uploadFile(string url, HttpPostedFile file)
{
//拼接分隔符號
string boundary = "---------------------------" + Guid.NewGuid().ToString();
byte[] boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");
//建立HttpWebRequest物件
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
webRequest.ContentType = "multipart/form-data; boundary=" + boundary;
webRequest.Method = "POST";
webRequest.KeepAlive = true;
//wr.Credentials = System.Net.CredentialCache.DefaultCredentials;
Stream requestStream = webRequest.GetRequestStream();
//將分隔符號資訊寫入requestStream
requestStream.Write(boundarybytes, 0, boundarybytes.Length);
//一定要用雙引號
string headerTemplate = "Content-Disposition: form-data; name=\"file\"; filename=\"{0}\"\r\nContent-Type:application/octet-stream\r\n\r\n";
string header = string.Format(headerTemplate, file.FileName);
byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(header);
//將header資訊寫入requestStream
requestStream.Write(headerbytes, 0, headerbytes.Length);
//取得上傳檔案的串流
Stream fileStream = file.InputStream;
//宣告要儲存檔案的byte陣列
byte[] bytefile = new byte[fileStream.Length];
//自fileStream讀進byte陣列
fileStream.Read(bytefile, 0, bytefile.Length);
//關閉串流
fileStream.Close();
//把檔案的byte陣列寫入requestStream
requestStream.Write(bytefile, 0, bytefile.Length);
//將結束的分隔符號寫入requestStream
byte[] trailer = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n");
requestStream.Write(trailer, 0, trailer.Length);
WebResponse wresp = null;
try
{
wresp = webRequest.GetResponse();//執行Request來取得Response
}
catch (Exception ex)
{
}
finally
{
//釋放資源
if (wresp != null)
{
wresp.Close();
wresp = null;
}
//關閉串流
requestStream.Close();
requestStream = null;
webRequest = null;
}
}
}
執行畫面:
先選擇檔案
再確認JSP網站根目錄目前是沒有上傳過來的檔案後
回到ASP.net的上傳畫面按下「上傳檔案」
FileUpload控制項的值被清空
到JSP的網站根目錄查看,有多了兩個檔案
ASP.net也可以藉由HttpWebRequest上傳檔案到JSP網站
而至於JSP要怎麼模擬HttpConnection來上傳檔案到ASP.net,這部份因為沒什麼用到,改天有空再研究
JSP可以參考:上传文件multipart form-data boundary 说明
本文參考資料:
Upload files with HTTPWebrequest (multipart/form-data)
檔案上傳 - 使用 Oreilly MultiPartRequest by 良葛格