【Java EE】-博客系统一(前后端分离)

news2024/9/22 23:19:50

作者:学Java的冬瓜
博客主页:☀冬瓜的主页🌙
专栏:【JavaEE】
分享:
谜一样的 沉默着的
故事你真的在听吗
——《平凡之路》

主要内容:准备工作:创建maven,引入依赖。设计数据库并编写数据库代码。前后端分离功能的实现。博客列表,博客详情,登录功能,注册功能,验证登录,退出登录功能实现。

在这里插入图片描述

文章目录

  • 一、博客系统展示
  • 二、准备项目和基本代码
    • 1)准备工作
    • 2)设计数据库
    • 3)编写数据库代码
      • 1> sql建表
      • 2> 封装DBUtil
      • 3> 创建实体类:Blog、User
      • 4> 编写UserDao和BlogDao
  • 三、前后端分离实现博客系统
    • 1)博客列表
    • 2)博客详情
    • 3)登录功能
    • 4)验证登录
    • 5)注册用户
    • 6)退出登录

一、博客系统展示

1.登录
在这里插入图片描述
2.注册
在这里插入图片描述
3.博客列表:展示登录用户信息(暂时只有头像和名字),展示博客列表。
在这里插入图片描述
4.博客详情:展示博客作者信息,显示博客详情。如果当前登录用户和博客作者一致,则显示博客编辑和删除按钮。
在这里插入图片描述
在这里插入图片描述
5.新增博客:点击写博客,输入博客标题和正文发布,新增博客。
在这里插入图片描述
6.编辑博客:在详情页点击编辑博客,跳转博客编辑页,修改标题或正文,发布文章,修改博客。
在这里插入图片描述

在这里插入图片描述
7.删除博客:在博客详情页点击删除按钮,跳转回到博客列表页,重新从数据库获取博客列表展示在页面上。
在这里插入图片描述
8.上传头像:在博客列表页将鼠标移动到头像显示 点击头像修改个人信息(可以扩充名字,gitee地址修改等),点击后跳转到上传头像页面,如下图,上传完成后点击显示的返回,回到博客列表页,重新申请头像信息,获取头像。
在这里插入图片描述
在这里插入图片描述

二、准备项目和基本代码

1)准备工作

创建项目;引入依赖(servlet,mysql,jackson…),在pox.xml中引入依赖,是在WEB-INF下的lib包中引入jar包的简写。引入前面的博客系统前端部分的代码,放在webapp目录下。
如下图所示:我这里是写完代码,才写这篇博客,因此这里比起之前发布的前端页面的博客,我新增了注册的页面。

在这里插入图片描述

2)设计数据库

分析:博客系统的表结构,其实很简单,最基本的表是:博客表,用户表。想要分类功能可以加上个分类表(博客和分类表一对多),想要博客评论功能加上个评论表(博客和评论一对多)。这篇博客里就只使用到用户表,博客表,具体字段如下:

user(userId, username, password)
blog(blogId, title, content, postTime, userId)

注:用户和博客是一对多的关系,所以在博客表中增加一个userId字段,从而定位这篇博客的作者

3)编写数据库代码

1> sql建表

可以在src目录下新建一个sql表,将这个项目的关于数据库的代码放在这里,以便有需要时,在其它机器上快速部署。

sql建库建表语句

-- 不存在则建库
create database if not exists blog_system;
use blog_system;

-- 存在则删表
drop table if exists blog;
drop table if exists user;

-- 建表
create table blog(
    blogId int primary key auto_increment,
    title varchar(48),
    content varchar(4096),
    postTime dateTime,
    userId int
);
create table user(
    userId int primary key auto_increment,
    username varchar(20),
    password varchar(20)
);

2> 封装DBUtil

package model;

import com.mysql.cj.jdbc.MysqlDataSource;

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

public class DBUtil {
    private static DataSource dataSource = new MysqlDataSource();

    static {
        ((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/blog_system?charset=utf8&useSSL=false&allowPublicKeyRetrieval=true");
        ((MysqlDataSource)dataSource).setUser("root");
        ((MysqlDataSource)dataSource).setPassword("xxxxxx");//此处输入你自己的数据库密码
    }

    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }
    public static 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();
            }
        }
    }
}

