首页 > 其他分享 >Servlet实现博客系统

Servlet实现博客系统

时间:2024-10-25 16:17:21浏览次数:8  
标签:resp 系统 博客 blog html user Servlet blogid

博客系统

一。博客系统的基本情况:

1.四个页面:

(1)博客列表页,显示列表页上有哪些博客

(2)博客详情页,点击某个博客可以观看对应的详情页

(3)博客编辑页,用户可以在这里进行博客的编写

(4)登陆页

2。博客系统要实现的功能

(1)实现博客列表:让页面从服务器上拿到博客数据(数据库)

(2)实现博客详情页:点击想看的博客,让其从服务器上拿到完整的数据

(3)实现登陆的页面

(4)实现强制执行登陆的页面:当用户在列表页,详情页,编辑页的时候,发现用户没有登陆,那么就进行强制执行登陆,跳转到登陆页

(5)实现显示用户信息,从服务器上获取;博客列表页上要有用户的信息;博客详情页上要有作者的详细信息

(6)实现退出登陆

(7)实现发布博客

二。准备工作:

(1)创建项目,引入依赖,创建目录结构

依赖(servlet,mysql,Jackson)

目录结构:在main路径下创建一个webapp文件夹,在webapp这个文件夹中创建WEB-INF文件夹,在WEB-INF文件夹中创建web.xml,一般将前端的代码都放在webapp这个文件夹之中

(2)数据库的设计

Step1:找到实体:博客(blog表),用户(user表)

Step2:确定实体之间的关系:一个博客只能属于一个用户,一个用户可以创建多个博客;因此就要在博客表中引入一个userId这样的属性

blig表(blogid,title,content,postTime,userid)

user表(userid, username,password)

在main路径下创建一个db.sql的文件,这个文件中存放的是对数据库的操作(创库,创表,增数据…)

create database if not exits java666_blog_system charset=utf8;
use java666_blog_system;
drop table if exits blog;
drop table if exits user;
create table blog(blogid int primary key auto-increment,title varchar(1024),content varchar(4096),postTime datatime, userid int);
create table user(userid int primary key auto-increment,username varchar(50) unique,password varchar(50));
//插入一些数据,方便后面进行
insert into blog values(1,"第一篇博客","今天",now(),1);
insert into blog values(2,"第二篇博客","昨天",now(),1);
insert into blog values(3,"第三篇博客","前天",now(),1);
insert into user values(1,"zhangsan",'123');
insert into user values(2,'lisi','123');

(3)对数据库操作的代码进行封装

首先要在main文件夹中创建一个model文件夹,在model中创建一个文件叫做DBUtil.java,在这个文件中创建一个类(DBUtil类),通过这个类封装数据库建立连接的操作

由于接下来的很多servlet代码都要用到数据库,因此就要有单独的地方吧datasource这里的操作进行封装,而不是只放到某个servlet的init之中,此处就可以使用单例模式来表示,单例模式线程是不安全的,当前servlet本身就是在多线程环境下完成的,Tomcat收到多个请求的时候,就会用多线程的方式执行不同的servlet代码

package model;

