【微信小程序】微信小程序的接口调入 获取太阳码 根据返回值的类型进行接收,微信接口可能直接返回图片,也可能返回一个错误信息的json,同时兼容处理这两种情况

事件起因

在开发一个关于微信小程序的过程中,有一个这样的需求,要求生成微信小程序的太阳码,然而这个东西的请求方式我们是这样的:我作为后端服务去请求这个太阳码的二维码,然后将获取到的太阳码二维码的图片返回给小程序端进行接收,然后小程序端进行一个展示

原本以为他们小程序端直接去请求那个图片就行了,但是最后商讨下来还是由我们后端去请求这个太阳码,然后返回给前端去展示
过程中就遇到一些数据请求和转换的问题,就先在这儿记录一下,以便后来者踩坑

环境和工具

java jdk1.8

操作过程

先是接口层,最后完成的版本是这样:

    @PostMapping("/getSunQRCode")
    @ApiOperation(value = "生成太阳码-获取小程序不限制的QR码", notes = "生成太阳码-获取小程序不限制的QR码")
    public Result<SunQRCodeVo> getUnlimitedQRCode(@RequestBody UnlimitedQRCodeDTO unlimitedQRCodeDTO, HttpServletResponse response) throws IOException {
        return newUserService.getUnlimitedQRCode(unlimitedQRCodeDTO);
    }

