首页
关于小站
朋友
壁纸
留言
时光之书
笔顺字帖
LayUI手册
Search
1
【PHP】PHPoffice/PHPSpreadsheet读取和写入Excel
1,673 阅读
2
【Layui】控制页面元素展示隐藏
1,520 阅读
3
【Git】No tracked branch configured for branch master or the branch doesn't exist.
1,460 阅读
4
【PHP】PHP实现JWT生成和验证
1,370 阅读
5
精准检测,助力社交管理 —— 微信好友检测服务来袭!
1,278 阅读
默认分类
PHP
ThinkPHP
Laravel
面向对象
设计模式
算法
基础
网络安全
Web
HTML
CSS
JavaScript
jQuery
Layui
VUE
uni-app
Database
MySQL
Redis
RabbitMQ
Nginx
Git
Linux
Soft Ware
Windows
网赚
Go
Docker
登录
Search
标签搜索
PHP
函数
方法
类
MySQL
ThinkPHP
JavaScript
OOP
Layui
Web
Server
Docker
Linux
PHPSpreadsheet
PHPoffice
Array
设计模式
Git
排序算法
基础
小破孩
累计撰写
244
篇文章
累计收到
13
条评论
首页
栏目
默认分类
PHP
ThinkPHP
Laravel
面向对象
设计模式
算法
基础
网络安全
Web
HTML
CSS
JavaScript
jQuery
Layui
VUE
uni-app
Database
MySQL
Redis
RabbitMQ
Nginx
Git
Linux
Soft Ware
Windows
网赚
Go
Docker
页面
关于小站
朋友
壁纸
留言
时光之书
笔顺字帖
LayUI手册
搜索到
240
篇与
的结果
2025-05-22
【MySQL】查询百万数据导出处理方法(数据集合统一返回)
public function getExportList($map) { // 定义初始分页大小和最小分页大小 $initialPageSize = 1000; $minPageSize = 100; $pageSize = $initialPageSize; // 计算可用内存(保留15%缓冲) $memoryLimit = (int) ini_get('memory_limit') * 0.85; $lastId = 0; $allData = []; $hasMoreData = true; // 用于动态调整分页大小的变量 $lastBatchMemoryUsage = 0; $avgRecordSize = 0; while ($hasMoreData) { // 动态调整分页大小 if ($lastBatchMemoryUsage > 0 && $avgRecordSize > 0) { $currentMemory = memory_get_usage(true) / (1024 * 1024); $availableMemory = $memoryLimit - $currentMemory; // 基于剩余内存和记录大小计算安全分页大小 $safePageSize = max( $minPageSize, min( $initialPageSize, (int)($availableMemory / ($avgRecordSize * 1.5)) // 1.5倍安全系数 ) ); $pageSize = ($safePageSize < $pageSize) ? $safePageSize : $pageSize; } // 执行分页查询 $list = self::where($map) ->withoutField(['z_create_time', 'z_update_time']) ->where('z_id', '>', $lastId) ->order('z_id', 'asc') ->limit($pageSize) ->select(); if ($list->isEmpty()) { break; } $listData = $list->toArray(); $batchCount = count($listData); // 计算当前批次内存占用 $batchMemory = memory_get_usage(true); foreach ($listData as $record) { $allData[] = $record; // 直接添加减少内存操作 } $batchMemory = (memory_get_usage(true) - $batchMemory) / (1024 * 1024); // 更新内存跟踪指标 if ($batchCount > 0) { $currentAvg = $batchMemory / $batchCount; $avgRecordSize = ($avgRecordSize > 0) ? ($avgRecordSize * 0.7 + $currentAvg * 0.3) // 平滑平均 : $currentAvg; $lastBatchMemoryUsage = $batchMemory; } // 更新迭代变量 $hasMoreData = ($batchCount === $pageSize); if ($hasMoreData) { $lastRecord = end($listData); $lastId = (int)$lastRecord['z_id']; reset($listData); // 重置数组指针 } // 资源清理 unset($list, $listData); if (gc_enabled()) { gc_collect_cycles(); } } return $allData; } //导出14730条数据,需要34.05秒,字段有50个,全是非空状态,字段数量会影响响应时间,一般导出起飞无压力 public function getExportList($map) { $pageSize = 1000; $lastId = 0; $allData = []; while (true) { // 查询当前批次 $list = self::where($map) ->withoutField(['z_create_time', 'z_update_time']) ->where('z_id', '>', $lastId) ->order('z_id', 'asc') ->limit($pageSize) ->select(); // 无数据时终止循环 if ($list->isEmpty()) { break; } $batch = $list->toArray(); $batchSize = count($batch); // 直接追加数据(避免array_merge内存峰值) foreach ($batch as $record) { $allData[] = $record; } // 到达数据末尾 if ($batchSize < $pageSize) { break; } // 更新最后ID $lastId = (int)end($batch)['z_id']; // 资源清理 unset($list, $batch); if ($batchSize >= 500) { // 仅在大批次后回收 gc_collect_cycles(); } } return $allData; } //这个是34.59秒。其他有很多方法,正在尝试30秒内
2025年05月22日
10 阅读
0 评论
1 点赞
2025-05-17
【ThinkPHP】创建有背景的微信小程序二维码
<?php namespace app\common\lib\wechat; use think\Exception; use think\facade\Cache; use think\facade\Request; use think\Image; use think\facade\Db; class QrCode extends Basic { // 小程序页面路径 private string $path = "pages/myCenter/invite"; // 小程序码保存路径 private string $savePath = "./storage/qrcode/"; // 二维码参数 private string $param = ""; public function __construct(string $path = "", string $field = "", string $param = "", int $width = 430) { if (!empty($path) && empty($field)) { $this->path = $path; } if (!empty($path) && !empty($field) && !empty($param)) { $this->path = "{$path}?{$field}={$param}"; } $this->param = $param; } /** * 生成小程序码并可选择合并背景图 * * @param string $backgroundPath 背景图路径 * @param int $qrWidth 二维码在背景图上的宽度位置 * @param int $qrHeight 二维码在背景图上的高度位置 * @return string 生成后的二维码URL */ public function setQrcode(string $backgroundPath = '', int $qrWidth = 160, int $qrHeight = 530): string { try { // 获取访问令牌 $accessToken = Cache::get('accesstoken'); if (empty($accessToken)) { $accessToken = (new AccessToken())->getAccesToken(); Cache::set('accesstoken', $accessToken, 7200); // 假设token有效期为2小时 } // 请求小程序码 $url = "https://api.weixin.qq.com/wxa/getwxacode?access_token={$accessToken}"; $data = [ 'path' => $this->path, 'scene' => 'type=qrcode', 'width' => 430, ]; $result = $this->curlPost($url, $data, 'POST'); if ($result === false || isset($result['errcode'])) { throw new Exception("Failed to get QR code: " . json_encode($result)); } // 保存二维码到文件 $fileName = md5($this->param); $directory = $this->savePath . date('Ymd') . '/'; if (!$this->createDirectory($directory)) { throw new Exception("目录创建失败: {$directory}"); } $filePath = "{$directory}{$fileName}.png"; if (!file_put_contents($filePath, $result)) { throw new Exception("文件写入失败: {$filePath}"); } // 生成完整URL $fullDomain = (new \app\common\lib\data\Str())->getFullDomain(); $qrcodeUrl = $fullDomain . ltrim($filePath, '.'); // 合并背景图(如果提供) if (!empty($backgroundPath)) { return $this->mergeWithBackground($backgroundPath, $filePath, $qrcodeUrl, $qrWidth, $qrHeight); } return $qrcodeUrl; } catch (Exception $e) { // 记录错误日志 error_log($e->getMessage()); return ''; } } /** * 将二维码与背景图合并 */ private function mergeWithBackground(string $backgroundPath, string $qrcodePath, string $defaultUrl, int $qrWidth, int $qrHeight): string { try { $fileName = md5(uniqid() . time()); $newImagePath = $this->savePath . date('Ymd') . "/{$fileName}.png"; $background = Image::open($backgroundPath); $background->water($qrcodePath, [$qrWidth, $qrHeight])->save($newImagePath); $imageInfo = [ 'url' => Request::domain() . substr($newImagePath, 1), 'size' => filesize($newImagePath), 'name' => $fileName, 'mime' => mime_content_type($newImagePath), 'ext' => 'png', ]; $fileData = [ 'f_uuid' => setUUID(), 'f_file' => $imageInfo['url'], 'f_location' => 0, 'f_type' => 'image', 'f_info' => serialize($imageInfo), 'f_user_uuid' => $this->request->index_user_uuid ?? '', 'f_create_time' => time(), ]; Db::name('File')->insert($fileData); return $imageInfo['url']; } catch (Exception $e) { // 记录错误日志 error_log($e->getMessage()); return $defaultUrl; } } /** * 递归创建目录 */ private function createDirectory(string $path, int $mode = 0777, bool $recursive = true): bool { if (is_dir($path)) { return true; } if (mkdir($path, $mode, $recursive)) { chmod($path, $mode); return true; } if (!is_dir(dirname($path))) { if ($this->createDirectory(dirname($path), $mode, $recursive)) { return $this->createDirectory($path, $mode, $recursive); } } return false; } /** * 发送HTTP POST请求 */ // public function curlPost($url, $data, $method = "POST") // { // $ch = curl_init(); //1.初始化 // curl_setopt($ch, CURLOPT_URL, $url); //2.请求地址 // curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);//3.请求方式 // //4.参数如下 // curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);//https // curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); // curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (compatible; MSIE 5.01; Windows NT 5.0)');//模拟浏览器 // curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); // curl_setopt($ch, CURLOPT_AUTOREFERER, 1); // curl_setopt($ch, CURLOPT_HTTPHEADER, array('Accept-Encoding: gzip, deflate'));//gzip解压内容 // curl_setopt($ch, CURLOPT_ENCODING, 'gzip,deflate'); // // if ($method == "POST") {//5.post方式的时候添加数据 // $data = json_encode($data); // curl_setopt($ch, CURLOPT_POSTFIELDS, $data); // } // curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // $tmpInfo = curl_exec($ch);//6.执行 // // if (curl_errno($ch)) {//7.如果出错 // return curl_error($ch); // } // curl_close($ch);//8.关闭 // return $tmpInfo; // } }
2025年05月17日
15 阅读
0 评论
0 点赞
2025-05-13
【PHP】PHPExcel 使用手册
PHPExcel 是一个用于操作 Microsoft Excel 格式文件的 PHP 库,它支持读取和写入多种格式(如 .xls, .xlsx, .csv 等)。不过需要注意,PHPExcel 项目已停止维护,推荐使用其继任者 PhpSpreadsheet。以下是 PHPExcel 的基本使用指南:1. 安装 PHPExcel# 使用 Composer 安装(推荐) composer require phpoffice/phpexcel2. 读取 Excel 文件require 'vendor/autoload.php'; use PHPExcel_IOFactory; // 读取文件 $inputFileName = 'example.xlsx'; $objPHPExcel = PHPExcel_IOFactory::load($inputFileName); // 获取第一个工作表 $sheet = $objPHPExcel->getActiveSheet(); // 获取最高行和最高列 $highestRow = $sheet->getHighestRow(); $highestColumn = $sheet->getHighestColumn(); // 遍历数据 for ($row = 1; $row <= $highestRow; $row++) { for ($col = 'A'; $col <= $highestColumn; $col++) { $cellValue = $sheet->getCell($col.$row)->getValue(); echo "Row $row, Column $col: $cellValue\n"; } }3. 创建新的 Excel 文件require 'vendor/autoload.php'; use PHPExcel; use PHPExcel_IOFactory; // 创建新的 PHPExcel 对象 $objPHPExcel = new PHPExcel(); // 设置文档属性 $objPHPExcel->getProperties() ->setCreator("Your Name") ->setTitle("Sample Excel File"); // 获取活动工作表 $sheet = $objPHPExcel->getActiveSheet(); // 设置单元格值 $sheet->setCellValue('A1', 'Hello'); $sheet->setCellValue('B1', 'World!'); $sheet->setCellValue('A2', 'This is a sample spreadsheet.'); // 保存为 .xlsx 文件 $objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007'); $objWriter->save('new_file.xlsx');4. 设置样式// 设置字体样式 $sheet->getStyle('A1')->getFont() ->setName('Arial') ->setSize(14) ->setBold(true) ->setColor(new PHPExcel_Style_Color(PHPExcel_Style_Color::COLOR_RED)); // 设置单元格背景色 $sheet->getStyle('A1')->getFill() ->setFillType(PHPExcel_Style_Fill::FILL_SOLID) ->getStartColor()->setARGB('FFEEEEEE'); // 设置对齐方式 $sheet->getStyle('A1')->getAlignment() ->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_CENTER) ->setVertical(PHPExcel_Style_Alignment::VERTICAL_CENTER); // 设置列宽 $sheet->getColumnDimension('A')->setWidth(20);5. 合并单元格// 合并 A1 到 B1 的单元格 $sheet->mergeCells('A1:B1'); // 取消合并 $sheet->unmergeCells('A1:B1');6. 处理日期格式// 设置日期值(PHPExcel 使用 Excel 时间戳格式) $dateTime = new DateTime(); $sheet->setCellValue('A1', $dateTime->format('Y-m-d H:i:s')); // 设置单元格格式为日期 $sheet->getStyle('A1')->getNumberFormat() ->setFormatCode('yyyy-mm-dd hh:mm:ss');7. 保存为不同格式// 保存为 .xlsx 格式 $objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007'); $objWriter->save('file.xlsx'); // 保存为 .xls 格式 $objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel5'); $objWriter->save('file.xls'); // 保存为 CSV 格式 $objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'CSV'); $objWriter->save('file.csv');8. 从浏览器下载文件// 设置响应头 header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); header('Content-Disposition: attachment;filename="download.xlsx"'); header('Cache-Control: max-age=0'); // 输出到浏览器 $objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007'); $objWriter->save('php://output'); exit;注意事项性能问题:处理大量数据时,PHPExcel 可能占用较多内存。考虑使用 PHPExcel_CachedObjectStorageFactory 进行优化。替代方案:推荐使用 PhpSpreadsheet,它是 PHPExcel 的官方继任者,修复了许多问题并提供更好的性能。内存优化:// 设置为只读模式以减少内存消耗 $objReader = PHPExcel_IOFactory::createReader('Excel2007'); $objReader->setReadDataOnly(true); $objPHPExcel = $objReader->load('large_file.xlsx');如需更详细的文档,请参考 PHPExcel 官方文档(注意:项目已停止维护)。
2025年05月13日
14 阅读
0 评论
0 点赞
2025-05-08
毕业设计,程序启航 —— 为大学生打造专属编程毕业设计服务
前言大学尾声,毕业设计是每位学子迈向专业领域的重要里程碑。对于计算机相关专业的学生而言,编程毕业设计更是展现技术实力、创新思维与实践能力的核心舞台。然而,面对从网页设计到前后端开发等复杂多样的项目需求,许多同学往往感到无从下手。别担心!我们提供一站式编程毕业设计服务,助你轻松开启毕业设计之旅,为未来职业生涯筑牢根基。一、网页设计:打造数字世界的视觉盛宴网页是互联网时代的关键窗口,优质的网页设计既能吸引用户,又能高效传递信息、彰显创意。我们深谙网页设计的重要性,在毕业设计中为你提供全方位服务:创意规划定制:基于你的毕业设计主题,我们将与你深度沟通,挖掘独特创意点。无论是企业官网、个人作品展示,还是特定功能专题页面,我们都会量身定制整体规划。从页面布局、色彩搭配,到导航结构、交互元素,每个细节都贴合设计需求,兼顾用户体验与视觉美感。专业视觉塑造:专业设计团队运用前沿理念与工具,精心雕琢网页视觉效果。从高清图片处理、精美图标设计,到流畅动画效果、和谐色彩搭配,力求让网页在视觉上脱颖而出,为毕业设计增添亮眼亮点。响应式完美适配:在多设备浏览的当下,响应式设计至关重要。我们确保网页在桌面电脑、笔记本、平板电脑及手机等各类屏幕尺寸上,都能呈现一致且优质的浏览体验,体现你对技术细节的全面把控,提升毕业设计专业性。二、前端代码编写:构建交互流畅的用户界面前端代码是实现网页功能与交互的关键,直接影响用户体验。我们的前端开发服务聚焦于打造高效、稳定且具创意的前端代码:精准技术选型:依据毕业设计项目需求,选择 HTML5、CSS3、JavaScript 等适配的前端技术栈,并结合 Vue.js、React.js 等流行框架,快速搭建稳固架构。这些框架可提升开发效率,保障代码的可维护性与扩展性,增强毕业设计技术竞争力。交互功能实现:我们以用户体验为核心,精心设计并实现各类交互功能。无论是表单验证、动态数据展示,还是拖拽、滑动、折叠等复杂交互效果,都能通过精湛代码实现流畅自然的交互体验,让网页从静态展示升级为智能互动界面,为毕业设计注入趣味性与实用性。性能深度优化:开发过程中,我们高度关注网页性能。通过代码压缩、图片优化、缓存策略等技术手段,确保网页加载迅速、运行流畅,展示你对技术细节与性能优化的重视,助力毕业设计脱颖而出。三、后台程序编写:筑牢数据处理与业务逻辑的基石后台程序是毕业设计的核心,承担数据存储、业务逻辑处理及前后端交互等关键任务。我们提供专业后台程序编写服务,保障毕业设计稳定高效运行:数据库设计优化:根据毕业设计业务需求,精心设计合理数据库结构,选用 MySQL、MongoDB 等适配的数据库管理系统,并进行性能优化。从数据表创建、索引建立,到数据操作与复杂查询优化,全方位保障数据库高效存储与处理数据,为毕业设计提供坚实数据支撑。业务逻辑实现:深入理解你的设计需求,将复杂业务逻辑转化为清晰高效的后台代码。无论是用户管理、订单处理,还是数据分析等业务功能,都以严谨编程实现准确可靠的功能。同时注重代码可读性与可维护性,遵循编程规范,使毕业设计技术实现更专业规范,便于后续扩展维护。接口开发与安全防护:在前后端分离模式下,开发稳定高效的 API 接口,确保数据交互顺畅安全。采用身份验证、数据加密、访问控制等技术手段,防止数据泄露与恶意攻击,守护毕业设计数据与系统安全。四、全程辅导与技术支持:伴你成长,助你成功我们明白,毕业设计不仅是代码编写,更是学习成长的过程。为此,我们提供全程辅导与技术支持:一对一专属辅导:专业导师将提供一对一辅导服务,从选题到答辩全程跟踪进度。针对技术难题、设计思路优化等问题,根据你的实际情况定制个性化辅导方案,助力顺利完成毕业设计。丰富学习资源:为帮助你提升技术能力,我们提供丰富技术培训与学习资源,涵盖编程语言基础教程、前端框架实战课程、后台开发高级技巧等。让你在完成毕业设计的同时,积累宝贵技术经验,为职业发展奠基。科学项目管理:制定详细项目计划,将毕业设计分解为具体任务并明确时间节点。实施过程中定期沟通,跟踪进度,及时解决问题,确保按时高质量完成。同时根据实际灵活调整计划,保障毕业设计顺利有序推进。五、联系方式如需咨询或下单,欢迎通过 QQ 3584685883 与我们私聊,我们随时在线为你服务。六、结语毕业设计是大学生涯的重要里程碑,也是迈向专业领域的关键一步。选择我们的编程毕业设计服务,你将获得专业的网页设计、前端开发、后台程序编写及全程辅导支持。我们致力于打造高质量、有创意且技术先进的毕业设计作品,助你在众多作品中脱颖而出,为职业生涯开启成功之门。让我们携手同行,共同书写编程毕业设计的精彩篇章!
2025年05月08日
18 阅读
0 评论
0 点赞
2025-05-07
【PHP】PHP实现无限级树形分类 树形分类 如果子集的pid不是空,父级id不存在,则子集不展示
/** * @Author:小破孩 * @Email:3584685883@qq.com * @Time:2024/12/17 22:27 * @param $arr * @param $id * @param $pid * @return array * @Description:树形分类 如果子集的pid不是空,父级id不存在,则子集不展示 */ public function getTreeByDateDelChile($arr,$id,$pid) { $items = []; foreach($arr as $v){ $items[$v[$id]] = $v; } $tree = []; foreach($items as $k => $item){ if($item[$pid] &&!isset($items[$item[$pid]])){ unset($items[$k]); continue; } if(isset($items[$item[$pid]])){ $items[$item[$pid]]['child'][] = &$items[$k]; }else{ $tree[] = &$items[$k]; } } return $tree; } /** * @Author:小破孩 * @Email:3584685883@qq.com * @Time:2024/9/14 16:59 * @param array $arr * @param string $children * @return array * @Description:将树形数组转换成一维数组 */ public function setManyTosingle(array $arr = [], string $children = 'child'): array { $result = []; foreach ($arr as $item) { // 先将当前节点添加到结果数组中 $newItem = $item; if (isset($newItem[$children])) { unset($newItem[$children]); } $result[] = $newItem; // 递归处理子节点 if (isset($item[$children]) && is_array($item[$children])) { $result = array_merge($result, $this->setManyTosingle($item[$children], $children)); } } return $result; }
2025年05月07日
19 阅读
0 评论
0 点赞
2025-05-06
【PHP】清空MySQL数据,索引重置
<?php // 定义排除表的常量 const EXCLUDE_TABLES = [ 'web_admin_company', 'web_admin_func', 'web_admin_role', 'web_admin_user', 'web_app_config', 'web_china_city', 'web_china_city_area', 'web_china_city_backup', 'web_company_config', 'web_shop_category', 'web_tppay', // 'web_shop_goods_tmpserver', ]; class SomeClass { public function truncateTables() { try { // 开启事务 Db::startTrans(); // 获取所有表名 $tables = Db::query('SHOW TABLES'); $tableNames = array_map('current', $tables); foreach ($tableNames as $tableName) { if (!in_array($tableName, EXCLUDE_TABLES)) { // 使用参数化查询清空表并重置索引 Db::execute("TRUNCATE TABLE `$tableName`"); echo "表 {$tableName} 已清空<br>"; } } // 提交事务 Db::commit(); } catch (\Exception $e) { // 回滚事务 Db::rollback(); // 记录错误日志 error_log("发生错误: " . $e->getMessage()); echo "发生错误: " . $e->getMessage(); } } }
2025年05月06日
17 阅读
0 评论
0 点赞
2025-04-29
【Nginx】什么是Nginx
Nginx(发音为“engine x”)是一款高性能的开源Web服务器、反向代理服务器,同时也支持HTTP缓存、负载均衡、邮件代理等功能。它由俄罗斯工程师Igor Sysoev于2004年开发,旨在解决高并发场景下的性能问题,2011年成立Nginx公司(现属于F5 Networks),目前广泛应用于全球大型网站和复杂分布式系统中。核心功能与特点高性能与高并发处理采用事件驱动的异步非阻塞模型(Epoll/Kqueue),能高效处理海量并发连接(单台服务器可支持数万并发),内存占用低,适合高流量场景。对比传统服务器(如Apache),在静态资源处理和反向代理场景下性能优势显著。反向代理与负载均衡反向代理:接收客户端请求,转发至后端多个服务器(如Tomcat、Node.js、Django等),隐藏后端架构细节,提升安全性。负载均衡:支持轮询、加权轮询、IP哈希、最少连接数等策略,将流量均匀分配到后端服务器,避免单点压力。HTTP缓存与静态资源处理内置缓存机制(如Proxy Cache),可缓存静态文件(HTML、CSS、JS、图片等),减少后端服务器压力,加速客户端响应。直接高效处理静态资源,无需依赖额外模块。丰富的功能扩展支持HTTPS(SSL/TLS加密)、URL重写、Gzip压缩、跨域请求(CORS)、限流(如限制IP访问频率)等。可通过插件(如Lua脚本、Nginx Plus模块)实现自定义逻辑,满足复杂业务需求。轻量与灵活配置文件简洁(nginx.conf),支持热加载(无需重启服务即可更新配置)。资源消耗低,适合运行在容器(Docker)或资源受限的环境中。典型应用场景Web服务器:直接托管静态资源,或通过FastCGI协议处理动态请求(如PHP、Python应用)。反向代理服务器:作为前端入口,转发请求到后端多个应用服务器,实现高可用性和扩展性。负载均衡器:在分布式系统中分发流量,避免单节点过载,提升整体吞吐量。API网关:在微服务架构中作为统一入口,处理路由、认证、限流等逻辑。缓存服务器:通过缓存静态或动态内容,降低后端压力,优化用户访问速度。知名应用案例国内外大型网站:Google、Facebook、Twitter、京东、淘宝、新浪、网易、知乎等均使用Nginx作为核心服务器组件。云计算与CDN:AWS、阿里云、腾讯云等云服务商的CDN节点大量部署Nginx,用于边缘节点的内容分发。总结Nginx以高性能、低资源消耗、高可扩展性成为现代Web架构的核心组件,尤其适合高并发、分布式系统和微服务场景。无论是作为独立Web服务器,还是与其他技术(如Tomcat、Kubernetes)结合使用,都能有效提升系统的稳定性和性能。
2025年04月29日
18 阅读
0 评论
0 点赞
2025-04-23
【PHP】管家婆各个大类的基础调用数据方法
<?php namespace app\common\lib\gjp\warehouse; use think\Exception; class Warehouse { protected $dbName; public function __construct() { $this->dbName = "*****"; // } //查询单据 public function getWarehouse($paramkey = "", $paramJson = "", $userId = "***********")// { $instanceGjpBasic = new \app\common\lib\gjp\Basic(); $gjpSignInfo = $instanceGjpBasic->getSignKey(); $instanceGjpApiUrl = new \app\common\lib\gjp\Apiurl($userId); $gjpApiUrlInfo = $instanceGjpApiUrl -> getApiUrl(); $mobile = empty($gjpApiUrlInfo['GraspCloudMobile']) ? 0 : $gjpApiUrlInfo['GraspCloudMobile']; $serviceid = empty($gjpApiUrlInfo['GraspCloudServerId']) ? 0 : $gjpApiUrlInfo['GraspCloudServerId']; $requestUrl = $gjpApiUrlInfo['ApiServerAddress']; $md5BeforeStr = "apiparam".$gjpApiUrlInfo['ApiParam']."apitype".'query'."dbname".(string)$this->dbName."interiorapi"."1"."managename"."GraspCMServerApi.dll"."mobile".$mobile."paramjson".$paramJson."paramkey".$paramkey."serviceid".$serviceid.$gjpSignInfo['SignKey']; $data = [ 'managename' => (string)"GraspCMServerApi.dll", 'dbname' => (string)$this->dbName, 'paramkey' => (string)$paramkey, 'paramjson' => (string)($paramJson), 'apiparam' => (string)$gjpApiUrlInfo['ApiParam'], 'apitype' => (string)"query", 'sign' => (string)md5($md5BeforeStr), 'mobile' => (string)$mobile, 'serviceid' => (string)$serviceid, 'interiorapi' => (integer)1, ]; $encodedParams = http_build_query($data); $result = $instanceGjpBasic->curlRequest($requestUrl,"POST",$encodedParams,true,false); if($result['code'] != 0){ print_r($result);die; } return $result; } //生产单据 public function setReceipts($vchtype = 0,$billdata = '',$userId = "*************"){ $instanceGjpBasic = new \app\common\lib\gjp\Basic(); $gjpSignInfo = $instanceGjpBasic->getSignKey(); $instanceGjpApiUrl = new \app\common\lib\gjp\Apiurl($userId); $gjpApiUrlInfo = $instanceGjpApiUrl -> getApiUrl(); $requestUrl = $gjpApiUrlInfo['ApiServerAddress']; $mobile = empty($gjpApiUrlInfo['GraspCloudMobile']) ? 0 : $gjpApiUrlInfo['GraspCloudMobile']; $serviceid = empty($gjpApiUrlInfo['GraspCloudServerId']) ? 0 : $gjpApiUrlInfo['GraspCloudServerId']; $md5BeforeStr = "apiparam".$gjpApiUrlInfo['ApiParam']."apitype".'process'."billdata". $billdata ."dbname".(string)$this->dbName."interiorapi"."1"."managename"."GraspCMServerApi.dll"."mobile".$mobile."processtype"."0"."serviceid".$serviceid."vchcode"."0"."vchtype".$vchtype.$gjpSignInfo['SignKey']; $data = [ 'managename' => (string)"GraspCMServerApi.dll", 'dbname' => (string)$this->dbName, 'processtype' => (integer)0, 'vchtype' => (integer)$vchtype, 'vchcode' => (integer)0, 'billdata' => (string)$billdata, 'apiparam' => (string)$gjpApiUrlInfo['ApiParam'], 'apitype' => (string)"process", 'sign' => (string)md5($md5BeforeStr), 'mobile' => (string)$mobile, 'serviceid' => (string)$serviceid, 'interiorapi' => (integer)1, ]; // print_r($data);die; $encodedParams = http_build_query($data); $result = $instanceGjpBasic->curlRequest($requestUrl,"POST",$encodedParams,true,false); return $result; } //新增或修改 基础资料新增 public function businessBaseInfo($basetype = "", $baseinfodata = "", $rec = "", $type = 1, $userId = "*********"){ if($type == 1){ $typeName = "add"; }else{ $typeName = "modify"; } if(empty($rec)){ (string)$rec = "0"; } $instanceGjpBasic = new \app\common\lib\gjp\Basic(); $gjpSignInfo = $instanceGjpBasic->getSignKey(); $instanceGjpApiUrl = new \app\common\lib\gjp\Apiurl($userId); $gjpApiUrlInfo = $instanceGjpApiUrl -> getApiUrl(); // print_r($gjpApiUrlInfo);die; $mobile = empty($gjpApiUrlInfo['GraspCloudMobile']) ? 0 : $gjpApiUrlInfo['GraspCloudMobile']; $serviceid = empty($gjpApiUrlInfo['GraspCloudServerId']) ? 0 : $gjpApiUrlInfo['GraspCloudServerId']; $requestUrl = $gjpApiUrlInfo['ApiServerAddress']; $md5BeforeStr ="actiontype".$typeName."apiparam".$gjpApiUrlInfo['ApiParam']."apitype".'baseinfo'."baseinfodata".$baseinfodata."basetype".$basetype."dbname".(string)$this->dbName."interiorapi"."1"."managename"."GraspCMServerApi.dll"."mobile".$mobile."rec".$rec."serviceid".$serviceid.$gjpSignInfo['SignKey']; // "actiontype".$typeName."apiparam".$gjpApiUrlInfo['ApiParam']."apitype"."baseinfo"."basetype".$basetype."baseinfodata".$baseinfodata."dbname".$this->dbName."interiorapi".1."managename"."GraspCMServerApi.dll"."mobile".$mobile."serviceid".$serviceid."sign".md5($md5BeforeStr) $data = [ 'managename' => (string)"GraspCMServerApi.dll", 'dbname' => (string)$this->dbName, 'actiontype' => (string)$typeName, 'rec' => (string)$rec, 'basetype' => (string)$basetype, 'baseinfodata' => (string)$baseinfodata, 'apiparam' => (string)$gjpApiUrlInfo['ApiParam'], 'apitype' => (string)"baseinfo", 'sign' => (string)md5($md5BeforeStr), 'mobile' => (string)$mobile, 'serviceid' => (string)$serviceid, 'interiorapi' => (integer)1, ]; $encodedParams = http_build_query($data); $result = $instanceGjpBasic->curlRequest($requestUrl,"POST",$encodedParams,true,false); if($result['code'] != 0){ print_r($result);die; } return $result; } }
2025年04月23日
17 阅读
0 评论
0 点赞
2025-04-23
【PHP】获取程序Api地址 - 管家婆基础对接 PHP版本
<?php namespace app\common\lib\gjp; class Apiurl { protected $userId; protected $appKey; protected $SercretKey; protected $currentTimestamp; protected $dbName; public function __construct($userId = '********') { $this->appKey = "*****************"; $this->SercretKey = "*******************"; $this->currentTimestamp = time(); $this->userId = $userId; $this->dbName = '*****'; } public function getApiUrl() { $url = "http://api.cmgrasp.com/CMGraspApi/GateWay"; $instanceGjpBasic = new \app\common\lib\gjp\Basic(); $instanceStr = new \app\common\lib\data\Str(); $randamStr = $instanceStr->setNonce(32,true); $md5BeforeStr = "AppKey".$this->appKey."InvalidTime".date('YmdHis',$this->currentTimestamp)."RandamStr".$randamStr."UserId".$this->userId.$this->SercretKey; $data = [ 'MethodName' => (string)"graspcm.cmapi.getcustomerapiurl", 'AppKey' => (string)$this->appKey, 'UserId' => (string)$this->userId, 'InvalidTime' => (string)date('Y-m-d H:i:s'), 'RandamStr' => (string)$randamStr, 'SignStr' => (string)md5($md5BeforeStr), 'DbName' => (string)$this->dbName ]; $jsonData = json_encode($data); $result = $instanceGjpBasic->curlRequest($url,"POST",$jsonData,true,false); if($result['RetCode'] != 0){ $this->getApiUrl(); } $resultData = json_decode($result['RetMsg'],true); return $resultData; } }
2025年04月23日
15 阅读
0 评论
0 点赞
2025-04-23
【PHP】获取接口所需的SignKey - 管家婆基础对接 PHP版本
<?php namespace app\common\lib\gjp; use think\Exception; class Basic { protected $appKey; protected $SercretKey; protected $currentTimestamp; public function __construct() { $this->appKey = "*************"; $this->SercretKey = "*************"; $this->currentTimestamp = time(); } public function getSignKey() { if(!empty( cache('gjp_sign'))) { $dataResult = cache('gjp_sign'); return $dataResult; } $signUrl = "http://api.cmgrasp.com/CMGraspApi/GateWay"; $instanceStr = new \app\common\lib\data\Str(); $randamStr = $instanceStr->setNonce(32,true); $md5BeforeStr = "AppKey".$this->appKey."InvalidTime".date('YmdHis',$this->currentTimestamp)."RandamStr".$randamStr.$this->SercretKey; $data = [ "MethodName" => (string)"graspcm.cmapi.getsignstr", 'AppKey' => (string)$this->appKey, 'InvalidTime' => (string)date('Y-m-d H:i:s',$this->currentTimestamp), 'RandamStr' => (string)$randamStr, 'SignStr' => (string)md5($md5BeforeStr), ]; $jsonData = json_encode($data); $result = $this->curlRequest($signUrl,"POST", $jsonData,true,false); if($result['RetCode'] != 0) { $this->getSignKey(); } $dataResult = json_decode($result['RetMsg'],true); if(empty( cache('gjp_sign'))) { $dataResult = json_decode($result['RetMsg'],true); cache('gjp_sign',$dataResult,60*60*20); } return $dataResult; } /** * @Author: 小破孩嫩 * @Email: 3584685883@qq.com * @Time: 2021/4/1 10:39 * @param string $url url地址 * @param string $method 请求方法,默认为 'GET',可选值为 'GET' 或 'POST' * @param mixed $data 要发送的数据,如果是 POST 请求则为数据内容,否则为 null * @param array $headers 自定义请求头信息 * @param int $timeout 超时时间,默认为 30 秒 * @param bool $verifySSL 是否验证 SSL 证书,默认为 true * @param bool $flbg 返回值是否转成数组,默认不转 * @param bool $headercontent 是否获取请求的header值内容,默认不获取 * @return array|bool|mixed|string * @Description:curl请求 */ public function curlRequest($url, $method = 'GET', $data = null, $flbg = false, $verifySSL = true, $headers = [], $headerContent = false, $timeout = 30) { // 初始化 cURL 会话 $ch = curl_init(); // 设置要请求的 URL curl_setopt($ch, CURLOPT_URL, $url); // 设置获取的信息以字符串形式返回,而不是直接输出 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 设置超时时间 curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); // 设置请求方法 if ($method === 'POST') { curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $data); } // 设置请求头 if (!empty($headers)) { curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); } // 设置是否验证 SSL 证书 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verifySSL); // 执行 cURL 会话并获取响应 $response = curl_exec($ch); // 获取 HTTP 响应码 $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); // 如果 cURL 执行出错 if (curl_errno($ch)) { // 输出错误信息 echo 'Curl error: ' . curl_error($ch); // 关闭 cURL 会话并返回 false curl_close($ch); return false; } // 如果 HTTP 响应码大于等于 400(表示错误) elseif ($httpCode >= 400) { // 输出错误信息 echo "HTTP error: $httpCode"; // 关闭 cURL 会话并返回 false curl_close($ch); return false; } // 处理是否获取请求头内容 if ($headerContent && $httpCode == 200) { $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE); $headers = substr($response, 0, $headerSize); $body = substr($response, $headerSize); curl_close($ch); return [$headers, $body]; } // 关闭 cURL 会话 curl_close($ch); // 处理是否将响应转换为数组 if ($flbg) { $response = json_decode($response, true); } // 返回响应内容 return $response; } }
2025年04月23日
14 阅读
0 评论
0 点赞
2025-04-23
精准检测,助力社交管理 —— 微信好友检测服务来袭!
精准检测,助力社交管理 —— 微信好友检测服务来袭!不发消息也能查!微信好友删除 / 拉黑检测服务上线。不用再群发 “测试消息” 尴尬试探!我们的静默检测技术,0 打扰标注两大核心状态 ——「删除我的人」「拉黑我的人」,5000 好友状态 1 次搞定,社交管理从此精准避雷!
2025年04月23日
1,278 阅读
0 评论
59 点赞
2025-04-18
【Docker】Docker Compose
什么是 Docker ComposeDocker Compose 是 Docker 官方提供的一个工具,它允许你使用 YAML 文件来定义和管理多个 Docker 容器的应用。通过一个单独的 docker-compose.yml 文件,你可以定义应用的服务、网络和卷等配置,然后使用一条命令就能轻松地部署和管理整个应用栈。这大大简化了多容器应用的部署和管理过程,提高了开发和运维效率。安装 Docker ComposeLinux 系统:可以通过以下命令下载并安装 Docker Compose:sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose sudo chmod +x /usr/local/bin/docker-composemacOS 和 Windows 系统:在安装 Docker Desktop 时,Docker Compose 会自动安装。基本概念服务(Services)服务是定义在 docker-compose.yml 文件中的一个或多个容器的集合,每个服务都有自己的配置,如使用的镜像、端口映射、环境变量等。例如,一个 Web 应用可能包含一个 Web 服务器服务和一个数据库服务。网络(Networks)网络用于连接不同的服务,使得它们之间可以相互通信。Docker Compose 默认会创建一个网络,所有的服务都会连接到这个网络中。卷(Volumes)卷用于持久化存储容器中的数据,防止数据在容器销毁时丢失。你可以在 docker-compose.yml 文件中定义卷,并将其挂载到容器的指定目录。编写 docker-compose.yml 文件以下是一个简单的 docker-compose.yml 文件示例,用于部署一个包含 Web 服务器和数据库的应用:这个示例中定义了两个服务:web 服务:使用 nginx 镜像,将容器的 80 端口映射到宿主机的 80 端口,并依赖于 db 服务。db 服务:使用 mysql:5.7 镜像,设置了 MySQL 的 root 密码和数据库名,并将数据卷 db-data 挂载到容器的 /var/lib/mysql 目录。使用 Docker Compose 命令启动应用在包含 docker-compose.yml 文件的目录下,执行以下命令启动应用:docker-compose up -d-d 参数表示以守护进程模式运行容器,即容器在后台运行。停止应用执行以下命令停止并删除所有由 Docker Compose 创建的容器、网络和卷:docker-compose down查看服务状态使用以下命令查看应用中各个服务的状态:docker-compose ps查看服务日志要查看某个服务的日志,可以使用以下命令:docker-compose logs web这里的 web 是服务的名称,你可以根据实际情况替换为其他服务名。总结Docker Compose 是一个非常实用的工具,它可以帮助你更方便地管理多容器应用。通过编写 docker-compose.yml 文件,你可以定义应用的各个组件及其配置,然后使用简单的命令就能完成应用的部署、启动、停止等操作。
2025年04月18日
17 阅读
0 评论
0 点赞
2025-04-18
【Docker】Docker Desktop的使用
Docker Desktop 是一个易于安装的应用程序,适用于 Mac、Windows 系统,它能让你在本地开发和测试 Docker 应用程序。以下是 Docker Desktop 的使用介绍:安装与启动安装:访问 Docker 官方网站(https://www.docker.com/products/docker-desktop ),根据自己的操作系统下载对应的 Docker Desktop 安装程序,然后按照安装向导完成安装。启动:安装完成后,在开始菜单(Windows)或应用程序文件夹(Mac)中找到 Docker Desktop 并启动。启动后,Docker 图标会出现在系统托盘中(Windows)或菜单栏中(Mac),当图标变为绿色时,表示 Docker 服务已成功启动。界面介绍Docker Desktop 提供了图形化界面,包含以下主要部分:Images(镜像):显示本地所有的 Docker 镜像,你可以查看镜像的详细信息、标签、大小等,还能对镜像进行删除、运行等操作。Containers(容器):展示正在运行或已停止的容器列表,可查看容器的状态、端口映射、日志等信息,同时支持对容器进行启动、停止、重启、删除等操作。Volumes(数据卷):用于管理 Docker 数据卷,数据卷可用于持久化存储容器中的数据。你可以创建、删除和查看数据卷的详细信息。Networks(网络):显示 Docker 网络的相关信息,包括网络类型、子网、网关等,支持创建和管理自定义网络。常用操作拉取镜像你可以在命令行中使用 docker pull 命令拉取镜像,也可以在 Docker Desktop 的界面中进行操作。例如,要拉取 nginx 镜像,在命令行中执行:docker pull nginx拉取完成后,在 Docker Desktop 的 Images 页面就能看到 nginx 镜像。运行容器命令行方式:使用 docker run 命令启动容器。例如,启动一个 nginx 容器并将容器的 80 端口映射到宿主机的 8080 端口:docker run -d -p 8080:80 nginx界面方式:在 Docker Desktop 的 Images 页面找到 nginx 镜像,点击 Run 按钮,在弹出的配置窗口中设置端口映射等参数,然后点击 Run 即可启动容器。启动后,在 Containers 页面可以看到正在运行的 nginx 容器。查看容器日志在 Containers 页面找到要查看日志的容器,点击容器名称进入详情页面,在 Logs 标签页中可以查看容器的实时日志信息。停止和删除容器停止容器:在 Containers 页面,找到要停止的容器,点击 Stop 按钮即可停止容器。删除容器:停止容器后,点击 Remove 按钮可将容器从本地删除。构建镜像如果你有一个 Dockerfile,可以使用 docker build 命令构建镜像。例如,在包含 Dockerfile 的目录下执行:docker build -t my-custom-image:1.0 .构建完成后,新的镜像会出现在 Docker Desktop 的 Images 页面。其他功能Kubernetes 支持:Docker Desktop 集成了 Kubernetes,可以在本地快速搭建 Kubernetes 环境。在 Docker Desktop 的设置中,找到 Kubernetes 选项卡,勾选 Enable Kubernetes 即可启用。资源管理:可以在 Docker Desktop 的设置中调整 Docker 引擎的资源分配,如 CPU、内存、磁盘等,以满足不同应用的需求。
2025年04月18日
18 阅读
0 评论
0 点赞
2025-04-18
【Docker】实践环节 编写dockerfile, 创建镜像,启动容器的这个过程
下面通过一个简单的 Python Flask 应用示例,详细介绍编写 Dockerfile、创建镜像以及启动容器的完整过程。步骤 1:准备 Flask 应用代码首先,创建一个简单的 Flask 应用。在项目根目录下创建 app.py 文件,内容如下:from flask import Flask app = Flask(__name__) @app.route('/') def hello_world(): return 'Hello, Docker!' if __name__ == '__main__': app.run(debug=True, host='0.0.0.0', port=5000) 接着,创建 requirements.txt 文件,列出应用所需的依赖:flask步骤 2:编写 Dockerfile在项目根目录下创建 Dockerfile 文件,其内容如下:# 使用 Python 3.9 作为基础镜像 FROM python:3.9-slim # 设置工作目录 WORKDIR /app # 复制 requirements.txt 文件到工作目录 COPY requirements.txt . # 安装依赖 RUN pip install --no-cache-dir -r requirements.txt # 复制当前目录下的所有文件到工作目录 COPY . . # 暴露端口 EXPOSE 5000 # 容器启动时执行的命令 CMD ["python", "app.py"] 步骤 3:构建 Docker 镜像打开终端,进入项目根目录,执行以下命令来构建 Docker 镜像:docker build -t my-flask-app:1.0 .这里的 -t 参数用于为镜像指定标签,my-flask-app:1.0 是镜像的名称和版本号,. 表示使用当前目录下的 Dockerfile 进行构建。构建过程中,Docker 会按照 Dockerfile 中的指令依次执行,最终创建出一个包含 Flask 应用的镜像。步骤 4:查看构建好的镜像构建完成后,可使用以下命令查看本地已有的镜像:docker images在输出列表中,你应该能看到刚刚构建的 my-flask-app:1.0 镜像。步骤 5:启动 Docker 容器使用以下命令启动基于该镜像的容器:docker run -d -p 5000:5000 my-flask-app:1.0参数解释:-d:表示以守护进程模式运行容器,即容器在后台运行。-p 5000:5000:将容器内部的 5000 端口映射到宿主机的 5000 端口,这样就可以通过宿主机的 5000 端口访问容器内的 Flask 应用。my-flask-app:1.0:指定要使用的镜像名称和版本号。步骤 6:验证应用是否正常运行打开浏览器,访问 http://localhost:5000,如果看到 Hello, Docker! 的输出,就说明容器内的 Flask 应用已成功运行。步骤 7:停止和删除容器若要停止运行中的容器,可使用以下命令:docker stop <容器 ID>其中 <容器 ID> 可通过 docker ps 命令查看。停止容器后,若要删除容器,可执行:docker rm <容器 ID>通过以上步骤,你就完成了编写 Dockerfile、创建镜像以及启动容器的整个过程。
2025年04月18日
8 阅读
0 评论
0 点赞
2025-04-18
【Docker】容器化和Dockerfile
容器化概述容器化是一种将应用程序及其依赖项打包成独立容器的技术,这些容器可以在不同的环境中一致地运行。容器化技术的核心目标是实现应用的隔离性、可移植性和资源的高效利用。隔离性:容器使用操作系统的内核特性(如命名空间和控制组)来隔离应用程序的运行环境,使得每个容器中的应用程序相互独立,不会相互干扰。可移植性:容器将应用程序及其所有依赖项打包在一起,形成一个独立的运行单元。这意味着容器可以在任何支持容器化技术的环境中运行,无需担心环境差异导致的兼容性问题。资源高效利用:相比于传统的虚拟机技术,容器不需要运行完整的操作系统,因此占用的资源更少,启动速度更快,可以在同一台物理服务器上运行更多的容器。Dockerfile 概述Dockerfile 是一个文本文件,用于定义 Docker 镜像的构建过程。通过编写 Dockerfile,你可以自动化地创建自定义的 Docker 镜像。基本结构与常用指令基础镜像指定(FROM):指定构建镜像所基于的基础镜像。例如:FROM ubuntu:20.04这行代码指定使用 Ubuntu 20.04 作为基础镜像。维护者信息(MAINTAINER 或 LABEL):用于注明镜像的维护者信息。示例:LABEL maintainer="your_email@example.com"运行命令(RUN):在构建镜像的过程中执行命令。例如,安装软件包:RUN apt-get update && apt-get install -y python3这行代码会在基础镜像中更新软件包列表并安装 Python 3。复制文件(COPY 或 ADD):将本地文件复制到镜像中。例如:COPY app.py /app/这会将本地的 app.py 文件复制到镜像的 /app/ 目录下。工作目录设置(WORKDIR):指定后续命令的工作目录。例如:WORKDIR /app后续的命令都会在 /app 目录下执行。环境变量设置(ENV):设置环境变量。例如:ENV PORT 8080这会在镜像中设置 PORT 环境变量为 8080。容器启动命令(CMD 或 ENTRYPOINT):指定容器启动时执行的命令。例如:CMD ["python3", "app.py"]这表示容器启动时会运行 python3 app.py 命令。Dockerfile 构建镜像示例以下是一个简单的 Dockerfile 示例,用于构建一个运行 Python Flask 应用的镜像:# 使用 Python 3.9 作为基础镜像 FROM python:3.9-slim # 设置工作目录 WORKDIR /app # 复制当前目录下的所有文件到工作目录 COPY . /app # 安装依赖 RUN pip install --no-cache-dir -r requirements.txt # 设置环境变量 ENV FLASK_APP=app.py ENV FLASK_RUN_HOST=0.0.0.0 # 暴露端口 EXPOSE 5000 # 容器启动时执行的命令 CMD ["flask", "run"] 使用以下命令可以基于这个 Dockerfile 构建镜像:docker build -t my-flask-app .其中,-t 用于指定镜像的标签,. 表示使用当前目录下的 Dockerfile 进行构建。综上所述,容器化是一种先进的应用部署技术,而 Dockerfile 是实现容器化过程中用于构建自定义镜像的重要工具。
2025年04月18日
12 阅读
0 评论
0 点赞
2025-04-18
【Docker】Docker的安装
以下为你介绍在不同操作系统上安装 Docker 的方法:在 Ubuntu 系统安装 Docker步骤 1:更新系统软件包列表sudo apt-get update步骤 2:安装必要的依赖包sudo apt-get install \ ca-certificates \ curl \ gnupg \ lsb-release步骤 3:添加 Docker 的官方 GPG 密钥sudo mkdir -p /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg步骤 4:设置 Docker 软件源echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null步骤 5:再次更新软件包列表sudo apt-get update步骤 6:安装 Docker 引擎sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin步骤 7:验证 Docker 是否安装成功sudo docker run hello-world在 CentOS 系统安装 Docker步骤 1:卸载旧版本(如果有)sudo yum remove docker \ docker-client \ docker-client-latest \ docker-common \ docker-latest \ docker-latest-logrotate \ docker-logrotate \ docker-engine步骤 2:安装必要的依赖包sudo yum install -y yum-utils步骤 3:设置 Docker 软件源sudo yum-config-manager \ --add-repo \ https://download.docker.com/linux/centos/docker-ce.repo步骤 4:安装 Docker 引擎sudo yum install docker-ce docker-ce-cli containerd.io docker-compose-plugin步骤 5:启动 Docker 服务并设置开机自启sudo systemctl start docker sudo systemctl enable docker步骤 6:验证 Docker 是否安装成功sudo docker run hello-world在 Windows 系统安装 Docker步骤 1:确保系统满足要求Windows 10 64 位:专业版、企业版或教育版(1607 版本及以上),或者 Windows 11。开启 Hyper - V 和容器功能。步骤 2:下载 Docker Desktop 安装程序访问 Docker 官方网站(https://www.docker.com/products/docker-desktop/),下载适用于 Windows 的 Docker Desktop 安装程序。步骤 3:运行安装程序双击下载的安装程序,按照提示完成安装。安装完成后,启动 Docker Desktop。步骤 4:验证安装打开命令提示符或 PowerShell,运行以下命令:docker run hello-world在 macOS 系统安装 Docker步骤 1:确保系统满足要求macOS Catalina 10.15 及以上版本。步骤 2:下载 Docker Desktop 安装程序访问 Docker 官方网站(https://www.docker.com/products/docker-desktop/),下载适用于 macOS 的 Docker Desktop 安装程序。步骤 3:运行安装程序双击下载的 .dmg 文件,将 Docker 图标拖到“应用程序”文件夹中。在“应用程序”文件夹中找到 Docker 并打开,按照提示完成设置。步骤 4:验证安装打开终端,运行以下命令:docker run hello-world通过上述步骤,你就可以在不同操作系统上完成 Docker 的安装,并通过运行 hello - world 镜像验证安装是否成功。
2025年04月18日
17 阅读
0 评论
0 点赞
2025-04-18
【Docker】Docker的基本原理和概念
基本概念1. 镜像(Image)镜像是一个只读的模板,它包含了运行应用程序所需的所有文件系统、代码、依赖库、环境变量和配置文件等。可以把镜像看作是一个软件的“安装包”,它是静态的,不包含任何动态数据。例如,你可以有一个基于Ubuntu系统的Python镜像,这个镜像中已经安装好了Python环境以及相关的依赖库。2. 容器(Container)容器是镜像的运行实例。当你启动一个镜像时,就会创建一个容器。容器是一个独立的运行环境,它可以被启动、停止、删除等操作。容器之间相互隔离,每个容器都有自己独立的文件系统、进程空间和网络环境。例如,基于前面提到的Python镜像启动的容器,就可以在其中运行Python程序。3. 仓库(Registry)仓库是用于存储和分发镜像的地方。类似于代码仓库,镜像仓库可以包含多个镜像,每个镜像又可以有不同的版本。Docker官方提供了公共的镜像仓库Docker Hub,其中包含了大量的开源镜像,你也可以搭建自己的私有镜像仓库。4. DockerfileDockerfile是一个文本文件,它包含了一系列的指令,用于构建Docker镜像。通过编写Dockerfile,你可以定义镜像的构建步骤,包括基础镜像的选择、软件的安装、环境变量的设置等。例如,你可以在Dockerfile中指定从Ubuntu镜像开始,然后安装Python和相关的依赖库,最后将你的应用程序代码复制到镜像中。基本原理1. 容器化技术基础Docker主要基于Linux内核的两个特性来实现容器化:命名空间(Namespaces):命名空间提供了一种隔离机制,它可以将系统资源(如进程、网络、文件系统等)隔离开来,使得不同的命名空间中的进程看起来好像拥有自己独立的系统资源。例如,PID命名空间可以让每个容器都有自己独立的进程ID,NET命名空间可以让每个容器都有自己独立的网络栈。控制组(Control Groups,简称cgroups):控制组用于限制和监控容器对系统资源(如CPU、内存、磁盘I/O等)的使用。通过cgroups,可以为每个容器分配一定的资源配额,防止某个容器占用过多的系统资源而影响其他容器的正常运行。2. 镜像构建原理当你使用docker build命令根据Dockerfile构建镜像时,Docker会按照Dockerfile中的指令依次执行每个步骤。每执行一个指令,就会创建一个新的镜像层(Layer),这些镜像层是只读的,并且可以被多个镜像共享。最终的镜像就是由这些只读的镜像层叠加而成的。例如,当你在Dockerfile中使用RUN指令安装一个软件时,就会创建一个新的镜像层,该层包含了安装好的软件。3. 容器运行原理当你使用docker run命令启动一个容器时,Docker会在镜像的基础上创建一个可写的容器层(Container Layer)。容器层位于镜像层之上,所有对容器内文件系统的写操作都会发生在这个可写层中。当容器被删除时,容器层也会被删除,但镜像层不会受到影响。例如,当你在容器中创建一个新文件时,这个文件会被存储在容器层中。4. 网络通信原理Docker提供了多种网络模式,如bridge、host、none等。默认情况下,Docker使用bridge网络模式,它会在宿主机上创建一个虚拟网桥(docker0),每个容器都会连接到这个网桥上。容器之间可以通过IP地址进行通信,同时也可以通过端口映射将容器内的端口映射到宿主机上,使得外部网络可以访问容器内的服务。
2025年04月18日
12 阅读
0 评论
0 点赞
2025-04-18
【Docker】Docker和虚拟机的区别
Docker和虚拟机在实现原理、资源占用、性能、隔离性等方面存在明显差异,以下是详细对比:实现原理Docker:基于容器化技术,利用Linux内核的特性(如命名空间和控制组)来实现进程的隔离。容器共享宿主机的操作系统内核,只需打包应用程序及其依赖项,就能在不同环境中运行。虚拟机:通过虚拟机管理程序(Hypervisor)模拟出硬件环境,在这个虚拟的硬件上安装完整的操作系统,每个虚拟机都有独立的操作系统实例。资源占用Docker:容器共享内核,不需要额外的操作系统开销,因此资源占用少,启动速度快,通常只需几秒钟。虚拟机:每个虚拟机都包含一个完整的操作系统,需要分配独立的CPU、内存、存储等资源,资源占用大,启动时间长,可能需要几分钟。性能Docker:由于直接使用宿主机的内核,容器的性能损耗小,接近原生应用程序的性能。虚拟机:因为需要模拟硬件层,并且运行独立的操作系统,存在一定的性能开销,性能相对较低。隔离性Docker:隔离性相对较弱,容器之间共享内核,一个容器的崩溃可能会影响其他容器,但通过合理的配置和管理可以降低这种风险。虚拟机:提供了更强的隔离性,每个虚拟机都有独立的操作系统和硬件环境,一个虚拟机的故障通常不会影响其他虚拟机。便携性Docker:容器镜像是轻量级的,易于打包、分发和部署,可以在不同的Docker环境中快速迁移。虚拟机:虚拟机镜像通常较大,包含完整的操作系统,迁移和部署相对复杂。应用场景Docker:适用于微服务架构、持续集成/持续部署(CI/CD)、开发和测试环境等场景,能够快速部署和扩展应用程序。虚拟机:适合需要完全隔离的环境,如运行不同操作系统的应用程序、安全要求较高的场景等。以下表格对上述区别进行了总结:对比维度Docker虚拟机实现原理基于容器化技术,共享宿主机内核通过Hypervisor模拟硬件,运行独立操作系统资源占用少,启动快大,启动慢性能接近原生,损耗小有性能开销,相对较低隔离性相对较弱强便携性轻量级,易迁移镜像大,迁移复杂应用场景微服务、CI/CD、开发测试需完全隔离、多操作系统、高安全场景
2025年04月18日
14 阅读
0 评论
0 点赞
2025-04-18
【Docker】为什么要使用Docker
Docker是一款流行的容器化平台,使用Docker主要有以下几个原因:环境一致性:Docker容器可以确保应用程序及其所有依赖项在任何环境中都能以相同的方式运行。无论是开发环境、测试环境还是生产环境,只要安装了Docker,容器内的应用程序就会运行在相同的环境中,避免了因环境差异导致的“在我机器上能运行,在其他地方不行”的问题。轻量级和高效性:与传统的虚拟机相比,Docker容器不需要包含完整的操作系统,它们共享宿主机的操作系统内核,因此启动速度快、占用资源少。这使得在同一台物理服务器上可以同时运行多个容器,提高了服务器的资源利用率。易于部署和扩展:使用Docker,可以将应用程序及其依赖打包成一个容器镜像,然后轻松地在不同的服务器上部署。当应用程序的流量增加时,可以快速启动多个容器副本进行水平扩展,以满足业务需求。便于团队协作:开发人员可以在自己的本地环境中使用Docker容器进行开发和测试,然后将容器镜像分享给其他团队成员或部署到生产环境。这使得团队成员之间的环境更加一致,减少了因环境配置不同而导致的问题,提高了协作效率。隔离性:Docker容器提供了良好的隔离性,每个容器都有自己独立的文件系统、进程空间和网络环境。这意味着一个容器内的应用程序出现问题不会影响到其他容器,提高了系统的稳定性和可靠性。版本控制和可重复性:可以对Docker容器镜像进行版本控制,就像对代码进行版本控制一样。这使得在需要时可以轻松回滚到之前的版本,并且能够确保每次部署都是可重复的,提高了系统的可维护性。多语言和多框架支持:Docker可以用于各种不同的编程语言和框架。无论是Python、Java、Node.js还是其他语言,都可以将其应用程序及其依赖项打包到Docker容器中,实现跨语言和跨框架的统一部署和管理。
2025年04月18日
12 阅读
0 评论
0 点赞
2025-03-27
【JavaScript】网站底部版权年份自动更换
/** * 将当前年份赋值给指定 id 的元素 * @param {string} elementId - 要赋值的元素的 id * @returns {boolean} - 如果元素存在并成功赋值,返回 true;否则返回 false */ function setCurrentYear(elementId) { // 获取当前年份 const currentYear = new Date().getFullYear(); // 获取指定 id 的元素 const element = document.getElementById(elementId); // 检查元素是否存在 if (element) { // 更新元素内容 element.textContent = currentYear; return true; } else { console.error(`元素 id "${elementId}" 不存在`); return false; } } 实例 <!DOCTYPE html> <html> <head> <title>显示当前年份</title> </head> <body> <span id="currentYear"></span> <script> // 调用封装好的方法 setCurrentYear('currentYear'); </script> </body> </html> 方法2 /** * 将当前年份嵌入到指定元素的内容中 * @param {string} elementId - 要赋值的元素的 id * @param {string} prefix - 年份前的文本 * @param {string} suffix - 年份后的文本 * @returns {boolean} - 如果元素存在并成功赋值,返回 true;否则返回 false */ function setCurrentYearWithText(elementId, prefix = '', suffix = '') { const currentYear = new Date().getFullYear(); const element = document.getElementById(elementId); if (element) { element.textContent = `${prefix}${currentYear}${suffix}`; return true; } else { console.error(`元素 id "${elementId}" 不存在`); return false; } } // 输出 "Copyright © 2025" setCurrentYearWithText('currentYear', 'Copyright © ', ''); // <span id="currentYear">Copyright © </span> // 获取当前日期 const currentDate = new Date(); // 获取当前年份 const currentYear = currentDate.getFullYear(); //赋值 document.getElementById('currentYear').textContent = `Copyright © ${currentYear}`;
2025年03月27日
15 阅读
0 评论
0 点赞
1
2
...
12