基于Servlet的个人博客系统

目录

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
    <!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 中引入 Servlet API 依赖的 jar 包(把中央仓库中提供的 xml 复制到项目的 pom.xml 中)

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

                 

3.数据库设计

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

         

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

 代码如下:

//通过这个类来封装DataSource资源
public class DBUtil {
    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("jdbc:mysql://127.0.0.1:3306/blog_system?characterEncoding=utf8&useSSL=false");
                    //用户名
                    ((MysqlDataSource) dataSource).setUser("root");
                    //密码
                    ((MysqlDataSource) dataSource).setPassword("20010211");
                }
            }
        }
        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();
            }
        }
    }
}
  • 创建两个实体类,设计的表结构怎么设计就怎么实现,每一个实体类对应表结构的一条记录.

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

public class Blog {
    private int blogId;
    private String title;
    private String content;
    //MySQL的有关时间都是使用Timestamp来表示
    private Timestamp postTime;
    private int userId;

    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 String getPostTime() {
        //魔改一下时间日期,格式化时间
        SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return simpleDateFormat.format(postTime);
    }

    public void setPostTime(Timestamp postTime) {
        this.postTime = postTime;
    }

    public int getUserId() {
        return userId;
    }

    public void setUserId(int userId) {
        this.userId = userId;
    }
}

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

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;
    }
}
  •  针对数据库增删改查操作分别对两个实体类进行封装
  • 对博客类进行封装
  1.  插入一个博客到数据库中 -- 发布博客

代码如下:

 // 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
            int ret = statement.executeUpdate();
            if (ret != 1) {
                System.out.println("博客插入失败!");
            } else {
                System.out.println("博客插入成功!");
            }
            //    [注意!!] close 其实不应该在这里调用. 一旦上面抛出异常, 此处的 close 可能无法被执行.
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            // 4. 释放对应的资源
            DBUtil.close(connection, statement, null);
        }
    }

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

代码如下:

 // 2. 根据博客 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. 遍历结果集合
            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;
    }

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

代码如下: 

<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
    <script src="js/app.js"></script>
    <script>
        // 发送 ajax 从服务器获取数据
        function getBlogs() {
            $.ajax({
                type: 'get',
                url: 'blog',
                success: function(body) {
                    // 获取成功, 则 body 就是一个 js 对象数组. 每个元素就是一个博客
                    //清空右半部分内容
                    let container = document.querySelector('.container-right');
                    //遍历body,构造出一个个bodyDive
                    for (let blog of body) {
                        // 构造 blogDiv
                        let blogDiv = document.createElement('div');
                        blogDiv.className = 'blog';

                        // 构造博客标题
                        let titleDiv = document.createElement('div');
                        titleDiv.className = 'title';
                        titleDiv.innerHTML = blog.title;

                        // 构造博客的日期
                        let dateDiv = document.createElement('div');
                        dateDiv.className = 'date';
                        dateDiv.innerHTML = blog.postTime;

                        // 构造博客的摘要
                        let descDiv = document.createElement('div');
                        descDiv.className = 'desc';
                        descDiv.innerHTML = blog.content;

                        // 构造查看全文按钮
                        let a = document.createElement('a');
                        a.href = 'blog_detail.html?blogId=' + blog.blogId;
                        a.innerHTML = '查看全文 &gt;&gt;';

                        // 拼装最终结果
                        blogDiv.appendChild(titleDiv);
                        blogDiv.appendChild(dateDiv);
                        blogDiv.appendChild(descDiv);
                        blogDiv.appendChild(a);
                        container.appendChild(blogDiv);
                    }
                }
            });
        }

        // 此处还需要来一个函数调用. 
        getBlogs();

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

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

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

  •  修改服务器代码,通过blogid参数来判断是获取列表还是详情页
WebServlet("/blog")
public class BlogServlet extends HttpServlet {
    private ObjectMapper objectMapper = new ObjectMapper();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 按照约定的接口格式返回数据
        // 在博客列表页中, 已经使用了 BlogServlet.doGet 方法了.
        // 博客详情页, 也想用. 就需要做出区分. 使用 query string 来区分.
        // 如果请求带有 query string , 有 blogId 这个参数, 就认为是博客详情页的请求.
        // 如果请求不带有 query string, 就认为是博客列表页的请求.
        resp.setContentType("application/json; charset=utf8");

