前面我们学习了前端的博客系统,然后我们现在又学了后端的 servlet 技术,基本就可以写一个可以自己增删查改的网页了
所谓的前后端分离,通俗的说,就是这种方式下的服务器端不关注页面的内容,而只是给网页端提供数据,然后网页端通过 ajax 的方式和服务器之间交互数据,网页拿到数据之后再根据数据的内容渲染到页面上..
渲染就是相当于给你一个模板,然后里面的内容可以通过后端数据随意更改.
一. 准备工作
先准备好servlet:servlet准备工作
之前讲过的,我这里就简单点写了
1.创建Maven项目

2. 引入依赖. (servlet,jackson,mysql)
去中央仓库搜索下载(版本别搞错了):https://mvnrepository.com/
<!-- 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/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.49</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.0</version>
</dependency>

引入后记得刷新一下:

3.创建必要的目录

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>

4. 编写代码
在 java目录里新建一个HelloServlet

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;
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("hello");
}
}
注意路径
5/6. 打包部署程序
我们下载的 smart tomcat,就不用频繁的去打包部署了
7. 在浏览器中验证
点击小三角运行:
到这里准备工作算是做完了,接下来就可以执行接下来的步骤了
二. 编写数据库的操作代码
1.创建数据库/表结构(数据库设计)
这里就要根据你的前端页面来设计了,之前搞得什么页面,需求是什么就设计什么,我们实现的博客系统,需要用户表和博客表,我们就设计这俩
建议大家现在记事本上写好了在直接拷贝到数据库上,这样不容易出错
db.sql
-- 编写建库建表的 sql
create database if not exists blog_system;
use blog_system;
-- 创建一个博客表.
drop table if exists blog;
create table blog (
blogId int primary key auto_increment,
title varchar(1024),
content mediumtext,
userId int, -- 文章作者的 id
postTime datetime -- 发布时间
);
-- 给博客插点数据,后面方便我们进行测试
insert into blog values(null,'第一篇博客','今天开始学Java了!',1,now());
insert into blog values(null,'第二篇博客','昨天开始学Java!',1,now());
insert into blog values(null,'第三篇博客','明天开始学Java',1,now());
insert into blog values(null,'第一篇博客','今天开始学C++',2,now());
insert into blog values(null,'第二篇博客','明天开始学C++',2,now());
-- 创建一个用户表
drop table if exists user;
create table user (
userId int primary key auto_increment,
username varchar(128) unique, -- 后续会使用用户名进行登录, 一般用于登录的用户名都是不能重复的.
password varchar(128)
);
insert into user values(null,'zhangsan','123');
insert into user values(null,'lisi','123');

2. 封装数据库操作
2.1 先创建 DBUtil 封装数据库连接的操作
我们相关都操作放到各自的包里面,这样让我们后面写起来不容易混乱!!
这里就先用之前学过的 JDBC 来连接数据库
package model;
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
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 final String URL = "jdbc:mysql://127.0.0.1:3306/blog_system?characterEncoding=utf8&useSSL=false";
private static final String USERNAME = "root";
private static final String PASSWORD = "root";
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(URL);
((MysqlDataSource)dataSource).setUser(USERNAME);
((MysqlDataSource)dataSource).setPassword(PASSWORD);
}
}
}
return dataSource;
}
public static Connection getConnection() throws SQLException {
return getDataSource().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();
}
}
}
}
2.2 创建实体类
使用实体类来表示数据库中的一条记录,根据数据库创建的表,我们需要创建 Blog 类和 User 类
这样写方便我们观察:

