项目实战(P15)(Day 43)

2024-02-19 20:40
文章标签 实战 项目 43 day p15

本文主要是介绍项目实战(P15)(Day 43),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

学习目标:

学习内容:

        客户流失实现:

客户流失的思想:

dao层

service层

出现问题:

遇到问题:

解决方法:

        客户流失管理和暂缓流失列表:

思想:

DAO层

 service层

 Controller层

确认流失操作

service层:

 controller层:


学习目标:

客户流失实现和客户流失页面和客户暂缓流失列表的增删改查


学习内容:

        客户流失实现:

客户流失的思想:

流失客户定义:客户自创建起,超过六个月未域企业产生任何订单或者客户最后下单日期距离现在超过六个月的客户定义为流失客户规则分析:1.客户数据录入到系统的时间距离现在的时间超过六个月    (前提条件)2.客户与公司没有产生(已支付)订单记录||客户最后下单时间距离现在时间超过六个月2.1查询没有订单记录的客户2.2 查询最后的订单时间距离现在超过六个月的客户实现思路:查询2.1与2.2的客户并去除重复的记录具体实现:用反向查询来等级啊与查询2.1和2.2的记录查询产生过订单记录并且最后的下单时间距离现在时间不超过六个与的客户,然后再从客户表中排除这些客户ps:在(1)的基础上满足(2)的情况更新客户流失状态1.查询待流失的客户数据2.将流失客户数据批量提案极爱到客户流失表中3.批量更新客户的流失状态 0=正常客户 1=流失客户

dao层

根据思路来书写查询语句

//查询带流失的客户List<Customer> queryLossCustomers();
//通过客户ID批量跟新客户流失状态int updateCustomerStateByIds(List<Integer> lossCustomerIds);//通过客户ID查询最后一条订单记录CustomerOrder queryLossCustomerOrderByCustomerId(Integer id);
<!-- 查询待流失的客户 --><select id="queryLossCustomers" resultType="com.xxxx.crm.vo.Customer">SELECT*FROMt_customer cWHEREis_valid = 1AND state = 0AND DATE_ADD(c.create_date,INTERVAL 6 MONTH) &lt; NOW()AND c.id NOT IN (SELECT DISTINCTcus_idFROMt_customer_order oWHEREis_valid = 1AND state = 1AND DATE_ADD(o.order_date,INTERVAL 6 MONTH) &gt; NOW())</select>
<!-- 批量跟新客户流失状态 --><update id="updateCustomerStateByIds" >updatet_customersetstate = 1whereid in<foreach collection="list" item="item" open="(" close=")" separator=",">#{item}</foreach></update><!-- 查询指定客户最后一条订单记录 --><select id="queryLossCustomerOrderByCustomerId" parameterType="int" resultType="com.xxxx.crm.vo.CustomerOrder">SELECT*FROMt_customer_orderWHEREis_valid = 1AND cus_id = {customerId}ORDER BYorder_date DESCLIMIT 1</select><!-- 批量添加 --><insert id="insertBatch">insert intot_customer_loss (cus_no, cus_name, cus_manager, last_order_time, confirm_loss_time, state, loss_reason, is_valid, create_date, update_date)values<foreach collection="list" separator="," item="item">(#{item.cusNo},#{item.cusName},#{item.cusManager},#{item.lastOrderTime},#{item.confirmLossTime},#{item.state},#{item.lossReason},1,now(),now())</foreach></insert>

service层

