diff --git a/pom.xml b/pom.xml index 998c63d..17fc067 100644 --- a/pom.xml +++ b/pom.xml @@ -196,6 +196,27 @@ fastjson 1.2.75 + + + com.github.wechatpay-apiv3 + wechatpay-apache-httpclient + 0.4.8 + + + + + com.squareup.okhttp3 + okhttp + 4.9.3 + + + + + commons-lang + commons-lang + 2.6 + + diff --git a/src/main/java/org/springblade/weixin/controller/AppEbLoginController.java b/src/main/java/org/springblade/weixin/controller/AppEbLoginController.java index 8a85e6f..7fca346 100644 --- a/src/main/java/org/springblade/weixin/controller/AppEbLoginController.java +++ b/src/main/java/org/springblade/weixin/controller/AppEbLoginController.java @@ -8,16 +8,14 @@ import org.springblade.common.cache.DictCache; import org.springblade.common.enums.DictEnum; import org.springblade.core.log.exception.ServiceException; import org.springblade.core.tool.api.R; -import org.springblade.core.tool.support.Kv; import org.springblade.core.tool.utils.SpringUtil; import org.springblade.modules.auth.endpoint.BladeTokenEndPoint; -import org.springblade.modules.system.entity.User; -import org.springblade.modules.system.service.IUserService; import org.springblade.weixin.entity.WeChatPhone; import org.springblade.weixin.entity.WeChatPhoneInfo; import org.springblade.weixin.entity.WeChatUser; import org.springblade.weixin.service.IWeChatUserService; import org.springblade.weixin.utils.WeChatUtil; +import org.springblade.weixin.utils.WxPayUtils; import org.springframework.web.bind.annotation.*; import java.util.HashMap; @@ -33,15 +31,10 @@ public class AppEbLoginController { /** * 获取openid - * - * @param weChatPhone - * @return */ @PostMapping("/login") public R login(@RequestBody WeChatPhone weChatPhone) { - //小程序appId appSecret -// String appId = "wx432c2efe6df3b97a"; -// String appSecret = "859df8b167e74223e9237dee1b344524"; + //小程序 appId = "wx432c2efe6df3b97a" appSecret = "859df8b167e74223e9237dee1b344524" String appId = DictCache.getValue(DictEnum.WECHAT_APP, "appId"); String appSecret = DictCache.getValue(DictEnum.WECHAT_APP, "appSecret"); @@ -57,7 +50,7 @@ public class AppEbLoginController { WeChatUser user = weChatUserService.getOne(Wrappers.lambdaQuery().eq(WeChatUser::getOpenId, openid)); if (user != null) { map.put("userInfo", user); -// BladeTokenEndPoint point = SpringUtil.getBean(BladeTokenEndPoint.class); + BladeTokenEndPoint point = SpringUtil.getBean(BladeTokenEndPoint.class); // Kv admin = point.token("000000", "admin", "21232f297a57a5a743894a0e4a801fc3", "", ""); } //获得响应的数据 @@ -109,4 +102,9 @@ public class AppEbLoginController { return R.data(phoneInfo.getPurePhoneNumber()); } + @PostMapping("/createOrder") + public R createOrder(String openId) { + return R.data(WxPayUtils.createOrderJSApiV3(openId)); + } + } \ No newline at end of file diff --git a/src/main/java/org/springblade/weixin/controller/WeChatAddressController.java b/src/main/java/org/springblade/weixin/controller/WeChatAddressController.java new file mode 100644 index 0000000..7f397fe --- /dev/null +++ b/src/main/java/org/springblade/weixin/controller/WeChatAddressController.java @@ -0,0 +1,43 @@ +package org.springblade.weixin.controller; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.AllArgsConstructor; +import org.springblade.core.mp.support.Condition; +import org.springblade.core.mp.support.Query; +import org.springblade.core.tool.api.R; +import org.springblade.core.tool.utils.Func; +import org.springblade.weixin.entity.WeChatAddress; +import org.springblade.weixin.entity.WeChatUser; +import org.springblade.weixin.service.IWeChatAddressService; +import org.springframework.web.bind.annotation.*; + +@RestController +@AllArgsConstructor +@RequestMapping("/address") +public class WeChatAddressController { + + private final IWeChatAddressService weChatAddressService; + + @GetMapping("/list") + public R> list(WeChatUser weChatUser, Query query) { +// return R.data(weChatAddressService.getPage(weChatUser, Condition.getPage(query))); + return R.data(weChatAddressService.page(Condition.getPage(query), Wrappers.lambdaQuery().eq(weChatUser.getId() != null, WeChatAddress::getUserId, weChatUser.getId()))); + } + + @PostMapping("/save") + public R save(@RequestBody WeChatAddress weChatAddress) { + return R.status(weChatAddressService.add(weChatAddress)); + } + + @PostMapping("/update") + public R update(@RequestBody WeChatAddress weChatAddress) { + return R.status(weChatAddressService.edit(weChatAddress)); + } + + @PostMapping("/delete") + public R delete(@RequestParam String ids) { + return R.status(weChatAddressService.deleteLogic(Func.toLongList(ids))); + } + +} \ No newline at end of file diff --git a/src/main/java/org/springblade/weixin/controller/WeChatUserController.java b/src/main/java/org/springblade/weixin/controller/WeChatUserController.java index 5bc8b1a..95d435a 100644 --- a/src/main/java/org/springblade/weixin/controller/WeChatUserController.java +++ b/src/main/java/org/springblade/weixin/controller/WeChatUserController.java @@ -24,7 +24,8 @@ public class WeChatUserController { @PostMapping("/save") public R save(@RequestBody WeChatUser weChatUser) { - return R.status(weChatUserService.save(weChatUser)); + weChatUserService.save(weChatUser); + return R.data(weChatUser); } @PostMapping("/update") diff --git a/src/main/java/org/springblade/weixin/entity/WeChatAddress.java b/src/main/java/org/springblade/weixin/entity/WeChatAddress.java new file mode 100644 index 0000000..0074cc9 --- /dev/null +++ b/src/main/java/org/springblade/weixin/entity/WeChatAddress.java @@ -0,0 +1,42 @@ +package org.springblade.weixin.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import org.springblade.core.mp.base.BaseEntity; + +@Data +@TableName("eh_address") +public class WeChatAddress extends BaseEntity { + private static final long serialVersionUID = 1L; + + /** + * 用户id + */ + private Long userId; + + /** + * 收货人 + */ + private String consignee; + + /** + * 手机号码 + */ + private String phone; + + /** + * 所在地区 + */ + private String area; + + /** + * 详细地址 + */ + private String address; + + /** + * 是否默认地址(0否 1是) + */ + private Integer isDefault; + +} diff --git a/src/main/java/org/springblade/weixin/entity/WeChatUser.java b/src/main/java/org/springblade/weixin/entity/WeChatUser.java index 78b38b3..42b4648 100644 --- a/src/main/java/org/springblade/weixin/entity/WeChatUser.java +++ b/src/main/java/org/springblade/weixin/entity/WeChatUser.java @@ -2,11 +2,11 @@ package org.springblade.weixin.entity; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; -import org.springblade.core.tenant.mp.TenantEntity; +import org.springblade.core.mp.base.BaseEntity; @Data @TableName("eh_wx_user") -public class WeChatUser extends TenantEntity { +public class WeChatUser extends BaseEntity { private static final long serialVersionUID = 1L; /** @@ -15,17 +15,17 @@ public class WeChatUser extends TenantEntity { private String openId; /** - * 微信用户唯一标识 + * 昵称 */ private String username; /** - * 微信用户唯一标识 + * 手机 */ private String phone; /** - * 微信用户唯一标识 + * 头像 */ private String avatar; diff --git a/src/main/java/org/springblade/weixin/mapper/WeChatAddressMapper.java b/src/main/java/org/springblade/weixin/mapper/WeChatAddressMapper.java new file mode 100644 index 0000000..251851f --- /dev/null +++ b/src/main/java/org/springblade/weixin/mapper/WeChatAddressMapper.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2018-2028, Chill Zhuang All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the dreamlu.net developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: Chill 庄骞 (smallchill@163.com) + */ +package org.springblade.weixin.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import org.springblade.weixin.entity.WeChatAddress; +import org.springblade.weixin.entity.WeChatUser; + +import java.util.List; + +/** + * Mapper 接口 + * @author BladeX + */ +public interface WeChatAddressMapper extends BaseMapper { + + List getPage(IPage page, WeChatUser weChatUser); +} diff --git a/src/main/java/org/springblade/weixin/mapper/WeChatAddressMapper.xml b/src/main/java/org/springblade/weixin/mapper/WeChatAddressMapper.xml new file mode 100644 index 0000000..27cd5bc --- /dev/null +++ b/src/main/java/org/springblade/weixin/mapper/WeChatAddressMapper.xml @@ -0,0 +1,23 @@ + + + + + + diff --git a/src/main/java/org/springblade/weixin/service/IWeChatAddressService.java b/src/main/java/org/springblade/weixin/service/IWeChatAddressService.java new file mode 100644 index 0000000..535923a --- /dev/null +++ b/src/main/java/org/springblade/weixin/service/IWeChatAddressService.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2018-2028, Chill Zhuang All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the dreamlu.net developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: Chill 庄骞 (smallchill@163.com) + */ +package org.springblade.weixin.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import org.springblade.core.mp.base.BaseService; +import org.springblade.weixin.entity.WeChatAddress; +import org.springblade.weixin.entity.WeChatUser; + +/** + * 服务类 + * + * @author BladeX + */ +public interface IWeChatAddressService extends BaseService { + + IPage getPage(WeChatUser weChatUser, IPage page); + + boolean add(WeChatAddress weChatAddress); + + boolean edit(WeChatAddress weChatAddress); +} diff --git a/src/main/java/org/springblade/weixin/service/impl/WeChatAddressServiceImpl.java b/src/main/java/org/springblade/weixin/service/impl/WeChatAddressServiceImpl.java new file mode 100644 index 0000000..f3e5fc8 --- /dev/null +++ b/src/main/java/org/springblade/weixin/service/impl/WeChatAddressServiceImpl.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2018-2028, Chill Zhuang All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the dreamlu.net developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: Chill 庄骞 (smallchill@163.com) + */ +package org.springblade.weixin.service.impl; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.AllArgsConstructor; +import org.springblade.core.mp.base.BaseServiceImpl; +import org.springblade.weixin.entity.WeChatAddress; +import org.springblade.weixin.entity.WeChatUser; +import org.springblade.weixin.mapper.WeChatAddressMapper; +import org.springblade.weixin.service.IWeChatAddressService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** + * 服务实现类 + */ +@Service +@AllArgsConstructor +public class WeChatAddressServiceImpl extends BaseServiceImpl implements IWeChatAddressService { + + private final WeChatAddressMapper weChatAddressMapper; + + @Override + public IPage getPage(WeChatUser weChatUser, IPage page) { + return page.setRecords(weChatAddressMapper.getPage(page, weChatUser)); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean add(WeChatAddress weChatAddress) { + weChatAddress.setIsDefault(0); +// if (weChatAddress.getIsDefault() == 1) { +// WeChatAddress address = this.getOne(Wrappers.lambdaQuery().eq(WeChatAddress::getUserId, weChatAddress.getUserId()).eq(WeChatAddress::getIsDefault, 1)); +// if (address != null) { +// address.setIsDefault(0); +// this.updateById(address); +// } +// } + return this.save(weChatAddress); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean edit(WeChatAddress weChatAddress) { + if (weChatAddress.getIsDefault() == 1) { + WeChatAddress address = this.getOne(Wrappers.lambdaQuery().eq(WeChatAddress::getUserId, weChatAddress.getUserId()).eq(WeChatAddress::getIsDefault, 1)); + if (address != null && !address.getId().equals(weChatAddress.getId())) { + address.setIsDefault(0); + this.updateById(address); + } + } + return this.updateById(weChatAddress); + } + +} diff --git a/src/main/java/org/springblade/weixin/utils/WeChatUtil.java b/src/main/java/org/springblade/weixin/utils/WeChatUtil.java index 42c2c21..04ea712 100644 --- a/src/main/java/org/springblade/weixin/utils/WeChatUtil.java +++ b/src/main/java/org/springblade/weixin/utils/WeChatUtil.java @@ -5,10 +5,12 @@ import cn.hutool.json.JSONUtil; import com.alibaba.fastjson.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.commons.codec.binary.Base64; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.util.EntityUtils; import org.springblade.core.http.util.HttpUtil; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.client.RestTemplate; @@ -21,6 +23,8 @@ import java.util.Map; public class WeChatUtil { + private static CloseableHttpClient httpClient; + /** * 请求微信接口服务,获取小程序全局唯一后台接口调用凭据(access_token) * https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/access-token/auth.getAccessToken.html diff --git a/src/main/java/org/springblade/weixin/utils/WxPayUtils.java b/src/main/java/org/springblade/weixin/utils/WxPayUtils.java new file mode 100644 index 0000000..230d567 --- /dev/null +++ b/src/main/java/org/springblade/weixin/utils/WxPayUtils.java @@ -0,0 +1,329 @@ +package org.springblade.weixin.utils; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder; +import com.wechat.pay.contrib.apache.httpclient.auth.*; +import com.wechat.pay.contrib.apache.httpclient.util.PemUtil; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.util.EntityUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.security.*; +import java.util.*; + +public class WxPayUtils { + + private static Logger logger = LoggerFactory.getLogger(WxPayUtils.class); + + //appId 微信公众号里创建的AppId,这里的公众号需要关联到微信支付上, + // 微信公众平台-基本配置-开发者ID(AppID),这个绑定到微信支付-产品中心-AppID账号管理-关联AppID.这里关联公众号的AppId + public static String appId = "wx432c2efe6df3b97a"; + + //微信支付商户号 微信支付-账户中心-商户信息-微信支付商户号.查看 + public static String mchId = "1650865884"; + + // 微信下单回调地址,支付成功后会回调这个地址。 + //对应文档 https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter4_1_5.shtml + public static String callbackUri = "http://www.baidu.com"; + + //APIv3密钥 在微信支付商户平台-账户中心-API安全里设置,如果设置了不知道,就只有修改 + public static String apiV3Key = "2q5w8e3a6s9d1eeeeee8p5M6N9a09"; + + // 第三方用户唯一凭证密钥,即appsecret 微信公众平台-基本配置-开发者密码(AppSecret) 公众号基本配置里查询 + public static String appSecret = "859df8b167e74223e9237dee1b344524"; + + // JSApi下单url地址 + public static String JSApiPayUrl = "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi"; + + // 商户私钥 获取对应的签名需要 在微信支付商户平台-账户中心-API安全里设置 养宠物那边复制的 +// 对应文档 https://pay.weixin.qq.com/wiki/doc/apiv3_partner/open/pay/chapter2_1.shtml + private static String privateKey = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC3qbz0hDWoilpKR6vYnyi4q+CCjmQUjZVIO9R9QE3OfU4qVIaUYavTL/QReO9QfMZcU3LN8JrfKBRedleBfObXXVTP9e1FZh078LEYOiI9Kdzipf3NvSzjaJqkweMe7gOaGWj60zUBQyIVN9+kQVIcqA/2oNgq3Pz88fRFaOgV91okPTj4yfE5mVZujsuHN1ov1Bbky+cbd77SIA5Vl0dXDVUB+A7ZSpc3GXeXPxbEUvHeeeeeeebOpZzcVYsnR82BfTyKmfKIhvHhQjJpHVwmjw/USxxyblLh7Nc1td7pjoommr9yvBn/knq52mPolurmUTHloOCUyxLFDfUeeeepF9iogaSswxGw6B2qK+Jd1ZOoUHnHS2XrazMwKnG1RuvZ9S6On2/lJBXxjWOcvAeKm0c/Nza3lGxcNFwD6CjiXwo+2cq82L9Y3aBiSJRQKb1"; + + //商户证书序列号 + // 对应文档 https://pay.weixin.qq.com/wiki/doc/apiv3_partner/open/pay/chapter2_1.shtml + private static String mchSerialNo = "23BC1D2F580D5eeeeeeF63D95837CC5"; + + private static CloseableHttpClient httpClient; + + /** + * 第一步:获取code + * 获取用户openID第一步,获取下一个接口的code参数 + * 访问这个url后,页面将跳转至 redirect_uri/?code=CODE&state=STATE。 + * 跳转的url携带code参数 + * 官方文档路径 + * https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html + * + * @return url + */ + public static String getCodeUrl(String reUrl) { + String url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect"; + url = url.replace("APPID", appId).replace("REDIRECT_URI", URLEncoder.encode(reUrl)); + return url; + } + + + /** + *第二部:获取AccessToken,里面包含openId + * 根据微信公众号的信息获取微信的accessToken + * {"access_token":"61_SiCTd--EFgkIpWZ4MrciAKJN0N_Dv-qdZLnJyh-","expires_in":7870,"refresh_token":"-kpaMn5czZelR87thefNLEC2WK_-","openid":"5vrCjeeMz36PQkCK57bo","scope":"snsapi_base"} + * 官方文档路径 + * https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html + */ +// public static String getAccessToken(String code) { +// String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code"; +// url = url.replace("APPID", appId).replace("SECRET", appSecret).replace("CODE",code); +// System.out.println(url); +// String res = HttpRequestsUtils.sendGet(url, ""); +// System.out.println(res); +// return res; +// } + + /** + * 第三步:JSAPI下单 + * 使用官方开发库请求下单 + * + * @param openId openId + * @return {"prepay_id": "wx2611215250487459928b000"} + * 官方文档路径 + * https://pay.weixin.qq.com/wiki/doc/apiv3_partner/open/pay/chapter2_1.shtml + */ + public static String createOrderJSApiV3(String openId) { + payLoading(); + //请求URL + HttpPost httpPost = new HttpPost(JSApiPayUrl); + // 请求body参数 + StringEntity entity = new StringEntity(JSONObject.toJSONString(buildWxJsApiV3PayJson(openId, 0)), "utf-8"); + entity.setContentType("application/json"); + httpPost.setEntity(entity); + httpPost.setHeader("Accept", "application/json"); + + //完成签名并执行请求 + CloseableHttpResponse response = null; + try { + response = httpClient.execute(httpPost); + int statusCode = response.getStatusLine().getStatusCode(); + if (statusCode == 200) { + return EntityUtils.toString(response.getEntity()); + } else if (statusCode == 204) { + return ""; + } else { + System.out.println("failed,resp code = " + statusCode + ",return body = " + EntityUtils.toString(response.getEntity())); + throw new IOException("request failed"); + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + assert response != null; + response.close(); + httpClient.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return ""; + } + + + /** + * 第四步:生成支付参数 + * 生成支付所需的参数 + * + * @param prepay_id 下单接口返回的参数 预支付交易会话标识 + * @return JSONObject + * @throws Exception e + */ + public static JSONObject getTokenWeiXin(String prepay_id) { + // 获取随机字符串 + String nonceStr = getNonceStr(); + // 获取微信小程序支付package + String packagestr = "prepay_id=" + prepay_id; + long timestamp = System.currentTimeMillis() / 1000; + //签名,使用字段appId、timeStamp、nonceStr、package计算得出的签名值 + String message = buildMessageTwo(appId, timestamp, nonceStr, packagestr); + //获取对应的签名 + String signature = sign(message.getBytes(StandardCharsets.UTF_8)); + // 组装返回 + JSONObject json = new JSONObject(new JSONObject()); + json.put("appId", appId); + json.put("timeStamp", String.valueOf(timestamp)); + json.put("nonceStr", nonceStr); + json.put("package", packagestr); + json.put("signType", "RSA"); + json.put("paySign", signature); + return json; + } + + + /** + * 先调用下单,然后调用生成支付参数 + * + * @param openId openId + * @return 支付参数 + */ + public static Object getPayParam(String openId) { + JSONObject jsonObject = JSON.parseObject(createOrderJSApiV3(openId)); + return getTokenWeiXin(jsonObject.getString("prepay_id")); + + } + + + /** + * 构造下单的json(第三步需要) + * + * @param description 商品描述 + * @param amount 订单金额 + * @param openId 用户ID onAky51Fojn3NoLrnKwcY + * @return JSONObject + */ + public static JSONObject buildWxJsApiV3PayJson(String description, String amount, String openId) { + + //订单金额json + JSONObject amountJson = new JSONObject(); + amountJson.put("total", Integer.valueOf(amount)); + amountJson.put("currency", "CNY"); + + //支付者json + JSONObject payerJson = new JSONObject(); + payerJson.put("openid", openId); + + //基础信息json + JSONObject json = new JSONObject(); +// 微信公众号里创建的APPID + json.put("appid", appId); +// 直连商户号 微信支付-账户中心-商户信息查看 + json.put("mchid", mchId); + json.put("description", description); +// 商户订单号 自己生成 + json.put("out_trade_no", generateNonceStr()); + json.put("notify_url", callbackUri); + json.put("amount", amountJson); + json.put("payer", payerJson); + return json; + } + + /** + * 根据商品goodsId构造下单的json (第三步需要) + * + * @return JSONObject + */ + public static JSONObject buildWxJsApiV3PayJson(String openId, Integer goodsId) { + return buildWxJsApiV3PayJson("测试商品", "1", openId); + } + + /** + * 构造下单的json 无参数 + * + * @return JSONObject + */ + public static JSONObject buildWxJsApiV3PayJson() { + return buildWxJsApiV3PayJson("测试商品", "1", "123123123124"); + } + + /** + * 初始化httpClient的通用方法(第三步:JSAPI下单) + * 微信支付官方开发库 + * 创建加载商户私钥、加载平台证书 + */ + public static void payLoading() { + logger.info("----------初始化httpClient-----------"); + // 加载商户私钥(privateKey:私钥字符串) + PrivateKey merchantPrivateKey = PemUtil + .loadPrivateKey(new ByteArrayInputStream(privateKey.getBytes(StandardCharsets.UTF_8))); + + // 加载平台证书(mchId:商户号,mchSerialNo:商户证书序列号,apiV3Key:V3密钥) + AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier( + new WechatPay2Credentials(mchId, new PrivateKeySigner(mchSerialNo, merchantPrivateKey)), apiV3Key.getBytes(StandardCharsets.UTF_8)); + + // 初始化httpClient + httpClient = WechatPayHttpClientBuilder.create() + .withMerchant(mchId, mchSerialNo, merchantPrivateKey) + .withValidator(new WechatPay2Validator(verifier)).build(); + } + + /** + * 看情况调用 ,关闭httpClient客户端 + * + * @throws IOException e + */ + public void after() throws IOException { + httpClient.close(); + logger.info("----------关闭httpClient-----------"); + } + + /** + * 根据微信公众号的信息获取微信的Token(没有使用) + * 官方文档:https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_access_token.html + */ +// public static String getToken() { +// String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET"; +// url = url.replace("APPID", appId).replace("APPSECRET", appSecret); +// +// String result = HttpRequestsUtils.sendGet(url,""); +// System.out.println(result); +// JSONObject jsonObject = JSON.parseObject(result); +// return jsonObject.getString("access_token"); +// } + public static void main(String[] args) { + System.out.println(WxPayUtils.getCodeUrl("")); +// String str = WxPayUtils.getAccessToken(); +// System.out.println(str); + } + + + // 获取随机字符串 + public static String getNonceStr() { + return UUID.randomUUID().toString() + .replaceAll("-", "") + .substring(0, 32); + } + + // 签名连接成一串 + private static String buildMessageTwo(String appId, long timestamp, String nonceStr, String packag) { + return appId + "\n" + + timestamp + "\n" + + nonceStr + "\n" + + packag + "\n"; + } + + + /** + * 生成签名 + * 官方文档:https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_0.shtml + * + * @param message message + * @return String + */ + private static String sign(byte[] message) { + Signature sign = null; + try { + sign = Signature.getInstance("SHA256withRSA"); + sign.initSign(PemUtil.loadPrivateKey(privateKey)); + sign.update(message); + return Base64.getEncoder().encodeToString(sign.sign()); + } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) { + e.printStackTrace(); + } + return null; + + } + + /** + * 随机字符串 订单号 + * + * @return + */ + public static String generateNonceStr() { + return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32); + } + +}