ThinkPHP新闻发布系统实战:从环境搭建到前后台管理全流程
简介一套基于ThinkPHP框架的新闻发布系统源码与配套学习资料面向PHP初学者和Web开发入门者直观展示MVC分层思想、数据库操作以及前台展示与后台管理两大模块的协作方式适合想从零搭建新闻网站、理解真实项目结构的读者。压缩包共1117个文件主体为414个PHP脚本辅以23个HTML页面、21个CSS样式、31个JavaScript脚本以及UEditor富文本编辑器所需的503个GIF图标和图片上传、文件管理等服务端处理相关ashx文件整体仅6.43MB轻量易部署目录结构清晰。目前已有4729人学习下载学习热度可观。内容涵盖文章发布、分类管理、UEditor集成、前端分页搜索等完整流程附SQL数据库文件、安装说明及后台管理示例从数据库表设计、ActiveRecord模型操作到控制器请求处理和模板引擎渲染都有可直接运行的代码可供对照。脚本中还包含参数过滤、数据转义等安全处理并预留缓存优化空间可作为PHP项目实战与框架入门的参考。1. 为什么说这套 ThinkPHP 新闻发布系统是真的易学易用如果你接手的第一个完整 Web 项目就是要做一个新闻发布系统那么 ThinkPHP 这套“前台后台”方案几乎是当前最不容易劝退人的选择。它把前台展示、后台管理和数据库操作拆成了标准 MVC 结构控制器里几十行代码就能撑起一个列表页模板里几个标签就能把数据渲染出来完全不需要手工拼 SQL 拼 HTML。很多想做 PHP 开发的人就是靠这种新闻系统跨过了“会语法但不会做项目”的坎。本文不做纸面介绍直接带你从建环境、建表、写控制器一路把前台列表、后台登录、新闻增删改查和文件上传全部跑通顺便把新手最容易翻车的几个地方提前说透。这套东西也适合作为外包、毕设或公司内部信息发布的基础骨架改一改就能接别的业务。2. 从零跑通 ThinkPHP 新闻项目环境准备与目录骨架2.1 为什么选 ThinkPHPMVC 思路与中文生态动手前先想清楚选型。写新闻系统你当然可以用原生 PHP 从头写但那样你会把大量时间耗在过滤参数、拼接 SQL、处理分页这些重复劳动上你也可以用 Laravel功能确实强但对刚接触框架的人来说命令行工具、服务容器、中间件概念叠在一起很容易学着学着就放弃。ThinkPHP 则是把 MVC 思路用最直白的方式摆在你面前浏览器请求某个 URL路由找到对应控制器方法控制器里取数据模板负责渲染整个过程一条线下来非常符合正常人理解和排查问题的习惯。我接触过不少从零学 PHP 的开发者他们第一周能照着官方示例跑通一个 Hello World第二周就卡在“我该怎么组织一堆文件”上。ThinkPHP 的项目结构把控制器、模型、视图、配置分成了固定目录你要做的只是在里面填业务代码而不是先设计一套架构。而且它的报错页面会直接告诉你“哪行代码、哪个文件、什么类型错误”新手不会面对一个 500 空白的黑匣子。这套新闻系统选它的第二层原因是部署门槛低只要一台能跑 PHP 的服务器就够了不需要额外常驻进程很多虚拟主机都能直接跑。2.2 最小可运行环境与两条安装路径先说环境。以当前常用版本为例建议 PHP 版本不低于 7.4正式做项目直接用 PHP 8 以上更好数据库用 MySQL 5.7 或 8.0Web 服务器用 Nginx 或 Apache 都行。这里有一个容易被新手忽略的点PHP 需要开启 pdo_mysql 扩展否则后面连数据库会直接报“找不到驱动”。安装 ThinkPHP 最常见的做法是用 Composer 创建项目。打开命令行进入你的 Web 根目录执行composer create-project topthink/think tp_news cd tp_news如果下载速度很慢先在全局配一个国内 Composer 镜像再执行上面的命令几分钟就能拿到完整项目骨架。另一个常见做法是直接从官网下载 Release 包解压适合没有装 Composer 的临时环境。我个人的建议是宁可花十分钟装 Composer也别手工去补依赖后面你如果要加验证码组件、图片处理库Composer 一条命令就解决了手工下载迟早出问题。项目跑起来前还要配置虚拟主机或 Nginx。最关键的一条是把站点根目录指向public而不是项目根目录。ThinkPHP 的入口文件在public/index.php这样做也是出于安全考虑Web 只能访问 public 里的文件项目里的应用代码、配置、日志都留在外面。Nginx 下常见配置是server { listen 80; server_name tpnews.local; root /var/www/tp_news/public; index index.php index.html; location / { if (!-e $request_filename) { rewrite ^(.*)$ /index.php?s$1 last; } } location ~ \.php$ { include fastcgi_params; fastcgi_pass 127.0.0.1:9000; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; } }注意rewrite这行是关键ThinkPHP 的 URL 走了伪静态请求会经过入口文件解析路由。本地写 host 把tpnews.local指到 127.0.0.1浏览器访问http://tpnews.local能看到默认欢迎页就说明环境通了。2.3 先认准项目里的三个关键目录与配置文件环境通了别急着写代码先花几分钟把目录结构认清楚。以我们创建的tp_news项目为例你后面 90% 的操作都集中在这几个地方tp_news/ ├─ app/ │ ├─ controller/ │ │ ├─ Index.php │ │ └─ admin/ │ ├─ model/ │ │ ├─ News.php │ │ └─ Category.php │ ├─ view/ │ │ ├─ index/ │ │ └─ admin/ │ └─ BaseController.php ├─ config/ │ ├─ app.php │ └─ database.php ├─ public/ │ ├─ index.php │ ├─ static/ │ └─ storage/ ├─ route/ │ └─ app.php └─ .envapp/controller放前台控制器后台控制器我习惯在下面再建一个admin子目录这样前后台代码从目录上就是分离的模块边界很清楚。app/model放模型文件News 模型对应新闻表Category 模型对应分类表。app/view放模板模板路径默认和控制器名、方法名对应比如Index 控制器的 index 方法对应 app/view/index/index.html。route/app.php是路由定义文件URL 地址和控制器方法之间的映射关系写在这里。config/database.php负责数据库连接配置。数据库连接是最先要改的配置。打开.env或config/database.php把数据库名、用户名和密码填对database tp_news, username root, password your_password, hostname 127.0.0.1, hostport 3306, charset utf8mb4,charset我建议固定用utf8mb4而不是老项目常见的utf8。utf8mb4 才能存 emoji 和生僻字新闻内容里偶尔会有特殊符号用 utf8 容易出现“保存成功但查出来乱码”。填完配置下一步就是建数据表。3. 新闻系统的数据基础建表、模型与链式查询3.1 三张核心表字段设计思路与建表 SQL新闻系统的数据结构并不复杂但字段设计直接影响后面的开发效率。一个最实用的新闻系统只需要三张表新闻表news、分类表category、管理员表admin。先说新闻表字段就是标题、分类、正文、封面、状态、点击量、时间信息CREATE TABLE news ( id int(11) unsigned NOT NULL AUTO_INCREMENT, title varchar(100) NOT NULL DEFAULT , category_id int(11) unsigned NOT NULL DEFAULT 0, content text NOT NULL, cover varchar(255) NOT NULL DEFAULT , status tinyint(1) NOT NULL DEFAULT 1, views int(11) unsigned NOT NULL DEFAULT 0, create_time int(11) NOT NULL DEFAULT 0, update_time int(11) NOT NULL DEFAULT 0, delete_time int(11) DEFAULT NULL, PRIMARY KEY (id), KEY idx_category (category_id), KEY idx_status_time (status, create_time) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;字段设计都是有原因的。title定成 varchar(100)一般新闻标题足够用太长是浪费索引空间。status用 tinyint1 表示发布、0 表示下架将来做“草稿箱”功能也能扩展。views是点击量做阅读数排行时直接ORDER BY views就能查。create_time和update_time我用的是整型时间戳ThinkPHP 默认就能自动写入比 datetime 类型更适合程序处理和时区换算。delete_time默认是 NULL这就是软删除的标记查询时框架会自动给你加上delete_time IS NULL条件。分类表和管理员表相对简单CREATE TABLE category ( id int(11) unsigned NOT NULL AUTO_INCREMENT, name varchar(50) NOT NULL DEFAULT , sort int(11) NOT NULL DEFAULT 0, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE admin ( id int(11) unsigned NOT NULL AUTO_INCREMENT, username varchar(50) NOT NULL DEFAULT , password varchar(255) NOT NULL DEFAULT , PRIMARY KEY (id), UNIQUE KEY uk_username (username) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;admin表的password字段特意留成 varchar(255)因为存的是password_hash()生成的安全散列值而不是明文。很多新手直接存明文密码这是后台系统里最致命的安全漏洞后面登录那章我会写出来正确做法。3.2 模型定义关联、时间戳与软删除表建好了接下来在app/model里建立对应模型。ThinkPHP 的模型类不只是“一张表的映射”它还能帮你自动处理时间戳、软删除和表关联。News 模型的完整写法?php namespace app\model; use think\Model; use think\model\concern\SoftDelete; class News extends Model { use SoftDelete; protected $name news; protected $autoWriteTimestamp true; protected $createTime create_time; protected $updateTime update_time; protected $deleteTime delete_time; public function category() { return $this-belongsTo(Category::class, category_id); } }这里use SoftDelete是开启软删除特性$deleteTime指定软删除字段。$autoWriteTimestamp true表示新增、更新时自动写入时间戳。category()方法定义了与分类模型的关联关系新闻表里的category_id指向分类表id所以用belongsTo。看名字也能理解——每条新闻属于一个分类。Category 模型可以精简一些?php namespace app\model; use think\Model; class Category extends Model { protected $name category; public function news() { return $this-hasMany(News::class, category_id); } }hasMany是反向定义一个分类下有多条新闻。关联方法不需要手动写 SQL后面查询直接用with([category])就能把新闻和分类一次性查出来避免 N1 问题。这里要提醒一句如果建表时你没用create_time这些标准字段名而是用了created_at那$createTime也要改成对应字段名否则时间戳不写入你会看到新增的数据时间字段全是 0。3.3 链式查询把列表数据一次拼装好模型定义完真正的查询套路就来了。ThinkPHP 的链式查询用起来很像是在“说人话”每个方法就是查询的一个条件按顺序接在后面。前台首页要显示已发布的新闻按发布时间倒序带出分类名每页 10 条$list News::with([category]) -where(status, 1) -order(create_time, desc) -paginate(10);这一句干了四件事。with([category])预载入关联分类执行时为避免不了要连表但 ThinkPHP 会先把新闻查出来再按 category_id 批量查分类而不是每条新闻都执行一次分类查询。where(status, 1)只取已发布内容。order(create_time, desc)控制排序注意是desc不是desc()写错了会报方法不存在。paginate(10)返回一个分页对象里面不仅有当前页数据还带着“上一页、下一页、总页数”这些信息。很多时候列表页还需要统计点击量或者按分类筛选查询条件会更多。不要每次都从零写我习惯把通用条件抽成一个私有方法private function baseQuery() { return News::with([category])-where(status, 1); } public function index() { $list $this-baseQuery() -order(create_time, desc) -paginate(10); return view(index, [list $list]); }这样做的好处是列表页、搜索页共用同一套基础条件以后如果要加“仅显示置顶新闻”只改一处就够了。另一个常见坑是paginate()和select()别混select()返回的是纯数组/模型集合没有分页方法模板里直接{$list|raw}会报错只有paginate()返回的对象才带render()。前台的列表、详情、分页到底怎么写下一章展开。4. 前台三件套列表、详情、分页与搜索4.1 前台控制器列表与详情的标准写法前台控制器我放在app/controller/Index.php对应网站首页和新闻详情。先看列表方法和详情方法的完整代码?php namespace app\controller; use app\BaseController; use app\model\News; use think\facade\Request; class Index extends BaseController { public function index() { $list News::with([category]) -where(status, 1) -order(create_time, desc) -paginate(10); $this-assign(list, $list); return $this-fetch(); } public function detail($id) { $info News::with([category]) -where(id, $id) -where(status, 1) -find(); if (!$info) { abort(404, 新闻不存在); } News::where(id, $id)-inc(views)-update(); $this-assign(info, $info); return $this-fetch(); } }detail($id)里的$id是路由传过来的参数ThinkPHP 会自动绑定到方法参数上。find()查不到数据时返回null所以做了!$info判断并调用abort(404)给出友好提示避免模板里访问不存在的对象报错。阅读数自增用了inc(views)这是框架提供的原子递增方法比先find再views1再save靠谱并发下不会丢数据。assign和fetch是控制器与模板之间的桥梁。assign(info, $info)把数据传给模板模板里用$info就是这条新闻fetch()默认找app/view/index/detail.html这个模板文件不需要手动写模板路径默认映射机制就能对上。4.2 模板渲染从变量赋值到分页控件模板是这套系统里最容易看出“易学易用”的地方。ThinkPHP 的模板语法没有引入太复杂的概念HTML 里嵌一点循环标签就能干活。列表页的核心模板div classnews-list {volist namelist iditem} div classnews-item h2a href/index/detail/id/{$item.id}{$item.title}/a/h2 p classmeta 分类{$item.category.name|default未分类} | 点击{$item.views} /p /div {/volist} /div div classpage-nav {$list|raw} /div{volist namelist iditem}相当于 foreachname是控制器 assign 过来的变量名id是循环里的当前元素。{$item.title}输出标题模板引擎默认做了 HTML 转义即便标题里有script标签也会被转成普通文本这是防 XSS 的基础保障。{$item.category.name}能直接点出一层关联数据前提是控制器里用了with([category])预载入否则这里要额外查库页面会变慢。{$item.category.name|default未分类}是模板过滤器的用法意思是如果分类名为空就显示“未分类”新闻没选分类时就不会白屏报错。分页输出这里有个新手经典坑直接写{$list|raw}还是{$list-render()|raw}取决于框架版本和 Paginator 输出方式。我习惯在控制器里先把渲染好的分页字符串单独 assign 出来模板只用变量不关心内部实现。比如控制器里再加一行$this-assign(pages, $list-render());模板这边就变成div classpage-nav {$pages|raw} /div$list-render()返回的是一段 HTML|raw告诉模板引擎“这段内容不要转义直接输出”。分页的样式默认很朴素如果你用的是 Bootstrap 或 Layui需要去分页类里配置list_rows模板属性才能生成带对应 class 的分页导航做法不太统一建议直接参照 UI 组件的手动 CSS 覆盖。分页要能用远古条件去调试后面避坑章细说。4.3 分类筛选与关键词搜索参数传递的坑新闻列表一般还会有两个入口按分类看某一类新闻、按关键词搜索标题。这两个功能都不需要新写一套逻辑在基础查询上追加条件即可。控制器里我这样组织public function index() { $cid (int) Request::param(cid, 0); $kw trim(Request::param(kw, )); $query News::with([category])-where(status, 1); if ($cid 0) { $query-where(category_id, $cid); } if ($kw ! ) { $query-where(title, like, %{$kw}%); } $list $query-order(create_time, desc) -paginate([ list_rows 10, query Request::param(), ]); $this-assign(list, $list); $this-assign(pages, $list-render()); return $this-fetch(); }关键在这一行query Request::param()。它的作用是把当前 URL 里的cid、kw参数原样带到分页链接里。如果不加翻页链接就会变成/index/index?page2分类和搜索条件全部丢失用户点了第二页就“跳出”当前筛选结果。$cid前面加了(int)强制转整数是为了防止有人把cid传成字符串去干扰 SQL 拼接搜索词用了trim去掉首尾空格不然kw php查出来一片空。前台模板里搜索框与分类下拉需要把当前选中状态回填上否则用户一刷新就不知道自己选了哪个分类。模板做法是form action/index/index methodget select namecid option value0全部分类/option {volist namecategories idcat} option value{$cat.id} {eq namecid value$cat.id}selected{/eq}{$cat.name}/option {/volist} /select input typetext namekw value{$kw|default} placeholder搜索标题 button typesubmit搜索/button /form{eq namecid value$cat.id}是模板里的比较判断满足条件就输出selected。注意value{$kw|default}里因为$kw可能未定义使用default过滤器兜底。分类下拉数据要单独查一遍分类表并 assign 过来看分类筛选功能时不能只查新闻表所有分类都要列出来给用户选。5. 后台登录与新闻管理从请求到入库的完整链路5.1 后台登录密码校验、会话与退出后台是整个新闻系统的管理端第一道门就是登录。一个合格的登录要做到三件事密码不能明文存储、登录状态要用 Session 记录、所有后台操作先过鉴权。管理员表里password字段存的是password_hash()生成的散列那校验就该用password_verify()。看登录控制器?php namespace app\controller\admin; use app\BaseController; use app\model\Admin; use think\facade\Request; use think\facade\Session; class Login extends BaseController { public function index() { return $this-fetch(); } public function doLogin() { $username trim(Request::param(username, )); $password Request::param(password, ); $admin Admin::where(username, $username)-find(); if ($admin password_verify($password, $admin-password)) { Session::set(admin_id, $admin-id); Session::set(admin_name, $admin-username); return redirect(/admin/news/index); } return 用户名或密码错误; } public function logout() { Session::delete(admin_id); Session::delete(admin_name); return redirect(/admin/login); } }登录成功后只把admin_id和admin_name放进 Session不要存整个管理员对象。Session 存在服务端你可以把 admin_id 拿出来后随时再查库拿最新数据。登出就是删 Session然后跳回登录页。很多项目在这时候漏掉一个细节用户改了密码原来登录态依然有效。要处理这个问题登录后的后续操作里每次比对一下 Session 里的管理员信息跟数据库是否一致但要注意别频繁查库我一般会在改密码的请求里把对应 Session 清掉。密码散列的生成方式也要说清楚建议用 PHP 自带函数$hash password_hash(你的初始密码, PASSWORD_DEFAULT);生成一次后直接 UPDATE 到 admin 表。PASSWORD_DEFAULT在不同 PHP 版本下算法可能不同但password_verify()不受影响它能兼容历史版本产生的散列。注意不要自己拼 MD5 加盐MD5 的碰撞风险已经被验证过多次password_hash 才是现在标配的安全做法。5.2 新闻新增与编辑数据校验和入库后台核心操作是新闻的增删改查。新增和编辑共用一个表单靠隐藏字段区分是“创建”还是“更新”。我先说新增的保存逻辑public function save() { $data Request::only([ title, category_id, content, status, cover ]); $validate (new \think\Validate()) -rule(title, require|max:100) -rule(content, require); if (!$validate-check($data)) { return 标题必填且不超过100字内容必填; } if ((int) $data[category_id] 0) { return 请选择分类; } $news News::create($data); return redirect(/admin/news/edit/id/ . $news-id); }Request::only()只取表单里指定的几个字段避免用户恶意提交额外参数覆盖你不想被改的字段。校验规则写在业务层而不是数据库层是因为有些校验必须结合业务才能判断比如“分类 ID 必须存在”。News::create($data)走模型创建如果模型里配置了自动时间戳create_time 和 update_time 会自己写入。编辑和新增的区别仅仅是多了 id 和 updatepublic function update() { $id (int) Request::param(id, 0); $news News::find($id); if (!$news) { return 新闻不存在; } $data Request::only([ title, category_id, content, status, cover ]); $news-save($data); return redirect(/admin/news/edit/id/ . $id); }这里要提醒一个非常隐蔽的坑模型创建或更新时如果数据表字段很多而你又没在模型里定义字段允许列表的话ThinkPHP 的严格字段检测可能把一些字段过滤掉。表现就是表单里明明传了cover入库后却是空字符串。解决办法是在模型里加一句声明protected $schema [ id int, title string, category_id int, content string, cover string, status int, views int, ];这样模型就明确知道哪些字段是自己管理的create和save才会完整保留这些数据。这个坑我在给某公司做内部信息台时踩过排查了半个下午最后就是差这么一行声明。5.3 图片上传与中间件保护后台路由新闻封面几乎都是必有的功能。ThinkPHP 的上传很简单但安全和路径两个问题必须处理。控制器里的上传方法public function upload() { $file Request::file(cover); try { $file-validate([ size 2097152, ext jpg,jpeg,png,gif,webp ]); $savename \think\facade\Filesystem::disk(public) -putFile(news_cover, $file); return json([code 1, url /storage/ . $savename]); } catch (\think\exception\ValidateException $e) { return json([code 0, msg $e-getMessage()]); } }size单位是字节2097152就是 2MB。这个限制建议别放太大新闻封面图 2MB 以内足够限制大小能避免有人传超大文件把磁盘塞满。ext严格指定允许的扩展名只信任图片类型可以让上传入口更安全。Filesystem::disk(public)-putFile()会把文件存到public/storage目录并生成随机文件名随机名是为了避免文件名冲突和路径猜测。/storage/...这个 URL 直接拼在表单的cover字段里用。表单那边记得加上enctypemultipart/form-dataform action/admin/news/save methodpost enctypemultipart/form-data input typetext nametitle select namecategory_id ... /select input typefile namecover textarea namecontent/textarea button typesubmit提交/button /form如果你忘了这行PHP 会收不到文件上传功能表现为“一直没反应”因为文件根本没发到服务端。后台所有路由都要保护起来不能让人没登录就能直接访问/admin/news/delete把数据删光。最常见的做法是路由分组加中间件。在route/app.phpuse think\facade\Route; Route::group(admin, function () { Route::get(login, admin.Login/index); Route::post(login, admin.Login/doLogin); Route::get(logout, admin.Login/logout); Route::get(news/index, admin.News/index); Route::get(news/edit/:id, admin.News/edit); Route::post(news/save, admin.News/save); Route::post(news/update, admin.News/update); Route::post(news/delete, admin.News/delete); })-middleware(\app\middleware\AdminAuth::class);中间件类写在app/middleware/AdminAuth.php?php namespace app\middleware; use think\facade\Session; class AdminAuth { public function handle($request, \Closure $next) { if (!Session::has(admin_id)) { return redirect(/admin/login); } return $next($request); } }这里的关键是登录路由/admin/login也在这个分组里但它不能要求登录。两种处理方式一种是中间件里判断当前请求地址是admin/login就放行另一种是把登录路由拆出来不放进这个分组。我推荐后者路由规则更清晰不会在中间件里写死地址判断。中间件作用在分组上分组内所有路由先过中间件Session 没登录就弹回登录页进不了新闻管理。6. 常见问题排查与进阶验证交付前的三个自查习惯分页链接样式失效或参数丢失。现象列表页第一页正常点第二页要么样式全没了要么分类搜索条件没了。原因分页 HTML 里没有引入对应 CSS或者paginate()没传query参数翻页链接丢掉了cid、kw。解决模板里引入 Bootstrap 或 Layui 的分页样式控制器分页数组里加query Request::param()。模型时间戳字段不写值。现象新增新闻后create_time是 0排序乱套。原因项目用了非默认字段名比如数据表里叫created_at而模型里没有声明$createTime。解决模型加一行protected $createTime created_at;同时$updateTime也对应改。如果你不希望个别字段自动维护就设成false。上传大图报错或文件不落盘。现象前端上传转圈后提示失败后端日志有 Upload Error。原因php.ini的upload_max_filesize默认只有 2M或表单没有enctypemultipart/form-data。解决改php.ini里upload_max_filesize 20M、post_max_size 20M并重启 PHP确认表单属性写全。改完用phpinfo()验证是否生效。交付前我只做三件事。第一步未登录状态直接访问后台新闻编辑页确认会被踢回登录页第二步后台新增一条标题带script的新闻去前台看它被转义成普通文本而不是执行弹窗第三步把新闻 status 改成 0确认前台不再展示。这三关过了系统才算能交。数据库那边若数据量上万给news表加一个(status, create_time)的组合索引列表查询翻页速度会明显提升。详情页可以做一层简单缓存cache(news_ . $id, $info, 3600)发布或编辑时再cache(news_ . $id, null)清掉新闻站阅读量大时能省不少数据库压力。我自己的习惯是每个版本交付前把 debug 关掉、开启日志记录跑一遍增删改查加登录登出再放手。每一个看似“简单”的新闻系统细节处都有不少需要打磨的地方这套流程至少能让你少走两个月的弯路希望帮到你。本文还有配套的精品资源点击获取

