SpringBoot整合微信支付

Posted LL.LEBRON

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringBoot整合微信支付相关的知识,希望对你有一定的参考价值。

SpringBoot整合微信支付

1.准备工作

1.1 数据库表

这里涉及微信支付一共两个表:

订单表

支付记录表

1.2 实体类

数据库对应的实体类:

订单表

@Data
@ToString
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("t_order")
@ApiModel(value = "Order对象", description = "订单")
public class Order implements Serializable 

    private static final long serialVersionUID = 1L;

    @TableId(value = "id", type = IdType.ID_WORKER_STR)
    private String id;

    @ApiModelProperty(value = "订单号")
    private String orderNo;

    @ApiModelProperty(value = "课程id")
    private String courseId;

    @ApiModelProperty(value = "课程名称")
    private String courseTitle;

    @ApiModelProperty(value = "课程封面")
    private String courseCover;

    @ApiModelProperty(value = "讲师名称")
    private String teacherName;

    @ApiModelProperty(value = "会员id")
    private String memberId;

    @ApiModelProperty(value = "会员昵称")
    private String nickname;

    @ApiModelProperty(value = "会员手机")
    private String mobile;

    @ApiModelProperty(value = "订单金额(分)")
    private BigDecimal totalFee;

    @ApiModelProperty(value = "支付类型(1:微信 2:支付宝)")
    private Integer payType;

    @ApiModelProperty(value = "订单状态(0:未支付 1:已支付)")
    private Integer status;

    @ApiModelProperty(value = "逻辑删除 1(true)已删除, 0(false)未删除")
    private Boolean isDeleted;

    @ApiModelProperty(value = "创建时间")
    @TableField(fill = FieldFill.INSERT)
    private Date gmtCreate;

    @ApiModelProperty(value = "更新时间")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date gmtModified;

支付日志表

@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("t_pay_log")
@ApiModel(value = "PayLog对象", description = "支付日志表")
public class PayLog implements Serializable 

    private static final long serialVersionUID = 1L;

    @TableId(value = "id", type = IdType.ID_WORKER_STR)
    private String id;

    @ApiModelProperty(value = "订单号")
    private String orderNo;

    @ApiModelProperty(value = "支付完成时间")
    private Date payTime;

    @ApiModelProperty(value = "支付金额(分)")
    private BigDecimal totalFee;

    @ApiModelProperty(value = "交易流水号")
    private String transactionId;

    @ApiModelProperty(value = "交易状态")
    private String tradeState;

    @ApiModelProperty(value = "支付类型(1:微信 2:支付宝)")
    private Integer payType;

    @ApiModelProperty(value = "其他属性")
    private String attr;

    @ApiModelProperty(value = "逻辑删除 1(true)已删除, 0(false)未删除")
    private Boolean isDeleted;

    @ApiModelProperty(value = "创建时间")
    @TableField(fill = FieldFill.INSERT)
    private Date gmtCreate;

    @ApiModelProperty(value = "更新时间")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date gmtModified;

1.3 导入依赖

在订单模块service_order导入微信支付需要的依赖:

<dependencies>
    <dependency>
        <groupId>com.github.wxpay</groupId>
        <artifactId>wxpay-sdk</artifactId>
        <version>0.0.3</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
    </dependency>
</dependencies>

1.4 配置文件

在配置文件application.properties配置相关的信息:

# 服务端口
server.port=8007
# 服务名
spring.application.name=service-order
# mysql数据库连接
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/guli?serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=root
#返回json的全局时间格式
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss

spring.jackson.time-zone=GMT+8
#配置mapper xml文件的路径
mybatis-plus.mapper-locations=classpath:com/atguigu/eduorder/mapper/xml/*.xml
#mybatis日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
# nacos服务地址
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
#开启熔断机制
#feign.hystrix.enabled=true
# 设置hystrix超时时间,默认1000ms
#hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=3000

#关联的公众号appid
wx.pay.app_id=wx74862e0dfc69954
#商户号
wx.pay.partner=155895011
#商户key
wx.pay.partnerkey=T6m9iK73b0kn9g5v426MKHQH7X8rKwb
#回调地址
wx.pay.notifyurl=http://guli.shop/api/order/weixinPay/weixinNotify
#微信提供的固定地址
wx.pay.wxurl=https://api.mch.weixin.qq.com/pay/unifiedorder
#微信查询状态地址
wx.pay.queryUrl=https://api.mch.weixin.qq.com/pay/orderquery

1.5 创建读取微信支付相关信息的工具类

创建一个读取微信支付需要的信息的工具类ConstantWxPayUtils

@Controller
public class ConstantWxPayUtils implements InitializingBean 
    @Value("$wx.pay.app_id")
    private String appID;
    @Value("$wx.pay.partner")
    private String partner;
    @Value("$wx.pay.partnerkey")
    private String partnerKey;
    @Value("$wx.pay.notifyurl")
    private String notifyUrl;
    @Value("$wx.pay.wxurl")
    private String wxUrl;
    @Value("$wx.pay.queryUrl")
    private String queryUrl;

    //定义公共静态常量
    public static String WX_PAY_APP_ID;
    public static String WX_PAY_PARTNER;
    public static String WX_PAY_PARTNER_KEY;
    public static String WX_PAY_NOTIFY_URL;
    public static String WX_PAY_WX_URL;
    public static String WX_PAY_QUERY_URL;

    @Override
    public void afterPropertiesSet() throws Exception 
        WX_PAY_APP_ID = appID;
        WX_PAY_PARTNER = partner;
        WX_PAY_PARTNER_KEY = partnerKey;
        WX_PAY_NOTIFY_URL = notifyUrl;
        WX_PAY_WX_URL = wxUrl;
        WX_PAY_QUERY_URL=queryUrl;
    

1.6 其他工具类

用于随机生成订单号的工具类OrderNoUtil

public class OrderNoUtil 
    /**
     * 获取订单号
     * @return
     */
    public static String getOrderNo() 
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        String newDate = sdf.format(new Date());
        String result = "";
        Random random = new Random();
        for (int i = 0; i < 3; i++) 
            result += random.nextInt(10);
        
        return newDate + result;
    

HttpClient工具类:

/**
 * http请求客户端
 * 
 * @author xppll
 * 
 */
public class HttpClient 
    private String url;
    private Map<String, String> param;
    private int statusCode;
    private String content;
    private String xmlParam;
    private boolean isHttps;

    public boolean isHttps() 
        return isHttps;
    

    public void setHttps(boolean isHttps) 
        this.isHttps = isHttps;
    

    public String getXmlParam() 
        return xmlParam;
    

    public void setXmlParam(String xmlParam) 
        this.xmlParam = xmlParam;
    

    public HttpClient(String url, Map<String, String> param) 
        this.url = url;
        this.param = param;
    

    public HttpClient(String url) 
        this.url = url;
    

    public void setParameter(Map<String, String> map) 
        param = map;
    

    public void addParameter(String key, String value) 
        if (param == null)
            param = new HashMap<String, String>();
        param.put(key, value);
    

    public void post() throws ClientProtocolException, IOException 
        HttpPost http = new HttpPost(url);
        setEntity(http);
        execute(http);
    

    public void put() throws ClientProtocolException, IOException 
        HttpPut http = new HttpPut(url);
        setEntity(http);
        execute(http);
    

    public void get() throws ClientProtocolException, IOException 
        if (param != null) 
            StringBuilder url = new StringBuilder(this.url);
            boolean isFirst = true;
            for (String key : param.keySet()) 
                if (isFirst)
                    url.append("?");
                else
                    url.append("&");
                url.append(key).append("=").append(param.get(key));
            
            this.url = url.toString();
        
        HttpGet http = new HttpGet(url);
        execute(http);
    

    /**
    * set http post,put param
    */
    private void setEntity(HttpEntityEnclosingRequestBase http) 
        if (param != null) 
            List<NameValuePair> nvps = new LinkedList<NameValuePair>();
            for (String key : param.keySet())
                nvps.add(new BasicNameValuePair(key, param.get(key))); // 参数
            http.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8)); // 设置参数
        
        if (xmlParam != null) 
            http.setEntity(new StringEntity(xmlParam, Consts.UTF_8));
        
    

    private void execute(HttpUriRequest http) throws ClientProtocolException,
    IOException 
        CloseableHttpClient httpClient = null;
        try 
            if (isHttps) 
                SSLContext sslContext = new SSLContextBuilder()
                    .loadTrustMaterial(null, new TrustStrategy() 
                        // 信任所有
                        public boolean isTrusted(X509Certificate[] chain,
                                                 String authType)
                            throws CertificateException 
                            return true;
                        
                    ).build();
                SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                    sslContext);
                httpClient = HttpClients.custom().setSSLSocketFactory(sslsf)
                    .build();
             else 
                httpClient = HttpClients.createDefault();
            
            CloseableHttpResponse response = httpClient.execute(http);
            try 
                if (response != null) 
                    if (response.getStatusLine() != null)
                        statusCode = response.getStatusLine().getStatusCode();
                    HttpEntity entity = response.getEntity();
                    // 响应内容
                    content = EntityUtils.toString(entity, Consts.UTF_8);
                
             finally 
                response.close();
            
         catch (Exception e) 
            e.printStackTrace();
         finally 
            httpClient.close();
        
    

    public int getStatusCode() 
        return statusCode;
    

    public String getContent() throws ParseException, IOException 
        return content;
    


