建议:一定要先看官方文档
https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842
注意事项和说明官方文档都有说明,我就不说了
两种方案:第一种原生代码,我这里说第二种sdk实现,github上面有很多优秀的sdk,这里只说其一
github sdk地址: https://github.com/Wechat-Group/weixin-java-tools/wiki
这是之前的版本,后面改名为 WXJava 了,对于新版的sdk,下面的代码有些已经不适用了,可更具新版sdk自行更改代码
本人拥有丰富的微信公众号开发和小程序开发以及支付开发经验,最近有点时间就打算写写博客
我使用的环境是springboot,ieda
使用方法:
1)第一步:
导包一一>maven或者gradle
maven:
com.github.binarywang
weixin-java-mp
3.1.0
gradle:
compile 'com.github.binarywang:weixin-java-mp:3.1.0'
2)第二部: 配置sdk的config
配置文件
yml中
official:
appId: wx1c0abaaa92fbeef9
appSecret: 5bf7cb8732af714d8540bbc5641f2df4
# host必须加http或https
host: http://like.s1.natapp.cc
属性config:
package com.xiaoyu.tool.configs.property;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;@ConfigurationProperties(prefix = "official")
@Data
public class OfficialProperty {
private String appId;
private String appSecret;
private String host;
}
configuration: 重写sdk方法,使用redis管理access_token,防止两小时内每调用一次sdk方法就刷新一次access_token,此方法在分布式中尤为重要且解决了微信接口调用次数的限制
package com.xiaoyu.tool.configs;
import com.xiaoyu.tool.configs.property.OfficialProperty;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;@Slf4j
@Configuration
@EnableConfigurationProperties(OfficialProperty.class)
public class WeixinMpConfiguration {
private final RedisTemplateredisTemplate;
@Autowired
private OfficialProperty officialProperty;public WeixinMpConfiguration(RedisTemplate
redisTemplate) {
this.redisTemplate = redisTemplate;
}
@Bean
public WxMpService wxMpService(){
WxMpSpringRedisConfigStorage configStorage = new WxMpSpringRedisConfigStorage(redisTemplate);
configStorage.setAppId(officialProperty.getAppId());
configStorage.setSecret(officialProperty.getAppSecret());
WxMpService wxMpService = new WxMpServiceImpl();
wxMpService.setWxMpConfigStorage(configStorage);
return wxMpService;
}
}
configStorage:重写sdk底层storage
package com.xiaoyu.tool.configs;
import me.chanjar.weixin.mp.api.WxMpInMemoryConfigStorage;
import org.springframework.data.redis.core.RedisTemplate;
import java.util.concurrent.TimeUnit;
public class WxMpSpringRedisConfigStorage extends WxMpInMemoryConfigStorage {
private final static String ACCESS_TOKEN_KEY = "wechat_access_token_";
private final static String JSAPI_TICKET_KEY = "wechat_jsapi_ticket_";
private final static String CARDAPI_TICKET_KEY = "wechat_cardapi_ticket_";
private final RedisTemplate redisTemplate;
private String accessTokenKey;
private String jsapiTicketKey;
private String cardapiTicketKey;
public WxMpSpringRedisConfigStorage(RedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}
@Override
public void setAppId(String appId) {
super.setAppId(appId);
// 定义redis中存储的名称
this.accessTokenKey = ACCESS_TOKEN_KEY.concat(appId);
this.jsapiTicketKey = JSAPI_TICKET_KEY.concat(appId);
this.cardapiTicketKey = CARDAPI_TICKET_KEY.concat(appId);
}
@Override
public String getAccessToken() {
return redisTemplate.opsForValue().get(this.accessTokenKey);
}
@Override
public boolean isAccessTokenExpired() {
return redisTemplate.getExpire(this.accessTokenKey) < 2;
}
@Override
public synchronized void updateAccessToken(String accessToken, int expiresInSeconds) {
redisTemplate.opsForValue().set(this.accessTokenKey,accessToken,expiresInSeconds - 200, TimeUnit.SECONDS);
}
@Override
public void expireAccessToken() {
redisTemplate.expire(this.accessTokenKey, 0, TimeUnit.SECONDS);
}
@Override
public String getJsapiTicket() {
return redisTemplate.opsForValue().get(this.jsapiTicketKey);
}
@Override
public boolean isJsapiTicketExpired() {
return redisTemplate.getExpire(this.jsapiTicketKey) < 2;
}
@Override
public synchronized void updateJsapiTicket(String jsapiTicket, int expiresInSeconds) {
redisTemplate.opsForValue().set(this.jsapiTicketKey, jsapiTicket, expiresInSeconds - 200, TimeUnit.SECONDS);
}
@Override
public void expireJsapiTicket() {
redisTemplate.expire(this.jsapiTicketKey, 0, TimeUnit.SECONDS);
}
@Override
public String getCardApiTicket() {
return redisTemplate.opsForValue().get(this.cardapiTicketKey);
}
@Override
public boolean isCardApiTicketExpired() {
return redisTemplate.getExpire(this.cardapiTicketKey) < 2;
}
@Override
public synchronized void updateCardApiTicket(String cardApiTicket, int expiresInSeconds) {
redisTemplate.opsForValue().set(this.cardapiTicketKey, cardApiTicket, expiresInSeconds - 200, TimeUnit.SECONDS);
}
@Override
public void expireCardApiTicket() {
redisTemplate.expire(this.cardapiTicketKey, 0, TimeUnit.SECONDS);
}
}
redis配置:
package com.xiaoyu.tool.configs;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@ComponentScan
@Configuration
public class RedisConfiguration {
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
3)第三步:具体实现 controller代码
package com.xiaoyu.tool.controller.user;
import com.xiaoyu.tool.configs.property.OfficialProperty;
import com.xiaoyu.tool.entity.User.User;
import com.xiaoyu.tool.service.user.UserWebAuthorizedService;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.net.URLEncoder;
/**
* @Author:xiaoyu
* @Created on 2018/9/17
* @Description 公众号网页授权登录
*/
@Controller
@RequestMapping(value = "/webAuthorized")
@Slf4j
public class UserWebAuthorizedController {
private final OfficialProperty officialProperty;
private final WxMpService wxMpService;
private final UserWebAuthorizedService userWebAuthorizedService;
public UserWebAuthorizedController(OfficialProperty officialProperty, WxMpService wxMpService, UserWebAuthorizedService userWebAuthorizedService) {
this.officialProperty = officialProperty;
this.wxMpService = wxMpService;
this.userWebAuthorizedService = userWebAuthorizedService;
}
/**
*sdk 简单便捷
*/
@ApiOperation("微信网页授权")
@GetMapping("/authorize")
public String welcome(){
//授权成功后跳转同域名下的网页
String returnUrl = officialProperty.getHost() + "/index";
//重定向的回调链接地址
String url = officialProperty.getHost() + "/wechat_alipay_tool/webAuthorized/oauth2";
String redirectUrl = wxMpService.oauth2buildAuthorizationUrl(url, WxConsts.OAuth2Scope.SNSAPI_USERINFO, URLEncoder.encode(returnUrl));
return "redirect:" + redirectUrl;
}
@ApiOperation("授权获取用户信息")
@GetMapping("/oauth2")
public String oauth2(@RequestParam(name = "code") String code,
@RequestParam("state") String returnUrl) {
try {
WxMpOAuth2AccessToken accessToken = wxMpService.oauth2getAccessToken(code);
WxMpUser wxMpUser = wxMpService.oauth2getUserInfo(accessToken, "zh_CN");
User user = userWebAuthorizedService.createAndUpdateUser(wxMpUser);
log.info("用户信息:{}",user);
} catch (WxErrorException e) {
log.error("通过code获取accessToken失败/获取用户信息失败:{}",e.getMessage());
}
return "redirect:" + returnUrl;
}
}
测试环境: 申请微信测试号,配置natapp域名穿透
微信测试号登录:
https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login&token=1361182780&lang=zh_CN
配置:
这几个不要配置错了,根据自己的域名配置
natapp:
https://natapp.cn/