案例:送水系统5

news/2024/11/25 20:01:51/

计算工资界面

 老板为工人发工资,需要统计工资。统计结果如下:

 这里的计算是非常复杂的,如:张三给老李、老王、小刘都送过水怎么办?所以要计算张三的送水数量,还要给这个数量加上一个时间的区间,比如说一个月统计一次 

在写sql之前要知道:

1.送水工  基本工资  每桶提成   送水数量    实发工资

2.实发工资= (送水数量 *  每桶提成)+基本工资

3.前三列都是worker表的(不用计算)     后面的送水数量和始发工资需要我们计算         数量         实发工资

4.先查  SELECT * FROM  tb_worker

得到我们想要的数据,然后依照得到的数据再去查询

用左连接去写 :

 实发工资= (送水数量 *  每桶提成)+基本工资  红色的条件已经拿到,目前缺少送水的数量

送水的数量在 tb_history表里,既然是求数量就要使用聚合函数sum(),可以写成SUM (h.send_water_count)  还可以给它起一个别名send_water_count,写成 AS send_water_count,

再给它们一个分组GROUP BY w . wid就可以了(不加分组出不来)

我们数量拿到之后就应该去求实发工资

SUM (send_water_count * worker_money)+worker_salary

然后可以给它起一个别名(方便查询后展示用的)

5.此时出现了一个问题,没有送水的话也要给他发基本工资,所以不能是空的。(如果送水数量为null,默认显示0),解决方法:要在sql语句中进行一个判断IFNULL(expr1,expr2)

把SUM (h.send_water_count)丢进去,然后expr2为0(意思就是:如果总数量为空就是0)

6.如果实发工资为null,默认显示基本工资

通用的判断操作:LFNULL(SUM (send_water_count * worker_money)+worker_salary , w.worker_salary)

7.具体展示:

SELECT w.worker_name, w.worker_salary,w.worker_money,
-- 如果送水数量为null,默认显示0
IFNULL(SUM(h.send_water_count),0) AS send_water_count,
-- 如果实发工资为null,默认显示基本工资
IFNULL(SUM(send_water_count * w.worker_money)+w.worker_money,w.worker_salary) AS final_salary
FROM 
tb_worker w LEFT JOIN tb_history h ON w.wid = h.worker_id
GROUP BY w.wid

1.1 定义计算工资Salary实体类

这个实体类数据库中并没有这张表,这个实体类是我们专门封装的一个类,就是把各个表中需要的字段封装成一个实体类

package com.minzu.entities;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;/*** TODO: 计算工资相关的实体类* @author caojie* @version 1.0*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Salary {/*** 送水工名称*/private String workerName;/*** 送水工底薪*/private Integer workerSalary;/*** 送水工提成*/private Double workerMoney;/*** 送水数量*/private Integer sendWaterCount;/*** 实发工资*/private Double finalSalary;
}

1.2 定义SalaryMapper接口

package com.minzu.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.minzu.entities.Customer;
import com.minzu.entities.Salary;
import org.springframework.stereotype.Repository;import java.util.List;/*** TODO: 计算工资映射器* @author caojie* @version 1.0*/
@Repository
public interface SalaryMapper extends BaseMapper<Customer> {/*** 计算所有送水工的工资* @return 工资列表*/List<Salary> calcSalary();
}

1.3 定义映射文件

定义SalaryMapper接口对应的映射器SalaryMapper.xml  

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.minzu.mapper.SalaryMapper"><select id="calcSalary" resultType="Salary">SELECT w.worker_name , w.worker_salary , w.worker_money,ifnull(sum(h.send_water_count),0) as send_water_count,ifnull(sum(h.send_water_count * w.worker_money)+w.worker_salary , w.worker_salary) as final_salaryFROM tb_worker w left join tb_history h on w.wid = h.worker_idGROUP BY w.widORDER BY final_salary desc</select>
</mapper>

1.4 定义SalaryService接口

package com.minzu.service;import com.minzu.entities.Salary;import java.util.List;/*** TODO:计算工资相关的业务逻辑* @author caojie* @version 1.0*/
public interface SalaryService {/*** 计算所有送水工的工资* @return 工资列表*/List<Salary> calcSalary();
}

1.5 定义SalaryService实现类

package com.minzu.service.impl;import com.minzu.entities.Salary;
import com.minzu.mapper.SalaryMapper;
import com.minzu.service.SalaryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;/*** TODO* @author caojie* @version 1.0*/
@Service
public class SalaryServiceImpl implements SalaryService {@Autowiredprivate SalaryMapper salaryMapper;/*** 计算所有送水工的工资** @return 工资列表*/@Overridepublic List<Salary> calcSalary() {return salaryMapper.calcSalary();}
}

