0


【JavaWeb项目】博客系统

1. 项目简介

1.1 项目背景

在网络学完HTTP协议,前端学完html,css,js,后端学完Servlet开发后,做一个博客系统,巩固一下所学知识,并将所学知识运用到实际当中,以此来进一步提升对学习编程的兴趣

1.2 项目用到的技术

  • 前端使用到html,css,js,使用ajax技术发送http请求,请求body的格式为json格式
  • 后端使用Servlet进行开发
  • 使用Mysql数据库保存数据
  • 除此还引入了editor.md,editor.md是一个开源的页面markdown编辑器组件
  • 采用Maven构建工具搭建项目开发环境

1.3 项目功能简单介绍

  • 登陆页面:输入用户及密码,点击提交,如果用户或密码错误,会提示用户或密码错误,账号及密码正确则登陆成功,成功后跳转到博客列表页面
  • 博客列表页面:博客列表页面展示所有发布过的文章,文章显示最多显示50字,如果想查看全文,则需要点击文章下的显示全文
  • 博客详情页面:点击某篇文章的显示全文按钮,则会展示文章的全部内容
  • 博客编辑页面:点击博客列表的写博客,会跳转到博客编辑页面,输入文章题目及文章内容点击发布文章,文章即可发布成功,发布成功后会跳转到博客列表页面,可以查看发布过的文章
  • 博客注销按钮:点击博客注销按钮,则会跳转到博客登陆页面

2. 页面及功能展示

登陆页面

输入用户和密码,点击提交,登陆成功后跳转到博客列表页面

点击写博客,跳转到博客编辑页面

输入文章标题和文章内容,点击发布文章,发布成功后跳转到博客列表页面

在博客列表页面,点击刚发布文章的显示全文,就会显示刚才发布文章的全部内容

点击注销又跳转到博客登陆页面

3. 博客系统页面设计

这里附上静态页面设计的码云地址,可以点击查看,本篇文章只展示后端代码与前端ajax交互的部分,想要查看博客系统页面设计代码,请点击:个人博客系统的页面设计代码

4. 项目准备工作

创建Maven项目在pom.xml中添加项目依赖

  • 后端采用Servlet开发
  • 数据库使用Mysql
  • jackson框架可以进行序列化和反序列化,将java对象和json字符串相互转化
  • junit框架提供单元测试
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>my-blog</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.49</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.12.3</version>
        </dependency>
        <!--  单元测试框架      -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.1</version>
        </dependency>
    </dependencies>
    <build>
        <finalName>my-blog</finalName>
    </build>
</project>

创建与开发相关的包

引入前端资源

将前端资源都放在main/webapp目录下,前端资源从上面码云地址中获取,web.xml存放在main/webapp/WEB-INF目录下

5. 博客系统功能设计

5.1 设计数据库表

  • 有用户登陆,所以有一张用户表,观察博客列表有显示用户昵称,所以用户表设计有四个字段:用户id,用户名,密码,昵称
  • 有文章展示,所以有一张文章表,文章有文章id,标题,发布时间,文章内容,关联用户的外键
  • 一个用户可以发布多篇文章,所以用户与文章对应关系为1:m,用户id作为文章表的外键

创建表的时候可以插入一些数据便于后续的测试

drop database if exists blog;
create database blog character set utf8mb4;
use blog;
create table user(
    id int primary key auto_increment,
    username varchar(20) not null unique,
    password varchar(20) not null,
    nickname varchar(10) not null
);
insert into user values(null,'abc','123','糯米');

create table article(
    id int primary key auto_increment,
    title varchar(50) not null,
    `date` date,
    content mediumtext,
    user_id int,
    foreign key (user_id) references user(id)
);
insert into article values(null,'文章1','2022-9-9','今天要好好学习',1);
insert into article values(null,'文章2','2022-9-17','今天要玩游戏',1);

5.2 工具类util

  1. 创建数据库工具类DBUtil,提供获取数据库连接和统一释放资源
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

//数据库工具类,提供获取数据库连接,释放资源统一代码
public class DBUtil {