相关新闻

手写PID算法从入门到实战:C语言实现与积分饱和、微分滤波工程技巧

手写PID算法从入门到实战:C语言实现与积分饱和、微分滤波工程技巧

1. 从一次电机抖动说起:为什么我要手写PID 去年帮一个做小型云台的朋友调设备,他用的开源飞控里自带PID参数整定界面,但响应总是慢半拍,稍微加大比例项就开始等幅振荡。我把他那段控制代码翻出来一看,好家伙&#xff0…

2026/10/14 18:11:37 阅读更多 →
PinchBench贡献指南:从单元测试到Lint检查,提交你的第一个基准任务

PinchBench贡献指南:从单元测试到Lint检查,提交你的第一个基准任务

【免费下载链接】skill PinchBench is a benchmarking system for evaluating LLM models as OpenClaw coding agents. Made with 🦀 by the humans at https://kilo.ai 项目地址: https://gitcode.com/gh_mirrors/skill1/skill 点击查看 免费下载 Pinc…

2026/10/14 18:10:36 阅读更多 →
PMW脉冲宽度调制从原理到实战:占空比、频率与死区时间调试指南

PMW脉冲宽度调制从原理到实战:占空比、频率与死区时间调试指南

1. 从三个字母说起:PMW到底指什么第一次看到“PMW”这三个字母,很多人会愣一下。它不像“AI”“IoT”那样有明确的指向,也不像“KPI”“ROI”那样在职场语境里被反复提及。但如果你在硬件圈、嵌入式圈或者电源设计圈待过一段时间,…

