当前位置: 首页 > news >正文

ASP.NET MVC在服务端把异步上传的图片裁剪成不同尺寸分别保存,并设置上传目录的尺寸限制...


我曾经试过使用JSAjaxFileUploader插件来把文件、照片以异步的方式上传,就像"MVC文件图片ajax上传轻量级解决方案,使用客户端JSAjaxFileUploader插件01-单文件上传"中说的,这种方法足够轻、足够好。但今天,要在前面的基础上再增加2个需求:

 

1、异步判断上传的图片是否超过最大限制
2、把上传的图片裁剪成大中小3张图片,分别保存,删除的时候一块被删除

 

上传图片如果超出最大尺寸限制,终止上传,并报错误信息。
7

 

前台上传图片,显示缩略图。
3

 

在项目根目录下的指定文件夹AjaxUpload中同时有了大中小3张图片。
4

 

点击图片行的删除按钮或重新上传新的图片,原先的大中小3张图片一块被删除。重新上传新图片:
5

 

在项目根目录下的指定文件夹AjaxUpload中同时有了新的大中小3张图片。
6


前端还是使用JSAjaxFileUploader插件,后端使用ImageResizer组件实现对图片的裁剪和保存。

 

当前端拿到异步请求的返回结果后,需要显示图片、记录下图片的名称、错误信息等,可以把这些信息封装到UploadFileResult类中,让服务端以json格式返回。


 
namespace MvcApplication1.Models
{
    public class UploadFileResult
    {
        public string LargeFileName { get; set; } //带后缀名的图片名称,比如:20141112_large.jpg
        public string MediumFileName { get; set; }
        public string SmallFileName { get; set; } 
        public int Length { get; set; } //图片的字节数
        public string Type { get; set; } //图片的类型:image/jpeg
        public bool IsValid { get; set; } //用来判断是否超过尺寸最大限制
        public string Message { get; set; }
        public string LargeFilePath { get; set; }  //图片的保存路径:~/AjaxUpload/20141112_large.jpg
        public string MediumFilePath { get; set; }
        public string SmallFilePath { get; set; }  
    }
}

以上,
LargeFileName用来保存裁剪大图的名称,类似"20141112_large.jpg",当前台需要删除图片的时候,还需要把这个图片名称传递给服务端,再到指定文件夹删除图片。
LargeFilePath用来保存图片的路径,类似"~/AjaxUpload/20141112_large.jpg",前台显示图片的时候需要这个。
IsValid为true表示可以裁剪保存图片,为false表示超过最大的尺寸限制,取消上传

 

通过NuGet安装ImageResizer。安装完后,在"引用"下面多了一个ImageResizer组件。
1

 