    //一个程序,连接一个数据库,只需要一个连接池,其中保存了多个数据库连接对象
    private static MysqlDataSource ds; //静态变量,类加载时执行初始化,只执行一次
    //获取连接池,内部使用,不开放
    private static DataSource getDataSource(){
        if(ds == null){
            ds = new MysqlDataSource();
            ds.setURL("jdbc:mysql://127.0.0.1:3306/blog");
            ds.setUser("root");
            ds.setPassword("xiaobai520..@@@");
            ds.setUseSSL(false); //不安全连接,不设置会有警告
            ds.setCharacterEncoding("UTF-8");
        }
        return ds;
    }

    //获取数据库连接对象,开放给外部的jdbc代码使用
    public static Connection getConnection(){
        try {
            return getDataSource().getConnection();
        } catch (SQLException e) {
            throw new RuntimeException("获取数据库连接报错",e);
        }
    }

    //释放资源,查询操作需要释放三个资源
    public static void close(Connection c, Statement s, ResultSet rs){
        try {
            if(rs != null) rs.close();
            if(s != null) s.close();
            if(c != null) c.close();
        } catch (SQLException e) {
            throw new RuntimeException("释放数据库资源出错",e);
        }
    }

    //更新操作释放两个资源
    public static void close(Connection c,Statement s){
        close(c,s,null);
    }
}
  1. 创建Web工具类WebUtil,提供一个类专门检查用户是否登陆,还提供序列化与反序列化类,用来将java对象与json字符串相互转化
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.example.model.User;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.InputStream;

public class WebUtil {
    public static User checkLogin(HttpServletRequest req){
        User user = null;
        HttpSession session = req.getSession(false);
        user = (User) session.getAttribute("user");
        return user;
    }

    //使用单例
    private static ObjectMapper mapper = new ObjectMapper();

    //反序列化:json字符串转换Java对象
    //使用泛型,传一个什么类型,就返回该类型的对象
    //泛型方法:方法限定符 <类型型参列表> 返回值类型 方法名
    public static <T> T read(InputStream is,Class<T> clazz){
        try {
            return mapper.readValue(is,clazz);
        } catch (IOException e) {
            throw new RuntimeException("json反序列化出错",e);
        }
    }

    //序列化:将java对象转化为json字符串
    public static String write(Object o){
        try {
            return mapper.writeValueAsString(o);
        } catch (JsonProcessingException e) {
            throw new RuntimeException("json序列化出错",e);
        }
    }
}

5.3 实体类model

每张用户表对应有一个实体类,所以创建User和Article类,创建类的时候提供Getter和Setter方法并且重写toString方法

用户类User

public class User {
    private Integer id;
    private String username;
    private String password;
    private String nickname;

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", nickname='" + nickname + '\'' +
                '}';
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    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;
    }

    public String getNickname() {
        return nickname;
    }

    public void setNickname(String nickname) {
        this.nickname = nickname;
    }
}

文章类Article

import java.util.Date;

public class Article {
    private Integer id;
    private String title;
    private Date date; //时间
    private String content;
    private Integer userId;
    private String dateString;//日期字符串

    @Override
    public String toString() {
        return "Article{" +
                "id=" + id +
                ", title='" + title + '\'' +
                ", date=" + date +
                ", content='" + content + '\'' +
                ", userId=" + userId +
                ", dateString='" + dateString + '\'' +
                '}';
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }

    public String getContent() {
        return content;
    }

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

    public Integer getUserId() {
        return userId;
    }

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

    public String getDateString() {
        return dateString;
    }

    public void setDateString(String dateString) {
        this.dateString = dateString;
    }
}

Java对象JsonResult类

后端返回给前端的响应时返回的是json字符串,所以需要一个JsonResult类,该类的字段保存操作是否成功和要返回给前端的数据,后端在返回给前端json字符串的时候只需要将该类序列化为json字符串返回给前端,该类也得提供Getter与Setter方法并且重写toString方法

public class JsonResult {
    private boolean ok;//标识执行一个操作是否成功
    private Object data;//操作成功,且是一个查询操作,需要返回一些数据给前端

    @Override
    public String toString() {
        return "JsonResult{" +
                "ok=" + ok +
                ", data=" + data +
                '}';
    }

