package com.fdkankan.scene.service.impl; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.fdkankan.common.constant.CommonStatus; import com.fdkankan.common.constant.ErrorCode; import com.fdkankan.common.constant.FileBizType; import com.fdkankan.common.exception.BusinessException; import com.fdkankan.common.util.FileUtils; import com.fdkankan.fyun.face.FYunFileServiceInterface; import com.fdkankan.model.constants.ConstantFilePath; import com.fdkankan.model.constants.UploadFilePath; import com.fdkankan.redis.constant.RedisKey; import com.fdkankan.redis.constant.RedisLockKey; import com.fdkankan.redis.util.RedisLockUtil; import com.fdkankan.redis.util.RedisUtil; import com.fdkankan.scene.bean.TagBean; import com.fdkankan.scene.entity.SceneEditInfoExt; import com.fdkankan.scene.entity.ScenePlus; import com.fdkankan.scene.entity.ScenePlusExt; import com.fdkankan.scene.service.*; import com.fdkankan.scene.vo.BaseJsonArrayParamVO; import com.fdkankan.scene.vo.BaseSceneParamVO; import com.fdkankan.scene.vo.DeleteFileParamVO; import com.fdkankan.scene.vo.DeleteSidListParamVO; import com.fdkankan.web.response.ResultData; import com.google.j2objc.annotations.AutoreleasePool; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.io.IOException; import java.util.*; import java.util.stream.Collectors; @Service public class CutModelServiceImpl implements ICutModelService { private final String CUT_MODEL_JSON_NAME = "cutModel.json"; @Autowired private IScenePlusService scenePlusService; @Autowired private IScenePlusExtService scenePlusExtService; @Autowired private ISceneEditInfoExtService sceneEditInfoExtService; @Autowired private ISceneEditInfoService sceneEditInfoService; @Autowired private RedisUtil redisUtil; @Autowired private RedisLockUtil redisLockUtil; @Autowired private FYunFileServiceInterface fYunFileService; @Autowired private ISceneUploadService sceneUploadService; @Override public ResultData saveCutModel(BaseJsonArrayParamVO param) throws Exception { ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getNum()); this.addOrUpdate(param.getNum(), param.getData()); //保存数据库 SceneEditInfoExt sceneEditInfoExt = sceneEditInfoExtService.getByScenePlusId(scenePlus.getId()); this.updateDb(param.getNum(), scenePlus.getId()); // this.updateById(sceneEditInfoExt); sceneEditInfoService.upgradeVersionById(sceneEditInfoExt.getEditInfoId()); return ResultData.ok(); } @Override public List listCutModel(BaseSceneParamVO param) throws Exception { List tags = new ArrayList<>(); ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getNum()); SceneEditInfoExt sceneEditInfoExt = sceneEditInfoExtService.getByScenePlusId(scenePlus.getId()); this.syncFileToRedis(param.getNum()); //获取裁剪模型数据 String key = String.format(RedisKey.SCENE_CUT_MODEL, param.getNum()); List list = redisUtil.hgetValues(key); if(CollUtil.isNotEmpty(list)){ List sortList = list.stream().map(str -> { JSONObject jsonObject = JSON.parseObject(str); TagBean tagBean = new TagBean(); tagBean.setCreateTime(jsonObject.getLong("createTime")); jsonObject.remove("createTime"); tagBean.setTag(jsonObject); return tagBean; }).collect(Collectors.toList()); sortList.sort(Comparator.comparingLong(TagBean::getCreateTime).reversed()); tags = sortList.stream().map(item -> item.getTag()).collect(Collectors.toList()); } return tags; } @Override public ResultData deleteCutModel(DeleteSidListParamVO param) throws Exception { ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getNum()); ScenePlusExt scenePlusExt = scenePlusExtService.getScenePlusExtByPlusId(scenePlus.getId()); String bucket = scenePlusExt.getYunFileBucket(); List deleteSidList = param.getSidList(); this.syncFileToRedis(param.getNum()); //处理删除状态数据 List deleteList = this.deleteCutModel(param.getNum(), deleteSidList, bucket); //写入本地文件,作为备份 this.writeFile(param.getNum()); //保存数据库 SceneEditInfoExt sceneEditInfoExt = sceneEditInfoExtService.getByScenePlusId(scenePlus.getId()); this.updateDb(param.getNum(), scenePlus.getId()); sceneEditInfoService.upgradeVersionById(sceneEditInfoExt.getEditInfoId()); return ResultData.ok(); } @Override public void publicCutModel(String sceneNum, String bucket) throws IOException { String Key = String.format(RedisKey.SCENE_CUT_MODEL, sceneNum); String userEditPath = String.format(UploadFilePath.USER_EDIT_PATH, sceneNum) + "cutModel.json"; List list = redisUtil.hgetValues(Key); if(CollUtil.isEmpty(list)){ fYunFileService.deleteFile(bucket, userEditPath); return; } List collect = list.stream().map(str -> JSON.parseObject(str)).collect(Collectors.toList()); fYunFileService.uploadFile(bucket, JSON.toJSONString(collect).getBytes(), userEditPath); } private List deleteCutModel(String num, List deleteSidList, String bucket) throws Exception { if(CollUtil.isEmpty(deleteSidList)){ return null; } //从redis中加载热点数据 String key = String.format(RedisKey.SCENE_CUT_MODEL, num); List deletDataList = redisUtil.hMultiGet(key, deleteSidList); if(CollUtil.isNotEmpty(deletDataList)){ redisUtil.hdel(key, deleteSidList.toArray()); } return deletDataList; } private void updateDb(String num, Long scenePlusId){ //查询缓存是否包含热点数据 String key = String.format(RedisKey.SCENE_CUT_MODEL, num); Map cutModelMap = redisUtil.hmget(key); boolean hasCutModel= false; for (Map.Entry tagMap : cutModelMap.entrySet()) { if(StrUtil.isEmpty(tagMap.getValue())){ continue; } hasCutModel = true; break; } //更改热点状态 sceneEditInfoExtService.update( new LambdaUpdateWrapper() .set(SceneEditInfoExt::getCutModel, hasCutModel ? CommonStatus.YES.code().intValue() : CommonStatus.NO.code().intValue()) .eq(SceneEditInfoExt::getScenePlusId,scenePlusId)); } private void addOrUpdate(String num, List data) throws Exception{ Map addOrUpdateMap = new HashMap<>(); int i = 0; for (JSONObject jsonObject : data) { jsonObject.put("createTime", Calendar.getInstance().getTimeInMillis() + i++); addOrUpdateMap.put(jsonObject.getString("sid"), JSON.toJSONString(jsonObject)); } this.syncFileToRedis(num); //处理新增和修改数据 this.addOrUpdateHandler(num, addOrUpdateMap); } private void addOrUpdateHandler(String num, Map addOrUpdateMap){ if(CollUtil.isEmpty(addOrUpdateMap)) return; //批量写入缓存 String key = String.format(RedisKey.SCENE_CUT_MODEL, num); redisUtil.hmset(key, addOrUpdateMap); //写入本地文件,作为备份 this.writeFile(num); } private void writeFile(String num){ String lockKey = String.format(RedisLockKey.LOCK_CUT_MODEL_SYNC, num); String lockVal = cn.hutool.core.lang.UUID.randomUUID().toString(); boolean lock = redisLockUtil.lock(lockKey, lockVal, RedisKey.EXPIRE_TIME_1_MINUTE); if(!lock){ return; } try{ String dataKey = String.format(RedisKey.SCENE_CUT_MODEL, num); String cutModelJsonPath = String.format(ConstantFilePath.SCENE_USER_PATH_V4, num) + CUT_MODEL_JSON_NAME; if(!redisUtil.hasKey(dataKey)){ FileUtil.del(cutModelJsonPath); return; } Map cutModelmap = redisUtil.hmget(dataKey); List list = cutModelmap.entrySet().stream().map(entry->JSON.parseObject(entry.getValue())).collect(Collectors.toList()); FileUtil.writeUtf8String(JSON.toJSONString(list), cutModelJsonPath); }finally { redisLockUtil.unlockLua(lockKey, lockVal); } } private void syncFileToRedis(String num) throws Exception{ String key = String.format(RedisKey.SCENE_CUT_MODEL, num); boolean exist = redisUtil.hasKey(key); if(exist){ return; } String lockKey = String.format(RedisLockKey.LOCK_CUT_MODEL_SYNC, num); String lockVal = cn.hutool.core.lang.UUID.randomUUID().toString(); boolean lock = redisLockUtil.lock(lockKey, lockVal, RedisKey.EXPIRE_TIME_1_MINUTE); if(!lock){ throw new BusinessException(ErrorCode.SYSTEM_BUSY); } try{ exist = redisUtil.hasKey(key); if(exist){ return; } String cutModelFilePath = String.format(ConstantFilePath.SCENE_USER_PATH_V4, num) + CUT_MODEL_JSON_NAME; String cutModelData = FileUtils.readUtf8String(cutModelFilePath); if(StrUtil.isEmpty(cutModelData)){ return; } JSONArray tagsArr = JSON.parseArray(cutModelData); if(CollUtil.isEmpty(tagsArr)){ return; } Map map = new HashMap<>(); for (Object o : tagsArr) { JSONObject jo = (JSONObject)o; map.put(jo.getString("sid"), jo.toJSONString()); } redisUtil.hmset(key, map); }finally { redisLockUtil.unlockLua(lockKey, lockVal); } } }