Lesson12:博客系统(基于模板引擎)

目录

一、准备工作

1.1 基本环境的搭建

1.2 对博客系统的分析

二、数据库

2.1 数据库设计

2.2 封装数据库相关操作并验证

2.2.1 创建相关的类

2.2.2 封装数据库的相关操作

三、Thymeleaf的相关操作

3.1 Thymeleaf初始化的优化

3.2 编写模板文件

四、实现登录页面、强制登录功能和注册页面

4.1 实现登录页面

4.2 实现强制登录功能

4.3 实现注册页面

五、实现博客详情页

5.1 博客详情展示

5.2 评论的显示

5.3 评论功能

5.4 提问功能

5.5 问题删除功能

5.6 注意

⑤如何将页面按照markdown的形式显示。

5.7 前端代码

六、博客删除页

七、实现博客编辑页

7.1 前端页面的设计

7.2 后端实现逻辑

八、实现博客修改页

九、实现上传头像功能

十、实现问题回答页

10.1 前端页面设计

10.2 后端设计

十一、实现注销功能

 十二、实现博客列表页

12.1 实现流程

12.2 生成模板

12.3 博客的内容太多,超过设置的背景

12.4 完成Servlet的代码,实现整个页面的渲染


一、准备工作

1.1 基本环境的搭建

主要分为7个步骤:

创建maven项目、引入依赖、创建目录结构、写一个测试代码、打包、部署、验证

具体操作见博客Lesson9:Tomcat 和 Servlet(基础篇)_刘减减的博客-CSDN博客中的第三小节。

1.2 对博客系统的分析

主要包含三个部分的逻辑:

①处理数据库的部分 M(Model)

②处理前端请求的部分 C(controller)

③前端展示的细节部分 V(View)

这三个部分称为MVC,是一个通用的概念,可以使用该框架开发web程序。

二、数据库

2.1 数据库设计

主要包含四个部分的数据:博客数据、用户数据、评论数据、问题数据

2.2 封装数据库相关操作并验证

2.2.1 创建相关的类

分别创建Blog、User、Comment、Question四个类,类中的成员变量和数据库中保持一致,生成成员变量的get、set和toString方法。以创建Blog类为例:

public class Blog {
    private int blogId;
    private String blogTitle;
    private String blogContent;
    private Timestamp blogTime;
    private int blogAuthor;
    private int visitCount;
    private int commentCount;

    public int getVisitCount() {
        return visitCount;
    }

    public void setVisitCount(int visitCount) {
        this.visitCount = visitCount;
    }

    public int getCommentCount() {
        return commentCount;
    }

    public void setCommentCount(int commentCount) {
        this.commentCount = commentCount;
    }

    public int getBlogId() {
        return blogId;
    }

    public void setBlogId(int blogId) {
        this.blogId = blogId;
    }

    public String getBlogTitle() {
        return blogTitle;
    }

    public void setBlogTitle(String blogTitle) {
        this.blogTitle = blogTitle;
    }


    public String getBlogContent() {
        return blogContent;
    }

    public void setBlogContent(String blogContent) {
        this.blogContent = blogContent;
    }

    public Timestamp getBlogTime() {
        return blogTime;
    }

    public void setBlogTime(Timestamp blogTime) {
        this.blogTime = blogTime;
    }

    public int getBlogAuthor() {
        return blogAuthor;
    }

    public void setBlogAuthor(int blogAuthor) {
        this.blogAuthor = blogAuthor;
    }

    @Override
    public String toString() {
        return "Blog{" +
                "blogId=" + blogId +
                ", blogTitle='" + blogTitle + '\'' +
                ", blogContent='" + blogContent + '\'' +
                ", blogTime=" + blogTime +
                ", blogAuthor=" + blogAuthor +
                ", visitCount=" + visitCount +
                ", commentCount=" + commentCount +
                '}';
    }
}

2.2.2 封装数据库的相关操作

DBUtil:封装数据库的连接

BlogDao:实现对博客的增删改查。

        insert方法:增加一个博客

        delete方法:删除一个博客

        selectOne方法:根据博客Id查找博客。用户博客详情页。

        selectAll方法:查找所有的博客。用户博客列表页的展示。

        updateBlog方法:修改博客的内容和标题。用于博客修改页。

        updateVisistCount:更新博客的访问次数。在用户的信息卡片上展示。

        updateCommentCount:更新博客的评论次数。在用户的信息卡片上展示。

        selectVisitAllCount:根据用户Id查找用户的总访问次数。在用户的信息卡片上展示。

        selectVisitCount:根据博客Id查找博客的总访问次数。在用户的信息卡片上展示。

        main方法:测试以上方法是否正确

UserDao:实现用户信息的增删改查

        login:注册。注意在注册十,只需要输入用户名和密码,用户的其他属性可以通过其他方法增加。

        getBlogCount:根据用户Id,得到用户总的博客数量。用户信息卡片的展示会用到。

        selectByName:根据用户名 查找用户。登录时使用的是用户名密码登录,因此需要实现该功能。

        uploadImages:上传头像。用户可以修改自己的头像。

        changeBlogCount:修改用户的博客数量。新增一篇博客时会用到该方法。

        deleteUser:删除用户。

        main方法:测试以上方法是否正确

CommentDao:实现评论的增加、删除和选择。

        insert:新增一个评论。

        delete:删除一个评论。

        selelctAll:查找该博客的所有评论。

QuestionDao:实现问题的增加、删除和选择。

        insert:新增一个问题。

        delete:删除一个问题。

        selelctAll:查找所有问题。

        selelctOne:根据问题ID查找问题。主要用户回答页面的使用。

以上的方法都是类似的。只展示DButil和BlogDao的代码,其他代码可以在这个基础上修改得到。

