当前位置: 首页 > news >正文

Docker一键部署项目,无需登录XShell

文章目录

  • 一键部署项目
    • Docker手动部署SpringBoot项目
      • 编写docker部署的脚本文件
        • script.sh 脚本内容
      • 特别注意!
      • 编写dockerfile
        • dockerfile 文件内容
      • 上传后端服务的jar包到服务器中
      • 执行 script 脚本部署后端服务
    • 自动部署SpringBoot项目
      • 引入jsch依赖
      • 编写jsch工具类
      • 执行部署命令
    • Docker手动部署Vue项目
      • 编写docker部署的脚本文件
        • script.sh 脚本内容
      • 编写dockerfile
        • dockerfile文件内容
      • 编写nginx配置文件
        • nginx配置文件内容
      • 上传前端服务的打包文件到服务器
      • 执行 script 脚本部署前端服务
      • 访问 ip:9002 查看是否运行成功
    • 自动部署Vue项目
      • 工具类(慎重!包含服务器的删除操作!)
      • main 函数
  • 总结

一键部署项目

Git仓库地址!

我们每次部署项目都需要手动传输 jar 包,或者前端打包好的文件到服务器上,再连接服务器执行部署脚本,为了省去这个步骤,我们直接借助 jsch 包,来通过执行一个方法,就可以将打包好的文件上传至服务器,并且自动执行部署脚本。

Docker手动部署SpringBoot项目

编写docker部署的脚本文件

cd / # 进入根目录
mkdir develop/docker-deploy # 创建两级目录
cd develop/docker-deploy
vi script.sh # 编写部署脚本chmod +x ./script.sh # 授予脚本文件可执行的权限

script.sh 脚本内容

特别注意!

在 script.sh 脚本文件中,docker build 命令使用 -f 参数指定 dockerfile 文件的路径,并且指定docker镜像构建的上下文

  • dockerfile 文件路径为 /develop/docker-deploy/dockerfile

  • 指定 docker 镜像构建上下文目录为 /develop/docker-deploy/

那么在镜像构建的时候,就会把当前服务器的 /develop/docker-deploy/目录下的所有文件都发送给 docker 的守护进程。

在构建的时候会去执行 dockerfile 中的命令,在 dockerfile 中,ADD <src> <dest> 将 src 文件复制到容器的 dest 中,这里的 src 只能使用相对路径,相对的就是构建镜像的上下文,即 /develop/docker-deploy/ 目录。

我们后边使用 jsch 进行自动化部署时,由于 jsch 无法执行 cd 命令,不能切换路径,因此都需要通过绝对路径来指定docker的构建环境!

#!/bin/bash#构建docker镜像
echo "========================================正在构建镜像================================="
# -f 指定dockerfile文件  docker build最后边的参数不可以使用. 如果在其他目录执行该脚本文件
# 就会把执行脚本文件的目录当作构建镜像的上下文传送给docker的守护进程,那么在dockerfile中通过add添加的文件
# 都是以相对路径添加的,那么就会出现找不到文件的情况
docker build -t docker-deploy:01 -f /develop/docker-deploy/dockerfile /develop/docker-deploy/ # 停止并删除容器
echo "========================================正在删除容器================================="
docker stop docker-deploy
docker rm docker-deploy# 运行容器
echo "========================================正在创建新容器================================="
docker run --name docker-deploy -p 9001:9001 -d docker-deploy:01

编写dockerfile

cd develop/docker-deploy
vi dockerfile # 编写 dockerfile,如下

dockerfile 文件内容

#基础镜像
FROM openjdk:8-jdk-alpine
#作者
MAINTAINER abc
#执行命令,主要用来安装相关的软件
#RUN
# ADD将文件复制到镜像中
ADD Docker-Deploy-0.0.1-SNAPSHOT.jar /usr/local 
RUN chmod u+x /usr/local/Docker-Deploy-0.0.1-SNAPSHOT.jar # 给当前目录下的test.py文件所有者添加执行权限
#挂载目录到容器
#VOLUME ["/data"]
#环境变量设置
#ENV #开放端口
EXPOSE 9001
#启动时执行的命令
CMD ["/bin/bash"]
#启动时执行的命令
ENTRYPOINT ["java","-jar","/usr/local/Docker-Deploy-0.0.1-SNAPSHOT.jar"]