import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class DBUtil{
    private volatile static DataSource dataSource=null;
    private static DataSource getDataSource(){
        if(dataSource==null){
            synchronized (DBUtil.class){
                if(dataSource==null){
                    dataSource=new MysqlDataSource();
                    ((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3301/java109_blog_system");
                    ((MysqlDataSource)dataSource).setUser("root");
                    ((MysqlDataSource)dataSource).setPassword("2222");
                }
            }
        }
        return dataSource;
    }
    public static Connection getConnection() throws SQLException {
        return getDataSource().getConnection();
    }
    public static void close(Connection connection, PreparedStatement statement, ResultSet resultSet){
        try {
            resultSet.close();
            statement.close();
            resultSet.close();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
}

DBUtil完成了数据的创建和关闭的过程

下一步:创建实体类

每个表都要用一个专门的类来表示,表里的一条数据就会对应到这个类的一个对象,这样就把数据库中的数据和代码连接起来

在model文件夹中创建Blog.java文件

public class Blog{
  private int blogid;
  private String title;
  private String content;
  private TimeStamp postTime;
  private int userid;
  //下面的getter和setter让idea自动生成一下
   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 int getUserId() {
        return userId;
    }

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

    public Timestamp getPostTime() {
        return postTime;
    }

    public String getPostTime() {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return format.format(postTime);
    }

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

同样在model文件夹中创建User.java文件

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;
    }
}

下面就要创建两个类(BlogDao,UserDao),来完成针对博客表和用户表的增删查改操作

Dao:Data Access Object 数据访问对象,通过这个类的对象,来完成针对数据表的操作

通过BlogDao完成对Blog表的操作,在model文件夹中创建BlogDao.java文件

在这个BlogDao类中,要实现四种功能:(1)新增数据(提交博客时会用到)(2)查询博客列表(博客列表页),把数据库中所有的博客都拿到 (3)根据博客id查询指定的博客 (4)根据博客id删除博客

(1)新增数据:

public void insert(Blog blog){
  Connection connection=DBUtil.getConnection();//建立连接
  PreparedStatement statement=null;
  try{
    String sql="insert into blog values(null,?,?,now(),?)";//构建sql
    statement=connection.preparedStatement(sql);
    statement.setString(1,blog.getTitle());
    statement.setString(2,blog.getContent());
    statement.setString(3,blog.getUserid());
    statement.executeUpdate();//执行sql
  }catch(SQLException){
    throw new RuntimeException();
  }finally{
    DBUtil.close(connection,statement,null);
  }
}

(2)查询博客列表:

public List<Blog> SelectAll(){
  List<Blog> blogList=new ArrayList<>();
  Connection connection=null;
  PreparedStatement statement=null;
  ResultSet resultSet=null;
  //上面这么写是为了便于最后进行释放资源
  try{
    connection=DBUtil.getConnection();
    String sql="select * from blog";
    statement=connection.preparedStatement(sql);
    resultSet=statement.executeQuery();
    while(resultSet.next()){
      Blog blog=new Blog();
      blog.setBlogId(resultSet.getInt("blogid"));
      blog.setTitle(resultSet.getString("title"));
      //由于此处正文是整个文章的内容,太多了,因此在列表页中,只希望出现一小部分(摘要),对此content只需要进行一个小小的截断,这个截断长度是可以自定的
      String content=resultSet.getString("content");
      if(content.length()>100){
        content=content.subString(0,100)+"......";
      }
      blog.setContent(content);
      blog.setPostTime(result.setTimestamp("postTime"));
      blog.setUserid(result.setInt("userid"));
      blogList.add(blog);
    }
  }catch(SQLException e){
    throw new RuntimeException();
  }finally{
    DBUtil.close(connection,statement,resultSet);
  }
  return blogList;
}

(3).根据博客id查询指定的博客

public Blog selectOne(int blogid){
  Connection connection=null;
  PreparedStatement statement=null;
  ResultSet resultset=null;
  try{
    connection=DBUtil.getConnection();
    String sql="select * from blog where blogid=?";
    statement=connection.preparedStatemnt(sql);
    statement.setInt(1,blogid);
    resultSet=statement.executeQuery();
    //由于这里的resultSet非0即1,所以不用使用while(此处拿着blogid进行查询,blogid是主键,是唯一的)
    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){
      throw new RuntimeException();
    }finally{
      DBUtil.close(connection,statement,resultSet);
    }
    return null;
  }
}

//4.根据博客id删除博客

public void delete(int blogid){
  Connection connection=null;
  PreparedStatement statement=null;
  try{
    connection=DBUtil.getConnection();
    String sql="delete from blog where blogid = ?";
    statement=connection.preparedStatement(sql);
    statement.setInt(1,blogid);
    statement.executeUpdate();
  }catch (SQLException e) {
      e.printStackTrace();
  } finally {
      DBUtil.close(connection, statement, null);
  }
}

通过UserDao完成User表的操作:

UserDao要实现的操作:(1)根据userid查询到对应的用户信息(获取用户信息) (2)根据username来查询到对应的用户信息(登陆)

(1)根据userid查询对应的用户信息

public User getUserById(int userid){
  Connection connection=null;
  PreparedStatement statement=null;
  ResultSet resultSet=null;
  try{
    connection=DBUtil.getConnection();
    String sql="select * from user where userid = ?";
    statement=connection.PreparedStaement(sql);
    statement.setInt(1,userid);
    resultSet=statement.executeQuery();
    if(resultSet.next()){
      User user=new User();
      user.setUserid(resultSet.getInt("userid"));
      user.setUserName(resultSet.getString("useName"));
      user.setUserPassword(resultSet.getString("password"));
      return user;
    }catch(SQLException e){
      throw new RuntimeException();
    }finally{
      DBUtil.close(connection,statement,resultSet);
    }
    return null;
  }
}

(2)根据username来查询到对应的用户信息(登陆)

public User getUserByUserName(String username){
  Connection connection=null;
  PreparedStatement Statement=null;
  ResultSet resultset=null;
  try{
    connection=DBUtil.getConnection();
    String sql="select * from user where username = ?";
    statement=connection.preparedStatement(sql);
    statement.setUserName(1,username);
    resultSet=statement.executeQuery();
    if(resultSet.next()){
      User user=new User();
      user.setUserid(resultSet.getInt("userid"));
      user.setUserName(resultSet.getString("userName"));
      user.setUserPassword(resultSet.getString("userPassword"));
      return user;
    }catch(SQLException e){
      throw new RuntimeException();
    }finally{
      DBUtil.close(connection,statement,resultSet);
    }
    return null;
  }
}

以上就是所有的准备工作,下面就要进行前后端交互的代码,从而实现四个页面和7个功能

三。前后端交互:

1.获取博客列表页

在博客列表加载的时候,发送ajax给服务器发送请求,从服务器(数据库)中拿到博客列表数据,并显示到页面上

(1)约定前后端交互接口:

请求:GET /blog

响应:HTTP/1.1 200 ok

​ Content—Type:application/json

​ Body:

[
  {
    blogid=1,
    title="这是标题",
    content="这时文章",
    postTime="......",
    userid=1
  }
]

(2)编写请求代码(前端)

让浏览器给服务器发送请求,在前端中新加入script标签(注:前端代码已经把部分写好了,没有写与前后端交互的部分,其他部分见博客最后)

<script>
  function getblogs(){//把ajax封装到函数之中,js中定义函数,使用function关键字,不需要返回值类型
    $.ajax({
      type:'get',
      url:'blog',
      success:function(body){
        //.....当服务器成功响应之后,调用的回调函数,根据返回的响应数据,构造页面片段
      }
    })
    grtblogs();//定义完函数一定要在最后面调用一下
  }
</script>
  

(3)让服务器处理请求,返回响应数据(查询数据库)

@WebServlet("/blog")
public class BlogServlet extends HttpServlet {
  private ObjectMapper objectMapper = new ObjectMapper();
  protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    BlogDao blogDao=new BlogDao();
    List<Blog> blogs=blogDao.selectAll();
    String respJson=objectMapper.writeValueAsString(blogs);
    resp.setContentType("application/json; charset=utf8");
    resp.getWritter().write(respjson);
  } 
}

(4)让前端代码处理上述响应数据

构造html片段,显示到页面上,这里构造的过程还是之前的api

querySelector:获取页面已有的元素

createElement:创建新的元素

.innerHtml:设置元素里的内容

.className:设置元素的class属性

appendChild:把这个元素加到另一个元素的末尾

由这个例子就可以大概知道下面要怎么构造这个响应

<!-- 右侧信息 -->
        <div class="container-right">
            <!-- 这个 div 表示一个 博客  -->
            <!-- <div class="blog">
                <div class="title">我的第一篇博客博客博客博客</div>
                <div class="date">2023-05-11 20:00:00</div>
                <div class="desc">
                    从今天起, 我要认真敲代码. 
                </div>
                <a href="blog_detail.html?blogId=1">查看全文 &gt;&gt; </a>
            </div> -->
        </div>
success:function(body){
  let containerDiv=document.querySelector('container-right');//这句话后面有解释
  for(int i=0;i<body.length;i++){
    let blog=body[i];//blog就是形如{blogid='1',title='xxx',......}
    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.innerHTML="查看全文";
    a.href="blog_detil.html?blogid="+blog.blogid;//点击不同的博客跳转到不同的博客详情页
    //上面的操作完成了每个零件的创建,还要往往一起进行组装
    blogDiv.appendChild(TitleDiv);
    blogDiv.appendChild(dateDiv);
    blogDiv.appendChild(descDiv);
    blogDiv.appendChild(a);
    //最后要在循环外边获取container-right,所以加上let containerDiv=document.querySelector('container-right');
    containerDiv.appendChild(blogDiv);
  }
}

通过运行就可以发现存在两个问题:

(1)页面显示的postTime是一个时间戳,我们无法看懂,所以要把这里的上次登陆时间转换成人们能看懂的形式

解决方法:要在Blog类中找到PostTime的getter方法,由于标准库提供了一个SimpleDateFormat类,完成时间戳到格式化的转换(这个不用背,用的时候查一下就行)

public String getPostTime() {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return format.format(postTime);
}

(2)顺序问题:

正常来说,咱们希望新的博客在上面,老的博客在下面

解决办法,在BlogDao类中找到getBlogs方法,然后改sql语句就行

String sql="select * from blog order by postTime desc";

2.博客详情页:

点不同的博客跳转过去都会带有不同的blogid的queryString,后续在博客详情页中,就可以给服务器发ajax请求,根据这里的blogid查询数据库,博客的具体内容再返回,前端还是把得到的数据构造到页面上

点击查看全文就会跳转到这个网址:127.0.0.1:8080/blog_system/blog_detail.html?blogid=4

(1)约定前后端接口:

请求:GET/blog?blogid=1

响应:HTTP/1.1 200 ok

​ Content_Type: application/json

{
  blogid:1,
  title:"这时一篇博客",
  content:"这时博客正文",
  postTime:"20231-11-07 10:20:00",
  userid:1
}

(2)让前端代码通过ajax发起请求

在前端代码中找到blog_detail.html文件,在这个文件中添加script标签

<script>
  function getBlog(){
    $.ajax({
      type:'get',
      url:'blog'+location.search
      success:function(body){
         //当服务器成功传回响应
      }
    })
  }
  get getBlog();
</script>

此处有个问题,发起ajax请求时要带有blogid,blogid当前处于博客详情页的url之中,这里通过loaction.search来获取到url中的queryString

通过观察,我们可以发现博客列表页和博客详情页可以通过是否有queryString进行区分,博客列表页没有queryString,博客详情页有queryString,因此可以把这两个需求写在一个servlet之中,通过是否包含queryString进行判断进行哪个逻辑代码

(3)后端接收处理请求,并给出响应

@WebServlet("/blog")
public class BlogServlet extends HttpServlet {
    private ObjectMapper objectMapper = new ObjectMapper();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
      //从queryString中查询一下是否有内容,如果有就查指定博客,如果没有就查询所以博客
      BlogDao blogDao=new BlogDao();
      String blogid=req.getParameter("blogid");
      if(blogid==null){
        List<Blog> blogs=blogDao.selectAll();
        //以json的形式返回给客户端
        String respJson=objectMapper.writeValueAsString(blogs);
        resp.setContentType("application/json;charset=utf8");
        resp.getWritter.write(respJson);
      }else{
        Blog blog=blogDao.selectOne(Integer.parseInt(blogId));
        //以json的形式返回给客户端
        String respJson=objectMapper.writeValueAsString(blog);
        resp.setContentType("application/json;charset=utf8");
        resp.getWritter.write(respJson);
      }
    }
}

