功能简介
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 文件:
数据库设计
设计当前的代码中用到的数据库中有几张表,每个表包含哪些字段,每个表之间的关联关系。在这里我们需要两张表,用户和文章表。
- 创建数据库
- 设计用户表
需要userId、name、password字段 - 设计文章表
需要articleId、title、content字段,且需要关联用户表,关系表现为1个用户多篇文章,所以在文章表建立外键userId关联用户表的主键userId
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)
);
实现数据库相关操作
创建一个DBUtil类来管理链接
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;
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 Article
User:
package modle;
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;
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;
public class UserDao {
public void add(User user) {
Connection connection = DBUtil.getConnection();
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());
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 User selectByName(String name) {
Connection connection = DBUtil.getConnection();
String sql = "select * from user where name = ?";
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
statement = connection.prepareStatement(sql);
statement.setString(1, name);
resultSet = statement.executeQuery();
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 User selectById(int userId) {
Connection connection = DBUtil.getConnection();
String sql = "select * from user where userId = ?";
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
statement = connection.prepareStatement(sql);
statement.setInt(1, userId);
resultSet = statement.executeQuery();
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;
}
}
通过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;
public class ArticleDao {
public void add (Article article) {
Connection connection = DBUtil.getConnection();
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());
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 List<Article> selectAll() {
List<Article> articles = new ArrayList<Article>();
Connection connection = DBUtil.getConnection();
String sql = "select articleId, title, userId from article";
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
statement = connection.prepareStatement(sql);
resultSet = statement.executeQuery();
while (resultSet.next()) {
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;
}
public Article selectById (int articleId) {
Connection connection = DBUtil.getConnection();
String sql = "select * from article where articleId = ?";
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
statement = connection.prepareStatement(sql);
statement.setInt(1, articleId);
resultSet = statement.executeQuery();
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;
}
public void delete (int articleId) {
Connection connection = DBUtil.getConnection();
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);
}
}
}
单元测试
我们可以针对上边的数据库操作进行简单的测试,有助于提前发现问题,在这里我们需要一些库/框架可以便于测试。
pom.xml 中导入我们的依赖:
一个常见问题
我们可能会出现数据库连接不上,就会抛出异常
常见原因:
1)url 写错了
2)用户名,密码错误
3)数据库服务器没有正常启动
4)连接了其他主机的数据库
注意:如果拼装 sql ,直接使用String 来按照字符串拼接的方式来拼装,这样会出现一些问题,比如:不方便也不安全。要尽可能防止SQL注入。
SQL注入理解:
进行前后端接口设计
分别实现接口API
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;
public class LoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html; charset=utf-8");
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;
}
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;
}
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;
public class RegisterServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html; charset=utf-8");
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;
}
UserDao userDao = new UserDao();
User existUser = userDao.selectByName(name);
if (existUser != null) {
String html = HtmlGenerator.getMessagePage("用户名重复,请换个名字!", "register.html");
resp.getWriter().write(html);
return;
}
User user = new User();
user.setName(name);
user.setPassword(password);
userDao.add(user);
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;
public class ArticleServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html; charset=utf-8");
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");
String articleIdStr = req.getParameter("articleId");
if (articleIdStr == null) {
getAllArticle(user, resp);
} else {
getOneArticle(Integer.parseInt(articleIdStr), user, resp);
}
}
private void getOneArticle(int articleId, User user, HttpServletResponse resp) throws IOException {
ArticleDao articleDao = new ArticleDao();
Article article = articleDao.selectById(articleId);
if (article == null) {
String html = HtmlGenerator.getMessagePage("文章不存在", "article");
resp.getWriter().write(html);
return;
}
UserDao userDao = new UserDao();
User author = userDao.selectById(article.getUserId());
String html = HtmlGenerator.getArticleDetailPage(article, user, author);
resp.getWriter().write(html);
}
private void getAllArticle(User user, HttpServletResponse resp) throws IOException {
ArticleDao articleDao = new ArticleDao();
List<Article> articles = articleDao.selectAll();
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");
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");
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;
}
ArticleDao articleDao = new ArticleDao();
Article article = new Article();
article.setUserId(user.getUserId());
article.setContent(content);
article.setTitle(title);
articleDao.add(article);
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;
public class DeleteArticleServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html; charset=utf-8");
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");
String articleIdStr = req.getParameter("articleId");
if (articleIdStr == null || "".equals(articleIdStr)) {
String html = HtmlGenerator.getMessagePage("要删除的文章不存在", "article");
resp.getWriter().write(html);
return;
}
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;
}
articleDao.delete(Integer.parseInt(articleIdStr));
String html = HtmlGenerator.getMessagePage("删除成功!",
"article");
resp.getWriter().write(html);
}
}
注意:如果我们出现一些问题一定不要慌,要去定位问题解决问题。
比如:提交没反应
我们先用Fiddle 抓包看看,如果请求构造的有问题,那么就是网页的问题;如果请求构造ok,相应的结果错误,那么就是服务器的问题;如果请求构造ok,响应结果ok,可能还是网页的问题。
GitHub链接
java_blogDemo 完整代码
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)