kindEditer富文本编辑器从前端到后台完整经验

引言:kindEditer是现在免费开源的富文本编辑器中很轻巧和实用的,所以在比较之后决定使用它来满足项目的需求。

下载:http://kindeditor.net/demo.php

导入:由于官方没有完整项目jar包,所以把整个项目都导入到自己项目中,大小大约600多KB,导入位置随意,建议在根目录webapp下面就可以了。

kindEditer富文本编辑器从前端到后台完整经验_第1张图片kindEditer富文本编辑器从前端到后台完整经验_第2张图片

测试:把kindEditer解压之后导入到项目中,过程中可以选择性的保留和去掉一些不需要的包,以达到更轻巧的目的,笔者后台为javaweb项目,所以保留了,jsp包,把其他三种类型的都删掉了。然后看下demo.jsp,这个是测试页,在浏览器上输入地址(http://localhost:8082/kindeditor/jsp/demo.jsp)看下能否出现效果,能的话就表示导入成功。

效果展示:

kindEditer富文本编辑器从前端到后台完整经验_第3张图片


注意,upload_json.jsp这个jsp文件是kindEditer提供的图片上传的程序,这里面比较详细的写明了上传的逻辑代码,不过可能因为每个人的业务不同,所以需要修改一下路径。

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="java.util.*,java.io.*" %>
<%@ page import="java.text.SimpleDateFormat" %>
<%@ page import="org.apache.commons.fileupload.*" %>
<%@ page import="org.apache.commons.fileupload.disk.*" %>
<%@ page import="org.apache.commons.fileupload.servlet.*" %>
<%@ page import="org.json.simple.*" %>
<%

/**
 * KindEditor JSP
 * 
 * 本JSP程序是演示程序,建议不要直接在实际项目中使用。
 * 如果您确定直接使用本程序,使用之前请仔细确认相关安全设置。
 * 
 */

//文件保存目录路径
String savePath = pageContext.getServletContext().getRealPath("/") + "attached/";

//文件保存目录URL
String saveUrl  = request.getContextPath() + "/attached/";

//定义允许上传的文件扩展名
HashMap extMap = new HashMap();
extMap.put("image", "gif,jpg,jpeg,png,bmp");
extMap.put("flash", "swf,flv");
extMap.put("media", "swf,flv,mp3,wav,wma,wmv,mid,avi,mpg,asf,rm,rmvb");
extMap.put("file", "doc,docx,xls,xlsx,ppt,htm,html,txt,zip,rar,gz,bz2");

//最大文件大小
long maxSize = 1000000;

response.setContentType("text/html; charset=UTF-8");

if(!ServletFileUpload.isMultipartContent(request)){
	out.println(getError("请选择文件。"));
	return;
}
//检查目录
File uploadDir = new File(savePath);
if(!uploadDir.isDirectory()){
	out.println(getError("上传目录不存在。"));
	return;
}
//检查目录写权限
if(!uploadDir.canWrite()){
	out.println(getError("上传目录没有写权限。"));
	return;
}

String dirName = request.getParameter("dir");
if (dirName == null) {
	dirName = "image";
}
if(!extMap.containsKey(dirName)){
	out.println(getError("目录名不正确。"));
	return;
}
//创建文件夹
savePath += dirName + "/";
saveUrl += dirName + "/";
File saveDirFile = new File(savePath);
if (!saveDirFile.exists()) {
	saveDirFile.mkdirs();
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
String ymd = sdf.format(new Date());
savePath += ymd + "/";
saveUrl += ymd + "/";
File dirFile = new File(savePath);
if (!dirFile.exists()) {
	dirFile.mkdirs();
}

FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
upload.setHeaderEncoding("UTF-8");
List items = upload.parseRequest(request);
Iterator itr = items.iterator();
while (itr.hasNext()) {
	FileItem item = (FileItem) itr.next();
	String fileName = item.getName();
	long fileSize = item.getSize();
	if (!item.isFormField()) {
		//检查文件大小
		if(item.getSize() > maxSize){
			out.println(getError("上传文件大小超过限制。"));
			return;
		}
		//检查扩展名
		String fileExt = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
		if(!Arrays.asList(extMap.get(dirName).split(",")).contains(fileExt)){
			out.println(getError("上传文件扩展名是不允许的扩展名。\n只允许" + extMap.get(dirName) + "格式。"));
			return;
		}

		SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
		String newFileName = df.format(new Date()) + "_" + new Random().nextInt(1000) + "." + fileExt;
		try{
			File uploadedFile = new File(savePath, newFileName);
			item.write(uploadedFile);
		}catch(Exception e){
			out.println(getError("上传文件失败。"));
			return;
		}

		JSONObject obj = new JSONObject();
		obj.put("error", 0);
		obj.put("url", saveUrl + newFileName);
		out.println(obj.toJSONString());
	}
}
%>
<%!
private String getError(String message) {
	JSONObject obj = new JSONObject();
	obj.put("error", 1);
	obj.put("message", message);
	return obj.toJSONString();
}
%>

结合自己的需求:笔者公司因为有单独的文件静态服务器,所以不会把图片存放在服务器下,所以通过接口的方式把图片存在单独服务器上面,通过网络协议建立tcp连接,本文考虑通过socket向指定ip和端口的服务器发送文件数据。

/**
	 * KindEditor 
	 * 
	 */
	@RequestMapping(value="/uploadOK.do", produces = "application/json; charset=utf-8")
	@ResponseBody
	public String uploadOK(@RequestParam("imgFile") CommonsMultipartFile[] files,HttpServletRequest request, Map model,HttpServletResponse response){
		JSONObject jb=new JSONObject();
		jb.put("error", 0);
		//文件保存目录路径
		String saveHost =omsHost;
		String savePost =omsPost;
		//定义允许上传的文件扩展名
		HashMap extMap = new HashMap();
		extMap.put("image", "gif,jpg,jpeg,png,bmp");
		extMap.put("media", "swf,flv,mp3,wav,wma,wmv,mid,avi,mpg,asf,rm,rmvb");
		extMap.put("file", "doc,docx,xls,xlsx,ppt,htm,html,txt,zip,rar,gz,bz2");

		//最大文件大小
		long maxSize = 1024 * 1024 *2;
		if(!ServletFileUpload.isMultipartContent(request)){
			jb.put("error", 1);
			jb.put("message", "请选择文件");
			return jb.toJSONString();
		}
		String dirName  =request.getParameter("dir");
		if (dirName == null) {
			dirName = "image";
		}
		if(!extMap.containsKey(dirName)){
			jb.put("error", 1);
			jb.put("message", "目录名不正确");
			return jb.toJSONString();
		}
		try {
			if (files!=null&&files.length>0) {
				for (CommonsMultipartFile commonsMultipartFile : files) {
					FileItem fileItem = commonsMultipartFile.getFileItem();
					String fileName = getFileName(commonsMultipartFile);
					long fileSize = commonsMultipartFile.getSize();
						//检查文件大小
						if(fileSize > maxSize){
							jb.put("error", 1);
							jb.put("message", "上传文件大小不能超过2M");
							return jb.toJSONString();
						}
						//检查扩展名
						String fileExt = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
						if(!Arrays.asList(extMap.get(dirName).split(",")).contains(fileExt)){
							jb.put("error", 1);
							jb.put("message", "上传文件扩展名是不允许的扩展名\n只允许" + extMap.get(dirName) + "格式。");
							return jb.toJSONString();
						}
					try {
						byte[] bs =null;
						byte[] bytes = fileItem.get();
						bs= (bytes != null ? bytes : new byte[0]);
						//通过socket流向静态文件服务器写入图片数据172.28.21.224
						Socket socket = new Socket(saveHost, Integer.valueOf(savePost));
//						Socket socket = new Socket("127.0.0.1", 4303);
						socket.setSoTimeout(10000);
						DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
						DataInputStream dis = new DataInputStream(socket.getInputStream());
						dos.writeUTF(FileOp.UPLOAD.toString());
						dos.writeUTF(fileName);
						dos.write(bs);
						dos.flush();
						socket.shutdownOutput();
						String fileInfo = dis.readUTF();
						if (MyUtils.isNotEmpty(fileInfo)) {
							FileInfo pic=JSON.parseObject(fileInfo,FileInfo.class);
							String path="http://"+omsHost+"/"+pic.getPath();
							jb.put("url", path);
							logger.info("上传文件成功:{}",jb.toJSONString());
//							jb.put("url", "blob:http://localhost:8082/19cc387c-c016-4a80-9946-4041620b8de8");
//							jb.put("url", "http://54.223.57.79/2016/08/08/25/3d2adf5d-c807-4293-b4e9-55dee70aa07c.jpg");
						}else{
							jb.put("error", 1);
							jb.put("message", "上传文件失败");
						}
					}catch(Exception e){
							jb.put("error", 1);
							jb.put("message", "上传文件失败"+e.getMessage());
							logger.error("上传文件失败:{}",e.getMessage());
							return jb.toJSONString();
					}
//					jb.put("url", "http://54.223.57.79/2016/08/08/25/3d2adf5d-c807-4293-b4e9-55dee70aa07c.jpg");
					System.out.println(jb.toJSONString());
				}
			}
		} catch (Exception e1) {
			jb.put("error", 1);
			jb.put("message", e1.getMessage());
			logger.error("上传文件失败:{}",e1.getMessage());
			return jb.toJSONString();
		}
		return jb.toJSONString();
	}

这里有点需要注意:
FileItem 这个类是文件上传的核心处理类,通常上传文件都是将文件转换为byte数组存储,这个类提供get()方法byte[] bytes = fileItem.get();可以完成。
至于
@RequestParam("imgFile") CommonsMultipartFile[] files这里为什么这样接收,断点进去发现kindEditer前端传过来几个请求,这是其中一个,当然也可以像kindEditer给的例子
那样写:
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
upload.setHeaderEncoding("UTF-8");
List items = upload.parseRequest(request);
Iterator itr = items.iterator();
while (itr.hasNext()) {
	FileItem item = (FileItem) itr.next();
}
这样其实也是转换为FileItem类。原理相同的。
 好了,这样前端和后端都介绍完毕了。下面介绍几个笔者用到的kindEditer比较烦的细节:

send : function() {
			//初始化编辑器
			messageManager.editor = KindEditor.create('textarea[name="menuJson"]', {//这里的name是子页面对应的 textarea 的name属性值
				width:$(window).width() * 0.5, //宽度,自由设置,笔者根据屏幕大小设置的
		        	minHeight:$(window).height() * 0.8 - 120, 
		                themeType : 'default',
		                resizeType : 2,//表示插件的左右上下是否可扩展,就是滚动条
		                allowPreviewEmoticons : true,
		                allowImageUpload : true,
		                fullscreenMode:false,//是否全屏
		                fillDescAfterUploadImage:false,,
		                items:[
		                 'source', '|', 'undo', 'redo', '|', 'preview', 'print', 'template', 'code', 'cut', 'copy', 'paste',
		                 'plainpaste', 'wordpaste', '|', 'justifyleft', 'justifycenter', 'justifyright',
		                 'justifyfull', 'insertorderedlist', 'insertunorderedlist', 'indent', 'outdent', 'subscript',
		                 'superscript', 'clearhtml', 'quickformat', 'selectall', '|', 'fullscreen', '/',
		                 'formatblock', 'fontname', 'fontsize', '|', 'forecolor', 'hilitecolor', 'bold',
		                 'italic', 'underline', 'strikethrough', 'lineheight', 'removeformat', '|', 'image',
		                 'insertfile', 'table', 'hr', 'emoticons', 'baidumap', 'pagebreak',
		                 'anchor', 'link', 'unlink', '|', 'about'
		         		],
				cssPath : '${baseurl}kindeditor/plugins/code/prettify.css',
				uploadJson : '${baseurl}/message/uploadOK.do',
				afterUpload : function(data) {//这个是在上传图片之后回调函数
					messageManager.editor.hideDialog();//表示上传图片之后隐藏模态框
			        }
		            });
				messageManager.editor.readonly(false);//表示是否是只读状态,如果是则不可编辑,这里工具栏同时也不能点击
                                //但是有时需要在禁用编辑的同时上面的工具栏可用。。这个要修改源码啦。

                               messageManager.editor2.readonly(true);//只读,但是这里修改了源码,保留了工具栏上的全屏按钮,就是全屏还是可以点击的,这里有个bug
                      messageManager.editor2.clickToolbar('fullscreen', function() {//就是全屏之后偶变成可读状态了,所以引入点击工具栏事件,全屏之后
                         messageManager.editor2.readonly(true);//直接再次禁用,好吧,方法有点笨,不过占时只能想到这里了。。。。
                         });
 
		},






你可能感兴趣的:(kindEditer)