
效果图2

效果图3

三、开讲内容
大的方向为以下三个内容:
summernote的页面布局(资源引入、初始参数)
summernote从本地上传图片方法(前端onImageUpload方法、后端springMVC文件保存)
summernote所在form表单的数据提交
①、summernote的页面布局
<!DOCTYPE html><html lang="zh-CN"><%@ include file="/components/common/taglib.jsp"%><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /><title>summernote - bs3fa4</title><!-- include jquery --><script type="text/javascript" src="${ctx}/components/jquery/jquery.js"></script><!-- include libs stylesheets --><link type="text/css" rel="stylesheet" href="${ctx}/components/bootstrap/css/bootstrap.css" /><script type="text/javascript" src="${ctx}/components/bootstrap/js/bootstrap.min.js"></script><!-- include summernote --><link type="text/css" rel="stylesheet" href="${ctx}/components/summernote/summernote.css" /><script type="text/javascript" src="${ctx}/components/summernote/summernote.js"></script><script type="text/javascript" src="${ctx}/components/summernote/lang/summernote-zh-CN.js"></script><script type="text/javascript">$("div.summernote").each(function() {var $this = $(this);var placeholder = $this.attr("placeholder") || "";var url = $this.attr("action") || "";$this.summernote({lang : "zh-CN",placeholder : placeholder,minHeight : 300,dialogsFade : true,// Add fade effect on dialogsdialogsInBody : true,// Dialogs can be placed in body, not in// summernote.disableDragAndDrop : false,// default false You can disable drag// and dropcallbacks : {onImageUpload : function(files) {var $files = $(files);$files.each(function() {var file = this;var data = new FormData();data.append("file", file);$.ajax({data : data,type : "POST",url : url,cache : false,contentType : false,processData : false,success : function(response) {var json = YUNM.jsonEval(response);YUNM.debug(json);YUNM.ajaxDone(json);if (json[YUNM.keys.statusCode] == YUNM.statusCode.ok) {// 文件不为空if (json[YUNM.keys.result]) {var imageUrl = json[YUNM.keys.result].completeSavePath;$this.summernote("insertImage", imageUrl, function($image) {});}}},error : YUNM.ajaxError});});}}});});</script></head><body><div class="container"><form class="form-horizontal required-validate" action="#" enctype="multipart/form-data" method="post" onsubmit="return iframeCallback(this, pageAjaxDone)"><div class="form-group"><label for="" class="col-md-2 control-label">项目封面</label><div class="col-md-8 tl th"><input type="file" name="image" class="projectfile" value="${deal.image}"/><p class="help-block">支持jpg、jpeg、png、gif格式,大小不超过2.0M</p></div></div><div class="form-group"><label for="" class="col-md-2 control-label">项目详情</label><div class="col-md-8"><div class="summernote" name="description" placeholder="请对项目进行详细的描述,使更多的人了解你的" action="${ctx}/file">${deal.description}</div></div></div></form></div></body></html><!DOCTYPE html>html5的标记是必须的,注意千万不能是<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">这种doctype,否则summernote的组件显示怪怪的,按钮的大小布局不一致,这里就不再上图了,但是千万注意!<div class="summernote" name="description" placeholder="请对项目进行详细的描述,使更多的人了解你的" action="${ctx}/file">${deal.description}</div>相信你也看到了我为div加上的三个属性name、placeholder、action,那么我们来详细介绍一下三个属性的作用:$("div.summernote").each(function() {var $this = $(this);var placeholder = $this.attr("placeholder") || "";var url = $this.attr("action") || "";$this.summernote({lang : "zh-CN",placeholder : placeholder,minHeight : 300,dialogsFade : true,// Add fade effect on dialogsdialogsInBody : true,// Dialogs can be placed in body, not in// summernote.disableDragAndDrop : false,// default false You can disable drag// and drop});});使用jquery获取到页面上的summernote,对其进行初始化,我们来详细介绍列出参数的用法(先不介绍图片上传的onImageUpload 方法)。$(".summernote").summernote({height:300,onImageUpload: function(files, editor, welEditable) {sendFile(files[0],editor,welEditable);}});});function sendFile(file, editor, welEditable) {data = new FormData();data.append("file", file);url = "http://localhost/spichlerz/uploads";$.ajax({data: data,type: "POST",url: url,cache: false,contentType: false,processData: false,success: function (url) {editor.insertImage(welEditable, url);}});}</script>以上资源来自于stackoverflow。Override image upload handler(default: base64 dataURL on IMG tag). You can upload image to server or AWS S3: more…// onImageUpload callback$("#summernote").summernote({callbacks: {onImageUpload: function(files) {// upload image to server and create imgNode...$summernote.summernote("insertNode", imgNode);}}});// summernote.image.upload$("#summernote").on("summernote.image.upload", function(we, files) {// upload image to server and create imgNode...$summernote.summernote("insertNode", imgNode);});那么此时onImageUpload的具体写法呢?(后端为springMVC):callbacks : {// onImageUpload的参数为files,summernote支持选择多张图片onImageUpload : function(files) {var $files = $(files);// 通过each方法遍历每一个file$files.each(function() {var file = this;// FormData,新的form表单封装,具体可百度,但其实用法很简单,如下var data = new FormData();// 将文件加入到file中,后端可获得到参数名为“file”data.append("file", file);// ajax上传$.ajax({data : data,type : "POST",url : url,// div上的actioncache : false,contentType : false,processData : false,// 成功时调用方法,后端返回json数据success : function(response) {// 封装的eval方法,可百度var json = YUNM.jsonEval(response);// 控制台输出返回数据YUNM.debug(json);// 封装方法,主要是显示错误提示信息YUNM.ajaxDone(json);// 状态ok时if (json[YUNM.keys.statusCode] == YUNM.statusCode.ok) {// 文件不为空if (json[YUNM.keys.result]) {// 获取后台数据保存的图片完整路径var imageUrl = json[YUNM.keys.result].completeSavePath;// 插入到summernote$this.summernote("insertImage", imageUrl, function($image) {// todo,后续可以对image对象增加新的css式样等等,这里默认});}}},// ajax请求失败时处理error : YUNM.ajaxError});});}}注释当中加的很详细,这里把其他关联的代码一并贴出,仅供参照。debug : function(msg) {if (this._set.debug) {if (typeof (console) != "undefined")console.log(msg);elsealert(msg);}},jsonEval : function(data) {try {if ($.type(data) == "string")return eval("(" + data + ")");elsereturn data;} catch (e) {return {};}},ajaxError : function(xhr, ajaxOptions, thrownError) {if (xhr.responseText) {$.showErr("<div>" + xhr.responseText + "</div>");} else {$.showErr("<div>Http status: " + xhr.status + " " + xhr.statusText + "</div>" + "<div>ajaxOptions: " + ajaxOptions + "</div>"+ "<div>thrownError: " + thrownError + "</div>");}},ajaxDone : function(json) {if (json[YUNM.keys.statusCode] == YUNM.statusCode.error) {if (json[YUNM.keys.message]) {YUNM.debug(json[YUNM.keys.message]);$.showErr(json[YUNM.keys.message]);}} else if (json[YUNM.keys.statusCode] == YUNM.statusCode.timeout) {YUNM.debug(json[YUNM.keys.message]);$.showErr(json[YUNM.keys.message] || YUNM.msg("sessionTimout"), YUNM.loadLogin);}},2、后端springMVC文件保存<bean id="multipartResolver"class="org.springframework.web.multipart.commons.CommonsMultipartResolver" p:defaultEncoding="UTF-8"><property name="maxUploadSize" value="1024000000"></property></bean><mvc:annotation-driven conversion-service="conversionService" /><bean id="conversionService"class="org.springframework.format.support.FormattingConversionServiceFactoryBean"><property name="converters"><list><!-- 这里使用string to date可以将dao在jsp到controller转换的时候直接将string格式的日期转换为date类型 --><bean class="com.honzh.common.plugin.StringToDateConverter" /><!-- 为type为file类型的数据模型增加转换器 --><bean class="com.honzh.common.plugin.CommonsMultipartFileToString" /></list></property></bean>这里就不做过多介绍了,可参照我之前写的SpringMVC之context-dispatcher.xml,了解基本的控制器
package com.honzh.spring.controller;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.apache.log4j.Logger;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import com.honzh.common.base.UploadFile;import com.honzh.spring.service.FileService;@Controller@RequestMapping(value = "/file")public class FileController extends BaseController {private static Logger logger = Logger.getLogger(FileController.class);@Autowiredprivate FileService fileService;@RequestMapping("")public void index(HttpServletRequest request, HttpServletResponse response) {logger.debug("获取上传文件...");try {UploadFile uploadFiles = fileService.saveFile(request);renderJsonDone(response, uploadFiles);} catch (Exception e) {logger.error(e.getMessage());logger.error(e.getMessage(), e);renderJsonError(response, "文件上传失败");}}}2.3、FileService.javapackage com.honzh.spring.service;import java.io.IOException;import java.util.Iterator;import java.util.Map;import java.util.Random;import javax.servlet.http.HttpServletRequest;import org.apache.commons.io.FileUtils;import org.apache.log4j.Logger;import org.springframework.stereotype.Service;import org.springframework.web.multipart.MultipartFile;import org.springframework.web.multipart.MultipartHttpServletRequest;import com.honzh.common.Variables;import com.honzh.common.base.UploadFile;import com.honzh.common.util.DateUtil;@Servicepublic class FileService {private static Logger logger = Logger.getLogger(FileService.class);public UploadFile saveFile(HttpServletRequest request) throws IOException {logger.debug("获取上传文件...");// 转换为文件类型的requestMultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;// 获取对应file对象Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();Iterator<String> fileIterator = multipartRequest.getFileNames();// 获取项目的相对路径(http://localhost:8080/file)String requestURL = request.getRequestURL().toString();String prePath = requestURL.substring(0, requestURL.indexOf(Variables.ctx));while (fileIterator.hasNext()) {String fileKey = fileIterator.next();logger.debug("文件名为:" + fileKey);// 获取对应文件MultipartFile multipartFile = fileMap.get(fileKey);if (multipartFile.getSize() != 0L) {validateImage(multipartFile);// 调用saveImage方法保存UploadFile file = saveImage(multipartFile);file.setPrePath(prePath);return file;}}return null;}private UploadFile saveImage(MultipartFile image) throws IOException {String originalFilename = image.getOriginalFilename();logger.debug("文件原始名称为:" + originalFilename);String contentType = image.getContentType();String type = contentType.substring(contentType.indexOf("/") + 1);String fileName = DateUtil.getCurrentMillStr() + new Random().nextInt(100) + "." + type;// 封装了一个简单的file对象,增加了几个属性UploadFile file = new UploadFile(Variables.save_directory, fileName);file.setContentType(contentType);logger.debug("文件保存路径:" + file.getSaveDirectory());// 通过org.apache.commons.io.FileUtils的writeByteArrayToFile对图片进行保存FileUtils.writeByteArrayToFile(file.getFile(), image.getBytes());return file;}private void validateImage(MultipartFile image) {}}2.4、UploadFile.javapackage com.honzh.common.base;import java.io.File;import com.honzh.common.Variables;public class UploadFile {private String saveDirectory;private String fileName;private String contentType;private String prePath;private String completeSavePath;private String relativeSavePath;public UploadFile(String saveDirectory, String filesystemName) {this.saveDirectory = saveDirectory;this.fileName = filesystemName;}public String getFileName() {return fileName;}public String getSaveDirectory() {return saveDirectory;}public String getContentType() {return contentType;}public void setContentType(String contentType) {this.contentType = contentType;}public String getPrePath() {if (prePath == null) {return "";}return prePath;}public void setPrePath(String prePath) {this.prePath = prePath;setCompleteSavePath(prePath + getRelativeSavePath());}public String getCompleteSavePath() {return completeSavePath;}public void setCompleteSavePath(String completeSavePath) {this.completeSavePath = completeSavePath;}public String getRelativeSavePath() {return relativeSavePath;}public void setRelativeSavePath(String relativeSavePath) {this.relativeSavePath = relativeSavePath;}public void setSaveDirectory(String saveDirectory) {this.saveDirectory = saveDirectory;}public void setFileName(String fileName) {this.fileName = fileName;}public File getFile() {if (getSaveDirectory() == null || getFileName() == null) {return null;} else {setRelativeSavePath(Variables.ctx + "/" + Variables.upload + "/" + getFileName());return new File(getSaveDirectory() + "/" + getFileName());}}}后端文件保存方法也非常简单,懂java的同学都可以看得懂,那么对于后端不使用springmvc的同学,你可以再找找方法。
③. summernote所在form表单的数据提交
这里,我们再回顾一下summernote所在的form表单,其中还包含了一个普通file的input标签,也就是说,该form还需要上传一张项目封面。
<form class="form-horizontal required-validate" action="#" enctype="multipart/form-data" method="post" onsubmit="return iframeCallback(this, pageAjaxDone)">先看一下form的属性:
function iframeCallback(form, callback) {YUNM.debug("带文件上传处理");var $form = $(form), $iframe = $("#callbackframe");var data = $form.data("bootstrapValidator");if (data) {if (!data.isValid()) {return false;}}// 富文本编辑器$("div.summernote", $form).each(function() {var $this = $(this);if (!$this.summernote("isEmpty")) {var editor = "<input type="hidden" name="" + $this.attr("name") + "" value="" + $this.summernote("code") + "" />";$form.append(editor);} else {$.showErr("请填写项目详情");return false;}});if ($iframe.size() == 0) {$iframe = $("<iframe id="callbackframe" name="callbackframe" src="about:blank" style="display:none"></iframe>").appendTo("body");}if (!form.ajax) {$form.append("<input type="hidden" name="ajax" value="1" />");}form.target = "callbackframe";_iframeResponse($iframe[0], callback || YUNM.ajaxDone);}function _iframeResponse(iframe, callback) {var $iframe = $(iframe), $document = $(document);$document.trigger("ajaxStart");$iframe.bind("load", function(event) {$iframe.unbind("load");$document.trigger("ajaxStop");if (iframe.src == "javascript:"%3Chtml%3E%3C/html%3E";" || // For// Safariiframe.src == "javascript:"<html></html>";") { // For FF, IEreturn;}var doc = iframe.contentDocument || iframe.document;// fixing Opera 9.26,10.00if (doc.readyState && doc.readyState != "complete")return;// fixing Opera 9.64if (doc.body && doc.body.innerHTML == "false")return;var response;if (doc.XMLDocument) {// response is a xml document Internet Explorer propertyresponse = doc.XMLDocument;} else if (doc.body) {try {response = $iframe.contents().find("body").text();response = jQuery.parseJSON(response);} catch (e) { // response is html document or plain textresponse = doc.body.innerHTML;}} else {// response is a xml documentresponse = doc;}callback(response);});}贴上全部代码以供参考,但是这里我们只讲以下部分:// 富文本编辑器$("div.summernote", $form).each(function() {var $this = $(this);if (!$this.summernote("isEmpty")) {var editor = "<input type="hidden" name="" + $this.attr("name") + "" value="" + $this.summernote("code") + "" />";$form.append(editor);} else {$.showErr("请填写项目详情");return false;}});通过form获取到summernote对象$this 后,通过!$this.summernote("isEmpty")来判断用户是否对富文本编辑器有内容上的填写,保证不为空,为空时,就弹出提示信息。<p><img src="http://localhost:8080/ymeng/upload/2016033117093076.jpeg" style=""></p><p><br></p><p>你好,有兴趣可以加入到沉默王二的群啊<br></p>页面效果为:

好了,好了,终于写完了,没想到写的这么累,如果你有什么新鲜的玩意,也可以联系我啊,欢迎你的指导!
关于Bootstrap 富文本编辑器summernote小编就给大家介绍到这里,希望对大家有所帮助!有不同见解欢迎提出宝贵意见,共同学习进步!