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

在此前,我也写过一个行转列的文章,是用存储过程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个月的数据那么表头展示就是这样:动态赋值获取表列数

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

VueX使用简明笔记

1、作用&#xff1a; vuex是使用vue中必不可少的一部分&#xff0c;基于父子、兄弟组件&#xff0c;我们传值可能会很方便&#xff0c;但是如果是没有关联的组件之间要使用同一组数据&#xff0c;就显得很无能为力&#xff0c;那么vuex就很好的解决了我们这种问题&#xff0c;…

MySQL数据库 – node使用

1 MySQL查询对象 2 MySQL查询数组 3 mysql2库介绍使用 4 mysql2预处理语句 5 mysql2连接池使用 6 mysql2的Promi 这里仅说明如何使用服务器连接数据库并进行操作。 预处理语句就是可以输入变量的语句&#xff08;表现形式是有符号&#xff1a;&#xff1f;&#xff09;。需…

portraiture宿主插件最新v4中文版本下载及使用教程

自拍怎么可以不修图呢&#xff1f;如果要修图的话&#xff0c;磨皮就是其中非常重要的一环。皮肤看起来细腻光滑了&#xff0c;整个人的颜值都会瞬间拉高。下面就让我们介绍一下磨皮用什么软件好用&#xff0c;什么软件可以手动磨皮的相关内容。portraiture是ps人像修图中常用的…

为何唐宋诗词鼎盛,而到了明清变成了小说

我国是一个历史悠久的国家&#xff0c;在漫长的历史长河中&#xff0c;随着朝代的更替&#xff0c;很多事也发生了有趣的变化。 例如唐宋时期盛行的是诗词&#xff0c;而到了明清时代&#xff0c;小说又开始盛行了起来&#xff0c;那么造成这种文风改变的原因是什么呢&#xf…

Java版本spring cloud 工程管理系统软件 系统源代码 自主研发,工程行业适用

Java版工程项目管理系统 Spring CloudSpring BootMybatisVueElementUI前后端分离 功能清单如下&#xff1a; 首页 工作台&#xff1a;待办工作、消息通知、预警信息&#xff0c;点击可进入相应的列表 项目进度图表&#xff1a;选择&#xff08;总体或单个&#xff09;项目显示…

实战案例|黑灰产肆虐,腾讯ACE一键打造清朗游戏世界

随着游戏行业的快速发展&#xff0c;相关黑色产业链的问题日益严重&#xff0c;各种外挂、违规内容、非法交易现象的出现破坏着游戏的生态&#xff0c;为行业带来诸多安全挑战&#xff0c;也影响着玩家们的游戏体验。越来越多游戏厂商开始重视游戏安全问题&#xff0c;并探索全…

华为OD机试真题 JavaScript 实现【最远足迹】【2022Q4 100分】,附详细解题思路

一、题目描述 某探险队负责对地下洞穴进行探险。探险队成员在进行探险任务时&#xff0c;随身携带的记录器会不定期地记录自身的坐标&#xff0c;但在记录的间隙中也会记录其他数据。探索工作结束后&#xff0c;探险队需要获取到某成员在探险过程中相对于探险队总部的最远的足…

Mujoco210 Ubuntu 22.04配置安装(一)

目录 .1 下载 1.1 解压 1.2 许可问题 1.3 环境配置 1.4 测试mujoco .2 安装mujoco-py 2.1 conda激活虚拟环境\或新创建一个环境 2.2 下载mujoco-py ​编辑 2.3 配置环境变量 2.4 测试mujoco-py 2.5 测试时的一些报错处理 2.5.0 command /usr/bin/gcc failed with…

读写ini配置文件(C++)

文章目录 1、为什么要使用ini或者其它(例如xml,json)配置文件&#xff1f;2、ini文件基本介绍3、ini配置文件的格式4、C读写ini配置文件5、 代码示例6、 配置文件的解析库 文章转载于&#xff1a;https://blog.csdn.net/weixin_44517656/article/details/109014236 1、为什么要…

docker harbor私有仓库部署

docker harbor私有仓库部署 docker system prune -a 删除停掉的服务&#xff0c;自定义网络等。 docker 私有仓库 docker配置文件 vim /etc/docker.daemon.josn { “insecury-registries”: ["192.168.232.10:5000]&#xff0c;#指定私有仓库 } docker pull/push 19…

