springboot中使用kindeditor富文本编辑器实现博客功能

  kindeditor在之前已经用过,现在在springboot项目中使用。并且也在里面使用了图片上传以及回显等功能。

  其实主要的功能是图片的处理:kindeditor对输入的内容会作为html标签处理,对于image的做法是先将图片传到后台服务器,然后上传成功之后回传图片的URL,之后内容中增加<img src='url'>进行回显,当然保存到数据库也是img标签进行保存的。

  下面的代码涉及到了:Restful风格的请求、SpringMVC文件的上传、不配置虚拟路径的前提下请求图片资源、kindeditor、thymeleaf模板的使用。

1.首先编写接收kindeditor图片上传和图片请求的类:

package cn.qs.controller.user;

import java.io.File;
import java.io.FileInputStream;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import cn.qs.bean.user.Blogpicture;
import cn.qs.service.user.BlogPictureService;
import cn.qs.utils.FileHandleUtil;
import cn.qs.utils.UUIDUtil;

@Controller
@RequestMapping("blogPicture")
public class BlogPictureController {

    private static final Logger logger = LoggerFactory.getLogger(BlogPictureController.class);

    @Autowired
    private BlogPictureService blogPictureService;

    /**
     * Restful风格获取图片
     * 
     * @param request
     * @param response
     * @param pictureId
     */
    @RequestMapping("/getPicture/{pictureId}")
    public void getPicture(HttpServletRequest request, HttpServletResponse response, @PathVariable() String pictureId) {
        FileInputStream in = null;
        ServletOutputStream outputStream = null;
        try {
            String picturePath = blogPictureService.getPicturePathByPictureId(pictureId);
            File fileByName = FileHandleUtil.getFileByName(picturePath);
            in = new FileInputStream(fileByName);
            outputStream = response.getOutputStream();
            IOUtils.copyLarge(in, outputStream);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            IOUtils.closeQuietly(in);
            IOUtils.closeQuietly(outputStream);
        }
    }

    /**
     * 图片上传
     * 
     * @param imgFile
     * @return
     */
    @RequestMapping("/uploadPicture")
    @ResponseBody
    public Map<String, Object> uploadPicture(MultipartFile imgFile) {
        Map<String, Object> result = new HashMap<String, Object>();
        result.put("error", 1);

        if (imgFile == null) {
            result.put("message", "文件没接到");
            return result;
        }
        logger.debug("file -> {},viewId ->{}", imgFile.getOriginalFilename());

        String fileOriName = imgFile.getOriginalFilename();// 获取原名称
        String fileNowName = UUIDUtil.getUUID2() + "." + FilenameUtils.getExtension(fileOriName);// 生成唯一的名字
        try {
            FileHandleUtil.uploadSpringMVCFile(imgFile, fileNowName);

        } catch (Exception e) {
            logger.error("uploadPicture error", e);
            return result;
        }

        String id = UUIDUtil.getUUID();
        Blogpicture blogpicture = new Blogpicture();
        blogpicture.setCreatetime(new Date());
        blogpicture.setId(id);
        blogpicture.setPath(fileNowName);
        blogpicture.setOriginname(fileNowName);
        blogPictureService.insert(blogpicture);

        result.put("error", 0);
        result.put("url", "/blogPicture/getPicture/" + id);

        return result;
    }
}

  图片上传:参数接受名字必须是imgFile,否则接收不到文件。收到文件之后先生成一个全局唯一的名称然后保存到本地,并保存到数据库之后返回一个图片的URL例如:  /blogPicture/getPicture/94995b51-901c-44e9-87ec-12c109098f5e

  图片获取:通过restful风格的请求将图片的ID传到后台,根据ID查询到图片的路径,然后调用IOUtils将文件流回传回去实现图片的src请求显示拖。

FileHandleUtil类是图片保存以及获取,保存到本地的固定文件夹下面。

package cn.qs.utils;

import java.io.File;
import java.util.Locale;
import java.util.ResourceBundle;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.multipart.MultipartFile;

public class FileHandleUtil {

    public static final String LANGUAGE = "zh";

    public static final String COUNTRY = "CN";

    private static String getProperties(String baseName, String section) {
        String retValue = "";
        try {
            Locale locale = new Locale(LANGUAGE, COUNTRY);
            ResourceBundle rb = ResourceBundle.getBundle(baseName, locale);
            retValue = (String) rb.getObject(section);
        } catch (Exception e) {
        }
        return retValue;
    }

    public static String getValue(String fileName, String key) {
        String value = getProperties(fileName, key);
        return value;
    }

