最近踩的雷你中招了吗?spring boot ftp 生成二维码、上传附件以及回显

环境: 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/p/13689419.html

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 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搭建网上有很多,或是以后有时间会继续补充,

这个是最近开发时踩的雷,更多的雷希望互相学习,本人会不间断更新JAVA相关干货文,如果你觉得文章还不错,欢迎关注收藏。

作者:mooncharmzx

链接:https://blog.bccn.net/mooncharmzx/67393

你可能感兴趣的:(最近踩的雷你中招了吗?spring boot ftp 生成二维码、上传附件以及回显)