2026/10/14 18:10:36 阅读更多 →

最新新闻

AI逆向工程实战:31.2K Star开源项目如何用大模型辅助二进制分析

AI逆向工程实战:31.2K Star开源项目如何用大模型辅助二进制分析

1. 当AI把目光投向二进制:逆向工程的门槛正在被重新定义第一次看到“AI开始搞逆向工程”这个说法,我的反应是:终于有人把这件事摆到台面上了。逆向工程这个领域,长期以来都是少数人的游戏——你得懂汇编,得熟悉PE/ELF文…

2026/10/14 23:16:08 阅读更多 →
ARM架构CentOS 7.6网口bond配置实战与优化指南

ARM架构CentOS 7.6网口bond配置实战与优化指南

1. 项目背景与需求拆解1.1 为什么要在ARM架构的CentOS 7.6上做网口bond在ARM服务器上跑CentOS 7.6,这个组合本身就有点意思。ARM架构的服务器这几年在数据中心里越来越常见,尤其是那些对功耗敏感、需要高密度部署的场景。但ARM平台跟传统的x86平台在硬件…

2026/10/14 23:16:08 阅读更多 →
两级式光伏MMC并网系统故障穿越Simulink仿真模型解析

两级式光伏MMC并网系统故障穿越Simulink仿真模型解析