        BlogDao blogDao = new BlogDao();
        String blogId = req.getParameter("blogId");
        if (blogId == null) {
            // 博客列表页发起的请求
            List<Blog> blogs = blogDao.selectAll();
            resp.getWriter().write(objectMapper.writeValueAsString(blogs));
        } else {
            // 博客详情页发起的请求
            Blog blog = blogDao.selectOne(Integer.parseInt(blogId));
            resp.getWriter().write(objectMapper.writeValueAsString(blog));
        }
    }
  •  修改博客详情页的代码,改变其中不变的内容(博客的正文是markdown格式,数据库存的也是markdown格式,根据获取到的响应数据, 通过 editor.md 转换成 html, 并显示)
<!-- 通过 ajax 获取到博客详情内容 -->
<script src="js/app.js"></script>
<script>
        function getBlog() {
            $.ajax({
                type: 'get',
                //location.search 拿到了形如 '?blogId=1' 这样的一段内容
                url: 'blog' + location.search,
                success: function(body) {
                    let h3 = document.querySelector('.blog-detail>h3');
                    h3.innerHTML = body.title;
                    let dateDiv = document.querySelector('.blog-detail>.date');
                    dateDiv.innerHTML = body.postTime;
                    let contentDiv = document.querySelector('#content');
                    contentDiv.innerHTML = body.content;
                    // 构造博客正文
                    // 如果直接把 content 设为 innerHTML, 此时展示在界面上的内容, 是原始的 markdown 字符串
                    // 此处需要的是渲染后的, 带有格式的效果
                    
 
                    // 第一个参数对应 id=content 的 html 标签. 渲染后得到的 html 片段就会被放到这个 标签下.

                    // 构造博客正文此处使用 editor.md 来进行渲染
                    editormd.markdownToHTML('content', { markdown: body.content });
                }
            });
        }

        getBlog();

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

  • 约定前后端请求

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

usename=张三&password=123

响应:

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

  • 实现服务器登录 
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 1. 从请求中获取到用户名和密码
        req.setCharacterEncoding("utf-8");
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        if (username == null || username.equals("") || password == null || password.equals("20010211")) {
            // 用户名密码为空. 直接返回登陆失败
            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);
        // 在会话中保存一下 user, 以备后面使用. 后续访问其他页面, 就可以直接通过会话拿到当前是哪个用户在访问了.
        session.setAttribute("user", user);

        // 4. 构造 302 响应报文
        resp.sendRedirect("blog_list.html");
    }
  • 登陆页面提供一个 form 表单 , 通过 form 的方式把用户名密码提交给服务器。(修改了button提交按钮,加上了login和post)
<!-- 用这个元素作为页面的版心, 把对话框放到这个元素里面, 垂直水平居中 -->
<div class="login-container">
    <form action="login" method="post">
        <!-- 登录对话框 -->
        <div class="dialog">
            <h3>登录</h3>
            <div class="row">
                <span>用户名</span>
                <!-- 这两个框很关键, 后面还要用, 就起个 id 作为标识 -->
                <input type="text" id="username" name="username">
            </div>
            <div class="row">
                <span>密码</span>
                <input type="password" id="password" name="password">
            </div>
            <div class="row">
                <input id="login-btn" value="登陆" type="submit">
            </div>
        </div>
    </form>
