1. ¿Qué es UReport2?
UReport2 es un motor de informes de Java puro de alto rendimiento basado en Spring, que puede generar informes de estilo chino arbitrariamente complejos mediante la iteración de celdas. Este informe es un motor de informes chino de código abierto basado en el protocolo Apache-2.0 desarrollado por Shanghai Ruidao Information Technology Co., Ltd. (haga clic para ingresar a la página de código fuente de gitee ). El motor de informes actual no ha sido mantenido por el autor por razones desconocidas, pero los documentos anteriores son relativamente detallados ( haga clic para ingresar a la página del documento ).
2. ¿Por qué se debe integrar UReport2?
El autor también está interesado en el principio de implementación del motor de informes, así que descargué el código fuente y ajusté y optimicé algunos detalles. Se recomienda que los estudiantes que estén interesados en el motor de informes puedan descargar el código fuente para el ajuste personalizado y la optimización de la investigación. Al mismo tiempo, se implementa una demostración de informe simple usando springboot+mysql+jfinal+iview+jquery. Aquí hay un registro de estudio simple y compártalo con todos los estudiantes. Espero poder continuar mejorando y mejorando mi capacidad técnica junto con tú.
3. Date cuenta del resultado
Primera parte de la captura de pantalla para mostrar los resultados de la implementación.
3.1 Lista de informes
3.2 Diseñador de informes
3.3 Vista previa del informe de puntaje promedio del estudiante
3.4 Vista previa del informe de puntuación integral
3.5 Vista previa del informe de expediente académico del estudiante
4. Proceso de implementación
Primero ponga un diagrama de estructura de archivos del sistema
4.1 Crear un proyecto springboot
Asigne un nombre al proyecto ureport y agregue las dependencias maven requeridas en el archivo pom.xml
<?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>
Aquí, el paquete jar de ureport2 depende de que el autor vuelva a editar y compilar el código fuente para generarlo. Si utiliza directamente el paquete jar descargado oficial de UReport2, es posible que esta demostración no pueda ejecutarse. Si el usuario necesita la versión actual paquete jar, póngase en contacto con el autor.
4.2 Agregar información de configuración de yml
aplicación.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 Agregue el archivo de configuración de Spring context.xml que hace referencia a UReport2
El autor se coloca en el directorio 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, agregar archivo de propiedades
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
El motor de informes de UReport2 utiliza el sistema de archivos de forma predeterminada, donde ureport.fileStoreDir es la ruta física del archivo de informe generado por la configuración, ureport.disableFileProvider define si deshabilitar el sistema de archivos del informe actual, verdadero está deshabilitado, falso está habilitado . La idea actual del autor es combinar el sistema de archivos con la base de datos mysql para la administración, por lo que la configuración está deshabilitada.
4.4.2, ureport.fileToDbStoreDir
ureport.fileToDbStoreDir es una forma de combinar el sistema de archivos mysql+ ampliado por el autor. Este parámetro también es la ruta de configuración. Si la configuración de ureport.disableFileDbProvider está deshabilitada
4.4.3, ureport.contextPath
El parámetro ureport.contextPath es un parámetro agregado por el autor.Este parámetro puede ayudar a los usuarios a darse cuenta de la situación en la que la dirección de ruta de recursos predeterminada del informe no coincide cuando el sistema de antecedentes comerciales está separado del front-end. La demostración actual no utiliza la separación front-end y back-end, por lo que este parámetro se puede configurar o no. Si no se configura, el valor predeterminado es la ruta de contexto correspondiente al archivo application.yaml.
4.5, código fuente 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;
}
}
Esta clase se usa principalmente para inicializar el enlace de la base de datos y Jfinal de acuerdo con el archivo de configuración.
Si los usuarios no saben mucho sobre JFinal, pueden aprender por sí mismos en Baidu. JFinal es un marco de desarrollo web extremadamente rápido basado en el lenguaje Java. Sus principales objetivos de diseño son un desarrollo rápido, menos código, fácil aprendizaje, funciones potentes, ligero, de fácil expansión y tranquilo. La demostración actual utiliza principalmente las funciones de la base de datos de Jfinal.
4.5.2, clase de modelo Report.java,BaseReport.java,_MappingKit.java
El modelo es la clase de objeto de entidad de jfinal, que se utiliza principalmente para la relación de mapeo orm con la tabla de datos.
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, Clase de controlador
ReportController.java, clase de controlador de informe
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, Clase de servicio 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, Clase de proveedor
La clase de proveedor es una clase de interfaz abierta por UReport para que la implemente el sistema comercial. Los usuarios pueden implementar diferentes clases de proveedor al mismo tiempo para satisfacer las necesidades comerciales del usuario desde el nivel del código.
DsProvider.java : a través de la interfaz BuildingDatasource, los usuarios pueden proporcionar fuentes de datos a nivel de interfaz para la interfaz de diseño de informes.
Una vez que se implementa la interfaz actual, el enlace de la base de datos actual se puede usar directamente en la interfaz de diseño de informes.
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 : al implementar la interfaz ReportProvider, los usuarios pueden agregar métodos de almacenamiento de informes que satisfagan sus propias necesidades (UReport2 mismo ha implementado el método de almacenamiento de informes de almacenamiento de sistema de archivos puro). Al implementar la interfaz actual, el autor se da cuenta del uso de la base de datos para almacenar la información básica del informe, el sistema de archivos para almacenar el archivo del informe y la base de datos para registrar la dirección del informe. Es decir, puede usar tablas de datos mysql para administrar archivos de informes.
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;
}
}
método loadReport : encuentre el archivo de informe de la base de datos a través de los parámetros proporcionados, genere un objeto InputStream de acuerdo con la dirección de la dirección y el diseñador de informes representa el archivo de informe que se está diseñando de acuerdo con el objeto InputStream devuelto
Método deleteReport : Proporcione los parámetros dados para eliminar el archivo de informe. La operación de este método es eliminar primero los registros en la base de datos correspondiente y luego eliminar el archivo de informe físico correspondiente.
Método getReportFiles : carga todos los registros de informes de datos actuales.
Método saveReport : encuentre el registro del informe a través de los parámetros dados, actualice la dirección de vista previa del informe y guarde el archivo del informe físico.
UreportContextProvider.java es una interfaz extendida por el autor para cambiar el parámetro contextPath del informe. Su función es la misma que la del parámetro ureport.contextPath en el archivo config.properties. No se usa aquí, por lo que no se presentará.
4.5.5, clase de inicio springboot
UreportApplication.java
@ImportResource("classpath:config/context.xml") no se puede perder, es el archivo de configuración de primavera que presenta ureport2.
El método buildUReprtServlet es registrar UReport como un Servlet, que es el archivo de entrada para usar UReport, que no puede faltar.
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, otras clases
Result.java : devuelve la clase Dto de front-end
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 : Devuelve la clase de enumeración de estado de front-end
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;
}
}
Clase de herramienta Tool.java (no utilizada), RecordModelGenerator.java genera automáticamente la clase de archivo de entidad Jfinal, para ahorrar espacio, no se publicará aquí
4.6 Código de front-end
El front-end se realiza utilizando la forma tradicional de introducir archivos de biblioteca js en archivos html. La tecnología utilizada es jquery, iview. Los archivos front-end incluyen report.html y report.js, y los otros son archivos de biblioteca de clases.
informe.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>
informe.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. El funcionamiento del programa
Haga clic con el botón derecho en el archivo de inicio (UreportApplication.java) y haga clic en el menú Ejecutar UreportApplication.java en el menú emergente para iniciar el sistema.
Después de que el inicio sea exitoso, abra el navegador, ingrese http://localhost:9090/pro/views/report.html para ingresar a la página de administración de informes, haga clic en el botón [Agregar], aparecerá un nuevo formulario de informe, complete
el información básica del formulario, haga clic en el botón [Guardar] para enviar el nuevo registro del informe.
Seleccione el registro de informe recién agregado en la lista de informes y haga clic en el botón [Diseño de informe] para ingresar al diseñador de informes. En
este punto, puede usar el diseñador de informes para diseñar informes de acuerdo con sus necesidades comerciales. Una vez completado el diseño, puede hacer clic en el botón del icono de vista previa para obtener una vista previa del informe.
Si desea aprender a diseñar informes, puede ingresar aquí para aprender.Este documento de aprendizaje puede ayudar a los usuarios a diseñar más informes que satisfagan sus necesidades comerciales.
En este punto, el uso compartido del informe UReport2 integrado de Springboot ha terminado.
Si necesita el código fuente para aprender, haga clic [aquí]