上述代码就将博客列表页和博客详情页进行了结合,让他们放在一个servlet的doget请求之中,通过是否包含queryString进行判断进行哪个代码逻辑

(4)前端拿到响应之后,把响应数据构造成html片段

写之前,blog_detail.html文件中给了页面的html代码

<!-- 右侧信息 -->
        <div class="container-right">
            <h3></h3>
            <div class="date"></div>
            <div id="content">
            </div>
        </div>

下面就要在上面图片中已经写好的html代码中加入要填入的东西,但是不能直接填,要让代码变得灵活,实现代码的复用

querySelector是获取页面已有元素

success function(blog){//因为后端返回的就是blog,所以这里的body可以写成blog
  let h3=document.querySelector('.container-right h3');//不是div标签,前面要加点,后面h3不用加点
  h3.innerHTML=blog.Title;
  let dateDiv=document.querySelector('container-right .date')//是div标签,前面不要加点,后面date要加点
  dadteDiv.innerHTML=blog.PostTime;
  let contentDiv=document.querySelector('.container-right .content');
  contentDiv.innerHTML=blog.content;
}

此时经过运行就会出现问题:

(1)刷新发现内容没变,和上一次没改的内容一样,这是因为浏览器缓存的原因,只需要按ctrl+f5进行强制刷新即可