3> 创建实体类:Blog、User

//User
package model;
// 封装User,对应数据库中的user表
public class User {
    // 根据数据库中的blog表的字段来定这里blog的 成员变量
    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;
    }
}
//Blog
package model;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;

// 封装Blog,对应数据库中的blog表
public class Blog {
    // 根据数据库中的blog表的字段来定这里blog的 成员变量
    private int blogId;
    private String title;
    private String content;
    private Timestamp postTime;
    private int userId;

    public int getBlogId() {
        return blogId;
    }

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

    public String 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 Timestamp getPostTimestamp() {
        return postTime;
    }
    public String getPostTime(){
        // 格式化输入时间SimpleDateFormat类
        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;
    }


    @Override
    public String toString() {
        return "Blog{" +
                "blogId=" + blogId +
                ", title='" + title + '\'' +
                ", content='" + content + '\'' +
                ", postTime=" + postTime +
                ", userId=" + userId +
                '}';
    }
}

4> 编写UserDao和BlogDao

Dao的全写是,data access object,是针对数据进行操作。此处就是针对blog表和user表,使用UserDao和BlogDao进行数据库的相关操作。

//UserDao
package model;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

// 对应数据库user表,对user表进行增删查改操作
public class UserDao {
    // 注册时使用
    public void add(User user){
        Connection connection = null;
        PreparedStatement statement = null;
        try {
            connection = DBUtil.getConnection();
            String sql = "insert into user values(null, ?, ?)";
            statement = connection.prepareStatement(sql);
            statement.setString(1, user.getUsername());
            statement.setString(2, user.getPassword());
            statement.executeUpdate();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            DBUtil.close(connection, statement, null);
        }
    }
    // 通过userId查找用户(在前后端交互内部使用,userId对应到博客)
    public User searchById(int userId){
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try {
            connection = DBUtil.getConnection();
            String sql = "select * from user where userId = ?";
            statement = connection.prepareStatement(sql);
            statement.setInt(1, userId);
            resultSet = statement.executeQuery();
            if (resultSet.next()){
                User user = new User();
                user.setUserId(resultSet.getInt("userId"));
                user.setUsername(resultSet.getString("username"));
                user.setPassword(resultSet.getString("password"));
                return user;
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            DBUtil.close(connection, statement, resultSet);
        }
        return null;
    }
    // 通过username查找用户(登录的时候使用)
    public User searchByName(String username){
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try {
            connection = DBUtil.getConnection();
            String sql = "select * from user where username = ?";
            statement = connection.prepareStatement(sql);
            statement.setString(1, username);
            resultSet = statement.executeQuery();
            if (resultSet.next()){
                User user = new User();
                user.setUserId(resultSet.getInt("userId"));
                user.setUsername(resultSet.getString("username"));
                user.setPassword(resultSet.getString("password"));
                return user;
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            DBUtil.close(connection, statement, resultSet);
        }
        return null;
    }
}
//BlogDao
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;

// 对应数据库blog表,对blog表进行增删查改操作
public class BlogDao {
    // 操作1:
    // 新增博客
    public void add(Blog blog){
        Connection connection = null;
        PreparedStatement statement = null;
        try {
            // 1.获取连接
            connection = DBUtil.getConnection();
            // 2.创建sql
            String sql = "insert into blog values(null, ?, ?, ?, ?)";
            // 3.进行预编译,并填充数据
            statement = connection.prepareStatement(sql);
            statement.setString(1, blog.getTitle());
            statement.setString(2, blog.getContent());
            statement.setTimestamp(3, blog.getPostTimestamp());
            statement.setInt(4, blog.getUserId());
            // 4.进行数据库操作
            statement.executeUpdate();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            DBUtil.close(connection, statement, null);
        }
    }
    // 操作2:
    // 根据博客id查询博客,博客列表跳转到博客详情处使用
    public Blog searchById(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 = ?";
            // 3.进行预编译,并填充数据
            statement = connection.prepareStatement(sql);
            statement.setInt(1, blogId);
            // 4.进行数据库操作
            resultSet = statement.executeQuery();
            // 5.处理结果集
            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 throwables) {
            throwables.printStackTrace();
        } finally {
            DBUtil.close(connection, statement, resultSet);
        }
        return null;
    }
    // 操作3:
    // 查询所有博客,博客列表页
    public List<Blog> searchAll(){
        List<Blog> blogList = new ArrayList<>();
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;

        try {
            connection = DBUtil.getConnection();

            // 在查询全部时,查出并按照时间逆序排序,从而使博客列表是按照时间逆序的
            String sql = "select * from blog order by postTime desc";
            statement = connection.prepareStatement(sql);

            resultSet = statement.executeQuery();
            while (resultSet.next()){
                Blog blog = new Blog();
                blog.setBlogId(resultSet.getInt("blogId"));
                blog.setTitle(resultSet.getString("title"));
                // 注意:博客列表页,正文显示字数有限制。以下是对超过字数的博客正文进行截取操作
                String content = resultSet.getString("content");
                if(content.length() >= 200){
                    content = content.substring(0, 200) + "...";
                }
                blog.setContent(content);
                blog.setPostTime(resultSet.getTimestamp("postTime"));
                blog.setUserId(resultSet.getInt("userId"));

                blogList.add(blog);
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            DBUtil.close(connection, statement, resultSet);
        }
        return blogList;
    }
    // 操作4:
    // 删除博客
    public void delete(int blogId){
        Connection connection = null;
        PreparedStatement statement = null;
        try {
            // 1.获取连接
            connection = DBUtil.getConnection();
            // 2.创建sql
            String sql = "delete from blog where blogId = ?";
            // 3.进行预编译,并填充数据
            statement = connection.prepareStatement(sql);
            statement.setInt(1, blogId);
            // 4.进行数据库操作
            statement.executeUpdate();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            DBUtil.close(connection, statement, null);
        }
    }
}

三、前后端分离实现博客系统

前后端分离:前端向后端发送请求,后端给前端返回数据,让前端自己去展示。
非前后端分离:前端给后端发送请求,展示页面由后端渲染,再给前端返回一个该页面。

前后端分离的好处:
1>降低了后端服务器的压力 2>更好的做到了解耦合

1)博客列表

说明:处理登录请求的后端servlet,完成操作后,跳转到blog_list.html页面,在blog_list.html页面中,通过jQuery封装的Ajax发送get请求,从后端获取所有博客信息,并把信息展示在这个blog_list.html页面中。

1>约定前后端交互接口
在这里插入图片描述

2>开发前端代码
在blog_list.html页面中:

  • 在博客列表页面(blog_list.html)加载过程中,触发ajax请求,访问数据库的博客列表数据,再把博客列表数据通过json格式从回调函数中取到并展示到页面上。
  • 下面代码注意调用函数getBlogs。sucess: function(body){ }即回调函数,响应的数据是一个json格式的字符串,此处body已经被jQuery自动解析成JavaScript对象。
    在这里插入图片描述
    我这里直接调用最原始的js操作dom树的方式,创建博客列表元素,并将数据展示在页面上,如果使用前端的框架,比如vue,react会简单很多。
    在这里插入图片描述
  • 在回调函数中可以得到博客的blogId,在每一篇博客添加一个查看全文的按钮(使用a标签),从而跳转到博客详情页面。
    在这里插入图片描述

3>开发后端代码
在BlogServlet的doGet方法中:

  • 约定前后端交互接口时,请求为get请求,因此在后端需要使用一个servlet的doGet方法来处理这个请求。且这个获取博客列表的请求的路径是/blog,因此这个处理请求的servlet的路径也是/blog(这里使用注解的方式)
    在这里插入图片描述
    在doGet方法中,使用Dao层去操作数据库,将数据查询出来放入blog对象中,把blog对象添加到list集合中,再利用引入的依赖jackson把list集合中的全部blog对象转成json格式字符串,并写入resp中,tomcat将resp对象转成http响应数据包,json格式的数据就在响应数据包的响应体中。
    在这里插入图片描述

  • 注意1:此处是获取博客列表页,正文应当是只显示部分,这怎们实现?可以在从数据库读取出来时(blogDao的searchAll()方法中),截断一下,如下代码所示:
    在这里插入图片描述

