Spring boot 集成 Ureport2 报表存储至sftp服务器

公司有项目在使用ureport来实现报表功能,报表功能已经实现了,但是目前存在一个问题,生产环境是多机集群环境,报表生成后,报表文件是存在单机的服务器上,这样会存在问题,导致访问负载地址时,报表信息不存在。

基于以上问题,在网上找了些资料看了下,原来ureport中提供了ReportProvider接口,实现其接口即可实现存储到sftp服务器(还有其他的模式,比如说存储到数据库),这样就能解决集群不同步的问题。好了,开始上代码

pom.xml
<dependency>
            <groupId>com.bstek.ureport</groupId>
            <artifactId>ureport2-console</artifactId>
            <version>2.2.9</version>
        </dependency>
        <dependency>
            <groupId>commons-net</groupId>
            <artifactId>commons-net</artifactId>
            <version>3.3</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/commons-pool/commons-pool -->
        <dependency>
            <groupId>commons-pool</groupId>
            <artifactId>commons-pool</artifactId>
            <version>1.6</version>
        </dependency>
        <!-- 消除冗余代码,可以省去get、set、构造器... 方法 -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.jcraft</groupId>
            <artifactId>jsch</artifactId>
            <version>0.1.54</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <!-- 添加MySQL依赖 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <!-- 添加JDBC依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <!-- 添加Druid依赖 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.6</version>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.3.5</version>
        </dependency>

application.yml

# ureport FTP 存储
ureport:
  ftp:
    provider:
      prefix: ftp-
      disabled: false
      basePath: ureport_file/
#
sftp:
  client:
    protocol: sftp
    host: ***
    port: ***
    username: ****
    password: ****
    root: /data/home/miapp/ureport/
    privateKey:
    passphrase:
    sessionStrictHostKeyChecking: no
    sessionConnectTimeout: 15000
    channelConnectedTimeout: 15000

DataSourceConfig


import com.alibaba.druid.pool.DruidDataSource;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

@Configuration
@Data
@ConfigurationProperties(prefix = "spring.datasource")
public class DataSourceConfig {
	
	private String url;
	private String username;
	private String password;

	@Bean
	public DataSource getDataSource() {
		DruidDataSource dataSource = new DruidDataSource();
		dataSource.setUrl(url);
		dataSource.setUsername(username);
		dataSource.setPassword(password);
		return dataSource;
	}
}

UreportDataSource


import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import javax.sql.DataSource;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
 
import com.bstek.ureport.definition.datasource.BuildinDatasource;
 
/**
 * Ureport 数据源
 * @author 
 * @version 
 *
 */
 
@Component
public class UreportDataSource implements BuildinDatasource {
	private static final String NAME = "MyDataSource";
	private Logger log = LoggerFactory.getLogger(UreportDataSource.class);
	
	@Autowired
	private DataSource dataSource;
	
        /**
         * 数据源名称
         **/
	@Override
	public String name() {
		return NAME;
	}
        
        /**
         * 获取连接
         **/
	@Override
	public Connection getConnection() {
		try {
			System.out.println(dataSource.toString());
			Connection connection = dataSource.getConnection();
			return dataSource.getConnection();
		} catch (SQLException e) {
			log.error("Ureport 数据源 获取连接失败!");
			e.printStackTrace();
		}
		return null;
	}
 
}

SFTPProvider


import com.bstek.ureport.provider.report.ReportFile;
import com.bstek.ureport.provider.report.ReportProvider;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import net.yondervision.service.FileSystemService;
import org.apache.commons.net.ftp.FTPFile;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

/**
 * @Description FTP文件服务器 报表存储
 * @Author 
 * @Date Created in 2020/5/25
 */
@Setter
@Slf4j
@Component
@ConfigurationProperties(prefix = "ureport.ftp.provider")
public class SFTPProvider implements ReportProvider {

    private static final String NAME = "ftp-provider";
    private String basePath = "/data/home/miapp/ureport/";
    private String prefix = "ftp:";

