引言:kindEditer是现在免费开源的富文本编辑器中很轻巧和实用的,所以在比较之后决定使用它来满足项目的需求。
下载:http://kindeditor.net/demo.php
导入:由于官方没有完整项目jar包,所以把整个项目都导入到自己项目中,大小大约600多KB,导入位置随意,建议在根目录webapp下面就可以了。
测试:把kindEditer解压之后导入到项目中,过程中可以选择性的保留和去掉一些不需要的包,以达到更轻巧的目的,笔者后台为javaweb项目,所以保留了,jsp包,把其他三种类型的都删掉了。然后看下demo.jsp,这个是测试页,在浏览器上输入地址(http://localhost:8082/kindeditor/jsp/demo.jsp)看下能否出现效果,能的话就表示导入成功。
效果展示:
注意,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();
}
%>
/**
* 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();
}
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);//直接再次禁用,好吧,方法有点笨,不过占时只能想到这里了。。。。
});
},