先把所有的流失客户查出来,然后再把这些数据放到流失表中,最后跟新客户状态为流失

 /*** 更新客户流失状态*   1.查询待流失的客户数据*   2.将流失客户数据批量提案极爱到客户流失表中*   3.批量更新客户的流失状态 0=正常客户 1=流失客户* @author QQ星** @param* @return void* @Date 2022/4/20 21:45*/@Transactional(propagation = Propagation.REQUIRED)public void updateCustomerState(){/* 1.查询待流失的客户数据 */List<Customer> lossCustomerList = customerMapper.queryLossCustomers();/* 2.将流失客户数据批量添加到客户流失表中 *///判断流失客户数据是否存在if (lossCustomerList !=null && lossCustomerList.size()>0){//定义集合 用来接受流失客户IDList<Integer> lossCustomerIds = new ArrayList<>();//定义流失客户列表List<CustomerLoss> customerLossList = new ArrayList<>();//遍历查询到的流失客户数据lossCustomerList.forEach(customer -> {// 定义流失客户对象CustomerLoss customerLoss = new CustomerLoss();// 创建时间  系统当前时间customerLoss.setCreateDate(new Date());// 客户经理customerLoss.setCusManager(customer.getCusManager());// 客户名称customerLoss.setCusName(customer.getName());// 客户编号customerLoss.setCusNo(customer.getKhno());// 是否有效  1=有效customerLoss.setIsValid(1);// 修改时间  系统当前时间customerLoss.setUpdateDate(new Date());// 客户流失状态   0=暂缓流失状态  1=确认流失状态customerLoss.setState(0);//客户最后下单时间//通过客户ID查询最后的订单记录(最后一条订单记录)CustomerOrder customerOrder = customerOrderMapper.queryLossCustomerOrderByCustomerId(customer.getId());//判断客户订单是否存在,如果存在,则设置最后下单时间if(customerOrder !=null){customerLoss.setLastOrderTime(customerOrder.getOrderDate());}//把流失客户对象设置到对应的集合中customerLossList.add(customerLoss);//将流失客户id设置到哦对应的集合里lossCustomerIds.add(customer.getId());});//批量添加流失客户记录AssertUtil.isTrue(customerLossMapper.inserBatch(customerLossList) !=customerLossList.size(),"客户流失数据转移失败");/* 3.批量更新客户的流失状态 */AssertUtil.isTrue(customerMapper.updateCustomerStateByIds(lossCustomerIds)!=lossCustomerIds.size(),"更新客户失败");}}
}

出现问题:

每次都需要把数据放到loss表中,那万一有傻呗天天刷新天天放数据效率太低,根据流失客户比较久的这个特性来设置一个任务来定时任务

/*** 定时任务* @author QQ星** @Date 2022/4/21 23:30*/
@Component
public class JobTask {@Resourceprivate CustomerService customerService;/*** 每月最后一天的23:42分执行* @author QQ星** @param* @return void* @Date 2022/4/21 23:44*///测试是否有效//@Scheduled(cron = "0/2 * * * * ?")@Scheduled(cron = "0 42 23 L * ? ")public void job(){System.out.println("定时任务开始执行 --> " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));//调用需要被定时执行的方法customerService.updateCustomerState();}
}

遇到问题:

Spring默认定时@Scheduled不支持L关键字

解决方法:

        客户流失管理和暂缓流失列表:

思想:

添加暂缓数据1. 参数校验流失客户ID  lossId非空,数据存在暂缓措施内容 measure非空2. 设置参数的默认值是否有效默认有效,1创建时间系统当前时间修改时间系统当前时间3. 执行添加操作,判断受影响的行数修改暂缓数据1. 参数校验主键ID    id非空,数据存在流失客户ID  lossId非空,数据存在暂缓措施内容 measure非空2. 设置参数的默认值修改时间系统当前时间3. 执行修改操作,判断受影响的行数删除暂缓数据1. 判断id是否为空,且数据存在2. 设置isvalid为03. 执行更新操作,判断受影响的行数更新流失客户的流失状态1. 参数校验判断id非空且对应的数据存在流失原因非空2. 设置参数的默认值设置流失状态  state=1  0=暂缓流失,1=确认流失流失原因客户流失时间  系统当前时间更新时间     系统当前时间3. 执行更新操作,判断受影响的行数

