基于Servlet实现个人博客

核心功能

在这里插入图片描述

数据库设计

两张表,一位用户可以发布多篇博客。因此在Article表中使用了user_id作为外键将两张表关联起来。

User表

属性类型说明
idintprimary key auto_increment(主键作为user的唯一表示)
usernamevarchar(20)unique
passwordvarchar(20)not null

Article表

属性类型说明
idintprimary key auto_increment(主键作为Artilce的唯一表示)
titlevarchar(20)not null
contentmediumtextnot null
create_timetimestampdefault now()
user_idintforeign key

服务器API设计

注册

请求:
POST /register
data:username=abc&password=123
响应:
{"success":false,"code":"RegisterError","message":"用户已存在","data":null}

登录

请求:
POST /login
data:username=abc&password=123
响应:
{"success":false,"code":"Login003","message":"用户名或者密码错误","data":null}

新增博客

请求:
Get /articleAdd
响应:
{"success":true,"code":null,"message":null,"data":null}

删除博客

请求:
Get /articleDelete
响应:
{"success":true,"code":null,"message":null,"data":null}

修改博客

请求:
Get /articleDetail
响应:
{"success":true,"code":null,"message":null,"data":{"id":9,"title":"张继科yyds","content":"<p>科科最帅<br/></p>","userId":null,"createTime":null}}

数据库封装操作

使用数据库连接池,减少多次创建(释放)连接带来的开销

单例模式(双重校验锁)
volatile关键字:一个进程进行读操作,一个线程进行写操作;当实例化dataSource对象时涉及读取操作和修改操作,因此需要使用 volatile;
synchronized关键字:涉及对象操作非原子性;当实例化dataSource对象时涉及判断对象是否为空,然后再对其进行实例化,操作不是原子的,可能线程不安全,因此需要使用synchronized;

同时还用到了方法的重载,实现了代码的复用

import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
import org.example.exception.AppException;

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

public class DBUtil {
    private static String url = "jdbc:mysql://localhost:3306/servlet_blog?characterEncoding=utf-8&useSSL=false";
    private static String username = "root";
    private static String password = "261919Zss";
    private static volatile DataSource dataSource;
    private static DataSource getDataSource(){
        if (dataSource == null){
            synchronized (DBUtil.class){
                if (dataSource == null){
                    dataSource = new MysqlDataSource();
                    ((MysqlDataSource)dataSource).setURL(url);
                    ((MysqlDataSource)dataSource).setUser(username);
                    ((MysqlDataSource)dataSource).setPassword(password);
                }
            }
        }
        return dataSource;
    }
    //获取Connection对象
    public static Connection getConnection(){
        try {
            return getDataSource().getConnection();
        } catch (SQLException e) {
            //返回自定义异常
            throw new AppException("DBError001","数据库连接异常",e);
        }
    }

    public static void close(Connection connection, PreparedStatement statement, ResultSet resultSet){
        try {
            if (resultSet != null){
                resultSet.close();
            }
            if (statement != null){
                statement.close();
            }
            if (connection != null){
                connection.close();
            }
        } catch (SQLException e) {
            throw new AppException("DBError002","数据库关闭资源失败",e);
        }
    }
    public static void close(Connection connection, PreparedStatement statement){
        close(connection, statement,null);
    }
}

代码复用

创建一个servlet的抽象类,做好初始化工作,后面子类直接继承即可

import org.example.exception.AppException;
import org.example.model.JSONResponse;
import org.example.util.JSONUtil;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * 创建一个servlet的抽象类,做好初始化工作,后面子类直接继承即可
 * */
public abstract class AbstractBaseServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置请求(响应)编码和方式
        req.setCharacterEncoding("UTF-8");
        resp.setCharacterEncoding("UTF-8");
        //请求数据类型为application/json,req.getInputStream获取请求体,数据作为输入流获取
        //通过json框架反序列化为一个Java对象,请求数据要和对象数据类型一致
        //服务端也返回application/json
        resp.setContentType("application/json");

        //使用req.getServletPath()获取请求路径
        JSONResponse json = new JSONResponse();
        try {
            //调用子类重写的方法
            Object data = process(req, resp);
            //子类的process方法正常执行,没有异常
            json.setSuccess(true);
            json.setData(data);
        }catch (Exception e){
            //处理异常,如SQLException,JSON异常,使用自定义异常返回异常
            e.printStackTrace();
            String s = "未知错误";
            String code = "UnknownError";
            if (e instanceof AppException){
                code = ((AppException)e).getCode();
                s = e.getMessage();
            }
            //json.setSuccess默认值就是false,此处可以不用设置
            json.setCode(code);
            json.setMessage(s);
        }
        PrintWriter pw = resp.getWriter();
        pw.write(JSONUtil.serialize(json));
        pw.flush();
        pw.close();
    }
    //模板方法,用来完成servlet初始化操作
    protected abstract Object process(HttpServletRequest req,
                                    HttpServletResponse resp) throws IOException;
}

servlet层的具体实现

注册功能

import org.example.dao.UserDao;
import org.example.exception.AppException;
import org.example.model.User;

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/register")
public class RegisterServlet extends AbstractBaseServlet{
    @Override
    protected Object process(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        User user = UserDao.findUser(username);
        if (user == null){
            User newUser = new User();
            newUser.setUsername(username);
            newUser.setPassword(password);
            UserDao.addUser(newUser);
        }else {
            throw new AppException("RegisterError","用户已存在");
        }
        return null;
    }
}

登录功能

import org.example.dao.LoginDao;
import org.example.exception.AppException;
import org.example.model.User;

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

@WebServlet("/login")
public class LoginServlet extends AbstractBaseServlet{

    @Override
    protected Object process(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        //解析请求数据
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        //进行数据库用户名密码校验
        User user = LoginDao.query(username);
        if (user == null){
            throw new AppException("Login002","用户不存在");
        }
        if (!user.getPassword() .equals(password)){
            throw new AppException("Login003","用户名或者密码错误");
        }
        HttpSession session = req.getSession();
        session.setAttribute("user",user);
        return null;
    }
}

新增博客功能

import org.example.dao.ArticleDao;
import org.example.model.Article;
import org.example.model.User;
import org.example.util.JSONUtil;

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

@WebServlet("/articleAdd")
public class ArticleAddServlet extends AbstractBaseServlet{
    @Override
    protected Object process(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        HttpSession session = req.getSession(false);
        User user = (User)session.getAttribute("user");
        //请求数据类型是application/json,需要用输入流
        InputStream inputStream = req.getInputStream();
        Article article = JSONUtil.deserialize(inputStream,Article.class);
        article.setUserId(user.getId());
        int num = ArticleDao.insert(article);
        return null;
    }
}

删除功能

@WebServlet("/articleDelete")
public class ArticleDeleteServlet extends AbstractBaseServlet{
    @Override
    protected Object process(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        String ids = req.getParameter("ids");
        int num = ArticleDao.delete(ids.split(","));

        return null;
    }
}

修改博客内容功能

import org.example.dao.ArticleDao;
import org.example.model.Article;
import org.example.util.JSONUtil;

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;

@WebServlet("/articleDetail")
public class ArticleUpdateServlet extends AbstractBaseServlet{
    @Override
    protected Object process(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        //请求的格式是application/json,需要将其反序列化为一个Java对象
        InputStream inputStream = req.getInputStream();
        Article article = JSONUtil.deserialize(inputStream,Article.class);
        int num = ArticleDao.update(article);
        return null;
    }
}

部分功能截图展示

在这里插入图片描述
在这里插入图片描述
项目源码以及前端源码链接:
github链接

  • 1
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值