博客系统(升级(Spring))(四)(完)基本功能(阅读,修改,添加,删除文章)(附带项目)

news2024/11/22 13:19:45

博客系统 (三)

  • 博客系统
  • 博客主页
    • 前端
    • 后端
    • 个人博客
      • 前端
      • 后端
        • 显示个人文章
        • 删除文章
    • 修改文章
      • 前端
      • 后端
        • 提取文章
        • 修改文章
      • 显示正文内容
        • 前端
        • 后端
        • 文章阅读量功能
  • 添加文章
    • 前端
    • 后端
  • 如何使用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 {
    @Autowired
    private ArticleMapper articleMapper;

    public List<Articleinfo> getListByPage (int psize,int offset){
        return articleMapper.getListByPage(psize, offset);
    } 
}

通过Controller层调用service层方法

@RestController
@RequestMapping("/article")
public class ArticleController {
    @Autowired
    private ArticleService articleService;

    @Resource
    private 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 {
    @Autowired
    private ArticleMapper articleMapper;

    
    public List<Articleinfo> getUidByArticle(int uid){
        return articleMapper.getUidByArticle(uid);
    }
}

调用Controller 层调用service层

@RestController
@RequestMapping("/article")
public class ArticleController {
    @Autowired
    private ArticleService articleService;

    @Resource
    private ThreadPoolTaskExecutor taskExecutor;

    @Resource
    private 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 {
    @Autowired
    private ArticleMapper articleMapper;

    
}

Controller层调用service
这个代码太多了我只展示主要代码

@RestController
@RequestMapping("/article")
public class ArticleController {
    @Autowired
    private ArticleService articleService;

