【业务功能篇20】Springboot java逻辑实现动态行转列需求

news2024/11/26 5:43:07

在此前,我也写过一个行转列的文章,是用存储过程sql处理的一个动态的逻辑

Mysql 存储过程\Mybatis框架call调用 实现动态行转列

那么后面我们同样又接收了业务的一个新需求,针对的是不同的业务数据,做的同样的一个展示数据报表,同样还是产品归属信息表头,拼接查询年月表头列,动态展示多个查询年月的产品产量数据。

  • 这里我们具体分析下业务需求:
  • 首先是一个业务产量表,记录着每个产品编码的产量数,产量时间
  • 另外是一个编码归属表,记录着每个产品编码的归属信息,属于哪个产品,哪个项目等的归属信息 

一般情况下,我们先设计后台表,然后先进行数据的sql处理,那么我们这里就从dao层开始来展开:

参数就是基于前台请求的参数类来传递,比如前端传递查询对象: 开始时间:2022-06,结束时间:2023-06,  只有时间,或者说还带上了一些 产品:产品A等

参数类:

package xxx.vo;

import java.util.List;


@Data
public class ProductionShipmentVO implements Serializable {

	private static final long serialVersionUID = 952332486490268095L;

	private String label;
	private String value;
	private List<String> proList;
	private List<String> itemList;
	private List<String> codeList;
	private List<String> taskNoList;
	private List<String> customerList;
	private List<String> contractList;
	private List<String> subList;
	private String isFlag;
	private String startTime;
	private String endTime;
	private String code;
	private Integer num;
	private String date;
	
	private String product;									//产品名
	private String project;                                 //项目
	private String jobNum;                                 //任务令号
	private String planStarttime;                          //计划开工时间 plan_starttime
	private String planEndtime;                            //计划完工时间 plan_endtime
	private String releaseTime;                            //释放时间 release_time
	private String jobStatus;                              //任务令状态 job_status
	private String itemcode;                                //编码 
	private String transactionQuantity;                    //交易数量 transaction_quantity
	private String transactionTime;                        //交易时间 transaction_time
	private String transactionDate;                        //交易日期 transaction_date
	private String transactionType;                        //交易类型 transaction_type
	private String groupId;                                //组织ID group_id
	private String subinventory;                            //子库
	private String supplierName;                           //供应商名称 supplier_name
	private String itemcodeCout;                           //单板点数 itemcode_cout
	private String processingLocationcode;                 //加工地代码 processing_locationcode
	private String processingLocationname;                 //加工地名称 processing_locationname
	private String productFamily;                          //产品族 product_family
	private String productSmall;                           //产品小类 product_small
	private String productBig;                             //产品大类 product_big
	private String smtLine;                                //SMT线体 smt_line
	private String itemcodeLine;                           //模块线体 itemcode_line
	private String system;                                  //系统源
	private String lastUpdatetime;                         //最后更新时间 last_updatetime
	private String lv1;                                     //l1部门
	private String lv2;                                     //l2部门
	private String lv3;                                     //l3部门
	private String lv4;                                     //l4部门
	private String type;                                    //类型
	private String locator;                                 //货位
	

}

dao层 mapper接口 

public interface IProductionShipmentDao {
    public List<ProductionShipmentVO> getYieldTabelProduct(ProductionShipmentVO productionShipmentVO);
}

dao层 xml文件映射

1. <sql id="yieldTabel"> 标签语句

我们把产量明细表 左联 编码归属表 的结果语句sql抽象出来放到一个sql标签中,作为共用调用的作用,可以结合业务场景判断,如果这个基础连表查询后续会多个地方需要调用,那么代码sql就可以抽出来一个sql标签中,避免重复代码过多

2.<sql id="listWhere"> 标签语句

同理与第一点,目前还是抽象出公共的语句,避免多处的接口sql重复代码过多,这里是一个参数的请求条件,也是极具通用的 多处地方可能会用到,所以就单独定义一个sql标签进行调用

3.<select id="getYieldTabelProduct" resultType="com.xxx.vo.ProductionShipmentVO">

