• springboot集成 生成二维码微信支付


    目录

    1、添加依赖

     2、封装工具类

    2.1 HttpUtil

    2.2 WebServletUtil

    2.3 Swagger2Conf

    2.4 向微信发送请求并获取code_url

    3、控制层

    4、配置文件

    payconfig.properties

    5、测试

    5.1、访问doc.html

    5.2、获取二维码


    1、添加依赖

            
                org.springframework.boot
                spring-boot-starter-web
            
            
                com.fasterxml.jackson.core
                jackson-databind
                2.11.0
            
              
            
              com.fasterxml.jackson.datatype
              jackson-datatype-jsr310
              2.9.3
            
            
            
                org.projectlombok
                lombok
                true
            
            
                org.springframework.boot
                spring-boot-starter-test
                test
            
            
                org.springframework.boot
                spring-boot-configuration-processor
                true
            
            
            
            
                 com.google.zxing
                 core
                 3.2.1
             
             
                 com.google.zxing
                 javase
                 3.2.0
             
             
             
                com.github.wxpay
                wxpay-sdk
                0.0.3
            
    
             
            
                org.apache.httpcomponents
                httpclient
            
    
             
            
                com.github.xiaoymin
                swagger-bootstrap-ui
                1.9.6
            
            
                com.spring4all
                swagger-spring-boot-starter
                1.9.1.RELEASE
            

     2、封装工具类

    2.1 HttpUtil

    1. public class HttpUtil {
    2. private String url;
    3. private Map param;
    4. private int statusCode;//状态码
    5. private String content;//主体部分
    6. private String xmlParam;//生成的xml
    7. private boolean isHttps;
    8. public boolean isHttps() {
    9. return isHttps;
    10. }
    11. public void setHttps(boolean isHttps) {
    12. this.isHttps = isHttps;
    13. }
    14. public String getXmlParam() {
    15. return xmlParam;
    16. }
    17. public void setXmlParam(String xmlParam) {
    18. this.xmlParam = xmlParam;
    19. }
    20. public HttpUtil(String url, Map param) {
    21. this.url = url;
    22. this.param = param;
    23. }
    24. public HttpUtil(String url) {
    25. this.url = url;
    26. }
    27. public void setParameter(Map map) {
    28. param = map;
    29. }
    30. public void addParameter(String key, String value) {
    31. if (param == null)
    32. param = new HashMap();
    33. param.put(key, value);
    34. }
    35. public void post() throws ClientProtocolException, IOException {
    36. HttpPost http = new HttpPost(url);
    37. setEntity(http);
    38. execute(http);
    39. }
    40. public void put() throws ClientProtocolException, IOException {
    41. HttpPut http = new HttpPut(url);
    42. setEntity(http);
    43. execute(http);
    44. }
    45. public void get() throws ClientProtocolException, IOException {
    46. if (param != null) {
    47. StringBuilder url = new StringBuilder(this.url);
    48. boolean isFirst = true;
    49. for (String key : param.keySet()) {
    50. if (isFirst)
    51. url.append("?");
    52. else
    53. url.append("&");
    54. url.append(key).append("=").append(param.get(key));
    55. }
    56. this.url = url.toString();
    57. }
    58. HttpGet http = new HttpGet(url);
    59. execute(http);
    60. }
    61. /**
    62. * set http post,put param
    63. */
    64. private void setEntity(HttpEntityEnclosingRequestBase http) {
    65. if (param != null) {
    66. List nvps = new LinkedList();
    67. for (String key : param.keySet())
    68. nvps.add(new BasicNameValuePair(key, param.get(key))); // 参数
    69. http.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8)); // 设置参数
    70. }
    71. if (xmlParam != null) {
    72. http.setEntity(new StringEntity(xmlParam, Consts.UTF_8));
    73. }
    74. }
    75. private void execute(HttpUriRequest http) throws ClientProtocolException,
    76. IOException {
    77. CloseableHttpClient httpClient = null;
    78. try {
    79. if (isHttps) {
    80. SSLContext sslContext = new SSLContextBuilder()
    81. .loadTrustMaterial(null, new TrustStrategy() {
    82. // 信任所有
    83. public boolean isTrusted(X509Certificate[] chain,
    84. String authType)
    85. throws CertificateException {
    86. return true;
    87. }
    88. }).build();
    89. SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
    90. sslContext);
    91. httpClient = HttpClients.custom().setSSLSocketFactory(sslsf)
    92. .build();
    93. } else {
    94. httpClient = HttpClients.createDefault();
    95. }
    96. CloseableHttpResponse response = httpClient.execute(http);
    97. try {
    98. if (response != null) {
    99. if (response.getStatusLine() != null)
    100. statusCode = response.getStatusLine().getStatusCode();
    101. HttpEntity entity = response.getEntity();
    102. // 响应内容
    103. content = EntityUtils.toString(entity, Consts.UTF_8);
    104. }
    105. } finally {
    106. response.close();
    107. }
    108. } catch (Exception e) {
    109. e.printStackTrace();
    110. } finally {
    111. httpClient.close();
    112. }
    113. }
    114. public int getStatusCode() {
    115. return statusCode;
    116. }
    117. public String getContent() throws ParseException, IOException {
    118. return content;
    119. }
    120. }

    2.2 WebServletUtil

    可以根据上下文获取Reques和Response对象

    1. public class WebServletUtil {
    2. private static ServletRequestAttributes servletRequestAttributes;
    3. static {
    4. servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
    5. }
    6. public static HttpServletRequest getRequest(){
    7. return servletRequestAttributes.getRequest();
    8. }
    9. public static HttpServletResponse getResponse(){
    10. return servletRequestAttributes.getResponse();
    11. }
    12. }

    2.3 Swagger2Conf

    为了更方便测试接口集成了swagger文档

    1. @Configuration
    2. @EnableSwagger2//开启swagger
    3. public class Swagger2Conf {
    4. @Bean
    5. public Docket webApiConfig(){
    6. return new Docket(DocumentationType.SWAGGER_2)
    7. .groupName("webApi")
    8. .apiInfo(webApiInfo())
    9. .select()
    10. .apis(RequestHandlerSelectors.basePackage("com.gzh.weixinpay.controller"))
    11. //过滤掉所有error或error.*页面
    12. .paths(Predicates.not(PathSelectors.regex("/error.*")))
    13. .build();
    14. }
    15. private ApiInfo webApiInfo(){
    16. return new ApiInfoBuilder()
    17. .title("权限管理API文档")
    18. .description("本文档描述了权限管理接口定义")
    19. .version("1.0")
    20. .contact(new Contact("gzh", "http://taobao.com", "1984274233@qq.com"))
    21. .build();
    22. }
    23. }

    2.4 向微信发送请求并获取code_url

    1. package com.gzh.weixinpay.conf;
    2. import com.fasterxml.jackson.core.JsonProcessingException;
    3. import com.fasterxml.jackson.databind.ObjectMapper;
    4. import com.github.wxpay.sdk.WXPayUtil;
    5. import com.google.zxing.BarcodeFormat;
    6. import com.google.zxing.EncodeHintType;
    7. import com.google.zxing.MultiFormatWriter;
    8. import com.google.zxing.client.j2se.MatrixToImageWriter;
    9. import com.google.zxing.common.BitMatrix;
    10. import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
    11. import com.gzh.weixinpay.util.HttpUtil;
    12. import com.gzh.weixinpay.util.WebServletUtil;
    13. import lombok.Data;
    14. import org.springframework.beans.factory.annotation.Value;
    15. import org.springframework.boot.context.properties.ConfigurationProperties;
    16. import org.springframework.context.annotation.PropertySource;
    17. import org.springframework.stereotype.Component;
    18. import java.io.OutputStream;
    19. import java.io.Serializable;
    20. import java.text.SimpleDateFormat;
    21. import java.util.Date;
    22. import java.util.HashMap;
    23. import java.util.Map;
    24. /**
    25. * TODO
    26. *
    27. * @author DELL
    28. * @version 1.0
    29. * @since 2022-08-12 21:00:56
    30. */
    31. @Data
    32. @Component("config")
    33. @ConfigurationProperties(prefix = "weixin")//让配置参数能分离出来
    34. @PropertySource("classpath:payconfig.properties")
    35. public class WxConfig implements Serializable {
    36. @Value("${APPID}")
    37. private String APPID;
    38. @Value("${MCH_ID}")
    39. private String MCH_ID;
    40. @Value("${KEY}")
    41. private String KEY;
    42. @Value("${SPBILL_CREATE_IP}")
    43. private String SPBILL_CREATE_IP;
    44. @Value("${NOTIFY_URL}")
    45. private String NOTIFY_URL;
    46. @Value("${TRADE_TYPE}")
    47. private String TRADE_TYPE;
    48. @Value("${PLACEANORDER_URL}")
    49. private String PAY_URL;
    50. @Value("${QUERY_URL}")
    51. private String QRY_URL;
    52. /**
    53. *
    54. * @param out_trade_no 订单编号
    55. * @param total_fee 总金额
    56. * @param expireTimeMin 失效时间
    57. * @return
    58. */
    59. public Map createNative(String out_trade_no, int total_fee , Integer expireTimeMin) throws JsonProcessingException {
    60. Map param = new HashMap();
    61. param.put("appid", APPID);
    62. param.put("mch_id", MCH_ID);
    63. param.put("nonce_str", WXPayUtil.generateNonceStr());
    64. param.put("body", "测试支付功能"); //定义订单内容
    65. param.put("out_trade_no", out_trade_no); //商户订单编号
    66. param.put("fee_type", "CNY");
    67. param.put("total_fee", new ObjectMapper().writeValueAsString(total_fee)); //总金额
    68. param.put("spbill_create_ip", SPBILL_CREATE_IP);
    69. param.put("notify_url", NOTIFY_URL); //回调地址
    70. param.put("trade_type", "NATIVE");
    71. Date date = new Date();
    72. long time = date.getTime();
    73. SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
    74. String timeStart = simpleDateFormat.format(time);
    75. String timeEnd = simpleDateFormat.format(time + expireTimeMin * 60000);
    76. param.put("time_start", timeStart); //订单创建时间
    77. param.put("time_expire", timeEnd); //定义失效时间
    78. try {
    79. String xmlParam = WXPayUtil.generateSignedXml(param, KEY); //参数转换
    80. HttpUtil client = new HttpUtil(PAY_URL);
    81. client.setHttps(true);
    82. client.setXmlParam(xmlParam);
    83. client.post();
    84. String result = client.getContent();
    85. Map resultMap = WXPayUtil.xmlToMap(result);
    86. if (resultMap.get("err_code") != null && resultMap.get("err_code").equals("ORDERPAID")) {
    87. System.out.println("<--"+out_trade_no+"--> :订单已经支付!");
    88. }
    89. Map map = new HashMap<>();
    90. String code_url = resultMap.get("code_url");
    91. map.put("code_url", code_url);
    92. map.put("total_fee", String.valueOf(total_fee));
    93. map.put("out_trade_no", out_trade_no);
    94. return map;
    95. } catch (Exception e) {
    96. e.printStackTrace();
    97. return null;
    98. }
    99. }
    100. /**
    101. * @param out_trade_no 订单id
    102. * @return
    103. */
    104. public Map queryPayStatus(String out_trade_no) {
    105. Map param = new HashMap();
    106. param.put("appid", APPID);
    107. param.put("mch_id", MCH_ID);
    108. param.put("out_trade_no", out_trade_no);
    109. param.put("nonce_str", WXPayUtil.generateNonceStr());
    110. try {
    111. String xmlParam = WXPayUtil.generateSignedXml(param, KEY);
    112. HttpUtil client = new HttpUtil(QRY_URL);
    113. client.setHttps(true);
    114. client.setXmlParam(xmlParam);
    115. client.post();
    116. String result = client.getContent();
    117. Map map = WXPayUtil.xmlToMap(result);
    118. if (map.get("err_code") != null && map.get("err_code").equals("ORDERNOTEXIST")) {
    119. System.out.println("订单不存在!");
    120. }
    121. if (map.get("trade_state").equals("SUCCESS")) {
    122. //支付成功,未支付为:NOTPAY
    123. }
    124. return map;
    125. } catch (Exception e) {
    126. e.printStackTrace();
    127. return null;
    128. }
    129. }
    130. }

    3、控制层

    1. @RestController
    2. @CrossOrigin
    3. @RequestMapping("/order")
    4. public class PayController {
    5. @Resource
    6. WxConfig config;
    7. @PostMapping("/createPay")
    8. public BusiResult createPayOrder(@RequestBody PayVo payVo) throws JsonProcessingException {
    9. //向微信发起调用生成预付链接
    10. Map res = config.createNative(payVo.getOrderId(),
    11. payVo.getFee(),
    12. payVo.getExpirTime());
    13. System.out.println(res);
    14. return BusiResult.success(res);
    15. }
    16. //生成二维码图片
    17. @GetMapping("getImg")
    18. public void getImg(String code_url){
    19. if(code_url == null) throw new NullPointerException();
    20. try {
    21. //生成二维码配置
    22. Map hints = new HashMap<>();
    23. // 设置纠错等级
    24. hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);
    25. // 编码类型
    26. hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
    27. BitMatrix bitMatrix = new MultiFormatWriter().encode(code_url, BarcodeFormat.QR_CODE, 400, 400, hints);
    28. OutputStream outputStream = WebServletUtil.getResponse().getOutputStream();
    29. MatrixToImageWriter.writeToStream(bitMatrix, "png", outputStream);
    30. } catch (Exception e){
    31. e.printStackTrace();
    32. }
    33. }
    34. @PostMapping("/queryPayStatus")
    35. public BusiResult queryPayStatus(@RequestBody PayVo payVo){
    36. //向微信发起调用生成预付链接
    37. Map res = config.queryPayStatus(payVo.getOrderId());
    38. System.out.println(res);
    39. return BusiResult.success(res);
    40. }
    41. }

    4、配置文件

    payconfig.properties

    #公众号appleId
    APPID=?
    #商户号
    MCH_ID=?
    #商户密钥
    KEY=?
    #APP和网页支付提交用户端ip, Native支付填调用微信支付API的机器IP, 即:服务器ip地址
    SPBILL_CREATE_IP=127.0.0.1
    #接收微信支付异步通知回调地址,通知url必须为直接可访问的url,不能携带参数。(需要配置)
    NOTIFY_URL=http://225m5x.natappfree.cc/page/notify
    #支付方式,取值如下:JSAPI,NATIVE,APP
    TRADE_TYPE=NATIVE
    # 微信支付 - 统一下单地址
    PLACEANORDER_URL=https://api.mch.weixin.qq.com/pay/unifiedorder
    
    QUERY_URL=https://api.mch.weixin.qq.com/pay/orderquery

    5、测试

    5.1、访问doc.html

    5.2、获取二维码

     

  • 相关阅读:
    小程序环境切换自定义组件
    mogodb简单整理
    win11该文件没有与之关联的应用怎么办
    JAXB实现xml到bean录入数据库
    Python潮流周刊#10:Twitter 的强敌 Threads 是用 Python 开发的
    知识直播:时代乐见搜狐的长期主义选择
    49. 字母异位词分组
    C++ STL标准模板库(一)
    即时通讯开发Netty实现心跳机制、断线重连机制
    根据您的数据量定制的ChatGPT,改变客户服务的方式
  • 原文地址:https://blog.csdn.net/qq_41720578/article/details/126319804