上传后端服务的jar包到服务器中

最后目录如下:

在这里插入图片描述

执行 script 脚本部署后端服务

/develop/docker-deploy/script.sh # 测试绝对路径执行脚本

显示结果如下,表示执行成功

在这里插入图片描述

使用 docker ps 查看是否部署 docker 镜像成功

在这里插入图片描述

那么,手动部署没问题了,我们就可以通过 Java 的 jsch 包来实现不需要去服务器就可以进行部署项目。

自动部署SpringBoot项目

引入jsch依赖

<!--    jsch	-->
<dependency><groupId>com.jcraft</groupId><artifactId>jsch</artifactId><version>0.1.54</version>
</dependency>

编写jsch工具类

package com.example.jschquickdeploy.utils;import com.jcraft.jsch.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;/*** @author 千祎来了* @date 2023/8/7 15:08*/
public class ShellCommandExecution {private static final Logger logger = LoggerFactory.getLogger(ShellCommandExecution.class);public static Session getSession(String username, String password, String host, int port) {// 创建JSch对象JSch jSch = new JSch();Session jSchSession = null;try {// 根据主机账号、ip、端口获取一个Session对象jSchSession = jSch.getSession(username, host, port);// 存放主机密码jSchSession.setPassword(password);Properties config = new Properties();// 去掉首次连接确认config.put("StrictHostKeyChecking", "no");jSchSession.setConfig(config);// 超时连接时间为3秒jSchSession.setTimeout(3000);// 进行连接jSchSession.connect();} catch (Exception e) {logger.warn(e.getMessage());}return jSchSession;}/*** 下载文件,将 sourceFile 文件下载至 destinationFile* @param jSchSession* @param sourceFile* @param destinationFile* @throws Exception*/public static void downloadFiles(Session jSchSession, String sourceFile, String destinationFile) throws Exception {// Opening an SFTP ChannelChannelSftp chSftp = (ChannelSftp)jSchSession.openChannel("sftp");// Example Establish a connection to the SFTP channelchSftp.connect();// Set encoding formatchSftp.setFilenameEncoding("UTF-8");/*** 说明:* 1、当前上读取文件信息没有任何反馈,如果没有异常则代表成功* 2、如果需要判断是否读取成功的进度,可参考https://blog.csdn.net/coding99/article/details/52416373?locationNum=13&fps=1* 3、将src文件下载到dst路径中*/chSftp.get(sourceFile, destinationFile);logger.info("download file " + sourceFile + " success,location is:" + destinationFile);}/*** 将 sourceFile 上传至 destinationFile* @param jSchSession* @param sourceFile* @param destinationFile*/public static void uploadFiles(Session jSchSession, String sourceFile, String destinationFile) throws Exception{// Opening an SFTP ChannelChannelSftp chSftp = (ChannelSftp)jSchSession.openChannel("sftp");// Example Establish a connection to the SFTP channelchSftp.connect();// Set encoding formatchSftp.setFilenameEncoding("UTF-8");/*** 说明:* 1、当前上读取文件信息没有任何反馈,如果没有异常则代表成功* 2、如果需要判断是否读取成功的进度,可参考https://blog.csdn.net/coding99/article/details/52416373?locationNum=13&fps=1* 3、将src文件下载到dst路径中*/chSftp.put(sourceFile, destinationFile);logger.info("upload file " + sourceFile + " success,location is:" + destinationFile);}/*** 执行命令* @param command* @param jSchSession* @return* @throws Exception*/public static StringBuffer execCommand(String command, Session jSchSession) throws Exception{Channel exec = null;StringBuffer result = new StringBuffer();try {exec = jSchSession.openChannel("exec");((ChannelExec) exec).setCommand(command);exec.setInputStream(null);// 错误信息输出流,用于输出错误的信息,当exitstatus<0的时候((ChannelExec) exec).setErrStream(System.err);// 执行命令,等待结果exec.connect();// 获取命令执行结果InputStream in = exec.getInputStream();// 推出状态码int exitStatus = 0;/*** 通过channel获取信息的方式,采用官方Demo代码*/byte[] tmp = new byte[1024];while (true) {while (in.available() > 0) {int i = in.read(tmp, 0, 1024);if (i < 0) {break;}result.append(new String(tmp, 0, i));}// 从channel获取全部信息之后,channel会自动关闭if (exec.isClosed()) {if (in.available() > 0) {continue;}exitStatus = exec.getExitStatus();break;}try {Thread.sleep(1000);} catch (Exception ee) {}}logger.info("命令:【" + command + "】的执行结果为:" + result);// 如果状态码不是0,则表示执行失败if (exitStatus != 0) {logger.error("状态码为:" + exitStatus + ",命令执行失败:" + result);throw new Exception("命令:【" + command + "】执行失败,执行结果为:" + result);}} finally {// 关闭 jschChannel 流if (exec != null && exec.isConnected()) {exec.disconnect();}}return result;}
}

执行部署命令

在 main 方法中,只需要做2件事就可以一键部署了:

