博客管理系统--博客列表页

准备工作

博客管理系统前端部分在学习前端、css、js部分实现;现在我们将完成后端工作;并且部署云服务上;使其能让所有联网的人使用。
创建maven项目;先导入三个依赖;jackson;mysql;servlet;

 <dependencies>
        <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.14.1</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.49</version>
        </dependency>
    </dependencies>

把前端代码;复制进去webapp;如果直接复制blog到时候代码结构比较难写路径;所以直接把这里面复制进去简单
在这里插入图片描述

还有给tomcat的投名状;不然怎么让tomcat带着我们项目跑呢;
在这里插入图片描述

设计数据库

分析:博客系统涉及两个实体;博客、用户。创建两张表;表示博客和用户;关系是一对多:一个用户可以写多篇博客;一个博客只能属于一个用户。
blog(blogId,title,content,postTime,userId)
user(userId,username,password)
有了上次表白墙的经验:这一次就知道把sql语句保存在文件里;当我们要部署云服务器上直接复制、粘贴就能完成建库建表操作。

-- 写sql语句;把这些保存下来;当需要部署在其它机器就直接复制粘贴即可

create database if not exists liao_blog;
--删除旧;创建新的;防止之前的残留数据对我们的影响;严谨起见
--创建这个数据库和选中这个数据库
use liao_blog;

drop table if exists user;
drop table if exists blog;

--创建表;
create table blog(
--设置主键
blogId int primary key auto_incremaet,
title varchar(128),
--正文
content varchar(4096),
--发布时间
postTome datetime,
userId int

);

create table user(
userId int primary key auto_incremaet,
username varchar(20) unique,--要求用户名不重复
password varchar(20)

);

封装数据库操作

前面的数据库版本表白墙程序也是有这个操作:一模一样的代码封装;以后我们使用的是框架;不需要再像这样子手动封装。


import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

//数据库的连接;把连接的过程封装一下;作为工具类;提供一些static让我们使用更方便
public class DBlianjie {
    
    
//    静态成员相当于饿汉单例模式
public static DataSource dataSource=new MysqlDataSource();

//初始化DataSource
static {
    
    

    ((MysqlDataSource)dataSource).setURL("jdbc:mysql://127.0.0.1:3306/liao?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){
    
    

        // 此处的三个 try catch 分开写更好, 避免前面的异常导致后面的代码不能执行.
        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();
            }
        }

    }

}

创建实体类

实体类:和表中的记录对应的类;和表的结构 (列)密切相关
blog表:Blog类对应的一个对象;对应是表中的一条记录;就是一篇博客。
user表:User类对应的一个对象;对应是表中的一个记录;就是一个用户

import java.sql.Timestamp;
//都生成get和set方法;用来获取博客的内容。
public class Blog {
    
    
    private int blogId;
    private   String tatle;
    private String content;
    private Timestamp postTimel;
    private int userId;

    public int getBlogId() {
    
    
        return blogId;
    }

    public void setBlogId(int blogId) {
    
    
        this.blogId = blogId;
    }

    public String getTatle() {
    
    
        return tatle;
    }

    public void setTatle(String tatle) {
    
    
        this.tatle = tatle;
    }

    public String getContent() {
    
    
        return content;
    }

    public void setContent(String content) {
    
    
        this.content = content;
    }

    public Timestamp getPostTimel() {
    
    
        return postTimel;
    }

    public void setPostTimel(Timestamp postTimel) {
    
    
        this.postTimel = postTimel;
    }

    public int getUserId() {
    
    
        return userId;
    }

    public void setUserId(int userId) {
    
    
        this.userId = userId;
    }
}

public class User {
    
    
    private int userId;
    private String username;
    private String password;

    public int getUserId() {
    
    
        return userId;
    }

    public void setUserId(int userId) {
    
    
        this.userId = userId;
    }

    public String getUsername() {
    
    
        return username;
    }

    public void setUsername(String username) {
    
    
        this.username = username;
    }

    public String getPassword() {
    
    
        return password;
    }

    public void setPassword(String password) {
    
    
        this.password = password;
    }
}

数据库增删查改操作(写法几乎很相似)

