支付相关
This commit is contained in:
27
doc/Order.sql
Normal file
27
doc/Order.sql
Normal file
@@ -0,0 +1,27 @@
|
||||
DROP TABLE IF EXISTS `pay_order`;
|
||||
CREATE TABLE `pay_order`
|
||||
(
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`sid` varchar(64) NOT NULL COMMENT 'sid',
|
||||
`lockVersion` int(11) NOT NULL DEFAULT '0' COMMENT '记录版本,锁',
|
||||
`createTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '记录创建时间',
|
||||
`modifyTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '记录最后修改时间',
|
||||
`isEnable` int(11) NOT NULL DEFAULT '1' COMMENT '记录是否可用,1:可用,0:不可用',
|
||||
`state` int(11) DEFAULT '1' COMMENT '状态',
|
||||
`isDelete` int(11) DEFAULT NULL COMMENT '记录是否被删除,0:未删除,1:已经删除',
|
||||
`remarks` varchar(255) DEFAULT NULL COMMENT '备注信息',
|
||||
`createBySid` varchar(64) DEFAULT NULL COMMENT '创建者',
|
||||
`updateBySid` varchar(64) DEFAULT NULL COMMENT '更新者',
|
||||
`outTradeNo` varchar(500) DEFAULT NULL COMMENT '订单编号',
|
||||
`source` int(64) DEFAULT NULL COMMENT '来源:0、云菜窖',
|
||||
`name` varchar(500) DEFAULT NULL COMMENT '需传入应用市场上的APP名字-实际商品名称,如天天爱消除-游戏充值',
|
||||
`totalTee` varchar(500) DEFAULT NULL COMMENT '金额',
|
||||
`openId` varchar(500) DEFAULT NULL COMMENT 'openId',
|
||||
`payTypeValue` varchar(500) DEFAULT NULL COMMENT '支付方式Value',
|
||||
`payType` varchar(500) DEFAULT NULL COMMENT '支付方式key',
|
||||
`timeRemarks` int(64) DEFAULT NULL COMMENT '过期时间设置(以分钟为准,例如5分钟,则为5)',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `id` (`id`)
|
||||
) ENGINE = InnoDB
|
||||
AUTO_INCREMENT = 18
|
||||
DEFAULT CHARSET = utf8 COMMENT ='订单表';
|
||||
130
pom.xml
Normal file
130
pom.xml
Normal file
@@ -0,0 +1,130 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<parent>
|
||||
<groupId>com.yxt</groupId>
|
||||
<artifactId>yxt-parent</artifactId>
|
||||
<version>0.0.1</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>yxt-pay</artifactId>
|
||||
<groupId>com.yxt.pay</groupId>
|
||||
<version>1.0.0</version>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.yxt</groupId>
|
||||
<artifactId>yxt-common-base</artifactId>
|
||||
<version>0.0.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
<version>5.0.4</version>
|
||||
</dependency>
|
||||
<!-- huTool 工具包 -->
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-crypto</artifactId>
|
||||
<version>5.0.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-core</artifactId>
|
||||
<version>5.0.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.zxing</groupId>
|
||||
<artifactId>core</artifactId>
|
||||
<version>3.5.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>easyexcel</artifactId>
|
||||
<version>3.3.2</version>
|
||||
</dependency>
|
||||
<!--mysql-->
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>dom4j</groupId>
|
||||
<artifactId>dom4j</artifactId>
|
||||
<version>1.6.1</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<version>2.5.6</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>repackage</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/java</directory>
|
||||
<includes>
|
||||
<include>**/*Mapper.xml</include>
|
||||
</includes>
|
||||
</resource>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<includes>
|
||||
<include>**/*.*</include>
|
||||
</includes>
|
||||
<filtering>false</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
23
src/main/java/com/yxt/pay/PayApplication.java
Normal file
23
src/main/java/com/yxt/pay/PayApplication.java
Normal file
@@ -0,0 +1,23 @@
|
||||
package com.yxt.pay;
|
||||
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
|
||||
/**
|
||||
* @author dimengzhe
|
||||
*/
|
||||
@SpringBootApplication(scanBasePackages = {
|
||||
"com.yxt.common.base.config",
|
||||
"com.yxt.pay"
|
||||
})
|
||||
@EnableDiscoveryClient
|
||||
@EnableFeignClients(basePackages = {})
|
||||
public class PayApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(PayApplication.class, args);
|
||||
}
|
||||
}
|
||||
29
src/main/java/com/yxt/pay/api/order/OrderDto.java
Normal file
29
src/main/java/com/yxt/pay/api/order/OrderDto.java
Normal file
@@ -0,0 +1,29 @@
|
||||
package com.yxt.pay.api.order;
|
||||
|
||||
import com.yxt.common.core.dto.Dto;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @description:
|
||||
* @author: dimengzhe
|
||||
* @date: 2024/1/6
|
||||
**/
|
||||
@Data
|
||||
public class OrderDto implements Dto {
|
||||
|
||||
@ApiModelProperty("来源:0、云菜窖")
|
||||
private int source;
|
||||
@ApiModelProperty("金额")
|
||||
private String totalTee;
|
||||
@ApiModelProperty("微信唯一标识openid")
|
||||
private String openId;
|
||||
@ApiModelProperty("用户sid")
|
||||
private String userSid;
|
||||
@ApiModelProperty("商品名称")
|
||||
private String name;
|
||||
@ApiModelProperty("过期时间:以分钟为单位")
|
||||
private int timeRemarks;
|
||||
|
||||
|
||||
}
|
||||
19
src/main/java/com/yxt/pay/api/order/OrderQuery.java
Normal file
19
src/main/java/com/yxt/pay/api/order/OrderQuery.java
Normal file
@@ -0,0 +1,19 @@
|
||||
package com.yxt.pay.api.order;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @description:
|
||||
* @author: dimengzhe
|
||||
* @date: 2024/1/7
|
||||
**/
|
||||
@Data
|
||||
public class OrderQuery {
|
||||
|
||||
private String mainSid;
|
||||
@ApiModelProperty("支付类型:微信wxpay")
|
||||
private String type;
|
||||
|
||||
|
||||
}
|
||||
17
src/main/java/com/yxt/pay/api/order/OrderVo.java
Normal file
17
src/main/java/com/yxt/pay/api/order/OrderVo.java
Normal file
@@ -0,0 +1,17 @@
|
||||
package com.yxt.pay.api.order;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @description:
|
||||
* @author: dimengzhe
|
||||
* @date: 2024/1/7
|
||||
**/
|
||||
@Data
|
||||
public class OrderVo {
|
||||
|
||||
|
||||
private Map<Object,Object> orderInfo;
|
||||
}
|
||||
65
src/main/java/com/yxt/pay/api/order/PayOrder.java
Normal file
65
src/main/java/com/yxt/pay/api/order/PayOrder.java
Normal file
@@ -0,0 +1,65 @@
|
||||
package com.yxt.pay.api.order;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.yxt.common.base.utils.StringRandom;
|
||||
import com.yxt.common.core.domain.BaseEntity;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @description:
|
||||
* @author: dimengzhe
|
||||
* @date: 2024/1/6
|
||||
**/
|
||||
@Data
|
||||
public class PayOrder extends BaseEntity {
|
||||
@ApiModelProperty("订单编号")
|
||||
private String outTradeNo;
|
||||
@ApiModelProperty("来源:0云菜窖")
|
||||
private int source;
|
||||
@ApiModelProperty("金额")
|
||||
private String totalTee;
|
||||
@ApiModelProperty("支付方式:wxPay微信")
|
||||
private String payType;
|
||||
private String payTypeValue;
|
||||
|
||||
private String name;
|
||||
|
||||
private String openId;
|
||||
@ApiModelProperty("过期时间描述:以分钟为单位,例如:5")
|
||||
private int timeRemarks;
|
||||
|
||||
/*@TableField(exist = false)
|
||||
private String appId;
|
||||
@TableField(exist = false)
|
||||
private String mchId;
|
||||
@TableField(exist = false)
|
||||
private String secret;
|
||||
@TableField(exist = false)
|
||||
private String remark;*/
|
||||
|
||||
|
||||
public String getTime() {
|
||||
SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
|
||||
return format.format(new Date());
|
||||
}
|
||||
|
||||
public PayOrder(int source) {
|
||||
String Randomstr = StringRandom.getRandomString(15);
|
||||
if (source == 0) {//云菜窖
|
||||
outTradeNo = "YCJ" + getTime() + Randomstr;
|
||||
/* appId = "wx4724e3a3c27f36b5";
|
||||
mchId = "1664882765";
|
||||
secret = "yxtcxjshbyxgs1234567898765432101";*/
|
||||
|
||||
} else if (source == 1) {
|
||||
|
||||
} else if (source == 2) {
|
||||
|
||||
}
|
||||
this.source = source;
|
||||
}
|
||||
}
|
||||
39
src/main/java/com/yxt/pay/api/order/PayTypeEnum.java
Normal file
39
src/main/java/com/yxt/pay/api/order/PayTypeEnum.java
Normal file
@@ -0,0 +1,39 @@
|
||||
package com.yxt.pay.api.order;
|
||||
|
||||
/**
|
||||
* @description:
|
||||
* @author: dimengzhe
|
||||
* @date: 2024/1/7
|
||||
**/
|
||||
public enum PayTypeEnum {
|
||||
|
||||
WECHAT("wxPay","微信支付"),
|
||||
ZHIFUBAO("zfbPay","支付宝支付"),
|
||||
|
||||
|
||||
;
|
||||
|
||||
private String code;
|
||||
|
||||
private String remarks;
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public String getRemarks() {
|
||||
return remarks;
|
||||
}
|
||||
|
||||
|
||||
|
||||
PayTypeEnum(String code,String remarks){
|
||||
this.code = code;
|
||||
this.remarks = remarks;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
36
src/main/java/com/yxt/pay/api/wxpay/WxPayVo.java
Normal file
36
src/main/java/com/yxt/pay/api/wxpay/WxPayVo.java
Normal file
@@ -0,0 +1,36 @@
|
||||
package com.yxt.pay.api.wxpay;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.yxt.common.base.utils.StringRandom;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @description:
|
||||
* @author: dimengzhe
|
||||
* @date: 2024/1/7
|
||||
**/
|
||||
@Data
|
||||
public class WxPayVo {
|
||||
|
||||
@ApiModelProperty("来源:0云菜窖")
|
||||
private int source;
|
||||
|
||||
private String appId;
|
||||
private String mchId;
|
||||
private String secret;
|
||||
|
||||
public WxPayVo(int source) {
|
||||
if (source == 0) {//云菜窖
|
||||
appId = "wx4724e3a3c27f36b5";
|
||||
mchId = "1664882765";
|
||||
secret = "yxtcxjshbyxgs1234567898765432101";
|
||||
|
||||
} else if (source == 1) {
|
||||
|
||||
} else if (source == 2) {
|
||||
|
||||
}
|
||||
this.source = source;
|
||||
}
|
||||
}
|
||||
15
src/main/java/com/yxt/pay/biz/order/OrderMapper.java
Normal file
15
src/main/java/com/yxt/pay/biz/order/OrderMapper.java
Normal file
@@ -0,0 +1,15 @@
|
||||
package com.yxt.pay.biz.order;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.yxt.pay.api.order.PayOrder;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* @description:
|
||||
* @author: dimengzhe
|
||||
* @date: 2024/1/6
|
||||
**/
|
||||
@Mapper
|
||||
public interface OrderMapper extends BaseMapper<PayOrder> {
|
||||
PayOrder selectBySn(String out_trade_no);
|
||||
}
|
||||
9
src/main/java/com/yxt/pay/biz/order/OrderMapper.xml
Normal file
9
src/main/java/com/yxt/pay/biz/order/OrderMapper.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.yxt.pay.biz.order.OrderMapper">
|
||||
<select id="selectBySn" resultType="com.yxt.pay.api.order.PayOrder">
|
||||
select *
|
||||
from pay_order
|
||||
where outTradeNo = #{out_trade_no}
|
||||
</select>
|
||||
</mapper>
|
||||
52
src/main/java/com/yxt/pay/biz/order/OrderRest.java
Normal file
52
src/main/java/com/yxt/pay/biz/order/OrderRest.java
Normal file
@@ -0,0 +1,52 @@
|
||||
package com.yxt.pay.biz.order;
|
||||
|
||||
import com.yxt.common.core.result.ResultBean;
|
||||
import com.yxt.pay.api.order.OrderDto;
|
||||
import com.yxt.pay.api.order.OrderQuery;
|
||||
import com.yxt.pay.api.order.OrderVo;
|
||||
import com.yxt.pay.utils.ApiBaseAction;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @description:
|
||||
* @author: dimengzhe
|
||||
* @date: 2024/1/6
|
||||
**/
|
||||
@RestController
|
||||
@RequestMapping("/order")
|
||||
public class OrderRest extends ApiBaseAction {
|
||||
//9370ec84-2723-40ee-bb6f-680fce6a25a2
|
||||
//05ba58d6-f1f0-4f68-9bcc-62ceeaf4c088
|
||||
//o81zC60V3ymrfjgK-BifvcyWfJBo
|
||||
|
||||
@Autowired
|
||||
private OrderService orderService;
|
||||
|
||||
@PostMapping("createOrder")
|
||||
ResultBean<String> createOrder(@RequestBody OrderDto dto) {
|
||||
return orderService.createOrder(dto);
|
||||
}
|
||||
|
||||
@PostMapping("/pay")
|
||||
ResultBean pay(@RequestBody OrderQuery query) {
|
||||
return orderService.pay(query, getClientIp());
|
||||
}
|
||||
|
||||
@PostMapping("wxPayNotify")
|
||||
ResultBean wxPayNotify(HttpServletRequest request) throws IOException {
|
||||
return orderService.wxPayNotify(request.getInputStream());
|
||||
}
|
||||
|
||||
@PostMapping("selectOrder")
|
||||
ResultBean selectOrder(@RequestBody OrderQuery query) {
|
||||
return orderService.selectOrder(query);
|
||||
}
|
||||
}
|
||||
248
src/main/java/com/yxt/pay/biz/order/OrderService.java
Normal file
248
src/main/java/com/yxt/pay/biz/order/OrderService.java
Normal file
@@ -0,0 +1,248 @@
|
||||
package com.yxt.pay.biz.order;
|
||||
|
||||
import com.yxt.common.base.service.MybatisBaseService;
|
||||
import com.yxt.common.core.result.ResultBean;
|
||||
import com.yxt.pay.api.order.*;
|
||||
import com.yxt.pay.api.wxpay.WxPayVo;
|
||||
import com.yxt.pay.biz.wxpay.WxPayService;
|
||||
import com.yxt.pay.utils.*;
|
||||
import com.yxt.pay.utils.applet.WechatRefundApiResult;
|
||||
import com.yxt.pay.utils.applet.WechatUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.axis.i18n.RB;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.servlet.ServletInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @description:
|
||||
* @author: dimengzhe
|
||||
* @date: 2024/1/6
|
||||
**/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class OrderService extends MybatisBaseService<OrderMapper, PayOrder> {
|
||||
|
||||
@Autowired
|
||||
private UrlComponent urlComponent;
|
||||
|
||||
String tradeType = "JSAPI";
|
||||
//微信统一下单
|
||||
String uniformorder = "https://api.mch.weixin.qq.com/pay/unifiedorder";
|
||||
|
||||
public ResultBean<String> createOrder(OrderDto dto) {
|
||||
ResultBean<String> rb = ResultBean.fireFail();
|
||||
PayOrder order = new PayOrder(dto.getSource());
|
||||
order.setTotalTee(dto.getTotalTee());
|
||||
order.setTimeRemarks(dto.getTimeRemarks());
|
||||
order.setName(dto.getName());
|
||||
order.setCreateBySid(dto.getUserSid());
|
||||
order.setOpenId(dto.getOpenId());
|
||||
baseMapper.insert(order);
|
||||
/* OrderVo orderVo = new OrderVo();
|
||||
Map<Object, Object> resultObj = new TreeMap();
|
||||
if (dto.getPayType() == 0) {//支付宝
|
||||
return rb.setMsg("暂不支持支付宝支付");
|
||||
} else if (dto.getPayType() == 1) {
|
||||
try {
|
||||
Map<Object, Object> parame = new TreeMap<Object, Object>();
|
||||
parame.put("appid", order.getAppId());
|
||||
// 商家账号。
|
||||
parame.put("mch_id", order.getMchId());
|
||||
String randomStr = CharUtil.getRandomNum(18).toUpperCase();
|
||||
// 随机字符串
|
||||
parame.put("nonce_str", randomStr);
|
||||
// 商户订单编号
|
||||
parame.put("out_trade_no", order.getOutTradeNo());
|
||||
|
||||
// 商品描述
|
||||
parame.put("body", order.getRemark());
|
||||
|
||||
//支付金额
|
||||
parame.put("total_fee", new BigDecimal(dto.getTotalTee()).multiply(new BigDecimal(100)).intValue());
|
||||
// 回调地址
|
||||
parame.put("notify_url", "http://192.168.0.111:7777/wxPay/payNotify");
|
||||
// 交易类型APP
|
||||
parame.put("trade_type", tradeType);
|
||||
parame.put("spbill_create_ip", ip);
|
||||
parame.put("openid", dto.getOpenId());
|
||||
String sign = WechatUtil.arraySign(parame, order.getSecret());
|
||||
// 数字签证
|
||||
parame.put("sign", sign);
|
||||
String xml = MapUtils.convertMap2Xml(parame);
|
||||
log.info("xml:" + xml);
|
||||
Map<String, Object> resultUn = XmlUtil.xmlStrToMap(WechatUtil.requestOnce(uniformorder, xml));
|
||||
// 响应报文
|
||||
String return_code = MapUtils.getString("return_code", resultUn);
|
||||
String return_msg = MapUtils.getString("return_msg", resultUn);
|
||||
if (return_code.equalsIgnoreCase("FAIL")) {
|
||||
return rb.setMsg("支付失败," + return_msg);
|
||||
} else if (return_code.equalsIgnoreCase("SUCCESS")) {
|
||||
String prepay_id = MapUtils.getString("prepay_id", resultUn);
|
||||
// 先生成paySign 参考https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_7&index=5
|
||||
resultObj.put("appId", order.getAppId());
|
||||
resultObj.put("timeStamp", DateUtils.timeToStr(System.currentTimeMillis() / 1000, DateUtils.DATE_TIME_PATTERN));
|
||||
resultObj.put("nonceStr", nonceStr);
|
||||
// resultObj.put("package", "prepay_id=" + prepay_id);
|
||||
resultObj.put("package", "Sign=WXPay");
|
||||
resultObj.put("partnerid", order.getMchId());
|
||||
resultObj.put("signType", "MD5");
|
||||
resultObj.put("prepayid", prepay_id);
|
||||
String paySign = WechatUtil.arraySign(resultObj, order.getSecret());
|
||||
// resultObj.put("paySign", paySign);
|
||||
resultObj.put("sign", paySign);
|
||||
return rb.success().setData(orderVo);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return rb.setMsg("支付失败,error=" + e.getMessage());
|
||||
}
|
||||
}*/
|
||||
|
||||
return rb.success().setData(order.getSid());
|
||||
}
|
||||
|
||||
public ResultBean pay(OrderQuery query, String ip) {
|
||||
ResultBean rb = ResultBean.fireFail();
|
||||
PayOrder payOrder = fetchBySid(query.getMainSid());
|
||||
if (payOrder == null) {
|
||||
return rb.setMsg("此订单不存在");
|
||||
}
|
||||
//验证订单是否已过期
|
||||
Date createTime = payOrder.getCreateTime();
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(createTime);
|
||||
calendar.add(Calendar.MINUTE, payOrder.getTimeRemarks());
|
||||
//过期时间
|
||||
long newTimeInMillis = calendar.getTimeInMillis();
|
||||
// 获取当前时间的毫秒表示
|
||||
long currentTimeInMillis = System.currentTimeMillis();
|
||||
if (newTimeInMillis < currentTimeInMillis) {
|
||||
return rb.setMsg("订单已过期");
|
||||
}
|
||||
//订单是否已支付过
|
||||
if (payOrder.getState() == 2) {
|
||||
return rb.setMsg("订单不是未支付,不能重复支付");
|
||||
}
|
||||
Map<Object, Object> resultObj = new TreeMap();
|
||||
if (query.getType().equals(PayTypeEnum.WECHAT.getCode())) {//微信
|
||||
WxPayVo wxPayVo = new WxPayVo(payOrder.getSource());
|
||||
String nonceStr = CharUtil.getRandomString(32);
|
||||
try {
|
||||
Map<Object, Object> parame = new TreeMap<Object, Object>();
|
||||
parame.put("appid", wxPayVo.getAppId());
|
||||
// 商家账号。
|
||||
parame.put("mch_id", wxPayVo.getMchId());
|
||||
String randomStr = CharUtil.getRandomNum(18).toUpperCase();
|
||||
// 随机字符串
|
||||
parame.put("nonce_str", randomStr);
|
||||
// 商户订单编号
|
||||
parame.put("out_trade_no", payOrder.getOutTradeNo());
|
||||
|
||||
// 商品描述
|
||||
parame.put("body", payOrder.getName());
|
||||
|
||||
//支付金额
|
||||
parame.put("total_fee", new BigDecimal(payOrder.getTotalTee()).multiply(new BigDecimal(100)).intValue());
|
||||
// 回调地址
|
||||
parame.put("notify_url", urlComponent.getDoMainUrl() + "/wxPay/payNotify");
|
||||
// 交易类型APP
|
||||
parame.put("trade_type", tradeType);
|
||||
parame.put("spbill_create_ip", ip);
|
||||
parame.put("openid", payOrder.getOpenId());
|
||||
String sign = WechatUtil.arraySign(parame, wxPayVo.getSecret());
|
||||
// 数字签证
|
||||
parame.put("sign", sign);
|
||||
String xml = MapUtils.convertMap2Xml(parame);
|
||||
log.info("xml:" + xml);
|
||||
Map<String, Object> resultUn = XmlUtil.xmlStrToMap(WechatUtil.requestOnce(uniformorder, xml));
|
||||
// 响应报文
|
||||
String return_code = MapUtils.getString("return_code", resultUn);
|
||||
String return_msg = MapUtils.getString("return_msg", resultUn);
|
||||
if (return_code.equalsIgnoreCase("FAIL")) {
|
||||
return rb.setMsg("支付失败," + return_msg);
|
||||
} else if (return_code.equalsIgnoreCase("SUCCESS")) {
|
||||
String prepay_id = MapUtils.getString("prepay_id", resultUn);
|
||||
// 先生成paySign 参考https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_7&index=5
|
||||
resultObj.put("appId", wxPayVo.getAppId());
|
||||
resultObj.put("timeStamp", DateUtils.timeToStr(System.currentTimeMillis() / 1000, DateUtils.DATE_TIME_PATTERN));
|
||||
resultObj.put("nonceStr", nonceStr);
|
||||
// resultObj.put("package", "prepay_id=" + prepay_id);
|
||||
resultObj.put("package", "Sign=WXPay");
|
||||
resultObj.put("partnerid", wxPayVo.getMchId());
|
||||
resultObj.put("signType", "MD5");
|
||||
resultObj.put("prepayid", prepay_id);
|
||||
String paySign = WechatUtil.arraySign(resultObj, wxPayVo.getSecret());
|
||||
// resultObj.put("paySign", paySign);
|
||||
resultObj.put("sign", paySign);
|
||||
payOrder.setPayType(PayTypeEnum.WECHAT.getCode());
|
||||
baseMapper.updateById(payOrder);
|
||||
return rb.success().setData(resultObj);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return rb.setMsg("支付失败,error=" + e.getMessage());
|
||||
}
|
||||
} else {
|
||||
|
||||
}
|
||||
return rb;
|
||||
}
|
||||
|
||||
public ResultBean wxPayNotify(ServletInputStream inputStream) {
|
||||
ResultBean rb = ResultBean.fireFail();
|
||||
try {
|
||||
ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
|
||||
byte[] buffer = new byte[1024];
|
||||
int len = 0;
|
||||
while ((len = inputStream.read(buffer)) != -1) {
|
||||
outSteam.write(buffer, 0, len);
|
||||
}
|
||||
outSteam.close();
|
||||
inputStream.close(); //xml数据
|
||||
String reponseXml = new String(outSteam.toByteArray(), "utf-8");
|
||||
WechatRefundApiResult result = (WechatRefundApiResult) XmlUtil.xmlStrToBean(reponseXml, WechatRefundApiResult.class);
|
||||
String result_code = result.getResult_code();
|
||||
//订单编号
|
||||
String out_trade_no = result.getOut_trade_no();
|
||||
log.error("订单" + out_trade_no + "支付成功");
|
||||
// 业务处理
|
||||
//根据订单编号查询
|
||||
PayOrder payOrder = baseMapper.selectBySn(out_trade_no);
|
||||
payOrder.setState(2);
|
||||
payOrder.setModifyTime(new Date());
|
||||
payOrder.setPayTypeValue("微信");
|
||||
if (result_code.equalsIgnoreCase("FAIL")) {
|
||||
log.error("订单" + out_trade_no + "支付失败");
|
||||
return rb.setMsg("订单" + out_trade_no + "支付失败");
|
||||
} else if (result_code.equalsIgnoreCase("SUCCESS")) {
|
||||
baseMapper.updateById(payOrder);
|
||||
return rb.success();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return rb;
|
||||
}
|
||||
|
||||
public ResultBean selectOrder(OrderQuery query) {
|
||||
ResultBean rb = ResultBean.fireFail();
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
PayOrder payOrder = fetchBySid(query.getMainSid());
|
||||
if (payOrder == null) {
|
||||
return rb.setMsg("订单不存在");
|
||||
}
|
||||
map.put("createTime", DateUtils.format(payOrder.getCreateTime(), "yyyy-MM-dd HH:mm:ss"));
|
||||
map.put("payTime", DateUtils.format(payOrder.getModifyTime(), "yyyy-MM-dd HH:mm:ss"));
|
||||
map.put("outTradeNo", payOrder.getOutTradeNo());
|
||||
map.put("mainSid", payOrder.getSid());
|
||||
map.put("payType", payOrder.getPayTypeValue());
|
||||
return rb.success().setData(map);
|
||||
}
|
||||
}
|
||||
144
src/main/java/com/yxt/pay/biz/wxpay/WxPayRest.java
Normal file
144
src/main/java/com/yxt/pay/biz/wxpay/WxPayRest.java
Normal file
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
package com.yxt.pay.biz.wxpay;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.nacos.client.utils.ValidatorUtils;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.yxt.common.base.utils.StringUtils;
|
||||
import com.yxt.common.core.result.ResultBean;
|
||||
import com.yxt.pay.api.wxpay.*;
|
||||
import com.yxt.pay.config.WxPayApi;
|
||||
import com.yxt.pay.utils.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
*/
|
||||
/**
|
||||
* @description:
|
||||
* @author: dimengzhe
|
||||
* @date: 2024/1/3
|
||||
**//*
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/wxPay")
|
||||
public class WxPayRest extends AbstractWxPayApiController {
|
||||
|
||||
private Logger log = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
@Autowired
|
||||
WxPayBean wxPayBean;
|
||||
|
||||
private String notifyUrl;
|
||||
private String refundNotifyUrl;
|
||||
private static final String USER_PAYING = "USERPAYING";
|
||||
|
||||
@Override
|
||||
public WxPayApiConfig getApiConfig() {
|
||||
WxPayApiConfig apiConfig;
|
||||
try {
|
||||
apiConfig = WxPayApiConfigKit.getApiConfig(wxPayBean.getAppId());
|
||||
} catch (Exception e) {
|
||||
apiConfig = WxPayApiConfig.builder()
|
||||
.appId(wxPayBean.getAppId())
|
||||
.mchId(wxPayBean.getMchId())
|
||||
.partnerKey(wxPayBean.getPartnerKey())
|
||||
.certPath(wxPayBean.getCertPath())
|
||||
.domain(wxPayBean.getDomain())
|
||||
.build();
|
||||
}
|
||||
notifyUrl = apiConfig.getDomain().concat("/wxPay/payNotify");
|
||||
refundNotifyUrl = apiConfig.getDomain().concat("/wxPay/refundNotify");
|
||||
return apiConfig;
|
||||
}
|
||||
|
||||
@PostMapping(value = "/miniAppPay")
|
||||
ResultBean miniAppPay(HttpServletRequest request, PayOrderQuery payOrderQuery) {
|
||||
ResultBean rb = ResultBean.fireFail();
|
||||
try {
|
||||
String ip = IpKit.getRealIp(request);
|
||||
if (StringUtils.isBlank(ip)) {
|
||||
ip = "127.0.0.1";
|
||||
}
|
||||
WxPayBean wxPayApiConfig = new WxPayBean();
|
||||
|
||||
wxPayApiConfig.setAppId(payOrderQuery.getAppId());
|
||||
wxPayApiConfig.setMchId(payOrderQuery.getMchId());
|
||||
wxPayApiConfig.setDomain(payOrderQuery.getNotifyUrl());
|
||||
wxPayApiConfig.setPartnerKey(payOrderQuery.getPaySignKey());
|
||||
Map<String, String> params = UnifiedOrderModel
|
||||
.builder()
|
||||
.appid(wxPayApiConfig.getAppId())
|
||||
.mch_id(wxPayApiConfig.getMchId())
|
||||
.nonce_str(WxPayKit.generateStr())
|
||||
.body("小程序支付")
|
||||
.attach("Node.js 版:https://gitee.com/javen205/TNW")
|
||||
.out_trade_no(payOrderQuery.getOrderSn())
|
||||
.total_fee(new BigDecimal(payOrderQuery.getAmount()).multiply(new BigDecimal("100")) + "")
|
||||
.spbill_create_ip(ip)
|
||||
.notify_url(notifyUrl)
|
||||
.trade_type(TradeType.JSAPI.getTradeType())
|
||||
.openid(payOrderQuery.getOpenId())
|
||||
.build()
|
||||
.createSign(wxPayApiConfig.getPartnerKey(), SignType.HMACSHA256);
|
||||
//统一下单
|
||||
String xmlResult = WxPayApi.pushOrder(false, params);
|
||||
log.info(xmlResult);
|
||||
Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
|
||||
|
||||
String returnCode = result.get("return_code");
|
||||
String returnMsg = result.get("return_msg");
|
||||
if (!WxPayKit.codeIsOk(returnCode)) {
|
||||
return rb.setMsg(returnMsg);
|
||||
}
|
||||
String resultCode = result.get("result_code");
|
||||
if (!WxPayKit.codeIsOk(resultCode)) {
|
||||
return rb.setMsg(returnMsg);
|
||||
}
|
||||
// 以下字段在 return_code 和 result_code 都为 SUCCESS 的时候有返回(统一下单成功)
|
||||
String prepayId = result.get("prepay_id");
|
||||
Map<String, String> packageParams = WxPayKit.miniAppPrepayIdCreateSign(wxPayApiConfig.getAppId(), prepayId,
|
||||
wxPayApiConfig.getPartnerKey(), SignType.HMACSHA256);
|
||||
String jsonStr = JSON.toJSONString(packageParams);
|
||||
log.info("小程序支付的参数:" + jsonStr);
|
||||
return rb.success().setData(packageParams);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return rb.setMsg(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping(value = "/payNotify")
|
||||
@ResponseBody
|
||||
public String payNotify(HttpServletRequest request) {
|
||||
String xmlMsg = HttpKit.readData(request);
|
||||
Map<String, String> params = WxPayKit.xmlToMap(xmlMsg);
|
||||
log.info("微信支付通知=" + params);
|
||||
String returnCode = params.get("return_code");
|
||||
//订单编号
|
||||
String out_trade_no = params.get("out_trade_no");
|
||||
// 注意重复通知的情况,同一订单号可能收到多次通知,请注意一定先判断订单状态
|
||||
// 注意此处签名方式需与统一下单的签名类型一致
|
||||
if (WxPayKit.verifyNotify(params, this.getApiConfig().getPartnerKey(), SignType.HMACSHA256)) {
|
||||
if (WxPayKit.codeIsOk(returnCode)) {
|
||||
// 发送通知等
|
||||
Map<String, String> xml = new HashMap<String, String>(2);
|
||||
xml.put("return_code", "SUCCESS");
|
||||
xml.put("return_msg", "OK");
|
||||
return WxPayKit.toXml(xml);
|
||||
} else {
|
||||
log.error("订单" + out_trade_no + "支付失败");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
*/
|
||||
13
src/main/java/com/yxt/pay/biz/wxpay/WxPayService.java
Normal file
13
src/main/java/com/yxt/pay/biz/wxpay/WxPayService.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package com.yxt.pay.biz.wxpay;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @description:
|
||||
* @author: dimengzhe
|
||||
* @date: 2024/1/7
|
||||
**/
|
||||
@Service
|
||||
public class WxPayService {
|
||||
|
||||
}
|
||||
126
src/main/java/com/yxt/pay/utils/ApiBaseAction.java
Normal file
126
src/main/java/com/yxt/pay/utils/ApiBaseAction.java
Normal file
@@ -0,0 +1,126 @@
|
||||
package com.yxt.pay.utils;
|
||||
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.TypeMismatchException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.propertyeditors.StringTrimmerEditor;
|
||||
import org.springframework.validation.BindException;
|
||||
import org.springframework.web.bind.MissingServletRequestParameterException;
|
||||
import org.springframework.web.bind.WebDataBinder;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.InitBinder;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.context.request.WebRequest;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* @author mallplus
|
||||
* @ClassName: ApiBaseAction
|
||||
* @Description: 基础控制类
|
||||
* @date 2016年9月2日
|
||||
*/
|
||||
@Slf4j
|
||||
public class ApiBaseAction {
|
||||
|
||||
/**
|
||||
* 得到request对象
|
||||
*/
|
||||
@Autowired
|
||||
protected HttpServletRequest request;
|
||||
/**
|
||||
* 得到response对象
|
||||
*/
|
||||
@Resource
|
||||
protected HttpServletResponse response;
|
||||
/**
|
||||
* 获取请求的用户Id
|
||||
*
|
||||
* @return 客户端Ip
|
||||
*/
|
||||
/*public String getUserId() {
|
||||
String token = request.getHeader(AuthorizationInterceptor.LOGIN_TOKEN_KEY);
|
||||
//查询token信息
|
||||
TokenEntity tokenEntity = tokenService.queryByToken(token);
|
||||
if (tokenEntity == null || tokenEntity.getExpireTime().getTime() < System.currentTimeMillis()) {
|
||||
return null;
|
||||
}
|
||||
return tokenEntity.getUserId();
|
||||
}*/
|
||||
|
||||
/**
|
||||
* @param requestCode
|
||||
* @param msg
|
||||
* @param data
|
||||
* @return Map<String, Object>
|
||||
* @throws
|
||||
* @Description:构建统一格式返回对象
|
||||
* @date 2016年9月2日
|
||||
* @author zhuliyun
|
||||
*/
|
||||
public static Map<String, Object> toResponsObject(int requestCode, String msg, Object data) {
|
||||
Map<String, Object> obj = new HashMap<String, Object>();
|
||||
obj.put("code", requestCode);
|
||||
obj.put("msg", msg);
|
||||
if (data != null)
|
||||
obj.put("data", data);
|
||||
return obj;
|
||||
}
|
||||
|
||||
public static Map<String, Object> toResponsSuccessForSelect(Object data) {
|
||||
Map<String, Object> result = new HashMap<>(2);
|
||||
result.put("list", data);
|
||||
return toResponsObject(200, "执行成功", result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 参数绑定异常
|
||||
*/
|
||||
@ExceptionHandler({BindException.class, MissingServletRequestParameterException.class, TypeMismatchException.class})
|
||||
@ResponseBody
|
||||
public Map<String, Object> bindException(Exception e) {
|
||||
if (e instanceof BindException) {
|
||||
return toResponsObject(1, "参数绑定异常", e.getMessage());
|
||||
}
|
||||
return toResponsObject(1, "处理异常", e.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* initBinder 初始化绑定 <br>
|
||||
* 这里处理了3种类型<br>
|
||||
* 1、字符串自动 trim 去掉前后空格 <br>
|
||||
* 2、java.util.Date 转换为 "yyyy-MM-dd HH:mm:ss" 格式<br>
|
||||
* 3、java.sql.Date 转换为 "yyyy-MM-dd" 格式<br>
|
||||
* 4、java.util.Timestamps 时间转换
|
||||
*
|
||||
* @param binder WebDataBinder 要注册的binder
|
||||
* @param request 前端请求
|
||||
*/
|
||||
@InitBinder
|
||||
public void initBinder(WebDataBinder binder, WebRequest request) {
|
||||
|
||||
// 字符串自动Trim
|
||||
binder.registerCustomEditor(String.class, new StringTrimmerEditor(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取请求方IP
|
||||
*
|
||||
* @return 客户端Ip
|
||||
*/
|
||||
public String getClientIp() {
|
||||
String xff = request.getHeader("x-forwarded-for");
|
||||
if (xff == null) {
|
||||
xff = "127.0.0.1";
|
||||
}
|
||||
return xff;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
80
src/main/java/com/yxt/pay/utils/CharUtil.java
Normal file
80
src/main/java/com/yxt/pay/utils/CharUtil.java
Normal file
@@ -0,0 +1,80 @@
|
||||
package com.yxt.pay.utils;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class CharUtil {
|
||||
|
||||
/**
|
||||
* 获取随机字符串
|
||||
*
|
||||
* @param num
|
||||
* @return
|
||||
*/
|
||||
public static String getRandomString(Integer num) {
|
||||
String base = "abcdefghijklmnopqrstuvwxyz0123456789";
|
||||
Random random = new Random();
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (int i = 0; i < num; i++) {
|
||||
int number = random.nextInt(base.length());
|
||||
sb.append(base.charAt(number));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取随机字符串
|
||||
*
|
||||
* @param num
|
||||
* @return
|
||||
*/
|
||||
public static String getRandomNum(Integer num) {
|
||||
String base = "0123456789";
|
||||
Random random = new Random();
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (int i = 0; i < num; i++) {
|
||||
int number = random.nextInt(base.length());
|
||||
sb.append(base.charAt(number));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 右补位,左对齐
|
||||
*
|
||||
* @param oriStr 原字符串
|
||||
* @param len 目标字符串长度
|
||||
* @param fillChar 补位字符
|
||||
* @return 目标字符串
|
||||
*/
|
||||
public static String padRight(String oriStr, int len, char fillChar) {
|
||||
String str = "";
|
||||
int strlen = oriStr.length();
|
||||
if (strlen < len) {
|
||||
for (int i = 0; i < len - strlen; i++) {
|
||||
str = str + fillChar;
|
||||
}
|
||||
}
|
||||
str = str + oriStr;
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* 左补位,右对齐
|
||||
*
|
||||
* @param oriStr 原字符串
|
||||
* @param len 目标字符串长度
|
||||
* @param fillChar 补位字符
|
||||
* @return 目标字符串
|
||||
*/
|
||||
public static String padLeft(String oriStr, int len, char fillChar) {
|
||||
int strlen = oriStr.length();
|
||||
String str = "";
|
||||
if (strlen < len) {
|
||||
for (int i = 0; i < len - strlen; i++) {
|
||||
str = str + fillChar;
|
||||
}
|
||||
}
|
||||
str = oriStr + str;
|
||||
return str;
|
||||
}
|
||||
}
|
||||
220
src/main/java/com/yxt/pay/utils/DateUtils.java
Normal file
220
src/main/java/com/yxt/pay/utils/DateUtils.java
Normal file
@@ -0,0 +1,220 @@
|
||||
package com.yxt.pay.utils;
|
||||
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 日期处理
|
||||
*
|
||||
* @author zscat
|
||||
* @email 951449465@qq.com
|
||||
* @date 2016年12月21日 下午12:53:33
|
||||
*/
|
||||
public class DateUtils {
|
||||
/**
|
||||
* 时间格式(yyyy-MM-dd)
|
||||
*/
|
||||
public final static String DATE_PATTERN = "yyyy-MM-dd";
|
||||
/**
|
||||
* 时间格式(yyyy-MM-dd HH:mm:ss)
|
||||
*/
|
||||
public final static String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
|
||||
/**
|
||||
* 无分隔符日期格式 "yyyyMMddHHmmssSSS"
|
||||
*/
|
||||
public static String DATE_TIME_PATTERN_YYYY_MM_DD_HH_MM_SS_SSS = "yyyyMMddHHmmssSSS";
|
||||
// 日期转换格式数组
|
||||
public static String[][] regularExp = new String[][]{
|
||||
|
||||
// 默认格式
|
||||
{"\\d{4}-((([0][1,3-9]|[1][0-2]|[1-9])-([0-2]\\d|[3][0,1]|[1-9]))|((02|2)-(([1-9])|[0-2]\\d)))\\s+([0,1]\\d|[2][0-3]|\\d):([0-5]\\d|\\d):([0-5]\\d|\\d)",
|
||||
DATE_TIME_PATTERN},
|
||||
// 仅日期格式 年月日
|
||||
{"\\d{4}-((([0][1,3-9]|[1][0-2]|[1-9])-([0-2]\\d|[3][0,1]|[1-9]))|((02|2)-(([1-9])|[0-2]\\d)))",
|
||||
DATE_PATTERN},
|
||||
// 带毫秒格式
|
||||
{"\\d{4}((([0][1,3-9]|[1][0-2]|[1-9])([0-2]\\d|[3][0,1]|[1-9]))|((02|2)(([1-9])|[0-2]\\d)))([0,1]\\d|[2][0-3])([0-5]\\d|\\d)([0-5]\\d|\\d)\\d{1,3}",
|
||||
DATE_TIME_PATTERN_YYYY_MM_DD_HH_MM_SS_SSS}
|
||||
};
|
||||
// 日志
|
||||
private static org.slf4j.Logger logger = LoggerFactory.getLogger(DateUtils.class);
|
||||
|
||||
public static String format(Date date) {
|
||||
return format(date, DATE_PATTERN);
|
||||
}
|
||||
|
||||
public static String format(Date date, String pattern) {
|
||||
if (date != null) {
|
||||
SimpleDateFormat df = new SimpleDateFormat(pattern);
|
||||
return df.format(date);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String timeToStr(Long time, String pattern) {
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat(pattern);
|
||||
if (time.toString().length() < 13) {
|
||||
time = time * 1000L;
|
||||
}
|
||||
Date date = new Date(time);
|
||||
String value = dateFormat.format(date);
|
||||
return value;
|
||||
}
|
||||
|
||||
public static long strToTime(String timeStr) {
|
||||
Date time = strToDate(timeStr);
|
||||
return time.getTime() / 1000;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 转换为时间类型格式
|
||||
*
|
||||
* @param strDate 日期
|
||||
* @return
|
||||
*/
|
||||
public static Date strToDate(String strDate) {
|
||||
try {
|
||||
String strType = getDateFormat(strDate);
|
||||
SimpleDateFormat sf = new SimpleDateFormat(strType);
|
||||
return new Date((sf.parse(strDate).getTime()));
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据传入的日期格式字符串,获取日期的格式
|
||||
*
|
||||
* @return 秒
|
||||
*/
|
||||
public static String getDateFormat(String date_str) {
|
||||
String style = null;
|
||||
if (StringUtils.isEmpty(date_str)) {
|
||||
return null;
|
||||
}
|
||||
boolean b = false;
|
||||
for (int i = 0; i < regularExp.length; i++) {
|
||||
b = date_str.matches(regularExp[i][0]);
|
||||
if (b) {
|
||||
style = regularExp[i][1];
|
||||
}
|
||||
}
|
||||
if (StringUtils.isEmpty(style)) {
|
||||
logger.info("date_str:" + date_str);
|
||||
logger.info("日期格式获取出错,未识别的日期格式");
|
||||
}
|
||||
return style;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字符串类型的转换成Date类型
|
||||
*
|
||||
* @param dateStr 字符串类型的日期 yyyy-MM-dd
|
||||
* @return Date类型的日期
|
||||
* @throws ParseException
|
||||
*/
|
||||
public static Date convertStringToDate(String dateStr) {
|
||||
// 返回的日期
|
||||
Date resultDate = null;
|
||||
try {
|
||||
// 日期格式转换
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
||||
resultDate = sdf.parse(dateStr);
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return resultDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字符串类型的转换成Date类型
|
||||
*
|
||||
* @param dateStr 字符串类型的日期 yyyy-MM-dd
|
||||
* @return Date类型的日期
|
||||
* @throws ParseException
|
||||
*/
|
||||
public static Date convertStringToDate(String dateStr, String formate) {
|
||||
// 返回的日期
|
||||
Date resultDate = null;
|
||||
try {
|
||||
// 日期格式转换
|
||||
SimpleDateFormat sdf = new SimpleDateFormat(formate);
|
||||
resultDate = sdf.parse(dateStr);
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return resultDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加小时
|
||||
*
|
||||
* @param date
|
||||
* @param hour
|
||||
* @return
|
||||
*/
|
||||
public static String addHours(Date date, int hour) {
|
||||
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.setTime(date);
|
||||
cal.add(Calendar.HOUR, hour);// 24小时制
|
||||
date = cal.getTime();
|
||||
cal = null;
|
||||
return format.format(date);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加分钟
|
||||
*
|
||||
* @param date
|
||||
* @param min
|
||||
* @return
|
||||
*/
|
||||
public static String addMins(Date date, int min) {
|
||||
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.setTime(date);
|
||||
cal.add(Calendar.MINUTE, min);// 24小时制
|
||||
date = cal.getTime();
|
||||
cal = null;
|
||||
return format.format(date);
|
||||
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws ParseException {
|
||||
System.out.println(DateUtils.addMins(new Date(), 10));
|
||||
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
// 获取当前时间
|
||||
Date date = new Date();
|
||||
String nowtime = df.format(date);
|
||||
// System.out.println(nowtime);
|
||||
Date d2 = df.parse("2019-09-10 10:07:00"); //86400000 1728
|
||||
Date d1 = df.parse(nowtime);
|
||||
|
||||
long diff = d1.getTime() - d2.getTime();// 这样得到的差值是微秒级别
|
||||
System.out.println(d1.getTime());
|
||||
System.out.println(diff);
|
||||
System.out.println(1000 * 60 * 60 * 24);
|
||||
long days = diff / (1000 * 60 * 60 * 24);//天
|
||||
|
||||
long hours = (diff - days * (1000 * 60 * 60 * 24))
|
||||
/ (1000 * 60 * 60); //小时
|
||||
long mins = (diff - days * (1000 * 60 * 60 * 24) - hours * (1000 * 60 * 60)) / (1000 * 60); //小时
|
||||
long sc = (diff - days * (1000 * 60 * 60 * 24) - hours
|
||||
* (1000 * 60 * 60) - mins * (1000 * 60)) / (1000); // 秒
|
||||
|
||||
System.out.println(days);
|
||||
System.out.println(hours);
|
||||
System.out.println(mins);
|
||||
System.out.println(sc);
|
||||
}
|
||||
}
|
||||
7
src/main/java/com/yxt/pay/utils/DealMapValueHelper.java
Normal file
7
src/main/java/com/yxt/pay/utils/DealMapValueHelper.java
Normal file
@@ -0,0 +1,7 @@
|
||||
package com.yxt.pay.utils;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public interface DealMapValueHelper {
|
||||
void dealValue(String key, Map<String, Object> map);
|
||||
}
|
||||
306
src/main/java/com/yxt/pay/utils/MapUtils.java
Normal file
306
src/main/java/com/yxt/pay/utils/MapUtils.java
Normal file
@@ -0,0 +1,306 @@
|
||||
package com.yxt.pay.utils;
|
||||
|
||||
|
||||
import com.yxt.common.base.utils.StringUtils;
|
||||
import org.apache.commons.beanutils.PropertyUtilsBean;
|
||||
import org.apache.commons.lang.ArrayUtils;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.math.BigDecimal;
|
||||
import java.sql.Date;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 获取map中值的工具类,自动进行类型转换
|
||||
*
|
||||
* @author DT_panda
|
||||
*/
|
||||
public class MapUtils {
|
||||
|
||||
public static String getString(String key, Map<String, Object> map) {
|
||||
if (map == null || key == null)
|
||||
throw new IllegalArgumentException();
|
||||
if (!map.containsKey(key))
|
||||
return null;
|
||||
Object value = map.get(key);
|
||||
if (value == null)
|
||||
return null;
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
public static Integer getInteger(String key, Map<String, Object> map) {
|
||||
if (map == null || key == null) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
if (!map.containsKey(key)) {
|
||||
return null;
|
||||
}
|
||||
Object value = map.get(key);
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Integer) {
|
||||
return (Integer) value;
|
||||
}
|
||||
if (value instanceof String)
|
||||
return Integer.valueOf((String) value);
|
||||
//Date 不支持变成为date类型
|
||||
if (value instanceof Date)
|
||||
throw new ClassCastException();
|
||||
if (value instanceof Number)
|
||||
return ((Number) value).intValue();
|
||||
throw new ClassCastException();
|
||||
}
|
||||
|
||||
public static Long getLong(String key, Map<String, Object> map) {
|
||||
if (map == null || key == null)
|
||||
throw new IllegalArgumentException();
|
||||
if (!map.containsKey(key))
|
||||
return null;
|
||||
Object value = map.get(key);
|
||||
if (value == null)
|
||||
return null;
|
||||
if (value instanceof Long)
|
||||
return (Long) value;
|
||||
if (value instanceof Number)
|
||||
return ((Number) value).longValue();
|
||||
if (value instanceof String)
|
||||
return Long.valueOf((String) value);
|
||||
if (value instanceof Date) {
|
||||
return (((Date) value).getTime());
|
||||
}
|
||||
if (value instanceof java.sql.Time) {
|
||||
return ((java.sql.Time) value).getTime();
|
||||
}
|
||||
if (value instanceof Timestamp) {
|
||||
return ((Timestamp) value).getTime();
|
||||
}
|
||||
|
||||
throw new ClassCastException();
|
||||
}
|
||||
|
||||
public static Double getDouble(String key, Map<String, Object> map) {
|
||||
if (map == null || key == null)
|
||||
throw new IllegalArgumentException();
|
||||
if (!map.containsKey(key))
|
||||
return null;
|
||||
Object value = map.get(key);
|
||||
if (value == null)
|
||||
return null;
|
||||
if (value instanceof Double)
|
||||
return (Double) value;
|
||||
if (value instanceof Number)
|
||||
return ((Number) value).doubleValue();
|
||||
if (value instanceof String)
|
||||
return Double.valueOf((String) value);
|
||||
throw new ClassCastException();
|
||||
}
|
||||
|
||||
public static BigDecimal getBigDecimal(String key, Map<String, Object> map) {
|
||||
if (map == null || key == null)
|
||||
throw new IllegalArgumentException();
|
||||
if (!map.containsKey(key))
|
||||
return null;
|
||||
Object value = map.get(key);
|
||||
if (value == null)
|
||||
return null;
|
||||
if (value instanceof BigDecimal)
|
||||
return (BigDecimal) value;
|
||||
if (value instanceof Integer)
|
||||
return new BigDecimal((Integer) value);
|
||||
if (value instanceof Short)
|
||||
return new BigDecimal((Short) value);
|
||||
if (value instanceof Byte)
|
||||
return new BigDecimal((Byte) value);
|
||||
if (value instanceof Long)
|
||||
return new BigDecimal((Long) value);
|
||||
if (value instanceof Float)
|
||||
return new BigDecimal((Float) value);
|
||||
if (value instanceof Double)
|
||||
return new BigDecimal((Double) value);
|
||||
if (value instanceof Date) {
|
||||
return new BigDecimal(((Date) value).getTime());
|
||||
}
|
||||
if (value instanceof java.sql.Time) {
|
||||
return new BigDecimal(((java.sql.Time) value).getTime());
|
||||
}
|
||||
if (value instanceof Timestamp) {
|
||||
return new BigDecimal(((Timestamp) value).getTime());
|
||||
}
|
||||
if (value instanceof String) {
|
||||
if (!StringUtils.isBlank((String) value))
|
||||
return new BigDecimal((String) value);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
throw new ClassCastException();
|
||||
}
|
||||
|
||||
/**
|
||||
* 将bean转化为map
|
||||
*
|
||||
* @param bean
|
||||
* @return
|
||||
*/
|
||||
public static Map<String, Object> getMap(Object bean) {
|
||||
return beanToMap(bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将map中key为likeKey的value前后加上字符'%',用于like查询
|
||||
*
|
||||
* @param map
|
||||
* @param likeKey
|
||||
*/
|
||||
public static void toLikeValue(Map<String, Object> map, String... likeKey) {
|
||||
if (ArrayUtils.isEmpty(likeKey))
|
||||
return;
|
||||
for (String key : likeKey) {
|
||||
if (map.containsKey(key))
|
||||
map.put(key, "%" + map.get(key) + "%");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取日期
|
||||
*
|
||||
* @param key
|
||||
* @param map
|
||||
* @return
|
||||
*/
|
||||
public static Date getDate(String key, Map<String, Object> map) {
|
||||
if (map == null || key == null)
|
||||
throw new IllegalArgumentException();
|
||||
if (!map.containsKey(key))
|
||||
return null;
|
||||
Object value = map.get(key);
|
||||
if (value == null)
|
||||
return null;
|
||||
else {
|
||||
if (value instanceof Date) {
|
||||
return (Date) value;
|
||||
} else if (value instanceof Timestamp) {
|
||||
return new Date(((Timestamp) value).getTime());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取日期
|
||||
*
|
||||
* @param key
|
||||
* @param map
|
||||
* @return
|
||||
*/
|
||||
public static java.util.Date getTimestamp(String key, Map<String, Object> map) {
|
||||
if (map == null || key == null)
|
||||
throw new IllegalArgumentException();
|
||||
if (!map.containsKey(key))
|
||||
return null;
|
||||
Object value = map.get(key);
|
||||
if (value == null)
|
||||
return null;
|
||||
else {
|
||||
if (value instanceof Date) {
|
||||
return (Date) value;
|
||||
} else if (value instanceof Timestamp) {
|
||||
Timestamp ts = (Timestamp) value;
|
||||
return ts;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果value不为空 ,则放到map中
|
||||
*
|
||||
* @param map
|
||||
* @param key
|
||||
* @param value
|
||||
*/
|
||||
public static void putIfValueNotNull(Map<String, Object> map, String key, Object value) {
|
||||
Assert.notNull(map);
|
||||
Assert.hasText(key);
|
||||
if (value != null)
|
||||
map.put(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果value不为空 ,则放到map中
|
||||
*
|
||||
* @param map
|
||||
* @param key
|
||||
* @param value
|
||||
*/
|
||||
public static void putIfValueNotEmpty(Map<String, Object> map, String key, String value) {
|
||||
Assert.notNull(map);
|
||||
Assert.hasText(key);
|
||||
if (!StringUtils.isBlank(value))
|
||||
map.put(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将map中指定的key的value值进行处理
|
||||
*
|
||||
* @param key
|
||||
* @param map
|
||||
* @param helper
|
||||
*/
|
||||
public static void convertMapValuePattern(String key, Map<String, Object> map, DealMapValueHelper helper) {
|
||||
Assert.hasText(key);
|
||||
Assert.notNull(map);
|
||||
Assert.notNull(helper);
|
||||
helper.dealValue(key, map);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将javabean实体类转为map类型,然后返回一个map类型的值
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static Map<String, Object> beanToMap(Object beanObj) {
|
||||
Map<String, Object> params = new HashMap<String, Object>(0);
|
||||
try {
|
||||
PropertyUtilsBean propertyUtilsBean = new PropertyUtilsBean();
|
||||
PropertyDescriptor[] descriptors = propertyUtilsBean.getPropertyDescriptors(beanObj);
|
||||
for (int i = 0; i < descriptors.length; i++) {
|
||||
String name = descriptors[i].getName();
|
||||
if (!"class".equals(name)) {
|
||||
params.put(name, propertyUtilsBean.getNestedProperty(beanObj, name));
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
public static String convertMap2Xml(Map<Object, Object> paraMap) {
|
||||
StringBuffer xmlStr = new StringBuffer();
|
||||
if (paraMap != null) {
|
||||
xmlStr.append("<xml>");
|
||||
Set<Object> keySet = paraMap.keySet();
|
||||
Iterator<Object> keyIte = keySet.iterator();
|
||||
while (keyIte.hasNext()) {
|
||||
String key = (String) keyIte.next();
|
||||
String val = String.valueOf(paraMap.get(key));
|
||||
xmlStr.append("<");
|
||||
xmlStr.append(key);
|
||||
xmlStr.append(">");
|
||||
xmlStr.append(val);
|
||||
xmlStr.append("</");
|
||||
xmlStr.append(key);
|
||||
xmlStr.append(">");
|
||||
}
|
||||
xmlStr.append("</xml>");
|
||||
}
|
||||
return xmlStr.toString();
|
||||
}
|
||||
}
|
||||
|
||||
20
src/main/java/com/yxt/pay/utils/UrlComponent.java
Normal file
20
src/main/java/com/yxt/pay/utils/UrlComponent.java
Normal file
@@ -0,0 +1,20 @@
|
||||
package com.yxt.pay.utils;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @description:
|
||||
* @author: dimengzhe
|
||||
* @date: 2024/1/7
|
||||
**/
|
||||
@Component
|
||||
public class UrlComponent {
|
||||
|
||||
@Value("${domain.url:http://127.0.0.1:7777}")
|
||||
private String doMainUrl;
|
||||
|
||||
public String getDoMainUrl() {
|
||||
return doMainUrl;
|
||||
}
|
||||
}
|
||||
254
src/main/java/com/yxt/pay/utils/XmlHelper.java
Normal file
254
src/main/java/com/yxt/pay/utils/XmlHelper.java
Normal file
@@ -0,0 +1,254 @@
|
||||
package com.yxt.pay.utils;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.xpath.XPath;
|
||||
import javax.xml.xpath.XPathConstants;
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
import javax.xml.xpath.XPathFactory;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.StringReader;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* xpath解析xml
|
||||
* <p>
|
||||
* <pre>
|
||||
* 文档地址:
|
||||
* http://www.w3school.com.cn/xpath/index.asp
|
||||
* </pre>
|
||||
*
|
||||
* @author L.cm
|
||||
*/
|
||||
public class XmlHelper {
|
||||
private final XPath path;
|
||||
private final Document doc;
|
||||
|
||||
private XmlHelper(InputSource inputSource) throws ParserConfigurationException, SAXException, IOException {
|
||||
DocumentBuilderFactory dbf = getDocumentBuilderFactory();
|
||||
// This is the PRIMARY defense. If DTDs (doctypes) are disallowed, almost all
|
||||
// XML entity attacks are prevented
|
||||
// Xerces 2 only -
|
||||
// http://xerces.apache.org/xerces2-j/features.html#disallow-doctype-decl
|
||||
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
|
||||
|
||||
// If you can't completely disable DTDs, then at least do the following:
|
||||
// Xerces 1 -
|
||||
// http://xerces.apache.org/xerces-j/features.html#external-general-entities
|
||||
// Xerces 2 -
|
||||
// http://xerces.apache.org/xerces2-j/features.html#external-general-entities
|
||||
// JDK7+ - http://xml.org/sax/features/external-general-entities
|
||||
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
|
||||
|
||||
// Xerces 1 -
|
||||
// http://xerces.apache.org/xerces-j/features.html#external-parameter-entities
|
||||
// Xerces 2 -
|
||||
// http://xerces.apache.org/xerces2-j/features.html#external-parameter-entities
|
||||
// JDK7+ - http://xml.org/sax/features/external-parameter-entities
|
||||
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
|
||||
|
||||
// Disable external DTDs as well
|
||||
dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
|
||||
|
||||
// and these as well, per Timothy Morgan's 2014 paper: "XML Schema, DTD, and
|
||||
// Entity Attacks"
|
||||
dbf.setXIncludeAware(false);
|
||||
dbf.setExpandEntityReferences(false);
|
||||
DocumentBuilder db = dbf.newDocumentBuilder();
|
||||
doc = db.parse(inputSource);
|
||||
path = getXpathFactory().newXPath();
|
||||
}
|
||||
|
||||
private static XmlHelper create(InputSource inputSource) {
|
||||
try {
|
||||
return new XmlHelper(inputSource);
|
||||
} catch (ParserConfigurationException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (SAXException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static XmlHelper of(InputStream is) {
|
||||
InputSource inputSource = new InputSource(is);
|
||||
return create(inputSource);
|
||||
}
|
||||
|
||||
public static XmlHelper of(File file) {
|
||||
InputSource inputSource = new InputSource(file.toURI().toASCIIString());
|
||||
return create(inputSource);
|
||||
}
|
||||
|
||||
public static XmlHelper of(String xmlStr) {
|
||||
StringReader sr = new StringReader(xmlStr.trim());
|
||||
InputSource inputSource = new InputSource(sr);
|
||||
XmlHelper xmlHelper = create(inputSource);
|
||||
sr.close();
|
||||
return xmlHelper;
|
||||
}
|
||||
|
||||
private static DocumentBuilderFactory getDocumentBuilderFactory() {
|
||||
return XmlHelperHolder.documentBuilderFactory;
|
||||
}
|
||||
|
||||
private static XPathFactory getXpathFactory() {
|
||||
return XmlHelperHolder.xPathFactory;
|
||||
}
|
||||
|
||||
private Object evalXpath(String expression, Object item, QName returnType) {
|
||||
item = null == item ? doc : item;
|
||||
try {
|
||||
return path.evaluate(expression, item, returnType);
|
||||
} catch (XPathExpressionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取String
|
||||
*
|
||||
* @param expression 路径
|
||||
* @return String
|
||||
*/
|
||||
public String getString(String expression) {
|
||||
return (String) evalXpath(expression, null, XPathConstants.STRING);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Boolean
|
||||
*
|
||||
* @param expression 路径
|
||||
* @return String
|
||||
*/
|
||||
public Boolean getBoolean(String expression) {
|
||||
return (Boolean) evalXpath(expression, null, XPathConstants.BOOLEAN);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Number
|
||||
*
|
||||
* @param expression 路径
|
||||
* @return {Number}
|
||||
*/
|
||||
public Number getNumber(String expression) {
|
||||
return (Number) evalXpath(expression, null, XPathConstants.NUMBER);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取某个节点
|
||||
*
|
||||
* @param expression 路径
|
||||
* @return {Node}
|
||||
*/
|
||||
public Node getNode(String expression) {
|
||||
return (Node) evalXpath(expression, null, XPathConstants.NODE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取子节点
|
||||
*
|
||||
* @param expression 路径
|
||||
* @return NodeList
|
||||
*/
|
||||
public NodeList getNodeList(String expression) {
|
||||
return (NodeList) evalXpath(expression, null, XPathConstants.NODESET);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取String
|
||||
*
|
||||
* @param node 节点
|
||||
* @param expression 相对于node的路径
|
||||
* @return String
|
||||
*/
|
||||
public String getString(Object node, String expression) {
|
||||
return (String) evalXpath(expression, node, XPathConstants.STRING);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取
|
||||
*
|
||||
* @param node 节点
|
||||
* @param expression 相对于node的路径
|
||||
* @return String
|
||||
*/
|
||||
public Boolean getBoolean(Object node, String expression) {
|
||||
return (Boolean) evalXpath(expression, node, XPathConstants.BOOLEAN);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取
|
||||
*
|
||||
* @param node 节点
|
||||
* @param expression 相对于node的路径
|
||||
* @return {Number}
|
||||
*/
|
||||
public Number getNumber(Object node, String expression) {
|
||||
return (Number) evalXpath(expression, node, XPathConstants.NUMBER);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取某个节点
|
||||
*
|
||||
* @param node 节点
|
||||
* @param expression 路径
|
||||
* @return {Node}
|
||||
*/
|
||||
public Node getNode(Object node, String expression) {
|
||||
return (Node) evalXpath(expression, node, XPathConstants.NODE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取子节点
|
||||
*
|
||||
* @param node 节点
|
||||
* @param expression 相对于node的路径
|
||||
* @return NodeList
|
||||
*/
|
||||
public NodeList getNodeList(Object node, String expression) {
|
||||
return (NodeList) evalXpath(expression, node, XPathConstants.NODESET);
|
||||
}
|
||||
|
||||
/**
|
||||
* 针对没有嵌套节点的简单处理
|
||||
*
|
||||
* @return map集合
|
||||
*/
|
||||
public Map<String, String> toMap() {
|
||||
Element root = doc.getDocumentElement();
|
||||
|
||||
// 将节点封装成map形式
|
||||
NodeList list = root.getChildNodes();
|
||||
Map<String, String> params = new HashMap<String, String>(list.getLength());
|
||||
for (int i = 0; i < list.getLength(); i++) {
|
||||
Node node = list.item(i);
|
||||
params.put(node.getNodeName(), node.getTextContent());
|
||||
}
|
||||
// 含有空白符会生成一个#text参数
|
||||
params.remove("#text");
|
||||
return params;
|
||||
}
|
||||
|
||||
/**
|
||||
* 内部类单例
|
||||
*/
|
||||
private static class XmlHelperHolder {
|
||||
private static DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
|
||||
private static XPathFactory xPathFactory = XPathFactory.newInstance();
|
||||
}
|
||||
|
||||
}
|
||||
201
src/main/java/com/yxt/pay/utils/XmlUtil.java
Normal file
201
src/main/java/com/yxt/pay/utils/XmlUtil.java
Normal file
@@ -0,0 +1,201 @@
|
||||
package com.yxt.pay.utils;
|
||||
|
||||
|
||||
import com.yxt.common.base.utils.StringUtils;
|
||||
import org.dom4j.Document;
|
||||
import org.dom4j.DocumentHelper;
|
||||
import org.dom4j.Element;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* xml相关的工具类
|
||||
*
|
||||
* @author yang.y
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public class XmlUtil {
|
||||
|
||||
/**
|
||||
* xml字符串转换成bean对象
|
||||
*
|
||||
* @param xmlStr xml字符串
|
||||
* @param clazz 待转换的class
|
||||
* @return 转换后的对象
|
||||
*/
|
||||
public static Object xmlStrToBean(String xmlStr, Class clazz) {
|
||||
Object obj = null;
|
||||
try {
|
||||
// 将xml格式的数据转换成Map对象
|
||||
Map<String, Object> map = xmlStrToMap(xmlStr);
|
||||
// 将map对象的数据转换成Bean对象
|
||||
obj = mapToBean(map, clazz);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将xml格式的字符串转换成Map对象
|
||||
*
|
||||
* @param xmlStr xml格式的字符串
|
||||
* @return Map对象
|
||||
* @throws Exception 异常
|
||||
*/
|
||||
public static Map<String, Object> xmlStrToMap(String xmlStr) throws Exception {
|
||||
if (StringUtils.isBlank(xmlStr)) {
|
||||
return null;
|
||||
}
|
||||
Map<String, Object> map = new HashMap<String, Object>();
|
||||
// 将xml格式的字符串转换成Document对象
|
||||
Document doc = DocumentHelper.parseText(xmlStr);
|
||||
// 获取根节点
|
||||
Element root = doc.getRootElement();
|
||||
// 获取根节点下的所有元素
|
||||
List children = root.elements();
|
||||
// 循环所有子元素
|
||||
if (children != null && children.size() > 0) {
|
||||
for (int i = 0; i < children.size(); i++) {
|
||||
Element child = (Element) children.get(i);
|
||||
map.put(child.getName(), child.getTextTrim());
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将xml格式字符串转换成Bean对象
|
||||
* 多级子节点递归遍历
|
||||
*
|
||||
* @param xmlStr
|
||||
* @param clazz
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static Object xmlStrToJavaBean(String xmlStr, Class clazz) {
|
||||
if (StringUtils.isBlank(xmlStr)) {
|
||||
return null;
|
||||
}
|
||||
Object obj = null;
|
||||
Map<String, Object> map = new HashMap<String, Object>();
|
||||
// 将xml格式的字符串转换成Document对象
|
||||
Document doc;
|
||||
try {
|
||||
doc = DocumentHelper.parseText(xmlStr);
|
||||
|
||||
// 获取根节点
|
||||
Element root = doc.getRootElement();
|
||||
map = elementToMap(root, map);
|
||||
// 将map对象的数据转换成Bean对象
|
||||
obj = mapToBean(map, clazz);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归遍历xml子节点,转换Map
|
||||
*
|
||||
* @param element
|
||||
* @param map
|
||||
* @return
|
||||
*/
|
||||
public static Map<String, Object> elementToMap(Element element, Map<String, Object> map) {
|
||||
if (element == null || map == null)
|
||||
return null;
|
||||
List children = element.elements();
|
||||
if (children != null && children.size() > 0) {
|
||||
for (int i = 0; i < children.size(); i++) {
|
||||
Element child = (Element) children.get(i);
|
||||
if (child.elements() != null && child.elements().size() > 0)
|
||||
elementToMap(child, map);
|
||||
else
|
||||
map.put(child.getName(), child.getTextTrim());
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将Map对象通过反射机制转换成Bean对象
|
||||
*
|
||||
* @param map 存放数据的map对象
|
||||
* @param clazz 待转换的class
|
||||
* @return 转换后的Bean对象
|
||||
* @throws Exception 异常
|
||||
*/
|
||||
public static Object mapToBean(Map<String, Object> map, Class clazz) throws Exception {
|
||||
Object obj = clazz.newInstance();
|
||||
if (map != null && map.size() > 0) {
|
||||
for (Map.Entry<String, Object> entry : map.entrySet()) {
|
||||
String propertyName = entry.getKey();
|
||||
Object value = entry.getValue();
|
||||
String setMethodName = "set" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);
|
||||
Field field = getClassField(clazz, propertyName);
|
||||
if (field != null) {
|
||||
Class fieldTypeClass = field.getType();
|
||||
value = convertValType(value, fieldTypeClass);
|
||||
clazz.getMethod(setMethodName, field.getType()).invoke(obj, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将Object类型的值,转换成bean对象属性里对应的类型值
|
||||
*
|
||||
* @param value Object对象值
|
||||
* @param fieldTypeClass 属性的类型
|
||||
* @return 转换后的值
|
||||
*/
|
||||
private static Object convertValType(Object value, Class fieldTypeClass) {
|
||||
Object retVal = null;
|
||||
if (Long.class.getName().equals(fieldTypeClass.getName())
|
||||
|| long.class.getName().equals(fieldTypeClass.getName())) {
|
||||
retVal = Long.parseLong(value.toString());
|
||||
} else if (Integer.class.getName().equals(fieldTypeClass.getName())
|
||||
|| int.class.getName().equals(fieldTypeClass.getName())) {
|
||||
retVal = Integer.parseInt(value.toString());
|
||||
} else if (Float.class.getName().equals(fieldTypeClass.getName())
|
||||
|| float.class.getName().equals(fieldTypeClass.getName())) {
|
||||
retVal = Float.parseFloat(value.toString());
|
||||
} else if (Double.class.getName().equals(fieldTypeClass.getName())
|
||||
|| double.class.getName().equals(fieldTypeClass.getName())) {
|
||||
retVal = Double.parseDouble(value.toString());
|
||||
} else {
|
||||
retVal = value;
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定字段名称查找在class中的对应的Field对象(包括查找父类)
|
||||
*
|
||||
* @param clazz 指定的class
|
||||
* @param fieldName 字段名称
|
||||
* @return Field对象
|
||||
*/
|
||||
private static Field getClassField(Class clazz, String fieldName) {
|
||||
if (Object.class.getName().equals(clazz.getName())) {
|
||||
return null;
|
||||
}
|
||||
Field[] declaredFields = clazz.getDeclaredFields();
|
||||
for (Field field : declaredFields) {
|
||||
if (field.getName().equals(fieldName)) {
|
||||
return field;
|
||||
}
|
||||
}
|
||||
|
||||
Class superClass = clazz.getSuperclass();
|
||||
if (superClass != null) {// 简单的递归一下
|
||||
return getClassField(superClass, fieldName);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
29
src/main/java/com/yxt/pay/utils/applet/MD5.java
Normal file
29
src/main/java/com/yxt/pay/utils/applet/MD5.java
Normal file
@@ -0,0 +1,29 @@
|
||||
package com.yxt.pay.utils.applet;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
|
||||
public class MD5 {
|
||||
private MD5() {
|
||||
}
|
||||
|
||||
/* * 生成 MD5
|
||||
*
|
||||
* @param data 待处理数据
|
||||
* @return MD5结果
|
||||
*/
|
||||
public static String getMessageDigest(String data) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance("MD5");
|
||||
byte[] array = md.digest(data.getBytes("UTF-8"));
|
||||
|
||||
for (byte item : array) {
|
||||
sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
return sb.toString().toUpperCase();
|
||||
}
|
||||
|
||||
}
|
||||
39
src/main/java/com/yxt/pay/utils/applet/WechatConfig.java
Normal file
39
src/main/java/com/yxt/pay/utils/applet/WechatConfig.java
Normal file
@@ -0,0 +1,39 @@
|
||||
package com.yxt.pay.utils.applet;
|
||||
|
||||
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
|
||||
import org.apache.http.conn.ssl.SSLContexts;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import java.io.InputStream;
|
||||
import java.security.KeyStore;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public class WechatConfig {
|
||||
|
||||
private static SSLConnectionSocketFactory sslcsf;
|
||||
|
||||
public static SSLConnectionSocketFactory getSslcsf() {
|
||||
if (null == sslcsf) {
|
||||
setSsslcsf();
|
||||
}
|
||||
return sslcsf;
|
||||
}
|
||||
|
||||
private static void setSsslcsf() {
|
||||
try {
|
||||
KeyStore keyStore = KeyStore.getInstance("PKCS12");
|
||||
Thread.currentThread().getContextClassLoader();
|
||||
InputStream instream = new WechatRefundApiResult().getClass().getResourceAsStream("certName");
|
||||
try {
|
||||
keyStore.load(instream, "mchId".toCharArray());
|
||||
} finally {
|
||||
instream.close();
|
||||
}
|
||||
SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, "mchId".toCharArray()).build();
|
||||
sslcsf = new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1"}, null, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
package com.yxt.pay.utils.applet;
|
||||
|
||||
public class WechatRefundApiResult {
|
||||
private String return_code;
|
||||
private String return_msg;
|
||||
|
||||
private String result_code;
|
||||
private String err_code;
|
||||
private String err_code_des;
|
||||
private String appid;
|
||||
private String mch_id;
|
||||
private String device_info;
|
||||
private String nonce_str;
|
||||
private String sign;
|
||||
private String transaction_id;
|
||||
private String out_trade_no;
|
||||
private String out_refund_no;
|
||||
private String refund_id;
|
||||
private String refund_channel;
|
||||
private String refund_fee;
|
||||
private String settlement_refund_fee;
|
||||
private String total_fee;
|
||||
private String settlement_total_fee;
|
||||
private String fee_type;
|
||||
private String cash_fee;
|
||||
private String cash_refund_fee;
|
||||
private String refund_status;
|
||||
|
||||
public String getRefund_status() {
|
||||
return refund_status;
|
||||
}
|
||||
|
||||
public void setRefund_status(String refund_status) {
|
||||
this.refund_status = refund_status;
|
||||
}
|
||||
|
||||
public String getReturn_code() {
|
||||
return return_code;
|
||||
}
|
||||
|
||||
public void setReturn_code(String return_code) {
|
||||
this.return_code = return_code;
|
||||
}
|
||||
|
||||
public String getReturn_msg() {
|
||||
return return_msg;
|
||||
}
|
||||
|
||||
public void setReturn_msg(String return_msg) {
|
||||
this.return_msg = return_msg;
|
||||
}
|
||||
|
||||
public String getResult_code() {
|
||||
return result_code;
|
||||
}
|
||||
|
||||
public void setResult_code(String result_code) {
|
||||
this.result_code = result_code;
|
||||
}
|
||||
|
||||
public String getErr_code() {
|
||||
return err_code;
|
||||
}
|
||||
|
||||
public void setErr_code(String err_code) {
|
||||
this.err_code = err_code;
|
||||
}
|
||||
|
||||
public String getErr_code_des() {
|
||||
return err_code_des;
|
||||
}
|
||||
|
||||
public void setErr_code_des(String err_code_des) {
|
||||
this.err_code_des = err_code_des;
|
||||
}
|
||||
|
||||
public String getAppid() {
|
||||
return appid;
|
||||
}
|
||||
|
||||
public void setAppid(String appid) {
|
||||
this.appid = appid;
|
||||
}
|
||||
|
||||
public String getMch_id() {
|
||||
return mch_id;
|
||||
}
|
||||
|
||||
public void setMch_id(String mch_id) {
|
||||
this.mch_id = mch_id;
|
||||
}
|
||||
|
||||
public String getDevice_info() {
|
||||
return device_info;
|
||||
}
|
||||
|
||||
public void setDevice_info(String device_info) {
|
||||
this.device_info = device_info;
|
||||
}
|
||||
|
||||
public String getNonce_str() {
|
||||
return nonce_str;
|
||||
}
|
||||
|
||||
public void setNonce_str(String nonce_str) {
|
||||
this.nonce_str = nonce_str;
|
||||
}
|
||||
|
||||
public String getSign() {
|
||||
return sign;
|
||||
}
|
||||
|
||||
public void setSign(String sign) {
|
||||
this.sign = sign;
|
||||
}
|
||||
|
||||
public String getTransaction_id() {
|
||||
return transaction_id;
|
||||
}
|
||||
|
||||
public void setTransaction_id(String transaction_id) {
|
||||
this.transaction_id = transaction_id;
|
||||
}
|
||||
|
||||
public String getOut_trade_no() {
|
||||
return out_trade_no;
|
||||
}
|
||||
|
||||
public void setOut_trade_no(String out_trade_no) {
|
||||
this.out_trade_no = out_trade_no;
|
||||
}
|
||||
|
||||
public String getOut_refund_no() {
|
||||
return out_refund_no;
|
||||
}
|
||||
|
||||
public void setOut_refund_no(String out_refund_no) {
|
||||
this.out_refund_no = out_refund_no;
|
||||
}
|
||||
|
||||
public String getRefund_id() {
|
||||
return refund_id;
|
||||
}
|
||||
|
||||
public void setRefund_id(String refund_id) {
|
||||
this.refund_id = refund_id;
|
||||
}
|
||||
|
||||
public String getRefund_channel() {
|
||||
return refund_channel;
|
||||
}
|
||||
|
||||
public void setRefund_channel(String refund_channel) {
|
||||
this.refund_channel = refund_channel;
|
||||
}
|
||||
|
||||
public String getRefund_fee() {
|
||||
return refund_fee;
|
||||
}
|
||||
|
||||
public void setRefund_fee(String refund_fee) {
|
||||
this.refund_fee = refund_fee;
|
||||
}
|
||||
|
||||
public String getSettlement_refund_fee() {
|
||||
return settlement_refund_fee;
|
||||
}
|
||||
|
||||
public void setSettlement_refund_fee(String settlement_refund_fee) {
|
||||
this.settlement_refund_fee = settlement_refund_fee;
|
||||
}
|
||||
|
||||
public String getTotal_fee() {
|
||||
return total_fee;
|
||||
}
|
||||
|
||||
public void setTotal_fee(String total_fee) {
|
||||
this.total_fee = total_fee;
|
||||
}
|
||||
|
||||
public String getSettlement_total_fee() {
|
||||
return settlement_total_fee;
|
||||
}
|
||||
|
||||
public void setSettlement_total_fee(String settlement_total_fee) {
|
||||
this.settlement_total_fee = settlement_total_fee;
|
||||
}
|
||||
|
||||
public String getFee_type() {
|
||||
return fee_type;
|
||||
}
|
||||
|
||||
public void setFee_type(String fee_type) {
|
||||
this.fee_type = fee_type;
|
||||
}
|
||||
|
||||
public String getCash_fee() {
|
||||
return cash_fee;
|
||||
}
|
||||
|
||||
public void setCash_fee(String cash_fee) {
|
||||
this.cash_fee = cash_fee;
|
||||
}
|
||||
|
||||
public String getCash_refund_fee() {
|
||||
return cash_refund_fee;
|
||||
}
|
||||
|
||||
public void setCash_refund_fee(String cash_refund_fee) {
|
||||
this.cash_refund_fee = cash_refund_fee;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
296
src/main/java/com/yxt/pay/utils/applet/WechatUtil.java
Normal file
296
src/main/java/com/yxt/pay/utils/applet/WechatUtil.java
Normal file
@@ -0,0 +1,296 @@
|
||||
package com.yxt.pay.utils.applet;
|
||||
|
||||
import com.yxt.pay.utils.CharUtil;
|
||||
import com.yxt.pay.utils.MapUtils;
|
||||
import com.yxt.pay.utils.XmlUtil;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.config.RegistryBuilder;
|
||||
import org.apache.http.conn.socket.ConnectionSocketFactory;
|
||||
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
|
||||
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* <p>Title: 微信退款工具类</p>
|
||||
* <p>Description: 微信退款工具类,通过充值客户端的不同初始化不同的工具类,得到相应微信退款相关的appid和muchid</p>
|
||||
*
|
||||
* @author xubo
|
||||
* @date 2017年6月6日 下午5:05:03
|
||||
*/
|
||||
public class WechatUtil {
|
||||
/**
|
||||
* 充值客户端类型--微信公众号
|
||||
*/
|
||||
public static Integer CLIENTTYPE_WX = 2;
|
||||
/**
|
||||
* 充值客户端类型--app
|
||||
*/
|
||||
public static Integer CLIENTTYPE_APP = 1;
|
||||
private static Logger logger = LoggerFactory.getLogger(WechatUtil.class);
|
||||
|
||||
/**
|
||||
* 方法描述:微信退款逻辑
|
||||
* 创建时间:2017年4月12日 上午11:04:25
|
||||
* 作者: xubo
|
||||
*
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
/* public static WechatRefundApiResult wxRefund(String out_trade_no, Double orderMoney, Double refundMoney) {
|
||||
//初始化请求微信服务器的配置信息包括appid密钥等
|
||||
//转换金钱格式
|
||||
BigDecimal bdOrderMoney = new BigDecimal(orderMoney, MathContext.DECIMAL32);
|
||||
BigDecimal bdRefundMoney = new BigDecimal(refundMoney, MathContext.DECIMAL32);
|
||||
//构建请求参数
|
||||
Map<Object, Object> params = buildRequsetMapParam(out_trade_no, bdOrderMoney, bdRefundMoney);
|
||||
String mapToXml = MapUtils.convertMap2Xml(params);
|
||||
//请求微信
|
||||
String reponseXml = sendSSLPostToWx(mapToXml, WechatConfig.getSslcsf());
|
||||
WechatRefundApiResult result = (WechatRefundApiResult) XmlUtil.xmlStrToBean(reponseXml, WechatRefundApiResult.class);
|
||||
return result;
|
||||
}*/
|
||||
|
||||
/**
|
||||
* 方法描述:得到请求微信退款请求的参数
|
||||
* 创建时间:2017年6月8日 上午11:27:02
|
||||
* 作者: xubo
|
||||
*
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
/* private static Map<Object, Object> buildRequsetMapParam(String out_trade_no, BigDecimal bdOrderMoney, BigDecimal bdRefundMoney) {
|
||||
Map<Object, Object> params = new HashMap<Object, Object>();
|
||||
//微信分配的公众账号ID(企业号corpid即为此appId)
|
||||
params.put("appid", ResourceUtil.getConfigByName("wx.appId"));
|
||||
//微信支付分配的商户号
|
||||
params.put("mch_id", ResourceUtil.getConfigByName("wx.mchId"));
|
||||
//随机字符串,不长于32位。推荐随机数生成算法
|
||||
params.put("nonce_str", CharUtil.getRandomString(16));
|
||||
//商户侧传给微信的订单号
|
||||
params.put("out_trade_no", out_trade_no);
|
||||
//商户系统内部的退款单号,商户系统内部唯一,同一退款单号多次请求只退一笔
|
||||
params.put("out_refund_no", getBundleId());
|
||||
//订单总金额,单位为分,只能为整数
|
||||
params.put("total_fee", bdOrderMoney.multiply(new BigDecimal(100)).intValue());
|
||||
//退款总金额,订单总金额,单位为分,只能为整数
|
||||
params.put("refund_fee", bdRefundMoney.multiply(new BigDecimal(100)).intValue());
|
||||
//操作员帐号, 默认为商户号
|
||||
params.put("op_user_id", ResourceUtil.getConfigByName("wx.mchId"));
|
||||
//签名前必须要参数全部写在前面
|
||||
params.put("sign", arraySign(params, ResourceUtil.getConfigByName("wx.paySignKey")));
|
||||
return params;
|
||||
}*/
|
||||
|
||||
/**
|
||||
* ResourceUtil.getConfigByName("wx.refundUrl")
|
||||
* 请求微信https
|
||||
**/
|
||||
public static String sendSSLPostToWx(String mapToXml, SSLConnectionSocketFactory sslcsf, String refundUrl) {
|
||||
logger.info("*******退款(WX Request:" + mapToXml);
|
||||
HttpPost httPost = new HttpPost(refundUrl);
|
||||
httPost.addHeader("Connection", "keep-alive");
|
||||
httPost.addHeader("Accept", "*/*");
|
||||
httPost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
|
||||
httPost.addHeader("Host", "api.mch.weixin.qq.com");
|
||||
httPost.addHeader("X-Requested-With", "XMLHttpRequest");
|
||||
httPost.addHeader("Cache-Control", "max-age=0");
|
||||
httPost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
|
||||
httPost.setEntity(new StringEntity(mapToXml, "UTF-8"));
|
||||
CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslcsf).build();
|
||||
CloseableHttpResponse response = null;
|
||||
try {
|
||||
response = httpClient.execute(httPost);
|
||||
HttpEntity entity = response.getEntity();
|
||||
String xmlStr = EntityUtils.toString(entity, "UTF-8");
|
||||
logger.info("*******退款(WX Response:" + xmlStr);
|
||||
return xmlStr;
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
return null;
|
||||
} finally {
|
||||
try {
|
||||
if (response != null) {
|
||||
response.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付交易ID
|
||||
*/
|
||||
public static String getBundleId() {
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmssSSS");
|
||||
String tradeno = dateFormat.format(new Date());
|
||||
String str = "000000" + (int) (Math.random() * 1000000);
|
||||
tradeno = tradeno + str.substring(str.length() - 6);
|
||||
return tradeno;
|
||||
}
|
||||
|
||||
/**
|
||||
* 方法描述:根据签名加密请求参数
|
||||
* 创建时间:2017年6月8日 上午11:28:52
|
||||
* 作者: xubo
|
||||
*
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
public static String arraySign(Map<Object, Object> params, String paySignKey) {
|
||||
boolean encode = false;
|
||||
Set<Object> keysSet = params.keySet();
|
||||
Object[] keys = keysSet.toArray();
|
||||
Arrays.sort(keys);
|
||||
StringBuffer temp = new StringBuffer();
|
||||
boolean first = true;
|
||||
for (Object key : keys) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
temp.append("&");
|
||||
}
|
||||
temp.append(key).append("=");
|
||||
Object value = params.get(key);
|
||||
String valueString = "";
|
||||
if (null != value) {
|
||||
valueString = value.toString();
|
||||
}
|
||||
if (encode) {
|
||||
try {
|
||||
temp.append(URLEncoder.encode(valueString, "UTF-8"));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
temp.append(valueString);
|
||||
}
|
||||
}
|
||||
temp.append("&key=");
|
||||
temp.append(paySignKey);
|
||||
System.out.println(temp.toString());
|
||||
String packageSign = MD5.getMessageDigest(temp.toString());
|
||||
return packageSign;
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求,只请求一次,不做重试
|
||||
*
|
||||
* @param url
|
||||
* @param data
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static String requestOnce(final String url, String data) throws Exception {
|
||||
BasicHttpClientConnectionManager connManager;
|
||||
connManager = new BasicHttpClientConnectionManager(
|
||||
RegistryBuilder.<ConnectionSocketFactory>create()
|
||||
.register("http", PlainConnectionSocketFactory.getSocketFactory())
|
||||
.register("https", SSLConnectionSocketFactory.getSocketFactory())
|
||||
.build(),
|
||||
null,
|
||||
null,
|
||||
null
|
||||
);
|
||||
|
||||
HttpClient httpClient = HttpClientBuilder.create()
|
||||
.setConnectionManager(connManager)
|
||||
.build();
|
||||
|
||||
HttpPost httpPost = new HttpPost(url);
|
||||
|
||||
RequestConfig requestConfig = RequestConfig.custom()
|
||||
.setSocketTimeout(5000)
|
||||
.setConnectTimeout(5000)
|
||||
.setConnectionRequestTimeout(10000).build();
|
||||
|
||||
httpPost.setConfig(requestConfig);
|
||||
|
||||
StringEntity postEntity = new StringEntity(data, "UTF-8");
|
||||
httpPost.addHeader("Content-Type", "text/xml");
|
||||
httpPost.addHeader("User-Agent", "wxpay sdk java v1.0 " + "mchId");
|
||||
httpPost.setEntity(postEntity);
|
||||
|
||||
HttpResponse httpResponse = httpClient.execute(httpPost);
|
||||
HttpEntity httpEntity = httpResponse.getEntity();
|
||||
String reusltObj = EntityUtils.toString(httpEntity, "UTF-8");
|
||||
logger.info("请求结果:" + reusltObj);
|
||||
return reusltObj;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 方法描述:微信查询退款逻辑
|
||||
* 创建时间:2017年4月12日 上午11:04:25
|
||||
* 作者: xubo
|
||||
*
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
|
||||
|
||||
public Map<String, Object> wxRefundquery(String out_trade_no, String out_refund_no) {
|
||||
Map<Object, Object> params = new HashMap<Object, Object>();
|
||||
//微信分配的公众账号ID(企业号corpid即为此appId)
|
||||
params.put("appid", "xx");
|
||||
//微信支付分配的商户号
|
||||
params.put("mch_id", "xx");
|
||||
//随机字符串,不长于32位。推荐随机数生成算法
|
||||
params.put("nonce_str", CharUtil.getRandomString(16));
|
||||
//商户侧传给微信的订单号
|
||||
params.put("out_trade_no", out_trade_no);
|
||||
//签名前必须要参数全部写在前面
|
||||
//签名
|
||||
params.put("sign", arraySign(params, "wx.paySignKey"));
|
||||
String mapToXml = MapUtils.convertMap2Xml(params);
|
||||
HttpPost httPost = new HttpPost("refundqueryUrl");
|
||||
httPost.addHeader("Connection", "keep-alive");
|
||||
httPost.addHeader("Accept", "*/*");
|
||||
httPost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
|
||||
httPost.addHeader("Host", "api.mch.weixin.qq.com");
|
||||
httPost.addHeader("X-Requested-With", "XMLHttpRequest");
|
||||
httPost.addHeader("Cache-Control", "max-age=0");
|
||||
httPost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
|
||||
httPost.setEntity(new StringEntity(mapToXml, "UTF-8"));
|
||||
CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(WechatConfig.getSslcsf()).build();
|
||||
CloseableHttpResponse response = null;
|
||||
try {
|
||||
response = httpClient.execute(httPost);
|
||||
HttpEntity entity = response.getEntity();
|
||||
String xmlStr = EntityUtils.toString(entity, "UTF-8");
|
||||
System.out.println(xmlStr);
|
||||
Map<String, Object> result = XmlUtil.xmlStrToMap(xmlStr);//.xmlStrToBean(xmlStr, WechatRefundApiResult.class);
|
||||
return result;
|
||||
//将信息保存到数据库
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
return null;
|
||||
} finally {
|
||||
try {
|
||||
if (response != null) {
|
||||
response.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
30
src/main/resources/application-devv.yml
Normal file
30
src/main/resources/application-devv.yml
Normal file
@@ -0,0 +1,30 @@
|
||||
spring:
|
||||
datasource:
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
url: jdbc:mysql://127.0.0.1:3306/yxt_pay?serverTimezone=GMT%2B8&autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&nullCatalogMeansCurrent=true
|
||||
username: root
|
||||
password: root
|
||||
cloud:
|
||||
nacos:
|
||||
discovery:
|
||||
server-addr: 127.0.0.1:8848
|
||||
redis:
|
||||
database: 3 # Redis数据库索引(默认为0)
|
||||
host: 127.0.0.1
|
||||
jedis:
|
||||
pool:
|
||||
max-active: -1 #连接池最大连接数(使用负值表示没有限制)
|
||||
max-idle: 8 #连接池中的最大空闲连接
|
||||
max-wait: -1 # 连接池最大阻塞等待时间(使用负值表示没有限制)
|
||||
min-idle: 0 # 连接池中的最小空闲连接
|
||||
password: 123456
|
||||
port: 6379
|
||||
timeout: 0 # 连接超时时间(毫秒)
|
||||
|
||||
image:
|
||||
upload:
|
||||
path: D:\\pay\\upload\\
|
||||
url:
|
||||
prefix: http://192.168.1.120:8111/upload/
|
||||
domain:
|
||||
urlPrex: http://192.168.0.111:7777
|
||||
0
src/main/resources/application-pro.yml
Normal file
0
src/main/resources/application-pro.yml
Normal file
0
src/main/resources/application-test.yml
Normal file
0
src/main/resources/application-test.yml
Normal file
62
src/main/resources/application.yml
Normal file
62
src/main/resources/application.yml
Normal file
@@ -0,0 +1,62 @@
|
||||
spring:
|
||||
application:
|
||||
name: yxt_pay
|
||||
profiles:
|
||||
active: devv
|
||||
messages:
|
||||
# 国际化资源文件路径
|
||||
basename: i18n/messages
|
||||
servlet:
|
||||
#上传文件
|
||||
multipart:
|
||||
max-file-size: 50MB
|
||||
max-request-size: 100MB
|
||||
devtools:
|
||||
restart:
|
||||
# 热部署开关
|
||||
enabled: true
|
||||
mvc:
|
||||
async:
|
||||
request-timeout: 20000
|
||||
|
||||
|
||||
|
||||
server:
|
||||
port: 7777
|
||||
max-http-header-size: 102400
|
||||
tomcat:
|
||||
max-http-form-post-size: -1
|
||||
#mybatis
|
||||
mybatis-plus:
|
||||
# 配置mapper的扫描,找到所有的mapper.xml映射文件
|
||||
mapper-locations: classpath*:**Mapper.xml
|
||||
global-config:
|
||||
refresh: true
|
||||
db-config:
|
||||
#定义生成ID的类型
|
||||
id-type: Auto
|
||||
db-type: mysql
|
||||
configuration:
|
||||
map-underscore-to-camel-case: false
|
||||
cache-enabled: true
|
||||
call-setters-on-nulls: true
|
||||
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
||||
|
||||
#hystrix的超时时间
|
||||
hystrix:
|
||||
command:
|
||||
default:
|
||||
execution:
|
||||
timeout:
|
||||
enabled: true
|
||||
isolation:
|
||||
thread:
|
||||
timeoutInMilliseconds: 60000
|
||||
#ribbon的超时时间
|
||||
ribbon:
|
||||
ReadTimeout: 60000
|
||||
ConnectTimeout: 60000
|
||||
|
||||
|
||||
|
||||
|
||||
13
src/main/resources/banner.txt
Normal file
13
src/main/resources/banner.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
,----.. ____
|
||||
/ / \ ,' , `.
|
||||
| : : ,---. ,-+-,.' _ | ,---. ,---,
|
||||
. | ;. / ' ,'\ ,-+-. ; , || ' ,'\ ,-+-. / |
|
||||
. ; /--` / / | ,--.'|' | || ,---. / / | ,--.'|' |
|
||||
; | ; . ; ,. :| | ,', | |,/ \ . ; ,. :| | ,"' |
|
||||
| : | ' | |: :| | / | |--'/ / | ' | |: :| | / | |
|
||||
. | '___' | .; :| : | | , . ' / | ' | .; :| | | | |
|
||||
' ; : .'| : || : | |/ ' ; /| | : || | | |/
|
||||
' | '/ :\ \ / | | |`-' ' | / | \ \ / | | |--'
|
||||
| : / `----' | ;/ | : | `----' | |/
|
||||
\ \ .' '---' \ \ / '---'
|
||||
`---` `----'
|
||||
54
src/main/resources/logback-spring.xml
Normal file
54
src/main/resources/logback-spring.xml
Normal file
@@ -0,0 +1,54 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
|
||||
<property name="log.base" value="logs/yxt_pay"/>
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符 :
|
||||
|%blue(%thread) 线程 如 :DiscoveryClient-CacheRefreshExecutor-0-->
|
||||
<!--<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>-->
|
||||
<pattern>%yellow(%date{yyyy-MM-dd HH:mm:ss}) |%highlight(%-5level) |%green(%logger:%line) |%blue(%msg%n)
|
||||
</pattern>
|
||||
<!--<charset>UTF-8</charset> -->
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- 彩色日志 -->
|
||||
<!-- 彩色日志依赖的渲染类 -->
|
||||
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
|
||||
<conversionRule conversionWord="wex"
|
||||
converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>
|
||||
<conversionRule conversionWord="wEx"
|
||||
converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>
|
||||
<!-- 彩色日志格式 -->
|
||||
<property name="CONSOLE_LOG_PATTERN"
|
||||
value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
|
||||
|
||||
<appender name="FILEOUT"
|
||||
class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${log.base}.log</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<fileNamePattern>${log.base}.%d{yyyyMMdd}.%i.log.zip
|
||||
</fileNamePattern>
|
||||
<!-- 当文件大小超过10MB时触发滚动 -->
|
||||
<timeBasedFileNamingAndTriggeringPolicy
|
||||
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
|
||||
<maxFileSize>1MB</maxFileSize>
|
||||
</timeBasedFileNamingAndTriggeringPolicy>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<!--<pattern>%date [%thread] %-5level %logger{35} - %msg%n</pattern>-->
|
||||
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36}
|
||||
-%msg%n
|
||||
</Pattern>
|
||||
<!--<charset>UTF-8</charset> -->
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="STDOUT"/>
|
||||
<appender-ref ref="FILEOUT"/>
|
||||
</root>
|
||||
|
||||
</configuration>
|
||||
Reference in New Issue
Block a user