123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569 |
- package com.persagy.bdtp.adm.service.impl;
- import cn.hutool.core.date.DatePattern;
- import cn.hutool.core.date.DateUtil;
- import cn.hutool.core.util.ArrayUtil;
- import cn.hutool.core.util.IdUtil;
- import cn.hutool.core.util.ReflectUtil;
- import cn.hutool.core.util.StrUtil;
- import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
- import com.fasterxml.jackson.databind.JsonNode;
- import com.fasterxml.jackson.databind.ObjectMapper;
- import com.fasterxml.jackson.databind.node.ArrayNode;
- import com.fasterxml.jackson.databind.node.ObjectNode;
- import com.persagy.bdtp.adm.client.OldAdmClient;
- import com.persagy.bdtp.adm.common.AdmConst;
- import com.persagy.bdtp.adm.common.AdmResult;
- import com.persagy.bdtp.adm.dao.AdmJobSpaceMapper;
- import com.persagy.bdtp.adm.dao.AdmObjectMapper;
- import com.persagy.bdtp.adm.entity.db.AdmJobSpace;
- import com.persagy.bdtp.adm.entity.db.AdmObject;
- import com.persagy.bdtp.adm.entity.oldadm.*;
- import com.persagy.bdtp.adm.service.CallException;
- import com.persagy.bdtp.adm.service.IAdmObjectService;
- import com.persagy.bdtp.adm.service.IQueryFromOldAdm;
- import com.persagy.bdtp.adm.service.ISyncOldAdm;
- import com.persagy.bdtp.adm.util.GeomUtil;
- import com.persagy.dmp.common.constant.ResponseCode;
- import com.persagy.dmp.common.constant.ValidEnum;
- import com.persagy.dmp.common.exception.BusinessException;
- import com.persagy.dmp.common.helper.SpringHelper;
- import com.persagy.dmp.file.client.FileClientFacade;
- import com.persagy.dmp.file.model.FileInfo;
- import com.persagy.dmp.file.model.FileInfoCreator;
- import com.persagy.dmp.storage.utils.FileStorageHelper;
- import feign.Response;
- import org.locationtech.jts.geom.Polygon;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Service;
- import org.springframework.transaction.annotation.Transactional;
- import java.io.IOException;
- import java.io.InputStream;
- import java.lang.reflect.Field;
- import java.util.*;
- import java.util.stream.Collectors;
- @Service
- public class SyncOldAdmImpl implements ISyncOldAdm {
- @Autowired
- private IQueryFromOldAdm queryOldAdm;
- @Autowired
- private IAdmObjectService objectService;
- @Autowired
- private AdmObjectMapper objectMapper;
- @Autowired
- private AdmJobSpaceMapper jobSpaceMapper;
- @Override
- @Transactional(rollbackFor = Exception.class)
- public Map<String, Object> syncData(String groupCode, String projectId) {
- String token = queryOldAdm.login();
- if(StrUtil.isNotBlank(token)){
- List<OBuilding> bdList = queryOldAdm.queryBdAnFl(token, groupCode, projectId);
- List<OSpace> spList = queryOldAdm.querySpace(token, groupCode, projectId);
- spList = spList.stream().filter(space -> GeomUtil.checkPolygon(space.getOutline())).collect(Collectors.toList());
- List<OEquip> eqList = queryOldAdm.queryEquip(token, groupCode, projectId);
- List<AdmObject> bdObjs = new ArrayList<>(bdList.size());
- List<AdmObject> flObjs = new ArrayList<>();
- List<AdmObject> spObjs = new ArrayList<>(spList.size());
- List<AdmObject> eqObjs = new ArrayList<>(eqList.size());
- transEntities(bdObjs, bdList, (bdObj, oBd) -> {
- setBdData(bdObj, (OBuilding) oBd);
- if(((OBuilding) oBd).getFloor() != null)
- transEntities(flObjs, ((OBuilding) oBd).getFloor(), (flObj, oFl) -> setFlData(flObj, (OFloor) oFl));
- });
- transEntities(spObjs, spList, (spObj, oSp) -> setSpData(spObj, (OSpace) oSp));
- transEntities(eqObjs, eqList, (eqObj, oEq) -> setEqData(eqObj, (OEquip) oEq));
- Map<String, String> floorIdMap = new HashMap<>();
- List<AdmObject> dbBds = objectService.queryM2dByObjType(projectId, AdmConst.OBJ_TYPE_BUILDING);
- List<AdmObject> dbFls = objectService.queryM2dByObjType(projectId, AdmConst.OBJ_TYPE_FLOOR);
- List<AdmObject> dbSps = objectService.queryM2dByObjType(projectId, AdmConst.OBJ_TYPE_SPACE);
- List<AdmObject> dbEqs = objectService.queryM2dByObjType(projectId, AdmConst.OBJ_TYPE_EQUIPMENT);
- List<AdmObject>[] operations = new List[]{new ArrayList<>(), new ArrayList<>()};
- syncObjs(bdObjs, dbBds, operations, 1, floorIdMap);
- syncObjs(flObjs, dbFls, operations, 2, floorIdMap);
- syncObjs(spObjs, dbSps, operations, 3, floorIdMap);
- syncObjs(eqObjs, dbEqs, operations, 4, floorIdMap);
- objectService.insert(operations[0]);
- objectService.update(operations[1]);
- /*uploadFloorMap(flObjs, groupCode, projectId);*/
- HashMap<String, Object> rtn = new HashMap<>();
- rtn.put(AdmConst.OBJ_TYPE_BUILDING, bdObjs.size());
- rtn.put(AdmConst.OBJ_TYPE_FLOOR, flObjs.size());
- rtn.put(AdmConst.OBJ_TYPE_SPACE, spObjs.size());
- rtn.put(AdmConst.OBJ_TYPE_EQUIPMENT, eqObjs.size());
- return rtn;
- }
- throw new CallException(new AdmResult(ResponseCode.A0220.getCode(), "ADM platform: " + ResponseCode.A0220.getDesc()));
- }
- //TODO 设备同步时,按正逆向规则过滤
- private void syncObjs(List<AdmObject> objs, List<AdmObject> dbItems, List<AdmObject>[] operations, int objMark, Map<String, String> floorIdMap){
- HashMap<String, AdmObject> dbMap = new HashMap<>();
- for (AdmObject dbItem : dbItems){
- dbMap.put(getFixedIdForSync(dbItem, objMark), dbItem);
- }
- String timestamp = DateUtil.format(new Date(), DatePattern.PURE_DATETIME_PATTERN);
- for(AdmObject obj : objs) {
- AdmObject dbItem = dbMap.remove(getFixedIdForSync(obj, objMark));
- if(dbItem == null) {
- obj.setCreator(AdmConst.CREATOR_SYNC);
- obj.setModifiedTime(timestamp); //保留从老adm同步过来的createTime,设置updateTime
- obj.setD2mState(ValidEnum.TRUE.getType());
- obj.setDeliveryState(ValidEnum.FALSE.getType());
- if(objMark == 3 || objMark == 4) { //新增空间|设备
- if(floorIdMap.size() > 0){
- String fixedFloorId = floorIdMap.get(obj.getFloorId());
- if(fixedFloorId != null)
- obj.setFloorId(fixedFloorId);
- }
- }
- operations[0].add(obj); //add
- } else {
- AdmObject updateItem = mergeObj(obj, dbItem, timestamp, objMark);
- if(updateItem != null)
- operations[1].add(updateItem); //modify
- if(objMark == 2 && !obj.getId().equals(dbItem.getId())) {
- floorIdMap.put(obj.getId(), dbItem.getId());
- }
- }
- }
- if (dbMap.size() > 0) { //remove
- for(AdmObject obj : dbMap.values()){
- obj.setValid(ValidEnum.FALSE.getType());
- obj.setModifiedTime(timestamp);
- obj.setModifier(AdmConst.CREATOR_SYNC);
- obj.setUploadFlag(null);
- operations[1].add(obj);
- }
- }
- }
- /**
- * 同步数据时固定的id,优先取bimId,没有bimId取数据id
- */
- private String getFixedIdForSync(AdmObject obj, int objMark){
- String bimId = null;
- JsonNode node = obj.getInfo("bimId");
- if(node != null)
- bimId = node.asText();
- if(StrUtil.isNotBlank(bimId))
- return bimId;
- if(objMark == 1) //建筑
- return obj.getLocalId();
- else if(objMark == 2) //楼层
- return obj.getBuildingId() + ":" + obj.getLocalId();
- return obj.getId();
- }
- private AdmObject mergeObj(AdmObject obj, AdmObject dbItem, String timestamp, int objMark){
- if(objNotChange(obj, dbItem))
- return null;
- //合并属性和信息点
- // if(objMark == 3) {//space
- //
- // } else if(objMark == 4) {//equipment
- //
- // }
- if (obj.getInfos() != null) {
- if (dbItem.getInfos() == null)
- dbItem.setInfos(obj.getInfos());
- else
- dbItem.getInfos().setAll(obj.getInfos());
- }
- dbItem.setModifiedTime(timestamp);
- dbItem.setModifier(AdmConst.CREATOR_SYNC);
- dbItem.setUploadFlag(null);
- dbItem.setD2mState(ValidEnum.TRUE.getType());
- dbItem.setDeliveryState(ValidEnum.FALSE.getType());
- return dbItem;
- }
- private boolean objNotChange(AdmObject obj, AdmObject dbItem){
- //TODO 数据无变化判断
- return false;
- }
- private <T extends OBase> void transEntities(List<AdmObject> targetList, List<T> list, SetDataAction setDataAction){
- if(list != null && list.size() > 0) {
- for(T item : list) {
- AdmObject obj = buildAdmObject(item);
- setDataAction.setData(obj, item);
- targetList.add(obj);
- }
- }
- }
- private AdmObject buildAdmObject(OBase base){
- AdmObject obj = new AdmObject();
- obj.setId(base.getId());
- obj.setLocalId(base.getLocalId());
- obj.setName(base.getName());
- obj.setLocalName(base.getLocalName());
- obj.setObjType(base.getObjectType());
- if (base.getInfos() != null)
- obj.setInfos(mapToNode(base.getInfos()));
- if(base.getCreateTime() != null) //同步数据中没有createTime时,设置为当前时间
- obj.setCreationTime(DateUtil.format(new Date(), DatePattern.PURE_DATETIME_PATTERN));
- obj.setValid(ValidEnum.TRUE.getType());
- return obj;
- }
- private void setBdData(AdmObject obj, OBuilding bd){
- obj.setProjectId(bd.getProjectId());
- obj.setClassCode(bd.getObjectType());
- //obj.setBuildingId(bd.getId());
- if(bd.getDefaultQRCode() != null)
- getInfos(obj).put("defaultQRCode", bd.getDefaultQRCode());
- if(bd.getBuildQRCode() != null)
- getInfos(obj).put("buildQRCode", bd.getBuildQRCode());
- }
- private void setFlData(AdmObject obj, OFloor fl){
- obj.setProjectId(fl.getProjectId());
- obj.setBuildingId(fl.getBuildingId());
- //obj.setFloorId(fl.getId());
- obj.setClassCode(fl.getObjectType());
- setInfos(obj, fl, "projectId", "buildingId", "floorId");
- }
- private void setSpData(AdmObject obj, OSpace sp) {
- obj.setProjectId(sp.getProjectId());
- obj.setBuildingId(sp.getBuildingId());
- obj.setFloorId(sp.getFloorId());
- obj.setClassCode(sp.getClassCode());
- obj.setObjType(AdmConst.OBJ_TYPE_SPACE);
- setInfos(obj, sp, "projectId", "buildingId", "floorId", "classCode");
- }
- private void setEqData(AdmObject obj, OEquip eq) {
- obj.setProjectId(eq.getProjectId());
- obj.setBuildingId(eq.getBuildingId());
- obj.setFloorId(eq.getFloorId());
- obj.setClassCode(eq.getClassCode());
- setInfos(obj, eq, "projectId", "buildingId", "floorId", "propertyId", "classCode");
- }
- private void setInfos(AdmObject obj, OBase oEntity, String... ignoreFields){
- Field[] fields = oEntity.getClass().getDeclaredFields();
- for (Field field : fields) {
- if(ignoreFields.length == 0 || !ArrayUtil.contains(ignoreFields, field.getName())) {
- Object val = ReflectUtil.getFieldValue(oEntity, field);
- if(val != null) {
- ObjectNode infos = getInfos(obj);
- if(val instanceof String)
- infos.put(field.getName(), (String)val);
- else if(val instanceof Integer)
- infos.put(field.getName(), (Integer)val);
- else if(val instanceof Float)
- infos.put(field.getName(), (Float)val);
- else if(val instanceof Double)
- infos.put(field.getName(), (Double)val);
- else if(val instanceof List)
- infos.putArray(field.getName()).addAll(listToNode((List)val));
- else if(val instanceof Map)
- infos.putObject(field.getName()).setAll(mapToNode((Map)val));
- }
- }
- }
- }
- private ObjectNode getInfos(AdmObject obj) {
- ObjectNode objectNode = obj.getInfos();
- if(objectNode == null){
- ObjectMapper objectMapper = SpringHelper.getBean(ObjectMapper.class);
- objectNode = objectMapper.createObjectNode();
- obj.setInfos(objectNode);
- }
- return objectNode;
- }
- private ObjectNode mapToNode(Map<String, Object> map){
- ObjectMapper objectMapper = SpringHelper.getBean(ObjectMapper.class);
- try {
- String json = objectMapper.writeValueAsString(map);
- return objectMapper.readValue(json, ObjectNode.class);
- } catch (IOException e) {
- throw new BusinessException(ResponseCode.A0427.getCode(), ResponseCode.A0427.getDesc());
- }
- }
- private ArrayNode listToNode(List<Object> list){
- ObjectMapper objectMapper = SpringHelper.getBean(ObjectMapper.class);
- try {
- String json = objectMapper.writeValueAsString(list);
- return objectMapper.readValue(json, ArrayNode.class);
- } catch (IOException e) {
- throw new BusinessException(ResponseCode.A0427.getCode(), ResponseCode.A0427.getDesc());
- }
- }
- interface SetDataAction {
- void setData(AdmObject obj, OBase oldAdmEntity);
- }
- /**
- * 创建/合并任务空间数据
- */
- @Override
- @Transactional(rollbackFor = Exception.class)
- public void handleJobSpace(String projectId){
- QueryWrapper<AdmObject> queryWrapper = new QueryWrapper<>();
- queryWrapper.eq("project_id", projectId).eq("obj_type", AdmConst.OBJ_TYPE_SPACE).eq("valid", ValidEnum.TRUE.getType()).orderByAsc("floor_id");
- List<AdmObject> spaceList = objectMapper.selectList(queryWrapper);
- QueryWrapper<AdmJobSpace> wrapper = new QueryWrapper<>();
- wrapper.eq("project_id", projectId).eq("valid", ValidEnum.TRUE.getType());
- List<AdmJobSpace> jobSpaceList = jobSpaceMapper.selectList(wrapper);
- //空间按层分组,优先使用OtherZone,缺省GeneralZone
- LinkedHashMap<String, List<AdmObject>> map = new LinkedHashMap<>();
- String floorId = null;
- List<AdmObject> generalList = null;
- List<AdmObject> otherList = null;
- for(AdmObject sp : spaceList){
- if(floorId == null || !floorId.equals(sp.getFloorId())) {
- if(floorId != null)
- map.put(floorId, otherList.size() > 0 ? otherList : generalList);
- floorId = sp.getFloorId();
- generalList = new ArrayList<>();
- otherList = new ArrayList<>();
- }
- String zone = sp.getClassCode();
- if("GeneralZone".equals(zone))
- generalList.add(sp);
- else if("OtherZone".equals(zone))
- otherList.add(sp);
- }
- if(floorId != null)
- map.put(floorId, otherList.size() > 0 ? otherList : generalList);
- List<AdmJobSpace> toCreate = new ArrayList<>();
- List<AdmJobSpace> toModify = new ArrayList<>();
- String time = DateUtil.format(new Date(), DatePattern.PURE_DATETIME_PATTERN);
- //按楼层进行空间匹配操作
- for (Map.Entry<String, List<AdmObject>> entry : map.entrySet()) {
- floorId = entry.getKey();
- HashMap<String, AdmJobSpace> jobMap = new HashMap<>();
- for (int i = 0; i < jobSpaceList.size(); i++) {
- AdmJobSpace jobSpace = jobSpaceList.get(i);
- if(jobSpace.getFloorId().equals(floorId)){
- jobMap.put(jobSpace.getSpaceId(), jobSpace);
- jobSpaceList.remove(i);
- i--;
- }
- }
- List<AdmObject> sps = entry.getValue();
- for(AdmObject sp : sps){
- ArrayNode spOutline = (ArrayNode) sp.getInfo("outline");
- AdmJobSpace job = jobMap.remove(sp.getId());
- if(job != null) {
- //id匹配,轮廓变化的空间,重置任务状态
- if(!outlineMatch(job.getOutline(), spOutline)){
- job.setArchState(AdmConst.JOB_STATE_PROCESSING);
- job.setEquipState(AdmConst.JOB_STATE_PROCESSING);
- job.setOutline(spOutline);
- toModify.add(job);
- } // else id和轮廓都匹配,不做处理
- } else {
- //id未匹配,轮廓完全一致的任务空间,重新设置spaceId
- job = matchByOutline(jobMap, sp);
- if(job != null) {
- job.setSpaceId(sp.getId());
- toModify.add(job);
- }
- }
- if (job == null) {
- job = new AdmJobSpace();
- job.setId(IdUtil.fastUUID());
- job.setSpaceId(sp.getId());
- job.setOutline((ArrayNode) sp.getInfo("outline"));
- job.setArchState(AdmConst.JOB_STATE_PROCESSING);
- job.setEquipState(AdmConst.JOB_STATE_PROCESSING);
- job.setProjectId(projectId);
- job.setBuildingId(sp.getBuildingId());
- job.setFloorId(sp.getFloorId());
- job.setCreationTime(time);
- job.setCreator(AdmConst.CREATOR_SYNC);
- job.setValid(ValidEnum.TRUE.getType());
- toCreate.add(job);
- }
- }
- //楼层中未找到匹配关系的任务空间
- for(AdmJobSpace job : jobMap.values()){
- job.setValid(ValidEnum.FALSE.getType());
- toModify.add(job);
- }
- }
- //项目下未找到匹配关系的任务空间
- for(AdmJobSpace job : jobSpaceList){
- job.setValid(ValidEnum.FALSE.getType());
- toModify.add(job);
- }
- for(AdmJobSpace job : toCreate) {
- jobSpaceMapper.insert(job);
- }
- for(AdmJobSpace job : toModify) {
- job.setModifiedTime(time);
- job.setModifier(AdmConst.CREATOR_SYNC);
- job.setUploadFlag(null);
- jobSpaceMapper.updateById(job);
- }
- }
- private AdmJobSpace matchByOutline(HashMap<String, AdmJobSpace> jobMap, AdmObject space){
- if(jobMap.size() == 0)
- return null;
- ArrayNode o1 = (ArrayNode) space.getInfo("outline");
- if(!isValidOutline(o1))
- return null;
- Polygon[] ps = GeomUtil.getPolygon(o1);
- Map.Entry<String, AdmJobSpace> target = null;
- for(Map.Entry<String, AdmJobSpace> entry : jobMap.entrySet()){
- ArrayNode o2 = entry.getValue().getOutline();
- if(isValidOutline(o2) && polygonsMatch(ps, GeomUtil.getPolygon(o2))){
- target = entry;
- break;
- }
- }
- if(target != null){
- jobMap.remove(target.getKey());
- return target.getValue();
- }
- return null;
- }
- /**
- * 判断空间轮廓是否变化
- * TODO 区分覆盖等情况
- */
- private boolean outlineMatch(ArrayNode o1, ArrayNode o2){
- return polygonsMatch(GeomUtil.getPolygon(o1), GeomUtil.getPolygon(o2));
- }
- /**
- * 轮廓匹配判断
- * TODO 暂不考虑顺序
- */
- private boolean polygonsMatch(Polygon[] ps1, Polygon[] ps2){
- if (ps1.length == ps2.length) {
- for (int i = 0; i < ps2.length; i++) {
- if (!ps1[i].equalsExact(ps2[i]))
- return false;
- }
- return true;
- }
- return false;
- }
- private boolean isValidOutline(ArrayNode outline) {
- if(outline != null && outline.size() > 0 && outline.get(0).isArray()) {
- ArrayNode o1 = (ArrayNode) outline.get(0);
- if (o1.size() > 0 && o1.get(0).isArray()) {
- ArrayNode o2 = (ArrayNode) o1.get(0);
- return o2.size() >= 3;
- }
- }
- return false;
- }
- @Autowired
- private OldAdmClient oldAdmClient;
- /**
- * 把地图文件从image-service转存到文件服务
- */
- @Override
- @Transactional(rollbackFor = Exception.class)
- public void uploadFloorMap(String groupCode, String projectId) {
- List<AdmObject> floors = objectService.queryM2dByObjType(projectId, AdmConst.OBJ_TYPE_FLOOR);
- List<AdmObject> modifiedFloors = new ArrayList<>();
- for(AdmObject floor : floors) {
- ObjectNode infos = floor.getInfos();
- if(infos != null) {
- JsonNode mapNode = infos.get("floorMap");
- JsonNode mapIdNode = infos.get("floorMapId");
- if(mapNode != null){
- String map = mapNode.asText();
- String mapId = mapIdNode != null ? mapIdNode.asText() : null;
- if(mapId != null) {
- FileInfo fileInfo = FileClientFacade.load(mapId);
- if(fileInfo != null && fileInfo.getFileName().equals(map))
- continue; //文件无变化
- //删除之前的地图文件
- FileStorageHelper.deleteFile(mapId);
- }
- try {
- Response serviceResponse = oldAdmClient.getFloorMap(map, "revit");
- Response.Body body = serviceResponse.body();
- InputStream inputStream = body.asInputStream();
- FileInfo fileInfo = FileInfoCreator.of(groupCode, projectId, AdmConst.APP_ID, map);
- String fileId = FileStorageHelper.uploadFile(fileInfo, inputStream);
- infos.put("floorMapId", fileId);
- modifiedFloors.add(floor);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- }
- objectService.update(modifiedFloors);
- }
- }
|