简单项目——前后端分离实现博客系统

news2024/11/26 1:29:02

文章目录

  • 一、项目实现的准备工作
  • 二、数据库的设计以及构建
  • 三、封装数据库连接、创建实体类
  • 四、封装数据库的增删查改操作
  • 五、实现博客系统核心操作
    • 1.获取博客列表页
    • 2.获取博客详情页
    • 3. 实现博客登录页
    • 4. 实现所有页面检查并强制登录
    • 5.退出登录状态
    • 6. 实现博客发布
    • 7. 实现删除文章操作

本篇文章 主要说明前后端之间的交互,会对代码中重点衔接部分进行解释,全部详细代码已经存放至本人的 码云 blog_System

一、项目实现的准备工作

准备工作大致分为三类:
创建项目、引入依赖、前端页面的引入。

  • 创建项目
    首先创建 Maven 项目,并且创建相应的文件夹。
    在这里插入图片描述
  • 引入依赖
    在 pom.xml 中引入 servlet、mysql、jackson 依赖。
    在 webapp 中创建 WEB-INF 其中引入 web.xml
    对于在 pom.xml 中依赖的引入,是可以在 Maven 中央仓库直接搜索即可。
    web.xml 中引入的依赖代码如下:
<!DOCTYPE web-app PUBLIC
        "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
        "http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
    <display-name>Archetype Created Web Application</display-name>
</web-app>
  • 拷贝前端代码
    在这里插入图片描述

二、数据库的设计以及构建

对博客系统的用户情况分析,这里需要两张表,分别是:用户表(User)、博客表(blog)。

分析两个表格之间的联系:
对于用户(一对多),一个用户可以写多篇博客。
对于博客(一对一),一个博客属于一个用户。

在这里插入图片描述

  • 数据库代码的编写与表的创建
-- 这个文件主要写建表语句。
-- 这里需要手动创建到数据库中
create database if not exists blog_system character set utf8;
use blog_system;

-- 删除旧表,重新创建新的表,防止之前的表残留数据影响后面的表
drop table if exists user;
drop table if exists blog;

-- 创建博客内容表
create table blog (
    blogId int primary key auto_increment,  -- 这里设置成一个自增主键
    title varchar(128),
    content varchar(4096),
    postTime datetime,
    userId int
);

-- 创建博客用户表
create table user(
    userId int primary key auto_increment,
    username varchar(20) unique,    -- 要求用户名不能重复
    password varchar(20)
);

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

三、封装数据库连接、创建实体类

  • 封装数据库连接
    在 model 文件夹中创建一个 用来封装实现 后端与数据库断开连接的类 DButil
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;

//通过这个类将数据库连接封装一下
// 此处这个类作为一个工具类,提供 static 方法供以调用
public class DBUtil {
    //静态成员跟随类对象,类对象在整个进程中只有一份
    //静态成员相当于是唯一的事例。(单例模式,饿汉模式)
    private static DataSource dataSource = new MysqlDataSource();

    //这里的代码在类加载的时间就会被创建出来
    static{
        //使用静态代码块,针对 DataSource 进行初始化
        //这里与 JDBC 有相似之处,需要将连接的信息建立起来
        // 这里的信息根据自己的不同有所修改
        ((MysqlDataSource)dataSource).setURL("jdbc:mysql://127.0.0.1:3306/blog_system?characterEncoding=utf8&useSSL=false");
        ((MysqlDataSource)dataSource).setUser("root");
        ((MysqlDataSource)dataSource).setPassword("wjh123456");
    }

    //通过这个方法来建立连接
    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }

    //通过这个方法断开连接,释放资源
    //connection    就是指连接的状态
    //statement     是指当前正在执行的 sql 语句
    //resultSet     是指当前正在获取 sql 语句执行的结果
    public static void close(Connection connection, PreparedStatement statement, ResultSet resultSet){
        // 此处的三个 try catch 分开写更好, 避免前面的异常导致后面的代码不能执行.
        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();
            }
        }
    }
}
  • 创建两个实体的对应表

blog 表

package model;

import java.sql.Timestamp;
import java.text.SimpleDateFormat;