    public boolean isOk() {
        return ok;
    }

    public void setOk(boolean ok) {
        this.ok = ok;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }
}

5.4 前后端业务处理

前后端业务逻辑的实现顺序:

  1. 先在前端构造ajax请求
  2. 再做后端业务逻辑
  3. 最后再前端才设置回调函数执行回调

说明:后面实现的顺序是先前端再后端,但是观看参考时,建议按照上面的逻辑顺序,因为实际开发时就是按照这个顺序来开发的

5.4.1 登陆页面功能设计

所有的请求都是使用ajax发送http请求,所以将封装的ajax函数写在一个js文件中,后续发送请求时只需将封装的ajax函数引入即可

封装的ajax函数

//封装ajax函数,args为一个js对象
//args对象属性如下:
//method:请求方法,url:请求资源路径,contenType:请求正文格式
//body:请求正文,callback:回调函数,客户端接收到响应数据后调用
function ajax(args) {
    let xhr = new XMLHttpRequest();
    //设置回调函数
    xhr.onreadystatechange = function () {
        //4:客户端接收到服务端响应
        if (xhr.readyState == 4) {
            //回调函数可能会使用响应的内容,作为传入参数
            args.callback(xhr.status, xhr.responseText);
        }
    }
    xhr.open(args.method, args.url);
    //如果args中contentType有内容,就设置Content-Type请求头
    if (args.contentType) {//js中if可以判断是否有值
        xhr.setRequestHeader("Content-Type", args.contentType);
    }
    //如果args中body有内容,设置body请求正文
    if (args.body) {
        xhr.send(args.body);
    } else {
        xhr.send();
    }
}

前端设计

  1. 给登陆提交按钮绑定点击事件,获取到输入的用户名和密码后,发送ajax请求
  2. 请求方法为post,请求url为login,后端的Servlet路径也要与此对应,设置contentType为application/json,请求body为json字符串
  3. json对象保存输入的用户名和密码,将json对象转化为json字符串设置到body中
  4. 设置回调函数,回调函数有两个参数,一个为响应状态码,一个为后端返回的响应为json字符串,后端返回的json字符串中保存操作是否成功字段
  5. 如果响应状态码为200,并且ok为true,则登陆成功,跳转到博客列表页面,如果ok为false则用户名或密码错误,如果响应状态码不为200,则提示响应状态码及响应body,以便程序员作出更改
<script src="js/util.js"></script>
<script>
    let submit = document.querySelector("#submit");
    //绑定提交按钮点击事件
    submit.onclick = function(){
        let username = document.querySelector("#username").value;
        let password = document.querySelector("#password").value;
        //发送ajax请求,需要设置method,url,contentType,body
        ajax({
            method: "post",
            url: "login",
            contentType: "application/json",
            body: JSON.stringify({
                //冒号前是前后端约定的键,冒号后是变量值
                username: username,
                password: password
            }),
            callback: function(status,responseText){
                if(status == 200){
                    let json = JSON.parse(responseText);
                    if(json.ok){
                        alert("登陆成功");
                        window.location.href = "blog_list.html";
                    }else {
                        alert("账号或密码错误");
                    }
                }else {
                    alert("响应状态码:"+status+"/nbody:"+responseText);
                }
            }
        });
    }
</script>

后端Servlet设计

  1. 前端发送的body为json字符串
  2. 所以先使用InputStream输入流获取请求数据,将请求数据转化为user对象
  3. 使用该对象在数据库做校验,如果校验成功,设置session,设置要返回给前端的JsonResult对象json
  4. 设置完后,将json对象序列化json字符串后返回给前端
  5. 前端的回调函数就是依据后端返回的json字符串做相应的逻辑处理
