话接上文,我们讲述了实现一个项目的大体步骤和实现了项目的 view 层,也就是前端部分,从这一篇开始,我们来肝后端部分。
上篇博客地址:手把手教你实现一个JavaWeb项目:创建一个自己的网页博客系统(前端+后端)(一)_小型骷髅的博客-CSDN博客
目录:
1、具体代码实现:
2、M——数据库部分:
model 层分为 sql 和jdbc ,先来创建数据库和数据表,打开mysql,输入下列 sql 语句:
-- 通过这个文件来编写建库建表的sql
-- 先建立数据库:
create database if not exists blogSystem;
-- 选中数据库:
use java102_blog;
-- 创建一个博客表:
drop table if exists blog;
create table blog(
blogId int primary key auto_increment, -- 创建博客ID列,并作为主键约束,设置自增主键
title varchar(1024), -- 创建标题列
content mediumtext, -- 创建正文列,类型设为mediumtext,表示较长的字符串
userId int, -- 创建作者ID列,表明文章的作者是谁
postTime datetime -- 创建发布时间列
);
-- 在博客表插入两条数据:
insert into blog values(null,'我的第一篇博客','一二三四五,六七八九十',1,now());
insert into blog values(null,'我的第二篇博客','一二三四五,十九八七六',1,now());
insert into blog values(null,'我的第三篇博客','一二三四五,六六六六六',1,now());
insert into blog values(null,'我的第一篇博客','一二三四五,上山打老虎',2,now());
-- 创建一个用户表:
drop table if exists user;
create table user(
userId int primary key auto_increment, -- 创建用户ID列,并作为自增主键
username varchar(128) unique, -- 创建用户名列,因为后续会使用用户名登录,所以要求不能重复
password varchar(128)
);
-- 在用户表插入两条数据:
insert into user values(null,"zhangsan","123");
insert into user values(null,"lisi","123");
建立好数据后,在main目录下的java目录里创建一个文件夹,命名为 model :
1)创建一个文件,命名为 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 simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return simpleDateFormat.format(postTime);
}
public void setPostTime(Timestamp postTime) {
this.postTime = postTime;
}
}
2)创建一个文件,命名为 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;
/**
* 描述:这个类用于封装 博客表 的基本操作(增删改查)
* 这些操作中是增删查,还没有改的操作
* JDBC 基本代码
*/
public class BlogDao {
//1、往博客表里插入一篇博客:
public void insert(Blog blog){
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 e) {
e.printStackTrace();
}finally {
//4)释放资源,关闭连接:
DBUtil.close(connection,statement,null);
}
}
//2、能够获取到博客表里所有的博客信息(用于博客列表页,每篇博客不一定是显示全部信息)
public List<Blog> selectAll(){
List<Blog> blogs = new ArrayList<>();
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
//1)和数据库建立连接:
connection = DBUtil.getConnection();
//2)构造SQl语句:
String sql = "select * from blog order by postTime desc";
statement = connection.prepareStatement(sql);
//3)执行SQL:
resultSet = statement.executeQuery();
//4)遍历结果集(将查询到的结果resultSet变为blog对象放到blogs数组里)
while (resultSet.next()){
Blog blog = new Blog();
blog.setBlogId(resultSet.getInt("blogId"));
blog.setTitle(resultSet.getString("title"));
//这里针对博客列表页的“正文”content进行截取,如果其长度大于50,那么只取前50:
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 e) {
e.printStackTrace();
}finally {
//5)释放资源,关闭连接:
DBUtil.close(connection,statement,resultSet);
}
return blogs;
}
//3、能够根据博客id获取到指定的博客内容(用于博客详情页)
public Blog selectOne(int blogId){
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
//1)和数据库建立连接:
connection = DBUtil.getConnection();
//2)构造SQl语句:
String sql = "select * from blog where blogId = ?";
statement = connection.prepareStatement(sql);
statement.setInt(1,blogId);
//3)执行SQL:
resultSet = statement.executeQuery();
//4)遍历结果集:
//因为此处是blogId(使用了主键约束)作为查询依据的,结果要么为1,要么为0,所以不用where,而用if
//如果resultSet里没有数据,就不会执行if,直接返回null
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 e) {
e.printStackTrace();
}finally {
//5)释放资源,关闭连接:
DBUtil.close(connection,statement,resultSet);
}
return null;
}
//4、从博客表中,根据博客id,删除某篇博客
public void delete(int blogId){
Connection connection = null;
PreparedStatement statement = null;
try {
//1)和数据库建立连接:
connection = DBUtil.getConnection();
//2)构造SQl语句:
String sql = "delete from blog where blogId = ?";
statement = connection.prepareStatement(sql);
statement.setInt(1,blogId);
//3)执行SQL:
statement.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}finally {
//4)释放资源,关闭连接:
DBUtil.close(connection,statement,null);
}
}
}
3)创建一个文件,命名为 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;
}
}
4)创建一个文件,命名为 UserDao :
package model;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* 描述:这个类用于封装 用户表 的基本操作(增删改查)
*/
public class UserDao {
//需要实现的操作:
//针对这个类来说,简化写就行了,不考虑注册/注销 这样的功能。
//1、根据用户名来查找用户信息(在登录逻辑中出现):
public User selectByName(String username){
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
//1)和数据库建立连接:
connection = DBUtil.getConnection();
//2)构造SQl语句:
String sql = "select * from user where username = ?";
statement = connection.prepareStatement(sql);
statement.setString(1,username);
//3)执行SQL:
resultSet = statement.executeQuery();
//4)遍历结果集:
//因为此处username使用的是unique约束,所以要么查到的结果为1要么为0,所以用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 {
//5)释放资源,关闭连接:
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 {
//1)和数据库建立连接:
connection = DBUtil.getConnection();
//2)构造SQl语句:
String sql = "select * from user where userId = ?";
statement = connection.prepareStatement(sql);
statement.setInt(1,userId);
//3)执行SQL:
resultSet = statement.executeQuery();
//4)遍历结果集:
//因为此处username使用的是unique约束,所以要么查到的结果为1要么为0,所以用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 {
//5)释放资源,关闭连接:
DBUtil.close(connection,statement,resultSet);
}
return null;
}
}
5)创建一个文件,命名为 DBUtil :
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/java102_blog?characterEncoding=utf8&useSSL=false";
//用户名
private static final String USERNAME = "root";
//密码
private static final String PASSWORD = "1234";
//创建一个数据源对象:
private volatile static 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 preparedStatement, ResultSet resultSet){
if (resultSet != null){
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (preparedStatement != null){
try {
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
3、C——控制器,后端部分:
这一层主要包含后端服务器代码,咱们现在java目录里创建一个文件夹,命名为 controller 。
1)创建一个文件,命名为 BlogServlet :
package controller;
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 javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.List;
/**
* 描述:通过这个类,来处理 /blog 这个路径的请求
*/
@WebServlet("/blog")
public class BlogServlet extends HttpServlet {
private ObjectMapper objectMapper = new ObjectMapper();
//这个方法来获取数据库中的博客列表:
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("application/json; charset=utf8");
BlogDao blogDao = new BlogDao();
// 先尝试获取到 req 中的 blogId 参数. 如果该参数存在, 说明是要请求博客详情
// 如果该参数不存在, 说明是要请求博客的列表.
String param = req.getParameter("blogId");
if (param == null) {
// 不存在参数, 获取博客列表
List<Blog> blogs = blogDao.selectAll();
// 把 blogs 对象转成 JSON 格式.
String respJson = objectMapper.writeValueAsString(blogs);
resp.getWriter().write(respJson);
} else {
// 存在参数, 获取博客详情
int blogId = Integer.parseInt(param);
Blog blog = blogDao.selectOne(blogId);
String respJson = objectMapper.writeValueAsString(blog);
resp.getWriter().write(respJson);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session = req.getSession(false);
if (session == null){
// 当前用户未登录,不能提交博客!
resp.setContentType("text/html;charset=utf8");
resp.getWriter().write("当前用户未登录,不能提交博客!");
return;
}
User user = (User) session.getAttribute("user");
if (user == null){
// 当前用户未登录,不能提交博客!
resp.setContentType("text/html;charset=utf8");
resp.getWriter().write("当前用户未登录,不能提交博客!");
return;
}
// 一定得先指定好请求按照哪种编码来执行
req.setCharacterEncoding("utf8");
// 先从请求中获取参数(博客的标题和正文)
String title = req.getParameter("title");
String content =req.getParameter("content");
if (title == null || "".equals(title) || content == null || "".equals(content)){
// 直接告诉客户端,请求参数不对
resp.setContentType("text/html;charset=utf8");
resp.getWriter().write("提交博客失败!缺少必要的请求参数!");
return;
}
// 构造Blog对象,把当前信息填进去,并插入到数据库中
// 此处要给Blog设置的属性,主要为:title,content,userId(作者信息)
Blog blog = new Blog();
blog.setTitle(title);
blog.setContent(content);
// 作者Id就是当前提交这个博客的用户的id
blog.setUserId(user.getUserId());
BlogDao blogDao = new BlogDao();
blogDao.insert(blog);
// 博客提交成功后,跳转(重定向)到博客列表页
resp.sendRedirect("blog_list.html");
}
}
2)创建一个文件,命名为 LoginServlet :
package controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import model.User;
import model.UserDao;
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 javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
private ObjectMapper objectMapper = new ObjectMapper();
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf8"); //针对请求进行设置,使用utf8格式来解析请求;
resp.setCharacterEncoding("utf8"); //针对响应进行设置,构造数据时,按照utf8来构造;
//1、获取到请求中的参数
String username = req.getParameter("username");
String password = req.getParameter("password");
if (username == null || "".equals(username) || password == null || "".equals(password)){
//请求的内容缺失,肯定是登陆失败!
resp.setContentType("text/html;charset=utf8");
resp.getWriter().write("用户名或者密码为空,请重新输入!");
return;
}
//2、和数据库中的数据比较
UserDao userDao = new UserDao();
User user = userDao.selectByName(username);
if (user == null || !user.getPassword().equals(password)){
//用户不存在或者密码不正确,也是登陆失败!
resp.setContentType("text/html;charset=utf8");
resp.getWriter().write("用户名或者密码错误,请重新输入!");
return;
}
//3、如果比较通过就创建会话
HttpSession session = req.getSession(true);
// 把刚才的用户信息存储到会话中:
session.setAttribute("user",user);
//4、返回一个重定向报文,跳转到博客列表页:
resp.sendRedirect("blog_list.html");
}
//这个方法用来检测当前的登陆状态:
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("application/json;charset=utf8");
HttpSession session = req.getSession(false);
//检测会话是否存在:
if (session == null){
//不存在说明未登录
User user = new User();
resp.getWriter().write(objectMapper.writeValueAsString(user));
return;
}
User user = (User) session.getAttribute("user");
if (user == null){
//虽然有会话,但是会话没有user对象,也视为未登录
user = new User();
resp.getWriter().write(objectMapper.writeValueAsString(user));
return;
}
//若代码运行到这,说明已经是登陆状态:
//注意:此处不应该把密码返回到前端,不然会泄露。
user.setPassword("");
resp.getWriter().write(objectMapper.writeValueAsString(user));
}
}
3)创建一个文件,命名为 LogoutServlet :
package controller;
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 javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/logout")
public class LogoutServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 先找到当前用户的会话
HttpSession session = req.getSession(false);
if (session == null){
// 用户没有登录,也就谈不上注销
resp.getWriter().write("当前用户未登录!无法退出!");
return;
}
// 然后把这个用户的会话中的信息给删掉就行了
session.removeAttribute("user");
// 接来下重定向操作,跳转到登录页面:
resp.sendRedirect("blog_login.html");
}
}
4)创建一个文件,命名为 BlogDeleteServlet :
package controller;
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 javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/blogDelete")
public class BlogDeleteServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 1、先检测当前用户是否登录
HttpSession session = req.getSession(false);
if (session == null){
resp.setContentType("text/html;charset=utf8");
resp.getWriter().write("当前用户未登录!不能删除!");
return;
}
User user = (User) session.getAttribute("user");
if (user == null){
resp.setContentType("text/html;charset=utf8");
resp.getWriter().write("当前用户未登录!不能删除!");
return;
}
// 2、获取到当前参数的blogId
String blogId = req.getParameter("blogId");
if (blogId == null || "".equals(blogId)){
resp.setContentType("text/html;charset=utf8");
resp.getWriter().write("当前 blogId参数 不正确!");
return;
}
// 3、获取到要删除的博客信息
BlogDao blogDao = new BlogDao();
Blog blog = blogDao.selectOne(Integer.parseInt(blogId));
if (blog == null){
resp.setContentType("text/html;charset=utf8");
resp.getWriter().write("当前要删除的博客不存在!");
return;
}
// 4、再次校验,当前用户是否为博客的作者
if (user.getUserId() != blog.getUserId()){
// 这一点在前端也处理过,但是再校验一次也不是坏事。
resp.setContentType("text/html;charset=utf8");
resp.getWriter().write("当前登录的用户不是作者,没有权限删除!");
return;
}
// 5、开始删除
blogDao.delete(Integer.parseInt(blogId));
// 6、跳转(重定向)到博客列表页
resp.sendRedirect("blog_list.html");
}
}
5)创建一个文件,命名为 AuthorServlet :
package controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import model.Blog;
import model.BlogDao;
import model.User;
import model.UserDao;
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("/authorInfo")
public class AuthorServlet extends HttpServlet {
private ObjectMapper objectMapper = new ObjectMapper();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("application/json;charset=utf8");
//通过这个方法,来获取到指定博客的作业信息
String param = req.getParameter("blogId");
if (param == null || "".equals(param)){
//缺少参数
resp.getWriter().write("{ \"ok\": false,\"reason\": \"参数缺失\" }");
return;
}
//根据当前的blogId在数据库中进行查找,找到对应的Blog对象,再进一步根据Blog对象,找到作者信息:
BlogDao blogDao = new BlogDao();
Blog blog = blogDao.selectOne(Integer.parseInt(param));
if (blog == null){ //说明此时要找的博客不存在
resp.getWriter().write("{ \"ok\": false,\"reason\": \"要查询的博客不存在!\" }");
return;
}
//根据blog对象,查询到用户对象
UserDao userDao = new UserDao();
User author = userDao.selectById(blog.getUserId());
if (author == null){
resp.getWriter().write("{ \"ok\": false,\"reason\": \"要查询的用户不存在!\" }");
return;
}
//把author返回到浏览器这边
//注意:要把密码给消掉,防止泄露密码
author.setPassword("");
resp.getWriter().write(objectMapper.writeValueAsString(author));
}
}
结语:
项目到这呢,已经全部结束了,你可以先运行服务器,然后在浏览器输入:127.0.0.1:8080/blog_system/blog_login.html 验证一下你自己的JavaWeb项目。最后如果你觉得对自己有帮助的话不妨点个赞,谢谢!
码云:博客系统地址