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

python+django5.1+docker实现CICD自动化部署springboot 项目前后端分离vue-element

一、开发环境搭建和配置

# channels是一个用于在Django中实现WebSocket、HTTP/2和其他异步协议的库。
pip install channels#channels-redis是一个用于在Django Channels中使用Redis作为后台存储的库。它可以用于处理#WebSocket连接的持久化和消息传递。
pip install channels-redis#安装 docker(此处采用 mac安装)
brew install --cask docker

二、构建django应用

# 创建 operation 项目
django-admin startproject operation#项目结构
├── db.sqlite3
├── dbOperations
│   ├── __init__.py
│   ├── __pycache__
│   │   ├── __init__.cpython-313.pyc
│   │   ├── admin.cpython-313.pyc
│   │   ├── apps.cpython-313.pyc
│   │   ├── models.cpython-313.pyc
│   │   └── views.cpython-313.pyc
│   ├── admin.py
│   ├── apps.py
│   ├── migrations
│   │   ├── __init__.py
│   │   └── __pycache__
│   │       └── __init__.cpython-313.pyc
│   ├── models.py
│   ├── tests.py
│   └── views.py
├── deployments
│   ├── Consumers.py
│   ├── __init__.py
│   ├── __pycache__
│   │   ├── Consumers.cpython-313.pyc
│   │   ├── __init__.cpython-313.pyc
│   │   ├── admin.cpython-313.pyc
│   │   ├── apps.cpython-313.pyc
│   │   ├── models.cpython-313.pyc
│   │   ├── routing.cpython-313.pyc
│   │   └── views.cpython-313.pyc
│   ├── admin.py
│   ├── apps.py
│   ├── migrations
│   │   ├── 0001_initial.py
│   │   ├── __init__.py
│   │   └── __pycache__
│   │       ├── 0001_initial.cpython-313.pyc
│   │       └── __init__.cpython-313.pyc
│   ├── models.py
│   ├── routing.py
│   ├── tests.py
│   └── views.py
├── log
│   ├── __init__.py
│   ├── __pycache__
│   │   ├── __init__.cpython-313.pyc
│   │   ├── admin.cpython-313.pyc
│   │   ├── apps.cpython-313.pyc
│   │   ├── models.cpython-313.pyc
│   │   └── views.cpython-313.pyc
│   ├── admin.py
│   ├── apps.py
│   ├── migrations
│   │   ├── 0001_initial.py
│   │   ├── __init__.py
│   │   └── __pycache__
│   │       ├── 0001_initial.cpython-313.pyc
│   │       └── __init__.cpython-313.pyc
│   ├── models.py
│   ├── tests.py
│   └── views.py
├── manage.py
├── monitor
│   ├── __init__.py
│   ├── __pycache__
│   │   ├── __init__.cpython-313.pyc
│   │   ├── admin.cpython-313.pyc
│   │   ├── apps.cpython-313.pyc
│   │   ├── models.cpython-313.pyc
│   │   ├── signals.cpython-313.pyc
│   │   ├── tasks.cpython-313.pyc
│   │   └── views.cpython-313.pyc
│   ├── admin.py
│   ├── apps.py
│   ├── migrations
│   │   ├── 0001_initial.py
│   │   ├── __init__.py
│   │   └── __pycache__
│   │       ├── 0001_initial.cpython-313.pyc
│   │       └── __init__.cpython-313.pyc
│   ├── models.py
│   ├── signals.py
│   ├── tasks.py
│   ├── tests.py
│   └── views.py
├── operation
│   ├── __init__.py
│   ├── __pycache__
│   │   ├── __init__.cpython-313.pyc
│   │   ├── asgi.cpython-313.pyc
│   │   ├── settings.cpython-313.pyc
│   │   ├── urls.cpython-313.pyc
│   │   └── wsgi.cpython-313.pyc
│   ├── asgi.py
│   ├── common
│   │   ├── __init__.py
│   │   ├── __pycache__
│   │   │   └── __init__.cpython-313.pyc
│   │   ├── enum
│   │   │   ├── BuildProjectEnum.py
│   │   │   ├── EventTypesEnum.py
│   │   │   ├── OperatorTypeEnum.py
│   │   │   ├── ResponeCodeEnum.py
│   │   │   ├── __init__.py
│   │   │   └── __pycache__
│   │   │       ├── BuildProjectEnum.cpython-313.pyc
│   │   │       ├── EventTypesEnum.cpython-313.pyc
│   │   │       ├── OperatorTypeEnum.cpython-313.pyc
│   │   │       ├── ResponeCodeEnum.cpython-313.pyc
│   │   │       └── __init__.cpython-313.pyc
│   │   ├── exception
│   │   │   ├── BusinessException.py
│   │   │   ├── __init__.py
│   │   │   └── __pycache__
│   │   │       ├── BusinessException.cpython-313.pyc
│   │   │       └── __init__.cpython-313.pyc
│   │   └── utils
│   │       ├── CommonResult.py
│   │       ├── PageUtils.py
│   │       ├── Serializers.py
│   │       ├── __init__.py
│   │       └── __pycache__
│   │           ├── CommonResult.cpython-313.pyc
│   │           ├── PageUtils.cpython-313.pyc
│   │           ├── Serializers.cpython-313.pyc
│   │           └── __init__.cpython-313.pyc
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── templates
└── user├── __init__.py├── __pycache__│   ├── __init__.cpython-313.pyc│   ├── admin.cpython-313.pyc│   ├── apps.cpython-313.pyc│   ├── models.cpython-313.pyc│   └── views.cpython-313.pyc├── admin.py├── apps.py├── migrations│   ├── 0001_initial.py│   ├── __init__.py│   └── __pycache__│       ├── 0001_initial.cpython-313.pyc│       └── __init__.cpython-313.pyc├── models.py├── tests.py└── views.py

三、构建springboot应用

