博客系统(升级(Spring))(四)(完)基本功能(阅读,修改,添加,删除文章)(附带项目)
博客系统 (三)
- 博客系统
- 博客主页
- 前端
- 后端
- 个人博客
- 前端
- 后端
- 显示个人文章
- 删除文章
- 修改文章
- 前端
- 后端
- 提取文章
- 修改文章
- 显示正文内容
- 前端
- 后端
- 文章阅读量功能
- 添加文章
- 前端
- 后端
- 如何使用Redis
- 项目地点:
博客系统
博客系统是干什么的?
CSDN就是一个典型的博客系统。而我在这里就是通过模拟实现一个博客系统,这是一个较为简单的博客系统,但是主要功能一个不缺,不过就是 UI 有些 low,我学习前端是为了写后端更加顺手。不至于前后端完全分离,但是有个问题设计的 web 页面不是很好看。
首先我将整体的业务流程展现
我们继博客系统(二)继续,编写,到了主页的业务逻辑了
接下来的流程是通过,网页端,后端统一数据结构交互的数据结构。
博客主页
前端
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>博客列表</title><link rel="stylesheet" href="css/list.css"><link rel="stylesheet" href="css/blog_list.css"><link rel="stylesheet" href="css/conmmon.css"></lin><script src="js/jquery.min.js"></script><style>.nav{position: fixed;top: 0;left: 0;right: 0;height: 50px;}.container{padding-top: 80px;height: auto;}.container-right{width: auto;}.blog-pagnation-wrapper{height: 40px;margin: 16px 0;text-align: center;}.blog-pagnation-item{display: inline-block;padding: 8px;border: 1px solid #d0d0d5;color: #333;}.blog-pagnation-item:hover{background: #4e4eeb;color: #fff;}.blog-pagnation-item.actvie{background: #4e4eeb;color: #fff;}</style><script src="js/urluitils.js"></script>
</head><body><!-- 导航栏 --><div class="nav"><img src="img/sleep.jpg" alt=""><span class="title">我的博客系统</span><!-- 用来占据中间位置 --><span class="spacer"></span><a href="blog_list.html">主页</a><a href="blog_add.html">写博客</a><a href="myblog_list.html">我的博客</a><a href="javascript:logout()">注销</a></div><!-- 版心 --><div class="container"><!-- 右侧内容详情 --><div class="container-right" style="width: 100%;"><div id="artListDiv"><!-- 每一篇博客包含标题, 摘要, 时间 --></div><div class="blog-pagnation-wrapper"><button class="blog-pagnation-item" onclick="doFirst()">首页</button> <button class="blog-pagnation-item" onclick="doBefore()">上一页</button> <button class="blog-pagnation-item" onclick="doNext()">下一页</button><button class="blog-pagnation-item" onclick="doLast()">末页</button> 当前在第<span id="pindex"></span>页共:<span id="psize"></span>页</div></div></div><script>var psize=2;var pindex=1;var totalpage=1;//总页//初始化数据function init(){//得到url中的分页参数psize=getParamValue("psize");if(psize==null){psize=2;}pindex=getParamValue("pindex");if(pindex==null){pindex=1;}jQuery("#pindex").html(pindex);//请求后端接口jQuery.ajax({url:"/article/getlistbypage",type:"get",data:{"pindex":pindex,"psize":psize},success:function(res){if(res.code==200&&res.data!=null){var createHtml="";if(res.data.list!=null&&res.data.list.length>0){//文章totalpage =res.data.list.szie;jQuery("#psize").html(totalpage);var artList=res.data.list;for(var i=0;i<artList.length;i++){var art=artList[i];createHtml+='<div class="blog">';createHtml+='<div class="title">'+art.title+'</div>';createHtml+='<div class="date">'+art.createtime+'</div>';createHtml+='<div class="desc">'+art.content+'</div>';createHtml+=' <a href="blog_content.html?aid='+art.id+'" class="detail">查看全文 >></a>';createHtml+='</div>';}}else{createHtml+='<h3 style="margin-top:20px;margin-left:20px">暂无文章!</h3>';}jQuery("#artListDiv").html(createHtml);}else{alert("抱歉:查询失败"+res.msg);}}});}init();function doFirst(){//判断是否在首页if(pindex<=1){alert("已经在首页了,不需跳转");return false;}location.href="blog_list.html";}function doLast(){if(pindex>=totalpage){alert("已经在末页了,不需跳转");return false;}location.href="blog_list.html?pindex="+(parseInt(totalpage));}function doBefore(){if(pindex<=1){alert("已经在首页了,不需跳转");return false;}location.href="blog_list.html?pindex="+(parseInt(pindex-1));}function doNext(){if(pindex>=totalpage){alert("已经在末页了,不需跳转");return false;}location.href="blog_list.html?pindex="+(parseInt(pindex+1));}</script>
</body>
</html>
后端
首先在主页中需要注意的是,我在这里添加了分页功能,如何解决分页问题,诺是将整个数据库里的文章全部读取到内存里,对于内存的消耗极大,所以这里我用sql语言中的 limt 语言进行分页读取(不知道的可以看我Mysql的文章)
通过mapper接口调用数据库
@Mapper
public interface ArticleMapper {@Select("select * from articleinfo order by id desc limit #{psize} offset #{offset}")List<Articleinfo> getListByPage(@Param("pszie") int pszie,@Param("offset") int offset);
}
通过service层调用mapper接口
@Service
public class ArticleService {@Autowiredprivate ArticleMapper articleMapper;public List<Articleinfo> getListByPage (int psize,int offset){return articleMapper.getListByPage(psize, offset);}
}
通过Controller层调用service层方法
@RestController
@RequestMapping("/article")
public class ArticleController {@Autowiredprivate ArticleService articleService;@Resourceprivate ThreadPoolTaskExecutor taskExecutor;public ResultAjax getListByPage(Integer pindex,Integer psize) throws ExecutionException, InterruptedException {if (pindex==null||pindex<1){pindex=1;}if (psize==null||psize<1){psize=1;}Integer finalPsize=psize;int offset=psize*(pindex-1);FutureTask<List<Articleinfo>> listFutureTask=new FutureTask<>(()->{return articleService.getListByPage(finalPsize,offset);});taskExecutor.submit(listFutureTask);FutureTask<Integer> sizeTask=new FutureTask<>(()->{int count= articleService.getCount(); double sizeTemp=((count*1.0)/(finalPsize*1.0));return (int)Math.ceil(sizeTemp);});taskExecutor.submit(sizeTask);List<Articleinfo> articleinfos=listFutureTask.get();int size=sizeTask.get();HashMap<String ,Object> map=new HashMap<>();map.put("list",articleinfos);map.put("szie",size);return ResultAjax.success(map);}
}
解释:
- 我在页面中每页所展示两个文章。而 limit finalPsize offset offset 我定位为 finalPsize 为第 几 行,offset 显示几个数据(具体原则在我的myslq 文章中有体现)(LIMIT [位置偏移量,] 行数)
- 使用多线程可以避开,有读者写数据,有读者读数据的情况。并且可以以最快速度反应的客户端
- 这个线程池Spring提供的,线程池,可以不需要去设置参数。
- 第一个线程池用来查找页面每页的内容,第二个线程池用来查找文章的总数。
个人博客
前端
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>博客列表</title><link rel="stylesheet" href="css/conmmon.css"><link rel="stylesheet" href="css/blog_list.css"><script src="js/jquery.min.js"></script><script src="js/logout.js"></script>
</head><body><!-- 导航栏 --><div class="nav"><img src="img/sleep.jpg" alt=""><span class="title">我的博客系统</span><!-- 用来占据中间位置 --><span class="spacer"></span><a href="blog_list.html">主页</a><a href="blog_add.html">写博客</a><a href="myblog_list.html">我的博客</a><a href="javascript:logout()">注销</a></div><!-- 版心 --><div class="container"><!-- 左侧个人信息 --><div class="container-left"><div class="card"><img src="img/sleep.jpg" class="avtar" alt=""><h3 id="username"></h3><a href="http:www.github.com">github 地址</a><div class="counter"><span>文章</span></div><div class="counter"><span id="artcount"></span></div></div></div><!-- 右侧内容详情 --><div id="artListDiv" class="container-right" ></div></div><script>function init(){jQuery.ajax({url:"/article/mylist",type:"get",data:{},success:function(res){if(res.code==200){var creatHtml="";var arrList=res.data.artList;if(res.code==200&&res.data!=null){var user=res.data.user;var size=res.data.size;var art=res.data.artList;if(user!=null){if(user.photo!=""){jQuery("#photo").att("src",user.photo);}jQuery("#username").html(user.username);jQuery("#artcount").html(size);}else{alert("抱歉查询失败"+res.msg);}}if(arrList!=null&&arrList.length>0){ for( var i=0;i<arrList.length;i++){var art =arrList[i];creatHtml+='<div class="blog">';creatHtml+='<div class="title">'+art.title+'</div>';creatHtml+='<div class="date">'+art.createtime+'</div>';creatHtml+='<div class="desc">'+ art.content+' </div>';creatHtml+=' <a href="blog_content.html?aid='+art.id+'" class="detail">查看全文 >></a> ';creatHtml+='<a href="blog_edit.html?aid='+art.id+'" class="detail">修改 >></a> ';creatHtml+='<a οnclick="del('+art.id+')" class="detail">删除 >></a>';creatHtml+=' </div>';}}else{creatHtml+='<h3 style="margin-top:20px;margin-left:20px">暂无文章,请先添加<a href="blog_add.html">添加</a> </h3>';}jQuery("#artListDiv").html(creatHtml);}else{alert("抱歉,操作失败"+res.msg);}}});}init();function del(aid){//1.参数校验if(aid=""||aid<=0){alert("参数错误!");return false;}jQuery.ajax({url:"/art/del",type:"post",data:{"aid":aid},success:function(res){if(res.code==200&& res.data==1){alert("恭喜:删除成功");location.href=location.href;}else{alert("删除失败"+res.msg);}}});}</script>
</body></html>
后端
显示个人文章
调用mapper层控制数据库
@Mapper
public interface ArticleMapper {@Select("select * from articleinfo where uid=#{uid}")List<Articleinfo> getUidByArticle(@Param("uid") int uid);
}
调用service层调用mapper接口
@Service
public class ArticleService {@Autowiredprivate ArticleMapper articleMapper;public List<Articleinfo> getUidByArticle(int uid){return articleMapper.getUidByArticle(uid);}
}
调用Controller 层调用service层
@RestController
@RequestMapping("/article")
public class ArticleController {@Autowiredprivate ArticleService articleService;@Resourceprivate ThreadPoolTaskExecutor taskExecutor;@Resourceprivate UserinfoVO userinfoVO;@RequestMapping("/mylist")public ResultAjax getUidByArticle(HttpServletRequest request){Userinfo userinfo= SessionUtis.getUser(request);if (userinfo==null){return ResultAjax.fail(-1,"请先登录");}List<Articleinfo> list =articleService.getUidByArticle(userinfo.getUid());int size=articleService.getArtCountById(userinfo.getUid());if (list!=null&&list.size()>0){list.stream().forEach(articleinfo -> {if (articleinfo.getContent().length()>120){articleinfo.setContent(articleinfo.getContent().substring(0,120));}});}HashMap<String ,Object> map=new HashMap<>();map.put("artList",list);map.put("user",userinfo);map.put("size",size);return ResultAjax.success(map);}
}
删除文章
调用mapper层控制数据库
@Mapper
public interface ArticleMapper {@Delete("delete from articleinfo where aid=#{aid} and uid=#{uid}")int delArt(@Param("aid")int aid,@Param("uid") int uid);
}
调用service层调用mapper接口
@Service
public class ArticleService {@Autowiredprivate ArticleMapper articleMapper;}
Controller层调用service
这个代码太多了我只展示主要代码
@RestController
@RequestMapping("/article")
public class ArticleController {@Autowiredprivate ArticleService articleService;@Resourceprivate ThreadPoolTaskExecutor taskExecutor;@RequestMapping("/del")public ResultAjax delArt(Integer aid,HttpServletRequest request){if (aid==null||aid<=0){return ResultAjax.fail(-1,"请先登录");}Userinfo userinfo=SessionUtis.getUser(request);int result= articleService.delArt(aid,userinfo.getUid());return ResultAjax.success(result);}}
修改文章
前端
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>博客编辑</title><!-- 引入自己写的样式 --><link rel="stylesheet" href="css/conmmon.css"><link rel="stylesheet" href="css/blog_edit.css"><!-- 引入 editor.md 的依赖 --><link rel="stylesheet" href="editor.md/css/editormd.min.css" /><script src="js/jquery.min.js"></script><script src="js/urluitils.js"></script><script src="editor.md/editormd.js"></script>
</head><body><!-- 导航栏 --><div class="nav"><img src="img/sleep.jpg" alt=""><span class="title">我的博客系统</span><!-- 用来占据中间位置 --><span class="spacer"></span><a href="blog_list.html">主页</a><a href="javascript:logout()">注销</a></div><!-- 编辑框容器 --><div class="blog-edit-container"><!-- 标题编辑区 --><div class="title"><input type="text" placeholder="在这里写下文章标题" id="title"><button onclick="doUpdate()">修改文章</button></div><!-- 创建编辑器标签 --><div id="editorDiv"><textarea id="editor-markdown" style="display:none;"></textarea></div></div><script>var editor;var aid=getParamValue("aid");function initEdit(md){// 编辑器设置editor = editormd("editorDiv", {// 这里的尺寸必须在这里设置. 设置样式会被 editormd 自动覆盖掉. width: "100%",// 高度 100% 意思是和父元素一样高. 要在父元素的基础上去掉标题编辑区的高度height: "calc(100% - 50px)",// 编辑器中的初始内容markdown: md,// 指定 editor.md 依赖的插件路径path: "editor.md/lib/",saveHTMLToTextarea: true // });}initEdit("# 在这里写下一篇博客"); // 初始化编译器的值// 提交function doUpdate(){var title=jQuery("#title");if(title.val()==""){alert("输入标题");title.focus();return false;}if(editor.getValue()==""){alert("请先输入正文");return false;}jQuery.ajax({url:"/article/update",type:"post",data:{"aid":aid,"title":title.val(),"content":editor.getValue()},success:function(res){if(res.code==200&&res.data==1){alert("恭喜,修改成功");location.href="myblog_list.html";}else if(res.code==-2){alert("未登录")location.href="login.html";}else{alert("抱歉,修改失败!"+res.msg);}}});}//初始化页面function init(){//校验aidif(aid==null||aid<0){alert("非法参数");return false;}//查询文章详情jQuery.ajax({url:"/article/update_init",type:"get",data:{"aid":aid},success: function(res){if(res.code==200&&res.data!=null&&res.data.id>0){jQuery("#title").val(res.data.title);initEdit(res.data.content);}else if(res.code==-2){alert("未登录")location.href="login.html";}else{alert("抱歉查询失败"+res.msg);}}});//将文章内容展示到页面}init();</script>
</body></html>
后端
提取文章
调用mapper层控制数据库
@Mapper
public interface ArticleMapper {@Select("select * from articleinfo where aid=#{aid} and uid=#{uid}")Articleinfo getArtByaidAnduid(@Param("aid")int aid,@Param("uid") int uid);
}
调用service层调用mapper接口
@Service
public class ArticleService {@Autowiredprivate ArticleMapper articleMapper;public Articleinfo getArtByaidAnduid(int aid,int uid){return articleMapper.getArtByaidAnduid(aid,uid);}
}
Controller层调用service
@RestController
@RequestMapping("/article")
public class ArticleController {@Autowiredprivate ArticleService articleService;@Resourceprivate ThreadPoolTaskExecutor taskExecutor;@Resourceprivate UserinfoVO userinfoVO;@RequestMapping("/update_init")public ResultAjax updataInti(Integer aid,HttpServletRequest request){if (aid<=0||aid==null){return ResultAjax.fail(-1,"参数有误");}Userinfo userinfo=SessionUtis.getUser(request);if (userinfo==null){return ResultAjax.fail(-2,"请先登录");}Articleinfo articleinfo=articleService.getArtByaidAnduid(aid,userinfo.getUid());return ResultAjax.success(articleinfo);}}
修改文章
调用mapper层控制数据库
@Mapper
public interface ArticleMapper {@Update("Update articleinfo set title=#{title},content=#{content} where aid=#{aid} and uid=#{uid}")int setArt(Articleinfo articleinfo);
}
调用service层调用mapper接口
@Service
public class ArticleService {@Autowiredprivate ArticleMapper articleMapper;public int setArt(Articleinfo articleinfo){return articleMapper.setArt(articleinfo);}
}
Controller层调用service
@RestController
@RequestMapping("/article")
public class ArticleController {@Autowiredprivate ArticleService articleService;@Resourceprivate ThreadPoolTaskExecutor taskExecutor;@Resourceprivate UserinfoVO userinfoVO;@RequestMapping("/update")public ResultAjax setArt(Articleinfo articleinfo,HttpServletRequest request){if (articleinfo==null||!StringUtils.hasLength(articleinfo.getContent())||!StringUtils.hasLength(articleinfo.getTitle())){return ResultAjax.fail(-1,"参数非法");}Userinfo userinfo=SessionUtis.getUser(request);if (userinfo==null){return ResultAjax.fail(-2,"请先登录");}articleinfo.setUid(userinfo.getUid());int result=articleService.setArt(articleinfo);return ResultAjax.success(result);}
}
显示正文内容
前端
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>博客正文</title><link rel="stylesheet" href="css/conmmon.css"><link rel="stylesheet" href="css/blog_content.css"><link rel="stylesheet" href="editor.md/css/editormd.preview.min.css" /><script src="js/jquery.min.js"></script><script src="editor.md/editormd.js"></script><script src="editor.md/lib/marked.min.js"></script><script src="editor.md/lib/prettify.min.js"></script><script src="js/urluitils.js"></script>
</head><body><!-- 导航栏 --><div class="nav"><img src="img/sleep.jpg" alt=""><span class="title">我的博客系统</span><!-- 用来占据中间位置 --><span class="spacer"></span><a href="blog_list.html">主页</a><a href="blog_edit.html">写博客</a><a href="myblog_list.html">我的博客</a><a href="login.html">登陆</a><a href="javascript:logout()">注销</a></div><!-- 版心 --><div class="container"><!-- 左侧个人信息 --><div class="container-left"><div class="card"><img src="img/sleep.jpg" class="avtar" id="photo"><h3 id="username"></h3><a href="http:www.github.com">github 地址</a><div class="counter"><span>文章</span></div><div class="counter"><span id="artcount"></span></div></div></div><!-- 右侧内容详情 --><div class="container-right"><div class="blog-content"><!-- 博客标题 --><h3 id="title"></h3><!-- 博客时间 --><div class="date" >发布时间: <span id="createtime"></span>| 阅读量: <span id="rcount"></span></div><!-- 博客正文 --><div id="editorDiv"></div></div></div></div><script type="text/javascript">var aid=getParamValue("aid");var editormd;function initEdit(md){editormd = editormd.markdownToHTML("editorDiv", {markdown : md, });}//初始化页面function init(){if(aid==null||aid<=0){alert("参数有误");return false;}jQuery.ajax({url:"/article/detail",type:"get",data:{"aid":aid},success:function(res){if(res.code==200&&res.data!=null){var user=res.data.user;var art=res.data.art;if(user!=null){if(user.photo!=""){jQuery("#photo").att("src",user.photo);}jQuery("#username").html(user.username);jQuery("#artcount").html(user.artCoout);}else{alert("抱歉查询失败"+res.msg);}if(art!=null){jQuery("#title").html(art.title);jQuery("#createtime").html(art.createtime);jQuery("#rcount").html(art.rcount);initEdit(art.content);}else{alert("抱歉查询失败"+res.msg);}}else{alert("抱歉查询失败"+res.msg);}}});}init();function incrementRCount(){if (aid==null||aid<=0) {return false;}jQuery.ajax({url:"/article/increment_rcount",type:"post",data:{"aid":aid},success:function(res){}})}incrementRCount();</script>
</body></html>
后端
调用mapper层控制数据库
UserMapper
@Mapper
public interface UserMapper {@Select("select * from userinfo where uid=#{uid}")UserinfoVO getUserById(@Param("uid")int uid);
}
ArticleMapper
@Mapper
public interface ArticleMapper {@Update("Update articleinfo set title=#{title},content=#{content} where aid=#{aid} and uid=#{uid}")int setArt(Articleinfo articleinfo);@Select("select * from articleinfo where aid=#{aid}")Articleinfo readDetail(@Param("aid")int aid);}
调用service层调用mapper接口
UserServie
@Service
public class UserService {@Autowiredprivate UserMapper userMapper;public UserinfoVO getUserByUid(int uid){return userMapper.getUserById(uid);}
}
ArticleService
@Service
public class ArticleService {@Autowiredprivate ArticleMapper articleMapper;public Articleinfo readDetail(int aid){return articleMapper.readDetail(aid);}
}
Controller层调用service
ArticleController
@RestController
@RequestMapping("/article")
public class ArticleController {@Autowiredprivate ArticleService articleService;@Resourceprivate ThreadPoolTaskExecutor taskExecutor;@Resourceprivate UserService userService;@Resourceprivate UserinfoVO userinfoVO;@RequestMapping("/detail")public ResultAjax readDetail(Integer aid) throws ExecutionException, InterruptedException {if (aid<=0||aid==null){return ResultAjax.fail(-1,"非法参数");}Articleinfo articleinfo=articleService.readDetail(aid);if (articleinfo==null){return ResultAjax.fail(-1,"非法参数");}FutureTask<UserinfoVO> userTask=new FutureTask<>(()->{return userService.getUserByUid(articleinfo.getUid());});taskExecutor.submit(userTask);FutureTask<Integer> artCountTask=new FutureTask<>(()->{return articleService.getArtCountById(articleinfo.getUid());});taskExecutor.submit(artCountTask);UserinfoVO userinfoVO=userTask.get();int artCount=artCountTask.get();userinfoVO.setArtCount(artCount);HashMap<String,Object> map=new HashMap<>();map.put("user",userinfoVO);map.put("art",articleinfo);return ResultAjax.success(map);}
}
文章阅读量功能
调用mapper层控制数据库
@Mapper
public interface ArticleMapper {@Update("upate articleinfo set readcount=readcount+1 where aid=#{aid}")int readArtCount(@Param("aid")int aid);}
调用service层调用mapper接口
@Service
public class ArticleService {@Autowiredprivate ArticleMapper articleMapper;public int readArtCount(int aid){return articleMapper.readArtCount(aid);}
}
Controller层调用service
@RestController
@RequestMapping("/article")
public class ArticleController {@Autowiredprivate ArticleService articleService;@Resourceprivate ThreadPoolTaskExecutor taskExecutor;@Resourceprivate UserService userService;@Resourceprivate UserinfoVO userinfoVO;@RequestMapping("/increment_rcount")public ResultAjax readArtCount(Integer aid){if (aid==null||aid<=0){return ResultAjax.fail(-1,"参数有误");}int result = articleService.readArtCount(aid);return ResultAjax.success(result);}
}
添加文章
前端
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>博客编辑</title><!-- 引入自己写的样式 --><link rel="stylesheet" href="css/conmmon.css"><link rel="stylesheet" href="css/blog_edit.css"><!-- 引入 editor.md 的依赖 --><link rel="stylesheet" href="editor.md/css/editormd.min.css" /><script src="js/jquery.min.js"></script><script src="editor.md/editormd.js"></script>
</head><body><!-- 导航栏 --><div class="nav"><img src="img/sleep.jpg" alt=""><span class="title">我的博客系统</span><!-- 用来占据中间位置 --><span class="spacer"></span><a href="blog_list.html">主页</a><a href="myblog_list.html">我的博客</a><a href="javascript:logout()">注销</a></div><!-- 编辑框容器 --><div class="blog-edit-container"><!-- 标题编辑区 --><div class="title" ><input type="text" placeholder="在这里写下文章标题" id="title"><button onclick="mysub()" >发布文章</button></div><!-- 创建编辑器标签 --><div id="editor"><textarea id="editor-markdown" style="display:none;"></textarea></div></div><script>var editor;function initEdit(md){// 编辑器设置editor = editormd("editor", {// 这里的尺寸必须在这里设置. 设置样式会被 editormd 自动覆盖掉. width: "100%",// 高度 100% 意思是和父元素一样高. 要在父元素的基础上去掉标题编辑区的高度height: "calc(100% - 50px)",// 编辑器中的初始内容markdown: md,// 指定 editor.md 依赖的插件路径path: "editor.md/lib/",saveHTMLToTextarea: true // });}initEdit("# 在这里写下一篇博客"); // 初始化编译器的值// 提交function mysub(){//非空校验var title=jQuery("#title");if(title.val()==""){alert("输入标题");title.focus();return false;}if(editor.getValue()==""){alert("请先输入正文");return false;}//将用户提交的数据传递给后端jQuery.ajax({url:"/article/add",type:"post",data:{"title":title.val(),"content":editor.getValue()},success:function(res){if(res.code==200&&res.data==1){if(confirm("恭喜:添加成功,是否继续添加文章")){Location.href=Location.href;}else{location.href="myblog_list.html";}}else{alert("抱歉:操作失败"+res.msg); }}});//将返回的数据展现给用户}</script>
</body></html>
后端
mapper
@Insert("insert into articleinfo(title,content,uid) values(#{title},#{content},#{uid})")int add(Articleinfo articleinfo);
Service
public int add(Articleinfo articleinfo) {return articleMapper.add(articleinfo);}
Controller
@RequestMapping("/add")public ResultAjax add(Articleinfo articleinfo,HttpServletRequest request){if (articleinfo==null||!StringUtils.hasLength(articleinfo.getTitle())||!StringUtils.hasLength(articleinfo.getContent())){return ResultAjax.fail(-1,"非法参数");}Userinfo userinfo=SessionUtis.getUser(request);if (userinfo==null){return ResultAjax.fail(-2,"请先登录");}articleinfo.setUid(userinfo.getUid());int result=articleService.add(articleinfo);return ResultAjax.success(result);}
补充一点:
如何使用Redis
具体详情可以看我的Redis哪一章文章链接
你会发现启动的并没有成功。原因我这里留了一个坑,关于拦截器的。
@Configuration
public class MyConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new LoginIntercpet()).addPathPatterns("/**").excludePathPatterns("/css/*").excludePathPatterns("/js/*").excludePathPatterns("/css").excludePathPatterns("/img/*").excludePathPatterns("/reg.html").excludePathPatterns("/blog_list.html").excludePathPatterns("/article/detail").excludePathPatterns("/article/getlistbypage").excludePathPatterns("/user/reg").excludePathPatterns("/user/login").excludePathPatterns("/editor.md/*").excludePathPatterns("/blog_content.html").excludePathPatterns("/login.html");}
}
第二个启动这里要添加mapper映射否则会失败
@SpringBootApplication
@MapperScan("com.example.myblog.mapper")
public class MyblogApplication {public static void main(String[] args) {SpringApplication.run(MyblogApplication.class, args);}}
项目地点:
项目的Gitee链接(实际调试完毕的项目)
相关文章:
博客系统(升级(Spring))(四)(完)基本功能(阅读,修改,添加,删除文章)(附带项目)
博客系统 (三) 博客系统博客主页前端后端个人博客前端后端显示个人文章删除文章 修改文章前端后端提取文章修改文章 显示正文内容前端后端文章阅读量功能 添加文章前端后端 如何使用Redis项目地点: 博客系统 博客系统是干什么的? CSDN就是一…...
常用的辅助类(必会)
1.CountDownLatch package com.kuang.add;import java.util.concurrent.CountDownLatch;//计数器 减法 public class CountDownLatchDemo {public static void main(String[] args) throws InterruptedException {//总数是6,必须要执行任务的时候,再使用…...
Java常用类之 String、StringBuffer、StringBuilder
Java常用类 文章目录 一、字符串相关的类1.1、String的 不可变性1.2、String不同实例化方式的对比1.3、String不同拼接操作的对比1.4、String的常用方法1.5、String类与其他结构之间的转换1.5.1、String 与基本数据类型、包装类之间的转换1.5.2、String 与char[]的转换1.5.3、…...
linux在所有文件中查找某一个字符串
linux在所有文件中查找某一个字符串 有时候我们需要在大量文件中查找某一个字符串,手工一个一个打开文件查找非常耗时,我们可以使用 find 和 xargs 两个命令来实现查找指定字符串。 命令详解 find <directory> -type f -name "*.c" |…...
WebSocket vs SSE: 实时数据推送到前端的选择与实现(详细)
Websocket和Server-Sent Events 对比推送数据给前端及各自的实现 二者对比WebSocket:Server-Sent Events (SSE):选择 WebSocket 还是 SSE: Websocket 实现使用原生 WebSocket API:使用 Netty 创建 WebSocket:总结和选择…...
Redis从入门到精通(二:数据类型)
数据存储类型介绍 Redis 数据类型(5种常用) string hash list set sorted_set/zset(应用性较低) redis 数据存储格式 redis 自身是一个 Map,其中所有的数据都是采用 key : value 的形式存储 数据类型指的是存储的数据…...
基于SSM的珠宝首饰交易平台
末尾获取源码 开发语言:Java Java开发工具:JDK1.8 后端框架:SSM 前端:采用JSP技术开发 数据库:MySQL5.7和Navicat管理工具结合 服务器:Tomcat8.5 开发软件:IDEA / Eclipse 是否Maven项目&#x…...
4款视频号数据分析平台!
很多人在做视频号的时候就会有创作参考的需求,那么你们知道视频号中有哪些数据平台?今天就和大家来分享一下 接下来就总结一下视频号数据平台有哪些?排名不分前后。 1:视频号助手(channels.weixin.qq.com)…...
【系统架构】什么是集群?为什么要使用集群架构?
什么是集群?为什么要使用集群架构? 1.什么是集群?2.为什么要使用集群?2.1 高性能2.2 价格有效性2.3 可伸缩性2.4 高可用性2.5 透明性2.6 可管理性2.7 可编程性 3.集群的常见分类3.1 负载均衡集群3.2 高可用性集群3.3 高性能计算集…...
Java手写拓扑排序和拓扑排序应用拓展案例
Java手写拓扑排序和拓扑排序应用拓展案例 1. 算法思维导图 #mermaid-svg-o8KpEXzxukfDM8c9 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-o8KpEXzxukfDM8c9 .error-icon{fill:#552222;}#mermaid-svg-o8KpEXzxukfD…...
练习:使用servlet显示试卷页面
试卷页面代码 在浏览器输入如下地址: http://localhost/examPageServlet 效果如下:...
视频监控系统/视频云存储EasyCVR接入国标GB28181设备无法播放设备录像,是什么原因?
安防视频监控平台EasyCVR支持将部署在监控现场的前端设备进行统一集中接入,可兼容多协议、多类型设备,管理员可选择任意一路或多路视频实时观看,视频画面支持单画面、多画面显示,视频窗口数量有1、4、9、16个可选,还能…...
四叶草clover配置工具:Clover Configurator for Mac
Clover Configurator是一款Mac上的工具,用于配置和优化Clover引导加载器。Clover引导加载器是一种用于启动macOS的开源引导加载器。它允许用户在启动时选择操作系统和配置启动选项。 Clover Configurator提供了一个可视化的界面,让用户可以轻松地编辑和…...
计算机网络第四章——网络层(中)
提示:待到山花烂漫时,她在丛中笑。 文章目录 需要加头加尾,其中头部最重要的就是加了IP地址和MAC地址(也就是逻辑地址和物理地址)集线器物理层设备,交换机是物理链路层的设备,如上图路由器左边就…...
时序分解 | MATLAB实现基于小波分解信号分解分量可视化
时序分解 | MATLAB实现基于小波分解信号分解分量可视化 目录 时序分解 | MATLAB实现基于小波分解信号分解分量可视化效果一览基本介绍程序设计参考资料 效果一览 基本介绍 基于小波分解的分量可视化,MATLAB编程程序,用于将信号分解成不同尺度和频率的子信…...
VMware虚拟化环境搭建
虚拟化环境搭建 1. 什么是虚拟化环境?未来工作中在何处使用? 在网络安全中,虚拟化环境是一种技术,它将一个物理计算机系统划分成多个独立、可管理的虚拟环境。这种虚拟环境技术允许多个完全不同的操作系统、显示装置和软件在同一…...
Jenkins :添加node权限获取凭据、执行命令
拥有Jenkins agent权限的账号可以对node节点进行操作,通过添加不同的node可以让流水线项目在不同的节点上运行,安装Jenkins的主机默认作为master节点。 1.Jenkins 添加node获取明文凭据 通过添加node节点,本地监听ssh认证,选则凭…...
如何实现不同MongoDB实例间的数据复制?
作为一种Schema Free文档数据库,MongoDB因其灵活的数据模型,支撑业务快速迭代研发,广受开发者欢迎并被广泛使用。在企业使用MongoDB承载应用的过程中,会因为业务上云/跨云/下云/跨机房迁移/跨地域迁移、或数据库版本升级、数据库整…...
微服务保护-隔离
个人名片: 博主:酒徒ᝰ. 个人简介:沉醉在酒中,借着一股酒劲,去拼搏一个未来。 本篇励志:三人行,必有我师焉。 本项目基于B站黑马程序员Java《SpringCloud微服务技术栈》,SpringCloud…...
报错:appium AttributeError: ‘NoneType‘ object has no attribute ‘to_capabilities‘
报错如下 Traceback (most recent call last):File "C:\Users\wlb\Desktop\test\python\2.py", line 16, in <module>driver webdriver.Remote("http://127.0.0.1:4723/wd/hub", caps)File "D:\software\python3\lib\site-packages\appium\we…...
MFC - 一文带你从小白到项目应用(全套1)
文章篇幅可能会比较长,从入门到基本能上项目的全部内容。建议观看的过程中,用电脑跟着学习案例。 持续输出优质文章是作者的追求,因为热爱,所以热爱。 最近看动漫被一句鸡汤感动到了,也送给各位朋友: 只要有…...
(2596. 检查骑士巡视方案leetcode,经典深搜)-------------------Java实现
(2596. 检查骑士巡视方案leetcode,经典深搜)-------------------Java实现 题目表述 骑士在一张 n x n 的棋盘上巡视。在 有效 的巡视方案中,骑士会从棋盘的 左上角 出发,并且访问棋盘上的每个格子 恰好一次 。 给你一个 n x n …...
Docker 部署 Bitwarden RS 服务
Bitwarden RS 服务是官方 Bitwarden server API 的 Rust 重构版。因为 Bitwarden RS 必须要通过 https 才能访问, 所以在开始下面的步骤之前, 建议先参考 《Ubuntu Nginx 配置 SSL 证书》 配置好域名和 https 访问。 部署 Bitwarden RS 拉取最新版本的 docker.io/vaultwarden…...
python与mongodb交互-->pymongo
from pymongo import MongoClient# 创建数据库连接对象 client=MongoClient(ip,27017)# 选择一个数据库 db=client[admin]db.authenticate(python,python)# 选择一个集合 col=client[pydata][test]col.insert({"class":"python"})col.find() for data in c…...
【网络】计算机网络基础
Linux网络 对网络的理解 在网络传输中存在的问题: 找到我们所需要传输的主机解决远距离数据传输丢失的问题怎么进行数据转发,路径选择的问题 有问题,就有解决方案; 我们把相同性质的问题放在一起,做出解决方案 解…...
(1)输入输出函数:cin和cout(2)数学函数:sqrt、pow、sin、cos、tan等
输入输出函数:cin 和 cout 在C编程语言中,为了与用户进行交互和显示程序的结果,我们使用了两个非常重要的函数:cin 和 cout。这两个函数分别用于输入和输出。 cin是C中的标准输入流对象,它用于从键盘接收用户的输入。…...
ArmSom-W3开发板之PCIE的开发指南(一)
1. 简介 RK3588从入门到精通本⽂介绍RK平台配置pcie的方法开发板:ArmSoM-W3 2、PCIE接口概述 PCIe(Peripheral Component Interconnect Express)是一种用于连接计算机内部组件的高速接口标准。以下是关于PCIe接口的简要介绍: …...
Android 13.0 framework修改AlertDialog对话框的button样式
1.概述 在13.0系统产品开发中 在AlertDialog 系统对话框原生的确定和取消 两个button 按钮中,由于产品觉得字体默认颜色的不太好看,由于产品的需求修改button字体的颜色,所以需要找到AlertDialog的字体样式然后修改就可以了 2.framework修改AlertDialog 对话框的button样式…...
如何使用ArcGIS Pro提取河网水系
DEM数据除了可以看三维地图和生成等高线之外,还可以用于水文分析,这里给大家介绍一下如何使用ArcGIS Pro通过水文分析提取河网水系,希望能对你有所帮助。 数据来源 本教程所使用的数据是从水经微图中下载的DEM数据,除了DEM数据&a…...
python pytesseract 中文文字批量识别
用pytesseract 来批量把图片转成文字 1、安装好 pytesseract 包 2、下载安装OCR https://download.csdn.net/download/m0_37622302/88348824https://download.csdn.net/download/m0_37622302/88348824 Index of /tesseracthttps://digi.bib.uni-mannheim.de/tesseract/ 我是…...
建设网站 翻译/网站seo关键词设置
最近负责的邮箱系统项目中有一个这样的需求:提供一个接口给业务层,可以通过邮箱查询到该用户的未读邮件个数。 之前的方案是通过查看用户目录下.INBOX/new目录中的文件个数,但是这个方法不准确,当有用户连接到邮箱服务器时&#x…...
长沙广告网络公司/怎么进行seo
2019独角兽企业重金招聘Python工程师标准>>> 1. EXPLAIN简介 使用EXPLAIN关键字可以模拟优化器执行SQL查询语句,从而知道MySQL是如何处理你的SQL语句的。分析你的查询语句或是表结构的性能瓶颈。 ➤ 通过EXPLAIN,我们可以分析出以下结果&…...
公司网站设计很好的/网络营销工具包括
浑浑噩噩已经走了这么长时间了,那么,留下点什么吧。 一种积累,一种出口。 转载于:https://www.cnblogs.com/Peong/p/10438157.html...
海尔网站建设目标/长沙seo网站排名
Mosquitto库依赖libuuid和openssl库,所以我们在交叉编译Mosquitto之前需要先交叉编译他所需要的依赖库,这里作者已经把需要的源码都下载好了,大家可以在这个文档的目录下找到。不建议大家下载和我不一致的版本,可能会出问题。 mq…...
重庆网站开发商城/今天国际新闻最新消息
一、python语言基础 1.1变量变量.png 1.2数据类型数据类型.png 1.3序列 序列分类:可变序列list,不可变序列tuple、str。在python中,内建了6中序列:列表、元组、字符串、unicode字符串、buffer对象、xrange对象。 (1)list列表list列…...
做策划的网站推广/网站排名掉了怎么恢复
地图图像服务(ImageryService)提供了根据地理位置(经度和纬度)坐标和地图的缩放级别解析出对应于地图图片系统的完整地图数据元数据,包括图片映射地址、图片大小等一系列详细参数。通过该服务的服务接口也可以反向实现…...