public class Blog {
    // 这里的元素分别对应的是 数据库表中的列
    private int blogId;
    private String title;
    private String content;
    // 这里 Timestamp 接收的是 SQL 中 postTime 类型的元素
    private Timestamp postTime;
    private int userId;

//    public Timestamp getPostTime() {
//        return postTime;
//    }
public String getPostTime() {
    // 把时间戳转成 格式化 时间.
    // 这个类的用法千万不要背, 一定要去查一下.
    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
    return simpleDateFormat.format(postTime);
}

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

    public int getUserId() {
        return userId;
    }

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

    //生成 get 和 set
    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;
    }

}

这里是引用
注意这里,为了在后端读取到的数据返回到前端后出现时间乱码问题,这里对时间进行修改控制。

user表

package model;

public class User {
    private int userId;
    private String username;
    private String password;
    private int isYourBlog;

    //实现 get 和 set

    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

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 {
    // 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,?,?,?,?)";
                //将语句添加到执行方法中
            statement = connection.prepareStatement(sql);
                // 将相应字段进行替换
            statement.setString(1, blog.getTitle());
            statement.setString(2, blog.getContent());
            statement.setString(3, blog.getPostTime());
            statement.setInt(4,blog.getUserId());
            // 3. 执行 SQL 语句
                //这里是查询,所以使用的是 Update
            statement.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            // 4. 与数据库断开连接
            DBUtil.close(connection,statement,null);
        }
    }
    // 2. 根据博客的 ID 来查询指定的博客(博客详情页)
    public Blog selectById(int blogId){
        // 首先将 连接 、 填入 、 获取数据 方法 创建出来
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try {
            // 1. 实现数据库连接
            connection = DBUtil.getConnection();
            // 2. 构造 SQL 语句
            String sql = "select * from blog where blogId = ?";
                //将语句添加到执行方法中
            statement = connection.prepareStatement(sql);
            statement.setInt(1,blogId);
            // 3. 执行 SQL,并且将获取到的信息记录
            resultSet = statement.executeQuery();
            // 4. 遍历结果集合,这里与 迭代器 比较相似
                // 这里的 blogId 在 blog 表中是唯一的
                // 此时的查询结果要不是 没有,要不就是 只有唯一一条
                // 此处使用 if 进行一次判断即可 不需要 while 进行多次判断
            if (resultSet.next()) {
                Blog blog = new Blog();
                blog.setBlogId(resultSet.getInt("blogId"));
                blog.setTitle(resultSet.getString("title"));
                blog.setContent(resultSet.getString("content"));
                blog.setPostTime(resultSet.getTimestamp("postTime"));
                blog.setUserId(resultSet.getInt("userId"));
                return blog;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }   finally {
            // 5. 断开与数据库之间的连接
            DBUtil.close(connection,statement,resultSet);
        }
        // 当没有返回数据时 返回null
        return null;
    }
    // 3. 直接查询出数据库中所有的博客列表 (博客列表页)
    public List<Blog> selectAll(){
        // 创建出一个 顺序表 将查询到的博客进行存储
        List<Blog> blogs = new ArrayList<>();
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try {
            // 1. 和数据库建立连接
            connection = DBUtil.getConnection();
            // 2. 构造对应的 SQL 语句,这里需要进行全部的查找
                // 这里需要保证查找到的信息的顺序是新写的博客在上后写的在下,这里就需要将数据从大到小排列
            String sql = "select * from blog order by postTime desc";
            statement = connection.prepareStatement(sql);
            // 3. 执行对应的语句
            resultSet = statement.executeQuery();
            // 4. 遍历返回的结果集合
            while (resultSet.next()){
                // 创建出一个 空 blog 表接受当前获取到的信息
                Blog blog = new Blog();
                // 将获取到的信息 赋给新的 blog 表,并返回
                blog.setBlogId(resultSet.getInt("blogId"));
                blog.setTitle(resultSet.getString("title"));
                    //这里对正文的查询,在显示全部的博客信息时,是不需要将全部的正文信息都显示出来的
                String content = resultSet.getString("content");
                    // 这里简单判断一下,检查一下当前获取正文的长度,限定显示的范围
                if(content.length() >= 100){
                    content = content.substring(0,100) + "...";
                }
                // 这里将 截断 的正文信息进行传入
                blog.setContent(content);
                blog.setPostTime(resultSet.getTimestamp("postTime"));
                blog.setUserId(resultSet.getInt("userId"));
                // 将博客添加到顺序表
                blogs.add(blog);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            // 5. 断开与数据库的连接
            DBUtil.close(connection,statement,resultSet);
        }
        return blogs;
    }
    // 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 = ?";
            statement = connection.prepareStatement(sql);
            statement.setInt(1,blogId);
            // 3. 执行代码
            statement.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            // 4. 断开连接
            DBUtil.close(connection,statement,null);
        }
    }
}

