package com.zoniot.ccrc.scheduled; import cn.hutool.core.date.DateField; import cn.hutool.core.date.DateTime; import cn.hutool.core.date.DateUtil; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.zoniot.ccrc.commom.Constants; import com.zoniot.ccrc.commom.utils.HttpRequest; import com.zoniot.ccrc.commom.utils.RedisUtil; import com.zoniot.ccrc.commom.utils.SnowflakeIdWorker; import com.zoniot.ccrc.dao.CommunityMapper; import com.zoniot.ccrc.dao.MeterReadRecordMapper; import com.zoniot.ccrc.dao.MeterRecordMapper; import com.zoniot.ccrc.entity.*; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.io.IOException; import java.math.BigDecimal; import java.text.SimpleDateFormat; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Date; import java.util.List; @Slf4j @Service public class SyncData { @Resource SnowflakeIdWorker snowflakeIdWorker ; @Resource MeterReadRecordMapper meterReadRecordMapper; @Resource MeterRecordMapper meterRecordMapper; @Autowired RedisUtil redisUtil; @Value("${site_id}") private String siteId; @Value("${province_id}") private String provinceId; @Value("${city_id}") private String cityId; @Value("${region_id}") private String regionId; @Value("${geomap.apikey}") private String apikey; @Value("${geomap.api.url}") private String apiUrl; @Resource private CommunityMapper communityMapper; @Scheduled(cron = "0 0 20 * * ?") public void synchronousData(){ syncCell(); log.info("同步小区完毕"); syncDevice(); log.info("同步设备完毕"); syncReading(); log.info("同步设备读数完毕"); synchronizeLatitudeAndLongitude(); log.info("小区地理反编码完毕"); } private void syncDevice(){ meterRecordMapper.syncDevice(siteId,1); meterRecordMapper.deleteDevice(); } private void syncCell(){ meterRecordMapper.syncCell(siteId,provinceId,cityId,regionId); } private void syncReading(){ int size=1000; int offset=0; SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyyMMdd"); int readDay=Integer.parseInt(simpleDateFormat.format(new Date())); while(true){ List waterMeterList =meterRecordMapper. findWaterMeterListWithPage(offset, size); if(waterMeterList.isEmpty()){ break; } offset=offset+size; generateReadingRecords(waterMeterList,readDay); } meterRecordMapper.updateDeviceStatus(); } private String[] getInfoFromGaode(String name,String city){ name=name.trim(); String request = apiUrl+"?key="+apikey+"&address="+name+"&city="+city; String[] tts=null; try { String jsonContent = HttpRequest.doGet(request); JSONObject parse = (JSONObject)JSON.parse(jsonContent); int count = Integer.parseInt((String)parse.get("count")); if(count != 0) { JSONObject geocodes=parse.getJSONArray("geocodes").getJSONObject(0); String rtnContent =geocodes.get("location").toString(); if(StringUtils.isNotBlank(rtnContent)) { tts=new String[3]; String []latitudeAndLongitude= rtnContent.split(","); tts[0] =latitudeAndLongitude[0]; tts[1] =latitudeAndLongitude[1]; tts[2] =geocodes.getString("formatted_address"); } } } catch (IOException e) { e.printStackTrace(); } return tts; } private void synchronizeLatitudeAndLongitude(){ meterRecordMapper.deleteCell(); Listcommunitys=meterRecordMapper.getCommunityIds(); communitys.forEach(community -> { String[] infoFromGaode = getInfoFromGaode(community.getName(),community.getAddress()); Community updateCommunity=new Community(); updateCommunity.setId(community.getId()); if(infoFromGaode!=null){ updateCommunity.setAddress(infoFromGaode[2]); updateCommunity.setLongitude(Double.parseDouble(infoFromGaode[0])); updateCommunity.setLatitude(Double.parseDouble(infoFromGaode[1])); } updateCommunity.setSyncFlag(1); communityMapper.updateByPrimaryKeySelective(updateCommunity); }); } public void generateReadingRecords(List waterMeterList, Integer readDay){ log.info("begin batch create meter record , data size = {},readDay={}",waterMeterList.size(),readDay); int i = 0 ; if(compareMeterReadDay(readDay) < 0 ){ log.warn("Not Support Passed ReadDay = {}",readDay); } else{ List meterReadRecordList = new ArrayList<>(); for (WaterMeter waterMeter : waterMeterList){ MeterReadRecord meterReadRecord = buildUnReadRecord(waterMeter, readDay); if(meterReadRecord != null){ meterReadRecordList.add(meterReadRecord); updateReadData(waterMeter); } if (meterReadRecordList.size() == Constants.BATCH_SIZE){ // 按批次提交 int insert = meterReadRecordMapper.batchInsert(meterReadRecordList); i = i+insert ; meterReadRecordList.clear(); } } if(!meterReadRecordList.isEmpty()){ int insert = meterReadRecordMapper.batchInsert(meterReadRecordList); i = i+insert ; meterReadRecordList.clear(); } } log.info("end batch create meter record , readDay={} ,result size = {}",readDay,i); } public void updateReadData(WaterMeter waterMeter){ if(waterMeter.getDeviceTypeId()==1){ MeterReadRecord meterReadRecord=new MeterReadRecord(); meterReadRecord.setDeviceId(waterMeter.getDeviceId()); setMeterRead(waterMeter.getRegistNo(),meterReadRecord); DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyyMMdd"); LocalDateTime endDateTime = LocalDateTime.now().plusDays(-1); Integer readDay = Integer.valueOf(endDateTime.format(df)); meterReadRecord.setReadDate(readDay); meterRecordMapper.updateReadData(meterReadRecord); } } /** * 将抄表日期与当期日期进行比较 * 若抄表日期大于当前日期返回值>0 * 若抄表日期等于当前日期返回值=0 * 若抄表日期早于当前日期返回值<0 * @param readDay * @return */ protected int compareMeterReadDay(int readDay){ Integer today = Integer.parseInt(DateUtil.format(DateUtil.date(), Constants.DEFAULT_METER_READ_DATE_FORMAT)); return readDay-today; } /** * 构造未抄记录 * @param waterMeter * @param readDay * @return */ protected MeterReadRecord buildUnReadRecord(WaterMeter waterMeter , Integer readDay){ MeterReadRecord meterReadRecord = new MeterReadRecord() ; Integer type=waterMeter.getDeviceTypeId(); meterReadRecord.setSiteId(waterMeter.getSiteId()); meterReadRecord.setSysId(waterMeter.getSysId()); meterReadRecord.setCommunity(waterMeter.getCommunity()); meterReadRecord.setMeterFileNo(waterMeter.getMeterFileNo()); meterReadRecord.setMeterNo(waterMeter.getMeterNo()); meterReadRecord.setDateCreate(LocalDateTime.now()); meterReadRecord.setDeviceId(waterMeter.getDeviceId()); meterReadRecord.setDeviceNo(waterMeter.getDeviceNo()); meterReadRecord.setDeviceTypeId(waterMeter.getDeviceTypeId()); meterReadRecord.setId(snowflakeIdWorker.nextId()); meterReadRecord.setLastCost(new BigDecimal(0)); meterReadRecord.setLocation(waterMeter.getLocation()); meterReadRecord.setCreateBy(Constants.SYS_FLAG); meterReadRecord.setStatus(1); meterReadRecord.setReadDate(readDay); meterReadRecord.setCity(Integer.parseInt(cityId)); meterReadRecord.setReadStatus(Constants.UN_READ); meterReadRecord.setRegion(Integer.parseInt(regionId)); meterReadRecord.setProvince(Integer.parseInt(provinceId)); meterReadRecord.setLastValid(getMeterLastValid(waterMeter,readDay)); if(type==2){ setMeterRead(waterMeter.getRegistNo(),meterReadRecord); meterReadRecord.setReadStatus(Constants.READ); } return meterReadRecord ; } private LocalDateTime changeDateType(Date date){ LocalDateTime localDateTime=null; if(date!=null){ localDateTime= date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime(); } return localDateTime; } private void setMeterRead(String registNo,MeterReadRecord meterReadRecord){ MeterRecord meterRecord = meterRecordMapper.get(registNo); if(meterRecord!=null){ String reading=meterRecord.getMeterReading()+""; meterReadRecord.setLastValid(reading); meterReadRecord.setReadTime(changeDateType(meterRecord.getReadingTime())); meterReadRecord.setReadData(reading); BigDecimal todayCost = BigDecimal.valueOf(calculateTodayCost(reading, new Double(meterReadRecord.getLastValid()))); todayCost = todayCost.setScale(3,BigDecimal.ROUND_HALF_UP); meterReadRecord.setLastCost(todayCost); meterReadRecord.setValveState(meterRecord.getValveStatus()); meterReadRecord.setMeterStatusInfo(meterRecord.getMeterStatusInfo()); meterReadRecord.setReadStatus(meterRecord.getMeterStatus()+""); setMeterLastDataToCache(meterReadRecord.getDeviceId(),reading); } } private Double calculateTodayCost(String currentReading,Double lastValid){ Double currentValid = new Double(currentReading); return currentValid-lastValid; } /** * 获取水表最后止度,先从缓存中获取止度,缓存无数据则从数据库中获取 * @param waterMeter * @param readDate * @return */ protected String getMeterLastValid(WaterMeter waterMeter,Integer readDate){ String lastValid = "0" ; String lastValidFromCache = getMeterLastValidFromCache(waterMeter); if(StringUtils.isBlank(lastValidFromCache)){ String lastValidFromDB = getMeterLastValidFromDB(waterMeter, readDate); if(StringUtils.isNotBlank(lastValidFromDB)){ lastValid = lastValidFromDB; } } else{ lastValid = lastValidFromCache ; } return lastValid; } /** * 从数据库中获取最后止度,默认为前一天的抄表最后止度 * @param waterMeter * @param readDate * @return */ protected String getMeterLastValidFromDB(WaterMeter waterMeter,Integer readDate){ // 默认水表止度 String lastValid = "" ; // 计算输入日期的前一日 DateTime inputDate = DateUtil.parse(String.valueOf(readDate), Constants.DEFAULT_METER_READ_DATE_FORMAT); DateTime previousDate = DateUtil.offset(inputDate, DateField.DAY_OF_MONTH, -1); int previousDay = Integer.parseInt(DateUtil.format(previousDate.toJdkDate(), Constants.DEFAULT_METER_READ_DATE_FORMAT)); // 查询前一日抄表记录 MeterReadRecord previousRecord= findRecordByMeterIdAndReadDate(waterMeter, previousDay); if(previousRecord != null){ lastValid = previousRecord.getLastValid(); } return lastValid ; } /** * 从缓存中获取水表的最后止度 * @param waterMeter * @return */ protected String getMeterLastValidFromCache(WaterMeter waterMeter){ // 默认水表止度 String lastValid = "" ; String meterLastData = getMeterLastDataFromCache(waterMeter.getDeviceId()); if(StringUtils.isNotBlank(meterLastData)){ lastValid=meterLastData; } return lastValid ; } /** * 从缓存中获取水表最后上报数据 * @param deviceId * @return */ protected String getMeterLastDataFromCache(Long deviceId){ return redisUtil.get(Constants.PREFIX_CACHE_FLAG+deviceId); } public MeterReadRecord findRecordByMeterIdAndReadDate(WaterMeter waterMeter, Integer readDate) { return meterReadRecordMapper.findRecordByReadDayAndDeviceId(waterMeter.getDeviceId(), readDate); } protected void setMeterLastDataToCache(Long deviceId ,String measuringData){ redisUtil.set(Constants.PREFIX_CACHE_FLAG+deviceId,measuringData); } }