博客系统(后端编程)

这里还是这四个页面:

博客列表页

博客详情页

登录页

博客编辑页

一、准备工作:

1.引入依赖

引入mysql,servlet,jackson的依赖,并且把之前的前端页面拷贝进去.

2.创建目录

 并且把相关代码复制进去.

此时目录就完成了!!!

3.复制前端代码

 直接ctrl+v我们之前的前端代码到webapp目录即可!!!

二、设计数据库

结合我们的需求,我们可以发现在当前的博客实体中,主要设计两个实体:

博客,用户

所以我们要创建两个表:

设计表首先要确定:实体,关系

实体是用户和博客,关系是一对多(一个用户可以写多篇博客,而一片博客只能属于一个用户).

blog(blogId,title,content,postTime,useId)

user(userId,username,password)

三、数据库的创建

首先创建一个db.sql文件留存我们的数据库文件以观后用. 

此时这两张表就创建好了!!!


接下来是数据库的封装操作:
 

public class DBUtil {
    private static DataSource dataSource=new MysqlDataSource();
    static {
        ((MysqlDataSource) dataSource).setUrl("jdbc:mysql://127.0.0.1/3306/blog_system?characterEncoding=utf8&useSSL=false");
        ((MysqlDataSource) dataSource).setUser("root");
        ((MysqlDataSource) dataSource).setPassword("111111");
    }
    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }
    public static void close(Connection connection, PreparedStatement statement, ResultSet resultSet){
        if(resultSet!=null){
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(statement!=null){
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(connection!=null){
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

之后就是创建实体类了(和表中的记录对应的类):

其实为的是把表中的数据提取出来,所以实体类的元素是和表的结构密切相关的.

 之后就是进行数据库增删改查的封装了:

针对博客表,创建BlogDao.

针对用户表创建UserDao.

这个Dao就是Data Access Object的缩写,意思是这是一个用来访问数据的对象. 

接下来就是"增删改查"的编写了:

 首先是"增":

接下来是"查ID" :

接下来是"查全部":

 

//3.直接查询出数据库中所有的博客列表(用于博客列表页)
    public List<Blog> selectAll(){
        List<Blog> blogs=new ArrayList<>();

        Connection connection=null;
        PreparedStatement statement=null;
        ResultSet resultSet=null;
        try {
            //1.与数据库建立连接
            connection=DBUtil.getConnection();
            //2.构造sql语句
            String sql="select * from blog";
            statement=connection.prepareStatement(sql);
            //3.执行sql语句
            resultSet=statement.executeQuery();
            //4.遍历结果
            while(resultSet.next()){
                Blog blog=new Blog();
                blog.setBlogId(resultSet.getInt("blogId"));
                blog.setTitle(resultSet.getString("title"));
                //注意此处的content是不能在博客列表页中显示全部内容的.所以要判断长度,返回指定长度
                String content=resultSet.getString("content");
                if(content.length()>=100){
                    content=content.substring(1,100)+"...";
                }
                blog.setContent(content);
                blog.setPostTime(resultSet.getTimestamp("postTime"));
                blog.setUserId(resultSet.getInt("userId"));
                blogs.add(blog);

            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            DBUtil.close(connection,statement,resultSet);
        }
        return blogs;
    }

 最后就是"删除":

之后是UserDao的代码编写:

 和上述几乎一致,不需要用脑.

此时我们的准备工作基本完成,接下来就是真正的后端代码的编写了:

 首先是围绕"博客列表页"进行后端的编程:

 当前博客列表页的内容都是写死的.正确的做法是通过数据库读取数据显示到页面上去

我们实现这个功能的基本思路就是:

让博客列表页在加载的时候,通过ajax给服务器发送一个请求.服务器在查数据库数据获取到博客列表数据,返回给浏览器浏览器再根据数据构造页面.

这样的交互过程,也被称为是"前后端分离",前端只向后端请求数据,而不请求页面的具体内容.后端也仅仅是返回数据.

这样设定的目的就是使前端和后端更加的"解耦合".

(之前的网站都是直接让服务器把一个完整的页面拼装好,然后把整个页面返回给浏览器(服务器渲染))

上述是实现博客列表页的基本思路!!!

接下来需要:

1.约定前后端交互接口

我们要确定前端要发什么内容,和后端要回应什么内容.

程序设计:

请求:GET/blog

响应:(使用json格式的数据来组织)(数组)

[

       {

             blogId:1,

             title:"这是一篇博客",

             content:"从今天开始我要开始写代码了!!!",

             postTime:"2023-4-4  21:05:00",

             userId:1

        }

]

这是我们设计的传输数据的格式(当然使用其他的格式也是可以的!!!)

2.开发后端代码

首先创建BlogServlet类:

具体原理就是将存储的字符串格式转化为json格式然后传给前端网站.

有点乱整理一下目录:

  

3.开发前端代码

在博客列表页的加载过程中,触发ajax,访问服务器中的数据.

再把拿到的数据构造到页面中.

首先引入jquery:

因为之前在写前端程序的时候再文件夹中引入了jqueryMin所以现在我们可以直接引入文件夹的就可以了,不需要引入网络链接.

接下来就是依照之前的代码格式,将其以js的格式实现出来:

<script src="./js/jqueryMin.js"></script>
    <script>
        function getBlog(){
            $.ajax({
                type:'get',
                url:'blog',
                //注意这里是我们之前自己设置的接收json格式的数组,
                //所以自然也需要循环读取每一个键值对
                success:function(body){
                    for(let blog of body){
                        //构造整个博客div
                        let blogDiv=document.createElement('div');
                        blogDiv.className='blog';
                        //构造title的div
                        let titleDiv=document.createElement('div');
                        titleDiv.className='title';
                        titleDiv.innerHTML=blog.title;
                        blogDiv.appendChild(titleDiv);
                        //构造发布时间的div
                        let dateDiv=document.createElement('div');
                        dateDiv.className='date';
                        dateDiv.innerHTML=blog.postTime;
                        blogDiv.appendChild(dateDiv);
                        //构造全文摘要部分
                        let descDiv=document.createElement('div');
                        descDiv.className='desc';
                        descDiv.innerHTML=blog.content;
                        blogDiv.appendChild(descDiv);
                        //构造查看全文按钮
                        let a=document.createElement('a');
                        a.innerHTML='查看全文 &gt; &gt;';
                        //这里我们希望的是点击按钮之后实现页面之间的跳转
                        //但是这里我们还是需要把用户信息给传到博客详情页去.
                        a.href='blogDetail.html?blogId='+blog.blogId;
                        blogDiv.appendChild(a);
                    }
                }
            });
        }
    </script>

 之后还有一步将我们现在写的代码挂到父类之上:

注意:此处以后我们学习了框架之后会大量的简化代码. 

此时我们的博客列表页也就写的差不多了!!!

启动Tomcat看看效果

 此时没有东西是正常的,因为此时数据库没有数据!!

如果想要测试可以自行添加数据:

另外,此时的博客列表页的发布时间是由bug的,所以我们要进行发布时间返回值的重构(这个直接搜一下就有): 

 

此时博客列表页也就完成了!!!

接下来就是实现博客详情页的功能:

具体流程:

点击"查看全文"按钮,就能跳转到博客详情页中去,跳转过去后在博客详情页发起一个ajax标签,从服务器获取到当前博客的内容.

1.约定前端后端接口

请求:

GET/blog?blogId=1

这里的blog路径和博客列表页是同一个,此处是不是同一个其实都可以,约定成同一个就直接在BlogServlet中进行修改.约定成不同路径,就创建新类然后重新写一个.

注意:这里的请求中是有query string的,因为需要去索取指定博客id.

响应:

HTTP/1.1 200 OK

{

    blogId:1,

    title:"这是第一篇博客",

    content:"从今天起我要开始写博客了!",

    postTime:"2023-04-20:00:00",

    userId:1

}

此时请求与响应的格式就已经约定完成了.接下来我们要进行后端代码的编写了:

2.实现后端代码

实现是通过queryString过去blogId,然后尝试去判断blogId

 我们只需要使用blogId获取selectById中的blog就可以实现博客的获取了:

注意:此处的getParameter返回的不是一个整数,而是一个字符串,所以我们这里要首先将其转换为一个整数.

此处我们获取到了blog,现在就需要把这个blog使用jackson转换为json格式然后再发给前端:

 此时后端的代码也就搞定了!!!

3.实现前端代码

首先我们删除之前所编写的所有固定内容:

接下来,就是在BlogDetail.html中加入ajax,来获取上述数据.

 注意理解这里的location.search

这个 location.search是用来获取queryString的.

而这个queryString是来自我们的博客列表页:

此时,我们的服务器就可以得知blogId了,就可以指定blogId进行博客的搜索了!!! 

接下来是页面中一些标签的设定:

首先是标题与日期更新:

 然后是博客正文更新:

 注意一点:这里的博客是使用markdown编译器进行的编译,而markdown中有很多类似' # '之类的有特殊意义的字符,而我们想在博客详情页中展示的是右边经过熏染完成了的部分,所以这里我们要借助editor.md中提供的editormd.markdownToHTML这个方法把md字符串转化为html片段.

这里我们的editormd.markdownToHTML只能识别id选择器,其他的它看不懂!!!

在使用方法之前我们还要引入mditor.md的依赖:

 然后就是博客正文部分的更新:

 此处就是完成了一个格式的转换!!

此时我们的博客详情页的前端+后端其实就写完了,但当我们运行的时候:

发现有bug 此处开始改bug

首先是它:

 这个favicon.ico其实就是浏览器的图标

 就是这个东西,因为我们这里没有设置,所以无伤大雅,它访问不到很正常!!!

这里推荐一个阿里的图标库:iconfont-阿里巴巴矢量图标库

之后就是它了:

 

点进去发现,其实就是body写成了blog 

 修改完成后,我们发现标题没出来:

 这里我们发现我们的博客题目和title不太对劲,所以看看前端代码:

我们发现导航栏和标题都是"title"所以才出现了问题.

只要让这个选择器更加精确一点:

这样就大功告成了!!!

接下来就是登录页的实现了:

此处的输入用户名和密码点击登录,就会触发一个http请求.服务器验证用户名和密码,然后就可以根据结果,判断是否登录成功.

现在只是一个单纯的输入框,需要改成from表单才能进行信息的提交.

1.前后端交互接口

请求:

POST/login

username=zhangsan&password=123

响应:

HTTP/1.1 302

Location:blogList.html 

注意:这里需要使用form表单的形式然后返回302才能进行页面的跳转.

2.修改前端代码 

我们的任务是加上form表单,让数据能够进行交互.

以上是修改的内容

  此时使用fiddler进行抓包,发现此时的请求和我们要求的一致. 

3.修改后端代码

此处就需要一个servlet来处理登录请求.

package api;

import model.User;
import model.UserDao;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 86139
 * Date: 2023-04-12
 * Time: 16:03
 */
@WebServlet("/login")
public class LogInServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //此处是告诉servlet以怎样的格式去理解请求
        req.setCharacterEncoding("utf8");
        //此处是告诉servlet以怎样的格式来构造响应
//        resp.setCharacterEncoding("utf8");
        resp.setContentType("text/html;charset=utf8");
        //1.读取参数中的用户名和密码
        String username=req.getParameter("username");
        String password=req.getParameter("password");
        if(username==null || "".equals(username) || password == null || "".equals(password)){
            String html="<h3>登录失败!缺少 username 或者 password 字段</h3>";
            resp.getWriter().write(html);
            return;
        }
        //2.读一下数据库看一下,用户名是否存在,并且密码是否匹配
        UserDao userDao=new UserDao();
        User user=userDao.selectByUsername(username);
        if(user == null){
            String html="<h3>登录失败,用户名或者密码错误!!!</h3>";
            resp.getWriter().write(html);
            return;
        }
        if(!password.equals(user.getPassword())){
            String html="<h3>登录失败,用户名或者密码错误!!!</h3>";
            resp.getWriter().write(html);
            return;
        }
        //3.用户名密码验证通过,登陆成功,接下来创建会话,使用该会话保存用户信息.
        HttpSession session=req.getSession(true);
        session.setAttribute("user",user);
        //4.进行重定向,跳转到博客列表页
        resp.sendRedirect("blogList.html");
    }
}

这段代码和之前的登录案例几乎一致,过多的就不再描述了.

注意如果此时尝试登录的话是无法成功的,因为数据库中压根就没有你的数据,所以要先添加数据:

 

此时就正常登录了!!!

之后我们来实现强制要求登录功能:

 当用户访问 博客列表页/详情页/编辑页的时候,要求用户必须是已经登录的状态.

如果用户还没登录,就会强制跳转到登录页面.

实现思路:

在页面加载的时候,专门发起一个新的ajax(一个页面可以发N个ajax请求)

如果是在博客列表页

会先发起一个请求获取博客列表页,再发一个ajax获取用户的登录状态,如果此时用户已经登录,相安无事,如果未登录,则跳转到页面登录页.

1.约定前后端交互接口

请求:

GET/login

响应:

HTTP/1.1 200 OK

{

         userId:1,

         username:'zhangsan'

}

2.实现后端代码

注意:此处的存与取是遥相呼应的.是因为之前存了,所以这里才能取,就是把这个session当做了一个map,存放键值对,此处是在取键值对.

 此时后端代码就完成了!!!

3.实现前端代码

 注意:此处的location.assign()就是属于一个前端的强制跳转方法.

此处就相当于一个简单的强制跳转的代码格式.需要把这段代码粘贴到个页面,之后就大功告成了!!!

此时如果我们重新启动服务器,然后访问博客列表页,就会自动跳转到登录页面:

 

重启服务器就会重置所有的sessionId 

 之后就是用户信息部分的编写了:

也就是这一部分,要实现两个功能:

1.如果是博客列表页,此处显示登录用户的信息.

2.如果是博客详情页,此处显示的是该文章的作者. 

还是老三套:

1.约定前后端交互接口(这里可以直接复用检测登录状态的接口)

博客列表页:

请求:

GET/login

响应:

HTTP/1.1 200 OK

{

      userId:1,

      username:'zhangsan',

      password:'123'

}

博客详情页:

请求:

GET/author?blogId=1

响应:

HTTP/1.1 200 OK

{

          userId:1,

          username:'zhangsan',

          password:'123'

}

2.修改前端代码

 利用选择器找到指定标签,然后实现文件内容的修改.

之后就是博客详情页的用户信息了:

在这里抓住一点,就是什么时候要写一个新的servlet呢?

每个servlet都是绑定一个路径的,什么时候需要新写一个访问路径的时候,就多写一个servlet.

 1.修改后端代码:

2.修改前端代码

 就是根据选择器选中名字,然后根据收到的数据修改用户姓名.

我们可以看到,现在是以lisi的账号进去的

 但是查询的确实zhangsan的博客:

之后就是注销功能了:

这里的注销当然不是消除账户了,只是退出登录

判断登录状态:

1.看是否能查到http session对象.

2.看session对象里面有没有user

这里的注销其实就是:

删除其中任何一个都是注销了.

但是HTTPsession对象想要删除,很难,getSession只有过去和创建会话,但不能删除.

所以这里我们选择把user干掉.使用removeAttribute 

还是三板斧

1.约定前后端接口

请求:

GET/blogOut

响应:

HTTP/1.1 302

location:blogIn.html

2.修改后端代码

其实就是一个删除逻辑,尝试获取会话,如果没有就直接显示未登录,如果有就删除然后跳转到登录页面.

3.修改前端代码

其实就是改一下导航栏的链接

 此时注销功能也就完成了:

最后一个功能就是发布博客:

主要还是博客编辑页的编写

此时写好一片博客后,点击发布博客,没有任何效果.依旧是三板斧

1.约定前后端交互接口 

这里我们依旧使用form表单进行实现

首先我们要明确:

一片博客

blogId                   自增主键,自己生成

title                       

content

userId                   作者信息,可以从提交博客的人获取

postTime              当前时刻

所以说需要前后端交互的信息只有title与content.

请求:

POST/blog

title=这是标题&content=这个是正文

响应:

HTTP/1.1 302

Location:blogList.html

2.编写服务器代码

此处的的代码在blogservlet里进行编写用blog统一调用.

 看着挺长其实就是根据逻辑进行编写.

 @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //实现发布博客功能
        //读取请求,构造 Blog 对象,插入数据库中即可

        HttpSession httpSession=req.getSession(false);
        if(httpSession == null){
            resp.setContentType("text/html; charset=utf8");
            resp.getWriter().write("当前未登录,无法发布博客!!!");
            return;
        }
        User user=(User) httpSession.getAttribute("user");
        if(user == null){
            resp.setContentType("text/html; charset=utf8");
            resp.getWriter().write("当前未登录,无法发布博客!!!");
            return;
        }
        //确保登录之后,就可以把作者给拿到了

        //获取博客标题和正文
        String title=req.getParameter("title");
        String content=req.getParameter("content");
        if(title == null || "".equals(title) || content == null || "".equals(content)){
            resp.setContentType("text/html; charset=utf8");
            resp.getWriter().write("当前提交数据有误! 标题或正文部分为空!");
            return;
        }

        //构造 blog 对象
        Blog blog=new Blog();
        blog.setTitle(title);
        blog.setContent(content);
        blog.setUserId(user.getUserId());
        //当前发布时间我们可以在Java中生成也可以在数据库中生成
        blog.setPostTime(new Timestamp(System.currentTimeMillis()));
        //插入数据库库
        BlogDao blogDao=new BlogDao();
        blogDao.add(blog);

        resp.sendRedirect("blogList.html");
    }

3.编写客户端代码

把页面改造一下,能够构造出请求并且发送即可.

 这是我们对前端博客编辑页的修改,1.加上form标签 2.加上name属性   3.把button改成input标签type submit  4.textarea这是editor.md对于form表单要求的写法(其功能就是把用户输入的markdown 内容自动的放入一个隐藏的textarea里面)这样后续点击submit就能够自动提交了

这里的display: none就是把内容隐藏不显示出来.

此时启动服务器:

发现此时是有bug的

发开开发者工具,发现此时控制页面大小的是

 

 

此处的编写代码页大小使用的是100%-50px,而这里的100%是其父元素的100%. 

但加了form后,是代码编写块的父元素成为了form,所以才会出现此bug.将form标签的大小也设置成100%就可以了!!!

 此时就OK了!!!

 此时随便发布一篇博客,点击提交:

 发现乱码了!!!

这里的乱码一定是字符集的问题导致的,所以我们此时可以看看数据库中存放的内容,如果也是乱码,那么就是服务器读取的时候出现了问题:

 

此时就是正常的了!!!

此时博客系统就完成了!!!

当然还可以扩展很多其他的功能:

1.上传头像

2.删除博客

3.修改博客

......

 

 该讲得东西都讲过了,之后想要继续扩展也可以自行进行实现了!!!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值