1、什么是UReport2?

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

2、为啥要整合UReport2?

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

3、实现结果

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

3.1、报表列表

3.2、报表设计器

3.3、学生平均分报表预览

3.4、综合成绩报表预览

3.5、学生成绩单报表预览

4、实现过程

先放一张系统文件结构图

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: 9090servlet:context-path: /pro
spring:http:encoding:force: trueenabled: truecharset: UTF-8datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/ureport?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false&allowMultiQueries=true&nullNamePatternMatchesAll=trueusername: rootpassword:type: com.alibaba.druid.pool.DruidDataSourceresources: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();}/*** 设置数据源代理*/@Beanpublic TransactionAwareDataSourceProxy transactionAwareDataSourceProxy() {TransactionAwareDataSourceProxy transactionAwareDataSourceProxy = new TransactionAwareDataSourceProxy();transactionAwareDataSourceProxy.setTargetDataSource(druidDataSource());return transactionAwareDataSourceProxy;}/*** 设置ActiveRecord*/@Beanpublic 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报表@Beanpublic 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";@Overridepublic 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接口,用户可以为报表设计界面提供接口级别的数据源。
实现当前接口后,在报表设计界面可直接使用当前数据库链接。

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 {@Autowiredprivate DataSource dataSource;@Overridepublic String name() {return "scoreSys";}@Overridepublic 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;@Overridepublic 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("报表文件不存在");}}@Overridepublic 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();}}@Overridepublic 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>(){@Overridepublic int compare(ReportFile f1, ReportFile f2) {return f2.getUpdateDate().compareTo(f1.getUpdateDate());}});return list;}@Overridepublic 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("报表文件不存在");}}@Overridepublic String getName() {return "数据库文件系统";}@Overridepublic boolean disabled() {return false;}@Overridepublic 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报表@Beanpublic 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;}@Overridepublic 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、前端代码


前端使用的是传统的在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 - 160var _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菜单启动系统。
启动成功后,打开浏览器,输入http://localhost:9090/pro/views/report.html即可进入报表管理页面
点击【新增】按钮,弹出新增报表表单,完善表单基本信息,点击【保存】按钮提交新增报表记录。
在报表列表中选中新增的报表记录,点击【报表设计】按钮,进入报表设计器

到此就可以使用报表设计器设计器根据自己的业务需要进行报表设计了。设计完成后,可以点击预览图标按钮进行报表预览。

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

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

实现Springboot整合UReport2相关推荐

  1. SpringBoot整合UReport2(报表开发)(配置类版)

    文章目录 前言 一.UReport2是什么? 二.使用步骤 1.导入POM 2.添加context.properties 3.编写config配置类 4.访问{ip}{端口}/ureport/desi ...

  2. 实现Springboot整合uflo2

    1.什么是UFlo2? UFLO2是一款纯Java流程引擎,它架构于Spring.Hibernate之上,提供诸如并行.动态并行.串行.会签等各种常见及不常见的业务流程流转功能,支持单机或集群部署.它 ...

  3. SpringBoot第九篇: springboot整合Redis

    这篇文章主要介绍springboot整合redis,至于没有接触过redis的同学可以看下这篇文章:5分钟带你入门Redis. 引入依赖: 在pom文件中添加redis依赖: <dependen ...

  4. es springboot 不设置id_原创 | 一篇解决Springboot 整合 Elasticsearch

    ElasticSearch 结合业务的场景,在目前的商品体系需要构建搜索服务,主要是为了提供用户更丰富的检索场景以及高速,实时及性能稳定的搜索服务. ElasticSearch是一个基于Lucene的 ...

  5. springboot整合shiro使用shiro-spring-boot-web-starter

    此文章仅仅说明在springboot整合shiro时的一些坑,并不是教程 增加依赖 <!-- 集成shiro依赖 --> <dependency><groupId> ...

  6. db2 springboot 整合_springboot的yml配置文件通过db2的方式整合mysql的教程

    springboot整合MySQL很简单,多数据源就master,slave就行了,但是在整合DB2就需要另起一行,以下是同一个yml文件 先配置MySQL,代码如下 spring: datasour ...

  7. 九、springboot整合rabbitMQ

    springboot整合rabbitMQ 简介 rabbitMQ是部署最广泛的开源消息代理. rabbitMQ轻量级,易于在内部和云中部署. 它支持多种消息传递协议. RabbitMQ可以部署在分布式 ...

  8. 八、springboot整合Spring Security

    springboot整合Spring Security 简介 Spring Security是一个功能强大且可高度自定义的身份验证和访问控制框架.它是保护基于Spring的应用程序的事实标准. Spr ...

  9. 六、springboot整合swagger

    六.springboot整合swagger 简介 swagger 提供最强大,最易用的工具,以充分利用OpenAPI规范. 官网 : https://swagger.io/ 准备工作 pom.xml ...

  10. SpringBoot整合mybatis、shiro、redis实现基于数据库的细粒度动态权限管理系统实例(转)...

    SpringBoot整合mybatis.shiro.redis实现基于数据库的细粒度动态权限管理系统实例 shiro 目录(?)[+] 前言 表结构 maven配置 配置Druid 配置mybatis ...

最新文章

  1. Vue2.0 探索之路——生命周期和钩子函数的一些理解
  2. 蓝桥杯java第七届决赛第一题--愤怒小鸟
  3. 高效学习,战胜拖延症
  4. Automapper 3.2.1以下方法或属性之间的调用不明确
  5. Java学习笔记day08_day09_对象实例化_private_this
  6. python数组初始化_Python科学计算库Numpy数组的初始化和基本操作
  7. Ubuntu安装anaconda,tensorflow,keras,pytorch
  8. 罗斯蒙特电磁流量计8723说明书_罗斯蒙特电磁流量计8732E型的性能规格
  9. php 生产一维码,透过 PHP 生成 一维码
  10. 做一个管理者/技术负责人的学习之路--001
  11. Nginx+php+mysql超时问题总结
  12. 圆和长方形周长相等谁的面积大_长方形,正方形和圆的面积相等时,谁的周长最大...
  13. 基于Selenium爬取动态网页
  14. 如何在线绘制简单又漂亮的思维导图
  15. ios 拍照人像识别_Google相册为iOS用户添加了人像深度编辑和色彩弹出功能
  16. JQuery学习04篇(层次选择器)
  17. 设置支付后跳转到一个指定的网页,自动成交出售虚拟产品
  18. 北京中医药大学本科毕业论文答辩PPT模板
  19. jmeter4.0 统计结果次数 BeanShell Sampler,Debug Sampler
  20. [Un-Routed Net Constraint Violation] 问题解决

热门文章

  1. 黑龙江省谷歌高清卫星地图下载
  2. 触摸屏驱动开发——转载
  3. 计算机视觉:图像分割算法综述总结
  4. 【python】BMR基础代谢率计算器的设计
  5. 向量叉乘在永磁同步电机电磁转矩计算中的应用
  6. QTTabBar 使用教程:用浏览器的方式管理 Windows 资源管理器
  7. QTTabBar 汉化 给资源管理器添加标签、文件批量重命名依据扩展名选中等功能
  8. 游戏开发新手快速入门指南
  9. 求你们不要再问我录屏软件了,这些电脑、手机录屏软件全给你们!
  10. 白话浅谈——组播那点事