教育训练处考试制证系统后端
heheng
2025-01-23 f8b251573040d2762507909a02f274a6cf4d751c
特种作业非煤缴费版本优化
已修改12个文件
已添加5个文件
1245 ■■■■ 文件已修改
exam-system/pom.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
exam-system/src/main/java/com/gkhy/exam/pay/controller/NonCoalPayController.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
exam-system/src/main/java/com/gkhy/exam/pay/dto/rep/NonCoalCateRep.java 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
exam-system/src/main/java/com/gkhy/exam/pay/dto/rep/NonCoalPayOrder.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
exam-system/src/main/java/com/gkhy/exam/pay/dto/rep/NonCoalStuRep.java 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
exam-system/src/main/java/com/gkhy/exam/pay/mapper/NonCoalPayMapper.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
exam-system/src/main/java/com/gkhy/exam/pay/service/NonCoalPayStudentService.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
exam-system/src/main/java/com/gkhy/exam/pay/service/impl/CoalPayServiceImpl.java 61 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
exam-system/src/main/java/com/gkhy/exam/pay/service/impl/NonCoalPayStudentServiceImpl.java 148 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
exam-system/src/main/java/com/gkhy/exam/pay/utils/PayUtils.java 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
exam-system/src/main/resources/mapper/pay/NonCoalPayMapper.xml 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
exam-system/src/test/java/TextPay.java 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/resources/application-dev.yml 237 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/resources/application-pro.yml 237 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/config/RedissonConfig.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/utils/RandomUtil.java 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/utils/RedisLock.java 98 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
exam-system/pom.xml
@@ -31,6 +31,12 @@
            <artifactId>qiniu-java-sdk</artifactId>
            <version>[7.2.0, 7.2.99]</version>
        </dependency>
        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson</artifactId>
            <version>3.18.0</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>
exam-system/src/main/java/com/gkhy/exam/pay/controller/NonCoalPayController.java
@@ -147,7 +147,7 @@
     */
    @PostMapping("/editNonCoalStu")
    @ApiOperation(value = "修改非煤缴费学员")
    public AjaxResult editNonCoalStu(@RequestBody NonCoalPayStudent nonCoalPayStudent) {
    public AjaxResult editNonCoalStu(@Validated @RequestBody NonCoalPayStudent nonCoalPayStudent) {
        return toAjax(nonCoalPayStudentService.updateNonCoalPayStudent(nonCoalPayStudent));
    }
@@ -194,4 +194,16 @@
    }
    @PostMapping("/sendOrder")
    @ApiOperation(value = "生成财政订单")
    @Anonymous
    @RepeatSubmit
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", dataTypeClass = Long.class, value = "个人缴费学员数据id,团队缴费数据id", required = true),
            @ApiImplicitParam(name = "payType", dataTypeClass = String.class, value = "1个人2是团队", required = true),
    })
    public AjaxResult sendOrder(@RequestParam("id") Long id, @RequestParam("payType") String payType) {
        return success(nonCoalPayStudentService.sendOrder(id, payType));
    }
}
exam-system/src/main/java/com/gkhy/exam/pay/dto/rep/NonCoalCateRep.java
对比新文件
@@ -0,0 +1,68 @@
package com.gkhy.exam.pay.dto.rep;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class NonCoalCateRep {
    /**
     * $column.columnComment
     */
    private Long id;
    /**
     * $column.columnComment
     */
    @ApiModelProperty("非煤管理id")
    private Long nonCoalPayId;
    /**
     * 类别id
     */
    @ApiModelProperty("类别id")
    private Long categoryId;
    @ApiModelProperty("类别名称")
    private String subjectName;
    /**
     * 类别1理论2实操
     */
    @ApiModelProperty("类别类型id")
    private Long categoryType;
    @ApiModelProperty("缴费金额")
    private BigDecimal categoryAmount;
    @ApiModelProperty("业务编码")
    private String businessCode;
    /**
     * 单位编码
     */
    @ApiModelProperty("单位编码")
    private String companyCode;
    /**
     * 开票人
     */
    @ApiModelProperty("开票人")
    private String drawer;
    /**
     * 复核人
     */
    @ApiModelProperty("复核人")
    private String reviewer;
    /**
     * 开票单位社会信用代码
     */
    @ApiModelProperty("开票单位社会信用代码")
    private String invoicingCompanyCode;
}
exam-system/src/main/java/com/gkhy/exam/pay/dto/rep/NonCoalPayOrder.java
对比新文件
@@ -0,0 +1,20 @@
package com.gkhy.exam.pay.dto.rep;
import lombok.Data;
import java.math.BigDecimal;
import java.util.List;
@Data
public class NonCoalPayOrder {
    private Long id;
    private String batchName;
    private BigDecimal amount;
    private Long payPersonType;
    private String payCompanyName;
    private String payCompanyCard;
    private List<NonCoalStuRep> nonCoalStuList;
    private List<NonCoalCateRep> nonCoalPayCategoryList;
}
exam-system/src/main/java/com/gkhy/exam/pay/dto/rep/NonCoalStuRep.java
对比新文件
@@ -0,0 +1,46 @@
package com.gkhy.exam.pay.dto.rep;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
public class NonCoalStuRep {
    private Long id;
    /**
     * 姓名
     */
    @ApiModelProperty("姓名")
    private String studentName;
    /**
     * 身份证号
     */
    @ApiModelProperty("身份证号")
    private String idCard;
    /**
     * 电话
     */
    @ApiModelProperty("电话")
    private String phone;
    /**
     * 0男 1女 2未知
     */
    @ApiModelProperty("性别 0男1女2未知")
    private Long sex;
    /**
     * 是否缴款0否1是
     */
    @ApiModelProperty("是否缴款0否1是")
    private Long payStatus;
    @ApiModelProperty("财政订单编号")
    private String orderId;
}
exam-system/src/main/java/com/gkhy/exam/pay/mapper/NonCoalPayMapper.java
@@ -3,6 +3,7 @@
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.gkhy.exam.pay.dto.rep.NonCoalPayDetailH5RepDto;
import com.gkhy.exam.pay.dto.rep.NonCoalPayDetailRepDto;
import com.gkhy.exam.pay.dto.rep.NonCoalPayOrder;
import com.gkhy.exam.pay.dto.rep.NonCoalPayPageRepDto;
import com.gkhy.exam.pay.entity.NonCoalPay;
import org.apache.ibatis.annotations.Param;
@@ -59,6 +60,8 @@
     */
    public int insertNonCoalPay(NonCoalPay nonCoalPay);
    List<NonCoalPayOrder> selectNonCoalPayOrderByParam(@Param("dataId") Long dataId, @Param("payType") Long payType);
    /**
     * 修改【请填写功能名称】
     *
exam-system/src/main/java/com/gkhy/exam/pay/service/NonCoalPayStudentService.java
@@ -31,6 +31,8 @@
     */
    public List<NonCoalPayStudent> selectNonCoalPayStudentList(NonCoalPayStudent nonCoalPayStudent);
    public String sendOrder(Long dataId, String payType);
    /**
     * 新增【请填写功能名称】
     *
exam-system/src/main/java/com/gkhy/exam/pay/service/impl/CoalPayServiceImpl.java
@@ -23,7 +23,6 @@
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.mapper.SysDeptMapper;
import org.aspectj.lang.reflect.UnlockSignature;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
@@ -37,7 +36,6 @@
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.stream.Collectors;
@Service
@@ -58,11 +56,13 @@
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private PayUtils payUtils;
    /**
     * 缴费管理列表
     *
     * @param coalPay
     * @return
     */