Blog
package model;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
//每一个 Blog 对象 对应到 blog 表中的一条记录,所以我们要对照着表结构来设置
public class Blog {
private int blogId;
private String title;
private String content;
private int userId;
private Timestamp postTime;
public int getBlogId() {
return blogId;
}
public void setBlogId(int blogId) {
this.blogId = blogId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
// public Timestamp getPostTime() {
// return postTime;
// }
// 把这里的 getter 方法给改了, 不是返回一个时间戳对象, 而是返回一个 String (格式化好的时间)
public String getPostTime() {
// 使用 SimpleDateFormat 来完成时间戳到格式化日期时间的转换.
// 这个转换过程, 需要在构造方法中指定要转换的格式, 然后调用 format 来进行转换
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return simpleDateFormat.format(postTime);
}
public void setPostTime(Timestamp postTime) {
this.postTime = postTime;
}
}
User
package model;
//每个 User对象,表示 user 表中的一条记录
public class User {
//先初始化,后面判断是否是登录状态
private int userId = 0;
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;
}
}
2.3 封装针对数据的增删改查
我们把提供了增删改查这样的类,称为 DAO
BlogDao
package model;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
//这个类用于去封装博客表的基本操作
public class BlogDao {
// 一. 往博客列表里插入一个博客.
public void insert(Blog blog){
//JDBC 的基本代码
Connection connection = null;
PreparedStatement statement = null;
try {
// 1. 和数据库建立连接
connection = DBUtil.getConnection();
// 2. 构造 sql 语句
String sql = "insert into blog values(null,?,?,?,now())";
statement = connection.prepareStatement(sql);
statement.setString(1,blog.getTitle());
statement.setString(2,blog.getContent());
statement.setInt(3,blog.getUserId());
// 3. 执行 sql
statement.executeUpdate();
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
// 4. 关闭资源
DBUtil.close(connection,statement,null);
}
}
//二. 能够获取到博客表中的所有博客的信息(用于博客列表页,注意此处的获取不一定就是 里面的所有内容)
public List<Blog> selectAll(){
List<Blog> blogs = new ArrayList<>();
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
connection = DBUtil.getConnection();
//我们想要让最新的排在博客列表最上面
String sql = "select * from blog order by postTime desc";
statement = connection.prepareStatement(sql);
resultSet = statement.executeQuery();
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() > 50){
content = content.substring(0,50)+"...";
}
blog.setContent(content);
blog.setUserId(resultSet.getShort("userId"));
blog.setPostTime(resultSet.getTimestamp("postTime"));
blogs.add(blog);
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
DBUtil.close(connection,statement,resultSet);
}
return blogs;
}
//三. 能够根据博客 id 获取到指定的博客内容(用于在博客详情页)
public Blog selectOne(int blogId){
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
connection = DBUtil.getConnection();
String sql = "select * from blog where blogId = ?";
statement = connection.prepareStatement(sql);
statement.setInt(1,blogId);
resultSet = statement.executeQuery();
// 这里根据主键来查询的,查到的要么是 0,要么是 1..
if(resultSet.next()){
Blog blog = new Blog();
blog.setBlogId(resultSet.getInt("blogId"));
blog.setTitle(resultSet.getString("title"));
blog.setContent(resultSet.getString("content"));
blog.setUserId(resultSet.getShort("userId"));
blog.setPostTime(resultSet.getTimestamp("postTime"));
return blog;
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
DBUtil.close(connection,statement,resultSet);
}
return null;
}
//四. 从博客列表中,根据博客 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 throwables) {
throwables.printStackTrace();
}finally {
DBUtil.close(connection,statement,null);
}
}
//五. 修改
public void update(Blog blog) {
Connection connection = null;
PreparedStatement statement = null;
try {
// 1. 建立连接
connection = DBUtil.getConnection();
// 2. 拼装 SQL 语句
String sql = "update blog set content = ? ,title = ? where blogId = ?";
statement = connection.prepareStatement(sql);
statement.setString(1, blog.getContent());
statement.setString(2, blog.getTitle());
statement.setInt(3, blog.getBlogId());
// 3. 执行 SQL 语句
int ret = statement.executeUpdate();
if (ret == 1) {
System.out.println("编辑成功");
} else {
System.out.println("编辑失败");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBUtil.close(connection, statement, null);
}
}
//6. 计算个人文章的总数
public static Integer selectTotal(int userId){
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
connection = DBUtil.getConnection();
String sql = "select count(userId) from blog where userId = ?";
statement = connection.prepareStatement(sql);
statement.setInt(1,userId);
resultSet = statement.executeQuery();
if(resultSet.next()){
}
return resultSet.getInt(1);
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
DBUtil.close(connection,statement,resultSet);
}
return null;
}
public static void main(String[] args) {
Integer ret1 = selectTotal(2);
System.out.println(ret1);
BlogDao blogDao = new BlogDao();
Blog blog = new Blog();
blog.setUserId(1);
blog.setBlogId(1);
blog.setTitle("hahah");
blog.setContent("fff");
blogDao.update(blog);
}
}
UserDao
package model;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
//提供了针对用户表的基本操作
public class UserDao {
public void insert(User user){
Connection connection = null;
PreparedStatement statement = null;
try {
connection = DBUtil.getConnection();
String sql = "insert into user values(null,?,?)";
statement = connection.prepareStatement(sql);
statement.setString(1, user.getUsername());
statement.setString(2, user.getPassword());
statement.executeUpdate();
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
DBUtil.close(connection,statement,null);
}
}
//主要实现
// 1. 根据用户名来查找用户信息
//这个会在登录逻辑中使用
public User selectByName(String username) {
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
connection = DBUtil.getConnection();
String sql = "select * from user where username = ?";
statement = connection.prepareStatement(sql);
statement.setString(1, username);
resultSet = statement.executeQuery();
// 此处 username 使用 unique 约束, 要么能查到一个, 要么一个都查不到.
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 throwables) {
throwables.printStackTrace();
} finally {
DBUtil.close(connection, statement, resultSet);
}
return null;
}
// 2. 根据用户 id 来找用户信息.
// 博客详情页, 就可以根据用户 id 来查询作者的名字, 把作者名字显示出来.
public User selectById(int userId) {
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
connection = DBUtil.getConnection();
String sql = "select * from user where userId = ?";
statement = connection.prepareStatement(sql);
statement.setInt(1, userId);
resultSet = statement.executeQuery();
// 此处 username 使用 unique 约束, 要么能查到一个, 要么一个都查不到.
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 throwables) {
throwables.printStackTrace();
} finally {
DBUtil.close(connection, statement, resultSet);
}
return null;
}
}
到这里 数据库操作都给准备好了
下面就是实现服务器的代码了
三. 约定前后端交互接口
我们先把之前写的前端博客系统给拷贝到 webapp 里面

