无关风月
2025-03-06 41e05da9a811cd9394ce9bddf5edcb7cde58db06
Merge branch 'master' of https://gitee.com/xiaochen991015/xizang
8个文件已添加
22个文件已修改
2260 ■■■■■ 已修改文件
bankapi/src/main/java/com/taxi591/bankapi/dto/QueryBillRequest.java 317 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
bankapi/src/main/java/com/taxi591/bankapi/dto/QueryBillResponse.java 1027 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/pom.xml 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/BankOutController.java 190 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/COSController.java 155 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/SysFileController.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TContractController.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/PdfUtils.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/TencentCosUtil.java 215 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/WordUtil.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/core/config/FileUploaderConfig.java 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/resources/application-prod.yml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/resources/application-test.yml 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/TInformationController.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-applet/src/main/resources/application-test.yml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/config/FileUploadConfig.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/TokenService.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysFileMapper.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/model/TContract.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/model/TFile.java 81 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/SysFileService.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysFileServiceImpl.java 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TBillServiceImpl.java 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TContractServiceImpl.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TFlowManagementServiceImpl.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TPayOrderServiceImpl.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/resources/mapper/system/TBankFlowMapper.xml 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/resources/mapper/system/TBillMapper.xml 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/resources/mapper/system/TFlowManagementMapper.xml 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
bankapi/src/main/java/com/taxi591/bankapi/dto/QueryBillRequest.java
New file
@@ -0,0 +1,317 @@
package com.taxi591.bankapi.dto;
import com.alibaba.fastjson2.annotation.JSONField;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import java.io.Serializable;
/**
 *  直连商户平台账单查询输入对象,需要转换成json串发送给第三方系统
 *  @author DELL
 *
 */
@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
public class QueryBillRequest implements Serializable {
    private static final long serialVersionUID = 1L;
    /** 格式 */
    @JSONField(name = "format")
    private String format;
    /** 消息 */
    @JSONField(name = "message")
    private Message message;
    @Override
    public String toString() {
        return "QueryBillRequest[format=" + format + ",message=" + message.toString() + "]";
    }
    public String getFormat() {
        return format;
    }
    @JSONField(name = "format")
    public void setFormat(String format) {
        this.format = format;
    }
    public Message getMessage() {
        return message;
    }
    @JSONField(name = "message")
    public void setMessage(Message message) {
        this.message = message;
    }
    /**
     *
     * 账单查询内部消息对象实体message内部类
     *
     */
    @JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
    public class Message implements Serializable {
        private static final long serialVersionUID = 1L;
        /** 消息头部 */
        @JSONField(name = "head")
        private Head head;
        /** 消息体  */
        @JSONField(name = "info")
        private Info info;
        @Override
        public String toString() {
            return "QueryBillRequest.Message[head=" + head.toString() + ",info=" + info.toString() + "]";
        }
        public Head getHead() {
            return head;
        }
        @JSONField(name = "head")
        public void setHead(Head head) {
            this.head = head;
        }
        public Info getInfo() {
            return info;
        }
        @JSONField(name = "info")
        public void setInfo(Info info) {
            this.info = info;
        }
        /**
         *  message子对象head消息头内部类
         */
        @JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
        public class Head implements Serializable {
            private static final long serialVersionUID = 1L;
            /**  渠道编码 */
            @JSONField(name = "channel")
            private String channel;
            /**  交易码  */
            @JSONField(name = "transCode")
            private String transCode;
            /**  交易上行下送标志位  */
            @JSONField(name = "transFlag")
            private String transFlag;
            /**  缴费中心交易序列号 */
            @JSONField(name = "transSeqNum")
            private String transSeqNum;
            /**   时间戳  */
            @JSONField(name = "timeStamp")
            private String timeStamp;
            /**   4为分行iGoal码  */
            @JSONField(name = "branchCode")
            private String branchCode;
            @Override
            public String toString() {
                return "QueryBillRequest.Message.Head[channel=" + channel +",transCode=" + transCode +
                        ",transFlag=" + transFlag + ",transSeqNum=" + transSeqNum + ",timestamp=" + timeStamp + ",branchCode=" + branchCode + "]";
            }
            public String getChannel() {
                return channel;
            }
            @JSONField(name = "channel")
            public void setChannel(String channel) {
                this.channel = channel;
            }
            public String getTransFlag() {
                return transFlag;
            }
            @JSONField(name = "transFlag")
            public void setTransFlag(String transFlag) {
                this.transFlag = transFlag;
            }
            public String getTransCode() {
                return transCode;
            }
            @JSONField(name = "transCode")
            public void setTransCode(String transCode) {
                this.transCode = transCode;
            }
            public String getTransSeqNum() {
                return transSeqNum;
            }
            @JSONField(name = "transSeqNum")
            public void setTransSeqNum(String transSeqNum) {
                this.transSeqNum = transSeqNum;
            }
            public String getTimeStamp() {
                return timeStamp;
            }
            @JSONField(name = "timeStamp")
            public void setTimeStamp(String timeStamp) {
                this.timeStamp = timeStamp;
            }
            public String getBranchCode() {
                return branchCode;
            }
            @JSONField(name = "branchCode")
            public void setBranchCode(String branchCode) {
                this.branchCode = branchCode;
            }
        }
        /**
         * message子对象info消息实体内部类
         */
        @JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
        public class Info implements Serializable {
            private static final long serialVersionUID = 1L;
            /** 缴费项目编号*/
            @JSONField(name = "epayCode")
            private String epayCode;
            /** 第三方商户编号*/
            @JSONField(name = "merchantId")
            private String merchantId;
            /** 输入要素1*/
            @JSONField(name = "input1")
            private String input1;
            /** 输入要素2*/
            @JSONField(name = "input2")
            private String input2;
            /** 输入要素3*/
            @JSONField(name = "input3")
            private String input3;
            /** 输入要素4*/
            @JSONField(name = "input4")
            private String input4;
            /** 输入要素5*/
            @JSONField(name = "input5")
            private String input5;
            /** 16位客户号*/
            @JSONField(name = "userId")
            private String userId;
            /** 缴费中心流水号*/
            @JSONField(name = "traceNo")
            private String traceNo;
            @Override
            public String toString() {
                return "QueryBillRequest.Message.Info[epayCode=" + epayCode + ",merchantId=" + merchantId +
                        ",input1=" + input1 + ",input2=" + input2 + ",input3=" + input3 + ",input4=" + input4 + ",input5=" + input5 +
                        ",userId=" + userId + ",traceNo=" + traceNo + "]";
            }
            public String getEpayCode() {
                return epayCode;
            }
            @JSONField(name = "epayCode")
            public void setEpayCode(String epayCode) {
                this.epayCode = epayCode;
            }
            public String getMerchantId() {
                return merchantId;
            }
            @JSONField(name = "merchantId")
            public void setMerchantId(String merchantId) {
                this.merchantId = merchantId;
            }
            public String getInput1() {
                return input1;
            }
            @JSONField(name = "input1")
            public void setInput1(String input1) {
                this.input1 = input1;
            }
            public String getInput2() {
                return input2;
            }
            @JSONField(name = "input2")
            public void setInput2(String input2) {
                this.input2 = input2;
            }
            public String getInput3() {
                return input3;
            }
            @JSONField(name = "input3")
            public void setInput3(String input3) {
                this.input3 = input3;
            }
            public String getInput4() {
                return input4;
            }
            @JSONField(name = "input4")
            public void setInput4(String input4) {
                this.input4 = input4;
            }
            public String getInput5() {
                return input5;
            }
            @JSONField(name = "input5")
            public void setInput5(String input5) {
                this.input5 = input5;
            }
            public String getUserId() {
                return userId;
            }
            @JSONField(name = "userId")
            public void setUserId(String userId) {
                this.userId = userId;
            }
            public String getTraceNo() {
                return traceNo;
            }
            @JSONField(name = "traceNo")
            public void setTraceNo(String traceNo) {
                this.traceNo = traceNo;
            }
        }
    }
}
bankapi/src/main/java/com/taxi591/bankapi/dto/QueryBillResponse.java
New file
@@ -0,0 +1,1027 @@
package com.taxi591.bankapi.dto;
import com.alibaba.fastjson2.annotation.JSONField;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import java.io.Serializable;
import java.util.ArrayList;
/**
 *  直连商户平台账单查询返回对象
 *  @author DELL
 *
 */