  • 注意2:时间的类型转换。封装的Blog对象的postTime是TimeStamp类型的时间格式为yyyy-MM-dd HH:mm:ss.SSS,即:是毫秒级的时间,想要具体到哪里自己需要进行类型转换。如下图所示,在Blog的javaBean中,getPostTime方法返回值格式化后是精确到秒,并返回一个字符串。
    在这里插入图片描述
    还需要注意的是,前端代码需要调用的是这个转换后的方法postTime对应的getPostTime方法从而显示正确的格式。
    在这里插入图片描述
    上面的代码中,blog.postTime本质上就是getPostTime这个格式化之后的方法返回的值,为什么呢?抓个包就知道了! 响应报文的响应体中的数据包含下面两个关于时间的,postTime就是我们在Blog类中的getPostTime格式化之后的方法。而postTimeStamp则是后端代码从数据库查询出后放在Tmstamp类型的blog对象的postTime属性中,经过jackson转换成json字符串后依然是Tmstamp类型的时间戳。
    在这里插入图片描述
    为什么强调前端的blog.postTime对应的是getPostTime方法呢?因为getPostTimeStamp方法中的postTime返回一个TimeStamp类型的时间戳,和结果不符,具体打印格式如下:精度是0.1秒,秒后面还跟个小数位。
    在这里插入图片描述

  • 注意3: 博客从上到下的顺序:越新发布的博客,越靠近上方。可以在查询数据库时根据时间倒序查询出博客。
    在这里插入图片描述

2)博客详情

说明:在博客列表页(blog_list.html)点击查看全文,会带着blogId跳转到博客详情页(blog_detail),在博客详情页中带上blogId发送get请求给后端,获取blogId对应的该篇博客,并展示在前端页面中。

1>约定前后端交互接口
在这里插入图片描述

2>开发前端代码
在blog_detail.html页面中:

  • 从点击查看全文到博客详情显示这个过程,经历了哪些?
    ①点击查看全文时,blog_list.html页面的回调函数中的创建的每个博客有个a标签,点击的博客对应的a标签发送一个get请求给后端。
    在这里插入图片描述
    ②如果是第一次发送获取列表的请求,还没有列表页面的缓存,服务器就返回相应的请求给前端,如果浏览器已经有了列表页面的缓存,后端会直接返回304告诉浏览器从缓存中获取。从而获取到blog_detail.html页面。
    第一次请求:
    在这里插入图片描述
    后续请求(从缓存中获取部分信息):
    在这里插入图片描述
    ③访问到blog_detail.html后,blog_detail.html中通过ajax发送带有blogId的请求(location.search在此处等价于?blogId=博客id)。
    在这里插入图片描述
    ④后端通过获取query string得到前端发送过来的blogId,从而去查询数据库中的数据。
    ⑤需要注意的点是,博客正文部分的显示,需要使用markdown官方文档的要求实现,从而写博客将博客信息写入数据库,查博客从数据库查询出来时,能够正确使用markdown语法渲染前端页面。
    具体实现:在blog_detail.html的回调函数中写相关显示博客正文的代码前,要在这些代码上面,需要引入关于markdown的js文件。同时使用editormd.markdownToHTML()显示正文部分。下图中editormd中的markdownToHTML()方法将markdown格式的字符串转换成html,显示到#content这个标签内。
    引入markdown相关的样式。
    在这里插入图片描述
    回调函数中使用markdown显示正文:
    在这里插入图片描述
    注意1:这个正文部分的id必须是和上图editormd.markdownToHTML('content', {markdown: body.content})的相对应的第一个参数对应。
    在这里插入图片描述
    注意2:如果修改页面正确后,但是没有正确显示,一定要注意缓存!解决:ctrl+f5强制刷新 or ctrl+shift+delete删除缓存。

