本文主要是介绍项目实战(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) < NOW()AND c.id NOT IN (SELECT DISTINCTcus_idFROMt_customer_order oWHEREis_valid = 1AND state = 1AND DATE_ADD(o.order_date,INTERVAL 6 MONTH) > 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)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!