我们需要想清楚;哪些需要存数据在数据库;哪里需要从数据库取数据库;存的时候传blog对象是存的对象。取的时候就把数据赋值于一个blog对象;到时候我们根据这个方法获取到这个对象就能取到我们想要的东西。
(比如点击发布文章;点击查看全文;博客列表页的内容;删除博客)我们通过的就是实体类来当一个中介的角色;要存什么放这个类的对象里再存;要取什么取到的结果放这个对象里。
Dao:Data Access Object访问数据的对象。
博客表:创建BlogDao
用户表:创建UserDao

import java.util.List;

//通过这个类对博客表的基本操作
public class BlogDao {
    
    
   //1.新增博客
        public void add(Blog blog){
    
    
            //这两个的声明在这里为了提升作用域;免得在finally里没法用这个对象.
            Connection connection=null;
            PreparedStatement statement=null;
            try{
    
    
                //1:创建数据库连接
                connection=DBlianjie.getConnection();
                //2:构造sql;自增主键不用我们设置;所以就是null;

                String sql="insert into blog values(null,?,?,?,?)";
                //进行替换;来源;存的过程我们要在Blog获取。
                // Blog的初始化内容来自用户前端博客;就是我们调用这个方法;会传一个Blog对象;是已经初始化后的
                statement.setString(1,blog.getTitle());
                statement.setString(2,blog.getContent());
                statement.setTimestamp(3,blog.getPostTimel());
                statement.setInt(4,blog.getUserId());
                //3:执行sql;把这个东西存到数据库
                statement.executeUpdate();
            }catch (SQLException e){
    
    
                e.printStackTrace();
            }finally {
    
    
                //4:释放资源;没用到的写null
                DBlianjie.close(connection,statement,null);
            }
        }



 // 2.根据博客id查询指定博客(博客详情页);
        // 就是对应我们查看全文的按钮后显示结果(相当于从数据库取东西;根据博客id进行条件查询想要的博客)
        public  Blog selectById(int blogId){
    
    
           Connection connection=null;
           PreparedStatement statement=null;
            ResultSet resultSet=null;
            try{
    
    
//                //1:建立连接
                connection=DBlianjie.getConnection();
                //2:构造sql
                String sql = "select * from blog where blogId = ?";
                statement=connection.prepareStatement(sql);
//                //进行替换
                statement.setInt(1,blogId);
                //3:执行
                resultSet = statement.executeQuery();
                // 4. 遍历结果集合. 由于 blogId 在 blog 表中是唯一的. (主键);
                // 说明我们这里查到数据只可能是一条;不需要循环。if就好了;
                // 我们就把结果用来初始化一个blog对象;进行返回。我们就根据这个对象获取里面博客的内容
                if(resultSet.next()){
    
    
                    Blog blog = new Blog();
                    blog.setBlogId(resultSet.getInt("blogId"));
                    blog.setTitle(resultSet.getString("title"));
                    blog.setContent(resultSet.getString("content"));
                    blog.setPostTime(resultSet.getTimestamp("postTime"));
                    blog.setUserId(resultSet.getInt("userId"));
                    return blog;


                }

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

            }
            //没有查到这个博客id的博客
       return null;
        }







