当前位置:   article > 正文

基于Servlet的个人博客系统_利用servlet、jdbc、jsp、html等技术完成一个微型博客系统,能够实现发布博客、删

利用servlet、jdbc、jsp、html等技术完成一个微型博客系统,能够实现发布博客、删

目录

1.创建Maven项目

2.把前端博客系统代码复制到webapp目录下

3.数据库设计

4.实现博客列表页

5.实现博客详情页

6.实现博客登录页

7.实现用户信息界面修改

8.实现博客注销

9.实现博客删除

10.发布博客

11.对博客进行测试


1.创建Maven项目

  • 创建webapp目录,在webapp里面创建WEB-INF目录,在WEB-INF里面创建web.xml(Tomcat 找到这个文件才能正确处理 webapp 中的动态资源.   

  • 配置web.xml
    1. <!DOCTYPE web-app PUBLIC
    2. "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    3. "http://java.sun.com/dtd/web-app_2_3.dtd" >
    4. <web-app>
    5. <display-name>Archetype Created Web Application</display-name>
    6. </web-app>
                     
  • 在 pom.xml 中引入 Servlet API 依赖的 jar 包(把中央仓库中提供的 xml 复制到项目的 pom.xml 中)

 2.把前端博客系统代码复制到webapp目录下

                 

3.数据库设计

  • 在main目录下创建db.sql来存放设计的表(博客表,用户表)

         

 建立DBUtil类来封装数据库,实现数据库的连接和断开代码

 代码如下:

  1. //通过这个类来封装DataSource资源
  2. public class DBUtil {
  3. private static volatile DataSource dataSource = null;
  4. public static DataSource getDataSource() {
  5. if (dataSource==null){
  6. synchronized (DBUtil.class){
  7. if (dataSource == null) {
  8. dataSource = new MysqlDataSource();
  9. ((MysqlDataSource) dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/blog_system?characterEncoding=utf8&useSSL=false");
  10. //用户名
  11. ((MysqlDataSource) dataSource).setUser("root");
  12. //密码
  13. ((MysqlDataSource) dataSource).setPassword("20010211");
  14. }
  15. }
  16. }
  17. return dataSource;
  18. }
  19. public static Connection getConnection() throws SQLException {
  20. return getDataSource().getConnection();
  21. }
  22. public static void close(Connection connection, PreparedStatement statement, ResultSet resultSet){
  23. if (resultSet!=null){
  24. try {
  25. resultSet.close();
  26. } catch (SQLException e) {
  27. e.printStackTrace();
  28. }
  29. }
  30. if (statement!=null){
  31. try {
  32. statement.close();
  33. } catch (SQLException e) {
  34. e.printStackTrace();
  35. }
  36. }
  37. if (connection!=null){
  38. try {
  39. connection.close();
  40. } catch (SQLException e) {
  41. e.printStackTrace();
  42. }
  43. }
  44. }
  45. }
  • 创建两个实体类,设计的表结构怎么设计就怎么实现,每一个实体类对应表结构的一条记录.

         博客类(博客id,文章标题,文章内容,发布时间,用户id)

  1. public class Blog {
  2. private int blogId;
  3. private String title;
  4. private String content;
  5. //MySQL的有关时间都是使用Timestamp来表示
  6. private Timestamp postTime;
  7. private int userId;
  8. public int getBlogId() {
  9. return blogId;
  10. }
  11. public void setBlogId(int blogId) {
  12. this.blogId = blogId;
  13. }
  14. public String getTitle() {
  15. return title;
  16. }
  17. public void setTitle(String title) {
  18. this.title = title;
  19. }
  20. public String getContent() {
  21. return content;
  22. }
  23. public void setContent(String content) {
  24. this.content = content;
  25. }
  26. public String getPostTime() {
  27. //魔改一下时间日期,格式化时间
  28. SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  29. return simpleDateFormat.format(postTime);
  30. }
  31. public void setPostTime(Timestamp postTime) {
  32. this.postTime = postTime;
  33. }
  34. public int getUserId() {
  35. return userId;
  36. }
  37. public void setUserId(int userId) {
  38. this.userId = userId;
  39. }
  40. }

用户类(用户名,密码,用户id)

  1. public class User {
  2. private int userId;
  3. private String username;
  4. private String password;
  5. public int getUserId() {
  6. return userId;
  7. }
  8. public void setUserId(int userId) {
  9. this.userId = userId;
  10. }
  11. public String getUsername() {
  12. return username;
  13. }
  14. public void setUsername(String username) {
  15. this.username = username;
  16. }
  17. public String getPassword() {
  18. return password;
  19. }
  20. public void setPassword(String password) {
  21. this.password = password;
  22. }
  23. }
  •  针对数据库增删改查操作分别对两个实体类进行封装
  • 对博客类进行封装
  1.  插入一个博客到数据库中 -- 发布博客

代码如下:

  1. // 1. 插入一个博客到数据库中 -- 发布博客
  2. public void insert(Blog blog) {
  3. Connection connection = null;
  4. PreparedStatement statement = null;
  5. try {
  6. // 1. 和数据库建立连接
  7. connection = DBUtil.getConnection();
  8. // 2. 构造 SQL
  9. String sql = "insert into blog values(null, ?, ?, now(), ?)";
  10. statement = connection.prepareStatement(sql);
  11. statement.setString(1, blog.getTitle());
  12. statement.setString(2, blog.getContent());
  13. statement.setInt(3, blog.getUserId());
  14. // 3. 执行 SQL
  15. int ret = statement.executeUpdate();
  16. if (ret != 1) {
  17. System.out.println("博客插入失败!");
  18. } else {
  19. System.out.println("博客插入成功!");
  20. }
  21. // [注意!!] close 其实不应该在这里调用. 一旦上面抛出异常, 此处的 close 可能无法被执行.
  22. } catch (SQLException e) {
  23. e.printStackTrace();
  24. } finally {
  25. // 4. 释放对应的资源
  26. DBUtil.close(connection, statement, null);
  27. }
  28. }

 2.根据博客 id 来查询指定博客 -- 博客详情页

代码如下:

  1. // 2. 根据博客 id 来查询指定博客 -- 博客详情页
  2. public Blog selectOne(int blogId) {
  3. Connection connection = null;
  4. PreparedStatement statement = null;
  5. ResultSet resultSet = null;
  6. try {
  7. // 1. 和数据库建立连接
  8. connection = DBUtil.getConnection();
  9. // 2. 构造 SQL
  10. String sql = "select * from blog where blogId = ?";
  11. statement = connection.prepareStatement(sql);
  12. statement.setInt(1, blogId);
  13. // 3. 执行 SQL
  14. resultSet = statement.executeQuery();
  15. // 4. 遍历结果集合
  16. if (resultSet.next()) {
  17. Blog blog = new Blog();
  18. blog.setBlogId(resultSet.getInt("blogId"));
  19. blog.setTitle(resultSet.getString("title"));
  20. blog.setContent(resultSet.getString("content"));
  21. blog.setPostTime(resultSet.getTimestamp("postTime"));
  22. blog.setUserId(resultSet.getInt("userId"));
  23. return blog;
  24. }
  25. } catch (SQLException e) {
  26. e.printStackTrace();
  27. } finally {
  28. DBUtil.close(connection, statement, resultSet);
  29. }
  30. return null;
  31. }

 3.直接查询博客列表 -- 博客列表页

 4.删除指定博客 -- 删除博客

  •  针对用户类的增删改查封装

      1.根据用户名来查询用户的详情 -- 登陆(用户名需要唯一)

 2.根据用户 id 来查询用户详情 -- 在获取用户信息的时候, 需要用到.

  4.实现博客列表页(进行前后端交互,页面发送http请求,服务器返回http请求)

  • 约定前后端接口(页面加载时通过ajax发起http请求,服务器获取到博客列表数据,考虑好要发送什么样的请求,返回什么样的响应)  

请求:GET/blog

响应: HTTP/1.1 200 OK   Content-Type:application/json

                                         [

                                            {

                                                  blogId:1,

                                                  title:"第一篇",

                                                  context::这是正文1"

                                                   posttime:"2020-11-24 12:00:01"

                                                   userid:1

                                            },

                                            

                                              {

                                                  blogId:2,

                                                  title:"第二篇",

                                                  context::这是正文2"

                                                  posttime:"2020-11-25 12:05:01"

                                                  userid:2

                                            },

                                           ..................................................

                                           ]

  •  先获取博客数据库列表,把它转换成json格式(服务器)
  1. @WebServlet("/blog")
  2. public class BlogServlet extends HttpServlet {
  3. private ObjectMapper objectMapper = new ObjectMapper();
  4. @Override
  5. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//从数据库中查询到博客列表,转成json 格式
  6. //获取博客列表
  7. BlogDao blogDao = new BlogDao();
  8. List<Blog> blogs = blogDao.selectAll();
  9. //转换
  10. String respJson = objectMapper.writeValueAsString(blogs);
  11. resp.setContentType("application/json;charset=utf8");
  12. resp.getWriter().write(respJson);
  13. }
  14. }
  • 修改博客列表页的客户端代码(之前的博客列表页内容是固定的,现在需要去修改这部分固定代码) 使用ajax给服务器发送http请求, 服务器返回json格式数据

代码如下: 

  1. <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
  2. <script src="js/app.js"></script>
  3. <script>
  4. // 发送 ajax 从服务器获取数据
  5. function getBlogs() {
  6. $.ajax({
  7. type: 'get',
  8. url: 'blog',
  9. success: function(body) {
  10. // 获取成功, 则 body 就是一个 js 对象数组. 每个元素就是一个博客
  11. //清空右半部分内容
  12. let container = document.querySelector('.container-right');
  13. //遍历body,构造出一个个bodyDive
  14. for (let blog of body) {
  15. // 构造 blogDiv
  16. let blogDiv = document.createElement('div');
  17. blogDiv.className = 'blog';
  18. // 构造博客标题
  19. let titleDiv = document.createElement('div');
  20. titleDiv.className = 'title';
  21. titleDiv.innerHTML = blog.title;
  22. // 构造博客的日期
  23. let dateDiv = document.createElement('div');
  24. dateDiv.className = 'date';
  25. dateDiv.innerHTML = blog.postTime;
  26. // 构造博客的摘要
  27. let descDiv = document.createElement('div');
  28. descDiv.className = 'desc';
  29. descDiv.innerHTML = blog.content;
  30. // 构造查看全文按钮
  31. let a = document.createElement('a');
  32. a.href = 'blog_detail.html?blogId=' + blog.blogId;
  33. a.innerHTML = '查看全文 &gt;&gt;';
  34. // 拼装最终结果
  35. blogDiv.appendChild(titleDiv);
  36. blogDiv.appendChild(dateDiv);
  37. blogDiv.appendChild(descDiv);
  38. blogDiv.appendChild(a);
  39. container.appendChild(blogDiv);
  40. }
  41. }
  42. });
  43. }
  44. // 此处还需要来一个函数调用.
  45. getBlogs();

 5.实现博客详情页(点击查看全文按钮,就会发送一个get请求,这个请求需要告诉服务器要请求哪篇博客,进入博客详情页,需要让博客详情页再次发送ajax请求,向服务器获取到当前blogid对应的博客内容)

  •  约定前后端接口相比于博客列表页请求,此时博客详情页在blog里面多加了一个参数

 [ 请求 ]
GET / blog ? blogId = 1
[ 响应 ]
{
    blogId : 1 ,
    title : " 第一篇博客 " ,
    content : " 博客正文 " ,
    userId : 1 ,
    postTime : "2022-07-06 12:00:00"
},

  •  修改服务器代码,通过blogid参数来判断是获取列表还是详情页
  1. WebServlet("/blog")
  2. public class BlogServlet extends HttpServlet {
  3. private ObjectMapper objectMapper = new ObjectMapper();
  4. @Override
  5. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  6. // 按照约定的接口格式返回数据
  7. // 在博客列表页中, 已经使用了 BlogServlet.doGet 方法了.
  8. // 博客详情页, 也想用. 就需要做出区分. 使用 query string 来区分.
  9. // 如果请求带有 query string , 有 blogId 这个参数, 就认为是博客详情页的请求.
  10. // 如果请求不带有 query string, 就认为是博客列表页的请求.
  11. resp.setContentType("application/json; charset=utf8");
  12. BlogDao blogDao = new BlogDao();
  13. String blogId = req.getParameter("blogId");
  14. if (blogId == null) {
  15. // 博客列表页发起的请求
  16. List<Blog> blogs = blogDao.selectAll();
  17. resp.getWriter().write(objectMapper.writeValueAsString(blogs));
  18. } else {
  19. // 博客详情页发起的请求
  20. Blog blog = blogDao.selectOne(Integer.parseInt(blogId));
  21. resp.getWriter().write(objectMapper.writeValueAsString(blog));
  22. }
  23. }
  •  修改博客详情页的代码,改变其中不变的内容(博客的正文是markdown格式,数据库存的也是markdown格式,根据获取到的响应数据, 通过 editor.md 转换成 html, 并显示)
  1. <!-- 通过 ajax 获取到博客详情内容 -->
  2. <script src="js/app.js"></script>
  3. <script>
  4. function getBlog() {
  5. $.ajax({
  6. type: 'get',
  7. //location.search 拿到了形如 '?blogId=1' 这样的一段内容
  8. url: 'blog' + location.search,
  9. success: function(body) {
  10. let h3 = document.querySelector('.blog-detail>h3');
  11. h3.innerHTML = body.title;
  12. let dateDiv = document.querySelector('.blog-detail>.date');
  13. dateDiv.innerHTML = body.postTime;
  14. let contentDiv = document.querySelector('#content');
  15. contentDiv.innerHTML = body.content;
  16. // 构造博客正文
  17. // 如果直接把 content 设为 innerHTML, 此时展示在界面上的内容, 是原始的 markdown 字符串
  18. // 此处需要的是渲染后的, 带有格式的效果
  19. // 第一个参数对应 id=content 的 html 标签. 渲染后得到的 html 片段就会被放到这个 标签下.
  20. // 构造博客正文此处使用 editor.md 来进行渲染
  21. editormd.markdownToHTML('content', { markdown: body.content });
  22. }
  23. });
  24. }
  25. getBlog();

 6.登录页面(用户输入用户名和密码,点击登录按钮,发起一个请求,把用户名和密码提交给服务器,服务器对其进行验证,成功后即可登录)

  • 约定前后端请求

 请求:POST/login             Content-Type:application/x-www-from-urlencode

usename=张三&password=123

响应:

Http:1.1 302   location:body_list html  (实现在博客列表页强制登录)

  • 实现服务器登录 
  1. @WebServlet("/login")
  2. public class LoginServlet extends HttpServlet {
  3. @Override
  4. protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  5. // 1. 从请求中获取到用户名和密码
  6. req.setCharacterEncoding("utf-8");
  7. String username = req.getParameter("username");
  8. String password = req.getParameter("password");
  9. if (username == null || username.equals("") || password == null || password.equals("20010211")) {
  10. // 用户名密码为空. 直接返回登陆失败
  11. resp.setContentType("text/html; charset=utf8");
  12. resp.getWriter().write("用户名或密码为空! 登陆失败!");
  13. return;
  14. }
  15. // 2. 查询数据库, 验证用户名密码是否正确
  16. UserDao userDao = new UserDao();
  17. User user = userDao.selectByName(username);
  18. if (user == null || !user.getPassword().equals(password)) {
  19. // 用户名不存在, 或者密码不相同, 返回登陆失败
  20. resp.setContentType("text/html; charset=utf8");
  21. resp.getWriter().write("用户名或密码错误! 登陆失败!");
  22. return;
  23. }
  24. // 3. 如果正确, 创建一个会话对象
  25. HttpSession session = req.getSession(true);
  26. // 在会话中保存一下 user, 以备后面使用. 后续访问其他页面, 就可以直接通过会话拿到当前是哪个用户在访问了.
  27. session.setAttribute("user", user);
  28. // 4. 构造 302 响应报文
  29. resp.sendRedirect("blog_list.html");
  30. }
  • 登陆页面提供一个 form 表单 , 通过 form 的方式把用户名密码提交给服务器。(修改了button提交按钮,加上了login和post)
  1. <!-- 用这个元素作为页面的版心, 把对话框放到这个元素里面, 垂直水平居中 -->
  2. <div class="login-container">
  3. <form action="login" method="post">
  4. <!-- 登录对话框 -->
  5. <div class="dialog">
  6. <h3>登录</h3>
  7. <div class="row">
  8. <span>用户名</span>
  9. <!-- 这两个框很关键, 后面还要用, 就起个 id 作为标识 -->
  10. <input type="text" id="username" name="username">
  11. </div>
  12. <div class="row">
  13. <span>密码</span>
  14. <input type="password" id="password" name="password">
  15. </div>
  16. <div class="row">
  17. <input id="login-btn" value="登陆" type="submit">
  18. </div>
  19. </div>
  20. </form>
  21. </div>
  • 实现强制登录功能(在博客列表页,编辑页,详情页在页面加载后发起ajax请求,这个请求从服务器获取当前登陆状态,如果当下未登录则返回到登录页,已经登陆不用处理)
    1. // 这个文件里放一些页面公共的代码
    2. // 加上一个逻辑, 通过 GET /login 这个接口来获取下当前的登录状态~
    3. function getUserInfo(pageName) {
    4. $.ajax({
    5. type: 'get',
    6. url: 'login',
    7. success: function(body) {
    8. // 判定此处的 body 是不是一个有效的 user 对象(userId 是否非 0)
    9. if (body.userId && body.userId > 0) {
    10. // 登录成功!
    11. // 不做处理!
    12. console.log("当前用户登录成功! 用户名: " + body.username);
    13. // 根据当前用户登录的情况, 把当前用户名设置到界面上
    14. if (pageName == 'blog_list.html') {
    15. changeUserName(body.username);
    16. }
    17. } else {
    18. // 登录失败!
    19. // 让前端页面, 跳转到 login.html
    20. alert("当前您尚未登录! 请登录后再访问博客列表!");
    21. location.assign('blog_login.html');
    22. }
    23. },
    24. error: function() {
    25. alert("当前您尚未登录! 请登录后再访问博客列表!");
    26. location.assign('blog_login.html');
    27. }
    28. });
    29. }
    30. function changeUserName(username) {
    31. let h3 = document.querySelector('.card>h3');
    32. h3.innerHTML = username;

  • 博客编辑页页面修改:

    7.修改用户信息(如果当前页面是博客列表页 , 则显示当前登陆用户的信息 ,当前页面是博客详情页 , 则显示该博客的作者用户信息

  • 约定前后端请求 

针对列表页:

请求:GET/userinfo                    

响应: HTTP/1.1  200 ok

Content-Type:application/json

{

userid:1,

username:"张三"

针对详情页:

请求:GET/userinfo /blogid=1                   

响应: HTTP/1.1  200 ok

Content-Type:application/json

{

userid:1,

username:"张三"

  • 实现服务器代码 
    1. @WebServlet("/userInfo")
    2. public class UserInfoServlet extends HttpServlet {
    3. private ObjectMapper objectMapper = new ObjectMapper();
    4. @Override
    5. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    6. // 获取用户信息
    7. String blogId = req.getParameter("blogId");
    8. if (blogId == null) {
    9. // 列表页, 获取当前登陆用户的信息
    10. // 直接从 session 中获取即可~~
    11. getUserInfoFromSession(req, resp);
    12. } else {
    13. // 详情页, 获取文章作者的信息
    14. // 查询数据库
    15. getUserInfoFromDB(req, resp, Integer.parseInt(blogId));
    16. }
    17. }
    18. private void getUserInfoFromDB(HttpServletRequest req, HttpServletResponse resp, int blogId) throws IOException {
    19. // 1. 先根据 blogId 查询 Blog 对象, 获取到 userId (作者是谁)
    20. BlogDao blogDao = new BlogDao();
    21. Blog blog = blogDao.selectOne(blogId);
    22. if (blog == null) {
    23. // 如果参数传来的这个 blogId 是随便瞎写的. 数据库里没有.
    24. resp.setStatus(404);
    25. resp.setContentType("text/html;charset=utf8");
    26. resp.getWriter().write("blogId 不存在");
    27. return;
    28. }
    29. // 2. 根据 userId 查询对应的 User 对象即可
    30. UserDao userDao = new UserDao();
    31. User user = userDao.selectById(blog.getUserId());
    32. if (user == null) {
    33. resp.setStatus(404);
    34. resp.setContentType("text/html;charset=utf8");
    35. resp.getWriter().write("blogId 不存在");
    36. return;
    37. }
    38. // 3. 把 user 对象返回给浏览器了
    39. user.setPassword("");
    40. resp.setContentType("application/json;charset=utf8");
    41. resp.getWriter().write(objectMapper.writeValueAsString(user));
    42. }
    43. private void getUserInfoFromSession(HttpServletRequest req, HttpServletResponse resp) throws IOException {
    44. HttpSession session = req.getSession(false);
    45. if (session == null) {
    46. resp.setStatus(403);
    47. resp.setContentType("text/html;charset=utf8");
    48. resp.getWriter().write("当前未登录");
    49. return;
    50. }
    51. User user = (User) session.getAttribute("user");
    52. if (user == null) {
    53. resp.setStatus(403);
    54. resp.setContentType("text/html;charset=utf8");
    55. resp.getWriter().write("当前未登录");
    56. return;
    57. }
    58. // user 获取到了, 把 user 中的 password 给干掉, 然后返回.
    59. user.setPassword("");
    60. resp.setContentType("application/json; charset=utf8");
    61. resp.getWriter().write(objectMapper.writeValueAsString(user));
    62. }
    63. }

    8.实现注销登录(点击注销按钮,给服务器发送一个http请求告诉服务器,要退出登录,服务器就会把会话中user对象给删除了,同时重新定向跳转到登录页)

  • 约定前后端交互接口 

请求: GET/logout

响应:HTTP/1.1 302

location:login.html 

  • 服务器 注销
  1. @WebServlet("/logout")
  2. public class LogoutServlet extends HttpServlet {
  3. @Override
  4. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  5. HttpSession session = req.getSession(false);
  6. if (session == null) {
  7. resp.setStatus(403);
  8. return;
  9. }
  10. // 直接把 session 中之前的 user 对象给删掉即可!!
  11. session.removeAttribute("user");
  12. // 不要忘记重定向到登陆页面!
  13. resp.sendRedirect("login.html");
  14. }
  15. }
  •  客户端代码只需要调一个注销按钮,将注销按钮设置为 <a href="logout"> , 点击的时候就会发送 GET /logou 这样的请求

9.删除博客 (在博客详情页导航栏加上删除按钮,通过a标签的hearf属性发送get请求,但是删除要做一个判断,如果当前登录用户就是文章作者可以删除,否则不可以)

  • 约定前后端交互接口 

 请求: GET/blog-delete?blogid=1

 响应:删除成功  HTTP/1.1 302

                          location:blog_list.html

           删除失败   HTTP/1.1 403

                           没有删除权限  

  • 服务器删除代码 
    1. @WebServlet("/blog_delete")
    2. public class BlogDeleteServlet extends HttpServlet {
    3. @Override
    4. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    5. // 1. 先判定用户的登陆状态
    6. HttpSession session = req.getSession(false);
    7. if (session == null) {
    8. resp.setStatus(403);
    9. resp.setContentType("text/html; charset=utf8");
    10. resp.getWriter().write("您当前未登录, 不能删除!");
    11. return;
    12. }
    13. User user = (User) session.getAttribute("user");
    14. if (user == null) {
    15. resp.setStatus(403);
    16. resp.setContentType("text/html; charset=utf8");
    17. resp.getWriter().write("您当前未登录, 不能删除!");
    18. return;
    19. }
    20. // 2. 获取到 blogId
    21. String blogId = req.getParameter("blogId");
    22. if (blogId == null) {
    23. // 这个 blogId 参数不存在, 无法删除
    24. resp.setStatus(404);
    25. resp.setContentType("text/html; charset=utf8");
    26. resp.getWriter().write("您当前删除的 blogId 有误");
    27. return;
    28. }
    29. // 3. 查询出这个 blogId 对应的 Blog 对象
    30. BlogDao blogDao = new BlogDao();
    31. Blog blog = blogDao.selectOne(Integer.parseInt(blogId));
    32. if (blog == null) {
    33. // 这个 blogId 参数不存在, 无法删除
    34. resp.setStatus(404);
    35. resp.setContentType("text/html; charset=utf8");
    36. resp.getWriter().write("您当前删除的 博客 不存在! blogId=" + blogId);
    37. return;
    38. }
    39. // 4. 判定登陆用户是否就是文章作者
    40. if (blog.getUserId() != user.getUserId()) {
    41. // blog.getUserId() 文章的作者
    42. // user.getUserId() 从 session 里拿的登陆的用户是谁.
    43. // 不一样, 说明在删别人的文章.
    44. // 直接返回 403
    45. resp.setStatus(403);
    46. resp.setContentType("text/html; charset=utf8");
    47. resp.getWriter().write("当前您不能删除别人的博客!");
    48. return;
    49. }
    50. // 5. 真正执行删除操作.
    51. blogDao.delete(Integer.parseInt(blogId));
    52. // 6. 返回 302 重定向
    53. resp.sendRedirect("blog_list.html");
    54. }

  • 修改blog_detail.html的页面 
  1. // 刚才少了一步, 需要把当前的 blogId 给设置上来的~~
  2. function updateDeleteURL() {
  3. let deleteBtn = document.querySelector('#delete-btn');
  4. deleteBtn.href = 'blog_delete' + location.search;
  5. }
  6. updateDeleteURL();

 10.发布博客(用户在编辑页进行编辑,点击发布博客,发起http请求,服务器将收到的对象构造成一个Blog对象,插入数据库)

  • 前后端交互接口 

 请求:POST/login             Content-Type:application/x-www-from-urlencode

  title=标题$content=正文

响应:

Http:1.1 302   location:body_list html  (实现在博客列表页强制登录)

  • 服务器代码 
  1. @Override
  2. protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  3. // 使用这个方法, 来实现提交新博客
  4. // 1. 先检查一下用户的登陆状态, 获取到会话和用户信息.
  5. // 如果未登录, 显然不能提交博客~
  6. HttpSession session = req.getSession(false);
  7. if (session == null) {
  8. resp.setStatus(403);
  9. resp.setContentType("text/html; charset=utf8");
  10. resp.getWriter().write("当前未登录, 不能发布博客!");
  11. return;
  12. }
  13. User user = (User) session.getAttribute("user");
  14. if (user == null) {
  15. resp.setStatus(403);
  16. resp.setContentType("text/html; charset=utf8");
  17. resp.getWriter().write("当前未登录, 不能发布博客!");
  18. return;
  19. }
  20. // 2. 获取请求中的参数(博客的标题和正文)
  21. req.setCharacterEncoding("utf8");
  22. String title = req.getParameter("title");
  23. String content = req.getParameter("content");
  24. // 3. 构造 Blog 对象, 并且插入到数据库中.
  25. Blog blog = new Blog();
  26. blog.setTitle(title);
  27. blog.setContent(content);
  28. blog.setUserId(user.getUserId());
  29. // blogId 是自增主键, 不需要设置. postTime 直接在数据库操作中, 已经使用 now 来设置了.
  30. BlogDao blogDao = new BlogDao();
  31. blogDao.insert(blog);
  32. // 4. 构造 重定向报文, 回到 博客列表页.
  33. resp.sendRedirect("blog_list.html");
  34. }
  • 实现客户端代码 

 

11.对博客进行测试

11.1设计测试用例

 11.2对相关页面进行自动化测试

11.2.1查看登录页面是否含有主页和写博客
  1. public void test1() throws InterruptedException {
  2. EdgeOptions options = new EdgeOptions();
  3. options.addArguments("--remote-allow-origins=*");
  4. EdgeDriver driver = new EdgeDriver(options);
  5. driver.get("http://127.0.0.1:8080/blog_system/login.html");
  6. Thread.sleep(3000);
  7. driver.findElement(By.cssSelector("body > div.nav > a:nth-child(4)"));
  8. Thread.sleep(3000);
  9. driver.findElement(By.cssSelector("body > div.nav > a:nth-child(5)"));
  10. Thread.sleep(3000);
  11. driver.quit();
  12. }
  13. public static void main(String[] args) throws InterruptedException {
  14. Test test=new Test();
  15. test.test1();
  16. }
11.2.2 输入用户名和密码测试正确登录功能
  1. @ParameterizedTest
  2. @CsvSource({"zhangsan,123","张三,123"})
  3. void test2(String name,String password) throws InterruptedException {
  4. EdgeOptions options = new EdgeOptions();
  5. options.addArguments("--remote-allow-origins=*");
  6. EdgeDriver driver = new EdgeDriver(options);
  7. driver.get("http://127.0.0.1:8080/blog_system/login.html");
  8. Thread.sleep(3000);
  9. //找到用户名,写入
  10. driver.findElement(By.cssSelector("#username")).sendKeys(name);
  11. Thread.sleep(3000);
  12. //找到密码写入
  13. driver.findElement(By.cssSelector("#password")).sendKeys(password);
  14. Thread.sleep(3000);
  15. //点击登录
  16. driver.findElement(By.cssSelector("#login-btn")).click();
  17. //查看是否登陆成功
  18. driver.findElement(By.cssSelector("body > div.container > div.container-right > div:nth-child(1) > a"));
  19. Thread.sleep(3000);
  20. driver.navigate().back();
  21. driver.quit();
  22. }
11.2.3输入用户名和密码测试异常登录
  1. @ParameterizedTest
  2. @CsvSource({"zhang,123","aaa,123"})
  3. void test3(String name,String password) throws InterruptedException {
  4. EdgeOptions options = new EdgeOptions();
  5. options.addArguments("--remote-allow-origins=*");
  6. EdgeDriver driver = new EdgeDriver(options);
  7. driver.get("http://127.0.0.1:8080/blog_system/login.html");
  8. Thread.sleep(3000);
  9. //找到用户名,写入
  10. driver.findElement(By.cssSelector("#username")).sendKeys(name);
  11. Thread.sleep(3000);
  12. //找到密码写入
  13. driver.findElement(By.cssSelector("#password")).sendKeys(password);
  14. Thread.sleep(3000);
  15. //点击登录
  16. driver.findElement(By.cssSelector("#login-btn")).click();
  17. //查看是否登陆成功
  18. //期望的文本
  19. String exptxt="用户名或密码错误! 登陆失败!";
  20. //实际的文本
  21. String actual=driver.findElement(By.cssSelector("body")).getText();
  22. Assertions.assertEquals(exptxt,actual);
  23. Thread.sleep(3000);
  24. driver.navigate().back();
  25. driver.quit();
  26. }
11.2.4列表页正常登录
  1. void test4() throws InterruptedException {
  2. EdgeOptions options = new EdgeOptions();
  3. options.addArguments("--remote-allow-origins=*");
  4. EdgeDriver driver = new EdgeDriver(options);
  5. driver.get("http://127.0.0.1:8080/blog_system/blog_list.html");
  6. Thread.sleep(3000);
  7. driver.findElement(By.cssSelector("body > div.container > div.container-left > div > div:nth-child(4) > span:nth-child(1)"));
  8. driver.findElement(By.cssSelector("body > div.container > div.container-left > div > div:nth-child(4) > span:nth-child(2)"));
  9. driver.quit();
  10. }
11.2.5编辑页正常登录
  1. @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
  2. public class BlogEditTest extends AutotestUtils {
  3. public static EdgeDriver driver = createDriver();
  4. @BeforeAll
  5. static void baseControl(){
  6. driver.get("http://42.192.83.143:8563/blog_system/blog_edit.html");
  7. }
  8. /**
  9. * 检查博客编辑页可以正常打开
  10. */
  11. @Test
  12. @Order(1)
  13. void editPageLoadRight() throws IOException {
  14. driver.findElement(By.cssSelector("body > div.nav > a:nth-child(5)"));
  15. driver.findElement(By.cssSelector("body > div.nav > a:nth-child(6)"));
  16. getScreenShot(getClass().getName());
  17. }
  18. @Test
  19. @Order(2)
  20. void editAndSubimitBlog() throws IOException {
  21. String expect = "java104&105 Autotest";
  22. driver.findElement(By.cssSelector("#title")).sendKeys(expect);
  23. //因博客系统使用到的编辑是第三方软件,所以不能直接使用sendKeys向编辑模块发送文本
  24. driver.findElement(By.cssSelector("#editor > div.editormd-toolbar > div > ul > li:nth-child(21) > a")).click();
  25. driver.findElement(By.cssSelector("#editor > div.editormd-toolbar > div > ul > li:nth-child(5) > a")).click();
  26. driver.findElement(By.cssSelector("#submit")).click();
  27. getScreenShot(getClass().getName());
  28. //获取列表页第一条博客的标题文本,检查是否跟预期相符
  29. String actual = driver.findElement(By.cssSelector("body > div.container > div.right > div:nth-child(1) > div.title")).getText();
  30. Assertions.assertEquals(expect,actual);
  31. }
 11.2.6对时间进行判断
  1. public List<String> getTime(){
  2. //文件能不能按照天的维度按文件夹进行保存
  3. //文件格式 20230212-123030毫秒
  4. SimpleDateFormat sim1 = new SimpleDateFormat("yyyyMMdd-HHmmssSS");
  5. SimpleDateFormat sim2 = new SimpleDateFormat("yyyyMMdd");
  6. String filename = sim1.format(System.currentTimeMillis());
  7. String dirname = sim2.format(System.currentTimeMillis());
  8. List<String> list = new ArrayList<>();
  9. list.add(dirname);
  10. list.add(filename);
  11. return list;
  12. }
  13. /**
  14. * 获取屏幕截图,把所有的用例执行的结果保存下来
  15. */
  16. public void getScreenShot(String str) throws IOException {
  17. List<String> list = getTime();
  18. //dir+filename
  19. // ./指的是当前的项目路径下,也就是BlogAutoTest下
  20. // ./src/test/java/com/blogWebAutoTest/dirname/filename
  21. // ./src/test/java/com/blogWebAutoTest/20230212/logintest_20230212-123030毫秒.png
  22. String filename = "./src/test/java/com/blogWebAutoTest/"+list.get(0)+"/"+str+"_"+list.get(1)+".png";
  23. File srcfile = driver.getScreenshotAs(OutputType.FILE);
  24. //把屏幕截图生成的文件放到指定的路径
  25. FileUtils.copyFile(srcfile,new File(filename));
  26. }
 11.2.7对博客详情页进行判断(不要获取动态的)
  1. public class BlogDetailTest extends AutotestUtils {
  2. public static ChromeDriver driver = createDriver();
  3. @BeforeAll
  4. static void baseControl(){
  5. driver.get("http://42.192.83.143:8563/blog_system/blog_detail.html?blogId=79");
  6. }
  7. @Test
  8. void blogDeailLoadRight() throws IOException{
  9. driver.findElement(By.cssSelector("body > div.container > div.right > div > h3"));
  10. driver.findElement(By.cssSelector("body > div.container > div.right > div > div.date"));
  11. getScreenShot(getClass().getName());
  12. }
  13. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/675467
推荐阅读
相关标签
  

闽ICP备14008679号