@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
public class QueryBillResponse implements Serializable {
    private static final long serialVersionUID = 1L;
    /** 格式 */
    @JSONField(name = "format")
    private String format;
    /** 消息体 */
    @JSONField(name = "message")
    private Message message;
    public QueryBillResponse(){
    }
    /**
     * 构造函数,通过输入对象,构造返回对象数据信息
     * @param request
     */
    public QueryBillResponse(QueryBillRequest request) {
        this.setFormat(request.getFormat());
        this.setMessage(new Message(request.getMessage()));
    }
    @Override
    public String toString() {
        return "QueryBillResponse[format=" + format + ",message=" + message==null?"":message.toString() + "]";
    }
    public String getFormat() {
        return format;
    }
    @JSONField(name = "format")
    public void setFormat(String format) {
        this.format = format;
    }
    public Message getMessage() {
        return message;
    }
    @JSONField(name = "message")
    public void setMessage(Message message) {
        this.message = message;
    }
    /**
     *
     * 账单查询内部消息对象返回实体message内部类
     *
     */
    @JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
    public class Message implements Serializable {
        private static final long serialVersionUID = 1L;
        /** 消息头部 */
        @JSONField(name = "head")
        private Head head;
        /** 消息实体  */
        @JSONField(name = "info")
        private Info info;
        public Message() {
            this.head = new Head();
            this.info = new Info();
        }
        public Message(QueryBillRequest.Message requestMessage){
            this.setHead(new Head(requestMessage.getHead()));
            this.setInfo(new Info(requestMessage.getInfo()));
        }
        @Override
        public String toString() {
            return "QueryBillResponse.Message[head=" + head.toString() + ",info=" + info.toString() + "]";
        }
        public Head getHead() {
            return head;
        }
        @JSONField(name = "head")
        public void setHead(Head head) {
            this.head = head;
        }
        public Info getInfo() {
            return info;
        }
        @JSONField(name = "info")
        public void setInfo(Info info) {
            this.info = info;
        }
        /**
         *
         * 账单查询内部消息对象返回实体Head内部类
         *
         */
        @JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
        public class Head implements Serializable {
            private static final long serialVersionUID = 1L;
            /**  渠道 */
            @JSONField(name = "channel")
            private String channel;
            /**  交易码  */
            @JSONField(name = "transCode")
            private String transCode;
            /**  交易上行下送标志  */
            @JSONField(name = "transFlag")
            private String transFlag;
            /**  缴费中心交易序列号 */
            @JSONField(name = "transSeqNum")
            private String transSeqNum;
            /** 时间戳  */
            @JSONField(name = "timeStamp")
            private String timeStamp;
            /**  查询返回码 */
            @JSONField(name = "returnCode")
            private String returnCode ;
            /**  返回提示信息  */
            @JSONField(name = "returnMessage")
            private String returnMessage;
            public Head(QueryBillRequest.Message.Head reqMessHead) {
                this.setChannel(reqMessHead.getChannel());
                this.setTransSeqNum(reqMessHead.getTransSeqNum());
                this.setTransCode(reqMessHead.getTransCode());
                this.setReturnCode("");
                this.setReturnMessage("");
                this.setTimeStamp("");
            }
            public Head() {
            }
            @Override
            public String toString() {
                return "QueryBillResponse.Message.Head[channel=" + channel  + ",transCode=" + transCode + ",transSeqNum=" + transSeqNum
                        + ",timeStamp=" + timeStamp + ",returnCode=" + returnCode + ",returnMessage=" + returnMessage  + "]";
            }
            public String getChannel() {
                return channel;
            }
            public String getTransCode() {
                return transCode;
            }
            @JSONField(name = "transCode")
            public void setTransCode(String transCode) {
                this.transCode = transCode;
            }
            public String getTransFlag() {
                return transFlag;
            }
            @JSONField(name = "transFlag")
            public void setTransFlag(String transFlag) {
                this.transFlag = transFlag;
            }
            @JSONField(name = "channel")
            public void setChannel(String channel) {
                this.channel = channel;
            }
            public String getTransSeqNum() {
                return transSeqNum;
            }
            @JSONField(name = "transSeqNum")
            public void setTransSeqNum(String transSeqNum) {
                this.transSeqNum = transSeqNum;
            }
            public String getTimeStamp() {
                return timeStamp;
            }
            @JSONField(name = "timestamp")
            public void setTimeStamp(String timeStamp) {
                this.timeStamp = timeStamp;
            }
            public String getReturnCode() {
                return returnCode;
            }
            @JSONField(name = "returnCode")
            public void setReturnCode(String returnCode) {
                this.returnCode = returnCode;
            }
            public String getReturnMessage() {
                return returnMessage;
            }
            @JSONField(name = "returnMessage")
            public void setReturnMessage(String returnMessage) {
                this.returnMessage = returnMessage;
            }
        }
        /**
         *
         * 账单查询内部消息对象返回实体Info内部类
         *
         */
        @JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
        public class Info implements Serializable {
            private static final long serialVersionUID = 1L;
            /** 缴费项目唯一标识号*/
            @JSONField(name = "epayCode")
            private String epayCode;
            /** 直连商户第三方商户号*/
            @JSONField(name = "merchantId")
            private String merchantId;
            /** 缴费中心流水号*/
            @JSONField(name = "traceNo")
            private String traceNo;
            /** 输入要素1*/
            @JSONField(name = "input1")
            private String input1;
            /** 输入要素2*/
            @JSONField(name = "input2")
            private String input2;
            /** 输入要素3*/
            @JSONField(name = "input3")
            private String input3;
            /** 输入要素4*/
            @JSONField(name = "input4")
            private String input4;
            /** 输入要素5*/
            @JSONField(name = "input5")
            private String input5;
            /** 户主名称*/
            @JSONField(name = "custName")
            private String custName;
            /** 户主地址*/
            @JSONField(name = "custAddress")
            private String custAddress;
            /** 账单关联客户手机号,部分项目可根据该字段,要求客户做短信验证码校验后才显示账单结果*/
            @JSONField(name = "cellPhone")
            private String cellPhone;
            /** 缓存域信息*/
            @JSONField(name = "cacheMem")
            private String cacheMem;
            /** 备注字段*/
            @JSONField(name = "remark")
            private String remark;
            /** 跳转商户地址*/
            @JSONField(name = "callBackUrl")
            private String callBackUrl;
            /** 跳转商户地址超链接提示*/
            @JSONField(name = "callBackText")
            private String callBackText;
            /** 缴费金额计算规则*/
            @JSONField(name = "amtRule")
            private String amtRule;
            /** 子账单数量*/
            @JSONField(name = "totalBillCount")
            private String totalBillCount;
            /** 定制附言信息(有定制电子回单附言信息的,需添加自定义定制附言信息字段)*/
            @JSONField(name = "merchantRemark")
            private String merchantRemark;
            /** 账单信息体*/
            @JSONField(name = "bills")
            private ArrayList<Bill> bills;
            public Info() {
            }
            public Info(QueryBillRequest.Message.Info reqMessInfo) {
                this.setEpayCode(reqMessInfo.getEpayCode());
                this.setInput1(reqMessInfo.getInput1());
                this.setInput2(reqMessInfo.getInput2());
                this.setInput3(reqMessInfo.getInput3());
                this.setInput4(reqMessInfo.getInput4());
                this.setInput5(reqMessInfo.getInput5());
                this.bills = new ArrayList<Bill>();
            }
            /**
             * @return the merchantRemark
             */
            public String getMerchantRemark() {
                return merchantRemark;
            }
            /**
             * @param merchantRemark the merchantRemark to set
             */
            @JSONField(name = "merchantRemark")
            public void setMerchantRemark(String merchantRemark) {
                this.merchantRemark = merchantRemark;
            }
            @Override
            public String toString() {
                return "QueryBillResponse.Message.Info[epayCode=" + epayCode + ", input1="
                        + input1 + ", input2=" + input2 + ", input3=" + input3
                        + ", input4=" + input4 + ", input5=" + input5
                        + ", totalBillCount=" + totalBillCount + ",merchantRemark="
                        + merchantRemark + ", bills=" + bills.toString() + "]";
            }
            public String getEpayCode() {
                return epayCode;
            }
            @JSONField(name = "epayCode")
            public void setEpayCode(String epayCode) {
                this.epayCode = epayCode;
            }
            public String getMerchantId() {
                return merchantId;
            }
            @JSONField(name = "merchantId")
            public void setMerchantId(String merchantId) {
                this.merchantId = merchantId;
            }
            public String getTraceNo() {
                return traceNo;
            }
            @JSONField(name = "traceNo")
            public void setTraceNo(String traceNo) {
                this.traceNo = traceNo;
            }
            public String getInput1() {
                return input1;
            }
            @JSONField(name = "input1")
            public void setInput1(String input1) {
                this.input1 = input1;
            }
            public String getInput2() {
                return input2;
            }
            @JSONField(name = "input2")
            public void setInput2(String input2) {
                this.input2 = input2;
            }
            public String getInput3() {
                return input3;
            }
            @JSONField(name = "input3")
            public void setInput3(String input3) {
                this.input3 = input3;
            }
            public String getInput4() {
                return input4;
            }
            @JSONField(name = "input4")
            public void setInput4(String input4) {
                this.input4 = input4;
            }
            public String getInput5() {
                return input5;
            }
            @JSONField(name = "input5")
            public void setInput5(String input5) {
                this.input5 = input5;
            }
            public String getCustName() {
                return custName;
            }
            @JSONField(name = "custName")
            public void setCustName(String custName) {
                this.custName = custName;
            }
            public String getCustAddress() {
                return custAddress;
            }
            @JSONField(name = "custAddress")
            public void setCustAddress(String custAddress) {
                this.custAddress = custAddress;
            }
            public String getCellPhone() {
                return cellPhone;
            }
            @JSONField(name = "cellPhone")
            public void setCellPhone(String cellPhone) {
                this.cellPhone = cellPhone;
            }
            public String getCacheMem() {
                return cacheMem;
            }
            @JSONField(name = "cacheMem")
            public void setCacheMem(String cacheMem) {
                this.cacheMem = cacheMem;
            }
            public String getRemark() {
                return remark;
            }
            @JSONField(name = "remark")
            public void setRemark(String remark) {
                this.remark = remark;
            }
            public String getCallBackUrl() {
                return callBackUrl;
            }
            @JSONField(name = "callBackUrl")
            public void setCallBackUrl(String callBackUrl) {
                this.callBackUrl = callBackUrl;
            }
            public String getCallBackText() {
                return callBackText;
            }
            @JSONField(name = "callBackText")
            public void setCallBackText(String callBackText) {
                this.callBackText = callBackText;
            }
            public String getAmtRule() {
                return amtRule;
            }
            @JSONField(name = "amtRule")
            public void setAmtRule(String amtRule) {
                this.amtRule = amtRule;
            }
            public String getTotalBillCount() {
                return totalBillCount;
            }
            @JSONField(name = "totalBillCount")
            public void setTotalBillCount(String totalBillCount) {
                this.totalBillCount = totalBillCount;
            }
            public ArrayList<Bill> getBills() {
                return bills;
            }
            /**
             *  @param bills
             *  设置账单循环域子账单
             */
            @JSONField(name = "bills")
            public void setBill(ArrayList<Bill> bills) {
                this.bills = bills;
            }
            /**
             *
             * 账单查询内部消息对象返回实体Bill内部类
             *
             */
            @JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
            public class Bill implements Serializable {
                private static final long serialVersionUID = 1L;
                /** 账单编号*/
                @JSONField(name = "billNo")
                private String billNo;
                /** 账单名称*/
                @JSONField(name = "billName")
                private String billName;
                /** 欠费金额*/
                @JSONField(name = "oweAmt")
                private String oweAmt;
                /** 手续费*/
                @JSONField(name = "feeAmt")
                private String feeAmt;
                /** 最小金额*/
                @JSONField(name = "minAmt")
                private String minAmt;
                /** 最大金额*/
                @JSONField(name = "maxAmt")
                private String maxAmt;
                /** 余额*/
                @JSONField(name = "balance")
                private String balance;
                /** 缴费账单到期日*/
                @JSONField(name = "expireDate")
                private String expireDate;
                /** 收款商户号*/
                @JSONField(name = "rcvMerchantId")
                private String rcvMerchantId;
                /** 收款账号*/
                @JSONField(name = "rcvAcc")
                private String rcvAcc;
                /** 分账模板号*/
                @JSONField(name = "tempSplitAcc")
                private String tempSplitAcc;
                /** 均匀时段缴费 */
                @JSONField(name = "unitDetail")
                private UnitDetail unitDetail;
                /** 选择套餐*/
                @JSONField(name = "optionDetails")
                private ArrayList<OptionDetail> optionDetails;
                /** 账单详情描述*/
                @JSONField(name = "descDetails")
                private ArrayList<DescDetail> descDetails;
                /** 平台商户分账子商户循环域 */
                @JSONField(name = "splitSubMerInfos")
                private ArrayList<SplitSubMerInfo> splitSubMerInfos;
                /** 子账单必缴标志,多账单合并支付时默认选中不可不选  true:必选    false:非必选 */
                @JSONField(name = "mustPayFlag")
                private String mustPayFlag;
                /**
                 * @return
                 */
                public String getMustPayFlag() {
                    return mustPayFlag;
                }
                /**
                 * @param mustPayFlag
                 */
                @JSONField(name = "mustPayFlag")
                public void setMustPayFlag(String mustPayFlag) {
                    this.mustPayFlag = mustPayFlag;
                }
                /**
                 * @return
                 */
                public String getTempSplitAcc() {
                    return tempSplitAcc;
                }
                /**
                 * 获取平台商户分账子商户循环域信息
                 * @return
                 */
                public ArrayList<SplitSubMerInfo> getSplitSubMerInfos() {
                    return splitSubMerInfos;
                }
                /**
                 * 设置平台商户分账子商户循环域信息
                 * @param splitSubMerInfos
                 */
                @JSONField(name = "splitSubMerInfos")
                public void setSplitSubMerInfos(ArrayList<SplitSubMerInfo> splitSubMerInfos) {
                    this.splitSubMerInfos = splitSubMerInfos;
                }
                public Bill() {
                }
                @Override
                public String toString() {
                    return "Bill [billNo=" + billNo + ", billName=" + billName
                            + ", oweAmt=" + oweAmt + ", feeAmt=" + feeAmt
                            + ", minAmt=" + minAmt + ", maxAmt=" + maxAmt
                            + ", balance=" + balance + ", expireDate="
                            + expireDate + ", rcvMerchantId=" + rcvMerchantId
                            + ", rcvAcc=" + rcvAcc + ", tempSplitAcc="
                            + tempSplitAcc + ", unitDetail=" + unitDetail
                            + ", optionDetails=" + optionDetails
                            + ", descDetails=" + descDetails
                            + ", splitSubMerInfos=" + splitSubMerInfos
                            + ", mustPayFlag=" + mustPayFlag + "]";
                }
                public String getBillNo() {
                    return billNo;
                }
                @JSONField(name = "billNo")
                public void setBillNo(String billNo) {
                    this.billNo = billNo;
                }
                public String getBillName() {
                    return billName;
                }
                @JSONField(name = "billName")
                public void setBillName(String billName) {
                    this.billName = billName;
                }
                public String getOweAmt() {
                    return oweAmt;
                }
                @JSONField(name = "oweAmt")
                public void setOweAmt(String oweAmt) {
                    this.oweAmt = oweAmt;
                }
                public String getFeeAmt() {
                    return feeAmt;
                }
                @JSONField(name = "feeAmt")
                public void setFeeAmt(String feeAmt) {
                    this.feeAmt = feeAmt;
                }
                public String getMinAmt() {
                    return minAmt;
                }
                @JSONField(name = "minAmt")
                public void setMinAmt(String minAmt) {
                    this.minAmt = minAmt;
                }
                public String getMaxAmt() {
                    return maxAmt;
                }
                @JSONField(name = "maxAmt")
                public void setMaxAmt(String maxAmt) {
                    this.maxAmt = maxAmt;
                }
                public String getBalance() {
                    return balance;
                }
                @JSONField(name = "balance")
                public void setBalance(String balance) {
                    this.balance = balance;
                }
                public String getExpireDate() {
                    return expireDate;
                }
                @JSONField(name = "expireDate")
                public void setExpireDate(String expireDate) {
                    this.expireDate = expireDate;
                }
                public String getRcvMerchantId() {
                    return rcvMerchantId;
                }
                @JSONField(name = "rcvMerchantId")
                public void setRcvMerchantId(String rcvMerchantId) {
                    this.rcvMerchantId = rcvMerchantId;
                }
                public String getRcvAcc() {
                    return rcvAcc;
                }
                @JSONField(name = "rcvAcc")
                public void setRcvAcc(String rcvAcc) {
                    this.rcvAcc = rcvAcc;
                }
                /**
                 * 分账模板号
                 * @return
                 */
                public String getTmpSplitAcc() {
                    return tempSplitAcc;
                }
                @JSONField(name = "tempSplitAcc")
                public void setTempSplitAcc(String tempSplitAcc) {
                    this.tempSplitAcc = tempSplitAcc;
                }
                public UnitDetail getUnitDetail() {
                    return unitDetail;
                }
                @JSONField(name = "unitDetail")
                public void setUnitDetail(UnitDetail unitDetail) {
                    this.unitDetail = unitDetail;
                }
                public ArrayList<DescDetail> getDescDetails() {
                    return descDetails;
                }
                /**
                 *  设置账单描述详情键值对
                 *  @param feeDetails
                 */
                @JSONField(name = "descDetails")
                public void setDescDetails(ArrayList<DescDetail> descDetails) {
                    this.descDetails = descDetails;
                }
                public ArrayList<OptionDetail> getOptionDetails() {
                    return optionDetails;
                }
                @JSONField(name = "optionDetails")
                public void setOptionDetails(ArrayList<OptionDetail> optionDetails) {
                    this.optionDetails = optionDetails;
                }
                /**
                 * 均匀时段
                 *
                 * @date 2017年12月21日
                 */
                @JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
                public class UnitDetail implements Serializable {
                    private static final long serialVersionUID = 1L;
                    /** 单位名称 */
                    @JSONField(name = "unitName")
                    private String unitName;
                    /** 单位金额 */
                    @JSONField(name = "unitAmount")
                    private String unitAmount;
                    /** 最小单位数量 */
                    @JSONField(name = "minUnitNum")
                    private String minUnitNum;
                    public UnitDetail(){}
                    public UnitDetail(String unitName, String unitAmount, String minUnitNum) {
                        super();
                        this.unitName = unitName;
                        this.unitAmount = unitAmount;
                        this.minUnitNum = minUnitNum;
                    }
                    public String getUnitName() {
                        return unitName;
                    }
                    @JSONField(name = "unitAmount")
                    public void setUnitName(String unitName) {
                        this.unitName = unitName;
                    }
                    public String getUnitAmount() {
                        return unitAmount;
                    }
                    @JSONField(name = "unitAmount")
                    public void setUnitAmount(String unitAmount) {
                        this.unitAmount = unitAmount;
                    }
                    public String getMinUnitNum() {
                        return minUnitNum;
                    }
                    @JSONField(name = "minUnitNum")
                    public void setMinUnitNum(String minUnitNum) {
                        this.minUnitNum = minUnitNum;
                    }
                    @Override
                    public String toString() {
                        return "QueryBillResponse.Message.Info.Bill.unitDetail[unitName=" + unitName
                                + ", unitAmount=" + unitAmount + ", minUnitNum=" + minUnitNum + "]";
                    }
                }
                /**
                 * @title 选择套餐循环
                 *
                 *  @date 2017-12-18
                 *
                 *
                 */
                @JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
                public class OptionDetail implements Serializable {
                    private static final long serialVersionUID = 1L;
                    /**套餐编号 根据编号排序*/
                    @JSONField(name = "optionCode")
                    private String optionCode;
                    /**套餐名称*/
                    @JSONField(name = "optionName")
                    private String optionName;
                    /**套餐金额*/
                    @JSONField(name = "optionAmt")
                    private String optionAmt;
                    public OptionDetail(){
                    }
                    public OptionDetail(String optionCode, String optionName, String optionAmt) {
                        super();
                        this.optionCode = optionCode;
                        this.optionName = optionName;
                        this.optionAmt = optionAmt;
                    }
                    public String getOptionCode() {
                        return optionCode;
                    }
                    @JSONField(name = "optionCode")
                    public void setOptionCode(String optionCode) {
                        this.optionCode = optionCode;
                    }
                    public String getOptionName() {
                        return optionName;
                    }
                    @JSONField(name = "optionName")
                    public void setOptionName(String optionName) {
                        this.optionName = optionName;
                    }
                    public String getOptionAmt() {
                        return optionAmt;
                    }
                    @JSONField(name = "optionAmt")
                    public void setOptionAmt(String optionAmt) {
                        this.optionAmt = optionAmt;
                    }
                    @Override
                    public String toString() {
                        return "QueryBillResponse.Message.Info.Bill.OptionDetail[optionCode=" + optionCode
                                + ", optionName=" + optionName + ", optionAmt=" + optionAmt + "]";
                    }
                }
                /**
                 * @title 账单详情
                 *
                 *  @date 2017-12-18
                 */
                @JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
                public class DescDetail implements Serializable {
                    private static final long serialVersionUID = 1L;
                    /**账单详情-名称*/
                    @JSONField(name = "sCpt")
                    private String sCpt;
                    /**账单详情-取值*/
                    @JSONField(name = "sVal")
                    private String sVal;
                    public DescDetail(){
                    }
                    public DescDetail(String sCpt, String sVal) {
                        super();
                        this.sCpt = sCpt;
                        this.sVal = sVal;
                    }
                    public String getSCpt() {
                        return sCpt;
                    }
                    @JSONField(name = "sCpt")
                    public void setSCpt(String sCpt) {
                        this.sCpt = sCpt;
                    }
                    public String getSVal() {
                        return sVal;
                    }
                    @JSONField(name = "sVal")
                    public void setSVal(String sVal) {
                        this.sVal = sVal;
                    }
                    @Override
                    public String toString() {
                        return "QueryBillResponse.Message.Info.Bill.FeeDetail[sCpt=" + sCpt + ",sVal=" + sVal + "]";
                    }
                }
                /**
                 * @title 平台商户分账子商户循环域
                 *
                 * @date 2020-10-22
                 *
                 * @author marui
                 */
                @JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
                public class SplitSubMerInfo implements Serializable {
                    private static final long serialVersionUID = 1L;
                    /**二级子商户号*/
                    @JSONField(name = "splitMerchantId")
                    private String splitMerchantId;
                    /**二级子商户分账金额*/
                    @JSONField(name = "splitAmount")
                    private String splitAmount;
                    public SplitSubMerInfo(){
                    }
                    public SplitSubMerInfo(String splitMerchantId, String splitAmount) {
                        super();
                        this.splitMerchantId = splitMerchantId;
                        this.splitAmount = splitAmount;
                    }
                    public String getSplitMerchantId() {
                        return splitMerchantId;
                    }
                    @JSONField(name = "splitMerchantId")
                    public void setSplitMerchantId(String splitMerchantId) {
                        this.splitMerchantId = splitMerchantId;
                    }
                    public String getSplitAmount() {
                        return splitAmount;
                    }
                    @JSONField(name = "splitAmount")
                    public void setSplitAmount(String splitAmount) {
                        this.splitAmount = splitAmount;
                    }
                    @Override
                    public String toString() {
                        return "QueryBillResponse.Message.Info.Bill.SplitSubMerInfo[splitMerchantId=" + splitMerchantId
                                + ", splitAmount=" + splitAmount + "]";
                    }
                }
            }
        }
    }
}
ruoyi-admin/pom.xml
@@ -32,11 +32,11 @@
            <version>31.1-jre</version> <!-- 请根据需要选择合适的版本 -->
        </dependency>
        <!-- spring-boot-devtools -->
