欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

富文本编辑器kindeditor的使用(JAVA)

程序员文章站 2022-07-02 22:31:25
...

环境搭建

官方文档 :编辑器使用方法

  1. 下载并解压放入项目中
  2. 在需要显示编辑器的位置添加textarea输入框
	<textarea id="editor_id" name="content" style="width:700px;height:300px;">

	</textarea>
  1. 引入文件并初始化编辑器
	//引入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. 图片空间的实现

  1. 初始化设置,在初始化编辑器设置显示图片空间按钮并设置图片空间URL
		//显示图片空间按钮
	    allowFileManager:true,
	    //图片空间按钮的URL
	    fileManagerJson:'项目名/article/showImages',
  1. 后台代码编写
	@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. 图片上传的的实现

  1. 初始化设置,在初始化编辑器设置文件上传URL和后台接收的图片名称
	//文件上传的URL
	uploadJson:'项目名/article/upload',
	//指定后台接收的图片名称
	filePostName:'image',
  1. 后台代码编写
	@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>"
                        +"&nbsp;&nbsp;&nbsp;<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">&times;</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>&nbsp;&nbsp;&nbsp;&nbsp;
                    <%--<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;
    }

}