博客系统:链接
1. 实现博客列表
1.1约定前后端交互接口
[请求]
GET /blog
[响应] [
{
blogId: 1,
title: "第一篇博客",
content: "博客正文",
userId: 1,
postTime: "2022-05-27 12:00:00"
},
{
blogId: 2,
title: "第二篇博客",
content: "博客正文",
userId: 1,
postTime: "2022-05-27 12:10:00"
},
...
]
我们约定, 浏览器给服务器发送一个 GET /blog 这样的 HTTP 请求, 服务器给浏览器返回了一个 JSON 格式的数据.
1.2 实现服务器代码
package controller;
import model.Blog;
import model.BlogDao;
import com.fasterxml.jackson.databind.ObjectMapper;
import javax.servlet.ServletException;
import javax

本文详细介绍了如何利用Maven、Servlet和Jackson库构建一个前后端分离的个人博客系统。首先,通过创建Maven项目并引入相关依赖,接着配置web.xml和编写HelloServlet。然后,设计数据库表结构,使用DBUtil、BlogDao、UserDao等类封装数据库操作。在实现博客列表、详情、登录、注销、发布、删除和显示用户信息等功能时,约定前后端交互接口,并编写相应的服务器和客户端代码。最后,通过Postman验证了各个接口的正确性,实现了完整的个人博客系统。





最低0.47元/天 解锁文章
353