(2)显示效果是markdown的原始情况,但是我们希望得到的是mackdown渲染之后的情景

Step1:确保引入了jquery依赖(在前端)

<script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>

Step2:引入editor.md依赖(在前端)

<link rel="stylesheet" href="editor.md/css/editormd.min.css" />
<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>

Step3:进行渲染

editormd.markdownToHTML('content',{markdown:blog.content});

这里的editormd是库里给的一个全局变量,把依赖正确饮用,这个变量就可以使用

小括号里的第一个是一个html标签,可以有很多属性,class属性往往是用来和css样式配合使用的,id属性则是一个身份标识,要求一个页面上,id必须唯一

小括号第二个是要渲染的对象,这里是要对content正文进行渲染,所以对象就是content

3.实现登陆:

在登陆页面,在输入框中填写用户名和密码,点击登陆,就会给服务器发起HTTP请求(可以使用ajax,也可使用form)

服务器处理登陆请求,读取用户名密码,在数据库中查询,匹配如果成功创建会话,跳转到博客列表页

(1)约定前后端交互接口

请求:POST/login

content-Type:application/www-form-urlencoded

username=zhangsan %ipassword=lisi

响应:HTTP/1.1 302

Location: blog_list.html

(2)让前端发送请求(login.html)

<!-- 登录页的版心 -->
    <div class="login-container">
        <!-- 登录对话框 -->
        <div class="login-dialog">
            <h3>登录</h3>
            <!-- 使用 form 包裹一下下列内容, 便于后续给服务器提交数据 -->
            <form action="login" method="post">
                <div class="row">
                    <span>用户名</span>
                    <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 type="submit" id="submit" value="登录">
                </div>
            </form>
        </div>
    </div>

(3)让服务器处理请求并返回响应,新建一个loginServlet文件

@WebServlet("/login")
public class LoginServlet extends HttpServlet {
    private ObjectMapper objectMapper = new ObjectMapper();

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
      req.setCharacterEncoding("utf8");
      // 1. 从请求中, 获取到用户名和密码.
      String username=req.getParameter("username");
      String password=req.getParameter("password");
      //2.读取数据库,看看这里的用户名和密码是否和数据库中的匹配
      UserDao userDao=new UserDao();
      User user=userDao.selectUserByName(username);
      if(user==null){
        String html="<h3>用户名或密码错误! </h3>";
        resp.setContentType("test/html;charset=utf8");
        resp.getWriter().write(html);
        return;
      }
      if(!password.equals(user.getPassword())){
        String html = "<h3>用户名或密码错误! </h3>";
        resp.setContentType("text/html; charset=utf8");
        resp.getWriter().write(html);
        return;
      }
      //用户名和密码都正确,此时要创建一个对话
      HttpSession session=req.getSession(true);
      //此时要把用户对象放入一个回话之中,下次访问其他对象就可以直接进入
      session.setAttribute("user",user);
      //4.返回一个重定向响应,能跳转到博客列表页
      resp.sendRedirect("blog_list.html");
    }
}

4.强制要求登陆:

在博客列表页,详情页,编辑页,判定当前用户是否登陆,如果没有登陆,则强制跳转到登陆页

在这几个页面中,在页面加载是,给服务器发起ajax请求,从服务器上获取登陆状态

(1)约定前后端交互接口

GET/login

登陆成功HTTP/1.1 200

登陆失败HTTP/1.1 403

也有一种方法来区分成功和失败,都返回200,但是两者的body不同

(2)前端部分

在blog_list.html文件中的script标签中加上一下代码

function getLoginSatus(){
  $.ajax({
    type:'get',
    url:'login',
    success:function(body){
      console.log("已经登陆了");
    }
    error:function(body){
      location.assign('login.html');//前端页面跳转的写法
    }
  })
}
getLoginStatus();