2.生成订单

这里一共涉及service_order订单模块、service_ucenter用户模块、service-edu课程模块。

service_order使用Fegin远程调用其他模块的方法。

详细的Fegin的使用可以参考:SpringCloud-Feign远程调用

2.1 远程调用用户模块和课程模块

service_order订单模块创建:

@Component
@FeignClient("service-ucenter") //调用的服务名称
public interface UcenterClient 

    //根据用户id获取用户信息,用于生成订单使用
    @PostMapping("/educenter/member/getUserInfoOrder/id")
    public UcenterMemberOrder getUserInfoOrder(@PathVariable("id") String id);

@Component
@FeignClient("service-edu") //调用的服务名称
public interface CourseClient 

    //根据课程id查询课程信息
    @PostMapping("/eduservice/coursefront/getCourseInfoOrder/id")
    public CourseWebOrder getCourseInfoOrder(@PathVariable("id") String id);


2.2 远程调用方法的实现

service-edu课程模块实现根据课程id查询课程信息的getCourseInfoOrder方法

controller层:

/**
 * 根据课程id查询课程信息
 * @param id 客场id
 * @return CourseWebOrder
 */
@PostMapping("getCourseInfoOrder/id")
public CourseWebOrder getCourseInfoOrder(@PathVariable("id") String id) 
    CourseWebVo courseInfo = courseService.getBaseCourseInfo(id);
    CourseWebOrder courseWebOrder = new CourseWebOrder();
    BeanUtils.copyProperties(courseInfo, courseWebOrder);
    return courseWebOrder;

service层:

/**
 * 根据课程id,编写sql语句查询课程信息
 * @param courseId 课程id
 * @return CourseWebVo
 */
@Override
public CourseWebVo getBaseCourseInfo(String courseId) 
    return baseMapper.getBaseCourseInfo(courseId);

mapper层:

<!--根据课程id查询课程基本信息-->
<select id以上是关于SpringBoot整合微信支付的主要内容,如果未能解决你的问题,请参考以下文章

Springboot----项目整合微信支付(引入延迟队列实现订单过期取消以及商户主动查单)

pringboot整合微信支付sdk

低价SpringBoot2.x整合微信支付在线教育网站高级项目实战课2018年

Springboot----项目整合微信支付与RabbitMQ(使用RabbitMQ延迟插件实现订单管理)

SpringBoot整合支付宝支付流程

2019刘老师教你用springboot2.x开发整合微信支付的线上教育平台带源码送springboot2.x零基础入门到高级实战教程