<!--        <dependency>-->
<!--            <groupId>org.springframework.boot</groupId>-->
<!--            <artifactId>spring-boot-devtools</artifactId>-->
<!--            <optional>true</optional> &lt;!&ndash; 表示依赖不会传递 &ndash;&gt;-->
<!--        </dependency>-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional> <!-- 表示依赖不会传递 -->
        </dependency>
        <!-- swagger3-->
        <dependency>
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/BankOutController.java
@@ -1,8 +1,23 @@
package com.ruoyi.web.controller.api;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.ruoyi.common.constant.AmountConstant;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.dto.TBillDto;
import com.ruoyi.system.model.TOrderBill;
import com.ruoyi.system.model.TPayOrder;
import com.ruoyi.system.service.TBillService;
import com.ruoyi.system.service.TOrderBillService;
import com.ruoyi.system.service.TPayOrderService;
import com.taxi591.bankapi.dto.CovertPayBackResult;
import com.taxi591.bankapi.dto.QueryBillRequest;
import com.taxi591.bankapi.dto.QueryBillResponse;
import com.taxi591.bankapi.service.BankService;
import com.taxi591.bankapi.service.SignatureAndVerification;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@@ -10,9 +25,16 @@
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@RestController
@RequestMapping("open/bank")
@Slf4j
public class BankOutController {
    @Autowired
@@ -20,6 +42,16 @@
    @Autowired
    TBillService tBillService;
    @Autowired
    SignatureAndVerification signatureAndVerification;
    @Autowired
    TOrderBillService orderBillService;
    @Autowired
    TPayOrderService payOrderService;
    @PostMapping(value = "payCallback")
    public @ResponseBody String payCallback(HttpServletRequest request){
        CovertPayBackResult result = bankService.covertPayCallBack(request, (billRequest) -> {
@@ -29,7 +61,165 @@
        return result.getBack();
    }
    @PostMapping(value = "queryBill")
    public void bills(HttpServletRequest request, HttpServletResponse httpServletResponse){
        log.info("进入QueryBillController账单查询接口--------(金额规则为0的)-------");
        String responseJson = null;
        try {
            //接收报文request返回截取并返回requestBody和使用base64解析后的requestBody
            Map<String, String> requestMap = signatureAndVerification.requestBodyOfBase64(request);
            //使用base64解析完成后的requestBody
            String requestBodyOfDecoded = requestMap.get("requestBodyOfDecoded");
            //解析前的requestBody
            String requestBody = requestMap.get("requestBody");
            //获取缴费中心传送过来的签名
            String signatureString = requestMap.get("signatureString");
            // 验签
            boolean flag = signatureAndVerification.read_cer_and_verify_sign(requestBody,
                    signatureString);
            log.info("【QueryBill:getBill4DirectJoinMerch】缴费中心响应的报文验签结果为:{}" , flag);
            QueryBillRequest queryBillRequest = JSON.parseObject(requestBodyOfDecoded,
                    new TypeReference<QueryBillRequest>() {
                    });
            //交易编号
            String traceNo = queryBillRequest.getMessage().getInfo()
                    .getTraceNo();
            //返回给缴费中心的响应
            QueryBillResponse response = new QueryBillResponse(queryBillRequest);
            QueryBillResponse.Message respMessage = response.getMessage();
            QueryBillResponse.Message.Head respHead = response.getMessage()
                    .getHead();
            QueryBillResponse.Message.Info respInfo = response.getMessage()
                    .getInfo();
            //缴费账单子账单
            ArrayList<QueryBillResponse.Message.Info.Bill> respBills = new ArrayList<QueryBillResponse.Message.Info.Bill>();
            ArrayList<QueryBillResponse.Message.Info.Bill.DescDetail> respDescDetail =
                    new ArrayList<QueryBillResponse.Message.Info.Bill.DescDetail>();
            QueryBillResponse.Message.Info.Bill respBill = respInfo.new Bill();
            //缴费子商户账单
//            ArrayList<QueryBillResponse.Message.Info.Bill.SplitSubMerInfo> splitSubMerInfos = new ArrayList<QueryBillResponse.Message.Info.Bill.SplitSubMerInfo>();
            //封装返回给缴费中心的响应
            String epayCode = queryBillRequest.getMessage().getInfo()
                    .getEpayCode();
            respInfo.setEpayCode(epayCode);
            String merchantId = queryBillRequest.getMessage().getInfo()
                    .getMerchantId();
            respInfo.setMerchantId(merchantId);
            respInfo.setTraceNo(traceNo);
            respInfo.setInput1(queryBillRequest.getMessage().getInfo()
                    .getInput1());
            respInfo.setInput2(queryBillRequest.getMessage().getInfo()
                    .getInput2());
            respInfo.setInput3(queryBillRequest.getMessage().getInfo()
                    .getInput3());
            respInfo.setInput4(queryBillRequest.getMessage().getInfo()
                    .getInput4());
            respInfo.setInput5(queryBillRequest.getMessage().getInfo()
                    .getInput5());
            String orderid= queryBillRequest.getMessage().getInfo().getInput1();
            if (StringUtils.isEmpty(orderid)){
                respHead.setReturnCode("0009");
                respHead.setReturnMessage("参数错误,input1订单号不能为空");
            }else{
                if (flag){
                    TPayOrder order = payOrderService.getById(orderid);
                    List<TOrderBill> orderBills = orderBillService.getByOrderNo(orderid);
                    List<TBillDto> bills = orderBills.stream().map(ob
                            -> tBillService.getDetailByBillId(ob.getBillId())).collect(Collectors.toList());
//            封装详细账单信息
                    respBill.setBillName(order.getUserName());
                    respBill.setFeeAmt(BigDecimal.valueOf(order.getAmount()).divide(AmountConstant.b100,2, RoundingMode.HALF_DOWN).toPlainString());
                    respBills.add(respBill);
                    respInfo.setCustName(order.getUserName());
                    respInfo.setCustAddress("");
                    respInfo.setCacheMem("");
                    respInfo.setRemark("");
                    respInfo.setCallBackText("西藏国资委");
                    //respInfo.setCallBackUrl("https://abcsr.keepfx.cn/b/ejy/payResult/");
                    //使用base64加密信息
//                    respInfo.setCallBackUrl("aHR0cDp3d3cuYWJjaGluYS5jb20vY24v");
                    //金额规则字段
                    String amtRule = "0";
                    respInfo.setAmtRule(amtRule);
                /*QueryBillResponse.Message.Info.Bill.UnitDetail unitDetail = respBill.new UnitDetail(
                        "unitName", "6.66", "1");*/
                    BigDecimal outstandAmount = bills.stream().map(TBillDto::getOutstandingMoney).reduce(BigDecimal::add).get();
                    //欠费金额
                    respBill.setOweAmt(outstandAmount.setScale(2,RoundingMode.HALF_DOWN).toPlainString());
                    respBill.setFeeAmt("0.00");
//
//                    QueryBillResponse.Message.Info.Bill.DescDetail descDtail1 = respBill.new DescDetail(
//                            "缴费月份:", "2020年6月份");
//                    QueryBillResponse.Message.Info.Bill.DescDetail descDtail2 = respBill.new DescDetail(
//                            "供电局编号:", "4340152");
//                    QueryBillResponse.Message.Info.Bill.DescDetail descDtail3 = respBill.new DescDetail(
//                            "欠费金额:", "0.00元");
//                    QueryBillResponse.Message.Info.Bill.DescDetail descDtail4 = respBill.new DescDetail(
//                            "缴费月份:", "2020年6月份");
//                    QueryBillResponse.Message.Info.Bill.DescDetail descDtail5 = respBill.new DescDetail(
//                            "服务时间:", "每天0:30-23:30期间均可缴费");
//                    QueryBillResponse.Message.Info.Bill.DescDetail descDtail6 = respBill.new DescDetail(
//                            "温馨提示:", "北京电力电费代缴,咨询电话:95598 该用户为:预付费用户");
//                    respDescDetail.add(descDtail1);
//                    respDescDetail.add(descDtail2);
//                    respDescDetail.add(descDtail3);
//                    respDescDetail.add(descDtail4);
//                    respDescDetail.add(descDtail5);
//                    respDescDetail.add(descDtail6);
//                    respBill.setRcvMerchantId("103881104410001");
//              商户子商户详细信息
//                    QueryBillResponse.Message.Info.Bill.SplitSubMerInfo splitSubMerInfo1 =respBill.new SplitSubMerInfo("10388", "0.01");
//                    QueryBillResponse.Message.Info.Bill.SplitSubMerInfo splitSubMerInfo2 =respBill.new SplitSubMerInfo("1038819201", "0.02");
//                    splitSubMerInfos.add(splitSubMerInfo1);
//                    splitSubMerInfos.add(splitSubMerInfo2);
//                    respBill.setSplitSubMerInfos(splitSubMerInfos);
//                    respBill.setDescDetails(respDescDetail);
                    respInfo.setTotalBillCount(String.valueOf(respBills.size()));
                    respInfo.setBill(respBills);
                    // 有定制电子回单附言信息的,需添加自定义定制附言信息字段
                    respInfo.setMerchantRemark("");
                    respHead.setReturnCode("0000");
                    respHead.setReturnMessage("账单查询成功,返回成功标志");
                }else {
                    respHead.setReturnCode("0009");
                    respHead.setReturnMessage("缴费中心传送给商户的请求报文签名验签失败!");
                }
            }
            respHead.setTransFlag("02");
            respHead.setTimeStamp(DateUtil.format(new Date(),"yyyyMMddHHmmssSSS"));
            respMessage.setInfo(respInfo);
            respMessage.setHead(respHead);
            response.setMessage(respMessage);
            responseJson = JSON.toJSONString(response);
            // 加签名
            String signatrue = signatureAndVerification
                    .signWhithsha1withrsa(responseJson);
            log.info("signatrue" + responseJson);
            log.info("responseJson打印结果是(responseJson加密前):" + responseJson);
            responseJson = signatrue + "||"
                    + new String(Base64.encodeBase64(responseJson.getBytes("utf-8")));
            log.info("responseJson打印结果是(responseJson加密后):{}", responseJson);
            httpServletResponse.setCharacterEncoding("utf-8");
            httpServletResponse.setContentType("text/plain");
            httpServletResponse.getWriter().write(responseJson);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/COSController.java
@@ -1,19 +1,33 @@
package com.ruoyi.web.controller.api;
import com.alibaba.fastjson2.JSON;
import com.ruoyi.common.config.FileUploadConfig;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.system.model.TFile;
import com.ruoyi.system.service.SysFileService;
import com.ruoyi.system.service.impl.SysFileServiceImpl;
import com.ruoyi.web.controller.tool.TencentCosUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.io.OutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLEncoder;
/**
 * @author HJL
@@ -23,18 +37,145 @@
@RestController
@RequestMapping("/cos")
@Api(tags = "公共-文件上传")
@Slf4j
public class COSController {
    @Resource
    private TencentCosUtil tencentCosUtil;
    @Autowired
    SysFileService sysFileService;
    @Autowired
    FileUploadConfig fileUploadConfig;
    @Autowired
    TokenService tokenService;
    public String getLocalUrlPrefix(){
        ServletRequestAttributes servletRequestAttributes = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes());
        if (servletRequestAttributes==null || servletRequestAttributes.getRequest()==null){
            return fileUploadConfig.getFileUrlPrefix();
        }
        HttpServletRequest request = servletRequestAttributes.getRequest();
        StringBuffer url = new StringBuffer();
        url.append(request.getScheme()).append("://")
                .append(request.getServerName())
                .append((request.getServerPort() == 80 ? "" : ":" + request.getServerPort()))
                .append(request.getContextPath());
        return url.toString();
    }
    public  String getLocalFileUrlPrefix(String fileId){
        String token = tokenService.getLoginUser().getToken();
        StringBuffer url = new StringBuffer();
        url.append(getLocalUrlPrefix())
                .append("/cos/get/").append(fileId).append("?s=").append(URLEncoder.encode(token))
        ;
        return url.toString();
    }
    public static void failResponse(String message){
        ServletRequestAttributes servletRequestAttributes = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes());
        HttpServletResponse response = servletRequestAttributes.getResponse();
        String failResult =  JSON.toJSONString(R.fail(message));
        //设置编码格式
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json;charset=UTF-8");
        PrintWriter pw = null;
        try {
            pw = response.getWriter();
            pw.write(failResult);
            pw.flush();
        } catch (IOException e) {
            log.error("io异常");
        }finally {
            if (pw!=null) {
                pw.close();
            }
        }
    }
    @Autowired
    private RedisCache redisCache;
    @GetMapping("get/{fileId}")
    public void get(@PathVariable("fileId") String fileid,@RequestParam("s") String s){
        if (StringUtils.isEmpty(fileid)){
            failResponse("文件ID不能为空");
            return;
        }
        if (StringUtils.isEmpty(s)){
            failResponse("token不能为空");
            return;
        }
        Object object = redisCache.getCacheObject(CacheConstants.LOGIN_TOKEN_KEY + s);
        if (object==null){
            failResponse("用户登录已失效");
            return;
        }
        TFile file = sysFileService.getById(fileid);
        if (file==null){
            failResponse("图片不存在");
            return;
        }
        tencentCosUtil.download(file);
    }
    @GetMapping("get/file")
    public void getFile(@RequestParam("fileUrl") String fileUrl,@RequestParam("s") String s){
        if (StringUtils.isEmpty(fileUrl)){
            failResponse("文件路径不能为空");
            return;
        }
        if (StringUtils.isEmpty(s)){
            failResponse("token不能为空");
            return;
        }
        Object object = redisCache.getCacheObject(CacheConstants.LOGIN_TOKEN_KEY + s);
        if (object==null){
            failResponse("用户登录已失效");
            return;
        }
        tencentCosUtil.download(fileUrl);
    }
    /**
     * 新上传接口,下一版更新
     * @param file
     * @param folder 上传到cos的文件目录:如/contract/
     * @return
     */
    @PostMapping("/uploadnew")
    @ApiOperation(value = "文件上传,带上传目录,返回文件ID", tags = "公共-文件上传")
    @ApiImplicitParams({
            @ApiImplicitParam(value = "文件", name = "file", dataType = "MultipartFile", required = true)
    })
    public R<TFile> uploadnew(@RequestParam("file") MultipartFile file, @RequestParam("folder") String folder) {
        TFile tFile = tencentCosUtil.upload(file,folder);
        tFile.setFileUrl(getLocalFileUrlPrefix(tFile.getId()));
        return R.ok(tFile);
    }
    /**
     *
     * @param file
     * @param
     * @return
     */
    @PostMapping("/upload")
    @ApiOperation(value = "文件上传", tags = "公共-文件上传")
    @ApiImplicitParams({
            @ApiImplicitParam(value = "文件", name = "file", dataType = "MultipartFile", required = true)
    })
    public R<String> upload(@RequestParam("file") MultipartFile file) {
        String url = tencentCosUtil.upLoadFile(file);
    public R<String> upload(@RequestParam("file") MultipartFile file,@RequestParam("folder") String folder) {
        String url = tencentCosUtil.upLoadFile(file,folder);
        return R.ok(url, url);
    }
    @PostMapping("/downloadImg")
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/SysFileController.java
New file
@@ -0,0 +1,22 @@
package com.ruoyi.web.controller.api;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
 * <p>
 * 文件列表 前端控制器
 * </p>
 *
 * @author yupeng
 * @since 2025-03-05
 */
@RestController
@RequestMapping("/sys-file")
public class SysFileController {
}
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TContractController.java
@@ -331,6 +331,7 @@
            }
            String url = wordUtil.generatePdf("/template", "1_yzj_租赁合同.xml", templateParam, "租赁合同", "E:\\");
            System.out.println(url);
            res.add(url);
        }
ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/PdfUtils.java
@@ -50,7 +50,7 @@
            //上传图片
            byte2File(stream.toByteArray(),filePath + "/pdf",fileName.substring(0,fileName.lastIndexOf(".")) + ".pdf");
            MultipartFile multipartFile = convertToMultipartFile(stream,fileName.substring(0,fileName.lastIndexOf(".")) );
            String s = tencentCosUtil.upLoadFile(multipartFile);
            String s = tencentCosUtil.upLoadFile(multipartFile,"/wordToPdf");
            stream.close();
            inputStream.close();
ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/TencentCosUtil.java
@@ -1,20 +1,23 @@
package com.ruoyi.web.controller.tool;
import cn.hutool.core.date.DateUtil;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.exception.CosClientException;
import com.qcloud.cos.exception.CosServiceException;
import com.qcloud.cos.http.HttpProtocol;
import com.qcloud.cos.model.COSObject;
import com.qcloud.cos.model.GetObjectRequest;
import com.qcloud.cos.model.ObjectMetadata;
import com.qcloud.cos.model.PutObjectResult;
import com.qcloud.cos.region.Region;
import com.qcloud.cos.utils.IOUtils;
import com.ruoyi.common.utils.WebUtils;
import org.springframework.beans.factory.annotation.Value;
import com.ruoyi.system.model.TFile;
import com.ruoyi.system.service.SysFileService;
import com.ruoyi.system.service.impl.SysFileServiceImpl;
import com.ruoyi.web.core.config.FileUploaderConfig;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
@@ -25,44 +28,17 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Base64;
import java.util.Date;
import java.util.UUID;
import static cn.hutool.core.date.DatePattern.NORM_DATE_FORMAT;
/**
 * @author HJL
 */
@Component
@Slf4j
public class TencentCosUtil {
    /**
     * COS的SecretId
     */
    @Value("${cos.client.accessKey}")
    private String secretId;
    /**
     * COS的SecretKey
     */
    @Value("${cos.client.secretKey}")
    private String secretKey;
    /**
     * 文件上传后访问路径的根路径,后面要最佳文件名字与类型
     */
    @Value("${cos.client.rootSrc}")
    private String rootSrc;
    /**
     * 上传的存储桶的地域
     */
    @Value("${cos.client.bucketAddr}")
    private String bucketAddr;
    /**
     * 存储桶的名字,是自己在存储空间自己创建的,我创建的名字是:qq-test-1303******
     */
    @Value("${cos.client.bucket}")
    private String bucketName;
    /**
     * 文件存放位置
     */
    @Value("${cos.client.location}")
    private String location;
    /**
     * 1.调用静态方法getCosClient()就会获得COSClient实例
@@ -70,16 +46,64 @@
     *
     * @return COSClient实例
     */
    private COSClient getCosClient() {
        // 1 初始化用户身份信息(secretId, secretKey)。
        COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);
        // 2.1 设置存储桶的地域(上文获得)
        Region region = new Region(bucketAddr);
        ClientConfig clientConfig = new ClientConfig(region);
        // 2.2 使用https协议传输
        clientConfig.setHttpProtocol(HttpProtocol.https);
        // 生成 cos 客户端
        return new COSClient(cred, clientConfig);
    @Autowired
    COSClient cosClient;
    @Autowired
    FileUploaderConfig cosConfig;
    @Autowired
    SysFileService sysFileService;
    /**
     * 上传文件,并存入sys_file,返回文件的主键ID
     * @param file
     * @param folder  格式:/xxxxx,/xxxx/xxxx ,最后不用加斜杠
     * @return
     */
    public TFile upload(MultipartFile file, String folder){
        try {
            // 获取上传的文件的输入流
            InputStream inputStream = file.getInputStream();
            // 避免文件覆盖,获取文件的原始名称,如123.jpg,然后通过截取获得文件的后缀,也就是文件的类型
            String originalFilename = file.getOriginalFilename();
            //获取文件的类型
            String fileType = originalFilename.substring(originalFilename.lastIndexOf("."));
            //使用UUID工具  创建唯一名称,放置文件重名被覆盖,在拼接上上命令获取的文件类型
            String fileName = UUID.randomUUID() + fileType;
            String filePath = (StringUtils.isNotEmpty(folder)?
                    folder+"/"
                    :"/default/") + DateUtil.format(new Date(),NORM_DATE_FORMAT)+"/"+fileName;
            // 指定文件上传到 COS 上的路径,即对象键。最终文件会传到存储桶名字中的images文件夹下的fileName名字
            filePath = cosConfig.getLocation() + filePath;
            // 创建上传Object的Metadata
            ObjectMetadata objectMetadata = new ObjectMetadata();
            // - 使用输入流存储,需要设置请求长度
            objectMetadata.setContentLength(inputStream.available());
            // - 设置缓存
            objectMetadata.setCacheControl("no-cache");
            // - 设置Content-Type
            objectMetadata.setContentType(fileType);
            //上传文件
            cosClient.putObject(cosConfig.getBucketName(), filePath, inputStream, objectMetadata);
            TFile tFile = new TFile();
            tFile.setFileName(filePath);
            tFile.setRealName(originalFilename);
            tFile.setFileType(fileType);
            tFile.setUrl(cosConfig.getRootSrc()+filePath);
            tFile.setContentType(file.getContentType());
            tFile.setFileSize(file.getSize());
            sysFileService.save(tFile);
            return tFile;
        } catch (Exception e) {
            log.error("上传文件发生异常",e);
            // 发生IO异常、COS连接异常等,返回空
            return null;
        }
    }
    /**
@@ -88,7 +112,7 @@
     * @param file
     * @return 返回文件的浏览全路径
     */
    public String upLoadFile(MultipartFile file) {
    public String upLoadFile(MultipartFile file,String folder) {
        try {
            // 获取上传的文件的输入流
            InputStream inputStream = file.getInputStream();
@@ -99,7 +123,11 @@
            //使用UUID工具  创建唯一名称,放置文件重名被覆盖,在拼接上上命令获取的文件类型
            String fileName = UUID.randomUUID() + fileType;
            // 指定文件上传到 COS 上的路径,即对象键。最终文件会传到存储桶名字中的images文件夹下的fileName名字
            String key = location+"/" + fileName;
            String filePath = (StringUtils.isNotEmpty(folder)?
                    folder+"/"
                    :"/default/") + DateUtil.format(new Date(),NORM_DATE_FORMAT)+"/"+fileName;
            filePath = cosConfig.getLocation()+"/" + filePath;
            // 创建上传Object的Metadata
            ObjectMetadata objectMetadata = new ObjectMetadata();
            // - 使用输入流存储,需要设置请求长度
@@ -109,14 +137,13 @@
            // - 设置Content-Type
            objectMetadata.setContentType(fileType);
            //上传文件
            PutObjectResult putResult = getCosClient().putObject(bucketName, key, inputStream, objectMetadata);
            PutObjectResult putResult = cosClient.putObject(cosConfig.getBucketName(), filePath, inputStream, objectMetadata);
            // 创建文件的网络访问路径
            String url = rootSrc + key;
            //关闭 cosClient,并释放 HTTP 连接的后台管理线程
            getCosClient().shutdown();
            String url = cosConfig.getRootSrc() + filePath;
            return url;
        } catch (Exception e) {
            e.printStackTrace();
            log.error("上传文件发生异常",e);
            // 发生IO异常、COS连接异常等,返回空
            return null;
        }
@@ -129,20 +156,11 @@
     */
    public void downLoadFile(String file) {
        HttpServletResponse response = WebUtils.response();
        String replace = file.replace(rootSrc, "");
        String replace = file.replace(cosConfig.getRootSrc(), "");
        response.setHeader("Access-Control-Expose-Headers","File-Type");
        COSCredentials cred = new BasicCOSCredentials(
                secretId,
                secretKey);
        // 2.1 设置存储桶的地域(上文获得)
        Region region = new Region(bucketAddr);
        ClientConfig clientConfig = new ClientConfig(region);
        // 2.2 使用https协议传输
        clientConfig.setHttpProtocol(HttpProtocol.https);
        COSClient cosClient = new COSClient(cred, clientConfig);
        try {
            // 5. 下载文件并获取输入流
            InputStream inputStream = cosClient.getObject(bucketName, replace).getObjectContent();
            InputStream inputStream = cosClient.getObject(cosConfig.getBucketName(), replace).getObjectContent();
            ServletOutputStream outputStream = response.getOutputStream();
            // 6. 处理输入流,例如读取内容或保存到本地文件
            // 这里仅作示例,实际应用中需要根据需求处理输入流
@@ -154,26 +172,15 @@
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 7. 关闭输入流
            cosClient.shutdown();
            log.error("下载文件发生异常",e);
        }
    }
    public String downLoadFileImg(String file) {
        byte[] data = null;
        String replace = file.replace(rootSrc, "");
        COSCredentials cred = new BasicCOSCredentials(
                secretId,
                secretKey);
        // 2.1 设置存储桶的地域(上文获得)
        Region region = new Region(bucketAddr);
        ClientConfig clientConfig = new ClientConfig(region);
        // 2.2 使用https协议传输
        clientConfig.setHttpProtocol(HttpProtocol.https);
        COSClient cosClient = new COSClient(cred, clientConfig);
        String replace = file.replace(cosConfig.getRootSrc(), "");
        try {
            // 5. 下载文件并获取输入流
            InputStream inputStream = cosClient.getObject(bucketName, replace).getObjectContent();
            InputStream inputStream = cosClient.getObject(cosConfig.getBucketName(), replace).getObjectContent();
            ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
            // 6. 处理输入流,例如读取内容或保存到本地文件
            byte[] buffer = new byte[1024];
@@ -185,10 +192,60 @@
            data = swapStream.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
            log.error("下载图片发生异常",e);
        } finally {
            // 7. 关闭输入流
            cosClient.shutdown();
        }
        return Base64.getEncoder().encodeToString(data);
    }
    public void download(String fileUrl) {
        HttpServletResponse response = WebUtils.response();
        fileUrl = fileUrl.replace(cosConfig.getRootSrc(), "");
            // 5. 下载文件并获取输入流
        COSObject object = cosClient.getObject(cosConfig.getBucketName(),fileUrl);
        try (
            InputStream is = object.getObjectContent();
             OutputStream os = response.getOutputStream()
        ) {
            String fileName = fileUrl.substring(fileUrl.lastIndexOf("/"));
            response.setContentType(object.getObjectMetadata().getContentType() + ";charset=utf-8");
            String filename = new String(fileName.getBytes("UTF-8"), "ISO-8859-1");
            response.addHeader("Content-Disposition", "attachment;filename=" + filename);
            response.addHeader("Content-Length", "" + object.getObjectMetadata().getContentLength());
            int len = 0;
            byte[] buffer = new byte[2048];
            while ((len = is.read(buffer)) > 0) {
                os.write(buffer, 0, len);
            }
            os.flush();
        } catch (IOException e) {
            log.error("读取cos图片发生异常", e);
        }
    }
    public void download(TFile file) {
        HttpServletResponse response = WebUtils.response();
        // 5. 下载文件并获取输入流
        COSObject object = cosClient.getObject(cosConfig.getBucketName(), file.getFileName());
        try (
                InputStream is = object.getObjectContent();
                OutputStream os = response.getOutputStream()
        ) {
            response.setContentType(file.getContentType() + ";charset=utf-8");
            String filename = new String(file.getRealName().getBytes("UTF-8"), "ISO-8859-1");
            response.addHeader("Content-Disposition", "attachment;filename=" + filename);
            response.addHeader("Content-Length", "" + file.getFileSize());
            int len = 0;
            byte[] buffer = new byte[2048];
            while ((len = is.read(buffer)) > 0) {
                os.write(buffer, 0, len);
            }
            os.flush();
        } catch (IOException e) {
            log.error("读取cos图片发生异常", e);
        }
    }
}
ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/WordUtil.java
@@ -101,7 +101,7 @@
                fis.read(fileContent);
            }
            MultipartFile mockMultipartFile = new MockMultipartFile(encodedFileName+".doc", fileContent);
            String s = tencentCosUtil.upLoadFile(mockMultipartFile);
            String s = tencentCosUtil.upLoadFile(mockMultipartFile,"/wordGenerate");
            return s;
        } catch (IOException | TemplateException e) {
            log.error("生成Word文档异常,异常原因:{}", e.getMessage(), e);
ruoyi-admin/src/main/java/com/ruoyi/web/core/config/FileUploaderConfig.java
New file
@@ -0,0 +1,67 @@
package com.ruoyi.web.core.config;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.http.HttpProtocol;
import com.qcloud.cos.region.Region;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@Data
public class FileUploaderConfig {
    /**
     * COS的SecretId
     */
    @Value("${cos.client.accessKey}")
    private String secretId;
    /**
     * COS的SecretKey
     */
    @Value("${cos.client.secretKey}")
    private String secretKey;
    /**
     * 文件上传后访问路径的根路径,后面要最佳文件名字与类型
     */
    @Value("${cos.client.rootSrc}")
    private String rootSrc;
    /**
     * 上传的存储桶的地域
     */
    @Value("${cos.client.bucketAddr}")
    private String bucketAddr;
    /**
     * 存储桶的名字,是自己在存储空间自己创建的,我创建的名字是:qq-test-1303******
     */
    @Value("${cos.client.bucket}")
    private String bucketName;
    /**
     * 文件存放位置
     */
    @Value("${cos.client.location}")
    private String location;
    @Value("${file.url.prefix}")
    private String fileUrlPrefix;
    @Bean
    public COSClient cosClient() {
        // 1 初始化用户身份信息(secretId, secretKey)。
        COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);
        // 2.1 设置存储桶的地域(上文获得)
        Region region = new Region(bucketAddr);
        ClientConfig clientConfig = new ClientConfig(region);
        // 2.2 使用https协议传输
        clientConfig.setHttpProtocol(HttpProtocol.https);
        // 生成 cos 客户端
        return new COSClient(cred, clientConfig);
    }
}
ruoyi-admin/src/main/resources/application-prod.yml
@@ -213,4 +213,4 @@
    bucket: xzgttest-1305134071
    bucketAddr: ap-chengdu
    rootSrc: https://xzgttest-1305134071.cos.ap-chengdu.myqcloud.com/
    location: xizang
    location: /xizang
ruoyi-admin/src/main/resources/application-test.yml
@@ -14,7 +14,6 @@
  addressEnabled: false
  # 验证码类型 math 数字计算 char 字符验证
  captchaType: math
# 开发环境配置
server:
  # 服务器的HTTP端口,默认为8080
@@ -103,7 +102,7 @@
    druid:
      # 主库数据源
      master:
        url: jdbc:mysql://xzgt.test.591taxi.cn:13306/xizang?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=Asia/Shanghai
        url: jdbc:mysql://xzgt.test.591taxi.cn:13306/xizang?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=Asia/Shanghai
        username: root
        password: 8f5z9g52gx4bg
      # 从库数据源
@@ -199,6 +198,8 @@
    qrLocation: /file/qrCode/
    accessPath: /file/
    allowExt: .jpg|.png|.gif|.jpeg|.doc|.docx|.apk|.MP4|.mp4|.pdf|.PDF
  url:
    prefix: http://localhost:${server.port}${server.servlet.context-path}
wx:
  conf:
    appId: wxe91f1af7638aa5dd
@@ -219,10 +220,18 @@
    bucket: xzgttest-1305134071
    bucketAddr: ap-chengdu
    rootSrc: https://xzgttest-1305134071.cos.ap-chengdu.myqcloud.com/
    location: xizang
    location: /xizang
sms:
  enable: true
  appId: 1400957506
  secretid: AKIDCF5EF2c0DE1e5JK8r4EGJF4mNsMgp26x
  secretkey: lLl184rUyFOOE0d5KNGC3kmfNsCWk4GU
  sign: 畅云出行
com:
  taxi591:
    bank:
      cer-path: D:\workspaces\工作文件\畅云\农业银行\TrustPayTest.cer
      base-url: http://hello.enjoy.abchina.com
      enable: true
      keystore-password:
      pfx-path: D:\workspaces\工作文件\畅云\农业银行\103882200000958.pfx
ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/TInformationController.java
@@ -51,7 +51,9 @@
    public R<TInformation> getDetailById(@RequestParam String id) {
        // 处理查看次数
        redisCache.increment(Constants.INFORMATION_VIEW + id);
        return R.ok(informationService.getById(id));
        TInformation information = informationService.getById(id);
        information.setViewCount(redisCache.getCacheObject(Constants.INFORMATION_VIEW + information.getId()));
        return R.ok(information);
    }
}
ruoyi-applet/src/main/resources/application-test.yml
@@ -103,7 +103,7 @@
    druid:
      # 主库数据源
      master:
        url: jdbc:mysql://xzgt.test.591taxi.cn:13306/xizang?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=Asia/Shanghai
        url: jdbc:mysql://xzgt.test.591taxi.cn:13306/xizang?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=Asia/Shanghai
        username: root
        password: 8f5z9g52gx4bg
      # 从库数据源
ruoyi-common/src/main/java/com/ruoyi/common/config/FileUploadConfig.java
@@ -18,4 +18,6 @@
    private String allowExt;
    private String location;
    private String qrLocation;
    private String fileUrlPrefix;
}
ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java
@@ -119,7 +119,7 @@
                        "/operations/getBySingleNum/**",
                        "/user/getUserInfoByNumber/**",
                        "/wxLogin/**",
                        "/open/**"
                        "/open/**","/cos/get/**"
                ).permitAll()
                // 静态资源,可匿名访问
                .antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/TokenService.java
@@ -204,6 +204,14 @@
            refreshToken(loginUser);
        }
    }
    public boolean verifyToken(String token)
    {
        Claims claims = parseToken(token);
        return true;
    }
    /**
     * 小程序验证令牌有效期,相差不足20分钟,自动刷新缓存
     *
ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysFileMapper.java
New file
@@ -0,0 +1,16 @@
package com.ruoyi.system.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.system.model.TFile;
/**
 * <p>
 * 文件列表 Mapper 接口
 * </p>
 *
 * @author yupeng
 * @since 2025-03-05
 */