    public static boolean deletePlainFile(String propertiesFileName, String fileName) {
        if (fileName == null) {
            return false;
        }

        String fileDir = StringUtils.defaultIfBlank(FileHandleUtil.getValue("path", "picture"), "E:/picture/");
        try {
            FileUtils.deleteQuietly(new File(fileDir + fileName));
        } catch (Exception e) {
            return false;
        }

        return true;
    }

    public static boolean uploadSpringMVCFile(MultipartFile multipartFile, String fileName) throws Exception {
        String fileDir = StringUtils.defaultIfBlank(FileHandleUtil.getValue("path", "picture"), "E:/picture/");

        if (!new File(fileDir).exists()) {
            new File(fileDir).mkdirs();
        }
        multipartFile.transferTo(new File(fileDir + fileName));// 保存文件

        return true;
    }

    public static File getFileByName(String path) {
        String fileDir = StringUtils.defaultIfBlank(FileHandleUtil.getValue("path", "picture"), "E:/picture/");
        return new File(fileDir+path);
    }
}

2.前台界面准备富文本编辑器并且保存输入的信息到数据库

<!DOCTYPE html>
<html>
  
  <head>
    <meta charset="UTF-8"/>
    <title>欢迎页面-X-admin2.0</title>
    <meta name="renderer" content="webkit"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
    <meta name="viewport" content="width=device-width,user-scalable=yes, minimum-scale=0.4, initial-scale=0.8,target-densitydpi=low-dpi" />
    <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
    <link rel="stylesheet" th:href="${#httpServletRequest.getContextPath()+'/static/x-admin/css/font.css'}"/>
    <link rel="stylesheet" th:href="${#httpServletRequest.getContextPath()+'/static/x-admin/css/xadmin.css'}"/>
    <script type="text/javascript" th:src="${#httpServletRequest.getContextPath()+'/static/js/jquery.min.js'}" charset="utf-8"></script>
    <script type="text/javascript" th:src="${#httpServletRequest.getContextPath()+'/static/x-admin/lib/layui/layui.js'}" charset="utf-8"></script>
    <script type="text/javascript" th:src="${#httpServletRequest.getContextPath()+'/static/x-admin/js/xadmin.js'}"></script>
    
    <!-- kindeditor相关  -->
       <link rel="stylesheet" th:href="${#httpServletRequest.getContextPath()+'/static/kindeditor/themes/default/default.css'}" />
       <link rel="stylesheet" th:href="${#httpServletRequest.getContextPath()+'/static/kindeditor/plugins/code/prettify.css'}" />
    <script charset="utf-8" th:src="${#httpServletRequest.getContextPath()+'/static/kindeditor/kindeditor-all.js'}"></script>
    <script charset="utf-8" th:src="${#httpServletRequest.getContextPath()+'/static/kindeditor/lang/zh-CN.js'}"></script>
       <script>
    var editor;
    KindEditor.ready(function(K) {
        editor = K.create('textarea[name="contentEditor"]', {
            resizeType : 1,
            allowPreviewEmoticons : false,
            uploadJson : '/blogPicture/uploadPicture.html',
            allowImageUpload : true,
            pasteType : 0,      //设置能否粘贴
            items : [
                'fontname', 'fontsize', '|', 'forecolor', 'hilitecolor', 'bold', 'italic', 'underline',
                'removeformat', '|', 'justifyleft', 'justifycenter', 'justifyright', 'insertorderedlist',
                'insertunorderedlist', '|', 'emoticons', 'image', 'link','fullscreen']
        });
    });
    </script>
    
    <!-- 让IE8/9支持媒体查询,从而兼容栅格 -->
    <!--[if lt IE 9]>
      <script src="https://cdn.staticfile.org/html5shiv/r29/html5.min.js"></script>
      <script src="https://cdn.staticfile.org/respond.js/1.4.2/respond.min.js"></script>
    <![endif]-->
  </head>
  
  <body>
    <div class="x-body layui-anim layui-anim-up">
    
     <form class="layui-form">
          <div class="layui-form-item">
              <label for="L_email" class="layui-form-label">
                  <span class="x-red">*</span>博客标题
              </label>
              <div class="layui-input-inline">
                  <input type="text" id="L_blogtitle" name="blogtitle" lay-verify="required"
                  autocomplete="off" class="layui-input"/>
              </div>
          </div>
          <div class="layui-form-item">
              <label for="L_email" class="layui-form-label">
                  <span class="x-red">*</span>内容
              </label>
              <div class="layui-input-inline">
                  <textarea name="contentEditor" id="test" cols="100" rows="8" style="width:700px;height:200px;visibility:hidden;"></textarea>
              </div>
          </div>
           
          <div class="layui-form-item">
              <label for="L_repass" class="layui-form-label">
              </label>
              <button  class="layui-btn" lay-filter="add" lay-submit="">
                  增加
              </button>
          </div>
      </form>
    </div>
  </body>
      <script>
      /*<![CDATA[*/
        layui.use(['form','layer'], function(){
           $ = layui.jquery;
          var form = layui.form
          ,layer = layui.layer;
        
          //监听提交
          form.on('submit(add)', function(data){
              var data = {
                     "blogtitle":$('[name="blogtitle"]').val(),
                     "content":editor.html()
              }
               //异步提交数据
                 $.post("/blog/doAddBlog.html",data,function(response){
                   if(response.success == true){
                     layer.msg("增加成功", {icon: 6},function () {
                      // 获得frame索引
                      var index = parent.layer.getFrameIndex(window.name);
                      //关闭当前frame
                      parent.layer.close(index);
                      // 父页面刷新
                      parent.location.reload();
                  });
                   }else{
                       layer.alert(response.msg);
                   }
               }); 
            return false;
          });
        });
        /*]]>*/
    </script>

