实现Springboot整合UReport2

这篇具有很好参考价值的文章主要介绍了实现Springboot整合UReport2。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1、什么是UReport2?

UReport2是一款高性能的架构在Spring之上纯Java报表引擎,通过迭代单元格可以实现任意复杂的中国式报表。该报表由上海锐道信息技术有限公司开发的一款基于Apache-2.0协议开源的中式报表引擎(点击进入gitee源码页面)。当前报表引擎不知是什么原因没有被作者继续维护,但是前期文档还是相对比较详细(点击进入文档页面)。

2、为啥要整合UReport2?

笔者也是处于对报表引擎的实现原理感兴趣,所以download了源码并对部分细节进行调整和优化。建议对报表引擎感兴趣的同学可以下载源码进行研究的个性化调整优化。同时使用springboot+mysql+jfinal+iview+jquery实现了一个简单的报表demo,在此做一个简单的学习记录,并同各位同学分享,希望能同各位一起不断进步和提升个人技术能力。

3、实现结果

先上部分截图展示一下实现结果

3.1、报表列表

实现Springboot整合UReport2

3.2、报表设计器

实现Springboot整合UReport2

3.3、学生平均分报表预览

实现Springboot整合UReport2

3.4、综合成绩报表预览

实现Springboot整合UReport2

3.5、学生成绩单报表预览

实现Springboot整合UReport2

4、实现过程

先放一张系统文件结构图
实现Springboot整合UReport2

4.1、创建一个springboot项目

将项目命名为ureport,并在pom.xml文件中添加需要的maven依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.crwl</groupId>
    <artifactId>ureport</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <spring-cloud.version>2.1.1.RELEASE</spring-cloud.version>
        <flowable.version>6.5.0</flowable.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
            <version>2.0.9.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.0.9.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <version>2.0.9.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
            <version>1.16.20</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>6.0.2</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>RELEASE</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>RELEASE</version>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>4.6.10</version>
        </dependency>
        <dependency>
            <groupId>com.jfinal</groupId>
            <artifactId>activerecord</artifactId>
            <version>4.8</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.6</version>
        </dependency>
        <dependency>
            <groupId>com.bstek.ureport</groupId>
            <artifactId>ureport2-console</artifactId>
            <version>2.3.0-pro</version>
        </dependency>
    </dependencies>
</project>

此处ureport2的jar包依赖为笔者重新修改并编译源码后生成,如果直接采用UReport2官方下载的jar包,针对本demo有可能无法运行,如由用户需要当前jar包可联系笔者。

4.2、添加yml配置信息

applicaiton.yaml

server:
  port: 9090
  servlet:
    context-path: /pro
spring:
  http:
    encoding:
      force: true
      enabled: true
      charset: UTF-8
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/ureport?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false&allowMultiQueries=true&nullNamePatternMatchesAll=true
    username: root
    password:
    type: com.alibaba.druid.pool.DruidDataSource
  resources:
    static-locations: classpath:/,classpath:/static/

4.3、添加引用UReport2的Spring配置文件context.xml

笔者是放在resources/config目录下面

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
    <import resource="classpath:ureport-console-context.xml" />
    <bean id="propertyConfigurer" parent="ureport.props">
        <property name="locations">
            <list>
                <value>classpath:config/config.properties</value>
            </list>
        </property>
    </bean>
    <bean id="ureport.fielToDataBaseProvider" class="com.crwl.provider.FileToDatabaserProvider">
        <property name="fileStoreDir" value="${ureport.fileToDbStoreDir}"></property>
        <property name="disabled" value="${ureport.disableFileDbProvider}"></property>
    </bean>
</beans>

4.4、添加property文件

config.properties

#配置文件系统对应的报表文件地址
#ureport.fileStoreDir=D:/myfile/ureportfiles
# 是否禁用
ureport.disableFileProvider=true
#配置同数据库关联文件系统对应的报表文件地址
ureport.fileToDbStoreDir=D:/myfile/ureportDbfiles
# 是否禁用
ureport.disableFileDbProvider=false
# 配置ureport根路径,对应ureport-console/src/main/resources/ureport-console-context.xml中的ureport.designerServletAction
ureport.contextPath=/pro
4.4.1、ureport.fileStoreDir

UReport2报表引擎默认采用文件系统,其中ureport.fileStoreDir是配置生成的报表文件的物理路径,ureport.disableFileProvider是定义是否禁用用当前报表的文件系统,true为禁用,false为启用。笔者当前的思路是将文件系统同mysql数据库结合起来进行管理,所以配置为禁用。

4.4.2、ureport.fileToDbStoreDir

ureport.fileToDbStoreDir为笔者扩展出来的mysql+文件系统结合的一种方式,此参数同样是配置路径,ureport.disableFileDbProvider配置是否禁用

4.4.3、ureport.contextPath

ureport.contextPath参数为笔者添加的参数,此参数可帮助用户实现业务后台系统同前端分离会出现的报表默认资源路径地址不匹配的情况。当前demo未采用前后端分离,所以此参数可以配置,也可以不配置,不配置默认为application.yaml文件对应的context-path。

4.5、java源码

4.5.1、DataSourceConfig.java
package com.crwl.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.crwl.model._MappingKit;
import com.jfinal.plugin.activerecord.ActiveRecordPlugin;
import com.jfinal.plugin.activerecord.CaseInsensitiveContainerFactory;
import com.jfinal.plugin.activerecord.dialect.MysqlDialect;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;