一个页面通常会触发多个ajax,这些ajax之间是并发执行的,彼此之间互不干预

这里不使用后端的跳转是因为只有判断为没登陆的时候才能触发error,就是因为error了,后端无法发送响应,才需要前端去进行跳转

(3)后端部分处理请求

找到后端代码中的loginServlet.java文件,加入doget方法

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  HttpSession session=req.getSession(false);//如果有session就直接使用,如果没有session就为空,不创建
  if(session==null){
    resp.setStatus(403);
    return;
  }
  User user=(User)session.getAttribute("user");
  if(user==null){
    resp.setStatus(403);
    return;
  }
  resp.setStatus(200);
}

上述这些代码是用在博客列表页中的,同样的道理,只需把前端代码复制粘贴进详情页和编辑页中的前端script标签之中即可

5.显示用户信息

博客列表页:显示当前登陆的用户信息

博客详情页:显示当前文章作者的信息

在页面加载的时候给服务器发ajax请求,服务器返回对应的用户数据,根据发起请求不同的页面,服务器返回不同的信息即可

(1)约定前后端接口

博客列表页:获取当前登陆的用户信息

请求:GET/userInfo

响应:HTTP/1.1 200 ok application/json

{
   userid:1
   username:'zhangsan'
}

博客详情页:获取当前博客的作者信息

请求:GET/authorInfo?blogid=1

响应:HTTP/1.1 200 ok application/json

{
   userid:1
   username:'zhangsan'
}

(2)博客列表页的前后端代码

在blog_list.html文件的script标签中加入一下代码

function getUserInfo(){
  $.ajax({
    type:'get',
    url:'userInfo',
    success:function(body){
      //.....
    }
  })
}

后端代码:

@WebServlet("/userInfo")
public class UserInfoServlet etends HttpServlet{
  protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    HttpSession session=req.getSession(false);
    if(session==null){
      resp.setContentType("text/html;charset=utf8");
      resp.getWriter().write("当前用户未登陆");
      return;
    }
    User user=(User)Session.getAttribute("user");
    if(user==null){
      resp.setContentType("text/html;charset=utf8");
      resp.getWriter().write("当前用户未登陆");
      return;
    }
    resp.setContentType("application/json;charset=utf8");//把user对象转换成json,并返回给浏览器
    user.setPassword("");//这么写的目的是user中有password,如果把password传给客户很不安全,所以设置成空
    string respJson=objectMapper.writeValueAsString(user);
    resp.getWriter.write(respJson);
  }
}

前端代码处理响应:

把响应的数据放到对应页面位置上

success:function(body){
  let h3=document.querySelector('.card h3');//把拿到的响应数据,取出其中usename,设置到页面的h3标签之中
  h3.innerHTML=user.username;
}

(3)博客详情页的前后端代码

在blog_detail.html文件中写入一下内容

function getAuthorInfo(){
  $.ajax({
    type:'get',
    url:'getAuthorInfo'+location.search
    success:function(user){
      //.....
    }
  })
}

后端代码:

创建AuthorInfoServlet文件

@WebServlet("/getAuthorInfo")
public class AuthorInfoServlet etends HttpServlet{
  protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
    String blogid=req.getParameter('blogid');
    if(blogid==null){
      resp.setContentType("text/html; charset=utf8");
      resp.getWriter().write("请求中缺少blogid");
      return;
    }
    BlogDao blogDao=new BlogDao();//在blog表中查询对应的blog对象
    Blog blog=blogDao.getBlog(Integer.parseInt(blogid));
    if(blog==null){
      resp.setContentType("text/html; charset=utf8");
      resp.getWriter().write("blogid没找到");
      return;
    }
    UserDao userDao=new UserDao();
    User user=userDao.getUserByid(blog.getuserid());
    if(user==null){
      resp.setContentType("text/html; charset=utf8");
      resp.getWriter().write("userid没找到");
      return;
    }
    //把这个对象返回给浏览器
    user.setPassword("");
    String respJson=objectMappe.writeValueAsString(user);
    resp.setContentType("application/json;charset=utf8");
    resp.getWriter().write(respJson);
  }

原理就是先从请求中获取到blogid,然后用blogid找到对应的blog对象,然后拿到blog对象中的userid,根据这个userid获取到user表中的对象,最后作为响应传给前端

前端处理响应:

success:function(user){
  let h3=document.querySelector('.card h3');
  h3.innerHTML=user.username;
}

注意:在博客列表页的前端代码中,使用了appendChild,在详情页以及之后的功能就没有使用过,主要是因为要看处理响应的代码中是否要创建html标签,如果不创建html标签,那么就用上面这个方式,把东西传到标签之中,如果要创建html标签,那么就要使用appendChild的方式进行写前端代码

6.退出登陆:

博客列表页,博客详情页,博客编辑页导航栏中都有一个“注销”的按钮

让用户点击“注销”的时候,就会发送一个HTTP请求(GET请求),服务器收到这个GET请求的时候,就会把user这个Attribute删除,由于判断用户是否登陆的代码的逻辑中,同时要判断session是否存在,和user Attribute是否存在,所以只要破坏一个,那么就会让登陆状态发生改变

