[ASP.net/JSP] ASP.net和JSP互相上傳多檔案、ASP.net使用HttpWebRequest上傳檔案到JSP

[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>

執行畫面檢視原始碼:

image

如果是自己手寫<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的內容分別是

image

 

 

 

開始寫程式

先看從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選取檔案

image

按下「上傳」

image

到JSP的網站根目錄查看

image

確實兩個檔案都進來了

接著把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

image

按下「上傳」

image

接著到JSP的網站根目錄查看

image

再上傳兩個檔案確實變成四個檔案

 

 

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選擇要上傳的檔案

image

按下「提交」

image

到ASP.net的upload資料夾底下查看

image

確實兩個檔案都進到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;
        }
    
    }


}

執行畫面:

先選擇檔案

image

再確認JSP網站根目錄目前是沒有上傳過來的檔案後

image

回到ASP.net的上傳畫面按下「上傳檔案」

FileUpload控制項的值被清空

image

到JSP的網站根目錄查看,有多了兩個檔案

ASP.net也可以藉由HttpWebRequest上傳檔案到JSP網站

image

 

而至於JSP要怎麼模擬HttpConnection來上傳檔案到ASP.net,這部份因為沒什麼用到,改天有空再研究

JSP可以參考:上传文件multipart form-data boundary 说明

 

 

 

本文參考資料:

Upload files with HTTPWebrequest (multipart/form-data)

檔案上傳 - 使用 Oreilly MultiPartRequest by 良葛格

Servlet/JSP Gossip: getPart()、getParts() by 良葛格

@MultipartConfig : Servlet 3.0 File Upload Example