You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 01:53:08