public interface SysFileMapper extends BaseMapper<TFile> {
}
ruoyi-system/src/main/java/com/ruoyi/system/model/TContract.java
@@ -172,6 +172,6 @@
    private String houseAddress;
    @ApiModelProperty(value = "审批流实例id")
    @TableField(exist = false)
    private Long instanceId;
    private String instanceId;
}
ruoyi-system/src/main/java/com/ruoyi/system/model/TFile.java
New file
@@ -0,0 +1,81 @@
package com.ruoyi.system.model;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
 * <p>
 * 文件列表
 * </p>
 *
 * @author yupeng
 * @since 2025-03-05
 */
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("t_file")
@ApiModel(value="t_file对象", description="文件列表")
public class TFile implements Serializable {
    private static final long serialVersionUID = 1L;
    @TableId("id")
    private String id;
    @ApiModelProperty(value = "文件分类,0.用户文件 1.钉钉文件")
    @TableField("type")
    private Integer type;
    @TableField("content_type")
    private String contentType;
    @ApiModelProperty(value = "文件类型(后缀)")
    @TableField("file_type")
    private String fileType;
    @ApiModelProperty(value = "文件真实名称")
    @TableField("real_name")
    private String realName;
    @ApiModelProperty(value = "文件名称")
    @TableField("file_name")
    private String fileName;
    @ApiModelProperty(value = "文件大小")
    @TableField("file_size")
    private Long fileSize;
    @TableField("create_time")
    private LocalDateTime createTime;
    @ApiModelProperty(value = "地址路径或者url")
    @TableField("url")
    private String url;
    @ApiModelProperty(value = "上传人ID")
    @TableField("creator_id")
    private String creatorId;
    @ApiModelProperty(value = "是否需要校验权限")
    @TableField("need_auth")
    private Boolean needAuth;
    @ApiModelProperty(value = "是否有效")
    @TableField("valid")
    private Boolean valid;
    /**
     * 返回文件对象时自动组装文件访问路径
     */
    @TableField(exist = false)
    @ApiModelProperty("文件访问路径")
    private String fileUrl;
}
ruoyi-system/src/main/java/com/ruoyi/system/service/SysFileService.java
New file
@@ -0,0 +1,17 @@
package com.ruoyi.system.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.system.model.TFile;
/**
 * <p>
 * 文件列表 服务类
 * </p>
 *
 * @author yupeng
 * @since 2025-03-05
 */