    private boolean disabled;

    @Autowired
    private FileSystemService ftpUtils;

    @Override
    public InputStream loadReport(String file) {
        return ftpUtils.downFile(getCorrectName(file));
    }

    @Override
    public void deleteReport(String file) {
        ftpUtils.deleteFile(getCorrectName(file));
    }

    @Override
    public List<ReportFile> getReportFiles() {
        List<FTPFile> fileList = ftpUtils.getFileList(basePath);
        List<ReportFile> reportFile = new ArrayList<>();
        for (FTPFile ftpFile : fileList) {
            Calendar timestamp = ftpFile.getTimestamp();
            reportFile.add(new ReportFile(ftpFile.getName(), timestamp.getTime()));
            log.info("---listinfo----" + ftpFile.getName());
        }
        return reportFile;
    }

    @Override
    public void saveReport(String file, String content) {
        ftpUtils.uploadFile(getCorrectName(file), new ByteArrayInputStream(content.getBytes()));
    }

    @Override
    public String getName() {
        return NAME;
    }

    @Override
    public boolean disabled() {
        return disabled;
    }

    @Override
    public String getPrefix() {
        return prefix;
    }

    /**
     * 获取没有前缀的文件名并加上FTP下存放Ureport文件夹前缀
     *
     * @param name
     * @return
     */
    private String getCorrectName(String name) {
        if (name.startsWith(prefix)) {
            name = name.substring(prefix.length(), name.length());
        }
        return basePath + name;
    }
}

ServletRegistrationBeanConfig


import com.bstek.ureport.console.UReportServlet;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;

/**
 * @author: Mr.Du
 * @date 2020-03-16 14:05
 **/
@SpringBootConfiguration
public class ServletRegistrationBeanConfig {

    @Bean
    public ServletRegistrationBean ureportServlet() {
        ServletRegistrationBean<UReportServlet> bean = new ServletRegistrationBean<>(new UReportServlet());
        bean.addUrlMappings("/ureport/*");
        return bean;
    }

}

SFTPConstants


import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/**
 * SFTPConstants 
 */

@Data
@Slf4j
@Component
@ConfigurationProperties("sftp.client")
public class SFTPConstants {

    /**
     * 协议信息
     **/
    private String protocol;
    /**
     * 地址信息
     **/
    private String host;
    /**
     * 端口
     **/
    private int port;
    /**
     * 用户名
     */
    private String username;
    /**
     * 密码
     */
    private String password;
    /**
     * 根目录
     */
    private String root;
    /**
     * 秘钥文件路径
     */
    private String privateKey;
    /**
     * 秘钥密码
     */
    private String passphrase;

    private String sessionStrictHostKeyChecking = "no";
    /**
     * session连接超时时间
     */
    private int sessionConnectTimeout;
    /**
     * channel连接超时时间
     */
    private int channelConnectedTimeout;

}

FileSystemService


import org.apache.commons.net.ftp.FTPFile;

import java.io.File;
import java.io.InputStream;
import java.util.List;

/**
 * @Description FileSystemService
 */
public interface FileSystemService {
    /**
     * 文件上传
     *
     * @param targetPath  目标文件目录
     * @param inputStream 文件流
     * @return boolean
     */
    boolean uploadFile(String targetPath, InputStream inputStream);

    /**
     * 文件上传
     *
     * @param targetPath 目标文件目录
     * @param file       文件
     * @return boolean
     */
    boolean uploadFile(String targetPath, File file);

    /**
     * 文件下传
     *
     * @param targetPath 目标文件目录
     * @return file
     */
    File downloadFile(String targetPath);

    /**
     * 文件下传
     *
     * @param targetPath 目标文件目录
     * @return InputStream
     */
    InputStream downFile(String targetPath);

    /**
     * 删除文件
     *
     * @param targetPath 目标文件目录
     * @return boolean
     */
    boolean deleteFile(String targetPath);