    @Resource
    private 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(){
           //校验aid
           if(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 {
    @Autowired
    private ArticleMapper articleMapper;

    public Articleinfo getArtByaidAnduid(int aid,int uid){
        return articleMapper.getArtByaidAnduid(aid,uid);
    }
}

Controller层调用service

@RestController
@RequestMapping("/article")
public class ArticleController {
    @Autowired
    private ArticleService articleService;

    @Resource
    private ThreadPoolTaskExecutor taskExecutor;

    @Resource
    private 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 {
    @Autowired
    private ArticleMapper articleMapper;

    public int setArt(Articleinfo articleinfo){
        return articleMapper.setArt(articleinfo);
    }
}

Controller层调用service

@RestController
@RequestMapping("/article")
public class ArticleController {
    @Autowired
    private ArticleService articleService;

    @Resource
    private ThreadPoolTaskExecutor taskExecutor;

    @Resource
    private 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 {
    @Autowired
    private UserMapper userMapper;

    public UserinfoVO getUserByUid(int uid){
        return userMapper.getUserById(uid);
    }
}

ArticleService

@Service
public class ArticleService {
    @Autowired
    private ArticleMapper articleMapper;

    public Articleinfo readDetail(int aid){
        return articleMapper.readDetail(aid);
    }
}

Controller层调用service

ArticleController

@RestController
@RequestMapping("/article")
public class ArticleController {
    @Autowired
    private ArticleService articleService;

    @Resource
    private ThreadPoolTaskExecutor taskExecutor;

    @Resource
    private UserService userService;
    @Resource
    private 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 {
    @Autowired
    private ArticleMapper articleMapper;

    public int readArtCount(int aid){
        return articleMapper.readArtCount(aid);
    }
}

Controller层调用service

@RestController
@RequestMapping("/article")
public class ArticleController {
    @Autowired
    private ArticleService articleService;

    @Resource
    private ThreadPoolTaskExecutor taskExecutor;

    @Resource
    private UserService userService;
    @Resource
    private 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 {
    @Override
    public 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链接(实际调试完毕的项目)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1010294.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Activity生命周期递归问题查看

这类问题一般比较难分析&#xff0c;符合以下情况的才有可能分析出来&#xff1a; 能够复现并调试有问题时的堆栈以及对应的event log TaskFragment#shouldSleepActivities 方法导致递归 There is a recursion among check for sleep and complete pause during sleeping 关…

dlib库详解及Python环境安装指南

dlib是一个开源的机器学习库&#xff0c;它包含了众多的机器学习算法&#xff0c;例如分类、回归、聚类等。此外&#xff0c;dlib还包含了众多的数据处理、模型训练等工具&#xff0c;使得其在机器学习领域被广泛应用。本文将详细介绍dlib库的基本概念、功能&#xff0c;以及如…

删除数据库

MySQL从小白到总裁完整教程目录:https://blog.csdn.net/weixin_67859959/article/details/129334507?spm1001.2014.3001.5502 语法格式: drop database 数据库名称;这个命令谨慎使用,俗话说:删库跑路! 案列:删除testing数据库,并验证 mysql> show databases; -----------…

Kernel for SQL Database Recovery 21.1 Crack

SQL Server恢复工具 Kernel for SQL Database Recovery 21.1 具有针对不同 SQL Server 版本的全面恢复选项。它具有预览和选择功能来恢复精确的数据库对象。 好处 SQL 数据库恢复可为您带来多种好处。 完全恢复所有数据库组件 将损坏的 MDF/NDF 文件有效恢复到 Live SQL Serve…

HDMI 直通 ILA 调试实验

FPGA教程学习 第十四章 HDMI 直通 ILA 调试实验 文章目录 FPGA教程学习前言实验原理程序设计实验过程实验尝试总结TODO 前言 HDMI 输入直通到 HDMI 输出的显示&#xff0c;完成一个简单的 HDMI 输入输出检测。 实验原理 开发板 HDMI 输出接口芯片使用 ADV7511&#xff0c;HD…

【深度学习】 Python 和 NumPy 系列教程(廿二):Matplotlib详解:2、3d绘图类型(8)3D饼图(3D Pie Chart)

一、前言 Python是一种高级编程语言&#xff0c;由Guido van Rossum于1991年创建。它以简洁、易读的语法而闻名&#xff0c;并且具有强大的功能和广泛的应用领域。Python具有丰富的标准库和第三方库&#xff0c;可以用于开发各种类型的应用程序&#xff0c;包括Web开发、数据分…

期权交易保证金比例一般是多少?

期权交易是一种非常受欢迎的投资方式之一&#xff0c;它为期权市场带来了更为多样化和灵活化的交易形式。而其中的期权卖方保证金比例是期权交易中的一个重要指标&#xff0c;直接关系到投资者的风险与收益&#xff0c;下文介绍期权交易保证金比例一般是多少&#xff1f;本文来…

第六章 图 九、拓扑排序

一、AOV网 二、拓扑排序 删除入度为0的结点。 第一次遍历&#xff0c;入度为0的点为0和2&#xff0c;将他们加入排序序列0->2 第二次遍历&#xff0c;入度为0的点为1和4&#xff0c;将他们加入排序序列0->2->1->4 第三次遍历&#xff0c;入度为0的点为3&#xf…

【webrtc】VCMSessionInfo 合并一个可解码的帧

知乎大神的概括&#xff1a;VCMFrameBuffer 帧中包含VCMSessionInfo的处理&#xff0c;对VPX、h264(分析Nalus)的同一帧中的所有包进行过滤并进行完整帧组帧&#xff0c;用于sink给后续的解码。用于解码器的所以插入的数据都是VCMPacketframe_buffer指向一帧的起始数据地址&…

Django系列:Django简介与MTV架构体系概述

Django系列 Django简介与MTV架构体系概述 作者&#xff1a;李俊才 &#xff08;jcLee95&#xff09;&#xff1a;https://blog.csdn.net/qq_28550263 邮箱 &#xff1a;291148484163.com 本文地址&#xff1a;https://blog.csdn.net/qq_28550263/article/details/132890054 【介…

企业架构LNMP学习笔记43

memcached的使用&#xff1a; 命令行连接和操作&#xff1a; telnet连接使用&#xff1a; memcached默认使用启动服务占用tcp 11211端口&#xff0c;可以通过telnet进行连接使用。 安装telnet进行连接&#xff1a; 连接成功&#xff0c;敲击多次&#xff0c;如果看到error&…

Linux常用命令字典篇

Linux命令 1. 翻页查看文件 less [-N] 文件名&#xff1a;可以向后翻页&#xff0c;也可以向前翻页&#xff0c;-N表示显示行号 more 文件名&#xff1a;仅可以向后翻页 2. 端口占用信息查看 netstat -tunlp | grep 端口号&#xff1a;查看端口号对应的信息 lsof i: 端口号…

Marin说PCB之封装设计系列---(02)--异形焊盘的封装设计总结

每天下班回家看电视本来是一件很美好的事情&#xff0c;可是正当我磕着瓜子看着异人之下的时候&#xff0c;手机突然响起来了&#xff0c;我以为是我们组哪个同事找我呢。一接电话居然是我的老朋友陈世美陈总&#xff0c;江湖人称少妇杀手。给我打电话主要是说他最近遇到一个异…

vite和webpack的区别

vite和webpack的区别 1、前言2、Webpack2.1 Webpack简述2.2 Webpack常用插件 3、Vite3.1 Vite简述3.2 Vite插件推荐 4、区别4.1 开发模式不同4.2 打包效率不同4.3 插件生态不同4.4 配置复杂度不同4.5 热更新机制不同 5、总结 1、前言 Webpack和Vite是现代前端开发中非常重要的…

线性代数的本质(九)——二次型与合同

文章目录 二次型与合同二次型与标准型二次型的分类度量矩阵与合同 二次型与合同 二次型与标准型 Grant&#xff1a;二次型研究的是二次曲面在不同基下的坐标变换 由解析几何的知识&#xff0c;我们了解到二次函数的一次项和常数项只是对函数图像进行平移&#xff0c;并不会改变…

HSRP(热备份路由选择协议)的概念,原理与配置实验

作者&#xff1a;Insist-- 个人主页&#xff1a;insist--个人主页 梦想从未散场&#xff0c;传奇永不落幕&#xff0c;持续更新优质网络知识、Python知识、Linux知识以及各种小技巧&#xff0c;愿你我共同在CSDN进步 目录 一、了解HSRP协议 1. 什么是HSRP协议 2、HSRP协议的…

2023年主流固定资管理系统的特征

随着科技的不断发展&#xff0c;固定资产管理系统也在不断演进&#xff0c;以满足企业日益增长的管理需求。在2023年&#xff0c;主流固定资产管理系统将呈现出一些重要的特征&#xff0c;包括RFID功能、低代码平台功能和云计算功能。易点易动固定资产管理系统正是结合了这些特…

UWB芯片DW3000之PDOA测向实现源码

介绍 DW3000芯片的双天线端口特性可以测量无线输入信号的相位。当与天线响应的信息相结合时,这些信息可以用来帮助确定到达的方向和传输的位置。 根据设备的不同,将有一个或两个天线端口。具有两个天线端口的设备称为PDoA部件,而其他是非PDoA部件(见表1)。当涉及到到达相位…

算法分析与设计编程题 贪心算法

活动安排问题 题目描述 解题代码 vector<bool> greedySelector(vector<vector<int>>& intervals) {int n intervals.size();// 将活动区间按结束时间的从小到大排序auto cmp [](vector<int>& interval1, vector<int>& interval2…

(文末赠书)我为什么推荐应该人手一本《人月神话》

能点进来的朋友&#xff0c;说明你肯定是计算机工作的朋友或者对这本书正在仔细琢磨着的朋友。 文章目录 1、人人都会编程的时代&#xff0c;我们如何留存?2、小故事说明项目管理着为什么必看这本书3、如何评价《人月神话&#xff1a;纪念典藏版》4、本书的目录&#xff08;好…