那为什么不直接删除session本身呢?

主要是因为servlet没提供删除session的方法,session提供了removeAttribute这样的方法,就可以把user这个Attribute给删除了

(1)约定前后端交互接口

请求:GET/logout

响应:直接重定向到登陆页 HTTP/1.1 302 Location:login.html

(2)编写前端,发送请求:

不用写ajax,直接给a标签设置href属性即可,博客列表页,博客详情页,博客编辑页都要加上这个标签

<a href="logout">注销</a>

(3)后端代码处理请求,给出响应

创建logout文件

@WebServlet("/logout")
public class LogoutServlet etends HttpServlet{
  protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
    HttpSession session=req.getSession(false);
    if(session==null){
      resp.setContentType("text/html;charset=utf8");
      resp.getWriter.write("当前尚未登陆");
    }
    session.removeAttribute("user");//把会话中的user属性删除
    resp.sendRedirect("login.html");
  }

四。原初的前端代码:

(1)blog_detail.html

<!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>博客详情页</title>
    <link rel="stylesheet" href="css/common.css">
    <link rel="stylesheet" href="css/blog_detail.css">
</head>
<body>
    <!-- 导航栏. nav 是 导航 这个词的缩写 -->
    <div class="nav">
        <!-- logo -->
        <img src="image/logo2.jpg" alt="">
        <div class="title">我的博客系统</div>
        <!-- 只是一个空白, 用来把后面的链接挤过去 -->
        <!-- 这是一个简单粗暴的写法~~ -->
        <div class="spacer"></div>
        <a href="blog_list.html">主页</a>
        <a href="blog_edit.html">写博客</a>
        <!-- 这里的地址回头再说 -->
        <a href="">注销</a>
    </div>
    <!-- 页面的主体部分 -->
    <div class="container">
        <!-- 左侧信息 -->
        <div class="container-left">
            <!-- 这个 div 表示整个用户信息的区域 -->
            <div class="card">
                <!-- 用户的头像 -->
                <img src="image/kun.jpg" alt="">
                <!-- 用户名 -->
                <h3>比特汤老湿</h3>
                <!-- github 地址 -->
                <a href="https://www.github.com">github 地址</a>
                <!-- 统计信息 -->
                <div class="counter">
                    <span>文章</span>
                    <span>分类</span>
                </div>
                <div class="counter">
                    <span>2</span>
                    <span>1</span>
                </div>
            </div>
        </div>

        <!-- 右侧信息 -->
        <div class="container-right">
            <h3>这是我的第一篇博客</h3>
            <div class="date">2023-05-11 20:00:00</div>
            <div class="content">
                <p>从今天开始我要认真写代码, Lorem ipsum dolor sit amet consectetur adipisicing elit. Ducimus quas soluta ipsam, molestiae totam accusamus minus beatae nam quo suscipit doloribus corporis eius alias ab minima impedit ullam? Optio, magni.</p>
                <p>从今天开始我要认真写代码, Lorem ipsum dolor sit amet consectetur adipisicing elit. Ducimus quas soluta ipsam, molestiae totam accusamus minus beatae nam quo suscipit doloribus corporis eius alias ab minima impedit ullam? Optio, magni.</p>
                <p>从今天开始我要认真写代码, Lorem ipsum dolor sit amet consectetur adipisicing elit. Ducimus quas soluta ipsam, molestiae totam accusamus minus beatae nam quo suscipit doloribus corporis eius alias ab minima impedit ullam? Optio, magni.</p>
                <p>从今天开始我要认真写代码, Lorem ipsum dolor sit amet consectetur adipisicing elit. Ducimus quas soluta ipsam, molestiae totam accusamus minus beatae nam quo suscipit doloribus corporis eius alias ab minima impedit ullam? Optio, magni.</p>
            </div>
        </div>
    </div>

</body>
</html>

(2)blog_edit.html

<!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>博客编辑页</title>
    <link rel="stylesheet" href="css/common.css">
    <link rel="stylesheet" href="css/blog_edit.css">
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
    <!-- 引入 editor.md 的依赖 -->
    <link rel="stylesheet" href="editor.md/css/editormd.min.css" />
    <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>
    <!-- 导航栏. nav 是 导航 这个词的缩写 -->
    <div class="nav">
        <!-- logo -->
        <img src="image/logo2.jpg" alt="">
        <div class="title">我的博客系统</div>
        <!-- 只是一个空白, 用来把后面的链接挤过去 -->
        <!-- 这是一个简单粗暴的写法~~ -->
        <div class="spacer"></div>
        <a href="blog_list.html">主页</a>
        <a href="blog_edit.html">写博客</a>
        <!-- 这里的地址回头再说 -->
        <a href="">注销</a>
    </div>

    <!-- 博客编辑页的版心 -->
    <div class="blog-edit-container">
        <form action="">
            <!-- 标题编辑区 -->
            <div class="title">
                <input type="text" id="title-input">
                <input type="submit" id="submit">
            </div>
            <!-- 博客编辑器 -->
            <!-- 把 md 编辑器放到这个 div 中 -->
            <div id="editor">

            </div>
        </form>
    </div>

    <script>
        var editor = editormd("editor", {
            // 这里的尺寸必须在这里设置. 设置样式会被 editormd 自动覆盖掉. 
            width: "100%",
            // 设定编辑器高度
            height: "calc(100% - 50px)",
            // 编辑器中的初始内容
            markdown: "# 在这里写下一篇博客",
            // 指定 editor.md 依赖的插件路径
            path: "editor.md/lib/"
        });
    </script>
