c#同時上傳文件和參數,Java接收的完整教程,炒雞簡單!網上的教程弱爆了!

工作需求,需要在c#端將文件和數據進行上傳,Java端接收文件上傳到oss,將數據處理到數據庫。

這個教程,秒殺市面百分九十九的帖子,絕對是樓主精心打造!

一、網上的一般做法

網上搜出來的教程,基本都是隻上傳文件的,但對於如何把數據和文件一起上傳,那能找到的資料就很少了,不過不管是單獨傳文件,還是文件帶數據,原理都一樣,都是模擬瀏覽器行爲,構造請求頭和請求參數上傳,對於帶文件的,需要指定contentType,然後通過流的方式進行上傳。

這種方法,不是很方便,因爲既要帶文件,又要帶數據,尤其如果數據是跟文件相關的時候,不好處理,Java中數據的接收方法如下:

c#中的發送數據如下:

1.完整的c#代碼如下:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Text;
using NUnit.Framework;
using System.Drawing;
namespace TestProject1
{  /// <summary>
    /// 實現文件和參數一起提交
    /// </summary>
    public static class FormUpload
    {
        /// <summary>
        /// 字符編碼格式
        /// </summary>
        private static readonly Encoding encoding = Encoding.UTF8;
        private const string DefaultUserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)";

        public static String ImageFile2Base64(String imageFile)
        {
            
            Image image = Image.FromFile(imageFile);
            MemoryStream ms = new MemoryStream();
            image.Save(ms, image.RawFormat);
            byte[] byteArray = ms.ToArray();
            ms.Close();
            return Convert.ToBase64String(byteArray);
        }
        
        
        
        /// <summary>
        /// 上傳圖像和參數
        /// </summary>
        /// <param name="url">上傳地址</param>
        /// <param name="image">圖像byte數組</param>
        /// <param name="imageName">圖像名稱,帶擴展名</param>
        /// <param name="data">參數</param>
        /// <returns>響應內容</returns>
        public static string UploadImageAndData(string url,byte[] image,string imageName,string data)
        {
            Dictionary<string, object> dic = new Dictionary<string, object>();
            //dic.Add("file", new FormUpload.FileParameter(image, imageName));
            dic.Add("file", new FormUpload.FileParameter(image, imageName));
            
            //可以封裝跟文件相關的其他屬性,這裏是最舒服的
            dic.Add("info", data);
            dic.Add("文件相關的業務參數", "1");
            
            
            try
            {
                HttpWebResponse r = FormUpload.MultipartFormDataPost(url, DefaultUserAgent, dic);
                Stream instream = r.GetResponseStream();
                StreamReader sr = new StreamReader(instream, Encoding.UTF8);
                //返回結果網頁(html)代碼 
                string retValue = sr.ReadToEnd();
                r.Close();
                sr.Close();
                return retValue;
            }
            catch (Exception e)
            {
                Debug.WriteLine("文件傳輸異常: " + e.Message);
                throw e;
            }
        }

        public static HttpWebResponse MultipartFormDataPost(string postUrl, string userAgent, Dictionary<string, object> postParameters)
        {
            //分割標記
            string formDataBoundary = String.Format("----------{0:N}", Guid.NewGuid());
            //內容類型
            string contentType = "multipart/form-data; boundary=" + formDataBoundary;
            byte[] formData = GetMultipartFormData(postParameters, formDataBoundary);
            return PostForm(postUrl, userAgent, contentType, formData);
        }

        private static HttpWebResponse PostForm(string postUrl, string userAgent, string contentType, byte[] formData)
        {
            HttpWebRequest request = WebRequest.Create(postUrl) as HttpWebRequest;
            if (request == null)
            {
                throw new NullReferenceException("request is not a http request");
            }
            // Set up the request properties. 
            request.Method = "POST";
            request.ContentType = contentType;
            //request.ContentType = "application/json;charset=utf-8";
           // request.UserAgent = userAgent;
           // request.CookieContainer = new CookieContainer();
            request.ContentLength = formData.Length;
            //request.Timeout = 1000*60;
            //request.Headers.Add("Seq","1");
            //request.Headers.Add("Authorization", "d10CdKTSbGPqdhrk9HcPvAnknuDp7d2WnsFDrWFA");
            //request.Headers.Add("Cha-Code","1501042092");
            
            // You could add authentication here as well if needed: 
            // request.PreAuthenticate = true; 
            // request.AuthenticationLevel = System.Net.Security.AuthenticationLevel.MutualAuthRequested; 
            // request.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(System.Text.Encoding.Default.GetBytes("username" + ":" + "password"))); 
            // Send the form data to the request. 
            using (Stream requestStream = request.GetRequestStream())
            {
                requestStream.Write(formData, 0, formData.Length);
                requestStream.Close();
            }
            return request.GetResponse() as HttpWebResponse;
        }