public class DBUtil {
    private static final String URL = "jdbc:mysql://127.0.0.1:3306/BlogSystem?characterEncoding=utf8&useSSL=false"; // BlogSystem是数据库的名称
    private static final String username = "root";
    private static final String password = "1111";  // 输入数据库的密码
    private static DataSource dataSource = new MysqlDataSource();
    static {
        ((MysqlDataSource)dataSource).setURL(URL);
        ((MysqlDataSource)dataSource).setUser(username);
        ((MysqlDataSource)dataSource).setPassword(password);
    }
    public Connection getConnectin() throws SQLException {
        return dataSource.getConnection();
    }
    public void close(Connection connection, PreparedStatement statement, ResultSet resultSet){
        if(resultSet != null){
            try {
                resultSet.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if(statement != null){
            try {
                statement.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if(connection == null){
            try {
                connection.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
}
package Model;

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 BlogDao {
    public static void insert(Blog blog){
        DBUtil dbUtil = new DBUtil();
        Connection connection = null;
        PreparedStatement statement = null;
        try {
            connection = dbUtil.getConnectin();
            String sql = "insert into blog (blogId,blogTitle,blogContent,blogTime,blogAuthor) values(null,?,?,?,?)";
            statement = connection.prepareStatement(sql);
            statement.setString(1,blog.getBlogTitle());
            statement.setString(2,blog.getBlogContent());
            statement.setTimestamp(3,blog.getBlogTime());
            statement.setInt(4,blog.getBlogAuthor());
            int ret = statement.executeUpdate();
            if(ret == 1){
                UserDao userDao = new UserDao();
                int blogcount = userDao.getBlogCount(blog.getBlogAuthor());
                System.out.println(blogcount);
                blogcount +=1;
                userDao.changeBlogCount(blogcount,blog.getBlogAuthor());
                System.out.println("插入成功");
            }else{
                System.out.println("插入失败");
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            dbUtil.close(connection,statement,null);
        }
    }
    public static void delete(int blogId){
        DBUtil dbUtil = new DBUtil();
        Connection connection = null;
        PreparedStatement statement = null;
        try {
            connection = dbUtil.getConnectin();
            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 throwables) {
            throwables.printStackTrace();
        }finally {
            dbUtil.close(connection,statement,null);
        }
    }
    public static Blog selectOne(int blogId){
        DBUtil dbUtil = new DBUtil();
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        Blog blog = new Blog();
        try {
            connection = dbUtil.getConnectin();
            String sql = "select * from blog where blogId=?";
            statement = connection.prepareStatement(sql);
            statement.setInt(1,blogId);
            resultSet = statement.executeQuery();
            if(resultSet.next()){
                blog.setBlogTitle(resultSet.getString("blogTitle"));
                blog.setBlogTime(resultSet.getTimestamp("blogTime"));
                blog.setBlogContent(resultSet.getString("blogContent"));
                blog.setBlogAuthor(resultSet.getInt("blogAuthor"));
                blog.setBlogId(resultSet.getInt("blogId"));
                blog.setCommentCount(resultSet.getInt("commentCount"));
                blog.setVisitCount(resultSet.getInt("visitCount"));
                return blog;
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            dbUtil.close(connection,statement,resultSet);
        }
        return null;
    }
    public static List<Blog> selectAll(){
        DBUtil dbUtil = new DBUtil();
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        List<Blog> blogs = new ArrayList<>();
        try {
            connection = dbUtil.getConnectin();
            String sql = "select * from blog order by blogTime desc";
            statement = connection.prepareStatement(sql);
            resultSet = statement.executeQuery();
            while (resultSet.next()){
                Blog blog = new Blog();
                blog.setBlogTitle(resultSet.getString("blogTitle"));
                blog.setBlogTime(resultSet.getTimestamp("blogTime"));
                String content = resultSet.getString("blogContent");
                if(content.length() > 100){
                    content = content.substring(0,100) + "...";
                    System.out.println(100);
                }
                blog.setBlogContent(content);
                blog.setBlogAuthor(resultSet.getInt("blogAuthor"));
                blog.setBlogId(resultSet.getInt("blogId"));
                blog.setCommentCount(resultSet.getInt("commentCount"));
                blog.setVisitCount(resultSet.getInt("visitCount"));
                blogs.add(blog);
            }
            return blogs;
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            dbUtil.close(connection,statement,resultSet);
        }
        return null;
    }
    public static void updateBlog(String blogTitle, String blogContent, int blogId){
        DBUtil dbUtil = new DBUtil();
        Connection connection = null;
        PreparedStatement statement = null;
        try {
            connection = dbUtil.getConnectin();
            String sql = "update blog set blogTitle = ?,blogContent=? where blogId = ?";
            statement = connection.prepareStatement(sql);
            statement.setString(1,blogTitle);
            statement.setString(2,blogContent);
            statement.setInt(3,blogId);
            int ret = statement.executeUpdate();
            if(ret == 1){
                System.out.println("修改成功");
            }else{
                System.out.println("修改失败");
            }
            return;
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            dbUtil.close(connection,statement,null);
        }
    }
    public static void updateVisitCount(int count,int blogId){
        DBUtil dbUtil = new DBUtil();
        Connection connection = null;
        PreparedStatement statement = null;
        try {
            connection = dbUtil.getConnectin();
            String sql = "update blog set visitCount = ? where blogId = ?";
            statement = connection.prepareStatement(sql);
            statement.setInt(1,count);
            statement.setInt(2,blogId);
            int ret = statement.executeUpdate();
            if(ret == 1){
                System.out.println("博客访问次数修改成功");
            }else{
                System.out.println("博客访问次数修改失败");
            }
            return;
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            dbUtil.close(connection,statement,null);
        }
    }
    public static void updateCommentCount(int count,int blogId){
        DBUtil dbUtil = new DBUtil();
        Connection connection = null;
        PreparedStatement statement = null;
        try {
            connection = dbUtil.getConnectin();
            String sql = "update blog set commentCount = ? where blogId = ?";
            statement = connection.prepareStatement(sql);
            statement.setInt(1,count);
            statement.setInt(2,blogId);
            int ret = statement.executeUpdate();
            if(ret == 1){
                System.out.println("评论次数修改成功");
            }else{
                System.out.println("评论次数修改失败");
            }
            return;
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            dbUtil.close(connection,statement,null);
        }
    }
    public static int selectVisitAllCount(int userId){
        DBUtil dbUtil = new DBUtil();
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        int count = 0;
        try {
            connection = dbUtil.getConnectin();
            String sql = "select sum(visitCount) from blog where blogAuthor = ?";
            statement = connection.prepareStatement(sql);
            statement.setInt(1,userId);
            resultSet = statement.executeQuery();
            if(resultSet.next()){
                count = resultSet.getInt("sum(visitCount)");
                return count;
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            dbUtil.close(connection,statement,null);
        }
        return 0;
    }
    public static int selectVisitCount(int blogId){
        DBUtil dbUtil = new DBUtil();
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        int count = 0;
        try {
            connection = dbUtil.getConnectin();
            String sql = "select visitCount from blog where blogId = ?";
            statement = connection.prepareStatement(sql);
            statement.setInt(1,blogId);
            resultSet = statement.executeQuery();
            if(resultSet.next()){
                count = resultSet.getInt("visitCount");
                return count;
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            dbUtil.close(connection,statement,null);
        }
        return 0;
    }

三、Thymeleaf的相关操作

3.1 Thymeleaf初始化的优化

如果我们按照博客Lesson11:模板引擎_刘减减的博客-CSDN博客中的操作实现博客列表页,就会在博客列表页中创建一个TemplateEngine实例,并且进行初始化操作。现在如果我们要在其他的页面,如博客详情页中使用TemplateEngine,就没法使用之前创建好的TemplateEngine对象。解决方案有以下几种:

①如果其他页面需要用到TemplateEngine,就再创建TemplateEngine实例,并再初始化一遍。

评价:可行但是不建议采用。TemplateEngine和数据库中的DataSource类似,只需要一份实例即可。如果搞了多份,每份TemplateEngine实例都要加载模板,会多消耗一份内存。会导致同一份模板数据,在数据库中存在了多份。

②能否把TemplateEngine做成一个单例呢?

ServletContextTemplateResolver resolver = new ServletContextTemplateResolver(getServletContext());
resolver.setPrefix("/WEB-INF/template/");
resolver.setSuffix(".html");
resolver.setCharacterEncoding("utf-8");

从TemplateEngine的初始化代码可以看到,初始化必须用到ServletContext对象。这个对象又只能在Servlet的环境下来获取到,即将上面的初始化代码,随便在servlet的某个方法里都好写。但是放在一个和Servlet无关的单独的类中,都不好写。因此这种方法并不推荐。

③借助Servlet中自身关于ServletContext的机制

ServletContext是上下文对象,每个webapp都有一个上下文对象 。可以让一个webapp内部的servlet之间共享同一个ServletContext。这样就可以依据ServletContext来进行多个Servlet之间的数据共享操作。基于这个机制,我们可以创建好一个TemplateEngine,保存到ServletContext中,这样,所有的servlet都可以使用这个TemplateEngine。

具体的解决方案:

在ServletContext被Tomcat创建好了之后,就立刻进行初始化TemplateEngine,并且把engine保存到ServletContext里面。servlet可以拿到ServletContext,进一步就可以拿到engine。

我们怎样才能捕获到Tomcat创建ServletContext呢?

使用Servlet的监听器可以允许程序员监听某些动作,当动作被Tomcat触发的时候,可以执行程序员自己写的代码。此时我们要监听的就是Tomcat创建ServletContext这个动作。


// 通过这个注解,Tomcat才能认识这是一个监听器对象
@WebListener
public class ThymeLeafListener implements ServletContextListener {
    // servletContext被创建时触发
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        // 1.创建一个模板引擎对象
        TemplateEngine engine = new TemplateEngine();
        // 2.创建一个ServletContextTemplateResolver对象,功能就是从磁盘上加载模板引擎文件
        // 这里需要改一下获取方式
        ServletContextTemplateResolver resolver = new ServletContextTemplateResolver(servletContextEvent.getServletContext());
        //3对resolver对象设置一些属性 加载 /WEB-INF/template/ 目录中, 以 .html 结尾的文件, 作为模板引擎
        resolver.setPrefix("/WEB-INF/template/");
        resolver.setSuffix(".html");
        resolver.setCharacterEncoding("utf-8");
        // 4 把resolver和engine关联起来
        engine.setTemplateResolver(resolver);
        // 5.将创建好的engine放到servletContext里面
        servletContextEvent.getServletContext().setAttribute("engine",engine);
        System.out.println("Themeleaf初始化完毕");
    }
    // ServletContext被销毁前触发 ,暂时不需要写
    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        
    }
}

注意:@WebListener这个注解一定要写。

3.2 编写模板文件

step1:把之前写的静态页面,全都拷贝到webapp目录中

step2:修改html文件,制作成Thymeleaf的模板文件

        将需要动态替换的部分,使用占位符占个位置。

step3:新建目录结构,将刚刚制作好的模板文件移到该目录下。具体操作见博客

Lesson11:模板引擎_刘减减的博客-CSDN博客的3.3小节。

四、实现登录页面、强制登录功能和注册页面

4.1 实现登录页面

登录页面是一个纯静态的页面,不需要通过servlet来渲染。登录页面的实现流程见博客Lesson10:ServletAPI详解(HttpServlet、HttpServletRequest、HttpServletResponse)_刘减减的博客-CSDN博客的第4.5小节。

@WebServlet("/login")
public class loginServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");
        resp.setContentType("text/html;charset=utf-8");
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        if(username == null || "".equals(username) || password == null || "".equals(password)){
            resp.getWriter().write("<h3>输入不合法</h3>");
            return;
        }
        User user = UserDao.selectByName(username);
        if(user == null){
            resp.getWriter().write("<h3>用户名或者密码错误</h3>");
            return;
        }
        boolean result = user.getPassword().equals(password);
        if(!result){
            resp.getWriter().write("<h3>用户名或者密码错误</h3>");
            return;
        }
        HttpSession session = req.getSession(true);
        session.setAttribute("user",user); // 将用户保存在session中
        resp.sendRedirect("bloglist.html"); // 登录成功后,跳转到博客列表页
    }
}

4.2 实现强制登录功能

我们约定,只有用户登录后,才能进入到博客系统中,访问到博客系统的各个页面。如果不登陆,直接尝试访问博客系统中的某一个页面,就会自动的跳转到登录页面。

如何实现呢?我们可以在进入代码入口的时候,先判定一下当前是否在已经登录的状态。这个功能可以通过session机制实现,在登录的时候 将user信息保存在session中,然后从session中读取user,如果可以读取到,就证明已经登录过了,执行正常的页面渲染。如果未读取到,则是未登录状态,就跳转到登录页面。由于每个页面都会用到强制登录功能,因此将其封装在一个类中。

public class Util {
    public static User checkLogin(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;
    }
}

4.3 实现注册页面

注册页面的前端实现部分只需要在登录页面上进行微调就可以。因此再次不做赘述。注册页面的实现逻辑:

点击登录页面上的注册——》跳转到注册页面——》输入用户名和两次密码——》点击注册,触发一个POST请求——》后端进行处理

后端拿到用户名和密码后:先从请求中读出用户名和密码——》判断输入是否合法——》在数据库中查询该用户是否已经存在——》不存在,判断两次密码输入是否一致——》一致就往数据库中的user表中插入该数据。

@WebServlet("/login")
public class LoginServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");
        resp.setContentType("text/html;charset=utf-8");
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        if(username == null || "".equals(username) || password == null || "".equals(password)){
            resp.getWriter().write("<h3>输入不合法</h3>");
            return;
        }
        User user = UserDao.selectByName(username);
        if(user == null){
            resp.getWriter().write("<h3>用户名或者密码错误</h3>");
            return;
        }
        boolean result = user.getPassword().equals(password);
        if(!result){
            resp.getWriter().write("<h3>用户名或者密码错误</h3>");
            return;
        }
        HttpSession session = req.getSession(true);
        session.setAttribute("user",user); // 将用户保存在session中
        resp.sendRedirect("bloglist.html"); // 登录成功后,跳转到博客列表页
    }
}

五、实现博客详情页

5.1 博客详情展示

实现流程:先判断是否登录——》从请求中读到blogId——》判断blogId的合法性——》根据blogId去数据库查询博客——》查询出来之后就更新博客的访问次数。

注意,此时信息卡片页显示的是博客作者的信息,根据博客的作者姓名在用户表里查到博客作者的信息。

@WebServlet("/blogdetail.html")
public class DetailServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");
        resp.setContentType ("text/html;charset=utf-8");
        // loginuser 表示当前登录的用户
        User Loginuser = Util.checkLogin(req);
        if(Loginuser == null){
            resp.sendRedirect("login.html");
            return;
        }
        String blogId = req.getParameter("blogId");
        HttpSession session = req.getSession(false);
        session.setAttribute("blogId",blogId);
        if(blogId == null || "".equals(blogId)){
            resp.getWriter().write("<h3>blogId不存在</h3>");
            return;
        }
        Blog blog = BlogDao.selectOne(Integer.parseInt(blogId));
        if(blog == null){
            resp.getWriter().write("<h3>查询的博客不存在</h3>");
            return;
        }else{
            // 此页的信息卡片需要显示作者的信息,根据博客的作者姓名在用户表里查到博客作者的信息
            User BlogUser = UserDao.selectOne(blog.getBlogAuthor());
            if(BlogUser == null){
                resp.getWriter().write("<h3>查询的博客作者不存在</h3>");
                return;
            }
            // 从评论表中查询出所有的博客
            List<Comment> comments = CommentDao.selectAll(Integer.parseInt(blogId));
            ServletContext servletContext = getServletContext();
            TemplateEngine engine = (TemplateEngine) servletContext.getAttribute("engine");
            WebContext webContext = new WebContext(req,resp,servletContext);
            // 如果读出的评论不为空,就显示评论
            if(comments != null){
                System.out.println(comments);
                webContext.setVariable("comments",comments);
            }
            // 进入到博客的详情页,该博客的访问量需要+1,先读出访问量,+1后,再写回到数据库
            int visitCount = blog.getVisitCount();
//            System.out.println("访问前的次数"+visitCount);
            visitCount +=1;
            BlogDao.updateVisitCount(visitCount,Integer.parseInt(blogId));
//            Blog blog2 = BlogDao.selectOne(Integer.parseInt(blogId));
//            int visitCount2 = blog2.getVisitCount();
//            System.out.println("访问后的次数"+visitCount2);
            webContext.setVariable("blog",blog);
            webContext.setVariable("bloguser",BlogUser);
//            System.out.println("登录用户"+Loginuser);
            // 在评论时,显示的是登录用户的信息
            webContext.setVariable("loginuser",Loginuser);

            int count = BlogDao.selectVisitCount(Integer.parseInt(blogId));
            webContext.setVariable("visitCount",count);
            // 只有登录的用户和博客作者是同一个人,才能删除博客、修改博客,为了避免发生错误,只有是同一个人才显示这两个按钮
            webContext.setVariable("showDeleteButton",Loginuser.getUserID()==blog.getBlogAuthor());
            webContext.setVariable("showAmendButton",Loginuser.getUserID()==blog.getBlogAuthor());
            engine.process("blogdetail",webContext, resp.getWriter());
        }
    }
}

5.2 评论的显示

实现流程和博客列表页的实现流程类似,在此不做赘述。

5.3 评论功能

先判断是否登录——》从请求中读到评论内容——》判断评论内容的合法性——》从session中读到blogId和user——》构造comment对象——》插入comment数据库——》根据blogID去blog中查询出被评论的博客,更新博客的评论次数。

@WebServlet("/comment")
public class CommentServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");
        resp.setContentType("text/html;charset=utf-8");
        User user = Util.checkLogin(req);
        if(user == null){
            resp.sendRedirect("login.html");
            return;
        }
        Comment comment = new Comment();
        String commentContent = req.getParameter("comment");
        System.out.println("从req中读到的评论内容"+commentContent);
        if(commentContent == null || "".equals(commentContent)){
            resp.getWriter().write("输入的评论不能为空");
            return;
        }
        HttpSession session = req.getSession(false);
        String blogId = (String) session.getAttribute("blogId");
//        System.out.println("从session中读到的blogId" + blogId);
        comment.setCommentContent(commentContent);
        comment.setCommentTime(new Timestamp(System.currentTimeMillis()));
        comment.setCommentUser(user.getUserName());
        comment.setBlogId(Integer.parseInt(blogId));
//        System.out.println(user.getUserPicture());
        comment.setCommentUserImage(user.getUserPicture());
//        System.out.println("登录用户的图片地址"+ user.getUserPicture());
//        System.out.println(comment);
        // comment表中新增一个数据后,评论数量+1
        CommentDao.insert(comment);
        Blog blog = BlogDao.selectOne(Integer.parseInt(blogId));
//        System.out.println("找出来的blog"+blog);
        int commentCount = blog.getCommentCount();
//        System.out.println("commentCount更新前" + commentCount);
        commentCount = commentCount + 1;
        BlogDao.updateCommentCount(commentCount,Integer.parseInt(blogId));
//        Blog blog2 = BlogDao.selectOne(Integer.parseInt(blogId));
//        int commentCount2 = blog2.getCommentCount();
//        System.out.println(blog2);
//        commentCount += 1;
//        System.out.println("commentCount更新后" + commentCount2);
        resp.sendRedirect("blogdetail.html?blogId=" + blogId);
    }
}

5.4 提问功能

提问功能的实现流程和评论功能类似,再此不做赘述。

问题提交后,会触发一个post请求。在servlet中处理post请求主要是将请求中的问题内容读出来并插入到数据库中。同时,问题提交后会跳转到问题展示页。此时会触发一个get请求,servlet在处理get请求时主要是显示所有的问题。


@WebServlet("/question.html")
public class QuestionServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");
        resp.setContentType("text/html;charset=utf-8");
        // loginuser 表示当前登录的用户
        User Loginuser = Util.checkLogin(req);
        if(Loginuser == null){
            resp.sendRedirect("login.html");
            return;
        }
//        String blogId = req.getParameter("blogId");
        List<Question> questions = QuestionDao.selectAll();
        if(questions != null){
            ServletContext servletContext = getServletContext();
            TemplateEngine engine = (TemplateEngine) servletContext.getAttribute("engine");
            WebContext webContext = new WebContext(req,resp,servletContext);
            webContext.setVariable("questions",questions);
            engine.process("question",webContext, resp.getWriter());
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");
        resp.setContentType("text/html;charset=utf-8");
//        System.out.println("进入到questionServlet的post请求");
        req.setCharacterEncoding("utf-8");
        resp.setContentType("text/html;charset=utf-8");
        User user = Util.checkLogin(req);
        if(user == null){
            resp.sendRedirect("KnowledgeList_list.html");
            return;
        }
        Question question = new Question();
        String commentContent = req.getParameter("comment");
//        System.out.println("从req中读到的问题内容"+commentContent);
        if(commentContent == null || "".equals(commentContent)){
            resp.getWriter().write("输入的问题不能为空");
            return;
        }
        HttpSession session = req.getSession(false);
        String blogId = (String) session.getAttribute("blogId");
//        System.out.println("从session中读到的blogId" + blogId);
        question.setQuestionContent(commentContent);
        question.setUserId(user.getUserID());
        question.setBlogId(Integer.parseInt(blogId));
        QuestionDao.insert(question);
        resp.sendRedirect("question.html");
    }
}

5.5 问题删除功能

实现流程和删除博客类似,再此不做赘述。

5.6 注意

①commentservlet是博客评论功能构建的form表单触发的get请求,在列表页的servlet代码的session中加入blogID,这样在commentservlet中就能知道被评论的博客是谁了,为更新博客的评论次数做铺垫。

②此时登录的用户就是评价的用户。所以评论中博客的相关用户信息就是登录用户的相关信息。

③注意,博客详情页涉及到两个用户,一个是登录用户,一个是博客作者。只有登录的用户和博客作者是同一个人,才能删除博客、修改博客。为了保险起见,只有是同一个人才显示删除博客和修改博客这两个按钮。

④一个input输入框会对应两个按钮,此时不能使用form标签了。可以用函数来实现。

⑤如何将页面按照markdown的形式显示。

借助editor.md的内置功能,