1.6 定义Controller控制器

package com.minzu.controller;import com.minzu.entities.Salary;
import com.minzu.service.SalaryService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;import java.util.List;/*** TODO:处理计算工资对应的请求* @author caojie* @version 1.0*/
@RequestMapping("/salary")
@Controller
@Slf4j
public class SalaryController {@Autowiredprivate SalaryService salaryService;/*** 点击"计算工资"显示所有送水工的工资* @param model* @return*/@RequestMapping("/calcSalary")public String calcWorkerSalary(Model model) {List<Salary> salaryList = salaryService.calcSalary();log.info("worker salary list size = "+salaryList.size());model.addAttribute("salaryList",salaryList);return "salaryList";}
}

1.7 定义计算工资列表页面

定义计算工资列表页面salaryList.html,显示所有送水工的工资  

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title> 冯宝宝送水后台管理系统</title><!--Bootstrap固定框架--><link rel='stylesheet' th:href="@{/webjars/bootstrap/3.3.7/css/bootstrap.css}"><link rel='stylesheet' th:href="@{/webjars/bootstrap/3.3.7/css/bootstrap-theme.css}"><!--图标库--><link rel='stylesheet' th:href='@{/css/material-design-iconic-font.min.css}'><!--核心样式--><link rel="stylesheet" th:href="@{/css/style.css}"></head>
<body><div id="viewport"><!-- Sidebar客户列表页面使用th:replace属性替换成主菜单的侧边栏,让代码能够复用th:replace="waterMainMenu::sidebar"waterMainMenu表示主菜单页面的文件名称sidebar表示主菜单页面的片段名称--><div id="sidebar" th:replace="waterMainMenu::sidebar"></div><!-- Content --><div id="content"><!--
th:replace="waterMainMenu::navbar"表示将nav标签里面所有的内容替换为主页面的navbar片段--><nav class="navbar navbar-default" th:replace="waterMainMenu::navbar"></nav><div class="container-fluid"><div class="row"><div class="col-md-12"><div class="col-md-8"><form class="form-inline" th:action="@{/salary/searchCalcSalay}"><input type="date"class="form-control"th:value="${startDate}"th:name="startDate" placeholder="请输入开始时间" required/><input type="date"class="form-control"th:value="${endDate}"th:name="endDate" placeholder="请输入结束时间" /><input type="submit" class="btn btn-primary" name="search" value="搜索"/></form></div></div><div class="col-md-12"><table class="table table-hover table-striped"><thead><tr><td>送水工</td><td>基本工资</td><td>每桶提成</td><td>送水数量</td><td>实发工资</td></tr></thead><tbody><!-- 渲染后客户列表${custList}是Controller渲染到前端列表的数据,是一个集合cust是集合里面的一个对象th:each遍历集合里面所有的对象${cust.custName}对象名.属性名来显示数据。但是程序运行的时候会调用属性对应的get方法th:表示Thymeleaf模板对象注意:后端渲染到前端的动态数据全部包裹在${}里面--><tr th:each="salary : ${salaryList}"><td th:text="${salary.workerName}"></td><td th:text="${salary.workerSalary}"></td><td th:text="${salary.workerMoney}"></td><td th:text="${salary.sendWaterCount}"></td><td th:text="${salary.finalSalary}"></td></tr></tbody></table></div></div></div></div></div></body>
</html>

1.8 修改主界面

 

      <li><a th:href="@{/salary/calcSalary}"><i class="zmdi zmdi-widgets"></i> 计算工资</a></li>

测试结果:

 

2 根计算某一段时间的工人工资

如1月1日到30日 


2.1 编写SalaryMapper接口  

 

SalaryMapper接口里面定义根据条件计算工资的方法。

注意:Mapper接口如果有多个方法必须定义@Param注解,否则无法传入Mapper映射文件

    /*** 根据搜索条件计算某一段时间的工资* @param startDate 开始时间* @param endDate 结束时间* @return 工资列表*/List<Salary> calcSalaryByCondition(@Param("startDate") String startDate,@Param("endDate") String endDate);

 

2.2 编写Mapper映射文件

    <select id="calcSalaryByCondition" parameterType="string" resultType="Salary">SELECT w.worker_name , w.worker_salary , w.worker_money,ifnull(sum(h.send_water_count),0) as send_water_count,ifnull(sum(h.send_water_count * w.worker_money)+w.worker_salary , w.worker_salary) as final_salaryFROM tb_worker w left join tb_history h on w.wid = h.worker_idwhere h.send_water_time between #{startDate} and #{endDate}GROUP BY w.widORDER BY final_salary desc</select>

 