@WebServlet("/login")//登陆
public class LoginServlet extends HttpServlet {
    //登陆功能,json提交{username:abc,password:123}
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //解析请求:通过输入流获取请求数据
        req.setCharacterEncoding("utf-8"); //设置请求对象的编码格式
        InputStream is = req.getInputStream();
        //将输入流中的json字符串转化为java对象
        //使用ObjectMapper将java对象和json字符串相互转换,Servlet都要用,封装到WebUtil中
        User get = WebUtil.read(is,User.class);
        //在数据库校验账号密码:通过账号密码在数据库查用户,若能查到则账号密码正确
        User user = UserDao.isLogin(get.getUsername(),get.getPassword());
        //不管登陆是否成功,返回的http响应正文(body)都是json字符串
        //需要设计一个类,这个类的成员变量属性,用于前端ajax解析响应
        //先创建一个响应正文需要的Java对象,然后在转换为json字符串,再设置到响应正文
        JsonResult json = new JsonResult();
        if(user != null){
            //登陆成功,设置session
            HttpSession session = req.getSession(true);
            session.setAttribute("user",user);
            //设置json对象中,操作是否成功为true
            json.setOk(true);

        }else {
            //登陆失败,设置操作是否成功字段为false
            json.setOk(false);
        }
        //设置响应正文的格式
        resp.setContentType("application/json; charset=utf-8");
        resp.getWriter().write(WebUtil.write(json));
    }
}

5.4.2 博客列表页面功能设计

前端设计

客户端展示页面时,就需要展示文章列表数据,加载完页面就发生ajax请求,来获取文章列表内容,待收到返回的响应执行回调时,解析响应的文章列表数据

  1. 发送的ajax请求,method为get,url为blog_list,对应的后端Servlet路径也要与之对应
  2. 因为是get请求,所以没有body
  3. 设置回调函数,与前面登陆的回调函数逻辑相似,将后端返回的json字符串转化为json对象时,如果ok为true,则解析返回的数据
  4. 将返回的nickname和文章数设置到前端,将返回的文章集合以循环的方式设置到前端
<script src="js/util.js"></script>
<script>
    //客户端展示页面时,就需要展示文章列表数据
    //加载完页面,就发送ajax请求获取文章列表的数据
    //返回响应执行回调时,解析响应的文章列表数据
    ajax({
        method: "get",
        url: "blog_list",
        callback: function(status,responseText){
            if(status == 200){
                let json = JSON.parse(responseText);
                if(json.ok){
                    let data = json.data;
                    let nickname = data.nickname;
                    let h3 = document.querySelector(".card>h3");
                    h3.innerHTML = nickname;
                    let articles = data.articles;
                    let div = document.querySelector(".container-right");
                    //str不赋值就是undefined,再去拼接字符串就会出错
                    let str = "";
                    for(let a of articles){
                        //``里面可以包括单引号和双引号
                        str += `<div class="row">`;
                        str += `<div class="title">`;
                        str += a.title;
                        str += `</div>`;
                        str += `<div class="date">`;
                        str += a.dateString;
                        str += `</div>`;
                        str += `<div class="desc">`;
                        str += `<p>`;
                        str += a.content;
                        str += `</p>`;
                        str += `</div>`;
                        str += `<div class="to-detail">`;
                        str += `<a href="blog_content.html?id=` + a.id;
                        str += `">显示全文>></a>`;
                        str += `</div>`;
                        str += `</div>`;
                    }
                    div.innerHTML = str;
                    let num = data.count;
                    let count = document.querySelector("#count");
                    count.innerHTML = num;
                }else {
                    alert("ok==false");
                }
            }else {
                alert("响应状态码:"+status+"/nbody:"+responseText)
            }
        }
    });
</script>
</html>

后端Servlet设计

  1. 先校验用户是否登陆,未登录不允许访问,直接跳转到用户登陆页面,登陆后才可执行后边逻辑
  2. 登陆成功后用用户的id查询该用户的所有文章并且查询该用户的所有文章数目
  3. 此时已经登陆成功,设置JsonResult对象json的ok为true
  4. 创建一个Map结构的data,保存要返回给前端的数据文章列表和用户昵称和文章数目
  5. 将data设置到json对象中,将json对象序列化为json字符串返回给前端
