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: Spring Boot是一种用于创建独立的、基于Spring的应用程序的框架。而UReport2是一种基于Java的开源报表工具,它支持多种数据源,并具有强大的报表设计和生成功能。 要在Spring Boot中引入UReport2的源码,可以按照以下步骤进行操作: 1. 下载UReport2的源码:可以从UReport2的官方网站或GitHub仓库中下载源码。 2. 创建Spring Boot项目:使用IDE或命令行工具创建一个新的Spring Boot项目。 3. 导入UReport2的源码:将下载的UReport2源码复制到Spring Boot项目中的合适位置。 4. 配置依赖:打开Spring Boot项目的pom.xml文件,并添加UReport2的依赖项。这些依赖项包括UReport2的核心库以及相关的依赖库。 5. 配置报表引擎:在Spring Boot项目的配置文件中,配置UReport2的报表引擎。这包括指定报表引擎的类型、数据源的配置等。 6. 编写报表代码:根据项目需求,编写UReport2的报表代码。这包括报表设计、数据源的设置、报表生成和展示等功能。 7. 运行项目:启动Spring Boot项目,访问报表的URL路径,即可进行报表的生成和展示。 通过以上步骤,就可以在Spring Boot项目中成功引入UReport2的源码,并使用其强大的报表功能。注意,在整个过程中,需要按照UReport2的文档和示例进行配置和使用,以确保正确集成和使用UReport2。 ### 回答2: 要引入ureport2源码,首先需要在项目的pom.xml文件中添加ureport2的依赖。可以通过在spring boot项目的pom.xml文件中,添加如下依赖: ```xml <dependency> <groupId>com.bstek.ureport</groupId> <artifactId>ureport2-spring-boot-starter</artifactId> <version>2.9.7</version> </dependency> ``` 引入该依赖后,需要在项目的配置文件中进行相应的配置。在application.properties或application.yml文件中,可以添加以下配置项: ```yaml # ureport配置 ureport: config-file: classpath:ureport/ureport.xml ``` 其中,`ureport.config-file`配置项指定了ureport的配置文件路径。 接下来,在项目中创建ureport配置文件对应的文件夹,并在文件夹中创建ureport.xml配置文件。ureport.xml文件用于配置ureport的一些参数,如数据源、报表资源等。 最后,你可以在spring boot项目中通过注入ureport的相关Bean来使用ureport的功能。例如,可以在Controller中注入`UReportService`或`ReportFileStore`等Bean来实现报表的生成与管理。 总结起来,引入ureport2源码可以通过以下步骤实现: 1. 添加ureport2的依赖到项目的pom.xml文件中。 2. 在项目的配置文件中进行ureport的相关配置。 3. 创建ureport配置文件,并进行相应的配置。 4. 在项目中使用相关的ureport Bean来实现报表的生成与管理。 ### 回答3: 要引入ureport2源码到Spring Boot项目中,可以按照以下步骤操作: 1. 首先,从ureport2的官方仓库(如GitHub)下载ureport2的源码。 2. 创建一个新的Spring Boot项目,可以使用Spring Initializr(https://start.spring.io/)进行快速初始化。确保选择正确的依赖项,如Spring Web和Spring Boot DevTools。 3. 将下载的ureport2源码解压缩,并将其拷贝到Spring Boot项目的src/main/java文件夹下。 4. 打开ureport2源码中的pom.xml文件,并复制其所有的依赖项。 5. 将复制的依赖项粘贴到Spring Boot项目的pom.xml文件中的<dependencies>标签下。 6. 在Spring Boot项目的src/main/resources文件夹下,创建一个ureport文件夹。 7. 将从ureport2源码中复制的src/main/resources/ureport文件夹下的所有文件和文件夹拷贝到Spring Boot项目的src/main/resources/ureport文件夹下。 8. 在Spring Boot项目的src/main/resources/application.properties文件中,添加ureport2所需的数据库配置(如数据库连接url、username和password)。 9. 在Spring Boot项目的src/main/java的启动类中,加入@EnableAutoConfiguration注解来自动配置ureport2所需的bean。 10. 根据需要,可以根据Spring Boot项目的具体情况,调整ureport2的配置文件,如ureport.properties和ureport.xml。 11. 启动Spring Boot项目,ureport2就会被成功引入到项目中。 以上是将ureport2源码引入到Spring Boot项目的简要步骤。根据具体情况,可能会有一些细微的调整和配置。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值