        private static byte[] GetMultipartFormData(Dictionary<string, object> postParameters, string boundary)
        {
            Stream formDataStream = new System.IO.MemoryStream();
            bool needsCLRF = false;
            foreach (var param in postParameters)
            {
                // Thanks to feedback from commenters, add a CRLF to allow multiple parameters to be added. 
                // Skip it on the first parameter, add it to subsequent parameters. 
                if (needsCLRF)
                {
                    formDataStream.Write(encoding.GetBytes("\r\n"), 0, encoding.GetByteCount("\r\n"));
                }
                needsCLRF = true;
                if (param.Value is FileParameter)
                {
                    FileParameter fileToUpload = (FileParameter)param.Value;
                    // Add just the first part of this param, since we will write the file data directly to the Stream 
                    string header = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"; filename=\"{2}\";\r\nContent-Type: {3}\r\n\r\n", boundary, param.Key, fileToUpload.FileName ?? param.Key, fileToUpload.ContentType ?? "application/octet-stream");
                    formDataStream.Write(encoding.GetBytes(header), 0, encoding.GetByteCount(header));
                    // Write the file data directly to the Stream, rather than serializing it to a string. 
                    formDataStream.Write(fileToUpload.File, 0, fileToUpload.File.Length);
                }
                else
                {
                    string postData = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"\r\n\r\n{2}", boundary, param.Key, param.Value);
                    formDataStream.Write(encoding.GetBytes(postData), 0, encoding.GetByteCount(postData));
                }
            }
            // Add the end of the request. Start with a newline 
            string footer = "\r\n--" + boundary + "--\r\n";
            formDataStream.Write(encoding.GetBytes(footer), 0, encoding.GetByteCount(footer));
            // Dump the Stream into a byte[] 
            formDataStream.Position = 0;
            byte[] formData = new byte[formDataStream.Length];
            formDataStream.Read(formData, 0, formData.Length); formDataStream.Close();
            return formData;
        }

        /// <summary>
        /// 文件參數對象
        /// </summary>
        public class FileParameter
        {
            /// <summary>
            /// 文件二進制數組
            /// </summary>
            public byte[] File { get; set; }
            /// <summary>
            /// 文件名稱,帶擴展名,例如:aaa.jpg
            /// </summary>
            public string FileName { get; set; }

            /// <summary>
            /// 內容類型,默認application/octet-stream
            /// </summary>
            public string ContentType { get; set; }
            public FileParameter(byte[] file)
                : this(file, null)
            {
            }
            public FileParameter(byte[] file, string filename)
                : this(file, filename, null)
            {
            }
            public FileParameter(byte[] file, string filename, string contenttype)
            {
                File = file;
                FileName = filename;
                ContentType = contenttype;
            }
        }
        
        
        class Programss
        {
            [Test]
            public void Test1()
            {
                
                
                string retValue = UploadFiles();
                Console.WriteLine(retValue);
                Console.Read();
        
            }

            static string UploadFiles()
            {
                string url= "http://ip:port/路徑";
                //string url = "http:.......";
                string imageName = Guid.NewGuid().ToString("N") + ".jpg";
                byte[] image = File.ReadAllBytes("D:\\1.jpg");
                string data = "提交參數";
                return FormUpload.UploadImageAndData(url,image, imageName, data);
            }
        }
    }
} 

2.Java端接收代碼:

//接收實體類
@Data
public class ReportImgVO {

	/** 文件*/
	private MultipartFile file;

	/** 文件名稱*/
	private String fileName;

	private String info;

	/** 業務字段*/
	private Integer sampleNo;
}
//mvc接收的方法
@RequestMapping("/file")
@ResponseBody
public Map<String,Object> file(ReportImgVO reportImgVO){
	Map<String, Object> map =new HashMap<>();		
	System.out.println(reportImgVO.getFile());		
	return map;
}

二、更優的選擇

上面的方法完全可以實現我的需求,也已經做出來了,但存在的問題是c#端的代碼比較複雜,因爲文件需要通過流的方式進行上傳,後面的一位大神朋友帥翔(座標上海)的提示下,文件既然是上傳後放到oss的,那爲何不直接把文件在c#就轉換成base64的字符串呢?這樣就不需要處理流的問題了。上傳就是一個普通的對象。

優化後的方法來了:

using System.Drawing;

//省略中間部分。。。

//文件轉base64
public static String ImageFile2Base64(String imageFile)
{            
     Image image = Image.FromFile(imageFile);
     MemoryStream ms = new MemoryStream();
     image.Save(ms, image.RawFormat);
     byte[] byteArray = ms.ToArray();
     ms.Close();
     return "data:image/png;base64,"+Convert.ToBase64String(byteArray);
}

注意,轉完還不行,需要給這個字符串加上一個頭,標識這是一個圖片,在這個字符串最前面加上

"data:image/png;base64,",注意,直接拷貝我的代碼,逗號不要丟了。

剩餘的c#代碼就簡單了,把跟流相關的都去掉,就是個普通的數據上傳,再不需要考慮文件的問題。

Java端的實體類變成:

@Data
public class ReportImgVO extends BaseEntity {

	/** 文件,變成了字符串*/
	private String file;
	
	/** 文件名稱*/
	private String fileName;

	private String info;

	/** 樣本號*/
	private Integer sampleNo;
}

這樣就簡單多了,其他沒啥太多變化,c#我也不熟,只能看得懂,會改。

三、接收到base64後的下一步處理

接收到的base64字符串直接可以在頁面顯示的,如圖:

在網頁的src、url中都可以直接顯示成圖片。更進一步,我們把圖片上傳到oss對象存儲中。

官方文檔:https://help.aliyun.com/document_detail/84781.html?spm=a2c4g.11186623.6.861.4a6513edP5RSuc

核心代碼:

搞定,收工!

 

參考資料:

  1. https://blog.csdn.net/bopisky/article/details/78404005

我的微信公衆號:架構真經(關注領取免費資源)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章