    /**
     * 获取文件目录文件信息
     *
     * @param targetPath 目标文件目录
     * @return list
     */
    List<FTPFile> getFileList(String targetPath);
}

FileSystemServiceImpl


import cn.hutool.core.date.DateUtil;
import com.jcraft.jsch.*;
import lombok.extern.slf4j.Slf4j;
import net.yondervision.service.FileSystemService;
import net.yondervision.constans.SFTPConstants;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.net.ftp.FTPFile;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Vector;

/**
 * @Description
 */

@Slf4j
@Service("fileSystemService")
public class FileSystemServiceImpl implements FileSystemService {

    @Autowired
    private SFTPConstants config;

    /**
     * 创建SFTP连接
     *
     * @return
     * @throws Exception
     */
    private ChannelSftp createSftp() throws Exception {
        JSch jsch = new JSch();

        Session session = createSession(jsch, config.getHost(), config.getUsername(), config.getPort());
        session.setPassword(config.getPassword());
        session.connect(config.getSessionConnectTimeout());

        Channel channel = session.openChannel(config.getProtocol());
        channel.connect(config.getChannelConnectedTimeout());

        return (ChannelSftp) channel;
    }

    /**
     * 加密秘钥方式登陆
     *
     * @return
     */
    private ChannelSftp connectByKey() throws Exception {
        JSch jsch = new JSch();

        // 设置密钥和密码 ,支持密钥的方式登陆
        if (StringUtils.isNotBlank(config.getPrivateKey())) {
            if (StringUtils.isNotBlank(config.getPassphrase())) {
                // 设置带口令的密钥
                jsch.addIdentity(config.getPrivateKey(), config.getPassphrase());
            } else {
                // 设置不带口令的密钥
                jsch.addIdentity(config.getPrivateKey());
            }
        }
        Session session = createSession(jsch, config.getHost(), config.getUsername(), config.getPort());
        // 设置登陆超时时间
        session.connect(config.getSessionConnectTimeout());
        // 创建sftp通信通道
        Channel channel = session.openChannel(config.getProtocol());
        channel.connect(config.getChannelConnectedTimeout());
        return (ChannelSftp) channel;
    }

    /**
     * 创建session
     *
     * @param jsch
     * @param host
     * @param username
     * @param port
     * @return
     * @throws Exception
     */
    private Session createSession(JSch jsch, String host, String username, Integer port) throws Exception {
        Session session = null;

        if (port <= 0) {
            session = jsch.getSession(username, host);
        } else {
            session = jsch.getSession(username, host, port);
        }

        if (session == null) {
            throw new Exception(host + " session is null");
        }

        session.setConfig(SESSION_CONFIG_STRICT_HOST_KEY_CHECKING, config.getSessionStrictHostKeyChecking());
        return session;
    }

    /**
     * 关闭连接
     *
     * @param sftp
     */
    private void disconnect(ChannelSftp sftp) {
        try {
            if (sftp != null) {
                if (sftp.isConnected()) {
                    sftp.disconnect();
                } else if (sftp.isClosed()) {
                    System.out.println("sftp is closed already");
                }
                if (null != sftp.getSession()) {
                    sftp.getSession().disconnect();
                }
            }
        } catch (JSchException e) {
            e.printStackTrace();
        }
    }

    // 设置第一次登陆的时候提示,可选值:(ask | yes | no)
    private static final String SESSION_CONFIG_STRICT_HOST_KEY_CHECKING = "StrictHostKeyChecking";


    @Override
    public boolean uploadFile(String targetPath, InputStream inputStream) {
        ChannelSftp sftp = null;
        try {
            sftp = this.createSftp();
            sftp.cd(config.getRoot());

            int index = targetPath.lastIndexOf("/");
            String fileDir = targetPath.substring(0, index);
            String fileName = targetPath.substring(index + 1);
            boolean dirs = this.createDirs(fileDir, sftp);
            if (!dirs) {
                throw new Exception("Upload File failure");
            }
            sftp.put(inputStream, fileName);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            this.disconnect(sftp);
        }
        return true;
    }

