Newer
Older
huludao / src / main / java / com / newfiber / api / pc / service / impl / HouseSiteSuppliesServiceImpl.java
package com.newfiber.api.pc.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.newfiber.api.core.commons.CustomException;
import com.newfiber.api.core.commons.PageRequestObject;
import com.newfiber.api.core.commons.PageResultObject;
import com.newfiber.api.core.commons.ResultCode;
import com.newfiber.api.core.redis.lock.RedisLock;
import com.newfiber.api.pc.dao.HouseSiteSuppliesMapper;
import com.newfiber.api.pc.dto.SiteDataOperationDTO;
import com.newfiber.api.pc.dto.SiteSubDTO;
import com.newfiber.api.pc.dto.DataOperationDTO;
import com.newfiber.api.pc.model.meet.HouseSiteSupplies;
import com.newfiber.api.pc.model.meet.MeetAlter;
import com.newfiber.api.pc.model.meet.ReturnGoods;
import com.newfiber.api.pc.service.HouseSiteSuppliesService;
import com.newfiber.api.pc.service.MeetAlterService;
import com.newfiber.api.pc.service.ReturnGoodsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundValueOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @Author:zzh
 * @CreateDate:2020/11/25 13:43
 * @Description:
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class HouseSiteSuppliesServiceImpl extends ServiceImpl<HouseSiteSuppliesMapper,HouseSiteSupplies> implements HouseSiteSuppliesService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private ReturnGoodsService returnGoodsService;

    @Autowired
    private RedisLock redisLock;

    @Autowired
    private MeetAlterService meetAlterService;



    @Override
    public List<HouseSiteSupplies> querySupByHouseSiteId(Integer hId) {
        if(StringUtils.isEmpty(hId)){
            throw new CustomException(ResultCode.PARAM_NULL);
        }
        BoundValueOperations<String, String> boundValueOps = stringRedisTemplate.boundValueOps("supplies:"+hId.toString());
        if(stringRedisTemplate.hasKey("supplies:"+hId.toString())){
            String json = boundValueOps.get();
            List<HouseSiteSupplies> houseSiteSupplies = JSON.parseArray(json, HouseSiteSupplies.class);
            return houseSiteSupplies;
        }

        EntityWrapper<HouseSiteSupplies> wrapper = new EntityWrapper<>();
        wrapper.eq("h_id",hId);
        List<HouseSiteSupplies> houseSiteSupplies = this.selectList(wrapper);
        //没有就将新添加的内容存入reids
        boundValueOps.set(JSONObject.toJSONString(houseSiteSupplies));
        boundValueOps.expire(20,TimeUnit.MINUTES);
        return houseSiteSupplies;
    }

    @Override
    public PageResultObject<HouseSiteSupplies> queryPage(PageRequestObject<SiteSubDTO> pageRequestObject) {
        int current =  pageRequestObject.getCurrent();
        int size = pageRequestObject.getSize();
        if(size == 0){
            return null;
        }
        Page<HouseSiteSupplies> objectPage = new Page<>();
        SiteSubDTO object = pageRequestObject.getObject();
        String key = "supPage:" + current + size + "+" + object.getSiteId() + "-" + object.getSubName();
        BoundValueOperations<String, String> boundValueOps = stringRedisTemplate.boundValueOps(key);
        if(stringRedisTemplate.hasKey(key)){
            String json = boundValueOps.get();
            PageResultObject<HouseSiteSupplies> suplies = JSON.parseObject(json,PageResultObject.class);
            return suplies;
        }

        //不存在则查找
        EntityWrapper<HouseSiteSupplies> wrapper = new EntityWrapper<>();

        if(!StringUtils.isEmpty(object.getSubName())){
            wrapper.like("sup_name",object.getSubName());
        }
        wrapper.eq("h_id",object.getSiteId());

        Page<HouseSiteSupplies> houseSitePage = this.selectPage(objectPage, wrapper);
        int count = this.selectCount(wrapper);
        PageResultObject<HouseSiteSupplies> resultObject = new PageResultObject<HouseSiteSupplies>(current, size, (long) count, houseSitePage.getRecords());
        String resultJson = JSONObject.toJSONString(resultObject);
        //存入redis中
        boundValueOps.set(resultJson);
        //设置超时时间为10分钟
        boundValueOps.expire(10, TimeUnit.MINUTES);
        return resultObject;
    }

    @Override
    public void addHouseSiteSup(HouseSiteSupplies houseSiteSupplies) {
        boolean insert = this.insert(houseSiteSupplies);
        List<HouseSiteSupplies> houseSiteSupplies1 = null;
        //更新
        String key = "supplies:"+houseSiteSupplies.getHId();
        BoundValueOperations<String, String> boundValueOps = stringRedisTemplate.boundValueOps(key);
        if(stringRedisTemplate.hasKey(key)){
            String json = boundValueOps.get();
            houseSiteSupplies1 = JSON.parseArray(json, HouseSiteSupplies.class);
        }else{
            houseSiteSupplies1 = new ArrayList<>();
        }
        houseSiteSupplies1.add(houseSiteSupplies);
        //添加更新
        boundValueOps.set(JSONObject.toJSONString(houseSiteSupplies1));
        if(!insert){
            throw new CustomException(ResultCode.SAVE_ERROR);
        }
    }

    @Override
    public void updateHouseSiteSup(HouseSiteSupplies houseSiteSupplies) {
        //更新
        String key ="supplies:"+houseSiteSupplies.getHId();
        BoundValueOperations<String, String> boundValueOps = stringRedisTemplate.boundValueOps(key);
        if(stringRedisTemplate.hasKey(key)){
            String json = boundValueOps.get();
            List<HouseSiteSupplies> siteSupplies = JSON.parseArray(json,HouseSiteSupplies.class);
            for(int i = 0; i < siteSupplies.size(); i++){
                HouseSiteSupplies supplies = siteSupplies.get(i);
                if(supplies.getSupId().equals(houseSiteSupplies.getSupId())){
                    siteSupplies.set(i,houseSiteSupplies);
                    break;
                }
            }
            boundValueOps.set(JSONObject.toJSONString(siteSupplies));
        }
        boolean update = this.updateById(houseSiteSupplies);
        if(!update){
            throw new CustomException(ResultCode.UPDATE_ERROR);
        }
    }


    @Override
    public boolean deductionSupplies(Integer alertId,Integer hId,List<DataOperationDTO> dataOperationDTO) {
        //取出传入的里面所有数据
        String key = "supplies:" + hId;
        //利用redis实现一个简单的同步方法
        //循环去判断是否获取到了锁
        int number = 0;
        while(!redisLock.lock(key)){
            if(number == 6){
                return false;
            }
            number++;
            try{
                Thread.sleep(1000);
            }catch (Exception e){
                throw new CustomException(ResultCode.THRED_SLEEP);
            }
        }
        //调用查询方法,从Redis中拿数据,拿的是存放点下的数据
        List<HouseSiteSupplies> houseSiteSupplies =  this.querySupByHouseSiteId(hId);
        //创建需要归还的物资数据集合
        List<ReturnGoods> reGoods = new ArrayList<>();
        //扣除相对应的数量
        for(DataOperationDTO dto : dataOperationDTO){
            for(HouseSiteSupplies supplies : houseSiteSupplies){
                //如果这两个物资编号相等
                if(dto.getSupId().equals(supplies.getSupId())){
                    //扣除物资数据
                    //如果需要使用到的物资数量小于存放点现有的数据时,先只给存放点已有的,然后在由调度人员去申请调度
                    if(supplies.getSupCount() < dto.getCount()){
                        supplies.setSupCount(0);

                        //发布一条调度消息(调度方法)未实现

                    }else{
                        supplies.setSupCount(supplies.getSupCount() - dto.getCount());
                    }

                    //判断要使用的物资类型(非一次性物资到最后是需要归还的)
                    if(!StringUtils.isEmpty(alertId)){
                        if(supplies.getNature().equals(2)){
                            ReturnGoods goods = new ReturnGoods();
                            goods.setHId(hId);
                            goods.setAId(alertId);
                            goods.setSupId(supplies.getSupId());
                            goods.setSupCount(dto.getCount());
                            //添加一个物资
                            reGoods.add(goods);

                            //找到匹配的就退出内层循环,加快执行效率
                            break;
                        }
                    }
                }
            }
        }

        //将更新数据重新写入Redis中
        stringRedisTemplate.opsForValue().set(key,JSONObject.toJSONString(houseSiteSupplies));
        //数据库的数据也需要同步写入(不需要写定时任务,写定时任务浪费,因为使用警情的使用频率是不很高。)
        this.updateBatchById(houseSiteSupplies);
        //将需要归还的数据写入数据库中
        if(!StringUtils.isEmpty(alertId)){
            returnGoodsService.insertBatch(reGoods);
        }
        //数据更新完毕
        //释放锁
        redisLock.delete(key);
        return true;
    }

    @Override
    public boolean returnSupplies(Integer alertId,List<SiteDataOperationDTO> dataOperationDTOs) {
        if(StringUtils.isEmpty(alertId)){
            throw new CustomException(ResultCode.PARAM_NULL);
        }
        List<String> redisKeys = new ArrayList<>();
        List<ReturnGoods> returnGoods = new ArrayList<>();
        //保存需要归还的物资id集合,用来查询物资表中的数据
        List<Integer> supIds = new ArrayList<>();
        for(SiteDataOperationDTO dto : dataOperationDTOs){
            ReturnGoods goods = new ReturnGoods();
            goods.setAId(alertId);
            goods.setHId(dto.getHId());
            //添加需要删除的redis key
            redisKeys.add("supplies:"+dto.getHId());
            for(DataOperationDTO operation :  dto.getDataOperationDTO()){
                supIds.add(operation.getSupId());
                goods.setSupId(operation.getSupId());
                goods.setSupCount(operation.getCount());
            }
            returnGoods.add(goods);
        }
        //根据需要归还的物资id查询物资在表中的数据
        List<HouseSiteSupplies> houseSiteSupplies = this.selectBatchIds(supIds);
        EntityWrapper<ReturnGoods> wrapper = new EntityWrapper<>();
        wrapper.eq("a_id",alertId);
        List<ReturnGoods> goodsList = returnGoodsService.selectList(wrapper);
        for(ReturnGoods tableGoods : goodsList){
            for(ReturnGoods paramGoods :  returnGoods){
                if(tableGoods.equals(paramGoods)){
                    // 如果归还的数量大于需要归还的数量,就抛出异常
                    if(paramGoods.getSupCount() > tableGoods.getSupCount()){
                        throw new CustomException(500,"归还的数量不能大于需要归还的数量");
                    }else{
                        tableGoods.setSupCount(tableGoods.getSupCount() - paramGoods.getSupCount());
                        //将查询出来的物资表中的数据 更新
                        for(HouseSiteSupplies housesite :houseSiteSupplies){
                            if(tableGoods.getSupId().equals(housesite.getSupId())){
                                housesite.setSupCount(housesite.getSupCount() + paramGoods.getSupCount());
                                //找到了就跳出本层循环
                                break;
                            }
                        }
                    }
                    //找到了就跳出内层循环
                    break;
                }
            }
        }
        //批量更新表中数据
        returnGoodsService.updateBatchById(goodsList);
        //更改警情状态
        MeetAlter meetAlter = meetAlterService.selectById(alertId);
        //设置物资为归还状态
        meetAlter.setIsReturnSup(1);
        meetAlterService.updateById(meetAlter);
        //增加物资表中的数量
        this.updateBatchById(houseSiteSupplies);
        //直接清空Redis中对应的站点id
        stringRedisTemplate.delete(redisKeys);
        return true;
    }

    @Override
    public void deleteHouseSiteSup(Integer id, Integer hId) {
        boolean b = this.deleteById(id);
        if(b){
            if(stringRedisTemplate.hasKey("supplies:"+hId)){
                List<HouseSiteSupplies> siteSupplies = JSON.parseArray(stringRedisTemplate.opsForValue().get("supplies:" + hId), HouseSiteSupplies.class);
                Optional<HouseSiteSupplies> first = siteSupplies.stream().filter(sup -> sup.getSupId().equals(id)).findFirst();
                if(first.isPresent()){
                    siteSupplies.remove(first.get());
                }
            }
        }else{
            throw new CustomException(ResultCode.DELETE_ERROR);
        }
    }
}