123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433 |
- 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.query.LambdaQueryWrapper;
- import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
- 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.SceneEditInfo;
- import com.fdkankan.scene.entity.SceneEditInfoExt;
- import com.fdkankan.scene.entity.ScenePlus;
- import com.fdkankan.scene.entity.ScenePlusExt;
- import com.fdkankan.scene.mapper.ISceneEditInfoExtMapper;
- import com.fdkankan.scene.service.*;
- import com.fdkankan.scene.vo.*;
- import com.fdkankan.web.response.ResultData;
- import org.aspectj.apache.bcel.generic.RET;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Service;
- import java.util.*;
- import java.util.concurrent.atomic.AtomicInteger;
- import java.util.stream.Collectors;
- /**
- * <p>
- * 服务实现类
- * </p>
- *
- * @author
- * @since 2022-03-07
- */
- @Service
- public class SceneEditInfoExtServiceImpl extends ServiceImpl<ISceneEditInfoExtMapper, SceneEditInfoExt> implements ISceneEditInfoExtService {
- @Autowired
- private IScenePlusService scenePlusService;
- @Autowired
- private IScenePlusExtService scenePlusExtService;
- @Autowired
- private ISceneEditInfoService sceneEditInfoService;
- @Autowired
- private RedisUtil redisUtil;
- @Autowired
- private RedisLockUtil redisLockUtil;
- @Autowired
- private FYunFileServiceInterface fYunFileService;
- @Autowired
- private ISceneUploadService sceneUploadService;
- @Override
- public SceneEditInfoExt getByScenePlusId(long scenePlusId) {
- return this.getOne(new LambdaQueryWrapper<SceneEditInfoExt>().eq(SceneEditInfoExt::getScenePlusId, scenePlusId));
- }
- @Override
- public SceneEditInfoExt getByEditInfoId(long editInfoId) {
- return this.getOne(new LambdaQueryWrapper<SceneEditInfoExt>().eq(SceneEditInfoExt::getEditInfoId, editInfoId));
- }
- @Override
- public void updateToursByNum(String num, Integer tours) {
- ScenePlus scenePlus = scenePlusService.getScenePlusByNum(num);
- if(Objects.isNull(scenePlus)){
- throw new BusinessException(ErrorCode.FAILURE_CODE_5005);
- }
- SceneEditInfo sceneEditInfo = sceneEditInfoService.getByScenePlusId(scenePlus.getId());
- sceneEditInfoService.upgradeVersionById(sceneEditInfo.getId());
- SceneEditInfoExt sceneEditInfoExt = this.getByEditInfoId(sceneEditInfo.getId());
- sceneEditInfoExt.setTours(tours);
- this.updateById(sceneEditInfoExt);
- }
- @Override
- public ResultData saveBillboards(BaseJsonArrayParamVO param) throws Exception {
- ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getNum());
- this.addOrUpdateBillboards(param.getNum(), param.getData());
- this.addOrUpdateBillboardsStyles(param.getNum(), param.getStyles());
- //保存数据库
- SceneEditInfoExt sceneEditInfoExt = this.getByScenePlusId(scenePlus.getId());
- this.updateBillboards(param.getNum(), sceneEditInfoExt);
- // this.updateById(sceneEditInfoExt);
- sceneEditInfoService.upgradeVersionById(sceneEditInfoExt.getEditInfoId());
- return ResultData.ok();
- }
- private void addOrUpdateBillboardsStyles(String num, List<JSONObject> styles) throws Exception{
- this.syncBillboardsStylesFromFileToRedis(num);
- if(CollUtil.isEmpty(styles)){
- return;
- }
- long time = Calendar.getInstance().getTimeInMillis();
- Map<String, String> styleMap = new HashMap<>();
- AtomicInteger index = new AtomicInteger();
- styles.stream().forEach(style->{
- String id = style.getString("sid");
- style.put("createTime", time + index.getAndIncrement());
- styleMap.put(id, style.toJSONString());
- });
- String key = String.format(RedisKey.SCENE_BILLBOARDS_STYLES, num);
- redisUtil.hmset(key, styleMap);
- //写入本地文件,作为备份
- this.writeBillboardStylesJson(num);
- }
- private void syncBillboardsStylesFromFileToRedis(String num) throws Exception{
- String key = String.format(RedisKey.SCENE_BILLBOARDS_STYLES, num);
- boolean exist = redisUtil.hasKey(key);
- if(exist){
- return;
- }
- String lockKey = String.format(RedisLockKey.LOCK_BILLBOARDS_STYLES_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 stylesPath = String.format(ConstantFilePath.SCENE_USER_PATH_V4, num);
- String stylesData = FileUtils.readUtf8String(stylesPath + "billboards-styles.json");
- if(StrUtil.isEmpty(stylesData)){
- return;
- }
- JSONArray stylesArr = JSON.parseArray(stylesData);
- if(CollUtil.isEmpty(stylesArr)){
- return;
- }
- Map<String, String> styleMap = new HashMap<>();
- for (Object style : stylesArr) {
- JSONObject styleObj = (JSONObject)style;
- String id = styleObj.getString("sid");
- styleMap.put(id, styleObj.toJSONString());
- }
- redisUtil.hmset(key, styleMap);
- }finally {
- redisLockUtil.unlockLua(lockKey, lockVal);
- }
- }
- @Override
- public ResultData deleteBillboards(DeleteSidListParamVO param) throws Exception {
- ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getNum());
- ScenePlusExt scenePlusExt = scenePlusExtService.getScenePlusExtByPlusId(scenePlus.getId());
- String bucket = scenePlusExt.getYunFileBucket();
- List<String> deleteSidList = param.getSidList();
- this.syncBillboardsFromFileToRedis(param.getNum());
- //处理删除状态数据
- this.deleteBillboards(param.getNum(), deleteSidList, bucket);
- //写入本地文件,作为备份
- this.writeBillboardJson(param.getNum());
- //保存数据库
- SceneEditInfoExt sceneEditInfoExt = this.getByScenePlusId(scenePlus.getId());
- this.updateBillboards(param.getNum(), sceneEditInfoExt);
- sceneEditInfoService.upgradeVersionById(sceneEditInfoExt.getEditInfoId());
- return ResultData.ok();
- }
- @Override
- public JSONObject listBillboards(BaseSceneParamVO param) throws Exception {
- JSONObject result = new JSONObject();
- List<JSONObject> tags = new ArrayList<>();
- List<JSONObject> styles = new ArrayList<>();
- ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getNum());
- SceneEditInfoExt sceneEditInfoExt = this.getByScenePlusId(scenePlus.getId());
- if(sceneEditInfoExt.getBillboards() == CommonStatus.NO.code().intValue()){
- result.put("tags", tags);
- result.put("styles", styles);
- return result;
- }
- this.syncBillboardsFromFileToRedis(param.getNum());
- //获取指示牌数据
- String key = String.format(RedisKey.SCENE_BILLBOARDS, param.getNum());
- List<String> list = redisUtil.hgetValues(key);
- List<TagBean> 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());
- result.put("tags", tags);
- //获取图标数据
- this.syncBillboardsStylesFromFileToRedis(param.getNum());
- key = String.format(RedisKey.SCENE_BILLBOARDS_STYLES, param.getNum());
- list = redisUtil.hgetValues(key);
- 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());
- styles = sortList.stream().map(item -> item.getTag()).collect(Collectors.toList());
- result.put("styles", styles);
- return result;
- }
- private void deleteBillboards(String num, List<String> deleteSidList, String bucket) throws Exception {
- if(CollUtil.isEmpty(deleteSidList)){
- return;
- }
- //从redis中加载热点数据
- String key = String.format(RedisKey.SCENE_BILLBOARDS, num);
- List<String> deletDataList = redisUtil.hMultiGet(key, deleteSidList);
- if(CollUtil.isEmpty(deletDataList))
- return;
- //从redis中移除热点数据
- redisUtil.hdel(key, deleteSidList.toArray());
- }
- private void addOrUpdateBillboards(String num, List<JSONObject> data) throws Exception{
- Map<String, String> 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.syncBillboardsFromFileToRedis(num);
- //处理新增和修改数据
- this.addOrUpdateBillboardsHandler(num, addOrUpdateMap);
- }
- /**
- * <p>
- 保证指示牌数据安全性,当redis宕机导致热点数据丢失时,可以从文件中读取,恢复到redis
- * </p>
- * @author dengsixing
- * @date 2022/3/3
- **/
- private void syncBillboardsFromFileToRedis(String num) throws Exception{
- String key = String.format(RedisKey.SCENE_BILLBOARDS, num);
- boolean exist = redisUtil.hasKey(key);
- if(exist){
- return;
- }
- String lockKey = String.format(RedisLockKey.LOCK_BILLBOARDS_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 billboardsFilePath = String.format(ConstantFilePath.SCENE_USER_PATH_V4, num) + "billboards.json";
- String billboardsData = FileUtils.readUtf8String(billboardsFilePath);
- if(StrUtil.isEmpty(billboardsData)){
- return;
- }
- JSONArray tagsArr = JSON.parseArray(billboardsData);
- if(CollUtil.isEmpty(tagsArr)){
- return;
- }
- Map<String, String> 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);
- }
- }
- private void addOrUpdateBillboardsHandler(String num, Map<String, String> addOrUpdateMap){
- if(CollUtil.isEmpty(addOrUpdateMap))
- return;
- //批量写入缓存
- String key = String.format(RedisKey.SCENE_BILLBOARDS, num);
- redisUtil.hmset(key, addOrUpdateMap);
- //写入本地文件,作为备份
- this.writeBillboardJson(num);
- }
- /**
- * <p>
- 热点数据保存
- * </p>
- * @author dengsixing
- * @date 2022/3/3
- *
- **/
- private void writeBillboardJson(String num){
- String lockKey = String.format(RedisLockKey.LOCK_BILLBOARDS_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_BILLBOARDS, num);
- String hotJsonPath = String.format(ConstantFilePath.SCENE_USER_PATH_V4, num) + "billboards.json";
- if(!redisUtil.hasKey(dataKey)){
- FileUtil.del(hotJsonPath);
- return;
- }
- Map<String, String> billboardMap = redisUtil.hmget(dataKey);
- List<JSONObject> billboardList = billboardMap.entrySet().stream().map(entry->JSON.parseObject(entry.getValue())).collect(Collectors.toList());
- FileUtil.writeUtf8String(JSON.toJSONString(billboardList), hotJsonPath);
- }finally {
- redisLockUtil.unlockLua(lockKey, lockVal);
- }
- }
- private void writeBillboardStylesJson(String num){
- String lockKey = String.format(RedisLockKey.LOCK_BILLBOARDS_STYLES_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_BILLBOARDS_STYLES, num);
- String stylesPath = String.format(ConstantFilePath.SCENE_USER_PATH_V4, num) + "billboards-styles.json";
- if(!redisUtil.hasKey(dataKey)){
- FileUtil.del(stylesPath);
- return;
- }
- Map<String, String> billboardStylesMap = redisUtil.hmget(dataKey);
- List<JSONObject> billboardStyleList = billboardStylesMap.entrySet().stream().map(entry->JSON.parseObject(entry.getValue())).collect(Collectors.toList());
- FileUtil.writeUtf8String(JSON.toJSONString(billboardStyleList), stylesPath);
- }finally {
- redisLockUtil.unlockLua(lockKey, lockVal);
- }
- }
- private void updateBillboards(String num, SceneEditInfoExt sceneEditInfoExt){
- //查询缓存是否包含热点数据
- String key = String.format(RedisKey.SCENE_BILLBOARDS, num);
- Map<String, String> billboardsMap = redisUtil.hmget(key);
- boolean hashBillboards= false;
- for (Map.Entry<String, String> tagMap : billboardsMap.entrySet()) {
- if(StrUtil.isEmpty(tagMap.getValue())){
- continue;
- }
- hashBillboards = true;
- break;
- }
- //更改热点状态
- sceneEditInfoExt.setBillboards(hashBillboards ? CommonStatus.YES.code().intValue() : CommonStatus.NO.code().intValue());
- this.updateById(sceneEditInfoExt);
- }
- @Override
- public ResultData deleteBillboardsStyles(DeleteStylesParamVO param) throws Exception {
- ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getNum());
- if (scenePlus == null)
- throw new BusinessException(ErrorCode.FAILURE_CODE_5005);
- List<String> sidList = param.getSidList();
- this.syncBillboardsStylesFromFileToRedis(param.getNum());
- String key = String.format(RedisKey.SCENE_BILLBOARDS_STYLES, param.getNum());
- List<String> deleteList = redisUtil.hMultiGet(key, sidList);
- redisUtil.hdel(key, sidList.toArray());
- //写入本地文件,作为备份
- this.writeBillboardStylesJson(param.getNum());
- //删除oss文件
- List<String> deleteFileList = deleteList.stream().map(str -> {
- JSONObject parse = JSON.parseObject(str);
- return parse.getString("url");
- }).collect(Collectors.toList());
- sceneUploadService.delete(
- DeleteFileParamVO.builder()
- .num(param.getNum())
- .fileNames(deleteFileList)
- .bizType(FileBizType.BILLBOARD_ICON.code()).build());
- return ResultData.ok();
- }
- }
|