java文件共享实现方案

写在前面,由于项目要求负载,又不想大动干戈采用比较贵的设备和高大上的框架,经过一番研究,想使用文件共享方式实现文件的跨服务器访问。本方案采用了jcifs和smbj框架,若想用,请自行查找资源。此为初步设计方案,若接口不全,请自行完善。通用类采用抽象类继承的方式,而不是接口实现(总觉得此处不适合使用接口);采用了单例模式。写的不好的地方,请各位大拿批评指正。

1、引入项目依赖 pom.xml

复制代码
 <!-- SMB共享1.0 -->
<dependency>
  <groupId>org.jcifs</groupId>
  <artifactId>jcifs</artifactId>
  <version>1.3.17</version>
</dependency>
<!-- SMB共享2、3 https://mvnrepository.com/artifact/com.hierynomus/smbj -->
<dependency>
  <groupId>com.hierynomus</groupId>
  <artifactId>smbj</artifactId>
  <version>0.11.5</version>
</dependency>
复制代码

 

2、共享相关配置 application.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#smb 文件共享配置
 
smbshare:
    #是否启用
    enabled: true
    #共享服务器地址 IP或其他
    domain: '192.168.192.100'
    #共享用户名
    username: xxxx
    #共享密码
    password: ******
    #smb 文件共享版本,默认1.0
    version: 1
    #smb 文件共享名称,版本2、3使用 为本地资源目录映射地址配置第一个目录相同
    sharename: resshare

  

3、配置类

复制代码


/**
* 读取项目smb文件共享相关配置
*
* @author wgp
*/
@Component
@ConfigurationProperties(prefix = "smbshare")
public class SmbShareConfig {
// @Value("${smbshare.enabled}")

/**
* 是否启用
*/
private static Boolean enabled;
/**
* 共享服务器地址
*/
private static String domain;
/**
* 用户名
*/
private static String username;
/**
* 密码
*/
private static String password;

/**
* smb文件共享版本 1、2、3
*/
private static String version;

/**
* 共享名称 2、3使用
*/
// @Value("${smbshare.sharename}")
private static String sharename;

public static Boolean getEnabled() {
if (enabled == null) enabled = new Boolean(false);
return enabled;
}

public void setEnabled(Boolean enabled) {
SmbShareConfig.enabled = enabled;
}

public static String getUsername() {
return username;
}

public void setUsername(String username) {
SmbShareConfig.username = username;
}

public static String getPassword() {
return password;
}

public void setPassword(String password) {
SmbShareConfig.password = password;
}

public static String getDomain() {
return domain;
}

public void setDomain(String domain) {
this.domain = domain;
}

public static String getVersion() {
if (version == null) version = "1";
return version;
}

public void setVersion(String version) {
this.version = version;
}

public static String getShareName(String defaultName) {
return (sharename == null || sharename == "") ? defaultName : sharename;
}

public void setShareName(String shareName) {
this.sharename = shareName;
}
}
 
复制代码

 4、上传文件通用类