#创建 一个springboot micro-admin 应用.
├── Dockerfile
├── README.md
├── config
│   └── application.yml
├── mvnw
├── mvnw.cmd
├── pom.xml
├── sqlconfig
│   └── admin.sql
└── src├── main│   ├── java│   │   └── com│   │       └── micro│   │           └── lss│   │               └── microadmin│   │                   ├── MicroAdminApplication.java│   │                   ├── config│   │                   │   ├── AdminDataSourceConfig.java│   │                   │   ├── GlobalMetaObjectHandler.java│   │                   │   ├── RedisConfig.java│   │                   │   └── SwaggerConfig.java│   │                   ├── constant│   │                   │   └── AccountConstant.java│   │                   ├── controller│   │                   │   ├── BaseController.java│   │                   │   ├── ValidException.java│   │                   │   ├── account│   │                   │   │   ├── ResourceListController.java│   │                   │   │   └── SysAccountController.java│   │                   │   ├── dict│   │                   │   │   └── SysDictController.java│   │                   │   ├── file│   │                   │   │   └── SysFileController.java│   │                   │   ├── organization│   │                   │   │   └── OrganizationController.java│   │                   │   ├── resource│   │                   │   ├── role│   │                   │   │   └── SysRoleController.java│   │                   │   └── user│   │                   │       └── SysUserController.java│   │                   ├── entity│   │                   │   ├── domain│   │                   │   │   ├── SysAccountExpense.java│   │                   │   │   ├── SysAccountIncome.java│   │                   │   │   ├── SysDict.java│   │                   │   │   ├── SysOrganization.java│   │                   │   │   ├── SysOrganizationUserJoin.java│   │                   │   │   ├── SysResource.java│   │                   │   │   ├── SysRole.java│   │                   │   │   ├── SysRoleResource.java│   │                   │   │   ├── SysUploadFile.java│   │                   │   │   ├── SysUser.java│   │                   │   │   ├── SysUserAccount.java│   │                   │   │   └── SysUserRole.java│   │                   │   ├── dto│   │                   │   │   ├── AccountIncomeAddDto.java│   │                   │   │   ├── OrgAddDto.java│   │                   │   │   ├── OrgUpdateDto.java│   │                   │   │   ├── RoleAddDto.java│   │                   │   │   ├── RoleUpdateDto.java│   │                   │   │   ├── RoleUpdateEnableflagDto.java│   │                   │   │   ├── SysResourceDto.java│   │                   │   │   ├── SysUploadDto.java│   │                   │   │   ├── UserAddDto.java│   │                   │   │   ├── UserRegisterDto.java│   │                   │   │   └── UserUpdateDto.java│   │                   │   ├── query│   │                   │   │   ├── AccountExpenseListQuery.java│   │                   │   │   ├── BigLogQuery.java│   │                   │   │   ├── FileListQuery.java│   │                   │   │   ├── IncomeListQuery.java│   │                   │   │   ├── OrgListQuery.java│   │                   │   │   ├── ResourceListQuery.java│   │                   │   │   ├── SysDictListQuery.java│   │                   │   │   ├── SysRoleListQuery.java│   │                   │   │   ├── UserJoinOrgListQuery.java│   │                   │   │   ├── UserListQuery.java│   │                   │   │   ├── UserLoginQuery.java│   │                   │   │   └── UserQuery.java│   │                   │   └── vo│   │                   │       ├── AccountExpenseListVo.java│   │                   │       ├── BigLogVo.java│   │                   │       ├── IncomeListVo.java│   │                   │       ├── IncomeSummaryVo.java│   │                   │       ├── OrgDeptListVo.java│   │                   │       ├── OrgDetailVo.java│   │                   │       ├── OrgListTreeVo.java│   │                   │       ├── OrgListVo.java│   │                   │       ├── ResourceListVo.java│   │                   │       ├── ResourceTreeVo.java│   │                   │       ├── RoleDetailVo.java│   │                   │       ├── RoleSelListVo.java│   │                   │       ├── SysDictListVo.java│   │                   │       ├── SysDictTreeListVo.java│   │                   │       ├── SysRoleListVo.java│   │                   │       ├── SysUploadFileListVo.java│   │                   │       ├── SysUserAccountDetailVo.java│   │                   │       ├── UserAddOrUpdateVo.java│   │                   │       ├── UserDetailVo.java│   │                   │       ├── UserJoinOrgLoginListVo.java│   │                   │       ├── UserJoinOrgVo.java│   │                   │       ├── UserLoginInfoVo.java│   │                   │       └── UserLoginListVo.java│   │                   ├── enums│   │                   │   ├── BaseEnum.java│   │                   │   └── IndexEnum.java│   │                   ├── mapper│   │                   │   ├── SysAccountExpenseMapper.java│   │                   │   ├── SysAccountIncomeMapper.java│   │                   │   ├── SysDictMapper.java│   │                   │   ├── SysOrganizationMapper.java│   │                   │   ├── SysOrganizationUserJoinMapper.java│   │                   │   ├── SysResourceMapper.java│   │                   │   ├── SysRoleMapper.java│   │                   │   ├── SysRoleResourceMapper.java│   │                   │   ├── SysUploadFileMapper.java│   │                   │   ├── SysUserAccountMapper.java│   │                   │   ├── SysUserMapper.java│   │                   │   └── SysUserRoleMapper.java│   │                   ├── service│   │                   │   ├── IBizLogService.java│   │                   │   ├── ISysAccountExpenseService.java│   │                   │   ├── ISysAccountIncomeService.java│   │                   │   ├── ISysDictService.java│   │                   │   ├── ISysOrganizationService.java│   │                   │   ├── ISysOrganizationUserJoinService.java│   │                   │   ├── ISysResourceService.java│   │                   │   ├── ISysRoleResourceService.java│   │                   │   ├── ISysRoleService.java│   │                   │   ├── ISysUploadFileService.java│   │                   │   ├── ISysUserAccountService.java│   │                   │   ├── ISysUserRoleService.java│   │                   │   ├── ISysUserService.java│   │                   │   └── impl│   │                   │       ├── BizLogServiceImpl.java│   │                   │       ├── H5BaseService.java│   │                   │       ├── SysAccountExpenseServiceImpl.java│   │                   │       ├── SysAccountIncomeServiceImpl.java│   │                   │       ├── SysDictServiceImpl.java│   │                   │       ├── SysOrganizationServiceImpl.java│   │                   │       ├── SysOrganizationUserJoinServiceImpl.java│   │                   │       ├── SysResourceServiceImpl.java│   │                   │       ├── SysRoleResourceServiceImpl.java│   │                   │       ├── SysRoleServiceImpl.java│   │                   │       ├── SysUploadFileServiceImpl.java│   │                   │       ├── SysUserAccountServiceImpl.java│   │                   │       ├── SysUserRoleServiceImpl.java│   │                   │       └── SysUserServiceImpl.java│   │                   └── util│   │                       ├── EsUtils.java│   │                       └── SFTPUtil.java│   └── resources│       ├── bootstrap.yml│       ├── logback.xml│       └── mapper│           ├── SysAccountExpenseMapper.xml│           ├── SysAccountIncomeMapper.xml│           ├── SysDictMapper.xml│           ├── SysOrganizationMapper.xml│           ├── SysOrganizationUserJoinMapper.xml│           ├── SysResourceMapper.xml│           ├── SysRoleMapper.xml│           ├── SysRoleResourceMapper.xml│           ├── SysUploadFileMapper.xml│           ├── SysUserAccountMapper.xml│           ├── SysUserMapper.xml│           └── SysUserRoleMapper.xml└── test└── java└── com└── micro└── lss└── microadmin└── MicroAdminApplicationTests.java

四、CICD相关代码