创建HomeController,主要完成以下工作:
1、接收前台上传图片,裁剪成大中小图片并分别保存
2、接收前台需要删除的图片名称,在指定文件夹中同时删除大中小图片
3、提供递归统计指定文件夹大小的方法
......


 
using System;
using System.Collections.Generic;
using System.IO;
using System.Web;
using System.Web.Mvc;
using ImageResizer;
using MvcApplication1.Models;

 
namespace MvcApplication1.Controllers
{
    public class HomeController : Controller
    {

 
        public ActionResult Index()
        {
            return View();
        }

 
        [HttpPost]
        public ActionResult UploadFile()
        {
            //需要返回给前台的结果
            List<UploadFileResult> results = new List<UploadFileResult>();

 
            //遍历从前台传递而来的文件
            foreach (string file in Request.Files)
            {
                //把每一个上传文件封装成HttpPostedFileBase
                HttpPostedFileBase hpf = Request.Files[file] as HttpPostedFileBase;

 
                //如果前台传来的文件集合中有null,继续遍历其他文件
                if (hpf.ContentLength == 0 || hpf == null)
                {
                    continue;
                }

 
                //给上传文件改名
                string date = DateTime.Now.ToString("yyyyMMddhhmmss");

 
                //目标文件夹的相对路径 ImageSize需要的格式
                string pathForSaving = Server.MapPath("~/AjaxUpload/");

 
                //目标文件夹的相对路径 统计文件夹大小需要的格式
                string pathForSaving1 = Server.MapPath("~/AjaxUpload");

 
                //保存文件并返回结果
                if (this.CreateFolderIfNeeded(pathForSaving))
                {
                    long currentSize = GetDirectoryLength(pathForSaving1);

 
                    //如果大于最大限制,直接返回json信息
                    //1M=1024*1024个字节
                    if (currentSize + hpf.ContentLength > 50 * 1024 * 1024)//最大允许50兆
                    {
                        results.Add(new UploadFileResult()
                        {
                            LargeFileName = "",
                            LargeFilePath = "",
                            MediumFileName = "",
                            MediumFilePath = "",
                            SmallFileName = "",
                            SmallFilePath = "",
                            IsValid = false,
                            Length = hpf.ContentLength,
                            Message = "超过最大限制无法上传",
                            Type = hpf.ContentType
                        });
                    }
                    else //如果小于最大限制,才保存大中小图片
                    {
                        //保存图片的各种版本:小图,中图,大图
                        var versions = new Dictionary<string, string>();
                        versions.Add("_small", "maxwidth=50&maxheight=50&format=jpg");
                        versions.Add("_medium", "maxwidth=200&maxheight=200&format=jpg");
                        versions.Add("_large", "maxwidth=600&maxheight=600&format=jpg");

 
                        //保存各个版本的缩略图
                        foreach (var key in versions.Keys)
                        {
                            hpf.InputStream.Seek(0, SeekOrigin.Begin);
                            ImageBuilder.Current.Build(new ImageJob(
                                hpf.InputStream,
                                pathForSaving + date + key, //不带后缀名的图片名称
                                new Instructions(versions[key]),
                                false,//是否保留原图
                                true));//是否增加后缀
                        }

 

 
                        results.Add(new UploadFileResult()
                        {
                            LargeFileName = date + "_large" + ".jpg",
                            LargeFilePath = Url.Content(String.Format("~/AjaxUpload/{0}", date + "_large" + ".jpg")),
                            MediumFileName = date + "_medium" + ".jpg",
                            MediumFilePath = Url.Content(String.Format("~/AjaxUpload/{0}", date + "_mediume" + ".jpg")),
                            SmallFileName = date + "_small" + ".jpg",
                            SmallFilePath = Url.Content(String.Format("~/AjaxUpload/{0}", date + "_small" + ".jpg")),
                            IsValid = true,
                            Length = hpf.ContentLength,
                            Message = "上传成功",
                            Type = hpf.ContentType
                        });
                    }
                    
                }
            }

 
            //单文件上传,实际上results中只有一个元素
            return Json(new
            {
                largename = results[0].LargeFileName,
                largepath = results[0].LargeFilePath,
                mediumname = results[0].MediumFileName,
                mediumpath = results[0].MediumFilePath,
                smallname = results[0].SmallFileName,
                smallpath = results[0].SmallFilePath,
                type = results[0].Type,
                size = string.Format("{0} bytes", results[0].Length),                
                msg = results[0].Message,
                isvalid = results[0].IsValid
            });
        }

 

 
        //根据文件名称删除文件
        [HttpPost]
        public ActionResult DeleteFileByNames(string largename, string mediumname, string smallname) 
        {
            string pathForSaving = Server.MapPath("~/AjaxUpload");
            System.IO.File.Delete(Path.Combine(pathForSaving, largename));
            System.IO.File.Delete(Path.Combine(pathForSaving, mediumname));
            System.IO.File.Delete(Path.Combine(pathForSaving, smallname));
            return Json(new
            {
                msg = true
            });
        }

 
        /// <summary>
        /// 根据目标文件夹的相对路径创建文件夹
        /// 如果目标文件夹不存在,就创建;存在就不创建
        /// 只有在创建目标文件夹发生异常的时候才返回false
        /// </summary>
        /// <param name="path">目标文件夹的相对路径</param>
        /// <returns></returns>
        private bool CreateFolderIfNeeded(string path)
        {
            bool result = true;
            if (!Directory.Exists(path))
            {
                try
                {
                    Directory.CreateDirectory(path);
                }
                catch (Exception)
                {
                    result = false;
                }
            }
            return result;
        }

 
        /// <summary>
        /// 根据目标文件夹的相对路径递归计算该文件夹的大小
        /// </summary>
        /// <param name="path">用相对路径表示的目标文件夹</param>
        /// <returns></returns>
        private static long GetDirectoryLength(string path)
        {
            //如果目标文件夹不存在就返回0
            if (!Directory.Exists(path))
            {
                return 0;
            }

 
            long size = 0;

 
            //获取目标文件夹的信息
            DirectoryInfo di = new DirectoryInfo(path);

 
            //遍历目标文件夹下的所有文件遍历累计每个文件的大小
            foreach (FileInfo fi in di.GetFiles())
            {
                size += fi.Length;
            }

 
            //获取目标文件夹下的所有子文件夹
            DirectoryInfo[] dis = di.GetDirectories();

 
            //如果确实有子文件夹
            if (dis.Length > 0)
            {
                //遍历这些子文件夹
                for (int i = 0; i < dis.Length; i++)
                {
                    //递归统计累计大小
                    size += GetDirectoryLength(dis[i].FullName);
                }
            }

 
            return size;
        }
    }
}

 
 
 

