活动介绍

LocalDate now = new Date().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

时间: 2024-04-08 17:32:44 浏览: 171
这是一段 Java 代码,用于获取当前日期。它使用了 `java.util.Date` 类中的 `toInstant()` 方法将 `Date` 对象转换为 `Instant` 对象,然后使用 `atZone()` 方法将其转换为系统默认时区的 `ZonedDateTime` 对象,最后使用 `toLocalDate()` 方法获取日期部分的 `LocalDate` 对象。这段代码可以用于获取当前日期并赋值给 `now` 变量。
相关问题

LocalDate inputDate = LocalDate.parse("2023-07", DateTimeFormatter.ofPattern("yyyy-MM")); LocalDate firstDay = inputDate.withDayOfMonth(1); LocalDate lastDay = inputDate.with(TemporalAdjusters.lastDayOfMonth()); 将firstDay 和lastDay 转换成date格式

<think>好的,我需要帮助用户将Java中的LocalDate类型(比如firstDay和lastDay)转换为传统的java.util.Date格式。首先,我得回顾一下Java 8引入的日期时间API,尤其是LocalDate类,以及如何与旧的java.util.Date进行互操作。 根据引用[5],用户被告知建议使用Java 8的日期时间类,而不是java.util.Date。这说明用户可能正在处理遗留代码,需要兼容旧的API。接下来,我需要找到正确的转换方法。 记得LocalDate表示的是日期,而java.util.Date包含日期和时间,所以转换时需要考虑到时区。因为LocalDate不包含时区信息,转换时必须指定一个时区来确定当天的起始时间(比如当天的零点)。通常,会使用系统默认时区,或者指定一个特定的时区。 步骤可能如下: 1. 将LocalDate转换为ZonedDateTime,指定一个时区(比如系统默认时区)。 2. 将ZonedDateTime转换为Instant,这个Instant表示时间线上的某个瞬间。 3. 使用Date.from(Instant)来创建java.util.Date对象。 例如,用户提供的LocalDate对象firstDay和lastDay,可以使用atStartOfDay方法得到当天的起始时间(LocalDateTime),然后结合时区转换为ZonedDateTime,再转为Instant。 另外,需要注意时区的影响,比如使用ZoneId.systemDefault()获取系统默认时区,或者显式指定如ZoneId.of("UTC")。 验证一下示例代码是否正确,比如: LocalDate firstDay = ...; Date utilDate = Date.from(firstDay.atStartOfDay(ZoneId.systemDefault()).toInstant()); 这样应该就能正确转换了。同时,提醒用户处理可能的时区问题,确保转换后的时间准确。 最后,确保引用了正确的参考资料,特别是引用[5]中提到使用Java 8的日期时间类,而这里正好是在处理两者的转换,所以需要引用相关的建议。</think>要将 Java 中的 `LocalDate` 类型转换为传统的 `java.util.Date` 格式,可以通过以下步骤实现: --- ### 1. 转换原理 `LocalDate` 表示不带时间的日期(如 `2024-05-30`),而 `java.util.Date` 本质上是时间戳(包含日期和时间)。因此,转换时需要通过时区信息将日期与时间关联,生成具体的瞬间(`Instant`)。 --- ### 2. 转换步骤 #### (1) 添加时区信息 使用 `atStartOfDay()` 方法将 `LocalDate` 转换为当天的起始时间(`LocalDateTime` 类型,默认时间为 `00:00:00`),并结合时区转换为 `ZonedDateTime`。 **示例代码**: ```java // 假设需要转换的 LocalDate 对象是 firstDay ZonedDateTime zonedDateTime = firstDay.atStartOfDay(ZoneId.systemDefault()); ``` #### (2) 转换为 Instant 从 `ZonedDateTime` 中提取时间戳(`Instant` 类型): ```java Instant instant = zonedDateTime.toInstant(); ``` #### (3) 生成 java.util.Date 通过 `Date.from()` 方法将 `Instant` 转换为 `java.util.Date`: ```java java.util.Date utilDate = java.util.Date.from(instant); ``` --- ### 3. 完整代码示例 ```java import java.time.*; import java.util.Date; public class LocalDateToUtilDate { public static void main(String[] args) { // 示例:获取本月第一天(LocalDate 类型) LocalDate firstDay = LocalDate.now().with(TemporalAdjusters.firstDayOfMonth()); // [^2] // 转换为 java.util.Date ZonedDateTime zonedDateTime = firstDay.atStartOfDay(ZoneId.systemDefault()); Date utilDate = Date.from(zonedDateTime.toInstant()); System.out.println("LocalDate: " + firstDay); // 输出:2024-05-01 System.out.println("java.util.Date: " + utilDate); // 输出:Wed May 01 00:00:00 CST 2024 } } ``` --- ### 4. 注意事项 - **时区影响**:`atStartOfDay(ZoneId)` 的时区选择会影响转换结果。如果未显式指定,使用系统默认时区(`ZoneId.systemDefault()`)。 - **精度问题**:`java.util.Date` 包含毫秒级精度,而 `LocalDate` 仅精确到天,转换后时间部分默认为 `00:00:00`。 ---