        // 3.查询数据库中的所以博客列表(博客列表页)
        public List<Blog> selectAll(){
    
    
            Connection connection=null;
            PreparedStatement statement=null;
            ResultSet resultSet=null;
            //创建一个list储存这很多篇博客
             List<Blog> blogs=new ArrayList<>();
            try {
    
    
            //1:建立连接
            connection=DBlianjie.getConnection();
            //2:构造sql语句;这里是查询所有博客的内容取前100个字进行摘要;所以是全列查询
                String sql="select * from blog";
              statement= connection.prepareStatement(sql);
                //3:执行sql
                resultSet=statement.executeQuery();

                //4:遍历结果集;把遍历的结果每一篇都放一个blog对象;
                // 每循环一次就创建这样子的一个对象;最后放list<blog>

                while (resultSet.next()){
    
    
                    Blog blog=new Blog();
                    blog.setBlogId(resultSet.getInt("blogId"));
                    blog.setTitle(resultSet.getString("title"));
                 //这里正文部分;因为是粗略显示;全部显示是在博客详情页;所以我们对读取的内容进行截取
                      String content=resultSet.getString("content");
                  if(content.length()>=100){
    
    
                      content=content.substring(0,100)+" ……";
                  }
                  blog.setContent(content);
                  blog.setPostTime(resultSet.getTimestamp("postTime"));
                  blog.setUserId(resultSet.getInt("userId"));
                  blogs.add(blog);
                }
            }catch (SQLException e){
    
    

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

        }




        //4.删除指定博客
        public void delete(int blogId){
    
    
       Connection connection=null;
       PreparedStatement statement=null;
       try{
    
    
           //1:建立连接
           connection=DBlianjie.getConnection();
           //2:构造sql
           String sql="delete from blog where blogId=?";
           statement=connection.prepareStatement(sql);

           //3:执行sql
            statement.executeUpdate();


       }catch (SQLException e){
    
    
           e.printStackTrace();

       }finally {
    
    
           DBlianjie.close(connection,statement,null);
       }



}


// 暂时不涉及修改博客;(修改、可以通过删除和新增;前端没有这样的功能)

}

userDao:这个实体类的对应是和创建表时的密切相关

在这里插入图片描述
因为当前注册功能待开发中:注册和登录实现差不多;先不搞add先;也没有用户删号功能. 也就不必 delete

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

//针对用户表的基本操作
public class UserDao {
    
    
    // 1. 根据 userId 来查用户信息;我好像还不知道这个是干嘛的;后面就知道了
    public  User selectById(int userId){
    
    
        Connection connection=null;
        PreparedStatement statement=null;
        ResultSet resultSet=null;

        try{
    
    
            //1:建立连接
            connection =DBlianjie.getConnection();
            //2:构造sql
            String sql="select * from user where userId=?";
            statement=connection.prepareStatement(sql);
            statement.setInt(1,userId);
            //3:执行sql
            resultSet=statement.executeQuery();
            //4:遍历结果集;一条记录还是用if就可以
            if(resultSet.next()){
    
    
                User user=new User();
                user.setUserId(resultSet.getInt("userId"));
                user.setUsername(resultSet.getString("username"));
                user.setPassword(resultSet.getString("password"));
                return user;

            }
        }catch (SQLException e){
    
    
            e.printStackTrace();


        }finally {
    
    
            DBlianjie.close(connection, statement, resultSet);
        }
        return null;

    }