防雪崩利器之Hystrix

Hystrix作为一个容错组件&#xff0c;本文从它的作用、熔断设计、工作流程和应用方面一一道来&#xff0c;帮助大家了解如何使用。 1、什么是灾难性雪崩效应 要讲Hystrix&#xff0c;我们就要讲一种场景&#xff0c;在微服务架构中&#xff0c;如果底层服务出现故障&#xff0…

BBA EDI 项目数据库方案开源介绍

近期为了帮助广大用户更好地使用 EDI 系统&#xff0c;我们根据以往的项目实施经验&#xff0c;将成熟的 EDI 项目进行开源。用户安装好知行之桥EDI系统之后&#xff0c;只需要下载我们整理好的示例代码&#xff0c;并放置在知行之桥指定的工作区中&#xff0c;即可开始使用。 …

Linux操作系统——第三章 基础IO

目录 接口介绍 open 文件描述符fd 0 & 1 & 2 文件描述符的分配规则 重定向 FILE 理解文件系统 inode ​编辑 理解硬链接 软链接 动态库和静态库 静态库与动态库 生成静态库 库搜索路径 生成动态库 使用动态库 运行动态库 使用外部库 接口介绍 o…

让小白也能看懂,ChatGPT入门级科普“十问十答”

由于现在GPT火热&#xff0c;360老板已经开始总动员. 白领的日常工作肯定是要发生颠覆性变化的。下面我们就通过自问自答的方式带领小白用户了解一下ChatGPT. 1、ChatGPT到底是什么&#xff1f; ChatGPT 是一个由美国人工智能公司 OpenAI 开发的自然语言处理&#xff08;NLP&…

湖南大学OS-2019期末考试解析

【特别注意】 答案来源于@wolf以及网络 是我在备考时自己做的,仅供参考,若有不同的地方欢迎讨论。 【试卷评析】 这张卷子有点老了,部分题目可能有用。如果仔细研究应该会有所收获。 【试卷与答案】 一、选择题(15%) 1、下面哪些行为会导致CPU进入内核模式 C (1)…

信噪比对重构算法的影响

前面分析了MP算法、OPM算法和SP算法的原理以及采样率对三种算法的影响。在实际的应用中&#xff0c;会混入噪声&#xff0c;没有噪声那是理想的情况&#xff0c;这里就研究一下信噪比对重构信号产生的MSE的影响。 1、 信噪比对MP算法的影响 首先研究信噪比对MP算法产生的影响…

基于VITS-fast-fine-tuning构建多speaker语音训练

1 VITS模型介绍 VITS&#xff08;Variational Inference with adversarial learning for end-to-end Text-to-Speech&#xff09;是一种语音合成方法&#xff0c;它使用预先训练好的语音编码器 (vocoder声码器) 将文本转化为语音。 VITS 的工作流程如下&#xff1a; &#xff0…

爆料,华为重回深圳,深圳第二个硅谷来了-龙华九龙山未来可期

房地产最重要的决定因素&#xff1a;科技等高附加值产业&#xff01;过去几年&#xff0c;发生的最大的变化就是——科技巨头对全球经济的影响力越来越大&#xff0c;中美之间的博弈&#xff0c;由贸易战升级为科技战&#xff0c;就是基于此原因。人工智能、电子信息技术产业、…

实验3 Tomasulo算法【计算机系统结构】

实验3 Tomasulo算法【计算机系统结构】 前言推荐实验3 Tomasulo算法1 实验目的2 实验平台3 实验内容和步骤4 实验总结与心得 最后 前言 2023-6-9 9:19:50 以下内容源自《【计算机系统结构】》 仅供学习交流使用 推荐 实验2 指令调度和延迟分支【计算机系统结构】 实验3 To…

C++算法:有向无环图拓扑排序(领接链表)

文章目录 前言一、邻接表二、代码1、生成图2、出度、入度计算3、拓扑排序 总结 前言 前文有向无环图实现游戏技能树中我们使用了矩阵存储图的关系&#xff0c;可以称之为邻接矩阵。显然&#xff0c;链表也是可以实现的。在图结构入门一文中&#xff0c;我们也提到了链表存储的…