From 2cda8e26c67cf450f667bc15eef50548f7e00113 Mon Sep 17 00:00:00 2001 From: chen-xin-zhi <3588068430@qq.com> Date: Mon, 9 Dec 2024 15:31:39 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E4=BA=86=E5=95=86=E5=93=81?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 6 + .../cultural/heritage/config/WxPayConfig.java | 78 ++++++ .../book/BookingDateController.java | 161 +++++++---- .../good/AppointmentDateController.java | 210 ++++++++++++++ .../controller/good/GoodController.java | 90 +++++- .../controller/wx/WeChatPayController.java | 120 ++++++++ .../heritage/mapper/TimeIntervalMapper.java | 7 + .../AppointmentDateSingleAddRequest.java | 44 +++ .../model/dto/book/BookingDateAddRequest.java | 25 +- .../dto/book/BookingDateUpdateRequest.java | 16 +- .../service/ServiceGoodUpdateRequest.java | 4 +- .../timeinterval/TimeIntervalAddRequest.java | 40 +++ .../timeperiod/TimePeriodUpdateRequest.java | 8 + .../single/TimePeriodSingleAddRequest.java | 46 +++ .../single/TimePeriodSingleUpdateRequest.java | 36 +++ .../heritage/model/entity/BookingDate.java | 12 - .../heritage/model/entity/TimeInterval.java | 67 +++++ .../heritage/model/vo/book/BookingDateVO.java | 19 +- .../model/vo/timeinterval/TimeIntervalVO.java | 36 +++ .../service/book/BookingDateService.java | 4 +- .../service/book/TimeIntervalService.java | 13 + .../book/impl/BookingDateServiceImpl.java | 35 ++- .../book/impl/TimeIntervalServiceImpl.java | 44 +++ .../heritage/service/wxpay/WeChatService.java | 53 ++++ .../service/wxpay/impl/WeChatServiceImpl.java | 265 ++++++++++++++++++ .../heritage/utils/AppointmentDateUtil.java | 23 -- src/main/resources/apiclient_key.pem | 28 ++ src/main/resources/application.yml | 19 +- .../resources/mapper/TimeIntervalMapper.xml | 7 + .../com/cultural/heritage/test/Animal.java | 39 +++ .../java/com/cultural/heritage/test/B.java | 8 +- 31 files changed, 1410 insertions(+), 153 deletions(-) create mode 100644 src/main/java/com/cultural/heritage/config/WxPayConfig.java create mode 100644 src/main/java/com/cultural/heritage/controller/good/AppointmentDateController.java create mode 100644 src/main/java/com/cultural/heritage/controller/wx/WeChatPayController.java create mode 100644 src/main/java/com/cultural/heritage/mapper/TimeIntervalMapper.java create mode 100644 src/main/java/com/cultural/heritage/model/dto/appointment/single/AppointmentDateSingleAddRequest.java create mode 100644 src/main/java/com/cultural/heritage/model/dto/timeinterval/TimeIntervalAddRequest.java create mode 100644 src/main/java/com/cultural/heritage/model/dto/timeperiod/single/TimePeriodSingleAddRequest.java create mode 100644 src/main/java/com/cultural/heritage/model/dto/timeperiod/single/TimePeriodSingleUpdateRequest.java create mode 100644 src/main/java/com/cultural/heritage/model/entity/TimeInterval.java create mode 100644 src/main/java/com/cultural/heritage/model/vo/timeinterval/TimeIntervalVO.java create mode 100644 src/main/java/com/cultural/heritage/service/book/TimeIntervalService.java create mode 100644 src/main/java/com/cultural/heritage/service/book/impl/TimeIntervalServiceImpl.java create mode 100644 src/main/java/com/cultural/heritage/service/wxpay/WeChatService.java create mode 100644 src/main/java/com/cultural/heritage/service/wxpay/impl/WeChatServiceImpl.java delete mode 100644 src/main/java/com/cultural/heritage/utils/AppointmentDateUtil.java create mode 100644 src/main/resources/apiclient_key.pem create mode 100644 src/main/resources/mapper/TimeIntervalMapper.xml create mode 100644 src/test/java/com/cultural/heritage/test/Animal.java diff --git a/pom.xml b/pom.xml index a5b8ea3..327420a 100644 --- a/pom.xml +++ b/pom.xml @@ -177,6 +177,12 @@ 5.2.0 + + + com.github.wechatpay-apiv3 + wechatpay-java + 0.2.10 + diff --git a/src/main/java/com/cultural/heritage/config/WxPayConfig.java b/src/main/java/com/cultural/heritage/config/WxPayConfig.java new file mode 100644 index 0000000..338b774 --- /dev/null +++ b/src/main/java/com/cultural/heritage/config/WxPayConfig.java @@ -0,0 +1,78 @@ +package com.cultural.heritage.config; + +import com.wechat.pay.java.core.RSAAutoCertificateConfig; +import com.wechat.pay.java.core.util.IOUtil; +import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension; +import com.wechat.pay.java.service.refund.RefundService; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.ClassPathResource; +import org.springframework.stereotype.Component; + +import java.io.IOException; + +@Data +@Slf4j +@Configuration +@Component("WxPayConfig") +@ConfigurationProperties(prefix = "wx.pay") +public class WxPayConfig { + + private String appId; + + private String apiV3Key; + + private String notifyUrl; + + private String merchantId; + + private String privateKeyPath; + + private String merchantSerialNumber; + + // RSA配置 + private RSAAutoCertificateConfig RSAConfig; + + // JSAPI支付 + private JsapiServiceExtension jsapiServiceExtension; + + // 退款 + private RefundService refundService; + + /** + * 初始化配置 + */ + @Bean + public boolean initWxPayConfig() throws IOException { + this.RSAConfig = buildRSAAutoCertificateConfig(); + this.jsapiServiceExtension = buildJsapiServiceExtension(RSAConfig); + this.refundService = buildRefundService(RSAConfig); + return true; + } + + // 构建并使用自动更新平台证书的RSA配置,一个商户号只能初始化一个配置,否则会因为重复的下载任务报错 + private RSAAutoCertificateConfig buildRSAAutoCertificateConfig() throws IOException { + // 将 resource 目录下的文件转为 InputStream,然后利用 IOUtil.toString(inputStream) 转化为密钥 + String privateKey = IOUtil.toString(new ClassPathResource(privateKeyPath).getInputStream()); + return new RSAAutoCertificateConfig.Builder() + .merchantId(merchantId) + .privateKey(privateKey) + .merchantSerialNumber(merchantSerialNumber) + .apiV3Key(apiV3Key) + .build(); + } + + // 构建JSAPI支付 + private JsapiServiceExtension buildJsapiServiceExtension(RSAAutoCertificateConfig config) { + return new JsapiServiceExtension.Builder().config(config).build(); + } + + // 构建退款 + private RefundService buildRefundService(RSAAutoCertificateConfig config) { + return new RefundService.Builder().config(config).build(); + } + +} diff --git a/src/main/java/com/cultural/heritage/controller/book/BookingDateController.java b/src/main/java/com/cultural/heritage/controller/book/BookingDateController.java index 31a7826..11988c9 100644 --- a/src/main/java/com/cultural/heritage/controller/book/BookingDateController.java +++ b/src/main/java/com/cultural/heritage/controller/book/BookingDateController.java @@ -1,6 +1,8 @@ package com.cultural.heritage.controller.book; +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.cultural.heritage.annotation.AuthCheck; import com.cultural.heritage.common.BaseResponse; @@ -11,27 +13,35 @@ import com.cultural.heritage.constant.UserConstant; import com.cultural.heritage.exception.BusinessException; import com.cultural.heritage.exception.ThrowUtils; import com.cultural.heritage.model.dto.CommonStringRequest; -import com.cultural.heritage.model.dto.book.BookingDateUpdateRequest; +import com.cultural.heritage.model.dto.book.BookingDateAddRequest; +import com.cultural.heritage.model.dto.timeinterval.TimeIntervalAddRequest; import com.cultural.heritage.model.entity.BookingDate; +import com.cultural.heritage.model.entity.TimeInterval; import com.cultural.heritage.model.vo.book.BookingDateVO; +import com.cultural.heritage.model.vo.timeinterval.TimeIntervalVO; import com.cultural.heritage.service.book.BookingDateService; +import com.cultural.heritage.service.book.TimeIntervalService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.BeanUtils; -import org.springframework.scheduling.annotation.Scheduled; import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; @RestController @RequestMapping("/book") @Slf4j -@Tag(name = "预约日期管理模块") +@Tag(name = "写真预约日期管理模块") public class BookingDateController { @@ -39,75 +49,130 @@ public class BookingDateController { private BookingDateService bookingDateService; + @Resource + private TimeIntervalService timeIntervalService; + + + /** - * (写真预约)初始化未来一天的预约日期 + * Web端管理员添加写真预约日期和时间段 + * @param bookingDateAddRequestList 预约日期列表 + * @return 是否添加成功 */ -// @Scheduled(cron = "*/5 * * * * ?") - // 每天00:00-00:00调用 - @Scheduled(cron = "0 0 0 * * ?") + @PostMapping("/add") + @Operation(summary = "Web端管理员添加写真预约日期和时间段", description = "参数:预约日期列表,权限:管理员(admin, boss),方法名:addBookingDate") @Transactional(rollbackFor = Exception.class) - @PostMapping("/init") - @Operation(summary = "(自动调用)初始化未来一天的预约日期", description = "参数:无,权限:自动调用,方法名:initCurrentBookingDate") - public void initCurrentBookingDate() { - // 初始化预约日期 - List bookingDateList = new ArrayList<>(); - BookingDate bookingDateRent = bookingDateService.initBookingDate(BookConstant.RENT_CLOTHES, 3); - BookingDate bookingDateOwn = bookingDateService.initBookingDate(BookConstant.OWN_CLOTHES, 3); - bookingDateList.add(bookingDateRent); - bookingDateList.add(bookingDateOwn); + @AuthCheck(mustRole = UserConstant.ADMIN_ROLE) + public BaseResponse addBookingDate(@RequestBody List bookingDateAddRequestList) { + if (bookingDateAddRequestList == null) { + throw new BusinessException(ErrorCode.PARAMS_ERROR); + } + // 添加写真预约日期 + List bookingDateList = bookingDateAddRequestList.stream().map(bookingDateAddRequest -> { + BookingDate bookingDate = new BookingDate(); + BeanUtils.copyProperties(bookingDateAddRequest, bookingDate); + bookingDateService.validBookingDate(bookingDate, false); + return bookingDate; + }).toList(); boolean result = bookingDateService.saveBatch(bookingDateList); ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR); + + // 添加写真预约时间段 + List timeIntervals = new ArrayList<>(); + for (int i = 0; i < bookingDateAddRequestList.size(); i++) { + BookingDate bookingDate = bookingDateList.get(i); + Long dateId = bookingDate.getId(); + BookingDateAddRequest bookingDateAddRequest = bookingDateAddRequestList.get(i); + List timeIntervalAddRequestList = bookingDateAddRequest.getTimeIntervalAddRequestList(); + List timeIntervalList = timeIntervalAddRequestList.stream().map(timeIntervalAddRequest -> { + TimeInterval timeInterval = new TimeInterval(); + BeanUtils.copyProperties(timeIntervalAddRequest, timeInterval); + timeInterval.setBookingDateId(dateId); + timeIntervalService.validTimeInterval(timeInterval, false); + return timeInterval; + }).toList(); + timeIntervals.addAll(timeIntervalList); + } + boolean success = timeIntervalService.saveBatch(timeIntervals); + ThrowUtils.throwIf(!success, ErrorCode.OPERATION_ERROR); + return ResultUtils.success(true); } - - /** - * 根据预约类别查询未来四天(包括今天)的预约日期 + * Web端管理员根据预约类型查询预约时间表 * @param commonStringRequest 预约类型 - * @return 当前预约类型未来四天的预约日期列表 + * @return 预约时间表 */ - @PostMapping("/list") - @Operation(summary = "(小程序端)根据预约类别查询未来四天(包括今天)的预约日期", description = "参数:预约类型, 权限:所有人,方法名:listBookingDateByType") + @PostMapping("/list/type") + @Operation(summary = "Web端管理员根据预约类型查询预约时间表", description = "参数:预约类型,权限:管理员(admin, boss),方法名:listBookingDateByType") + @Transactional(rollbackFor = Exception.class) + @AuthCheck(mustRole = UserConstant.ADMIN_ROLE) public BaseResponse> listBookingDateByType(@RequestBody CommonStringRequest commonStringRequest) { if (commonStringRequest == null || StringUtils.isBlank(commonStringRequest.getType())) { throw new BusinessException(ErrorCode.PARAMS_ERROR); } String type = commonStringRequest.getType(); + if (!type.equals(BookConstant.RENT_CLOTHES) && !type.equals(BookConstant.OWN_CLOTHES)) { + throw new BusinessException(ErrorCode.PARAMS_ERROR, "类型参数错误"); + } QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("type", type); List bookingDateList = bookingDateService.list(queryWrapper); - // 封装预约日期VO - List bookingDateVOS = bookingDateList.stream().map(bookingDate -> { + List timeIntervalList = timeIntervalService.list(); + // 存储写真预约时间段的map集合(键:预约日期id, 值:预约时间段列表) + Map> timeMap = new HashMap<>(); + // 处理预约时间段,将预约时间段存入map集合 + for (TimeInterval timeInterval : timeIntervalList) { + TimeIntervalVO timeIntervalVO = new TimeIntervalVO(); + BeanUtils.copyProperties(timeInterval, timeIntervalVO); + Long bookingDateId = timeInterval.getBookingDateId(); + List timeIntervalVOS = timeMap.get(bookingDateId); + if (timeIntervalVOS == null) { + timeIntervalVOS = new ArrayList<>(); + } + timeIntervalVOS.add(timeIntervalVO); + timeMap.put(bookingDateId, timeIntervalVOS); + } + // 处理预约日期,填充当前预约日期对应的预约时间段 + List bookingDateVOList = new ArrayList<>(); + for (BookingDate bookingDate : bookingDateList) { BookingDateVO bookingDateVO = new BookingDateVO(); BeanUtils.copyProperties(bookingDate, bookingDateVO); - return bookingDateVO; - }).toList(); - return ResultUtils.success(bookingDateVOS); - } - - - - /** - * 更新当天的预约情况 - * @param bookingDateUpdateRequest 预约日期更新请求体 - * @return 是否更新成功 - */ - @PostMapping("/update") - @AuthCheck(mustRole = UserConstant.ADMIN_ROLE) - @Operation(summary = "Web端管理员更新当天的预约情况", description = "参数:预约日期更新请求体, 权限:管理员(admin, boss),方法名:updateBookingDate") - public BaseResponse updateBookingDate(@RequestBody BookingDateUpdateRequest bookingDateUpdateRequest) { - if (bookingDateUpdateRequest == null || bookingDateUpdateRequest.getId() <= 0) { - throw new BusinessException(ErrorCode.PARAMS_ERROR); + Long dateId = bookingDate.getId(); + List timeIntervalVOS = timeMap.get(dateId); + bookingDateVO.setTimeIntervalVOList(timeIntervalVOS); + bookingDateVOList.add(bookingDateVO); } - BookingDate bookingDate = new BookingDate(); - BeanUtils.copyProperties(bookingDateUpdateRequest, bookingDate); - boolean result = bookingDateService.updateById(bookingDate); - ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR); - return ResultUtils.success(true); + + // 将预约日期从小到大排序 + bookingDateVOList.sort((book1, book2) -> { + DateTime date1 = DateUtil.parse(book1.getSpecificDate(), "yyyy-MM-dd"); + DateTime date2 = DateUtil.parse(book2.getSpecificDate(), "yyyy-MM-dd"); + return date1.compareTo(date2); + }); + + return ResultUtils.success(bookingDateVOList); } +// @PostMapping("/update") +// @Operation(summary = "Web端管理员根据预约类型更新预约时间表", description = "参数:预约类型,权限:管理员(admin, boss),方法名:updateBookingDate") +// @Transactional(rollbackFor = Exception.class) +// @AuthCheck(mustRole = UserConstant.ADMIN_ROLE) +// public BaseResponse updateBookingDate(@RequestBody CommonStringRequest commonStringRequest) { +// if (commonStringRequest == null || StringUtils.isBlank(commonStringRequest.getType())) { +// throw new BusinessException(ErrorCode.PARAMS_ERROR); +// } +// String type = commonStringRequest.getType(); +// if (!type.equals(BookConstant.RENT_CLOTHES) && !type.equals(BookConstant.OWN_CLOTHES)) { +// throw new BusinessException(ErrorCode.PARAMS_ERROR, "类型参数错误"); +// } +// QueryWrapper queryWrapper = new QueryWrapper<>(); +// queryWrapper.eq("type", type); +// return null; +// } + } diff --git a/src/main/java/com/cultural/heritage/controller/good/AppointmentDateController.java b/src/main/java/com/cultural/heritage/controller/good/AppointmentDateController.java new file mode 100644 index 0000000..54eb20f --- /dev/null +++ b/src/main/java/com/cultural/heritage/controller/good/AppointmentDateController.java @@ -0,0 +1,210 @@ +package com.cultural.heritage.controller.good; + + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import com.cultural.heritage.annotation.AuthCheck; +import com.cultural.heritage.common.BaseResponse; +import com.cultural.heritage.common.ErrorCode; +import com.cultural.heritage.common.ResultUtils; +import com.cultural.heritage.constant.UserConstant; +import com.cultural.heritage.exception.BusinessException; +import com.cultural.heritage.exception.ThrowUtils; +import com.cultural.heritage.model.dto.CommonRequest; +import com.cultural.heritage.model.dto.appointment.single.AppointmentDateSingleAddRequest; +import com.cultural.heritage.model.dto.timeperiod.TimePeriodAddRequest; +import com.cultural.heritage.model.dto.timeperiod.single.TimePeriodSingleAddRequest; +import com.cultural.heritage.model.dto.timeperiod.single.TimePeriodSingleUpdateRequest; +import com.cultural.heritage.model.entity.AppointmentDate; +import com.cultural.heritage.model.entity.TimePeriod; +import com.cultural.heritage.service.good.AppointmentDateService; +import com.cultural.heritage.service.good.TimePeriodService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeanUtils; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@RestController +@RequestMapping("/appointmentDate") +@Slf4j +@Tag(name = "服务类商品预约日期模块") +public class AppointmentDateController { + + + @Resource + private AppointmentDateService appointmentDateService; + + + + @Resource + private TimePeriodService timePeriodService; + + + /** + * Web端管理员根据id删除预约日期 + * @param commonRequest 预约日期id + * @return 是否删除成功 + */ + @PostMapping("/del/id") + @Operation(summary = "Web端管理员根据id删除预约日期", description = "参数:预约日期id,权限:管理员(admin, boss),方法名:delAppointmentDateById") + @Transactional(rollbackFor = Exception.class) + @AuthCheck(mustRole = UserConstant.ADMIN_ROLE) + public BaseResponse delAppointmentDateById(@RequestBody CommonRequest commonRequest) { + if (commonRequest == null || commonRequest.getId() <= 0) { + throw new BusinessException(ErrorCode.PARAMS_ERROR); + } + Long id = commonRequest.getId(); + // 删除这个预约日期关联的所有时间段 + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("appointmentDateId", id); + boolean remove = timePeriodService.remove(queryWrapper); + ThrowUtils.throwIf(!remove, ErrorCode.OPERATION_ERROR, "预约时间段删除失败"); + + // 删除这个预约日期 + boolean success = appointmentDateService.removeById(id); + ThrowUtils.throwIf(!success, ErrorCode.OPERATION_ERROR, "预约日期删除失败"); + return ResultUtils.success(true); + } + + + + + /** + * Web端管理员根据id删除预约时间段 + * @param commonRequest 预约时间段id + * @return 是否删除成功 + */ + @PostMapping("/del/time/id") + @Operation(summary = "Web端管理员根据id删除预约时间段", description = "参数:预约日期段id,权限:管理员(admin, boss),方法名:delTimePeriodById") + @AuthCheck(mustRole = UserConstant.ADMIN_ROLE) + public BaseResponse delTimePeriodById(@RequestBody CommonRequest commonRequest) { + if (commonRequest == null || commonRequest.getId() <= 0) { + throw new BusinessException(ErrorCode.PARAMS_ERROR); + } + Long id = commonRequest.getId(); + boolean remove = timePeriodService.removeById(id); + ThrowUtils.throwIf(!remove, ErrorCode.OPERATION_ERROR, "预约时间段删除失败"); + return ResultUtils.success(true); + } + + + + /** + * Web端管理员根据id修改预约日期的状态 + * @param commonRequest 预约日期id + * @return 是否更新成功 + */ + @PostMapping("/update/status") + @Operation(summary = "Web端管理员根据id修改预约日期的状态", description = "参数:预约日期id,权限:管理员(admin, boss),方法名:updateTimePeriodStatusById") + @AuthCheck(mustRole = UserConstant.ADMIN_ROLE) + public BaseResponse updateTimePeriodStatusById(@RequestBody CommonRequest commonRequest) { + if (commonRequest == null || commonRequest.getId() <= 0) { + throw new BusinessException(ErrorCode.PARAMS_ERROR); + } + Long id = commonRequest.getId(); + AppointmentDate appointmentDate = appointmentDateService.getById(id); + ThrowUtils.throwIf(appointmentDate == null, ErrorCode.OPERATION_ERROR, "预约日期不存在"); + Integer status = appointmentDate.getIsAvailable() == 0 ? 1 : 0; + UpdateWrapper updateWrapper = new UpdateWrapper<>(); + updateWrapper.eq("id", id); + updateWrapper.set("isAvailable", status); + boolean update = appointmentDateService.update(updateWrapper); + ThrowUtils.throwIf(!update, ErrorCode.OPERATION_ERROR, "预约日期状态修改失败"); + return ResultUtils.success(true); + } + + + + + /** + * Web端管理员根据id修改预约时间段的人数 + * @param timePeriodSingleUpdateRequest 预约日期id + * @return 是否更新成功 + */ + @PostMapping("/update/time") + @Operation(summary = "Web端管理员根据id修改预约时间段的人数", description = "参数:预约日期id,权限:管理员(admin, boss),方法名:updateTimePeriodPersonNumberById") + @AuthCheck(mustRole = UserConstant.ADMIN_ROLE) + public BaseResponse updateTimePeriodPersonNumberById(@RequestBody TimePeriodSingleUpdateRequest timePeriodSingleUpdateRequest) { + if (timePeriodSingleUpdateRequest == null || timePeriodSingleUpdateRequest.getId() <= 0) { + throw new BusinessException(ErrorCode.PARAMS_ERROR); + } + // 根据id获取当前的预约日期 + Long id = timePeriodSingleUpdateRequest.getId(); + TimePeriod time = timePeriodService.getById(id); + // 封装更新后的预约时间段 + TimePeriod timePeriod = new TimePeriod(); + BeanUtils.copyProperties(timePeriodSingleUpdateRequest, timePeriod); + timePeriod.setId(time.getId()); + timePeriod.setTimeSlot(time.getTimeSlot()); + + boolean update = timePeriodService.updateById(timePeriod); + ThrowUtils.throwIf(!update, ErrorCode.OPERATION_ERROR, "预约时间段人数修改失败"); + return ResultUtils.success(true); + } + + + /** + * Web端管理员添加预约时间段 + * @param timePeriodSingleAddRequest 预约时间段添加请求体 + * @return 是否添加成功 + */ + @PostMapping("/add/time") + @Operation(summary = "Web端管理员添加预约时间段", description = "参数:预约时间段添加请求体,权限:管理员(admin, boss),方法名:addAppointmentDate") + @Transactional(rollbackFor = Exception.class) + @AuthCheck(mustRole = UserConstant.ADMIN_ROLE) + public BaseResponse addTimePeriod(@RequestBody TimePeriodSingleAddRequest timePeriodSingleAddRequest) { + if (timePeriodSingleAddRequest == null) { + throw new BusinessException(ErrorCode.PARAMS_ERROR); + } + TimePeriod timePeriod = new TimePeriod(); + BeanUtils.copyProperties(timePeriodSingleAddRequest, timePeriod); + boolean save = timePeriodService.save(timePeriod); + ThrowUtils.throwIf(!save, ErrorCode.OPERATION_ERROR, "预约时间段添加失败"); + return ResultUtils.success(true); + } + + + + /** + * Web端管理员添加预约日期 + * @param appointmentDateSingleAddRequest 预约日期添加请求体 + * @return 是否添加成功 + */ + @PostMapping("/add") + @Operation(summary = "Web端管理员添加预约日期", description = "参数:预约日期添加请求体,权限:管理员(admin, boss),方法名:addAppointmentDate") + @Transactional(rollbackFor = Exception.class) + @AuthCheck(mustRole = UserConstant.ADMIN_ROLE) + public BaseResponse addAppointmentDate(@RequestBody AppointmentDateSingleAddRequest appointmentDateSingleAddRequest) { + if (appointmentDateSingleAddRequest == null) { + throw new BusinessException(ErrorCode.PARAMS_ERROR); + } + // 添加当前商品的预约日期 + AppointmentDate appointmentDate = new AppointmentDate(); + BeanUtils.copyProperties(appointmentDateSingleAddRequest, appointmentDate); + boolean save = appointmentDateService.save(appointmentDate); + ThrowUtils.throwIf(!save, ErrorCode.OPERATION_ERROR, "预约日期添加失败"); + + // 添加当前预约日期的预约时间段 + Long appointmentDateId = appointmentDate.getId(); + List timePeriodAddRequestList = appointmentDateSingleAddRequest.getTimePeriodAddRequestList(); + List timePeriodList = timePeriodAddRequestList.stream().map(timePeriodAddRequest -> { + TimePeriod timePeriod = new TimePeriod(); + BeanUtils.copyProperties(timePeriodAddRequest, timePeriod); + timePeriod.setAppointmentDateId(appointmentDateId); + return timePeriod; + }).toList(); + boolean result = timePeriodService.saveBatch(timePeriodList); + ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR, "批量添加预约时间段失败"); + + return ResultUtils.success(true); + } + +} diff --git a/src/main/java/com/cultural/heritage/controller/good/GoodController.java b/src/main/java/com/cultural/heritage/controller/good/GoodController.java index 1cbece6..a6aaaea 100644 --- a/src/main/java/com/cultural/heritage/controller/good/GoodController.java +++ b/src/main/java/com/cultural/heritage/controller/good/GoodController.java @@ -1,6 +1,8 @@ package com.cultural.heritage.controller.good; +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; @@ -14,7 +16,6 @@ import com.cultural.heritage.exception.ThrowUtils; import com.cultural.heritage.model.dto.CommonDelBatchRequest; import com.cultural.heritage.model.dto.CommonRequest; import com.cultural.heritage.model.dto.appointment.AppointmentDateAddRequest; -import com.cultural.heritage.model.dto.appointment.AppointmentDateUpdateRequest; import com.cultural.heritage.model.dto.good.GoodAddRequest; import com.cultural.heritage.model.dto.good.GoodQueryRequest; import com.cultural.heritage.model.dto.good.GoodUpdateRequest; @@ -291,7 +292,7 @@ public class GoodController { public BaseResponse> listGoodByPage(@RequestBody GoodQueryRequest goodQueryRequest) { long current = goodQueryRequest.getCurrent(); long pageSize = goodQueryRequest.getPageSize(); - QueryWrapper goodQueryWrapper = goodService.getGoodQueryWrapper(goodQueryRequest, true); + QueryWrapper goodQueryWrapper = goodService.getGoodQueryWrapper(goodQueryRequest, false); Page page = goodService.page(new Page<>(current, pageSize), goodQueryWrapper); List records = page.getRecords(); List goodPageVOS = records.stream().map(good -> { @@ -409,6 +410,13 @@ public class GoodController { appointmentDateVOList.add(appointmentDateVO); } + // 将预约日期从小到大排序 + appointmentDateVOList.sort((app1, app2) -> { + DateTime date1 = DateUtil.parse(app1.getSpecificDate(), "yyyy-MM-dd"); + DateTime date2 = DateUtil.parse(app2.getSpecificDate(), "yyyy-MM-dd"); + return date1.compareTo(date2); + }); + List serviceGoodVOList = new ArrayList<>(); for (Good good : records) { ServiceGoodVO serviceGoodVO = new ServiceGoodVO(); @@ -481,6 +489,14 @@ public class GoodController { appointmentDateVO.setTimePeriodVOList(timePeriodVOList); appointmentDateVOList.add(appointmentDateVO); } + + // 将预约日期从小到大排序 + appointmentDateVOList.sort((app1, app2) -> { + DateTime date1 = DateUtil.parse(app1.getSpecificDate(), "yyyy-MM-dd"); + DateTime date2 = DateUtil.parse(app2.getSpecificDate(), "yyyy-MM-dd"); + return date1.compareTo(date2); + }); + serviceGoodVO.setAppointmentDateVOList(appointmentDateVOList); return ResultUtils.success(serviceGoodVO); } @@ -517,6 +533,7 @@ public class GoodController { */ @PostMapping("/service/update") @Operation(summary = "Web端管理员更新服务类商品", description = "参数:服务类商品更新请求体,权限:管理员(admin, boss),方法名:updateServiceGoodById") + @Transactional(rollbackFor = Exception.class) @AuthCheck(mustRole = UserConstant.ADMIN_ROLE) public BaseResponse updateServiceGoodById(@RequestBody ServiceGoodUpdateRequest serviceGoodUpdateRequest) { if (serviceGoodUpdateRequest == null || serviceGoodUpdateRequest.getId() <= 0) { @@ -534,17 +551,74 @@ public class GoodController { boolean result = goodService.updateById(good); ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR, "商品不存在"); - List appointmentDateUpdateRequestList = serviceGoodUpdateRequest.getAppointmentDateUpdateRequestList(); - List appointmentDateList = appointmentDateUpdateRequestList.stream().map(appointmentDateUpdateRequest -> { + // 删除当前商品关联的所有日期和时间段 + CommonRequest commonRequest = new CommonRequest(); + commonRequest.setId(good.getId()); + deleteServiceGoodAppointment(commonRequest); + // 为当前商品重新添加预约日期和时间段 + ServiceGoodAddRequest serviceGoodAddRequest = new ServiceGoodAddRequest(); + BeanUtils.copyProperties(serviceGoodUpdateRequest, serviceGoodAddRequest); + dealServiceGoodAppointmentDate(serviceGoodAddRequest, good); + return ResultUtils.success(true); + } + + + + private void deleteServiceGoodAppointment(CommonRequest commonRequest) { + if (commonRequest == null || commonRequest.getId() <= 0) { + throw new BusinessException(ErrorCode.PARAMS_ERROR); + } + Long id = commonRequest.getId(); + + //删除预约时间段表中与该商品关联的记录 + QueryWrapper dateQueryWrapper = new QueryWrapper<>(); + dateQueryWrapper.eq("goodId", id); + List appointmentDateList = appointmentDateService.list(dateQueryWrapper); + List ids = appointmentDateList.stream().map(AppointmentDate::getId).toList(); + QueryWrapper timePeriodQueryWrapper = new QueryWrapper<>(); + timePeriodQueryWrapper.in("appointmentDateId", ids); + boolean remove = timePeriodService.remove(timePeriodQueryWrapper); + ThrowUtils.throwIf(!remove, ErrorCode.OPERATION_ERROR, "服务类商品预约时间段删除失败"); + + // 删除预约日期表中与该商品关联的记录 + boolean isSuccess = appointmentDateService.remove(dateQueryWrapper); + ThrowUtils.throwIf(!isSuccess, ErrorCode.OPERATION_ERROR, "服务类商品预约日期删除失败"); + } + + + private void dealServiceGoodAppointmentDate(ServiceGoodAddRequest serviceGoodAddRequest, Good good) { + // 添加当前商品的预约日期 + List appointmentDateAddRequestList = serviceGoodAddRequest.getAppointmentDateAddRequestList(); + List appointmentDateList = appointmentDateAddRequestList.stream().map(appointmentDateAddRequest -> { AppointmentDate appointmentDate = new AppointmentDate(); - BeanUtils.copyProperties(appointmentDateUpdateRequest, appointmentDate); + BeanUtils.copyProperties(appointmentDateAddRequest, appointmentDate); appointmentDate.setGoodId(good.getId()); + // 校验 + appointmentDateService.validAppointmentDate(appointmentDate, false); return appointmentDate; }).toList(); + boolean isSaveBatch = appointmentDateService.saveBatch(appointmentDateList); + ThrowUtils.throwIf(!isSaveBatch, ErrorCode.OPERATION_ERROR); - - - return ResultUtils.success(true); + // 添加当前商品的预约时间段 + List timePeriods = new ArrayList<>(); + for (int i = 0; i < appointmentDateAddRequestList.size(); i++) { + AppointmentDate appointmentDate = appointmentDateList.get(i); + AppointmentDateAddRequest appointmentDateAddRequest = appointmentDateAddRequestList.get(i); + Long appointmentDateId = appointmentDate.getId(); + List timePeriodAddRequestList = appointmentDateAddRequest.getTimePeriodAddRequestList(); + List timePeriodList = timePeriodAddRequestList.stream().map(timePeriodAddRequest -> { + TimePeriod timePeriod = new TimePeriod(); + BeanUtils.copyProperties(timePeriodAddRequest, timePeriod); + timePeriod.setAppointmentDateId(appointmentDateId); + // 校验 + timePeriodService.validTimePeriod(timePeriod, false); + return timePeriod; + }).toList(); + timePeriods.addAll(timePeriodList); + } + boolean result = timePeriodService.saveBatch(timePeriods); + ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR); } diff --git a/src/main/java/com/cultural/heritage/controller/wx/WeChatPayController.java b/src/main/java/com/cultural/heritage/controller/wx/WeChatPayController.java new file mode 100644 index 0000000..f80ff1d --- /dev/null +++ b/src/main/java/com/cultural/heritage/controller/wx/WeChatPayController.java @@ -0,0 +1,120 @@ +package com.cultural.heritage.controller.wx; + + +import com.cultural.heritage.annotation.AuthCheck; +import com.cultural.heritage.common.BaseResponse; +import com.cultural.heritage.common.ErrorCode; +import com.cultural.heritage.common.ResultUtils; +import com.cultural.heritage.constant.UserConstant; +import com.cultural.heritage.exception.BusinessException; +import com.cultural.heritage.exception.ThrowUtils; +import com.cultural.heritage.model.dto.CommonRequest; +import com.cultural.heritage.model.entity.Order; +import com.cultural.heritage.model.entity.User; +import com.cultural.heritage.service.order.OrderService; +import com.cultural.heritage.service.user.UserService; +import com.cultural.heritage.service.wxpay.WeChatService; +import com.wechat.pay.java.service.payments.jsapi.model.PrepayWithRequestPaymentResponse; +import com.wechat.pay.java.service.payments.model.Transaction; +import com.wechat.pay.java.service.refund.model.Refund; +import com.wechat.pay.java.service.refund.model.RefundNotification; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; + +/** + * 微信小程序相关接口 + **/ +@Slf4j +@RestController +@Tag(name = "微信支付接口") +@RequestMapping("/wechat") +public class WeChatPayController { + + @Resource + private UserService userService; + + @Resource + private OrderService ordersService; + + @Resource + private WeChatService weChatService; + + + /** + * JSAPI 下单 + */ + @PostMapping("/payment/create") + public BaseResponse createPayment(@RequestBody CommonRequest commonRequest, HttpServletRequest request) { + User loginUser = userService.getLoginUser(request); + String miniOpenId = loginUser.getMiniOpenId(); + ThrowUtils.throwIf(miniOpenId == null, ErrorCode.NOT_FOUND_ERROR, "不是小程序用户"); + Long orderId = commonRequest.getId(); + Order order = ordersService.getById(orderId); + ThrowUtils.throwIf(order == null, ErrorCode.NOT_FOUND_ERROR, "订单不存在"); +// ThrowUtils.throwIf(order.getState() != 0, ErrorCode.OPERATION_ERROR, "订单状态错误"); + if (!loginUser.getId().equals(order.getUserId())) { + throw new BusinessException(ErrorCode.NO_AUTH_ERROR, "你不是该订单用户!"); + } + PrepayWithRequestPaymentResponse response = weChatService.createPayment(String.valueOf(orderId), miniOpenId, order.getTotalAmount()); + return ResultUtils.success(response); + } + + /** + * JSAPI 下单回调 + */ + @PostMapping("/payment/callback") + @Transactional(rollbackFor = Exception.class) + public synchronized BaseResponse callbackPayment(HttpServletRequest request) throws IOException { + // 获取下单信息 + Transaction transaction = weChatService.getTransactionInfo(request); + System.out.println("下单信息:" + transaction); + // 支付回调 + boolean result = weChatService.paymentCallback(transaction); + ThrowUtils.throwIf(!result, ErrorCode.SYSTEM_ERROR, "微信支付回调失败"); + return ResultUtils.success(true); + } + + /** + * 退款(仅管理员和商家) + */ + @PostMapping("/refund/create") + @AuthCheck(mustRole = UserConstant.ADMIN_ROLE) + public BaseResponse createRefund(@RequestBody CommonRequest commonRequest) { + Long orderId = commonRequest.getId(); + Order order = ordersService.getById(orderId); + ThrowUtils.throwIf(order == null, ErrorCode.NOT_FOUND_ERROR, "订单不存在"); + Refund refund = weChatService.refundPayment(String.valueOf(orderId), order.getTotalAmount()); + return ResultUtils.success(refund); + } + + /** + * 退款回调 + */ + @PostMapping("/refund/callback") + public BaseResponse callbackRefund(HttpServletRequest request) { + // 获取退款信息 + RefundNotification refundNotification = weChatService.getRefundInfo(request); + // 退款回调 + boolean result = weChatService.refundCallback(refundNotification); + ThrowUtils.throwIf(!result, ErrorCode.SYSTEM_ERROR, "退款回调失败"); + return ResultUtils.success(true); + } + + /** + * 发送订阅消息 + */ + @GetMapping("/refund/callback") + public BaseResponse testSendMessage() { + String miniOpenId = "o0o_B5CMLFiOs96dJZwtkyHcJzcM"; + String templateId = "MK13FfX0XxsPV6m1vi6J8_8Bf7JT8rsayFs9q3f4FW4"; + boolean subscribeMessage = weChatService.sendSubscribeMessage(miniOpenId, templateId); + return ResultUtils.success(subscribeMessage); + } + +} diff --git a/src/main/java/com/cultural/heritage/mapper/TimeIntervalMapper.java b/src/main/java/com/cultural/heritage/mapper/TimeIntervalMapper.java new file mode 100644 index 0000000..62d589e --- /dev/null +++ b/src/main/java/com/cultural/heritage/mapper/TimeIntervalMapper.java @@ -0,0 +1,7 @@ +package com.cultural.heritage.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.cultural.heritage.model.entity.TimeInterval; + +public interface TimeIntervalMapper extends BaseMapper { +} diff --git a/src/main/java/com/cultural/heritage/model/dto/appointment/single/AppointmentDateSingleAddRequest.java b/src/main/java/com/cultural/heritage/model/dto/appointment/single/AppointmentDateSingleAddRequest.java new file mode 100644 index 0000000..df4b780 --- /dev/null +++ b/src/main/java/com/cultural/heritage/model/dto/appointment/single/AppointmentDateSingleAddRequest.java @@ -0,0 +1,44 @@ +package com.cultural.heritage.model.dto.appointment.single; + +import com.cultural.heritage.model.dto.timeperiod.TimePeriodAddRequest; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + + +@Data +@Schema(description = "预约日期请求体", requiredProperties = { + "specificDate", "isAvailable", "timePeriodAddRequestList" +}) +public class AppointmentDateSingleAddRequest implements Serializable { + + /** + * 商品id + */ + @Schema(description = "商品id", example = "2") + private Long goodId; + + /** + * 具体预约时间 + */ + @Schema(description = "具体预约时间", example = "2024-12-04") + private String specificDate; + + /** + * 是否可预约 + */ + @Schema(description = "是否可预约", example = "1") + private Integer isAvailable; + + /** + * 预约时间段列表 + */ + private List timePeriodAddRequestList; + + + @Serial + private static final long serialVersionUID = 1L; +} diff --git a/src/main/java/com/cultural/heritage/model/dto/book/BookingDateAddRequest.java b/src/main/java/com/cultural/heritage/model/dto/book/BookingDateAddRequest.java index 495f8b8..9dc576e 100644 --- a/src/main/java/com/cultural/heritage/model/dto/book/BookingDateAddRequest.java +++ b/src/main/java/com/cultural/heritage/model/dto/book/BookingDateAddRequest.java @@ -1,13 +1,15 @@ package com.cultural.heritage.model.dto.book; +import com.cultural.heritage.model.dto.timeinterval.TimeIntervalAddRequest; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.io.Serial; import java.io.Serializable; +import java.util.List; @Data -@Schema(description = "预约日期添加请求体", requiredProperties = {"specificDate", "timeSlot", "isAvailable", "maxNumber", "type"}) +@Schema(description = "预约日期添加请求体", requiredProperties = {"specificDate", "isAvailable", "type"}) public class BookingDateAddRequest implements Serializable { /** @@ -17,13 +19,6 @@ public class BookingDateAddRequest implements Serializable { private String specificDate; - /** - * 时间段 - */ - @Schema(description = "时间段", example = "8:00-10:00;12:00-14:00") - private String timeSlot; - - /** * 是否可预约 */ @@ -31,13 +26,6 @@ public class BookingDateAddRequest implements Serializable { private Integer isAvailable; - /** - * 各个时间段的最大预约人数(4,6..) - */ - @Schema(description = "各个时间段的最大预约人数(4,6..)", example = "4,5,6") - private String maxNumber; - - /** * 预约类别 */ @@ -45,6 +33,13 @@ public class BookingDateAddRequest implements Serializable { private String type; + /** + * 预约时间段列表 + */ + @Schema(description = "预约时间段列表") + private List timeIntervalAddRequestList; + + @Serial private static final long serialVersionUID = 1L; } diff --git a/src/main/java/com/cultural/heritage/model/dto/book/BookingDateUpdateRequest.java b/src/main/java/com/cultural/heritage/model/dto/book/BookingDateUpdateRequest.java index c0c16a3..0e89bdd 100644 --- a/src/main/java/com/cultural/heritage/model/dto/book/BookingDateUpdateRequest.java +++ b/src/main/java/com/cultural/heritage/model/dto/book/BookingDateUpdateRequest.java @@ -7,7 +7,7 @@ import java.io.Serial; import java.io.Serializable; @Data -@Schema(description = "预约日期更新请求体", requiredProperties = {"id", "specificDate", "timeSlot", "isAvailable", "maxNumber","type"}) +@Schema(description = "预约日期更新请求体", requiredProperties = {"id", "specificDate", "isAvailable","type"}) public class BookingDateUpdateRequest implements Serializable { @@ -25,13 +25,6 @@ public class BookingDateUpdateRequest implements Serializable { private String specificDate; - /** - * 时间段 - */ - @Schema(description = "时间段", example = "8:00-10:00;12:00-14:00") - private String timeSlot; - - /** * 是否可预约 */ @@ -39,13 +32,6 @@ public class BookingDateUpdateRequest implements Serializable { private Integer isAvailable; - /** - * 各个时间段的最大预约人数(4,6..) - */ - @Schema(description = "各个时间段的最大预约人数(4,6..)", example = "4,5,6") - private String maxNumber; - - /** * 预约类别 */ diff --git a/src/main/java/com/cultural/heritage/model/dto/good/service/ServiceGoodUpdateRequest.java b/src/main/java/com/cultural/heritage/model/dto/good/service/ServiceGoodUpdateRequest.java index 5e8dbc3..5515712 100644 --- a/src/main/java/com/cultural/heritage/model/dto/good/service/ServiceGoodUpdateRequest.java +++ b/src/main/java/com/cultural/heritage/model/dto/good/service/ServiceGoodUpdateRequest.java @@ -1,6 +1,6 @@ package com.cultural.heritage.model.dto.good.service; -import com.cultural.heritage.model.dto.appointment.AppointmentDateUpdateRequest; +import com.cultural.heritage.model.dto.appointment.AppointmentDateAddRequest; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @@ -67,7 +67,7 @@ public class ServiceGoodUpdateRequest implements Serializable { * 未来几天的预约时间表 */ @Schema(description = "未来的预约时间表") - private List appointmentDateUpdateRequestList; + private List appointmentDateAddRequestList; @Serial diff --git a/src/main/java/com/cultural/heritage/model/dto/timeinterval/TimeIntervalAddRequest.java b/src/main/java/com/cultural/heritage/model/dto/timeinterval/TimeIntervalAddRequest.java new file mode 100644 index 0000000..5401322 --- /dev/null +++ b/src/main/java/com/cultural/heritage/model/dto/timeinterval/TimeIntervalAddRequest.java @@ -0,0 +1,40 @@ +package com.cultural.heritage.model.dto.timeinterval; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +@Data +@Schema(description = "写真预约时间段添加请求体", requiredProperties = { + "timeSlot", "minNumber", "maxNumber"}) +public class TimeIntervalAddRequest implements Serializable { + + + /** + * 时间段 + */ + @Schema(description = "时间段", example = "08:00-10:00") + private String timeSlot; + + + /** + * 最小预约人数 + */ + @Schema(description = "最小预约人数", example = "3") + private Integer minNumber; + + + /** + * 最大预约人数 + */ + @Schema(description = "最大预约人数", example = "10") + private Integer maxNumber; + + + + @Serial + private static final long serialVersionUID = 1L; + +} diff --git a/src/main/java/com/cultural/heritage/model/dto/timeperiod/TimePeriodUpdateRequest.java b/src/main/java/com/cultural/heritage/model/dto/timeperiod/TimePeriodUpdateRequest.java index be9acad..45c04a6 100644 --- a/src/main/java/com/cultural/heritage/model/dto/timeperiod/TimePeriodUpdateRequest.java +++ b/src/main/java/com/cultural/heritage/model/dto/timeperiod/TimePeriodUpdateRequest.java @@ -17,6 +17,7 @@ public class TimePeriodUpdateRequest implements Serializable { @Schema(description = "预约时间段id(id > 0)", example = "10") private Long id; + /** * 时间段 */ @@ -39,6 +40,13 @@ public class TimePeriodUpdateRequest implements Serializable { + /** + * 预约日期id + */ + @Schema(description = "预约日期id", example = "12") + private Long appointmentDateId; + + @Serial private static final long serialVersionUID = 1L; } diff --git a/src/main/java/com/cultural/heritage/model/dto/timeperiod/single/TimePeriodSingleAddRequest.java b/src/main/java/com/cultural/heritage/model/dto/timeperiod/single/TimePeriodSingleAddRequest.java new file mode 100644 index 0000000..777b33d --- /dev/null +++ b/src/main/java/com/cultural/heritage/model/dto/timeperiod/single/TimePeriodSingleAddRequest.java @@ -0,0 +1,46 @@ +package com.cultural.heritage.model.dto.timeperiod.single; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +@Data +@Schema(description = "预约时间段添加请求体", requiredProperties = { + "timeSlot", "minNumber", "maxNumber" +}) +public class TimePeriodSingleAddRequest implements Serializable { + + /** + * 时间段 + */ + @Schema(description = "时间段", example = "08:00-10:00") + private String timeSlot; + + + /** + * 最小预约人数 + */ + @Schema(description = "最小预约人数", example = "3") + private Integer minNumber; + + + /** + * 最大预约人数 + */ + @Schema(description = "最大预约人数", example = "10") + private Integer maxNumber; + + + /** + * 预约日期id + */ + @Schema(description = "预约日期id", example = "12") + private Long appointmentDateId; + + + + @Serial + private static final long serialVersionUID = 1L; +} diff --git a/src/main/java/com/cultural/heritage/model/dto/timeperiod/single/TimePeriodSingleUpdateRequest.java b/src/main/java/com/cultural/heritage/model/dto/timeperiod/single/TimePeriodSingleUpdateRequest.java new file mode 100644 index 0000000..93b9165 --- /dev/null +++ b/src/main/java/com/cultural/heritage/model/dto/timeperiod/single/TimePeriodSingleUpdateRequest.java @@ -0,0 +1,36 @@ +package com.cultural.heritage.model.dto.timeperiod.single; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +@Data +@Schema(description = "预约时间段更新请求体", requiredProperties = {"id", "minNumber", "maxNumber"}) +public class TimePeriodSingleUpdateRequest implements Serializable { + + + /** + * 预约时间段id + */ + @Schema(description = "预约时间段id(id > 0)", example = "10") + private Long id; + + /** + * 最小预约人数 + */ + @Schema(description = "最小预约人数", example = "3") + private Integer minNumber; + + + /** + * 最大预约人数 + */ + @Schema(description = "最大预约人数", example = "10") + private Integer maxNumber; + + + @Serial + private static final long serialVersionUID = 1L; +} diff --git a/src/main/java/com/cultural/heritage/model/entity/BookingDate.java b/src/main/java/com/cultural/heritage/model/entity/BookingDate.java index 65c9f08..fb338e8 100644 --- a/src/main/java/com/cultural/heritage/model/entity/BookingDate.java +++ b/src/main/java/com/cultural/heritage/model/entity/BookingDate.java @@ -31,24 +31,12 @@ public class BookingDate implements Serializable { private String specificDate; - /** - * 时间段 - */ - private String timeSlot; - - /** * 是否可预约 */ private Integer isAvailable; - /** - * 各个时间段的最大预约人数(4,6..) - */ - private String maxNumber; - - /** * 预约类别 */ diff --git a/src/main/java/com/cultural/heritage/model/entity/TimeInterval.java b/src/main/java/com/cultural/heritage/model/entity/TimeInterval.java new file mode 100644 index 0000000..63d0868 --- /dev/null +++ b/src/main/java/com/cultural/heritage/model/entity/TimeInterval.java @@ -0,0 +1,67 @@ +package com.cultural.heritage.model.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 写真预约时间段表 + * @TableName time_interval + */ +@Data +@TableName("time_interval") +public class TimeInterval implements Serializable { + + /** + * 预约时间段id + */ + @TableId(type = IdType.AUTO) + private Long id; + + /** + * 时间段 + */ + private String timeSlot; + + + /** + * 最小预约人数 + */ + private Integer minNumber; + + + /** + * 最大预约人数 + */ + private Integer maxNumber; + + + /** + * 预约日期id + */ + private Long bookingDateId; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 更新时间 + */ + private Date updateTime; + + /** + * 是否删除 + */ + private Integer isDelete; + + @Serial + private static final long serialVersionUID = 1L; +} diff --git a/src/main/java/com/cultural/heritage/model/vo/book/BookingDateVO.java b/src/main/java/com/cultural/heritage/model/vo/book/BookingDateVO.java index 9be66ed..bb1594c 100644 --- a/src/main/java/com/cultural/heritage/model/vo/book/BookingDateVO.java +++ b/src/main/java/com/cultural/heritage/model/vo/book/BookingDateVO.java @@ -1,9 +1,11 @@ package com.cultural.heritage.model.vo.book; +import com.cultural.heritage.model.vo.timeinterval.TimeIntervalVO; import lombok.Data; import java.io.Serial; import java.io.Serializable; +import java.util.List; @Data public class BookingDateVO implements Serializable { @@ -21,30 +23,23 @@ public class BookingDateVO implements Serializable { private String specificDate; - /** - * 时间段 - */ - private String timeSlot; - - /** * 是否可预约 */ private Integer isAvailable; - /** - * 各个时间段的最大预约人数(4,6..) - */ - private String maxNumber; - - /** * 预约类别 */ private String type; + /** + * 预约时间段 + */ + private List timeIntervalVOList; + @Serial diff --git a/src/main/java/com/cultural/heritage/model/vo/timeinterval/TimeIntervalVO.java b/src/main/java/com/cultural/heritage/model/vo/timeinterval/TimeIntervalVO.java new file mode 100644 index 0000000..8ea45f0 --- /dev/null +++ b/src/main/java/com/cultural/heritage/model/vo/timeinterval/TimeIntervalVO.java @@ -0,0 +1,36 @@ +package com.cultural.heritage.model.vo.timeinterval; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +@Data +public class TimeIntervalVO implements Serializable { + + /** + * 预约时间段id + */ + private Long id; + + /** + * 时间段 + */ + private String timeSlot; + + + /** + * 最小预约人数 + */ + private Integer minNumber; + + + /** + * 最大预约人数 + */ + private Integer maxNumber; + + + @Serial + private static final long serialVersionUID = 1L; +} diff --git a/src/main/java/com/cultural/heritage/service/book/BookingDateService.java b/src/main/java/com/cultural/heritage/service/book/BookingDateService.java index dc59c56..eaeb458 100644 --- a/src/main/java/com/cultural/heritage/service/book/BookingDateService.java +++ b/src/main/java/com/cultural/heritage/service/book/BookingDateService.java @@ -7,7 +7,7 @@ public interface BookingDateService extends IService { /** - * 初始化未来一天的预约日期 + * 校验 */ - BookingDate initBookingDate(String type, int offset); + void validBookingDate(BookingDate bookingDate, boolean update); } diff --git a/src/main/java/com/cultural/heritage/service/book/TimeIntervalService.java b/src/main/java/com/cultural/heritage/service/book/TimeIntervalService.java new file mode 100644 index 0000000..3b41f12 --- /dev/null +++ b/src/main/java/com/cultural/heritage/service/book/TimeIntervalService.java @@ -0,0 +1,13 @@ +package com.cultural.heritage.service.book; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.cultural.heritage.model.entity.TimeInterval; + +public interface TimeIntervalService extends IService { + + + /** + * 校验 + */ + void validTimeInterval(TimeInterval timeInterval, boolean update); +} diff --git a/src/main/java/com/cultural/heritage/service/book/impl/BookingDateServiceImpl.java b/src/main/java/com/cultural/heritage/service/book/impl/BookingDateServiceImpl.java index 541fa81..245b5ef 100644 --- a/src/main/java/com/cultural/heritage/service/book/impl/BookingDateServiceImpl.java +++ b/src/main/java/com/cultural/heritage/service/book/impl/BookingDateServiceImpl.java @@ -1,28 +1,37 @@ package com.cultural.heritage.service.book.impl; -import cn.hutool.core.date.DateUtil; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.cultural.heritage.common.ErrorCode; +import com.cultural.heritage.exception.BusinessException; import com.cultural.heritage.mapper.BookingDateMapper; import com.cultural.heritage.model.entity.BookingDate; import com.cultural.heritage.service.book.BookingDateService; +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; @Service public class BookingDateServiceImpl extends ServiceImpl implements BookingDateService { - /** - * 初始化未来一天的预约日期 - */ @Override - public BookingDate initBookingDate(String type, int offset) { - String currentDate = DateUtil.formatDate(DateUtil.offsetDay(DateUtil.date(), offset)); - BookingDate bookingDate = new BookingDate(); - bookingDate.setSpecificDate(currentDate); - bookingDate.setTimeSlot("00:00-00:00"); - bookingDate.setIsAvailable(0); - bookingDate.setMaxNumber("0"); - bookingDate.setType(type); - return bookingDate; + public void validBookingDate(BookingDate bookingDate, boolean update) { + Long dateId = bookingDate.getId(); + String specificDate = bookingDate.getSpecificDate(); + Integer isAvailable = bookingDate.getIsAvailable(); + String type = bookingDate.getType(); + + if (update) { + if (dateId == null) { + throw new BusinessException(ErrorCode.PARAMS_ERROR, "id参数错误"); + } + } + if (ObjectUtils.isEmpty(isAvailable) || isAvailable != 1 && isAvailable != 0) { + throw new BusinessException(ErrorCode.PARAMS_ERROR, "是否可预约参数错误"); + } + if (StringUtils.isAnyBlank(specificDate, type)) { + throw new BusinessException(ErrorCode.PARAMS_ERROR, "存在字符串类型参数为空"); + } + } } diff --git a/src/main/java/com/cultural/heritage/service/book/impl/TimeIntervalServiceImpl.java b/src/main/java/com/cultural/heritage/service/book/impl/TimeIntervalServiceImpl.java new file mode 100644 index 0000000..642bef6 --- /dev/null +++ b/src/main/java/com/cultural/heritage/service/book/impl/TimeIntervalServiceImpl.java @@ -0,0 +1,44 @@ +package com.cultural.heritage.service.book.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.cultural.heritage.common.ErrorCode; +import com.cultural.heritage.exception.BusinessException; +import com.cultural.heritage.mapper.TimeIntervalMapper; +import com.cultural.heritage.model.entity.TimeInterval; +import com.cultural.heritage.service.book.TimeIntervalService; +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +@Service +public class TimeIntervalServiceImpl extends ServiceImpl implements TimeIntervalService { + + /** + * 校验 + */ + @Override + public void validTimeInterval(TimeInterval timeInterval, boolean update) { + + Long id = timeInterval.getId(); + Integer minNumber = timeInterval.getMinNumber(); + Integer maxNumber = timeInterval.getMaxNumber(); + String timeSlot = timeInterval.getTimeSlot(); + Long bookingDateId = timeInterval.getBookingDateId(); + + if (update) { + if (id == null) { + throw new BusinessException(ErrorCode.PARAMS_ERROR, "预约日期id参数错误"); + } + } + if (ObjectUtils.anyNull(minNumber, maxNumber, bookingDateId)) { + throw new BusinessException(ErrorCode.PARAMS_ERROR, "存在参数为空"); + } + if (minNumber > maxNumber) { + throw new BusinessException(ErrorCode.PARAMS_ERROR, "最小预约人数不能超过最大预约人数"); + } + if (StringUtils.isBlank(timeSlot)) { + throw new BusinessException(ErrorCode.PARAMS_ERROR, "时间段参数为空"); + } + + } +} diff --git a/src/main/java/com/cultural/heritage/service/wxpay/WeChatService.java b/src/main/java/com/cultural/heritage/service/wxpay/WeChatService.java new file mode 100644 index 0000000..b163dad --- /dev/null +++ b/src/main/java/com/cultural/heritage/service/wxpay/WeChatService.java @@ -0,0 +1,53 @@ +package com.cultural.heritage.service.wxpay; + + +import com.wechat.pay.java.service.payments.jsapi.model.PrepayWithRequestPaymentResponse; +import com.wechat.pay.java.service.payments.model.Transaction; +import com.wechat.pay.java.service.refund.model.Refund; +import com.wechat.pay.java.service.refund.model.RefundNotification; +import jakarta.servlet.http.HttpServletRequest; + +import java.io.IOException; +import java.math.BigDecimal; + +/** + * @author 玄德 + */ +public interface WeChatService { + + /** + * 微信支付 + */ + PrepayWithRequestPaymentResponse createPayment(String orderId, String miniOpenId, BigDecimal amount); + + /** + * 获取支付回调信息 + */ + Transaction getTransactionInfo(HttpServletRequest request); + + /** + * 支付回调 + */ + boolean paymentCallback(Transaction transaction) throws IOException; + + /** + * 退款申请 + */ + Refund refundPayment(String orderId, BigDecimal amount); + + /** + * 获取退款回调信息 + */ + RefundNotification getRefundInfo(HttpServletRequest request); + + /** + * 退款回调 + */ + boolean refundCallback(RefundNotification refundNotification); + + /** + * 发送订阅模板消息 + */ + boolean sendSubscribeMessage(String openid, String templateId); + +} diff --git a/src/main/java/com/cultural/heritage/service/wxpay/impl/WeChatServiceImpl.java b/src/main/java/com/cultural/heritage/service/wxpay/impl/WeChatServiceImpl.java new file mode 100644 index 0000000..fe1bcbb --- /dev/null +++ b/src/main/java/com/cultural/heritage/service/wxpay/impl/WeChatServiceImpl.java @@ -0,0 +1,265 @@ +package com.cultural.heritage.service.wxpay.impl; + + +import cn.binarywang.wx.miniapp.api.WxMaMsgService; +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.bean.WxMaSubscribeMessage; +import cn.hutool.core.util.RandomUtil; +import com.cultural.heritage.common.ErrorCode; +import com.cultural.heritage.config.WxOpenConfig; +import com.cultural.heritage.config.WxPayConfig; +import com.cultural.heritage.exception.BusinessException; +import com.cultural.heritage.model.entity.Order; +import com.cultural.heritage.service.order.OrderService; +import com.cultural.heritage.service.wxpay.WeChatService; +import com.wechat.pay.java.core.notification.NotificationParser; +import com.wechat.pay.java.core.notification.RequestParam; +import com.wechat.pay.java.service.payments.jsapi.model.Amount; +import com.wechat.pay.java.service.payments.jsapi.model.Payer; +import com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest; +import com.wechat.pay.java.service.payments.jsapi.model.PrepayWithRequestPaymentResponse; +import com.wechat.pay.java.service.payments.model.Transaction; +import com.wechat.pay.java.service.refund.model.AmountReq; +import com.wechat.pay.java.service.refund.model.CreateRequest; +import com.wechat.pay.java.service.refund.model.Refund; +import com.wechat.pay.java.service.refund.model.RefundNotification; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.io.BufferedReader; +import java.io.IOException; +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.util.ArrayList; +import java.util.List; + +/** + * @author 玄德 + */ +@Slf4j +@Service +public class WeChatServiceImpl implements WeChatService { + + @Resource + private WxPayConfig wxPayConfig; + + @Resource + private WxOpenConfig wxOpenConfig; + + @Resource + private OrderService ordersService; + + /** + * 请求参数 + */ + public static RequestParam requestParam = null; + + @Override + @Transactional(rollbackFor = Exception.class) + public synchronized PrepayWithRequestPaymentResponse createPayment(String orderId, String miniOpenId, BigDecimal amount) { + // request.setXxx(val)设置所需参数,具体参数可见Request定义 + PrepayRequest request = new PrepayRequest(); + // 金额 + Amount WxAmount = new Amount(); + WxAmount.setTotal(amount.movePointRight(2).intValue()); + WxAmount.setCurrency("CNY"); + request.setAmount(WxAmount); + // 公众号id + request.setAppid(wxPayConfig.getAppId()); + // 商户号 + request.setMchid(wxPayConfig.getMerchantId()); + // 支付者信息 + Payer payer = new Payer(); + payer.setOpenid(miniOpenId); + request.setPayer(payer); + // 描述 + request.setDescription("订单号:" + orderId); + // 微信回调地址 + request.setNotifyUrl(wxPayConfig.getNotifyUrl() + "/api/wechat/payment/callback"); + // 商户订单号 + request.setOutTradeNo(RandomUtil.randomNumbers(12)); + //返回数据,前端调起支付 + return wxPayConfig.getJsapiServiceExtension().prepayWithRequestPayment(request); + } + + @Override + public Transaction getTransactionInfo(HttpServletRequest request) { + NotificationParser notificationParser = getNotificationParser(request); + return notificationParser.parse(requestParam, Transaction.class); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public synchronized boolean paymentCallback(Transaction transaction) throws IOException { + System.out.println("---------------------------微信支付回调(开始)-------------------------------"); + // 获取订单信息 + String orderIdByString = transaction.getOutTradeNo(); + Order order = ordersService.getById(orderIdByString); + if (order == null) { + log.error("订单不存在"); + throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "订单不存在,订单号:" + transaction.getOutTradeNo()); + } + // 生成取餐码 + // 获取当日的日期 + LocalDate today = LocalDate.now(); + // 获取当日的 00:00 时间 + LocalDateTime startTime = today.atStartOfDay(); + // 获取当日的 23:59 时间 + LocalDateTime endTime = today.atTime(LocalTime.MAX); +// // 生成取餐码 +// QueryWrapper queryWrapper = new QueryWrapper<>(); +// queryWrapper.eq("businessId", order.getBusinessId()); +// queryWrapper.between("createTime", startTime, endTime); +// queryWrapper.in("state", 1, 2); +// long count = ordersService.count(queryWrapper); +// String pickupCode = String.format("%04d", count + 1); +// // 修改订单信息 +// order.setState(1); +// order.setPickupCode(pickupCode); +// Date date = new Date(); +// order.setUpdateTime(date); +// boolean update = ordersService.updateById(order); +// ThrowUtils.throwIf(!update, ErrorCode.OPERATION_ERROR, "修改订单状态失败"); +// // 通知商家新订单 +// Business business = businessService.getById(order.getBusinessId()); +// Long userId = order.getUserId(); +// Long businessId = business.getUserId(); +// MessageVO messageVO = new MessageVO(); +// messageVO.setType(1); +// messageVO.setUserId(userId); +// messageVO.setToUserId(businessId); +// messageVO.setContent(orderIdByString); +// String message = JSONUtil.toJsonStr(messageVO); +// // 通知商家新订单 +// webSocketServer.onMessage(message); + System.out.println("---------------------------微信支付回调(结束)-------------------------------"); + return true; + } + + @Override + public Refund refundPayment(String orderId, BigDecimal amount) { + // 退款请求 + CreateRequest createRequest = new CreateRequest(); + // 商户订单号 + createRequest.setOutTradeNo(orderId); + // 商户退款单号 + createRequest.setOutRefundNo(orderId); + // 退款结果回调 + createRequest.setNotifyUrl(wxPayConfig.getNotifyUrl() + "/api/wechat/refund/callback"); + // 退款金额 + AmountReq amountReq = new AmountReq(); + long refundAmount = amount.movePointRight(2).intValue(); + amountReq.setRefund(refundAmount); + amountReq.setTotal(refundAmount); + amountReq.setCurrency("CNY"); + createRequest.setAmount(amountReq); + // 申请退款 + System.out.println("退款请求:" + createRequest); + Refund refund = wxPayConfig.getRefundService().create(createRequest); + System.out.println("退款申请结果:" + refund); + return refund; + } + + @Override + public RefundNotification getRefundInfo(HttpServletRequest request) { + NotificationParser notificationParser = getNotificationParser(request); + return notificationParser.parse(requestParam, RefundNotification.class); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public synchronized boolean refundCallback(RefundNotification refundNotification) { + System.out.println("---------------------------微信退款回调(开始)-------------------------------"); + // 获取订单信息 + String orderIdByString = refundNotification.getOutTradeNo(); + Order order = ordersService.getById(orderIdByString); + // 修改订单信息 + order.setOrderStatus("已退款"); + ordersService.updateById(order); + System.out.println("---------------------------微信退款回调(结束)-------------------------------"); + return true; + } + + @Override + public boolean sendSubscribeMessage(String openid, String templateId) { + try { + // 获取小程序对象 + WxMaService wxMaService = wxOpenConfig.getWxMaService(); + // 获取消息接口 + WxMaMsgService msgService = wxMaService.getMsgService(); + // 构建订阅消息体 + WxMaSubscribeMessage wxMaSubscribeMessage = new WxMaSubscribeMessage(); + wxMaSubscribeMessage.setToUser(openid); + wxMaSubscribeMessage.setTemplateId(templateId); + List msgDataList = getMsgData(); + wxMaSubscribeMessage.setData(msgDataList); + // 发送消息 + msgService.sendSubscribeMsg(wxMaSubscribeMessage); + return true; + } catch (Exception e) { + log.error("发送订阅消息失败:", e); + throw new BusinessException(ErrorCode.SYSTEM_ERROR, "发送订阅消息失败"); + } + } + + /** + * 提取消息数据 + */ + private static List getMsgData() { + List msgDataList = new ArrayList<>(); + String[][] dataItems = { + {"thing1", "新订单"}, + {"phrase2", "已支付"}, + {"amount3", "666"}, + {"thing10", "666666"}, + {"time8", "2019-12-18 12:12:12"} + }; + for (String[] item : dataItems) { + WxMaSubscribeMessage.MsgData msgData = new WxMaSubscribeMessage.MsgData(); + msgData.setName(item[0]); + msgData.setValue(item[1]); + msgDataList.add(msgData); + } + return msgDataList; + } + + /** + * 根据微信官方发送的请求获取信息 + */ + @SneakyThrows + public NotificationParser getNotificationParser(HttpServletRequest request) { + System.out.println("---------------------------获取信息-------------------------------"); + // 获取RSA配置 + NotificationParser notificationParser = new NotificationParser(wxPayConfig.getRSAConfig()); + // 构建请求 + StringBuilder bodyBuilder = new StringBuilder(); + BufferedReader reader = request.getReader(); + String line; + while ((line = reader.readLine()) != null) { + bodyBuilder.append(line); + } + String body = bodyBuilder.toString(); + String timestamp = request.getHeader("Wechatpay-Timestamp"); + String nonce = request.getHeader("Wechatpay-Nonce"); + String signature = request.getHeader("Wechatpay-Signature"); + String singType = request.getHeader("Wechatpay-Signature-Type"); + String wechatPayCertificateSerialNumber = request.getHeader("Wechatpay-Serial"); + requestParam = new RequestParam.Builder() + .serialNumber(wechatPayCertificateSerialNumber) + .nonce(nonce) + .signature(signature) + .timestamp(timestamp) + .signType(singType) + .body(body) + .build(); + System.out.println(requestParam.toString()); + System.out.println("---------------------------信息获取完毕-------------------------------"); + return notificationParser; + } +} diff --git a/src/main/java/com/cultural/heritage/utils/AppointmentDateUtil.java b/src/main/java/com/cultural/heritage/utils/AppointmentDateUtil.java deleted file mode 100644 index 3e2299b..0000000 --- a/src/main/java/com/cultural/heritage/utils/AppointmentDateUtil.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.cultural.heritage.utils; - -import cn.hutool.core.date.DateTime; -import cn.hutool.core.date.DateUtil; - -import java.util.ArrayList; -import java.util.List; - -public class AppointmentDateUtil { - - // 将当天及未来三天的日期加入到集合中 - public static List getDates() { - List dates = new ArrayList<>(); - for (int i = 0; i < 4; i ++ ) { - DateTime date = DateUtil.date(); - DateTime dateTime = DateUtil.offsetDay(date, i); - String formatDate = DateUtil.formatDate(dateTime); - dates.add(formatDate); - } - return dates; - } - -} diff --git a/src/main/resources/apiclient_key.pem b/src/main/resources/apiclient_key.pem new file mode 100644 index 0000000..81400ad --- /dev/null +++ b/src/main/resources/apiclient_key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDQvDoLQ9+041aV +lLvDgIdhenuq54wx+UeuIWd2Zc4E4Io+47PCr6kzpbkLhq47//dKAG1Fobb2vCRu +HG+CUfhkOzYLxt9qC4k9TOAtQPWp3Hc3dTldw42C/pGzh8aro7rHtpRHDzQYdJgB +w4dPQ0+RoZ2U9meiGWsy2DVOydPVxabxN9gFeeP5FRKjZP2JUAoKJRgWrBD9Fgyn +mX/crOa8z5HTBK/LY+jBy57Bp9ZpUS9nDIpXSgdI7mZn3xvLmGfjki8WG9X8Ad99 +jvyTzD0HDcm7XoGo+Rp2Evh0pqQQf33R/OkH1WIFtcrqfwGUugTLDfIrFvDr3Qgc +KE2Z2U7pAgMBAAECggEAXgIn8iLjgchRmpSd6/LbBh/vyoz2KxumGNqaikxXeQLX +wHM05p3OiqA8suA5YHRrnzyJ+i5XBNC/Z4gPAJaCVEIGmU88F7qSWLVi0X7MJXBR +kPyOlZgZB8I3RLAF3g+jc4bbSRWj1M/OFh1Ft4ENOP2cxxYinnLsQL33ZECp00Cc +IXlX4lqjkoFbBaeCZLEV5tzZ3R/NsYZ5HTtvEh+vX7WdIqmgfL/cndfC+fIlWqbi +kKITyfI//Ik02/07qbFaZOwCLAQccUBT/0K8v7b0rqr0XeiqN3a+lXkVY6DpFxXx +aplsZ8rljBZ51AcAw8bS/JpwMkAQ5tYbgN2luEq3MQKBgQD/x2yk6YECbutRDsFA +EOlZK1cwMbJSkCMgVxIrfzv0Ubj937CCzZ7StxiHCxAa3+Oj8uX3aL57ZEatudyU +PsbZP6WWMqD3HiWUZoD1qcqRbp57FR9a3sFkgXoN9o93xdLiUS8LVAVLaqGSfO76 +o7euReXlK+hNAFmkAwFsPnVdawKBgQDQ6mWSaefUfDVddw8mPdgCtjCIKMBWTNs9 +U0ygVEsDs2FDxcC8175GQBbCNvtgh7DxWfOs847TVjH2CpZk74vSyt0Y59295Xx+ +t4Vn3CHCBxvYGIRCTOXjBRRUOxQLXjb+X6XN3y9pxhkhVdwr5m5q49JIWcNyNuAJ +LTqq6CLl+wKBgAjaAeyDGC/ZXtNjS1TIQQsQ8Od+EMnCqzSHTt2qfYyq91fx0c31 +B7YLGBI0U85aSSp3UXYKbe0fP0Lr17JZqdAC39wezGtA49QK6BOYWKZHybxAsuEW +LGMqB+tLyRNACVhDrvkZY0WE3yqOoEaUO9sQGDCiIFvp0zBV2krArpcZAoGAHiwM +GVY0RireJi6AwJwj61hWsAN6q7wT2cqDAZDK+LDadkhEKsHZ2Bl/b/My4OEX+/Nq +zuqqEPmc45Tp3Y//GKV1wxgRnVBcZ4yntrVDJtuR+Oapi03B0cS1B+k0XuPve1Nj +BdWa6mLS1E6rKqfwAH4Aq7RTFta4Cns+wtod2CsCgYAu7gHrFJfB6C/Dl93ZXTiL +HQdxpk0+L0hmXYaHFVK+0L2lswd7jlx6NLE3CNKEbUVr2fdhi8Qr2PLqiK/sAUCD +yRN6z17oSZ6eUfax5wKO5yXkuKq9DAoWpLitLgQmrxV1xfBx/q8ojVnFAG17q3F+ +lN+FSz/IRCR9pAaVuVKw0w== +-----END PRIVATE KEY----- diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 11d3faf..a32ff44 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -61,11 +61,26 @@ hwyun: wx: mini: - appId: wx3f968a09e31d6bed - appSecret: 847bdda7c2b01e88d59948b9ba50ef8d + appId: wx61b63e27bddf4ea2 + appSecret: 5ef9e1f17acd8180afe2d80199fd466e official: appId: wx5d04ca2de0e628a8 appSecret: 495af5bc4df1b86ffcfc21bb12daea76 + pay: + #应用id(小程序id) + appId: wx61b63e27bddf4ea2 + #商户号 + merchantId: 1700326544 + #商户API私钥 + privateKeyPath: apiclient_key.pem + #商户证书序列号 + merchantSerialNumber: 6DC8953AB741D309920DA650B92F837BE38A2757 + #商户APIv3密钥 + apiV3Key: fbemuj4Xql7CYlQJAoTEPYxvPSNgYT2t +# 通知地址 + notifyUrl: https://winning-mouse-internally.ngrok-free.app +# notifyUrl: http://localhost:9092 + knife4j: diff --git a/src/main/resources/mapper/TimeIntervalMapper.xml b/src/main/resources/mapper/TimeIntervalMapper.xml new file mode 100644 index 0000000..25ac858 --- /dev/null +++ b/src/main/resources/mapper/TimeIntervalMapper.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/src/test/java/com/cultural/heritage/test/Animal.java b/src/test/java/com/cultural/heritage/test/Animal.java new file mode 100644 index 0000000..61cabd4 --- /dev/null +++ b/src/test/java/com/cultural/heritage/test/Animal.java @@ -0,0 +1,39 @@ +package com.cultural.heritage.test; + +class Animal { + String name; + int age; + + public Animal(String name, int age) { + this.name = name; + this.age = age; + } + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return name; + } +} + +class Bird extends Animal { + public Bird(String name, int age) { + super(name, age); + } + + public void fly() { + System.out.println(name + " 能飞行"); + } + + public void showBirdInfo() { + System.out.println("鸟的名称: " + name); + } + + public static void main(String[] args) { + Bird bird = new Bird("麻雀", 2); + bird.showBirdInfo(); + bird.fly(); + } +} diff --git a/src/test/java/com/cultural/heritage/test/B.java b/src/test/java/com/cultural/heritage/test/B.java index 5907da3..4bf2a52 100644 --- a/src/test/java/com/cultural/heritage/test/B.java +++ b/src/test/java/com/cultural/heritage/test/B.java @@ -1,5 +1,11 @@ package com.cultural.heritage.test; public class B { - public Long num = 10L; + static { + System.out.println("静态块已执行"); + } + + public static void main(String[] args) { + new B(); // 创建对象,观察静态块是否执行 + } }