@WebServlet("/blog_list")//博客列表
public class BlogListServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //未登录,访问跳转到登陆页面
        User user = WebUtil.checkLogin(req);
        if(user == null){
            resp.sendRedirect("login.html");
            return; //未登录,直接跳转,不会执行后边逻辑
        }
        //通过登陆用户id查找所有文章
        List<Article> articles = ArticleDao.selectById(user.getId());
        //通过登陆用户id查找文章数目
        int count = ArticleDao.getCount(user.getId());

        //先构造响应正文需要的java对象,再转化为json字符串,再设置到响应正文
        JsonResult json = new JsonResult();
        json.setOk(true);
        //前端需要的数据有nickname,articles,可以用map保存,然后设置到json.data中
        Map<String,Object> data = new HashMap<>();
        data.put("nickname",user.getNickname());
        data.put("articles",articles);
        data.put("count",count);
        json.setData(data);

        resp.setContentType("application/json; charset=utf-8");
        resp.getWriter().write(WebUtil.write(json));
    }
}

5.4.3 博客详情页面功能设计

前端设计

博客详情是从博客列表的显示全文按钮跳转过来的,所以跳转的连接携带id,id标识文章id,表示显示的是哪篇文章的全部内容

  1. 先使用window.location.search.substring获取到文章id
  2. 再发送ajax请求,请求方法为get,请求url为blog_content?id=id,设置回调函数
  3. 待后端返回响应后执行回调函数,将响应正文转化为json对象,解析json对象
  4. 设置用户昵称,文章数目,文章标题,发表日期,文章内容
<script src="js/util.js"></script>
<script>
    //window.location.search获取的是queryString?后的部分,blog_content?id=1
    //也就是获取的是?id=1
    let id = window.location.search.substring(4);
    //页面一加载就需要展示博客详情页面,所以就发送ajax请求来获取内容
    ajax({
        method: "get",
        url: "blog_content?id="+id,
        callback: function(status,responseText){
            if(status == 200){
                let json = JSON.parse(responseText);
                if(json.ok){
                    let data = json.data;
                    let nickname = data.nickname;
                    let h3 = document.querySelector(".card>h3");
                    h3.innerHTML = nickname;
                    let num = data.count;
                    let count = document.querySelector("#count");
                    count.innerHTML = num;
                    let article = data.article;
                    let div = document.querySelector(".detail");
                    let str = "";
                    str += `<div class="title">`;
                    str += article.title;
                    str += `</div>`;
                    str += `<div class="date">`;
                    str += article.dateString;
                    str += `</div>`;
                    str += `<div id="article-content" class="desc">`;
                    //str += article.content;
                    str += `</div>`;
                    div.innerHTML = str;
                    //不能直接展示markdown源码,数据库保存的是markdown源码
                    editormd.markdownToHTML("article-content",{markdown: article.content});
                }else {
                    alert("ok == false");
                }
            }else {
                alert("响应状态码:"+status+"/nbody:"+responseText);
            }
        }
    });
</script>

后端Servlet设计

  1. 用户未登录不允许访问,直接跳转到用户登陆页面
  2. 请求数据携带在queryString中,所以使用req.getParameter解析请求获取到文章id
  3. 根据文章id查询整个文章将查询的数据设置到一个文章对象中
  4. 将JsonResult对象json的ok设置为true
  5. 使用一个Map结构data保存获取的文章数目,文章,用户昵称
  6. 将data设置到json对象中,将json对象序列化为json字符串后返回给前端
@WebServlet("/blog_content")//博客详情
public class BlogContentServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //未登录,访问跳转到登陆页面
        User user = WebUtil.checkLogin(req);
        if(user == null){
            resp.sendRedirect("login.html");
            return; //未登录,直接跳转,不会执行后边逻辑
        }

        //路径为:blog_content?id=文章id
        //解析请求
        String sid = req.getParameter("id"); //获取到文章id
        //通过文章id查询整篇文章
        Article a = ArticleDao.queryById(Integer.parseInt(sid));
        int count = ArticleDao.getCount(user.getId());

        JsonResult json = new JsonResult();
        json.setOk(true);
        Map<String,Object> data = new HashMap<>();
        data.put("nickname",user.getNickname());
        data.put("article",a);
        data.put("count",count);
        json.setData(data);
        resp.setContentType("application/json; charset=utf-8");
        resp.getWriter().write(WebUtil.write(json));
    }
}