</body>
</html>

(3)blog_list.html

<!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>博客列表页</title>

    <link rel="stylesheet" href="css/common.css">
    <link rel="stylesheet" href="css/blog_list.css">
</head>
<body>
    <!-- 导航栏. nav 是 导航 这个词的缩写 -->
    <div class="nav">
        <!-- logo -->
        <img src="image/logo2.jpg" alt="">
        <div class="title">我的博客系统</div>
        <!-- 只是一个空白, 用来把后面的链接挤过去 -->
        <!-- 这是一个简单粗暴的写法~~ -->
        <div class="spacer"></div>
        <a href="blog_list.html">主页</a>
        <a href="blog_edit.html">写博客</a>
        <!-- 这里的地址回头再说 -->
        <a href="">注销</a>
    </div>

    <!-- 页面的主体部分 -->
    <div class="container">
        <!-- 左侧信息 -->
        <div class="container-left">
            <!-- 这个 div 表示整个用户信息的区域 -->
            <div class="card">
                <!-- 用户的头像 -->
                <img src="image/kun.jpg" alt="">
                <!-- 用户名 -->
                <h3>比特汤老湿</h3>
                <!-- github 地址 -->
                <a href="https://www.github.com">github 地址</a>
                <!-- 统计信息 -->
                <div class="counter">
                    <span>文章</span>
                    <span>分类</span>
                </div>
                <div class="counter">
                    <span>2</span>
                    <span>1</span>
                </div>
            </div>
        </div>
        <!-- 右侧信息 -->
        <div class="container-right">
            <!-- 这个 div 表示一个 博客  -->
            <div class="blog">
                <!-- 博客标题 -->
                <div class="title">我的第一篇博客博客博客博客</div>
                <!-- 博客的发布时间 -->
                <div class="date">2023-05-11 20:00:00</div>
                <!-- 博客的摘要-->
                <div class="desc">
                    <!-- 使用 lorem 生成一段随机的字符串 -->
                    从今天起, 我要认真敲代码. Lorem ipsum dolor sit amet consectetur, adipisicing elit. Debitis repellendus voluptatum, reiciendis rem consectetur incidunt aspernatur eveniet excepturi magni quis sint, provident est at et pariatur dolorem aliquid fugit voluptatem.
                </div>
                <!-- html 中不能直接写 大于号, 大于号可能会被当成标签的一部分 -->
                <a href="blog_detail.html?blogId=1">查看全文 &gt;&gt; </a>
            </div>
            <div class="blog">
                <!-- 博客标题 -->
                <div class="title">我的第一篇博客</div>
                <!-- 博客的发布时间 -->
                <div class="date">2023-05-11 20:00:00</div>
                <!-- 博客的摘要-->
                <div class="desc">
                    <!-- 使用 lorem 生成一段随机的字符串 -->
                    从今天起, 我要认真敲代码. Lorem ipsum dolor sit amet consectetur, adipisicing elit. Debitis repellendus voluptatum, reiciendis rem consectetur incidunt aspernatur eveniet excepturi magni quis sint, provident est at et pariatur dolorem aliquid fugit voluptatem.
                </div>
                <!-- html 中不能直接写 大于号, 大于号可能会被当成标签的一部分 -->
                <a href="blog_detail.html?blogId=1">查看全文 &gt;&gt; </a>
            </div>
            <div class="blog">
                <!-- 博客标题 -->
                <div class="title">我的第一篇博客</div>
                <!-- 博客的发布时间 -->
                <div class="date">2023-05-11 20:00:00</div>
                <!-- 博客的摘要-->
                <div class="desc">
                    <!-- 使用 lorem 生成一段随机的字符串 -->
                    从今天起, 我要认真敲代码. Lorem ipsum dolor sit amet consectetur, adipisicing elit. Debitis repellendus voluptatum, reiciendis rem consectetur incidunt aspernatur eveniet excepturi magni quis sint, provident est at et pariatur dolorem aliquid fugit voluptatem.
                </div>
                <!-- html 中不能直接写 大于号, 大于号可能会被当成标签的一部分 -->
                <a href="blog_detail.html?blogId=1">查看全文 &gt;&gt; </a>
            </div>
        </div>
    </div>
</body>
</html>

(4)login.html

<!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>博客登录页</title>
    <link rel="stylesheet" href="css/common.css">
    <link rel="stylesheet" href="css/login.css">
