EJB入门项目实战:三类Session Bean与JNDI部署避坑指南
简介这是一份面向EJB初学者的入门实践项目基于IDEA与JBoss 7.1.1应用服务器覆盖无状态/有状态会话Bean、实体Bean与消息驱动Bean的搭建与部署适合正在学习Java EE组件化开发、希望理解EJB生命周期与事务控制的读者。压缩包共46个文件约2.84MB含5个Java源码、15个class编译文件、12个xml配置及JSP页面pom.xml负责依赖管理META-INF与resources目录承载部署描述符和数据库连接配置结构清晰便于对照学习。已有777人学习下载。通过该入门项目可获得完整可运行的EJB示例直观掌握注解使用、接口定义、JNDI绑定、事务处理及消息驱动Bean与JMS的集成方式为后续构建复杂的企业级Java EE应用打下基础。1. EJB入门项目到底在学什么把业务对象交还给容器托管的第一步同一个业务接口用Servlet写事务要自己begin/commit连接要自己管多实例部署时Session还得塞进数据库做同步换成EJB容器把事务、安全、并发、实例池全部接走业务类只需要是一个带注解的普通Java类。EJB入门项目要做的就是亲手把一个最小的无状态Bean部署进应用服务器再从客户端把它的远程接口调通。适合正在从Servlet或纯Spring Boot转向Jakarta EE的开发者也适合要接手老EJB系统的同事——看懂这个最小闭环后面翻任何架构文档都不再是黑匣子。2. 先分清三类Session BeanStateless、Stateful、Singleton的适用边界EJB家族里真正天天打交道的是三类Session Bean加上一个消息驱动Bean入门阶段我建议先把Session Bean选明白。选错类型不是编译报错而是上线后才暴露问题购物车状态被多实例共享、缓存被并发写穿、长事务把连接池拖垮。这一章把三类Bean的语义、生命周期和事务上下文讲清楚后面写代码才有依据。2.1 Stateless Session Bean无状态是“不保证有状态”不是不能写字段Stateless 是大多数EJB入门项目的第一个Bean也是最容易被名字误导的一个。它的全称是无状态会话Bean意思不是类里不能有字段而是容器不保证两次方法调用落到同一个实例上所以任何留在字段里的中间数据都不可信。Stateless public class OrderNoGeneratorBean { public String next(String prefix) { // 每次调用都可能是不同实例这里只能放无状态逻辑 return prefix - UUID.randomUUID(); } }这段代码里我没有写任何实例字段因为两次next()调用可能被容器分发到不同的实例。Stateless告诉容器这个Bean可以被池化实例可以在空闲时被回收或者复用。池化带来两个收益一是内存占用可控二是方法之间天然隔离并发安全压力小。容器默认把所有方法的事务属性设成REQUIRED也就是调用方没开事务时方法自己开一个方法正常返回就提交。选Stateless的典型场景是计算、查询、字典翻译、网关转发这类不携带用户会话的纯逻辑。如果你发现自己给Stateless Bean加了setUserId()再调业务方法那说明类型选错了应该考虑Stateful或者把用户身份作为方法参数传进来。项目里见过太多人把登录用户ID缓存在Stateless字段里多实例部署后时而正常时而串号这就是把“不保证有状态”理解成了“我运气好能碰上同一个实例”。2.2 Stateful Session Bean会话状态放内存前先想好超时和钝化Stateful 和 Stateless 正相反容器会保证同一个客户端拿到的代理后续方法调用都落在同一个Bean实例上。这个特性天然适合购物车、多步审批、向导式录入这类必须保留中间状态的过程。Stateful public class CartBean { private ListString items new ArrayList(); public void add(String sku) { items.add(sku); } public int size() { return items.size(); } Remove public void checkout() { // 结账后显式告诉容器这个实例可以销毁了 } }Remove是我在入门阶段不太容易被注意、但后期非常关键的注解。它标注的方法被调用后容器会销毁这个Bean实例并释放资源。如果不写Remove实例就只能等会话超时被回收购物车流程一多内存里堆积的全是不再使用的Bean。Stateful Bean还有一组生命周期回调PostConstruct、PrePassivate、PostActivate、PreDestroy。其中PrePassivate和PostActivate对应钝化与激活容器把不活跃实例序列化到磁盘再重新加载这时候记得把数据库连接、套接字这类不可序列化资源在回调里关掉和重建。选Stateful前要回答三个问题状态能不能由前端带回状态能不能存数据库或缓存中间件状态的量级是不是超过几KB如果前端能带回就带回能落库就落库Stateful Bean适合的是“必须在一次会话里连续操作多步而且每步产生的数据不适合立刻落库”的场景。2.3 Singleton Session Bean共享缓存和计数器的锁策略Singleton 是整个应用服务器里每个应用只有一个实例的Bean适合做配置缓存、计数器、应用级预热。它跟ApplicationScoped的CDI Bean定位接近但多了一套更严格的并发控制。Singleton public class AppConfigBean { private MapString, String cache new ConcurrentHashMap(); Lock(LockType.READ) public String get(String key) { return cache.get(key); } Lock(LockType.WRITE) public void put(String key, String value) { cache.put(key, value); } AccessTimeout(3000) public void refresh() { // 拿不到写锁时最多等3秒 } }默认情况下Singleton的锁策略是Lock(WRITE)也就是说所有方法默认串行执行。读多写少的场景一定要给查询方法标上Lock(READ)否则并发上来后查询全部排队性能直接崩。AccessTimeout(3000)表示拿锁超时时间单位毫秒超时后容器会抛ConcurrentAccessTimeoutException。还有个容易被忽略的注解是Startup它让Singleton在应用启动时就实例化并执行PostConstruct我一般用它做缓存预热和自检。Singleton 最容易踩的坑是“把重IO塞进被锁的方法里”。比如在put方法里同步写数据库写库耗时3秒所有读方法都被写锁挡住整个应用表现为卡死。正确做法是让写方法只更新内存缓存落库逻辑放到独立的异步线程或者另一个Stateless Bean里。3. 用Maven搭一个能部署的EJB入门工程pom配置、三类Bean代码与WildFly一键部署原理讲完就该动手了。这一章我按最常见的方案从零搭一个最小工程Maven 单war包 开源应用服务器。你会发现EJB 3.1之后Bean可以直接放在war包里不用再强制拆成ear入门阶段这个简化能省掉大量构建配置的干扰。3.1 工程骨架为什么入门阶段用war而不是ear传统EJB工程是ear结构一个ejb jar放业务Bean一个war放Web层ear负责打包两者。这样做的历史原因是老规范强制EJB必须在独立jar里而且ear能清晰表达模块边界。现在主流容器都支持在war里直接声明EJB对入门项目来说war结构只需要一个模块部署、调试、查日志都简单一个量级。ejb-min/ ├── pom.xml └── src/main/java/ └── com/example/biz/ ├── OrderService.java ├── OrderServiceBean.java └── ReportJobBean.java这个结构里OrderService是业务接口OrderServiceBean是实现ReportJobBean是定时任务。war包方式下Bean类和普通类没有任何目录区别靠的就是类上的Stateless、Stateful、Singleton注解被容器识别。我一般还会建一个src/main/webapp/WEB-INF/web.xml空文件避免某些容器对没有web.xml的war包做额外扫描。EJB的接口在这里有两条路线给接口标上Local或Remote这决定了调用方式是本地还是跨JVM。3.2 pom.xml里的三项关键配置依赖、打包插件、部署插件project xmlnshttp://maven.apache.org/POM/4.0.0 modelVersion4.0.0/modelVersion groupIdcom.example/groupId artifactIdejb-min/artifactId version1.0-SNAPSHOT/version packagingwar/packaging dependencies dependency groupIdjakarta.ejb/groupId artifactIdjakarta.ejb-api/artifactId version4.0.0/version scopeprovided/scope /dependency dependency groupIdjakarta.servlet/groupId artifactIdjakarta.servlet-api/artifactId version6.0.0/version scopeprovided/scope /dependency /dependencies build finalNameejb-min/finalName plugins plugin groupIdorg.apache.maven.plugins/groupId artifactIdmaven-war-plugin/artifactId version3.4.0/version /plugin plugin groupIdorg.wildfly.plugins/groupId artifactIdwildfly-maven-plugin/artifactId version4.2.0/version /plugin /plugins /build /project三个关键点第一jakarta.ejb-api的scope是provided因为应用服务器里已经内置了这套API打包进去反而会造成类冲突。第二finalName决定了war文件名也直接决定了后面JNDI里的模块名我习惯把artifactId和finalName设成一致省得部署后对不上号。第三wildfly-maven-plugin负责把war推到运行中的服务器上走的是管理端口不是HTTP端口。如果你用的容器不是WildFly这套配置思路同样适用依赖改成容器对应的jakarta.ejb-api部署插件换成容器官方提供的Maven插件或直接用管理接口上传。EJB API是所有容器共享的差别只在外围的部署通道。3.3 一个最小Stateless Bean加一个Schedule定时任务验证容器托管Bean代码是入门项目里最不花哨的部分但有几个约束必须刻在脑子里类必须是public的不能是final的不能有final方法。这些约束不是编译器校验的是容器在部署期通过反射检查的违反它你会看到一个看起来像是“部署失败”但实际是类结构不合法的问题。package com.example.biz; import jakarta.ejb.Stateless; Stateless public class OrderService { public String createOrder(String sku, int qty) { // 这里没有写事务代码容器自动管理 return ORDER- sku - qty; } }这个Bean没有实现任何接口走的是EJB 3.1的无接口视图。容器会给它生成一个代理同模块内的Servlet或者CDI Bean直接注入就能用。无接口视图的限制是它只能在本地调用不能跨JVM。如果你预感到这个Bean以后会被独立客户端远程调用从第一天就给它抽一个接口并标Remote。package com.example.biz; import jakarta.ejb.Schedule; import jakarta.ejb.Singleton; import jakarta.ejb.Startup; Singleton Startup public class ReportJobBean { Schedule(hour 2, minute 30, persistent false) public void generateDailyReport() { // 每天凌晨2:30由容器触发不需要外部调度器 } }Schedule是让人最快感受到“容器托管”价值的注解不用自己写守护线程不用接Quartz容器内部线程池负责按cron表达式触发。persistent false表示这个定时任务不持久化服务器重启后不补跑如果任务丢一次会出事故应该改成persistent true容器会在重启后补偿错过的触发点。写完之后执行部署mvn clean package mvn wildfly:deploy -Dwildfly.hostname127.0.0.1 -Dwildfly.port9990第一次跑wildfly:deploy之前确认服务器已启动并且管理端口9990可访问。成功后访问管理控制台能看到ejb-min.war处于active状态日志里会出现部署成功的行。这时候做一个最简单的验证改一下createOrder的返回值重新deploy再调用一次能看到容器把新代码加载进来这就是热部署的体现。4. 把客户端和EJB容器接上JNDI命名的三种写法与独立客户端lookupBean部署进去只是第一步客户端怎么找到它是入门项目真正卡人的地方。EJB的“寻址”靠JNDI而JNDI字符串几乎每个新手都要拼错几回。这一章把命名规则拆开讲再给一个从零写独立客户端lookup的完整例子。4.1 java:global / java:app / java:module三种命名的差异表JNDI名字看着是一长串路径其实结构非常规律前缀决定了查找的生效范围。JNDI前缀格式生效范围典型场景java:globaljava:global/应用名/模块名/Bean名!接口全名整个服务器所有应用独立客户端远程调用java:appjava:app/模块名/Bean名!接口全名同一个ear内部ear里war调用ejb jarjava:modulejava:module/Bean名!接口全名同一个模块内部war内Bean互相调用三个默认命名规则是血泪经验应用名默认是ear文件名去掉后缀模块名默认是jar或war文件名去掉后缀Bean名默认是类简单名。比如我的war叫ejb-min.war里面有个OrderService且带远程接口com.example.biz.OrderServiceRemote那它的完整JNDI就是java:global/ejb-min/ejb-min/OrderService!com.example.biz.OrderServiceRemote看出坑在哪了吧模块名和Bean名之间隔着两段相同的名字一个来自war文件名一个来自类名。很多人拼错就是少写了中间那段重复的模块名。对无接口视图的BeanJNDI名不带接口后缀直接是java:global/ejb-min/ejb-min/OrderService。4.2 独立客户端里手写InitialContext核心参数与依赖独立客户端是EJB远程调用的标准用法一个小Java程序通过JNDI拿远程代理然后像调本地方法一样调用。这里必须处理的不是业务代码而是“怎么让客户端知道服务器在哪、用什么协议”。package com.example.client; import com.example.biz.OrderServiceRemote; import javax.naming.Context; import javax.naming.InitialContext; import java.util.Properties; public class OrderClient { public static void main(String[] args) throws Exception { Properties props new Properties(); props.put(Context.INITIAL_CONTEXT_FACTORY, org.wildfly.naming.client.WildFlyInitialContextFactory); props.put(Context.PROVIDER_URL, http-remoting://127.0.0.1:8080); InitialContext ctx new InitialContext(props); OrderServiceRemote service (OrderServiceRemote) ctx.lookup( java:global/ejb-min/ejb-min/OrderService!com.example.biz.OrderServiceRemote); String orderId service.createOrder(SKU-1001, 2); System.out.println(created: orderId); } }两个参数是远程调用能不能成的关键INITIAL_CONTEXT_FACTORY指定客户端用哪个工厂类去解析JNDI这个类必须来自容器提供的客户端jarPROVIDER_URL使用的是http-remoting协议端口是HTTP端口8080不是管理端口9990。首次跑这个客户端记得在依赖里加上容器分发的客户端库WildFly对应的是jboss-client把这个jar放到客户端的classpath里上面两个类才能被找到。如果你觉得手写Properties太啰嗦也可以在客户端里放一个jndi.properties文件把这两行配置写进去直接new InitialContext()即可。但显式写Properties的好处是启动时能打印出来确定生效的配置是哪份——我就在多个环境切换时被classpath里的旧配置文件坑过显示配置永远比隐式配置好排错。4.3 JNDI解析失败的排查顺序从NoInitialContextException到NameNotFoundExceptionJNDI报错就两大类排查顺序非常固定。第一类NoInitialContextException意思是客户端压根没连上服务器优先检查三处容器是否在监听8080、PROVIDER_URL协议拼写对不对、客户端jar是否真的在classpath里。第二类NameNotFoundException意思是连上了但名字不对这时候别猜直接把服务器上实际绑定的名字列出来看。// 调试专用把该上下文下所有绑定名打印出来 java.util.HashtableString, Object env new java.util.Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, org.wildfly.naming.client.WildFlyInitialContextFactory); env.put(Context.PROVIDER_URL, http-remoting://127.0.0.1:8080); InitialContext ctx new InitialContext(env); java.util.Enumerationjavax.naming.NameClassPair list ctx.list(java:global); while (list.hasMoreElements()) { System.out.println(list.nextElement().getName()); }ctx.list(java:global)会把所有应用、模块、绑定名打出来对照着拼真实名字比盯着文档猜靠谱得多。我踩过最隐蔽的一次是war包被IDE热部署后文件名变成了ejb-min.war加时间戳副本finalName失效JNDI里模块名变成了带随机后缀的名字。从那以后凡是我在哪对JNDI名都先list看看这也是最快的学习路径。5. EJB入门项目避坑指南部署不生效、找不到Bean、ClassCastException与半夜回滚这一章收集的是入门项目里反复出现的四个现场每个都按“现象—原因—解决”来讲。这些不是理论问题是真实部署环境里会挡住你半天甚至一周的坎。5.1 部署日志一片正常但新代码不生效现象mvn wildfly:deploy提示success管理控制台里war是active但访问接口拿到的还是旧逻辑。原因八成不是EJB的问题是IDE或脚本把war包解压后做增量发布旧class文件残留。WildFly部署默认是解压式部署standalone/deployments目录下面会有一个和war同名的目录里面有解压后的class。如果本地构建只替换了war里的部分文件或者IDE默认做了“复制已更改文件”而不是“重建并完整上传”残留class就会和新class混在一起而容器优先加载了旧的。解决先mvn clean再package确保war里没有旧class部署前把standalone/deployments下对应目录删掉再重新deploy最后确认finalName没被IDE覆盖。我给自己定了条规矩排查部署不生效时第一件事是比对war包里的class时间戳和服务器上的class时间戳而不是重启服务器。5.2 “No EJB found”但JNDI名看着完全正确现象异常信息是NameNotFoundException名字和文档例子一字不差但就是找不到。同一套代码换个容器又能跑。原因JNDI名字里的“模块名”不等于“artifactId”它默认取打包产物的文件名。ear包里的模块名规则和war不同一个war部署到服务器模块名是war文件名但如果war被打进ear模块名变成war文件名内层再套一层ear文件名的路径。还有一种常见情况是IDE的部署工具自动给war改名为带上下文的版本号模块名就跟着变了。解决不要凭记忆拼启动服务器后用上一章的ctx.list(java:global)打出真实树。另一种办法是直接看启动日志WildFly在应用发布成功时会在日志里打印该应用绑定的JNDI名列表搜关键字“JNDI”就能看到完整名字。这个习惯帮我省下的时间比写业务代码还多。5.3 远程客户端抛ClassCastException业务代码却没问题现象独立客户端lookup成功代理也拿到了但强转接口类型时抛ClassCastException提示“xxx cannot be cast to xxx”两边的类名明明一模一样。原因远程调用时客户端拿到的是动态代理它只认服务器那边classloader加载过的那份接口类。如果客户端classpath里有一份自己打包的OrderServiceRemote服务器的web模块里也有一份OrderServiceRemote这两个类在JVM看来是“全限定名相同但身份不同”的类强转必然失败。这就是典型的包分裂问题常见于把接口类从业务模块里复制出来后直接拷给客户端。解决远程接口包括远程方法签名里用到的DTO必须单独抽成一个api jar服务器端和客户端都依赖这同一个jar而不是各自编译各自的副本。如果你临时调试可以把服务器解压后的class和客户端class用javap对比但最终方案一定是接口归一。这条规范我从入门第一天就执行后来接第三方的接口时少踩了无数坑。5.4 事务在凌晨回滚白天怎么测都不复现现象定时任务每天凌晨跑批量数据处理日志里出现TransactionRolledbackException提示事务超时或连接获取超时白天手动跑同样逻辑却正常。原因两个因素叠加。一是事务超时EJB方法默认事务超时时间通常只有几分钟实际值由容器配置决定如300秒凌晨批量数据量大事务超过时限被容器强制回滚。二是连接池竞争同一时刻其他定时任务和报表查询把连接池占满EJB拿不到连接等待超过时间后抛异常。很多人在bean方法里用try-catch把异常吞掉导致日志里只有一条业务错误真实原因被藏住。解决批量任务改用TransactionAttribute(REQUIRES_NEW)或者拆分成多条消息分批处理避免一个超长事务给不同任务调整Schedule的执行间隔错峰检查容器的transaction-timeout配置按业务量调大至合理值。最关键的一条纪律EJB方法里不要捕获异常后不处理容器判定回滚靠的是异常传播到方法边界你吞掉异常数据就停留在“看起来成功实际上没提交”的状态。6. 把入门项目养成一个长期骨架三个值得从第一天就坚持的EJB习惯入门项目跑通后很容易停在“能调通就行”的阶段。但EJB项目越到后面维护成本越取决于早期的三个习惯这里讲的就是我现在每个项目起步时必做的事。第一个习惯远程接口从第一天就单独抽一个api模块哪怕现在只有一个客户端用。war包和独立的客户端程序都依赖这个api jarDTO也放里面。这样做的回报在第一次跨模块调用时就能看到不会陷进上一章说的ClassCastException泥潭。第二个习惯业务异常全部用ApplicationException显式声明回滚语义不依赖默认规则去猜。ApplicationException(rollback true) public class OrderBusinessException extends RuntimeException { }这段代码的意思是任何抛出OrderBusinessException的地方容器都无条件回滚当前事务。如果忘了写rollback true默认Checked异常不会触发回滚数据会停留在半提交状态。每个项目的异常体系里只要有这一个注解事务边界就完全可控。第三个习惯用Singleton加Startup做一个轻量自检Bean在应用启动时检查数据库连通性、远程接口可达性、配置完整性启动失败就抛异常让部署失败。这样做把配置错误提前到部署期暴露而不是等到用户访问时才在日志里翻。这三个习惯花的都是小成本。有一次我在一个老项目里排查了三天的问题最后定位到就是接口类被copy了两份导致ClassCastException那是第一次让我下定决心所有EJB远程接口一律抽独立jar包。后面几个项目靠着这些习惯接口变更从两天缩短到半天事务问题几乎绝迹。把入门项目的骨架打正后面长出来的东西才值得维护希望帮到你。本文还有配套的精品资源点击获取

相关新闻

Nano Banana 2.1降价背后:API账单未减半的三大原因

Nano Banana 2.1降价背后:API账单未减半的三大原因

Nano Banana 2.1降价了,价格直接腰斩。按常理想,原来一个月花100元的API调用费,现在应该50元就够了。可我这几个月盯着账单数据,发现事情远没有这么简单——有些月份总花费只降了10%出头,甚至有一个周五的峰值账单比降…

2026/10/13 19:39:21 阅读更多 →
Git四部曲:add、commit、remote、push的本质与实操

Git四部曲:add、commit、remote、push的本质与实操

1. 项目概述:为什么“四部曲”这个说法在Git实操中如此根深蒂固你刚学Git时,是不是也听过这句话:“上传文件就四步——add、commit、remote、push”?我第一次带某高校开源社团做代码托管训练时,发现92%的新人把这四步当…

2026/10/13 19:39:20 阅读更多 →
数学建模B题穿越沙漠:Matlab动态规划源码拆解与调优

数学建模B题穿越沙漠:Matlab动态规划源码拆解与调优

简介:面向数学建模2020年B题的Matlab源码包,适合正在备战建模竞赛、需要参考完整赛题编程实现的学生和培训团队。资源围绕四关递进式求解展开,重点解决第二关双地图双村庄下的矿山与补给选择、第三四关天气不确定时的路线规划,并对…

2026/10/13 19:39:20 阅读更多 →

最新新闻

从零构建Agent技能库:技能层设计、动态装载与回归测试的工程实践

从零构建Agent技能库:技能层设计、动态装载与回归测试的工程实践

直接做Agent应用的人,这两年应该都有同感:单个Agent的对话能力已经不是瓶颈了,真正拉开差距的是Agent能不能稳定地调用外部能力、按流程完成任务。我最近在整理和重构一个内部项目,名字就叫“agent-skills”,本质上是一…

2026/10/13 20:34:36 阅读更多 →
基于MATLAB的脑电功率谱与多尺度熵分析工具箱实战解析

基于MATLAB的脑电功率谱与多尺度熵分析工具箱实战解析

简介:面向脑电信号分析的多尺度熵计算MATLAB代码包,主要服务神经科学、生物医学工程等领域的科研人员与工程师,可用于处理多通道EEG数据,完成从二进制文件读取、预处理、多尺度熵计算到频谱分析、批量统计的完整流程。代码由杨博士…

2026/10/13 20:34:36 阅读更多 →
用litellm搭建统一模型网关,解决多模型接入难题

用litellm搭建统一模型网关,解决多模型接入难题

1. 做了个模型网关,解决了我最头疼的多模型接入问题先交代一下背景。上个月要给一个内部工具接大模型能力,一开始需求很简单:调一个对话接口,把结果返回给前端就行。结果做着做着就失控了。产品那边今天说换某家的新模型试试&…

2026/10/13 20:34:36 阅读更多 →
吃透OpenCV类型宏CV_8UC3:位深通道与内存布局

吃透OpenCV类型宏CV_8UC3:位深通道与内存布局

写这篇文章的起因,是最近又看到不少人在图像处理群里问“为什么Mat创建老报错”“为什么读进来的图片和我心里想的不一样”,最后发现根子都出在同一个地方:没搞懂OpenCV的类型宏,比如CV_8UC3到底代表什么。这玩意儿看着像一串乱码…

2026/10/13 20:34:36 阅读更多 →
YOLOV4后处理解析:从NMS到DIOU-NMS的原理与Python实现

YOLOV4后处理解析:从NMS到DIOU-NMS的原理与Python实现

YOLOV4学习系列写到第三篇,前面咱们拆过CSPDarknet53骨干结构,聊过SPP和PANet的Neck设计,今天终于轮到推理阶段的最后一道工序——非极大值抑制。NMS这个词很多同学早就不陌生了,检测模型调试、比赛刷分、论文复现都绕不开它。但你…

2026/10/13 20:34:36 阅读更多 →
Zbrush次世代角色头部雕刻全流程:从结构认知到皮肤纹理

Zbrush次世代角色头部雕刻全流程:从结构认知到皮肤纹理

做次世代游戏角色,头部雕刻永远是绕不开的坎。常有人说,身体可以靠布料和铠甲遮,脸却始终暴露在玩家眼前,Zbrush头部细节雕刻直接决定了角色能站上哪个档次。这些年我经手过不少项目,也从大量废案里踩出一些实用的新技…

2026/10/13 20:33:28 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

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

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

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

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

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

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

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

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

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

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 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/12 21:05:09 阅读更多 →
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/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练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/12 18:11:17 阅读更多 →