大致解释j就是一个post请求,然后这个请求返回的是一个封装后的实体的Result,然后内部的实体是一个字符串(之所以是字符串,是因为最后图片以base64编码的格式返回给前端的,不然就得以流的形式返回

然后就是具体的实现层的操作,大致操作如下:

通过微信的接口请求太阳码 ----》将拿到的太阳码转换为对应的图片格式(微信那边默认返回的是jpeg格式,因为前端的要求,需要转换为png的格式,然后再转换为对应的base64的字符串,然后再返回给前端) ----》转换为base64的格式,封装实体返回给前端。

解决办法

最后的一个实现层的代码版本(这个代码有个优势:就是可以根据微信接口的返回内容,如果请求正确,微信的这个接口它会直接返回buffer的图片,但如果请求有问题,它的返回内容又是一个json,所以这种情况可以根据返回的内容去判断,然后再具体去考虑如何接收

import org.springframework.web.client.RestTemplate;

@Service("NewUserService")
public class NewUserServiceImpl extends BaseServiceImpl<NewUserDao, NewUserDO, BaseDTO> implements NewUserService {

private static RestTemplate restTemplate;

    public static RestTemplate getRestTemplate() {
        if (null == restTemplate) {
            synchronized (RestTemplate.class) {
                if (null == restTemplate) {
                    restTemplate = new RestTemplate();
                }
            }
        }
        return restTemplate;
    }


/**
     * 获取微信小程序的小程序码
     */
    @Override
    public Result<SunQRCodeVo> getUnlimitedQRCode(UnlimitedQRCodeDTO unlimitedQRCodeDTO) throws IOException {
        Result<SunQRCodeVo> result = new Result<>();
        //先根据配置的appid等信息获取到token
        String accessToken = this.getAccessToken().getAccess_token();

        String url = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + accessToken;

//        byte[] qrCodeVo = getRestTemplate().postForObject(url, paramMap, byte[].class,
//                ContentType.APPLICATION_JSON);
        CloseableHttpClient client = HttpClients.createDefault();
        HttpPost request = new HttpPost(url);
        request.setHeader("Content-Type", "application/json");

        // 将json参数作为请求体发送
        JSONObject jsonParam = new JSONObject();
        jsonParam.put("scene",unlimitedQRCodeDTO.getScene());
        jsonParam.put("env_version",unlimitedQRCodeDTO.getEnv_version());
        jsonParam.put("page",unlimitedQRCodeDTO.getPage());
        jsonParam.put("width",unlimitedQRCodeDTO.getWidth()==null?"280":unlimitedQRCodeDTO.getWidth());

        StringEntity entity = new StringEntity(jsonParam.toString(), ContentType.APPLICATION_JSON);
        request.setEntity(entity);

        CloseableHttpResponse response = client.execute(request);

        // 获取响应头中的Content-Type字段
        Header contentTypeHeader = response.getFirstHeader("Content-Type");
        if (contentTypeHeader != null && contentTypeHeader.getValue().contains("image/jpeg")) {

            // 如果返回值是jpeg类型,以输入流的形式读取
            InputStream is = response.getEntity().getContent();

            //字节数组的输出流,用户辅助图片在流之间的格式转换
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

            //将请求获取到的输入流 使用ImageIO转换为bufferedImage后以png的格式写入输出流,然后将输出流转换为字节数组,后面将字节数组转换为base64编码的字符串
            BufferedImage image = ImageIO.read(is);
            ImageIO.write(image, "png", outputStream);
            byte[] pngBytes = outputStream.toByteArray();
            outputStream.close();


            /* 该段注释代码 作用是
            byte[] buffer = new byte[1024];
            int length;
            while ((length = is.read(buffer)) != -1) {
                outputStream.write(buffer, 0, length);
            }
            byte[] data = outputStream.toByteArray();
            */
            //关闭创建的输入流inputStream
            is.close();
            SunQRCodeVo sunQRCodeVo = new SunQRCodeVo();
//            sunQRCodeVo.setData(data);
            // 二进制数据字节数组 转base64编码的字符串
            sunQRCodeVo.setBase64buffer(Base64.getEncoder().encodeToString(pngBytes));
            sunQRCodeVo.setErrcode(0);
            result.setResult(sunQRCodeVo);
            return result;
        } else {
            // 如果返回值是json类型,则解析json数据
            BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
            String line;
            StringBuilder sb = new StringBuilder();
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
            reader.close();
            String json = sb.toString();
            JSONObject obj = new JSONObject(json);
            SunQRCodeVo sunQRCodeVo = new SunQRCodeVo();
            sunQRCodeVo.setErrcode(obj.getInt("errcode"));
            sunQRCodeVo.setErrmsg(obj.getString("errmsg"));
            return result.error500(obj.getString("errmsg"));
        }
    }
    //访问微信的服务器找到指定的小程序,获取登录
    public AccessTokenVo getAccessToken() {
        String url =
                "https://api.weixin.qq.com/cgi-bin/token?grant_type=" + GRANT_TYPE + "&appid=" + APPID + "&secret=" + SECRET;
        return getRestTemplate().getForObject(url, AccessTokenVo.class);
    }

}

原本只贴了一个实现的方法,后面发现可能那个RestTemplate可能看不懂,就又给这个方法的import的包和在该实现层的具体实现给附加上了,上面代码中还有几个实体结构也在下面:

用于获取AccessTokenVo 的实体类:

@Data
public class AccessTokenVo {

    private String access_token;

    private Integer expires_in;

    /**
     * @description:
     * -1.系统繁忙,此时请开发者稍候再试
     * 0.请求成功
     * 40001.AppSecret 错误或者 AppSecret 不属于这个小程序,请开发者确认 AppSecret 的正确性
     * 40002.请确保 grant_type 字段值为 client_credential
     * 40013.不合法的 AppID,请开发者检查 AppID 的正确性,避免异常字符,注意大小写
     * @param: @param null
     * @return:
     * @author: liuanmin
     * @date: 2022/4/29
     */
    private Integer errcode;

    private String errmsg;
}

用于封装返回请求的SunQRCode实体:

@Data
public class SunQRCodeVo {
    /**
     * 二进制流
     */
    private byte[] data;

    /**
     * 图片二进制流转base64编码的字符串
     */
    private String base64buffer;

    /**
     * 小程序返回的错误码
     */
    private Integer errcode;

    /**
     * 小程序返回的错误信息
     */
    private String errmsg;
}

遇到的一点问题

上面有一小段我注释里的代码,是之前遇到的一点问题,但是经过排查后发现的问题所在如下:

拿到请求的内容后我使用new一个字节数组的大小刚好与返回获取的流一样的大小去读取这个InputStream,结果读出来只有一部分,没有读取完,如下
在对这部分进行验证时:
在这里插入图片描述
inputstream的大小:
在这里插入图片描述
通过available方法获取到的大小只有8010,当前是win11系统
在这里插入图片描述
关于这个获取到的大小的问题,问了一下"万能"的chatgpt
在这里插入图片描述

顺便说一下,这段时间以来使用chatgpt的一个感受:
能用,确实也挺智能,在数据库的管理和代码的提示上能提供不小的帮助,但也有一些小毛病,比如说 突然崩了,有时候对话它逻辑跟不上,有时候反应慢,有时候不能根据前面指定内容进行继续回答,还有就是回答内容过长时会断,让它继续输出时,中间会缺失部分内容;还有部分问题太细太专业,它也回答不了。
你描述得越准确,它的回答就越符合你的期望,将你的背景,使用情况描述得越清楚,就越贴近你想要的结果。

结束语

若是对你有所帮助的话,希望能获得你的 点赞、评论、收藏,这将是对我很大的鼓励!!! 这对我真的很重要!!!
蟹蟹٩(‘ω’)و

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿,葱来了-C is coming

老板大气

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值