    // 2. 根据 username 来查用户信息 (登录的时候)
public  User SelectByUsername(String username){
    
    
    Connection connection=null;
    PreparedStatement statement=null;
    ResultSet resultSet=null;

    try{
    
    
        //1:建立连接
        connection =DBlianjie.getConnection();
        //2:构造sql
        String sql="select * from user where username=?";
        statement=connection.prepareStatement(sql);
        statement.setString(1,username);
        //3:执行sql
        resultSet=statement.executeQuery();
        //4:遍历结果集;一条记录还是用if就可以
        if(resultSet.next()){
    
    
            User user=new User();
            user.setUserId(resultSet.getInt("userId"));
            user.setUsername(resultSet.getString("username"));
            user.setPassword(resultSet.getString("password"));
            return user;

        }
    }catch (SQLException e){
    
    
        e.printStackTrace();


    }finally {
    
    
        DBlianjie.close(connection, statement, resultSet);
    }
    return null;




}

}

上述就把后续会用到的操作封装成方法;后面就能直接使用。

前后端交互

第一个页面实现:
在进行前端的学习时;写的这个博客列表页数据是写死的。正确的做法是通过数据库读取数据显示页面上。
前后端交互;让博客列表页;加载这个页面的时候通过ajax等给服务器发请求;服务器查数据库获取博客列表页数据;返回给浏览器’;浏览器根据这些数据构造页面内容。(在没有前后端分离;我们页面是后端生成;返回整个页面给浏览器;前后端分离;解耦的同时;我们只需要返回数据由前端构造页面;大大提升效率;也减轻服务器的工作量)
在这里插入图片描述

三步走:不同情况可能开发前端和开发后端代码的顺序是不一样的
1:约定前后端交互接口
有什么功能;前端要发什么请求;后端要返回什么响应;交互的格式。这里需要注意五个部分;地址栏URL(html页面)、查看全文按钮、右上角的三个按钮。
URL:我们希望通过输入这个html页面然后就能发送一个请求给服务器;获得响应。这个只是普通的页面;这里的URL并不是关联到服务器的注解的路径(如果是直接关联;那就不输入URL就直接是发送一个GET请求);所以我们得在前端页面里构建这个请求。
请求 GET /blog(/blog是对应我们doGet注解的路径)

响应:使用json组织;数组的形式返回
[
{
blogId:1,
title:“我的第一篇博客”
contet:“第一次变成这样的我;让我怎么去否认……”
postTime:“2023-5-6 17:12:00”
userId:1

},

{
blogId:2,
title:“我的第二篇博客”
contet:“第二次变成这样的我;让我怎么去否认……”
postTime:“2023-5-6 17:12:00”
userId:1

},

{
blogId:3,
title:“我的第三篇博客”
contet:“第三次变成这样的我;让我怎么去否认……”
postTime:“2023-5-6 17:12:00”
userId:1

}

]

2:开发后端代码
处理这个输入URL的get请求;查数据库的过程。(写到这里就发现一个问题;光是管理和操作数据的类就有五个;再把servlet类写上去不就乱套了吗;分类一下;把这些类都放包里‘分别加上package model’)
所以创建多两个包:model;模型;管理和操作数据的部分。api:存放servle相关的类

package api;

import com.fasterxml.jackson.databind.ObjectMapper;
import model.Blog;
import model.BlogDao;
import model.User;

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 java.io.IOException;
import java.util.List;

@WebServlet(("/blog"))
public class BlogServlet extends HttpServlet {
    
    
      //定义在这里;别的方法也能用这个对象
    public ObjectMapper objectMapper=new ObjectMapper();
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
           //现在需要拿到数据库的数据;然后转成json格式;写回给前端
        //这里转成json格式就需要用到我们在准备工作时导入jackson依赖
        BlogDao blogDao = new BlogDao();
         //这个方法就会把数据库查到的所有博客返回List里
        List<Blog> blogs=blogDao.selectAll();

        //转成json
        String respjson=objectMapper.writeValueAsString(blogs);
        //一定不要忘记设置;告诉浏览器你返回的是什么类型和数据字符集,不然浏览器是不知道;还以为你的是普普通通字符串
        resp.setContentType("application/json;charset=utf8");
        resp.getWriter().write(respjson);


    }
}

3:开发前端代码;
请求的构造;
在这里插入图片描述
响应的结果重新构造页面:把我们之前写死的数据进行重新构造;我们自己用ajax构造GET请求(地址栏输入也是能触发这个GET请求)
留下一份作为参考;这是我们最终要构造成的文章样式
在这里插入图片描述
在这里插入图片描述

正文部分完成;

经过一波三折的测试;调试取得
在这里插入图片描述
目前两个bug:
1:时间戳问题;是应该显示系统时间;而不是时间戳。
这里格式化字符串;一定不要去背;因为不同语言、不同库;格式化时间的操作可能不同;上网查一查才是最稳的。
想想有什么办法能解决这个问题:
方法1:不用数据库的时间戳;使用idea的;但是这样子会数据库时间设置不进去;我们数据库的类型修改才string存进去就好了。或者是再写一个设置的时间是时间戳格式。一个用来设置进入数据库;一个后来返回响应。
在这里插入图片描述

这样子时间还是同一份;不同的get方法获取到的格式是不一样的;这个方法虽然显示没有调用;但是在objectMapper.writeValueAsString把这个对象转成json时;这个get方法会有用的。
在这里插入图片描述
最好的方法还是;获取idea的时间戳;然后转成string格式化;设置进数据库时使用statement.setString();数据库里就不用postTime类型;存的时候也不用存now()。直接是当个字符串.。取就按照字符串来取。

2:新的博客应该在上面的;老的在下面。
博客顺序问题简单:加个order by postTime desc。降序的按时间查询

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/m0_64254651/article/details/130512306