前期准备
分析需求
- 注册新用户
- 登录
- 博客列表页
- 博客详情页
- 博客编辑页
- 删除博客
创建项目
首先创建一个Maven项目.在main目录下创建一个webapp包,在webapp包中创建一个WEB-INF包,在WEB-INF下创建web.xml,并将下面代码写入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>
配置pom.xml
<dependencies>
<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>8.0.21</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.thymeleaf/thymeleaf -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>3.0.11.RELEASE</version>
</dependency>
</dependencies>
数据库设计
根据需求,我们需设计两张表,用户表和博客表,并将其存放在myblog库中。 用户表user用来存放用户的相关信息,用户Id,用户名(username),密码(password). 博客表blog用来存放博客的相关信息,博客Id(blogId),博客标题(title),博客内容(content),博客发布时间(postTime),用户Id(userId),此处的用户Id和用户表中的userId相对应。
create database if not exists myblog;
use myblog;
drop table if exists blog;
create table blog(
blogId int primary key auto_increment,
title varchar(1024),
content mediumtext,
postTime datetime,
userId int
);
drop table if exists user;
create table user(
userId int primary key auto_increment,
username varchar(128),
password varchar(128)
);
封装数据库操作
创建dao包,以下有关数据库的操作的类都存放在dao包下。
构造DBUtil
构造DBUtil类,进行数据库的连接。使用getDataSource方法进行实例化,使用getConnection方法进行数据库连接,使用close方法释放资源。
package dao;
import com.mysql.cj.jdbc.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:///myblog?useUnicode=true&characterEncoding=UTF8&serverTimezone=UTC&useSSL=false";
private static final String USERNAME = "root";
private static final String PASSWORD = "1234";
private static volatile DataSource dataSource = null;
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() 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();
}
}
}
}
创建实体类
User类 表示一个用户
创建User类包含用户Id(int userId),用户名(String username),密码(String password).并生成get(),set(),toString()方法.
package dao;
public class User {
private int userId;
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;
}
@Override
public String toString() {
return "User{" +
"userId=" + userId +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
Blog类 表示一篇博客
创建Blog类包含博客Id(int blogId),博客标题(String title),博客内容(String content),博客发布时间(Timestamp postTime),用户Id(int userId)并生成get(),set(),toString()方法.
package dao;
import java.sql.Timestamp;
public class Blog {
private int blogId;
private String title;
private String content;
private Timestamp postTime;
private int userId;
public int getBlogId() {
return blogId;
}
public void setBlogId(int blogId) {
this.blogId = blogId;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Timestamp getPostTime() {
return postTime;
}
public void setPostTime(Timestamp postTime) {
this.postTime = postTime;
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
@Override
public String toString() {
return "Blog{" +
"blogId=" + blogId +
", title='" + title + '\'' +
", postTime=" + postTime +
", userId=" + userId +
'}';
}
}
UserDao针对用户进行操作
创建UserDao类,实现新增用户,根据username查找用户,根据userId查找用户三个方法。
package dao;
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());
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);
}
}
public User select(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();
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 {
DBUtil.close(connection,statement,resultSet);
}
return null;
}
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();
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 {
DBUtil.close(connection,statement,resultSet);
}
return null;
}
}
BlogDao类针对博客操作
创建BlogDao类,实现插入博客,获取所有博客,根据blogId查找指定博客,根据blogId删除指定博客四个方法。
package dao;
import com.mysql.cj.util.DnsSrv;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class BlogDao {
public void insert(Blog blog) {
System.out.println("插入一个博客");
Connection connection=null;
PreparedStatement statement=null;
try {
connection=DBUtil.getConnection();
String sql="insert into blog values(null,?,?,?,?)";
statement=connection.prepareStatement(sql);
statement.setString(1,blog.getTitle());
statement.setString(2,blog.getContent());
statement.setTimestamp(3,blog.getPostTime());
statement.setInt(4,blog.getUserId());
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);
}
}
public List<Blog> selectAll() {
System.out.println("获取所有博客");
List<Blog> list=new ArrayList<Blog>();
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()>130) {
blog.setContent(content.substring(0,130)+"....");
}
blog.setContent(content);
blog.setPostTime(resultSet.getTimestamp("postTime"));
blog.setUserId(resultSet.getInt("userId"));
list.add(blog);
}
return list;
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBUtil.close(connection,statement,resultSet);
}
return null;
}
public Blog selectOne(int blogId) {
System.out.println("查找指定博客");
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();
if(resultSet.next()) {
Blog blog=new Blog();
blog.setBlogId(resultSet.getInt("blogId"));
blog.setTitle(resultSet.getString("title"));
blog.setContent(resultSet.getString("content"));
blog.setPostTime(resultSet.getTimestamp("postTime"));
blog.setUserId(resultSet.getInt("userId"));
return blog;
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBUtil.close(connection,statement,resultSet);
}
return null;
}
public void delete(int blogId) {
System.out.println("删除指定博客");
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);
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);
}
}
}
进行单元测试
对UserDao中的三个方法进行测试. 对插入操作进行测试.
public static void testInsert() {
UserDao userDao=new UserDao();
User user=new User();
user.setUsername("zhangsan");
user.setPassword("1234");
userDao.insert(user);
}
对根据username查找用户进行测试。
public static void testSelect() {
UserDao userDao=new UserDao();
User user=userDao.select("zhangsan");
System.out.println(user);
}
对根据userId查找用户进行测试。
public static void testSelectById() {
UserDao userDao=new UserDao();
User user=userDao.selectById(1);
System.out.println(user);
}
对BlogDao类中四个方法进行测试。 对新增博客方法进行测试。
public static void testInsert() {
BlogDao blogDao=new BlogDao();
Blog blog=new Blog();
blog.setTitle("我的第一篇博客");
blog.setContent("光阴里的故事光阴里的故事光阴里的故事光阴里的故事光阴里的故事光阴里的故事光阴里的故事光阴里的故事");
blog.setPostTime(new Timestamp(System.currentTimeMillis()));
blog.setUserId(1);
blogDao.insert(blog);
}
对获取所有博客方法进行测试。
public static void testSelectAll() {
BlogDao blogDao=new BlogDao();
List<Blog> list=blogDao.selectAll();
System.out.println(list);
}
对根据blogId查找指定博客进行测试。
public static void testSelectOne() {
BlogDao blogDao=new BlogDao();
Blog blog=blogDao.selectOne(1);
System.out.println(blog);
}
对根据blogId进行删除博客进行测试。
public static void testDelete() {
BlogDao blogDao=new BlogDao();
blogDao.delete(1);
}
实现前后端交互
创建view包,以下类都在view包下创建。
初始化TemplateEngine
package view;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.templateresolver.ServletContextTemplateResolver;
import javax.servlet.Servlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
@WebListener
public class ThymeleafConfig implements ServletContextListener {
public void contextInitialized(ServletContextEvent servletContextEvent) {
ServletContext context=servletContextEvent.getServletContext();
TemplateEngine engine=new TemplateEngine();
ServletContextTemplateResolver resolver=new ServletContextTemplateResolver(context);
resolver.setPrefix("/WEB-INF/template/");
resolver.setSuffix(".html");
resolver.setCharacterEncoding("utf-8");
engine.setTemplateResolver(resolver);
context.setAttribute("engine",engine);
System.out.println("初始化 TemplateEngine成功");
}
public void contextDestroyed(ServletContextEvent servletContextEvent) {
}
}
创建网页模板
将写好的博客系统静态页面拷贝到webapp目录中。 其中blog_list和blog_detaill需要借助服务器进行渲染放在templates目录中,其他内容不需要服务器渲染,直接放到webapp中。
实现注册功能
注册页面中提交form表单,需要服务器处理。 请求:POST/register name=myl&password=123 响应:返回一个提示页面,告诉用户注册成功还是失败,并跳转到登录页面。 创建registerServlet
@WebServlet("/register")
public class registerServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
req.setCharacterEncoding("utf-8");
String name=req.getParameter("username");
String password=req.getParameter("password");
if(name==null||password==null||name.equals("")||password.equals("")) {
String html= HtmlGenerator.getMessagePage("用户或密码为空","register.html");
resp.getWriter().write(html);
return;
}
UserDao userDao=new UserDao();
if(userDao.select(name)!=null) {
String html= HtmlGenerator.getMessagePage("用户名已经被注册,请重新输入","register.html");
resp.getWriter().write(html);
return;
}
User user=new User();
user.setUsername(name);
user.setPassword(password);
userDao.insert(user);
String html= HtmlGenerator.getMessagePage("注册成功点击跳转到登录页面","login.html");
resp.getWriter().write(html);
}
}
提示页面并跳转到指定页面
package common;
public class HtmlGenerator {
public static String getMessagePage(String message,String nextUrl ) {
StringBuilder stringBuilder=new StringBuilder();
stringBuilder.append("<html>");
stringBuilder.append("<head>");
stringBuilder.append("<meta charset=\"utf-8\">");
stringBuilder.append("<title>提示页面</title>");
stringBuilder.append("</head>");
stringBuilder.append("<body>");
stringBuilder.append("<h3>");
stringBuilder.append(message);
stringBuilder.append("</h3>");
stringBuilder.append(String.format("<a href=\"%s\"> 点击这里进行跳转 </a>",nextUrl));
stringBuilder.append("</body>");
stringBuilder.append("</html>");
return stringBuilder.toString();
}
}
实现登录功能
请求:POST/login name=myl&password=123 响应:返回一个提示页面,告诉用户登录成功还是失败。 登录成功后把user对象存放到httpSession中,并重定向到博客列表页。 创建LoginServlet
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
req.setCharacterEncoding("utf-8");
String username=req.getParameter("username");
System.out.println(username);
String password=req.getParameter("password");
System.out.println(password);
if(username==null||password==null||"".equals(username)||"".equals(password)) {
String html= HtmlGenerator.getMessagePage("登录失败!用户名/密码错误","login.html");
resp.getWriter().write(html);
return;
}
UserDao userDao=new UserDao();
User user=userDao.select(username);
if(user==null) {
String html= HtmlGenerator.getMessagePage("登录失败!用户名/密码错误","login.html");
resp.getWriter().write(html);
return;
}
if(!user.getPassword().equals(password)) {
String html= HtmlGenerator.getMessagePage("登录失败!用户名/密码错误","login.html");
resp.getWriter().write(html);
return;
}
HttpSession session=req.getSession(true);
session.setAttribute("user",user);
resp.sendRedirect("blog_list.html");
}
}
实现检测是否登录
当用户访问博客列表页和博客详情页时如果用户尚未登录跳转到登录页面。
package common;
import dao.User;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
public class util {
public static User checkLoginStatus(HttpServletRequest req) {
HttpSession session=req.getSession(false);
if(session==null) {
return null;
}
User user= (User) session.getAttribute("user");
if(user==null) {
return null;
}
return user;
}
}
获取文章列表
请求:GET/blog_list.html 响应:返回文章的列表页(包含标题,发布时间,部分内容) 修改blog_list.html,把展示博客列表替换成${blog.title}等
<div class="right">
<div class="blog" th:each="blog:${blogs}">
<div class="title" th:text="${blog.title}"></div>
<div class="date" th:text="${blog.postTime}"></div>
<div class="desc" th:text="${blog.content}"></div>
<a th:href="${'blog_detaill.html?blogId=' + blog.blogId}" class="detail">查看全文 > > </a>
<!-- <a href="${'blog_detaill.html?blogId='+blog.blogId}" class="detail">查看全文>></a>-->
</div>
</div>
创建BlogLIstServlet
@WebServlet("/blog_list.html")
public class BlogLIstServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
User user=util.checkLoginStatus(req);
if(user==null) {
resp.sendRedirect("login.html");
}
BlogDao blogDao=new BlogDao();
List<Blog> blogs=blogDao.selectAll();
ServletContext context=this.getServletContext();
TemplateEngine engine= (TemplateEngine) context.getAttribute("engine");
WebContext webContext=new WebContext(req,resp,context);
webContext.setVariable("blogs",blogs);
webContext.setVariable("user",user);
String html=engine.process("blog_list",webContext);
resp.getWriter().write(html);
}
}
获取文章详情
请求:GET/blog_detaill.html?blogId=1 响应:返回文章的详情页(包含文章内容) 修改blog_detaill.html.
<div class="right">
<div class="blog-content">
<h3 th:text="${blog.title}"></h3>
<div class="date" th:text="${blog.postTime}"></div>
<!-- markdown的原始内容就在这个div中-->
<div id="content" th:text="${blog.content}" style="background-color: transparent"></div>
</div>
</div>
创建BlogDetailServlet
@WebServlet("/blog_detaill.html")
public class BlogDetailServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
User user=util.checkLoginStatus(req);
if(user==null) {
resp.sendRedirect("login.html");
}
String blogId=req.getParameter("blogId");
if(blogId==null||"".equals(blogId)) {
String html="<h3>blogId字段缺失</h3>";
resp.getWriter().write(html);
return;
}
BlogDao blogDao=new BlogDao();
Blog blog=blogDao.selectOne(Integer.parseInt(blogId));
if(blog==null) {
String html="<h3>当前博客不存在</h3>";
resp.getWriter().write(html);
return;
}
UserDao userDao=new UserDao();
User author=userDao.selectById(blog.getUserId());
ServletContext context=this.getServletContext();
TemplateEngine engine= (TemplateEngine) context.getAttribute("engine");
WebContext webContext=new WebContext(req,resp,context);
webContext.setVariable("blog",blog);
webContext.setVariable("user",author);
webContext.setVariable("showDeleteBtn",blog.getUserId()==user.getUserId());
String html=engine.process("blog_detaill",webContext);
resp.getWriter().write(html);
}
}
新增/发布文章
请求:POST/blog_edit 响应:返回提示页面,告诉用户是否发布成功 修改blog_edit.html页面结构 增加form标签,action未blog_edit,method=post
<div class="blog_edit_container" >
<form action="blog_edit" method="post" style="height: 100%">
<div class="title">
<input type="text" id="title" name="title">
<input type="submit" id="submit" value="发布文章"></input>
</div>
<!-- markdown编辑器标签-->
<div id="editor">
<!-- 这里加上一个隐藏的textarea。这个东西不需要显示,只是为了后面的表单提交构造数据-->
<textarea name="content" style="display: none"></textarea>
</div>
</form>
</div>
初始化编辑器
<script>
var editor=editormd("editor",{
width:"1000px",
height:"500px",
markdown:"#在这里写下一篇博客",
path:"editor.md/lib/",
saveHTMLToTextarea:true
});
</script>
创建BlogEditServlet
@WebServlet("/blog_edit")
public class BlogEditServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text.html;charset=utf-8");
req.setCharacterEncoding("utf-8");
User user= util.checkLoginStatus(req);
if(user==null) {
String html="<h3>当前未登录</h3>";
resp.getWriter().write(html);
return;
}
String title=req.getParameter("title");
String content=req.getParameter("content");
if(title==null||"".equals(title)||content==null||"".equals(content)) {
String html="<h3>提交的title或content不存在</h3>";
resp.getWriter().write(html);
return;
}
BlogDao blogDao=new BlogDao();
Blog blog=new Blog();
blog.setTitle(title);
blog.setContent(content);
blog.setUserId(user.getUserId());
blog.setPostTime(new Timestamp(System.currentTimeMillis()));
blogDao.insert(blog);
resp.sendRedirect("blog_list.html");
}
}
删除文章
请求:GET/blogDelete 响应:返回提示页面
@WebServlet("/blogDelete")
public class BlogDeleteServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
User user= util.checkLoginStatus(req);
if(user==null) {
String html="<h3>当前尚未登陆</h3>";
resp.getWriter().write(html);
return;
}
String blogId=req.getParameter("blogId");
if(blogId==null||blogId.equals("")) {
String html="<h3>blogId缺失</h3>";
resp.getWriter().write(html);
return;
}
BlogDao blogDao=new BlogDao();
Blog blog=blogDao.selectOne(Integer.parseInt(blogId));
if(blog.getUserId()!=user.getUserId()) {
String html="<h3>不是作者不能删除</h3>";
resp.getWriter().write(html);
return;
}
blogDao.delete(Integer.parseInt(blogId));
resp.sendRedirect("blog_list.html");
}
}
|