1)注册新用户
2)登录已有用户
3)展示博客列表(包含文章标题以及作者信息),点击标题就会跳转到文章详情页
4)文章详情页中,显示文章标题,作者,以及文章内容
5)发布新的博客
6)删除自己的博客
点击文章列表后边的删除按钮就会删除文章,注意每个用户只能删除自己写的文章。
maven:使用maven来管理依赖,打包项目
mysql:使用MySQL作为业务数据的存储
html:使用HTML来编写前端页面
tomcat:使用Tomcat作为Web项目部署的服务器
servlet:每个页面调用后台接口都需要使用Servlet来完成业务。
多线程:synchronized、volatile关键字,在多线程下访问Servlet共享变量,需要保证线程安全
Maven、IDEA、MySQL、Chrome浏览器、Fiddler4抓包工具
加入依赖:a)Servlet API b)MySQL connector
配置pom.xml 文件:
设计当前的代码中用到的数据库中有几张表,每个表包含哪些字段,每个表之间的关联关系。在这里我们需要两张表,用户和文章表。
db.sql:
drop database if exists java16_blogdemo;
create database java16_blogdemo;
use java16_blogdemo;
drop table if exists user;
create table user (
userId int primary key auto_increment,
name varchar(50) unique,
password varchar(50)
);
drop table if exists article;
create table article (
articleId int primary key auto_increment,
title varchar(255),
content text,
userId int,
foreign key(userId) references user(userId)
);
package modle;
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;
/**
* @ Created with IntelliJ IDEA.
* @ClassName DBUtil
* @Description
* @Author by小房
* @Date 2020/7/15 17:51
*/
// 管理数据库连接 建立连接 断开连接
public class DBUtil {
private static volatile DataSource dataSource = null;
private static final String URL = "jdbc:mysql://127.0.0.1:3306/java16_blogdemo?characterEncoding=utf-8&useSSL=true";
private static final String USERNAME = "root";
private static final String PASSWORD = "***";//这里写自己的密码
public 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() {
try {
return getDataSource().getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
// 通过这个方法来断开连接
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) {
e.printStackTrace();
}
}
}
User:
package modle;
/**
* @ Created with IntelliJ IDEA.
* @ClassName User
* @Description
* @Author by小房
* @Date 2020/7/15 17:50
*/
public class User {
private int userId;
private String name;
private String password;
public int getUserId() {
return userId;
}
public String getName() {
return name;
}
public String getPassword() {
return password;
}
public void setUserId(int userId) {
this.userId = userId;
}
public void setName(String name) {
this.name = name;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"userId=" + userId +
", name='" + name + '\'' +
", password='" + password + '\'' +
'}';
}
}
article:
package modle;
/**
* @ Created with IntelliJ IDEA.
* @ClassName Article
* @Description
* @Author by小房
* @Date 2020/7/15 17:51
*/
public class Article {
private int articleId;
private String title;
private String content;
private int userId;
public int getArticleId() {
return articleId;
}
public String getTitle() {
return title;
}
public String getContent() {
return content;
}
public int getUserId() {
return userId;
}
public void setArticleId(int articleId) {
this.articleId = articleId;
}
public void setTitle(String title) {
this.title = title;
}
public void setContent(String content) {
this.content = content;
}
public void setUserId(int userId) {
this.userId = userId;
}
@Override
public String toString() {
return "Article{" +
"articleId=" + articleId +
", title='" + title + '\'' +
", content='" + content + '\'' +
", userId=" + userId +
'}';
}
}
Dao表示数据访问层
通过UserDao 这个类来实现对用户数据库表的操作
package modle;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* @ Created with IntelliJ IDEA.
* @ClassName UserDao
* @Description
* @Author by小房
* @Date 2020/7/16 22:03
*/
public class UserDao {
// 1、新增用户
public void add(User user) {
// 1、获取数据库连接
Connection connection = DBUtil.getConnection();
// 2、拼装 sql
String sql = "insert into user values (null, ?, ?)";
PreparedStatement statement = null;
try {
statement = connection.prepareStatement(sql);
statement.setString(1, user.getName());
statement.setString(2, user.getPassword());
// 3、执行 sql
int ret = statement.executeUpdate();
if (ret != 1) {
System.out.println("插入新用户失败");
return;
}
System.out.println("插入新用户成功");
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 4、释放数据库连接
DBUtil.close(connection, statement, null);
}
}
// 2、按照名字查找用户
public User selectByName(String name) {
// 1、建立数据库连接
Connection connection = DBUtil.getConnection();
// 2、拼装sql
String sql = "select * from user where name = ?";
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
statement = connection.prepareStatement(sql);
statement.setString(1, name);
// 3、执行 sql
resultSet = statement.executeQuery();
// 4、遍历结构集
if (resultSet.next()) {
User user = new User();
user.setUserId(resultSet.getInt("userId"));
user.setName(resultSet.getString("name"));
user.setPassword(resultSet.getString("password"));
return user;
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBUtil.close(connection, statement, resultSet);
}
return null;
}
// 根据用户 id 找到用户信息
public User selectById(int userId) {
// 1、建立数据库连接
Connection connection = DBUtil.getConnection();
// 2、拼装sql
String sql = "select * from user where userId = ?";
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
statement = connection.prepareStatement(sql);
statement.setInt(1, userId);
// 3、执行 sql
resultSet = statement.executeQuery();
// 4、遍历结构集
if (resultSet.next()) {
User user = new User();
user.setUserId(resultSet.getInt("userId"));
user.setName(resultSet.getString("name"));
user.setPassword(resultSet.getString("password"));
return user;
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBUtil.close(connection, statement, resultSet);
}
return null;
}
/*public static void main(String[] args) {
UserDao userDao = new UserDao();
// 1、先测试 add 方法
//User user = new User();
//user.setName("***");
// user.setPassword("********");
// userDao.add(user);
// 2、测试 selectByName
//User user = userDao.selectByName("fwh");
//System.out.println(user);
}*/
}
通过ArticleDao 这个类来实现对文章的数据库操作
package modle;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
/**
* @ Created with IntelliJ IDEA.
* @ClassName ArticleDao
* @Description
* @Author by小房
* @Date 2020/7/16 20:43
*/
public class ArticleDao {
// 1、新增文章
public void add (Article article) {
// 1、获取数据库连接
Connection connection = DBUtil.getConnection();
// 2、构造 sql
String sql = "insert into article values (null, ?, ?, ?)";
PreparedStatement statement = null;
try {
statement = connection.prepareStatement(sql);
statement.setString(1, article.getTitle());
statement.setString(2, article.getContent());
statement.setInt(3, article.getUserId());
// 3、执行sql
int ret = statement.executeUpdate();
if (ret != 1) {
System.out.println("执行插入文章操作失败");
return;
}
System.out.println("执行插入文章操作成功");
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 4、释放连接
DBUtil.close(connection, statement, null);
}
}
// 2、查看文章列表
public List<Article> selectAll() {
List<Article> articles = new ArrayList<Article>();
// 1、建立连接
Connection connection = DBUtil.getConnection();
// 2、拼装 sql
String sql = "select articleId, title, userId from article";
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
statement = connection.prepareStatement(sql);
// 3、执行 sql
resultSet = statement.executeQuery();
// 4、遍历结果集
while (resultSet.next()) {
// 针对每一个结果记录,都构造一个对应的 Article 对象
Article article = new Article();
article.setArticleId(resultSet.getInt("articleId"));
article.setTitle(resultSet.getString("title"));
article.setUserId(resultSet.getInt("userId"));
articles.add(article);
}
return articles;
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBUtil.close(connection, statement, resultSet);
}
return null;
}
// 3、查看指定文章详情
public Article selectById (int articleId) {
// 1、建立数据库连接
Connection connection = DBUtil.getConnection();
// 2、构造 SQL
String sql = "select * from article where articleId = ?";
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
statement = connection.prepareStatement(sql);
statement.setInt(1, articleId);
// 3、执行 sql
resultSet = statement.executeQuery();
// 4、便利结果集
if (resultSet.next()) {
Article article = new Article();
article.setArticleId(resultSet.getInt("articleId"));
article.setTitle(resultSet.getString("title"));
article.setContent(resultSet.getString("content"));
article.setUserId(resultSet.getInt("userId"));
return article;
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBUtil.close(connection, statement, resultSet);
}
return null;
}
// 4、删除指定文章
public void delete (int articleId) {
// 1、获取连接
Connection connection = DBUtil.getConnection();
// 2、拼装 sql
String sql = "delete from article where articleId = ?";
PreparedStatement statement = null;
try {
statement = connection.prepareStatement(sql);
statement.setInt(1, articleId);
int ret = statement.executeUpdate();
if (ret != 1) {
System.out.println("删除文章失败");
return;
}
System.out.println("删除文章成功");
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBUtil.close(connection, statement, null);
}
}
/*public static void main(String[] args) {
ArticleDao articleDao = new ArticleDao();
// 1、测试新增文章
Article article = new Article();
article.setTitle("this is title 2");
article.setContent("this is content 1 this is content 1 this is content 1this is content 1this is content 1this is content 1this is content 1this is content 1this is content 1this is content 1this is content 1this is content 1this is content 1this is content 1this is content 1this is content 1this is content 1");
article.setUserId(1);
articleDao.add(article);
}*/
}
我们可以针对上边的数据库操作进行简单的测试,有助于提前发现问题,在这里我们需要一些库/框架可以便于测试。
pom.xml 中导入我们的依赖:
我们可能会出现数据库连接不上,就会抛出异常
常见原因:
1)url 写错了
2)用户名,密码错误
3)数据库服务器没有正常启动
4)连接了其他主机的数据库
注意:如果拼装 sql ,直接使用String 来按照字符串拼接的方式来拼装,这样会出现一些问题,比如:不方便也不安全。要尽可能防止SQL注入。
SQL注入理解:
LoginServlet:
package api;
import modle.User;
import modle.UserDao;
import view.HtmlGenerator;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
/**
* @ Created with IntelliJ IDEA.
* @ClassName LoginServlet
* @Description
* @Author by小房
* @Date 2020/7/21 15:12
*/
public class LoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html; charset=utf-8");
//1、获取到用户名和密码, 并进行见到校验
String name = req.getParameter("name");
String password = req.getParameter("password");
if (name == null || "".equals(name) || password == null || "".equals(password)) {
String html = HtmlGenerator.getMessagePage("用户名和密码为空", "login.html");
resp.getWriter().write(html);
return;
}
// 2、数据库中查找,看用户是否存在
// 3、对比密码是否正确
UserDao userDao = new UserDao();
User user = userDao.selectByName(name);
if (user == null || !password.equals(user.getPassword())) {
String html = HtmlGenerator.getMessagePage("用户名或者密码输入错误", "login.html");
resp.getWriter().write(html);
return;
}
// 4、匹配成功则认为登录成功,创建一个 Session
HttpSession httpSession = req.getSession(true);
httpSession.setAttribute("user", user);
String html = HtmlGenerator.getMessagePage("登录成功!", "article");
resp.getWriter().write(html);
}
}
RegisterServlet:
package api;
import modle.User;
import modle.UserDao;
import view.HtmlGenerator;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @ Created with IntelliJ IDEA.
* @ClassName RegisterServlet
* @Description
* @Author by小房
* @Date 2020/7/20 16:46
*/
public class RegisterServlet extends HttpServlet {
//浏览器通过 POST 方法提交注册信息给服务器
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html; charset=utf-8");
// 1、获取到前端提交的数据(用户名, 密码),校验是否合法
String name = req.getParameter("name");
String password = req.getParameter("password");
if (name == null || "".equals(password)) {
// 用户提交的数据有误,返回一个错误页面
String html = HtmlGenerator.getMessagePage("用户名或者密码输入错误", "register.html");
resp.getWriter().write(html);
return;
}
//2、拿着用户名在数据库中进行查找, 看看用户名是否已经存在,如果存在,认为注册失败(用户名不能重复)
UserDao userDao = new UserDao();
User existUser = userDao.selectByName(name);
if (existUser != null) {
String html = HtmlGenerator.getMessagePage("用户名重复,请换个名字!", "register.html");
resp.getWriter().write(html);
return;
}
//3、根据前端提交的数据, 构造 User 对象并插入到数据库当中
User user = new User();
user.setName(name);
user.setPassword(password);
userDao.add(user);
// 4、返回一个结果页面, 提示当前注册成功
String html = HtmlGenerator.getMessagePage("注册成功!点击跳转登录页面", "login.html");
resp.getWriter().write(html);
}
}
ArticleServlet:
package api;
import modle.Article;
import modle.ArticleDao;
import modle.User;
import modle.UserDao;
import view.HtmlGenerator;
import javax.servlet.ServletException;
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;
/**
* @ Created with IntelliJ IDEA.
* @ClassName ArticleServlet
* @Description
* @Author by小房
* @Date 2020/7/21 15:34
*/
public class ArticleServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html; charset=utf-8");
// 1、验证用户是否已经登录,如果尚未登录,就提示用户进行登录操作
HttpSession httpSession = req.getSession(false);
if (httpSession == null) {
// 当前状态就是未登录状态
String html = HtmlGenerator.getMessagePage("请先进行登录!", "login.html");
resp.getWriter().write(html);
return;
}
User user = (User) httpSession.getAttribute("user");
// 2、判断请求是否存在 articleId 参数
String articleIdStr = req.getParameter("articleId");
if (articleIdStr == null) {
// a)没有这个参数就去执行获取文章列表操作
getAllArticle(user, resp);
} else {
// b) 有这个参数就去执行获取文章具体内容
getOneArticle(Integer.parseInt(articleIdStr), user, resp);
}
}
private void getOneArticle(int articleId, User user, HttpServletResponse resp) throws IOException {
// 1、查找数据库
ArticleDao articleDao = new ArticleDao();
Article article = articleDao.selectById(articleId);
if (article == null) {
// 文章未找到
String html = HtmlGenerator.getMessagePage("文章不存在", "article");
resp.getWriter().write(html);
return;
}
// 2、根据作者 id 找到作者信息,进一步得到作者姓名
UserDao userDao = new UserDao();
User author = userDao.selectById(article.getUserId()); //在这里刚才错误 在这里是根据用户id 获得作者信息
// 3、构造页面
String html = HtmlGenerator.getArticleDetailPage(article, user, author);
resp.getWriter().write(html);
}
private void getAllArticle(User user, HttpServletResponse resp) throws IOException {
// 1、查找数据库
ArticleDao articleDao = new ArticleDao();
List<Article> articles = articleDao.selectAll();
// 2、构造页面
String html = HtmlGenerator.getArticleListPage(articles, user);
resp.getWriter().write(html);
}
// 实现新增文章的逻辑
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html; charset=utf-8");
// 1、判断用户登录状态,如果用户上未登录,就要提醒用户登录
HttpSession httpSession = req.getSession(false);
if (httpSession == null) {
String html = HtmlGenerator.getMessagePage("您尚未登录", "login.html");
resp.getWriter().write(html);
return;
}
User user = (User) httpSession.getAttribute("user");
// 2、从请求中读取浏览器提交的数据(title , content) ,并进行简单的校验
String title = req.getParameter("title");
String content = req.getParameter("content");
if (title == null || "".equals(title)
|| content == null ||"".equals(content)) {
String html = HtmlGenerator.getMessagePage("提交的标题或者内容为空", "article");
resp.getWriter().write(html);
return;
}
// 3、把数据放在数据库中
ArticleDao articleDao = new ArticleDao();
Article article = new Article();
article.setUserId(user.getUserId());
article.setContent(content);
article.setTitle(title);
articleDao.add(article);
// 4、返回一个插入成功的页面
String html = HtmlGenerator.getMessagePage("发布成功!", "article");
resp.getWriter().write(html);
return;
}
}
DeleteArticleServlet:
package api;
import modle.Article;
import modle.ArticleDao;
import modle.User;
import view.HtmlGenerator;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
/**
* @ Created with IntelliJ IDEA.
* @ClassName DeleteArticleServlet
* @Description
* @Author by小房
* @Date 2020/7/21 18:08
*/
public class DeleteArticleServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html; charset=utf-8");
// 1、验证用户的登录状态,如果未登录,肯定不能删除
HttpSession httpSession = req.getSession(false);
if (httpSession == null) {
String html = HtmlGenerator.getMessagePage("您尚未登陆!", "login.html");
resp.getWriter().write(html);
return;
}
User user = (User) httpSession.getAttribute("user");
// 2、根据请求内容, 获取要删除的文章id
String articleIdStr = req.getParameter("articleId");
if (articleIdStr == null || "".equals(articleIdStr)) {
String html = HtmlGenerator.getMessagePage("要删除的文章不存在", "article");
resp.getWriter().write(html);
return;
}
// 3、根据文章id 查到文章的作者,只有当文章作者是当前用户才可以进行删除操作
ArticleDao articleDao = new ArticleDao();
Article article = articleDao.selectById(Integer.parseInt(articleIdStr));
if (article.getUserId() != user.getUserId()) {
String html = HtmlGenerator.getMessagePage("您只能删除自己的文章!", "article");
resp.getWriter().write(html);
return;
}
// 4、真正执行删除操作
articleDao.delete(Integer.parseInt(articleIdStr));
// 5、返回一个删除成功的页面
String html = HtmlGenerator.getMessagePage("删除成功!",
"article");
resp.getWriter().write(html);
}
}
注意:如果我们出现一些问题一定不要慌,要去定位问题解决问题。
比如:提交没反应
我们先用Fiddle 抓包看看,如果请求构造的有问题,那么就是网页的问题;如果请求构造ok,相应的结果错误,那么就是服务器的问题;如果请求构造ok,响应结果ok,可能还是网页的问题。
java_blogDemo 完整代码