</div>
  • 实现强制登录功能(在博客列表页,编辑页,详情页在页面加载后发起ajax请求,这个请求从服务器获取当前登陆状态,如果当下未登录则返回到登录页,已经登陆不用处理)
  • // 这个文件里放一些页面公共的代码
     
    // 加上一个逻辑, 通过 GET /login 这个接口来获取下当前的登录状态~
    function getUserInfo(pageName) {
        $.ajax({
            type: 'get',
            url: 'login',
            success: function(body) {
                // 判定此处的 body 是不是一个有效的 user 对象(userId 是否非 0)
                if (body.userId && body.userId > 0) {
                    // 登录成功!
                    // 不做处理!
                    console.log("当前用户登录成功! 用户名: " + body.username);
     
                    // 根据当前用户登录的情况, 把当前用户名设置到界面上
                    if (pageName == 'blog_list.html') {
                        changeUserName(body.username);
                    }
                } else {
                    // 登录失败!
                    // 让前端页面, 跳转到 login.html
                    alert("当前您尚未登录! 请登录后再访问博客列表!");
                    location.assign('blog_login.html');
                }
            },
            error: function() {
                alert("当前您尚未登录! 请登录后再访问博客列表!");
                location.assign('blog_login.html');
            }
        });
    }
     
    function changeUserName(username) {
        let h3 = document.querySelector('.card>h3');
        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:"张三"

  • 实现服务器代码 
    @WebServlet("/userInfo")
    public class UserInfoServlet extends HttpServlet {
        private ObjectMapper objectMapper = new ObjectMapper();
    
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            // 获取用户信息
            String blogId = req.getParameter("blogId");
            if (blogId == null) {
                // 列表页, 获取当前登陆用户的信息
                // 直接从 session 中获取即可~~
                getUserInfoFromSession(req, resp);
            } else {
                // 详情页, 获取文章作者的信息
                // 查询数据库
                getUserInfoFromDB(req, resp, Integer.parseInt(blogId));
            }
        }
    
        private void getUserInfoFromDB(HttpServletRequest req, HttpServletResponse resp, int blogId) throws IOException {
            // 1. 先根据 blogId 查询 Blog 对象, 获取到 userId (作者是谁)
            BlogDao blogDao = new BlogDao();
            Blog blog = blogDao.selectOne(blogId);
            if (blog == null) {
                // 如果参数传来的这个 blogId 是随便瞎写的. 数据库里没有.
                resp.setStatus(404);
                resp.setContentType("text/html;charset=utf8");
                resp.getWriter().write("blogId 不存在");
                return;
            }
            // 2. 根据 userId 查询对应的 User 对象即可
            UserDao userDao = new UserDao();
            User user = userDao.selectById(blog.getUserId());
            if (user == null) {
                resp.setStatus(404);
                resp.setContentType("text/html;charset=utf8");
                resp.getWriter().write("blogId 不存在");
                return;
            }
            // 3. 把 user 对象返回给浏览器了
            user.setPassword("");
            resp.setContentType("application/json;charset=utf8");
            resp.getWriter().write(objectMapper.writeValueAsString(user));
        }
    
        private void getUserInfoFromSession(HttpServletRequest req, HttpServletResponse resp) throws IOException {
            HttpSession session = req.getSession(false);
            if (session == null) {
                resp.setStatus(403);
                resp.setContentType("text/html;charset=utf8");
                resp.getWriter().write("当前未登录");
                return;
            }
            User user = (User) session.getAttribute("user");
            if (user == null) {
                resp.setStatus(403);
                resp.setContentType("text/html;charset=utf8");
                resp.getWriter().write("当前未登录");
                return;
            }
            // user 获取到了, 把 user 中的 password 给干掉, 然后返回.
            user.setPassword("");
    
            resp.setContentType("application/json; charset=utf8");
            resp.getWriter().write(objectMapper.writeValueAsString(user));
        }
    }

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

  • 约定前后端交互接口 

请求: GET/logout

响应:HTTP/1.1 302

location:login.html 

  • 服务器 注销
@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.setStatus(403);
            return;
        }
        // 直接把 session 中之前的 user 对象给删掉即可!!
        session.removeAttribute("user");
        // 不要忘记重定向到登陆页面!
        resp.sendRedirect("login.html");
    }
}
  •  客户端代码只需要调一个注销按钮,将注销按钮设置为 <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

                           没有删除权限  

  • 服务器删除代码 
    @WebServlet("/blog_delete")
    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.setStatus(403);
                resp.setContentType("text/html; charset=utf8");
                resp.getWriter().write("您当前未登录, 不能删除!");
                return;
            }
            User user = (User) session.getAttribute("user");
            if (user == null) {
                resp.setStatus(403);
                resp.setContentType("text/html; charset=utf8");
                resp.getWriter().write("您当前未登录, 不能删除!");
                return;
            }
            // 2. 获取到 blogId
            String blogId = req.getParameter("blogId");
            if (blogId == null) {
                // 这个 blogId 参数不存在, 无法删除
                resp.setStatus(404);
                resp.setContentType("text/html; charset=utf8");
                resp.getWriter().write("您当前删除的 blogId 有误");
                return;
            }
            // 3. 查询出这个 blogId 对应的 Blog 对象
            BlogDao blogDao = new BlogDao();
            Blog blog = blogDao.selectOne(Integer.parseInt(blogId));
            if (blog == null) {
                // 这个 blogId 参数不存在, 无法删除
                resp.setStatus(404);
                resp.setContentType("text/html; charset=utf8");
                resp.getWriter().write("您当前删除的 博客 不存在! blogId=" + blogId);
                return;
            }
            // 4. 判定登陆用户是否就是文章作者
            if (blog.getUserId() != user.getUserId()) {
                // blog.getUserId() 文章的作者
                // user.getUserId() 从 session 里拿的登陆的用户是谁.
                // 不一样, 说明在删别人的文章.
                // 直接返回 403
                resp.setStatus(403);
                resp.setContentType("text/html; charset=utf8");
                resp.getWriter().write("当前您不能删除别人的博客!");
                return;
            }
            // 5. 真正执行删除操作.
            blogDao.delete(Integer.parseInt(blogId));
            // 6. 返回 302 重定向
            resp.sendRedirect("blog_list.html");
        }

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

        updateDeleteURL();

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

  • 前后端交互接口 

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

  title=标题$content=正文