以上,
UploadFile方法中,通过Request.Files拿到所有的上传图片,然后遍历这些图片,通过Request.Files[key]获取某个图片,把该图片转换成HttpPostedFileBase类型。在裁剪保存图片之前,使用GetDirectoryLength方法获取当前文件夹的尺寸,如果没有超过尺寸的最大限制,就使用ImageResizer把图片裁剪成大中小3张图片,并分别保存。

DeleteFileByNames方法中,从前台接收大中小图片的名称,再到根目录下的指定文件夹AjaxUpload中删除大中小3张图片。

 

_Layout.cshtml中引入相关css、js文件。JQuery.JSAjaxFileUploaderSingle.js文件已经做了汉化,详细参考这里。


 
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>@ViewBag.Title</title>
    @Styles.Render("~/Content/css")
    <link href="~/Content/JSAjaxFileUploader/JQuery.JSAjaxFileUploader.css" rel="stylesheet" />
    @Scripts.Render("~/bundles/modernizr")
    @Scripts.Render("~/bundles/jquery")
    <script src="~/JSAjaxFileUploader/JQuery.JSAjaxFileUploaderSingle.js"></script>
</head>
<body>
    @RenderBody()    
    @RenderSection("scripts", required: false)
</body>

 

创建Home/Index.cshtml视图,主要工作包括:
1、处理图片上传,每次上传前需要把原先的3张图片删除,如果上传成功显示小图的缩略图,如果上传失败,给出错误提示。
2、提供一个动态创建图片行表格的方法
3、提供一个删除大中小图片的方法,向服务端发送3张图片的名称
......

 


 
@{
    ViewBag.Title = "Index";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

 
<style type="text/css">
    #tb table {
        border-collapse: collapse;
        width: 600px;
    }

 
    #tb td {
        text-align: center;
        padding-top: 5px;
        width: 25%;
    }

 
    #tb tr {
        background-color: #E3E3E3;
        line-height: 35px;
    }

 
    .limit {
        color: red;
    }
</style>

 
<div id="testId"></div>

 
<div id="tb">
    <table id="tbl">
        <tbody>
        </tbody>
    </table>
</div>

 
<div>
    <span class="limit"></span>
</div>

 
@section scripts
{
    <script type="text/javascript">
        $(function() {
            //隐藏显示图片的表格
            $('#tbl').hide();

 
            //图片上传
            $('#testId').JSAjaxFileUploader({
                uploadUrl: '@Url.Action("UploadFile","Home")',
                inputText: '选择上传文件',
                //fileName: 'photo',
                maxFileSize: 512000,    //Max 500 KB file 1kb=1024字节
                allowExt: 'gif|jpg|jpeg|png',
                zoomPreview: false,
                zoomWidth: 360,
                zoomHeight: 360,
                beforesend: function (file) {//每次点击都要删除原先的
                    if ($('.largeImgName').text() != "" && $('.mediumImgName').text() != "" && $('.smallImgName').text() != "") {
                        deleteImg();
                        $('#tbl').hide();
                    }
                },
                success: function (data) {
                    if (!data.isvalid) { //如果尺寸超过最大限制
                        $('.limit').css("display", "block");
                        $('.limit').text(data.msg);
                        return;
                    } else {
                        $('.limit').css("display", "none");
                        createTableTr();
                        $('#tbl').show();
                        $('.showImg').attr("src", data.smallpath);//显示小图片
                        $('.largeImgName').text(data.largename); //显示大图的名称
                        $('.mediumImgName').text(data.mediumname); //显示中图的名称
                        $('.smallImgName').text(data.smallname); //显示小图的名称
                    }                   
                },
                error: function (data) {
                    alert(data.msg);
                }
            });

 
            //点击删除链接删除刚上传图片
            $('#tbl').on("click", ".delImg", function () {
                deleteImg();
                //window.location.reload();
            });
        });

 
        //创建表格
        function createTableTr() {
            var table = $('#tbl');
            table.append("<tr><td><img class='showImg'/></td><td colspan='2'><span class='largeImgName'></span><br/><span class='mediumImgName'></span><br/><span class='smallImgName'></span></td><td><a class='delImg' href='javascript:void(0)'>删除</a></td></tr>");
        }

 
        //删除图片方法:点击删除链接或上传新图片删除原先图片用到
        function deleteImg() {
            $.ajax({
                cache: false,
                url: '@Url.Action("DeleteFileByNames", "Home")',
                type: "POST",
                data: { largename: $('.largeImgName').text(), mediumname: $('.mediumImgName').text(), smallname: $('.smallImgName').text() },
                success: function (data) {
                    if (data.msg) {
                        //alert("图片删除成功");
                        $('.delImg').parent().parent().remove();
                    }
                },
                error: function (jqXhr, textStatus, errorThrown) {
                    alert("出错了 '" + jqXhr.status + "' (状态: '" + textStatus + "', 错误为: '" + errorThrown + "')");
                }
            });
        }
    </script>
}

 
 
 