import javax.sql.DataSource;
/**
 * @author teamo
 * @Package com.crwl.config
 * @Description:
 * @date 2022-8-17
 */
@Configuration
public class DataSourceConfig {
    @Primary
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource druidDataSource() {
        return new DruidDataSource();
    }

    /**
     * 设置数据源代理
     */
    @Bean
    public TransactionAwareDataSourceProxy transactionAwareDataSourceProxy() {
        TransactionAwareDataSourceProxy transactionAwareDataSourceProxy = new TransactionAwareDataSourceProxy();
        transactionAwareDataSourceProxy.setTargetDataSource(druidDataSource());
        return transactionAwareDataSourceProxy;
    }

    /**
     * 设置ActiveRecord
     */
    @Bean
    public ActiveRecordPlugin activeRecordPlugin() {
        ActiveRecordPlugin arp = new ActiveRecordPlugin(transactionAwareDataSourceProxy());
        arp.setDialect(new MysqlDialect());
        arp.setContainerFactory(new CaseInsensitiveContainerFactory(true));//忽略大小写
        arp.setShowSql(true);
        arp.getEngine().setToClassPathSourceFactory();
        //arp.addSqlTemplate("sql/all.sql");
        _MappingKit.mapping(arp);
        arp.start();
        System.out.println("调用Jfinal ActiveRecordPlugin 成功");
        return arp;
    }
}

此类主要用于根据配置文件对数据库链接以及Jfinal的进行初始化工作。
如用户对JFinal不太了解,可以自行百度学习。JFinal 是基于Java 语言的极速 web 开发框架,其核心设计目标是开发迅速、代码量少、学习简单、功能强大、轻量级、易扩展、Restful。当前demo主要使用Jfinal的数据库部分的功能。

4.5.2、model类 Report.java, BaseReport.java,_MappingKit.java

model为jfinal的实体对象类,主要用于同数据表进行orm映射关系。

package com.crwl.model;

import com.crwl.model.base.BaseReport;
/**
 * Generated by JFinal.
 */
@SuppressWarnings("serial")
public class Report extends BaseReport<Report> {
	public static final Report dao = new Report().dao();
}

BaseReport.java

package com.crwl.model.base;

import com.jfinal.plugin.activerecord.IBean;
import com.jfinal.plugin.activerecord.Model;

import java.util.Date;

/**
 * Generated by JFinal, do not modify this file.
 */
@SuppressWarnings({"serial", "unchecked"})
public abstract class BaseReport<M extends BaseReport<M>> extends Model<M> implements IBean {
	public M setId(Integer id) {
		set("id", id);
		return (M)this;
	}
	public Integer getId() {
		return getInt("id");
	}
	public M setRptCode(String rptCode) {
		set("rpt_code", rptCode);
		return (M)this;
	}
	public String getRptCode() {
		return getStr("rpt_code");
	}
	public M setRptName(String rptName) {
		set("rpt_name", rptName);
		return (M)this;
	}
	public String getRptName() {
		return getStr("rpt_name");
	}
	public M setRptType(Integer rptType) {
		set("rpt_type", rptType);
		return (M)this;
	}
	public Integer getRptType() {
		return getInt("rpt_type");
	}
	public M setUreportName(String ureportName) {
		set("ureport_name", ureportName);
		return (M)this;
	}
	public String getUreportName() {
		return getStr("ureport_name");
	}
	public M setRptUrl(String rptUrl) {
		set("rpt_url", rptUrl);
		return (M)this;
	}
	public String getRptUrl() {
		return getStr("rpt_url");
	}
	public M setRemark(String remark) {
		set("remark", remark);
		return (M)this;
	}
	public String getRemark() {
		return getStr("remark");
	}
	public M setSort(Integer sort) {
		set("sort", sort);
		return (M)this;
	}
	public Integer getSort() {
		return getInt("sort");
	}
	public M setStatus(Integer status) {
		set("status", status);
		return (M)this;
	}
	public Integer getStatus() {
		return getInt("status");
	}
	public M setCreateUser(String createUser) {
		set("create_user", createUser);
		return (M)this;
	}
	public String getCreateUser() {
		return getStr("create_user");
	}
	public M setCreateDate(Date createDate) {
		set("create_date", createDate);
		return (M)this;
	}
	public Date getCreateDate() {
		return getDate("create_date");
	}
	public M setUpdateUser(String updateUser) {
		set("update_user", updateUser);
		return (M)this;
	}
	public String getUpdateUser() {
		return getStr("update_user");
	}
	public M setUpdateDate(Date updateDate) {
		set("update_date", updateDate);
		return (M)this;
	}
	public Date getUpdateDate() {
		return getDate("update_date");
	}
}

_MappingKit.java

package com.crwl.model;
import com.jfinal.plugin.activerecord.ActiveRecordPlugin;
public class _MappingKit {
	public static void mapping(ActiveRecordPlugin arp) {
		arp.addMapping("ur_report", "id", Report.class);
	}
}
4.5.3、Controller类

ReportController.java,报表Controller类

package com.crwl;

import com.bstek.ureport.console.UReportServlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ImportResource;
import org.springframework.transaction.annotation.EnableTransactionManagement;

/**
 * 入口类
 */
@SpringBootApplication()
@EnableTransactionManagement
@ImportResource("classpath:config/context.xml")
@ComponentScan(basePackages = {"com.crwl.*"})
public class UreportApplication {
    public static void main(String[] args) {
        SpringApplication.run(UreportApplication.class, args);
    }
    //ureport报表
    @Bean
    public ServletRegistrationBean buildUReprtServlet(){
        return new ServletRegistrationBean(new UReportServlet(),"/ureport/*");
    }
}
4.5.4、Service类 ReportService.java, ReportServiceImpl.java