  1. 将我们使用 maven 工具打包好的 jar 包的路径上传到服务器指定目录
  2. 调用服务器上的执行脚本即可

注意:这里执行需要使用绝对路径,在 jsch 中无法使用 cd 命令

package com.example.jschquickdeploy.utils;import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.util.Properties;/*** @author 千祎来了* @date 2023/8/9 21:43*/
public class QuickDeploy {private static final Logger logger = LoggerFactory.getLogger(ShellCommandExecution.class);public static void main(String[] args) {/*** 连接服务器*/String username = "root";String password = "123456";String host = "127.0.0.1";int port = 2222;Session jSchSession = null;try {jSchSession = ShellCommandExecution.getSession(username, password, host, port);/*** 上传 jar 包到服务器*/ShellCommandExecution.uploadFiles(jSchSession, "D:\\Project\\IDEA\\Docker-Deploy\\target\\Docker-Deploy-0.0.1-SNAPSHOT.jar", "/develop/docker-deploy");/*** 执行部署命令*/ShellCommandExecution.execCommand("/develop/docker-deploy/script.sh", jSchSession);/*** 查看镜像*/ShellCommandExecution.execCommand("docker ps", jSchSession);} catch (Exception e) {logger.warn(e.getMessage());} finally {// close jschSesson streamif (jSchSession != null && jSchSession.isConnected()) {jSchSession.disconnect();}}}
}

Docker手动部署Vue项目

编写docker部署的脚本文件

cd /develop # 进到部署对应目录
mkdir docker-deploy-front # 创建前端部署目录
cd docker-deploy-front
vi script.sh # 编写部署脚本
chmod +x ./script.sh # 授予脚本执行权限

script.sh 脚本内容

#!/bin/bashecho "========================================正在构建镜像================================="
docker build -t docker-deploy-front:1.0 -f /develop/docker-deploy-front/dockerfile /develop/docker-deploy-front/# 停止并删除容器
echo "========================================正在删除容器================================="
docker stop docker-deploy-front
docker rm docker-deploy-front# 运行容器
echo "========================================正在创建新容器================================="
docker run --name docker-deploy-front -d -p 9002:80  docker-deploy-front:1.0
~                                                                                    

编写dockerfile

vi dockerfile

dockerfile文件内容

# 设置基础镜像,这里使用最新的nginx镜像,前面已经拉取过了
FROM nginx
#作者
MAINTAINER abc
#执行命令,主要用来安装相关的软件
RUN rm /etc/nginx/conf.d/default.conf
# 将 nginx 配置文件复制到镜像中
ADD default.conf /etc/nginx/conf.d/ #添加文件
#将dist文件中的内容复制到 /usr/share/nginx/html/ 这个目录下面
#容器内nginx默认的html文件目录为 /usr/share/nginx/html/
COPY dist/  /usr/share/nginx/html/

编写nginx配置文件

vi default.conf

nginx配置文件内容

server {listen       80;listen  [::]:80;server_name  localhost;location / {root   /usr/share/nginx/html;index  index.html index.htm;try_files $uri $uri/ /index.html;}error_page   500 502 503 504  /50x.html;location = /50x.html {root   /usr/share/nginx/html;}
}

上传前端服务的打包文件到服务器

进入 vue 项目根目录,调用 npm run build 打包前端项目,生成 dist 文件夹

最后,前端需要的所有文件如下:

在这里插入图片描述

执行 script 脚本部署前端服务

执行 ./script 即可

/develop/docker-deploy-front/script # 执行脚本
docker ps # 查看docker容器是否启动成功

访问 ip:9002 查看是否运行成功

http://localhost:9002/ (我这里是本地,服务器要加上服务器ip)

在这里插入图片描述

自动部署Vue项目

这里使用的项目和自动部署后端项目使用的是同一个项目,因此依赖和工具类不需要重新引入

由于自动部署后端代码时,上传的只有一个 jar 包,因此上传功能比较好些,但是 vue 项目打包生成的是 dist 目录,因此需要给工具类添加上传目录的方法,如下:

工具类(慎重!包含服务器的删除操作!)

拿到工具类之后,不要立即执行在,将路径换为自己服务器上的路径再执行!以免误删文件!

uploadDir 方法中有一个删除操作,删除的是服务器上已经存在的打包的目录,也就是服务器上的 dist 文件夹所在目录!

相较于后端部署时,多添加了一个 uploadDir 方法,用于上传一整个目录

该方法中使用递归去遍历文件,因为 jsch 中并没有直接上传目录的操作,因此需要我们自己去遍历目录,并上传每一个文件

package com.example.jschquickdeploy.utils;import com.jcraft.jsch.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Objects;
import java.util.Properties;/*** @author 千祎来了* @date 2023/8/7 15:08*/
public class ShellCommandExecution {private static final Logger logger = LoggerFactory.getLogger(ShellCommandExecution.class);private static Session jSchSession = null;public static Session getSession(String username, String password, String host, int port) {// 创建JSch对象JSch jSch = new JSch();Session jSchSession = null;try {// 根据主机账号、ip、端口获取一个Session对象jSchSession = jSch.getSession(username, host, port);// 存放主机密码jSchSession.setPassword(password);Properties config = new Properties();// 去掉首次连接确认config.put("StrictHostKeyChecking", "no");jSchSession.setConfig(config);// 超时连接时间为3秒jSchSession.setTimeout(3000);// 进行连接jSchSession.connect();ShellCommandExecution.jSchSession = jSchSession;} catch (Exception e) {logger.warn(e.getMessage());}return jSchSession;}/*** 下载文件,将 sourceFile 文件下载至 destinationFile* @param sourceFile* @param destinationFile* @throws Exception*/public static void downloadFiles(String sourceFile, String destinationFile) throws Exception {// Opening an SFTP ChannelChannelSftp chSftp = (ChannelSftp)jSchSession.openChannel("sftp");// Example Establish a connection to the SFTP channelchSftp.connect();// Set encoding formatchSftp.setFilenameEncoding("UTF-8");/*** 说明:* 1、当前上读取文件信息没有任何反馈,如果没有异常则代表成功* 2、如果需要判断是否读取成功的进度,可参考https://blog.csdn.net/coding99/article/details/52416373?locationNum=13&fps=1* 3、将src文件下载到dst路径中*/chSftp.get(sourceFile, destinationFile);logger.info("download file " + sourceFile + " success,location is:" + destinationFile);}/*** 将 sourceDir 目录下的所有文件上传至 destinationDir 目录下* 假设 sourceDir = "D:\Project\IDEA\Docker-Quick-Deploy\docker-deploy-front\dist"* destinationDir = "/develop/docker-deploy-front"* 那么该方法将 dist 目录所有文件都传输至 /develop/docker-deploy-front/dist 目录中* @param sourceDir* @param destinationDir* @throws Exception*/public static void uploadDir(String sourceDir, String destinationDir) throws Exception{// Opening an SFTP ChannelChannelSftp chSftp = (ChannelSftp)jSchSession.openChannel("sftp");// Example Establish a connection to the SFTP channelchSftp.connect();// Set encoding formatchSftp.setFilenameEncoding("UTF-8");// 文件夹名称String dirName = sourceDir.substring(sourceDir.lastIndexOf("\\") + 1);String linuxRootDir =  destinationDir + "/" + dirName;String windowsRootDir =  sourceDir;execCommand("rm -rf " +  linuxRootDir);logger.info("删除文件夹" + linuxRootDir);execCommand("mkdir " +  linuxRootDir);logger.info("创建文件夹" + linuxRootDir);/*** 将 sourceDir 目录下的文件传输至 targetDir*/transFile(chSftp, sourceDir, windowsRootDir, linuxRootDir);}/*** 递归传输文件** @param chSftp* @param sourceDir* @param windowsRootDir* @param linuxRootDir* @throws IOException* @throws SftpException*/private static void transFile(ChannelSftp chSftp, String sourceDir, String windowsRootDir, String linuxRootDir) throws Exception {File root = new File(sourceDir);for (File file : Objects.requireNonNull(root.listFiles())) {if (file.isFile()) {Path src = Paths.get(file.getPath());String des = file.getPath().replace(windowsRootDir, linuxRootDir).replace("\\", "/");file.getPath().replace(windowsRootDir, "");logger.info("上传源文件:" + src.toString() + "到目的文件:" + des);chSftp.put(Files.newInputStream(src), des);} else if (file.isDirectory()) {String dirName = file.getPath().replace(windowsRootDir, linuxRootDir).replace("\\", "/");execCommand("mkdir " + dirName);logger.info("创建文件夹:" + dirName);transFile(chSftp, file.getPath(), windowsRootDir, linuxRootDir);}}}/*** 将 sourceFile 上传至 destinationFile* @param sourceFile 必须为文件* @param destinationFile*/public static void uploadFiles(String sourceFile, String destinationFile) throws Exception{ChannelSftp chSftp = null;try {// Opening an SFTP ChannelchSftp = (ChannelSftp)jSchSession.openChannel("sftp");// Example Establish a connection to the SFTP channelchSftp.connect();// Set encoding formatchSftp.setFilenameEncoding("UTF-8");/*** 说明:* 1、当前上读取文件信息没有任何反馈,如果没有异常则代表成功* 2、如果需要判断是否读取成功的进度,可参考https://blog.csdn.net/coding99/article/details/52416373?locationNum=13&fps=1* 3、将src文件下载到dst路径中*/chSftp.put(sourceFile, destinationFile, ChannelSftp.OVERWRITE);logger.info("upload file " + sourceFile + " success,location is:" + destinationFile);} finally {// 关闭 jschChannel 流if (chSftp != null && chSftp.isConnected()) {chSftp.disconnect();}}}/*** 执行命令* @param command* @return* @throws Exception*/public static StringBuffer execCommand(String command) throws Exception{Channel exec = null;StringBuffer result = new StringBuffer();try {exec = jSchSession.openChannel("exec");((ChannelExec) exec).setCommand(command);exec.setInputStream(null);// 错误信息输出流,用于输出错误的信息,当exitstatus<0的时候((ChannelExec) exec).setErrStream(System.err);// 执行命令,等待结果exec.connect();// 获取命令执行结果InputStream in = exec.getInputStream();// 推出状态码int exitStatus = 0;/*** 通过channel获取信息的方式,采用官方Demo代码*/byte[] tmp = new byte[1024];while (true) {while (in.available() > 0) {int i = in.read(tmp, 0, 1024);if (i < 0) {break;}result.append(new String(tmp, 0, i));}// 从channel获取全部信息之后,channel会自动关闭if (exec.isClosed()) {if (in.available() > 0) {continue;}exitStatus = exec.getExitStatus();break;}try {Thread.sleep(1000);} catch (Exception ee) {}}logger.info("命令:【" + command + "】的执行结果为:" + result);// 如果状态码不是0,则表示执行失败if (exitStatus != 0) {logger.error("状态码为:" + exitStatus + ",命令执行失败:" + result);throw new Exception("命令:【" + command + "】执行失败,执行结果为:" + result);}} finally {// 关闭 jschChannel 流if (exec != null && exec.isConnected()) {exec.disconnect();}}return result;}
}

main 函数

package com.example.jschquickdeploy.utils;import com.jcraft.jsch.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;/*** @author 千祎来了* @date 2023/8/10 9:51*/
public class QuickDeployFront {private static final Logger logger = LoggerFactory.getLogger(ShellCommandExecution.class);public static void main(String[] args) {/*** 连接服务器*/String username = "root";String password = "123456";String host = "127.0.0.1";int port = 2222;Session jSchSession = null;try {jSchSession = ShellCommandExecution.getSession(username, password, host, port);/*** 上传 Vue 打包文件到服务器*/ShellCommandExecution.uploadDir(jSchSession, "D:\\Project\\IDEA\\Docker-Quick-Deploy\\docker-deploy-front\\dist", "/develop/docker-deploy-front");/*** 执行部署命令*/ShellCommandExecution.execCommand("/develop/docker-deploy-front/script.sh", jSchSession);/*** 查看镜像*/ShellCommandExecution.execCommand("docker ps", jSchSession);} catch (Exception e) {logger.warn(e.getMessage());} finally {// close jschSesson streamif (jSchSession != null && jSchSession.isConnected()) {jSchSession.disconnect();}}}
}

总结

这样一键部署项目就完成了,部署步骤如下:

后端部署:

  1. 对 springboot 项目打成 jar 包
  2. 在方法中指定 jar 包位置和上传服务器位置
  3. 在方法中指定部署脚本 script 执行命令
  4. 执行 main 方法

前端部署:

  1. 对 vue 项目打包
  2. 在方法中指定 dist 文件夹位置和上传服务器位置
  3. 在方法中指定部署脚本 script 执行命令
  4. 执行 main 方法

相关文章:

Docker一键部署项目,无需登录XShell

文章目录 一键部署项目Docker手动部署SpringBoot项目编写docker部署的脚本文件script.sh 脚本内容 特别注意&#xff01;编写dockerfiledockerfile 文件内容 上传后端服务的jar包到服务器中执行 script 脚本部署后端服务 自动部署SpringBoot项目引入jsch依赖编写jsch工具类执行…...

GIt Squash 多个提交压缩提交

假设你有一个名为 feature 的分支&#xff0c;它包含三个提交&#xff08;A, B, C&#xff09;&#xff0c;并且你想将这三个提交压缩成一个。下面是如何做到这一点的。 首先&#xff0c;找出你要开始压缩的那个最早提交的哈希值。在这个例子中&#xff0c;我们假设 A 是最早的…...

【数据结构】栈与队列

1 栈 1.1 栈的概念及结构 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守后进先出 LIFO (Last In First Out) 的原则。 压栈&#xff1a;栈…...

突然让做性能测试?试试RunnerGo

当前&#xff0c;性能测试已经是一名软件测试工程师必须要了解&#xff0c;甚至熟练使用的一项技能了&#xff0c;在工作时可能每次发版都要跑一遍性能&#xff0c;跑一遍自动化。性能测试入门容易&#xff0c;深入则需要太多的知识量&#xff0c;今天这篇文章给大家带来&#…...

(7)(7.4) 集结航点

文章目录 7.4.1 概述 7.4.2 设置集结航点 7.4.3 飞行示例 7.4.4 附录 7.4.1 概述 通常情况下&#xff0c;当固定翼或旋翼飞机进入"返回发射"(Return to Launch (RTL))模式&#xff08;通常由自动驾驶仪失控保护触发&#xff09;(failsafe)时&#xff0c;默认行为…...

基于kubeadm部署K8S集群:上篇

目录 一、环境准备 1、主机初始化配置 2、配置主机名绑定hosts&#xff0c;不同主机名称不同 3、主机配置初始化 4、部署docker环境 二、部署kubernetes集群 1、组件介绍 2、所有主机配置阿里云yum源 3、安装kubelet 、kubeadm 、kubectl 4、配置init-config.yaml 5、…...

机器学习-特征选择:如何使用递归特征消除算法自动筛选出最优特征?

一、引言 在实际应用中&#xff0c;特征选择作为机器学习和数据挖掘领域的重要环节&#xff0c;对于提高模型性能和减少计算开销具有关键影响。特征选择是从原始特征集中选择最相关和最具区分力的特征子集&#xff0c;以提高模型的泛化能力和可解释性。 特征选择在实践中具有以…...

学生成绩管理系统V1.0

某班有最多不超过30人&#xff08;具体人数由键盘输入&#xff09;参加某门课程的考试&#xff0c;用一维数组作函数参数编程实现如下学生成绩管理&#xff1a; &#xff08;1&#xff09;录入每个学生的学号和考试成绩&#xff1b; &#xff08;2&#xff09;计算课程的总分…...

嵌入式:ARM Day1

1. 思维导图 2.作业一 3.作业2...

Android 网络协议与网络编程

一、TCP/IP协议 Transmission Control Protocol/Internet Protocol的简写&#xff0c;中译名为传输控制协议/因特网互联 协议&#xff0c;是Internet最基本的协议、Internet国际互联网络的基础&#xff0c;由网络层的IP协议和传输层的TCP 协议组成。协议采用了4层的层级结构。…...

【讯飞星火认知大模型】大模型之星火手机助理

目录 1. 讯飞星火认知大模型介绍 2. API 申请 3. 星火手机助理 4. 效果展示 1. 讯飞星火认知大模型介绍 讯飞星火认知大模型是科大讯飞自研的基于深度学习的自然语言处理模型&#xff0c;它可以理解和生成中文&#xff0c;执行多种任务&#xff0c;如问答、翻译、写作、编…...

centos中的swap.img可以删除吗

swap.img 是 CentOS 系统中的交换分区文件&#xff0c;用于辅助内存管理。交换分区在系统内存不足时用于存储不常用的数据&#xff0c;而不是直接写入硬盘。一般情况下&#xff0c;不建议删除交换分区文件&#xff0c;因为它对系统的正常运行非常重要。 如果您真的希望删除交换…...

Java多线程编程中的线程死锁

Java多线程编程中的线程死锁 ​ 在多线程编程中&#xff0c;线程死锁是一种常见的问题&#xff0c;它发生在两个或多个线程互相等待对方释放资源的情况下&#xff0c;导致程序无法继续执行。本文将介绍线程死锁的概念、产生原因、示例以及如何预防和解决线程死锁问题。 线程死…...

在浏览器中使用javascript打印HTML中指定Div带背景图片内容生成PDF电子证书查询的解决方案

在浏览器中使用javascript打印HTML中指定Div带背景图片内容生成PDF电子证书查询的解决方案 一、指定内容打印二、背景图片打印1.CSS背景图片设置2.div相对定位居中 三、完整案例展示1.CSS样式表2.HTML容器构建 一、指定内容打印 要调用浏览器中的打印功能&#xff0c;并指定需…...

【Redis实践篇】使用Redisson 优雅实现项目实践过程中的5种场景

文章目录 1.前言2.使用方式1. 添加Redisson依赖&#xff1a;2. 配置Redis连接信息3. 使用场景3.1. 分布式锁3.2. 限流器&#xff08;Rate Limiter&#xff09;3.3. 可过期的对象&#xff08;Expirable Object&#xff09;3.4. 信号量&#xff08;Semaphore&#xff09;3.5. 分布…...

污水处理厂人员定位方案介绍

污水处理厂人员定位在现代化的污水处理厂中具有重要的意义&#xff0c;它可以带来多方面的优势和好处&#xff1a; 安全管理&#xff1a; 污水处理厂通常涉及到各种危险环境和设备&#xff0c;如化学品、高压设备等。人员定位系统可以追踪人员的位置&#xff0c;确保他们不会进…...

约数个数(质因子分解)

思路&#xff1a; &#xff08;1&#xff09;由数论基本定理&#xff0c;任何一个正整数x都能写作&#xff0c;其中p1,p2..pk为x的质因子。 &#xff08;2&#xff09;由此可以推断&#xff0c;要求一个数约数的个数&#xff0c;注意到约数就是p1,p2...pk的一种组合&#xff…...

【QT】 QSS样式表设计一文了解

很高兴在雪易的CSDN遇见你 &#xff0c;给你糖糖 欢迎大家加入雪易社区-CSDN社区云 前言 本文分享QT界面设计中的QSS样式技术&#xff0c;主要从**、**和**方面展开&#xff0c;希望对各位小伙伴有所帮助&#xff01;学会了QSS样式设计&#xff0c;就可以开动你的审美&#…...

9-AJAX-1入门

AJAX 目录 AJAX 概念和 axios 使用认识 URLURL 查询参数常用请求方法和数据提交HTTP协议-报文接口文档案例 - 用户登录form-serialize 插件 01.AJAX 概念和 axios 使用 目标 了解 AJAX 概念并掌握 axios 库基本使用 讲解 什么是 AJAX ? mdn 使用浏览器的 XMLHttpRequest…...

ssh免密登录

客户端 第一步&#xff1a;生成密钥 ssh-keygen -t rsa 第二步&#xff1a;从“~/.ssh/id_rsa.pub”拷贝公钥 服务器端 填写公钥 打开authorized_keys&#xff0c;并把刚刚的公钥填进去 重启服务 sudo systemctl restart sshd...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误

HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误&#xff0c;它们的含义、原因和解决方法都有显著区别。以下是详细对比&#xff1a; 1. HTTP 406 (Not Acceptable) 含义&#xff1a; 客户端请求的内容类型与服务器支持的内容类型不匹…...

基于当前项目通过npm包形式暴露公共组件

1.package.sjon文件配置 其中xh-flowable就是暴露出去的npm包名 2.创建tpyes文件夹&#xff0c;并新增内容 3.创建package文件夹...

五年级数学知识边界总结思考-下册

目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解&#xff1a;由来、作用与意义**一、知识点核心内容****二、知识点的由来&#xff1a;从生活实践到数学抽象****三、知识的作用&#xff1a;解决实际问题的工具****四、学习的意义&#xff1a;培养核心素养…...

NFT模式:数字资产确权与链游经济系统构建

NFT模式&#xff1a;数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新&#xff1a;构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议&#xff1a;基于LayerZero协议实现以太坊、Solana等公链资产互通&#xff0c;通过零知…...

Map相关知识

数据结构 二叉树 二叉树&#xff0c;顾名思义&#xff0c;每个节点最多有两个“叉”&#xff0c;也就是两个子节点&#xff0c;分别是左子 节点和右子节点。不过&#xff0c;二叉树并不要求每个节点都有两个子节点&#xff0c;有的节点只 有左子节点&#xff0c;有的节点只有…...

【VLNs篇】07:NavRL—在动态环境中学习安全飞行

项目内容论文标题NavRL: 在动态环境中学习安全飞行 (NavRL: Learning Safe Flight in Dynamic Environments)核心问题解决无人机在包含静态和动态障碍物的复杂环境中进行安全、高效自主导航的挑战&#xff0c;克服传统方法和现有强化学习方法的局限性。核心算法基于近端策略优化…...

android RelativeLayout布局

<?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"android:gravity&…...

Xela矩阵三轴触觉传感器的工作原理解析与应用场景

Xela矩阵三轴触觉传感器通过先进技术模拟人类触觉感知&#xff0c;帮助设备实现精确的力测量与位移监测。其核心功能基于磁性三维力测量与空间位移测量&#xff0c;能够捕捉多维触觉信息。该传感器的设计不仅提升了触觉感知的精度&#xff0c;还为机器人、医疗设备和制造业的智…...

起重机起升机构的安全装置有哪些?

起重机起升机构的安全装置是保障吊装作业安全的关键部件&#xff0c;主要用于防止超载、失控、断绳等危险情况。以下是常见的安全装置及其功能和原理&#xff1a; 一、超载保护装置&#xff08;核心安全装置&#xff09; 1. 起重量限制器 功能&#xff1a;实时监测起升载荷&a…...

shell脚本质数判断

shell脚本质数判断 shell输入一个正整数,判断是否为质数(素数&#xff09;shell求1-100内的质数shell求给定数组输出其中的质数 shell输入一个正整数,判断是否为质数(素数&#xff09; 思路&#xff1a; 1:1 2:1 2 3:1 2 3 4:1 2 3 4 5:1 2 3 4 5-------> 3:2 4:2 3 5:2 3…...