5.4.4 博客编辑页面功能设计

前端设计

  1. 给发布文章绑定点击事件,点击发布,发送ajax请求用于给文章表中添加数据
  2. 获取到输入的文章标题和文章内容,将其设置为json对象
  3. 发送ajax请求的方法为post,url为blog_add,后端Servlet路径要与之对应,设置contentType为application/json,将设置的json对象转化为json字符串设置到body中
  4. 待收到后端返回的响应后,执行回调,提示发布文章成功并且跳转到博客列表页面
<script src="js/util.js"></script>
<script src="js/jquery.min.js"></script>
<script src="editor.md/lib/marked.min.js"></script>
<script src="editor.md/lib/prettify.min.js"></script>
<script src="editor.md/editormd.min.js"></script>
<script>
    $(function(){
        var editor = editormd("edit-content",{
            width: "100%",
            height: "calc(100% - 50px)",
            markdown: "# 在这里写下第一篇博客",
            path: "editor.md/lib/",
            saveHTMLToTextarea: true
        });
    })
    //发布文章点击事件
    function addContent(){
        let title = document.querySelector("#title").value;
        let content = document.querySelector("#content").value;
        ajax({
            method: "post",
            url: "blog_add",
            contentType: "application/json",
            body: JSON.stringify({
                title: title,
                content: content
            }),
            callback: function(status,responseText){
                if(status == 200){
                    let json = JSON.parse(responseText);
                    if(json.ok){
                        alert("发布文章成功");
                        window.location.href = "blog_list.html";
                    }else {
                        alert("ok == false");
                    }
                }else {
                    alert("响应状态码:"+status+"/nbody:"+responseText);
                }
            }
        });
    }
</script>

后端Servlet设计

  1. 用户未登录不允许访问,直接跳转到用户登录页面
  2. 使用InputStream解析请求,通过输入流获取数据
  3. 将输入流中的json字符串转化为文章对象
  4. 设置用户id,发布日期到该文章对象中
  5. 将JsonResult对象json的ok设置为true,将json对象序列化为json字符串后返回给前端
@WebServlet("/blog_add")//添加文章
public class BlogAddServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        User user = WebUtil.checkLogin(req);
        if(user == null){
            //未登录不允许访问
            resp.sendRedirect("login.html");
            return;
        }
        //解析请求
        req.setCharacterEncoding("utf-8");
        InputStream is = req.getInputStream();
        Article beInsert = WebUtil.read(is,Article.class);
        //数据库插入一条数据,相当于插入一个对象
        beInsert.setUserId(user.getId());
        beInsert.setDate(new java.util.Date());
        int n = ArticleDao.insertOne(beInsert);
        JsonResult json = new JsonResult();
        json.setOk(true);
        resp.setContentType("application/json; charset=utf-8");
        resp.getWriter().write(WebUtil.write(json));
    }
}

5.4.5 用户注销功能设计

  1. 获取到session
  2. 如果session不为空,将session中保存的user删除
  3. 删除后跳转到用户登陆页面
@WebServlet("/logout")
public class LogoutServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //注销就是通过session对象删除保存的用户信息
        HttpSession session = req.getSession(false);
        if(session != null){
            session.removeAttribute("user");
        }
        resp.sendRedirect("login.html");
    }
}

6. 数据库逻辑处理

前端后端做业务处理的数据库逻辑操作如下:

6.1 用户表的逻辑处理

通过登陆输入的用户名和密码查询到user并将user返回,以此来做用户密码校验功能

public class UserDao {
    public static User isLogin(String username, String password){
        Connection c = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            c = DBUtil.getConnection();
            String sql = "select * from user where username=? and password=?";
            ps = c.prepareStatement(sql);
            ps.setString(1,username);
            ps.setString(2,password);
            rs = ps.executeQuery();
            User user = null;
            while(rs.next()){
                user = new User();
                int id = rs.getInt("id");
                String nickname = rs.getString("nickname");
                user.setId(id);
                user.setNickname(nickname);
                user.setUsername(username);
                user.setPassword(password);
            }
            return user;
        } catch (SQLException e) {
            throw new RuntimeException("校验账号密码出错",e);
        } finally {
            DBUtil.close(c,ps,rs);
        }
    }

    @Test
    public void testLogin(){
        System.out.println(isLogin("abc","123"));
    }
}