可参考客户的开发计划

DAO层

加入两个多条件查询,用来查询列表

<!-- 多条件查询 --><select id="selectByParams" parameterType="com.xxxx.crm.query.CustomerLossQuery" resultType="com.xxxx.crm.vo.CustomerLoss">select<include refid="Base_Column_List"></include>fromt_customer_loss<where>is_valid = 1<if test="null != customerNo and customerNo != ''">and cus_no = #{customerNo}</if><if test="null != customerName and customerName != ''">and cus_name like concat('%',#{customerName},'%')</if><if test="null != state">and state = #{state}</if></where></select><!-- 多条件查询 --><select id="selectByParams" parameterType="com.xxxx.crm.query.CustomerReprieveQuery" resultType="com.xxxx.crm.vo.CustomerReprieve">select<include refid="Base_Column_List"></include>fromt_customer_reprieve<where>is_valid = 1<if test="null != lossId">and loss_id = #{lossId}</if></where></select>

 service层

CustomerLoss层只有一个分页查询与CustomerReprieve中分页查询一样,创建两个query供前端传给后端即可


public class CustomerLossQuery extends BaseQuery {// 客户编号private String customerNo;// 客户名称private String customerName;// 流失状态  0=暂缓流失状态  1=确认流失状态private Integer state;public String getCustomerNo() {return customerNo;}public void setCustomerNo(String customerNo) {this.customerNo = customerNo;}public String getCustomerName() {return customerName;}public void setCustomerName(String customerName) {this.customerName = customerName;}public Integer getState() {return state;}public void setState(Integer state) {this.state = state;}
}