3>开发后端代码
在BlogServlet的doGet方法中:

  • 获取博客列表页的请求是/blog,获取博客详情页的请求是/blog?blogId=博客Id,通过有没有query string,就可以判断是获取列表页请求还是获取详情页的请求。有blogId则为博客详情页请求,从而根据blogId从数据库获取博客信息并通过json格式的形式响应给前端。因此,在BlogServlst的doGet方法中,可以写成如下:
    在这里插入图片描述
  • 注意1:此时是获取博客详情页,因此博客正文部分content应当是完整的,而不是像获取博客博客列表页时的后端代码需要简述正文而去截断。因此这部分代码如下:
    在这里插入图片描述

3)登录功能

说明:blog_login.html使用post提交登录请求,后端使用doPost方法处理请求,验证输入是否为null,输入不空则根据信息查询数据库比对,是否已经注册,已注册则验证成功,创建session,并将用户信息放在session中,然后跳转到blog_list.html页面。

1>约定前后端交互接口
在这里插入图片描述
2>编写前端代码
在blog_login.html页面中:

  • 使用form表单,发送post请求。这里的action的值要和上面的@WebServlet("/login")相对应。
    在这里插入图片描述

3>编写后端代码
在LoginServlet的doPost方法中:

  • 前端点击登录按钮后,登录信息就放入请求报文的body中,然后跳转到@WebServlet("/login")这里执行doPost方法。
    在LoginServlet类的doPost方法中,通过getParameter方法获取用户名和密码(注意:getParameter里的参数一定要和前端输入时input标签里的name属性的值一致),需要验证用户名和密码是否为空,然后查数据库是否有该用户,没有则注册,有则跳转到博客列表blog_list.html页面。
    在这里插入图片描述

4)验证登录

说明:验证当前操作用户是否登录,如果未登录,就强制跳转到登录页面,要求先登录,才能进行后续操作。和过滤器的功能很相似。

注意:发送请求的部分前端代码需要写到blog_list.html、blog_detail.html、blog_edit.html等前端页面中中,在这些页面中,各自发送 GET /login请求,验证是否已经登录,而因为请求是相同的,所以后端都是用LoginServlet的 doGet方法处理这些请求,如果后端验证不通过则响应userId为0的对象给前端,如果通过,则从session中查出userId,并再去查询数据库(),响应从数据库中查询出来的user给前端。通过则看各自页面逻辑做相应处理,如果验证未通过,就强制跳转到blog_login.html页面。

1>约定前后端交互接口
在这里插入图片描述

2>编写前端代码

  • 如果验证登陆成功,跳转到blog_list.html页面后,使用jQuery封装的ajax提交get请求检查是否已经登录,请求路径是/login。在回调函数中通过是否有userId和userId是否大于0判断当前用户是否已经登录。未登录则在前端使用重定向,向后端重新发送重定向请求;如果已经登录,则暂时不做。等后续操作。
    在这里插入图片描述

3>编写后端代码
在LoginServlet的doGet方法中:

  • 请求是 GET /login,是使用LoginServlet的doGet方法来处理是否登录的验证。
  • 前提:在登录成功的时候,需要把该用户存入session。
    操作:验证登录的时候,获取session,如果session为null或者session里的user为null,代表用户未登录,返回一个空的user对象,这个对象的userId=0(java默认),如果session和user都不为空,则根据userId查询数据库,响应从数据库查询出来的user对象(不能直接返回这个session中的user,因为如果用登陆后做了信息修改,那么session中的user的信息就是过去的信息)。
    在这里插入图片描述

5)注册用户

说明:在登录页面中,点击注册账号,跳转到注册页面,输入信息,点击注册,就给后端发送post请求,后端使用doPost处理请求,获取信息,验证输入信息非空,查询数据库该用户是否已经存在,不存在则将当前用户信息插入到数据库中,注册成功则跳转到登录页面。

1>约定前后端交互接口
在这里插入图片描述

2>编写前端代码
blog_register.html页面中:

说明:可以直接复制粘贴登录页面的代码和样式,稍作修改,然后把form表单请求路径action的值改一下。然后在两个页面中添加一个a标签,用于实现两个标签之间的跳转即可。

在这里插入图片描述
在这里插入图片描述

3>编写后端代码
在RegisterServlet的doPost方法中:

说明:非空验证,是否注册验证,验证成功(不空,未注册),则向数据库插入数据,并且跳转到登陆页面

在这里插入图片描述

6)退出登录

