
commit
c54d4008c8
33 changed files with 2817 additions and 0 deletions
@ -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 ='订单表'; |
@ -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> |
@ -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); |
|||
} |
|||
} |
@ -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; |
|||
|
|||
|
|||
} |
@ -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; |
|||
|
|||
|
|||
} |
@ -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; |
|||
} |
@ -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; |
|||
} |
|||
} |
@ -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; |
|||
} |
|||
|
|||
|
|||
|
|||
} |
@ -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; |
|||
} |
|||
} |
@ -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); |
|||
} |
@ -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> |
@ -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); |
|||
} |
|||
} |
@ -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); |
|||
} |
|||
} |
@ -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; |
|||
} |
|||
} |
|||
*/ |
@ -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 { |
|||
|
|||
} |
@ -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; |
|||
} |
|||
|
|||
|
|||
} |
@ -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; |
|||
} |
|||
} |
@ -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); |
|||
} |
|||
} |
@ -0,0 +1,7 @@ |
|||
package com.yxt.pay.utils; |
|||
|
|||
import java.util.Map; |
|||
|
|||
public interface DealMapValueHelper { |
|||
void dealValue(String key, Map<String, Object> map); |
|||
} |
@ -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(); |
|||
} |
|||
} |
|||
|
@ -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; |
|||
} |
|||
} |
@ -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(); |
|||
} |
|||
|
|||
} |
@ -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; |
|||
} |
|||
} |
@ -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(); |
|||
} |
|||
|
|||
} |
@ -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; |
|||
} |
|||
|
|||
|
|||
} |
@ -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); |
|||
} |
|||
} |
|||
} |
|||
} |
@ -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,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 |
|||
|
|||
|
|||
|
|||
|
@ -0,0 +1,13 @@ |
|||
,----.. ____ |
|||
/ / \ ,' , `. |
|||
| : : ,---. ,-+-,.' _ | ,---. ,---, |
|||
. | ;. / ' ,'\ ,-+-. ; , || ' ,'\ ,-+-. / | |
|||
. ; /--` / / | ,--.'|' | || ,---. / / | ,--.'|' | |
|||
; | ; . ; ,. :| | ,', | |,/ \ . ; ,. :| | ,"' | |
|||
| : | ' | |: :| | / | |--'/ / | ' | |: :| | / | | |
|||
. | '___' | .; :| : | | , . ' / | ' | .; :| | | | | |
|||
' ; : .'| : || : | |/ ' ; /| | : || | | |/ |
|||
' | '/ :\ \ / | | |`-' ' | / | \ \ / | | |--' |
|||
| : / `----' | ;/ | : | `----' | |/ |
|||
\ \ .' '---' \ \ / '---' |
|||
`---` `----' |
@ -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> |
Loading…
Reference in new issue