    <script>
        // 先从html中拿到要渲染的字符串
        var markdown = document.querySelector("#content").innerHTML;
        // 清空原来的div
        document.querySelector("#content").innerHTML = "";
        // 通过内置的方式完成渲染,要想能够调用, 也需要先引入 editor.md 的 js 
        editormd.markdownToHTML('content',{markdown:markdown})
    </script>

5.7 前端代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="./css/common.css">
    <link rel="stylesheet" href="./css/detail.css">
    
    <link rel="stylesheet" href="./editor.md/css/editormd.css" />
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
    <script src="./editor.md/lib/marked.min.js"></script>
    <script src="./editor.md/lib/prettify.min.js"></script>
    <script src="./editor.md/editormd.js"></script>

</head>
<body>
    <!-- 所有的页面的导航栏都相同-->
    <div class="nav">
        <img src="pictures/logo.jpg" alt="图标">
        <span>我的博客系统</span>
        <span id="spacer"></span>
        <a href="KnowledgeList_list.html">主页</a>
        <a href="KnowledgeList_edit.html">写博客</a>
        <a th:if = "${showDeleteButton}" th:href="${'deleteBlog?blogId=' + blog.blogId}">删除博客</a>
        <a th:if = "${showAmendButton}" th:href="${'amendBlog?blogId=' + blog.blogId}">修改博客</a>
        <a href="question.html">问答区</a>
        <a href="logout" id="logout">注销</a>
    </div>
    <div class="container">
        <div class="left">
            <div class="card">
                <img th:src="${bloguser.userPicture}" alt="头像">
<!--                <img src="./pictures/piyo.jpg" alt="头像">-->
                <h3 th:text = "${bloguser.userName}"></h3>
                <a href="#">GitHub地址</a>
                <div class="count">
                    <span>文章</span>
                    <span>访问量</span>
                </div>
                <div class="count">
                    <span th:text = ${bloguser.blogCount}></span>
                    <span th:text = ${visitCount}></span>
                </div>
            </div>
            <div class="comment">
                <div class="commentedit">
                    <div><img th:src="${loginuser.userPicture}" alt="头像"></div>
                    <form name="form" method="post">
                        <input type="textarea" name="comment" id="comment" placeholder="请发表有价值的评论,博客评论不欢迎灌水,良好的社区氛围需大家一起维护。" >
                        <div class="button">
                            <input type="button" value="提交评论" id="button1" onclick="addComment()">
                            <input type="button" value="提交问题" id="button1" onclick="addQuestion()">
                        </div>
                    </form>
                </div>
                <div class="commentList">
                    <div class="commentInfo" th:each = "comment: ${comments}">
                        <div class="commentListLeft">
                            <img th:src="${comment.commentUserImage}" alt="用户头像">
<!--                            <img src="./pictures/piyo.jpg" alt="用户头像">-->
                        </div>
                        <div class="commentListRight">
                            <div class="commentListUserInfo">
                                <span th:text = "${comment.commentUser}"></span>
                                <span th:text = "${comment.commentTime}"></span>
                            </div>
                            <div class="commentListdetail">
                                <span th:text = "${comment.commentContent}"></span>
                            </div>
                        </div>
                    </div>
                </div>
            </div>   
        </div>
        <div class="right">
            <div class="essay">
                <div class="title" th:text = "${blog.blogTitle}"></div>
                <div class="date" th:text = "${blog.blogTime}"></div>
                <div class="content" th:text = "${blog.blogContent}" style="background-color:transparent" id="content"></div>
            </div>
        </div>
    </div>
    <script>
        // 先从html中拿到要渲染的字符串
        var markdown = document.querySelector("#content").innerHTML;
        // 清空原来的div
        document.querySelector("#content").innerHTML = "";
        // 通过内置的方式完成渲染,要想能够调用, 也需要先引入 editor.md 的 js 
        editormd.markdownToHTML('content',{markdown:markdown})
    </script>
    <script type="text/javascript">
        function addComment(){
            document.form.action="comment";//提交的url
            document.form.submit();
        }