public interface SysFileService extends IService<TFile> {
}
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysFileServiceImpl.java
New file
@@ -0,0 +1,42 @@
package com.ruoyi.system.service.impl;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.config.FileUploadConfig;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.system.mapper.SysFileMapper;
import com.ruoyi.system.model.TFile;
import com.ruoyi.system.service.SysFileService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.token.TokenService;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLEncoder;
/**
 * <p>
 * 文件列表 服务实现类
 * </p>
 *
 * @author yupeng
 * @since 2025-03-05
 */
@Service
@Slf4j
public class SysFileServiceImpl extends ServiceImpl<SysFileMapper, TFile> implements SysFileService {
    @Autowired
    FileUploadConfig fileUploadConfig;
}
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TBillServiceImpl.java
@@ -1,5 +1,6 @@
package com.ruoyi.system.service.impl;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.basic.PageInfo;
import com.ruoyi.common.config.SmsProperties;
@@ -7,10 +8,7 @@
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SmsUtil;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.TencentMailUtil;
import com.ruoyi.common.utils.*;
import com.ruoyi.common.utils.uuid.UUID;
import com.ruoyi.system.dto.*;
import com.ruoyi.system.mapper.TBillMapper;
@@ -252,7 +250,7 @@
            throw new ServiceException("实付金额不能高于于流水可抵扣剩余金额");
        }
        //如果实付金额大于欠费金额
        if (dto.getAmount().compareTo(bill.getOutstandingMoney())>=0){
        if (dto.getAmount().compareTo(bill.getOutstandingMoney())>0){
            throw new ServiceException("实付金额不能高于该账单欠费金额");
        }
@@ -276,6 +274,7 @@
        save.setPayType(3);
        save.setPayer(dto.getPayer());
        save.setPayTime(bankflow.getPayTime());
        save.setSysSerialNumber(OrderNos.getDid(30));
        save.setBankSerialNumber(bankflow.getBankSerialNumber());
        save.setFlowType(2);
        save.setPaymentBillId(back.getId());
@@ -332,6 +331,7 @@
                saveFlow.setPayType(1);
                saveFlow.setPayer(order.getUserId());
                saveFlow.setPayTime(DateUtils.dateToLocalDateTime(save.getPayTime()));
                saveFlow.setSysSerialNumber(OrderNos.getDid(30));
                saveFlow.setBankSerialNumber(save.getPayNo());
                saveFlow.setFlowType(2);
                saveFlow.setPaymentBillId(bill.getId());
@@ -464,7 +464,7 @@
                throw new ServiceException("实付金额不能高于于流水可抵扣剩余金额");
            }
            //如果实付金额大于欠费金额
            if (dto.getAmount().compareTo(bill.getOutstandingMoney())>=0){
            if (dto.getAmount().compareTo(bill.getOutstandingMoney())>0){
                throw new ServiceException("实付金额不能高于该账单欠费金额");
            }
        }
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TContractServiceImpl.java
@@ -73,6 +73,12 @@
        for (TContract tContract : list) {
            tContract.setPayType(DictUtils.getDictLabel(DictConstants.DICT_TYPE_CONTRACT_PAY_TYPE,tContract.getPayType()));
            tContract.setStatus(DictUtils.getDictLabel(DictConstants.DICT_TYPE_CONTRACT_STATUS,tContract.getStatus()));
            FlwHisTask flwHisTask = flwHisTaskMapper.selectOne(new LambdaQueryWrapper<FlwHisTask>()
                    .like(FlwHisTask::getVariable, tContract.getId())
                    .last("LIMIT 1"));
            if (Objects.nonNull(flwHisTask)){
                tContract.setInstanceId(Objects.nonNull(flwHisTask.getInstanceId())?String.valueOf(flwHisTask.getInstanceId()):"");
            }
        }
        pageInfo.setRecords(list);
        return pageInfo;
