共计 10716 个字符,预计需要花费 27 分钟才能阅读完成。
环境: centos、jdk1.8、vsftpd、nginx、spring boot、docker
ftp 上传附件,上传的附件有两种形式回显,在上面再具体阐明
此处省略 ftp 服务器、docker 服务器 nginx 服务器搭建过程。
上传首先在 application.yml 文件中增加 ftp 配置
ftp:
内网 000.000.000.000 外网 111.111.111.111
ip: 111.111.111.111
ip: 000.000.000.000
name: ftp_user
password: ftp_user
base:
path: /home/ftp_user
拜访 ftp 文件地址, 这里配的是 nginx 地址
file:
url: http://ip1:port/ftp/
设置上传文件的大小, 我是通过在 yml 文件中配置的,还有一种是通过 https://www.cnblogs.com/fswhq…
spring:
servlet:
multipart:
enabled: true
max-file-size: 102400 #设置时是 1024 的整数倍
max-request-size: 1000MB
一、通过 ftp 生成二维码,回显地址联合 nginx
import com.google.zxing.BarcodeFormat;
/**
- @author lz
- @description 二维码构建
*/
public class QRCode {
/**
- 二维码文本
*/
private final String text;
/**
- 图片宽度
*/
private final int width;
/**
- 图片高度
*/
private final int height;
/**
- 图片存储门路
*/
private final String imgPath;
/**
- 图片类型
*/
private final String imgType;
/**
- 二维码类型
*/
private final BarcodeFormat type;
public QRCode(Builder builder){
this.text = builder.text;
this.width = builder.width;
this.height = builder.height;
this.imgPath = builder.imgPath;
this.imgType = builder.imgType;
this.type = builder.type;
}
public String getText() {
return text;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public String getImgPath() {
return imgPath;
}
public String getImgType() {
return imgType;
}
public BarcodeFormat getType() {
return type;
}
public static class Builder {
public static final String PNG = “png”;
public static final String JPEG = “jpeg”;
public static final String JPG = “jpg”;
public static final String BMP = “bmp”;
/**
- 二维码文本
*/
private String text;
/**
- 图片宽度
*/
private int width = 260;
/**
- 图片高度
*/
private int height = 260;
/**
- 图片存储门路
*/
private String imgPath;
/**
- 图片类型
*/
private String imgType = PNG;
/**
- 二维码类型
*/
private BarcodeFormat type = BarcodeFormat.QR_CODE;
/**
- 设置文本
- @param text
- @return
*/
public Builder text(String text){
this.text = text;
return this;
}
/**
- 设置图片宽度
- @param width
- @return
*/
public Builder width(int width){
this.width = width;
return this;
}
/**
- 设置图片高度
- @param height
- @return
*/
public Builder height(int height){
this.height = height;
return this;
}
/**
- 设置图片保留门路
- @param imgPath
- @return
*/
public Builder imgPath(String imgPath){
this.imgPath = imgPath;
return this;
}
/**
- 设置图片类型
- @param imgType
- @return
*/
public Builder imgType(String imgType){
this.imgType = imgType;
return this;
}
/**
- 设置二维码类型(反对条形码)
- @param type
- @return
*/
public Builder type(BarcodeFormat type){
this.type = type;
return this;
}
public QRCode build(){
return new QRCode(this);
}
}
}
import com.ctsi.attachment.controller.AttachmentController;
import com.ctsi.ssdc.util.MatrixToImageWriter;
import com.google.zxing.EncodeHintType;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import java.io.*;
import java.util.Hashtable;
import java.util.StringTokenizer;
/**
- @author lz
- @description
*/
@Component
public class QRCodeClient {
private QRCodeClient() {
// nothing to do
}
@Value(“${ftp.ip}”)
private final String ftpIp;
@Value(“${ftp.name}”)
private final String ftpName;
@Value(“${ftp.password}”)
private final String ftpPassword;
@Value(“${ftp.base.path}”)
private final String ftpBasePath;
/**
- 环境变量
*/
@Autowired
private Environment environment;
// @Value(“${qr_server.path}”)
private String QR_CODE_PATH = “/qrcode”;
@Value(“${file.url}”)
private String fileUrl;
private final Logger logger = LoggerFactory.getLogger(AttachmentController.class);
public String generateQrcodeUrl(String code) {
String fileName = code + “-qrcode”;
// 返回图片地址
return generate(new QRCode.Builder().text(code)
.imgType(QRCode.Builder.PNG).build(), fileName);
}
/**
- 生成二维码图片
*
- @param qrcode 二维码对象
- @return 地址
*/
public String generate(QRCode qrcode, String fileName) {
FTPClient ftp = new FTPClient();
try {
QRCodeWriter qrCodeWriter = new QRCodeWriter();
BitMatrix bitMatrix = qrCodeWriter.encode(qrcode.getText(), qrcode.getType(), qrcode.getWidth(), qrcode.getHeight());
ByteArrayOutputStream out = new ByteArrayOutputStream();
MatrixToImageWriter.writeToStream(bitMatrix, qrcode.getImgType(), out);
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
ftp.connect(ftpIp, 21);// 设置地址和端口号
logger.info(“ 登陆前 ”);
ftp.login(ftpName, ftpPassword);// 用户名和明码
ftp.enterLocalPassiveMode();
ftp.setFileType(FTPClient.BINARY_FILE_TYPE);// 上传文件类型 二进制文件
int reply = ftp.getReplyCode();
logger.info(“reply:”+reply);
if (!FTPReply.isPositiveCompletion(reply)) {// 查看连贯是否无效
System.out.println(“error”);
}
StringTokenizer s = new StringTokenizer(ftpBasePath + QR_CODE_PATH, “/”);
s.countTokens();
String pathName = “”;
logger.info(“ 创立门路前 ”);
while (s.hasMoreElements()) {
pathName = pathName + “/” + (String) s.nextElement();
try {
ftp.mkd(pathName);
} catch (Exception e) {
logger.info(“ftp 文件夹创立失败 ”);
}
}
logger.info(“ 门路创立后, 打印当前工作目录:”+ftp.printWorkingDirectory());
ftp.changeWorkingDirectory(ftpBasePath + QR_CODE_PATH);
boolean boo = ftp.storeFile(fileName + “.” + qrcode.getImgType().toLowerCase(), in);// 要害代码, 把流长久化到硬盘上
return fileUrl+”qrcode/”.concat(fileName + “.” + qrcode.getImgType().toLowerCase()).replaceAll(“”, “/”);
} catch (Exception e) {
return null;
}
}
}
阐明: 测试间接调用 QRCodeClient 类中的 generateQrcodeUrl 办法,参数是想要通过扫码展现的二维码内容, 返回的是通过 nginx 做的二维码地址,或是能够在本地搭建一个 tomcat,而后把二维码生成在 webapps 外面,通过 tomcat 拜访
二、通过 ftp 上传文件,回显地址是联合 nginx
import cn.hutool.core.date.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.FileInputStream;
import java.util.*;
/**
- @Auther: lz
- @Description: 文件上传
*/
@RestController
@RequestMapping(“/attachment”)
@Slf4j
public class AttachmentController {
/**
- 日志输入
*/
private final Logger logger = LoggerFactory.getLogger(AttachmentController.class);
@Value(“${ftp.ip}”)
private String ftpIp;
@Value(“${ftp.name}”)
private String ftpName;
@Value(“${ftp.password}”)
private String ftpPassword;
@Value(“${ftp.base.path}”)
private String ftpBasePath;
private static final String STR_TXT = “.txt”;
private static final String STR_DOC = “.doc”;
private static final String STR_DOCX = “.docx”;
private static final String STR_XLS = “.xls”;
private static final String STR_XLSX = “.xlsx”;
private static final String STR_PPTX = “.pptx”;
private static final String STR_PPT = “.ppt”;
private static final String STR_ZIP = “.zip”;
private static final String STR_RAR = “.rar”;
private static final String STR_JPG = “.jpg”;
private static final String STR_PNG = “.png”;
/**
- 附件表 - 上传
*/
@PostMapping(“/upload”)
public Result upload(HttpServletRequest request,@RequestParam(“file”) MultipartFile importFile) {
Result result = new Result();
// 获取以后文件名
String fileName = importFile.getOriginalFilename();
String suffix = fileName.substring(fileName.lastIndexOf(“.”));
String[] strings = {STR_DOC, STR_DOCX, STR_JPG, STR_PNG, STR_PPT, STR_PPTX, STR_RAR, STR_TXT, STR_ZIP, STR_XLSX, STR_XLS};
Set<String> suffixSet = new HashSet<>(Arrays.asList(strings));
logger.info(“ 文件后缀:”+suffix);
if ((!suffixSet.contains(suffix))) {
logger.info(“ 后缀判断!”);
throw new RestControllerException(ATTACH_WRONG_FORMAT.getMsg(),new Throwable(ATTACH_WRONG_FORMAT.getMsg()));
}
String date = DateUtil.format(new Date(),”yyyyMMdd”);
Long time = System.currentTimeMillis();
fileName = time + suffix;
try {
// 文件流写入服务器中
// FileUtil.saveFile(importFile.getInputStream(), calssUrl, fileName);
String basePath = + “/” + date + “/” + time;
FTPClient ftp = new FTPClient();
logger.info(“ 文件上传 ftp 连贯前 ”);
// 文件流写入服务器中
ftp.connect(ftpIp, 21);// 设置地址和端口号
logger.info(“ 登陆前 ”);
ftp.login(ftpName, ftpPassword);// 用户名和明码
logger.info(“ 登陆后 ”);
ftp.enterLocalPassiveMode();// 这里有坑!!!!!
ftp.setFileType(FTPClient.BINARY_FILE_TYPE);// 上传文件类型 二进制文件
int reply = ftp.getReplyCode();
logger.info(“reply:”+reply);
if (!FTPReply.isPositiveCompletion(reply)) {// 查看连贯是否无效
System.out.println(“error”);
}
StringTokenizer s = new StringTokenizer(ftpBasePath + basePath, “/”);
s.countTokens();
String pathName = “”;
logger.info(“ 创立门路前 ”);
while (s.hasMoreElements()) {
pathName = pathName + “/” + (String) s.nextElement();
try {
ftp.mkd(pathName);
} catch (Exception e) {
log.info(“ftp 文件夹创立失败 ”);
}
}
logger.info(“ 门路创立后, 打印当前工作目录:”+ftp.printWorkingDirectory());
ftp.changeWorkingDirectory(ftpBasePath + basePath);
FileInputStream fis= (FileInputStream) importFile.getInputStream();
logger.info(“ 文件长久到服务器前 获取的文件大小:”+fis.available()+”;”);
boolean boo = ftp.storeFile(importFile.getOriginalFilename(), fis);// 要害代码, 把流长久化到硬盘上
logger.info(“ 文件保留服务器状态:”+boo);
fis.close();
ftp.logout();
logger.info(“ftp 登出后 ”);
ftp.disconnect();
logger.info(“ftp 勾销连贯后 ”);
} catch (Exception e) {
logger.info(“ftp 报错 ”);
throw new RestControllerException(ATTACH_UPLOAD_FAIL.getMsg(),new Throwable(ATTACH_UPLOAD_FAIL.getMsg()));
}
String url = (“http://ip1:port/ftp/”+ date + “/” + time+”/”+ importFile.getOriginalFilename()).replaceAll(“”, “/”);
result.setData(url)
return result;
}
}
阐明:
ftp.enterLocalPassiveMode();// 这里是一个大坑
因为服务器设置的有白名单所有我的项目公布到服务器上时须要把 ftp_ip 改为内网地址并且须要 enterLocalPassiveMode。应用外网拜访 ftp 时不须要做 enterLocalPassiveMode 设置,本地测试时,本地电脑是作为服务器的,个别不会设置防护火墙。
三、文件上传胜利后,通过实现 WebMvcConfigure 接口,addResourceHandle 办法设置动态文件映射,来拜访 ftp 上的文件
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.ResourceUtils;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.io.File;
import java.io.FileNotFoundException;
/**
- @Auther: lz
- @Description:
- @Date: 2020/10/30
*/
@Configuration
public class UploadFilePathConfig implements WebMvcConfigurer {
/**
- 日志输入
*/
private final Logger logger = LoggerFactory.getLogger(UploadFilePathConfig.class);
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
String os = System.getProperty(“os.name”);
File path = null;
try {
// 获取 classpath 目录的残缺门路
path = new File(ResourceUtils.getURL(“classpath:”).getPath());
} catch (FileNotFoundException e) {
e.printStackTrace();
}
logger.info(“ 增加内部资源映射地位 1 ″+path.getParentFile().getParentFile().getPath());
String gitPath=path.getParentFile().getParentFile().getParent()+File.separator+”ftp_user”+File.separator+”qrcode”+File.separator;
logger.info(“ 增加内部资源映射地位 2:”+gitPath);
// 后面一个参数是申请门路,前面一个是文件在服务器的绝对路径
registry.addResourceHandler(“/static/upload/**”).addResourceLocations(gitPath);
}
@Override
public void addCorsMappings(CorsRegistry registry){
logger.info(“ 增加内部资源映射申请增加跨域 ”);
registry.addMapping(“/static/upload/**”)
.allowedHeaders(“*”)
.allowedMethods(“POST”,”GET”,”PATCH”)
.allowedOrigins(“*”);
}
}
阐明: 应用这个办法时须要把下面提到的 ip1:port 改为后盾接口的申请门路
文档中提到的 ftp 服务器、nginx 服务器、docker 搭建网上有很多,或是当前有工夫会持续补充,
这个是最近开发时踩的雷,更多的雷心愿互相学习,如果你感觉文章还不错,欢送关注珍藏。