0
点赞
收藏
分享

微信扫一扫

Mac-终端相关操作

岛上码农 2023-07-13 阅读 63
java-eejava

【JavaEE】前后端综合项目-博客系统(上)

前端综合项目-个人博客网页设计_s:103的博客-CSDN博客

  • 在之前的前端综合项目里,我们已经有了博客系统的前端部分
  • 接下来我们将以所学的后端知识去搞定前端后端交互!
  • 实现一个真正的网站!

1. 创建项目

在src的main里创建目录结构:webapp/WEB-INF/web.xml

<!DOCTYPE web-app PUBLIC
        "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
        "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
    <display-name>Archetype Created Web Application</display-name>
</web-app>

Servlet依赖:

<!-- 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>

需要用到的jackson依赖:

<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.12.3</version>
</dependency>

MySQL依赖:

<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.49</version>
</dependency>

打war包语句:

<packaging>war</packaging>
<build>
    <finalName>showLove</finalName>
</build>

将前端部分的资源移动到webapp目录下:

2. 数据库设计

这个步骤很关键,因为这也对应着前后端信息交互的内容

设计表结构,有几个表,每个表里有啥?

最直观的就是:
在这里插入图片描述

博客信息:

  1. 博客标题
  2. 发布时间
  3. 博客内容(摘要来自内容)

在这里插入图片描述

用户信息:

  1. 用户名
  2. 用户密码
  3. 头像

所以就可以得到两种表(两个实体:博客 与 用户):

  • Blog表:

    1. 博客ID
    2. 作者ID
    3. 博客标题
    4. 正文
    5. 发布时间
  • User表:

    1. 作者ID
    2. 用户名
    3. 密码
    4. 头像
    5. 码云链接

一个用户对应多个博客(一对多),通过作者ID进行关联

不管怎么样,先这样,以后要改进,再说~

  1. 创建数据库
  2. 创建两个表

这个文件也只是为了部署到别的机器上时用到的一些固定sql语句,所以要清空之前的数据(drop…if exists…)

在这里插入图片描述

复制到数据库即可~
在这里插入图片描述

  • mysql不区分大小写,所以数据库名,表名变成小写也很正常~
insert into user values(null, '小马', '123456', '病人.png', 'https://gitee.com/carefree-state');

由于暂时没有注册功能,所以用户还不能直接在网站创建~

3. 数据库操作的封装

对于繁琐的数据库操作,我们通常会封装起来,方便后续的数据操作

在这里插入图片描述

数据库操作

  1. 连接
  2. 写入
  3. 读取
  4. 关闭

其中,对于DataSource,其实只需要一个,这也就是我们提到过的单例模式~

3.1 DataSource(单例)

博客链接:(31条消息) 【JavaEE】线程案例-单例模式 and 阻塞队列_s:103的博客-CSDN博客

//懒汉模式写法
public class DBUtil {
    private static volatile DataSource dataSource = null;