ReportService.java

package com.crwl.service;
import com.crwl.model.Report;
import com.jfinal.plugin.activerecord.Page;

public interface ReportService {
    /***
     * 获取表格数据
     * @param currentPage
     * @param pageSize
     * @param rptName
     * @param rptType
     * @return
     */
    Page<Report> getPageList(Integer currentPage, Integer pageSize, String rptName, String rptType);
}

ReportServiceImpl.java

package com.crwl.service.impl;

import com.crwl.model.Report;
import com.crwl.service.ReportService;
import com.jfinal.plugin.activerecord.Page;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;

@Service
public class ReportServiceImpl implements ReportService {
    private final String table = "ur_report";

    @Override
    public Page<Report> getPageList(Integer currentPage, Integer pageSize, String rptName, String rptType) {
        StringBuilder sql = new StringBuilder();
        sql.append(" from "+ table + " t where 1=1 ");
        if(StringUtils.isNotEmpty(rptName)){
            sql.append(" and instr(t.rpt_name,'"+rptName +"')>0 ");
        }
        if(StringUtils.isNotEmpty(rptType)){
            sql.append(" and t.rpt_type="+rptType);
        }
        sql.append(" order by t.sort desc ");
        Page<Report> pageList = Report.dao.paginate(currentPage,pageSize,"select t.* ",sql.toString());
        return pageList;
    }
}
4.5.4、Povider类

Provider类是实现UReport开放出来的供业务系统实现的接口类,用户可以同时实现不同的Provider类从代码层面去实现用户的业务需求。
DsProvider.java:通过事项BuildingDatasource接口,用户可以为报表设计界面提供接口级别的数据源。
实现当前接口后,在报表设计界面可直接使用当前数据库链接。
实现Springboot整合UReport2实现Springboot整合UReport2

package com.crwl.provider;

import com.bstek.ureport.definition.datasource.BuildinDatasource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;

//提供ureport 内置数据源连接
@Component("dsScoreSys")
public class DsProvider implements BuildinDatasource {
    @Autowired
    private DataSource dataSource;

    @Override
    public String name() {
        return "scoreSys";
    }
    @Override
    public Connection getConnection() {
        try {
            return dataSource.getConnection();
        } catch (SQLException e) {
            e.printStackTrace();
            return null;
        }
    }
}

FileToDatabaserProvider.java: 通过实现ReportProvider接口,用户可以增加符合用户自身需求的报表储存方式(UReport2自身已经实现了纯文件系统储存报表的存储方式)。笔者通过实现当前接口实现了使用数据库存储报表的基本信息,使用文件系统存储报表文件,数据库记录报表的寻址地址。即可以使用mysql数据表管理报表文件。

package com.crwl.provider;

import com.bstek.ureport.exception.ReportException;
import com.bstek.ureport.provider.report.ReportFile;
import com.bstek.ureport.provider.report.ReportProvider;
import com.crwl.model.Report;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;

import java.io.*;
import java.util.*;

public class FileToDatabaserProvider implements ReportProvider {
    private String prefix="fileToDb:";
    private String fileStoreDir;
    private String disabled;

    @Override
    public InputStream loadReport(String file) {
        if(StringUtils.isNotEmpty(file)){
            String[] arr = file.split("@");
            Report report = null;
            if(null != arr && arr.length==2){
                report = Report.dao.findById(Integer.parseInt(arr[1]));
                file = report.getUreportName();
            }else{
                report = Report.dao.findFirst(" select * from ur_report t where t.ureport_name=?", file);
            }
            if(null != report) {
                if (file.startsWith(prefix)) {
                    file = file.substring(prefix.length(), file.length());
                }
                String fullPath = fileStoreDir + "/" + file;
                try {
                    return new FileInputStream(fullPath);
                } catch (FileNotFoundException e) {
                    throw new ReportException(e);
                }
            }else{
                throw new ReportException("报表文件不存在");
            }
        }else{
            throw new ReportException("报表文件不存在");
        }
    }

    @Override
    public void deleteReport(String file) {
        Report report = Report.dao.findFirst(" select * from ur_report t where t.ureport_name=?",file);
        if(null != report){
            if(file.startsWith(prefix)){
                file=file.substring(prefix.length(),file.length());
            }
            String fullPath=fileStoreDir+"/"+file;
            File f=new File(fullPath);
            if(f.exists()){
                f.delete();
            }
            report.delete();
        }
    }
    @Override
    public List<ReportFile> getReportFiles() {
        List<Report> reportList = Report.dao.find("select * from ur_report t where t.rpt_type=2 ");
        File file=new File(fileStoreDir);
        List<ReportFile> list=new ArrayList<ReportFile>();
        for(File f:file.listFiles()){
            Calendar calendar=Calendar.getInstance();
            calendar.setTimeInMillis(f.lastModified());
            Report report = null;
            for(int i=0; i<reportList.size();i++){
                Report r = reportList.get(i);
                String reportName = r.getUreportName();
                if(StringUtils.isNotEmpty(reportName)){
                    reportName = reportName.substring(prefix.length(), reportName.length());
                    if(f.getName().equals(reportName)){
                        report = r;
                    }
                }
            }
            if(null != report){
                list.add(new ReportFile(report.getId(),f.getName(),calendar.getTime()));
            }
        }
        Collections.sort(list, new Comparator<ReportFile>(){
            @Override
            public int compare(ReportFile f1, ReportFile f2) {
                return f2.getUpdateDate().compareTo(f1.getUpdateDate());
            }
        });
        return list;
    }