响应:

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

  • 服务器代码 
@Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 使用这个方法, 来实现提交新博客
        // 1. 先检查一下用户的登陆状态, 获取到会话和用户信息.
        //    如果未登录, 显然不能提交博客~
        HttpSession session = req.getSession(false);
        if (session == null) {
            resp.setStatus(403);
            resp.setContentType("text/html; charset=utf8");
            resp.getWriter().write("当前未登录, 不能发布博客!");
            return;
        }
        User user = (User) session.getAttribute("user");
        if (user == null) {
            resp.setStatus(403);
            resp.setContentType("text/html; charset=utf8");
            resp.getWriter().write("当前未登录, 不能发布博客!");
            return;
        }

        // 2. 获取请求中的参数(博客的标题和正文)
        req.setCharacterEncoding("utf8");
        String title = req.getParameter("title");
        String content = req.getParameter("content");

        // 3. 构造 Blog 对象, 并且插入到数据库中.
        Blog blog = new Blog();
        blog.setTitle(title);
        blog.setContent(content);
        blog.setUserId(user.getUserId());
        // blogId 是自增主键, 不需要设置. postTime 直接在数据库操作中, 已经使用 now 来设置了.
        BlogDao blogDao = new BlogDao();
        blogDao.insert(blog);
        // 4. 构造 重定向报文, 回到 博客列表页.
        resp.sendRedirect("blog_list.html");
    }
  • 实现客户端代码 

 

11.对博客进行测试

11.1设计测试用例

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

11.2.1查看登录页面是否含有主页和写博客
public void test1() throws InterruptedException {
      EdgeOptions options = new EdgeOptions();
      options.addArguments("--remote-allow-origins=*");
      EdgeDriver driver = new EdgeDriver(options);
      driver.get("http://127.0.0.1:8080/blog_system/login.html");
      Thread.sleep(3000);
      driver.findElement(By.cssSelector("body > div.nav > a:nth-child(4)"));
      Thread.sleep(3000);
      driver.findElement(By.cssSelector("body > div.nav > a:nth-child(5)"));
      Thread.sleep(3000);
      driver.quit();
  }

    public static void main(String[] args) throws InterruptedException {
        Test test=new Test();
        test.test1();
    }
11.2.2 输入用户名和密码测试正确登录功能
 @ParameterizedTest
 @CsvSource({"zhangsan,123","张三,123"})
   void test2(String name,String password) throws InterruptedException {
       EdgeOptions options = new EdgeOptions();
       options.addArguments("--remote-allow-origins=*");
       EdgeDriver driver = new EdgeDriver(options);
       driver.get("http://127.0.0.1:8080/blog_system/login.html");
       Thread.sleep(3000);
       //找到用户名,写入
       driver.findElement(By.cssSelector("#username")).sendKeys(name);
       Thread.sleep(3000);
       //找到密码写入
       driver.findElement(By.cssSelector("#password")).sendKeys(password);
       Thread.sleep(3000);
       //点击登录
       driver.findElement(By.cssSelector("#login-btn")).click();
       //查看是否登陆成功
       driver.findElement(By.cssSelector("body > div.container > div.container-right > div:nth-child(1) > a"));
       Thread.sleep(3000);
       driver.navigate().back();
       driver.quit();
   }
11.2.3输入用户名和密码测试异常登录
@ParameterizedTest
    @CsvSource({"zhang,123","aaa,123"})
    void test3(String name,String password) throws InterruptedException {
        EdgeOptions options = new EdgeOptions();
        options.addArguments("--remote-allow-origins=*");
        EdgeDriver driver = new EdgeDriver(options);
        driver.get("http://127.0.0.1:8080/blog_system/login.html");
        Thread.sleep(3000);
        //找到用户名,写入
        driver.findElement(By.cssSelector("#username")).sendKeys(name);
        Thread.sleep(3000);
        //找到密码写入
        driver.findElement(By.cssSelector("#password")).sendKeys(password);
        Thread.sleep(3000);
        //点击登录
        driver.findElement(By.cssSelector("#login-btn")).click();
        //查看是否登陆成功
      //期望的文本
        String exptxt="用户名或密码错误! 登陆失败!";
        //实际的文本
        String actual=driver.findElement(By.cssSelector("body")).getText();
        Assertions.assertEquals(exptxt,actual);
        Thread.sleep(3000);
        driver.navigate().back();
        driver.quit();
    }