@@ -90,7 +96,7 @@
                    .like(FlwHisTask::getVariable, tContract.getId())
                    .last("LIMIT 1"));
            if (Objects.nonNull(flwHisTask)){
                tContract.setInstanceId(flwHisTask.getInstanceId());
                tContract.setInstanceId(Objects.nonNull(flwHisTask.getInstanceId())?String.valueOf(flwHisTask.getInstanceId()):"");
            }
        }
        pageInfo.setRecords(list);
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TFlowManagementServiceImpl.java
@@ -33,7 +33,7 @@
                .like(StringUtils.isNotEmpty(query.getPayer()),TFlowManagement::getPayer,query.getPayer())
                .ge(StringUtils.isNotEmpty(query.getPayStartTime()),TFlowManagement::getPayTime,query.getPayStartTime())
                .lt(StringUtils.isNotEmpty(query.getPayEndTime()),TFlowManagement::getPayTime,query.getPayEndTime())
                .eq(null != query.getFlowStatus(),TFlowManagement::getFlowStatus,query.getFlowStatus())
                .eq(null != query.getPayType(),TFlowManagement::getPayType,query.getPayType())
                .orderByDesc(TFlowManagement::getCreateTime)
        ;
        return this.baseMapper.selectPage(pageInfo,queryWrapper);
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TPayOrderServiceImpl.java
@@ -69,12 +69,13 @@
            if (bill == null) {
                throw new ServiceException("账单不存在");
            }
            //计算欠费金额:租金+违约金-实收金额
            long rent = caculateRentFee(bill);
            //欠费金额转成单位分比较
            long rent = bill.getOutstandingMoney().multiply(AmountConstant.b100)
                    .setScale(2,RoundingMode.HALF_DOWN).longValue();
            if (rent==0){
                throw new ServiceException("该账单已缴费");
            }
            if (rent>dto.getAmount()){
            if (rent<dto.getAmount()){
                throw new ServiceException("支付金额超过了账单欠费金额");
            }
@@ -105,7 +106,11 @@
            orderBills.add(new TOrderBill(orderNo,bill.getId()));
            return bill;
        }).collect(Collectors.toList());
        long sumRent = bills.stream().mapToLong((bill) -> caculateRentFee(bill)).sum();
        //欠费金额转成单位分比较
        long sumRent = bills.stream().mapToLong((bill)
                -> bill.getOutstandingMoney().multiply(AmountConstant.b100)
                .setScale(2,RoundingMode.HALF_DOWN).longValue())
                .sum();
        if (sumRent==0){
            throw new ServiceException("账单已缴费");
        }