    private static DataSource getDataSource() {
        if(dataSource == null) {
            synchronized (DBUtil.class) {
                if(dataSource == null) {
                    dataSource = new MysqlDataSource();
                    ((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/blogsystem?characterEncoding=utf8&useSSl=false");
                    ((MysqlDataSource)dataSource).setUser("root");
                    ((MysqlDataSource)dataSource).setPassword("mmsszsd666");//微信号哦,欢迎添加一起学习!
                }
            }
        }
        return dataSource;
    }
}

3.1 连接操作

在这里插入图片描述

  • 千万别选错了,这也会导致我们的代码错误!
public static Connection getConnection() throws SQLException {
    return getDataSource().getConnection();
}

3.2 关闭操作

public static void close(Connection connection, PreparedStatement preparedStatement, ResultSet resultSet) {
    if(resultSet != null) {
        try {
            resultSet.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    if(preparedStatement != null) {
        try {
            preparedStatement.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    if(connection != null) {
        try {
            connection.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

3.3 创建实体类

首先,先创建两个实体的实体类:Blog与User

  • 这两个类的对象就相当于数据库的一条记录,并且这个类也可以用做作son的构造

在这里插入图片描述

public class Blog {
    private int blogId;
    private String title;
    private String content;
    private int userId;
    private Timestamp postTime;//时间戳!
}
public class User {
    int userId;
    String username;
    String password;
    String image;
    String git;
}
  • 要生成getter和setter方法哦~

3.4 封装一些必要的增删改查操作

在这里插入图片描述

DAO ==> Data Access Object,数据访问对象,也就是说这个对象用于数据访问~

  • 目前没有注册操作,所以UserDao类暂且只涉及User部分属性的查找操作~

在这里插入图片描述

3.4.1 插入一篇博客

//插入一条Blog数据
public void insert(Blog blog) {
    Connection connection = null;
    PreparedStatement statement = null;
    try {
        connection = DBUtil.getConnection();
        String sql = "insert into blog values(null, ?, ?, ?, ?)";
        statement = connection.prepareStatement(sql);
        statement.setString(1, blog.getTitle());
        statement.setString(2, blog.getContent());
        statement.setInt(3, blog.getUserId());
        //写入数据库,可以用字符串也可以用时间戳
        statement.setTimestamp(4, blog.getPostTime());
        statement.executeUpdate();
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        DBUtil.close(connection, statement, null);
    }
}

3.4.2 查询博客

//查询blog表中的所有数据
public List<Blog> selectAll() {
    Connection connection = null;
    PreparedStatement statement = null;
    ResultSet set = null;
    List<Blog> blogs = new ArrayList<>();
    try {
        connection = DBUtil.getConnection();
        String sql = "select * from blog";
        statement = connection.prepareStatement(sql);
        set = statement.executeQuery();
        while(set.next()) {
            Blog blog = new Blog();
            blog.setBlogId(set.getInt("blogId"));
            blog.setContent(set.getString("title"));
            blog.setUserId(set.getInt("userId"));
            blog.setPostTime(set.getTimestamp("postTime"));
            blogs.add(blog);
        }
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        DBUtil.close(connection, statement, set);
    }
    return blogs;
}

//指定博客id查询博客
public Blog selectOne(int blogId) {
    Connection connection = null;
    PreparedStatement statement = null;
    ResultSet set = null;
    Blog blog = new Blog();
    try {
        connection = DBUtil.getConnection();
        String sql = "select * from blog where blogId = ?";
        statement = connection.prepareStatement(sql);
        statement.setInt(1, blogId);
        set = statement.executeQuery();
        if(set.next()) {
            blog.setBlogId(set.getInt("blogId"));
            blog.setContent(set.getString("content"));
            blog.setTitle(set.getString("title"));
            blog.setPostTime(set.getTimestamp("postTime"));
        }else {
            blog = null;
        }
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        DBUtil.close(connection, statement, set);
    }
    return blog;
}

3.4.3 删除博客

//指定博客id删除博客
public void delete(int blogId) {
    Connection connection = null;
    PreparedStatement statement = null;
    try {
        connection = DBUtil.getConnection();
        String sql = "delete from blog where blogId = ?";
        statement = connection.prepareStatement(sql);
        statement.setInt(1, blogId);
        statement.executeUpdate();
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        DBUtil.close(connection,statement, null);
    }
}

3.4.4 查找用户

//通过Id查找
public User selectUserById(int userId) {
    Connection connection = null;
    PreparedStatement statement = null;
    ResultSet set = null;
    User user = new User();
    try {
        connection = DBUtil.getConnection();
        String sql = "select * from user where userId = ?";
        statement = connection.prepareStatement(sql);
        statement.setInt(1, userId);
        set = statement.executeQuery();
        if(set.next()) {
            user.setUserId(set.getInt("userId"));
            user.setPassword(set.getString("password"));
            user.setUsername(set.getString("username"));
            user.setGit(set.getString("git"));
            user.setImage(set.getString("image"));
        }else {
            user = null;
        }
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        DBUtil.close(connection, statement, set);
    }
    return user;
}
//通过用户名查找
//用户名是唯一的,但是昵称不唯一,对于昵称,暂时不加入
public User selectUserByName(String username) {
    Connection connection = null;
    PreparedStatement statement = null;
    ResultSet set = null;
    User user = new User();
    try {
        connection = DBUtil.getConnection();
        String sql = "select * from user where username = ?";
        statement = connection.prepareStatement(sql);
        statement.setString(1, username);
        set = statement.executeQuery();
        if(set.next()) {
            user.setUserId(set.getInt("userId"));
            user.setPassword(set.getString("password"));
            user.setUsername(set.getString("username"));
            user.setGit(set.getString("git"));
            user.setImage(set.getString("image"));
        }else {
            user = null;
        }
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        DBUtil.close(connection, statement, set);
    }
    return user;
}

4. 前后端交互逻辑

4.1 博客列表页

在这里插入图片描述

  • 要求:把所有博客查询出来排列
  1. 约定前后端交互接口
  2. 写后端代码
  3. 写前端代码

3.1.1 约定前后端交互接口

请求:GET请求

向谁请求:/blog

响应:json格式

  • 注意要与我们的类的属性名一一对应!
[
    {
        blogId:xxx,
        title:xxx,
        content:xxx,
        userId:xxx,
        postTime:xxx
    },
    {
        ...
    },
    {
        ...
    }
]

3.1.2 后端代码

在这里插入图片描述

@WebServlet("/blog")
public class BlogServlet extends HttpServlet {
    
    
}
@WebServlet("/blog")
public class BlogServlet extends HttpServlet {

    ObjectMapper objectMapper = new ObjectMapper();
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        BlogDao blogDao = new BlogDao();
        List<Blog> blogList = blogDao.selectAll();
        String respString = objectMapper.writeValueAsString(blogList;
        resp.setContentType("application/json; charset=utf8");
        resp.getWriter().write(respString);
    }
}

3.1.3 前端代码

  • 构造ajax请求,按照上述约定,发送请求
    在这里插入图片描述

  • 一篇博客我们原本是写死的,所以删掉,留下一个作为参照:

在这里插入图片描述

  • 根据这个参照,去书写前端代码

在这里插入图片描述

  • 跳转连接,用到了query string的技巧,区分不同的博客

在这里插入图片描述

  • 目前数据库无数据
    • 我们可以自己手动在数据库内添加
insert into blog values(null, "我的第一篇博客", "博客正文", 1, "2023-07-07 12:00:00");
insert into blog values(null, "我的第二篇博客", "博客正文", 1, "2023-07-07 13:00:00");
insert into blog values(null, "我的第三篇博客", "博客正文", 1, "2023-07-07 14:00:00");
insert into blog values(null, "我的第四篇博客", "博客正文", 1, "2023-07-07 15:00:00");
  • 刷新页面

在这里插入图片描述

  • 接下来就是我们要处理的问题了
  1. 按照实际情况,最新发布的应该放在最前面~
    • 这个只需要在查询的时候,按照时间逆序就行了

在这里插入图片描述

在这里插入图片描述

  1. 时间应该是格式化时间而不是时间戳~

此处我们用jackson去获得的json字符串,我们要求类的属性是public,而这里是private,原因是其是用了getter和setter

  • 所以我们只需要让getter去获取时间的时候,获取到的是格式化时间即可
  • 在之前的学习我们知道
    1. jdbc填入数据库date数据的时候,可以是字符串也可以说时间戳
    2. 但是jdbc读取出来date数据的时候,只有时间戳

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  1. 博客列表应该显示的是摘要,而不是正文
    • 规定:摘要为正文的前100个字~

由于selectAll只在列表页用到,所以无需返回给前端全部的正文~

  • 所以可以这样:

在这里插入图片描述

  • 现在我们更改博客正文到一定大小:
update blog set content = '我嘛就不用多说了,大大的眼睛,长长的头发,白皙的皮肤,超真宗的万人迷咳咳,好吧,我就不自夸了。总之我最大的一个特点就是活泼,文静。在大厅广众面前,我是一个活跃分子,但在自己的自由王国里,我又安静的可以坐上几个钟头。大年十三夜,全家人尽情欢乐一天,便睡了,我就一个人独自躺在床上。在这宁静的晚上,我可以静静的思考过去一年自己走过的路,回忆那些可以称得上留下一段美好回忆的时光,展望新一年自己即将踏上的征途。在周末或星期天,我总爱一个人坐在书房里静静地看书,让自己沉浸在书的海洋里。但看完书后我又开始自娱自乐了。这样的我是不是很可爱呢?可爱中又带一点小俏皮,你们是不是很想和我做朋友呢?是的话就让我们一起来说友谊万岁吧!!' where userId = 1;

效果:

在这里插入图片描述

4.2 博客详情页

4.2.1 约定前后端交互接口

与列表页不同的是,这里需要完整的一篇正文,不需要所有的

请求:GET

向谁请求:/blog

  • 这不是冲突了吗?
    • 并没有,我们可以GET请求的地址,来区分,因为详情页的地址,是包含query string的所以有query string代表是详情页,没有则代表是列表页~
    • query string包含的数据就是blogId,对应特别的博客

响应:json格式

{
    ...
}

4.2.2 后端代码

在这里插入图片描述

4.2.3 前端代码

参考:

  • 记得导入jquery

在这里插入图片描述

function getBlog() {
    jQuery.ajax({
        type: "GET",
        url: "blog" + location.search,
        sucecss: function (body) {
            var aTitle = jQuery("<h3></h3>");
            aTitle.text(blog.title);
            var aDate = jQuery("<div></div>");
            aDate.attr("class", "date");
            aDate.text(blog.postTime);
            var aContent = jQuery("<div></div>");
            aContent.attr("class", "content");
            var aP = jQuery("<p></p>");
            aP.text(blog.content);
            aContent.append(aP);
            aTitle.append(jQuery(".article"));
            aDate.append(jQuery(".article"));
            aContent.append(jQuery(".article"));
        },
    });
}
getBlog();
  • 注意,页面的query string是html?blogId=xxx,而后端要获得的query string要的是blog?blogId=xxx,所以发送请求的时候要把信息“带上”(location.search)

在这里插入图片描述

问题接踵而至,一篇博客应该是格式丰富的,而不是纯文字~

  • 而我们经常用markdown渲染后的样式!

4.2.4 渲染markdown

  • 我们直接借助editor.md这个库即可~

editormd.markdownToHTML

  • 去博客编辑页拿对应的markdown依赖
<link rel="stylesheet" href="editor.md/css/editormd.min.css" />
<script src="editor.md/lib/marked.min.js"></script>
<script src="editor.md/lib/prettify.min.js"></script>
<script src="editor.md/editormd.js"></script>
  1. 生成html的元素id
  2. 一个对象{markdown: body.content}
function getBlog() {
    jQuery.ajax({
        type: "GET",
        url: "blog" + location.search,
        success: function (body) {
            jQuery(".article h3").text(body.title);
            jQuery(".article .date").text(body.postTime);
            editormd.markdownToHTML("pc", { markdown: body.content });
        },
    });
}
getBlog();

在这里插入图片描述

接下来我在数据库中插入一段markdown代码为正文的博客:

insert into blog values(null, "博客系统", "# 【JavaEE】前后端综合项目-博客系统

 [前端综合项目-个人博客网页设计_s:103的博客-CSDN博客](https://blog.csdn.net/Carefree_State/article/details/130744723?spm=1001.2014.3001.5501)

*   在之前的前端综合项目里,我们已经有了博客系统的前端部分
*   接下来我们将以所学的后端知识去搞定前端后端交互!
*   实现一个真正的网站!

", 1, "2023-07-07 20:00:00");

在这里插入图片描述

  • 对于手动输入数据库,还是很难使其正确显示的


举报

相关推荐

0 条评论