实现微信公众号扫描登录||Retrofit2 对接微信接口

https://developers.weixin.qq.com/doc/offiaccount/Account_Management/Generating_a_Parametric_QR_Code.html
1/通过ticket换取二维码
请求:https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=TICKET TICKET记得进行UrlEncode
返回:http 返回码是200,是一张图片,可以直接展示或者下载。
2/获取ticket
请求: POST URL: https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=TOKEN
参数:
{"expire_seconds": 604800, "action_name": "QR_STR_SCENE", "action_info": {"scene": {"scene_str": "test"}}}
返回:
{"ticket":"gQH47joAAAAAAAAAASxodHRwOi8vd2VpeGluLnFxLmNvbS9xL2taZ2Z3TVRtNzJXV1Brb3ZhYmJJAAIEZ23sUwMEmm
3sUw==","expire_seconds":60,"url":"http://weixin.qq.com/q/kZgfwMTm72WWPkovabbI"}
3/获取access_token
https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_access_token.html
公众号和小程序均可以使用AppID和AppSecret调用本接口来获取access_token。AppID和AppSecret可在“微信公众平台-设置与开发--基本配置
https://mp.weixin.qq.com/debug/cgi-bin/sandboxinfo?action=showinfo&t=sandbox/index
请求:https请求方式: GET https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
返回:{"access_token":"ACCESS_TOKEN","expires_in":7200}
流程图:

Retrofit2 对接微信获取 access_token 的接口为例

1.添加依赖
<dependency>
   <groupId>com.squareup.retrofit2</groupId>
   <artifactId>retrofit</artifactId>
   <version>2.9.0</version>
</dependency>
<dependency>
   <groupId>com.squareup.retrofit2</groupId>
   <artifactId>converter-jackson</artifactId>
   <version>2.9.0</version>
</dependency>
2.定义数据模型:创建一个 Java 类来映射返回的 JSON 数据。
@Data
public class WexinTokenRes {
   private String access_token;
   private int expires_in;
   private String errcode;
   private String errmsg;
}
3.定义 API 接口:使用 Retrofit2 定义一个接口来描述请求。
//使用 API 服务:在其他 Spring 组件(如 Service 类)中,直接注入 IWeixinApiService 并调用接口方法,无需手动处理 HTTP 请求。
public interface IWeixinApiService {
 
   @GET("cgi-bin/token")
   Call<WexinTokenRes> getAccessToken(//获取access_token 
           @Query("grant_type") String grantType,
           @Query("appid") String appid,
           @Query("secret") String secret
   );

   @POST("cgi-bin/qrcode/create")//获取ticket凭证
   Call<WeixinQrCodeRes> createQrCode(
           @Query("access_token") String accessToken,
           @Body WeixinQrCodeReq weixinQrCodeReq
   );

   @POST("cgi-bin/message/template/send")//发送模板消息
   Call<Void> sendMessage(@Query("access_token") String accessToken, @Body WeixinTemplateMessageVO weixinTemplateMessageVO);

}
4.接口实现
@Slf4j
@Configuration
public class Retrofit2Config {
   private static final String BASE_URL = "https://api.weixin.qq.com/";

   //配置 Retrofit 客户端:retrofit() 方法创建并配置 Retrofit,设置基础 URL 和 JSON 转换器。
   @Bean
   public Retrofit retrofit(){
       return new Retrofit.Builder()
               .baseUrl(BASE_URL)
               .addConverterFactory(JacksonConverterFactory.create())
               .build();
   }
   //生成 API 接口实现:weixinApiService() 方法利用 Retrofit 实例生成 IWeixinApiService 的代理对象。
   @Bean
   public IWeixinApiService weixinApiService(Retrofit retrofit){
       return retrofit.create(IWeixinApiService.class);
   }
}

5.使用示例:在其他类中调用getAccessToken方法获取微信 access_token。
@Service
public class WeixinLoginServiceImpl implements ILoginService {

   @Value("${weixin.config.app-id}")
   private String appid;
   @Value("${weixin.config.app-secret}")
   private String appSecret;
   @Value("${weixin.config.template_id}")
   private String template_id;


   @Resource
   private IWeixinApiService weixinApiService;
   @Resource
   private Cache<String, String>  weixinAccessToken;
   @Resource
   private Cache<String, String> openidToken;

   @Override
   public String createQrCodeTicket() throws Exception {
       //1.获取accessToken
       String accessToken = weixinAccessToken.getIfPresent(appid);
       if(accessToken == null){
           Call<WeixinTokenRes> call =  weixinApiService.getAccessToken("client_credential",appid,appSecret);
           WeixinTokenRes weixinTokenRes = call.execute().body();
           assert weixinTokenRes != null;
           accessToken  = weixinTokenRes.getAccess_token();
           weixinAccessToken.put(appid,accessToken);
       }

       //2.生成ticket
       WeixinQrCodeReq weixinQrCodeReq = WeixinQrCodeReq.builder()
               .expire_seconds(2592000)
               .action_name(WeixinQrCodeReq.ActionNameTypeVO.QR_SCENE.getCode())
               .action_info(WeixinQrCodeReq.ActionInfo.builder()
                       .scene(WeixinQrCodeReq.ActionInfo.Scene.builder()
                               .scene_id(100601)
                               .build())
                       .build())
               .build();
       Call<WeixinQrCodeRes> call =  weixinApiService.createQrCode(accessToken,weixinQrCodeReq);
       WeixinQrCodeRes weixinQrCodeRes = call.execute().body();
       assert null != weixinQrCodeRes;
       return weixinQrCodeRes.getTicket();
   }

@Override
   public String checkLogin(String ticket) {
       return openidToken.getIfPresent(ticket);
   }

   @Override
   public void saveLoginState(String ticket, String openid) throws IOException {
       openidToken.put(ticket, openid);
       // 1. 获取 accessToken
       String accessToken = weixinAccessToken.getIfPresent(appid);//发送模板消息
       if (null == accessToken) {
           Call<WeixinTokenRes> call = weixinApiService.getAccessToken("client_credential", appid, appSecret);
           WeixinTokenRes weixinTokenRes = call.execute().body();
           assert weixinTokenRes != null;
           accessToken = weixinTokenRes.getAccess_token();
           weixinAccessToken.put(appid, accessToken);
       }
       //2.发送模板消息
       Map<String, Map<String, String>> data = new HashMap<>();
       WeixinTemplateMessageVO.put(data, WeixinTemplateMessageVO.TemplateKey.USER, openid);

       WeixinTemplateMessageVO templateMessageDTO = new WeixinTemplateMessageVO(openid, template_id);
       templateMessageDTO.setTouser(openid);
       templateMessageDTO.setUrl("");
       templateMessageDTO.setData(data);
       Call<Void> call = weixinApiService.sendMessage(accessToken, templateMessageDTO);
       call.execute();
   }
}
posted @ 2025-05-11 10:05  必行之码  阅读(31)  评论(0)    收藏  举报