ruoyi-system/src/main/resources/mapper/system/TBankFlowMapper.xml
@@ -37,9 +37,9 @@
    <!-- 统计总额和微信支付金额 -->
    <select id="getPaymentStats" resultMap="PaymentStatsResultMap">
        SELECT
        SUM(flow_money) AS totalFlowMoney,
        SUM(deduction_money) AS totalDeductionMoney,
        SUM(remaining_money) AS totalRemainingMoney
        ifnull(SUM(flow_money),0) AS totalFlowMoney,
        ifnull(SUM(deduction_money),0) AS totalDeductionMoney,
        ifnull(SUM(remaining_money),0) AS totalRemainingMoney
        FROM
        t_bank_flow
        <where>
ruoyi-system/src/main/resources/mapper/system/TBillMapper.xml
@@ -63,7 +63,7 @@
                and t.id = #{query.userId}
            </if>
        </where>
        order by b.payable_fees_time
        order by b.payable_fees_time desc,b.create_time desc
    </select>
    <select id="getBillList" resultType="com.ruoyi.system.dto.TBillDto">
        SELECT
@@ -148,18 +148,18 @@
    </select>
    <select id="statisticsAllRent" resultType="java.math.BigDecimal">
        SELECT sum(payable_fees_money) as amount FROM t_bill
        SELECT ifnull(sum(payable_fees_money),0) as amount FROM t_bill
    </select>
    <select id="statisticsNoPay" resultType="java.math.BigDecimal">
        SELECT sum(outstanding_money) as amount FROM t_bill where pay_fees_status!=3
        SELECT ifnull(sum(outstanding_money),0) as amount FROM t_bill where pay_fees_status!=3
    </select>
    <select id="statisticsPayed" resultType="java.math.BigDecimal">
        SELECT sum(pay_fees_money) as amount FROM t_bill
        SELECT ifnull(sum(pay_fees_money),0) as amount FROM t_bill
    </select>
    <select id="statisticsOverdue" resultType="java.math.BigDecimal">
        SELECT sum(outstanding_money) as amount FROM t_bill where pay_fees_status=4
        SELECT ifnull(sum(outstanding_money),0) as amount FROM t_bill where pay_fees_status=4
    </select>
</mapper>
ruoyi-system/src/main/resources/mapper/system/TFlowManagementMapper.xml
@@ -39,10 +39,10 @@
    <!-- 统计总额和微信支付金额 -->
    <select id="getPaymentStats" resultMap="PaymentStatsResultMap">
        SELECT SUM(flow_money) AS total_amount,
               SUM(CASE WHEN pay_type = 1 THEN flow_money ELSE 0 END ) AS wechat_amount,
               SUM(CASE WHEN pay_type = 2 THEN flow_money ELSE 0 END ) AS alipay_amount,
               SUM(CASE WHEN pay_type = 3 THEN flow_money ELSE 0 END ) AS offline_amount
        SELECT ifnull(SUM(flow_money),0) AS total_amount,
        ifnull(SUM(CASE WHEN pay_type = 1 THEN flow_money ELSE 0 END ) ,0)AS wechat_amount,
        ifnull(SUM(CASE WHEN pay_type = 2 THEN flow_money ELSE 0 END ),0) AS alipay_amount,
        ifnull(SUM(CASE WHEN pay_type = 3 THEN flow_money ELSE 0 END ),0) AS offline_amount
        FROM
            t_flow_management
        <where>