一、添加文章
1、KindEditor富文本编辑器
到官方网站http://kindeditor.net/down.php下载最新版本,解压后把代码复制到项目的Scripts文件夹下。
2、添加界面的显示。
在ArticleController中添加Add 方法
1
2
3
4
5
6
7
8
|
/// < summary > /// 添加文章 /// </ summary > /// < returns >视图页面</ returns > public ActionResult Add() { return View(); } |
右键添加Article的强类型视图,代码如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
|
@section scripts{ < script type = "text/javascript" src = "~/Scripts/KindEditor/kindeditor-min.js" ></ script > < script type = "text/javascript" > //编辑框 KindEditor.ready(function (K) { window.editor = K.create('#Content', { height: '500px' }); }); </ script > } @model Ninesky.Models.Article @using (Html.BeginForm()) { @Html.AntiForgeryToken() < div class = "form-horizontal" role = "form" > < h4 >添加文章</ h4 > < hr /> @Html.ValidationSummary(true) < div class = "form-group" > < label class = "control-label col-sm-2" for = "CommonModel_CategoryID" >栏目</ label > < div class = "col-sm-10" > < input id = "CommonModel_CategoryID" name = "CommonModel.CategoryID" data-options = "url:'@Url.Action(" JsonTree", "Category", new { model = "Article" })'" class = "easyui-combotree" style = "height: 34px; width: 280px;" /> @Html.ValidationMessageFor(model => model.CommonModel.CategoryID)</ div > </ div > < div class = "form-group" > @Html.LabelFor(model => model.CommonModel.Title, new { @class = "control-label col-sm-2" }) < div class = "col-sm-10" > @Html.TextBoxFor(model => model.CommonModel.Title, new { @class = "form-control" }) @Html.ValidationMessageFor(model => model.CommonModel.Title) </ div > </ div > < div class = "form-group" > @Html.LabelFor(model => model.Author, new { @class = "control-label col-sm-2" }) < div class = "col-sm-10" > @Html.TextBoxFor(model => model.Author, new { @class = "form-control" }) @Html.ValidationMessageFor(model => model.Author) </ div > </ div > < div class = "form-group" > @Html.LabelFor(model => model.Source, new { @class = "control-label col-sm-2" }) < div class = "col-sm-10" > @Html.TextBoxFor(model => model.Source, new { @class = "form-control" }) @Html.ValidationMessageFor(model => model.Source) </ div > </ div > < div class = "form-group" > @Html.LabelFor(model => model.Intro, new { @class = "control-label col-sm-2" }) < div class = "col-sm-10" > @Html.TextAreaFor(model => model.Intro, new { @class = "form-control" }) @Html.ValidationMessageFor(model => model.Intro) </ div > </ div > < div class = "form-group" > @Html.LabelFor(model => model.Content, new { @class = "control-label col-sm-2" }) < div class = "col-sm-10" > @Html.EditorFor(model => model.Content) @Html.ValidationMessageFor(model => model.Content) </ div > </ div > < div class = "form-group" > @Html.LabelFor(model => model.CommonModel.DefaultPicUrl, new { @class = "control-label col-sm-2" }) < div class = "col-sm-10" > < img id = "imgpreview" class = "thumbnail" src = "" /> @Html.HiddenFor(model => model.CommonModel.DefaultPicUrl) < a id = "btn_picselect" class = "easyui-linkbutton" >选择…</ a > @Html.ValidationMessageFor(model => model.CommonModel.DefaultPicUrl) </ div > </ div > < div class = "form-group" > < div class = "col-sm-offset-2 col-sm-10" > < input type = "submit" value = "添加" class = "btn btn-default" /> </ div > </ div > </ div > } |
效果如图
3、后台接受的处理。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
[ValidateInput(false)] [HttpPost] [ValidateAntiForgeryToken] public ActionResult Add(Article article) { if(ModelState.IsValid) { //设置固定值 article.CommonModel.Hits = 0; article.CommonModel.Inputer = User.Identity.Name; article.CommonModel.Model = "Article"; article.CommonModel.ReleaseDate = System.DateTime.Now; article.CommonModel.Status = 99; article = articleService.Add(article); if (article.ArticleID > 0) { return View("AddSucess", article); } } return View(article); } |
在做架构的时候DAL、BLL的base类里有Add方法,我们可以直接使用ArticleService.Add方法添加到数据库
添加文章功能就实现了,但是不能上传附件,不能选择首页图片,不能删除多余的附件。下面就来实现附件功能。
二、附件上传
目标可以上传附件(图片,文件等),文件保存到上传目录中,且数据库中保存相应记录,可以浏览文件列表,未使用的附件可以删除记录。
一、添加附件
在AttachmentController添加Upload()方法,方法方法把文件写入磁盘中把附件的记录也保存到数据库中,中间会用到读取配置文件,见《.Net MVC 网站中配置文件的读写》。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
/// < summary > /// 上传附件 /// </ summary > /// < returns ></ returns > public ActionResult Upload() { var _uploadConfig = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~").GetSection("UploadConfig") as Ninesky.Models.Config.UploadConfig; //文件最大限制 int _maxSize = _uploadConfig.MaxSize; //保存路径 string _savePath; //文件路径 string _fileParth = "~/" + _uploadConfig.Path + "/"; //文件名 string _fileName; //扩展名 string _fileExt; //文件类型 string _dirName; //允许上传的类型 Hashtable extTable = new Hashtable(); extTable.Add("image", _uploadConfig.ImageExt); extTable.Add("flash", _uploadConfig.FileExt); extTable.Add("media", _uploadConfig.MediaExt); extTable.Add("file", _uploadConfig.FileExt); //上传的文件 HttpPostedFileBase _postFile = Request.Files["imgFile"]; if (_postFile == null) return Json(new { error = '1', message = "请选择文件" }); _fileName = _postFile.FileName; _fileExt = Path.GetExtension(_fileName).ToLower(); //文件类型 _dirName = Request.QueryString["dir"]; if (string.IsNullOrEmpty(_dirName)) { _dirName = "image"; } if (!extTable.ContainsKey(_dirName)) return Json(new { error = 1, message = "目录类型不存在" }); //文件大小 if (_postFile.InputStream == null || _postFile.InputStream.Length > _maxSize) return Json(new { error = 1, message = "文件大小超过限制" }); //检查扩展名 if (string.IsNullOrEmpty(_fileExt) || Array.IndexOf(((string)extTable[_dirName]).Split(','), _fileExt.Substring(1).ToLower()) == -1) return Json(new { error = 1, message = "不允许上传此类型的文件。 \n只允许" + ((String)extTable[_dirName]) + "格式。" }); _fileParth += _dirName + "/" + DateTime.Now.ToString("yyyy-MM") + "/"; _savePath = Server.MapPath(_fileParth); //检查上传目录 if (!Directory.Exists(_savePath)) Directory.CreateDirectory(_savePath); string _newFileName = DateTime.Now.ToString("yyyyMMdd_hhmmss") + _fileExt; _savePath += _newFileName; _fileParth += _newFileName; //保存文件 _postFile.SaveAs(_savePath); //保存数据库记录 attachmentService.Add(new Attachment() { Extension = _fileExt.Substring(1), FileParth = _fileParth, Owner = User.Identity.Name, UploadDate = DateTime.Now, Type = _dirName }); return Json(new { error = 0, url = Url.Content(_fileParth) }); } |
二、查询附件列表
打开InterfaceAttachmentService接口,添加两个方法,都进行了注释比较容易理解,直接上代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
/// < summary > /// 查找附件列表 /// </ summary > /// < param name = "modelID" >公共模型ID</ param > /// < param name = "owner" >所有者</ param > /// < param name = "type" >类型</ param > /// < returns ></ returns > IQueryable< Models.Attachment > FindList(Nullable< int > modelID, string owner, string type); /// < summary > /// 查找附件列表 /// </ summary > /// < param name = "modelID" >公共模型ID</ param > /// < param name = "owner" >所有者</ param > /// < param name = "type" >所有者</ param > /// < param name = "withModelIDNull" >包含ModelID为Null的</ param > /// < returns ></ returns > IQueryable< Models.Attachment > FindList(int modelID, string owner, string type,bool withModelIDNull); |
AttachmentService中写现实代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
public IQueryable< Models.Attachment > FindList(Nullable< int > modelID, string owner, string type) { var _attachemts = CurrentRepository.Entities.Where(a => a.ModelID == modelID); if (!string.IsNullOrEmpty(owner)) _attachemts = _attachemts.Where(a => a.Owner == owner); if (!string.IsNullOrEmpty(type)) _attachemts = _attachemts.Where(a => a.Type == type); return _attachemts; } public IQueryable< Models.Attachment > FindList(int modelID, string owner, string type, bool withModelIDNull) { var _attachemts = CurrentRepository.Entities; if (withModelIDNull) _attachemts = _attachemts.Where(a => a.ModelID == modelID || a.ModelID == null); else _attachemts = _attachemts.Where(a => a.ModelID == modelID); if (!string.IsNullOrEmpty(owner)) _attachemts = _attachemts.Where(a => a.Owner == owner); if (!string.IsNullOrEmpty(type)) _attachemts = _attachemts.Where(a => a.Type == type); return _attachemts; } |
由于KindEditor文件管理需要从服务器获取json格式文件列表,在Ninesky.Web.Areas.Member.Models中单独给列表格式写个视图模型。AttachmentManagerViewModel
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
namespace Ninesky.Web.Areas.Member.Models { /// < summary > /// KindEditor文件管理中文件视图模型 /// < remarks > /// 创建:2014.03.09 /// </ remarks > /// </ summary > public class AttachmentManagerViewModel { public bool is_dir{get;set;} public bool has_file {get;set;} public int filesize {get;set;} public bool is_photo{get;set;} public string filetype{get;set;} public string filename{get;set;} public string datetime { get; set; } } } |
在AttachmentController添加返回文件列表的方法FileManagerJson。方法供KindEditor的文件管理器调用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
/// < summary > /// 附件管理列表 /// </ summary > /// < param name = "id" >公共模型ID</ param > /// < param name = "dir" >目录(类型)</ param > /// < returns ></ returns > public ActionResult FileManagerJson(int? id ,string dir) { Models.AttachmentManagerViewModel _attachmentViewModel; IQueryable< Attachment > _attachments; //id为null,表示是公共模型id为null,此时查询数据库中没有跟模型对应起来的附件列表(以上传,但上传的文章……还未保存) if (id == null) _attachments = attachmentService.FindList(null, User.Identity.Name, dir); //id不为null,返回指定模型id和id为null(新上传的)附件了列表 else _attachments = attachmentService.FindList((int)id, User.Identity.Name, dir, true); //循环构造AttachmentManagerViewModel var _attachmentList = new List< Models.AttachmentManagerViewModel >(_attachments.Count()); foreach(var _attachment in _attachments) { _attachmentViewModel = new Models.AttachmentManagerViewModel() { datetime = _attachment.UploadDate.ToString("yyyy-MM-dd HH:mm:ss"), filetype = _attachment.Extension, has_file = false, is_dir = false, is_photo = _attachment.Type.ToLower() == "image" ? true : false, filename = Url.Content(_attachment.FileParth) }; FileInfo _fileInfo = new FileInfo(Server.MapPath(_attachment.FileParth)); _attachmentViewModel.filesize = (int)_fileInfo.Length; _attachmentList.Add(_attachmentViewModel); } return Json(new { moveup_dir_path = "", current_dir_path = "", current_url = "", total_count = _attachmentList.Count, file_list = _attachmentList },JsonRequestBehavior.AllowGet); } |
3、为图片创建缩略图
把创建缩略图的方法写着Common项目中
在Ninesky.Common的Picture类中添加方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
|
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Drawing; using System.Drawing.Drawing2D; using System.Security.Cryptography; namespace Ninesky.Common { /// < summary > /// 图片相关 /// < remarks > /// 创建:2014.02.11 /// </ remarks > /// </ summary > public class Picture { /// < summary > /// 创建缩略图 /// </ summary > /// < param name = "originalPicture" >原图地址</ param > /// < param name = "thumbnail" >缩略图地址</ param > /// < param name = "width" >宽</ param > /// < param name = "height" >高</ param > /// < returns >是否成功</ returns > public static bool CreateThumbnail(string originalPicture, string thumbnail, int width, int height) { //原图 Image _original = Image.FromFile(originalPicture); // 原图使用区域 RectangleF _originalArea = new RectangleF(); //宽高比 float _ratio = (float)width/height; if(_ratio > ((float)_original.Width/_original.Height)) { _originalArea.X =0; _originalArea.Width = _original.Width; _originalArea.Height = _originalArea.Width / _ratio; _originalArea.Y = (_original.Height - _originalArea.Height) / 2; } else { _originalArea.Y = 0; _originalArea.Height = _original.Height; _originalArea.Width = _originalArea.Height * _ratio; _originalArea.X = (_original.Width - _originalArea.Width) / 2; } Bitmap _bitmap = new Bitmap(width, height); Graphics _graphics = Graphics.FromImage(_bitmap); //设置图片质量 _graphics.InterpolationMode = InterpolationMode.High; _graphics.SmoothingMode = SmoothingMode.HighQuality; //绘制图片 _graphics.Clear(Color.Transparent); _graphics.DrawImage(_original, new RectangleF(0, 0, _bitmap.Width, _bitmap.Height), _originalArea, GraphicsUnit.Pixel); //保存 _bitmap.Save(thumbnail); _graphics.Dispose(); _original.Dispose(); _bitmap.Dispose(); return true; } } } |
在AttachmentController添加生成缩略图的action
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
/// < summary > /// 创建缩略图 /// </ summary > /// < param name = "originalPicture" >原图地址</ param > /// < returns >缩略图地址。生成失败返回null</ returns > public ActionResult CreateThumbnail(string originalPicture) { //原图为缩略图直接返回其地址 if (originalPicture.IndexOf("_s") > 0) return Json(originalPicture); //缩略图地址 string _thumbnail = originalPicture.Insert(originalPicture.LastIndexOf('.'), "_s"); //创建缩略图 if (Common.Picture.CreateThumbnail(Server.MapPath(originalPicture), Server.MapPath(_thumbnail), 160, 120)) { //记录保存在数据库中 attachmentService.Add(new Attachment(){ Extension= _thumbnail.Substring(_thumbnail.LastIndexOf('.')+1), FileParth="~"+_thumbnail, Owner= User.Identity.Name, Type="image", UploadDate= DateTime.Now}); return Json(_thumbnail); } return Json(null); } |
三、整合
添加和上传附件都做好了,现在把他们整合到一起,我们就可以上传附件了。
打开Add视图,在创建KindEditor位置添加脚本
现在打开浏览器就可以上传和管理附件了
添加文章的最后一个字段是文章的默认首页图片,我希望点击选择按钮,可以在已上传中选择图片,并创建缩略图。
那么在Add视图里再弹出一个文件空间让用户选择已上传的文件,用户选择后讲选择的地址发送到服务器创建缩略图,并返回缩略图地址,然后将地址复制给隐藏表单,CommonModel_DefaultPicUrl,同事复制个<img />的src属性用来显示图片。Js代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
//首页图片 var editor2 = K.editor({ fileManagerJson: '@Url.Action("FileManagerJson", "Attachment")' }); K('#btn_picselect').click(function () { editor2.loadPlugin('filemanager', function () { editor2.plugin.filemanagerDialog({ viewType: 'VIEW', dirName: 'image', clickFn: function (url, title) { var url; $.ajax({ type: "post", url: "@Url.Action("CreateThumbnail", "Attachment")", data: { originalPicture: url }, async: false, success: function (data) { if (data == null) alert("生成缩略图失败!"); else { K('#CommonModel_DefaultPicUrl').val(data); K('#imgpreview').attr("src", data); } editor2.hideDialog(); } }); } }); }); }); |
看下效果
在保存文章的action中删除未使用的附件
完整的Add方法代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
[ValidateInput(false)] [HttpPost] [ValidateAntiForgeryToken] public ActionResult Add(Article article) { if(ModelState.IsValid) { //设置固定值 article.CommonModel.Hits = 0; article.CommonModel.Inputer = User.Identity.Name; article.CommonModel.Model = "Article"; article.CommonModel.ReleaseDate = System.DateTime.Now; article.CommonModel.Status = 99; article = articleService.Add(article); if (article.ArticleID > 0) { //附件处理 InterfaceAttachmentService _attachmentService = new AttachmentService(); //查询相关附件 var _attachments = _attachmentService.FindList(null, User.Identity.Name, string.Empty).ToList(); //遍历附件 foreach(var _att in _attachments) { var _filePath = Url.Content(_att.FileParth); //文章首页图片或内容中使用了该附件则更改ModelID为文章保存后的ModelID if ((article.CommonModel.DefaultPicUrl != null && article.CommonModel.DefaultPicUrl.IndexOf(_filePath) >= 0) || article.Content.IndexOf(_filePath) > 0) { _att.ModelID = article.ModelID; _attachmentService.Update(_att); } //未使用改附件则删除附件和数据库中的记录 else { System.IO.File.Delete(Server.MapPath(_att.FileParth)); _attachmentService.Delete(_att); } } return View("AddSucess", article); } } return View(article); } |
单纯添加文章比较简单,复杂点在上传附件,浏览新添加的附件,删除文章中未使用的附件及生成缩略图上。KindEditor还支持批量上传附件,由于批量上传使用的swfupload,在提交时flash没传输cookie到服务器,无法验证用户导致上传失败,暂时无法使用批量上传,希望这篇文章可以对大家的学习有所帮助,大家可以结合小编之前发的文章进行学习,相信一定会有所收获。