富文本编辑器kindeditor的使用(JAVA)
程序员文章站
2022-07-02 22:31:25
...
环境搭建
官方文档 :编辑器使用方法
- 下载并解压放入项目中
- 在需要显示编辑器的位置添加textarea输入框
<textarea id="editor_id" name="content" style="width:700px;height:300px;">
</textarea>
- 引入文件并初始化编辑器
//引入js文件
<script charset="utf-8" src="/kindeditor/kindeditor-all-min.js"></script>
<script charset="utf-8" src="/kindeditor/lang/zh-CN.js"></script>
//集成KindEditor
KindEditor.create('#editor_id',{
width:'100%',
height:'350px',
//显示图片空间按钮
allowFileManager:true,
//图片空间按钮的URL
fileManagerJson:'项目名/article/showImages',
//文件上传的URL
uploadJson:'项目名/article/upload',
//指定后台接收的图片名称
filePostName:'image',
//失去焦点后保存文本域内容
afterBlur:function () {
this.sync();
}
});
第二种初始化方法:集成项目时可能不出效果,可直接使用第一种初始化方法;
<script>
KindEditor.ready(function(K) {
window.editor = K.create('#editor_id',{
//设置编辑器大小
width:'1000px',
height:'400px',
//显示图片空间按钮
allowFileManager:true,
//图片空间按钮的URL
fileManagerJson:'项目名/article/showImages',
//文件上传的URL
uploadJson:'项目名/article/upload',
//指定后台接收的图片名称
filePostName:'image',
//失去焦点后保存文本域内容
afterBlur:function () {
this.sync();
}
});
});
</script>
图片空间与上传图片
1. 图片空间的实现
- 初始化设置,在初始化编辑器设置显示图片空间按钮并设置图片空间URL
//显示图片空间按钮
allowFileManager:true,
//图片空间按钮的URL
fileManagerJson:'项目名/article/showImages',
- 后台代码编写
@RequestMapping("showImages")
public Images showImages(HttpServletRequest request){
Images images = new Images();
//获取图片文件夹中的数据
File file = new File(request.getSession().getServletContext().getRealPath("/view/article/image"));
File[] files = file.listFiles();
//设置数量
images.setTotal_count(files.length);
//设置url
String url = "http://"+request.getServerName()+":"+request.getServerPort()
+request.getContextPath()+"/view/article/image/";
images.setCurrent_url(url);
//设置集合人数据
List<Object> list = new ArrayList<>();
for (File file1 : files) {
Map<String, Object> map = new HashMap<>();
map.put("is_dir",false);
map.put("has_file",false);
map.put("filesize",file1.length());
map.put("is_photo",true);
//使用FilenameUtils时需要导入commons-io包
map.put("filetype", FilenameUtils.getExtension(file1.getName()));
map.put("filename",file1.getName());
map.put("datetime",new Date());
list.add(map);
}
images.setFile_list(list);
return images;
}
返回值说明:根据官方demo查得图片空间返回值如下。于是封装了Images对象属性current_url(String)、total_count(Integer),注意类型一定不能错。本想把上述map也封装一个对象,但get、set方法总是出错。
注意:使用FilenameUtils时需要导入commons-io包
{
"moveup_dir_path": "",
"current_dir_path": "",
"current_url": "/ke4/php/../attached/",
"total_count": 3,
"file_list": [
{
"is_dir": false,
"has_file": false,
"filesize": 208736,
"dir_path": "",
"is_photo": true,
"filetype": "jpg",
"filename": "1241601537255682809.jpg",
"datetime": "2018-06-06 00:36:39"
},
{
"is_dir": false,
"has_file": false,
"filesize": 14966,
"dir_path": "",
"is_photo": true,
"filetype": "jpg",
"filename": "1_192040_1.jpg",
"datetime": "2018-06-06 00:36:39"
},
{
"is_dir": false,
"has_file": false,
"filesize": 245132,
"dir_path": "",
"is_photo": true,
"filetype": "jpg",
"filename": "2009321101428.jpg",
"datetime": "2018-06-06 00:36:39"
}
]
}
2. 图片上传的的实现
- 初始化设置,在初始化编辑器设置文件上传URL和后台接收的图片名称
//文件上传的URL
uploadJson:'项目名/article/upload',
//指定后台接收的图片名称
filePostName:'image',
- 后台代码编写
@RequestMapping("upload")
public ImageJSON upload(MultipartFile image, HttpSession session,HttpServletRequest request) throws IOException {
//上传文件
String realPath = session.getServletContext().getRealPath("/view/article/image");
image.transferTo(new File(realPath,image.getOriginalFilename()));
//返回指定数据
String url = "http://"+request.getServerName()+":"
+request.getServerPort()+request.getContextPath()+"/view/article/image/"+image.getOriginalFilename();
System.out.println(url);
ImageJSON imageJSON = new ImageJSON(0,url);
return imageJSON;
}
返回值说明:根据官方demo查得图片空间返回值如下。于是封装了ImageJSON对象属性error(Integer)、url(String),注意类型一定不能错。
{
"error": 0,
"url": "/ke4/attached/W020091124524510014093.jpg"
}
集成项目遇到的一些问题
- 初始化时Kindeditor不出效果:
上文有介绍两种初始化方法,用第一种即可。 - 在使用bootstrap模态框时,图片空间里的图片无法设置大小
这是由于图层关系。把模态框中tabindex="-1" 删除即可。 - 文本域中内容获取不到
这是因为文本域中的内容不会自动保护。初始化时设置添加事件:文本域失去焦点后自动保存。
//失去焦点后自动保存文本域内容
afterBlur:function () {
this.sync();
}
完整代码
前台
<%@page contentType="text/html; UTF-8" isELIgnored="false" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:set value="${pageContext.request.contextPath}" var="app"/>
<%--这是部分页面,主页面已经引入jquery,bootstrap相关--%>
<script charset="utf-8" src="${app}/kindeditor/kindeditor-all-min.js"></script>
<script charset="utf-8" src="${app}/kindeditor/lang/zh-CN.js"></script>
<script>
$(function () {
$("#article-table").jqGrid({
// 整合使用bootstrap样式的属性
styleUI:'Bootstrap',
url:'${app}/article/findArticleByPage',
editurl:'${app}/article/operArticle',
// caption : "文章详细信息",
datatype:'json',
colNames:['id','名称','上师','内容','发布时间','操作'],
// 开启表格编辑模式
cellEdit:true,
colModel:[
{name:'id',align:'center',hidden:true},
{name:'title',align:'center',editable:true},
{
name:'guruId',
align:'center',
editable:true,
edittype:'select',
editoptions:{dataUrl:'${app}/guru/findAll'},
formatter:function (value,options,row) {
/**
* value: 第一次(url)加载到的数据(guruId)
* options: 略
* row: 当前行(url)的所有数据
*/
return row.guruName;
}
},
{name:'content',align:'center',editable:true},
{
name:'publishDate',
align:'center',
formatter:"date",
formatoptions: {srcformat:'Y-m-d H:i:s',newformat:'Y-m-d'}
},
{
name:'oprion',
align:'center',
formatter:function (value,option,rows) {
return "<a class='btn btn-primary' οnclick=\"showModal('edit','"+rows.id+"')\">修改</a>"
+" <a class='btn btn-danger' οnclick=\"delaa('"+rows.id+"')\">删除</a>";
}
},
],
//数据表格是否自适应父容器的大小宽度
autowidth:true,
//显示行号
rownumbers:true,
//在第一列前加入复选框
multiselect:true,
multiselectWidth:20,
//设置高度
height:400,
//添加分页
//使用分页工具栏
pager:'#article-pager',
rowList:[5,10,15],
rowNum:10,
page:1,
//显示总记录数
viewrecords:true,
closeAfterEdit:true,
}).navGrid('#article-pager',{edit : false,add : false,del : true,search:true},
{closeAfterEdit:true,},{ closeAfterAdd: true,}
);
})
//展示模态框
function showModal(oper,id) {
//填入下拉列表的值
$.ajax({
url:'${app}/guru/findAllBy',
type:'post',
datatype:'json',
success:function (result) {
$("#article-select").empty();
$.each(result,function (i,guru) {
//填值
var p = $("<option value='"+guru.id+"'>"+guru.dharma+"</option>");
$("#article-select").append(p);
})
//清空表单的值
//$("#article-form")[0].reset();
//清空kindeditor文本框的值
KindEditor.html("#editor_id","");
//修改时回显信息
var article = $("#article-table").jqGrid("getRowData",id);
$("#article-title").val(article.title);
$("#article-author").val(article.guruId);
$("#article-oper").val(oper);
$("#article-id").val(article.id);
KindEditor.html("#editor_id",article.content);
$("#article-modal").modal("show");
}
})
}
//集成KindEditor
KindEditor.create('#editor_id',{
width:'100%',
height:'350px',
//显示图片空间按钮
allowFileManager:true,
//图片空间按钮的URL
fileManagerJson:'${app}/article/showImages',
//文件上传的URL
uploadJson:'${app}/article/upload',
//指定后台接收的图片名称
filePostName:'image',
//失去焦点后自动保存文本域内容
afterBlur:function () {
this.sync();
}
});
//提交表单
function submit() {
$.ajax({
url:'${app}/article/operArticle',
type:'post',
data:$("#article-form").serialize(),
datatype:'json',
success:function () {
//关闭模态框
$("#article-modal").modal("hide");
//刷新表格
$("#article-table").trigger("reloadGrid");
}
})
}
function delaa(id) {
$.ajax({
url:'${app}/article/operArticle',
type:'post',
data:{'oper':'del','id':id},
datatype:'json',
success:function () {
//刷新表格
$("#article-table").trigger("reloadGrid");
}
})
}
</script>
<%--// tabindex="-1" 不能设置图片宽高--%>
<div class="modal fade" role="dialog" id="article-modal">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title">添加文章</h4>
</div>
<div class="modal-body">
<form class="form-inline" id="article-form">
<input type="hidden" id="article-oper" name="oper" value="add">
<input type="hidden" id="article-id" name="id">
<div class="form-group">
<label for="article-title">标题</label>
<input type="text" class="form-control" name="title" id="article-title" placeholder="请输入标题...">
</div>
<%--<div class="form-group">
<label for="article-author">作者</label>
<input type="text" class="form-control" name="guruName" id="article-author" placeholder="请输入作者...">
</div>--%>
<div class="form-group">
<label for="article-select">作者</label>
<%--<input type="select" class="form-control" name="guruName" id="article-author" placeholder="请输入作者...">--%>
<select name="guruId" id="article-select" class="form-control">
</select>
</div>
<div class="form-group">
<br>
<textarea id="editor_id" name="content">
</textarea>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" onclick="submit()" class="btn btn-primary">添加</button>
<button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
</div>
</div>
</div>
</div>
<ul class="nav nav-tabs">
<li role="presentation" class="active"><a href="#">文章详情</a></li>
<li role="presentation"><a onclick="showModal('add')">添加文章</a></li>
</ul>
<table id="article-table"></table>
<div id="article-pager"></div>
后台
@RequestMapping("article")
@RestController
public class ArticleController extends BaseApiService{
@Autowired
private ArticleService articleService;
@RequestMapping("findArticleByPage")
/**
* page:查询页数
* rows:每页显示条数
* searchField: 查询条件
* searchString: 查询内容
* 加入分页工具栏后,远程响应json数据格式为:
* {"rows":[当前页结果(list)],"page":"当前页","total":"总页数","records":"总条数"}
*/
public Map<String,Object> findArticleByPage(Integer page, Integer rows,
String searchField, String searchString){
//创建结果集
List<Article> articleList = null;
Integer records = 0;
HashMap<String, Object> map = new HashMap<>();
Integer total = 0;
//判断是否为模糊查询
if(searchField==null){
//查询集合
articleList = articleService.findAllByPage(page, rows);
//查询总条数
records = articleService.getCount();
//计算总页数
total = records%rows==0?records/rows:records/rows+1;
}else {
//查询集合
articleList = articleService.findAllByPageBySearch(page, rows,searchField,searchString);
//查询总条数
records = articleService.getCountBySearch(searchField,searchString);
//计算总页数
total = records%rows==0?records/rows:records/rows+1;
}
return setPageMap(articleList,page,total,records);
}
@RequestMapping("operArticle")
public Map<String,Object> operArticle(Article article,String id,String oper) {
//添加
if("add".equals(oper)){
String i = articleService.add(article);
return setResultSuccessData(i);
}
//修改
if("edit".equals(oper)){
String i = articleService.update(article);
return setResultSuccessData(i);
}
//删除
if("del".equals(oper)){
String[] ids = id.split(",");
for (String i : ids) {
articleService.delete(i);
}
}
return null;
}
@RequestMapping("upload")
public imageJSON upload(MultipartFile image, HttpSession session,HttpServletRequest request) throws IOException {
//上传文件
String realPath = session.getServletContext().getRealPath("/view/article/image");
image.transferTo(new File(realPath,image.getOriginalFilename()));
//返回指定数据
String url = "http://"+request.getServerName()+":"
+request.getServerPort()+request.getContextPath()+"/view/article/image/"+image.getOriginalFilename();
System.out.println(url);
imageJSON imageJSON = new imageJSON(0,url);
return imageJSON;
}
@RequestMapping("showImages")
public Images showImages(HttpServletRequest request){
Images images = new Images();
//获取图片文件夹中的数据
File file = new File(request.getSession().getServletContext().getRealPath("/view/article/image"));
File[] files = file.listFiles();
//设置数量
images.setTotal_count(files.length);
//设置url
String url = "http://"+request.getServerName()+":"+request.getServerPort()
+request.getContextPath()+"/view/article/image/";
images.setCurrent_url(url);
//设置集合人数据
List<Object> list = new ArrayList<>();
for (File file1 : files) {
Map<String, Object> map = new HashMap<>();
map.put("is_dir",false);
map.put("has_file",false);
map.put("filesize",file1.length());
map.put("is_photo",true);
map.put("filetype", FilenameUtils.getExtension(file1.getName()));
map.put("filename",file1.getName());
map.put("datetime",new Date());
list.add(map);
}
images.setFile_list(list);
return images;
}
}