调用标签1 作为临时表,然后根据产品 时间分组,对产量数求和,先得到一个表,每天数据表示: 产品A |  年月|  产量    的一个结果表,当然这里还需要将我们的年月的具体时间给转成列,并且对于的字段内容就是对应产品对应年月的产量。这个操作我们在service层再进行处理

	<sql id="yieldTabel">
		select A.*,IFNULL(B.PRODUCT_SERIES,'') PRODUCT_SERIES,IFNULL(B.MODEL,'') MODEL, IFNULL(B.MASS_DATE,'2500-01-01') MASS_DATE from txny.dwr_quality_xxx_proces_f A
		left join txny.dwr_mt_xxx_report_attr_f B on A.ITEM_CODE = B.PRODUCT_CODE where substr(A.JOB_NUM,3,1)='Z'  
	</sql>
	
	<sql id="listWhere">
		<where>
			<if test='isFlag == "1"'>
				and date_format(TIME_PERIOD,'%Y-%m-%d') > MASS_DATE 	
			</if>
			<if test='isFlag == "0"'>
				and date_format(TIME_PERIOD,'%Y-%m-%d')  <![CDATA[ <= ]]>  MASS_DATE 	
			</if>
			<if test="startTime != null and endTime != null">
				and date_format(TIME_PERIOD,'%Y-%m-%d') between #{startTime} and #{endTime} 	
			</if>
			<if test="proList != null and proList.size > 0">
				and PRODUCT_SERIES in 
				<foreach collection='proList' item="item" open="(" separator="," close=")">
					#{item}
				</foreach>
			</if>
			<if test="itemList != null and itemList.size > 0">
				and MODEL in 
				<foreach collection='itemList' item="item" open="(" separator="," close=")">
					#{item}
				</foreach>
			</if>
			<if test="codeList != null and codeList.size > 0">
				and ITEM_CODE in 
				<foreach collection='codeList' item="item" open="(" separator="," close=")">
					#{item}
				</foreach>
			</if>
		</where>
	</sql>
	
	<select id="getYieldTabelProduct" resultType="com.xxx.vo.ProductionShipmentVO">
		with table1 as (
			<include refid="yieldTabel"/>
		)
		select sum(QUANTITY) num,PRODUCT_SERIES product,date_format(TIME_PERIOD,'%Y-%m') date from  table1 
		<include refid="listWhere"/>
		group by PRODUCT_SERIES,date_format(TIME_PERIOD,'%Y-%m') order by PRODUCT_SERIES,date_format(TIME_PERIOD,'%Y-%m')
	</select>
	

 service层 impl实现类

通过运用java8新特性的 stream流处理数据转换,将dao层的接口方法返回的结果表:产品A |  年月|  产量   转换成一个 List<Map<String,Object>>集合,集合中每个元素Map就是一条横线的数据,比如:产品有多少个,list就有多少个元素,查询时间有多少个月,分别就会展示每个月该产品的产量以及合计产量

从而完成了数据年月的行转列

	@Named
public class ProductionShipmentService implements IProductionShipmentService {
	
	@Inject
	private IProductionShipmentDao iProductionShipmentDao;
	
	@Override
	public List<Map<String, Object>> getYieldTabelProduct(ProductionShipmentVO productionShipmentVO) {

        //取出前端传参的日期 格式为 yyyy-mm-dd 取出 起始年 月  截止年 月
		String[] sArr = productionShipmentVO.getStartTime().split("-");
		String[] eArr = productionShipmentVO.getEndTime().split("-");
		Integer sYear = Integer.valueOf(sArr[0]);
		Integer eYear = Integer.valueOf(eArr[0]);
		Integer sMonth = Integer.valueOf(sArr[1]);
		Integer eMonth = Integer.valueOf(eArr[1]);
		final List<Map<String, Object>> result = new ArrayList<Map<String, Object>>();
		List<ProductionShipmentVO> totaList = iProductionShipmentDao.getYieldTabelProduct(productionShipmentVO);
		totaList.stream().collect(Collectors.groupingBy(ProductionShipmentVO::getProduct,Collectors.collectingAndThen(Collectors.toList(), m ->{
			Map<String, Object> map = new HashMap<String,Object>();
            //遍历从起始到截止的查询年月 转换出区间内的每个年月 比如是23年6-9月 那么
            //date 就是表示 2023-06  2023-07 2023-08 2023-09 四个日期
			for (int i = sYear; i <= eYear; i++) {
				for (int j = 1; j <= 12; j++) {
					if((i== eYear && j> eMonth) || (i== sYear && j < sMonth)){
						continue;
					}
					String date =  String.valueOf(i)+"-"+(j < 10 ? "0"+String.valueOf(j): String.valueOf(j));

//anyMatch 有一个或一个以上的元素满足函数参数计算结果为true那整个方法返回值为true
//判断组内的数据中是否有该日期的数据 有则将其一条数据取出 
					if(m.stream().anyMatch(f->f.getDate().equals(date))){
						ProductionShipmentVO res = m.stream().filter(f->f.getDate().equals(date)).findFirst().get();

                        //map中插入日期 对应的产量  以及产品名称
						map.put(res.getDate(), res.getNum());
						map.put("product", res.getProduct());
					}else {
                        //如果没有该日期数据 就插入产量null
						map.put(date, null);
					}
				}
			}
            
            //每个年月数据取好之后,最后就是插入总累计产量
			Integer sum =  m.stream().mapToInt(ProductionShipmentVO::getNum).sum();
			map.put("num", sum);

            //把该产品的一条记录map插入list集合  依次将不同产品的map遍历插入
			result.add(map);
			return null;
		})));
		
		return result;
	}
}