    @Override
    public boolean uploadFile(String targetPath, File file) {
        boolean flag = false;
        try {
            flag = this.uploadFile(targetPath, new FileInputStream(file));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return flag;
    }

    @Override
    public File downloadFile(String targetPath) {
        ChannelSftp sftp = null;
        OutputStream outputStream = null;
        File file = null;
        try {
            sftp = this.createSftp();
            sftp.cd(config.getRoot());
            file = new File(targetPath.substring(targetPath.lastIndexOf("/") + 1));
            outputStream = new FileOutputStream(file);
            sftp.get(targetPath, outputStream);

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }
            this.disconnect(sftp);
        }
        return file;
    }

    @Override
    public InputStream downFile(String targetPath) {
        InputStream fileStream = null;
        try {
            File file = downloadFile(targetPath);
            fileStream = new FileInputStream(file);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return fileStream;
    }

    @Override
    public boolean deleteFile(String targetPath) {
        ChannelSftp sftp = null;
        try {
            sftp = this.createSftp();
            sftp.cd(config.getRoot());
            sftp.rm(targetPath);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("删除文件失败", e.getMessage());
        } finally {
            if (sftp != null) {
                this.disconnect(sftp);
            }
        }
        return true;
    }

    @Override
    public List<FTPFile> getFileList(String targetPath) {
        ChannelSftp sftp = null;
        List<FTPFile> list = new ArrayList<>();
        try {
            sftp = this.createSftp();
            String path = config.getRoot() + targetPath;
            SftpATTRS attrs = null;
            Vector<ChannelSftp.LsEntry> lsEntries = sftp.ls(path);
            for (ChannelSftp.LsEntry entry : lsEntries) {
                String fileName = entry.getFilename();
                if (checkFileName(fileName)) {
                    continue;
                }
                attrs = sftp.lstat(path + fileName);
                FTPFile ftpFile = new FTPFile();
                log.info("file-info-time" + attrs.getATime());
                ftpFile.setTimestamp(getCalendar(attrs.getMtimeString()));
                ftpFile.setName(fileName);
                list.add(ftpFile);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (sftp != null) {
                this.disconnect(sftp);
            }
        }
        return list;
    }

    private boolean createDirs(String dirPath, ChannelSftp sftp) {
        if (dirPath != null && !dirPath.isEmpty()
                && sftp != null) {
            String[] dirs = Arrays.stream(dirPath.split("/"))
                    .filter(StringUtils::isNotBlank)
                    .toArray(String[]::new);

            for (String dir : dirs) {
                try {
                    sftp.cd(dir);
                } catch (Exception e) {
                    try {
                        sftp.mkdir(dir);
                    } catch (SftpException e1) {
                        e1.printStackTrace();
                    }
                    try {
                        sftp.cd(dir);
                    } catch (SftpException e1) {
                        e1.printStackTrace();
                    }
                }
            }
            return true;
        }
        return false;
    }

    private boolean checkFileName(String fileName) {
        if (".".equals(fileName) || "..".equals(fileName)) {
            return true;
        }
        return false;
    }

	public Calendar getCalendar(String str){
        Calendar cal = Calendar.getInstance();
        String pattern = "EEE MMM dd HH:mm:ss zzz yyyy";
        SimpleDateFormat df = new SimpleDateFormat(pattern,Locale.US);
        Date date = null;
        try {
            date = df.parse(str);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        cal.setTime(date);
        return cal;
    }
}

App


import net.yondervision.config.DataSourceConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.ImportResource;

/**
 * Hello world!
 *
 */
@ImportResource("classpath:ureport-console-context.xml")
@SpringBootApplication
@EnableConfigurationProperties({DataSourceConfig.class})
public class App
{
    public static void main( String[] args )

    {
        SpringApplication.run(App.class,args);
    }
}

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值