复制代码
public abstract class ShareFileUploadUtils extends ShareFileUtilsParent {
private static volatile ShareFileUploadUtils instance = null; /** * 获取实例 * * @return */ public static ShareFileUploadUtils getInstance() { if (instance == null) { synchronized (ShareFileUploadUtils.class) { if (instance == null) { if (SmbShareConfig.getEnabled()) { if (SmbShareConfig.getVersion() == "1") { instance = new ShareSmbFileUploadUtilsImpl(); } else { instance = new ShareSmbJFileUploadUtilsImpl(); } } else { instance = new ShareFileUploadUtilsImpl(); } } } } return instance; } public final String getDefaultBaseDir() { return FileUploadUtils.getDefaultBaseDir(); } /** * 文件上传 * * @param file 上传的文件 * @return 文件名称 * @throws Exception */ public String upload(MultipartFile file) throws IOException { throw new IOException("方法未实现,请使用子类"); } /** * 根据文件路径上传 * * @param baseDir 相对应用的基目录 * @param file 上传的文件 * @return 文件名称 * @throws IOException */ public String upload(String baseDir, MultipartFile file) throws IOException { throw new IOException("方法未实现,请使用子类"); } /** * 根据文件路径上传到安全目录 * * @param baseDir * @param file * @return * @throws IOException */ public String uploadSafety(String baseDir, MultipartFile file) throws IOException { throw new IOException("方法未实现,请使用子类"); } /** * 文件上传 * * @param baseDir 相对应用的基目录 * @param file 上传的文件 * @param allowedExtension 上传文件类型 * @return 返回上传成功的文件名 * @throws FileSizeLimitExceededException 如果超出最大大小 * @throws FileNameLengthLimitExceededException 文件名太长 * @throws IOException 比如读写文件出错时 * @throws InvalidExtensionException 文件校验异常 */ public String upload(String baseDir, MultipartFile file, String[] allowedExtension) throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException, InvalidExtensionException { throw new IOException("方法未实现,请使用子类"); } public String uploadSafety(String baseDir, MultipartFile file, String[] allowedExtension) throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException, InvalidExtensionException { throw new IOException("方法未实现,请使用子类"); } /** * 编码文件名 */ public final String extractFilename(MultipartFile file) { return FileUploadUtils.extractFilename(file); } public final String getPathFileName(String uploadDir, String fileName) throws IOException { return FileUploadUtils.getPathFileName(uploadDir, fileName); } public final String getSafetyPathFileName(String uploadDir, String fileName) throws IOException { return FileUploadUtils.getSafetyPathFileName(uploadDir, fileName); } /** * 文件大小校验 * * @param file 上传的文件 * @return * @throws FileSizeLimitExceededException 如果超出最大大小 * @throws InvalidExtensionException */ protected void assertAllowed(MultipartFile file, String[] allowedExtension) throws IOException, FileSizeLimitExceededException, InvalidExtensionException { FileUploadUtils.assertAllowed(file, allowedExtension); } /** * 判断MIME类型是否是允许的MIME类型 * * @param extension * @param allowedExtension * @return */ public final boolean isAllowedExtension(String extension, String[] allowedExtension) { return FileUploadUtils.isAllowedExtension(extension, allowedExtension); } /** * 获取文件名的后缀 * * @param file 表单文件 * @return 后缀名 */ public final String getExtension(MultipartFile file) { return FileUploadUtils.getExtension(file); } } class ShareFileUploadUtilsImpl extends ShareFileUploadUtils { /** * 文件上传 实现 * * @param file 上传的文件 * @return 文件名称 * @throws Exception */ @Override public String upload(MultipartFile file) throws IOException { try { return upload(getDefaultBaseDir(), file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION); } catch (Exception e) { throw new IOException(e.getMessage(), e); } } /** * 文件上传 * * @param baseDir 相对应用的基目录 * @param file 上传的文件 * @param allowedExtension 上传文件类型 * @return 返回上传成功的文件名 * @throws FileSizeLimitExceededException 如果超出最大大小 * @throws FileNameLengthLimitExceededException 文件名太长 * @throws IOException 比如读写文件出错时 * @throws InvalidExtensionException 文件校验异常 */ @Override public String upload(String baseDir, MultipartFile file, String[] allowedExtension) throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException, InvalidExtensionException { return FileUploadUtils.upload(baseDir, file, allowedExtension); } /** * 根据文件路径上传 * * @param baseDir 相对应用的基目录 * @param file 上传的文件 * @return 文件名称 * @throws IOException */ @Override public String upload(String baseDir, MultipartFile file) throws IOException { try { return upload(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION); } catch (Exception e) { throw new IOException(e.getMessage(), e); } } /** * 文件上传到安全目录 * * @param baseDir 相对应用的基目录 * @param file 上传的文件 * @param allowedExtension 上传文件类型 * @return 返回上传成功的文件名 * @throws FileSizeLimitExceededException 如果超出最大大小 * @throws FileNameLengthLimitExceededException 文件名太长 * @throws IOException 比如读写文件出错时 * @throws InvalidExtensionException 文件校验异常 */ @Override public String uploadSafety(String baseDir, MultipartFile file, String[] allowedExtension) throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException, InvalidExtensionException { return FileUploadUtils.uploadSafety(baseDir, file, allowedExtension); } @Override public String uploadSafety(String baseDir, MultipartFile file) throws IOException { try { return uploadSafety(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION); } catch (Exception e) { throw new IOException(e.getMessage(), e); } } } class ShareSmbFileUploadUtilsImpl extends ShareFileUploadUtils { /** * 文件上传 * * @param file 上传的文件 * @return 文件名称 * @throws Exception */ @Override public String upload(MultipartFile file) throws IOException { try { return upload(getDefaultBaseDir(), file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION); } catch (Exception e) { throw new IOException(e.getMessage(), e); } } /** * 文件上传 * * @param baseDir 相对应用的基目录 * @param file 上传的文件 * @param allowedExtension 上传文件类型 * @return 返回上传成功的文件名 * @throws FileSizeLimitExceededException 如果超出最大大小 * @throws FileNameLengthLimitExceededException 文件名太长 * @throws IOException 比如读写文件出错时 * @throws InvalidExtensionException 文件校验异常 */ @Override public String upload(String baseDir, MultipartFile file, String[] allowedExtension) throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException, InvalidExtensionException { int fileNamelength = Objects.requireNonNull(file.getOriginalFilename()).length(); if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) { throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH); } assertAllowed(file, allowedExtension); String fileName = extractFilename(file); saveSmbFile(file, baseDir + "/" + fileName); return getPathFileName(baseDir, fileName); } /** * 根据文件路径上传 * * @param baseDir 相对应用的基目录 * @param file 上传的文件 * @return 文件名称 * @throws IOException */ @Override public String upload(String baseDir, MultipartFile file) throws IOException { try { return upload(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION); } catch (Exception e) { throw new IOException(e.getMessage(), e); } } /** * 文件上传到安全目录 * * @param baseDir 相对应用的基目录 * @param file 上传的文件 * @param allowedExtension 上传文件类型 * @return 返回上传成功的文件名 * @throws FileSizeLimitExceededException 如果超出最大大小 * @throws FileNameLengthLimitExceededException 文件名太长 * @throws IOException 比如读写文件出错时 * @throws InvalidExtensionException 文件校验异常 */ @Override public String uploadSafety(String baseDir, MultipartFile file, String[] allowedExtension) throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException, InvalidExtensionException { int fileNamelength = Objects.requireNonNull(file.getOriginalFilename()).length(); if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) { throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH); } assertAllowed(file, allowedExtension); String fileName = extractFilename(file); saveSmbFile(file, baseDir + "/" + fileName); return getSafetyPathFileName(baseDir, fileName); } @Override public String uploadSafety(String baseDir, MultipartFile file) throws IOException { try { return uploadSafety(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION); } catch (Exception e) { throw new IOException(e.getMessage(), e); } } /** * 保存文件 * * @param file * @param filePath * @throws IOException */ private void saveSmbFile(MultipartFile file, String filePath) throws IOException { InputStream inputStream = null; SmbFileOutputStream outputStream = null; try { inputStream = file.getInputStream(); SmbFile smbFile = getAbsoluteSmbFile(filePath); outputStream = new SmbFileOutputStream(smbFile); outputStream.write(file.getBytes()); // byte[] buffer = new byte[4096]; // int len = 0; // while ((len = inputStream.read(buffer, 0, buffer.length)) != -1) { // outputStream.write(buffer, 0, len); // } } catch (IOException e) { throw e; } finally { IOUtils.close(inputStream); IOUtils.close(outputStream); } } } class ShareSmbJFileUploadUtilsImpl extends ShareFileUploadUtils { public ShareSmbJFileUploadUtilsImpl() { session = getSmbjSession(); } private Session session; /** * 以默认配置进行文件上传 * * @param file 上传的文件 * @return 文件名称 * @throws Exception */ @Override public String upload(MultipartFile file) throws IOException { try { return upload(getDefaultBaseDir(), file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION); } catch (Exception e) { throw new IOException(e.getMessage(), e); } } /** * 文件上传 * * @param baseDir 相对应用的基目录 * @param file 上传的文件 * @param allowedExtension 上传文件类型 * @return 返回上传成功的文件名 * @throws FileSizeLimitExceededException 如果超出最大大小 * @throws FileNameLengthLimitExceededException 文件名太长 * @throws IOException 比如读写文件出错时 * @throws InvalidExtensionException 文件校验异常 */ @Override public String upload(String baseDir, MultipartFile file, String[] allowedExtension) throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException, InvalidExtensionException { int fileNamelength = Objects.requireNonNull(file.getOriginalFilename()).length(); if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) { throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH); } assertAllowed(file, allowedExtension); String fileName = extractFilename(file); writeFile(file.getBytes(), baseDir + "/" + fileName); return getPathFileName(baseDir, fileName); } /** * 根据文件路径上传 * * @param baseDir 相对应用的基目录 * @param file 上传的文件 * @return 文件名称 * @throws IOException */ @Override public String upload(String baseDir, MultipartFile file) throws IOException { try { return upload(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION); } catch (Exception e) { throw new IOException(e.getMessage(), e); } } /** * 文件上传到安全目录 * * @param baseDir 相对应用的基目录 * @param file 上传的文件 * @param allowedExtension 上传文件类型 * @return 返回上传成功的文件名 * @throws FileSizeLimitExceededException 如果超出最大大小 * @throws FileNameLengthLimitExceededException 文件名太长 * @throws IOException 比如读写文件出错时 * @throws InvalidExtensionException 文件校验异常 */ @Override public String uploadSafety(String baseDir, MultipartFile file, String[] allowedExtension) throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException, InvalidExtensionException { int fileNamelength = Objects.requireNonNull(file.getOriginalFilename()).length(); if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) { throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH); } assertAllowed(file, allowedExtension); String fileName = extractFilename(file); writeFile(file.getBytes(), baseDir + "/" + fileName); return getSafetyPathFileName(baseDir, fileName); } @Override public String uploadSafety(String baseDir, MultipartFile file) throws IOException { try { return uploadSafety(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION); } catch (Exception e) { throw new IOException(e.getMessage(), e); } } /** * 写入数据到文件 * * @param data * @param filePath * @throws IOException */ private void writeFile(byte[] data, String filePath) throws IOException { OutputStream fis = null; try { String[] filePathArr = getShareNameAndFileName(filePath); if (filePathArr == null) throw new IOException("未输入文件路径"); DiskShare diskShare = (DiskShare) session.connectShare(SmbShareConfig.getShareName(filePathArr[0])); if (!diskShare.fileExists(filePathArr[1])) { //创建 String parentPath = filePathArr[1].substring(0, filePathArr[1].lastIndexOf("/")); if (!diskShare.folderExists(parentPath)) { diskShare.mkdir(parentPath); } } com.hierynomus.smbj.share.File file = diskShare.openFile(filePathArr[1], EnumSet.of(AccessMask.GENERIC_ALL), (Set) null, SMB2ShareAccess.ALL, SMB2CreateDisposition.FILE_OPEN, (Set) null ); fis = file.getOutputStream(); fis.write(data); } catch (IOException e) { throw e; } finally { IOUtils.close(fis); } } }
复制代码

5、文件通用类

复制代码
/**
 * 文件操作处理类型,支持共享
 */
public abstract class ShareFileUtils extends ShareFileUtilsParent {
private static volatile ShareFileUtils instance = null; /** * 获取实例 * * @return */ public static ShareFileUtils getInstance() { if (instance == null) { synchronized (ShareFileUtils.class) { //考虑单例模式? if (instance == null) { if (SmbShareConfig.getEnabled()) { if (SmbShareConfig.getVersion() == "1") { instance = new ShareSmbFileUtilsImpl(); } else { instance = new ShareSmbJFileUtilsImpl(); } } else { instance = new ShareFileUtilsImpl(); } } } } return instance; } /** * 判断文件是否存在 * * @param filePath * @return * @throws IOException */ public boolean fileExists(String filePath) throws IOException { throw new IOException("未实现方法,请使用子类"); } /** * 输出指定文件的byte数组 * * @param filePath 文件路径 * @param os 输出流 * @return */ public void writeBytes(String filePath, OutputStream os) throws IOException { throw new IOException("未实现方法,请使用子类"); } /** * 写数据到文件中 * * @param data 数据 * @return 目标文件 * @throws IOException IO异常 */ public String writeImportBytes(byte[] data) throws IOException { throw new IOException("未实现方法,请使用子类"); } /** * 写数据到文件中 * * @param data 数据 * @param uploadDir 目标文件 * @return 目标文件 * @throws IOException IO异常 */ public String writeBytes(byte[] data, String uploadDir) throws IOException { throw new IOException("未实现方法,请使用子类"); } /** * 删除文件 * * @param filePath 文件 * @return */ public boolean deleteFile(String filePath) throws IOException { throw new IOException("未实现方法"); } /** * 文件名称验证 * * @param filename 文件名称 * @return true 正常 false 非法 */ public boolean isValidFilename(String filename) { return FileUtils.isValidFilename(filename); } /** * 下载文件名重新编码 * * @param request 请求对象 * @param fileName 文件名 * @return 编码后的文件名 */ public String setFileDownloadHeader(HttpServletRequest request, String fileName) throws UnsupportedEncodingException { return FileUtils.setFileDownloadHeader(request, fileName); } /** * 下载文件名重新编码 * * @param response 响应对象 * @param realFileName 真实文件名 */ public void setAttachmentResponseHeader(HttpServletResponse response, String realFileName) throws UnsupportedEncodingException { FileUtils.setAttachmentResponseHeader(response, realFileName); } /** * 百分号编码工具方法 * * @param s 需要百分号编码的字符串 * @return 百分号编码后的字符串 */ public String percentEncode(String s) throws UnsupportedEncodingException { return FileUtils.percentEncode(s); } /** * 获取图像后缀 * * @param photoByte 图像数据 * @return 后缀名 */ public String getFileExtendName(byte[] photoByte) { return FileUtils.getFileExtendName(photoByte); } public final File getAbsoluteFile(String uploadDir, String fileName) throws IOException { return FileUploadUtils.getAbsoluteFile(uploadDir, fileName); } } /** * ShareFileUtils 和 ShareFileUploadUtils 共用基类 不允许创建 */ abstract class ShareFileUtilsParent {
/** * 转换可访问路径,自动适配默认目录或安全目录 * * @param fileUrl 带有虚拟目录前缀的 文件地址,不带有http或https * @return */ public final String convertToDiskPath(String fileUrl) { if (StringUtils.isEmpty(fileUrl)) return fileUrl; String asbPath = ""; String prePath = ""; String prePathReplace = ""; if (fileUrl.startsWith(Constants.RESOURCE_PREFIX)) { prePath = Constants.RESOURCE_PREFIX; prePathReplace = ApplicationConfig.getProfile(); } else if (fileUrl.startsWith(Constants.RESOURCE_SAFETYPREFIX)) { prePath = Constants.RESOURCE_SAFETYPREFIX; prePathReplace = ApplicationConfig.getSafetyProfile(); } if (StringUtils.isEmpty(prePath) || StringUtils.isEmpty(prePathReplace)) return fileUrl; int dirLastIndex = prePath.length(); String subPath = StringUtils.substring(fileUrl, dirLastIndex); return (prePathReplace.endsWith("/") ? prePathReplace.substring(0, prePathReplace.length() - 1) : prePathReplace) + "/" + (subPath.startsWith("/") ? subPath.substring(1) : subPath); } /** * 转换为Web访问路径(带有虚拟目录前缀的文件地址,不带有http或https) * 自动适配默认目录或安全目录 * * @param diskPath 磁盘文件地址 * @return */ public final String convertToWebUrl(String diskPath) { if (StringUtils.isEmpty(diskPath)) return diskPath; String prePath = ""; String prePathReplace = ""; if (diskPath.startsWith(ApplicationConfig.getProfile())) { prePath = ApplicationConfig.getProfile(); prePathReplace = Constants.RESOURCE_PREFIX; } else if (diskPath.startsWith(Constants.RESOURCE_SAFETYPREFIX)) { prePath = ApplicationConfig.getSafetyProfile(); prePathReplace = Constants.RESOURCE_SAFETYPREFIX; } if (StringUtils.isEmpty(prePath) || StringUtils.isEmpty(prePathReplace)) return diskPath; int dirLastIndex = prePath.length(); String subPath = StringUtils.substring(diskPath, dirLastIndex); return (prePathReplace.endsWith("/") ? prePathReplace.substring(0, prePathReplace.length() - 1) : prePathReplace) + "/" + (subPath.startsWith("/") ? subPath.substring(1) : subPath); } /** * 获取文件名称 * * @param fileName 路径名称 * @return 没有文件路径的名称 */ public final String getName(String fileName) { if (fileName == null) { return null; } String tempFile = fileName; int quesIndex = tempFile.indexOf("?"); int dotIndex = tempFile.lastIndexOf("."); if (quesIndex > 0 && quesIndex > dotIndex) { tempFile = fileName.substring(0, quesIndex - 1); } int lastUnixPos = tempFile.lastIndexOf('/'); int lastWindowsPos = tempFile.lastIndexOf('\\'); int index = Math.max(lastUnixPos, lastWindowsPos); return tempFile.substring(index + 1); } /** * 检查文件是否可下载 * * @param resource 需要下载的文件 * @return true 正常 false 非法 */ public boolean checkAllowDownload(String resource) { return FileUtils.checkAllowDownload(resource); } public final String getRemotePathWithAuth(String filePath) { return StringUtils.format("smb://{}:{}@{}{}", SmbShareConfig.getUsername(), SmbShareConfig.getPassword(), SmbShareConfig.getDomain(), filePath); } /** * 获取已连接的文件 * * @param fullFilePath 全文件地址 * @return * @throws IOException */ protected final SmbFile getSmbFileConnected(String fullFilePath) throws IOException { // String remotePath = getRemotePathWithAuth(fullFilePath); // SmbFile file = new SmbFile(remotePath); // file.connect(); //是否需要连接 // return file; String remotePath = StringUtils.startsWithIgnoreCase(fullFilePath, "smb://") ? fullFilePath : StringUtils.format("smb://{}{}{}", SmbShareConfig.getDomain(), fullFilePath.startsWith("/") ? "" : "/", fullFilePath); NtlmPasswordAuthentication authentication = new NtlmPasswordAuthentication(SmbShareConfig.getDomain(), SmbShareConfig.getUsername(), SmbShareConfig.getPassword()); SmbFile file = new SmbFile(remotePath, authentication); file.connect(); //是否需要连接 return file; } /** * 获取文件地址,并创建文件夹 * * @param uploadDir * @param fileName * @return * @throws IOException */ public final SmbFile getAbsoluteSmbFile(String uploadDir, String fileName) throws IOException { SmbFile desc = getSmbFileConnected(uploadDir + File.separator + fileName); desc.connect(); if (!desc.exists()) { desc.mkdirs(); } return desc; } public final SmbFile getAbsoluteSmbFile(String fileName) throws IOException { SmbFile desc = getSmbFileConnected(fileName); if (!desc.exists()) { SmbFile pare = getSmbFileConnected(desc.getParent()); if (!pare.exists()) pare.mkdirs(); } return desc; } protected final Session getSmbjSession() { Session s = null; try { SMBClient client = new SMBClient(SmbConfig.createDefaultConfig()); Connection conn = client.connect(SmbShareConfig.getDomain()); s = conn.authenticate(new AuthenticationContext(SmbShareConfig.getUsername(), SmbShareConfig.getPassword().toCharArray(), SmbShareConfig.getDomain())); } catch (Exception e) { e.printStackTrace(); } return s; } /** * 将共享文件地址拆分成 共享目录和子目录,smb 2、3使用 * * @param filePath * @return */ protected final String[] getShareNameAndFileName(String filePath) { if (filePath == null) return null; String[] paths = filePath.replace("\\", "/").split("/"); String shareName = ""; List<String> subPaths = new ArrayList<>(); for (String path : paths) { if (StringUtils.isEmpty(path)) continue; if (StringUtils.isEmpty(shareName)) { shareName = path; continue; } subPaths.add(path); } return new String[]{ shareName, subPaths.size() == 0 ? "/" : String.join("/", subPaths) }; } } /** * 不共享方式实现 */ class ShareFileUtilsImpl extends ShareFileUtils { public boolean fileExists(String filePath) throws IOException { File file = new File(filePath); return file.exists(); } @Override public void writeBytes(String filePath, OutputStream os) throws IOException { FileUtils.writeBytes(filePath, os); } /** * 写数据到文件中 * * @param data 数据 * @return 目标文件 * @throws IOException IO异常 */ @Override public String writeImportBytes(byte[] data) throws IOException { return writeBytes(data, ApplicationConfig.getImportPath()); } @Override public String writeBytes(byte[] data, String uploadDir) throws IOException { return FileUtils.writeBytes(data, uploadDir); } /** * 删除文件 * * @param filePath 文件 * @return */ public boolean deleteFile(String filePath) { return FileUtils.deleteFile(filePath); } } /** * smb1共享方式实现 */ class ShareSmbFileUtilsImpl extends ShareFileUtils { @Override public boolean fileExists(String filePath) throws IOException { return getSmbFileConnected(filePath).exists(); } /** * 读取文件 * * @param filePath 文件路径 * @param os 输出流 * @throws IOException */ @Override public void writeBytes(String filePath, OutputStream os) throws IOException { SmbFileInputStream fis = null; try { SmbFile file = getSmbFileConnected(filePath); if (!file.exists()) { throw new FileNotFoundException(filePath); } fis = new SmbFileInputStream(file); byte[] b = new byte[1024]; int length; while ((length = fis.read(b)) > 0) { os.write(b, 0, length); } } catch (IOException e) { throw e; } finally { IOUtils.close(os); IOUtils.close(fis); } } /** * 写数据到文件中 * * @param data 数据 * @return 目标文件 * @throws IOException IO异常 */ @Override public String writeImportBytes(byte[] data) throws IOException { return writeBytes(data, ApplicationConfig.getImportPath()); } @Override public String writeBytes(byte[] data, String uploadDir) throws IOException { SmbFileOutputStream fos = null; String pathName = ""; try { String extension = getFileExtendName(data); pathName = DateUtils.datePath() + "/" + IdUtils.fastUUID() + "." + extension; SmbFile file = getAbsoluteSmbFile(uploadDir, pathName); fos = new SmbFileOutputStream(file); fos.write(data); } finally { IOUtils.close(fos); } return FileUploadUtils.getPathFileName(uploadDir, pathName); } /** * 删除文件 * * @param filePath 文件 * @return */ @Override public boolean deleteFile(String filePath) throws IOException { boolean flag = false; SmbFile file = getSmbFileConnected(filePath); // 路径为文件且不为空则进行删除 if (file.isFile() && file.exists()) { file.delete(); flag = true; } return flag; } }

/**
* smb2|3共享方式实现
*/
class ShareSmbJFileUtilsImpl extends ShareFileUtils {

public ShareSmbJFileUtilsImpl() {


}

private Session session;

private Session getSession() {
boolean isGetNew = false;
if (session == null) {
isGetNew = true;
} else if (session.getConnection() == null) {
isGetNew = true;
} else if (session.getConnection().release()) {
isGetNew = true;
}else if (session.getConnection().isConnected()) {
isGetNew = true;
}
if (isGetNew) session = getSmbjSession();
return session;
}

@Override
public boolean fileExists(String filePath) throws IOException {
String[] filePathArr = getShareNameAndFileName(filePath);
if (filePathArr == null) return false;
try (DiskShare diskShare = (DiskShare) getSession().connectShare(SmbShareConfig.getShareName(filePathArr[0]))) {
return diskShare.fileExists(filePathArr[1]);
}

}


/**
* 读取文件
*
* @param filePath 文件路径
* @param os 输出流
* @throws IOException
*/
@Override
public void writeBytes(String filePath, OutputStream os) throws IOException {

String[] filePathArr = getShareNameAndFileName(filePath);
if (filePathArr == null) return;

InputStream fis = null;
DiskShare diskShare = null;
try {
diskShare = (DiskShare) getSession().connectShare(SmbShareConfig.getShareName(filePathArr[0]));
if (!diskShare.fileExists(filePathArr[1])) {
throw new FileNotFoundException(filePath);
}
if (!diskShare.isConnected())
diskShare = (DiskShare) getSession().connectShare(SmbShareConfig.getShareName(filePathArr[0]));

com.hierynomus.smbj.share.File file = diskShare.openFile(filePathArr[1],
EnumSet.of(AccessMask.GENERIC_READ),
(Set) null,
SMB2ShareAccess.ALL,
SMB2CreateDisposition.FILE_OPEN,
(Set) null
);
fis = file.getInputStream();
byte[] b = new byte[4096];
int length;
while ((length = fis.read(b)) > 0) {
os.write(b, 0, length);
}
} catch (IOException e) {
System.out.println(StringUtils.format("共享错误:{}", JSON.toJSONString(e)));
throw e;
} finally {
IOUtils.close(os);
IOUtils.close(fis);
if (diskShare != null && diskShare.isConnected()) diskShare.close();
}
}

/**
* 写数据到文件中
*
* @param data 数据
* @return 目标文件
* @throws IOException IO异常
*/
@Override
public String writeImportBytes(byte[] data) throws IOException {
return writeBytes(data, ApplicationConfig.getImportPath());
}

/**
* 写数据到文件中
*
* @param data 数据
* @param uploadDir 目标文件
* @return
* @throws IOException
*/
@Override
public String writeBytes(byte[] data, String uploadDir) throws IOException {

String extension = getFileExtendName(data);
String pathName = DateUtils.datePath() + "/" + IdUtils.fastUUID() + "." + extension;
String fullName = uploadDir + "/" + pathName;
writeFile(data, fullName);
return convertToWebUrl(fullName);
//return FileUploadUtils.getPathFileName(uploadDir, pathName);
}

/**
* 删除文件
*
* @param filePath 文件
* @return
*/
@Override
public boolean deleteFile(String filePath) throws IOException {
boolean flag = false;
String[] filePathArr = getShareNameAndFileName(filePath);
if (filePathArr == null) return flag;
try (DiskShare diskShare = (DiskShare) getSession().connectShare(SmbShareConfig.getShareName(filePathArr[0]))) {
if (!diskShare.fileExists(filePathArr[1])) {
return true;
}
diskShare.rm(filePathArr[1]);
flag = true;
} catch (IOException e) {
throw e;
}
return flag;
}


/**
* 写入数据到文件
*
* @param data
* @param filePath
* @throws IOException
*/
private void writeFile(byte[] data, String filePath) throws IOException {
OutputStream fis = null;
try {
String[] filePathArr = getShareNameAndFileName(filePath);
if (filePathArr == null) throw new IOException("未输入文件路径");
DiskShare diskShare = (DiskShare) getSession().connectShare(SmbShareConfig.getShareName(filePathArr[0]));
if (!diskShare.fileExists(filePathArr[1])) {
//创建
String parentPath = filePathArr[1].substring(0, filePathArr[1].lastIndexOf("/"));
if (!diskShare.folderExists(parentPath)) {
diskShare.mkdir(parentPath);
}
}
com.hierynomus.smbj.share.File file = diskShare.openFile(filePathArr[1],
EnumSet.of(AccessMask.GENERIC_ALL),
(Set) null,
SMB2ShareAccess.ALL,
SMB2CreateDisposition.FILE_OPEN,
(Set) null
);
fis = file.getOutputStream();
fis.write(data);
} catch (IOException e) {
throw e;
} finally {
IOUtils.close(fis);
}
}
}

复制代码

6、关于负载

负载时,共享目录下静态文件处理方案:

  由于资源映射未找到,映射远程共享文件方法,故给出以下方案。

  a、子服务器访问时,请求代理到主服务器资源目录。

  b、添加拦截器,访问到静态资源目录时,通过共享方式获取文件,返回文件数据;项目启动时不做资源映射。

    拦截代码

  

复制代码
/**
     * 在业务处理器处理请求之前被调用
     *
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        ShareFileUtils shareFileUtils = ShareFileUtils.getInstance();
        try {
            //访问路径为文件地址
            String fileName = request.getServletPath();
            if (!shareFileUtils.checkAllowDownload(fileName)) {
                setErrorMsg(StringUtils.format("文件名称({})非法,不允许下载。 ", fileName), HttpStatus.NOT_FOUND, response, request);
                return false;
            }
            String realFileName = shareFileUtils.getName(fileName);
            String filePath = shareFileUtils.convertToDiskPath(fileName);
            if (!shareFileUtils.fileExists(filePath)) {
                setErrorMsg(StringUtils.format("文件不存在({})。 ", fileName), HttpStatus.NOT_FOUND, response, request);
                return false;
            }
            shareFileUtils.setAttachmentResponseHeader(response, realFileName);
            shareFileUtils.writeBytes(filePath, response.getOutputStream());

        } catch (Exception e) {
            setErrorMsg("文件下载异常", HttpStatus.ERROR, response, request);
            return false;
        }
        //返回文件即不必向下执行
        return false;
    }
复制代码

 

posted @   newbigapple  阅读(2065)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
点击右上角即可分享
微信分享提示