2.3 编写SalaryService接口

    /*** 根据搜索条件计算某一段时间的工资* @param startDate 开始时间* @param endDate 结束时间* @return 工资列表*/List<Salary> calcSalaryByCondition(String startDate,String endDate);

 

2.4 编写SalaryService实现类

    /*** 根据搜索条件计算某一段时间的工资** @param startDate 开始时间* @param endDate   结束时间* @return 工资列表*/@Overridepublic List<Salary> calcSalaryByCondition(String startDate, String endDate) {// 条件成立:表示“结束时间”为空,系统当前时间就为结束时间,然后再转换为字符串if (StrUtil.isEmpty(endDate)) {Date date = new Date(System.currentTimeMillis());                  //获取系统当前时间SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");  //date永远都是毫秒数,还是要给他格式化一下的endDate = sdf.format(date);                                        //format:格式}return salaryMapper.calcSalaryByCondition(startDate,endDate);         //开始时间可以是任意一天,但结束时间永远是当前时间}

 SalaryService实现类中的结束时间操作endDate的操作是因为开始时间可以是任意一天,但结束时间永远是当前时间

2.5 编写Controller控制器

@RequestMapping("/searchCalcSalary")public String searchCalcWorkerSalary(String startDate, String endDate, Model model) {List<Salary> salaryList = salaryService.calcSalaryByCondition(startDate, endDate);model.addAttribute("salaryList",salaryList);// 修复BUG,将搜索条件传入到前端页面model.addAttribute("startDate",startDate);model.addAttribute("endDate",endDate);return "salaryList";}

 

2.6 编写计算工资列表页面

salaryList.html页面中新增加搜索表单  

               <div class="col-md-12"><div class="col-md-8"><form class="form-inline" th:action="@{/salary/searchCalcSalay}"><input type="date"class="form-control"th:value="${startDate}"th:name="startDate" placeholder="请输入开始时间" required/><input type="date"class="form-control"th:value="${endDate}"th:name="endDate" placeholder="请输入结束时间" /><input type="submit" class="btn btn-primary" name="search" value="搜索"/></form></div></div>

 

3 修复BUG

如图所示:查询2020-01-01 ~ 2020-01-31时间段送过水的送水工工资,在这个时间段没有为客户送过水的送水工工资却没有显示。这个时间段没有为为客户送过水的送水工应该显示基本工资  

正确的查询结果应该是:

 

3.1 Mapper接口

 所以我们还要去给没有给客户送水的送水工信息

/*** 查询没有为客户送水的送水工信息* @return 送水工列表*/List<Worker> queryNotSendWaterWorker() ;

 

3.2 Mapper映射器配置文件

涉及到联合查询

 <!--    union联合查询:查询没有为客户送过水的送水工列表 “联合” 没有在该时间段送水的送水工列表--><select id="queryNotSendWaterWorker" resultType="Worker">SELECT  distinct w.worker_name,w.worker_salary,w.worker_moneyFROM tb_worker w left join tb_history h on w.wid = h.worker_idWHERE  not  h.send_water_time between  #{startDate} and #{endDate}UNIONSELECT w.worker_name,w.worker_salary,w.worker_moneyFROM tb_worker w left join tb_history h on w.wid = h.worker_idWHERE h.worker_id is null</select>
distinct:去重

UNION:关联

3.3 SalaryService接口实现类

修改SalaryService接口实现类的calcSalaryByCondition方法。计算没有送水的送水工的工资  

 /*** 根据搜索条件计算某一段时间的工资** @param startDate 开始时间* @param endDate   结束时间* @return 工资列表*/@Overridepublic List<Salary> calcSalaryByCondition(String startDate, String endDate) {// 条件成立:表示“结束时间”为空,系统当前时间为结束时间,然后再转换为字符串if (StrUtil.isEmpty(endDate)) {Date date = new Date(System.currentTimeMillis());SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");endDate = sdf.format(date);}// salaryList 在某个时间段已经为客户送过水的送水工信息List<Salary> salaryList = salaryMapper.calcSalaryByCondition(startDate, endDate);// 没有为客户送过水的送水工信息List<Worker> workerList = salaryMapper.queryNotSendWaterWorker();// 获取以送水的送水工名称//map提取,获取完了之后 在转成list集合List<String> workerNameList = salaryList.stream().map(Salary::getWorkerName).collect(Collectors.toList());// 将没有送水的送水工信息合并到salaryList// 遍历workerList,将worker对象的数据注入到Salary对象中,让后添加到salaryList集合workerList.forEach(worker -> {// 条件成立:表示没有没有送水的送水工在salaryList集合中不存在,将其放入集合if (!workerNameList.contains(worker.getWorkerName())){Salary sa = new Salary();sa.setWorkerName(worker.getWorkerName());sa.setWorkerSalary(worker.getWorkerSalary());sa.setWorkerMoney(worker.getWorkerMoney());// 没有送水的送水工默认送水数量为0sa.setSendWaterCount(0);// 没有送水的送水工默认实发工资为基本工资sa.setFinalSalary(Double.valueOf(worker.getWorkerSalary()));salaryList.add(sa);}});// 将“实发工资”按照降序排序// 需要对每个送水工的”实发工资“进行比较Collections.sort(salaryList,(o1, o2)->{if(o1.getFinalSalary() > o2.getFinalSalary()){return -1;} else if (o1.getFinalSalary() < o2.getFinalSalary()){return 1;} else {return 0;}});return salaryList;}
stream():stream流
collect:收集
Collectors:收集器
contains:包含
Collections.sort:集合排序

http://www.ppmy.cn/news/251737.html

相关文章

反渗透和一拖3恒压供水 西门子SMART和海为云触摸屏做的反渗透和恒压供水电气控制系统

反渗透和一拖3恒压供水 1.西门子SMART和海为云触摸屏做的反渗透和恒压供水电气控制系统&#xff0c; 程序注释完善&#xff0c;在山东某养鸡场运行正常。 2&#xff0c;有正常制水模式&#xff0c;反洗模式&#xff0c;原水恒压供水和供水恒压供水&#xff08;1托3&#xff09;…

基于51单片机智能热水器控制系统设计

一.硬件方案 智能热水器主要实现的功能是可以对水位进行设置并加水&#xff0c;先设置好需要加水的水位段数&#xff0c;单片机会根据这个数判断是否需要加水&#xff0c;同时还可以测量并显示水温、设置水温范围&#xff0c;若水温超过或低于所设置的水温范围&#xff0c;则会…

工业超纯水机:威立雅色谱分析超纯水机特色介绍

威立雅色谱分析超纯水机提供Ⅰ级、Ⅱ级和Ⅲ级水来供应普通实验室应用的大型清洗机、超纯水纯化系统以及用水终端。 威立雅色谱分析超纯水机特色 1、通过分配和循环系统供应流量达到每分钟10升的Ⅰ级、Ⅱ级和Ⅲ级水。 2、提供适用于供应超纯水系统和普通实验室应用的用水终端、纯…

工业超纯水机:化妆品工业超纯水设备特性概述

EDI超纯水设备具有半自动与全自动供用户选择&#xff0c;我们将根据客户的要求&#xff0c;设计出最符合用户需要的产品&#xff0c;务必达到性价比最高&#xff0c;反渗透系统具有进水高&#xff0c;低压保护&#xff0c;水箱高&#xff0c;中&#xff0c;实现无人操作。 反渗…

2022-2028年中国纯水机器市场全景调研与发展趋势研究报告

共研网发布的《2022-2028年中国纯水机器市场全景调研与发展趋势研究报告》共五章。首先介绍了纯水机器行业市场发展环境、纯水机器整体运行态势等&#xff0c;接着分析了纯水机器行业市场运行的现状&#xff0c;然后介绍了纯水机器市场竞争格局。随后&#xff0c;报告对纯水机器…

基于Springboot的休闲娱乐代理售票系统

摘要 网络的广泛应用给生活带来了十分的便利。所以把休闲娱乐代理售票管理与现在网络相结合&#xff0c;利用java技术建设休闲娱乐代理售票系统&#xff0c;实现休闲娱乐代理售票的信息化。则对于进一步提高休闲娱乐代理售票管理发展&#xff0c;丰富休闲娱乐代理售票管理经验能…

剑指offer打卡

这里写目录标题 day1 二叉树和为某一路径day2复杂链表的复刻day3二叉搜索树与双向链表day4数字排列day5找出出现次数超过一半的次数day6 二进制中1的个数day7 二叉树的最近公共祖先day8 字符串转换为整数day9 构建乘积数组day10不用加减乘除的加法day11求12....nday11 股票的最…

[chatGPT攻略] 如何检测文本内容是否由ChatGPT生成 ?

[chatGPT攻略] 如何检测文本内容是否由ChatGPT生成 ? 在 ChatGPT 爆火的两个月内&#xff0c;学生就已经自发用这种工具做作业、写论文偷懒&#xff0c;编剧会用它编故事试试出乎人意料的故事走向&#xff0c;文案编辑用它来给自己打工。 在用工具给自己省事这件事上&#xf…