CentOS下Samba安装和SpringBoot整合

Samba是在Linux系统上实现SMB协议的一个服务软件,SMB可以实现在局域网上共享文件和打印机,SMB(Server Messages Block,信息服务块)是一种在局域网上共享文件和打印机的一种通信协议,它为局域网内的不同计算机之间提供文件及打印机等资源的共享服务。客户机通过该SMB协议可以访问服务器上的共享文件系统、打印机及其他资源。类似于Windows的工项目了。

CentOS下安装Samba

下面介绍在CentOS上搭建共享文件服务Samba

1、首先yum方式安装samba服务

yum install samba

2、修改全局配置文件

[global]
	# security = share		# centos6 及其红帽 配置写这条参数
	
    security = user			# centos7 及其以上 配置写这条参数
    map to guest = Bad User

......
# 映射public目录
[public]
        path = /tmp/public
        writable = yes
        guest ok = yes

3、启动服务并测试

# 1. 启动服务
systemctl start smb		# 适用于centos 7 及其以上

# service smb start 	# 适用于centos6 及其红帽

4、创建认证用户

# sh命令
useradd jack
passwd jack
pdbedit -a jack		# 将普通用户jack 设置为Samba 用户
pdbedit -L			# 查看所有Samba用户
systemctl restart smb #重启服务

# 向jack用户授权文件夹
chown -R jack /home/jck

# 修改配置信息
vim /etc/samba/smb.conf
# 修改配置 映射jack目录
[jack]
        path = /home/jack
        writable = yes
        guest ok = yes

5、测试

在我的电脑输入\\10.200.xx.xx \\10.200.xx.xx\jack测试

SpringBoot整合Samba

1、引入pom

<dependency>
            <groupId>jcifs</groupId>
            <artifactId>jcifs</artifactId>
            <version>1.3.17</version>
        </dependency>

2、添加配置

smb:
  host: 192.168.90.133
  userName: jack
  password: jack
  port: 139
  workDir: /jack

3、配置类

package cn.customs.zskdatasync.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

/**
 * @author :rayfoo@qq.com
 * @date :Created in 2022/5/11 10:06
 * @description:smb配置类
 * @modified By:
 * @version: 1.0.0
 */
@Data@Configuration
@ConfigurationProperties(prefix = "smb")
public class SmbConfig {

    private String host;

    private String userName;

    private String password;

    private String port;

    private String workDir;

}

4、工具类

package cn.customs.zskdatasync.util;

import cn.customs.zskdatasync.config.SmbConfig;
import cn.customs.zskdatasync.entity.Result;
import jcifs.UniAddress;
import jcifs.smb.NtlmPasswordAuthentication;
import jcifs.smb.SmbFile;
import jcifs.smb.SmbSession;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;

/**
 * @author :rayfoo@qq.com
 * @date :Created in 2022/5/11 10:05
 * @description:smb文件读写工具类
 * @modified By:
 * @version: 1.0.0
 */
@Component@Slf4j
public class SmbUtil {

    @Resource
    private SmbConfig smbConfig;

    private final String protocol = "smb://";

    /**
     * 文件上传
     */
    public Result upload(MultipartFile file,String filePath, String fileName){

        try{
            // 创建地址对象
            UniAddress address = UniAddress.getByName(smbConfig.getHost());
            // 创建认证对象
            NtlmPasswordAuthentication ahth = new NtlmPasswordAuthentication(smbConfig.getHost(),smbConfig.getUserName(), smbConfig.getPassword());
            // 登录smb
            SmbSession.logon(address, ahth);
            // 创建文件上传对象
            SmbFile remoteFile = new SmbFile(protocol + smbConfig.getHost() + smbConfig.getWorkDir() + filePathAndName(filePath,fileName), ahth);
            log.info("文件:" + protocol + smbConfig.getHost() + smbConfig.getWorkDir() + filePathAndName(filePath,fileName));
            // 这里如果文件夹不存在不会提前创建
            createDir(protocol,smbConfig.getHost(),smbConfig.getWorkDir(),filePath,ahth);
            // 文件上传
            IOUtils.copyLarge(file.getInputStream(),remoteFile.getOutputStream());
            log.info("文件落地成功,文件名称:{}",fileName);
            return Result.builder().build().setMsg("文件上传成功").setCode(200).setData(null);
        }catch (Exception e){
            e.printStackTrace();
            log.error("文件落地失败,文件名称:{},异常类型:{}",fileName,e.getMessage());
            return Result.error("文件上传过程中出现异常,请检查后重试");
        }

    }

    /**
     * @description: 创建smb文件夹
     * @param protocol 协议
     * @param host smb服务器地址
     * @param workDir smb文件夹路径
     * @param filePath 文件夹路径
     * @param ahth 认证对象
     */
    private void createDir(String protocol,String host,String workDir,String filePath,NtlmPasswordAuthentication ahth){
        try {
            // 如果文件夹没有前缀
            if(!filePath.startsWith(File.separator)){
                filePath = File.separator + filePath;
            }
            // 创建文件夹
            SmbFile remoteFile = new SmbFile(protocol +host + workDir + filePath, ahth);
            if(!remoteFile.exists()){
                remoteFile.mkdirs();
                log.info("成功创建文件夹{}",filePath);
            }
        } catch (IOException e) {
            log.error("创建文件夹时发生异常{}",e.getMessage());
        }
    }

    /**
     * 去前空格,加后斜线
     * @param filePath
     * @param fileName
     * @return
     */
    private String filePathAndName(String filePath,String fileName){
        if(!filePath.startsWith(File.separator)){
            filePath = File.separator + filePath;
        }
        if(filePath.endsWith(File.separator)){
            return filePath + fileName;
        }else{
            return filePath + File.separator + fileName;
        }
    }



}

5、踩坑:jcifs.smb.SmbException: The system cannot find the path specified.

这是因为samba如果上传的文件夹不存在,需要手动创建

6、踩坑:The network name cannot be found.

这是因为samba如果上传的文件夹不合法,比如没有加/前缀,或分隔符用的不对

参考:CentOS基础系列八 :搭建Samba服务(详细图解)

参考:Samba 服务器搭建与 Java 客户端实现

参考:通过jcifs.jar 创建远程文件和文件夹