
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