那么前端框架,通过获取得到返回的数据,根据list中的元素map的键值对数,就能判断表头需要动态加载几列,比如前面展示的 查询3-6个月的数据那么表头展示就是这样:动态赋值获取表列数

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

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

相关文章

【C++11】 initializer_list | 右值引用 | 移动构造 | 完美转发

文章目录 1. 统一的列表初始化{ } 初始化initializer_list 2. 引用左值引用右值引用左值引用与右值引用的相互转换右值引用的真正使用场景移动构造 C98与C11传值返回问题注意事项总结 3. 完美转发 1. 统一的列表初始化 { } 初始化 C11 扩大了括号括起的列表(初始化列表)的使用…

使用PHP导出Excel时处理复杂表头的万能方法

使用PHP导出Excel时&#xff0c;如果是一级表头处理起来很简单&#xff0c;但如果碰到复杂一点的表头&#xff0c;比如二级、三级&#xff0c;甚至更多级别的表头要怎么办呢&#xff1f; 就像下面这个表头&#xff0c;有三层&#xff0c;并且每层都不太规则—— 难道我们每次处…

动态绑定v-model,并解决输入框无法输入和无法双向绑定问题

问题&#xff1a;在界面中想要动态获取数据库中返回的数据&#xff0c;作为下拉的值&#xff0c;每个下拉值中又包含不同的属性信息&#xff0c;给输入框动态绑定v-model&#xff0c;但是绑定成功后输入框内无法输入内容&#xff0c;且没有双向绑定 解决思路&#xff1a;1.双向…

SIM:基于搜索的用户终身行为序列建模

SIM&#xff1a;基于搜索的用户终身行为序列建模 论文&#xff1a;《Search-based User Interest Modeling with Lifelong Sequential Behavior Data for Click-Through Rate Prediction》 下载地址&#xff1a;https://arxiv.org/abs/2006.05639 1、用户行为序列建模回顾 1…

在 AWS 上使用 OpenText 实现业务关键型应用程序的现代化

通过在云中进行信息管理建立持久的竞争优势 创新在云中发生的速度比以往任何时候都快。 企业面临着数字经济快速转型的挑战&#xff0c;充分释放业务信息的能力对于建立持久的竞争优势至关重要。为分散的员工扩大安全可靠的协作范围将是生产力和创新的关键驱动力。 如今大多…

Web UI自动化测试之元素定位

目前&#xff0c;在自动化测试的实际应用中&#xff0c;接口自动化测试被广泛使用&#xff0c;但UI自动化测试也并不会被替代。让我们看看二者的对比&#xff1a; 接口自动化测试是跳过前端界面直接对服务端的测试&#xff0c;执行效率和覆盖率更高&#xff0c;维护成本更低&am…

【EtherCAT】一、入门基础

什么是EtherCAT&#xff1f; 介绍简介特点和优势EtherCAT系统组成主站从站 硬件EtherCAT主站芯片EtherCAT从站芯片 EtherCAT应用层协议 工具软件 介绍 简介 EtherCAT&#xff08;Ethernet Control Automation Technology&#xff09;是一种高性能实时以太网通信协议&#xff…

Ubuntu20.04设置开机自启动脚本

1.建立开机启动服务 sudo vim /lib/systemd/system/rc-local.service 在末尾添加 [Install] WantedBymulti-user.target Aliasrc-local.service2.创建 /etc/rc.local sudo touch /etc/rc.local && sudo chmod 755 /etc/rc.local #!/bin/bash cd /home/docker-data/ss…

前端框架笔记

Vue.js的安装 安装Vue.js有两种方法&#xff1a; &#xff08;1&#xff09;类似于Bootstrap或jQuery&#xff0c;直接通过HTML文件中的标签引用。为了方便开发者使用&#xff0c;Vue.js提供了相关的CDN&#xff0c;通过如下代码可以引用最新版本的Vue.js&#xff1a; <sc…

