博客系统实现

news2024/11/27 3:44:50

一.准备工作

1.创建项目,把前端写好的博客静态页面拷贝到webapp目录中

2.引入依赖,这里主要用到servlet,mysql5.1.47,jacson2.15.0

3.找到右上角的edit configurations->smartTomcat->进行配置

4.数据库设计:设计对应的表结构,并把数据库相关代码进行封装。如何设计表结构?首先确定实体,其次确认实体之间的关系。这里的实体就是博客和用户,所以就是一个blog表,一个user表。两者是一对多的关系->一个博客只能属于一个用户,然而一个用户可以拥有多篇博客。所以应在博客表中引入userid。

1.对数据库的操作

先把数据库创建好,并创建好表,为了方便创建,先在webapp下面新建一个文件db.sql,然后再这里面把sql语句编辑好,然后复制粘贴到MySQL中。这样方便修改语法错误(其实直接在MySQL中创建也可以)

然后我们把对数据库进行操作的代码进行封装。我们将对数据库的操作都放到model包中。所以在java目录下新建一个model包

建立连接等通用操作

然后再在model包中新建一个DButil类,用来封装数据库建立连接的代码。这是由于接下来的代码中有很多个servlet都需要使用库,所以就需要有单独的地方把DataSourse的操作进行封装,而不是只放到某个servlet的init中