1. 项目概述与问题背景做光伏并网研究的同学,对"故障穿越"这四个字应该都不陌生。无论你研究的是组串式逆变器、集中式逆变器,还是近几年大热的MMC拓扑,只要涉及并网,就绕不开电网故障时"能不能撑住、撑多久、怎么…

2026/10/14 23:16:08 阅读更多 →
AI Agent实操:五个新工具让AI学会用鼠标干活

AI Agent实操:五个新工具让AI学会用鼠标干活

1. 这次AI的进化方向,是先学会用鼠标Copilot能“直接操作”电脑这个事,让我琢磨了好几天。以前我们聊AI,聊的都是大模型能读多少token、能写多长的代码、能生成多像样的图。但那个层面的能力再强,它也是关在对话框里的——你问它答…

2026/10/14 23:16:08 阅读更多 →
OpenCV特征提取与匹配实战:SIFT、ORB、AKAZE选型与调参指南

OpenCV特征提取与匹配实战:SIFT、ORB、AKAZE选型与调参指南

1. 从一张拍歪的照片说起:为什么特征提取值得花时间搞懂很多人第一次接触OpenCV,都是从读图、灰度化、边缘检测这条线走下来的,觉得图像处理不过如此。直到某天需要把两张不同角度拍的同一场景对齐,或者想让程序在一堆商品图里找出…

2026/10/14 23:16:08 阅读更多 →
用Hermes Agent打造AI数字员工:企业自动化实战全解析

用Hermes Agent打造AI数字员工:企业自动化实战全解析

先交代一下背景,这个教程源自我在某企业内部做的一次 AI 自动化试点总结。当时团队的任务很直接,把重复性高、规则清晰但又需要人肉判断的活儿,逐步交给一套能听指挥、能调用工具、能自己干活的系统。市面上轮子很多,最终敲定用 H…

2026/10/14 23:14:55 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 22:01:27 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 7:53:34 阅读更多 →