public class CustomerReprieveQuery extends BaseQuery {//流失客户Idprivate Integer lossId;public Integer getLossId() {return lossId;}public void setLossId(Integer lossId) {this.lossId = lossId;}
}
@Service
public class CustomerReprieveService extends BaseService<CustomerReprieve,Integer> {@Resourceprivate CustomerReprieveMapper customerReprieveMapper;@Resourceprivate CustomerLossMapper customerLossMapper;/*** 分页查询流失客户暂缓操作的列表* @author QQ星** @param customerReprieveQuery* @return java.util.Map<java.lang.String,java.lang.Object>* @Date 2022/4/26 22:06*/public Map<String, Object> queryCustomerReprieveByParams(CustomerReprieveQuery customerReprieveQuery) {Map<String, Object> map = new HashMap<>();// 开启分页PageHelper.startPage(customerReprieveQuery.getPage(), customerReprieveQuery.getLimit());// 得到对应分页对象PageInfo<CustomerReprieve> pageInfo = new PageInfo<>(customerReprieveMapper.selectByParams(customerReprieveQuery));// 设置map对象map.put("code",0);map.put("msg","success");map.put("count",pageInfo.getTotal());// 设置分页好的列表map.put("data",pageInfo.getList());return map;}/*** 添加暂缓数据*   1. 参数校验*       流失客户ID  lossId*           非空,数据存在*       暂缓措施内容 measure*           非空*   2. 设置参数的默认值*       是否有效*           默认有效,1*       创建时间*           系统当前时间*       修改时间*           系统当前时间*   3. 执行添加操作,判断受影响的行数* @author QQ星** @param customerReprieve* @return void* @Date 2022/4/26 22:55*/@Transactional(propagation = Propagation.REQUIRED)public void addCustomerRepr(CustomerReprieve customerReprieve) {/* 1. 参数校验 */checkParams(customerReprieve.getLossId(), customerReprieve.getMeasure());/* 2. 设置参数的默认值 */customerReprieve.setIsValid(1);customerReprieve.setCreateDate(new Date());customerReprieve.setUpdateDate(new Date());/* 3. 执行添加操作,判断受影响的行数 */AssertUtil.isTrue(customerReprieveMapper.insertSelective(customerReprieve) < 1, "添加暂缓数据失败!");}/*** 参数校检* @author QQ星** @param lossId* @param measure* @return void* @Date 2022/4/26 23:01*/private void checkParams(Integer lossId, String measure) {// 流失客户ID lossId    非空,数据存在AssertUtil.isTrue(null == lossId|| customerLossMapper.selectByPrimaryKey(lossId) == null, "流失客户记录不存在!");// 暂缓措施内容 measure   非空AssertUtil.isTrue(StringUtils.isBlank(measure), "暂缓措施内容不能为空!");}/*** 修改暂缓数据* 1. 参数校验*      主键ID    id*          非空,数据存在*      流失客户ID  lossId*          非空,数据存在*      暂缓措施内容 measure*          非空*  2. 设置参数的默认值*      修改时间*          系统当前时间*  3. 执行修改操作,判断受影响的行数* @author QQ星** @param customerReprieve* @return void* @Date 2022/4/26 23:14*/@Transactional(propagation = Propagation.REQUIRED)public void updateCustomerRepr(CustomerReprieve customerReprieve) {/* 1. 参数校验 */// 主键ID    idAssertUtil.isTrue(null == customerReprieve.getId()|| customerReprieveMapper.selectByPrimaryKey(customerReprieve.getId()) == null, "待更新记录不存在!");// 参数校验checkParams(customerReprieve.getLossId(), customerReprieve.getMeasure());/* 2. 设置参数的默认值 */customerReprieve.setUpdateDate(new Date());/* 3. 执行修改操作,判断受影响的行数 */AssertUtil.isTrue(customerReprieveMapper.updateByPrimaryKeySelective(customerReprieve) < 1, "修改暂缓数据失败!");}/*** 删除暂缓数据*  1. 判断id是否为空,且数据存在*  2. 设置isvalid为0*  3. 执行更新操作,判断受影响的行数* @author QQ星** @param id* @return void* @Date 2022/4/26 23:35*/@Transactional(propagation = Propagation.REQUIRED)public void deleteCustomerRepr(Integer id) {// 判断id是否为空AssertUtil.isTrue(null == id, "待删除记录不存在!");// 通过id查询暂缓数据CustomerReprieve customerReprieve = customerReprieveMapper.selectByPrimaryKey(id);// 判断数据是否存在AssertUtil.isTrue(null == customerReprieve, "待删除记录不存在!");// 设置isValidcustomerReprieve.setIsValid(0);customerReprieve.setUpdateDate(new Date());// 执行更新操作,判断受影响的行数AssertUtil.isTrue(customerReprieveMapper.updateByPrimaryKeySelective(customerReprieve) < 1, "删除暂缓数据失败!");}
}