针对 用户表 创建 UserDao

package model;// 针对 用户表 进行基本操作封装

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

// 针对用户提供基本操作
// 这里还没有实现 创建用户功能,所以这里没有 add
// 也没有用户的账号删除功能,所以这里也没有 delete 功能
public class UserDao {
    // 1. 根据 userId 来查询用户信息
    public User selectById(int userId){
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try {
            // 1,和数据库建立连接
            connection = DBUtil.getConnection();
            // 2. 构造 SQL 语句
            String sql = "select * from user where userId = ?";
            statement = connection.prepareStatement(sql);
            statement.setInt(1,userId);
            // 3. 执行 语句
            resultSet = statement.executeQuery();
            // 4. 遍历获取到的结果集合
                // 同样的 这里使用的 userId 是一个自增主键,是唯一的
            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 e) {
            e.printStackTrace();
        } finally {
            // 5. 断开和数据库的连接
            DBUtil.close(connection,statement,resultSet);
        }
        return null;
    }
    // 2. 根据 username 来进行查找用户信息
    public User selectByUsername(String username){
            Connection connection = null;
            PreparedStatement statement = null;
            ResultSet resultSet = null;
            try {
                // 1,和数据库建立连接
                connection = DBUtil.getConnection();
                // 2. 构造 SQL 语句
                String sql = "select * from user where username = ?";
                statement = connection.prepareStatement(sql);
                statement.setString(1,username);
                // 3. 执行 语句
                resultSet = statement.executeQuery();
                // 4. 遍历获取到的结果集合
                // 同样的 这里使用的 userId 是一个自增主键,是唯一的
                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 e) {
                e.printStackTrace();
            } finally {
                // 5. 断开和数据库的连接
                DBUtil.close(connection,statement,resultSet);
            }
            return null;
    }
}

五、实现博客系统核心操作

这里只解释主要核心代码实现,整体代码详见 码云!!!

在解释后面操作实现之前,这里有两点需要明确:
1、前端页面获取后端信息 使用 get 请求
2、前端页面向后端提交信息,使用 post 请求。

1.获取博客列表页

博客列表页,如图所示:
在这里插入图片描述
简单来讲,就是前端页面在加载的时候,使用 ajax 向服务器发送一个请求,服务器查询数据获取到列表,浏览器在根据数据构造页面内容

  1. 约定前后端交互接口
    首先,获取页面 ,这里就说明了需要使用到 get 请求
    在当前页面下,前端发出请求,后端返回响应!
    在这里插入图片描述
    在这里插入图片描述

  2. 后端代码开发
    当前代码位置在 BlogServlet @WebServlet(“/blog”)
    在这里插入图片描述
    如上图所示,在第一步的约定中,前后端交互是通过 ajax ,所以,后端从 数据库 中获取到 博客信息 ,并将信息组织成 json 格式的字符串发送到前端

  3. 前端代码开发
    对于前端代码,在页面加载中,就会触发 ajax , 并向后端发送 get 请求,之后,会将接收到的 json 格式字符串进行解析,并构造到前端的页面中

ajax 在接收到 json 格式字符串时,会被 jquery 识别并修改为一块一块的数组形式。此时,就可以使用 for 循环进行遍历。 大致形式如图:
在这里插入图片描述

前端代码部分展示:
在这里插入图片描述

对于这里的代码,同质度较高,基本逻辑都是:
首先构造一个 div、设置当前 div 名称、获取当前 blog 中对应的内容信息、将新建的 div 插入到整体中。

  1. 简单图示前后端交互过程:

在这里插入图片描述

2.获取博客详情页