public class DButil {
    private static DataSource ds=null;
    private static DataSource getDataSourse(){
        if(ds==null){
            ds=new MysqlDataSource();
            ((MysqlDataSource)ds).setUrl("jdbc:mysql//127.0.0.1:3306/blog_system?charset=utf8&useSSL=false");
            ((MysqlDataSource)ds).setUser("root");
            ((MysqlDataSource)ds).setPassword("20050430zyh");
        }
        return ds;
    }
    public Connection getConnection() throws SQLException {
        return getDataSourse().getConnection();
    }
    public static void close(ResultSet resultSet, PreparedStatement statement,Connection connection){
        if(resultSet!=null){
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(statement!=null){
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(connection!=null){
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

如上,对外只开放建立连接和关闭的操作,建立数据源的操作直接封装起来

两个类表示两张表

每个表都需要专门搞一个类来表示

public class Blog {
    private int blogid;
    private String content;
    private Timestamp postTime;
    private int userid;

    public int getBlogid() {
        return blogid;
    }

    public void setBlogid(int blogid) {
        this.blogid = blogid;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public Timestamp getPostTime() {
        return 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 +
                ", content='" + content + '\'' +
                ", postTime=" + postTime +
                ", userid=" + userid +
                '}';
    }
}
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;
    }

    @Override
    public String toString() {
        return "User{" +
                "userid=" + userid +
                ", username='" + username + '\'' +
                '}';
    }
}

两个类完成对两张表的操作

就用BlogDao和UserDao来命名。Dao,就是Data Access Object(数据访问对象)通过这两个类的对象完成对数据的操作

public class BlogDao {
    //新增,提交博客
    public void insert(Blog blog){
        Connection connection=null;
        PreparedStatement statement=null;
        try {
            //建立连接
            connection=DButil.getConnection();
            //构造sql语句
            String sql="insert into blog values (null,?,?,now(),?)";
            statement=connection.prepareStatement(sql);
            statement.setString(1,blog.getTitle());
            statement.setString(2,blog.getContent());
            statement.setString(3,""+blog.getUserid());
            //执行sql
            statement.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            DButil.close(null,statement,connection);
        }
    }
    //查询博客列表(博客列表页),把库中所有博客都拿到
    public List<Blog> getBlogs(){
        Connection connection=null;
        PreparedStatement statement=null;
        ResultSet resultSet=null;
        List<Blog> blogList=new ArrayList<>();
        try {
            connection=DButil.getConnection();
            String sql="select * from blog";
            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()>100){
                    content=content.substring(100);
                }
                blog.setContent(content);
                blog.setPostTime(resultSet.getTimestamp("postTime"));
                blog.setUserid(resultSet.getInt("userid"));
                blogList.add(blog);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            DButil.close(resultSet,statement,connection);
        }
        return blogList;
    }
    //根据博客id查询指定博客
    public Blog getBlog(int blogid){
        Connection connection=null;
        PreparedStatement statement=null;
        ResultSet resultSet=null;
        Blog blog=new Blog();
        try {
            connection=DButil.getConnection();
            String sql="select * from blog where blogid=?";
            statement=connection.prepareStatement(sql);
            statement.setInt(1,blogid);
            resultSet=statement.executeQuery();
            if(resultSet.next()){
                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"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            DButil.close(resultSet,statement,connection);
        }
        return blog;
    }
    //根据博客id删除指定博客
    public void deleteBlog(int blogid){
        Connection connection=null;
        PreparedStatement statement=null;
        try {
            connection=DButil.getConnection();
            String sql="delete from blog where blogid=?";
            statement=connection.prepareStatement(sql);
            statement.setInt(1,blogid);
            statement.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            DButil.close(null,statement,connection);
        }
    }
}

注意,在getBlogs这个方法中,获取正文时,不要把全部正文内容都拿出来显示到列表页上,只需要拿出一部分即可,所以会有一个截断操作

在getBlog操作中,由于blogid时主键,所以只能查询到一篇博客,所以不需要while循环,只需要一个if判断,同时,正文不用截断!!!

public class UserDao {
    //根据userid查询对应用户信息(获取用户信息)
    public User getUserByid(int userid){
        Connection connection=null;
        PreparedStatement statement=null;
        ResultSet resultSet=null;
        User user=new User();
        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.setUserid(resultSet.getInt("userid"));
                user.setUsername(resultSet.getString("usernsme"));
                user.setPassword(resultSet.getString("password"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            DButil.close(resultSet,statement,connection);
        }
        return user;
    }
    //根据usernsme查询对应用户信息
    public User getUserByname(String username){
        Connection connection=null;
        PreparedStatement statement=null;
        ResultSet resultSet=null;
        User user=new User();
        try {
            connection=DButil.getConnection();
            String sql="select * from user where userid=?";
            statement=connection.prepareStatement(sql);
            statement.setString(1,username);
            resultSet=statement.executeQuery();
            if(resultSet.next()){
                user.setUserid(resultSet.getInt("userid"));
                user.setUsername(resultSet.getString("usernsme"));
                user.setPassword(resultSet.getString("password"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            DButil.close(resultSet,statement,connection);
        }
        return user;
    }
}

上面这两方法就都很相似。

二.前后端交互,实现博客功能

1.获取博客列表页

在博客列表页加载时,通过ajax方式给服务器发送请求,从服务器数据库中拿到数据显示到页面上

约定前后端交互接口

请求

GET /blog

响应

HTTP/1.1 200 OK

Content-Type:application/json

[

     {

         blogid:1

         title:' '

         content:

         postTime:

         userid:

      }

……

]

让浏览器给服务器发送请求

我们要对前端的blog_list.html使用ajax进行修改,所以首先要引入jquery库:也就是在head标签内加一个script标签:<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script>

编写前把写死的那部分标签给注释掉,然后在</body>上方进行代码编写,加一个<script>标签,在开始和结束标签之间进行编写:

我们直接将代码封装到函数中,但一定要记住调用!!

服务器处理请求

我们将所有服务器的代码都放到一个包里面,也就是servlet包,然后在改包中线新建一个BlogServlet类。由于对于博客列表页发送的请求的处理方式是要将表中数据按照json格式字符串返回,所以肯定要用到jackson,所以要定义一个成员变量ObjectMapper,最终代码如下:

让前端代码处理响应

这里的关键是根据服务器返回的博客信息去构造博客列表页!!我们使用的是比较朴素的方式来构造博客列表页,也就是基于dom api。dom api是浏览器提供的标准的api,不属于任何第三方库/框架。

如上,我们要构建出类似于这样结构的标签,这些标签有着包含关系以及并列关系,最大的标签是containner-right,其他所有标签都是在它里面。它里面就是一个一个博客,其中每个博客标签里面又并列包含了标题,发布时间,摘要,查看全文按钮

如上。由于在像一个中设置了正文格式为json,所以当把响应返回给客户端后,body部分就自动被解析成了一个json对象,这里由于响应是一个对象列表转化成的json字符串数组,所以是被解析成了json对象数组,所以要通过for循环遍历数组,拿出每一个blog对象进行遍历。

其中,在创建查看全文按钮时,我们的目的是创建一个类似于”查看全文>>"这样的标签,但是大于号要想在html中写出,就必须使用转义字符&gt;小于号就是&lt。因为html标签就是<>构成的。

其次,一点击查看全文,就要进入博客详情页,所以要用到超链接标签,也就是a标签。其中的href属性就是在描述点击后会跳转到哪个页面。同时,点击a标签就会自动发送一个get请求!!!之前我们提到过。

解决出现的问题

到这里,博客列表页就构造完了。我们来测试一下,发现几个问题:1.时间显示不对,现在显示的是时间戳,但我们希望是某年某月某日几点。2.返回的数据的顺序问题,正常来说,最上面的博客应该是最新的博客,但是我们现在再插入一篇博客后,它会被显示到博客列表页的最下面,而不是最上面。

解决时间问题

抓包观察是哪里出现了问题,仔细观察发现在获取博客数据的响应中的postTime就是时间戳。所以是resp.getWriter().write(respJson)出问题了。所以关键就是respJson,它是怎么获取到的呢?

1.首先jackson发现,blogList是一个list,于是就循环遍历了

2.它针对每一个元素(Blog对象)通过反射的方式获取到属性名字,然后再用get方法拿到属性的值。

所以关键就在于修改postTime的get方法,如下:

java标准库中提供了SimpleDateFormet类,来完成时间戳到格式化时间的转化。此类的使用很复杂,不需要背,每次使用前都查一下就行。创建SDF对象,传入指定字符串,用来描述当前时间日期的具体格式,然后使用format方法,里面的参数可以是时间戳,也可以是date对象

解决顺序问题

我们是到,数据库查询到结果的顺序其实是随机的,所以要想固定顺序,就要使用orderby关键字,并按照发布时间降序排列,如下选中部分。

2.获取博客详情页

这个就是在点击查看全文后,就会发送get请求并跳转到了博客详情页(这是我们刚刚编写的a标签实现的逻辑),那我们现在要实现的就是根据请求中的blogid去查询到对应的博客并返回给前端

约定前后端交互接口

请求

GET /blog?blogid=1

响应

HTTP/1.1 200 OK

Content-Type:application/json

{

      blogid:1

      title:

      content:

      postTime:

      userid:

}

前端使用ajax发起请求

打开blog_list.html,在</div>下面添加script标签,进行代码编写:

url中的blogid是如何得到的呢?这里就是用location.search来拿到当前页面的url中的queryString(因为在设置a标签时,其中的href属性中就带有?blogid=……)。(在浏览器中,ctrl+shift+i就可以打开控制台,输入location.search就可以看到当前页面的queryString语句)注意,location.search拿到的是整个query String语句,包括了问号!!

服务器处理上述请求

上面请求的路径还是blog,所以还是在BlogServlet中处理get方法。但是在获取博客列表页的时候已经写了一个doGet方法了呀,这该怎么办?找两者的不同,发现上面的请求时没有blogid的,而当前这个请求是有blogid的。这就是区别。所以进行如下编辑:

前端将响应数据构造成html片段

首先把containner-right里面的内容给注释掉

然后按这个格式去构造片段:

测试一下,发现了两个问题:

1.写完代码之后,会发现点击某个博客,有点博客详情页里还是那些注释掉的内容。这个问题是浏览器缓存引起的。浏览器在加载页面时,是通过网络获取资源的,但是网络速度很慢,所以浏览器会把已经加载是页面在本地硬盘中保存一份,后续再次访问同一个页面时,就不通过网络加载,而是直接加载本地硬盘中的这一份。那这如何克服呢?前端有专业的解决方案,不过咱们不用关心,只需要ctrl+F5刷新一下即可。

当前的详情页,虽然能够显示正文了,但是显示的正文是markdown的原始数据。正常应该显示md渲染后的效果。这就需要通过引入第三方库来完成:

引入依赖:在blog_editor.html的</head>前面粘贴

然后在刚才的构造页面正文的代码进行修改:

这个editormd是editor.md官方文档上提供的一个全局变量。此方法的第一个参数必须是一个标签的id,但是content标签没有设置id,所以我们要在上面的content标签内部加上一个id属性。第二个参数就是一个js对象:

最终这个函数的效果就是把blog.content这里的原始md数据渲染成html放到content div的内容中

3.实现登录

在login.html点击登陆后,应该给服务器发起一个http请求。服务器处理上述请求,读取用户名和密码,在库中查询匹配,若正确,则成功登录,创建会话,跳转到博客列表页(所以登陆成功就直接进行重定向跳转

约定前后端交互接口

请求

POST /login

Content-Type:application/x-www-form-urlencoded

username= &password=

响应

HTTP/1.1 302

Location:blog_list.html

注意,若使用ajax发送请求,就要再写代码完成跳转;但是使用form表单的话,只要提交成功,就可以直接使用302完成页面跳转

前端发送请求

打开login.html,对下面的代码进行逻辑修改:

修改完就是:

服务器处理请求返回响应

先将请求中的用户名和密码获取到,判断是否为空。然后根据用户名去获取对应的用户,要是没获取到,就说明用户名错误了,若获取到,就说明用户名是对的。然后拿着刚刚获取到的用户的密码和请求中的密码对照一下,要是不一致,就说明密码填错了(不过,不管是密码写错买时用户名写错,我们都统一提示用户名或密码不正确)。最后创建会话,还是参数是true,并且设置会话中的属性user就是user对象。

4.强制要求登录

这个功能就是在博客的列表页,详情页,编辑页去判定当前用户是否已经登陆。若未登录,就强制要求跳转到登录页。所以要在这几个页面中,在页面加载时,给服务器发送ajax请求,从服务器获取到一个登录状态即可

约定前后端交互接口

请求

GET /login

响应

HTTP/1.1 200 OK ->表示成功登录

HTTP/1.1 403       ->表示登录失败

响应的格式可以有很多种,比如返回的都是200,但是正文不一样

前端发起ajax请求

打开blog_list.html,在function getBlogs()下面再写一个方法:

这里success是在返回2开头的状态码时会执行,error则是在返回除2以外的数字开头的状态码就hi执行。location.assign就是强制要求跳转到login.html,这是前端页面跳转的方式。那为啥不待会儿在服务器直接返回个302,直接跳转到登录页呢?因为302这样的响应回到ajax中的error中后,无法被ajax直接处理。除非通过提交form表单或者点击a标签这种触发的http请求,浏览器才可以直接跳转。

处理响应的过程比较简单,所以一起写了

服务器处理请求

注意,未登录状态的判定不单单是看会话是否存在,还有看该会话中是否存放着user(为什么?待会实现退出登录的时候就知道了)

测试一下:直接打开列表页,在列表页刷新一下,就发现跳转到了登录页。

但有个问题,虽然已经登陆了,但是一旦重启服务器,就会被判定为未登录状态。因为登陆状态是根据服务器的内存中的session确定的,重启服务器意味着之前的内存要释放。其实这一设定并不科学,如何解决?以后再说。

现在,博客编辑页和详情页也要执行上述逻辑,所以在vscode中创建一个新目录js,js中创建新文件app.js,将getLoginStqatus函数复制过去。

然后在每个页面的<script>上再来个<script src="js/app.js"></script>,然后在下面的script中调用getLoginStatus即可:

这就是把一些公共的js代码单独提取出来放到某个.js文件中,然后通过html中的script标签来引用这些文件内容,此时就可以在html中调用对应的公共代码了。

5.显示用户信息

在列表页显示当前登录的用户的信息,在详情页显示作者信息。在页面加载时,给服务器发送ajax请求,服务器返回对应的用户信息

约定前后端交互接口

请求

GET /userinfo(详情页则是authorid)

响应

HTTP/1.1 200 OK

Type:application/json

{

        userid:

        username:

}

前端发起ajax请求

这是博客列表页

这是博客详情页,通过location.search查到对应的博客id,从而查找对应的作者

服务器处理上述请求

首先是针对博客列表页的。最终要将user对象转成json格式的字符串,所以要有一个ObjectMapper。然后,先取出会话,看看会话是否为空,或者会话中是否存储了user,要是没有,就说明未登录,反之就是已经登录了。最后,在显示用户信息时,为保证安全,就应该将密码置为空!!

最后就是处理博客详情页的请求,首先看看请求中是否带有blogid,要不然没法查询。然后就是根据blogid查到对应的博客。再根据博客找到作者,最后返回作者信息

前端将响应构造成html片段

首先是列表页:

应该将用户名显示到<h3>标签处,所以代码如下:

注意,h3标签没有class属性,所以前面不用加点。

然后是详情页,也是要设置到h3标签:

6.注销/退出登录

在博客列表页/编辑页/详情页都有注销按钮,这就是一个a标签,其中有一个href属性,点击就能够触发一个http请求,就能引起浏览器跳转到另一个页面。

我们现在要做的就是修改a标签,让用户一点击它,就能触发一个http请求,服务器收到了就会把会话中的这个user删除掉并跳转到登录页。(那为啥不直接把会话给删除呢?因为servlet没有提供删除会话的操作!!!不过也可以给会话设置一个过期时间,但是不够优雅。session提供了removeAttribute的方法)

约定前后端交互接口

请求

GET /logout

响应

HTTP/1.1 302

location:login.html

前端发起请求

不用写ajax,直接给a标签添加一个href属性即可

服务器处理请求

7.发布博客

输入标题,正文,期望一点击提交就能够发到服务器这边进行保存

约定前后端交互接口

请求

POST /blog

content-Type:application/x-www-form-urlencoded

title= &content=

响应

HTTP/1.1 302

location:blog_list.html

前端发起请求

就是修改这一块,变成:

也就是给title标签加上name属性。那么如何给正文加上name属性?就是在 <div id="editor">这个标签下加上<textarea name="content" style="display:none"></textarea>,textarea就是一个多行编辑器容器,就把name属性加到它上面即可,然后在初始化editormd对象时加上一个对应的属性即可,也就是在下面的图片中的var editor 中加一个属性saveHTMLToTextarea并赋值为true:

上面这个图片修改为:

表示会把用户在编辑器里面的内容自动保存到textarea中,这样,一点提交,就会在form表单中有拷贝

服务器处理请求

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

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

相关文章

十四款大型语言模型在《街头霸王III》中一决雌雄

上周在旧金山举办的Mistral AI黑客马拉松上&#xff0c;开发出了一款基于经典街机游戏《街头霸王III》的人工智能&#xff08;AI&#xff09;基准测试。这款名为“AI Street Fighter III”的开源基准测试由Stan Girard和Quivr Brain开发&#xff0c;游戏在模拟器中运行&#xf…

【力扣刷题日记】1495.上月播放的儿童适宜电影

前言 练习sql语句&#xff0c;所有题目来自于力扣&#xff08;https://leetcode.cn/problemset/database/&#xff09;的免费数据库练习题。 今日题目&#xff1a; 1495.上月播放的儿童适宜电影 表&#xff1a;TVProgram 列名类型program_datedatecontent_idintchannelvarc…

【机器学习】深入解析机器学习基础

在本篇深入探讨中&#xff0c;我们将揭开机器学习背后的基础原理&#xff0c;这不仅包括其数学框架&#xff0c;更涵盖了从实际应用到理论探索的全方位视角。机器学习作为数据科学的重要分支&#xff0c;其力量来源于算法的能力&#xff0c;这些算法能够从数据中学习并做出预测…

产品推荐 | 基于Intel(Altera)Arria 10 10AS027/048打造的水星Mercury+ AA1核心板

01 产品概述 水星Mercury AA1片上系统&#xff08;SoC&#xff09;核心板通过结合基于ARM处理器的SoC FPGA、快速DDR4 ECC SDRAM、eMMC flash、QSPI flash、Gigabit Ethernet PHY和RTC形成了一个高性能嵌入式处理方案&#xff0c;结合了CPU系统的灵活性和FPGA原始的、实时的并…

【PolarDB-X从入门到精通】 第四讲:一站式学习源码部署

亲爱的同学们&#xff1a; 大家好&#xff01;在之前的课程中&#xff0c;我们已经初步了解了PolarDB-X的架构、安装部署PolarDB-X的四种方式以及如何使用Docker和PXD进行安装部署。接下来&#xff0c;我们将进入更加专业的领域——源码编译部署PolarDB-X。 课程主题&#xf…

YOLOV8注意力改进方法:DilateFormer多尺度空洞 Transformer(附改进代码)

原论文地址:原论文下载地址 即插即用的多尺度全局注意力机制 本文提出了一种新颖的多尺度空洞 Transformer,简称DilateFormer,以用于视觉识别任务。原有的 ViT 模型在计算复杂性和感受野大小之间的权衡上存在矛盾。众所周知,ViT 模型使用全局注意力机制,能够在任意图像块…

C语言 函数——函数原型

目录 如何合并成一个完整的程序&#xff1f; 函数原型与函数定义的区别 函数原型的作用 如何合并成一个完整的程序&#xff1f; 问题&#xff1a;在一个函数中调用另一个函数&#xff0c;需要具备哪些条件呢&#xff1f; 若函数的定义出现在函数调用之前 若函数的定义出现…

Java绘图坐标体系

一、介绍 下图说明了Java坐标系。坐标原点位于左上角&#xff0c;以像素为单位。在Java坐标系中&#xff0c;第一个是x坐标&#xff0c;表示当前位置为水平方向&#xff0c;距离坐标原点x个像素&#xff1b;第二个是y坐标&#xff0c;表示当前位置为垂直方向&#xff0c;距离坐…

对OceanBase中的配置项与系统变量,合法性检查实践

在“OceanBase 配置项&系统变量实现及应用详解”的系列文章中&#xff0c;我们已经对配置项和系统变量的源码进行了解析。当涉及到新增配置项或系统变量时&#xff0c;通常会为其指定一个明确的取值范围或定义一个专门的合法性检查函数。本文将详细阐述在不同情境下&#x…

自动驾驶中的传感器融合算法:卡尔曼滤波器和扩展卡尔曼滤波器

自动驾驶中的传感器融合算法&#xff1a;卡尔曼滤波器和扩展卡尔曼滤波器 附赠自动驾驶学习资料和量产经验&#xff1a;链接 介绍&#xff1a; 追踪静止和移动的目标是自动驾驶技术领域最为需要的核心技术之一。来源于多种传感器的信号&#xff0c;包括摄像头&#xff0c;雷达…

设计模式系列:单例模式

作者持续关注WPS二次开发专题系列&#xff0c;持续为大家带来更多有价值的WPS开发技术细节&#xff0c;如果能够帮助到您&#xff0c;请帮忙来个一键三连&#xff0c;更多问题请联系我&#xff08;QQ:250325397&#xff09; 定义 单例&#xff08;Singleton&#xff09;模式的定…

CentOS7.9创建本地yum源操作步骤报错解决方法

1.基础信息 CentOS7.9-mini最小化安装的系统&#xff0c;在离线安装rpm时候需要大量依赖&#xff0c;需要花费大量时间去查找依赖包。受于环境限制无法接入互联网使用公开yum源&#xff0c;于是便有了搭建本机yum源的想法&#xff0c;在网上下载CentOS7.9标准版“CentOS-7-x86_…

代码随想录阅读笔记-回溯【组合】

题目 给定两个整数 n 和 k&#xff0c;返回 1 ... n 中所有可能的 k 个数的组合。 示例: 输入: n 4, k 2 输出: [ [2,4], [3,4], [2,3], [1,2], [1,3], [1,4], ] 思路 本题是回溯法的经典题目。 直接的解法当然是使用for循环&#xff0c;例如示例中k为2&#xff0c;很容…

查分约束学习

问题模型&#xff1a; 有n个变量&#xff1a;&#xff0c;有m个约束条件 令差分数组&#xff0c;可以知道如果x1x2<q&#xff0c;那么与j和i-1有关联 由画图可知&#xff0c;如果有在i-1至j建立的有向图中跑最短路&#xff0c;那么dis[n]即为最小的约束变量 另外&#x…

javaWeb车辆管理系统设计与实现

摘 要 随着经济的日益增长,车辆作为最重要的交通工具,在企事业单位中得以普及,单位的车辆数目已经远远不止简单的几辆,与此同时就产生了车辆资源的合理分配使用问题。 企业车辆管理系统运用现代化的计算机管理手段&#xff0c;不但可以对车辆的使用进行合理的管理&#xff0c;…

SpringBoot 定时任务实践、定时任务按指定时间执行

Q1. springboot怎样创建定时任务&#xff1f; 很显然&#xff0c;人人都知道&#xff0c;Scheduled(cron ".....") Q2. 如上所示创建了定时任务却未能执行是为什么&#xff1f; 如果你的cron确定没写错的话 cron表达式是否合法&#xff0c;可参考此处&#xff0c…

刷题之Leetcode59题(超级详细)

59.螺旋矩阵II 力扣题目链接(opens new window)https://leetcode.cn/problems/spiral-matrix-ii/ 给定一个正整数 n&#xff0c;生成一个包含 1 到 n^2 所有元素&#xff0c;且元素按顺时针顺序螺旋排列的正方形矩阵。 示例: 输入: 3 输出: [ [ 1, 2, 3 ], [ 8, 9, 4 ], [ …

云原生:5分钟了解一下Kubernetes是什么

在当今的云计算时代&#xff0c;容器化技术变得越来越重要。它能够帮助开发者更高效地部署和管理应用程序。而Kubernetes&#xff0c;作为容器编排领域的领军者&#xff0c;正逐渐成为企业构建和管理云原生应用的核心工具。 近期将持续为大家分享Kubernetes相关知识&#xff…

蓝桥杯 历届真题 双向排序【第十二届】【省赛】【C组】

资源限制 内存限制&#xff1a;256.0MB C/C时间限制&#xff1a;1.0s Java时间限制&#xff1a;3.0s Python时间限制&#xff1a;5.0s 改了半天只有60分&#xff0c;还是超时&#xff0c;还不知道怎么写&#xff0c;后面再看吧┭┮﹏┭┮ #include<bits/stdc.h> …

Python:如何对FY3D TSHS的数据集进行重投影并输出为TIFF文件以及批量镶嵌插值?

完整代码见 Github&#xff1a;https://github.com/ChaoQiezi/read_fy3d_tshs&#xff0c;由于代码中注释较为详细&#xff0c;因此博客中部分操作一笔带过。 01 FY3D的HDF转TIFF 1.1 数据集说明 FY3D TSHS数据集是二级产品(TSHS即MWTS/MWHS 融合大气温湿度廓线/稳定度指数/…