    @Override
    public void saveReport(String file, String content) {
        if(StringUtils.isNotEmpty(file)) {
            String[] arr = file.split("@");
            Report report = null;
            if(null != arr && arr.length==2){
                report = Report.dao.findById(Integer.parseInt(arr[0]));
                file = arr[1];
            }else{
                report = Report.dao.findFirst(" select * from ur_report t where t.ureport_name=?", file);
            }
            if (null != report) {
                report.setUreportName(file);
                report.setRptUrl("ureport/preview?_u=" + file);
                if (file.startsWith(prefix)) {
                    file = file.substring(prefix.length(), file.length());
                }
                String fullPath = fileStoreDir + "/" + file;
                FileOutputStream outStream = null;
                try {
                    outStream = new FileOutputStream(new File(fullPath));
                    IOUtils.write(content, outStream, "utf-8");
                } catch (Exception ex) {
                    throw new ReportException(ex);
                } finally {
                    if (outStream != null) {
                        try {
                            outStream.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
                report.setUpdateDate(new Date());
                report.update();
            } else {
                throw new ReportException("报表文件不存在");
            }
        }else{
            throw new ReportException("报表文件不存在");
        }
    }
    @Override
    public String getName() {
        return "数据库文件系统";
    }
    @Override
    public boolean disabled() {
        return false;
    }
    @Override
    public String getPrefix() {
        return prefix;
    }
    public void setFileStoreDir(String fileStoreDir) {
        this.fileStoreDir = fileStoreDir;
    }
    public void setDisabled(String disabled) {
        this.disabled = disabled;
    }
}

loadReport方法:通过给定的参数从数据库中找到报表文件,根据寻址地址生成一个InputStream对象,报表设计器根据返回的InputStream对象渲染出正在设计中的报表文件

deleteReport方法:提供过给定的参数删除报表文件,此方法的操作是先删除对应数据库中的记录,在删除对应的物理报表文件

getReportFiles方法:加载当前所有的数据报表记录。

saveReport方法:通过给定的参数找到报表记录,更新报表预览地址并保存物理报表文件。

UreportContextProvider.java是笔者扩展的更改报表contextPath参数的接口,它的作用同config.properties文件中的ureport.contextPath参数一致,此处未使用,故不做介绍了。

4.5.5、springboot启动类

UreportApplication.java
@ImportResource(“classpath:config/context.xml”)不能漏了,它是引入ureport2的spring配置文件。
buildUReprtServlet方法是将UReport注册为一个Servlet,是使用UReport的入口文件,不能缺少。

package com.crwl;

import com.bstek.ureport.console.UReportServlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ImportResource;
import org.springframework.transaction.annotation.EnableTransactionManagement;

/**
 * 入口类
 */
@SpringBootApplication()
@EnableTransactionManagement
@ImportResource("classpath:config/context.xml")
@ComponentScan(basePackages = {"com.crwl.*"})
public class UreportApplication {

    public static void main(String[] args) {
        SpringApplication.run(UreportApplication.class, args);
    }

    //ureport报表
    @Bean
    public ServletRegistrationBean buildUReprtServlet(){
        return new ServletRegistrationBean(new UReportServlet(),"/ureport/*");
    }
}
4.5.5、其它类

Result.java: 返回前端Dto类

package com.crwl.dto;
import com.crwl.enums.ResultEnum;
import java.io.Serializable;
/**
 * 返回的对象(统一返回)
 *
 * @author SmallStrong
 */
public class Result implements Serializable {
    /**
     *
     */
    private static final long serialVersionUID = 3337439376898084639L;
    /**
     * 处理状态
     */
    private Integer code;
    /**
     * 处理信息
     */
    private String msg;
    private String serverID;
    /**
     * 返回值
     */
    private Object data;
    private int total;
    private Object rows;
    /**
     * 成功,传入data(使用最多)
     *
     * @param data
     * @return
     */
    public static Result success(Object data) {
        return Result.success(data,"请求成功!");
    }
    /**
     * 成功,传入data(使用最多)
     * @param msg
     * @return
     */
    public static Result success(String msg) {
        Result result = new Result();
        result.setCode(ResultEnum.SUCCESS.getCode());
        result.setMsg(msg);
        return result;
    }
    /**
     * 成功,传入rows和total
     * @param rows
     * @param total
     * @return
     */
    public static Result success(Object rows,int total) {
        Result result = new Result();
        result.setCode(ResultEnum.SUCCESS.getCode());
        result.setMsg("请求成功!");
        result.setRows(rows);
        result.setTotal(total);
        return result;
    }

    /**
     * 成功,传入data 和 msg
     * @param data
     * @param msg
     * @return
     */
    public static Result success(Object data, String msg) {
        Result result = new Result();
        result.setCode(ResultEnum.SUCCESS.getCode());
        result.setMsg(msg);
        result.setData(data);
        return result;
    }
    /**
     * 失败
     * @return
     */
    public static Result error() {
        return Result.error("请求失败!");
    }
    /**
     * 失败 传入 msg
     * @param msg
     * @return
     */
    public static Result error(String msg) {
        return  Result.error(msg,ResultEnum.FAILURE);
    }

    public static Result error(String msg ,ResultEnum resultEnum){
        Result result = new Result();
        result.setCode(resultEnum.getCode());
        result.setMsg(msg);
        return result;
    }
    public Integer getCode() {
        return code;
    }
    public void setCode(Integer code) {
        this.code = code;
        if(null != this.data && this.data.getClass().getName().equals("com.crwl.commonserver.dto.CurrUser")){
            this.data = null;
        }
    }
    public String getMsg() {
        return msg;
    }
    public void setMsg(String msg) {
        this.msg = msg;
    }
    public String getServerID() {
        return serverID;
    }
    public void setServerID(String serverID) {
        this.serverID = serverID;
    }
    public Object getData() {
        return data;
    }
    public void setData(Object data) {
        this.data = data;
    }

    public int getTotal() {
        return total;
    }

    public void setTotal(int total) {
        this.total = total;
    }

    public Object getRows() {
        return rows;
    }

    public void setRows(Object rows) {
        this.rows = rows;
    }
    @Override
    public String toString() {
        return "Result{" +
                "code=" + code +
                ", msg='" + msg + '\'' +
                ", serverID='" + serverID + '\'' +
                ", data=" + data +
                ", total=" + total +
                ", rows=" + rows +
                '}';
    }
}

ResultEnum.java:返回前端状态枚举类

package com.crwl.enums;
/**
 * 返回状态
 */
public enum ResultEnum {
    /**
     * 200 OK     //客户端请求成功 
     * 400 Bad Request  //客户端请求有语法错误,不能被服务器所理解 
     * 401 Unauthorized //请求未经授权,这个状态代码必须和 WWW-Authenticate 报头域一起使用
     * 403 Forbidden  //服务器收到请求,但是拒绝提供服务 
     * 404 Not Found  //请求资源不存在,eg:输入了错误的 URL 
     * 500 Internal Server Error //服务器发生不可预期的错误 
     * 503 Server Unavailable  //服务器当前不能处理客户端的请求,一段时间后可能恢复正常 
     */
    SUCCESS(200, "操作成功"),ERROR(500,"操作失败"), FAILURE(404, "请求的网页不存在"),INVALID(503,"服务不可用"),LOGINOVERTIME(1000,"登录超时");
    private ResultEnum(Integer code, String data) {
        this.code = code;
        this.data = data;
    }
    private Integer code;
    private String data;
    public Integer getCode() {
        return code;
    }
    public void setCode(Integer code) {
        this.code = code;
    }
    public String getData() {
        return data;
    }
    public void setData(String data) {
        this.data = data;
    }
}

Tool.java工具类(未用到),RecordModelGenerator.java自动生成Jfinal实体文件类,为节省篇幅,此处不贴出来了

4.6、前端代码

实现Springboot整合UReport2
前端使用的是传统的在html文件引入的方式js库文件的方式实现。采用的技术是jquery,iview。前端文件包括一个report.html和report.js,其它都是类库文件。
report.html

<!DOCTYPE html>
<html lang="en">
<head>
	<meta http-equiv="content-type" content="text/html; charset=UTF-8">

	<meta charset="utf-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<title>报表管理</title>
	<!-- CSS -->
	<link rel="stylesheet" type = "text/css" href="../static/lib/iview/css/iview.css?v=1" />
	<script src="../static/js/jquery-1.8.2.min.js"></script>
	<script src="../static/lib/iview/vue.min.js"></script>
	<script src="../static/lib/iview/iview.min.js"></script>
	<script src="../static/js/common.js"></script>
	<script src="./js/report.js"></script>
	<style>
		#searchForm .ivu-form-item{
			margin-bottom:0px;
		}
		.clearfix{clear:both;}
		#searchForm .ivu-col{padding:10px 0;}
		.valCss{color:#515a6e!important;}
		.ivu-table-body{overflow-y:auto;overflow-x:hidden;}
		.ivu-input[disabled], fieldset[disabled]{
			color:#515a6e;
		}
		.ivu-form-item-content .ivu-form-item-error-tip{
			top:80%;
		}
		#reportDesignerIframe,#reportPreviewIframe{border:0;}
		#reportDesingerWin .ivu-modal-footer,#reportPreviewWin .ivu-modal-footer{display:none;}
		#reportDesingerWin .ivu-modal-body,#reportPreviewWin .ivu-modal-body{bottom:0}
	</style>
</head>
<body  scroll="no" style="overflow-y:hidden;scrollbar-width: none;">
<Layout id="app" style="overflow-y:hidden;">
	<div style="height:54px;">
		<i-row id="searchForm">
			<i-form :label-width="120">
				<i-col span="4">
					<form-item label="报表名称" prop="rptName">
						<i-input :size="styleSize" v-model="searchForm.rptName"></i-input>
					</form-item>
				</i-col>
				<i-col span="3">
					<i-Button :size="styleSize" type="primary" icon="ios-search" style="margin-left:15px;" @click="searchFunc">查询</i-Button>
				</i-col>
			</i-form>
			<div class="clearfix"></div>
		</i-row>
	</div>
	<i-row style="text-align:left;padding:5px;background:#fff;">
		<i-Button :size="styleSize" type="primary" icon="ios-add" @click="openEdit(1)">新增</i-Button>
		<i-Button :size="styleSize" type="primary" icon="ios-create" @click="openEdit(2)">修改</i-Button>
		<i-Button :size="styleSize" type="primary" icon="ios-remove" @click="deleteFunc()">删除</i-Button>
	</i-row>
	<Content>
		<i-Table :size="styleSize" row-key="id"  border :columns="columns" :data="tableDataList" ref="table" @on-row-click="selectRow" :height="tableHeight" :loading="loading" highlight-row style="overflow-y:auto;"></i-Table>
		<Page :total="dataCount" :page-size="pageSize" :page-size-opts="pageOptions"  show-sizer class="paging" @on-change="changepage" @on-page-size-change="pagesize"></Page>
	</Content>
	<Modal v-model="editModal"
		   :title="editFlag=='add'?'新增':'修改'"
		   width="800px"
	>
		<i-form ref="editValidate" :model="formData" :rules="editRuleValidate" :label-width="120" style="padding:5px 50px;">
			<i-col span="12">
				<form-item label="报表编码" prop="rptCode">
					<i-input :size="styleSize" v-model="formData.rptCode"  ></i-input>
				</form-item>
			</i-col>
			<i-col span="12">
				<form-item label="报表名称" prop="rptName">
					<i-input :size="styleSize" v-model="formData.rptName"  ></i-input>
				</form-item>
			</i-col>
			<i-col span="12">
				<form-item label="排序号" prop="sort">
					<i-input :size="styleSize" type="number" v-model="formData.sort"  ></i-input>
				</form-item>
			</i-col>
			<i-col span="12">
				<form-item label="状态" prop="status">
					<i-switch :size="styleSize" v-model="formData.status" true-value="1" false-value="0" :width="100" size="large">
						<span slot="open">启用</span>
						<span slot="close">禁用</span>
					</i-switch>
				</form-item>
			</i-col>
			<i-col span="24">
				<form-item label="备注" prop="remark">
					<i-input :size="styleSize"  type="textarea":rows="2" v-model="formData.remark" placeholder="请输入备注信息" style="width:100%"></i-input>
				</form-item>
			</i-col>
		</i-form>
		<div class="clearfix"></div>
		<div slot="footer">
			<i-Button :size="styleSize" type="primary" @click="submitFunc">保存</i-Button>
			<i-Button :size="styleSize" type="warning" @click="cancelFunc">取消</i-Button>
		</div>
	</Modal>

	<Modal id="reportDesingerWin" v-model="reportDesignerModal" title="报表设计" fullscreen="true">
		<iframe id="reportDesignerIframe" style="width:100%;height:100%;"></iframe>
	</Modal>
	<Modal id="reportPreviewWin" v-model="reportPreviewModal" title="报表预览"  fullscreen="true">
		<iframe id="reportPreviewIframe" style="width:100%;height:100%;"></iframe>
	</Modal>
</Layout>
</body>
</html>

report.js

$(function() {
    var height = $(window).height()-160;
    var vue = new Vue({
        el: '#app',
        data: {
            styleSize:constants.styleSize,
            editModal:false,
            editFlag:'add',
            tableHeight:height,
            loading:true,
            reportDesignerModal:false,
            reportPreviewModal:false,
            ureportPre:'fileToDb:',
            ureportSuffix:'.ureport.xml',
            columns :[
                {type:'selection',key: '',width:'60'},
                {title: '报表代码',width:'100',key: 'rptCode'},
                {title: '报表名称',width:'200',key: 'rptName'},
                //{title: '报表文件名',width:'200',key: 'ureportName'},
                {title: '预览地址',width:'280',key: 'rptUrl'},
                {title: '备注',width:'220',key: 'remark'},
                {title: '排序号',width:'80',key: 'sort'},
                {title: '状态',width:'80',key: 'status',render(h,column){
                    if(column.row.status==0){
                        return h('div', {
                            style: {
                                color: 'red'
                            },
                        }, '禁用');
                    }else {
                        return h('div',{style:{color:'green'}},'启用');
                    }
                }},
                {title: '创建日期',width:'160',key: 'createDate',render(h,column){
                    if(column.row.createDate != null && column.row.createDate != ""){
                        return commonFunc.formatDate(column.row.createDate,'date','date');
                    }
                }},
                {title: '操作',width:'200',render(h,column) {
                    var designBtn = h('Button',
                    {
                        props: {
                            type: 'primary',
                            size: 'small'
                        },
                        style: {
                            marginRight: '5px'
                        },
                        on: {
                            click: () => {
                                vue.openDesigner(column.row);
                            }
                        }
                    }, '报表设计');
                    var previewBtn = h('Button',
                    {
                        props: {
                            type: 'info',
                            size: 'small'
                        },
                        style: {
                            marginRight: '5px'
                        },
                        on: {
                            click: () => {
                                vue.openPreview(column.row);
                            }
                        }
                    }, '预览');
                    return h('div',[designBtn,previewBtn]);
                }

                }
            ],
            searchForm:{
                rptName:'',
                rptType:''
            },
            formData: {
                rptCode:'',
                rptName:'',
                //rptType:1,
                rptUrl:'',
                sort:1,
                status:'1',
                remark:''
            },
            editValidate: {

            },
            editRuleValidate: {
                rptCode:{required:true,message:'请输入报表编码',trigger: 'blur'},
                rptName:{required:true,message:'请输入报表名称',trigger: 'blur'},
                //rptUrl:{required:true,message:'请输入报表地址',trigger: 'blur'},
                //ureportName:{required:true,message:'请输入报表文件名称',trigger: 'blur'},
                sort:{required:true,message:'请输入排序号',trigger: 'blur'}
            },
            tableDataList:[],
            dataCount:0,
            // 每页显示多少条
            pageSize:20,
            // 当前页码
            currentPage:1,
            pageOptions:[20,40,60,80,100]
        },
        created:function(){
            this.initPage();
            var _this = this;
        },
        mounted :function(){
            //this.tableHeight = window.innerHeight - this.$refs.table.$el.offsetTop - 160
            var _this =this;
            window.onresize = () => {
                return (() => {
                    var height = $(window).height()-160;
                    _this.tableHeight = height;
                })()
            }
            //关闭弹窗
            $(".ivu-icon-ios-close").on("click",function(){
                _this.queryFunc();
            });
        },
        methods: {
            queryFunc(params){
                var _this = this ;
                _this.loading = true;
                var searchParam = this.searchForm;
                searchParam.currentPage = this.currentPage;
                searchParam.pageSize = this.pageSize;
                if(null != params){
                    for(var i in params){
                        searchParam[i] = params[i];
                    }
                }
                commonFunc.submit("/report/getTableList","post",searchParam,function(data){
                    _this.tableDataList = data.rows;
                    _this.dataCount = data.total;
                    _this.loading = false;
                },function(){});
            },
            initPage(){
                this.currentPage = 1;
                this.queryFunc();
            },
            changepage(index){
                this.pageFunc(index);
            },
            pagesize(index){
                this.pageFunc(index);
            },
            pageFunc(index){
                this.currentPage = index;
                this.queryFunc();
            },
            searchFunc(){
                this.currentPage = 1;
                this.queryFunc();
            },
            selectRow(data, index) {
                this.$refs.table.toggleSelect(index);
            },
            openEdit(flag){
                var _this = this;
                if(flag=="1"){
                    this.formData= {
                        rptCode:'',
                        rptName:'',
                        //ureportName:'',
                        sort:0,
                        status:'1',
                        remark:''
                    };
                    this.editFlag="add";
                    if(null != this.$refs.editValidate) {
                        this.$refs.editValidate.resetFields();
                    }
                }else{
                    var selRecList = this.$refs.table.getSelection();
                    if(selRecList.length==0 || selRecList.length>1){
                        this.$Message.error('请选择一条报表记录');
                        return;
                    }
                    if(null != this.$refs.editValidate) {
                        this.$refs.editValidate.resetFields();
                    }
                    var rec = selRecList[0];
                    this.formData=commonFunc.deepClone(rec);
                    this.formData.sort = rec.sort+'';
                    //this.formData.ureportName = this.formData.ureportName.replace(this.ureportPre,"");
                    //this.formData.ureportName = this.formData.ureportName.replace(this.ureportSuffix,"");
                    this.editFlag="update";

                }
                this.editModal = true;
            },
            submitFunc(){
                var _this = this;
                this.$refs['editValidate'].validate((valid) => {
                    if(valid) {
                        var submitUrl = "/report/save";
                        var param = commonFunc.deepClone(_this.formData);
                        //param.ureportName = _this.ureportPre+param.ureportName+_this.ureportSuffix;
                        commonFunc.submit(submitUrl,"post",param,function(data){
                            _this.$Message.success(data.msg);
                            _this.editModal = false;
                            _this.searchFunc();
                        },function(data){
                            _this.$Message.error(data.msg);
                        },'obj');
                    }
                });
            },
            deleteFunc(){
                var _this = this;
                var selRecList = this.$refs.table.getSelection();
                if(selRecList.length==0 ){
                    this.$Message.error('请选择报表记录');
                    return;
                }
                _this.$Modal.confirm({
                    title: '你确定删除选中的报表记录吗?',
                    okText: '确定',
                    cancelText: '取消',
                    onOk: function () {
                        commonFunc.submit("/report/delete","post",selRecList,function(data){
                            _this.$Message.success(data.msg);
                            _this.searchFunc();
                        },function(data){
                            _this.$Message.error(data.msg);
                        },'obj');
                    }
                });
            },
            cancelFunc(){
                this.editModal = false;
            },
            changeReportType(){

            },
            openDesigner(row){
                var src = "";
                if(null != row.ureportName && '' != row.ureportName){
                    src = "/pro/ureport/designer?_u="+row.ureportName+"&_rId="+row.id;
                }else{
                    src = "/pro/ureport/designer?_rId="+row.id;
                }
                var parent = $("#reportDesignerIframe").parent();
                var iframeHtml = '<iframe id="reportDesignerIframe" src="'+ src +'" style="width:100%;height:100%;"></iframe>';
                parent.html(iframeHtml);
                this.reportDesignerModal = true;
            },
            openPreview(row){
                var src = null;
                if(null != row.rptUrl && "" != row.rptUrl){
                    src = "/pro/"+row.rptUrl+"&reportId="+row.id;
                }else{
                    this.$Message.error("请先设计报表");
                    return;
                }
                var parent = $("#reportPreviewIframe").parent();
                var iframeHtml = '<iframe id="reportPreviewIframe" src="'+ src +'" style="width:100%;height:100%;"></iframe>';
                parent.html(iframeHtml);
                this.reportPreviewModal=true;
            }
        }
    });
});

5、程序的运行

右键点击启动文件(UreportApplication.java),在弹出的菜单中点击Run UreportApplication.java菜单启动系统。
实现Springboot整合UReport2启动成功后,打开浏览器,输入http://localhost:9090/pro/views/report.html即可进入报表管理页面
实现Springboot整合UReport2点击【新增】按钮,弹出新增报表表单,完善表单基本信息,点击【保存】按钮提交新增报表记录。
实现Springboot整合UReport2在报表列表中选中新增的报表记录,点击【报表设计】按钮,进入报表设计器
实现Springboot整合UReport2实现Springboot整合UReport2
到此就可以使用报表设计器设计器根据自己的业务需要进行报表设计了。设计完成后,可以点击预览图标按钮进行报表预览。

如需学习如何设计报表,可以进入这里进行学习,该学习文档可帮助用户设计出更多符合用户业务需求的报表。

到此,Springboot整合UReport2报表分享结束。

如有需要源码进行学习的同学,请点击【这里】文章来源地址https://www.toymoban.com/news/detail-402602.html

到了这里,关于实现Springboot整合UReport2的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 什么是kafka,如何学习kafka,整合SpringBoot

    目录 一、什么是Kafka,如何学习 二、如何整合SpringBoot 三、Kafka的优势   Kafka是一种分布式的消息队列系统,它可以用于处理大量实时数据流 。学习Kafka需要掌握如何安装、配置和运行Kafka集群,以及如何使用Kafka API编写生产者和消费者代码来读写数据。此外,还需要了解Ka

    2024年02月10日
    浏览(40)
  • SpringBoot入门篇3 - 整合junit、整合mybatis、基于SpringBoot实现ssm整合

    目录 Spring整合JUnit  SpringBoot整合JUnit 测试类注解:@SpringBootTest 作用:设置JUnit加载的SpringBoot启动类 ①使用spring initializr初始化项目的时候,添加依赖。  ②设置数据源application.yml 注意: SpringBoot版本低于2.4.3,Mysql驱动版本大于8.0时,需要在url连接串中配置时区。 ③定义数据

    2024年02月10日
    浏览(45)
  • 学完C/C++,再学Python是一种什么体验?

    你好,我是安然无虞。 与C/C++等其他语言不同的是,Python中两个整数相除的结果为浮点数 Python中浮点数在内存中存储的时候遵循IEEE754标准,这套标准在表示浮点数时可能会存在微小的误差,但这个误差在实际开发中不会造成太大的影响 Python中创建变量的语法非常简单,比如

    2024年01月17日
    浏览(72)
  • SpringBoot实现SSMP整合

    1、Spring 整合 JUnit 核心注解有两个: @RunWith(SpringJUnit4ClassRunner.class) 是设置Spring专用于测试的类运行器(Spring程序执行程序有自己的一套独立的运行程序的方式,不能使用JUnit提供的类运行方式) @ContextConfiguration(classes = SpringConfig.class) 是用来设置Spring核心配置文件或配置类的

    2024年02月07日
    浏览(54)
  • SpringBoot整合实现RabbitMQ

    本文大纲 一.RabbitMQ介绍 二.RabbitMQ的工作原理 2.1 RabbitMQ的基本结构 2.2 组成部分说明 2.3 生产者发送消息流程 2.4 消费者接收消息流程 三.SpringBoot 整合实现RabbitMQ 3.1创建mq-rabbitmq-producer(生产者)发送消息 3.1.1pom.xml中添加相关的依赖 3.1.2 配置application.yml 3.1.3 配置RabbitMQ常量类

    2024年02月17日
    浏览(44)
  • 在fpga上开发音视频是一种什么体验?

    今天周末回公司解决了解码播放问题,最近周末也没啥事情,一般周六都会过去公司学习音视频开源项目(过去公司,主要是住的近,所以很方便!),待在家里也是无聊,所以就回去看开源项目,提升自己的视野和水平! 然后这里也分享一些关于音视频开发的一些感悟和日记

    2024年02月08日
    浏览(48)
  • SpringBoot项目(支付宝整合)——springboot整合支付宝沙箱支付 & 从极简实现到IOC改进

    1.springboot整合支付宝沙箱支付; 2.准备工作:沙箱api,内网穿透; 3.极简实现理解支付,异步回调等; 4.按照spring依赖注入的思想改造基础demo; https://gitee.com/pet365/springboot-alipay 支付宝开放平台 (alipay.com) 支付参数 natapp.cn官网 启动和配置 订单ID,需要唯一;价格;物品名称(

    2024年02月11日
    浏览(42)
  • 【SpringBoot】1、SpringBoot整合JWT实现Token验证

    单点登录(Single Sign On), 简称为 SSO , 是目前比较流行的企业业务整合的解决方案之一. SSO的定义:在多个应用系统中, 用户只需要登录一次就可以访问所有相互信任的应用系统, 企业间需要相互授信 众所皆知, HTTP是 无状态的协议 , 这意味着 服务器无法确认用户的信息。 于是乎,

    2024年02月03日
    浏览(75)
  • springboot整合FTP实现文件传输

    实现ftp文件传输的步骤: 1.ftp绑定ip端口登录 2.切换到指定地址 3.文件下载 4.关闭ftp连接 项目中使用的jar包 项目中使用ftp代码: 使用ftp实现上传功能

    2024年02月06日
    浏览(55)
  • SpringBoot整合RestHighLevelClient实现查询操作

    😊 @ 作者: 一恍过去 💖 @ 主页: https://blog.csdn.net/zhuocailing3390 🎊 @ 社区: Java技术栈交流 🎉 @ 主题: SpringBoot整合RestHighLevelClient实现查询操作 ⏱️ @ 创作时间: 2022年08月14日 为了方便查询操作,创建索引叫做: nba ,并且添加数据,http请求如下: 结果: term 查询被用于

    2024年02月04日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包