package com.yj.earth.business.controller; import cn.dev33.satoken.stp.StpUtil; import cn.hutool.core.io.FileUtil; import cn.hutool.core.lang.UUID; import cn.hutool.core.util.IdUtil; import cn.hutool.crypto.digest.DigestUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.drew.imaging.ImageMetadataReader; import com.drew.imaging.ImageProcessingException; import com.drew.metadata.Directory; import com.drew.metadata.Metadata; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.yj.earth.annotation.CheckAuth; import com.yj.earth.business.domain.FileInfo; import com.yj.earth.business.domain.Role; import com.yj.earth.business.domain.Source; import com.yj.earth.business.service.*; import com.yj.earth.common.service.SourceDataGenerator; import com.yj.earth.common.service.SourceParamsValidator; import com.yj.earth.common.util.ApiResponse; import com.yj.earth.common.util.MapUtil; import com.yj.earth.dto.source.*; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.*; import static com.yj.earth.common.constant.GlobalConstant.DIRECTORY; import static com.yj.earth.common.constant.GlobalConstant.SHOW; @Slf4j @Tag(name = "树形结构管理") @RestController @RequestMapping("/source") public class SourceController { @Resource private SourceService sourceService; @Resource private UserService userService; @Resource private RoleSourceService roleSourceService; @Resource private RoleService roleService; @Resource private SourceParamsValidator sourceParamsValidator; @Resource private SourceDataGenerator sourceDataGenerator; @Resource private FileInfoService fileInfoService; @Resource private FileInfoController fileInfoControllerl; @Value("${file.upload.path}") private String uploadPath; @PostMapping("/addDirectory") @Operation(summary = "新增目录资源") public ApiResponse addDirectory(@RequestBody AddDirectoryDto addDirectoryDto) { // 校验是否通过 String message = sourceService.checkIsPass(addDirectoryDto.getParentId(), addDirectoryDto.getSourceName()); if (message != null) { return ApiResponse.failure(message); } // 通过之后保存资源 Source source = new Source(); BeanUtils.copyProperties(addDirectoryDto, source); source.setSourceType(DIRECTORY); source.setIsShow(SHOW); sourceService.save(source); // 添加资源到该用户的角色下 roleSourceService.addRoleSource(userService.getById(StpUtil.getLoginIdAsString()).getRoleId(), source.getId()); return ApiResponse.success(source); } @Operation(summary = "新增模型资源") @PostMapping("/addModelSource") public ApiResponse addModelSource(@RequestBody AddModelSourceDto addModelSourceDto) { // 获取资源绝对路径 String sourcePath = addModelSourceDto.getSourcePath(); // 获取资源名称 String sourceName = FileUtil.mainName(sourcePath); // 校验是否通过 String message = sourceService.checkIsPass(addModelSourceDto.getParentId(), sourceName); if (message != null) { return ApiResponse.failure(message); } // 调用SDK加载资源 String sourceId = sourceService.addAndGetSourceId(sourcePath); // 获取文件路径并处理详情 String detail = sourceService.getDetail(sourcePath, sourceId); // 构建并保存资源对象 Source source = new Source(); source.setId(addModelSourceDto.getId()); source.setSourcePath(sourcePath); source.setSourceName(sourceName); source.setParentId(addModelSourceDto.getParentId()); source.setTreeIndex(addModelSourceDto.getTreeIndex()); source.setParams(addModelSourceDto.getParams()); source.setDetail(detail); source.setSourceType(MapUtil.getString(MapUtil.jsonToMap(detail), "fileType")); source.setIsShow(SHOW); sourceService.save(source); // 添加资源到该用户的角色下 roleSourceService.addRoleSource(userService.getById(StpUtil.getLoginIdAsString()).getRoleId(), source.getId()); return ApiResponse.success(source); } @Operation(summary = "新增其他资源") @PostMapping("/addOtherSource") public ApiResponse addOtherSource(@RequestBody AddOtherSourceDto addOtherSourceDto) throws JsonProcessingException { // 校验是否通过 String message = sourceService.checkIsPass(addOtherSourceDto.getParentId(), addOtherSourceDto.getSourceName()); if (message != null) { return ApiResponse.failure(message); } // 验证并转换参数 Object validatedParams = sourceParamsValidator.validateAndConvert( addOtherSourceDto.getSourceType(), addOtherSourceDto.getParams() ); Source source = new Source(); BeanUtils.copyProperties(addOtherSourceDto, source); source.setIsShow(SHOW); source.setParams(MapUtil.objectToJson(validatedParams)); sourceService.save(source); // 添加资源到该用户的角色下 roleSourceService.addRoleSource(userService.getById(StpUtil.getLoginIdAsString()).getRoleId(), source.getId()); return ApiResponse.success(source); } @Operation(summary = "更新资源信息") @PostMapping("/update") public ApiResponse updateSource(@RequestBody UpdateSourceDto updateSourceDto) { // 查询资源 Source source = sourceService.getById(updateSourceDto.getId()); if (source == null) { return ApiResponse.failure("资源不存在"); } // 更新基本信息 BeanUtils.copyProperties(updateSourceDto, source); // 处理参数更新 if (updateSourceDto.getParams() != null && !updateSourceDto.getParams().isEmpty()) { // 获取类型 String sourceType = source.getSourceType(); // 验证参数 Object validatedParams = sourceParamsValidator.validateAndConvert( sourceType, updateSourceDto.getParams() ); // 获取原始数据的 Map 并合并新参数 Map dataMap = MapUtil.jsonToMap(source.getParams()); MapUtil.mergeMaps(dataMap, updateSourceDto.getParams()); source.setParams(MapUtil.mapToString(dataMap)); } // 保存更新 sourceService.updateById(source); return ApiResponse.success(source); } @Operation(summary = "获取资源列表") @GetMapping("/list") public ApiResponse list() { return ApiResponse.success(sourceService.getSourceListByUserId(StpUtil.getLoginIdAsString())); } @Operation(summary = "删除资源数据") @PostMapping("/delete") public ApiResponse delete(@RequestBody DeleteSourceDto deleteSourceDto) { if (deleteSourceDto.getIds() == null || deleteSourceDto.getIds().isEmpty()) { return ApiResponse.failure("资源ID列表不能为空"); } // 收集所有需要删除的资源ID(包括子资源) Set allIds = new HashSet<>(); for (String id : deleteSourceDto.getIds()) { // 获取资源 Source source = sourceService.getById(id); if (source == null) { return ApiResponse.failure("资源ID为" + id + "的资源不存在"); } // 查询ID等于自身或者父级ID等于自身的资源 LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(Source::getId, source.getId()) .or() .eq(Source::getParentId, source.getId()); List list = sourceService.list(queryWrapper); // 筛选ID列表并添加到总集合中 list.stream().map(Source::getId).forEach(allIds::add); } // 删除这些资源 sourceService.removeByIds(allIds); // 删除这些资源下的所有角色资源关系 roleSourceService.deleteRoleSource( userService.getById(StpUtil.getLoginIdAsString()).getRoleId(), new ArrayList<>(allIds) ); return ApiResponse.success(null); } @PostMapping("/uploadLocationImage") @Operation(summary = "新增定位图片") public ApiResponse uploadLocationImage(@RequestParam("ids") @Parameter(description = "上传定位图片ID列表") List ids, @RequestParam(value = "parentId", required = false) @Parameter(description = "父节点ID") String parentId, @RequestParam(value = "treeIndex", required = false) @Parameter(description = "树状索引") Integer treeIndex, @RequestParam("files") @Parameter(description = "带有定位的图片文件", required = true) MultipartFile[] files) { for (int i = 0; i < files.length; i++) { String detail = fileInfoControllerl.handleLocationImageUpload(files[i]); // 构建并保存资源对象 Source source = new Source(); source.setId(ids.get(i)); source.setSourceName(files[i].getOriginalFilename()); source.setParentId(parentId); source.setSourceType("locationImage"); source.setTreeIndex(treeIndex); source.setDetail(detail); source.setIsShow(SHOW); sourceService.save(source); // 添加资源到该用户的角色下 roleSourceService.addRoleSource(userService.getById(StpUtil.getLoginIdAsString()).getRoleId(), source.getId()); } return ApiResponse.success(null); } @GetMapping("/type") @Operation(summary = "获取已有类型") public ApiResponse getSupportedSourceTypes() { Set supportedTypes = sourceParamsValidator.getSupportedSourceTypes(); return ApiResponse.success(supportedTypes); } @Operation(summary = "获取示例数据") @GetMapping("/paramsExample") public String getExampleData(String sourceType) throws JsonProcessingException { return sourceDataGenerator.generateDefaultJson(sourceType); } @Operation(summary = "设置默认数据") @GetMapping("/default") public ApiResponse getDefaultData() { log.info("开始初始化默认资源数据"); String userId = StpUtil.getLoginIdAsString(); String roleId = userService.getById(userId).getRoleId(); // 创建一级目录 createSourceIfNotExists("倾斜模型", "directory", null, 0, 1, roleId); createSourceIfNotExists("人工模型", "directory", null, 0, 1, roleId); createSourceIfNotExists("卫星底图", "directory", null, 0, 1, roleId); createSourceIfNotExists("地形", "directory", null, 0, 1, roleId); // 创建"在线图源"目录及其子资源 Source onlineSource = createSourceIfNotExists("在线图源", "directory", null, 0, 1, roleId); if (onlineSource != null) { String onlineSourceId = onlineSource.getId(); createSourceIfNotExists("卫星图", "arcgisWximagery", onlineSourceId, 0, 1, roleId); createSourceIfNotExists("暗黑地图", "arcgisBlueImagery", onlineSourceId, 0, 1, roleId); createSourceIfNotExists("路网图", "gdlwImagery", onlineSourceId, 0, 1, roleId); createSourceIfNotExists("矢量图", "gdslImagery", onlineSourceId, 0, 1, roleId); } log.info("默认资源数据初始化完成"); return ApiResponse.success(null); } /** * 检查资源是否存在、不存在则创建并关联角色资源 */ private Source createSourceIfNotExists(String sourceName, String sourceType, String parentId, int treeIndex, int isShow, String roleId) { // 检查资源是否已存在(通过名称和父ID组合判断唯一性) Source existingSource = sourceService.getOne(new LambdaQueryWrapper() .eq(Source::getSourceName, sourceName) .eq(parentId != null, Source::getParentId, parentId) .isNull(parentId == null, Source::getParentId)); if (existingSource != null) { return existingSource; } // 不存在则创建新资源 try { Source newSource = new Source(); newSource.setId(cn.hutool.core.lang.UUID.fastUUID().toString(true)); newSource.setSourceName(sourceName); newSource.setSourceType(sourceType); newSource.setParentId(parentId); newSource.setTreeIndex(treeIndex); newSource.setIsShow(isShow); sourceService.save(newSource); // 关联角色资源 roleSourceService.addRoleSource(roleId, newSource.getId()); return newSource; } catch (Exception e) { return null; } } }