写在开头
最近在做一个美食博客的网站系统,需要实现发布文章页面的效果(类似CSDN的Markdown写文章的功能),所以使用了UEditor编辑器代替了Markdown的编辑器,发布文章的时候可以将文章的html生成出来并直接插入到数据库数据中。
先看一下效果
下面详细介绍一步一步实现改功能
下载UEditor文件
gitee下载地址:https://gitee.com/chef_git/ueditor
下载ZIP解压后将UEditor文件夹放在web目录下
UEditor的使用
<!DOCTYPE HTML>
<html lang="en-US">
<head>
<meta charset="UTF-8">
<title>ueditor demo</title>
</head>
<body>
<!-- 加载编辑器的容器 -->
<script id="container" name="content" type="text/plain">这里写你的初始化内容</script>
<!-- 配置文件 -->
<script type="text/javascript" src="ueditor/ueditor.config.js"></script>
<!-- 编辑器源码文件 -->
<script type="text/javascript" src="ueditor/ueditor.all.js"></script>
<!-- 实例化编辑器 -->
<script type="text/javascript">
var ue = UE.getEditor('container',{
initialFrameHeight :600,
});
var ready=function () {
var html = ue.getContent();//获取html内容,返回: <p>hello</p>
var text=ue.getContentTxt();//获取纯文本内容
alert(html);
};
</script>
<button type="button" onclick="ready()">发布文章</button>
</body>
</html>
进入正题:发布文章页面
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
<title>写文章</title>
<!-- Bootstrap -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- HTML5 shim 和 Respond.js 是为了让 IE8 支持 HTML5 元素和媒体查询(media queries)功能 -->
<!-- 警告:通过 file:// 协议(就是直接将 html 页面拖拽到浏览器中)访问页面时 Respond.js 不起作用 -->
<!--[if lt IE 9]>
<script src="https://cdn.jsdelivr.net/npm/html5shiv@3.7.3/dist/html5shiv.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/respond.js@1.4.2/dest/respond.min.js"></script>
<![endif]-->
<!-- jQuery (Bootstrap 的所有 JavaScript 插件都依赖 jQuery,所以必须放在前边) -->
<script src="https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js"></script>
<!-- 加载 Bootstrap 的所有 JavaScript 插件。你也可以根据需要只加载单个插件。 -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js"></script>
</head>
<body>
<!--1.顶部导航条-->
<nav class="navbar navbar-default" style="margin-bottom: 0px">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">◄ 文章管理</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<!--搜索框-->
<form class="navbar-form navbar-left">
<div class="form-group">
<input type="text" class="form-control" placeholder="请输入文章标题" style="width: 1050px;" id="search_input"> <span id="tishi" style="font-weight: bold;">0</span>/200
</div>
<script>
$('#search_input').on('input focus keyup',
function(){
var strs = $(this).val();
remain = strs.length;
var content_msg = remain;
$(this).next().html(content_msg);
//.next() 方法返回被选元素的后一个同级元素。
}
);
</script>
<button type="submit" class="btn btn-default">保存草稿</button>
<button type="button" class="btn btn-default btn-danger" id="btn_put">发布文章</button>
</form>
<ul class="nav navbar-nav navbar-right">
<!-- <li><a href="#">Link</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
<li><a href="#">Something else here</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">Separated link</a></li>
</ul>
</li>-->
<li class="dropdown">
<a href="#" class="" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" style="padding: 0px;margin-top: 5px;margin-right: 10px;"><img src="img/about-img/1.jpg" class="img-responsive img-circle" style="width: 40px;height: 40px;"/></a>
<ul class="dropdown-menu" style="width: 40px;">
<li><a href="#">博文管理</a></li>
<li><a href="#">我的博客</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">退出</a></li>
</ul>
</li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
<!--2.UEditor编辑器-->
<div class="container-fluid" style="padding: 0px;">
<!-- 加载编辑器的容器 -->
<script id="container" name="content" type="text/plain">这里写你的文章内容</script>
<!-- 配置文件 -->
<script type="text/javascript" src="ueditor/ueditor.config.js"></script>
<!-- 编辑器源码文件 -->
<script type="text/javascript" src="ueditor/ueditor.all.js"></script>
<!-- 实例化编辑器 -->
<script type="text/javascript">
var ue = UE.getEditor('container',{
initialFrameHeight :590,
initialFrameWidth :1534,
});
/*
UEditor的后台配置失败!!!!
ue.loadServerConfig();
alert(ue.isServerConfigLoaded());*/
var ready=function () {//点击发布文章按钮
var html = ue.getContent();//获取html内容,返回: <p>hello</p>
var text=ue.getContentTxt();//获取纯文本内容
alert(html);
};
</script>
<!--点击按钮,跳出面板-->
<script>
$("#btn_put").click(function () {
$("#myModalLabel").text("发布文章");
var summary=ue.getContentTxt().substring(0,200);
$("#txt_statu").val(summary);
$('#myModal').modal();
});
</script>
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<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" id="myModalLabel">发布文章</h4>
</div>
<div class="modal-body">
<div class="form-group">
<label for="txt_departmentname">文章标签</label>
<input type="text" name="txt_departmentname" class="form-control" id="txt_departmentname" placeholder="自定义文章标签 ( 多个使用“、”分开!)">
</div>
<div class="form-group">
<label>分类专栏</label>
<select class="form-control" id="type_select">
<option>请选择</option>
<option>美食人生</option>
<option>美食评论</option>
<option>大厨授课</option>
<option>达人推荐</option>
<option>旅途美食</option>
<option>回家吃饭</option>
<option>饭后甜点</option>
</select>
</div>
<div class="form-group">
<label>文章类型</label>
<select class="form-control">
<option>请选择</option>
<option>原创</option>
<option>转载</option>
<option>翻译</option>
</select>
</div>
<div class="form-group">
<label for="txt_statu">摘要</label>
<input type="text" name="txt_statu" class="form-control" id="txt_statu" placeholder="摘要">
</div>
<div class="form-group">
<label>文章图片</label>
<!--实现上传图片-->
<form action="/upload" enctype="multipart/form-data" method="post" id="upload_img">
<div class="row" style="height: auto;width: 94%;margin-left: 10px;cursor: pointer;border:1px gainsboro solid;border-radius: 10px 10px;" id="upload_div">
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAEbUlEQVR4Xu2aTWgdVRTHz5l8LfyiipKlLnSnC9G4MQYrCIIUdSGVWjCmyTkTMbS6EJFCFqULwQ/CwzcnL1aN1UUofi3cqKWmIFJEEDeCIt1WF2mpEIKZd+TKPHkZ33tzZ+7MvD7e3E3g3Tvnnv/vnnPmzr1BGPKGQ64fKgBVBAw5gSoFhjwAqiLYtxQQkUcB4AgAhKp6ipm/6kc09gWAiBwFgLdigo8R0dtlQygdQBfxLd2lQygVQIL4vkAoDYCl+BaERSKql5EOpQAQER8A3kkpqBQIhQPIKL60SCgUgKP4UiAUBiAn8f9CQMS5hYWFUylTyGp4IQB6iVfVLUT8DQDub/dQVS8AwJ2IuK+D54qIR4qAkDuA1dXV51X13U74I/EzqvoKIh6KjTkNAK+r6rdlQsgVQCR+zURtHEBLPBH9HATB6U4AiOiwiNxdJoTcANiKN2B6ATD9BgIAnAeAmzqlQ7PZPOz7/kdWSZ4wKBcAvcQDwBUAmDYr3/IlCUAE4V4AOFs0BGcA9Xr9kOd5H3YK+0j8fiL6sX0hbACUBcEJQBbxNinQDktECo2EzACyik8LwCYSVPVpZj6TpSZkAuAiPgsACwjmUOVgFgipAbiKzwqgKAipAIjIEwDwSZqC1yksbYtgp2cTaoKJhAPM/KVtOlgDWF5e9iYnJ8029sYOxs2r7n/VvpsTLgCSIkFVLzLzHbkDWF9fv257e/svV/EuKRB/O0Q7xuvjPo2Pj++bnZ29bAPBOgIixzcRcbrNcKqVT7MRsnFeRB5Q1a8R8T8IqvorM99l87wZkwpAvV6/3fO8GgA8pKrfI+LL7Ts820ldU6B9nkajcU8Yhm8i4hQAbIZhuLS4uPi7rS+pANgaTRqXJ4CkuZL6KwBJhIroryKgx3lAEcB72axSoGziee0D8vK7ioC8SKaxUxXBqgh2PxVOE0l5jLWqAWtrazfv7u4eRMQ/d3Z2vlhaWtpxmVxEzC3PbLsNc5fAzOY/RjK3jY2Nka2tradU9VZVPeP7/h9JxhIB1Gq1W8bGxr4DgNYHxi+jo6NTc3NzV5OMd+sPguAlRHyjvb/ZbD7rctQdfa5/joiPR3avqOoMM//ktA8QEfPx80LMyDwRmQuQTG1lZWViYmLiUwB4LDJQI6IXMxmLHgqC4BlE/Dhm4wMies4VwDkAmImF6wlmPu7isHnWfF2av77vX3S1JSInAOC1mJ/nmPlhJwBBEMTPAIy9k0S0ZzJXAa7PB0FwEhFfjQHYZOY9ixefJ7EGVACqCBjyFBARc0G5p5Co6nlENL9fS+0RAHgwVgPOMrP5vWuzqQHvIWLPV8m1RCEG4H1m3rPhSl0Eo8sQ884exPYkEX3mFAGqiiJyARHvGyQCqvoDEU0hojoBiDYst3me1wCAA4MAwdwNjIyMTM/Pz19K8jexBrQbaDQa+8MwPIaINyQZ7lO/2f/XEfEbIvrbxodUAGwMDtqYCsCgrVje/lYRkDfRQbNXRcCgrVje/g59BPwDxZ9wX+EKb6cAAAAASUVORK5CYII=" alt="" class="col-md-offset-4">
<span class="vicp-hint">点击上传图片至此处</span>
</div>
<input type="file" name="file" id="upload_file" style="display: none;"/>
<!--<input type="submit" value="upload">-->
</form>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal"><span class="glyphicon glyphicon-remove" aria-hidden="true"></span>取消</button>
<button type="button" id="btn_submit" class="btn btn-primary" data-dismiss="modal"><span class="glyphicon glyphicon-floppy-disk" aria-hidden="true"></span>发布文章</button>
</div>
<script>
var imgUrl;
$("#upload_div").click(function () {//div点击触发inputfile按钮上传文件的功能
$("#upload_file").click();
});
$("#upload_file").change(function () {//选中文件后,异步上传文件并获取上传文件的地址
var fromData = new FormData($("#upload_img")[0]);
/*$("#upload_img").submit();//非异步提交上传文件的表单*/
$.ajax( {/*异步提交上传文件的表单*/
url:'/upload',
data:fromData,
type:'post',
//ajax2.0可以不用设置请求头,但是jq帮我们自动设置了,这样的话需要我们自己取消掉
contentType:false,
//取消帮我们格式化数据,是什么就是什么
processData:false,
success:function(data){
console.log(data);
//异步刷新图片
var imgPath=$("#upload_file").val().split("\\");
var imgName=imgPath[2];
imgUrl='/img/blog-img/'+imgName;
$("#upload_div").html('<img src="'+imgUrl+'" alt="" class="img-responsive img-rounded">\n');
}
});
/*alert(imgUrl);*/
});
$("#btn_submit").click(function () {//点击发布文章按钮,异步提交文章数据,跳转页面
//title,
var title=$("#search_input").val();
if (title){
console.log("title"+title);
} else {
alert("标题不能为空!");
return;
}
// summary,
var summary=ue.getContentTxt().substring(0,200);
if (summary=="这里写你的文章内容" || summary==""){
alert("文章内容什么也没写哦!");
return;
}
console.log("summary"+summary);
// releaseDate,
var date=new Date();
console.log("date"+date);
// content,
var content=ue.getContentTxt();
console.log("content"+content);
// typeid,
var typeName=$("#type_select").val();
if (typeName=="请选择"){
alert("请选择文章类型!");
return;
} else {
var typeid;
switch (typeName) {
case "美食人生":typeid=1;break;
case "美食评论":typeid=2;break;
case "大厨授课":typeid=3;break;
case "达人推荐":typeid=4;break;
case "旅途美食":typeid=5;break;
case "回家吃饭":typeid=6;break;
case "饭后甜点":typeid=7;break;
}
/*alert(typeid);*/
}
// keyWord,
var keyWord=$("#txt_departmentname").val();
/*alert(keyWord);*/
// imgUrl,
imgUrl=imgUrl.substr(1);//去掉第一个 "/"
// author
var author="chif";
blog={title:title,summary:summary,releaseDate:date,likes:0,replyHit:0,content:content,typeid:typeid,keyWord:keyWord,imgUrl:imgUrl,author:author};
//ajax 发布博客
$.post("/addBlog",blog,function (data) {
/*var result=$.parseJSON(data);*/
alert(data);
})
});
</script>
</div>
</div>
</div>
</div>
</body>
</html>
页面中ajax请求的后台接口
/upload
package com.chif.controller;
import com.alibaba.druid.support.json.JSONUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
@Controller
public class FileController {
//@RequestParam("file") 将name=file控件得到的文件封装成CommonsMultipartFile 对象
//批量上传CommonsMultipartFile则为数组即可
@RequestMapping("/upload")
@ResponseBody
public String fileUpload(@RequestParam("file") CommonsMultipartFile file , HttpServletRequest request) throws IOException {
//获取文件名 : file.getOriginalFilename();
String uploadFileName = file.getOriginalFilename();
//如果文件名为空,直接回到首页!
if ("".equals(uploadFileName)){
return "redirect:/index.jsp";
}
System.out.println("上传文件名 : "+uploadFileName);
//上传路径保存设置
String path = request.getServletContext().getRealPath("/img/blog-img");
//如果路径不存在,创建一个
File realPath = new File(path);
if (!realPath.exists()){
realPath.mkdir();
}
System.out.println("上传文件保存地址:"+realPath);
InputStream is = file.getInputStream(); //文件输入流
OutputStream os = new FileOutputStream(new File(realPath,uploadFileName)); //文件输出流
//读取写出
int len=0;
byte[] buffer = new byte[1024];
while ((len=is.read(buffer))!=-1){
os.write(buffer,0,len);
os.flush();
}
os.close();
is.close();
return JSONUtils.toJSONString("上传文件成功!");
}
}
/addBlog
/**
* 增加一篇博客
* @param blog
* @return
*/
@RequestMapping("/addBlog")
public String addBook(Blog blog){
blogService.addBlog(blog);
return "发布成功";
}