        function addQuestion(){
            document.form.action="question.html";//提交的url
            document.form.submit();
        }
    </script>

</body>
</html>

六、博客删除页

先判断是否登录——》从请求中读取博客Id——》判断blogId是否为空——》去数据库中查询是否存在——》存在就删除——》跳转到博客列表页。


@WebServlet("/deleteBlog")
public class DeleteBlogServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        User user = Util.checkLogin(req);
        if(user == null){
            resp.sendRedirect("login.html");
            return;
        }
        String blogId = req.getParameter("blogId");
        if(blogId == null){
            resp.getWriter().write("<h3>blogId不存在</h3>");
            return;
        }
        Blog blog = BlogDao.selectOne(Integer.parseInt(blogId));
        if(blog == null){
            resp.getWriter().write("<h3>您要删除的博客不存在</h3>");
            return;
        }
        BlogDao.delete(Integer.parseInt(blogId));
        resp.sendRedirect("bloglist.html");
    }
}

七、实现博客编辑页

7.1 前端页面的设计

①加入form表单,点击提交按钮可以触发一个HTTP请求。

②需要提交一个标题和正文,标题已经是一个input标签了,正文可以在editor.md这个第三方库中进行编辑,editor.md也支持form表单,具体设置为:

先在博客编辑区的div中放一个隐藏的text area。再在初始化editor对象的时候,指定一个特殊的选项saveHTMLToTextArea:true,这个选项的功能就是editor.md把用户编辑的正文放到这个text area里面。