</html>

界面如下:

最终生成的内容保存到数据库之后如下:

<p>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;测试
</p>
<p>
    <img src="http://localhost:8088/static/kindeditor/plugins/emoticons/images/20.gif" border="0" alt="" />
</p>
<p>
    <img src="/blogPicture/getPicture/efe5134f-8a41-4e75-9108-6ab045979db6" alt="" />
</p>

最终经过代码处理后在界面显示如下:

    @RequestMapping("/getBlogdetail/{blogId}")
    public String getBlogdetail(ModelMap map, @PathVariable() Integer blogId, HttpServletRequest request) {
        Blog blog = blogService.getBlogdetail(blogId);

        // 获取当前用户
        HttpSession session = request.getSession();
        User user = (User) session.getAttribute("user");
        String username = user.getUsername();
        String blogUsername = StringUtils.defaultIfBlank(blog.getBlogblank(), "admin");

        if (blogUsername.equals(username)) {
            map.put("blog", blog);
        } else {
            map.put("blog", new Blog());
        }

        return "blogDetail";
    }
<!DOCTYPE html>
<html>
  
  <head>
    <meta charset="UTF-8"/>
    <title th:text="${blog.blogtitle}"></title>
    <meta name="renderer" content="webkit"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
    <meta name="viewport" content="width=device-width,user-scalable=yes, minimum-scale=0.4, initial-scale=0.8,target-densitydpi=low-dpi" />
    <link rel="shortcut icon" href="/static/x-admin/favicon.ico" type="image/x-icon" />
    <link rel="stylesheet" th:href="${#httpServletRequest.getContextPath()+'/static/x-admin/css/font.css'}"/>
    <link rel="stylesheet" th:href="${#httpServletRequest.getContextPath()+'/static/x-admin/css/xadmin.css'}"/>
    <script type="text/javascript" src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
    <script type="text/javascript" th:src="${#httpServletRequest.getContextPath()+'/static/x-admin/lib/layui/layui.all.js'}" charset="utf-8"></script>
    <script type="text/javascript" th:src="${#httpServletRequest.getContextPath()+'/static/x-admin/js/xadmin.js'}"></script>
    
    <span th:if="${session.user.username} eq 'admin'">
        <script>
            var admin = true;
        </script>
    </span>
    <style type="text/css">
    body{ 
    text-align:center;
    background-color: #dcdcdc;
    }
    #container{
        text-align:left;
        margin:0 auto;
        width: 80%;
        background-color: #fff;
    }
    </style>
  </head>
  
  <body class="layui-anim layui-anim-up">
      <div id="container">
            <center>
              <h1 th:text="${'标题:'+blog.blogtitle}"></h1>
              <h2 th:text="${'所属人'+blog.blogblank}"></h2>
          </center>
            <hr/>
            <span th:utext="${blog.content}"></span>
      </div>
  </body>
</html>

补充:kindeditor可选的显示插件有好多,如下需要的时候items里面增加对应的选项即可

    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', 'multiimage',
        'flash', 'media', 'insertfile', 'table', 'hr', 'emoticons', 'baidumap', 'pagebreak',
        'anchor', 'link', 'unlink', '|', 'about'
    ]

源码git地址:https://github.com/qiao-zhi/bs-tourism2.git

猜你喜欢

转载自www.cnblogs.com/qlqwjy/p/10685460.html