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
#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文件共享实现方案的更多相关文章
- 项目四:Java秒杀系统方案优化-高性能高并发实战
技术栈 前端:Thymeleaf.Bootstrap.JQuery 后端:SpringBoot.JSR303.MyBatis 中间件:RabbitMQ.Redis.Druid 功能模块 分布式会话,商 ...
- Java架构师方案—多数据源开发详解及原理(二)(附完整项目代码)
1. mybatis下数据源开发工作 2. 数据源与DAO的关系原理模型 3. 为什么要配置SqlSessionTemplate类的bean 4. 多数据源应用测试 1. mybatis下数据源开发工 ...
- 基于Java IO 序列化方案的memcached-session-manager多memcached节点配置
在公司项目里想要在前端通过nginx将请求负载均衡,而后台的几组tomcat的session通过memcached(non-sticky模式)进行统一管理,这几组tomcat部署的web app是同一 ...
- windows下双击可运行的Java软件打包方案(转)
出处: http://www.cnblogs.com/shiyangxt/ 刚开始学Java的时候,挺郁闷的,写出来的java类文件,需要dos下编译,然后再dos下运行看效果.这使初学者常常 觉得麻 ...
- Java实现统计方案
统计方案 题目描述 在一无限大的二维平面中,我们做如下假设: 1.每次只能移动一格: 2.不能向后走(假设你的目的地是"向上",那么你可以向左走,可以向右走,也可以向上走,但是不可 ...
- 分布式锁1 Java常用技术方案
前言: 由于在平时的工作中,线上服务器是分布式多台部署的,经常会面临解决分布式场景下数据一致性的问题,那么就要利用分布式锁来解决这些问题.所以自己结合实际工作中的一些经验和网上看到的一些资 ...
- java 分布式锁方案
第一步,自身的业务场景: 在我日常做的项目中,目前涉及了以下这些业务场景: 场景一: 比如分配任务场景.在这个场景中,由于是公司的业务后台系统,主要是用于审核人员的审核工作,并发量并不是很高,而且任务 ...
- java编码转化方案-备用
import java.io.UnsupportedEncodingException; /** * 转换字符串的编码 */ public class changeCharSet { /** 7位AS ...
- 分布式锁1 Java常用技术方案(转)
转:http://www.cnblogs.com/PurpleDream/p/5559352.html#3450419 前言: 由于在平时的工作中,线上服务器是分布式多台部署的,经常会面临 ...
- Java秒杀系统方案优化 高性能高并发实战(1)
首先先把 springboot +thymeleaf 搞起来 ,参考 springboot 官方文档 本次学习 使用 springboot + thymeleaf+mybatis+redis+Rabb ...
随机推荐
- Python 使用类和实例
使用类和实例 直接修改实例的属性 编写方法以特定的方式进行修改 # 案例: class Car(): '''一次模拟汽车的简单尝试''' def __init__(self,make,model,ye ...
- [[SCOI2008]城堡] 解题报告
[SCOI2008]城堡 最大值最小,显然二分答案,但考虑二分后如何 check. \(n\) 个点 \(n\) 条边,显然这是一个基环树森林.对于基环树,常用的套路是拆环为链,枚举删去哪条边.但这题 ...
- 解决PaddlePaddle飞桨在迁移学习使用预训练模型时更改num_classes参数出现警告
当我们使用 PaddlePaddle 进行迁移学习的时候,直接导入模型虽然是可以的,但是总是会有个警告 如直接用官方的 resnet101 并加载预训练模型的话 model = paddle.visi ...
- 文心一言 VS chatgpt (11)-- 算法导论2.3 7题 3.1 4~5题
四.2 ^ (n+1)=O(2 ^ n)成立吗? 2^(2n)=O(2 ^ n)成立吗? 文心一言: chatgpt: 第一个式子不成立,第二个式子成立. 2 ^ (n+1) = O(2 ^ n) 该 ...
- 2022-09-08:以下go语言代码输出什么?A:5 66;B:5 88;C:7 88;D:以上都不对。 package main func main() { var x = []int{4:
2022-09-08:以下go语言代码输出什么?A:5 66:B:5 88:C:7 88:D:以上都不对. package main func main() { var x = []int{4:44, ...
- 2021-01-07:cdn加速是什么原理?
福哥答案2021-01-07:[答案来自此链接:](https://www.zhihu.com/question/438234873)CDN(Content Delivery Network):内容分 ...
- Midjourney|文心一格prompt教程[Text Prompt(上篇)]:品牌log、App、徽章、插画、头像场景生成,各种风格选择:科技风、运动风
Midjourney|文心一格prompt教程[Text Prompt(上篇)]:品牌log.App.徽章.插画.头像场景生成,各种风格选择:科技风.运动风 1.撰写 Text Prompt 注意事项 ...
- Python基础 - 算数运算符
算数运算符 运算符 描述 实例 + 加 - 两个对象相加 a + b 输出结果 30 - 减 - 得到负数或是一个数减去另一个数 a - b 输出结果 -10 * 乘 - 两个数相乘或是返回一个被 ...
- MySQL的sql语句执行流程(简述)
导言: MySQL和服务器端对接的时候,我们知道一般就是服务器端会打包一些SQL命令去增删改查数据库,这个打包的数据库SQL语句数据包一般为4MB,再大一些就不会被数据库端接收了 但是我们可以自己更改 ...
- cookie和session以及token
cookie和seesion以及token 技术都基于状态保持, cookie: 有服务器生成, 以 k:v 形式保持在浏览器端,下次请求服务器,附带cookie信息:存在恶意修改可能:可以对co ...