@@ -72,7 +72,7 @@
        List<CoalPay> coalPays = coalPayMapper.selectCoalPayList(coalPay);
        for (CoalPay pay : coalPays) {
            CoalPayRepDto coalPayRepDto = new CoalPayRepDto();
            BeanUtils.copyProperties(pay,coalPayRepDto);
            BeanUtils.copyProperties(pay, coalPayRepDto);
            //部门数据
            SysDept sysDept = sysDeptMapper.selectDeptById(pay.getDeptId());
            coalPayRepDto.setDeptName(sysDept.getDeptName());
@@ -98,7 +98,7 @@
        //基本数据
        CoalPay coalPay = coalPayMapper.selectById(id);
        BeanUtils.copyProperties(coalPay,coalPayRepDto);
        BeanUtils.copyProperties(coalPay, coalPayRepDto);
        //考点名称
        SysDept sysDept = sysDeptMapper.selectDeptById(coalPay.getDeptId());
        coalPayRepDto.setDeptName(sysDept.getDeptName());
@@ -120,12 +120,12 @@
    @Override
    public int insertCoalPay(CoalPayDto coalPayDto) {
        CoalPay coalPay = new CoalPay();
        BeanUtils.copyProperties(coalPayDto,coalPay);
        BeanUtils.copyProperties(coalPayDto, coalPay);
        coalPay.setCreateBy(SecurityUtils.getUsername());
        coalPay.setCreateTime(new Date());
        int insert = coalPayMapper.insertBath(coalPay);
        if (CollectionUtils.isEmpty(coalPayDto.getCoalPayCategoryies())){
            throw new BusinessException(this.getClass(),ResultConstants.BUSINESS_ERROR,"工种类别不能为空");
        if (CollectionUtils.isEmpty(coalPayDto.getCoalPayCategoryies())) {
            throw new BusinessException(this.getClass(), ResultConstants.BUSINESS_ERROR, "工种类别不能为空");
        }
        List<CoalPayCategory> coalPayCategories = coalPayDto.getCoalPayCategoryies();
        for (CoalPayCategory coalPayCategory : coalPayCategories) {
@@ -137,18 +137,19 @@
    /**
     * 修改缴费信息
     *
     * @param coalPayDto
     * @return
     */
    @Override
    public int updateCoalPay(CoalPayDto coalPayDto) {
        CoalPay coalPay = new CoalPay();
        BeanUtils.copyProperties(coalPayDto,coalPay);
        BeanUtils.copyProperties(coalPayDto, coalPay);
        coalPay.setUpdateBy(SecurityUtils.getUsername());
        coalPay.setUpdateTime(new Date());
        int i = coalPayMapper.updateCoalPayById(coalPay);
        int update = coalPayCategoryMapper.deleteByCoalPayId(coalPayDto.getId());
        if (update>0){
        if (update > 0) {
            List<CoalPayCategory> coalPayCategories = coalPayDto.getCoalPayCategoryies();
            for (CoalPayCategory coalPayCategory : coalPayCategories) {
                coalPayCategory.setCoalPayId(coalPay.getId());
@@ -161,13 +162,13 @@
    @Override
    public AjaxResult deleteCoalPayByIds(Long[] ids) {
        for (Long id : ids) {
            List<CoalPayStudent> coalPayStudents = coalPayStudentService.selectByCoalPayIdAndPayStatus(id,1);
            if (!CollectionUtils.isEmpty(coalPayStudents)){
                throw new BusinessException(this.getClass(), ResultConstants.BUSINESS_ERROR,"已有学员完成缴费,请勿删除");
            List<CoalPayStudent> coalPayStudents = coalPayStudentService.selectByCoalPayIdAndPayStatus(id, 1);
            if (!CollectionUtils.isEmpty(coalPayStudents)) {
                throw new BusinessException(this.getClass(), ResultConstants.BUSINESS_ERROR, "已有学员完成缴费,请勿删除");
            }
        }
        int i = coalPayMapper.updateByIds(ids);
        if (i>0){
        if (i > 0) {
            return AjaxResult.success();
        }
        return AjaxResult.error();
@@ -175,7 +176,7 @@
    //个人查询缴费
    @Override
    public List<CoalPayStudentRep> selectCoalPay(String idcard,String phone) {
    public List<CoalPayStudentRep> selectCoalPay(String idcard, String phone) {
        CoalPayStudentReq coalPayStudentReq = new CoalPayStudentReq();
        coalPayStudentReq.setIdCard(idcard);
        coalPayStudentReq.setPhone(phone);
@@ -194,7 +195,7 @@
            //查询对应批次以及批次包含工种类别
            CoalPay coalPay = coalPayMapper.selectById(payStudent.getCoalPayId());
            CoalPayRepDto coalPayRepDto = new CoalPayRepDto();
            BeanUtils.copyProperties(coalPay,coalPayRepDto);
            BeanUtils.copyProperties(coalPay, coalPayRepDto);
            //考点名称
            SysDept sysDept = sysDeptMapper.selectDeptById(coalPay.getDeptId());
            coalPayRepDto.setDeptName(sysDept.getDeptName());
@@ -210,8 +211,8 @@
    @Override
    public int updateCoalPayType(CoalPayTypeReq coalPayTypeReq) {
        CoalPay byId = coalPayMapper.selectById(coalPayTypeReq.getCoalPayId());
        if (coalPayTypeReq.getPayPersonType() != null && byId.getPayPersonType() == 2){
            throw new BusinessException(this.getClass(),ResultConstants.BUSINESS_ERROR,"已为团体缴费,不可更改");
        if (coalPayTypeReq.getPayPersonType() != null && byId.getPayPersonType() == 2) {
            throw new BusinessException(this.getClass(), ResultConstants.BUSINESS_ERROR, "已为团体缴费,不可更改");
        }
        return coalPayMapper.updateByPayId(coalPayTypeReq);
    }
@@ -224,7 +225,7 @@
        CoalTicket coalTicket = coalCategoryMapper.selectCoalTicket();
        PayReqData payReqData = new PayReqData();
        payReqData.setOrderNo(RandomUtil.generateOrderNumber());
        payReqData.setOrderNo(RandomUtil.generateOrderNumber(coalPayId, "CO"));
        payReqData.setMoney(coalPay.getAmount());
        payReqData.setAmount(1);
        payReqData.setPayerName(coalPayStudent.getName());
@@ -248,34 +249,34 @@
        CoalPayStudent payStudent = new CoalPayStudent();
        RLock lock = redissonClient.getLock("SWSPKMAS_PAY_PERSON");
        RLock lock = redissonClient.getLock("SWSPKMAS_PAY_PERSON_" + coalPayId);
        try {
            lock.lock(10, TimeUnit.SECONDS);
            if (coalPayStudent.getGovPayStatus()!=0){
                throw new BusinessException(this.getClass(),ResultConstants.BUSINESS_ERROR,"请勿重复发起支付");
            if (coalPayStudent.getGovPayStatus() != 0) {
                throw new BusinessException(this.getClass(), ResultConstants.BUSINESS_ERROR, "请勿重复发起支付");
            }
            if (StringUtils.isEmpty(coalPayStudent.getPayCode())){
            if (StringUtils.isEmpty(coalPayStudent.getPayCode())) {
            }
            ResultVo resultVo = PayUtils.sendApiPost(payReqData);
            if (resultVo.getRespcode().equals("BUS0000")){
            ResultVo resultVo = payUtils.sendApiPost(payReqData);
            if (resultVo.getRespcode().equals("BUS0000")) {
                payStudent.setId(studentId);
                payStudent.setOrderId(resultVo.getRespdata().getOrderNo());
                payStudent.setGovPayStatus(1);
                payStudent.setPayCode(resultVo.getRespdata().getBillNo());
                coalPayStudentService.updateByCoalPayStudent(payStudent);
                return resultVo.getRespdata().getBillNo();
            }else {
                throw new BusinessException(this.getClass(),ResultConstants.BUSINESS_ERROR,"发起支付失败,请稍后重试");
            } else {
                throw new BusinessException(this.getClass(), ResultConstants.BUSINESS_ERROR, "发起支付失败,请稍后重试");
            }
        }catch (BusinessException e){
            throw new BusinessException(this.getClass(),ResultConstants.BUSINESS_ERROR,"请稍后重试");
        } catch (BusinessException e) {
            throw new BusinessException(this.getClass(), ResultConstants.BUSINESS_ERROR, "请稍后重试");
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if(lock.isLocked()){
            if (lock.isLocked()) {
                lock.unlock();
            }
        }
exam-system/src/main/java/com/gkhy/exam/pay/service/impl/NonCoalPayStudentServiceImpl.java
@@ -4,23 +4,34 @@
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gkhy.exam.institutionalaccess.enums.StudentSex;
import com.gkhy.exam.pay.dto.rep.NonCoalCateRep;
import com.gkhy.exam.pay.dto.rep.NonCoalPayOrder;
import com.gkhy.exam.pay.dto.rep.NonCoalStuRep;
import com.gkhy.exam.pay.dto.req.NonCoalPayStuImport;
import com.gkhy.exam.pay.dto.req.NonCoalPayStudentReqDto;
import com.gkhy.exam.pay.entity.NonCoalPay;
import com.gkhy.exam.pay.entity.NonCoalPayStudent;
import com.gkhy.exam.pay.entity.PayReqData;
import com.gkhy.exam.pay.mapper.NonCoalPayMapper;
import com.gkhy.exam.pay.mapper.NonCoalPayStudentMapper;
import com.gkhy.exam.pay.service.NonCoalPayStudentService;
import com.gkhy.exam.pay.utils.PayUtils;
import com.gkhy.exam.pay.utils.ResultVo;
import com.ruoyi.common.constant.ResultConstants;
import com.ruoyi.common.exception.BusinessException;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.RandomUtil;
import com.ruoyi.common.utils.RedisLock;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@@ -31,11 +42,138 @@
 * @date 2025-01-16
 */
@Service
@Slf4j
public class NonCoalPayStudentServiceImpl extends ServiceImpl<NonCoalPayStudentMapper, NonCoalPayStudent> implements NonCoalPayStudentService {
    @Resource
    private NonCoalPayStudentMapper nonCoalPayStudentMapper;
    @Resource
    private NonCoalPayMapper nonCoalPayMapper;
    @Resource
    private PayUtils payUtils;
    @Autowired
    private RedisLock redisLock;
    private static final String NON_COAL_PAY_STUDENT_LOCK = "NON_COAL_PAY_STUDENT_LOCK_";
    @Override
    public String sendOrder(Long dataId, String payType) {
        String lockKey = NON_COAL_PAY_STUDENT_LOCK + dataId + "_PAY_TYPE_" + payType;
        Boolean b = redisLock.tryLock(lockKey, 10, 20, TimeUnit.SECONDS);
        if (b) {
            String orderNo = RandomUtil.generateOrderNumber(dataId, "NC");
            List<NonCoalPayOrder> nonCoalPayOrders = nonCoalPayMapper.selectNonCoalPayOrderByParam(dataId, Long.valueOf(payType));
            if (StringUtils.isEmpty(nonCoalPayOrders)) {
                throw new BusinessException(this.getClass(), ResultConstants.BUSINESS_ERROR, "未找到相关缴费信息");
            }
            NonCoalPayOrder nonCoalPayOrder = nonCoalPayOrders.get(0);
            List<NonCoalStuRep> nonCoalStuList = nonCoalPayOrder.getNonCoalStuList();
            if (StringUtils.isEmpty(nonCoalStuList)) {
                throw new BusinessException(this.getClass(), ResultConstants.BUSINESS_ERROR, "未找到需要缴费的学员");
            }
            NonCoalStuRep nonCoalStuRep = nonCoalStuList.get(0);
            if (nonCoalStuRep.getPayStatus() == 1) {
                throw new BusinessException(this.getClass(), ResultConstants.BUSINESS_ERROR, "已缴费请勿重复缴费");
            }
            List<NonCoalCateRep> nonCoalPayCategoryList = nonCoalPayOrder.getNonCoalPayCategoryList();
            if (StringUtils.isEmpty(nonCoalPayCategoryList)) {
                throw new BusinessException(this.getClass(), ResultConstants.BUSINESS_ERROR, "缴费信息缺失");
            }
            // 业务处理
            //查询主信息   查询是否是团队
            PayReqData payReqData = dealData(nonCoalPayOrder, orderNo, payType);
            try {
                ResultVo resultVo = payUtils.sendApiPost(payReqData);
                log.info("调用接口返回结果:" + resultVo);
                if (resultVo.getRespcode().equals("BUS0000")) {
                    String orderId = resultVo.getRespdata().getOrderId();
                    String billNo = resultVo.getRespdata().getBillNo();
                    if (StringUtils.isNotEmpty(orderId)) {
                        // 更新订单
                        if ("1".equals(payType)) {
                            baseMapper.update(null, Wrappers.<NonCoalPayStudent>lambdaUpdate()
                                    .set(NonCoalPayStudent::getOrderId, orderId)
                                    .set(NonCoalPayStudent::getOrderNo, orderNo)
                                    .set(NonCoalPayStudent::getPayCode, billNo)
                                    .eq(NonCoalPayStudent::getId, dataId).eq(NonCoalPayStudent::getDelFlag, 0)
                                    .eq(NonCoalPayStudent::getPayType, payType).eq(NonCoalPayStudent::getPayStatus, 0));
                        } else {
                            //团体缴费
                            baseMapper.update(null, Wrappers.<NonCoalPayStudent>lambdaUpdate()
                                    .set(NonCoalPayStudent::getOrderId, orderId)
                                    .set(NonCoalPayStudent::getOrderNo, orderNo)
                                    .set(NonCoalPayStudent::getPayCode, billNo)
                                    .eq(NonCoalPayStudent::getNonCoalPayId, dataId).eq(NonCoalPayStudent::getDelFlag, 0)
                                    .eq(NonCoalPayStudent::getPayType, payType).eq(NonCoalPayStudent::getPayStatus, 0));
                        }
                    }
                    return orderId;
                } else {
                    log.error("生成订单失败:" + resultVo.getRespmsg() + ",请稍后重试,错误编码:" + resultVo.getRespcode() + "参数如下:" + payReqData);
                    throw new BusinessException(this.getClass(), ResultConstants.BUSINESS_ERROR, "发起支付失败,请稍后重试");
                }
            } catch (Exception e) {
                log.error("发起支付调用接口失败:" + e);
                throw new BusinessException(this.getClass(), ResultConstants.BUSINESS_ERROR, e.getMessage());
            } finally {
                redisLock.unlock(lockKey);
            }
        }
        return null;
    }
    private PayReqData dealData(NonCoalPayOrder nonCoalPayOrder, String orderNo, String payType) {
        List<NonCoalStuRep> nonCoalStuList = nonCoalPayOrder.getNonCoalStuList();
        List<NonCoalCateRep> nonCoalPayCategoryList = nonCoalPayOrder.getNonCoalPayCategoryList();
        PayReqData payReqData = new PayReqData();
        payReqData.setOrderNo(orderNo);
        payReqData.setPayerType(Integer.valueOf(payType));
        payReqData.setMoney(nonCoalPayOrder.getAmount().multiply(BigDecimal.valueOf(nonCoalStuList.size())));
        payReqData.setAmount(nonCoalStuList.size());
        payReqData.setDesc(nonCoalPayOrder.getBatchName());
        NonCoalCateRep nonCoalCateRep1 = nonCoalPayCategoryList.get(0);
        payReqData.setHandlingPerson(nonCoalCateRep1.getDrawer());
        payReqData.setChecker(nonCoalCateRep1.getReviewer());
        payReqData.setEnterCode(nonCoalCateRep1.getCompanyCode());
        payReqData.setInvoiceSocialCode(nonCoalCateRep1.getInvoicingCompanyCode());
        List<PayReqData.Feedata> feedatas1 = new ArrayList<>();
        for (NonCoalCateRep nonCoalCateRep : nonCoalPayCategoryList) {
            PayReqData.Feedata feedatas = new PayReqData.Feedata();
            feedatas.setAmount(nonCoalStuList.size());
            feedatas.setBusCode(nonCoalCateRep.getBusinessCode());
            feedatas.setPrice(nonCoalCateRep.getCategoryAmount());
            feedatas1.add(feedatas);
        }
        payReqData.setFeeDatas(feedatas1);
        if ("1".equals(payType)) {
            //个人缴费
            NonCoalStuRep nonCoalStuRep = nonCoalStuList.get(0);
            payReqData.setPayerName(nonCoalStuRep.getStudentName());
            payReqData.setCertNo(nonCoalStuRep.getIdCard());
        } else {
            //团体缴费
            payReqData.setPayerName(nonCoalPayOrder.getPayCompanyName());
            payReqData.setCertNo(nonCoalPayOrder.getPayCompanyCard());
            //todo 待确认
            payReqData.setInvoiceSocialCode(nonCoalPayOrder.getPayCompanyCard());
            payReqData.setEnterCode(nonCoalPayOrder.getPayCompanyCard());
        }
        return payReqData;
    }
    /**
     * 查询【请填写功能名称】
@@ -212,7 +350,7 @@
                    stu1.setName(stu.getName());
                    stu1.setIdCard(stu.getIdCard());
                    stu1.setPhone(stu.getPhone());
//                    stu1.setOrderNo(RandomUtil.generateOrderNumber());
                    stu1.setSex(StudentSex.BOY.getStatus().equals(stu.getSex().trim()) ? 0L : 1L);
                    nonCoalPayStudentMapper.insertNonCoalPayStudent(stu1);
exam-system/src/main/java/com/gkhy/exam/pay/utils/PayUtils.java
@@ -2,8 +2,12 @@
import com.alibaba.fastjson2.JSONObject;
import com.gkhy.exam.pay.entity.PayReqData;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.http.*;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.StatusLine;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.HttpResponseException;
@@ -25,8 +29,9 @@
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
@@ -40,32 +45,45 @@
/**
 * 缴费相关接口
 */
@Component
@Slf4j
public class PayUtils {
    private final static String appid="ED76A5F1703540BE977D34780B371FEB";
//    private final static String appid = "ED76A5F1703540BE977D34780B371FEB";
    @Value("${finance.orderUrl}")
    private String orderUrl;
    public static ResultVo sendApiPost(PayReqData payReqData) throws IOException {
    @Value("${finance.payNotifyUrl}")
    private String payNotifyUrl;
    @Value("${finance.payQueryUrl}")
    private String payQueryUrl;
    @Value("${finance.apiId}")
    private String appId;
    public ResultVo sendApiPost(PayReqData payReqData) throws IOException {
        //正式
        String proUrl="http://finpt.xjcz.gov.cn/fs-service/fs-pay/invoice.do";
        String proUrl = "http://finpt.xjcz.gov.cn/fs-service/fs-pay/invoice.do";
        //测试
        String testUrl= "http://finpt.xjcz.gov.cn/fs-service-test/fs-pay/invoice.do";
        String testUrl = "http://finpt.xjcz.gov.cn/fs-service-test/fs-pay/invoice.do";
        Map<String, String> param = new HashMap<>();
        HttpPost httpPost = new HttpPost(testUrl);
        HttpPost httpPost = new HttpPost(orderUrl);
        //请求参数转为json格式base64编码
        String reqData = Base64.getEncoder().encodeToString(JSONObject.toJSONString(payReqData).getBytes());
        String mac = appid+"||"+reqData;
        String mac = appId + "||" + reqData;
        mac = DigestUtils.md5Hex(mac.getBytes());
        param.put("appid",appid);
        param.put("reqdata",reqData);
        param.put("mac",mac);
        param.put("appid", appId);
        param.put("reqdata", reqData);
        param.put("mac", mac);
        httpPost.setEntity(assemblyFormEntity(param,"utf-8"));
        HttpClient httpClient = getHttpClient(testUrl);
        httpPost.setEntity(assemblyFormEntity(param, "utf-8"));
        HttpClient httpClient = getHttpClient(orderUrl);
        HttpResultVo execute = httpClient.execute(httpPost, getResponseHandler());
        String stringContent = execute.getStringContent();
        ResultVo resultVo = JSONObject.parseObject(stringContent, ResultVo.class);
@@ -117,13 +135,15 @@
                }
                @Override
                public void checkClientTrusted(X509Certificate[] xcs, String str) {}
                public void checkClientTrusted(X509Certificate[] xcs, String str) {
                }
                @Override
                public void checkServerTrusted(X509Certificate[] xcs, String str) {}
                public void checkServerTrusted(X509Certificate[] xcs, String str) {
                }
            };
            SSLContext ctx = SSLContext.getInstance(SSLConnectionSocketFactory.TLS);
            ctx.init(null, new TrustManager[] {trustManager}, null);
            ctx.init(null, new TrustManager[]{trustManager}, null);
            SSLConnectionSocketFactory socketFactory =
                    new SSLConnectionSocketFactory(ctx, NoopHostnameVerifier.INSTANCE);
            // 创建Registry
@@ -210,81 +230,79 @@
    //缴费结果通知
    public static Map<String,String> receive(JSONObject jsonObject) throws IOException {
    public Map<String, String> receive(JSONObject jsonObject) throws IOException {
        Map<String, String> params = new HashMap<>();
        JSONObject reqdata = new JSONObject();
        Map<String,String> result = (Map<String, String>) jsonObject.get("reqdata");
        Map<String, String> result = (Map<String, String>) jsonObject.get("reqdata");
        String orderNo = result.get("orderNo");
        //确认是否成功
        String  notarize= affirmPost(orderNo);
        reqdata.put("orderNo",orderNo);
        reqdata.put("status",notarize);
        String notarize = affirmPost(orderNo);
        reqdata.put("orderNo", orderNo);
        reqdata.put("status", notarize);
        String req = Base64.getEncoder().encodeToString(reqdata.toJSONString().getBytes());
        String mac = appid+"||"+req;
        String mac = appId + "||" + req;
        mac = DigestUtils.md5Hex(mac.getBytes());
        params.put("appid",appid);
        params.put("reqdata",req);
        params.put("mac",mac);
        params.put("appid", appId);
        params.put("reqdata", req);
        params.put("mac", mac);
        return params;
    }
    //缴费结果确认查询
    public static String affirmPost(String orderNo) throws IOException {
        String porUrl="http://finpt.xjcz.gov.cn/fs-service/fs-pay/notifyConfirm.do";
        String testUrl="http://finpt.xjcz.gov.cn/fs-service-test/fs-pay/notifyConfirm.do";
    public String affirmPost(String orderNo) throws IOException {
        HashMap<String, String> param = new HashMap<>();
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("orderNo",orderNo);
        jsonObject.put("orderNo", orderNo);
        String reqdata = Base64.getEncoder().encodeToString(jsonObject.toJSONString().getBytes());
        String mac = appid+"||"+reqdata;
        mac=DigestUtils.md5Hex(mac.getBytes());
        param.put("appid",appid);
        param.put("reqdata",reqdata);
        param.put("mac",mac);
        String mac = appId + "||" + reqdata;
        mac = DigestUtils.md5Hex(mac.getBytes());
        param.put("appid", appId);
        param.put("reqdata", reqdata);
        param.put("mac", mac);
        HttpPost httppost = new HttpPost(testUrl);
        httppost.setEntity(assemblyFormEntity(param,"utf-8"));
        HttpClient httpClient = getHttpClient(testUrl);
        HttpPost httppost = new HttpPost(payNotifyUrl);
        httppost.setEntity(assemblyFormEntity(param, "utf-8"));
        HttpClient httpClient = getHttpClient(payNotifyUrl);
        HttpResultVo execute = httpClient.execute(httppost, getResponseHandler());
        String stringContent = execute.getStringContent();
        ResultVo resultVo = JSONObject.parseObject(stringContent, ResultVo.class);
        System.out.printf("请求结果为:"+resultVo);
        if (resultVo.getRespcode().equals("BUS0000")){
        log.info("请求结果为:" + resultVo);
        if (resultVo.getRespcode().equals("BUS0000")) {
            return "success";
        }
        return "fail";
    }
    //缴费结果查询
    public static JSONObject query(String orderNo) throws IOException {
        String proUrl="http://finpt.xjcz.gov.cn/fs-service/fs-pay/query.do";
        String testUrl="http://finpt.xjcz.gov.cn/fs-service-test/fs-pay/query.do";
    public JSONObject query(String orderNo) throws IOException {
        String proUrl = "http://finpt.xjcz.gov.cn/fs-service/fs-pay/query.do";
        String testUrl = "http://finpt.xjcz.gov.cn/fs-service-test/fs-pay/query.do";
        HashMap<String, String> param = new HashMap<>();
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("orderNo",orderNo);
        jsonObject.put("orderNo", orderNo);
        String reqdata = Base64.getEncoder().encodeToString(jsonObject.toJSONString().getBytes());
        String mac = appid+"||"+reqdata;
        String mac = appId + "||" + reqdata;
        mac = DigestUtils.md5Hex(mac.getBytes());
        param.put("appid",appid);
        param.put("reqdata",reqdata);
        param.put("mac",mac);
        param.put("appid", appId);
        param.put("reqdata", reqdata);
        param.put("mac", mac);
        HttpPost httppost = new HttpPost(testUrl);
        httppost.setEntity(assemblyFormEntity(param,"utf-8"));
        HttpClient httpClient = getHttpClient(testUrl);
        HttpPost httppost = new HttpPost(payQueryUrl);
        httppost.setEntity(assemblyFormEntity(param, "utf-8"));
        HttpClient httpClient = getHttpClient(payQueryUrl);
        HttpResultVo execute = httpClient.execute(httppost, getResponseHandler());
        String stringContent = execute.getStringContent();
        JSONObject result = JSONObject.parseObject(stringContent);
        System.out.printf("请求结果json为:"+result);
        log.info("请求结果json为:" + result);
        return result;
    }
}
exam-system/src/main/resources/mapper/pay/NonCoalPayMapper.xml
@@ -202,6 +202,75 @@
    </select>
    <resultMap type="com.gkhy.exam.pay.dto.rep.NonCoalPayOrder" id="getNonCoalPayResultOrder">
        <result property="id" column="id"/>
        <result property="batchName" column="batch_name"/>
        <result property="amount" column="amount"/>
        <result property="payPersonType" column="pay_person_type"/>
        <result property="payCompanyName" column="pay_company_name"/>
        <result property="payCompanyCard" column="pay_company_card"/>
        <collection property="nonCoalPayCategoryList" javaType="java.util.List"
                    resultMap="nonCoalPayCategoryListOrder"/>
        <collection property="nonCoalStuList" javaType="java.util.List"
                    resultMap="nonCoalPayStuListOrder"/>
    </resultMap>
    <resultMap id="nonCoalPayCategoryListOrder" type="com.gkhy.exam.pay.dto.rep.NonCoalCateRep">
        <result property="id" column="non_category_id"/>
        <result property="businessCode" column="business_code"/>
        <result property="companyCode" column="company_code"/>
        <result property="invoicingCompanyCode" column="invoicing_company_code"/>
        <result property="drawer" column="drawer"/>
        <result property="reviewer" column="reviewer"/>
        <result property="categoryId" column="category_id"/>
        <result property="subjectName" column="subject_name"/>
        <result property="categoryType" column="category_type"/>
        <result property="categoryAmount" column="category_amount"/>
    </resultMap>
    <resultMap id="nonCoalPayStuListOrder" type="com.gkhy.exam.pay.dto.rep.NonCoalStuRep">
        <result property="id" column="non_coal_student_id"/>
        <result property="phone" column="phone"/>
        <result property="idCard" column="id_card"/>
        <result property="studentName" column="student_name"/>
        <result property="payStatus" column="pay_status"/>
        <result property="orderId" column="order_id"/>
    </resultMap>
    <select id="selectNonCoalPayOrderByParam" resultMap="getNonCoalPayResultOrder">
        select a.id,
        a.batch_name,
        a.pay_type,
        a.amount,
        a.pay_person_type,
        a.pay_company_name,
        a.pay_company_card,
        b.id as non_category_id,
        b.category_id,
        c.subject_name,
        c.category_type,
        c.business_code,
        c.company_code,
        c.drawer,
        c.reviewer,
        c.invoicing_company_code,
        b.category_amount,
        t.id as non_coal_student_id,
        t.phone,
        t.id_card,
        t.name as student_name,
        t.pay_status,
        t.order_id
        from non_coal_pay a
        inner join non_coal_pay_student t on t.non_coal_pay_id = a.id and t.del_flag = 0 and t.pay_status = 0
        inner join non_coal_pay_category b on a.id = b.non_coal_pay_id and b.del_flag = 0
        left join non_coal_category c on b.category_id = c.id and c.del_flag = 0
        where a.del_flag = 0
        <if test="payType != null and payType == 2 ">and a.id = #{dataId} and t.pay_type = #{payType}</if>
        <if test="payType != null and payType == 1 ">and t.id = #{dataId} and t.pay_type = #{payType}</if>
    </select>
    <insert id="insertNonCoalPay" parameterType="NonCoalPay" useGeneratedKeys="true" keyProperty="id">
        insert into non_coal_pay
exam-system/src/test/java/TextPay.java
@@ -1,21 +1,16 @@
import com.alibaba.fastjson2.JSONObject;
import com.gkhy.exam.pay.entity.PayReqData;
import com.gkhy.exam.pay.utils.PayUtils;
import com.gkhy.exam.pay.utils.ResultVo;
import com.google.gson.JsonObject;
import com.ruoyi.common.utils.RandomUtil;
import com.ruoyi.common.utils.uuid.UUID;
import lombok.extern.log4j.Log4j2;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@SpringBootTest(classes = TextPay.class)
@ActiveProfiles("dev")
@@ -23,53 +18,49 @@
public class TextPay {
   @Test
   public void paytext() throws IOException {
    @Test
    public void paytext() throws IOException {
       PayReqData payReqData = new PayReqData();
       PayReqData.Feedata feedatas = new PayReqData.Feedata();
        PayReqData payReqData = new PayReqData();
        PayReqData.Feedata feedatas = new PayReqData.Feedata();
       payReqData.setDesc("安全技术考试考务费_煤矿安全作业-001504");
       payReqData.setOrderNo(RandomUtil.generateOrderNumber());
       payReqData.setMoney(BigDecimal.valueOf(103));
       payReqData.setAmount(1);
       payReqData.setPayerName("测试");
       payReqData.setCertNo("411381199801093991");
       payReqData.setPayerType(1);
       payReqData.setInvoiceSocialCode("11650000MB1957293J");
       payReqData.setHandlingPerson("张三");
       payReqData.setChecker("李四");
       payReqData.setEnterCode("680534083");
        payReqData.setDesc("安全技术考试考务费_煤矿安全作业-001504");
        payReqData.setOrderNo(RandomUtil.generateOrderNumber(1L, "CO"));
        payReqData.setMoney(BigDecimal.valueOf(103));
        payReqData.setAmount(1);
        payReqData.setPayerName("测试");
        payReqData.setCertNo("411381199801093991");
        payReqData.setPayerType(1);
        payReqData.setInvoiceSocialCode("11650000MB1957293J");
        payReqData.setHandlingPerson("张三");
        payReqData.setChecker("李四");
        payReqData.setEnterCode("680534083");
       List<PayReqData.Feedata> feedatas1 = new ArrayList<>();
       feedatas.setAmount(1);
       feedatas.setBusCode("DZ001504");
       feedatas.setPrice(BigDecimal.valueOf(103));
       feedatas1.add(feedatas);
       payReqData.setFeeDatas(feedatas1);
        List<PayReqData.Feedata> feedatas1 = new ArrayList<>();
        feedatas.setAmount(1);
        feedatas.setBusCode("DZ001504");
        feedatas.setPrice(BigDecimal.valueOf(103));
        feedatas1.add(feedatas);
        payReqData.setFeeDatas(feedatas1);
       PayUtils payUtils = new PayUtils();
       ResultVo resultVo = payUtils.sendApiPost(payReqData);
       System.out.printf("请求结果:"+resultVo);
        PayUtils payUtils = new PayUtils();
        ResultVo resultVo = payUtils.sendApiPost(payReqData);
        System.out.printf("请求结果:" + resultVo);
   }
    }
   @Test
    public void text001(){
       try {
//           String s = PayUtils.affirmPost("10000001");
           JSONObject query = PayUtils.query("1000001");
       } catch (IOException e) {
           throw new RuntimeException(e);
       }
   }
    @Test
    public void text001() {
//       try {
////           String s = PayUtils.affirmPost("10000001");
//           //JSONObject query = PayUtils.query("1000001");
//       } catch (IOException e) {
//           throw new RuntimeException(e);
//       }
    }
}
ruoyi-admin/src/main/resources/application-dev.yml
@@ -1,132 +1,139 @@
# 开发环境配置
server:
    # 服务器的HTTP端口,默认为8080
    port: 8085
    servlet:
        # 应用的访问路径
        context-path: /api
    tomcat:
        # tomcat的URI编码
        uri-encoding: UTF-8
        # 连接数满后的排队数,默认为100
        accept-count: 1000
        threads:
            # tomcat最大线程数,默认为200
            max: 800
            # Tomcat启动初始化的线程数,默认值10
            min-spare: 100
  # 服务器的HTTP端口,默认为8080
  port: 8085
  servlet:
    # 应用的访问路径
    context-path: /api
  tomcat:
    # tomcat的URI编码
    uri-encoding: UTF-8
    # 连接数满后的排队数,默认为100
    accept-count: 1000
    threads:
      # tomcat最大线程数,默认为200
      max: 800
      # Tomcat启动初始化的线程数,默认值10
      min-spare: 100
# 数据源配置
spring:
    datasource:
        type: com.alibaba.druid.pool.DruidDataSource
        driverClassName: com.mysql.cj.jdbc.Driver
        druid:
            # 主库数据源
            master:
                url: jdbc:mysql://192.168.2.16:7006/swspkmas?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&allowMultiQueries=true
                username: root
                password: 2farwL3yPXfbH2AP
            # 从库数据源
            slave:
                # 从数据源开关/默认关闭
                enabled: false
                url:
                username:
                password:
            # 初始连接数
            initialSize: 5
            # 最小连接池数量
            minIdle: 10
            # 最大连接池数量
            maxActive: 20
            # 配置获取连接等待超时的时间
            maxWait: 60000
            # 配置连接超时时间
            connectTimeout: 30000
            # 配置网络超时时间
            socketTimeout: 60000
            # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
            timeBetweenEvictionRunsMillis: 60000
            # 配置一个连接在池中最小生存的时间,单位是毫秒
            minEvictableIdleTimeMillis: 300000
            # 配置一个连接在池中最大生存的时间,单位是毫秒
            maxEvictableIdleTimeMillis: 900000
            # 配置检测连接是否有效
            validationQuery: SELECT 1 FROM DUAL
            testWhileIdle: true
            testOnBorrow: false
            testOnReturn: false
            webStatFilter:
                enabled: true
            statViewServlet:
                enabled: true
                # 设置白名单,不填则允许所有访问
                allow:
                url-pattern: /druid/*
                # 控制台管理用户名和密码
                login-username: ruoyi
                login-password: 123456
            filter:
                stat:
                    enabled: true
                    # 慢SQL记录
                    log-slow-sql: true
                    slow-sql-millis: 1000
                    merge-sql: true
                wall:
                    config:
                        multi-statement-allow: true
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    druid:
      # 主库数据源
      master:
        url: jdbc:mysql://192.168.2.16:7006/swspkmas?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&allowMultiQueries=true
        username: root
        password: 2farwL3yPXfbH2AP
      # 从库数据源
      slave:
        # 从数据源开关/默认关闭
        enabled: false
        url:
        username:
        password:
      # 初始连接数
      initialSize: 5
      # 最小连接池数量
      minIdle: 10
      # 最大连接池数量
      maxActive: 20
      # 配置获取连接等待超时的时间
      maxWait: 60000
      # 配置连接超时时间
      connectTimeout: 30000
      # 配置网络超时时间
      socketTimeout: 60000
      # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
      timeBetweenEvictionRunsMillis: 60000
      # 配置一个连接在池中最小生存的时间,单位是毫秒
      minEvictableIdleTimeMillis: 300000
      # 配置一个连接在池中最大生存的时间,单位是毫秒
      maxEvictableIdleTimeMillis: 900000
      # 配置检测连接是否有效
      validationQuery: SELECT 1 FROM DUAL
      testWhileIdle: true
      testOnBorrow: false
      testOnReturn: false
      webStatFilter:
        enabled: true
      statViewServlet:
        enabled: true
        # 设置白名单,不填则允许所有访问
        allow:
        url-pattern: /druid/*
        # 控制台管理用户名和密码
        login-username: ruoyi
        login-password: 123456
      filter:
        stat:
          enabled: true
          # 慢SQL记录
          log-slow-sql: true
          slow-sql-millis: 1000
          merge-sql: true
        wall:
          config:
            multi-statement-allow: true
    # redis 配置
    redis:
        # 地址
        host: 192.168.2.16
        # 端口,默认为6379
        port: 6379
        # 数据库索引
        database: 5
        # 密码
#        password: wioowr23923sd3*&
        # 连接超时时间
        timeout: 10s
        lettuce:
            pool:
                # 连接池中的最小空闲连接
                min-idle: 0
                # 连接池中的最大空闲连接
                max-idle: 8
                # 连接池的最大数据库连接数
                max-active: 8
                # #连接池最大阻塞等待时间(使用负值表示没有限制)
                max-wait: -1ms
  # redis 配置
  redis:
    # 地址
    host: 192.168.2.16
    # 端口,默认为6379
    port: 6379
    # 数据库索引
    database: 5
    # 密码
    #    password: wioowr23923sd3*&
    # 连接超时时间
    timeout: 10s
    lettuce:
      pool:
        # 连接池中的最小空闲连接
        min-idle: 0
        # 连接池中的最大空闲连接
        max-idle: 8
        # 连接池的最大数据库连接数
        max-active: 8
        # #连接池最大阻塞等待时间(使用负值表示没有限制)
        max-wait: -1ms
tripartite:
    restSever: https://inspurtestcx.saws.org.cn/sjjh
    appKey: hj92qe
    appPwd: dxep6j
  restSever: https://inspurtestcx.saws.org.cn/sjjh
  appKey: hj92qe
  appPwd: dxep6j
#windous测试
file:
    path:
        #基础路径
        dcPath: upload
        urlRootPath: /uploadfile/
        module:
            #用户模块
            accountPath: /account/
  path:
    #基础路径
    dcPath: upload
    urlRootPath: /uploadfile/
    module:
      #用户模块
      accountPath: /account/
#线程池配置
threadPool:
    corePoolSize: 20
    maxPoolSize: 20
    queueCapacity: 10000
    scheduling:
        #控制线程是否执行 true:执行;false:不执行
        enabled: true
  corePoolSize: 20
  maxPoolSize: 20
  queueCapacity: 10000
  scheduling:
    #控制线程是否执行 true:执行;false:不执行
    enabled: true
# 七牛云相关信息
safecheckqiniuymes:
    accesskey: 5YprpjY0BJiyjII2VqlHed7UhBEvvkPZicbwd8Kl
    secretkey: m3gGQNQ9cLmVBBZwPXZ5-Wzr0duzyAPPmJUx4_ay
    templateid: 1844221365930962944
  accesskey: 5YprpjY0BJiyjII2VqlHed7UhBEvvkPZicbwd8Kl
  secretkey: m3gGQNQ9cLmVBBZwPXZ5-Wzr0duzyAPPmJUx4_ay
  templateid: 1844221365930962944
#财政接口地址及api
finance:
  apiId: ED76A5F1703540BE977D34780B371FEB
  orderUrl: http://finpt.xjcz.gov.cn/fs-service-test/fs-pay/invoice.do
  payNotifyUrl: http://finpt.xjcz.gov.cn/fs-service-test/fs-pay/notifyConfirm.do
  payQueryUrl: http://finpt.xjcz.gov.cn/fs-service/fs-pay/query.do
ruoyi-admin/src/main/resources/application-pro.yml
@@ -1,131 +1,138 @@
# 开发环境配置
server:
    # 服务器的HTTP端口,默认为8080
    port: 8085
    servlet:
        # 应用的访问路径
        context-path: /api
    tomcat:
        # tomcat的URI编码
        uri-encoding: UTF-8
        # 连接数满后的排队数,默认为100
        accept-count: 1000
        threads:
            # tomcat最大线程数,默认为200
            max: 800
            # Tomcat启动初始化的线程数,默认值10
            min-spare: 100
  # 服务器的HTTP端口,默认为8080
  port: 8085
  servlet:
    # 应用的访问路径
    context-path: /api
  tomcat:
    # tomcat的URI编码
    uri-encoding: UTF-8
    # 连接数满后的排队数,默认为100
    accept-count: 1000
    threads:
      # tomcat最大线程数,默认为200
      max: 800
      # Tomcat启动初始化的线程数,默认值10
      min-spare: 100
# 数据源配置
spring:
    datasource:
        type: com.alibaba.druid.pool.DruidDataSource
        driverClassName: com.mysql.cj.jdbc.Driver
        druid:
            # 主库数据源
            master:
                url: jdbc:mysql://127.0.0.1:7006/swspkmas?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&allowMultiQueries=true
                username: root
                password: 2farwL3yPXfbH2AP
            # 从库数据源
            slave:
                # 从数据源开关/默认关闭
                enabled: false
                url:
                username:
                password:
            # 初始连接数
            initialSize: 5
            # 最小连接池数量
            minIdle: 10
            # 最大连接池数量
            maxActive: 20
            # 配置获取连接等待超时的时间
            maxWait: 60000
            # 配置连接超时时间
            connectTimeout: 30000
            # 配置网络超时时间
            socketTimeout: 60000
            # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
            timeBetweenEvictionRunsMillis: 60000
            # 配置一个连接在池中最小生存的时间,单位是毫秒
            minEvictableIdleTimeMillis: 300000
            # 配置一个连接在池中最大生存的时间,单位是毫秒
            maxEvictableIdleTimeMillis: 900000
            # 配置检测连接是否有效
            validationQuery: SELECT 1 FROM DUAL
            testWhileIdle: true
            testOnBorrow: false
            testOnReturn: false
            webStatFilter:
                enabled: true
            statViewServlet:
                enabled: true
                # 设置白名单,不填则允许所有访问
                allow:
                url-pattern: /druid/*
                # 控制台管理用户名和密码
                login-username: ruoyi
                login-password: 123456
            filter:
                stat:
                    enabled: true
                    # 慢SQL记录
                    log-slow-sql: true
                    slow-sql-millis: 1000
                    merge-sql: true
                wall:
                    config:
                        multi-statement-allow: true
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    druid:
      # 主库数据源
      master:
        url: jdbc:mysql://127.0.0.1:7006/swspkmas?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&allowMultiQueries=true
        username: root
        password: 2farwL3yPXfbH2AP
      # 从库数据源
      slave:
        # 从数据源开关/默认关闭
        enabled: false
        url:
        username:
        password:
      # 初始连接数
      initialSize: 5
      # 最小连接池数量
      minIdle: 10
      # 最大连接池数量
      maxActive: 20
      # 配置获取连接等待超时的时间
      maxWait: 60000
      # 配置连接超时时间
      connectTimeout: 30000
      # 配置网络超时时间
      socketTimeout: 60000
      # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
      timeBetweenEvictionRunsMillis: 60000
      # 配置一个连接在池中最小生存的时间,单位是毫秒
      minEvictableIdleTimeMillis: 300000
      # 配置一个连接在池中最大生存的时间,单位是毫秒
      maxEvictableIdleTimeMillis: 900000
      # 配置检测连接是否有效
      validationQuery: SELECT 1 FROM DUAL
      testWhileIdle: true
      testOnBorrow: false
      testOnReturn: false
      webStatFilter:
        enabled: true
      statViewServlet:
        enabled: true
        # 设置白名单,不填则允许所有访问
        allow:
        url-pattern: /druid/*
        # 控制台管理用户名和密码
        login-username: ruoyi
        login-password: 123456
      filter:
        stat:
          enabled: true
          # 慢SQL记录
          log-slow-sql: true
          slow-sql-millis: 1000
          merge-sql: true
        wall:
          config:
            multi-statement-allow: true
    # redis 配置
    redis:
        # 地址
        host: 127.0.0.1
        # 端口,默认为6379
        port: 6379
        # 数据库索引
        database: 5
        # 密码
        password: akj78avauba789a
        # 连接超时时间
        timeout: 10s
        lettuce:
            pool:
                # 连接池中的最小空闲连接
                min-idle: 0
                # 连接池中的最大空闲连接
                max-idle: 8
                # 连接池的最大数据库连接数
                max-active: 8
                # #连接池最大阻塞等待时间(使用负值表示没有限制)
                max-wait: -1ms
  # redis 配置
  redis:
    # 地址
    host: 127.0.0.1
    # 端口,默认为6379
    port: 6379
    # 数据库索引
    database: 5
    # 密码
    password: akj78avauba789a
    # 连接超时时间
    timeout: 10s
    lettuce:
      pool:
        # 连接池中的最小空闲连接
        min-idle: 0
        # 连接池中的最大空闲连接
        max-idle: 8
        # 连接池的最大数据库连接数
        max-active: 8
        # #连接池最大阻塞等待时间(使用负值表示没有限制)
        max-wait: -1ms
tripartite:
    restSever: https://inspurtestcx.saws.org.cn/sjjh
    appKey: hj92qe
    appPwd: dxep6j
  restSever: https://inspurtestcx.saws.org.cn/sjjh
  appKey: hj92qe
  appPwd: dxep6j
#windous测试
file:
    path:
        #基础路径
        dcPath: upload
        urlRootPath: /uploadfile/
        module:
            #用户模块
            accountPath: /account/
  path:
    #基础路径
    dcPath: upload
    urlRootPath: /uploadfile/
    module:
      #用户模块
      accountPath: /account/
#线程池配置
threadPool:
    corePoolSize: 20
    maxPoolSize: 20
    queueCapacity: 10000
    scheduling:
        #控制线程是否执行 true:执行;false:不执行
        enabled: true
  corePoolSize: 20
  maxPoolSize: 20
  queueCapacity: 10000
  scheduling:
    #控制线程是否执行 true:执行;false:不执行
    enabled: true
# 七牛云相关信息
safecheckqiniuymes:
    accesskey: 5YprpjY0BJiyjII2VqlHed7UhBEvvkPZicbwd8Kl
    secretkey: m3gGQNQ9cLmVBBZwPXZ5-Wzr0duzyAPPmJUx4_ay
    templateid: 1844221365930962944
  accesskey: 5YprpjY0BJiyjII2VqlHed7UhBEvvkPZicbwd8Kl
  secretkey: m3gGQNQ9cLmVBBZwPXZ5-Wzr0duzyAPPmJUx4_ay
  templateid: 1844221365930962944
finance:
  apiId: ED76A5F1703540BE977D34780B371FEB
  orderUrl: http://finpt.xjcz.gov.cn/fs-service/fs-pay/invoice.do
  payNotifyUrl: http://finpt.xjcz.gov.cn/fs-service/fs-pay/notifyConfirm.do
  payQueryUrl: http://finpt.xjcz.gov.cn/fs-service-test/fs-pay/query.do
ruoyi-common/src/main/java/com/ruoyi/common/config/RedissonConfig.java
对比新文件
@@ -0,0 +1,29 @@
package com.ruoyi.common.config;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RedissonConfig {
    @Value("${spring.redis.host}")
    private String host;
    @Value("${spring.redis.port}")
    private String port;
//    @Value("${spring.redis.password}")
//    private String password;
    @Bean(destroyMethod = "shutdown")
    @ConditionalOnMissingBean(RedissonClient.class)
    public RedissonClient redissonClient() {
        Config config = new Config();
        config.useSingleServer().setAddress("redis://" + host + ":" + port); // 更多.set
        return Redisson.create(config);
    }
}
ruoyi-common/src/main/java/com/ruoyi/common/utils/RandomUtil.java
@@ -35,20 +35,20 @@
    public static void main(String[] args) {
        String s = generateRandomString(26);
        System.out.println(s);
        System.out.println(generateOrderNumber());
        System.out.println(generateOrderNumber(10L, "NC"));
    }
    private static final Random RANDOM = new Random();
    private static final AtomicInteger SEQUENCE = new AtomicInteger(0);
    private static final int MAX_SEQUENCE = 99999;// 5位数的序列号
    private static final String ORDER_PER = "SN";
    public static synchronized String generateOrderNumber() {
    public static String generateOrderNumber(Long dataId, String orderType) {
        String datePart = new SimpleDateFormat("yyyyMMddhhmm").format(new Date());
        int sequencePart = SEQUENCE.getAndIncrement() % MAX_SEQUENCE;
        String sequenceStr = String.format("%05d", sequencePart); // 保证序列号是5位数,不足的前面补0
        int randomPart = RANDOM.nextInt(90000) + 10000; // 生成5位随机数
        return ORDER_PER + datePart + sequenceStr;
        return ORDER_PER + datePart + String.format("%05d", randomPart) + dataId;
    }
}
ruoyi-common/src/main/java/com/ruoyi/common/utils/RedisLock.java
对比新文件
@@ -0,0 +1,98 @@
package com.ruoyi.common.utils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
@Component
public class RedisLock {
    @Autowired
    private RedissonClient redissonClient;
    /**
     * 获取锁
     *
     * @param lockKey 锁实例key
     * @return 锁信息
     */
    public RLock getRLock(String lockKey) {
        return redissonClient.getLock(lockKey);
    }
    /**
     * 加锁
     *
     * @param lockKey 锁实例key
     * @return 锁信息
     */
    public RLock lock(String lockKey) {
        RLock lock = getRLock(lockKey);
        lock.lock();
        return lock;
    }
    /**
     * 加锁
     *
     * @param lockKey   锁实例key
     * @param leaseTime 上锁后自动释放锁时间
     * @return true=成功;false=失败
     */
    public Boolean tryLock(String lockKey, long leaseTime) {
        return tryLock(lockKey, 0, leaseTime, TimeUnit.SECONDS);
    }
    /**
     * 加锁
     *
     * @param lockKey   锁实例key
     * @param leaseTime 上锁后自动释放锁时间
     * @param unit      时间颗粒度
     * @return true=加锁成功;false=加锁失败
     */
    public Boolean tryLock(String lockKey, long leaseTime, TimeUnit unit) {
        return tryLock(lockKey, 0, leaseTime, unit);
    }
    /**
     * 加锁
     *
     * @param lockKey   锁实例key
     * @param waitTime  最多等待时间
     * @param leaseTime 上锁后自动释放锁时间
     * @param unit      时间颗粒度
     * @return true=加锁成功;false=加锁失败
     */
    public Boolean tryLock(String lockKey, long waitTime, long leaseTime, TimeUnit unit) {
        RLock rLock = getRLock(lockKey);
        boolean tryLock = false;
        try {
            tryLock = rLock.tryLock(waitTime, leaseTime, unit);
        } catch (InterruptedException e) {
            return false;
        }
        return tryLock;
    }
    /**
     * 释放锁
     *
     * @param lockKey 锁实例key
     */
    public void unlock(String lockKey) {
        RLock lock = getRLock(lockKey);
        lock.unlock();
    }
    /**
     * 释放锁
     *
     * @param lock 锁信息
     */
    public void unlock(RLock lock) {
        lock.unlock();
    }
}