博客详情页,如图:
在这里插入图片描述
这个页面就是我们在博客列表页时,点击 查看全文 按钮后,就会进入到当前的整片文章的页面。

  1. 约定前后端交互接口
    同样的,首先得知 获取页面 ,这里在前端构造的请求,必然是 get 请求
    在这里插入图片描述
    这里的响应同样使用 json 格式字符串进行组织。
    在这里插入图片描述

  2. 后端代码开发:
    注:当前代码仍然在 BlogServlet @WebServlet(“/blog”) 中
    在这里插入图片描述
    这里的代码逻辑就是,通过获取 前端请求访问的 博客 ID 在后端进行查找,当查找到相应的信息后,同样的构造成 json 格式字符串返回到前端中。

  3. 前端页面开发:
    在这里插入图片描述
    如图,这些代码构成博客详情页面中,对应信息的空间位置。
    在这里插入图片描述
    同样的,这里构造出 ajax 请求,在获取到后端信息后,将对应的信息分别存放在对应的位置

注意:
问题一:
在上述前端代码中,红色标注的 url 中的 location.search 这是前端获取当前导航栏中 “?” 后的全部信息。即就是 queryString。如图:
在这里插入图片描述
由于后端需要向前端反馈详细的博客页面,这个 blogId 是必须的。
问题二:
这个 blogId 是从哪里来的?为什么点击 “显示全文” 按钮就会有 queryString
其实这里的 blogId 信息之所以存在,就是在博客列表页的前端代码中(blog_list.html),早就已经添加进去了,如图:
在这里插入图片描述

  1. 简单图示前后端交互过程
    在这里插入图片描述

3. 实现博客登录页

在这里插入图片描述
如上图所示,这就是一个登录窗口。
这里的实现思路就是,用户在前端输入对应的信息,将信息传递到后端后,后端通过在数据库的查询,以此来判断当前的用户是否存在并进行登录。

  1. 约定前后段交互接口
    这里,我们可以明确的知道,此处是将信息从前端 发送 到后端进行判断的。对此,此处的请求属于 post 请求。
    在这里插入图片描述
    在这里插入图片描述
  2. 展示前端代码
    需要注意的是,在通过上面的分析,我们发现,首先,这里构造的是 post 请求。其次,这个请求最终的相应是要实现页面跳转的。
    对此,这里需要使用 from 表单ajax 构造请求只能构造 get 请求!!!
    部分代码如下:
    在这里插入图片描述

使用抓包工具观察其工作形式
如图:
在这里插入图片描述
如图所示,在登录框中输入的 “用户名”、“密码” 这两个信息,会在点击提交时,被构造在 post 请求的 body 中并传递到后端。

  1. 后端核心代码展示
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 这里为了防止从浏览器获取到的信息中的汉字出现乱码,所以这里需要设置字符集
        req.setCharacterEncoding("utf8");
        //resp.setCharacterEncoding("utf8");
        // 这里设置响应
        resp.setContentType("text/html; charset=utf8");
        // 1,读取参数中的用户名和密码
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        if(username == null || "".equals(username) || password == null || "".equals(password)){
            // 对登录失败的情况做出响应
            String html = "<h3>登录失败!!!缺少 password 或 username 字段<h3>";
            resp.getWriter().write(html);
            return;
        }
        // 2. 读取数据库,看用户是否存在,并且是否匹配
        UserDao userDao = new UserDao();
            // 通过用户名进行查询
        User user = userDao.selectByUsername(username);
        if(user == null){
            // 用户名错误
            String html = "<h3>登录失败!!!用户名或者密码错误<h3>";
            resp.getWriter().write(html);
            return;
        }
        if(!password.equals(user.getPassword())){
            // 密码错误
            String html = "<h3>登录失败!!!用户名或者密码错误<h3>";
            resp.getWriter().write(html);
            return;
        }
        // 3. 用户登陆验证成功,此时创建出一个会话,以此来维持用户的登录状态
        HttpSession session = req.getSession(true);
            // 将用户的所有信息存储到当前的 Session 内部的键值对中
        session.setAttribute("user",user);
        // 4. 进行重定向,定向到博客列表页
        resp.sendRedirect("blog_list.html");
    }

如上述代码所示,此处使用的是 doPost 方法

解释重点逻辑代码在这里插入图片描述
如上图所示,这是在经过一系列判断后,确定了用户可以登陆的操作。 这里就运用到了 Session 和 cookie 这两个东西。
这里是首次登录,就新写入一个 session 用来记录当前用户登录信息
在这里插入图片描述
这个操作,就是将当前 以 user 信息的键值对构造的 session 对象,再以 user 命名组成一个新的键值对
通过抓包观察 响应在这里插入图片描述
对于cookie 和 Session 之间的工作原理不太清楚的 可以看看本人的这篇文章:介绍 HTTPServlet 三部分使用与 cookie 和 session 的阐述