</head>
<body>
    <!-- 导航栏. nav 是 导航 这个词的缩写 -->
    <div class="nav">
        <!-- logo -->
        <img src="image/logo2.jpg" alt="">
        <div class="title">我的博客系统</div>
        <!-- 只是一个空白, 用来把后面的链接挤过去 -->
        <!-- 这是一个简单粗暴的写法~~ -->
        <div class="spacer"></div>
        <a href="blog_list.html">主页</a>
        <a href="blog_edit.html">写博客</a>
    </div>

    <!-- 登录页的版心 -->
    <div class="login-container">
        <!-- 登录对话框 -->
        <div class="login-dialog">
            <h3>登录</h3>
            <!-- 使用 form 包裹一下下列内容, 便于后续给服务器提交数据 -->
            <form action="">
                <div class="row">
                    <span>用户名</span>
                    <input type="text" id="username">
                </div>
                <div class="row">
                    <span>密码</span>
                    <input type="password" id="password">
                </div>
                <div class="row">
                    <input type="submit" id="submit" value="登录">
                </div>
            </form>
        </div>
    </div>
</body>
</html>

标签:resp,系统,博客,blog,html,user,Servlet,blogid
From: https://blog.csdn.net/Eliaukqwe/article/details/143237655

相关文章

  • 基于springboot+vue实现的房产信息管理系统(源码+L文+ppt)4-101
     基于springboot+vue实现的房产信息管理系统(源码+L文+ppt)4-1014.1功能模块设计房产信息管理系统根据权限类型进行分类,主要可分为用户端和管理员端两大模块。用户端模块主要实现了作物图谱,病虫害科普等操作,加强了用户的操作体验。管理员服务端模块主要根据管理员对整个系统......
  • 基于springboot+vue实现的老年人健康管理系统 (源码+L文+ppt)4-100
      基于springboot+vue实现的老年人健康管理系统(源码+L文+ppt)4-100摘   要随着人口老龄化的不断加剧,老年人健康管理成为社会关注的焦点之一。本论文旨在设计和开发一款基于SpringBoot框架的老年人健康管理系统,以提升老年人的健康管理效率和质量。该系统通过整合各种......
  • 基于springboot+vue实现的房产信息管理系统(源码+L文+ppt)4-101
     基于springboot+vue实现的房产信息管理系统(源码+L文+ppt)4-1014.1功能模块设计房产信息管理系统根据权限类型进行分类,主要可分为用户端和管理员端两大模块。用户端模块主要实现了作物图谱,病虫害科普等操作,加强了用户的操作体验。管理员服务端模块主要根据管理员对整个系统......
  • 基于springboot+vue实现的老年人健康管理系统 (源码+L文+ppt)4-100
      基于springboot+vue实现的老年人健康管理系统(源码+L文+ppt)4-100摘   要随着人口老龄化的不断加剧,老年人健康管理成为社会关注的焦点之一。本论文旨在设计和开发一款基于SpringBoot框架的老年人健康管理系统,以提升老年人的健康管理效率和质量。该系统通过整合各种......
  • 基于springboot+vue实现的健身房管理系统 (源码+L文+ppt)4-097
     基于springboot+vue实现的健身房管理系统(源码+L文+ppt)4-097通过研究,本系统以MySQL为后端数据库,以JAVA为前端技术,以IDEA为开发系统,采用SPRINGBOOT架构,建立一个提供用户、员工、健身教练、健身课程、预约课程、课程签到、预约取消、器材信息、器材租用、器材归还、用户等级......
  • 基于springboot+vue实现的房产信息管理系统(源码+L文+ppt)4-101
     基于springboot+vue实现的房产信息管理系统(源码+L文+ppt)4-1014.1功能模块设计房产信息管理系统根据权限类型进行分类,主要可分为用户端和管理员端两大模块。用户端模块主要实现了作物图谱,病虫害科普等操作,加强了用户的操作体验。管理员服务端模块主要根据管理员对整个系统......
  • 基于springboot+vue实现的老年人健康管理系统 (源码+L文+ppt)4-100
      基于springboot+vue实现的老年人健康管理系统(源码+L文+ppt)4-100摘   要随着人口老龄化的不断加剧,老年人健康管理成为社会关注的焦点之一。本论文旨在设计和开发一款基于SpringBoot框架的老年人健康管理系统,以提升老年人的健康管理效率和质量。该系统通过整合各种......
  • 基于springboot+vue实现的健身房管理系统 (源码+L文+ppt)4-097
     基于springboot+vue实现的健身房管理系统(源码+L文+ppt)4-097通过研究,本系统以MySQL为后端数据库,以JAVA为前端技术,以IDEA为开发系统,采用SPRINGBOOT架构,建立一个提供用户、员工、健身教练、健身课程、预约课程、课程签到、预约取消、器材信息、器材租用、器材归还、用户等级......
  • 基于springboot+vue实现的老年人健康管理系统 (源码+L文+ppt)4-100
      基于springboot+vue实现的老年人健康管理系统(源码+L文+ppt)4-100摘   要随着人口老龄化的不断加剧,老年人健康管理成为社会关注的焦点之一。本论文旨在设计和开发一款基于SpringBoot框架的老年人健康管理系统,以提升老年人的健康管理效率和质量。该系统通过整合各种......
  • Linux系统rpm安装MySQL详细操作步骤
    安装方式介绍在Linux系统中,安装软件的方式主要有四种,这四种安装方式的特点如下:安装方式特点二进制发布包安装软件已经针对具体平台编译打包发布,只要解压,修改配置即可rpm安装软件已经按照redhat的包管理规范进行打包,使用rpm命令进行安装(不能自行解决库依赖问题)yum安装一种在线......