SpringBoot如何实现整合微信支付

SpringBoot如何实现整合微信支付

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

1.准备工作

1.1 数据库表

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

订单表

支付记录表

1.2 实体类

数据库对应的实体类:

订单表

@Data@ToString@EqualsAndHashCode(callSuper=false)@Accessors(chain=true)@TableName("t_order")@ApiModel(value="Order对象",description="订单")publicclassOrderimplementsSerializable{privatestaticfinallongserialVersionUID=1L;@TableId(value="id",type=IdType.ID_WORKER_STR)privateStringid;@ApiModelProperty(value="订单号")privateStringorderNo;@ApiModelProperty(value="课程id")privateStringcourseId;@ApiModelProperty(value="课程名称")privateStringcourseTitle;@ApiModelProperty(value="课程封面")privateStringcourseCover;@ApiModelProperty(value="讲师名称")privateStringteacherName;@ApiModelProperty(value="会员id")privateStringmemberId;@ApiModelProperty(value="会员昵称")privateStringnickname;@ApiModelProperty(value="会员手机")privateStringmobile;@ApiModelProperty(value="订单金额(分)")privateBigDecimaltotalFee;@ApiModelProperty(value="支付类型(1:微信2:支付宝)")privateIntegerpayType;@ApiModelProperty(value="订单状态(0:未支付1:已支付)")privateIntegerstatus;@ApiModelProperty(value="逻辑删除1(true)已删除,0(false)未删除")privateBooleanisDeleted;@ApiModelProperty(value="创建时间")@TableField(fill=FieldFill.INSERT)privateDategmtCreate;@ApiModelProperty(value="更新时间")@TableField(fill=FieldFill.INSERT_UPDATE)privateDategmtModified;}

支付日志表

@Data@EqualsAndHashCode(callSuper=false)@Accessors(chain=true)@TableName("t_pay_log")@ApiModel(value="PayLog对象",description="支付日志表")publicclassPayLogimplementsSerializable{privatestaticfinallongserialVersionUID=1L;@TableId(value="id",type=IdType.ID_WORKER_STR)privateStringid;@ApiModelProperty(value="订单号")privateStringorderNo;@ApiModelProperty(value="支付完成时间")privateDatepayTime;@ApiModelProperty(value="支付金额(分)")privateBigDecimaltotalFee;@ApiModelProperty(value="交易流水号")privateStringtransactionId;@ApiModelProperty(value="交易状态")privateStringtradeState;@ApiModelProperty(value="支付类型(1:微信2:支付宝)")privateIntegerpayType;@ApiModelProperty(value="其他属性")privateStringattr;@ApiModelProperty(value="逻辑删除1(true)已删除,0(false)未删除")privateBooleanisDeleted;@ApiModelProperty(value="创建时间")@TableField(fill=FieldFill.INSERT)privateDategmtCreate;@ApiModelProperty(value="更新时间")@TableField(fill=FieldFill.INSERT_UPDATE)privateDategmtModified;}

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-ddHH:mm:ssspring.jackson.time-zone=GMT+8#配置mapperxml文件的路径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#关联的公众号appidwx.pay.app_id=wx74862e0dfc69954#商户号wx.pay.partner=155895011#商户keywx.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:

@ControllerpublicclassConstantWxPayUtilsimplementsInitializingBean{@Value("${wx.pay.app_id}")privateStringappID;@Value("${wx.pay.partner}")privateStringpartner;@Value("${wx.pay.partnerkey}")privateStringpartnerKey;@Value("${wx.pay.notifyurl}")privateStringnotifyUrl;@Value("${wx.pay.wxurl}")privateStringwxUrl;@Value("${wx.pay.queryUrl}")privateStringqueryUrl;//定义公共静态常量publicstaticStringWX_PAY_APP_ID;publicstaticStringWX_PAY_PARTNER;publicstaticStringWX_PAY_PARTNER_KEY;publicstaticStringWX_PAY_NOTIFY_URL;publicstaticStringWX_PAY_WX_URL;publicstaticStringWX_PAY_QUERY_URL;@OverridepublicvoidafterPropertiesSet()throwsException{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:

publicclassOrderNoUtil{/***获取订单号*@return*/publicstaticStringgetOrderNo(){SimpleDateFormatsdf=newSimpleDateFormat("yyyyMMddHHmmss");StringnewDate=sdf.format(newDate());Stringresult="";Randomrandom=newRandom();for(inti=0;i<3;i++){result+=random.nextInt(10);}returnnewDate+result;}}

HttpClient工具类:

/***http请求客户端**@authorxppll**/publicclassHttpClient{privateStringurl;privateMap<String,String>param;privateintstatusCode;privateStringcontent;privateStringxmlParam;privatebooleanisHttps;publicbooleanisHttps(){returnisHttps;}publicvoidsetHttps(booleanisHttps){this.isHttps=isHttps;}publicStringgetXmlParam(){returnxmlParam;}publicvoidsetXmlParam(StringxmlParam){this.xmlParam=xmlParam;}publicHttpClient(Stringurl,Map<String,String>param){this.url=url;this.param=param;}publicHttpClient(Stringurl){this.url=url;}publicvoidsetParameter(Map<String,String>map){param=map;}publicvoidaddParameter(Stringkey,Stringvalue){if(param==null)param=newHashMap<String,String>();param.put(key,value);}publicvoidpost()throwsClientProtocolException,IOException{HttpPosthttp=newHttpPost(url);setEntity(http);execute(http);}publicvoidput()throwsClientProtocolException,IOException{HttpPuthttp=newHttpPut(url);setEntity(http);execute(http);}publicvoidget()throwsClientProtocolException,IOException{if(param!=null){StringBuilderurl=newStringBuilder(this.url);booleanisFirst=true;for(Stringkey:param.keySet()){if(isFirst)url.append("?");elseurl.append("&");url.append(key).append("=").append(param.get(key));}this.url=url.toString();}HttpGethttp=newHttpGet(url);execute(http);}/***sethttppost,putparam*/privatevoidsetEntity(HttpEntityEnclosingRequestBasehttp){if(param!=null){List<NameValuePair>nvps=newLinkedList<NameValuePair>();for(Stringkey:param.keySet())nvps.add(newBasicNameValuePair(key,param.get(key)));//参数http.setEntity(newUrlEncodedFormEntity(nvps,Consts.UTF_8));//设置参数}if(xmlParam!=null){http.setEntity(newStringEntity(xmlParam,Consts.UTF_8));}}privatevoidexecute(HttpUriRequesthttp)throwsClientProtocolException,IOException{CloseableHttpClienthttpClient=null;try{if(isHttps){SSLContextsslContext=newSSLContextBuilder().loadTrustMaterial(null,newTrustStrategy(){//信任所有publicbooleanisTrusted(X509Certificate[]chain,StringauthType)throwsCertificateException{returntrue;}}).build();SSLConnectionSocketFactorysslsf=newSSLConnectionSocketFactory(sslContext);httpClient=HttpClients.custom().setSSLSocketFactory(sslsf).build();}else{httpClient=HttpClients.createDefault();}CloseableHttpResponseresponse=httpClient.execute(http);try{if(response!=null){if(response.getStatusLine()!=null)statusCode=response.getStatusLine().getStatusCode();HttpEntityentity=response.getEntity();//响应内容content=EntityUtils.toString(entity,Consts.UTF_8);}}finally{response.close();}}catch(Exceptione){e.printStackTrace();}finally{httpClient.close();}}publicintgetStatusCode(){returnstatusCode;}publicStringgetContent()throwsParseException,IOException{returncontent;}}

2.生成订单

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

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

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

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

在service_order订单模块创建:

@Component@FeignClient("service-ucenter")//调用的服务名称publicinterfaceUcenterClient{//根据用户id获取用户信息,用于生成订单使用@PostMapping("/educenter/member/getUserInfoOrder/{id}")publicUcenterMemberOrdergetUserInfoOrder(@PathVariable("id")Stringid);}

@Component@FeignClient("service-edu")//调用的服务名称publicinterfaceCourseClient{//根据课程id查询课程信息@PostMapping("/eduservice/coursefront/getCourseInfoOrder/{id}")publicCourseWebOrdergetCourseInfoOrder(@PathVariable("id")Stringid);}

2.2 远程调用方法的实现

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

controller层:

/***根据课程id查询课程信息*@paramid客场id*@returnCourseWebOrder*/@PostMapping("getCourseInfoOrder/{id}")publicCourseWebOrdergetCourseInfoOrder(@PathVariable("id")Stringid){CourseWebVocourseInfo=courseService.getBaseCourseInfo(id);CourseWebOrdercourseWebOrder=newCourseWebOrder();BeanUtils.copyProperties(courseInfo,courseWebOrder);returncourseWebOrder;}

service层:

/***根据课程id,编写sql语句查询课程信息*@paramcourseId课程id*@returnCourseWebVo*/@OverridepublicCourseWebVogetBaseCourseInfo(StringcourseId){returnbaseMapper.getBaseCourseInfo(courseId);}

mapper层:

<!--根据课程id查询课程基本信息--><selectid="getBaseCourseInfo"resultType="com.atguigu.eduservice.entity.frontvo.CourseWebVo">SELECTec.id,ec.`title`,ec.`price`,ec.lesson_numaslessonNum,ec.cover,ec.buy_countasbuyCount,ec.view_countasviewCount,ecd.description,et.idteacherId,et.`name`ASteacherName,et.intro,et.avatar,es1.idassubjectLevelOneId,es1.`title`ASsubjectLevelOne,es2.idassubjectLevelTwoId,es2.`title`ASsubjectLevelTwoFROMedu_courseecLEFTJOINedu_course_descriptionecdONec.id=ecd.idLEFTJOINedu_teacheretONec.`teacher_id`=et.`id`LEFTJOINedu_subjectes1ONec.`subject_parent_id`=es1.`id`LEFTJOINedu_subjectes2ONec.`subject_id`=es2.`id`WHEREec.id=#{courseId}</select>

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

controller层:

/***根据用户id获取用户信息,用于生成订单使用**@paramid用户id*@returnUcenterMemberOrder*/@PostMapping("getUserInfoOrder/{id}")publicUcenterMemberOrdergetUserInfoOrder(@PathVariable("id")Stringid){UcenterMembermember=memberService.getById(id);UcenterMemberOrdermemberOrder=newUcenterMemberOrder();BeanUtils.copyProperties(member,memberOrder);returnmemberOrder;}

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

controller层:

@CrossOrigin@RestController@RequestMapping("/eduorder/order")publicclassOrderController{@AutowiredprivateOrderServiceorderService;/***生成订单的方法**@paramcourseId课程id*@paramrequest用于获取用户id*@return返回订单号*/@PostMapping("createOrder/{courseId}")publicRsaveOrder(@PathVariable("courseId")StringcourseId,HttpServletRequestrequest){//通过JWT工具类获取用户id//创建订单,返回订单号StringorderNo=orderService.createOrderById(courseId,JwtUtils.getMemberIdByJwtToken(request));returnR.ok().data("orderId",orderNo);}}

service层:

/***根据courseId和userId生成订单**@paramcourseId课程id*@paramuserId用户id*@return返回订单号*/@OverridepublicStringcreateOrderById(StringcourseId,StringuserId){//通过远程调佣根据用户id获取用户信息UcenterMemberOrderuserInfoOrder=ucenterClient.getUserInfoOrder(userId);//通过远程调佣根据课程id获取课程信息CourseWebOrdercourseInfoOrder=courseClient.getCourseInfoOrder(courseId);Orderorder=newOrder();//订单号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已支付:1order.setStatus(0);//支付类型微信:1支付宝:2order.setPayType(1);//保存到数据库baseMapper.insert(order);//返回订单号returnorder.getOrderNo();}

3.查询订单信息

3.1 controller层

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

/***根据订单id查询订单信息*@paramorderId订单id*@return返回订单信息*/@GetMapping("getOrderInfo/{orderId}")publicRgetOrderInfo(@PathVariable("orderId")StringorderId){Orderorder=orderService.getOrderByOrderId(orderId);returnR.ok().data("item",order);}

3.2 service层

/***根据订单id查询订单信息**@paramorderId订单id*@return返回订单信息*/@OverridepublicOrdergetOrderByOrderId(StringorderId){LambdaQueryWrapper<Order>queryWrapper=newLambdaQueryWrapper<>();queryWrapper.eq(Order::getOrderNo,orderId);returnbaseMapper.selectOne(queryWrapper);}

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

4.1 controller层

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

@CrossOrigin@RestController@RequestMapping("/eduorder/paylog")publicclassPayLogController{@AutowiredprivatePayLogServicepayLogService;/***根据订单号生成微信支付二维码*@paramorderNo订单号*@returnR*/@GetMapping("createNative/{orderNo}")publicRcreateNative(@PathVariable("orderNo")StringorderNo){//返回信息,包含二维码地址,还有其他信息Mapmap=payLogService.createNative(orderNo);returnR.ok().data(map);}}

4.2 service层

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

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

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

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

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

  6. 最终返回封装数据

/***根据订单号生成微信支付二维码*@paramorderNo订单号*@returnmap*/@OverridepublicMapcreateNative(StringorderNo){try{//1.根据订单号查询订单信息Orderorder=orderService.getOrderByOrderId(orderNo);//2.使用map设置生成二维码需要的参数Mapm=newHashMap();//关联的公众号appidm.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(newBigDecimal("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格式,传入微信支付提供的固定地址HttpClientclient=newHttpClient(ConstantWxPayUtils.WX_PAY_WX_URL);//设置xml格式的参数,需要传入二维码参数m和商户keyclient.setXmlParam(WXPayUtil.generateSignedXml(m,ConstantWxPayUtils.WX_PAY_PARTNER_KEY));//默认不支持https,设置为true支持client.setHttps(true);//执行请求发送client.post();//4.得到发送请求返回的结果//返回的内容是xml格式Stringxml=client.getContent();//把xml格式转换为map集合Map<String,String>resultMap=WXPayUtil.xmlToMap(xml);//5.最终返回封装数据Mapmap=newHashMap();//订单号map.put("out_trade_no",orderNo);//课程idmap.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"));returnmap;}catch(Exceptione){thrownewGuliException(20001,"生成微信支付二维码失败");}}

5.查询订单支付状态

5.1 controller层

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

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

5.2 service层

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

  1. 封装参数

  2. 发送httpclient

  3. 得到请求返回的内容

/***根据订单号查询订单支付状态*@paramorderNo*@return*/@OverridepublicMap<String,String>queryPayStatus(StringorderNo){try{//1.封装参数Mapm=newHashMap();//关联的公众号appidm.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.发送httpclientHttpClientclient=newHttpClient(ConstantWxPayUtils.WX_PAY_QUERY_URL);client.setXmlParam(WXPayUtil.generateSignedXml(m,ConstantWxPayUtils.WX_PAY_PARTNER_KEY));client.setHttps(true);client.post();//3.得到请求返回的内容Stringxml=client.getContent();Map<String,String>resultMap=WXPayUtil.xmlToMap(xml);returnresultMap;}catch(Exceptione){e.printStackTrace();thrownewGuliException(20001,"查询订单支付状态失败");}}

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

/***向支付表添加记录,更新订单表订单状态*@parammap*/@OverridepublicvoidupdateOrdersStatus(Map<String,String>map){//从map获取订单号StringorderNo=map.get("out_trade_no");Orderorder=orderService.getOrderByOrderId(orderNo);//更新订单表t_order的订单状态statusif(order.getStatus().intValue()==1){return;}order.setStatus(1);orderService.updateById(order);//向支付表t_pag_log添加记录PayLogpayLog=newPayLog();payLog.setOrderNo(orderNo);payLog.setPayTime(newDate());//支付类型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如何实现整合微信支付”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。

发布于 2022-03-03 21:24:25
收藏
分享
海报
0 条评论
46
上一篇:element怎么用脚本自动化构建新组件 下一篇:如何使用java实现双层圣诞树加修饰
目录

    0 条评论

    本站已关闭游客评论,请登录或者注册后再评论吧~

    忘记密码?

    图形验证码