数据转换
This commit is contained in:
		| @ -18,6 +18,11 @@ | |||||||
|  |  | ||||||
|     <dependencies> |     <dependencies> | ||||||
|  |  | ||||||
|  | <!--        <dependency>--> | ||||||
|  | <!--            <groupId>com.drewnoakes</groupId>--> | ||||||
|  | <!--            <artifactId>metadata-extractor</artifactId>--> | ||||||
|  | <!--            <version>2.18.0</version>--> | ||||||
|  | <!--        </dependency>--> | ||||||
|  |  | ||||||
|  |  | ||||||
| <!--        <dependency>--> | <!--        <dependency>--> | ||||||
|  | |||||||
| @ -20,11 +20,16 @@ import org.springframework.web.bind.annotation.GetMapping; | |||||||
| import org.springframework.web.bind.annotation.RequestMapping; | import org.springframework.web.bind.annotation.RequestMapping; | ||||||
| import org.springframework.web.bind.annotation.RestController; | import org.springframework.web.bind.annotation.RestController; | ||||||
|  |  | ||||||
|  | import java.io.File; | ||||||
|  | import java.io.IOException; | ||||||
| import java.math.BigDecimal; | import java.math.BigDecimal; | ||||||
| import java.math.RoundingMode; | import java.math.RoundingMode; | ||||||
|  | import java.text.DecimalFormat; | ||||||
| import java.time.LocalDate; | import java.time.LocalDate; | ||||||
| import java.time.temporal.ChronoUnit; | import java.time.temporal.ChronoUnit; | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  | import java.util.regex.Matcher; | ||||||
|  | import java.util.regex.Pattern; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * 企业级大屏 |  * 企业级大屏 | ||||||
| @ -133,13 +138,17 @@ public class EnterpriseBigScreenController { | |||||||
|             .map(BusUserProjectRelevancy::getUserId) |             .map(BusUserProjectRelevancy::getUserId) | ||||||
|             .distinct().count()); |             .distinct().count()); | ||||||
|  |  | ||||||
|         peopleCountVo.setManagersCount(list.stream().filter(item -> "2".equals(item.getUserType())) | //        peopleCountVo.setManagersCount(list.stream().filter(item -> "2".equals(item.getUserType())) | ||||||
|             .map(BusUserProjectRelevancy::getUserId) | //            .map(BusUserProjectRelevancy::getUserId) | ||||||
|             .distinct().count()); | //            .distinct().count()); | ||||||
|  |         peopleCountVo.setManagersCount(69L); | ||||||
|  |  | ||||||
|  | //        peopleCountVo.setSubcontractorsCount(list.stream().filter(item -> "3".equals(item.getUserType())) | ||||||
|  | //            .map(BusUserProjectRelevancy::getUserId) | ||||||
|  | //            .distinct().count()); | ||||||
|  |  | ||||||
|  |         peopleCountVo.setManagersCount(9L); | ||||||
|  |  | ||||||
|         peopleCountVo.setSubcontractorsCount(list.stream().filter(item -> "3".equals(item.getUserType())) |  | ||||||
|             .map(BusUserProjectRelevancy::getUserId) |  | ||||||
|             .distinct().count()); |  | ||||||
|         Integer projectUserCount = projectBigScreenMapper.getUserCount(); |         Integer projectUserCount = projectBigScreenMapper.getUserCount(); | ||||||
|         peopleCountVo.setConstructionPersonnelCount(Long.valueOf(projectUserCount)); |         peopleCountVo.setConstructionPersonnelCount(Long.valueOf(projectUserCount)); | ||||||
|         return R.ok(peopleCountVo); |         return R.ok(peopleCountVo); | ||||||
|  | |||||||
| @ -358,41 +358,104 @@ public class ProjectBigScreenController { | |||||||
|         List<Map<String, Object>> sxtChildrenMap = new ArrayList<>(); |         List<Map<String, Object>> sxtChildrenMap = new ArrayList<>(); | ||||||
|         HashMap<String, Object> map1 = new HashMap<>(); |         HashMap<String, Object> map1 = new HashMap<>(); | ||||||
|         map1.put("id", "55"); |         map1.put("id", "55"); | ||||||
|         map1.put("label", "1222222"); |         map1.put("label", "那荷4号方阵-1"); | ||||||
|         map1.put("name", "22"); |         map1.put("name", "22"); | ||||||
|         map1.put("type", "camera"); |         map1.put("type", "camera"); | ||||||
|         map1.put("lng", 106.48349615411811); |         map1.put("lng", 107.111325); | ||||||
|         map1.put("lat", 29.54856374364732); |         map1.put("lat", 23.820919); | ||||||
|         map1.put("alt", 0); |         map1.put("alt", 0); | ||||||
|         HashMap<String, Object> map2 = new HashMap<>(); |         HashMap<String, Object> map2 = new HashMap<>(); | ||||||
|         map2.put("id", "56"); |         map2.put("id", "56"); | ||||||
|         map2.put("label", "1222223"); |         map2.put("label", "甫必 1号方阵"); | ||||||
|         map2.put("name", "23"); |         map2.put("name", "23"); | ||||||
|         map2.put("type", "camera"); |         map2.put("type", "camera"); | ||||||
|         map2.put("lng", 106.48442273257676); |         map2.put("lng", 107.091297); | ||||||
|         map2.put("lat", 29.53841670498476); |         map2.put("lat", 23.813567); | ||||||
|         map2.put("alt", 0); |         map2.put("alt", 0); | ||||||
|         HashMap<String, Object> map3 = new HashMap<>(); |         HashMap<String, Object> map3 = new HashMap<>(); | ||||||
|         map3.put("id", "57"); |         map3.put("id", "57"); | ||||||
|         map3.put("label", "1222224"); |         map3.put("label", "1222224"); | ||||||
|         map3.put("name", "24"); |         map3.put("name", "24"); | ||||||
|         map3.put("type", "camera"); |         map3.put("type", "camera"); | ||||||
|         map3.put("lng", 106.49197896482423); |         map3.put("lng", 107.085442); | ||||||
|         map3.put("lat", 29.52931974282576); |         map3.put("lat", 23.811958); | ||||||
|         map3.put("alt", 0); |         map3.put("alt", 0); | ||||||
|         HashMap<String, Object> map4 = new HashMap<>(); |         HashMap<String, Object> map4 = new HashMap<>(); | ||||||
|         map4.put("id", "58"); |         map4.put("id", "58"); | ||||||
|         map4.put("label", "1222225"); |         map4.put("label", "甫必2号方阵-1"); | ||||||
|         map4.put("name", "25"); |         map4.put("name", "25"); | ||||||
|         map4.put("type", "camera"); |         map4.put("type", "camera"); | ||||||
|         map4.put("lng", 106.50293584930655); |         map4.put("lng", 107.085181); | ||||||
|         map4.put("lat", 29.533025743929034); |         map4.put("lat", 23.810556); | ||||||
|         map4.put("alt", 0); |         map4.put("alt", 0); | ||||||
|  |         HashMap<String, Object> map5 = new HashMap<>(); | ||||||
|  |         map5.put("id", "58"); | ||||||
|  |         map5.put("label", "甫必 4号方阵"); | ||||||
|  |         map5.put("name", "25"); | ||||||
|  |         map5.put("type", "camera"); | ||||||
|  |         map5.put("lng", 107.081747); | ||||||
|  |         map5.put("lat", 23.808131); | ||||||
|  |         map5.put("alt", 0); | ||||||
|  |         HashMap<String, Object> map6 = new HashMap<>(); | ||||||
|  |         map6.put("id", "58"); | ||||||
|  |         map6.put("label", "甫必 7号方阵-1"); | ||||||
|  |         map6.put("name", "25"); | ||||||
|  |         map6.put("type", "camera"); | ||||||
|  |         map6.put("lng", 107.077922); | ||||||
|  |         map6.put("lat", 23.798344); | ||||||
|  |         map6.put("alt", 0); | ||||||
|  |         HashMap<String, Object> map7 = new HashMap<>(); | ||||||
|  |         map7.put("id", "58"); | ||||||
|  |         map7.put("label", "68甫必6"); | ||||||
|  |         map7.put("name", "25"); | ||||||
|  |         map7.put("type", "camera"); | ||||||
|  |         map7.put("lng", 107.077333); | ||||||
|  |         map7.put("lat", 23.797969); | ||||||
|  |         map7.put("alt", 0); | ||||||
|  |         HashMap<String, Object> map8 = new HashMap<>(); | ||||||
|  |         map8.put("id", "58"); | ||||||
|  |         map8.put("label", "甫必5号方阵"); | ||||||
|  |         map8.put("name", "25"); | ||||||
|  |         map8.put("type", "camera"); | ||||||
|  |         map8.put("lng", 107.075853); | ||||||
|  |         map8.put("lat", 23.796711); | ||||||
|  |         map8.put("alt", 0); | ||||||
|  |         HashMap<String, Object> map9 = new HashMap<>(); | ||||||
|  |         map9.put("id", "58"); | ||||||
|  |         map9.put("label", "西牛2号方阵"); | ||||||
|  |         map9.put("name", "25"); | ||||||
|  |         map9.put("type", "camera"); | ||||||
|  |         map9.put("lng", 107.078942); | ||||||
|  |         map9.put("lat", 23.789306); | ||||||
|  |         map9.put("alt", 0); | ||||||
|  |         HashMap<String, Object> map10 = new HashMap<>(); | ||||||
|  |         map10.put("id", "58"); | ||||||
|  |         map10.put("label", "福绿1号方阵"); | ||||||
|  |         map10.put("name", "25"); | ||||||
|  |         map10.put("type", "camera"); | ||||||
|  |         map10.put("lng", 107.090061); | ||||||
|  |         map10.put("lat", 23.790411); | ||||||
|  |         map10.put("alt", 0); | ||||||
|  |         HashMap<String, Object> map11 = new HashMap<>(); | ||||||
|  |         map11.put("id", "58"); | ||||||
|  |         map11.put("label", "福绿6号方阵-2"); | ||||||
|  |         map11.put("name", "25"); | ||||||
|  |         map11.put("type", "camera"); | ||||||
|  |         map11.put("lng",  107.112883); | ||||||
|  |         map11.put("lat", 23.771378); | ||||||
|  |         map11.put("alt", 0); | ||||||
|  |  | ||||||
|         sxtChildrenMap.add(map1); |         sxtChildrenMap.add(map1); | ||||||
|         sxtChildrenMap.add(map2); |         sxtChildrenMap.add(map2); | ||||||
|         sxtChildrenMap.add(map3); |         sxtChildrenMap.add(map3); | ||||||
|         sxtChildrenMap.add(map4); |         sxtChildrenMap.add(map4); | ||||||
|  |         sxtChildrenMap.add(map5); | ||||||
|  |         sxtChildrenMap.add(map6); | ||||||
|  |         sxtChildrenMap.add(map7); | ||||||
|  |         sxtChildrenMap.add(map8); | ||||||
|  |         sxtChildrenMap.add(map9); | ||||||
|  |         sxtChildrenMap.add(map10); | ||||||
|  |         sxtChildrenMap.add(map11); | ||||||
|  |  | ||||||
|         return sxtChildrenMap; |         return sxtChildrenMap; | ||||||
|     } |     } | ||||||
| @ -401,41 +464,22 @@ public class ProjectBigScreenController { | |||||||
|         List<Map<String, Object>> sxtChildrenMap = new ArrayList<>(); |         List<Map<String, Object>> sxtChildrenMap = new ArrayList<>(); | ||||||
|         HashMap<String, Object> map1 = new HashMap<>(); |         HashMap<String, Object> map1 = new HashMap<>(); | ||||||
|         map1.put("id", "65"); |         map1.put("id", "65"); | ||||||
|         map1.put("label", "6222222"); |         map1.put("label", "田东无人机"); | ||||||
|         map1.put("name", "32"); |         map1.put("name", "32"); | ||||||
|         map1.put("type", "drone"); |         map1.put("type", "drone"); | ||||||
|         map1.put("lng", 106.49556855602525); |         map1.put("lng", 107.12744694624267); | ||||||
|         map1.put("lat", 29.534393226355515); |         map1.put("lat", 23.615965741917278); | ||||||
|         map1.put("alt", 0); |         map1.put("alt", 0); | ||||||
|         HashMap<String, Object> map2 = new HashMap<>(); | //        HashMap<String, Object> map2 = new HashMap<>(); | ||||||
|         map2.put("id", "66"); | //        map2.put("id", "66"); | ||||||
|         map2.put("label", "2222223"); | //        map2.put("label", "长顺无人机"); | ||||||
|         map2.put("name", "33"); | //        map2.put("name", "33"); | ||||||
|         map2.put("type", "drone"); | //        map2.put("type", "drone"); | ||||||
|         map2.put("lng", 106.49142431645038); | //        map2.put("lng", 106.49142431645038); | ||||||
|         map2.put("lat", 29.534472802500083); | //        map2.put("lat", 29.534472802500083); | ||||||
|         map2.put("alt", 0); | //        map2.put("alt", 0); | ||||||
|         HashMap<String, Object> map3 = new HashMap<>(); |  | ||||||
|         map3.put("id", "67"); |  | ||||||
|         map3.put("label", "2222224"); |  | ||||||
|         map3.put("name", "34"); |  | ||||||
|         map3.put("type", "drone"); |  | ||||||
|         map3.put("lng", 106.49142125177437); |  | ||||||
|         map3.put("lat", 29.541881138875755); |  | ||||||
|         map3.put("alt", 0); |  | ||||||
|         HashMap<String, Object> map4 = new HashMap<>(); |  | ||||||
|         map4.put("id", "68"); |  | ||||||
|         map4.put("label", "2222225"); |  | ||||||
|         map4.put("name", "35"); |  | ||||||
|         map4.put("type", "drone"); |  | ||||||
|         map4.put("lng", 106.50256649933792); |  | ||||||
|         map4.put("lat", 29.54260793685717); |  | ||||||
|         map4.put("alt", 0); |  | ||||||
|  |  | ||||||
|         sxtChildrenMap.add(map1); |         sxtChildrenMap.add(map1); | ||||||
|         sxtChildrenMap.add(map2); | //        sxtChildrenMap.add(map2); | ||||||
|         sxtChildrenMap.add(map3); |  | ||||||
|         sxtChildrenMap.add(map4); |  | ||||||
|  |  | ||||||
|         return sxtChildrenMap; |         return sxtChildrenMap; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -21,7 +21,7 @@ import java.io.Serial; | |||||||
|  */ |  */ | ||||||
| @Data | @Data | ||||||
| @EqualsAndHashCode(callSuper = true) | @EqualsAndHashCode(callSuper = true) | ||||||
| @TableName("bus_attendance") | @TableName("bus_attendance_copy1") | ||||||
| public class BusAttendance extends BaseEntity { | public class BusAttendance extends BaseEntity { | ||||||
|  |  | ||||||
|     @Serial |     @Serial | ||||||
|  | |||||||
| @ -188,6 +188,7 @@ public class BusProjectTeamServiceImpl extends ServiceImpl<BusProjectTeamMapper, | |||||||
|         // 判断是否重名 |         // 判断是否重名 | ||||||
|         String teamName = entity.getTeamName(); |         String teamName = entity.getTeamName(); | ||||||
|         LambdaQueryWrapper<BusProjectTeam> queryWrapper = new LambdaQueryWrapper<>(); |         LambdaQueryWrapper<BusProjectTeam> queryWrapper = new LambdaQueryWrapper<>(); | ||||||
|  |         queryWrapper.eq(BusProjectTeam::getProjectId, entity.getProjectId()); | ||||||
|         queryWrapper.eq(BusProjectTeam::getTeamName, teamName); |         queryWrapper.eq(BusProjectTeam::getTeamName, teamName); | ||||||
|         if (entity.getId() != null) { |         if (entity.getId() != null) { | ||||||
|             queryWrapper.ne(BusProjectTeam::getId, entity.getId()); |             queryWrapper.ne(BusProjectTeam::getId, entity.getId()); | ||||||
|  | |||||||
| @ -24,6 +24,7 @@ import org.dromara.common.oss.core.OssClient; | |||||||
| import org.dromara.common.oss.entity.UploadResult; | import org.dromara.common.oss.entity.UploadResult; | ||||||
| import org.dromara.common.oss.enumd.AccessPolicyType; | import org.dromara.common.oss.enumd.AccessPolicyType; | ||||||
| import org.dromara.common.oss.factory.OssFactory; | import org.dromara.common.oss.factory.OssFactory; | ||||||
|  | import org.dromara.common.satoken.utils.LoginHelper; | ||||||
| import org.dromara.system.domain.SysOss; | import org.dromara.system.domain.SysOss; | ||||||
| import org.dromara.system.domain.bo.SysOssBo; | import org.dromara.system.domain.bo.SysOssBo; | ||||||
| import org.dromara.system.domain.vo.SysOssUploadVo; | import org.dromara.system.domain.vo.SysOssUploadVo; | ||||||
| @ -44,10 +45,8 @@ import java.net.URI; | |||||||
| import java.net.URL; | import java.net.URL; | ||||||
| import java.net.URLConnection; | import java.net.URLConnection; | ||||||
| import java.time.Duration; | import java.time.Duration; | ||||||
| import java.util.ArrayList; | import java.time.LocalDateTime; | ||||||
| import java.util.Collection; | import java.util.*; | ||||||
| import java.util.List; |  | ||||||
| import java.util.Map; |  | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * 文件上传 服务层实现 |  * 文件上传 服务层实现 | ||||||
| @ -400,6 +399,13 @@ public class SysOssServiceImpl implements ISysOssService, OssService { | |||||||
|         oss.setFileName(uploadResult.getFilename()); |         oss.setFileName(uploadResult.getFilename()); | ||||||
|         oss.setOriginalName(originalfileName); |         oss.setOriginalName(originalfileName); | ||||||
|         oss.setService(configKey); |         oss.setService(configKey); | ||||||
|  |  | ||||||
|  |         //罗成负责删掉 | ||||||
|  |         oss.setCreateBy(1L); | ||||||
|  |         oss.setUpdateBy(1L); | ||||||
|  |         oss.setCreateTime(new Date()); | ||||||
|  |         oss.setUpdateTime(new Date()); | ||||||
|  |  | ||||||
|         baseMapper.insert(oss); |         baseMapper.insert(oss); | ||||||
|         SysOssVo sysOssVo = MapstructUtils.convert(oss, SysOssVo.class); |         SysOssVo sysOssVo = MapstructUtils.convert(oss, SysOssVo.class); | ||||||
|         return this.matchingUrl(sysOssVo); |         return this.matchingUrl(sysOssVo); | ||||||
|  | |||||||
| @ -1,10 +1,15 @@ | |||||||
| package org.dromara.transferData.controller; | package org.dromara.transferData.controller; | ||||||
|  |  | ||||||
|  | import cn.dev33.satoken.annotation.SaCheckPermission; | ||||||
| import cn.hutool.core.collection.CollectionUtil; | import cn.hutool.core.collection.CollectionUtil; | ||||||
| import com.baomidou.mybatisplus.core.toolkit.Wrappers; | import com.baomidou.mybatisplus.core.toolkit.Wrappers; | ||||||
| import jakarta.activation.MimetypesFileTypeMap; | import jakarta.activation.MimetypesFileTypeMap; | ||||||
| import jakarta.annotation.Resource; | import jakarta.annotation.Resource; | ||||||
|  | import jakarta.validation.constraints.NotNull; | ||||||
| import lombok.extern.slf4j.Slf4j; | import lombok.extern.slf4j.Slf4j; | ||||||
|  | import org.dromara.common.core.domain.R; | ||||||
|  | import org.dromara.contractor.domain.vo.constructionuser.SubConstructionUserVo; | ||||||
|  | import org.dromara.project.domain.BusAttendanceRule; | ||||||
| import org.dromara.project.domain.vo.BusAttendanceRuleVo; | import org.dromara.project.domain.vo.BusAttendanceRuleVo; | ||||||
| import org.dromara.transferData.domain.ConstructionUserCopy; | import org.dromara.transferData.domain.ConstructionUserCopy; | ||||||
| import org.dromara.transferData.domain.OldAttendance; | import org.dromara.transferData.domain.OldAttendance; | ||||||
| @ -15,6 +20,9 @@ import org.dromara.project.service.IBusAttendanceRuleService; | |||||||
| import org.dromara.project.service.IBusAttendanceService; | import org.dromara.project.service.IBusAttendanceService; | ||||||
| import org.dromara.system.domain.vo.SysOssVo; | import org.dromara.system.domain.vo.SysOssVo; | ||||||
| import org.dromara.system.service.ISysOssService; | import org.dromara.system.service.ISysOssService; | ||||||
|  | import org.dromara.transferData.service.TransferDataService; | ||||||
|  | import org.springframework.web.bind.annotation.GetMapping; | ||||||
|  | import org.springframework.web.bind.annotation.PathVariable; | ||||||
| import org.springframework.web.bind.annotation.RequestMapping; | import org.springframework.web.bind.annotation.RequestMapping; | ||||||
| import org.springframework.web.bind.annotation.RestController; | import org.springframework.web.bind.annotation.RestController; | ||||||
|  |  | ||||||
| @ -27,9 +35,15 @@ import java.nio.file.Paths; | |||||||
| import java.time.LocalDate; | import java.time.LocalDate; | ||||||
| import java.time.LocalDateTime; | import java.time.LocalDateTime; | ||||||
| import java.time.LocalTime; | import java.time.LocalTime; | ||||||
|  | import java.time.format.DateTimeFormatter; | ||||||
| import java.time.format.DateTimeParseException; | import java.time.format.DateTimeParseException; | ||||||
| import java.time.temporal.ChronoUnit; | import java.time.temporal.ChronoUnit; | ||||||
|  | import java.util.ArrayList; | ||||||
|  | import java.util.Arrays; | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  | import java.util.Map; | ||||||
|  | import java.util.concurrent.ScheduledExecutorService; | ||||||
|  | import java.util.stream.Collectors; | ||||||
|  |  | ||||||
| @RestController | @RestController | ||||||
| @RequestMapping("/transferData") | @RequestMapping("/transferData") | ||||||
| @ -39,13 +53,10 @@ public class TransferDataController { | |||||||
|     @Resource |     @Resource | ||||||
|     private TransferDataMapper transferDataMapper; |     private TransferDataMapper transferDataMapper; | ||||||
|     @Resource |     @Resource | ||||||
|     private IBusAttendanceService attendanceService; |  | ||||||
|     @Resource |  | ||||||
|     private IBusAttendanceRuleService attendanceRuleService; |     private IBusAttendanceRuleService attendanceRuleService; | ||||||
|     @Resource |     @Resource | ||||||
|     private ISubConstructionUserService constructionUserService; |     private TransferDataService transferDataService; | ||||||
|     @Resource |  | ||||||
|     private ISysOssService ossService; |  | ||||||
|  |  | ||||||
|     // 两个候选基础URL |     // 两个候选基础URL | ||||||
|     private static final String[] BASE_URLS = { |     private static final String[] BASE_URLS = { | ||||||
| @ -56,7 +67,14 @@ public class TransferDataController { | |||||||
|  |  | ||||||
|     @RequestMapping("/transferAttendance") |     @RequestMapping("/transferAttendance") | ||||||
|     public void transferAttendance() { |     public void transferAttendance() { | ||||||
|  |         List<BusAttendance> arrs = new ArrayList<>(); | ||||||
|  |  | ||||||
|         List<OldAttendance> data = transferDataMapper.getData(); |         List<OldAttendance> data = transferDataMapper.getData(); | ||||||
|  |  | ||||||
|  |         List<BusAttendanceRule> list = attendanceRuleService.list(Wrappers.<BusAttendanceRule>lambdaQuery() | ||||||
|  |             .in(BusAttendanceRule::getProjectId, Arrays.asList(1897160897167638529L, 1897161054676336641L))); | ||||||
|  |         Map<Long, BusAttendanceRule> rules = list.stream().collect(Collectors.toMap(BusAttendanceRule::getProjectId, vo -> vo)); | ||||||
|  |  | ||||||
|         for (OldAttendance oldAttendance : data) { |         for (OldAttendance oldAttendance : data) { | ||||||
|             ConstructionUserCopy constructionUserCopy = transferDataMapper.getConstructionUserCopy(oldAttendance.getOpenid()); |             ConstructionUserCopy constructionUserCopy = transferDataMapper.getConstructionUserCopy(oldAttendance.getOpenid()); | ||||||
|  |  | ||||||
| @ -64,27 +82,37 @@ public class TransferDataController { | |||||||
|                 continue; |                 continue; | ||||||
|             } |             } | ||||||
|             LocalDate clockDate = LocalDate.parse(oldAttendance.getPrintingDate()); |             LocalDate clockDate = LocalDate.parse(oldAttendance.getPrintingDate()); | ||||||
|             //判定是否重读 | //            //判定是否重读 | ||||||
|             List<BusAttendance> list = attendanceService.list(Wrappers.lambdaQuery(BusAttendance.class) | //            List<BusAttendance> list = attendanceService.list(Wrappers.lambdaQuery(BusAttendance.class) | ||||||
|                 .eq(BusAttendance::getUserId, constructionUserCopy.getSysUserId()) | //                .eq(BusAttendance::getUserId, constructionUserCopy.getSysUserId()) | ||||||
|                 .eq(BusAttendance::getProjectId, constructionUserCopy.getProjectId()) | //                .eq(BusAttendance::getProjectId, constructionUserCopy.getProjectId()) | ||||||
|                 .eq(BusAttendance::getClockDate, clockDate) | //                .eq(BusAttendance::getClockDate, clockDate) | ||||||
|                 .eq(BusAttendance::getClockType, oldAttendance.getCommuter()) | //                .eq(BusAttendance::getClockType, oldAttendance.getCommuter()) | ||||||
|             ); | //            ); | ||||||
|             if(CollectionUtil.isNotEmpty(list)){ | //            if(CollectionUtil.isNotEmpty(list)){ | ||||||
|                 continue; | //                continue; | ||||||
|  | //            } | ||||||
|  |             if (oldAttendance.getProjectId() == 60){ | ||||||
|  |                 oldAttendance.setProjectId(1897160897167638529L); | ||||||
|  |             } | ||||||
|  |             if (oldAttendance.getProjectId() == 59){ | ||||||
|  |                 oldAttendance.setProjectId(1897161054676336641L); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             BusAttendance busAttendance = new BusAttendance(); |             BusAttendance busAttendance = new BusAttendance(); | ||||||
|  |  | ||||||
|             if(oldAttendance.getPacePhoto()!=null){ |             //处理照片 | ||||||
|                 Long l = handleFaceImage(oldAttendance.getPacePhoto()); |  | ||||||
|                 busAttendance.setFacePic(l==null?"":l.toString()); |             busAttendance.setFacePic(oldAttendance.getPacePhoto()); | ||||||
|             } |  | ||||||
|  | //            if(oldAttendance.getPacePhoto()!=null){ | ||||||
|  | //                Long l = handleFaceImage(oldAttendance.getPacePhoto()); | ||||||
|  | //                busAttendance.setFacePic(l==null?"":l.toString()); | ||||||
|  | //            } | ||||||
|  |  | ||||||
|             busAttendance.setUserName(constructionUserCopy.getUserName()); |             busAttendance.setUserName(constructionUserCopy.getUserName()); | ||||||
|             busAttendance.setUserId(constructionUserCopy.getSysUserId()); |             busAttendance.setUserId(constructionUserCopy.getSysUserId()); | ||||||
|             busAttendance.setProjectId(constructionUserCopy.getProjectId()); | //            busAttendance.setProjectId(constructionUserCopy.getProjectId()); | ||||||
|  |  | ||||||
|             // 转换日期字段 |             // 转换日期字段 | ||||||
|             busAttendance.setClockDate(clockDate); |             busAttendance.setClockDate(clockDate); | ||||||
| @ -102,7 +130,7 @@ public class TransferDataController { | |||||||
|                 busAttendance.setClockTime(parseClockOn(oldAttendance.getClockOn(), busAttendance)); |                 busAttendance.setClockTime(parseClockOn(oldAttendance.getClockOn(), busAttendance)); | ||||||
|             } |             } | ||||||
|             //规则和迟到早退时间计算 |             //规则和迟到早退时间计算 | ||||||
|             BusAttendanceRuleVo busAttendanceRuleVo = attendanceRuleService.queryByProjectId(busAttendance.getProjectId()); |             BusAttendanceRule busAttendanceRuleVo = rules.get(busAttendance.getProjectId()); | ||||||
|             if (busAttendanceRuleVo != null) { |             if (busAttendanceRuleVo != null) { | ||||||
|                 LocalTime clockInTime = busAttendanceRuleVo.getClockInTime(); |                 LocalTime clockInTime = busAttendanceRuleVo.getClockInTime(); | ||||||
|                 LocalTime clockOutTime = busAttendanceRuleVo.getClockOutTime(); |                 LocalTime clockOutTime = busAttendanceRuleVo.getClockOutTime(); | ||||||
| @ -125,53 +153,35 @@ public class TransferDataController { | |||||||
|                 } |                 } | ||||||
|                 busAttendance.setHandle("5".equals(oldAttendance.getIsPinch())?"1":"0"); |                 busAttendance.setHandle("5".equals(oldAttendance.getIsPinch())?"1":"0"); | ||||||
|             } |             } | ||||||
|  |             arrs.add(busAttendance); | ||||||
|  |             if(arrs.size() >= 1000){ | ||||||
|  |                 List<BusAttendance> batchList = new ArrayList<>(arrs); | ||||||
|  |                 // 提交异步任务:处理照片 + 批量保存 | ||||||
|  |                 transferDataService.handlePhotoAndSaveBatch(batchList); | ||||||
|  |                 arrs.clear(); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if (CollectionUtil.isNotEmpty(arrs)) { | ||||||
|  |             List<BusAttendance> batchList = new ArrayList<>(arrs); | ||||||
|  |             transferDataService.handlePhotoAndSaveBatch(batchList); | ||||||
|  |         } | ||||||
|  | //        attendanceService.saveBatch(arrs); | ||||||
|  |  | ||||||
|  | //        transferDataMapper.saveBatchCopy(arrs); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     public Long handleFaceImage(String relativePath) { |  | ||||||
|         String normalizedPath = relativePath.replace("\\", "/"); |  | ||||||
|         String filename = Paths.get(normalizedPath).getFileName().toString(); |  | ||||||
|  |  | ||||||
|         // 使用 MimetypesFileTypeMap 解析 |  | ||||||
|         MimetypesFileTypeMap fileTypeMap = new MimetypesFileTypeMap(); |  | ||||||
|         String contentType = fileTypeMap.getContentType(filename); |  | ||||||
|  |  | ||||||
|         for (String baseUrl : BASE_URLS) { |  | ||||||
|             String fullUrl = baseUrl + normalizedPath; |  | ||||||
|             try { |  | ||||||
|                 HttpClient client = HttpClient.newHttpClient(); |  | ||||||
|                 HttpRequest request = HttpRequest.newBuilder() |  | ||||||
|                     .uri(URI.create(fullUrl)) |  | ||||||
|                     .GET() |  | ||||||
|                     .build(); |  | ||||||
|  |  | ||||||
|                 HttpResponse<InputStream> response = client.send(request, HttpResponse.BodyHandlers.ofInputStream()); |  | ||||||
|  |  | ||||||
|                 if (response.statusCode() == 200) { |  | ||||||
|                     long contentLength = response.headers().firstValueAsLong("Content-Length").orElse(-1); |  | ||||||
|                     SysOssVo ossVo = ossService.upload(response.body(), filename, contentType, contentLength); |  | ||||||
|                     return ossVo.getOssId(); |  | ||||||
|                 } |  | ||||||
|             } catch (Exception e) { |  | ||||||
|                 log.warn("尝试URL失败: {}", fullUrl, e); |  | ||||||
|                 continue; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         return null; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private LocalDateTime parseClockOn(String clockOn, BusAttendance busAttendance) { |     private LocalDateTime parseClockOn(String clockOn, BusAttendance busAttendance) { | ||||||
|         if (clockOn == null || "缺卡".equals(clockOn)) { |         if (clockOn == null || "缺卡".equals(clockOn)) { | ||||||
|             return null; |             return null; | ||||||
|         } |         } | ||||||
|  |         DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); | ||||||
|  |         DateTimeFormatter formatter1 = DateTimeFormatter.ofPattern("yyyy-MM-dd H:mm:ss"); | ||||||
|         try { |         try { | ||||||
|  |  | ||||||
|             // 1. 尝试完整日期时间解析(如 "2023-10-14 07:35:07") |             // 1. 尝试完整日期时间解析(如 "2023-10-14 07:35:07") | ||||||
|             return LocalDateTime.parse(clockOn); |             return LocalDateTime.parse(clockOn,formatter); | ||||||
|         } catch (DateTimeParseException e) { |         } catch (DateTimeParseException e) { | ||||||
|             try { |             try { | ||||||
|                 // 2. 仅时间解析(如 "5:38:00")并结合已有的日期 |                 // 2. 仅时间解析(如 "5:38:00")并结合已有的日期 | ||||||
| @ -179,7 +189,7 @@ public class TransferDataController { | |||||||
|                 if (date == null) { |                 if (date == null) { | ||||||
|                     return null; // 日期不存在时返回 null |                     return null; // 日期不存在时返回 null | ||||||
|                 } |                 } | ||||||
|                 LocalTime time = LocalTime.parse(clockOn); |                 LocalTime time = LocalTime.parse(clockOn,formatter1); | ||||||
|                 return LocalDateTime.of(date, time); |                 return LocalDateTime.of(date, time); | ||||||
|             } catch (DateTimeParseException ex) { |             } catch (DateTimeParseException ex) { | ||||||
|                 log.warn("无法解析打卡时间: {}", clockOn); |                 log.warn("无法解析打卡时间: {}", clockOn); | ||||||
|  | |||||||
| @ -1,5 +1,7 @@ | |||||||
| package org.dromara.transferData.domain; | package org.dromara.transferData.domain; | ||||||
|  |  | ||||||
|  | import com.baomidou.mybatisplus.annotation.IdType; | ||||||
|  | import com.baomidou.mybatisplus.annotation.TableId; | ||||||
| import lombok.Data; | import lombok.Data; | ||||||
| import java.math.BigDecimal; | import java.math.BigDecimal; | ||||||
| import java.time.LocalDateTime; | import java.time.LocalDateTime; | ||||||
|  | |||||||
| @ -1,9 +1,11 @@ | |||||||
| package org.dromara.transferData.mapper; | package org.dromara.transferData.mapper; | ||||||
|  |  | ||||||
| import com.baomidou.dynamic.datasource.annotation.DS; | import com.baomidou.dynamic.datasource.annotation.DS; | ||||||
|  | import org.apache.ibatis.annotations.Insert; | ||||||
| import org.apache.ibatis.annotations.Mapper; | import org.apache.ibatis.annotations.Mapper; | ||||||
| import org.apache.ibatis.annotations.Param; | import org.apache.ibatis.annotations.Param; | ||||||
| import org.apache.ibatis.annotations.Select; | import org.apache.ibatis.annotations.Select; | ||||||
|  | import org.dromara.project.domain.BusAttendance; | ||||||
| import org.dromara.transferData.domain.ConstructionUserCopy; | import org.dromara.transferData.domain.ConstructionUserCopy; | ||||||
| import org.dromara.transferData.domain.OldAttendance; | import org.dromara.transferData.domain.OldAttendance; | ||||||
|  |  | ||||||
| @ -15,10 +17,27 @@ public interface TransferDataMapper { | |||||||
|  |  | ||||||
|  |  | ||||||
|     @DS("slave") |     @DS("slave") | ||||||
|     @Select("select * from bus_attendance") |     @Select("select * from bus_attendance where  project_id in (59,60)") | ||||||
|     List<OldAttendance> getData(); |     List<OldAttendance> getData(); | ||||||
|  |  | ||||||
|  |  | ||||||
|     @Select("select id,sys_user_id,project_id,user_name from sub_construction_user_copy1 where go_openid = #{openId}") |     @Select("select id,sys_user_id,project_id,user_name from sub_construction_user_copy1 where go_openid = #{openId}") | ||||||
|     ConstructionUserCopy getConstructionUserCopy(@Param("openId") String openId); |     ConstructionUserCopy getConstructionUserCopy(@Param("openId") String openId); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     @Insert("<script>" + | ||||||
|  |         "insert into sub_construction_user_copy1 " + | ||||||
|  |         "(id, sys_user_id, project_id, user_name, go_openid, " + | ||||||
|  |         "face_pic, clock_date, clock_time, clock_status, " + | ||||||
|  |         "minute_count, clock_type, clock_location, lng, lat, " + | ||||||
|  |         "rule_time, handle, create_time, update_time) " + | ||||||
|  |         "values " + | ||||||
|  |         "<foreach collection='list' item='item' separator=','>" + | ||||||
|  |         "(#{item.id}, #{item.userId}, #{item.projectId}, #{item.userName}, #{item.openId}, " + | ||||||
|  |         "#{item.facePic}, #{item.clockDate}, #{item.clockTime}, #{item.clockStatus}, " + | ||||||
|  |         "#{item.minuteCount}, #{item.clockType}, #{item.clockLocation}, #{item.lng}, #{item.lat}, " + | ||||||
|  |         "#{item.ruleTime}, #{item.handle}, #{item.createTime}, #{item.updateTime})" + | ||||||
|  |         "</foreach>" + | ||||||
|  |         "</script>") | ||||||
|  |     int saveBatchCopy(@Param("list") List<BusAttendance> busAttendanceList); | ||||||
| } | } | ||||||
|  | |||||||
| @ -0,0 +1,29 @@ | |||||||
|  | package org.dromara.transferData.service; | ||||||
|  |  | ||||||
|  | import org.springframework.context.annotation.Bean; | ||||||
|  | import org.springframework.context.annotation.Configuration; | ||||||
|  | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; | ||||||
|  | import java.util.concurrent.Executor; | ||||||
|  | import java.util.concurrent.ThreadPoolExecutor; | ||||||
|  |  | ||||||
|  | @Configuration | ||||||
|  | public class TransferAsyncConfig { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 考勤异步任务专用线程池 | ||||||
|  |      */ | ||||||
|  |     @Bean("attendanceAsyncPool") | ||||||
|  |     public Executor attendanceAsyncPool() { | ||||||
|  |         ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); | ||||||
|  |         int corePoolSize = Runtime.getRuntime().availableProcessors() * 2; // 核心线程数:CPU核心数*2 | ||||||
|  |         executor.setCorePoolSize(corePoolSize); | ||||||
|  |         executor.setMaxPoolSize(corePoolSize * 2); // 最大线程数 | ||||||
|  |         executor.setQueueCapacity(1000); // 任务队列容量 | ||||||
|  |         executor.setKeepAliveSeconds(60); // 空闲线程存活时间 | ||||||
|  |         executor.setThreadNamePrefix("attendance-async-"); // 线程名称前缀(便于排查) | ||||||
|  |         // 拒绝策略:任务满时,由提交任务的线程(如主线程)执行,避免任务丢失 | ||||||
|  |         executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); | ||||||
|  |         executor.initialize(); | ||||||
|  |         return executor; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,229 @@ | |||||||
|  | package org.dromara.transferData.service; | ||||||
|  |  | ||||||
|  | import jakarta.activation.MimetypesFileTypeMap; | ||||||
|  | import jakarta.annotation.Resource; | ||||||
|  | import lombok.extern.slf4j.Slf4j; | ||||||
|  | import org.apache.commons.lang3.SerializationUtils; | ||||||
|  | import org.dromara.common.core.service.OssService; | ||||||
|  | import org.dromara.contractor.service.ISubConstructionUserService; | ||||||
|  | import org.dromara.project.domain.BusAttendance; | ||||||
|  | import org.dromara.project.service.IBusAttendanceRuleService; | ||||||
|  | import org.dromara.project.service.IBusAttendanceService; | ||||||
|  | import org.dromara.system.domain.vo.SysOssVo; | ||||||
|  | import org.dromara.system.service.ISysOssService; | ||||||
|  | import org.springframework.beans.factory.annotation.Qualifier; | ||||||
|  | import org.springframework.scheduling.annotation.Async; | ||||||
|  | import org.springframework.stereotype.Service; | ||||||
|  |  | ||||||
|  | import java.io.InputStream; | ||||||
|  | import java.net.URI; | ||||||
|  | import java.net.http.HttpClient; | ||||||
|  | import java.net.http.HttpRequest; | ||||||
|  | import java.net.http.HttpResponse; | ||||||
|  | import java.nio.file.Paths; | ||||||
|  | import java.time.Duration; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.concurrent.CompletableFuture; | ||||||
|  | import java.util.concurrent.Executor; | ||||||
|  | import java.util.stream.Collectors; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @Author 铁憨憨 | ||||||
|  |  * @Date 2025/9/14 10:53 | ||||||
|  |  * @Version 1.0 | ||||||
|  |  */ | ||||||
|  | @Service | ||||||
|  | @Slf4j | ||||||
|  | public class TransferDataService { | ||||||
|  |     // 1. 全局复用HttpClient(设置超时,线程安全) | ||||||
|  |     private final HttpClient httpClient = HttpClient.newBuilder() | ||||||
|  |         .connectTimeout(Duration.ofSeconds(5)) // 连接超时5秒 | ||||||
|  |         .followRedirects(HttpClient.Redirect.NORMAL) // 跟随重定向 | ||||||
|  |         .build(); | ||||||
|  |  | ||||||
|  |     // 2. 注入依赖(原依赖不变) | ||||||
|  |     @Resource | ||||||
|  |     private IBusAttendanceService attendanceService; | ||||||
|  |     @Resource | ||||||
|  |     private ISysOssService ossService; | ||||||
|  |     @Resource | ||||||
|  |     @Qualifier("attendanceAsyncPool") // 对应之前 AsyncConfig 中定义的线程池Bean名 | ||||||
|  |     private Executor attendanceAsyncExecutor; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     // 两个候选基础URL | ||||||
|  |     private static final String[] BASE_URLS = { | ||||||
|  |         "http://xny.yj-3d.com:7464", | ||||||
|  |         "http://xny.yj-3d.com:7363" | ||||||
|  |     }; | ||||||
|  |     /** | ||||||
|  |      * 异步处理照片并批量保存(修复线程安全 + 性能优化) | ||||||
|  |      * @param batchList 原始批量数据(浅拷贝) | ||||||
|  |      */ | ||||||
|  |     // 2. 修复后的照片批量异步处理逻辑 | ||||||
|  |     public CompletableFuture<Boolean> handlePhotoAndSaveBatch(List<BusAttendance> batchList) { | ||||||
|  |         log.info("异步处理照片和保存开始,条数:{}", batchList.size()); | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             // 步骤1:深度拷贝集合(不变,确保线程安全) | ||||||
|  |             List<BusAttendance> deepCopyList = batchList.stream() | ||||||
|  |                 .map(attendance -> { | ||||||
|  |                     // 深拷贝实现(二选一,根据实体类是否实现Serializable) | ||||||
|  |                     // 方式1:Spring SerializationUtils(需实体类实现Serializable) | ||||||
|  |                     BusAttendance copy = SerializationUtils.deserialize(SerializationUtils.serialize(attendance)); | ||||||
|  |                     // 方式2:手动拷贝(无Serializable依赖) | ||||||
|  |                     // BusAttendance copy = new BusAttendance(); | ||||||
|  |                     // BeanUtils.copyProperties(attendance, copy); | ||||||
|  |                     copy.setCreateBy(1L); | ||||||
|  |                     copy.setUpdateBy(1L); | ||||||
|  |                     return copy; | ||||||
|  |                 }) | ||||||
|  |                 .collect(Collectors.toList()); | ||||||
|  |  | ||||||
|  |             // 步骤2:修复Stream流语法,生成CompletableFuture数组(关键修复点) | ||||||
|  |             // 核心:map(中间操作)→ collect(终止操作生成列表)→ toArray(转数组) | ||||||
|  |             CompletableFuture<Void> photoHandleFuture = CompletableFuture.allOf( | ||||||
|  |                 // 2.1 流处理:每条数据生成一个CompletableFuture | ||||||
|  |                 deepCopyList.stream() | ||||||
|  |                     .map(attendance -> | ||||||
|  |                         // 2.2 异步执行单条照片处理(使用自定义线程池,避免复用HttpClient线程池) | ||||||
|  |                         CompletableFuture.runAsync(() -> { | ||||||
|  |                             try { | ||||||
|  |                                 handleSinglePhoto(attendance); // 处理单张照片 | ||||||
|  |                             } catch (Exception e) { | ||||||
|  |                                 log.error("处理单条照片失败,userId={}, clockDate={}", | ||||||
|  |                                     attendance.getUserId(), attendance.getClockDate(), e); | ||||||
|  |                                 attendance.setFacePic(""); // 失败标记,不影响整体保存 | ||||||
|  |                             } | ||||||
|  |                         }, attendanceAsyncExecutor) // 改用自定义线程池(核心优化) | ||||||
|  |                     ) | ||||||
|  |                     // 2.3 终止操作:将Stream<CompletableFuture<Void>> 转为 List | ||||||
|  |                     .collect(Collectors.toList()) | ||||||
|  |                     // 2.4 转数组:List → 数组,适配CompletableFuture.allOf的参数要求 | ||||||
|  |                     .toArray(new CompletableFuture[0]) | ||||||
|  |             ); | ||||||
|  |  | ||||||
|  |             // 步骤3:等待所有照片处理完成(阻塞当前异步任务线程,不阻塞主线程) | ||||||
|  |             photoHandleFuture.get(); // 若需超时控制,可加参数:photoHandleFuture.get(30, TimeUnit.SECONDS) | ||||||
|  |  | ||||||
|  |             // 步骤4:批量保存数据库(不变) | ||||||
|  |             boolean saveSuccess = attendanceService.saveBatch(deepCopyList); | ||||||
|  |             if (saveSuccess) { | ||||||
|  |                 log.info("异步批量保存成功,条数:{}", deepCopyList.size()); | ||||||
|  |             } else { | ||||||
|  |                 log.error("异步批量保存失败,条数:{}", deepCopyList.size()); | ||||||
|  |                 // 可选:重试逻辑 | ||||||
|  |                 saveSuccess = attendanceService.saveBatch(deepCopyList); | ||||||
|  |                 log.info("异步批量保存重试结果:{},条数:{}", saveSuccess ? "成功" : "失败", deepCopyList.size()); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return CompletableFuture.completedFuture(saveSuccess); | ||||||
|  |  | ||||||
|  |         } catch (Exception e) { | ||||||
|  |             log.error("异步处理照片和保存整体失败,条数:{}", batchList.size(), e); | ||||||
|  |             return CompletableFuture.completedFuture(false); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 处理单条照片(修复资源释放 + 超时控制 + 重试) | ||||||
|  |      */ | ||||||
|  |     private void handleSinglePhoto(BusAttendance attendance) { | ||||||
|  |         String facePicRelativePath = attendance.getFacePic(); | ||||||
|  |         if (facePicRelativePath == null || facePicRelativePath.isEmpty()) { | ||||||
|  |             attendance.setFacePic(""); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // 1. 规范化路径(原逻辑不变) | ||||||
|  |         String normalizedPath = facePicRelativePath.replace("\\", "/"); | ||||||
|  |         String filename = Paths.get(normalizedPath).getFileName().toString(); | ||||||
|  |  | ||||||
|  |         // 2. 解析文件类型(优化:优先从HTTP响应头获取,其次用文件名) | ||||||
|  |         String contentType = "application/octet-stream"; // 默认二进制类型 | ||||||
|  |  | ||||||
|  |         // 3. 多URL重试(原逻辑,增加超时和流关闭) | ||||||
|  |         for (int retry = 0; retry < 2; retry++) { // 重试1次(共2次机会) | ||||||
|  |             for (String baseUrl : BASE_URLS) { | ||||||
|  |                 String fullUrl = baseUrl + normalizedPath; | ||||||
|  |                 try { | ||||||
|  |                     // 构建带超时的HTTP请求 | ||||||
|  |                     HttpRequest request = HttpRequest.newBuilder() | ||||||
|  |                         .uri(URI.create(fullUrl)) | ||||||
|  |                         .GET() | ||||||
|  |                         .timeout(Duration.ofSeconds(10)) // 读取超时10秒 | ||||||
|  |                         .build(); | ||||||
|  |  | ||||||
|  |                     // 发送请求并处理响应 | ||||||
|  |                     try (InputStream inputStream = httpClient.send(request, HttpResponse.BodyHandlers.ofInputStream()).body()) { | ||||||
|  |                         // 从响应头获取真实Content-Type(比文件名解析更准确) | ||||||
|  |                         HttpResponse<?> response = httpClient.send(request, HttpResponse.BodyHandlers.discarding()); | ||||||
|  |                         contentType = response.headers().firstValue("Content-Type").orElse(contentType); | ||||||
|  |                         long contentLength = response.headers().firstValueAsLong("Content-Length").orElse(-1); | ||||||
|  |  | ||||||
|  |                         // 上传OSS(此时流已通过try-with-resources自动关闭) | ||||||
|  |                         SysOssVo ossVo = ossService.upload(inputStream, filename, contentType, contentLength); | ||||||
|  |                         attendance.setFacePic(ossVo.getOssId() == null ? "" : ossVo.getOssId().toString()); | ||||||
|  |                         return; // 成功则跳出所有循环 | ||||||
|  |                     } | ||||||
|  |                 } catch (Exception e) { | ||||||
|  |                     log.warn("尝试URL失败(重试{}次): {}", retry + 1, fullUrl, e); | ||||||
|  |                     continue; // 重试下一个URL | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // 所有URL和重试都失败 | ||||||
|  |         log.error("照片处理失败,所有URL重试完毕,relativePath={}", normalizedPath); | ||||||
|  |         attendance.setFacePic(""); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     private Long handleSinglePhoto1(String facePicRelativePath) { | ||||||
|  |  | ||||||
|  |         if (facePicRelativePath == null || facePicRelativePath.isEmpty()) { | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // 1. 规范化路径(原逻辑不变) | ||||||
|  |         String normalizedPath = facePicRelativePath.replace("\\", "/"); | ||||||
|  |         String filename = Paths.get(normalizedPath).getFileName().toString(); | ||||||
|  |  | ||||||
|  |         // 2. 解析文件类型(优化:优先从HTTP响应头获取,其次用文件名) | ||||||
|  |         String contentType = "application/octet-stream"; // 默认二进制类型 | ||||||
|  |  | ||||||
|  |         // 3. 多URL重试(原逻辑,增加超时和流关闭) | ||||||
|  |         for (int retry = 0; retry < 2; retry++) { // 重试1次(共2次机会) | ||||||
|  |             for (String baseUrl : BASE_URLS) { | ||||||
|  |                 String fullUrl = baseUrl + normalizedPath; | ||||||
|  |                 try { | ||||||
|  |                     // 构建带超时的HTTP请求 | ||||||
|  |                     HttpRequest request = HttpRequest.newBuilder() | ||||||
|  |                         .uri(URI.create(fullUrl)) | ||||||
|  |                         .GET() | ||||||
|  |                         .timeout(Duration.ofSeconds(10)) // 读取超时10秒 | ||||||
|  |                         .build(); | ||||||
|  |  | ||||||
|  |                     // 发送请求并处理响应 | ||||||
|  |                     try (InputStream inputStream = httpClient.send(request, HttpResponse.BodyHandlers.ofInputStream()).body()) { | ||||||
|  |                         // 从响应头获取真实Content-Type(比文件名解析更准确) | ||||||
|  |                         HttpResponse<?> response = httpClient.send(request, HttpResponse.BodyHandlers.discarding()); | ||||||
|  |                         contentType = response.headers().firstValue("Content-Type").orElse(contentType); | ||||||
|  |                         long contentLength = response.headers().firstValueAsLong("Content-Length").orElse(-1); | ||||||
|  |  | ||||||
|  |                         // 上传OSS(此时流已通过try-with-resources自动关闭) | ||||||
|  |                         SysOssVo ossVo = ossService.upload(inputStream, filename, contentType, contentLength); | ||||||
|  |                         return ossVo.getOssId(); // 成功则跳出所有循环 | ||||||
|  |                     } | ||||||
|  |                 } catch (Exception e) { | ||||||
|  |                     log.warn("尝试URL失败(重试{}次): {}", retry + 1, fullUrl, e); | ||||||
|  |                     continue; // 重试下一个URL | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // 所有URL和重试都失败 | ||||||
|  |         log.error("照片处理失败,所有URL重试完毕,relativePath={}", normalizedPath); | ||||||
|  |        return null; | ||||||
|  |     } | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user