#模块目录deployments
│   ├── Consumers.py
│   ├── __init__.py
│   ├── __pycache__
│   │   ├── Consumers.cpython-313.pyc
│   │   ├── __init__.cpython-313.pyc
│   │   ├── admin.cpython-313.pyc
│   │   ├── apps.cpython-313.pyc
│   │   ├── models.cpython-313.pyc
│   │   ├── routing.cpython-313.pyc
│   │   └── views.cpython-313.pyc
│   ├── admin.py
│   ├── apps.py
│   ├── migrations
│   │   ├── 0001_initial.py
│   │   ├── __init__.py
│   │   └── __pycache__
│   │       ├── 0001_initial.cpython-313.pyc
│   │       └── __init__.cpython-313.pyc
│   ├── models.py
│   ├── routing.py
│   ├── tests.py
│   └── views.py
***************************/operation/settings.py***************************
# Application definition
#它列出了所有在你的项目中启用的应用(apps)。每个应用可以提供特定的功能或服务
#通过在 INSTALLED_APPS 中列出这些应用,Django会在启动时自动加载它们,
# 并使它们的功能在你的项目中可用。
# 这样,你可以利用这些内置功能来快速开发和扩展你的应用
INSTALLED_APPS = ['django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles','log','monitor','user','dbOperations','deployments','channels'       # 需要增加 channels
]ASGI_APPLICATION = 'operation.asgi.application'#channels-redis
CHANNEL_LAYERS = {'default': {'BACKEND': 'channels_redis.core.RedisChannelLayer','CONFIG': {"hosts": ["redis://:password@ip:端口/0",],},},
}#指定 Gitee 上项目对应的 URL
PROJECT_REPO_URL = 'https://xx/xx.git'
# 本地目录
PROJECT_REPO_DIR = '/xx/xx'
#jdk_path
JDK_PATH = '/Library/Java/JavaVirtualMachines/jdk1.8.0_202.jdk/Contents/Home'
#maven
MAVEN_PATH = '/xx/soft/apache-maven-3.6.2/bin:'
**********************************/operation/asgi.py************************
"""Web框架和Web应用之间的通信,它允许你编写异步的Django视图和其他组件,以提高应用的性能和响应能力,部署时需要用到部署的时候才用到
"""import osfrom django.core.asgi import get_asgi_application
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack# 设置 DJANGO_SETTINGS_MODULE 环境变量
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'operation.settings')# 获取 ASGI 应用
django_asgi_app = get_asgi_application()# 延迟导入其他模块
from deployments import routing  # 这里是你需要延迟导入的模块application = ProtocolTypeRouter({"http": django_asgi_app,"websocket": AuthMiddlewareStack(URLRouter(routing.websocket_urlpatterns))
})
*****************************/operation/urls.py***************************
"""这个文件是用来配置URL路由的,比如访问http://127.0.0.1/about/是访问关于页面,则需要再当前文件配置"""
from django.contrib import admin
from django.urls import path
from log import views as log_views
from monitor import views as monitor_views
from user import views as user_views
from dbOperations import views as db_views
from deployments import views as deployment_views"""说明:这个路径将 /admin/ 开头的 URL 映射到 Django 自带的管理后台。admin.site.urls 是 Django 管理后台的 URL 配置,包含了管理后台的所有功能和页面。这个路径将 /log/ 开头的 URL 映射到 log 应用中的 getLogList 视图函数。name='log' 为这个 URL 路径定义了一个名称,可以在模板或其他地方通过这个名称来引用这个 URL。
"""
urlpatterns = [path('admin/', admin.site.urls),path('log/getLogList', log_views.getLogList, name='log_list'),path('log/getDebugLogList', log_views.getDebugLogList,name='debug_log_list'),path('monitor/getSystemInfo', monitor_views.getSystemInfo,name='system_info'),path('monitor/getAlarmList', monitor_views.getAlarmList, name='alarm_list'),path('user/login',user_views.login, name='login'),path('dbOperations/executeSQLView', db_views.executeSQLView,name='execute_sql_view'),path('deployments/getDeploymentsList', deployment_views.getDeploymentsList,name='deployments_list'),path('deployments/viewCICD', deployment_views.viewCICD, name='viewCICD'),path('deployments/addDeployment', deployment_views.addDeployment, name='add_deployment')
]
***************************/deployments/routing.py***********************
from django.urls import pathfrom . import Consumerswebsocket_urlpatterns = [path('ws/cicd_progress/', Consumers.ChatConsumer.as_asgi())
]
***************************/deployments/models.py******************
import loggingfrom operation.common.enum.ResponeCodeEnum import ResponseCodeEnum
from operation.common.exception.BusinessException import BusinessException
from django.db import modelsclass Deployment(models.Model):name = models.CharField(max_length=255)status = models.CharField(max_length=50)created_at = models.DateTimeField(auto_now_add=True)progress = models.IntegerField(default=0)def __str__(self):return self.nameclass Meta:db_table = 'program_deployment'def to_dict(self):return {'id': self.id,'name': self.name,'status': self.status,'created_at': self.created_at.strftime('%Y-%m-%d %H:%M:%S') if self.created_at else None,'progress': self.progress}@staticmethoddef update_deployment_model(projectId, projectName, status, progress):try:deployment = Deployment.objects.get(id=projectId, name=projectName)deployment.status = statusdeployment.progress = progressdeployment.save()except Deployment.DoesNotExist:logging.error(f"Deployment 记录不存在: id={projectId}, name={projectName}")raise BusinessException(f"Deployment 记录不存在: id={projectId}, name={projectName}", ResponseCodeEnum.DATA_NONE.code)
***************************/deployments/Consumers.py******************
import os
from typing import Anyimport django
import loggingfrom channels.generic.websocket import AsyncWebsocketConsumer
import jsonfrom deployments.views import cicd_execute
from operation.common.enum.ResponeCodeEnum import ResponseCodeEnum# 手动设置 DJANGO_SETTINGS_MODULE
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'operation.settings')# 配置 Django
django.setup()class ChatConsumer(AsyncWebsocketConsumer):async def connect(self):logging.info("connect")await self.accept()async def disconnect(self, close_code):pass"""Exception inside application: You cannot call this from an async context - use a thread or sync_to_async.Traceback (most recent call last):这个错误提示表明你在异步上下文中调用了同步代码,这在 Django Channels 中是不允许的。你需要将同步代码转换为异步代码,或者使用 sync_to_async 包装同步代码。"""async def receive(self, text_data):text_data_json = json.loads(text_data)id = text_data_json['id']project_name = text_data_json['projectName']# 调用CI/CD执行函数await self.channel_layer.send(self.channel_name,{'type': 'execute_cicd','id': id,'project_name': project_name,})async def execute_cicd(self, event):id = event['id']project_name = event['project_name']# 调用CI/CD执行函数await cicd_execute(id, project_name, self.send_progress,self.send_news)"""发送 进度"""async def send_progress(self, progress,status,code,message):await self.send(text_data=json.dumps({'type': 'progress','code': code,'message': message,'data': {'progress': progress,  #进度值'status': status        # 状态}}))"""发送 执行日志: 类型注解,用于明确指定 responseCodeEnum 参数的类型是 ResponseCodeEnum"""async def send_news(self,logInfo: Any,responseCodeEnum:ResponseCodeEnum):await self.send(text_data=json.dumps({'type': 'news','code': responseCodeEnum.code,'message': responseCodeEnum.message,'data': {'logInfo':logInfo   #日志信息}}))
***************************/deployments/views.py******************
import asyncio
import json
import logging
import os
import subprocessimport git
from django.http import JsonResponse, HttpResponse
from django.views.decorators.csrf import csrf_exempt
from git import Repofrom deployments.models import Deployment
from operation import settings
from operation.common.enum.BuildProjectEnum import BuildProjectEnum
from operation.common.enum.ResponeCodeEnum import ResponseCodeEnum
from operation.common.exception.BusinessException import BusinessException
from operation.common.utils.CommonResult import CommonResult
from operation.common.utils.PageUtils import paginate_queryset
from asgiref.sync import sync_to_async# Create your views here."""
****************************创建 deployments API视图
""""""获取应用列表
"""@csrf_exempt
def getDeploymentsList(request):try:if request.method == 'POST':json_data = request.bodydata = json.loads(json_data)page = data.get('page', 1)page_size = data.get('page_size', 10)else:raise BusinessException(ResponseCodeEnum.METHOD_ERROR.message, ResponseCodeEnum.METHOD_ERROR.code)deployment_list = Deployment.objects.all().order_by('created_at')deployment_lists, pagination_info = paginate_queryset(deployment_list, page, page_size)deployment_lists = [Deployment.to_dict() for Deployment in deployment_lists]logging.info(type(deployment_lists))return JsonResponse(CommonResult.success_pagination(deployment_lists, pagination_info),json_dumps_params={'ensure_ascii': False})except BusinessException as e:return JsonResponse(CommonResult.error(e.code, e.message), json_dumps_params={'ensure_ascii': False})"""增加应用
"""@csrf_exempt
def addDeployment(request):if request.method == "GET":return BusinessException(ResponseCodeEnum.METHOD_ERROR.message, ResponseCodeEnum.METHOD_ERROR.code)try:json_data = request.bodydata = json.loads(json_data)name = data.get('name')if name is None:raise BusinessException(ResponseCodeEnum.PARAMS_ERROR.message, ResponseCodeEnum.PARAMS_ERROR.code)# 保存应用Deployment.objects.create(name=name,status=BuildProjectEnum.NOT_STARTED.code)return JsonResponse(CommonResult.success_data(None), json_dumps_params={'ensure_ascii': False})except BusinessException as e:return JsonResponse(CommonResult.error(e.code, e.message), json_dumps_params={'ensure_ascii': False})"""*********部署角本报错: You cannot call this from an async context - use a thread or sync_to_async.解决方案:1.使用 sync_to_async  2.使用 使用线程
"""
# 定义全局变量 progress
progress = 0async def cicd_execute(project_id, project_name, send_progress, send_news):global progress  # 声明 progress 为全局变量try:# 每次点击发布时,重置 progress 为0progress = 0# 1.初始化阶段await init_project(project_id, project_name, send_progress)# 2.构建阶段await build_and_deploy_project(project_id, project_name, send_progress, send_news)# 3.运行阶段await run_project(project_id, project_name, send_progress,send_news)except BusinessException as e:logging.info(f"发生系统内部异常: {e}")return"""1.初始化阶段
"""async def init_project(project_id, project_name, send_progress):global progress  # 声明 progress 为全局变量try:logging.info("=================开始初始化 项目 %s" % (project_name))logging.info("初始化中......")# 更新状态为 "初始化中" 记录进度值progress += 20await update_deployment_status(project_id, project_name, BuildProjectEnum.INITIALIZING.code, progress)# 发送事件await send_progress(progress, BuildProjectEnum.INITIALIZING.code, ResponseCodeEnum.SUCCESS.status_code,ResponseCodeEnum.SUCCESS.message)projectName = project_nameprojectId = project_idif projectName is None or projectId is None:raise BusinessException(ResponseCodeEnum.PARAMS_ERROR.message, ResponseCodeEnum.PARAMS_ERROR.code)# 环境变量配置set_environment_variables()# 加载仓库 拉取代码await clone_or_pull_repo(project_name)# 更新状态为 "初始化成功" 记录进度值progress += 20await update_deployment_status(project_id, project_name, BuildProjectEnum.INITIAL_SUCCESS.code, progress)# 发送事件await send_progress(progress, BuildProjectEnum.INITIAL_SUCCESS.code, ResponseCodeEnum.SUCCESS.status_code,ResponseCodeEnum.SUCCESS.message)logging.info("初始化成功......")except BusinessException as e:logging.info("初始化失败......")# 更新状态为 "初始化失败"await update_deployment_status(project_id, project_name, BuildProjectEnum.INITIAL_FAILURE.code, progress)# 发送事件await send_progress(progress, BuildProjectEnum.INITIAL_FAILURE.code,ResponseCodeEnum.INTERNAL_SERVER_ERROR.status_code,ResponseCodeEnum.INTERNAL_SERVER_ERROR.message)# 抛出异常raise BusinessException(ResponseCodeEnum.INTERNAL_SERVER_ERROR.message,ResponseCodeEnum.INTERNAL_SERVER_ERROR.code)"""2.构建阶段
"""
async def build_and_deploy_project(project_id, project_name, send_progress, send_news):global progresslogging.info("=================构建 项目 %s" % (project_name))logging.info("部署中......")try:# 更新状态为 "部署中" 记录进度值 60progress += 20await update_deployment_status(project_id, project_name, BuildProjectEnum.DEPLOYMENT_IN.code, progress)# 发送事件await send_progress(progress, BuildProjectEnum.DEPLOYMENT_IN.code, ResponseCodeEnum.SUCCESS.status_code,ResponseCodeEnum.SUCCESS.message)projectName_image = project_name + "-image"projectName_dir = os.path.join(settings.PROJECT_REPO_DIR, project_name)await clean_old_containers(projectName_image)await clean_old_images(projectName_image)os.chdir(projectName_dir)logging.info(f"当前工作目录: {os.getcwd()}")# 执行 maven 打包await execute_maven_build(send_news)logging.info("mvn clean install -DskipTests 执行完成......")# 构建 imageawait build_docker_image(projectName_image,send_news)logging.info("docker build -t , projectName_image . 执行完成")# 更新状态为 "部署成功" 记录进度值 80progress += 20await update_deployment_status(project_id, project_name, BuildProjectEnum.DEPLOYMENT_SUCCESS.code, progress)# 发送事件await send_progress(progress, BuildProjectEnum.DEPLOYMENT_SUCCESS.code, ResponseCodeEnum.SUCCESS.status_code,ResponseCodeEnum.SUCCESS.message)logging.info("部署成功......")except Exception as ex:# 更新状态为 "部署失败"logging.info("部署失败......")await update_deployment_status(project_id, project_name, BuildProjectEnum.DEPLOYMENT_FAILURE.code, progress)# 发送事件await send_progress(progress, BuildProjectEnum.DEPLOYMENT_FAILURE.code,ResponseCodeEnum.INTERNAL_SERVER_ERROR.status_code,ResponseCodeEnum.INTERNAL_SERVER_ERROR.message)# 抛出异常raise BusinessException(ResponseCodeEnum.INTERNAL_SERVER_ERROR.message,ResponseCodeEnum.INTERNAL_SERVER_ERROR.code)"""3.运行阶段
"""
async def run_project(project_id, project_name, send_progress,send_news):global progresslogging.info("=================启动 项目 %s" % (project_name))logging.info("启动中......")try:# 更新状态为 "启动中" 记录进度值 70progress += 10await update_deployment_status(project_id, project_name, BuildProjectEnum.STARTING.code, progress)# 发送事件await send_progress(progress, BuildProjectEnum.STARTING.code, ResponseCodeEnum.SUCCESS.status_code,ResponseCodeEnum.SUCCESS.message)projectName_image = project_name + "-image"await run_docker_container(projectName_image,send_news)# 更新状态为 "启动成功" 记录进度值 80progress += 10await update_deployment_status(project_id, project_name, BuildProjectEnum.STARTED_SECCESS.code, progress)# 发送事件await send_progress(progress, BuildProjectEnum.STARTED_SECCESS.code, ResponseCodeEnum.SUCCESS.status_code,ResponseCodeEnum.SUCCESS.message)logging.info("启动成功......")except Exception as ex:# 更新状态为 "启动失败"logging.info("启动失败......")await update_deployment_status(project_id, project_name, BuildProjectEnum.STARTED_FAILURE.code, progress)# 发送事件await send_progress(progress, BuildProjectEnum.STARTED_FAILURE.code,ResponseCodeEnum.INTERNAL_SERVER_ERROR.status_code,ResponseCodeEnum.INTERNAL_SERVER_ERROR.message)# 抛出异常raise BusinessException(ResponseCodeEnum.INTERNAL_SERVER_ERROR.message,ResponseCodeEnum.INTERNAL_SERVER_ERROR.code)"""加载环境变量
"""def set_environment_variables():logging.info("加载环境变量......")os.environ['PATH'] = settings.MAVEN_PATH + os.environ['PATH']jdk_path = settings.JDK_PATHos.environ['JAVA_HOME'] = jdk_pathos.environ['PATH'] = f"{jdk_path}/bin:{os.environ['PATH']}"logging.info("环境变量加载成功......")"""加载仓库 拉取代码
"""async def clone_or_pull_repo(project_name):logging.info("拉取仓库代码......")project_repo_url = settings.PROJECT_REPO_URLproject_repo_dir = settings.PROJECT_REPO_DIRif not os.path.exists(project_repo_dir):await sync_to_async(Repo.clone_from)(project_repo_url, project_repo_dir)else:project_repo = await sync_to_async(Repo)(project_repo_dir)await sync_to_async(project_repo.remotes.origin.pull)()logging.info("拉取仓库代码成功......")"""清理旧容器
"""
async def clean_old_containers(projectName_image):cid = await sync_to_async(subprocess.check_output)(["docker", "ps", "-a", "-q", "--filter", f"ancestor={projectName_image}"])if cid:# 去除末尾的换行符并转换为字符串cid_str = cid.decode().strip()logging.info("=================cid: %s" % (cid_str))logging.info(f"清理旧容器 docker rm -f {cid_str}")await sync_to_async(subprocess.run)(["docker", "rm", "-f", cid_str])"""清理旧镜像
"""
async def clean_old_images(projectName_image):iid = await sync_to_async(subprocess.check_output)(["docker", "images", "-q", projectName_image])if iid:# 去除末尾的换行符并转换为字符串iid_str = iid.strip()logging.info("=================iid: %s" % (iid_str))logging.info(f"清理旧镜像 docker rmi -f {iid_str}")await sync_to_async(subprocess.run)(["docker", "rmi", "-f", iid_str])"""maven 打包构建
"""
async def execute_maven_build(send_news):# 使用 asyncio.create_subprocess_exec 创建异步进程processObject = await asyncio.create_subprocess_exec('mvn', 'clean', 'install', '-DskipTests',stdout=asyncio.subprocess.PIPE,stderr=asyncio.subprocess.PIPE)logging.info("发送maven打包构建执行日志......")await deployment_log_output(processObject, send_news, ResponseCodeEnum.SUCCESS)"""构建镜像
"""
async def build_docker_image(projectName_image, send_news):logging.info(f"=================构建镜像 docker build -t {projectName_image} .")# 使用 asyncio.create_subprocess_exec 来异步执行命令imageProcessObject = await asyncio.create_subprocess_exec('docker', 'build', '-t', projectName_image, '.',stdout=asyncio.subprocess.PIPE,stderr=asyncio.subprocess.PIPE)logging.info("发送构建镜像执行日志......")await deployment_log_output(imageProcessObject, send_news, ResponseCodeEnum.SUCCESS)"""运行 docker
"""
async def run_docker_container(projectName_image, send_news):logging.info(f"=================运行 docker run -d -p 8084:8084 {projectName_image} .")containerRunProcessObject = await asyncio.create_subprocess_exec('docker', 'run', '-d', '-p', '8084:8084', projectName_image, '.',stdout=asyncio.subprocess.PIPE,stderr=asyncio.subprocess.PIPE)logging.info("发送启动docker执行日志......")# 获取容器 IDstdout, stderr = await containerRunProcessObject.communicate()container_id = stdout.decode('utf-8').strip()# 异步运行 docker logs 命令containerRunlogprocess = await asyncio.create_subprocess_exec('docker', 'logs', '-f', '-n', '100', container_id,stdout=asyncio.subprocess.PIPE,stderr=asyncio.subprocess.PIPE)# 异步读取容器日志asyncio.create_task(deployment_log_output(containerRunlogprocess, send_news, ResponseCodeEnum.SUCCESS))"""更新model
"""
async def update_deployment_status(project_id, project_name, status, progress):await sync_to_async(Deployment.update_deployment_model)(project_id, project_name, status=status, progress=progress)"""
读取mvn 执行命令定义一个异步的 函数 deployment_log_outputasync def:协程(协程是由用户程序控制的) 可以暂停和恢复执行部署日志模块记录processObject: 进程对象send_news: 处理消息的方法buildProjectEnum:构建项目的 Enum类responseCodeEnum: 响应Enum类progress: 进度值
"""
async def deployment_log_output(processObject, send_news, responseCodeEnum: ResponseCodeEnum):try:# 使用 async for 循环读取日志async for line in processObject.stdout:if not line:break# 发送日志await send_news(line.decode('utf-8'), responseCodeEnum)logging.info(f"发送日志信息成功: %s" % (line.decode('utf-8')))finally:# 等待子进程执行完毕await processObject.wait()
************************/operation/commom/enum/BuildProjectEnum.py*************
from enum import Enum
"""构建状态 Initial failure
"""
class BuildProjectEnum(Enum):NOT_STARTED = (0, '未启动')INITIALIZING = (1, "初始化中")INITIAL_SUCCESS = (2, "初始化成功")INITIAL_FAILURE = (3, "初始失败")DEPLOYMENT_IN = (4, '部署中')DEPLOYMENT_SUCCESS = (5, '部署成功')DEPLOYMENT_FAILURE= (6, '部署失败')STARTING = (7, '启动中')STARTED_SECCESS = (8, '启动成功')STARTED_FAILURE = (9, '启动失败')UNKNOWN_STATE = (10, '未知状态')def __init__(self, code, message):self.code = codeself.message = message# @property 是 Python 中用于将类的方法转换为属性访问的装饰器。# 使用 @property 装饰器,你可以像访问属性一样访问方法,而不需要调用它@propertydef status_code(self):return self.code@propertydef error_message(self):return self.message***************************/operation/commom/enum/ResponseCodeEnum.py*************
from enum import Enumclass ResponseCodeEnum(Enum):SUCCESS = (200, "操作成功!")PARAMS_ERROR = (400, "参数解析失败,请核对参数!")UNAUTHORIZED = (401, "未认证(签名错误)")FORBIDDEN = (402, "请求错误")  # 返回失败业务公共codeMEDIA_TYPE_ERROR = (403, "不支持的媒体异常,请核对contentType!")URL_REQ_NULL = (404, "请求路径不存在")METHOD_ERROR = (405, "不支持当前请求方法,请核对请求方法!")INTERNAL_SERVER_ERROR = (500, "服务器内部错误!")  # 系统异常公共codeNULL_POINTER_ERROR = (600, "请核对必填字段是否为空!")NUMBER_FORMAT_ERROR = (601, "数据类型不一致!")PARAMS_TYPE_ERROR = (602, "参数类型错误!")TIMEOUT_ERROR = (603, "token失效连接超时!")TIMEOUT_EXPIRE_ERROR = (604, "token登录过期!")TOKEN_ILLEGAL = (605, "非法token!")USER_LOGIN_FAIL = (1001,"用户登录失败!")DATA_NONE = (1002, "记录不存在!")def __init__(self, code, message):self.code = codeself.message = message#@property 是 Python 中用于将类的方法转换为属性访问的装饰器。# 使用 @property 装饰器,你可以像访问属性一样访问方法,而不需要调用它@propertydef status_code(self):return self.code@propertydef error_message(self):return self.message#<class 'enum.EnumType'> 枚举类
# print(type(ResponseCodeEnum))
#<enum 'ResponseCodeEnum'> SUCCESS 是 ResponseCodeEnum 枚举类的一个实例。
# print(type(ResponseCodeEnum.SUCCESS))**********************/operation/commom/utils/CommonResult.py**********************
from typing import Any, Optionalfrom operation.common.enum.ResponeCodeEnum import ResponseCodeEnumclass CommonResult:def __init__(self, res: ResponseCodeEnum, data: Any, pagination: Optional[dict] = None):self.ResponseCodeEnum = ResponseCodeEnumself.data = dataself.pagination = pagination"""表态方法定义 直接通过 CommonResult.success  类名.静态方法名@staticmethod 不能访问或修改类或实例的属性。"""@staticmethoddef success_pagination(data: Any, pagination: Optional[dict] = None):return {'code': ResponseCodeEnum.SUCCESS.status_code,'message': ResponseCodeEnum.SUCCESS.message,'data': data,  # 将 QuerySet 序列化为 JSON,'pagination': pagination}@staticmethoddef error(code,message):return {'code': code,'message': message,'data': None,  # 将 QuerySet 序列化为 JSON,'pagination': None}@staticmethoddef success_data(data: Any):return {'code': ResponseCodeEnum.SUCCESS.status_code,'message': ResponseCodeEnum.SUCCESS.message,'data': data,  # 将 QuerySet 序列化为 JSON,}**************************/operation/commom/utils/PageUtils.py**************
from django.core.paginator import Paginator, EmptyPage, PageNotAnIntegerdef paginate_queryset(queryset, page, page_size):"""分页封装函数:param queryset: 查询集:param page: 页码:param page_size: 每页记录数:return: 分页后的数据和分页信息"""paginator = Paginator(queryset, page_size)try:page_obj = paginator.page(page)except PageNotAnInteger:page_obj = paginator.page(1)except EmptyPage:page_obj = paginator.page(paginator.num_pages)pagination_info = {'total_pages': paginator.num_pages,'current_page': page_obj.number,'has_next': page_obj.has_next(),'has_previous': page_obj.has_previous(),'next_page_number': page_obj.next_page_number() if page_obj.has_next() else None,'previous_page_number': page_obj.previous_page_number() if page_obj.has_previous() else None,'total': paginator.count}return page_obj.object_list, pagination_info***********************/operation/commom/exception/BusinessException.py*********
class BusinessException(Exception):def __init__(self,message,code):self.message = messageself.code = code

五、springboot 项目根目录下创建dockerfile 文件

**************************dockerfile文*******************************# 使用官方的 OpenJDK 8 镜像作为基础镜像
FROM openjdk:8-jdk-alpine# 设置镜像的维护者信息
LABEL maintainer="heshuai <xxx@qq.com.com>"# 配置镜像源
RUN echo "http://mirrors.aliyun.com/alpine/v3.6/main" > /etc/apk/repositories \&& echo "http://mirrors.aliyun.com/alpine/v3.6/community" >> /etc/apk/repositories \&& apk update upgrade \&& apk add --no-cache openssh  vim \&& apk add --no-cache procps unzip curl bash tzdata \&& ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \&& echo "Asia/Shanghai" > /etc/timezone# 创建目录
RUN mkdir /data
RUN mkdir /micro-admin
RUN mkdir /data/log# 设置工作目录
WORKDIR /micro-admin# 复制构建好的 JAR 文件到容器中
COPY target/micro-admin.jar /micro-admin# 设置容器启动时执行的命令
ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /micro-admin/micro-admin.jar"]# 暴露 Spring Boot 的默认端口
EXPOSE 8084

六、创建和应用迁移

#创建数据库迁移文件并应用(指定应用模块)
python manage.py makemigrations deployments
python manage.py migrate deployments

七、启动django项目 (需要支持WebSocket或其他异步通信,使用daphne启动)

"""和项目交互基本上都是基于这个文件,一般都是在终端输入python3 manage.py [子命令]manage.py输入python3 manage.py help查看更多启动项目  python3 manage.py runserver 创建app模块 python3 manage.py startapp app生成迁移文件,描述如何将模型更改应用到数据库中 python3 manage.py makemigrations将这些文件迁移应用到数据库中 python3 manage.py migrate如果你需要支持WebSocket或其他异步通信,使用daphne operation.asgi:application。如果你只需要简单的HTTP服务,使用python manage.py runserver。export DJANGO_SETTINGS_MODULE=your_project_name.settings"""
#安装Daphne
pip install daphne#终端输入
daphne operation.asgi:application

八、前端部分代码

********************************deploymentPage.vue******************************<template><div class="app-container"><el-card shadow="always"><el-form ref="searchForm" :inline="true" :model="searchMap" style="margin-top: 20px"><el-form-item><el-button type="primary" icon="el-icon-search" @click="searchLog('searchForm')">搜索</el-button><el-button type="primary" icon="el-icon-clear" @click="resetForm('searchForm')">重置</el-button></el-form-item></el-form></el-card><el-card shadow="always"><template><el-button size="mini" icon="el-icon-plus" type="primary" @click="openAddDrawer()">新增</el-button></template></el-card><el-row :gutter="24"><el-col :span="24"><el-card shadow="always"><div><el-table ref="multipleTable" v-loading="listLoading" :data="getDeploymentListDto" border fit highlight-current-row style="width: 100%;" class="tb-edit"><el-table-column prop="id" label="应用id" width="180px" align="center"></el-table-column><el-table-column prop="name" label="应用名称" width="180px" align="center"></el-table-column><el-table-column prop="status" label="状态" width="180px" align="center" :formatter="statusFormatter"></el-table-column><el-table-column prop="created_at" label="创建时间" width="180px" align="center"></el-table-column><el-table-column prop="actions" label="操作"><template slot-scope="scope"><el-button type="text" @click="redeploy(scope.row)">重新部署</el-button></template></el-table-column><el-table-column label="部署进度"><template slot-scope="scope"><el-progress :percentage="scope.row.progress" v-if="scope.row.progress"></el-progress></template></el-table-column></el-table></div><div class="block"><el-pagination :current-page="currentPage" :page-sizes="[5, 10, 15, 20]" :page-size="5" layout="total, sizes, prev, pager, next, jumper" :total="total" @size-change="handleSizeChange" @current-change="handleCurrentChange" /></div></el-card></el-col></el-row><!--新增项目 Drawer 层--><el-drawer title="增加应用" :visible.sync="addDrawerVisible" :direction="direction" size="50%"><el-card shadow="always"><el-form ref="addProjectForm" :model="addProjectForm" status-icon :rules="rules" label-width="100px" class="demo-ruleForm"><el-form-item label="应用名称" prop="name"><el-input v-model="addProjectForm.name" placeholder="请输入应用名称" /></el-form-item><el-form-item><el-button type="primary" @click="addProjectSubmitForm('addProjectForm')">保存</el-button></el-form-item></el-form></el-card></el-drawer></div>
</template><script>import {getDeploymentsList,viewCICD,addDeployment} from '@/api/deployment/deployment-request'import {message} from 'rhea-promise'export default {name: 'DeploymentPage',data() {return {getDeploymentListDto: [], // 数据传给list,列表渲染的数据total: 0,listLoading: true,dialogVisible: false,currentPage: 1,addDrawerVisible: false,jsonstr: {"id": "","projectName": ""},addProjectForm: {name: ""},rules: {name: [{required: true,message: '请输入应用名称',trigger: 'blur'}],},params: {page: 1, // 当前页码page_size: 5 // 每页显示数目},searchMap: {},socket: null}},mounted() {this.getDeploymentsList()},beforeDestroy() {if (this.socket) {this.socket.close()}},methods: {handleSizeChange(val) {console.log(`每页 ${val} 条`)this.params.page_size = valthis.getDeploymentsList()},handleCurrentChange(val) {console.log(`当前页: ${val}`)this.params.page = valthis.getDeploymentsList()},// 格式化 列statusFormatter(row, column, cellValue) {switch (cellValue) {case '0':return '未启动';case '1':return '初始化中';case '2':return '初始化成功';case '3':return '初始失败';case '4':return '部署中';case '5':return '部署成功';case '6':return '部署失败';case '7':return '启动中';case '8':return '启动成功';case '9':return '启动失败';default:return '未知状态';}},// 重置功能, element ui 提供的功能resetForm(formName) {console.log(this.$refs[formName].resetFields)this.$refs[formName].resetFields()this.getDeploymentsList()},searchLog(formName) {console.log(this.searchMap)this.getDeploymentsList()},//新增项目openAddDrawer() {this.addDrawerVisible = true; // 显示Drawer},// 操作日志列表 ajax 请求getDeploymentsList() {// 目标需求:在历史查询列表页面中加入查询的转圈的loading加载动画。this.dataLoading = trueconsole.log('请求参数:' + this.params)getDeploymentsList(this.params).then((res) => {console.log('响应:', res.data.data)this.getDeploymentListDto = res.data.datathis.total = res.data.pagination.totalsetTimeout(() => { // 超过指定超时时间  关闭查询的转圈的loading加载动画this.listLoading = false}, 1.5 * 1000)})},addProjectSubmitForm(formName) {this.$refs[formName].validate((valid) => {if (valid) {this.addProjectInfo();} else {console.log('error submit!!');this.getDeploymentsList();return false;}});},//增加应用addProjectInfo() {this.dataLoading = trueaddDeployment(this.addProjectForm).then((res) => {console.log(res);this.addDrawerVisible = false; // 关闭抽屉this.getDeploymentsList();this.$refs.addOrgForm.resetFields();// this.$router.push('/organizationList'); // 假设列表页的路由路径是 /listsetTimeout(() => {this.listLoading = false}, 1.5 * 1000)})},redeploy(row) {// row.status = '3'; // 更新状态为“部署中”// row.progress = 0; // 初始化进度this.socket = new WebSocket('ws://localhost:8000/ws/cicd_progress/');this.jsonstr.id = row.id;this.jsonstr.projectName = row.name;// alert(JSON.stringify(this.jsonstr));this.socket.onopen = () => {this.socket.send(JSON.stringify(this.jsonstr));};this.socket.onmessage = (event) => {const data = JSON.parse(event.data);// alert(event.data)if (data.code !== 200) {// 处理错误消息row.status = data.data.status; // 更新当前状态// alert("error:" + row.status)console.error(data.message);this.$message.error(data.message); // 显示错误消息this.getDeploymentsList();} else {// alert(data.data.progress)// 更新进度条const progress = data.data.progress; // 假设服务器返回的进度数据在progress字段中row.progress = progress; // 更新进度条的百分比row.status = data.data.status; //更新当前状态// alert("info:" + row.status)this.getDeploymentsList();}};this.socket.onclose = () => {console.log('WebSocket closed');row.status = '5'; // 假设部署成功后状态为5};this.socket.onerror = (error) => {console.error('WebSocket error:', error);row.status = '6'; // 假设部署失败后状态为6this.$message.error('WebSocket 连接错误'); // 显示错误消息};},}}
</script><style>
</style>

九、效果

# 启动前端    新增发布应用,点击重先发布按钮
npm run dev

十、发布成功后 springboot 应用 接口测试

相关文章:

python+django5.1+docker实现CICD自动化部署springboot 项目前后端分离vue-element

一、开发环境搭建和配置 # channels是一个用于在Django中实现WebSocket、HTTP/2和其他异步协议的库。 pip install channels#channels-redis是一个用于在Django Channels中使用Redis作为后台存储的库。它可以用于处理#WebSocket连接的持久化和消息传递。 pip install channels…...

python代码示例(读取excel文件,自动播放音频)

目录 python 操作excel 表结构 安装第三方库 代码 自动播放音频 介绍 安装第三方库 代码 python 操作excel 表结构 求出100班同学的平均分 安装第三方库 因为这里的表结构是.xlsx文件,需要使用openpyxl库 如果是.xls格式文件,需要使用xlrd库 pip install openpyxl /…...

【第十课】Rust并发编程(一)

目录 前言 Fork和Join 前言 本节会介绍Rust中的并发编程&#xff0c;并发编程在编程中是提升cpu使用率的一大利器&#xff0c;通过多线程技术提升效率&#xff0c;Rust的并发和其他编程语言的并发不同的地方在于&#xff0c;Rust号称无畏并发。更重要的一点是安全。Rust中所有…...

图形渲染性能优化

variable rate shading conditional render 设置可见性等&#xff0c; 不需要重新build command buffer indirect draw glMultiDraw* - 直接支持多次绘制glMultiDrawIndirect - 间接多次绘制multithreading 多线程录制 实例化渲染 lod texture array 小对象剔除 投影到…...

elasticsearch的索引模版使用方法

5 索引模版⭐️⭐️⭐️⭐️⭐️ 索引模板就是创建索引时要遵循的模板规则索引模板仅对新创建的索引有效&#xff0c;已经创建的索引并不受索引模板的影响 5.1 索引模版的基本使用 1.查看所有的索引模板 GET 10.0.0.91:9200/_index_template2.创建自定义索引模板 xixi &…...

论文学习——进化动态约束多目标优化:测试集和算法

论文题目&#xff1a;Evolutionary Dynamic Constrained Multiobjective Optimization: Test Suite and Algorithm 进化动态约束多目标优化&#xff1a;测试集和算法&#xff08;Guoyu Chen ,YinanGuo , Member, IEEE, Yong Wang , Senior Member, IEEE, Jing Liang , Senior …...

C++中的volatile关键字

作用&#xff1a; 1.它用于修饰变量&#xff0c;告知编译器该变量的值可能会在程序的外部被改变&#xff0c;编译器不能对这个变量的访问进行优化。这是因为编译器通常会对代码进行优化&#xff0c;例如把变量的值缓存到寄存器中&#xff0c;但对于 volatile 变量&#xff0c;…...

linux桌面qt应用程序UI自动化实现之dogtail

1. 前言 Dogtail适用于Linux 系统上进行 GUI 自动化测试,利用 Accessibility 技术与桌面程序通信;Dogtail 包含一个名为 sniff 的组件,这是一个嗅探器,用于 GUI 程序追踪; 源码下载:​​dogtail PyPI 可通过sudo python setup.py install安装或sudo pip install dogt…...

Hello World C#

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System; 引入了System命名空间&#xff0c;基本输入输出。一般只用这个&#xff0c;后面的不用 using System.Collections.Generic; 包含了定…...

SAP开发语言ABAP开发入门

1. 了解ABAP开发环境和基础知识 - ABAP简介 - ABAP&#xff08;Advanced Business Application Programming&#xff09;是SAP系统中的编程语言&#xff0c;主要用于开发企业级的业务应用程序&#xff0c;如财务、物流、人力资源等模块的定制开发。 - 开发环境搭建 - 首先需…...

应急响应靶机——easy溯源

载入虚拟机&#xff0c;开启虚拟机&#xff1a; &#xff08;账户密码&#xff1a;zgsfsys/zgsfsys&#xff09; 解题程序.exe是额外下载解压得到的&#xff1a; 1. 攻击者内网跳板机IP地址 2. 攻击者服务器地址 3. 存在漏洞的服务(提示:7个字符) 4. 攻击者留下的flag(格式…...

【前端】vscode报错: 无法加载文件 D:\nodejs\node_global\yarn.ps1,因为在此系统上禁止运行脚本。

vscode运行前端代码时候&#xff0c;执行yarn install时候报错 问题&#xff1a; 无法加载文件 D:\nodejs\node_global\yarn.ps1&#xff0c;因为在此系统上禁止运行脚本。 解决方式&#xff1a; 首先用管理员身份运行vscode 查看 get-ExecutionPolicy&#xff0c;Restrict…...

Spring Web MVC(详解中)

文章目录 Spring MVC&#xff08;中&#xff09;RESTFul风格设计RESTFul风格概述RESTFul风格特点RESTFul风格设计规范RESTFul风格好处RESTFul风格实战需求分析RESTFul风格接口设计后台接口实现 基于RESTFul风格练习&#xff08;前后端分离模式&#xff09;案例功能和接口分析功…...

Flutter:encrypt插件 AES加密处理

1、pubspec.yaml导入插件 cupertino_icons: ^1.0.8 # 密码加密 encrypt: 5.0.3encrypt封装 import package:encrypt/encrypt.dart; /// 加密类 class EncryptUtil {static final EncryptUtil _instance EncryptUtil._internal();factory EncryptUtil() > _instance;Encrypt…...

Python bytes类型及用法

在Python中&#xff0c;bytes类型是一种不可变的字节序列&#xff0c;用于存储原始的二进制数据。bytes对象通常用于处理文件、网络通信和其他需要处理原始字节数据的场景。 以下是bytes类型的一些基本用法和特性&#xff1a; 1. 创建bytes对象 可以通过多种方式创建bytes对…...

阅读《基于蒙特卡洛法的破片打击无人机易损性分析》_笔记

目录 基本信息 1 引言 1.1 主要研究内容 1.2 研究必要性&#xff08;为什么要研究&#xff09; 1.3 该领域研究现状&#xff08;别人做了什么/怎么做的&#xff09; 2 主要研究过程&#xff08;我们做了什么&#xff09; 2.1 建立目标仿真模型 2.2 确定毁伤依据 2.3 无…...

【vim】vim怎么把某一列内容复制到另一列

1. vim 怎么把某一列内容复制到另一列 移动光标到你想复制的列的第一个字符上。按下 ctrlv 进入选择模式。按下方向键选择多行。按下 h 或 j 或 k 或 l&#xff0c;选择整列。按下 y 复制所选择的列。移动光标到你想粘贴内容的列的第一个字符上。按下 p 粘贴内容。...

IP划分(笔记)

IPv4 32位4字节 IPv6 128位16字节 IPv4转IPv6 前10字节全0,2字节全1&#xff0c;再加ipv4的4个字节 IPv4划分笔记&#xff08;有类域&#xff09;&#xff1a; A类&#xff1a;首字节必为0b0xxxxxxx 0.0.0.0/8-127.255.255.255/8 实际范围&#xff1a;1.0.0.1/8-126.25…...

【ChatGPT大模型开发调用】如何获得 OpenAl API Key?

如何获取 OpenAI API Key 获取 OpenAI API Key 主要有以下三种途径&#xff1a; OpenAI 官方平台 (推荐): 开发者用户可以直接在 OpenAI 官方网站 (platform.openai.com) 注册并申请 API Key。 通常&#xff0c;您可以在账户设置或开发者平台的相关页面找到申请入口。 Azure…...

人证合一开启安全认证新时代、C#人证合一接口集成、人脸识别

在数字化转型加速推进的今天&#xff0c;确保用户身份的真实性和唯一性成为了各行各业关注的重点。从金融交易到在线教育&#xff0c;从远程办公到智慧医疗&#xff0c;如何高效准确地验证“你是你”变得至关重要。正是在这种背景下&#xff0c;翔云“人证合一”接口应运而生&a…...

EBS 中 Oracle Payables (AP) 模块的相关集成

Oracle E-Business Suite (EBS) 中的 Oracle Payables (AP) 模块是一个全面的应付账款管理系统&#xff0c;它不仅提供了丰富的功能来管理与供应商的财务交易&#xff0c;还通过与其他模块的紧密集成&#xff0c;实现了企业内部各个业务流程的无缝衔接。以下是 Oracle Payables…...

Flask项目入门—会话技术Cookie和Session

Session和Cookie都是用于跟踪用户会话的技术、它们可以存储用户信息&#xff0c;以便在用户与网站进行交互时提供个性化的体验。然而&#xff0c;这两者在存储位置、使用方式、安全性等方面存在显著的差异。 工作原理/流程 Cookie 1、用户第一次访问时候服务器生成 Cookie&a…...

通达OA down存在信息泄露漏洞

免责声明: 本文旨在提供有关特定漏洞的深入信息,帮助用户充分了解潜在的安全风险。发布此信息的目的在于提升网络安全意识和推动技术进步,未经授权访问系统、网络或应用程序,可能会导致法律责任或严重后果。因此,作者不对读者基于本文内容所采取的任何行为承担责任。读者在…...

Python中的简单爬虫

文章目录 一. 基于FastAPI之Web站点开发1. 基于FastAPI搭建Web服务器2. Web服务器和浏览器的通讯流程3. 浏览器访问Web服务器的通讯流程4. 加载图片资源代码 二. 基于Web请求的FastAPI通用配置1. 目前Web服务器存在问题2. 基于Web请求的FastAPI通用配置 三. Python爬虫介绍1. 什…...

Scala入门基础(20)数据集复习拓展

一.Stack栈二.Queue 队列 一.Stack栈 Stack:栈&#xff0c;特殊的结构。它对元素的操作是在头部&#xff1a;栈顶 先进后出的队列。pop表示取出&#xff0c;push表示在栈中添加元素 二.Queue 队列 Queue 队列;先进先出.enqueue入队&#xff0c;dequeue出队。...

leetcode 二叉树的最大深度

104. 二叉树的最大深度 已解答 简单 相关标签 相关企业 给定一个二叉树 root &#xff0c;返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;3…...

elasticsearch集群部署及加密通讯

原文地址&#xff1a;elasticsearch集群部署及加密通讯 – 无敌牛 欢迎参观我的个人博客&#xff1a;无敌牛 – 技术/著作/典籍/分享等 第零步&#xff0c;准备 给各台设备配置虚拟主机名&#xff0c;这样集群不依赖IP&#xff0c;即使IP变动&#xff0c;改动也更方便。参考…...

ML 系列:第 32节 — 机器学习中的统计简介

文章目录 一、说明二、统计概述三、描述性统计与推断性统计3.1 描述统计学3.2 推论统计 四、描述性统计中的均值、中位数和众数 一、说明 机器学习中的统计 随着我们深入研究机器学习领域&#xff0c;了解统计学在该领域的作用至关重要。统计学是机器学习的支柱&#xff0c;它…...

CatVton升级版?CatVton-Flux:AI虚拟试衣方案新选择。

之前的文章中已经和大家介绍过虚拟试衣方案CatVton&#xff0c;感兴趣的小伙伴可以点击下面链接阅读~ 中山大学与Pixocial联手提出CatVTON&#xff1a;轻量化架构与高效训练&#xff0c;助力虚拟试衣技术落地应用&#xff01; 今天给大家介绍的是CatVton-FLUX&#xff0c;它是…...

JavaEE---计算机是如何工作的?

1.了解冯诺依曼体系结构 2.CPU的核心概念,CPU的两个重要指标(核心数和频率) 3.CPU执行指令的流程(指令表,一条一条指令,取指令,解析指令,执行指令) 4.操作系统核心概念(管理硬件,给软件提供稳定的运行环境) 5.进程的概念(运行起来的程序和可执行文件的区别) 6.进程的管理(…...

免费做手机网站有哪些/网络销售平台怎么做

《民法学》作业 一、单项选择题 1&#xff0e;诉讼时效作为权利人不行使权利就丧失人民法院保护其民事权利的法定期间&#xff0c;它一般适用于&#xff1f; A&#xff0e;支配权    B&#xff0e;请求权    C&#xff0e;形成权    D&#xff0e;抗辨…...

wordpress制作/百度开车关键词

我说句实在话啊&#xff0c;GitHub这个网址真的很能勾起人学习的欲望&#xff0c;一进入GitHub的注册页面真的让我这个英语学渣瑟瑟发抖&#xff0c;瞬间立下个flag&#xff1a;好好学习英语。。。。。 我对python的求知欲怎么能被英语所阻挡&#xff0c;感谢Google Chrome网页…...

网站开发助理工程师/郑州seo顾问培训

1. 前言 Druid 的目标是提供一个能够在大数据集上做实时数据摄入与查询的平台&#xff0c;然而对于大多数系统而言&#xff0c;提供数据的快速摄入与提供快速查询是难以同时实现的两个指标。例如对于普通的RDBMS,如果想要获取更快的查询速度&#xff0c;就会因为创建索引而牺牲…...

贵州做团队培训的网站/中国百强县市榜单

1. windows系统 键盘中&#xff1a;鼠标右键 shift F10转载于:https://www.cnblogs.com/rocky-fang/p/6238769.html...

wordpress 安卓主题/seo关键词使用

这道题我们可以看成给定两个黑白树&#xff0c;可以修改其中一棵树的颜色&#xff0c;问最少修改多少颜色可以使两棵树同构。 首先我们知道在树的同构中树上最长链中点&#xff08;如果是偶数的话就是中间两个点&#xff09;是不变的&#xff0c;我们把这个点叫做树的重心&…...

dw网站的滑屏怎么做/网站优化有哪些类型

1&#xff0c;首先安装maven&#xff0c;并配置。 2&#xff0c;新建maven project. 3,选择maven-archetype-webapp. 4,填写afrifact ID即为项目名称。 5&#xff0c;finish后 build path,修改jre为环境默认版本。&#xff08;此时项目结构会变得正确&#xff09; 6&#xff0c…...