<div class="container">
        <div class="container-edit">
            <!-- 包含两个部分,标题编辑区和内容编辑区 -->
            <form action="edit" method="post" style="height: 100%">
                <div class="container-edit-title">
                    <input type="text"  id="title" autocomplete="off" placeholder="在这里输入标题" name="title">
                    <!-- <input type="button" value="发布文章" > -->
                    <input type="submit" value="发布文章" class="submit-button">
                </div>
                <div id="editor" >
                    <textarea name="content" style="display: none"></textarea>
                </div>
            </form>
            
        </div>
    </div>
    <script>
            // 初始化 editor.md
            var editor = editormd("editor", {
            // 这里的尺寸必须在这里设置. 设置样式会被 editormd 自动覆盖掉. 
            width: "1000px",
            // 设定编辑器高度
            height: "calc(100% - 60px)",
            // 编辑器中的初始内容
            markdown: "# 在这里写下一篇博客",
            // 指定 editor.md 依赖的插件路径
            path: "./editor.md/lib/",
            saveHTMLToTextArea:true
        });
    </script>

7.2 后端实现逻辑

先判断是否登录——》从请求中读去博客标题和博客内容——》判断博客标题和博客内容是否合法——》构造博客对象并插入到数据库中——》跳转到博客列表页。


@WebServlet("/edit")
public class EditServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");
        resp.setContentType("text/html;charset=utf-8");
        //1. 判断是否登录
        User user = Util.checkLogin(req);
        if(user == null){
            resp.sendRedirect("login.html");
            return;
        }
        // 2.从rep中拿到title和content,并校验
        String title = req.getParameter("title");
