本篇,在ASP.NET MVC4下实现单个图片上传,具体功能包括:
- 1、在客户端选择图片,并限制图片的大小和格式
- 2、在客户端上传图片,并显示预览图
- 3、在服务端限制图片的大小和格式
- 4、在服务端保存图片时,把图片裁剪成某个固定尺寸
本篇源码在:https://github.com/darrenji/FileUploadInMVC
实现的大致思路是:
- 客户端限制图片大小和格式,通过写一个jQuery插件来实现
- 服务端实现图片裁剪,通过使用ImageSize组件来实现
首先是一个用来承载上传信息的类:
public class UploadFileResult | |
{ | |
//带后缀的名称,比如xxx.jpg | |
public string FileName { get; set; } | |
//图片的字节数 | |
public int Length { get; set; } | |
//图片的类型:image/jpeg | |
public string Type { get; set; } | |
public bool IsValid { get; set; } | |
public string Message { get; set; } | |
//图片的完整路径:~/AjaxUpload/20141112_large.jpg | |
public string FilePath { get; set; } | |
} |
在HomeController中,需要提供一个接收前端上传文件并返回json格式的Action方法,还需要提供一个根据文件名删除图片的Action方法。
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Linq; | |
using System.Web; | |
using System.Web.Mvc; | |
using ImageResizer; | |
using MvcApplication10.Models; | |
namespace MvcApplication10.Controllers | |
{ | |
public class HomeController : Controller | |
{ | |
public ActionResult Index() | |
{ | |
return View(); | |
} | |
//接收上传图片 | |
[ | ]|
public ActionResult UploadFile() | |
{ | |
//允许的图片格式 | |
var allowedExtensions = new[] { ".png", ".gif", ".jpg", ".jpeg" }; | |
//返回给前台的结果,最终以json返回 | |
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; | |
} | |
else | |
{ | |
if (hpf.ContentLength > 1024*1024) //如果大于规定最大尺寸 | |
{ | |
results.Add(new UploadFileResult() | |
{ | |
FileName = "", | |
FilePath = "", | |
IsValid = false, | |
Length = hpf.ContentLength, | |
Message = "图片尺寸不能超过1024KB", | |
Type = hpf.ContentType | |
}); | |
} | |
else | |
{ | |
var extension = Path.GetExtension(hpf.FileName); | |
if (!allowedExtensions.Contains(extension))//如果文件的后缀名不包含在规定的后缀数组中 | |
{ | |
results.Add(new UploadFileResult() | |
{ | |
FileName = "", | |
FilePath = "", | |
IsValid = false, | |
Length = hpf.ContentLength, | |
Message = "图片格式必须是png、gif、jpg或jpeg", | |
Type = hpf.ContentType | |
}); | |
} | |
else | |
{ | |
//给上传文件改名 | |
string date = DateTime.Now.ToString("yyyyMMddhhmmss"); | |
//目标文件夹的相对路径 ImageSize需要的格式 | |
string pathForSaving = Server.MapPath("~/AjaxUpload/"); | |
//目标文件夹的相对路径 统计文件夹大小需要的格式 | |
string pathForSaving1 = Server.MapPath("~/AjaxUpload"); | |
//在根目录下创建目标文件夹AjaxUpload | |
if (this.CreateFolderIfNeeded(pathForSaving)) | |
{ | |
//保存小图 | |
var versions = new Dictionary<string, string>(); | |
versions.Add("_small", "maxwidth=400&maxheight=250&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() | |
{ | |
FileName = date + "_small" + ".jpg", | |
FilePath = Url.Content(String.Format("~/AjaxUpload/{0}", date + "_small" + ".jpg")), | |
IsValid = true, | |
Length = hpf.ContentLength, | |
Message = "上传成功", | |
Type = hpf.ContentType | |
}); | |
} | |
} | |
} | |
} | |
} | |
return Json(new | |
{ | |
filename = results[0].FileName, | |
filepath=results[0].FilePath, | |
isvalid=results[0].IsValid, | |
length=results[0].Length, | |
message=results[0].Message, | |
type=results[0].Type | |
}); | |
} | |
//根据文件名删除文件 | |
[ | ]|
public ActionResult DeleteFileByName(string smallname) | |
{ | |
string pathForSaving = Server.MapPath("~/AjaxUpload"); | |
System.IO.File.Delete(Path.Combine(pathForSaving, smallname)); | |
return Json(new | |
{ | |
msg = true | |
}); | |
} | |
//根据相对路径在项目根路径下创建文件夹 | |
private bool CreateFolderIfNeeded(string path) | |
{ | |
bool result = true; | |
if (!Directory.Exists(path)) | |
{ | |
try | |
{ | |
Directory.CreateDirectory(path); | |
} | |
catch (Exception) | |
{ | |
result = false; | |
} | |
} | |
return result; | |
} | |
} | |
} |
在Home/Index.cshtml中,使用checkFileTypeAndSize.js插件来限制上传图片的大小和格式,使用FormData对象来接收图片文件并传递给服务端,客户端接收到服务端json数据动态创建表格行把预览图显示出来。
@{ | |
ViewBag.Title = "Index"; | |
Layout = "~/Views/Shared/_Layout.cshtml"; | |
} | |
<style type="text/css"> | |
#msg { | |
color: red; | |
} | |
</style> | |
<form id="file_upload_form" method="post" enctype="multipart/form-data" action=""> | |
<input name="file" id="file" size="27" type="file" /> | |
<img src="~/images/ajax-loader.gif" id="indicator" style="display: none;" /> | |
<br /> | |
<div id="imgArea"> | |
<table id="tbl"> | |
<tbody> | |
</tbody> | |
</table> | |
</div> | |
<div> | |
<span id="msg"></span> | |
</div> | |
</form> | |
@section scripts | |
{ | |
<script src="~/Scripts/checkFileTypeAndSize.js"></script> | |
<script type="text/javascript"> | |
$(function() { | |
$("#file").checkFileTypeAndSize({ | |
allowedExtensions: ['jpg','jpeg','gif','png'], | |
maxSize: 1024, //最大允许1024KB,即1MB | |
success: function () { | |
//显示进度提示 | |
$('#indicator').css("display", "block"); | |
//清空提示内容 | |
$('#msg').text(''); | |
if ($('#fn').text().length > 0) { | |
//删除图片 | |
deleteImg(); | |
} | |
//上传文件数据准备 | |
var fd = new FormData(); | |
fd.append('image', $('#file')[0].files[0]); | |
$.ajax({ | |
url: '@Url.Action("UploadFile","Home")', | |
type: "POST", | |
data: fd, | |
contentType: false, | |
cache: false, | |
processData: false, | |
dataType: 'json', | |
success: function (data) { | |
//隐藏进度提示 | |
$('#indicator').css("display", "none"); | |
if (data.isvalid) { | |
//$('#fileTemplate').tmpl(data).appendTo('#imgArea'); | |
createTableTr(); | |
$('#thumb').attr('src', data.filepath); | |
$('#fn').text(data.filename); | |
} else { | |
$('#msg').text(data.message); | |
} | |
} | |
}); | |
}, | |
extensionerror: function () { | |
//alert('允许的格式为:jpg,jpeg,gif,png'); | |
$('#msg').text('允许的格式为:jpg,jpeg,gif,png'); | |
return; | |
}, | |
sizeerror: function () { | |
//alert('最大尺寸1024KB,即1MB'); | |
$('#msg').text('最大尺寸1024KB,即1MB'); | |
return; | |
} | |
}); | |
}); | |
//删除图片 | |
function deleteImg() { | |
$.ajax({ | |
cache: false, | |
url: '@Url.Action("DeleteFileByName", "Home")', | |
type: "POST", | |
data: { smallname: $('#fn').text() }, | |
success: function (data) { | |
if (data.msg) { | |
$('#fn').parent().parent().remove(); | |
} | |
}, | |
error: function (jqXhr, textStatus, errorThrown) { | |
alert("出错了 '" + jqXhr.status + "' (状态: '" + textStatus + "', 错误为: '" + errorThrown + "')"); | |
} | |
}); | |
} | |
//创建表格 | |
function createTableTr() { | |
var table = $('#tbl'); | |
table.append("<tr><td><img id='thumb' /></td><td colspan='2'><span id='fn'></span></td></tr>"); | |
} | |
</script> | |
} |