说明:在blog_list.html、blog_detail.html、blog_edit.html等页面任何一处点击退出登录(a标签),发送get请求,后端使用doGet方法处理,删除session或者session里的用户信息后,返回到登录页面。

1>约定前后端交互接口
在这里插入图片描述

2>编写后端代码

  • LogoutServlet的doGet方法中,先判断有没有session,无session,返回错误,在判断session中有没有user,无user,返回错误,因为这两个都存在是登录的前提,如果有一个不存在就代表未登录(可以看登录的分析,获取了当前用户session,session里存了用户信息)。二者都有时,才表示当前已经登录,就可以退出登录。
  • 退出登录的具体操作:获取session和user,并判断两者都存在后,把user从session中remove或者销毁session。
    在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/708204.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

“去高精地图”跟“轻高精地图”有啥区别?落地的挑战又是啥? | 九章自动驾驶随笔之一...

交流群 | 进“传感器群/滑板底盘群/汽车基础软件群/域控制器群”请扫描文末二维码&#xff0c;添加九章小助手&#xff0c;务必备注交流群名称 真实姓名 公司 职位&#xff08;不备注无法通过好友验证&#xff09; 编辑 | 苏清涛 真正影响Mapless技术路线落地的最大难点在于…

C语言中的switch语句基本用法

导语&#xff1a;switch语句是一个多分支选择语句&#xff0c;并且可以支持嵌套 switch语句的基本格式 switch语句通过将表达式的值与常量值进行比对&#xff0c;如果相等则执行后面的语句&#xff0c;如果不相等则跳到下一个case语句&#xff0c;当表达式和常量值相等&#x…

探索Python条件语句的奇妙世界:解密逻辑与控制流

文章目录 前言if 语句if ... else ...多重判断&#xff08;if ... elif ... else...&#xff09;if 嵌套猜数字游戏三目运算符 前言 Python的条件语句用来根据特定的条件决定程序的执行流程。它允许程序根据条件的真假执行不同的代码块&#xff0c;从而实现不同情况下的不同操…

Linux系统Centos7 安装Tomcat详细步骤

必须安装过jdk &#xff08;1&#xff09;下载linux版本的tomcat&#x1f349; https://tomcat.apache.org/download-90.cgi (2) 把tomcat软件放到linux中&#x1f349; &#xff08;3&#xff09;解压&#x1f349; (4)防火墙放行tomcat端口&#x1f349; firewall-cmd -…

Verilog基础之十二、分频器实现

目录 一、前言 二、工程设计 2.1 工程代码 2.2 测试文件代码 2.3 综合结果 2.4 仿真结果 一、前言 分频器即将高频率的信号转化为更低频率的信号&#xff0c;常用的分频可使用锁相环PLL来实现&#xff0c;也可自己编写RTL代码来实现。根据分频的系数N(假设信号频率为M&am…

linux环境下重置mysql密码

一、my.cnf 首先&#xff0c;需要找到my.cnf这个文件。 Linux 操作系统中 MySQL 的配置文件是 my.cnf&#xff0c;一般会放在 /etc/my.cnf 或 /etc/mysql/my.cnf 目录下。总的来说&#xff0c;my.cnf 类似于 my.ini 配置文件。 如果实在找不到&#xff0c;使用命令&#xff…

C++ 信号处理

信号是由操作系统传给进程的中断&#xff0c;会提早终止一个程序。在 UNIX、LINUX、Mac OS X 或 Windows 系统上&#xff0c;可以通过按 CtrlC 产生中断。 有些信号不能被程序捕获&#xff0c;但是下表所列信号可以在程序中捕获&#xff0c;并可以基于信号采取适当的动作。这些…

组合预测模型 | Matlab基于时间卷积神经网络结合门控循环单元的(TCN-GRU)的回归预测预测,多变量输入模型