4. 实现所有页面检查并强制登录

实现页面强制要求登录,即就是:当用户访问 博客列表页 / 详情页 / 编辑页 要求用户必须是已经登录的状态!!
若没登录,就需要强制跳转到登录页面。

我们简单思考一下,这里的检查登录状态,其实就是在检查当前 cookie 中的 SessionID 与后端存储的是否匹配

  1. 约定前后端交互接口
    根据上述的分析,我们可以发现,要判断当前用户是否已经登录,前端需要向后端请求对应的 session 来判断情况。所以,这里需要使用 ajax 来构造 get 请求。
    在这里插入图片描述

  2. 后端代码实现
    在这里插入图片描述
    在上面的代码中,通过多次判断,在最终美好获取到 key 为 ‘user’ value 为 user 的信息
    将这个信息构建为 json 格式字符串之后传递给前端进行分析。

  3. 实现前端代码
    在这里插入图片描述
    如图所示,前端代码中最核心的就是这个 userID 信息。在数据库中,用户的 id 是设定为 从1开始。 因此,这里就只需要判断当前 userId 是否大于 0 即可!

这里的前端代码,直接根据需要放到对应的前端代码中即可。
切记!! 一定要调用对应的方法!
在这里插入图片描述

  1. 结合抓包信息解释前后端交互
  • 尝试直接获取博客列表页
    观察抓包情况如下:
    在这里插入图片描述

  • 当我们进行登陆之后,在进行页面的跳转
    抓包情况和代码共同分析:
    在这里插入图片描述

5.退出登录状态

对于退出登录状态,也就是 注销
要实现注销(也就是要判断登陆状态),大致思路如下:
1.看是否可以获取到 HTTP session 对象。
2.看 session 对象中是否存在着 user。
3.当 user 对象存在,将其删除。此时就会产生有 会话没有user 的情况。 这样也就是视为没有登陆。

  1. 约定前后端交互接口
    通过上面的分析,这里的操作是要删除 Session 并且将页面跳转到登录界面
    所以,这里是一个 get 请求。

这里只需要后端进行删除并跳转,前端页面不需要修改信息。根据上面的情况,这里使用 a 标签对后端代码进行引导即可!

在这里插入图片描述

  1. 前端代码修改
    在这里插入图片描述
    如图,这里就是在前端页面添加一个 a 标签,引导到后端代码中。

  2. 后端代码展示
    在这里插入图片描述
    如上图所示,就实现了退出登录的操作。

6. 实现博客发布

  1. 约定前后端交互接口
    这里的博客发布操作,总的来看就是要向后端发送信息,在后端实现保存,所以这里是 post 请求,使用的是 from 表单。
    在这里插入图片描述

  2. 实现前端代码
    在这里插入图片描述
    使用 post 请求 在 url 中构造出 queryString 交给后端读取并将内容保存到数据库中。

  3. 实现后端代码
    在这里插入图片描述
    到这里,发布博客的操作就实现完成了。

7. 实现删除文章操作

要实现删除文章的基本操作,思路还是比较简单的。
前端: 删除操作是在博客详情页发生的事情。前端在这里不需要修改前端页面信息,这里使用一个 a 标签导向到后端即可。
需要注意这里要将当前 blogId 传递到后端。

后端: 这里要删除需要多次核对信息。
1.首先获取到当前登录用户的信息(非文章作者不能删除)
2.在获取到当前博客 Id(通过当前博客Id查询作者Id)
3.核对当前作者 Id 信息。
4.实现删除并重定向到列表页。

  1. 约定前后端交互接口
    根据上面的分析,这里需要的是获取到后端的一个响应,不需要提交信息。所以这里使用 get 请求
    在这里插入图片描述
    在这里插入图片描述

  2. 实现前端代码
    在这里插入图片描述
    如上图所示,前端代码的实现是比较简单的,只需要对后端代码的定向设定即可

  3. 实现后端代码
    在这里插入图片描述

到这里,博客系统这个项目整体已经实现完毕,感谢各位的浏览。

码字不易,小小的点赞是对我最大的鼓励。

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

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

相关文章

线上观看人次2万+!「飞天技术沙龙-CentOS 迁移替换专场」北京站圆满结束