11.2.4列表页正常登录
 void test4() throws InterruptedException {
        EdgeOptions options = new EdgeOptions();
        options.addArguments("--remote-allow-origins=*");
        EdgeDriver driver = new EdgeDriver(options);
        driver.get("http://127.0.0.1:8080/blog_system/blog_list.html");
        Thread.sleep(3000);
        driver.findElement(By.cssSelector("body > div.container > div.container-left > div > div:nth-child(4) > span:nth-child(1)"));
        driver.findElement(By.cssSelector("body > div.container > div.container-left > div > div:nth-child(4) > span:nth-child(2)"));
        driver.quit();
    }
11.2.5编辑页正常登录
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class BlogEditTest extends AutotestUtils {
    public static EdgeDriver driver = createDriver();
    @BeforeAll
    static  void baseControl(){
        driver.get("http://42.192.83.143:8563/blog_system/blog_edit.html");
    }
    /**
     * 检查博客编辑页可以正常打开
     */
    @Test
    @Order(1)
    void editPageLoadRight() throws IOException {
        driver.findElement(By.cssSelector("body > div.nav > a:nth-child(5)"));
        driver.findElement(By.cssSelector("body > div.nav > a:nth-child(6)"));
        getScreenShot(getClass().getName());
    }
    
    @Test
    @Order(2)
    void editAndSubimitBlog() throws IOException {
        String expect = "java104&105 Autotest";
        driver.findElement(By.cssSelector("#title")).sendKeys(expect);
        //因博客系统使用到的编辑是第三方软件,所以不能直接使用sendKeys向编辑模块发送文本
        driver.findElement(By.cssSelector("#editor > div.editormd-toolbar > div > ul > li:nth-child(21) > a")).click();
        driver.findElement(By.cssSelector("#editor > div.editormd-toolbar > div > ul > li:nth-child(5) > a")).click();
        driver.findElement(By.cssSelector("#submit")).click();
        getScreenShot(getClass().getName());
        //获取列表页第一条博客的标题文本,检查是否跟预期相符
        String actual = driver.findElement(By.cssSelector("body > div.container > div.right > div:nth-child(1) > div.title")).getText();
        Assertions.assertEquals(expect,actual);

    }
 11.2.6对时间进行判断
public List<String> getTime(){
        //文件能不能按照天的维度按文件夹进行保存
        //文件格式 20230212-123030毫秒
        SimpleDateFormat sim1 = new SimpleDateFormat("yyyyMMdd-HHmmssSS");
        SimpleDateFormat sim2 = new SimpleDateFormat("yyyyMMdd");
        String filename = sim1.format(System.currentTimeMillis());
        String dirname = sim2.format(System.currentTimeMillis());
        List<String> list = new ArrayList<>();
        list.add(dirname);
        list.add(filename);
        return  list;
    }
    /**
     * 获取屏幕截图,把所有的用例执行的结果保存下来
     */
    public void getScreenShot(String str) throws IOException {
        List<String> list = getTime();
        //dir+filename
        // ./指的是当前的项目路径下,也就是BlogAutoTest下
        // ./src/test/java/com/blogWebAutoTest/dirname/filename
        // ./src/test/java/com/blogWebAutoTest/20230212/logintest_20230212-123030毫秒.png
        String filename = "./src/test/java/com/blogWebAutoTest/"+list.get(0)+"/"+str+"_"+list.get(1)+".png";
        File srcfile = driver.getScreenshotAs(OutputType.FILE);
        //把屏幕截图生成的文件放到指定的路径
        FileUtils.copyFile(srcfile,new File(filename));
    }
 11.2.7对博客详情页进行判断(不要获取动态的)
public class BlogDetailTest extends AutotestUtils {
    public static ChromeDriver driver = createDriver();
    @BeforeAll
    static  void baseControl(){
        driver.get("http://42.192.83.143:8563/blog_system/blog_detail.html?blogId=79");
    }
    @Test
    void blogDeailLoadRight() throws IOException{
        driver.findElement(By.cssSelector("body > div.container > div.right > div > h3"));
        driver.findElement(By.cssSelector("body > div.container > div.right > div > div.date"));
        getScreenShot(getClass().getName());

    }
}

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值