markdown 编辑器发表博客
markdown 页面编辑器:
http://blog.youkuaiyun.com/qq_19558705/article/details/51993884
markdown 操作文章 : http://blog.youkuaiyun.com/qq_19558705/article/details/52171181
markdown 分页 排序 搜索文章
:
http://blog.youkuaiyun.com/qq_19558705/article/details/52251519
markdown 文字标签:http://blog.youkuaiyun.com/qq_19558705/article/details/52265947
markdown 文字标签:http://blog.youkuaiyun.com/qq_19558705/article/details/52265947
个人主页:http://www.itit123.cn/ 更多干货等你来拿
今天花了点时间完成了发布博客的功能。页面很简陋,效果图如下:
直接上代码(只提供思路,所用框架为Spring + SpringMVC + Spring data jpa + shiro):
首先要一个博客的实体类,一开始没必要太复杂,有基本要素就可以了。
package com.real.blog.entity;
import java.util.Date;
import javax.persistence.Entity;
import javax.persistence.Table;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.validator.constraints.NotBlank;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.real.entity.IdEntity;
@Getter
@Setter
@Entity
@Table(name = "xlblog")
public class Blog extends IdEntity{
@NotBlank
private String title;
private String author;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+08:00") // 设定JSON序列化时的日期格式
private Date createdDate;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+08:00") // 设定JSON序列化时的日期格式
private Date updateDate;
private String content;
}
这里用到了lombok,不懂的可以看一下这个:http://blog.youkuaiyun.com/qq_19558705/article/details/50277745
核心处理类controller
package com.real.blog.web;
import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.apache.shiro.SecurityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import com.google.gson.Gson;
import com.real.blog.entity.Blog;
import com.real.blog.service.BlogService;
import com.real.service.qiniu.QiniuService;
import com.real.utils.GenerateUtils;
@Controller
@RequestMapping("blog")
public class BlogController{
private static final Logger logger = LoggerFactory.getLogger(BlogController.class);
@Autowired
private QiniuService qiniuService;
@Autowired
private BlogService blogService;
private static final String WEB_PATH = "http://ip:8080";
@RequestMapping("all")
public String execute(Model model){
logger.info("blogs : {} " , blogService.findAll(Blog.class));
model.addAttribute("blogs", blogService.findAll(Blog.class));
return "blog/index";
}
@RequestMapping("detail")
public String detail(){
return "blog/detail";
}
@RequestMapping("java")
public String java(){
return "blog/java";
}
/**
* 跳转编辑博客页面
*
* @param blogId
* @return
*/
@RequestMapping("edit")
public String edit(@RequestParam(value="blogId",required=false) String blogId){
if (null == blogId) {
}
return "blog/edit";
}
/**
* markdown 上传图片
*
*/
@RequestMapping(value = "uploadImage" , method = RequestMethod.POST)
@ResponseBody
public String uploadImage(HttpServletRequest request,
@RequestParam(value = "file" , required=false) MultipartFile file,
@RequestParam(value = "text" , required=false) String fileName) {
String realPath = request.getSession().getServletContext().getRealPath("/");
String resourcePath = "static\\images\\uploadImages\\";
String result = null;
if(file!=null){
if(GenerateUtils.allowUpload(file.getContentType())){
// 存储本地
File dir = new File(realPath + resourcePath);
if(!dir.exists()){
dir.mkdirs();
}
File saveFile = new File(dir,file.getOriginalFilename());
try {
file.transferTo(saveFile);
String callbackImgUrl = WEB_PATH + request.getSession().getServletContext().getContextPath() + "/" +resourcePath.replaceAll("\\\\","/") + file.getOriginalFilename();
Map<String, Object> resultMap = new HashMap<String, Object>();
resultMap.put("message", fileName);
resultMap.put("url", callbackImgUrl);
result = new Gson().toJson(resultMap);
} catch (IllegalStateException e) {
e.printStackTrace();
result = "{\"error\":\"upload error\"}";
} catch (IOException e) {
e.printStackTrace();
result = "{\"error\":\"upload error\"}";
}
}
}
logger.info("result : {} " ,result);
return result;
}
/**
* 发布博客
*
* @param blog
* @param redirectAttributes
* @return
*/
@RequestMapping(value = "update", method = RequestMethod.POST)
public String updateBlogContent(@RequestParam(value = "blogTitle" , required=true) String blogTitle,
@RequestParam(value = "blogContent" , required=true) String blogContent,
RedirectAttributes redirectAttributes) {
Blog blog = new Blog();
// 完善权限后在弄,即登录的用户才会有权限发表博客
// blog.setAuthor(SecurityUtils.getSubject().getPrincipal().toString());
blog.setTitle(blogTitle);
blog.setContent(blogContent);
blog.setCreatedDate(new Date());
try {
blogService.save(blog);
redirectAttributes.addFlashAttribute("message", "发布成功!");
} catch (Exception e) {
e.printStackTrace();
// FIXME 有待完善
redirectAttributes.addFlashAttribute("message", "发布失败,请稍后再试!");
}
return "redirect:all";
}
}
编辑页面:
<%@ page contentType="text/html;charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="tags" tagdir="/WEB-INF/tags"%>
<c:set var="ctx" value="${pageContext.request.contextPath}" />
<link rel="stylesheet" type="text/css" href="${ctx}/static/markdown/css/bootstrap.css"/>
<h1>编辑页面</h1>
<form id="blogForm" action="${ctx}/blog/update" method="post">
<input type="text" name="blogTitle" autofocus="autofocus" placeholder="请输入标题"><br/><br/>
<textarea id="markdown-textarea" rows="12" class="span7" name="blogContent" ></textarea>
<button>发布</button>
</form>
<script type="text/javascript" src="${ctx}/static/jquery/jquery-1.9.1.min.js"></script>
<script type="text/javascript" src="${ctx}/static/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="${ctx}/static/markdown/js/markdown.js"></script>
<script type="text/javascript" src="${ctx}/static/markdown/js/markdown-editor.js"></script>
<script type="text/javascript" src="${ctx}/static/markdown/js/custom.js"></script>
<script type="text/javascript" src="${ctx}/static/jquery-validation/jquery.validate-1.14.0.min.js"></script>
<script>
$().ready(function() {
$('#markdown-textarea').markdown();
$("#blogForm").validate({
rules: {
blogTitle: {
required: true,
minlength: 3
},
blogContent: "required"
},
messages: {
blogTitle: "标题不能为空",
blogContent: "请填写内容"
},
submitHandler:function(form){
form.submit();
}
});
});
</script>
展示页面:
<%@ page contentType="text/html;charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="tags" tagdir="/WEB-INF/tags"%>
<c:set var="ctx" value="${pageContext.request.contextPath}" />
<script type="text/javascript" src="${ctx}/static/markdown/js/markdown.js"></script>
<script type="text/javascript" src="${ctx}/static/markdown/js/markdown-editor.js"></script>
<c:forEach items="${blogs}" var="blog" varStatus="num">
<!-- 问题一:不能直接把${blog.content}作为值传给 markdown2html js对特殊字符敏感-->
<h2 class="blog-title">${blog.title}</h2>
<p>${blog.createdDate} ${blog.author}</p>
<input type="hidden" value="${blog.content}" class="blogContent">
<div class="blog-content"></div>
<script>
// 问题二:markdown2html(text) 内容相同 解决方法是给最后一个class添加
$(".blog-content:last").html(markdown2html($(".blogContent:last").val()));
</script>
<a href="${ctx}/blog/detail">查看详细页</a>
<br/>
</c:forEach>
只做了轮廓,之后在慢慢完善,优化,美观。
遇到的问题也写在代码中了,有什么问题,和建议可以提出来。一起学习一起成长一起装逼。