6.2 文章表的逻辑处理

通过用户id查询所有文章

    //通过用户id查询所有文章
    public static List<Article> selectById(Integer id){
        List<Article> articles = new ArrayList<>();
        Connection c = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try{
            c = DBUtil.getConnection();
            String sql = "select * from article where user_id=?";
            ps = c.prepareStatement(sql);
            ps.setInt(1,id);
            rs = ps.executeQuery();
            while(rs.next()){
                Article a = new Article();
                a.setId(rs.getInt("id"));
                a.setTitle(rs.getString("title"));
                java.sql.Date date = rs.getDate("date");
                long time = date.getTime();
                a.setDate(new java.util.Date(time));
                DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
                String dateString = df.format(a.getDate());
                a.setDateString(dateString);
                String content = rs.getString("content");
                a.setContent(content.length()>50 ? content.substring(0,50) : content);
                a.setUserId(id);
                articles.add(a);
            }
            return articles;
        } catch (SQLException e) {
            throw new RuntimeException("查询文章出错",e);
        } finally {
            DBUtil.close(c,ps,rs);
        }
    }

根据文章id查询整篇文章

    //根据文章id查文章
    public static Article queryById(int id) {
        Article a = null;
        Connection c = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try{
            c = DBUtil.getConnection();
            String sql = "select * from article where id=?";
            ps = c.prepareStatement(sql);
            ps.setInt(1,id);
            rs = ps.executeQuery();
            while(rs.next()){
                a = new Article();
                a.setId(id);
                a.setTitle(rs.getString("title"));
                java.sql.Date date = rs.getDate("date");
                DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
                String dateString = df.format(new java.util.Date(date.getTime()));
                a.setDateString(dateString);
                a.setContent(rs.getString("content"));
                a.setUserId(rs.getInt("user_id"));
            }
            return a;
        } catch (SQLException throwables) {
            throw new RuntimeException("查询文章详情jdbc出错",throwables);
        } finally{
            DBUtil.close(c,ps,rs);
        }
    }

插入一篇文章

    //插入文章
    public static int insertOne(Article a) {
        Connection c = null;
        PreparedStatement ps = null;
        try{
            c = DBUtil.getConnection();
            String sql = "insert into article(title,`date`,content,user_id) values(?,?,?,?)";
            ps = c.prepareStatement(sql);
            ps.setString(1,a.getTitle());
            //ps.setDate(2,new java.sql.Date(a.getDate().getTime()))
            ps.setDate(2,new java.sql.Date(System.currentTimeMillis()));
            ps.setString(3,a.getContent());
            ps.setInt(4,a.getUserId());
            return ps.executeUpdate();
        } catch (SQLException throwables) {
            throw new RuntimeException("发布文章jdbc出错",throwables);
        } finally {
            DBUtil.close(c,ps);
        }
    }

获取文章数目

    public static int getCount(Integer id) {
        Connection c = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try{
            c = DBUtil.getConnection();
            String sql = "select 0 from article where user_id=?";
            ps = c.prepareStatement(sql);
            ps.setInt(1,id);
            rs = ps.executeQuery();
            int count = 0;
            while(rs.next()){
                count++;
            }
            return count;
        } catch (SQLException throwables) {
            throw new RuntimeException("查询文章数目出错",throwables);
        } finally{
            DBUtil.close(c,ps,rs);
        }
    }

7. 博客系统设计源码

在做前后端逻辑处理的时候,前端代码有些稍微的改动,本文没有提及到,请点击查看源码,查看改动的细节以及所有后端的设计实现:个人博客系统设计源码

标签: java html servlet

本文转载自: https://blog.csdn.net/qq_58710208/article/details/126957212
版权归原作者 X_H学Java 所有, 如有侵权,请联系我们删除。

“【JavaWeb项目】博客系统”的评论:

还没有评论