# data_reports
**Repository Path**: kennyhu/data_reports
## Basic Information
- **Project Name**: data_reports
- **Description**: 轻量级的报表插件,可随意插拔
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 1
- **Forks**: 0
- **Created**: 2018-03-15
- **Last Updated**: 2024-10-11
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
一、前言
随着业务的飞速发展和各种业务数据库的扩展,很多场景需要用到导出线上数据进行报表分析,以便及时对业务做出核实的调整
二、各种导出工具
1、SQL工具导出,比如navicat、sqlyog等
缺点:比较原始的报表导出工具
1.1 一般需要运维或者DB开发在线上SQL运维工具执行sql导出数据,还需要应用开发人员提供相应的sql,对于业务和开发来说操作比较繁琐
1.2 查询大量数据时对业务数据库压力较大,容易造成数据库宕机
1.3 无法跨数据服务器执行SQL,整合报表数据比较困难
1.4 无法提供直观的可视化分析,比如web在线数据分析
2、通过写业务代码定制化报表
缺点:相比方式一,对业务来说比较方便了,可以随时在线导出报表,但是其他问题还是无法解决
1.1 查询大量数据时对业务数据库压力较大,容易造成数据库宕机
1.2 无法跨数据服务器执行SQL,整合报表数据比较困难
1.3 数据库结构改动需要重新开发上线,很难做到动态定制化报表
3、通过数据平台
缺点:相比方式一和方式二,解决了几乎大部分问题,同步各业务数据到数据平台的数据库,可以定制各种各种的数据报表,但是对于各自业务数据库来说,比较重量级,而且数据平台的技术开发需要对业务数据库模型和相关的业务比较熟悉才行
三、轻量级数据报表插件开发


1、V1.0 版本需求:
1.1 支持可插拔,即插即用模式,工作原理仿照阿里巴巴的druid数据源
1.2 支持自动建配置表
1.3 支持动态切换数据源,可动态配置执行sql的数据源
1.4 支持供外部接口调用
1.5 支持百万级以上大批量Excel数据导出
2、工作原理
1.1 可插拔功能实现,使用原始的Servlet,通过在web.xml配置请求Servlet
```
report
com.data.reports.support.SqlReportServlet
report
/report/*
```
1.2 支持自动建配置表功能实现,使用原始的jdbc建表
SQL数据源数据库表设计
```
CREATE TABLE `sql_db_config` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`config_code` varchar(100) DEFAULT NULL COMMENT '唯一编码',
`config_name` varchar(100) DEFAULT NULL COMMENT '数据源名称',
`url` varchar(255) DEFAULT NULL COMMENT '数据源url',
`username` varchar(100) DEFAULT NULL COMMENT '用户名',
`password` varchar(80) DEFAULT NULL COMMENT '密码',
`status` int(2) DEFAULT '0' COMMENT '状态',
`create_user` varchar(80) DEFAULT NULL COMMENT '创建人',
`create_time` bigint(20) DEFAULT NULL COMMENT '创建时间',
`modify_user` varchar(80) DEFAULT NULL COMMENT '更新人',
`modify_time` bigint(20) DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='数据源配置';
```
SQL配置表数据库表设计
```
CREATE TABLE `sql_reports_config` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`db_code` varchar(100) DEFAULT NULL,
`config_code` varchar(100) DEFAULT NULL,
`report_name` varchar(100) DEFAULT NULL COMMENT '报表名称',
`report_desc` varchar(255) DEFAULT NULL COMMENT '报表描述',
`sql_content` text COMMENT 'SQL执行内容',
`report_type` varchar(40) DEFAULT NULL COMMENT '报表类型',
`status` int(2) DEFAULT '0' COMMENT '状态',
`create_user` varchar(80) DEFAULT NULL COMMENT '创建人',
`create_time` bigint(20) DEFAULT NULL COMMENT '创建时间',
`modify_user` varchar(80) DEFAULT NULL COMMENT '更新人',
`modify_time` bigint(20) DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='报表配置';
```
JDBC代码实现
```
package com.data.reports.manager;
import com.data.reports.manager.database.DataSourceContextHolder;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementCallback;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.core.PreparedStatementSetter;
import org.springframework.jdbc.core.ResultSetExtractor;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.jdbc.support.rowset.SqlRowSet;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* 报表增删改查实现
* @author Hurricane.Hu
* @version V1.0
* @Title: JdbcSqlConfigService.java
* @Package com.data.com.data.reports.manager
* @Description
* @date 2018 03-12 16:38.
*/
public class JdbcSqlConfigService implements SqlConfigService {
private final static Logger LOGGER= LoggerFactory.getLogger(JdbcSqlConfigService.class);
private static String TABLE_NAME ="SQL_REPORTS_CONFIG";
private static final String ADD_CONFIG ="INSERT INTO "+ TABLE_NAME +" (db_code,config_code,report_name,report_desc,sql_content,report_type,status,create_user,create_time)" +
" VALUES(?, ?, ? , ? , ?, ?, ?, ?, ?, ROUND(UNIX_TIMESTAMP(NOW(4))*1000))";
private static final String DELETE_CONFIG ="DELETE FROM "+ TABLE_NAME +" WHERE id=?";
private static final String GET_BY_ID ="SELECT * FROM "+ TABLE_NAME + " WHERE id=?";
private static final String GET_BY_CODE ="SELECT * FROM "+ TABLE_NAME + " WHERE config_code=?";
private static final String CREATE_TABLE ="CREATE TABLE IF NOT EXISTS "+ TABLE_NAME +" (" +
"`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',"+
"`db_code` varchar(100) DEFAULT NULL COMMENT '数据源唯一编码'," +
"`config_code` varchar(100) DEFAULT NULL COMMENT '唯一编码'," +
"`report_name` varchar(100) DEFAULT NULL COMMENT '报表名称'," +
"`report_desc` varchar(255) DEFAULT NULL COMMENT '报表描述'," +
"`sql_content` text DEFAULT NULL COMMENT 'SQL执行内容'," +
"`report_type` varchar(40) DEFAULT NULL COMMENT '报表类型'," +
"`status` int(2) DEFAULT 0 COMMENT '状态'," +
"`create_user` varchar(80) DEFAULT NULL COMMENT '创建人'," +
"`create_time` bigint(20) DEFAULT NULL COMMENT '创建时间'," +
"`modify_user` varchar(80) DEFAULT NULL COMMENT '更新人'," +
"`modify_time` bigint(20) DEFAULT NULL COMMENT '更新时间'," +
"PRIMARY KEY (`id`)" +
") ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='报表配置'";
private static final String CHECK_EXISTS ="SHOW TABLES LIKE '"+ TABLE_NAME +"'";
private static volatile boolean isTableExists;
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
private static String getUpdateSqlAndArgs(SqlReportConfig config,List