//        System.out.println(title);
        String content = req.getParameter("content");
//        System.out.println(content);
        if(title == null || "".equals(title) || content == null || "".equals(content)){
            resp.getWriter().write("<h3>标题或者正文缺失</h3>");
            return;
        }
        //3.构建一个blog,插入到数据库中
        Blog blog = new Blog();
        blog.setBlogContent(content);
        blog.setBlogTitle(title);
        blog.setBlogTime(new Timestamp(System.currentTimeMillis()));
        blog.setBlogAuthor(user.getUserID());
        BlogDao blogDao = new BlogDao();
        blogDao.insert(blog);
        //4.跳转到博客列表页
        resp.sendRedirect("bloglist.html");
    }
}

八、实现博客修改页

和博客列表页的前端页面类似,只不过博客的标题和内容是从数据库中读出来的。可以先用thymeleaf进行占位,将从数据库中读到的数据再给渲染进去。

<div class="container">
        <div class="container-edit">
            <!-- 包含两个部分,标题编辑区和内容编辑区 -->
            <form action="amendBlog" method="post" style="height: 100%">
                <div class="container-edit-title">
                    <input type="text"  id="title" autocomplete="off" th:value="${blog.blogTitle}" name="title">
                    <!-- <input type="button" value="发布文章" > -->
                    <input type="submit" value="确认修改" class="submit-button">
                </div>
                <div id="editor" >
                    <textarea name="content" style="display: none" th:text = "${blog.blogContent}"></textarea>
                </div>
            </form>
            
        </div>
    </div>
    <script  th:inline="javascript">
            // 初始化 editor.md
            let content = /*[[${blog.blogContent}]]*/ "123";
            var editor = editormd("editor", {
            // 这里的尺寸必须在这里设置. 设置样式会被 editormd 自动覆盖掉. 
            width: "1000px",
            // 设定编辑器高度
            height: "calc(100% - 60px)",
            // 编辑器中的初始内容
            markdown: content,
            // 指定 editor.md 依赖的插件路径
            path: "./editor.md/lib/",
            saveHTMLToTextArea:true
        });
    </script>

