写在前面,由于项目要求负载,又不想大动干戈采用比较贵的设备和高大上的框架,经过一番研究,想使用文件共享方式实现文件的跨服务器访问。本方案采用了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

#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;
}

java文件共享实现方案的更多相关文章

  1. 项目四:Java秒杀系统方案优化-高性能高并发实战

    技术栈 前端:Thymeleaf.Bootstrap.JQuery 后端:SpringBoot.JSR303.MyBatis 中间件:RabbitMQ.Redis.Druid 功能模块 分布式会话,商 ...

  2. Java架构师方案—多数据源开发详解及原理(二)(附完整项目代码)

    1. mybatis下数据源开发工作 2. 数据源与DAO的关系原理模型 3. 为什么要配置SqlSessionTemplate类的bean 4. 多数据源应用测试 1. mybatis下数据源开发工 ...

  3. 基于Java IO 序列化方案的memcached-session-manager多memcached节点配置

    在公司项目里想要在前端通过nginx将请求负载均衡,而后台的几组tomcat的session通过memcached(non-sticky模式)进行统一管理,这几组tomcat部署的web app是同一 ...

  4. windows下双击可运行的Java软件打包方案(转)

    出处: http://www.cnblogs.com/shiyangxt/ 刚开始学Java的时候,挺郁闷的,写出来的java类文件,需要dos下编译,然后再dos下运行看效果.这使初学者常常 觉得麻 ...

  5. Java实现统计方案

    统计方案 题目描述 在一无限大的二维平面中,我们做如下假设: 1.每次只能移动一格: 2.不能向后走(假设你的目的地是"向上",那么你可以向左走,可以向右走,也可以向上走,但是不可 ...

  6. 分布式锁1 Java常用技术方案

    前言:       由于在平时的工作中,线上服务器是分布式多台部署的,经常会面临解决分布式场景下数据一致性的问题,那么就要利用分布式锁来解决这些问题.所以自己结合实际工作中的一些经验和网上看到的一些资 ...

  7. java 分布式锁方案

    第一步,自身的业务场景: 在我日常做的项目中,目前涉及了以下这些业务场景: 场景一: 比如分配任务场景.在这个场景中,由于是公司的业务后台系统,主要是用于审核人员的审核工作,并发量并不是很高,而且任务 ...

  8. java编码转化方案-备用

    import java.io.UnsupportedEncodingException; /** * 转换字符串的编码 */ public class changeCharSet { /** 7位AS ...

  9. 分布式锁1 Java常用技术方案(转)

    转:http://www.cnblogs.com/PurpleDream/p/5559352.html#3450419 前言:       由于在平时的工作中,线上服务器是分布式多台部署的,经常会面临 ...

  10. Java秒杀系统方案优化 高性能高并发实战(1)

    首先先把 springboot +thymeleaf 搞起来 ,参考 springboot 官方文档 本次学习 使用 springboot + thymeleaf+mybatis+redis+Rabb ...

随机推荐

  1. react中受控组件与非受控组件--

    非受控组件:随用随取 1 render() { 2 return ( 3 <div> 4 <h1>非受控组件</h1> 5 <form action=&quo ...

  2. C# 获取所有桌面窗口信息

    窗口标题.窗口类名.是否可见.是否最小化.窗口位置和大小.窗口所在进程信息 1 private static WindowInfo GetWindowDetail(IntPtr hWnd) 2 { 3 ...

  3. 数据结构(DataStructure)-03

    数据结构-03 **数据结构-03笔记** **递归** **二叉树** **广度遍历 - 二叉树** **深度遍历 - 二叉树** **二叉树练习一** **二叉树练习二** **二叉排序树练习一* ...

  4. [双目视差] 单双目MATLAB 相机标定(二)双目摄像机标定

    文章目录 单双目MATLAB 相机标定(二)双目摄像机标定 一.环境准备 二.标定过程 单双目MATLAB 相机标定(二)双目摄像机标定 一.环境准备 MATLAB R2014a+windows7 6 ...

  5. 基于.Net开发的数据库导入导出的开源项目

    在项目开发过程中,我们经常碰到从数据库导入导出的需求,虽然这样的功能不是很复杂,但是往往我们都会碰到一些问题. 比如导入的Excel格式问题.Excetl中图片导入问题,导出的需求为了方便客户查看,会 ...

  6. spring xml配置中引用java配置不能用ClassPathXmlApplicationContext

    现在的目的是想测试在xml配置中引用java配置的bean CD唱片的接口: package v4.c2; public interface CompactDisc { void play(); } ...

  7. Golang for循环遍历小坑

    一.for循环 循环:让程序多次执行相同的代码块for循环是Go语言中唯一一个循环结构for循环经典语法先执行表达式1执行表达式2判断是否成立,如果成立执行循环体循环体执行完成后,执行表达式3再次执行 ...

  8. 2020-12-01:java中,什么是安全点和安全区域?

    福哥答案2020-12-04: 安全点用户线程暂停,GC 线程要开始工作,但是要确保用户线程暂停的这行字节码指令是不会导致引用关系的变化.所以 JVM 会在字节码指令中,选一些指令,作为"安 ...

  9. 【GiraKoo】线程本地存储(Thread Local Storage, TLS)

    [技术分享]线程本地存储(Thread Local Storage, TLS) 在项目开发中,遇到了关于TLS相关的问题.为了了解该机制的用途,在微软的官网查找了一些资料. 本文参考官方文档, 简单介 ...

  10. AcWing 243. 一个简单的整数问题2-(区间修改,区间查询)

    给定一个长度为 N 的数列 A,以及 M 条指令,每条指令可能是以下两种之一: C l r d,表示把 A[l],A[l+1],-,A[r]都加上 d. Q l r,表示询问数列中第 l∼r个数的和. ...