关于java:最近踩的雷你中招了吗spring-boot-ftp-生成二维码上传附件以及回显

4次阅读

共计 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 搭建网上有很多,或是当前有工夫会持续补充,

这个是最近开发时踩的雷,更多的雷心愿互相学习,如果你感觉文章还不错,欢送关注珍藏。

正文完
 0