当跳转到博客修改页,会触发一个get请求,在处理这个get请求时需要将要修改的博客的标题的内容返回。

当修改完成点击提交按钮,会触发一个post请求,对该请求的处理流程为:先判断是否登录——》从请求中读取博客标题和博客内容——》判断博客标题和博客内容是否合法——》更新博客——》跳转到博客详情页,跳转时需要带上博客的id。


@WebServlet("/amendBlog")
public class AmendServlet extends HttpServlet {
    public static int blogId = 0;
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=utf-8");
        User user = Util.checkLogin(req);
        if(user == null){
            resp.sendRedirect("login.html");
            return;
        }
        String blogID = req.getParameter("blogId");
        if(blogID == null){
            resp.getWriter().write("<h3>blogId不存在</h3>");
            return;
        }
        blogId = Integer.parseInt(blogID);
        Blog blog = BlogDao.selectOne(blogId);
        if(blog == null){
            resp.getWriter().write("<h3>您要修改的博客不存在</h3>");
            return;
        }
        System.out.println("要修改的博客:"+ blog);
        ServletContext servletContext = getServletContext();
        TemplateEngine engine = (TemplateEngine) servletContext.getAttribute("engine");
        WebContext webContext = new WebContext(req,resp,servletContext);
        webContext.setVariable("blog",blog);
        engine.process("blog_amend.html",webContext, resp.getWriter());
//        resp.sendRedirect("blog_amend.html");

    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");
        resp.setContentType("text/html;charset=utf-8");
        //1. 判断是否登录
        User user = Util.checkLogin(req);
        if(user == null){
            resp.sendRedirect("KnowledgeList_login.html");
            return;
        }
        // 2.从rep中拿到title和content,并校验
        String title = req.getParameter("title");
//        System.out.println(title);
        String content = req.getParameter("content");
//        System.out.println(content);
        if(title == null || "".equals(title) || content == null || "".equals(content)){
            resp.getWriter().write("<h3>标题或者正文缺失</h3>");
            return;
        }
        BlogDao.updateBlog(title,content,blogId);
        resp.sendRedirect("blogdetail.html?blogId="+blogId);
    }
}

九、实现上传头像功能

先创建一个images文件夹,将用户的头像保存到这个文件夹里。

判断是否登录——》获取到images所在的磁盘路径——》获取到图片的part对象——》将头像存放在images目录中,并以用户名命名——》跳转到登录页面。

此时用户session中的user信息是没有头像属性的,会导致上传的头像无法正常显示出来。用户重新登录后,才能更新session中的user信息,此时才能将头像正常显示出来。


@MultipartConfig
@WebServlet("/imageUpload")
public class UploadImageServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        User user = Util.checkLogin(req);
        if(user == null){
            resp.sendRedirect("login.html");
            return;
        }
        String username = user.getUserName();
        System.out.println("用户的名字"+ username);
        // 获取到image所在的磁盘路径
        String path = getServletContext().getRealPath("/images");
        path = path + "/" + username + ".jpg";
       // System.out.println(path);
        // 获取到图片的Part对象
        Part part = req.getPart("image");
        // 获取到图片名字
        //String name = part.getSubmittedFileName();
        //System.out.println(name);
        // 把图片放在指定目录中
        String path2 = "./images/"+ username + ".jpg";
        part.write(path);
        UserDao userDao = new UserDao();
        userDao.uploadImages(username,path2);
        resp.sendRedirect("login.html");
    }
}

十、实现问题回答页

10.1 前端页面设计

前端页面的设计参考Lesson6:JS的WEBAPI实例练习_刘减减的博客-CSDN博客

中4.2TodoList的设计。此时约定:点击查看答案,博客的内容才会显示出来。使用display这个参数来控制,读出display的属性,如果display=none,点击后就将display=block。如果此时display=block,点击后就将display=none。可以用一个函数来实现这个功能。

<div class="container1" id="container">
        <div class="left">
            <h3>答题区</h3>
            <input type="textarea" name="answer" id="answer" width="200px" height="200px" >
        </div>
        <div class="right">
            <input type="button" value="点击查看答案" id="answerbutton">
            <span th:text = "${blog.blogContent}" style="display: none;" id="contentspan"></span>
        </div>
    </div>
    <script>
        let button = document.querySelector("#answerbutton");
        button.onclick = function(){
            let span = document.querySelector("#contentspan");
            if(span.style.display == "none"){
                span.style.display = "block";
            }else {
                span.style.display = "none";
            }
        }
    </script>

10.2 后端设计

点击回答按钮,会触发一个get请求,对该请求的处理流程为:先判断是否登录——》从请求中读取问题ID——》判断问题id是否合法——》根据问题ID在问题数据库中查找问题——》如果查找到问题,根据问题中的博客ID属性在博客数据库中找出博客信息——》将博客信息渲染到页面中。


