pipeline业务发布
业务环境介绍
公司当前业务上线流程首先是通过nginx灰度,dubbo-admin操作禁用,然后发布上线主机,发布成功后,dubbo-admin启用,nginx启用主机;之前是通过手动操作,很不方便,本次优化为pipeline方式实现自动发布,需要saltstack api支持。
pipeline发布流程图
准备工作
将saltstack端dubbo.py脚本部署好,可通过salt直接调用
将所有脚本分别放到对应的主机上面(saltstack端、jenkins端)
jenkins提前准备好 gitlab、nginx ssh、saltapi 相关凭据,mvn、jdk工具
jenkins配置
pipeline脚本
// 此pipeline用于nginx + dubbo结构的应用,如没有dubbo,删除dubbo相关步骤即可
// 提前定义:
// gitlab、nginx ssh、saltapi 相关凭据
// mvn,jdk等工具定义
// saltapi模板中servername地址// 以下所有变量根据实际情况修改
// 本项目的svn代码地址
def svnUrl = 'https://svn****'
// nginx ssh参数,多个以逗号未分隔符
def nginxHosts = '172.87.10.31,172.87.10.41'
// zookeeper主机端口,多个以逗号未分隔符
def zkHostPort = '172.87.40.14:2181,172.87.40.24:2181'
// jenkins发布机脚本绝对路径
def scriptAbsPath = '/app/jenkins_deploy/scripts'
// saltstack 脚本基于salt base路径
def saltScriptPath = 'jenkins_deploy/scripts'
// FTP存储路径映射到saltstack的路径
def ftpSaltPath = 'jenkins_deploy/jenkins_war_packages'
// 项目包名称
def packageName = 'app.war'
// 目包相对路径(相对于$workspace)
def source_file = 'target/' + "${packageName}"
// 应用重启命令
def appRestartCommand = '/app/apache-tomcat-9.0.37/bin/restart.sh app'
// 应用启动用户
def appStartUser = 'app'
// 构建命令
def buildCommand = 'mvn clean package -P product war:war'// saltapi模板
def Salt(salthost, saltfunc, saltargs) {result = salt(authtype: 'pam', clientInterface: local( arguments: saltargs,function: saltfunc, target: salthost, targettype: 'list'),credentialsId: "saltapi",saveFile: true,servername: "http://172.87.10.21:8000")return result
}pipeline {// 执行任务agent any// 定义工具tools {maven 'maven352'jdk 'jdk1.8'}stages {stage("Clone") {steps {checkout([$class: 'SubversionSCM', additionalCredentials: [], excludedCommitMessages: '', excludedRegions: '', excludedRevprop: '', excludedUsers: '', filterChangelog: false, ignoreDirPropChanges: false, includedRegions: '', locations: [[credentialsId: 'jenkinsprd', depthOption: 'infinity', ignoreExternalsOption: true, local: '.', remote: "${svnUrl}"]], workspaceUpdater: [$class: 'UpdateUpdater']])}}// nginx 禁用upstream主机stage("Nginx disable host") {steps {Salt("${nginxHosts}","cmd.script","salt://${saltScriptPath}/nginx_upstream.sh \"disabled ${targetHosts} ${nginx_config_file}\"")sh "/usr/bin/python3 ${scriptAbsPath}/view_saltoutput.py ${WORKSPACE}/saltOutput.json ${nginxHosts} cmd.script"}}// nginx 重新加载配置stage("Nginx reload 1") {input {message "是否重启nginx?"ok "确定"parameters {string(name: "nginx", defaultValue: "${nginx_config_file}", description: '此文件有所改动,请谨慎操作!!!')}}steps {Salt("${nginxHosts}","cmd.script","salt://${saltScriptPath}/nginx_reload.sh")sh "/usr/bin/python3 ${scriptAbsPath}/view_saltoutput.py ${WORKSPACE}/saltOutput.json ${nginxHosts} cmd.script"}}// dubbo 禁用生产者stage("Dubbo disable") {steps {script {// 获取主机注册的所有dubbo服务Salt("${targetHosts}","dubbo.ls","${dubbo_port}")dubbo_all_service = sh(script: "/usr/bin/python3 ${scriptAbsPath}/view_saltoutput.py ${WORKSPACE}/saltOutput.json ${targetHosts} dubbo.ls", returnStdout:true).trim()// dubbo禁用sh "/usr/bin/python3 ${scriptAbsPath}/dubbo.py disable ${zkHostPort} ${targetHosts} ${dubbo_port} ${dubbo_all_service}"}}}// mvn构建、代码发布到应用服务器stage("mvn build and deploy") {steps {// 构建命令sh "${buildCommand}"// 需要修改war包所在的路径sh "python3 ${scriptAbsPath}/ftp_upload.py ${WORKSPACE}/${source_file} ${source_file}"// /tmp/路径不能修改,这个路径要匹配restart.sh中配置的Salt("${targetHosts}","state.sls","""jenkins_deploy.scripts.sync_app_package pillar='{"package_name": "${packageName}"}'""")sh "/usr/bin/python3 ${scriptAbsPath}/view_saltoutput.py ${WORKSPACE}/saltOutput.json ${targetHosts} cp.get_file"// 项目包权限修改为项目启动用户Salt("${targetHosts}","file.chown", "/tmp/${packageName} ${appStartUser} ${appStartUser}")}}// 重启应用服务stage("restart app service") {steps {// 应用重启命令Salt("${targetHosts}","cmd.run","'${appRestartCommand}' env=\'{\"LC_ALL\": \"en_US.UTF-8\",\"LANG\": \"en_US.UTF-8\"}\' runas=${appStartUser}")sh "/usr/bin/python3 ${scriptAbsPath}/view_saltoutput.py ${WORKSPACE}/saltOutput.json ${targetHosts} cmd.run"}}// 测试目标主机是否恢复stage("Test") {steps {println("Test ...")sleep 5}}// dubbo启用生产者stage("Dubbo enable") {input {message "是否启用dubbo?"ok "确定"parameters {string(name: "dubbo", defaultValue: "${targetHosts}-${dubbo_port}", description: '请确定应用正常启动,谨慎操作!!!')}}steps {script {// 获取主机注册的所有dubbo服务Salt("${targetHosts}","dubbo.ls","${dubbo_port}")dubbo_all_service = sh(script: "/usr/bin/python3 ${scriptAbsPath}/view_saltoutput.py ${WORKSPACE}/saltOutput.json ${targetHosts} dubbo.ls", returnStdout:true).trim()// dubbo启用sh "/usr/bin/python3 ${scriptAbsPath}/dubbo.py enable ${zkHostPort} ${targetHosts} ${dubbo_port} ${dubbo_all_service}"}}}// nginx 启用upstream主机stage("Nginx enable host") {steps {Salt("${nginxHosts}","cmd.script","salt://${saltScriptPath}/nginx_upstream.sh \"enabled ${targetHosts} ${nginx_config_file}\"")sh "/usr/bin/python3 ${scriptAbsPath}/view_saltoutput.py ${WORKSPACE}/saltOutput.json ${nginxHosts} cmd.script"}}// nginx 重新加载配置stage("Nginx reload 2") {input {message "是否重启nginx?"ok "确定"parameters {string(name: "nginx", defaultValue: "${nginx_config_file}", description: '此文件有所改动,请谨慎操作!!!')}}steps {Salt("${nginxHosts}","cmd.script","salt://${saltScriptPath}/nginx_reload.sh")sh "/usr/bin/python3 ${scriptAbsPath}/view_saltoutput.py ${WORKSPACE}/saltOutput.json ${nginxHosts} cmd.script"}}}post {success {script {buildDescription "上次构建成功的主机:${params.targetHosts}"}}failure {script {// nginx 启用upstream主机Salt("${nginxHosts}","cmd.script","salt://${saltScriptPath}/nginx_upstream.sh \"enabled ${targetHosts} ${nginx_config_file}\"")sh "/usr/bin/python3 ${scriptAbsPath}/view_saltoutput.py ${WORKSPACE}/saltOutput.json ${nginxHosts} cmd.script"buildDescription "构建失败,请查看错误!"}}aborted {script {// nginx 启用upstream主机Salt("${nginxHosts}","cmd.script","salt://${saltScriptPath}/nginx_upstream.sh \"enabled ${targetHosts} ${nginx_config_file}\"")sh "/usr/bin/python3 ${scriptAbsPath}/view_saltoutput.py ${WORKSPACE}/saltOutput.json ${nginxHosts} cmd.script"buildDescription "手动取消构建!"}}}
}
saltstack server端主机上的脚本
nginx_reload.sh
#!/bin/bashsource /etc/profilenginx -t && nginx -s reload && sleep 3 ; ps -ef | grep nginx: | grep -v grep
nginx_upstream.sh
#!/bin/bash
# Filename : nginx_upstream.sh
# Date : 2021/08/26
# Author : beiguohao
# Email : oct_hao@163.com
# Description: 本脚本用于jenkins pipeline发布代码过程中的禁用启用nginx主机操作SWITCH="$1"
HOSTS="$2"
FILE_NAME="$3"usage(){echo "$0: [enable|enabled|disable|disabled] [hosts] [NGINX_UPSTREAM_CONFIG_FILE]"
}# 启用nginx主机
enabled(){hosts="$1"file_name="$2"IFS=$','for h in ${hosts}dosed -ri "s/.*($h)/ server \1/g" ${file_name}donecat ${file_name}
}# 禁用nginx主机
disabled(){hosts="$1"file_name="$2"IFS=$','for h in ${hosts}dosed -ri "s/.*($h)/# server \1/g" ${file_name}donecat ${file_name}
}# 传递参数不为3,或者任意参数为空则退出脚本
if [ "$#" -ne 3 -o -z "$SWITCH" -o -z "$HOSTS" -o -z "$FILE_NAME" ];thenusageexit 1
ficase $SWITCH inenable|enabled)enabled $HOSTS $FILE_NAME ;;disable|disabled)disabled $HOSTS $FILE_NAME;;*)usageexit 1;;
esac
sync_app_package.sls
{% set package_name = pillar["package_name"] %}sync_app_package:file.managed:- name: /tmp/{{ package_name }}- source: salt://jenkins_deploy/jenkins_war_packages/target/{{ package_name }}- user: zf- group: zf- mode: 644
dubbo.py (此脚本放在saltstack base/_modules目录下面)
# -*- coding: utf-8 -*-
# Filename : nginx_upstream.sh
# Date : 2021/08/26
# Author : beiguohao
# Email : oct_hao@163.com
# Description: 此脚本用于saltstack自定义模块from os.path import join as p_join
import telnetlib
import re__virtualname__ = 'dubbo'
finish = 'dubbo>'def __virtual__():return __virtualname__def ls(port, host='127.0.0.1', timeout=5):'''获取应用注册到dubbo的所有服务的详细信息'''tn = telnetlib.Telnet(host=host, port=port, timeout=timeout)tn.write('ls -l\n')res = tn.read_until(finish).strip(finish)tn.close()res_l = []# 遍历分割成列表的结果for service in res.strip('\r\n').split('\r\n'):serviceName = re.split('\s+->', service)[0]pattern = re.compile('group=(.*?)\&')d = pattern.search(service)if d:res_l.append(p_join(d.group(1), serviceName))continueres_l.append(serviceName)return ','.join(res_l)
test_url.sh
#!/bin/bash
# Filename : test_url.sh
# Date : 2021/08/26
# Author : beiguohao
# Email : oct_hao@163.com
# Description: 此脚本用于测试url是否可以访问URL="$1"
N=0
MAX_N="${2-9999}"usage(){if [ $1 -gt 2 ] || [ $1 -lt 1 ];thenecho "$0 [URL] [REQUEST_NUMBER]"exit 1fi
}Curl(){code=$(curl -s -o /dev/null -w '%{http_code}' $URL)while truedoif [ "$N" -ge "$MAX_N" ];thenecho "Test Fail."exit 1elseif [ "$code" == 200 ];thenecho "Test $URL success, Code: $code."exit 0fifisleep 1N=$((N+1))done
}usage $#
Curl
3. jenkins server端主机上面的脚本
dubbo.py
# -*- coding: utf-8 -*-
# Filename : dubbo.py
# Date : 2021/08/26
# Author : beiguohao
# Email : oct_hao@163.com
# Description: 此脚本操作dubbo-admin中服务的启用和禁用from check_port_connect import check_port
from zookeeper import Zk
from os import path
import urllib.parse
import sysclass Dubbo:def __init__(self, zk_host, dubbo_host, dubbo_port, dubbo_all_service, dubbo_path='/dubbo'):self.zk_host = zk_hostself.dubbo_host = dubbo_hostself.dubbo_port = dubbo_portself.dubbo_host_port = [host + ':%s' % self.dubbo_port for host in self.dubbo_host]self.dubbo_path = dubbo_pathself.zk = Zk(self.zk_host)self.all_node = dubbo_all_service# 写入zookeeper对应dubbo的服务配置模板self.template = 'override://%s/%s?category=configurators&disabled=true&dynamic=false&enabled=true'self._check_port()def _check_port(self):# 检测dubbo主机的端口连通性for host in self.dubbo_host:dubbo_port_test = check_port(host, self.dubbo_port)if dubbo_port_test != 0: sys.exit(1) def _format(self, zk_node, dubbo_host_port):# 分割服务名,group/service 根号分割的名称是有组的服务l = zk_node.split('/')# 大于1就是有组的服务if len(l) > 1:zk_node = l[1]override = self.template % (dubbo_host_port, l[1])override += '&group=' + l[0]else:zk_node = l[0]override = self.template % (dubbo_host_port, l[0])return zk_node, overridedef disable(self):# 循环所有node并禁用所有dubbo主机的服务for zk_node in self.all_node:for host_port in self.dubbo_host_port:zk_node, override = self._format(zk_node, host_port)d = urllib.parse.urlencode({'name': override}).split('name=')[1]self.zk.create('%s/%s/configurators/%s' % (self.dubbo_path, zk_node, d), b'[]')print('dubbo %s的服务已禁用,请查看WEB页面!' % ','.join(self.dubbo_host_port))self.zk.stop()def enable(self):# 循环所有node并禁用所有dubbo主机的服务for zk_node in self.all_node:for host_port in self.dubbo_host_port:zk_node, override = self._format(zk_node, host_port)d = urllib.parse.urlencode({'name': override}).split('name=')[1]self.zk.delete('%s/%s/configurators/%s' % (self.dubbo_path, zk_node, d))print('dubbo %s的服务已启用,请查看WEB页面!' % ','.join(self.dubbo_host_port))self.zk.stop()def servic_status(self):for host_port in self.dubbo_host_port:n = 0for zk_node in self.all_node:zk_node, override = self._format(zk_node, host_port)d = urllib.parse.urlencode({'name': override}).split('name=')[1]res = self.zk.ls('%s/%s/configurators' % (self.dubbo_path, zk_node))# 如果格式化后的值存在于列表中,即为禁用if d not in res:n += 1print('Host: %s, Total: %s, Enable: %s' % (host_port, len(self.all_node), n))if __name__ == '__main__':usage = 'usgae: %s [enable|disable|service_status] [zk_host:port,...] [dubbo_host] [dubbo_port] [dubbo_all_service]' % sys.argv[0]if len(sys.argv) != 6:sys.exit(usage)method = sys.argv[1] zk_host = sys.argv[2]dubbo_host = sys.argv[3].split(',')dubbo_port = sys.argv[4]dubbo_all_service = sys.argv[5].split(',')dubbo = Dubbo(zk_host=zk_host, dubbo_host=dubbo_host, dubbo_port=dubbo_port, dubbo_all_service=dubbo_all_service)if method == 'disable':dubbo.disable()elif method == 'enable':dubbo.enable()elif method == 'service_status':dubbo.servic_status()else:sys.exit(usage)
zookeeper.py
# -*- coding: utf-8 -*-
# Filename : zookeeper.py
# Date : 2021/08/26
# Author : beiguohao
# Email : oct_hao@163.com
# Description: 此脚本用于连接、操作zookeeperfrom kazoo.client import KazooClient
from kazoo.exceptions import NoNodeError
from check_port_connect import check_port
from sys import exitclass Zk:def __init__(self, hosts, timeout=10):self.hosts = hostsself.timeout = timeoutself._zk = KazooClient(hosts=self.hosts, timeout=self.timeout)self._zk.start()def ls(self, path='/'):'''获取Zk执行path中所有node:return: 所有node'''try:all_node = self._zk.get_children(path)return all_nodeexcept Exception as e:print(repr(e))exit(1) def create(self, path, data):'''Zk创建:return:'''try:res = self._zk.create(path, data, makepath=True)return resexcept Exception as e:print(repr(e))exit(1)def delete(self, path):'''Zk 删除节点:param path: 要删除的节点:return:'''try:res = self._zk.delete(path)return resexcept Exception as e:return repr(e)def stop(self):self._zk.stop()
view_saltoutput.py
# -*- coding: utf-8 -*-
# Filename : nginx_upstream.sh
# Date : 2021/08/26
# Author : beiguohao
# Email : oct_hao@163.com
# Description: 此脚本用于查看saltstack api的输出结果,因为saltapi中定义了saveFile: trueimport json, sysdef outPutJson(file_path, hosts, module):'''解析saltapi执行结果输出的json文件切记,不同模块输出格式有所不同'''with open(file_path, 'r') as read_f:data = json.load(read_f)for host in hosts:try:if module == 'cmd.script':res = (host, data[0][host]['ret']['stdout'])elif module == 'cmd.run':res = (host + '(stdout)', data[0][host]['ret'])elif module == 'cp.get_file':res = (host, data[0][host])if not res[1]:sys.exit(res)elif module == 'dubbo.ls':res = data[0][host]print(res)breakelse:res = ''print('%s {\n%s\n}' % res)except KeyError as e:print('KeyError: %s' % e)sys.exit(1)if __name__ == '__main__':usage = "usage: %s [SALT_OUTPUT_FILE] [HOSTS] [MODULE]" % sys.argv[0]if len(sys.argv) != 4:sys.exit(usage) file_path = sys.argv[1]hosts = sys.argv[2].split(',')module = sys.argv[3]outPutJson(file_path, hosts, module)
ftp_upload.py
# -*- coding: utf-8 -*-
# Filename : ftp_upload.py
# Date : 2021/08/26
# Author : beiguohao
# Email : oct_hao@163.com
# Description: 此脚本用于操作ftpfrom ftplib import FTP
from os import path
import sysclass FTPClient:def __init__(self, host, user, passwd, port=21):self.host = hostself.user = userself.passwd = passwdself.port = portself._ftp = Noneself._login()def _login(self):'''登录FTP服务器:return: 连接或登录出现异常时返回错误信息'''try:self._ftp = FTP()self._ftp.connect(self.host, self.port, timeout=30)self._ftp.login(self.user, self.passwd)except Exception as e:print(str(e))sys.exit(1)def upload(self, localpath, remotepath=None):'''上传ftp文件:param localpath: local file path:param remotepath: remote file path:return:'''if not localpath: return 'Please select a local file. '# 读取本地文件fp = open(localpath, 'rb')# 如果未传递远程文件路径,则上传到当前目录,文件名称同本地文件if not remotepath:remotepath = path.basename(localpath)# 上传文件try:self._ftp.storbinary('STOR ' + remotepath, fp)except Exception as e:print(str(e))def nlst(self, dir='/'):'''查看目录下的内容:return: 以列表形式返回目录下的所有内容'''files_list = self._ftp.nlst(dir)return files_listdef del_file(self, filename=None):'''删除文件:param filename: 文件名称:return: 执行结果'''if not filename: return 'Please input filename'try:del_f = self._ftp.delete(filename)except Exception as e:print(str(e))sys.exit(1)def close(self):'''退出ftp连接:return:'''try:# 向服务器发送quit命令self._ftp.quit()except Exception:print('No response from server')sys.exit(1)finally:# 客户端单方面关闭连接self._ftp.close()if __name__ == '__main__':usage = "usage: %s [FILE_NAME] [TARGET_PATH]" % sys.argv[0]ftp_host = '172.85.10.31'ftp_user = 'jenkins_deploy'ftp_password = 'jenkins@deploy_2021'if len(sys.argv) != 3:sys.exit(usage)ftp = FTPClient(host=ftp_host, user=ftp_user, passwd=ftp_password)file_path = sys.argv[1]target_path = sys.argv[2]all_file = ftp.nlst('target')if file_path.startswith('/'):file_path = path.join('/', file_path)f_path = 'target/' + path.basename(file_path)if f_path in all_file: ftp.del_file(f_path)ftp.upload(file_path, target_path)ftp.close()
check_port_connect.py
# -*- coding: utf-8 -*-
# Filename : check_port_connect.py
# Date : 2021/08/26
# Author : beiguohao
# Email : oct_hao@163.com
# Description: 此脚本用于检测端口连通性import socket
import syssocket.setdefaulttimeout(10) def check_port(ip, port):port = int(port)sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)res = sk.connect_ex((ip, port))if res == 0:# print('%s %s port is Open' % (ip, port))return 0else:print('%s %s port is Not Open' % (ip, port))sys.exit(1) if __name__ == '__main__':usage = 'usage: %s [IP|HSOTNAME] [PORT]'if len(sys.argv) != 3:sys.exit(usage) ip = sys.argv[1] port = sys.argv[2]check_port(ip, port)
相关文章:
pipeline业务发布
业务环境介绍公司当前业务上线流程首先是通过nginx灰度,dubbo-admin操作禁用,然后发布上线主机,发布成功后,dubbo-admin启用,nginx启用主机;之前是通过手动操作,很不方便,本次优化为…...
【巨人的肩膀】JAVA面试总结(七)
💪MyBatis 1、谈谈你对MyBatis的理解 Mybatis是一个半ORM(对象关系映射)框架,它内部封装了JDBC,加载驱动、创建连接、创建statement等繁杂的过程,开发者开发时只需要关注如何编写SQL语句,可以…...
Python满屏表白代码
目录 前言 爱心界面 无限弹窗 前言 人生苦短,我用Python!又是新的一周啦,本期博主给大家带来了一个全新的作品:满屏表白代码,无限弹窗版!快快收藏起来送给她吧~ 爱心界面 def Heart(): roottk.Tk…...
Spring学习流程介绍
Spring学习流程介绍 Spring技术是JavaEE开发必备技能,企业开发技术选型命中率>90%; Spring有下面两大优势: 简化开发: 降低企业级开发的复杂性 框架整合: 高效整合其他技术,提高企业级应用开发与运行效率 Spring官网: https://spring.io/ Spring发展…...
杭银消金基于 Apache Doris 的统一数据查询网关改造
导读: 随着业务量快速增长,数据规模的不断扩大,杭银消金早期的大数据平台在应对实时性更强、复杂度更高的的业务需求时存在瓶颈。为了更好的应对未来的数据规模增长,杭银消金于 2022 年 10 月正式引入 Apache Doris 1.2 对现有的风…...
Flink学习笔记(六)Time详解
一、Flink中Time的三种类型: Stream数据中的Time(时间)分为以下3种: 1.Event Time(事件产生的时间): 事件的时间戳,通常是生成事件的时间。Event time 是事件本身的时间,…...
「Vue面试题」在项目中你是如何解决跨域的?
文章目录一、跨域是什么二、如何解决CORSProxy一、跨域是什么 跨域本质是浏览器基于同源策略的一种安全手段 同源策略(Sameoriginpolicy),是一种约定,它是浏览器最核心也最基本的安全功能 所谓同源(即指在同一个域&…...
java八股文--数据库
数据库1.索引的基本原理2.聚簇和非聚簇索引的区别3.mysql索引的数据结构以及各自的优劣4.索引的设计原则5.事务的基本特性和隔离级别6.mysql主从同步原理7.简述MyISAM和InnoDB的区别8.简述mysql中索引类型及对数据库性能的影响9.Explain语句结果中各个字段分别表示什么10.索引覆…...
vue中名词解释
No名称略写作用应用场景其他1 单页面应用 (Single-page application) SPA 1,控制整个页面 2,抓取更新数据 3,无需加载,进行页面切换 丰富的交互,复杂的业务逻辑的web前端一般要求后端提供api数据…...
基于Java+SSM+Vue的旅游资源网站设计与实现【源码(完整源码请私聊)+论文+演示视频+包运行成功】
博主介绍:专注于Java技术领域和毕业项目实战 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇🏻 不然下次找不到哟 Java项目精品实战案例(200套) 目录 一、效果演示 二、…...
用于人工智能研究的开源Python微电网模拟器pymgrid(入门篇)
pymgrid是一个开源Python库,用于模拟微型电网的三级控制,允许用户创建或自行选择的微电网。并可以使用自定义的算法或pymgrid中包含的控制算法之一来控制这些微电网(基于规则的控制和模型预测控制)。 pymgrid还提供了与OpenAI Gy…...
运算放大器:电压比较器、电压跟随器、同相比例放大器
目录一、单限电压比较器二、滞回电压比较器三、窗口电压比较器四、正点原子直流电机驱动器电路分析实战1、电压采集电路2、电流采集电路3、过流检测电路Ⅰ、采用分压后的输入电压:Ⅱ、采用理想电压源的输入电压:Ⅲ、同相输入电压采用的是非理想电压源&am…...
Vector - CAPL - 实时时间on *(续2)
继续继续。。。四、键盘事件这个键盘事件是我个人起的名字,为了方便与其他事件进行区分,为什么要把这一个单独拉出来说呢,因为它的用处实在是太广泛了,基本只要是使用CANoe做一些基本的自动化测试小工具,都会用到它&am…...
数据质量管理的四个阶段
然而,我们需要按照什么流程来对数据质量进行有效的管控,从而提升数据质量,释放数据价值?一般来讲,数据质量控制流程分为4个阶段:启动、执行、检查、处理。在管控过程中这4个阶段需不断循环,螺旋…...
Spring源码面试最难问题——循环依赖
前言 问:Spring 如何解决循环依赖? 答:Spring 通过提前曝光机制,利用三级缓存解决循环依赖(这原理还是挺简单的,参考:三级缓存、图解循环依赖原理) 再问:Spring 通过提前…...
【计组】RAM的深入理解
一、存储机理 RAM的实现逻辑有种,分别是触发器和电容。 SRAM(Static)DRAM(Dynamic)存储方式触发器电容破坏性读出否(触发器具有稳态,能够锁住0或1两种状态)是(电容需要…...
JavaScript 之数据交互
在前后端交互中,前端通常需要对接口返回的数据进行格式转换、遍历、循环等;通常会用到以下函数和方法: forEach()、map()遍历数组(map返回新的数组);forEach()只能使用try catah终止循环;for in…...
Python 十大开源Python库,看看你熟悉几个?
嗨害大家好鸭!我是芝士❤ 对于码农来说, 关注的永远是新近有什么流行的、 既能解决问题又好用的利器。 本文就为你盘点十大开源Python库。 1、Pipenv 第一名非它莫属, 这个工具2017年初才发布, 但它已经能够影响每个Python开发…...
不愧是阿里开发的SpringBoot实战文档:入门+基础+进阶+项目,应有尽有
SpringBoot SpringBoot毋庸置疑,在Java开发中会因为项目流量太大需要切换到SpringCloud(SpringBoot)也会极为顺利。而且现在越来越多的公司都在采用SpringBoot,对SpringBoot关注和使用的开发者也越来越多了! SpringB…...
Vue(3)-vue中的Ajax、Vuex、路由及UI组件库
课程链接 目录4.Vue中的Ajax4.1.vue脚手架配置代理4.1.1.方法一4.1.2.方法二4.2.插槽5.Vuex5.1.理解Vuex5.1.1.概念5.1.2.何时使用?5.1.3.vuex原理5.2.vuex使用5.2.1.搭建vuex环境5.2.2.基本使用5.2.3.getters的使用5.2.4.四个map方法的使用5.2.5.模块化命名空间6.路…...
jwt 学习笔记
概述 JWT,Java Web Token,通过 JSON 形式作为 Web 应用中的令牌,用于在各方之间安全地将信息作为 JSON 对象传输,在数据传输过程中还可以完成数据加密、签名等相关处理 JWT 的作用如下: 授权:一旦用户登…...
网络安全实战从 0 到 1 彻底掌握 XXE
0x01 什么是 XXE个人认为,XXE 可以归结为一句话:构造恶意 DTD介绍 XXE 之前,我先来说一下普通的 XML 注入,这个的利用面比较狭窄,如果有的话应该也是逻辑漏洞。既然能插入 XML 代码,那我们肯定不能善罢甘休…...
如何安装 Composer
下载 Composer 安装前请务必确保已经正确安装了 PHP。打开命令行窗口并执行 php -v 查看是否正确输出版本号。 打开命令行并依次执行下列命令安装最新版本的 Composer: php -r "copy(https://install.phpcomposer.com/installer, composer-setup.php);"p…...
WPF 常用控件
WPF六种常用控件:布局控件、内容控件、带标题内容控件、条目控件、带标题条目控件和特殊内容控件(如:TextBox,TextBlock,Image等)。实例链接:WPF常用控件实例Window(窗体)Winodw窗体派生自ContentControl,有一个Content属性,里面可…...
河南工程学院蓝桥培训(2.21)
1,金币 461. 金币 - AcWing题库 #include <iostream> using namespace std; int n,a,ans,s; int main(){cin>>n;while(n--){if(a0)as;anss,a--;}cout<<ans;return 0; }...
新人使用Git获取远程仓库项目
前言 这篇git技术篇非常的简单基础,写它的原因很简单,因为现在很多的年轻人都很浮躁,刚入门就想学最牛x的,看不起基础的一些技术,比如说git操作、Linux基础命令,编程基础啥的。我身边有很多这样的年轻人&a…...
理解信号的
在日常生活中我们也经常面临许多的信号,手机通知、过红绿灯。。。这些信号在没有发生之前我们就知道这种信号产生我们需要干什么,那Linux里信号产生后,又怎么知道要做什么呢? -- 那当然是由程序员自己去设置啊 由于我们的用户空间…...
SpringSecurity学习(七)授权
授权 什么是权限管理 权限管理核心概念 SpringSecurity权限管理策略 基于URL地址的权限管理 基于方法的权限管理 一、权限管理 二、授权核心概念 在认证的过程成功之后会将当前用户登录信息保存到Authentication对象中,Authentication对象中有一个getAuthorities…...
【Vue3】模板语法
🏆今日学习目标:模板语法 😃创作者:颜颜yan_ ✨个人格言:生如芥子,心藏须弥 ⏰本期期数:第三期 🎉专栏系列:Vue3 文章目录前言声明响应式状态插值文本Attributeÿ…...
Linux基础
环境搭建:linux安装、远程连接常用命令:文件、目录、拷贝、移动、打包、压缩、文本编辑安装软件:文件上传、jdk、tomcat、mysql项目部署:Java应用、Python应用、日志查看、系统管理、用户权限Linux是一套免费使用、自由传播的操作…...
wordpress 图片服务器配置/百度网站推广价格查询
登录远程SQL服务器 一 看ping 服务器IP能否ping通。 这个实际上是看和远程sql server 2000服务器的物理连接是否存在。 如果不行,请检查网络,查看配置,当然得确保远程sql server 2000服务器的IP拼写正确。 二 在Dos或命令行下输入telnet …...
怎么做网站和服务器吗/年轻人不要做网络销售
一、进入dos命令行 按下菜单键windowsR弹出运行框,然后输入cmd,并回车。就会弹出dos命令行: 直接回车; 然后再退出数据库:exit; 然后输入mysqladmin -u root -p password 回车 第一个是密码有密码就打没…...
seo网站关键词优化方法/推广文案范例
前言:本人是java后端开发,用到的linux命令不是很多,只展示一些常用的命令,方便在工作中快速使用。一些命令的扩展及详细参数,请小伙伴们自行百度。内容有错误或者有异议的欢迎批评指正。用户&用户组创建用户&#…...
站长之家是什么/惠州seo公司
$_G 保存了 Discuz! 中所有的预处理数据缓存能够很好的提高程序的性能,一些配置数据没必要每次都查询数据库,只要在修改了的时候更新下缓存即可。Discuz! 中所有的缓存保存在 $_G[cache] 中$_G[member] 会员信息数据$_G[uid] 用户 uid$_G[username] 用户…...
如何再网站上做免费广告/品牌营销公司
上面我们说了神经网络的基础知识,根据上章的基础尝试搭建一个标准的3层神经网络,参考https://www.cnblogs.com/bestExpert/p/9128645.html 1.框架代码 1.>初始化函数 — 设定输入层节点、隐藏层节点、输出层节点的数量,设置学习率和各层的…...
北京公司网站设计价格/seo方案
在canvas API中,我们发现只提供了画实线的方法实现,并没有虚线的相关方法,那么如何实现画虚线呢?现实中,虚线是由一小段小段的实线线段组成,那么只要我们通过画出等长度的线段就可以组成我们想要的虚线.下面我们就可以根据上面的原理来实现虚线的画法.如下:var context docum…...