文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

SpringBoot如何实现整合微信支付

2023-06-22 04:30

关注

这篇文章将为大家详细讲解有关SpringBoot如何实现整合微信支付,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。

1.准备工作

1.1 数据库表

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

订单表

SpringBoot如何实现整合微信支付

支付记录表

SpringBoot如何实现整合微信支付

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.Driverspring.datasource.url=jdbc:mysql://localhost:3306/guli?serverTimezone=GMT%2B8spring.datasource.username=rootspring.datasource.password=root#返回json的全局时间格式spring.jackson.date-format=yyyy-MM-dd HH:mm:ssspring.jackson.time-zone=GMT+8#配置mapper xml文件的路径mybatis-plus.mapper-locations=classpath:com/atguigu/eduorder/mapper/xml    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工具类:

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);    }        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层:

@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层:

@Overridepublic CourseWebVo getBaseCourseInfo(String courseId) {    return baseMapper.getBaseCourseInfo(courseId);}

mapper层:

<!--根据课程id查询课程基本信息--><select id="getBaseCourseInfo" resultType="com.atguigu.eduservice.entity.frontvo.CourseWebVo">    SELECT ec.id,    ec.`title`,    ec.`price`,    ec.lesson_num as lessonNum,    ec.cover,    ec.buy_count  as buyCount,    ec.view_count as viewCount,    ecd.description,    et.id            teacherId,    et.`name`     AS teacherName,    et.intro,    et.avatar,    es1.id        as subjectLevelOneId,    es1.`title`   AS subjectLevelOne,    es2.id        as subjectLevelTwoId,    es2.`title`   AS subjectLevelTwo    FROM edu_course ec    LEFT JOIN edu_course_description ecd ON ec.id = ecd.id    LEFT JOIN edu_teacher et ON ec.`teacher_id` = et.`id`    LEFT JOIN edu_subject es1 ON ec.`subject_parent_id` = es1.`id`    LEFT JOIN edu_subject es2 ON ec.`subject_id` = es2.`id`    WHERE ec.id = #{courseId}</select>

在service_ucenter用户模块实现根据用户id获取用户信息的getUserInfoOrder方法

controller层:

@PostMapping("getUserInfoOrder/{id}")public UcenterMemberOrder getUserInfoOrder(@PathVariable("id") String id) {    UcenterMember member = memberService.getById(id);    UcenterMemberOrder memberOrder = new UcenterMemberOrder();    BeanUtils.copyProperties(member, memberOrder);    return memberOrder;}

2.3 根据课程id和用户id生成订单

controller层:

@CrossOrigin@RestController@RequestMapping("/eduorder/order")public class OrderController {    @Autowired    private OrderService orderService;        @PostMapping("createOrder/{courseId}")    public R saveOrder(@PathVariable("courseId") String courseId, HttpServletRequest request) {        //通过JWT工具类获取用户id        //创建订单,返回订单号        String orderNo = orderService.createOrderById(courseId, JwtUtils.getMemberIdByJwtToken(request));        return R.ok().data("orderId", orderNo);    }}

service层:

@Overridepublic String createOrderById(String courseId, String userId) {    //通过远程调佣根据用户id获取用户信息    UcenterMemberOrder userInfoOrder = ucenterClient.getUserInfoOrder(userId);    //通过远程调佣根据课程id获取课程信息    CourseWebOrder courseInfoOrder = courseClient.getCourseInfoOrder(courseId);    Order order = new Order();    //订单号    order.setOrderNo(OrderNoUtil.getOrderNo());    order.setCourseId(courseId);    order.setCourseTitle(courseInfoOrder.getTitle());    order.setCourseCover(courseInfoOrder.getCover());    order.setTeacherName(courseInfoOrder.getTeacherName());    order.setTotalFee(courseInfoOrder.getPrice());    order.setMemberId(userId);    order.setMobile(userInfoOrder.getMobile());    order.setNickname(userInfoOrder.getNickname());    //支付状态  未支付:0  已支付:1    order.setStatus(0);    //支付类型  微信:1    支付宝:2    order.setPayType(1);    //保存到数据库    baseMapper.insert(order);    //返回订单号    return order.getOrderNo();}

3.查询订单信息

3.1 controller层

在OrderController里创建getOrderInfo用于生成订单:

@GetMapping("getOrderInfo/{orderId}")public R getOrderInfo(@PathVariable("orderId") String orderId) {    Order order=orderService.getOrderByOrderId(orderId);    return R.ok().data("item", order);}

3.2 service层

@Overridepublic Order getOrderByOrderId(String orderId) {    LambdaQueryWrapper<Order> queryWrapper = new LambdaQueryWrapper<>();    queryWrapper.eq(Order::getOrderNo, orderId);    return baseMapper.selectOne(queryWrapper);}

4.生成微信支付的二维码

4.1 controller层

在PayLogController里创建createNative用于生成支付二维码:

@CrossOrigin@RestController@RequestMapping("/eduorder/paylog")public class PayLogController {    @Autowired    private PayLogService payLogService;        @GetMapping("createNative/{orderNo}")    public R createNative(@PathVariable("orderNo") String orderNo){        //返回信息,包含二维码地址,还有其他信息        Map map=payLogService.createNative(orderNo);        return R.ok().data(map);    }}

4.2 service层

  1. 生成微信支付二维码大概分为这几步:

  2. 根据订单号查询订单信息

  3. 使用map设置生成二维码需要的参数

  4. 发送httpclient请求,传递xml格式的参数,传入微信支付提供的固定地址

  5. 得到发送请求返回的结果

  6. 最终返回封装数据

@Overridepublic Map createNative(String orderNo) {    try {        //1.根据订单号查询订单信息        Order order = orderService.getOrderByOrderId(orderNo);        //2.使用map设置生成二维码需要的参数        Map m = new HashMap();        //关联的公众号appid        m.put("appid", ConstantWxPayUtils.WX_PAY_APP_ID);        //商户号        m.put("mch_id", ConstantWxPayUtils.WX_PAY_PARTNER);        //随机字符串        m.put("nonce_str", WXPayUtil.generateNonceStr());        //课程        m.put("body", order.getCourseTitle());        //订单号        m.put("out_trade_no", orderNo);        //价格        m.put("total_fee", order.getTotalFee().multiply(new BigDecimal("100")).longValue() + "");        //支付的ip地址        m.put("spbill_create_ip", "127.0.0.1");        m.put("notify_url", ConstantWxPayUtils.WX_PAY_NOTIFY_URL);        m.put("trade_type", "NATIVE");        //3.发送httpclient请求,传递参数xml格式,传入微信支付提供的固定地址        HttpClient client = new HttpClient(ConstantWxPayUtils.WX_PAY_WX_URL);        //设置xml格式的参数,需要传入二维码参数m和商户key        client.setXmlParam(WXPayUtil.generateSignedXml(m, ConstantWxPayUtils.WX_PAY_PARTNER_KEY));        //默认不支持https,设置为true支持        client.setHttps(true);        //执行请求发送        client.post();        //4.得到发送请求返回的结果        //返回的内容是xml格式        String xml = client.getContent();        //把xml格式转换为map集合        Map<String, String> resultMap = WXPayUtil.xmlToMap(xml);        //5.最终返回封装数据        Map map = new HashMap();        //订单号        map.put("out_trade_no", orderNo);        //课程id        map.put("course_id", order.getCourseId());        //价格        map.put("total_fee", order.getTotalFee());        //返回二维码操作状态码        map.put("result_code", resultMap.get("result_code"));        //二维码地址        map.put("code_url", resultMap.get("code_url"));        return map;    } catch (Exception e) {        throw new GuliException(20001, "生成微信支付二维码失败");    }}

5.查询订单支付状态

5.1 controller层

在PayLogController里创建queryPayStatus用于获取支付状态:

@GetMapping("queryPayStatus/{orderNo}")public R queryPayStatus(@PathVariable("orderNo") String orderNo){    Map<String, String> map=payLogService.queryPayStatus(orderNo);    if(map==null){        return R.error().message("支付出错!");    }    //如果map不为空,通过map获取订单状态    if(map.get("trade_state").equals("SUCCESS")){        //添加记录到支付表,更新订单表订单状态        payLogService.updateOrdersStatus(map);        return R.ok().message("支付成功!");    }    return R.ok().code(25000).message("正在支付中...");}

5.2 service层

根据订单号查询订单支付状态大概分为一下几步:

  1. 封装参数

  2. 发送httpclient

  3. 得到请求返回的内容

@Overridepublic Map<String, String> queryPayStatus(String orderNo) {    try {        //1.封装参数        Map m=new HashMap();        //关联的公众号appid        m.put("appid",ConstantWxPayUtils.WX_PAY_APP_ID);        //商户号        m.put("mch_id",ConstantWxPayUtils.WX_PAY_PARTNER);        //订单号        m.put("out_trade_no",orderNo);        //随机字符串        m.put("nonce_str",WXPayUtil.generateNonceStr());        //2.发送httpclient        HttpClient client = new HttpClient(ConstantWxPayUtils.WX_PAY_QUERY_URL);        client.setXmlParam(WXPayUtil.generateSignedXml(m,ConstantWxPayUtils.WX_PAY_PARTNER_KEY));        client.setHttps(true);        client.post();        //3.得到请求返回的内容        String xml = client.getContent();        Map<String, String> resultMap=WXPayUtil.xmlToMap(xml);        return resultMap;    } catch (Exception e) {        e.printStackTrace();        throw  new GuliException(20001,"查询订单支付状态失败");    }}

如果支付成功,需要添加记录到支付表,更新订单表订单状态:

@Overridepublic void updateOrdersStatus(Map<String, String> map) {    //从map获取订单号    String orderNo = map.get("out_trade_no");    Order order = orderService.getOrderByOrderId(orderNo);    //更新订单表t_order的订单状态status    if(order.getStatus().intValue()==1){        return;    }    order.setStatus(1);    orderService.updateById(order);    //向支付表 t_pag_log 添加记录    PayLog payLog=new PayLog();    payLog.setOrderNo(orderNo);    payLog.setPayTime(new Date());    //支付类型    payLog.setPayType(1);    //支付金额    payLog.setTotalFee(order.getTotalFee());    //支付状态    payLog.setTradeState(map.get("trade_state"));    //交易流水号    payLog.setTransactionId(map.get("transaction_id"));    //其他属性,转为json字符串    payLog.setAttr(JSONObject.toJSONString(map));    baseMapper.insert(payLog);}

关于“SpringBoot如何实现整合微信支付”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