public String addAttendance(HttpSession session) { Integer userId = (Integer) session.getAttribute("userid"); // Integer userId =1; LocalDateTime now = LocalDateTime.now(); Attendance lastAttendance = attendanceService.getByAscTime(userId); Attendance attendance = new Attendance(); attendance.setUserid(userId); attendance.setDate(Date.from(now.atZone(ZoneId.systemDefault()).toInstant())); // 获取当前本机时间 LocalDate localDate = now.toLocalDate(); LocalTime localTime = now.toLocalTime(); // 判断数据库没有打卡记录或者有下班签到 if (lastAttendance == null || lastAttendance.getType().equals("下班签到")) { if (localTime.isBefore(LocalTime.of(9, 0))) { attendance.setType("上班签到"); } else if (localDate.equals(getLastAttendanceDate(lastAttendance))) { attendance.setType("下班签到"); } else if (localTime.isAfter(LocalTime.of(9, 0))){ attendance.setType("迟到"); }else if (localTime.isBefore(LocalTime.of(9, 17))){ attendance.setType("早退"); } } else { if (localDate.equals(getLastAttendanceDate(lastAttendance))) { if (localTime.isBefore(LocalTime.of(9, 0))) { attendance.setType("上班签到"); } else if (localTime.isBefore(LocalTime.of(17, 0))){ attendance.setType("早退"); }else if (localTime.isBefore(LocalTime.of(17, 0))){ attendance.setType("下班签到"); } } else { if (localTime.isBefore(LocalTime.of(9, 0))) { attendance.setType("上班签到"); } else if (localTime.isAfter(LocalTime.of(9, 0))){ attendance.setType("迟到"); }else if (localTime.isBefore(LocalTime.of(17, 0))){ attendance.setType("早退"); } } } attendanceService.save(attendance); return "success"; } private LocalDate getLastAttendanceDate(Attendance lastAttendance) { if (lastAttendance == null) { return null; } Date date = lastAttendance.getDate(); Instant instant = date.toInstant(); ZoneId zoneId = ZoneId.systemDefault(); return instant.atZone(zoneId).toLocalDate(); } }

这段代码是一个Java方法,用于添加考勤记录。接收一个`HttpSession`对象作为参数,从中获取当前用户的id,然后根据当前时间判断考勤类型,并将考勤记录保存到数据库中。 下面是具体的解释: - `Integer userId = (Integer) session.getAttribute("userid")`:从`HttpSession`对象中获取当前用户的id。 - `LocalDateTime now = LocalDateTime.now()`:获取当前时间。 - `Attendance lastAttendance = attendanceService.getByAscTime(userId)`:根据用户id获取最近一次考勤记录。 - `Attendance attendance = new Attendance()`:创建一个新的考勤记录。 - `attendance.setUserid(userId)`:将当前用户的id设置为考勤记录的用户id。 - `attendance.setDate(Date.from(now.atZone(ZoneId.systemDefault()).toInstant()))`:将当前时间转换成`java.util.Date`类型,并设置为考勤记录的日期。 - `if (lastAttendance == null || lastAttendance.getType().equals("下班签到"))`:判断最近一次考勤记录是否为空或者为“下班签到”。如果是,则当前考勤记录为“上班签到”或“迟到”或“早退”。如果不是,则当前考勤记录为“下班签到”或“早退”。 - `if (localTime.isBefore(LocalTime.of(9, 0)))`:判断当前时间是否早于上午9点。 - `else if (localDate.equals(getLastAttendanceDate(lastAttendance)))`:判断当前日期是否与最近一次考勤记录的日期相同。 - `else if (localTime.isAfter(LocalTime.of(9, 0)))`:判断当前时间是否晚于上午9点。 - `else if (localTime.isBefore(LocalTime.of(9, 17)))`:判断当前时间是否早于上午9点17分。 - `else if (localTime.isBefore(LocalTime.of(17, 0)))`:判断当前时间是否早于下午5点。 - `else if (localTime.isBefore(LocalTime.of(17, 0)))`:判断当前时间是否早于下午5点。 - `attendanceService.save(attendance)`:将考勤记录保存到数据库。 - `return "success"`:返回一个字符串表示操作成功。
阅读全文

相关推荐

private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); /** * 精准分片 * * @param collection 对应分片库中所有分片表的集合 * @param preciseShardingValue 实际值 * @return 表名 */ @Override public String doSharding(Collection<String> collection, PreciseShardingValue<Date> preciseShardingValue) { Object value = preciseShardingValue.getValue(); String tableSuffix = null; if (value instanceof Date) { LocalDate localDate = ((Date) value).toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); tableSuffix = localDate.format(DateTimeFormatter.ofPattern("yyyyMM")); } else { String column = (String) value; tableSuffix = LocalDateTime.parse(column, formatter).format(DateTimeFormatter.ofPattern("yyyyMM")); } String logicTableName = preciseShardingValue.getLogicTableName(); String actualTableName = logicTableName.concat("_").concat(tableSuffix); if (!collection.contains(actualTableName)) { collection.add(actualTableName); } return actualTableName; } /** * 范围分片 * * @param collection 对应分片库中所有分片表的集合 * @param rangeShardingValue 分片范围 * @return 表名集合 */ @Override public Collection<String> doSharding(Collection<String> collection, RangeShardingValue<Date> rangeShardingValue) { // 逻辑表名 String logicTableName = rangeShardingValue.getLogicTableName(); // 范围参数 Range<Date> valueRange = rangeShardingValue.getValueRange(); //起始时间 结束时间 LocalDateTime start = null; LocalDateTime end = null; Object lowerEndpoint = valueRange.lowerEndpoint(); Object upperEndpoint = valueRange.upperEndpoint(); if (lowerEndpoint instanceof String) { String lower = (String) lowerEndpoint; String upper = (String) upperEndpoint; start = LocalDateTime.parse(lower, formatter); end = LocalDateTime.parse(upper, formatter); } else { start = valueRange.lowerEndpoint().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime(); end = valueRange.upperEndpoint().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime(); } if (end.isAfter(LocalDateTime.now())) { end = LocalDateTime.now(); } // 查询范围的表 Set<String> queryRangeTables = extracted(logicTableName, start, end); return queryRangeTables; } /** * 根据范围计算表名 * * @param logicTableName 表名前缀 * @param lowerEndpoint 起点 * @param upperEndpoint 终点 * @return 最终的表名集合 */ private Set<String> extracted(String logicTableName, LocalDateTime lowerEndpoint, LocalDateTime upperEndpoint) { Set<String> rangeTable = new HashSet<>(); while (lowerEndpoint.isBefore(upperEndpoint)) { String str = getTableNameByDate(lowerEndpoint, logicTableName); rangeTable.add(str); lowerEndpoint = lowerEndpoint.plusMonths(1); } // 获取物理表名 String tableName = getTableNameByDate(upperEndpoint, logicTableName); rangeTable.add(tableName); return rangeTable; } /** * 根据日期获取表名 * * @param dateTime 日期 * @param logicTableName 逻辑表名 * @return 物理表名 */ private String getTableNameByDate(LocalDateTime dateTime, String logicTableName) { String tableSuffix = dateTime.format(DateTimeFormatter.ofPattern("yyyyMM")); return logicTableName.concat("_").concat(tableSuffix); } 将这个算法换成 传递一个date日期 只返回对应的月份

我代码能力很差,你解释一下package com.foonsu.efenxiao.biz.handler; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.date.DateTime; import cn.hutool.core.date.DateUtil; import cn.hutool.core.text.csv.CsvReadConfig; import cn.hutool.core.text.csv.CsvReader; import cn.hutool.core.text.csv.CsvRow; import cn.hutool.core.util.ObjectUtil; import com.alibaba.excel.EasyExcel; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.foonsu.efenxiao.biz.config.CidReadListener; import com.foonsu.efenxiao.biz.feign.OrderClientWrapper; import com.foonsu.efenxiao.biz.util.OrderUtil; import com.foonsu.efenxiao.order.dto.CidOrder; import com.foonsu.efenxiao.biz.vo.ImportCidAccountVO; import com.foonsu.efenxiao.biz.vo.ProgressVo; import com.foonsu.efenxiao.common.utils.CollectionsUtil; import com.foonsu.efenxiao.order.dto.OrderDTO; import com.foonsu.efenxiao.order.dto.OrderExtendDto; import com.foonsu.efenxiao.order.dto.OrderGoodsDto; import com.foonsu.efenxiao.order.dto.OrderTradeDto; import com.foonsu.efenxiao.order.dubbo.CidClient; import com.foonsu.efenxiao.order.dubbo.OrderClient; import com.foonsu.efenxiao.order.entity.CidAccount; import com.foonsu.efenxiao.order.entity.CidAccountingDetail; import com.foonsu.efenxiao.order.entity.CidPlan; import com.foonsu.efenxiao.order.entity.Order; import com.foonsu.efenxiao.order.vo.CidAccountSearchVO; import com.foonsu.efenxiao.order.vo.CidOrderConsumption; import com.foonsu.efenxiao.order.vo.CidPlanSearchResp; import com.foonsu.efenxiao.order.vo.CidPlanSearchVo; import com.foonsu.efenxiao.order.vo.req.AdvertiserAccount; import com.foonsu.efenxiao.order.vo.req.HistoryPushAccountReq; import com.foonsu.efenxiao.platform.dubbo.GoodsClient; import com.foonsu.efenxiao.platform.entity.CidGoodsPriceHistory; import com.foonsu.efenxiao.platform.entity.PlatformGoods; import com.foonsu.efenxiao.platform.vo.PlatformGoodsSkuVO; import com.foonsu.efenxiao.platform.vo.PlatformGoodsVO; import com.foonsu.efenxiao.search.dubbo.OrderSearchClient; import com.foonsu.efenxiao.search.vo.ordersearch.*; import com.foonsu.efenxiao.webutil.progress.impl.CidImportAccountProgress; import com.foonsu.efenxiao.webutil.progress.impl.CidImportStatementProgress; import com.foonsu.framework.boot.common.utils.MD5Utils; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.StringUtils; import org.apache.dubbo.config.annotation.DubboReference; import org.springblade.core.tool.api.R; import org.springblade.core.tool.utils.BeanUtil; import org.springblade.core.tool.utils.StringUtil; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; import java.io.IOException; import java.io.InputStreamReader; import java.math.BigDecimal; import java.math.RoundingMode; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.util.*; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; import java.util.function.Supplier; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; @Component @Slf4j public class CidShopBillHandler { private static final Pattern PATTERN = Pattern.compile("\\d{6}-\\d{15}"); @Resource @Qualifier("cidHandleThreadPoolTaskExecutor") ThreadPoolTaskExecutor cidHandleThreadPoolTaskExecutor; @DubboReference private OrderClient orderClient; @DubboReference private CidClient cidClient; @DubboReference private OrderSearchClient orderSearchClient; @DubboReference private GoodsClient goodsClient; @Resource private OrderClientWrapper orderClientWrapper; @Resource private CidImportStatementProgress cidImportStatementProgress; @Resource private CidImportAccountProgress cidImportAccountProgress; @Value("${cid.tenant-id}") private String tenantId; public static final DateTimeFormatter DATETIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); public CidSearchOrderResp searchOrder(SearchOrderReq req, String tenantId) { SearchOrderBackendParam backendParam = new SearchOrderBackendParam(); backendParam.setTenantId(tenantId); EsSearchOrderResp resp = orderSearchClient.searchCidOrder(req, backendParam); CidSearchOrderResp cidSearchOrderResp = new CidSearchOrderResp(); if (!resp.getOrderNos().isEmpty()) { List<String> allOrderNos = resp.getOrderNos().stream().flatMap(Collection::stream).collect(Collectors.toList()); List<Order> ordersData = orderClientWrapper.queryByOrderNos(allOrderNos); List<CidOrderVO> cidOrderVOS = this.convertData(resp, ordersData); cidSearchOrderResp.setData(cidOrderVOS); } cidSearchOrderResp.setTotal(resp.getTotalCount().intValue()); cidSearchOrderResp.setCurrent(req.getPageNo()); cidSearchOrderResp.setSize(req.getPageSize()); cidSearchOrderResp.setPages(cidSearchOrderResp.getTotal() / req.getPageSize() + (cidSearchOrderResp.getTotal() % req.getPageSize() > 0 ? 1 : 0)); return cidSearchOrderResp; } private List<CidOrderVO> convertData(EsSearchOrderResp esSearchOrderResp, List<Order> orders) { List<CidOrderVO> cidOrderVOS = new ArrayList<>(); for (List<String> orderNos : esSearchOrderResp.getOrderNos()) { List<Order> onelineOrders = orders.stream().filter(t -> orderNos.contains(t.getOrderNo())).collect(Collectors.toList()); if (!onelineOrders.isEmpty()) { Map<String, List<Order>> tradeNoOrders = onelineOrders.stream().collect(Collectors.groupingBy(Order::getTradeNo)); for (String tradeNo : tradeNoOrders.keySet()) { List<Order> splitOrders = tradeNoOrders.get(tradeNo); List<OrderDTO> orderDTOS = OrderUtil.convertToDto(splitOrders); // cid默认单商品订单 OrderDTO orderDTO = orderDTOS.get(0); CidOrderVO cidOrderVO = new CidOrderVO(); cidOrderVO.setShopName(orderDTO.getShopName()); cidOrderVO.setJlId(orderDTO.getOrderGoodsDtoList().get(0).getBindJlId()); cidOrderVO.setTradeNo(orderDTO.getTradeNo()); cidOrderVO.setOrderNo(orderDTO.getOrderNo()); cidOrderVO.setPayAmount(orderDTO.getOrderTradeDto().getPayAmount()); CidOrderExtendVO cidOrderExtendVO = JSON.parseObject(orderDTO.getExtendInfo(), CidOrderExtendVO.class); cidOrderVO.setCidOrderExtendVO(cidOrderExtendVO); List<CidGoodsVo> goodsVos = JSON.parseArray(orderDTO.getGoods(), CidGoodsVo.class); cidOrderVO.setGoods(goodsVos); cidOrderVOS.add(cidOrderVO); } } } return cidOrderVOS; } public void compute(String tenantId, List<String> tradeNos) { Map<String, List<CidAccountingDetail>> accountDetailGroupByTradeNo = cidClient.queryAllImportCidTradeNo(tenantId, null, tradeNos) .stream().collect(Collectors.groupingBy(CidAccountingDetail::getTradeNo)); List<String> importCidTradeNos = new ArrayList<>(accountDetailGroupByTradeNo.keySet()); List> reqsList = CollectionsUtil.splitListToThreads(importCidTradeNos, 1500, 20); for (List<String> orders : reqsList) { cidHandleThreadPoolTaskExecutor.submit(() -> { for (String order : orders) { this.handleOrder(order, tenantId, accountDetailGroupByTradeNo.get(order)); } }); } } public void compute(List<CidAccountingDetail> accountingDetails) { accountingDetails = accountingDetails.stream().sorted(Comparator.comparing(CidAccountingDetail::getTradeNo)).collect(Collectors.toList()); CollectionsUtil.batchDeal(accountingDetails, 500, accountingDetailList -> { List<CidOrder> cidOrders = new ArrayList<>(); Set<String> tradeNos = accountingDetailList.stream().map(CidAccountingDetail::getTradeNo).collect(Collectors.toSet()); Map<String, List<LocalDateTime>> occurTimeByTradeNos = cidClient.queryOccurentTimeByTradeNos(tradeNos); Map<String, List<CidAccountingDetail>> accountDetailGroupByTradeNo = accountingDetailList.stream().collect(Collectors.groupingBy(CidAccountingDetail::getTradeNo)); List<Order> orders = orderClient.queryOrderByTradeNos(new ArrayList<>(tradeNos)); if (CollectionsUtil.isEmpty(orders)) return; Map<String, Order> ordergroupbyTradeNo = orders.stream().collect(Collectors.toMap(Order::getTradeNo, Function.identity())); Map<String, String> ordersGroupByProductIdMap = orders.stream().collect(Collectors.toMap(Order::getTradeNo, order -> { List<OrderGoodsDto> orderGoodsDtos = JSONArray.parseArray(order.getGoods(), OrderGoodsDto.class); return orderGoodsDtos.get(0).getProductId(); })); List<String> skuIds = orders.stream().map(order -> { List<OrderGoodsDto> orderGoodsDtos = JSONArray.parseArray(order.getGoods(), OrderGoodsDto.class); return orderGoodsDtos.get(0).getSkuId(); }).distinct().collect(Collectors.toList()); Map<String, List<CidGoodsPriceHistory>> cidGoodsPriceGroupBySkuIdMap = goodsClient.selectCidGoodsPriceHistory(tenantId, null, skuIds) .stream().collect(Collectors.groupingBy(CidGoodsPriceHistory::getSkuId)); List<String> productIds = ordersGroupByProductIdMap.values().stream().distinct().collect(Collectors.toList()); Map<String, PlatformGoodsVO> goodsGroupByProductId = goodsClient.selectCidGoods(tenantId, productIds, null) .stream().collect(Collectors.toMap(PlatformGoodsVO::getProductId, Function.identity())); accountDetailGroupByTradeNo.forEach((tradeNo, accountDetails) -> { if (ordergroupbyTradeNo.containsKey(tradeNo)) { Order order = ordergroupbyTradeNo.get(tradeNo); String productId = ordersGroupByProductIdMap.get(tradeNo); if (goodsGroupByProductId.containsKey(productId)) { PlatformGoodsVO platformGoodsVO = goodsGroupByProductId.get(productId); OrderExtendDto orderExtendDto = computeGoodsProfit(platformGoodsVO, order, cidGoodsPriceGroupBySkuIdMap); cidOrders.addAll(covertCidOrders(accountDetails, orderExtendDto, tradeNo, platformGoodsVO.getBindJlId(), occurTimeByTradeNos.get(tradeNo))); } } }); if (cidOrders.isEmpty()) return; orderSearchClient.saveCidOrders(cidOrders); }, cidHandleThreadPoolTaskExecutor); } private CidOrder createEsCidOrder(String tenantId, String bindJlId, String tradeNO) { CidOrder esCidOrder = new CidOrder(); esCidOrder.setAccountId(bindJlId); esCidOrder.setTenantId(tenantId); esCidOrder.setTradeNo(tradeNO); return esCidOrder; } private List<CidOrder> covertCidOrders(List<CidAccountingDetail> accountDetails, OrderExtendDto orderExtendDto, String tradeNO, String bindJlId, List<LocalDateTime> occurTimes) { List<CidOrder> esCidOrders = accountDetails.stream().map(accountingDetail -> { CidOrder cidOrder = createEsCidOrder(tenantId, bindJlId, tradeNO); cidOrder.setId(accountingDetail.getUniqueId()); cidOrder.setOccurrenceTime(Collections.singletonList(LocalDateTime.parse(accountingDetail.getOccurrenceTime(), DATETIME_FORMATTER))); cidOrder.setRefundType(orderExtendDto.getRefundType()); BigDecimal incomeAmount = accountingDetail.getIncomeAmount() == null ? BigDecimal.ZERO : accountingDetail.getIncomeAmount(); BigDecimal expenditureAmount = accountingDetail.getExpenditureAmount() == null ? BigDecimal.ZERO : accountingDetail.getExpenditureAmount(); cidOrder.setOrderProfit(incomeAmount.add(expenditureAmount)); switch (accountingDetail.getAccountingType()) { case "扣款": cidOrder.setDeductionSum(accountingDetail.getExpenditureAmount()); switch (accountingDetail.getServiceType()) { case "0040002": cidOrder.setSalesCompensate(accountingDetail.getExpenditureAmount()); break; case "0040003": cidOrder.setExpressCompensate(accountingDetail.getExpenditureAmount()); break; case "0040004": cidOrder.setDelaySendGoods(accountingDetail.getExpenditureAmount()); break; case "0040005": cidOrder.setFalseSendGoods(accountingDetail.getExpenditureAmount()); break; case "0040006": cidOrder.setOutOfStock(accountingDetail.getExpenditureAmount()); } break; case "技术服务费": cidOrder.setTechnologyFee(accountingDetail.getExpenditureAmount()); break; case "多多进宝": cidOrder.setDdjb(accountingDetail.getExpenditureAmount()); } return cidOrder; }).collect(Collectors.toList()); CidOrder esCidOrder = createEsCidOrder(tenantId, bindJlId, tradeNO); esCidOrder.setOrderProfit(BigDecimal.ZERO.subtract(orderExtendDto.getPurchaseExpressFee())); esCidOrder.setId(tradeNO); esCidOrder.setOccurrenceTime(occurTimes.stream().distinct().collect(Collectors.toList())); esCidOrders.add(esCidOrder); return esCidOrders; } private OrderExtendDto computeGoodsProfit(PlatformGoodsVO platformGoods, Order order, Map<String, List<CidGoodsPriceHistory>> cidGoodsPriceGroupBySkuIdMap) { OrderTradeDto orderTradeDto = JSON.parseObject(order.getTrade(), OrderTradeDto.class); List<OrderGoodsDto> orderGoodsDtos = JSONArray.parseArray(order.getGoods(), OrderGoodsDto.class); OrderGoodsDto orderGoodsDto = orderGoodsDtos.get(0); OrderExtendDto orderExtendDto = new OrderExtendDto(); List skuVOS = platformGoods.getGoodsSkuList().stream().filter(sku -> sku.getSkuId().equals(orderGoodsDto.getSkuId())).collect(Collectors.toList()); if (!skuVOS.isEmpty()) { PlatformGoodsSkuVO platformGoodsSkuVO = skuVOS.get(0); BigDecimal purchasePrice = platformGoodsSkuVO.getPurchaseUnitPrice(); BigDecimal expressFee = platformGoodsSkuVO.getExpressFee(); String skuId = platformGoodsSkuVO.getSkuId(); if (cidGoodsPriceGroupBySkuIdMap.containsKey(skuId)) { List<CidGoodsPriceHistory> cidGoodsPriceHistories = cidGoodsPriceGroupBySkuIdMap.get(skuId); for (CidGoodsPriceHistory cidGoodsPriceHistory : cidGoodsPriceHistories) { if (cidGoodsPriceHistory.getType() == 2 && DateUtil.toLocalDateTime(new Date(orderTradeDto.getSourceCreateDate())).isAfter(cidGoodsPriceHistory.getUpdateTime())) { purchasePrice = cidGoodsPriceHistory.getPrice(); } if (cidGoodsPriceHistory.getType() == 3 && DateUtil.toLocalDateTime(new Date(orderTradeDto.getSourceCreateDate())).isAfter(cidGoodsPriceHistory.getUpdateTime())) { expressFee = cidGoodsPriceHistory.getPrice(); } } } orderExtendDto.setPurchasePrice(purchasePrice == null ? BigDecimal.ZERO : purchasePrice); orderExtendDto.setExpressFee(expressFee == null ? BigDecimal.ZERO : expressFee); } if (orderGoodsDto.getRefundType() != null) { orderExtendDto.setPurchaseExpressFee(orderExtendDto.getExpressFee()); orderExtendDto.setRefundType(orderGoodsDto.getRefundType()); } else { if (orderExtendDto.getPurchasePrice() != null && orderExtendDto.getExpressFee() != null) { orderExtendDto.setPurchaseExpressFee(orderExtendDto.getPurchasePrice().add(orderExtendDto.getExpressFee())); } } return orderExtendDto; } private void handleOrder(String importCidTradeNo, String tenantId, List<CidAccountingDetail> cidAccountingDetails) { if (StringUtil.isBlank(importCidTradeNo)) { return; } List<Order> orders = orderClient.queryOrderByTradeNo(importCidTradeNo); if (orders.isEmpty()) { log.info("对账订单为空"); return; } // 默认都是单商品订单 Order order = orders.get(0); List<CidAccountingDetail> accountingDetails = cidClient.queryAccountingDetailByTradeNo(tenantId, importCidTradeNo); if (accountingDetails.isEmpty()) { log.info("对账明细为空"); return; } OrderTradeDto orderTradeDto = JSON.parseObject(order.getTrade(), OrderTradeDto.class); List<OrderGoodsDto> orderGoodsDtos = JSONArray.parseArray(order.getGoods(), OrderGoodsDto.class); OrderGoodsDto orderGoodsDto = orderGoodsDtos.get(0); List platformGoodsVOS = goodsClient.selectCidGoods(tenantId, null, null); if (platformGoodsVOS.isEmpty()) { return; } PlatformGoodsVO platformGoods = platformGoodsVOS.get(0); OrderExtendDto orderExtendDto = StringUtils.isBlank(order.getExtendInfo()) ? new OrderExtendDto() : JSON.parseObject(order.getExtendInfo(), OrderExtendDto.class); BigDecimal orderNum = BigDecimal.ZERO; BigDecimal deductionSum = BigDecimal.ZERO; BigDecimal technologyFee = BigDecimal.ZERO; BigDecimal ddjb = BigDecimal.ZERO; BigDecimal salesCompensate = BigDecimal.ZERO;// 售后补偿 BigDecimal expressCompensate = BigDecimal.ZERO;// 运费补偿 BigDecimal delaySendGoods = BigDecimal.ZERO;// 延迟发货 BigDecimal falseSendGoods = BigDecimal.ZERO;// 虚假发货 BigDecimal outOfStock = BigDecimal.ZERO;// 缺货 for (CidAccountingDetail accountingDetail : accountingDetails) { orderNum = orderNum.add(accountingDetail.getIncomeAmount()).add(accountingDetail.getExpenditureAmount()); boolean serviceFlag = false; switch (accountingDetail.getAccountingType()) { case "扣款": deductionSum = deductionSum.add(accountingDetail.getExpenditureAmount()); serviceFlag = true; break; case "技术服务费": technologyFee = technologyFee.add(accountingDetail.getExpenditureAmount()); break; case "多多进宝": ddjb = ddjb.add(accountingDetail.getExpenditureAmount()); } if (serviceFlag) { switch (accountingDetail.getServiceType()) { case "0040002": salesCompensate = salesCompensate.add(accountingDetail.getExpenditureAmount()); break; case "0040003": expressCompensate = expressCompensate.add(accountingDetail.getExpenditureAmount()); break; case "0040004": delaySendGoods = delaySendGoods.add(accountingDetail.getExpenditureAmount()); break; case "0040005": falseSendGoods = falseSendGoods.add(accountingDetail.getExpenditureAmount()); break; case "0040006": outOfStock = outOfStock.add(accountingDetail.getExpenditureAmount()); } } } orderExtendDto.setDeductionSum(deductionSum); orderExtendDto.setTechnologyFee(technologyFee); orderExtendDto.setDdjb(ddjb); orderExtendDto.setSalesCompensate(salesCompensate); orderExtendDto.setExpressCompensate(expressCompensate); orderExtendDto.setDelaySendGoods(delaySendGoods); orderExtendDto.setFalseSendGoods(falseSendGoods); orderExtendDto.setOutOfStock(outOfStock); orderExtendDto.setPurchasePrice(BigDecimal.ZERO); orderExtendDto.setExpressFee(BigDecimal.ZERO); List skuVOS = platformGoods.getGoodsSkuList().stream().filter(sku -> sku.getSkuId().equals(orderGoodsDto.getSkuId())).collect(Collectors.toList()); if (!skuVOS.isEmpty()) { PlatformGoodsSkuVO platformGoodsSkuVO = skuVOS.get(0); BigDecimal purchasePrice = platformGoodsSkuVO.getPurchaseUnitPrice(); BigDecimal expressFee = platformGoodsSkuVO.getExpressFee(); List<CidGoodsPriceHistory> cidGoodsPriceHistories = goodsClient.selectCidGoodsPriceHistory(tenantId, null, null); if (!cidGoodsPriceHistories.isEmpty()) { for (CidGoodsPriceHistory cidGoodsPriceHistory : cidGoodsPriceHistories) { if (cidGoodsPriceHistory.getType() == 2 && DateUtil.toLocalDateTime(new Date(orderTradeDto.getSourceCreateDate())).isAfter(cidGoodsPriceHistory.getUpdateTime())) { purchasePrice = cidGoodsPriceHistory.getPrice(); } if (cidGoodsPriceHistory.getType() == 3 && DateUtil.toLocalDateTime(new Date(orderTradeDto.getSourceCreateDate())).isAfter(cidGoodsPriceHistory.getUpdateTime())) { expressFee = cidGoodsPriceHistory.getPrice(); } } } orderExtendDto.setPurchasePrice(purchasePrice == null ? BigDecimal.ZERO : purchasePrice); orderExtendDto.setExpressFee(expressFee == null ? BigDecimal.ZERO : expressFee); } if (orderGoodsDto.getRefundType() != null) { orderExtendDto.setPurchaseExpressFee(orderExtendDto.getExpressFee()); orderExtendDto.setRefundType(orderGoodsDto.getRefundType()); } else { if (orderExtendDto.getPurchasePrice() != null && orderExtendDto.getExpressFee() != null) { orderExtendDto.setPurchaseExpressFee(orderExtendDto.getPurchasePrice().add(orderExtendDto.getExpressFee())); } } orderExtendDto.setOrderSum(orderNum); orderExtendDto.setOrderProfit(orderExtendDto.getOrderSum().subtract(orderExtendDto.getPurchaseExpressFee())); orderGoodsDtos.get(0).setBindJlId(platformGoods.getBindJlId()); order.setGoods(JSON.toJSONString(orderGoodsDtos)); order.setExtendInfo(JSON.toJSONString(orderExtendDto)); orderClient.updateCidOrder(order); orderSearchClient.saveCidOrders(orderExtendDto, tenantId, accountingDetails, platformGoods.getBindJlId(), importCidTradeNo); } public void importFile(MultipartFile file, String tenantId, String taskId) { ProgressVo progressVo = new ProgressVo(); R result = R.data(progressVo); try { progressVo.setTotalCount(0); progressVo.setAllHasDone(false); cidImportStatementProgress.saveProgress(taskId, result); CsvReader csvReader = new CsvReader(new InputStreamReader(file.getInputStream(), "GBK"), new CsvReadConfig()); List<CsvRow> rows = csvReader.read().getRows(); int size = rows.size(); log.info("文件行数:{}", size); if (size == 0) { log.info("文件为空"); progressVo.setTotalCount(0); progressVo.setAllHasDone(true); cidImportStatementProgress.saveProgress(taskId, result); return; } this.handlerAccountingDetail(rows, tenantId, taskId); } catch (IOException e) { log.error("导入失败", e); throw new RuntimeException(e); } } private void handlerAccountingDetail(List<CsvRow> rows, String tenantId, String taskId) { LocalDateTime importFileTime = LocalDateTime.now(); log.info("执行处理:{}", rows.size()); AtomicInteger atomicInteger = new AtomicInteger(0); List<CidAccountingDetail> accountingDetails = new ArrayList<>(); try { for (CsvRow row : rows) { try { // log.info("row:{}", row); if (row.size() != 7) { continue; } if (StringUtil.isBlank(row.get(1))) { continue; } if ("商户订单号".equals(row.get(0))) { continue; } atomicInteger.getAndIncrement(); CidAccountingDetail accountingDetail = new CidAccountingDetail(); accountingDetail.setTenantId(tenantId); String tradeNo = row.get(0); if (StringUtil.isBlank(tradeNo)) { Matcher matcher = PATTERN.matcher(row.get(5)); if (matcher.find()) { tradeNo = matcher.group(); } else { continue; } } accountingDetail.setTradeNo(tradeNo); accountingDetail.setOccurrenceTime(row.get(1)); accountingDetail.setIncomeAmount(new BigDecimal(row.get(2))); accountingDetail.setExpenditureAmount(new BigDecimal(row.get(3))); accountingDetail.setAccountingType(row.get(4)); accountingDetail.setRemark(row.get(5)); String[] service = row.get(6).split("\\|"); accountingDetail.setServiceType(service[0]); accountingDetail.setServiceDesc(service[1]); accountingDetail.setCreateTime(importFileTime); String uniqueId = MD5Utils.encryptMD5(accountingDetail.getTradeNo() + accountingDetail.getOccurrenceTime() + accountingDetail.getAccountingType()); accountingDetail.setUniqueId(uniqueId); accountingDetails.add(accountingDetail); } catch (Exception e) { throw new RuntimeException(e); } } if (accountingDetails.isEmpty()) return; CountDownLatch countDownLatch = new CountDownLatch(accountingDetails.size() / 200 + 1); for (int j = 0; j < accountingDetails.size(); j += 200) { List<CidAccountingDetail> cidAccountList = accountingDetails.subList(j, Math.min(j + 200, accountingDetails.size())); cidHandleThreadPoolTaskExecutor.submit(() -> { cidClient.batchSaveAccountingDetail(cidAccountList); countDownLatch.countDown(); }); } countDownLatch.await(); compute(accountingDetails); } catch (Exception e) { throw new RuntimeException(e); } } public void importAccount(MultipartFile file, String tenantId, String taskId) { LocalDateTime importTime = LocalDateTime.now(); ProgressVo progressVo = new ProgressVo(); R result = R.data(progressVo); try { progressVo.setTotalCount(0); progressVo.setAllHasDone(false); cidImportAccountProgress.saveProgress(taskId, result); CidReadListener cidReadListener = new CidReadListener(); cidReadListener.setTenantId(tenantId); EasyExcel.read(file.getInputStream(), ImportCidAccountVO.class, cidReadListener).sheet().doRead(); int size = cidReadListener.getCachedDataList().size(); log.info("账户文件行数:{}", size); if (size == 0) { progressVo.setTotalCount(0); progressVo.setAllHasDone(true); cidImportAccountProgress.saveProgress(taskId, result); log.info("文件为空"); return; } int threadHandlerNum = size / 5 + (size % 5 > 0 ? 1 : 0); int fromIdx = 0; for (int i = 0; i < 5; i++) { List<CidAccount> cidAccounts = cidReadListener.getCachedDataList().subList(fromIdx, size - fromIdx >= threadHandlerNum ? fromIdx + threadHandlerNum : size); cidHandleThreadPoolTaskExecutor.submit(() -> { for (int j = 0; j < cidAccounts.size(); j += 100) { List<CidAccount> cidAccountList = cidAccounts.subList(j, Math.min(j + 100, cidAccounts.size())); cidClient.batchSaveCidAccount(cidAccountList); } log.info("处理账户完成:{}", cidAccounts.size()); return "任务完成"; }); fromIdx += cidAccounts.size(); } try { Thread.sleep(5000); } catch (InterruptedException e) { throw new RuntimeException(e); } log.info("处理账户完成, 调用生成报表:{}", importTime); this.generatePlan(tenantId, taskId, importTime, size); } catch (IOException e) { log.error("导入报表失败:{}", e.getMessage(), e); throw new RuntimeException(e); } } public void generatePlan(String tenantId, String taskId, LocalDateTime importTime, int insertCidAccountCount) { log.info("生成cid报表开始"); CidAccountSearchVO cidAccountSearchVO = new CidAccountSearchVO(); cidAccountSearchVO.setTenantId(tenantId); cidAccountSearchVO.setImportTime(importTime); Long size = 0L; for (int i = 1; i <= 10; i++) { size = cidClient.queryCidAccountCount(cidAccountSearchVO); log.info("计算cidAccount中,查询数据:{}", size); if (insertCidAccountCount == size) { break; } try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } if (size > 0L) { log.info("查询到{}条数据", size); AtomicInteger num = new AtomicInteger(0); ProgressVo progressVo = new ProgressVo(); progressVo.setTotalCount(size.intValue()); R result = R.data(progressVo); progressVo.setSuccessCount(num.get()); cidImportAccountProgress.saveProgress(taskId, result); Long finalSize = size; int pages = 1; int pageNo = 1; do { cidAccountSearchVO.setPageNo(pageNo); Page<CidAccount> cidAccountPage = cidClient.queryCidAccountPage(cidAccountSearchVO); pages = (int) cidAccountPage.getPages(); cidHandleThreadPoolTaskExecutor.submit(() -> { log.info("处理数量:{}", cidAccountPage.getRecords().size()); this.handleGroupPlan(cidAccountPage.getRecords(), taskId, finalSize.intValue(), num); }); pageNo++; } while (pageNo <= pages); } log.info("生成cid报表完成"); } private void handleGroupPlan(List<CidAccount> cidAccounts, String taskId, int accountListSize, AtomicInteger num) { ProgressVo progressVo = new ProgressVo(); progressVo.setTotalCount(accountListSize); R result = R.data(progressVo); for (CidAccount cidAccount : cidAccounts) { List platformGoodsList = goodsClient.queryGoodsByAccountId(cidAccount.getTenantId(), cidAccount.getAccountId()); this.handlePlan(() -> { CidPlan cidPlan = new CidPlan(); cidPlan.setTenantId(cidAccount.getTenantId()); cidPlan.setAccountName(cidAccount.getAccount()); cidPlan.setChannel("巨量引擎"); cidPlan.setJlId(cidAccount.getAccountId()); cidPlan.setTotalConsumption(cidAccount.getConsume()); return cidPlan; }, platformGoodsList, null); num.getAndIncrement(); progressVo.setSuccessCount(num.get()); cidImportAccountProgress.saveProgress(taskId, result); } } private void handlePlan(Supplier<CidPlan> cidPlanSupplier, List platformGoodsList, CidPlanSearchVo cidPlanSearchVo) { CidPlan cidPlan = cidPlanSupplier.get(); CidPlan result = orderSearchClient.statisticsCidOrder(cidPlan, DateUtil.toLocalDateTime(cidPlanSearchVo.getStartTime()), DateUtil.toLocalDateTime(cidPlanSearchVo.getEndTime())); BeanUtil.copyProperties(result, cidPlan); if (CollectionUtil.isNotEmpty(platformGoodsList)) { log.info("计划:{},没有找到商品", cidPlan.getJlId()); PlatformGoods platformGoods = platformGoodsList.get(0); cidPlan.setSalePrice(platformGoods.getSaleUnitPrice()); cidPlan.setPurchasePrice(platformGoods.getPurchaseUnitPrice()); cidPlan.setExpressFee(platformGoods.getExpressFee()); } } private List<CidOrderVO> filterOrderByDate(CidPlanSearchVo cidPlanSearchVo, List<CidOrderVO> orders) { if (cidPlanSearchVo == null) return orders; List<String> tradeNos = cidClient.selectOrderByTradeNoAndTime( orders.stream().map(CidOrderVO::getTradeNo).collect(Collectors.toList()), cidPlanSearchVo); //orderS过滤掉不包含tradeNo的订单 return orders.stream().filter(cidOrderVO -> tradeNos.contains(cidOrderVO.getTradeNo())).collect(Collectors.toList()); } private void handleOrder(List<CidOrderVO> data, Map<String, BigDecimal> param, Map<String, BigDecimal> deductionDetail, Map<String, Integer> orderParam) { int count = (int) data.stream().filter(cidOrderVO -> cidOrderVO.getCidOrderExtendVO().getRefundType() != null).count(); orderParam.put("refundOrderNum", orderParam.get("refundOrderNum") + count); orderParam.put("orderNum", orderParam.get("orderNum") + data.size()); for (CidOrderVO cidOrderVO : data) { if (cidOrderVO.getCidOrderExtendVO().getDeductionSum() != null) { param.put("deductionSum", param.get("deductionSum").add(cidOrderVO.getCidOrderExtendVO().getDeductionSum())); } if (cidOrderVO.getCidOrderExtendVO().getTechnologyFee() != null) { param.put("technologyFee", param.get("technologyFee").add(cidOrderVO.getCidOrderExtendVO().getTechnologyFee())); } if (cidOrderVO.getCidOrderExtendVO().getDdjb() != null) { param.put("ddjb", param.get("ddjb").add(cidOrderVO.getCidOrderExtendVO().getDdjb())); } if (cidOrderVO.getCidOrderExtendVO().getOrderProfit() != null) { param.put("profit", param.get("profit").add(cidOrderVO.getCidOrderExtendVO().getOrderProfit())); } if (cidOrderVO.getCidOrderExtendVO().getSalesCompensate() != null) { deductionDetail.put("salesCompensate", deductionDetail.get("salesCompensate").add(cidOrderVO.getCidOrderExtendVO().getSalesCompensate())); } if (cidOrderVO.getCidOrderExtendVO().getExpressCompensate() != null) { deductionDetail.put("expressCompensate", deductionDetail.get("expressCompensate").add(cidOrderVO.getCidOrderExtendVO().getExpressCompensate())); } if (cidOrderVO.getCidOrderExtendVO().getDelaySendGoods() != null) { deductionDetail.put("delaySendGoods", deductionDetail.get("delaySendGoods").add(cidOrderVO.getCidOrderExtendVO().getDelaySendGoods())); } if (cidOrderVO.getCidOrderExtendVO().getFalseSendGoods() != null) { deductionDetail.put("falseSendGoods", deductionDetail.get("falseSendGoods").add(cidOrderVO.getCidOrderExtendVO().getFalseSendGoods())); } if (cidOrderVO.getCidOrderExtendVO().getOutOfStock() != null) { deductionDetail.put("outOfStock", deductionDetail.get("outOfStock").add(cidOrderVO.getCidOrderExtendVO().getOutOfStock())); } } } public CidPlanSearchResp searchPlan(CidPlanSearchVo cidPlanSearchVo) { CidPlanSearchResp cidPlanSearchResp = new CidPlanSearchResp(); Page<CidPlan> cidPlanPage = cidClient.queryCidPlanPage(cidPlanSearchVo); List<CidPlan> cidPlans = cidPlanPage.getRecords(); if (ObjectUtil.isAllNotEmpty(cidPlanSearchVo.getStartTime(), cidPlanSearchVo.getEndTime())) { realTimeCompute(cidPlans, cidPlanSearchVo); } BigDecimal currentProfit = cidPlans.stream().map(CidPlan::getProfit).reduce(BigDecimal.ZERO, BigDecimal::add).setScale(2, RoundingMode.HALF_UP); cidPlanSearchResp.setCurrentProfit(currentProfit); cidPlanSearchResp.setData(cidPlanPage); CidPlan result = orderSearchClient.statisticsCidOrder(new CidPlan(), DateUtil.toLocalDateTime(cidPlanSearchVo.getStartTime()), DateUtil.toLocalDateTime(cidPlanSearchVo.getEndTime())); cidPlanSearchResp.setTotalProfit(result.getProfit()); return cidPlanSearchResp; } private void realTimeCompute(List<CidPlan> cidPlans, CidPlanSearchVo cidPlanSearchVo) { if (CollectionsUtil.isEmpty(cidPlans)) return; computeCidPlan(cidPlans, cidPlanSearchVo, cidPlans.stream().map(CidPlan::getJlId).collect(Collectors.toList())); } private void computeCidPlan(List<CidPlan> cidPlans, CidPlanSearchVo cidPlanSearchVo, List<String> accountIds) { Map<String, List> goodsMapGroupByBindJlId = goodsClient.queryGoodsByAccountIds(cidPlanSearchVo.getTenantId(), accountIds) .stream().collect(Collectors.groupingBy(PlatformGoods::getBindJlId)); CountDownLatch countDownLatch = new CountDownLatch(cidPlans.size()); cidPlans.forEach(cidPlan -> cidHandleThreadPoolTaskExecutor.execute(() -> { this.handlePlan(() -> cidPlan, goodsMapGroupByBindJlId.get(cidPlan.getJlId()), cidPlanSearchVo); countDownLatch.countDown(); })); try { countDownLatch.await(); } catch (InterruptedException e) { log.error("realTimeCompute error: {}", e.getMessage()); } } @Transactional(rollbackFor = Exception.class) public Boolean pushAccount(List<AdvertiserAccount> data) { List<String> accountIds = data.stream().map(AdvertiserAccount::getAdvertiserId).collect(Collectors.toList()); Map<String, List> goodsMapGroupByBindJlId = goodsClient.queryGoodsByAccountIds(tenantId, accountIds) .stream().collect(Collectors.groupingBy(PlatformGoods::getBindJlId)); Map<String, CidPlan> cidPlanMap = cidClient.queryCidPlans(tenantId, accountIds).stream().collect(Collectors.toMap(CidPlan::getJlId, Function.identity())); CopyOnWriteArrayList<CidPlan> cidPlansList = new CopyOnWriteArrayList<>(); CountDownLatch count = new CountDownLatch(accountIds.size()); List<CidAccount> cidAccounts = data.stream().map(account -> { CidAccount cidAccount = account.mapToCidAccount(new HashMap<>(), tenantId); cidHandleThreadPoolTaskExecutor.execute(() -> { String accountId = cidAccount.getAccountId(); this.handlePlan(() -> dealHistoryPlan(cidAccount, cidPlanMap, cidPlansList), goodsMapGroupByBindJlId.get(accountId), null); count.countDown(); }); return cidAccount; }).collect(Collectors.toList()); cidClient.batchSaveCidPlan(cidPlansList); orderSearchClient.saveCidConsumption(convertEsCidOrderConsumption(data, new Date())); return cidClient.batchSaveCidAccount(cidAccounts); } private CidPlan dealHistoryPlan(CidAccount cidAccount, Map<String, CidPlan> cidPlanMap, CopyOnWriteArrayList<CidPlan> cidPlansList) { String accountId = cidAccount.getAccountId(); List<CidPlan.HistoryTotalConsumption> historyTotalConsumptions = cidPlanMap.containsKey(accountId) && CollectionsUtil.isNotEmpty(cidPlanMap.get(accountId).getHistoryTotalConsumptions()) ? cidPlanMap.get(accountId).getHistoryTotalConsumptions() : new ArrayList<>(); String today = DateUtil.formatDate(new Date()); BigDecimal consume = cidAccount.getConsume(); CidPlan.HistoryTotalConsumption todayData = new CidPlan.HistoryTotalConsumption(DateUtil.parseDate(today), consume); if (historyTotalConsumptions.isEmpty() || cidPlanMap.get(accountId).getHistoryTotalConsumptions().stream() .noneMatch(historyTotalConsumption -> today.equals(DateUtil.formatDate(historyTotalConsumption.getDate())))) { historyTotalConsumptions.add(todayData); } CidPlan cidPlan = new CidPlan(); cidPlan.setTenantId(cidAccount.getTenantId()); cidPlan.setAccountName(cidAccount.getAccount()); cidPlan.setChannel("巨量引擎"); cidPlan.setJlId(accountId); cidPlan.setTotalConsumption(consume); cidPlan.setHistoryTotalConsumption(JSON.toJSONString(historyTotalConsumptions)); cidPlansList.add(cidPlan); return cidPlan; } @Transactional(rollbackFor = Exception.class) public void pushHistoryData(HistoryPushAccountReq historyPushAccountReq) { String day = historyPushAccountReq.getDate(); DateTime time = DateUtil.parseDate(day); List<AdvertiserAccount> advertiserAccounts = historyPushAccountReq.getData(); List<String> accountIds = advertiserAccounts.stream().map(AdvertiserAccount::getAdvertiserId).collect(Collectors.toList()); Map<String, BigDecimal> historyDataMap = advertiserAccounts.stream().collect(Collectors.toMap(AdvertiserAccount::getAdvertiserId, AdvertiserAccount::getStatCost)); List<CidPlan> cidPlans = cidClient.queryCidPlans(tenantId, accountIds); cidPlans.forEach(cidPlan -> { BigDecimal consume = historyDataMap.get(cidPlan.getJlId()); CidPlan.HistoryTotalConsumption todayData = new CidPlan.HistoryTotalConsumption(time, consume); List<CidPlan.HistoryTotalConsumption> historyTotalConsumptions = cidPlan.getHistoryTotalConsumptions(); if (CollectionsUtil.isNotEmpty(historyTotalConsumptions)) { if (historyTotalConsumptions.stream() .noneMatch(consumption -> day.equals(DateUtil.formatDate(consumption.getDate())))) { historyTotalConsumptions.add(todayData); historyTotalConsumptions.sort(Comparator.comparing(CidPlan.HistoryTotalConsumption::getDate)); cidPlan.setHistoryTotalConsumption(JSON.toJSONString(historyTotalConsumptions)); } } else { cidPlan.setHistoryTotalConsumption(JSON.toJSONString(Collections.singleton(todayData))); } }); if (!cidPlans.isEmpty()) { cidClient.batchSaveCidPlan(cidPlans); orderSearchClient.saveCidConsumption(convertEsCidOrderConsumption(advertiserAccounts, time)); } } private List<CidOrderConsumption> convertEsCidOrderConsumption(List<AdvertiserAccount> advertiserAccounts, Date time) { return advertiserAccounts.stream().map(advertiserAccount -> new CidOrderConsumption(advertiserAccount, time.toInstant() .atZone(ZoneId.systemDefault()) .toLocalDate())).collect(Collectors.toList()); } public void syncData(String accountId) { CollectionsUtil.batchDealWholeData(pageNo -> { Page<CidPlan> cidPlanPage = cidClient.queryCidPlanPage(new CidPlanSearchVo(pageNo, 1000, tenantId, accountId)); List<CidPlan> cidPlans = cidPlanPage.getRecords(); log.info("cidPlans:{}", JSON.toJSONString(cidPlans)); List<CidOrderConsumption> cidOrderConsumptions = cidPlans.stream().flatMap(cidPlan -> cidPlan.getHistoryTotalConsumptions().stream() .filter(historyTotalConsumption -> BigDecimal.ZERO.compareTo(historyTotalConsumption.getTotalConsumption()) < 0) .map(historyTotalConsumption -> new CidOrderConsumption(cidPlan.getJlId(), historyTotalConsumption)) ).collect(Collectors.toList()); log.info("cidOrderConsumptions:{}", JSON.toJSONString(cidOrderConsumptions)); if (CollectionUtil.isNotEmpty(cidOrderConsumptions)) { orderSearchClient.saveCidConsumption(cidOrderConsumptions); } return cidPlans; }); } } 并且告诉我每一行为什么这样写

最新推荐

recommend-type

光子学领域基于连续域束缚态的铌酸锂二次谐波超表面COMSOL模拟研究 - 二次谐波

内容概要:本文探讨了基于连续域束缚态(BICs)的铌酸锂二次谐波超表面的COMSOL光子晶体模拟。首先介绍了BICs的概念及其在光学领域的应用潜力,然后详细描述了在COMSOL中建立的三维模型,包括周期性晶格结构和BICs模式。接着分析了模拟结果,展示了光子在铌酸锂超表面上的传播行为变化,特别是二次谐波效应的显著提升。最后讨论了代码实现和模拟结果的可视化方法,并展望了未来优化方向和其他潜在应用。 适合人群:从事光子学、光学工程及相关领域的研究人员和学生。 使用场景及目标:适用于希望深入了解BICs在铌酸锂二次谐波中的应用机制,以及希望通过COMSOL进行类似模拟实验的人群。 其他说明:文中涉及大量COMSOL建模和仿真细节,对于初学者可能有一定难度,建议先掌握相关基础知识再进行深入学习。
recommend-type

Webdiy.net新闻系统v1.0企业版发布:功能强大、易操作

标题中提到的"Webdiy.net新闻系统 v1.0 企业版"是一个针对企业级应用开发的新闻内容管理系统,是基于.NET框架构建的。从描述中我们可以提炼出以下知识点: 1. **系统特性**: - **易用性**:系统设计简单,方便企业用户快速上手和操作。 - **可定制性**:用户可以轻松修改网站的外观和基本信息,例如网页标题、页面颜色、页眉和页脚等,以符合企业的品牌形象。 2. **数据库支持**: - **Access数据库**:作为轻量级数据库,Access对于小型项目和需要快速部署的场景非常合适。 - **Sql Server数据库**:适用于需要强大数据处理能力和高并发支持的企业级应用。 3. **性能优化**: - 系统针对Access和Sql Server数据库进行了特定的性能优化,意味着它能够提供更为流畅的用户体验和更快的数据响应速度。 4. **编辑器功能**: - **所见即所得编辑器**:类似于Microsoft Word,允许用户进行图文混排编辑,这样的功能对于非技术人员来说非常友好,因为他们可以直观地编辑内容而无需深入了解HTML或CSS代码。 5. **图片管理**: - 新闻系统中包含在线图片上传、浏览和删除的功能,这对于新闻编辑来说是非常必要的,可以快速地为新闻内容添加相关图片,并且方便地进行管理和更新。 6. **内容发布流程**: - **审核机制**:后台发布新闻后,需经过审核才能显示到网站上,这样可以保证发布的内容质量,减少错误和不当信息的传播。 7. **内容排序与类别管理**: - 用户可以按照不同的显示字段对新闻内容进行排序,这样可以突出显示最新或最受欢迎的内容。 - 新闻类别的动态管理及自定义显示顺序,可以灵活地对新闻内容进行分类,方便用户浏览和查找。 8. **前端展示**: - 系统支持Javascript前端页面调用,这允许开发者将系统内容嵌入到其他网页或系统中。 - 支持iframe调用,通过这种HTML元素可以将系统内容嵌入到网页中,实现了内容的跨域展示。 9. **安全性**: - 提供了默认的管理账号和密码(webdiy / webdiy.net),对于企业应用来说,这些默认的凭证需要被替换,以保证系统的安全性。 10. **文件结构**: - 压缩包文件名称为"webdiynetnews",这可能是系统的根目录名称或主要安装文件。 11. **技术栈**: - 系统基于ASP.NET技术构建,这表明它使用.NET框架开发,并且可以利用.NET生态中的各种库和工具来实现功能的扩展和维护。 在实施和部署这样的系统时,企业可能还需要考虑以下方面: - **可扩展性**:随着业务的增长,系统应该能容易地扩展,以支持更多的用户和内容。 - **安全性**:除了更改为安全的管理员凭证外,还需考虑防止SQL注入、XSS攻击等网络安全问题。 - **备份和恢复**:定期备份数据库和内容是很重要的,以防数据丢失或需要恢复到先前的状态。 - **多用户和权限管理**:企业环境可能需要多级用户权限设置,以适应不同的团队和角色。 - **SEO优化**:系统应支持良好的搜索引擎优化实践,以便于内容在搜索引擎中的排名和发现。 - **移动适应性**:由于移动设备的广泛使用,系统应具备良好的响应式设计,以提供良好的移动用户体验。 根据描述,该系统似乎是一个成熟的解决方案,适用于需要快速搭建新闻网站的企业用户,但同时也应该注意定期的维护和更新,以确保系统的稳定性和安全性。
recommend-type

【Windows 11用户的福音】:一步到位解决GX Works2安装问题,让兼容性不再是问题!

# 1. GX Works2简介与Windows 11兼容性问题 ## 简介GX Works2 GX Works2是由三菱电机开发的一款针对其PLC(可编程逻辑控制器)产品的编程和调试软件。该软件以其直观的用户界面和强大的编程功能闻名于工业自动化领域,支持从简单的逻辑控制到复杂的系统集成项目。随着Windows操作系统的迭代升级,尤其是新推
recommend-type

电磁加热双边谐振和单边谐振的区别

<think>我们正在处理关于电磁加热技术中双边谐振与单边谐振的工作原理及区别的问题。 首先,需要明确用户意图是了解这两种谐振方式的区别以及它们的工作原理。 我们将通过以下步骤进行: 1. 调用网络搜索工具,检索关于电磁加热中双边谐振和单边谐振的信息。 2. 整合检索到的内容,按照要求生成回答,包括工作原理和区别,并组织成多个方法或步骤(但避免使用步骤词汇,用换行分隔)。 3. 在回答中,如果有公式或代码,按照指定格式处理。 4. 最后,添加相关问题部分。 注意:避免使用第一人称,避免步骤词汇,引用内容不集中末尾,而是融入回答中。 根据搜索,电磁加热中的谐振通常指的是感应加
recommend-type

EnvMan源代码压缩包内容及功能解析

根据给定文件信息,我们需要生成关于“EnvMan-source.zip”这一压缩包的知识点。首先,由于提供的信息有限,我们无法直接得知EnvMan-source.zip的具体内容和功能,但可以通过标题、描述和标签中的信息进行推断。文件名称列表只有一个“EnvMan”,这暗示了压缩包可能包含一个名为EnvMan的软件或项目源代码。以下是一些可能的知识点: ### EnvMan软件/项目概览 EnvMan可能是一个用于环境管理的工具或框架,其源代码被打包并以“EnvMan-source.zip”的形式进行分发。通常,环境管理相关的软件用于构建、配置、管理和维护应用程序的运行时环境,这可能包括各种操作系统、服务器、中间件、数据库等组件的安装、配置和版本控制。 ### 源代码文件说明 由于只有一个名称“EnvMan”出现在文件列表中,我们可以推测这个压缩包可能只包含一个与EnvMan相关的源代码文件夹。源代码文件夹可能包含以下几个部分: - **项目结构**:展示EnvMan项目的基本目录结构,通常包括源代码文件(.c, .cpp, .java等)、头文件(.h, .hpp等)、资源文件(图片、配置文件等)、文档(说明文件、开发者指南等)、构建脚本(Makefile, build.gradle等)。 - **开发文档**:可能包含README文件、开发者指南或者项目wiki,用于说明EnvMan的功能、安装、配置、使用方法以及可能的API说明或开发者贡献指南。 - **版本信息**:在描述中提到了版本号“-1101”,这表明我们所见的源代码包是EnvMan的1101版本。通常版本信息会详细记录在版本控制文件(如ChangeLog或RELEASE_NOTES)中,说明了本次更新包含的新特性、修复的问题、已知的问题等。 ### 压缩包的特点 - **命名规范**:标题、描述和标签中的一致性表明这是一个正式发布的软件包。通常,源代码包的命名会遵循一定的规范,如“项目名称-版本号-类型”,在这里类型是“source”。 - **分发形式**:以.zip格式的压缩包进行分发,是一种常见的软件源代码分发方式。虽然较现代的版本控制系统(如Git、Mercurial)通常支持直接从仓库克隆源代码,但打包成zip文件依然是一种便于存储和传输的手段。 ### 可能的应用场景 - **开发环境配置**:EnvMan可能是用于创建、配置和管理开发环境的工具,这种工具在开发人员设置新的开发机或新的项目环境时非常有用。 - **自动化部署**:EnvMan可能包含自动化部署环境的脚本或命令,使得部署流程变得快捷且高效。 - **监控与维护**:作为环境管理工具,EnvMan可能还支持对环境的监控功能,包括系统资源监控、服务状态检查等,以保证生产环境的稳定性。 ### 总结 尽管以上知识点是基于有限的信息进行的假设性推论,但EnvMan-source.zip包可能是一个用于环境管理的软件或项目的源代码包。该软件或项目可能包含构建和部署自动化环境的能力,以及对运行时环境的监控和维护。文件命名的一致性暗示这是一个正式的版本发布。如果要深入了解EnvMan的功能与用法,建议直接查看压缩包中的文档或源代码注释。同时,考虑到源代码的开发,我们还应该探究该项目所使用的技术栈、编程语言以及版本控制工具等,这将有助于进一步了解EnvMan的技术细节。
recommend-type

【Windows 11终极解决方案】:彻底攻克GX Works2安装中难缠的.Net Framework 3.5障碍!

# 1. Windows 11与GX Works2简介 ## 1.1 Windows 11操作系统概览 Windows 11,作为微软最新的操作系统,不仅仅提供了一种现代的用户体验,而且加强了在企业环境中的安全性与生产力工具。其引入了全新的界面设计、改进的多任务处理以及对Android应用的支持,使它成为IT专业人
recommend-type

贝叶斯gmm

<think>首先,用户的问题是关于贝叶斯高斯混合模型(Bayesian Gaussian Mixture Model, BGMM)的原理和应用。我需要根据系统指令来构建回答。 系统指令包括: - 所有行内数学表达式使用 `$...$` 格式。 - 独立公式使用 `$$...$$` 格式并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 在回答中引用的段落末尾自然地添加引用标识,如 `[^1]`。 - 回答结构清晰,帮助用户逐步解决问题。 - 保证回答真实可靠。 参考提供的引用: - 引用[1]:讨论了高斯混合模型在机器学习中的应用,包括其优点和挑战。 -
recommend-type

威海卫国旅游网美化版网站建设意向表下载

根据提供的文件信息,我们可以提取以下知识点: 1. 网站建设意向表概念: 网站建设意向表是指在网站开发过程中,客户或项目负责人填写的一份表单,用以明确表达网站建设的需求、目标、功能、风格偏好等关键信息。它是项目开发前期沟通的载体,确保开发团队能够准确理解客户需求并据此进行网站设计和功能实现。 2. 美化版的含义: 美化版通常指的是对原有产品、设计或界面进行视觉上的改进,使之更加吸引人和用户体验更佳。在网站建设的上下文中,美化版可能指对网站的设计元素、布局、色彩搭配等进行更新和优化,从而提高网站的美观度和用户交互体验。 3. 代码和CSS的优化: 代码优化:指的是对网站的源代码进行改进,包括但不限于提高代码的执行效率、减少冗余、提升可读性和可维护性。这可能涉及代码重构、使用更高效的算法、减少HTTP请求次数等技术手段。 CSS优化:层叠样式表(Cascading Style Sheets, CSS)是一种用于描述网页呈现样式的语言。CSS优化可能包括对样式的简化、合并、压缩,使用CSS预处理器、应用媒体查询以实现响应式设计,以及采用更高效的选择器减少重绘和重排等。 4. 网站建设实践: 网站建设涉及诸多实践,包括需求收集、网站规划、设计、编程、测试和部署。其中,前端开发是网站建设中的重要环节,涉及HTML、CSS和JavaScript等技术。此外,还需要考虑到网站的安全性、SEO优化、用户体验设计(UX)、交互设计(UI)等多方面因素。 5. 文件描述中提到的威海卫国旅游网: 威海卫国旅游网可能是一个以威海地区旅游信息为主题的网站。网站可能提供旅游景点介绍、旅游服务预订、旅游攻略分享等相关内容。该网站的这一项目表明,他们关注用户体验并致力于提供高质量的在线服务。 6. 文件标签的含义: 文件标签包括“下载”、“源代码”、“源码”、“资料”和“邮件管理类”。这些标签说明该压缩文件中包含了可以下载的资源,具体内容是网站相关源代码以及相关的开发资料。另外,提到“邮件管理类”可能意味着在网站项目中包含了用于处理用户邮件订阅、通知、回复等功能的代码或模块。 7. 压缩文件的文件名称列表: 该文件的名称为“网站建设意向表 美化版”。从文件名称可以推断出该文件是一个表单,用于收集网站建设相关需求,且经过了视觉和界面的改进。 综合上述内容,可以得出结论,本表单文件是一个为特定网站建设项目设计的需求收集工具,经过技术优化并美化了用户界面,旨在提升用户体验,并且可能包含了邮件管理功能,方便网站运营者与用户进行沟通。该文件是一份宝贵资源,尤其是对于需要进行网站建设或优化的开发者来说,可以作为参考模板或直接使用。
recommend-type

【FPGA设计高手必读】:高效除法的实现与基2 SRT算法优化

# 1. FPGA设计中的高效除法基础 ## 为何高效除法在FPGA设计中至关重要 在数字电路设计领域,尤其是在现场可编程门阵列(FPGA)中,高效的除法器设计对于实现高性能运算至关重要。由于除法运算相对复杂,其硬件实现往往涉及大量的逻辑门和触发器,消耗的资源和执行时间较多。因此,开发者必须设计出既高效又节省资源的除法器,以适应FPGA设计的性能和资源限制。此外,随着应用领域对计算速度和精度要求的不断提升,传统算法无法满足新需求,这就推动了高效除法算法的研究与发展。 ## 高效除法实现的挑战 实现FPGA设计中的高效除法,面临着诸多挑战。首先,除法操作的固有延迟限制了整体电路的性能;其
recommend-type

单片机的NOP指令时间看单片机的什么速率

<think>嗯,用户问的是单片机中NOP指令的执行时间与什么速率有关。这个问题涉及到单片机最底层的时序特性,需要从时钟周期和机器周期的关系来解释。 用户可能正在学习单片机底层原理或者在做精确时序控制相关的开发。从问题表述来看,用户应该已经了解NOP指令的基本作用(空操作),现在想深入理解其时间特性。这类问题通常出现在需要精确延时或同步的场景中。 参考之前的引用内容,虽然引用[1]提到51单片机的RAM结构,引用[2]展示串口通信,引用[3]涉及定时器中断,但这些都与当前问题没有直接关联。需要完全从单片机时钟体系的角度回答。 核心要点在于: - 所有指令执行时间都取决于时钟源 - NOP