@WebServlet("/answer.html")
public class AnswerServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=utf-8");
        req.setCharacterEncoding("utf-8");
        User user = Util.checkLogin(req);
        if(user == null){
            resp.sendRedirect("login.html");
            return;
        }
        String questionId = req.getParameter("questionId");
//        String blogId = req.getParameter("blogId");
        if(questionId == null){
            resp.getWriter().write("<h3>您要回答的问题不存在</h3>");
        }
//        if(blogId == null){
//            resp.getWriter().write("<h3>您要回答的问题相关的博客不存在</h3>");
//        }
        Question question = new Question();
        question = QuestionDao.selectOne(Integer.parseInt(questionId));
        if(question == null){
            resp.getWriter().write("<h3>您要回答的问题相关的博客没有查询到</h3>");
        }
        Blog blog = BlogDao.selectOne(question.getBlogId());
        if(blog == null){
            resp.getWriter().write("<h3>您要回答的问题相关的博客没有查询到</h3>");
        }
        WebContext webContext = new WebContext(req,resp,getServletContext());
        TemplateEngine engine = (TemplateEngine) getServletContext().getAttribute("engine");
        webContext.setVariable("blog",blog);
        engine.process("answer",webContext, resp.getWriter());
    }
}

十一、实现注销功能

实现流程:判断是否登录——》获取会话session——》从session中删除user字段——》跳转到登录页面。

@WebServlet("/logout")
public class LogoutServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        User user = Util.checkLogin(req);
        if(user == null){
            resp.getWriter().write("<h3>未登录</h3>");
            resp.sendRedirect("login.html");
        }
        HttpSession session = req.getSession();
        session.removeAttribute("user");
        resp.sendRedirect("login.html");
    }
}

 十二、实现博客列表页

12.1 实现流程

通过服务器代码,查询数据库,再将用户的信息和博客列表展示在页面上。此处需要用到Thymeleaf。

12.2 生成模板

将需要动态替换的信息使用th进行占位。博客列表的显示需要用到循环,具体步骤为:

①去掉原来页面多余的div,只保留一个页面的div。

②通过th:each的方式,根据服务器查询到包含所有博客信息的博客数组,来循环构建出这里的博客div。

③根据数据库中查询出的每个博客,将博客的标题、时间、博客内容信息,显示到页面上。

④没必要将博客正文的所有内容都显示出来,可以只显示一部分,增加一个查看全文按钮。此时,需要将blogId给拼接到a标签的url中,这时才能够知道需要从服务器中获取哪个博客。

12.3 博客的内容太多,超过设置的背景

给背景加上个css属性:overflow:auto 如果当前元素的内容溢出,就会自动加个滚动条。此时指的是给标签加上滚动条,而不是给页面加上滚动条。

    <div class="container">
        <div class="left">
            <div class="card">
                <img th:src="${user.userPicture}" alt="头像">
<!--                <img src="./pictures/piyo.jpg" alt="头像">-->
                <h3 th:text = "${user.userName}"></h3>
                <a th:href = "${user.userLink}">GitHub地址</a>
                <div class="count">
                    <span>文章</span>
                    <span>总访问量</span>
                </div>
                <div class="count">
                    <span th:text = ${user.blogCount}></span>
                    <span th:text = ${visitCount}></span>
                </div>
            </div>  
        </div>
        <div class="right">
            <div class="essay" th:each = "blog: ${blogs}">
                <div class="title" th:text = "${blog.blogTitle}"></div>
                <div class="date" th:text = "${blog.blogTime}"></div>
                <div class="content" th:text = "${blog.blogContent}"> </div>
                <a th:href="${'KnowledgeList_detail.html?blogId=' + blog.blogId }" class="detail">查看全文&gt&gt</a>
            </div>
        </div>
    </div>

12.4 完成Servlet的代码,实现整个页面的渲染


@WebServlet("/bloglist.html")
public class ListServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset = utf-8");
        User user = Util.checkLogin(req);
        if(user == null){
            resp.sendRedirect("login.html");
            return;
        }
        // 从数据库中读出所有的博客
        List<Blog> blogs = BlogDao.selectAll();
        // 在登录页面时已经将用户的信息保存到session中,在强制登录方法中从session中读到登录信息,返回一个User
        int visitCount = BlogDao.selectVisitAllCount(user.getUserID());
        WebContext webContext = new WebContext(req,resp,getServletContext());
        TemplateEngine engine = (TemplateEngine) getServletContext().getAttribute("engine");
        webContext.setVariable("blogs",blogs);
        webContext.setVariable("user",user);
        webContext.setVariable("visitCount",visitCount);
        engine.process("bloglist",webContext, resp.getWriter());
    }
}

如果需要源代码,可以在评论区留言呀!!!

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论
在课程中添加一个作业是一个很重要的步骤。作业可以帮助学生巩固他们所学到的知识,并帮助教师评估学生的学习进度和掌握程度。 首先,一个好的作业应该与课堂教学内容相结合。教师可以设计作业来帮助学生将课堂上学到的概念应用到实际问题中,或者进一步发掘和探索学生的思考能力。作业应该涵盖课程中的关键点和重要概念,以帮助学生加深对这些知识的理解。 其次,作业应该有明确的目标和要求。教师应该清楚地告诉学生他们需要完成什么,并给出明确的评估标准。这样一来,学生可以知道他们需要达到什么样的水平,并能有针对性地完成任务。 此外,作业应该适当地安排时间。教师需要考虑学生在完成作业时所需的时间,并在布置作业时给出合理的截止日期。这样一来,学生可以有足够的时间来完成作业,并且可以避免时间紧张导致的学习压力。 最后,作业的评估和反馈也是很重要的。教师可以通过评估学生的作业来了解学生的掌握程度,并根据作业的质量给出相应的反馈和建议。这样一来,学生可以知道他们的学习状况,并可以及时地调整学习策略。 总之,将作业添加到课程中是一个促进学生学习和教学效果的重要步骤。一个好的作业可以帮助学生加深对知识的理解,提高他们的学习效果。同时,教师通过评估和反馈也可以更好地了解学生的学习情况,并为他们提供相应的指导和支持。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刘减减

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值