 Controller层

在CustomerLossController层中书写首页和流失客户列表加上打开添加暂缓按钮的界面   


@RequestMapping("customer_loss")
@Controller
public class CustomerLossController extends BaseController {@ResourceCustomerLossService customerLossService;/*** 进入客户流失管理页面* @author QQ星** @param* @return java.lang.String* @Date 2022/4/26 0:27*/@RequestMapping("index")public String index(){return "customerLoss/customer_loss";}/*** 分页条件查询流失客户列表* @author QQ星** @param customerLossQuery* @return java.util.Map<java.lang.String,java.lang.Object>* @Date 2022/4/26 1:14*/@RequestMapping("list")@ResponseBodypublic Map<String, Object> queryCustomerLossByParams(CustomerLossQuery customerLossQuery) {return customerLossService.queryCustomerLossByParams(customerLossQuery);}/*** 打开添加暂缓页面* @author QQ星** @param lossId* @param model* @return java.lang.String* @Date 2022/4/26 21:49*/@RequestMapping("toCustomerLossPage")public String toCustomerLossPage(Integer lossId, Model model) {// 通过流失客户的ID查询对应流失客户的记录CustomerLoss customerLoss = customerLossService.selectByPrimaryKey(lossId);// 将流失客户对应的数据存到请求域中model.addAttribute("customerLoss", customerLoss);return "customerLoss/customer_rep";}
}

在CustomerReprieveController层中书写增删改查操做以及打开添加删除页面


@RequestMapping("customer_rep")
@Controller
public class CustomerReprieveController extends BaseController {@Resourceprivate CustomerReprieveService customerReprieveService;/*** 分页查询流失客户暂缓操作列表* @author QQ星** @param customerReprieveQuery* @return java.util.Map<java.lang.String,java.lang.Object>* @Date 2022/4/26 22:05*/@RequestMapping("list")@ResponseBodypublic Map<String, Object> queryCustomerReprieveByParams(CustomerReprieveQuery customerReprieveQuery) {return customerReprieveService.queryCustomerReprieveByParams(customerReprieveQuery);}/*** 添加暂缓数据* @author QQ星** @param customerReprieve* @return com.xxxx.crm.base.ResultInfo* @Date 2022/4/26 22:51*/@PostMapping("add")@ResponseBodypublic ResultInfo addCustomerRepr(CustomerReprieve customerReprieve) {customerReprieveService.addCustomerRepr(customerReprieve);return success("添加暂缓数据成功!");}/*** 跟新暂缓数据* @author QQ星** @param customerReprieve* @return com.xxxx.crm.base.ResultInfo* @Date 2022/4/26 23:11*/@PostMapping("update")@ResponseBodypublic ResultInfo updateCustomerRepr(CustomerReprieve customerReprieve) {customerReprieveService.updateCustomerRepr(customerReprieve);return success("修改暂缓数据成功!");}/*** 打开添加/修改暂缓数据的页面* @author QQ星** @param lossId* @param request* @param id* @return java.lang.String* @Date 2022/4/26 23:25*/@RequestMapping("toAddOrUpdateCustomerReprPage")public String toAddOrUpdateCustomerReprPage(Integer lossId, HttpServletRequest request, Integer id) {// 将流失客户ID存到作用域中request.setAttribute("lossId", lossId);// 判断ID是否为空if (id != null) {// 通过主键ID查询暂缓数据CustomerReprieve customerRep = customerReprieveService.selectByPrimaryKey(id);// 设置到请求域中request.setAttribute("customerRep", customerRep);}return "customerLoss/customer_rep_add_update";}/*** 删除暂缓数据* @author QQ星** @param id* @return com.xxxx.crm.base.ResultInfo* @Date 2022/4/26 23:28*/@PostMapping("delete")@ResponseBodypublic ResultInfo updateCustomerRepr(Integer id) {customerReprieveService.deleteCustomerRepr(id);return success("删除暂缓数据成功!");}
}

确认流失操作

service层:

    /*** 更新流失客户的流失状态*  1. 参数校验*      判断id非空且对应的数据存在*      流失原因非空*  2. 设置参数的默认值*      设置流失状态  state=1  0=暂缓流失,1=确认流失*      流失原因*      客户流失时间  系统当前时间*      更新时间     系统当前时间*  3. 执行更新操作,判断受影响的行数* @author QQ星** @param id* @param lossReason* @return void* @Date 2022/4/26 00:30*/@Transactional(propagation = Propagation.REQUIRED)public void updateCustomerLossStateById(Integer id, String lossReason) {/* 1. 参数校验 */// 判断id非空AssertUtil.isTrue(null == id, "待确认流失的客户不存在!");// 通过id查询流失客户的记录CustomerLoss customerLoss = customerLossMapper.selectByPrimaryKey(id);// 判断流失客户记录是否存在AssertUtil.isTrue(null == customerLoss, "待确认流失的客户不存在!");// 流失原因非空AssertUtil.isTrue(StringUtils.isBlank(lossReason), "流失原因不能为空!");/* 2. 设置参数的默认值 */// 设置流失状态  state=1  0=暂缓流失,1=确认流失customerLoss.setState(1);// 设置流失原因customerLoss.setLossReason(lossReason);// 客户流失时间  系统当前时间customerLoss.setConfirmLossTime(new Date());// 更新时间     系统当前时间customerLoss.setUpdateDate(new Date());/* 3. 执行更新操作,判断受影响的行数 */AssertUtil.isTrue(customerLossMapper.updateByPrimaryKeySelective(customerLoss) < 1, "确认流失失败!");}

 controller层:

/*** 确认流失* @author QQ星** @param id* @param lossReason* @return com.xxxx.crm.base.ResultInfo* @Date 2022/4/26 00:11*/@PostMapping("updateCustomerLossStateById")@ResponseBodypublic ResultInfo updateCustomerLossStateById(Integer id, String lossReason) {customerLossService.updateCustomerLossStateById(id, lossReason);return success("确认流失成功!");}

这篇关于项目实战(P15)(Day 43)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/725904

相关文章

网页解析 lxml 库--实战

lxml库使用流程 lxml 是 Python 的第三方解析库,完全使用 Python 语言编写,它对 XPath表达式提供了良好的支 持,因此能够了高效地解析 HTML/XML 文档。本节讲解如何通过 lxml 库解析 HTML 文档。 pip install lxml lxm| 库提供了一个 etree 模块,该模块专门用来解析 HTML/XML 文档,下面来介绍一下 lxml 库

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

如何用Docker运行Django项目

本章教程,介绍如何用Docker创建一个Django,并运行能够访问。 一、拉取镜像 这里我们使用python3.11版本的docker镜像 docker pull python:3.11 二、运行容器 这里我们将容器内部的8080端口,映射到宿主机的80端口上。 docker run -itd --name python311 -p

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

在cscode中通过maven创建java项目

在cscode中创建java项目 可以通过博客完成maven的导入 建立maven项目 使用快捷键 Ctrl + Shift + P 建立一个 Maven 项目 1 Ctrl + Shift + P 打开输入框2 输入 "> java create"3 选择 maven4 选择 No Archetype5 输入 域名6 输入项目名称7 建立一个文件目录存放项目,文件名一般为项目名8 确定

day-51 合并零之间的节点

思路 直接遍历链表即可,遇到val=0跳过,val非零则加在一起,最后返回即可 解题过程 返回链表可以有头结点,方便插入,返回head.next Code /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}*

滚雪球学Java(87):Java事务处理:JDBC的ACID属性与实战技巧!真有两下子!

咦咦咦,各位小可爱,我是你们的好伙伴——bug菌,今天又来给大家普及Java SE啦,别躲起来啊,听我讲干货还不快点赞,赞多了我就有动力讲得更嗨啦!所以呀,养成先点赞后阅读的好习惯,别被干货淹没了哦~ 🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,助你一臂之力,带你早日登顶🚀,欢迎大家关注&&收藏!持续更新中,up!up!up!! 环境说明:Windows 10

Vue3项目开发——新闻发布管理系统(六)

文章目录 八、首页设计开发1、页面设计2、登录访问拦截实现3、用户基本信息显示①封装用户基本信息获取接口②用户基本信息存储③用户基本信息调用④用户基本信息动态渲染 4、退出功能实现①注册点击事件②添加退出功能③数据清理 5、代码下载 八、首页设计开发 登录成功后,系统就进入了首页。接下来,也就进行首页的开发了。 1、页面设计 系统页面主要分为三部分,左侧为系统的菜单栏,右侧

SpringBoot项目是如何启动

启动步骤 概念 运行main方法,初始化SpringApplication 从spring.factories读取listener ApplicationContentInitializer运行run方法读取环境变量,配置信息创建SpringApplication上下文预初始化上下文,将启动类作为配置类进行读取调用 refresh 加载 IOC容器,加载所有的自动配置类,创建容器在这个过程