5 月 29 日&#xff0c;阿里云联合龙蜥社区共同举办的「飞天技术沙龙-CentOS 迁移替换专场」于北京圆满结束&#xff0c;在线观看人次 2 万。本次活动现场汇聚了来自浪潮信息、Intel、龙芯、统信软件、红旗软件、电子五所等多家操作系统产业头部企业和机构&#xff0c;大家围绕…

零基础非科班也能掌握的C语言知识21 编译链接(介于作者实力有限并且没有可以演示的过程软件仅仅浅谈)

编译链接 1.翻译环境和运行环境2.翻译环境2.1 编译2.1.1 预处理&#xff08;预编译&#xff09;2.1.2 编译2.1.3 汇编 2.2 链接 3.运行环境 1.翻译环境和运行环境 在ANSI C的任何⼀种实现中&#xff0c;存在两个不同的环境。 编译环境运行环境 2.翻译环境 翻译环境由编译和…

极氪汽车交出上市首份答卷:业绩交付“双开花”,新车型质量保优

近日&#xff0c;极氪汽车&#xff08;NYSE&#xff1a;ZK&#xff0c;下同“极氪”&#xff09;发布2024年第一季度财报&#xff0c;这也是该公司自5月20日登陆美股以来对外披露的首份业绩报告。 极氪汽车是继“蔚小理”之后第四家在美国上市的新能源车企&#xff0c;发布至今…

图形学初识--定义摄像机类(实战)

文章目录 前言正文定义摄像机的操作方式键盘操作鼠标操作 定义摄像机类核心数据视图矩阵回顾&#xff1a;模拟摄像机的移动模拟摄像机的旋转 结尾&#xff1a;喜欢的小伙伴点点关注赞哦! 前言 前面一些章节讲解了图形学的比较原理性的内容&#xff0c;这一章节咱就实战一下&am…

监控登录用户数

检查登录用户数 当登录系统用户数超过3个报警&#xff0c;并发送邮件提示 首先&#xff0c;配置发送邮件功能。 1、安装mailx [rootnode1 ~]# yum install mailx2、配置/etc/mail.rc [rootnode1 ~]# vim /etc/mail.rc set fromxxx163.com #发件人地址 set smtpsmtp.163…

深层网络:层数多真的更好吗?

深层网络&#xff1a;层数多真的更好吗&#xff1f; 在深度学习的世界里&#xff0c;"深度"始终是一个热门话题。随着技术的发展&#xff0c;我们有了越来越多的方法来构建更深的神经网络&#xff0c;这似乎暗示着“层数越多&#xff0c;效果越好”。然而&#xff0…

通用大模型与垂直大模型:双轨并进的人工智能未来

在人工智能(AI)的浩瀚宇宙中&#xff0c;大模型以其强大的学习能力和广泛的适用性&#xff0c;正逐步成为推动技术进步和产业革新的核心动力。在这股浪潮中&#xff0c;通用大模型与垂直大模型如同两颗璀璨的星辰&#xff0c;各自散发着独特的光芒&#xff0c;共同照亮了AI发展…

哪个品牌洗地机专业?四款明星精湛产品集结

当代快节奏的生活&#xff0c;人们每天下班回到家只想瘫倒在沙发&#xff0c;打扫卫生成为了一种负担......但洗地机的出现&#xff0c;大大的减轻了人们地板清洁的焦虑&#xff0c;因为它只需轻轻地推拉机子转悠房屋一圈&#xff0c;地面上的赃污便能清理干净&#xff0c;清洁…

如何优化大屏网站的响应式设计?技巧一览

为了显示不同屏幕尺寸设备的显示效果&#xff0c;有必要优先考虑响应设计&#xff0c;因为开发人员可以在不同的设备中构建应用程序。响应设计是一种灵活的设计&#xff0c;可以兼顾多屏幕和多场景&#xff0c;可以使我们的网页布局在各种屏幕下呈现出更好的效果。今天&#xf…

“JS加密在线”:简单直接的在线JS加密网站

网站名&#xff1a;“JS加密在线”&#xff0c; 功能&#xff1a;JavaScript源代码加密。 UI&#xff1a; http://jsjiami.online/ 非常简洁的JS加密网站&#xff0c;几乎只有两个功能&#xff1a;上传JS文件、下载加密后的JS文件。 JS加密&#xff0c;就应该这样简单直接。…

