当前位置: 首页 > news >正文

博客系统(升级(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>&nbsp; &nbsp; &nbsp; &nbsp;当前在第<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">查看全文 &gt;&gt;</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);}
}

解释:

  1. 我在页面中每页所展示两个文章。而 limit finalPsize offset offset 我定位为 finalPsize 为第 几 行,offset 显示几个数据(具体原则在我的myslq 文章中有体现)(LIMIT [位置偏移量,] 行数)
  2. 使用多线程可以避开,有读者写数据,有读者读数据的情况。并且可以以最快速度反应的客户端
  3. 这个线程池Spring提供的,线程池,可以不需要去设置参数。
  4. 第一个线程池用来查找页面每页的内容,第二个线程池用来查找文章的总数。

个人博客

前端

<!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">查看全文 &gt;&gt;</a>&nbsp;&nbsp;';creatHtml+='<a href="blog_edit.html?aid='+art.id+'" class="detail">修改 &gt;&gt;</a>&nbsp;&nbsp;';creatHtml+='<a οnclick="del('+art.id+')" class="detail">删除 &gt;&gt;</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))(四)(完)基本功能(阅读,修改,添加,删除文章)(附带项目)

博客系统 (三&#xff09; 博客系统博客主页前端后端个人博客前端后端显示个人文章删除文章 修改文章前端后端提取文章修改文章 显示正文内容前端后端文章阅读量功能 添加文章前端后端 如何使用Redis项目地点&#xff1a; 博客系统 博客系统是干什么的&#xff1f; CSDN就是一…...

常用的辅助类(必会)

1.CountDownLatch package com.kuang.add;import java.util.concurrent.CountDownLatch;//计数器 减法 public class CountDownLatchDemo {public static void main(String[] args) throws InterruptedException {//总数是6&#xff0c;必须要执行任务的时候&#xff0c;再使用…...

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在所有文件中查找某一个字符串 有时候我们需要在大量文件中查找某一个字符串&#xff0c;手工一个一个打开文件查找非常耗时&#xff0c;我们可以使用 find 和 xargs 两个命令来实现查找指定字符串。 命令详解 find <directory> -type f -name "*.c" |…...

WebSocket vs SSE: 实时数据推送到前端的选择与实现(详细)

Websocket和Server-Sent Events 对比推送数据给前端及各自的实现 二者对比WebSocket&#xff1a;Server-Sent Events (SSE)&#xff1a;选择 WebSocket 还是 SSE&#xff1a; Websocket 实现使用原生 WebSocket API&#xff1a;使用 Netty 创建 WebSocket&#xff1a;总结和选择…...

Redis从入门到精通(二:数据类型)

数据存储类型介绍 Redis 数据类型&#xff08;5种常用&#xff09; string hash list set sorted_set/zset&#xff08;应用性较低&#xff09; redis 数据存储格式 redis 自身是一个 Map&#xff0c;其中所有的数据都是采用 key : value 的形式存储 数据类型指的是存储的数据…...

基于SSM的珠宝首饰交易平台

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…...

4款视频号数据分析平台!

很多人在做视频号的时候就会有创作参考的需求&#xff0c;那么你们知道视频号中有哪些数据平台&#xff1f;今天就和大家来分享一下 接下来就总结一下视频号数据平台有哪些&#xff1f;排名不分前后。 1&#xff1a;视频号助手&#xff08;channels.weixin.qq.com&#xff09…...

【系统架构】什么是集群?为什么要使用集群架构?

什么是集群&#xff1f;为什么要使用集群架构&#xff1f; 1.什么是集群&#xff1f;2.为什么要使用集群&#xff1f;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显示试卷页面

试卷页面代码 在浏览器输入如下地址&#xff1a; http://localhost/examPageServlet 效果如下&#xff1a;...

视频监控系统/视频云存储EasyCVR接入国标GB28181设备无法播放设备录像,是什么原因?

安防视频监控平台EasyCVR支持将部署在监控现场的前端设备进行统一集中接入&#xff0c;可兼容多协议、多类型设备&#xff0c;管理员可选择任意一路或多路视频实时观看&#xff0c;视频画面支持单画面、多画面显示&#xff0c;视频窗口数量有1、4、9、16个可选&#xff0c;还能…...

四叶草clover配置工具:Clover Configurator for Mac

Clover Configurator是一款Mac上的工具&#xff0c;用于配置和优化Clover引导加载器。Clover引导加载器是一种用于启动macOS的开源引导加载器。它允许用户在启动时选择操作系统和配置启动选项。 Clover Configurator提供了一个可视化的界面&#xff0c;让用户可以轻松地编辑和…...

计算机网络第四章——网络层(中)

提示&#xff1a;待到山花烂漫时&#xff0c;她在丛中笑。 文章目录 需要加头加尾&#xff0c;其中头部最重要的就是加了IP地址和MAC地址&#xff08;也就是逻辑地址和物理地址&#xff09;集线器物理层设备&#xff0c;交换机是物理链路层的设备&#xff0c;如上图路由器左边就…...

时序分解 | MATLAB实现基于小波分解信号分解分量可视化

时序分解 | MATLAB实现基于小波分解信号分解分量可视化 目录 时序分解 | MATLAB实现基于小波分解信号分解分量可视化效果一览基本介绍程序设计参考资料 效果一览 基本介绍 基于小波分解的分量可视化&#xff0c;MATLAB编程程序&#xff0c;用于将信号分解成不同尺度和频率的子信…...

VMware虚拟化环境搭建

虚拟化环境搭建 1. 什么是虚拟化环境&#xff1f;未来工作中在何处使用&#xff1f; 在网络安全中&#xff0c;虚拟化环境是一种技术&#xff0c;它将一个物理计算机系统划分成多个独立、可管理的虚拟环境。这种虚拟环境技术允许多个完全不同的操作系统、显示装置和软件在同一…...

Jenkins :添加node权限获取凭据、执行命令

拥有Jenkins agent权限的账号可以对node节点进行操作&#xff0c;通过添加不同的node可以让流水线项目在不同的节点上运行&#xff0c;安装Jenkins的主机默认作为master节点。 1.Jenkins 添加node获取明文凭据 通过添加node节点&#xff0c;本地监听ssh认证&#xff0c;选则凭…...

如何实现不同MongoDB实例间的数据复制?

作为一种Schema Free文档数据库&#xff0c;MongoDB因其灵活的数据模型&#xff0c;支撑业务快速迭代研发&#xff0c;广受开发者欢迎并被广泛使用。在企业使用MongoDB承载应用的过程中&#xff0c;会因为业务上云/跨云/下云/跨机房迁移/跨地域迁移、或数据库版本升级、数据库整…...

微服务保护-隔离

个人名片&#xff1a; 博主&#xff1a;酒徒ᝰ. 个人简介&#xff1a;沉醉在酒中&#xff0c;借着一股酒劲&#xff0c;去拼搏一个未来。 本篇励志&#xff1a;三人行&#xff0c;必有我师焉。 本项目基于B站黑马程序员Java《SpringCloud微服务技术栈》&#xff0c;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…...

Python|GIF 解析与构建(5):手搓截屏和帧率控制

目录 Python&#xff5c;GIF 解析与构建&#xff08;5&#xff09;&#xff1a;手搓截屏和帧率控制 一、引言 二、技术实现&#xff1a;手搓截屏模块 2.1 核心原理 2.2 代码解析&#xff1a;ScreenshotData类 2.2.1 截图函数&#xff1a;capture_screen 三、技术实现&…...

51c自动驾驶~合集58

我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留&#xff0c;CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制&#xff08;CCA-Attention&#xff09;&#xff0c;…...

测试markdown--肇兴

day1&#xff1a; 1、去程&#xff1a;7:04 --11:32高铁 高铁右转上售票大厅2楼&#xff0c;穿过候车厅下一楼&#xff0c;上大巴车 &#xffe5;10/人 **2、到达&#xff1a;**12点多到达寨子&#xff0c;买门票&#xff0c;美团/抖音&#xff1a;&#xffe5;78人 3、中饭&a…...

第25节 Node.js 断言测试

Node.js的assert模块主要用于编写程序的单元测试时使用&#xff0c;通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试&#xff0c;通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...

视频字幕质量评估的大规模细粒度基准

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用&#xff0c;因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型&#xff08;VLMs&#xff09;在字幕生成方面…...

华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建

华为云FlexusDeepSeek征文&#xff5c;DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色&#xff0c;华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型&#xff0c;能助力我们轻松驾驭 DeepSeek-V3/R1&#xff0c;本文中将分享如何…...

让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比

在机器学习的回归分析中&#xff0c;损失函数的选择对模型性能具有决定性影响。均方误差&#xff08;MSE&#xff09;作为经典的损失函数&#xff0c;在处理干净数据时表现优异&#xff0c;但在面对包含异常值的噪声数据时&#xff0c;其对大误差的二次惩罚机制往往导致模型参数…...

面向无人机海岸带生态系统监测的语义分割基准数据集

描述&#xff1a;海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而&#xff0c;目前该领域仍面临一个挑战&#xff0c;即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...

深度剖析 DeepSeek 开源模型部署与应用:策略、权衡与未来走向

在人工智能技术呈指数级发展的当下&#xff0c;大模型已然成为推动各行业变革的核心驱动力。DeepSeek 开源模型以其卓越的性能和灵活的开源特性&#xff0c;吸引了众多企业与开发者的目光。如何高效且合理地部署与运用 DeepSeek 模型&#xff0c;成为释放其巨大潜力的关键所在&…...

保姆级【快数学会Android端“动画“】+ 实现补间动画和逐帧动画!!!

目录 补间动画 1.创建资源文件夹 2.设置文件夹类型 3.创建.xml文件 4.样式设计 5.动画设置 6.动画的实现 内容拓展 7.在原基础上继续添加.xml文件 8.xml代码编写 (1)rotate_anim (2)scale_anim (3)translate_anim 9.MainActivity.java代码汇总 10.效果展示 逐帧…...