zoukankan      html  css  js  c++  java
  • MVC 文件上传

    项目需要,做一个图片上传的功能,本来是很简单,但是需要同时上传多个文件,并分条带一些额外的信息,听上去很复杂,通过下面图就可以一目了然:

    网上找过一些方法,但多为不支持图片与其他信息关联,或者分两次上传(文件一次,返回一个indicator,然后通过json传其他信息),不理想。偶然发现一个MVC的方法,思路非常简单,就是MVC,独特之处是把图片作为一个HttpPostedFileBase类型的属性存到ViewModel里。直接看代码:

    <form action="" method="post" enctype="multipart/form-data">
            @for (int i = 0; i < Model.Count; i++)
                {
                <div class="col-xs-11 row space-top">
                    <div class="col-xs-2">
                        @Html.EditorFor(m => m[i].Title)
                    </div>
                    <div class="col-xs-2">
                        @Html.EditorFor(m => m[i].AltText)
                    </div>
                    <div class="col-xs-2">
                        @Html.EditorFor(m => m[i].Caption)
                    </div>
                    <div class="col-xs-3">
                        @Html.TextBoxFor(m => m[i].ImageUpload, new { type = "file" })
                    </div>
                </div>
            }
            <div class="container space-top" >
                <button class="btn col-xs-2 space-top" type="submit">Create</button>
            </div>
        </form>
    View
    // GET: Image
            public ActionResult Create()
            {
                var models = new List<ImageViewModel>();
                models.Add(new ImageViewModel());
                models.Add(new ImageViewModel());
                return View(models);
            }
    Controller
    public class ImageViewModel
        {
            [Required]
            public string Title { get; set; }
    
            public string AltText { get; set; }
    
            [DataType(DataType.Html)]
            public string Caption { get; set; }
    
            [DataType(DataType.Upload)]
            public HttpPostedFileBase ImageUpload { get; set; }
        }
    ViewModel
    [HttpPost]
            public ActionResult Create(List<ImageViewModel> models)
            {
                var model = models[0];
                var validImageTypes = new string[] { "image/gif", "image/jpeg", "image/pjpeg", "image/png" };
    
                if (model.ImageUpload == null || model.ImageUpload.ContentLength == 0)
                {
                    ModelState.AddModelError("ImageUpload", "This field is required");
                }
                else if (!validImageTypes.Contains(model.ImageUpload.ContentType))
                {
                    ModelState.AddModelError("ImageUpload", "Please choose either a GIF, JPG or PNG image.");
                }
                if (ModelState.IsValid)
                {
                    var image = new Image
                    {
                        Title = model.Title,
                        AltText = model.AltText,
                        Caption = model.Caption
                    };
    
                    if (model.ImageUpload != null && model.ImageUpload.ContentLength > 0)
                    {
                        //var uploadDir = "~/uploads";
                        //var imagePath = Path.Combine(Server.MapPath(uploadDir), model.ImageUpload.FileName);
                        //var imageUrl = Path.Combine(uploadDir, model.ImageUpload.FileName);
                        //model.ImageUpload.SaveAs(imagePath);
                        //image.ImageUrl = imageUrl;
                    }
                    //db.Create(image);
                    //db.SaveChanges();
                   // return RedirectToAction("Index");
                }
    
                return View(models);
            }
    Post Action

    原文链接

    发现原来还可以这样,但是由于我使用的knockout,所以提交数据需要用JS完成,需要将其转换,但当我构建完对象,将其转换为JSON的时候,发现文件不是随便就能序列化的。观察上面例子提交的请求:

    跟普通的Form相比,并无特殊之处,说明只要content-type为mutipart/form-data,Form的name按照序号加名称的格式填写,Action就能获得到指定的数据,我将代码改为这种形式:

    <form action="Create" encType="multipart/form-data" method="post">
    
        <div>
            <label for="">Title</label>
            <input name="[0].Title" type="text" value="a">
        </div>
        <div>
            <label for="">AltText</label>
            <input name="[0].AltText" type="text" value="a">
        </div>
        <div>
            <label for="">Caption</label>
            <input name="[0].Caption" type="text" value="a">
        </div>
        <div>
            <label for="">ImageUpload</label>
            <input name="[0].ImageUpload" type="file">
        </div>
        <div>
            <label for="">Title</label>
            <input name="[1].Title" type="text" value="b">
        </div>
        <div>
            <label for="">AltText</label>
            <input ame="[1].AltText" type="text" value="b">
        </div>
        <div>
            <label for="">Caption</label>
            <input name="[1].Caption" type="text" value="b">
        </div>
        <div>
            <label for="">ImageUpload</label>
            <input name="[1].ImageUpload" type="file">
        </div>
    
        <button type="submit">Create</button>
    </form>
    HTML

    依然work,说明推论合理。然后做进一步修改:

    function mySubmit() {
        var formData = new FormData();
        formData.append("[0].Title", $("[name='[0].Title'").val());
        formData.append("[0].AltText", $("[name='[0].AltText'").val());
        formData.append("[0].Caption", $("[name='[0].Caption'").val());
        formData.append("[0].ImageUpload", $("[name='[0].ImageUpload'").get(0).files[0]);
    
        formData.append("[1].Title", $("[name='[1].Title'").val());
        formData.append("[1].AltText", $("[name='[1].AltText'").val());
        formData.append("[1].Caption", $("[name='[1].Caption'").val());
        formData.append("[1].ImageUpload", $("[name='[1].ImageUpload'").get(0).files[0]);
        console.log(formData);
    
        $.ajax({
            contentType: false,
            url: "/Image/Create",
            type: "POST",
            processData: false,
            dataType: 'json',
            data: formData,
            success: function (result) {
    
            },
            error: function (err) {
                alert(err.statusText);
            }
        });
    }
    JS

    注意把contentType和processData都设为false,防止AJAX自己修改数据格式。

    到这里本来问题就解决了,但是,但是,IE9及以下不支持FormData,于是做了进一步修改,以来表单的提交功能,JS里构建需要的<input type="hidden" />,设置好name属性,然后提交表单$("#Form").submit(),思路就是这样,代码就不写了。

    其实,这里的原理我还是不大清楚,为什么action能将这样的一个name list还原为对象,我猜跟negotiation有关系,还需要进一步研究。

  • 相关阅读:
    【Codeforces】【161Div2】
    【ZOJ月赛】【树形DP】【I.Destroy】
    【Baltic 2001远程通信】
    【树形DP】【分组背包】【HDU1561】
    【差分约束系统】【仍未AC】【Asia Harbin 2010/2011】【THE MATRIX PROBLEM】
    【DP】【2012 ACM/ICPC 成都赛区现场赛】【I.Count】
    【ZOJ月赛】【二分查找】【A.Edward's Cola Plan】
    【DP】【单调队列多重背包】
    【树形依赖背包】
    SQL 格式
  • 原文地址:https://www.cnblogs.com/goldren/p/5795531.html
Copyright © 2011-2022 走看看