文章目录 效果一览文章概述部分源码参考资料效果一览 文章概述 基于时间卷积神经网络结合门控循环单元的(TCN-GRU)的回归预测预测,多变量输入模型(Matlab完整源码和数据) 基于时间卷积神经网络结合门控循环单元的(TCN-GRU)的回归预测预测,多变量输入模型(Matlab完整源码和数…

Vite 项目性能分析与优化

性能优化一直是前端工程化中老生常谈的话题&#xff0c;也是前端项目优化的重要的优化点。事实上&#xff0c;随着项目越来越庞大&#xff0c;稍不注意就会产生明显的性能问题。在不同的场景中&#xff0c;我们对于项目性能的关注点是不一样的。在项目开发阶段&#xff0c;我们…

English Learning - L3 作业打卡 Lesson7 Day55 2023.6.30 周五

English Learning - L3 作业打卡 Lesson7 Day55 2023.6.30 周五 引言&#x1f349;句1: I could feel the wind against my face and the beat of my racing heart as if it were happening in that very moment.成分划分弱读连读爆破语调 &#x1f349;句2: And that is when …

力扣 236. 二叉树的最近公共祖先

题目来源&#xff1a;https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-tree/description/ C题解&#xff1a;弄清思路就好写&#xff0c;理不清思路就唉。。 递归法&#xff1a; 1. 确定函数返回类型和参数&#xff1a;目标是最近公共节点&#xff0c;所以…

debian linux安装配置企业私有网盘

一、适用环境 1、中小型企业的某些部门之间经常要进行数据的交换与共享时&#xff0c;则可使用企业内部专业的服务器&#xff0c;把剩余的硬盘存储容量配置成为共享网盘的形式&#xff0c;供部门之间进行数据交换。 2、可将多个硬盘通过debian Linux系统组成软阵列的1个逻辑盘…

Scrapy框架之MongoDB聚合操作

目录 MongoDB聚合操作 聚合操作的基本语法 常用的聚合操作 管道命令之$group 按照某个字段进行分组 详解 计算集合中某个字段的平均值 常用表达式 管道命令之$match 示例 管道命令之$sort 管道命令之$skip 和 $limit 管道命令之$project MongoDB聚合操作 在…

ts:Set、Map

观看小满老师课程的随笔~ 前言 与 原生 js 中的原理和方法是相同的&#xff0c;这里只是用了 ts 中的 强类型 一、Set 天然去重&#xff0c;引用类型除外增删改查&#xff1a;add、has、delete、clear循环&#xff1a;forEach、entries、keys、for...of(内置的有iterator迭代…

CCF-CSP真题《202305-2 矩阵运算》思路+python,c++满分题解

想查看其他题的真题及题解的同学可以前往查看&#xff1a;CCF-CSP真题附题解大全 试题编号&#xff1a;202305-2试题名称&#xff1a;矩阵运算时间限制&#xff1a;5.0s内存限制&#xff1a;512.0MB问题描述&#xff1a; 题目背景 Softmax(QKTd)V 是 Transformer 中注意力模块的…

javac命令编译.java源文件报错“编码GBK的不可映射字符“

原因在于.java源文件编码方式是UTF-8 二cmd DOS窗口编码格式是GBK 解决办法 javac -encoding UTF-8 *.java

Kettle 实现动态表查询

文章目录 前言动态表名查询数据 :一、获取表名1、新建一个转换getTableName&#xff0c;拖入获取系统信息&#xff0c;字段选择&#xff0c;设置变量2、打开 获取系统信息 编辑界面&#xff0c;填写名称&#xff0c;点击类型选择要获取的信息类型3、打开字段选择&#xff0c;选…

深蓝学院C++基础与深度解析笔记 第 9 章 序列与关联容器

第 9 章 序列与关联容器 1. 容器概述 A、容器&#xff1a; 一种特殊的类型&#xff0c;其对象可以放置其它类型的对象&#xff08;元素&#xff09; – 需要支持的操作&#xff1a;对象的添加、删除、索引、遍历 – 有多种算法可以实现容器&#xff0c;每种方法各有利弊B、容…

nvdiffrecmc在Windows上的配置及使用

nvdiffrecmc是NVIDIA研究院开源的项目&#xff0c;源代码地址&#xff1a;https://github.com/NVlabs/nvdiffrecmc&#xff0c;论文为《Shape, Light, and Material Decomposition from Images using Monte Carlo Rendering and Denoising》&#xff0c;使用Monte Carlo渲染和去…