小黑回到学校,跟小老黑中老黑阿黄一起度过最后在学校的日子的leetcode之旅:3. 无重复字符的最长子串

双指针动态滑动窗口 class Solution:def lengthOfLongestSubstring(self, s: str) -> int:# 字符串长度n len(s)# 双指针left 0right 0# 存储集合set_ set()# 当前子串长度cur_len 0# 结果result 0# 分别遍历每一个右指针while right < n:# 该字符是重复的&#x…

向量相似搜索绕不开的局部敏感哈希

在搜索推荐中&#xff0c;通常使用相似Embedding进行推荐&#xff0c;此时就会有一个问题&#xff1a;如何快速找到与一个Embedding相近的其他Embedding。 如果两个Embedding在同一个向量空间中&#xff0c;我们就可以通过很多种方式&#xff08;内积、余弦、欧氏距离等&#…

python3 爬虫相关学习8:python 的常见报错内容 汇总收集

目录 1 拼写错误 AttributeError: NameError: 等等 2 类型错误 TypeError: 如字符串连接错误 TypeError: can only concatenate str (not “int“) to str 3 意外缩进 IndentationError: unexpected indent 4 找不到对应模块 ModuleNotFoundError: 5 语法错误 Syntax…

【Docker】deepin/centos安装docker

deepin虚拟机和centos服务器安装docker 1.更新软件包 # deepin sudo apt-get update && sudo apt-get upgrade # centos sudo yum update && yum upgrade安装docker之前&#xff0c;先更新一下软件包 mothramothra-PC:~$ sudo apt-get update && sud…

《Lua程序设计》--学习6

日期和时间 第1种表示方式是一个数字&#xff0c;这个数字通常是一个整型数。尽管并非是ISO C所必需的&#xff0c;但在大多数系统中这个数字是自一个被称为纪元&#xff08;epoch&#xff09;的固定日期后至今的秒数。 Lua语言针对日期和时间提供的第2种表示方式是一个表。日…

苹果新专利曝光,用户可通过Apple Watch及MR头显摄像头设置3D虚拟化身

美国专利商标局公布了苹果公司的一项专利申请&#xff0c;涉及提供计算机生成体验的计算机系统&#xff0c;包括但不限于通过显示器提供 VR 和 MR 体验的电子设备。 在一个例子中&#xff0c;苹果展示了 Apple Watch 的未来版本&#xff0c;该版本将允许用户使用 Apple Watch…

ceph安装搭建总结

ceph安装搭建总结 大纲 版本选择集群架构免密登录安装ceph-deploy部署ceph集群安装mgr安装ceph-dashboard 版本选择 ceph 版本信息如下 本次测试使用版本为Octopus 主版本号为15&#xff0c; 并且使用ceph-deploy 2.0.1安装ceph集群 Ceph Octopus 官方文档 相关环境与软件…

找不到msvcp140.dll无法继续执行代码,解决方法

msvcp140.dll电脑文件中的dll文件&#xff0c;即动态链接库文件&#xff0c;若计算机中丢失了某个dll文件&#xff0c;就会导致某些软件和游戏等程序无法正常启动运行&#xff0c;并且导致电脑系统弹窗报错&#xff0c;其安装方法&#xff1a;1、打开浏览器输入“【dll修复程序…

迅为iTOP-RK3588开发板Android12源码定制开发kernel开发

内核版本是 5.10.66 版本&#xff0c;内核默认的配置文件是 3588-android12/kernel-5.10/arch/arm64/configs/rockchip_defconfig 如果我们要使用图形化界面配置内核&#xff0c;操作方法如下所示&#xff1a; 方法一&#xff1a; 1 首先将默认的配置文件 rockchip_defconf…

stable diffusion其他微调方法

textual inversion 发布时间&#xff1a;2022 目标&#xff1a;与DreamBooth一样&#xff0c;都是想要微调模型生成特定目标或风格的图像 方法&#xff1a;通过在vocabulary中添加一个额外的embedding来学习输入的新特征。预训练模型的所有参数都锁住&#xff0c;只有新的emb…

yolo-v4

目录 一&#xff1a;前言 二&#xff1a;一些数据增强的方法 三&#xff1a;自提议 四&#xff1a;dropout 普通的dropout yolov4的dropblock 五&#xff1a;Label smothing 标签平滑 六&#xff1a; GIOU&#xff0c;DIOU&#xff0c;CIOU 七&#xff1a; 对网络结构的…