Spring Boot搭建简易SMB服务器遇目录同步错误求助
问题描述
我有一个全新的Spring Boot项目,希望搭建一个可通过Windows资源管理器连接的简易SMB服务器,仅需共享D:\smb-files\folder1目录,并支持通过指定用户名和密码访问。
当前配置
SmbConfig类
package com.example.smb; import java.io.File; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.integration.annotation.Gateway; import org.springframework.integration.annotation.MessagingGateway; import org.springframework.integration.dsl.IntegrationFlow; import org.springframework.integration.dsl.Pollers; import org.springframework.integration.file.FileHeaders; import org.springframework.integration.file.support.FileExistsMode; import org.springframework.integration.smb.dsl.Smb; import org.springframework.integration.smb.session.SmbSessionFactory; import jcifs.DialectVersion; @Configuration public class SmbConfig { public static final String REMOTE_DIRECTORY = "folder1"; @Bean public SmbSessionFactory smbSessionFactory() { SmbSessionFactory smbSession = new SmbSessionFactory(); smbSession.setHost("myHost"); smbSession.setPort(445); smbSession.setDomain("myDomain"); smbSession.setUsername("myUser"); smbSession.setPassword("myPassword"); smbSession.setShareAndDir("myShareAndDir"); smbSession.setSmbMinVersion(DialectVersion.SMB210); smbSession.setSmbMaxVersion(DialectVersion.SMB311); return smbSession; } @Bean public IntegrationFlow smbInboundFlow() { return IntegrationFlow .from(Smb.inboundAdapter(smbSessionFactory()) .preserveTimestamp(true) .remoteDirectory(REMOTE_DIRECTORY) .regexFilter(".*\\.txt$") .localFilename(f -> f.toUpperCase() + ".a") .localDirectory(new File("d:/smb-files")), e -> e.id("smbInboundAdapter") .autoStartup(true) .poller(Pollers.fixedDelay(5000))) .handle(m -> System.out.println(m.getPayload())) .get(); } @Bean public IntegrationFlow smbOutboundFlow() { return IntegrationFlow.from("toSmbChannel") .handle(Smb.outboundAdapter(smbSessionFactory(), FileExistsMode.REPLACE) .useTemporaryFileName(false) .fileNameExpression("headers['" + FileHeaders.FILENAME + "']") .remoteDirectory(REMOTE_DIRECTORY) ).get(); } @MessagingGateway public interface MyGateway { @Gateway(requestChannel = "toSmbChannel") void sendToSmb(File file); } }
Maven依赖
<dependency> <groupId>org.springframework.integration</groupId> <artifactId>spring-integration-smb</artifactId> </dependency>
日志配置
logging.level.org.springframework.integration=DEBUG
错误信息
核心错误:Problem occurred while synchronizing 'folder1' to local directory
最终根源为java.net.UnknownHostException: myHost,完整日志如下:
[payload=org.springframework.messaging.MessagingException: Problem occurred while synchronizing 'folder1' to local directory, headers={id=8a317e74-0c7e-129e-c7b2-e9a7a73a7be5, timestamp=1682786110723}] 2023-04-29T18:35:10.724+02:00 DEBUG 4300 --- [ scheduling-1] o.s.integration.handler.LoggingHandler : bean '_org.springframework.integration.errorLogger.handler' for component '_org.springframework.integration.errorLogger' received message: ErrorMessage [payload=org.springframework.messaging.MessagingException: Problem occurred while synchronizing 'folder1' to local directory, headers={id=8a317e74-0c7e-129e-c7b2-e9a7a73a7be5, timestamp=1682786110723}] 2023-04-29T18:35:10.725+02:00 ERROR 4300 --- [ scheduling-1] o.s.integration.handler.LoggingHandler : org.springframework.messaging.MessagingException: Problem occurred while synchronizing 'folder1' to local directory at org.springframework.integration.file.remote.synchronizer.AbstractInboundFileSynchronizer.synchronizeToLocalDirectory(AbstractInboundFileSynchronizer.java:348) at org.springframework.integration.file.remote.synchronizer.AbstractInboundFileSynchronizingMessageSource.doReceive(AbstractInboundFileSynchronizingMessageSource.java:267) at org.springframework.integration.file.remote.synchronizer.AbstractInboundFileSynchronizingMessageSource.doReceive(AbstractInboundFileSynchronizingMessageSource.java:69) at org.springframework.integration.endpoint.AbstractFetchLimitingMessageSource.doReceive(AbstractFetchLimitingMessageSource.java:47) at org.springframework.integration.endpoint.AbstractMessageSource.receive(AbstractMessageSource.java:142) at org.springframework.integration.endpoint.SourcePollingChannelAdapter.receiveMessage(SourcePollingChannelAdapter.java:212) at org.springframework.integration.endpoint.AbstractPollingEndpoint.doPoll(AbstractPollingEndpoint.java:443) at org.springframework.integration.endpoint.AbstractPollingEndpoint.pollForMessage(AbstractPollingEndpoint.java:412) at org.springframework.integration.endpoint.AbstractPollingEndpoint.lambda$createPoller$4(AbstractPollingEndpoint.java:348) at org.springframework.integration.util.ErrorHandlingTaskExecutor.lambda$execute$0(ErrorHandlingTaskExecutor.java:57) at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50) at org.springframework.integration.util.ErrorHandlingTaskExecutor.execute(ErrorHandlingTaskExecutor.java:55) at org.springframework.integration.endpoint.AbstractPollingEndpoint.lambda$createPoller$5(AbstractPollingEndpoint.java:341) at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:96) at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) at java.base/java.lang.Thread.run(Thread.java:833) Caused by: org.springframework.messaging.MessagingException: Failed to execute on session at org.springframework.integration.file.remote.RemoteFileTemplate.execute(RemoteFileTemplate.java:461) at org.springframework.integration.file.remote.synchronizer.AbstractInboundFileSynchronizer.synchronizeToLocalDirectory(AbstractInboundFileSynchronizer.java:341) ... 20 more Caused by: java.lang.IllegalStateException: Failed to create session. at org.springframework.integration.smb.session.SmbSessionFactory.getSession(SmbSessionFactory.java:65) at org.springframework.integration.smb.session.SmbSessionFactory.getSession(SmbSessionFactory.java:39) at org.springframework.integration.file.remote.RemoteFileTemplate.execute(RemoteFileTemplate.java:447) ... 21 more Caused by: java.io.IOException: Unable to initialize share: smb://myDomain;myUser:myPassword@myHost:445/myShareAndDir at org.springframework.integration.smb.session.SmbShare.init(SmbShare.java:113) at org.springframework.integration.smb.session.SmbSessionFactory.createSession(SmbSessionFactory.java:86) at org.springframework.integration.smb.session.SmbSessionFactory.getSession(SmbSessionFactory.java:62) ... 23 more Caused by: jcifs.smb.SmbException: Failed to connect to server at jcifs.smb.SmbTreeConnection.connectWrapException(SmbTreeConnection.java:429) at jcifs.smb.SmbFile.ensureTreeConnected(SmbFile.java:573) at jcifs.smb.SmbFile.exists(SmbFile.java:873) at org.springframework.integration.smb.session.SmbShare.init(SmbShare.java:98) ... 25 more Caused by: java.net.UnknownHostException: myHost at jcifs.netbios.NameServiceClientImpl.getAllByName(NameServiceClientImpl.java:1054) at jcifs.netbios.NameServiceClientImpl.getAllByName(NameServiceClientImpl.java:55) at jcifs.smb.SmbTransportPoolImpl.getSmbTransport(SmbTransportPoolImpl.java:173) at jcifs.smb.SmbTransportPoolImpl.getSmbTransport(SmbTransportPoolImpl.java:48) at jcifs.smb.SmbTreeConnection.connectHost(SmbTreeConnection.java:565) at jcifs.smb.SmbTreeConnection.connectHost(SmbTreeConnection.java:489) at jcifs.smb.SmbTreeConnection.connect(SmbTreeConnection.java:465) at jcifs.smb.SmbTreeConnection.connectWrapException(SmbTreeConnection.java:426) ... 28 more 2023-04-29T18:35:10.725+02:00 DEBUG 4300 --- [ scheduling-1] o.s.i.channel.PublishSubscribeChannel : postSend (sent=true) on channel 'bean 'errorChannel'', message: ErrorMessage [payload=org.springframework.messaging.MessagingException: Problem occurred while synchronizing 'folder1' to local directory, headers={id=8a317e74-0c7e-129e-c7b2-e9a7a73a7be5, timestamp=1682786110723}] 2023-04-29T18:35:15.733+02:00 INFO 4300 --- [ scheduling-1] o.s.i.smb.session.SmbSessionFactory : SMB share init: myHost:445/myShareAndDir
已尝试操作
- 配置有效的主机名和域名
- 将
ShareAndDir名称改为与REMOTE_DIRECTORY一致 - 删除并重建本地目录
解决方案
核心误解:Spring Integration SMB是客户端而非服务器
你当前使用的spring-integration-smb是SMB客户端,用于连接远程SMB服务器、同步文件,而不是搭建SMB服务器。这也是你遇到UnknownHostException的根本原因——配置里的myHost是要连接的远程SMB服务器地址,但你实际想做的是让自己的应用成为服务器。
正确搭建SMB服务器的方案
要在Spring Boot中搭建SMB服务器,需要使用专门的SMB服务器库,比如jcifs-ng(jcifs的升级版本),以下是实现步骤:
1. 添加Maven依赖
<dependency> <groupId>org.codelibs</groupId> <artifactId>jcifs-ng</artifactId> <version>2.1.31</version> </dependency>
2. 编写SMB服务器配置类
创建配置类初始化SMB服务器、共享目录和用户认证:
import jcifs.Configuration; import jcifs.config.PropertyConfiguration; import jcifs.context.BaseContext; import jcifs.context.SmbContext; import jcifs.smb.NtlmPasswordAuthenticator; import jcifs.smb.server.SmbServer; import jcifs.smb.server.SmbServerFactory; import jcifs.smb.server.SmbShare; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.io.File; import java.util.Properties; @Configuration public class SmbServerConfig { @Bean(destroyMethod = "stop") public SmbServer smbServer() throws Exception { // 配置SMB服务器参数 Properties props = new Properties(); props.setProperty("jcifs.smb.server.port", "445"); props.setProperty("jcifs.smb.server.name", "SpringBootSMB"); props.setProperty("jcifs.smb.server.domain", "myDomain"); Configuration config = new PropertyConfiguration(props); BaseContext context = new SmbContext(config); // 创建SMB服务器实例 SmbServer server = SmbServerFactory.createServer(context); // 配置共享目录:D:\smb-files\folder1 File shareDir = new File("D:\\smb-files\\folder1"); if (!shareDir.exists()) { shareDir.mkdirs(); } // 添加共享,设置共享名称为"folder1",允许读写 SmbShare share = server.createShare("folder1", shareDir.getAbsolutePath(), false); // 添加用户认证:指定用户名、密码、域名 NtlmPasswordAuthenticator auth = new NtlmPasswordAuthenticator("myDomain", "myUser", "myPassword"); share.addAccess(auth, 0x1F01FF); // FILE_ALL_ACCESS权限 // 启动服务器 server.start(); return server; } }
3. 测试连接
启动Spring Boot应用后,在Windows资源管理器中输入\\localhost\folder1,输入配置的用户名myUser和密码myPassword即可访问共享目录。
补充:若需连接远程SMB服务器
如果你的原需求是连接远程SMB服务器同步文件,需修正以下配置:
smbSessionFactory中的host必须是远程SMB服务器的有效IP或主机名,确保本地能ping通shareAndDir设置为远程服务器的共享名称(比如远程共享名为myShare,则填myShare)remoteDirectory是远程共享目录下的子目录,即myShare/folder1
内容的提问来源于stack exchange,提问作者Max
相关产品推荐
相关产品推荐

