宝诗单证使用手册,并使用抽象和反射做通用抽象类,节省开发成本

news2025/1/4 19:38:24

单证示例

1024最适合写blog了,别说了,别说了,建议变成法定节假日。

宝诗单证的官网:宝诗官网
(@宝诗团队记得给我打广告费)

宝诗单证的使用步骤
使用 抽象类 将获取字段的步骤抽象出来,极大的省略了代码量。节省开发成本。
抽象类在文章最下面,需要的自取。

步骤

1.创建报表
2.配置参数
3.创建数据源对象(javaBean)
4.创建DataSet实现类
5.在com.basksoft.report.core.model.dataset.BeanDataset配置文件中添加DataSet实现类的路径
6.加载自定义bean数据集
7.添加数据库报表记录

创建报表

右键创建一个报表文件

在这里插入图片描述

配置参数

在这里插入图片描述

在这里插入图片描述

这里的参数作用是获取数据使用的参数。

创建数据源对象


需要定义一个空参构造器和一个带一个Boolean参数的构造器,并在这个构造器中给属性赋值默认数据。
Boolean构造器的类型需要是装箱类型(boolean的装箱类型Boolean
添加Boolean构造器的目的是为了获取默认数据的对象。


@Data
public class AccountStatementVo {

    // 结算单位
    private String clientName;

    // 计费日期截至
    private Date reconcDeadline;

    // 折合币金额币制
    private String cyCode;

    // 折合币金额
    private BigDecimal amt;

    // 对账方式
    private String reconcMethod;

    // 说明
    private String actstmDesc;

    // 银行账户
    private String bankacctName;

    // 对账单号
    private String actstmNo;

    public AccountStatementVo() {}

    public AccountStatementVo(Boolean defaultValue) {
        this.clientName = "客户名称";
        this.reconcDeadline = new Date();
        this.cyCode = "CNY";
        this.amt = BigDecimal.ZERO;
        this.reconcMethod = "测试方法";
        this.actstmDesc = "文件备注";
        this.bankacctName = "中国银行";
        this.actstmNo = "HJ23424";
    }
}

创建DataSet实现类

添加一个DateSet类并继承AbstractBeanDataSet抽象类
抽象类需要指定两个泛型,如果返回结果是List类型,第一个泛型类型指定为List<T>,第二个类型指定为T。否则都指定为T

@Slf4j
public class BillDataset extends AbstractBeanDataSet<BillDocVo,BillDocVo> {

    @Override
    protected boolean getReturnDefaultData(BeanContext beanContext) {
        return false;
    }

    @Override
    public Result<BillDocVo> getDocVo(BeanContext beanContext) {
       return null;
    }

    @Override
    protected String name() {
        return "";
    }
}

返回List的接口

public class DemoDataSet extends AbstractBeanDataSet<List<BillDetailVo>,BillDataset> {
    @Override
    protected boolean getReturnDefaultData(BeanContext beanContext) {
        return false;
    }

    @Override
    public Result<List<BillDetailVo>> getDocVo(BeanContext beanContext) {
        return null;
    }

    @Override
    protected String name() {
        return null;
    }
}

重写AbstractBeanDataSet中的三个方法


boolean getReturnDefaultData(BeanContext beanContext)

通过beanContext.getReportParameter("billId")获取在第二步中定义的参数

返回boolean值,是否获取默认数据。

在这个方法中写自己获取默认数据的条件。


	@Override
    protected boolean getReturnDefaultData(BeanContext beanContext) {
        Long billId = ParameterUtils.parseLong(beanContext.getReportParameter("billId"));

        // 如果参数为空或为0,则获取默认数据
        if (Objects.isNull(billId) || Objects.equals(billId, 0L)) {
            return true;
        }
        return false;
    }

Result<BillDocVo> getDocVo(BeanContext beanContext)

获取数据源的方法。

在这个方法中通过http的方式调用fms项目中的接口获取数据源。(后面有必要的话可以在report项目中配置fms的数据源,直接从report项目获取数据)

返回的数据是在第三步中创建的数据源对象

最后在fms写这个获取数据源的接口返回所需要的数据对象


	@Override
    public Result<BillDocVo> getDocVo(BeanContext beanContext) {
        Long billId = ParameterUtils.parseLong(beanContext.getReportParameter("billId"));
        String token = (String) beanContext.getReportParameter("token");

        // 在FmsUrlConstants常量类中配置访问地址
        String url = FmsUrlConstants.api + FmsUrlConstants.BILL_DOC;
        if (!StringUtils.hasText(url)) {
            return null;
        }

        // 使用hutool工具包发送get请求,如果在fms写的是post请求,则发送post请求
        HttpResponse httpResponse = HttpRequest.get(url)
                .form("billId", billId)
                .header("token", token)
                .execute();
        
        // 将返回结果转换类型
        Result<BillDocVo> result = JSONUtil.toBean(httpResponse.body(), new TypeReference<Result<BillDocVo>>() { }, false);

        return result;
    }
String name()

返回数据源对象名称,在报表中显示的名称在这个方法中定义

	@Override
    protected String name() {
        return "账单";
    }

添加dataSet类配置

在这里插入图片描述

加载自定义bean数据集

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

可以添加多个数据集

添加数据库报表记录

uni_acv_doc(单证主表)

uni_acv_docmodel(单证明细模板表)

一对多的关系

在这两张表中添加报表数据

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

添加单证主表(uni_acv_doc),按各自的需求进行设置字段。
doccode,tab_code需要唯一

添加单证明细模板表(uni_acv_docmodel)记录时。

docid设置为单证主表(uni_acv_doc)的id,

file_idsys_file_id设置为模板的fileId,

is_default设置为1

其他数据按需求的要求设置

AbstractBeanDataSet抽象类

这个抽象类的功能:
如果是获取默认数据,调用Boolean构造器创建一个带有默认数据的对象。
否则获取从fms获取的数据。
将数据对象的所有字段封装成一个List<Map<String,Object>>对象。
package com.yunwuyun.easy.baskreport.dataset;

import com.basksoft.report.core.model.dataset.BeanDataset;
import com.basksoft.report.core.model.dataset.impl.BeanContext;
import com.basksoft.report.core.model.dataset.impl.Field;
import com.basksoft.report.core.model.dataset.impl.FieldType;
import com.yunwuyun.easy.baskreport.common.Result;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;

/**
 * 单证抽象类
 * @param <T>
 */
@Slf4j
public abstract class AbstractBeanDataSet<T,E> extends BeanDataset {

    protected Class<E> clazz;

    public AbstractBeanDataSet() {
        Type genericSuperclass = getClass().getGenericSuperclass();

        if (genericSuperclass instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
            Type[] typeArguments = parameterizedType.getActualTypeArguments();

            if (typeArguments.length > 0) {
                Type typeArgument = typeArguments[1];

                if (typeArgument instanceof Class) {
                    this.clazz = (Class<E>) typeArgument;
                }
            }
        }
    }

    @SneakyThrows
    @Override
    public List<?> getData(BeanContext beanContext) {

        boolean returnDefaultData = false;
        returnDefaultData = this.getReturnDefaultData(beanContext);
        if(returnDefaultData) {
            return getDefaultData();
        }

        Result<T> result = this.getDocVo(beanContext);
        if (result == null || result.getCode() != 200) {
            return Collections.emptyList();
        }

        T t = result.getResult();

        List<Map<String,Object>> datas = getDatas(t);

        return datas;
    }

    protected abstract boolean getReturnDefaultData(BeanContext beanContext);

    private List<Map<String, Object>> getDatas(T t) {
        List<Map<String,Object>> datas = new ArrayList<>();

        if(isListType()) {
            List<E> list = (List<E>) t;
            for (E obj: list) {
                Map<String, Object> dataMap = getDataMap(obj);
                datas.add(dataMap);
            }
        } else {
            E obj = (E) t;
            Map<String, Object> data = getDataMap(obj);
            datas.add(data);
        }

        return datas;
    }


    /**
     * 获取所有字段属性的map
     * @param t
     * @return
     */
    private Map<String, Object> getDataMap(E t) {

        List<Field> fields = this.getFields();
        Map<String, Object> data = new HashMap<>();

        for (Field field : fields) {
            String fieldName = field.getName();

            try {
                java.lang.reflect.Field fieldVo = this.clazz.getDeclaredField(fieldName);
                fieldVo.setAccessible(true);

                data.put(field.getName(), fieldVo.get(t));
            } catch (Exception e) {
                // 忽略异常,继续处理下一个字段
                log.error("Dataset error,fieldName:{}, message:{}", fieldName, e.getMessage());
            }
        }

        return data;
    }

    /**
     * 泛型类型是否为列表
     * @return
     */
    private Boolean isListType() {
        Type genericSuperclass = getClass().getGenericSuperclass();

        if (genericSuperclass instanceof ParameterizedType) {

            ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;

            Type[] typeArguments = parameterizedType.getActualTypeArguments();

            if (typeArguments.length > 0) {
                Type typeArgument = typeArguments[0];

                if (typeArgument instanceof ParameterizedType) {
                    return true;
                } else if (typeArgument instanceof Class) {
                    return false;
                }
            }
        }

        return false;
    }

    /**
     * 通过id获取数据
     * @param beanContext
     * @return
     */
    public abstract Result<T> getDocVo(BeanContext beanContext);

    @Override
    public List<String> getDependCells() {
        List<String> list = new ArrayList<>();
        return list;
    }

    @Override
    protected abstract String name();

    @Override
    public List<Field> getFields() {
        List<Field> fields = new ArrayList<>();

        java.lang.reflect.Field[] allFields = this.clazz.getDeclaredFields();
        for (java.lang.reflect.Field fieldVo : allFields) {
            Class<?> type = fieldVo.getType();
            String typeName = type.getSimpleName();
            Field field = new Field(fieldVo.getName(), FieldType.valueOf(typeName));
            fields.add(field);
        }

        return fields;
    }



    /**
     * 获取默认数据
     * @return 默认数据
     */
    private List<Map<String, Object>> getDefaultData() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException, InstantiationException {
        Constructor<E> constructor = this.clazz.getDeclaredConstructor(Boolean.class);
        E e = constructor.newInstance(true);

        List<Map<String,Object>> datas = new ArrayList<>();
        Map<String,Object> data = new HashMap<>();

        java.lang.reflect.Field[] allFields = this.clazz.getDeclaredFields();

        for (java.lang.reflect.Field field : allFields) {
            field.setAccessible(true);

            data.put(field.getName(), field.get(e));
        }
        datas.add(data);
        return datas;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1128710.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

苏州德创机器视觉工程师工作怎么样?

每一家公司都有自身特点&#xff0c;同时也每一家都有自身的bug。 苏州德创作为美国康耐视Cognex产品在华东最大的代理商&#xff0c;也是康耐视外包团队。那么苏州德创有哪些业务构成&#xff0c;业务的构成也是其招聘的主要人员的方向。 设备视觉供应商&#xff0c;如卓越&…

【Linux进阶之路】进程(中)—— 进程地址空间

文章目录 一、 进程地址空间1.概念引入2.基本概念3.深入概念3.1 初识信息交互3.2 区域划分3.3 进程地址空间3.4 再识页表缺页中断进程挂起 总结 一、 进程地址空间 1.概念引入 指针指向的地址是内存中的地址吗&#xff1f;下面我们用一个实验来证明一下。 先来写程序看一下程…

2010-2021年北大中国商业银行数字化转型指数数据(第三期)

2010-2021年北大中国商业银行数字化转型指数数据&#xff08;第三期&#xff09; 1、时间&#xff1a;2010-2021年 2、指标&#xff1a;银行名称、银行类型、年份、战略数字化、业务数字化、管理数字化、数字化总指数 3、来源&#xff1a;北大数字金融研究中心 4、数据说明…

中文大语言和多模态模型测评

Notion – The all-in-one workspace for your notes, tasks, wikis, and databases.A new tool that blends your everyday work apps into one. Its the all-in-one workspace for you and your teamhttps://yaofu.notion.site/C-Eval-6b79edd91b454e3d8ea41c59ea2af873排行榜…

Appium移动端自动测试框架,如何入门?

Appium是一个开源跨平台移动应用自动化测试框架。 既然只是想学习下Appium如何入门&#xff0c;那么我们就直奔主题。文章结构如下&#xff1a; 1、为什么要使用Appium&#xff1f; 2、如何搭建Appium工具环境?(超详细&#xff09; 3、通过demo演示Appium的使用 4、Appium如何…

【Unity程序技巧】异步保险箱管理器

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;Uni…

Servlet的两种部署方法

Servlet是实现动态页面的技术&#xff0c;是tomcat给Java提供的原生的进行web开发的api 第一个Servlet程序 写一个servlet程序&#xff0c;部署到tomcat上&#xff0c;通过浏览器访问&#xff0c;得到hello world字符串 1.创建项目 此处要创建的是maven项目 maven&#xf…

重磅官宣 | 第二届 OpenHarmony 技术峰会,邀您共启智联未来

"下一个技术未来在哪里&#xff1f;" 11 月 4 日 技术大咖齐聚北京为你解答 一场主论坛八大开源领域分论坛 探究终端操作系统十大技术挑战方向 与全球开源操作系统技术领袖、实践专家、一线导师携手 共绘 OpenHarmony 开源生态璀璨星图&#xff01; 点击链接&…

解决:无法打开Zotero数据库

在实验室电脑上面下载了Zotero和坚果云&#xff0c;一系列操作下来&#xff0c;我的笔记本上无法打开Zotero数据库了&#xff01;显示下面的界面&#xff1a; 于是网上找解决方法 1.https://www.zhihu.com/question/519740718 2.https://devpress.csdn.net/awstech/64e7311b…

Vue ref属性

Vue中的ref属性可以用来对HTML元素或者是对组件进行唯一标识。 一、设置ref属性 只需要在元素或者是组件后跟上如下语法即可&#xff1a; ref"标识名" 二、获取元素或对象 我们可以用如下方法获取我们设置ref的元素或组件&#xff1a; this.$refs.标识名 第一个输…

对批改网禁止复制粘贴问题的破解

首先进入到作文页面 右击鼠标显示弹窗选择检查 点击左上角图标 之后鼠标点击作文框&#xff0c;检查框会跳转到文本 点击鼠标右键选择文本&#xff0c;并选择编辑为HTML 在文本内写入内容点击空白处退出即可

JAVA设计模式全解(独家AI解析)

JAVA设计模式全解&#xff08;独家AI解析&#xff09; 一、JAVA介绍二、JAVA设计模式六大原则三、JAVA设计模式介绍四、JAVA设计模式详解4.1 单例模式4.1.1 懒汉式&#xff08;Lazy Initialization&#xff09;4.1.2 饿汉式&#xff08;Lazy Initialization&#xff09; 4.2 代…

Java中获取异常栈中的底层异常信息-分析Java异常栈

Java中获取异常栈中的底层异常信息-分析Java异常栈 首先&#xff0c;我们准备好一个多层异常栈堆叠的示例代码&#xff1a; public class ExceptionUtils {public static void main(String[] args) {try {buildMultiLayerExceptionStack();} catch (Exception e) {e.printSt…

RHCE---shell 条件测试

文章目录 目录 文章目录 前言 一.条件测试 概述&#xff1a; 文件测试 整数测试&#xff1a; 总结 前言 当我们完成某一命令的编写时&#xff0c;除了观察输出的内容&#xff0c;我们又如何得知命令是否执行成功呢&#xff1f; 这里&#xff0c;我们需要用到条件测试 一.条…

SEO内链优化的8个终极策略

网站SEO优化主要分为两个大类&#xff0c;一类是站外优化&#xff0c;另一类是站内优化。站内优化的内链建设优化是SEO优化工作的重中之重&#xff0c;可以视为网站内部的内功修炼之一。本文将介绍什么是内链以及如何通过内链优化来提升SEO排名。 什么是内链&#xff1f; 内链…

ArrayList与List的层级关系及ArrayList解析

List与ArrayList的关系 List List是一个接口&#xff0c;不能直接实例化。如果要使用必须去实例化List的实现类——ArrayList和LinkedList站在数据结构的角度看&#xff0c;List就是一个线性表。常见的线性表&#xff1a;顺序表、链表、栈、队列等 线性表 线性表是n个具有相…

解决SpringBoot整合Activiti引用JPA:缺少javax.persistence.EntityManagerFactory

系统接入工作流Activiti的时候&#xff0c;发现activiti初始化表&#xff0c;操作数据库使用的是jpa,我们这里解决办法就是引入spring-data-jpa-starter自动配置EntityManagerFactory。 首先把工作流sql文件执行 基础依赖jar引入 这里忽略Activiti的基础依赖&#xff0c;以下…

什么是云原生?土生土长?

“云原生”&#xff08;Cloud Native&#xff09;是一种构建和运行应用程序的方法&#xff0c;这种方法充分利用了云计算的优势。云原生应用程序是为云环境设计的&#xff0c;通常是在容器中运行&#xff0c;并被设计为在微服务架构中运行&#xff0c;这使得它们能够快速扩展和…

进公司第二天:绿盾+TFS拉取代码

1.配置绿盾 绿盾&#xff1a;一种安全软件 遇到的问题 TFS端口号&#xff1a;192.168.3.231 服务端口号&#xff1a;默认&#xff08;千万别瞎写啥的&#xff09; 2.配置TFS拉取代码 TFS利用插件 &#xff0c;输入公司给你的信息你的各种信息 拉取代码就行。 3.查看代码 —…

系统架构师备考倒计时12天(每日知识点)

1. 基于架构的软件设计&#xff08;ABSD) (ABSD方法是架构驱动&#xff0c;即强调由业务【商业】、质量和功能需求的组合驱动架构设计。ABSD方法有三个基础。第一个基础是功能的分解。在功能分解中&#xff0c;ABSD方法使用已有的基于模块的内聚和耦合技术&#xff1b;第二个基…