相关文章:

  • 有关AngularJS请求Web API资源的思路
  • C# 调用 C++ Dll 类库的传参问题
  • 转:fastText原理及实践(达观数据王江)
  • 算法问题实战策略
  • BZOJ 2584: [Wc2012]memory(扫描线+线段树)
  • 用最新NLP库Flair做文本分类
  • ASP.NET Core 2.0 : 三. 项目结构
  • 前后端分离架构中接口测试最佳实践
  • js闭包与高阶函数
  • java知识点1(this指针)
  • Confluent 修改开源许可证,限制云供应商滥用
  • vagrant设置虚拟机的名字
  • 寒假作业安排及注意点
  • 团队管理 - 团队发展五阶段
  • 线性代数---范数
  • 【跃迁之路】【669天】程序员高效学习方法论探索系列(实验阶段426-2018.12.13)...
  • 07.Android之多媒体问题
  • CEF与代理
  • JavaScript 是如何工作的:WebRTC 和对等网络的机制!
  • Javascript编码规范
  • JS基础篇--通过JS生成由字母与数字组合的随机字符串
  • Redis学习笔记 - pipline(流水线、管道)
  • Spring Cloud Alibaba迁移指南(一):一行代码从 Hystrix 迁移到 Sentinel
  • sublime配置文件
  • 阿里云购买磁盘后挂载
  • 阿里中间件开源组件:Sentinel 0.2.0正式发布
  • 浮现式设计
  • 让你成为前端,后端或全栈开发程序员的进阶指南,一门学到老的技术
  • 入门级的git使用指北
  • 运行时添加log4j2的appender
  • 再谈express与koa的对比
  • ​LeetCode解法汇总1410. HTML 实体解析器
  • ​软考-高级-信息系统项目管理师教程 第四版【第19章-配置与变更管理-思维导图】​
  • #### go map 底层结构 ####
  • #我与Java虚拟机的故事#连载12:一本书带我深入Java领域
  • #预处理和函数的对比以及条件编译
  • (10)工业界推荐系统-小红书推荐场景及内部实践【排序模型的特征】
  • (C++)八皇后问题
  • (附源码)spring boot网络空间安全实验教学示范中心网站 毕业设计 111454
  • (附源码)ssm基于jsp的在线点餐系统 毕业设计 111016
  • (简单有案例)前端实现主题切换、动态换肤的两种简单方式
  • (介绍与使用)物联网NodeMCUESP8266(ESP-12F)连接新版onenet mqtt协议实现上传数据(温湿度)和下发指令(控制LED灯)
  • (六)Hibernate的二级缓存
  • (免费分享)基于springboot,vue疗养中心管理系统
  • (四)鸿鹄云架构一服务注册中心
  • (一) storm的集群安装与配置
  • (转)使用VMware vSphere标准交换机设置网络连接
  • ./indexer: error while loading shared libraries: libmysqlclient.so.18: cannot open shared object fil
  • .net framework 4.0中如何 输出 form 的name属性。
  • .NET LINQ 通常分 Syntax Query 和Syntax Method
  • .NET MVC第五章、模型绑定获取表单数据
  • .net 桌面开发 运行一阵子就自动关闭_聊城旋转门家用价格大约是多少,全自动旋转门,期待合作...
  • .NET性能优化(文摘)
  • .NET学习全景图
  • :=