Splashtop 荣获“2024年安全校园白金奖”

2024年6月12日 加利福尼亚州库比蒂诺 作为远程访问和 IT 支持领域的领先企业&#xff0c;Splashtop 很荣幸地宣布获得“2024年安全校园白金奖”。Splashtop 的 Foxpass Cloud RADIUS 解决方案在专注校园安全的重要杂志《今日校园安全》颁发的访问控制和云端管理类别奖项中荣获…

Hyper-V 安装Win11注意事项

1. 安装前检查设置&#xff0c;勾选TPM2. 启动的时候要一直按F2&#xff0c;否则提示找不到系统镜像 3. 安装完成后开机后在查看里取消增强会话&#xff0c;否则开机进入锁屏界面&#xff0c;无法输入密码进入系统。一般这种情况出现在通过微软账户登录的系统&#xff0c;可首…

CG-85C 振弦式土压力计厂家 结构物内部土压力变化量如何测量?

产品概述 振弦式土压力计由背板、感应板、信号传输电缆、振弦及激振电磁线圈等组成&#xff0c;是了解被测结构物内部土压力变化量、并可同步测量埋设点温度的监测设备。 功能特点 ◆精度高&#xff0c;能够提供准确的测量结果。 ◆稳定性好&#xff0c;不易受到外界因素的…

后端开发面经系列 -- 小鹏汽车一面面经

小鹏汽车一面面经 公众号&#xff1a;阿Q技术站 来源&#xff1a;职言详情页 (maimai.cn) 文章目录 小鹏汽车一面面经1、String类型为什么不可变&#xff1f;1. 安全性2. 缓存和性能优化3. 哈希码缓存4. 类设计和接口5. 简单性和可读性 2、在浏览器中输入url地址到显示主页的过…

Anti-ABCD3 Antibody-Monoclonal Antibody against Human ABCD3

本篇是对Atlas生产的Anti-ABCD3 Antibody的简单介绍&#xff0c;如需购买该产品或了解更多产品详情&#xff0c;可联系一级代理商欣博盛生物。 产品名称&#xff1a;Anti-ABCD3 Antibody 品牌&#xff1a;Atlas antibodies 货号&#xff1a;AMAb90995 规格&#xff1a;100ul…

大模型「训练」与「微调」概念详解【6000字长文】

本文你将学到什么 1、大模型预训练与微调的基本流程 2、预训练、训练、后期预训练、微调的区别 3、大模型训练与微调的一些概念&#xff0c;如&#xff1a; Post-pretrain、SFT、RLHF、模型对齐、Lora、Q-Lora、大模型量化、微调指标、微调参数、大模型评测指标 预训练与微…

AI Agent 热门的10篇论文

人工智能代理领域广阔,涵盖广泛的主题,包括多代理系统、强化学习、上下文感知系统以及将大型语言模型 (LLMs) 集成到基于代理的系统中。以下是 arXiv 的一些顶级论文,涵盖了人工智能代理的各个方面: A Framework For Intelligent Multi Agent System Based Neural Network …

[深度学习]使用python转换pt并部署yolov10的tensorrt模型封装成类几句完成目标检测加速任务

【简单介绍】 使用Python将YOLOv10模型从PyTorch格式&#xff08;.pt&#xff09;转换为TensorRT格式&#xff0c;并通过封装成类来实现目标检测加速任务&#xff0c;是一个高效且实用的流程。以下是该过程的简要介绍&#xff1a; 模型转换&#xff1a; 利用官方提供导出命令…

69. UE5 RPG 使用Gameplay Cue 实现技能表现效果

在上一章中&#xff0c;我们实现了敌人的攻击技能的特效和音效。如果我们在多人模式下打开&#xff0c;发现&#xff0c;其它客户端看不到对应的效果。 造成这种问题的原因是因为敌人的技能是运行在服务器端的&#xff0c;它只复制到拥有它的客户端&#xff0c;而敌人的效果对于…

2024最新流媒体在线音乐系统网站源码 音乐社区 多语言开心版

本文选自&#xff1a;2024最新流媒体在线音乐系统网站源码 音乐社区 多语言开心版 - 源码1688 应用介绍 简介&#xff1a; 2024最新流媒体在线音乐系统网站源码| 音乐社区 | 多语言 | 开心版 图片&#xff1a;