Java开发PC微信扫码登录

请注意,本文编写于 98 天前,最后修改于 65 天前,其中某些信息可能已经过时。

前期准备工作

需要现在微信开发平台注册 https://open.weixin.qq.com/ 并认证一个网站应用
获取到应用的AppID和AppSercret的值,然后需要绑定授权回调域名

授权回调域名开发阶段建议绑定nat映射工具的公网域名,推荐natapp,我是mac 使用的是uTools工具中的nat插件,方便简单,如果是mac用户同样推荐使用,下载完成后可在插件中心安装nat插件然后自定义一个域名到微信开发平台中绑定(绑定注意是域名,不是url不需要前面的协议头)
uTools下载地址:https://www.u.tools/

image-20200103112209892
image-20200103112209892

参数配置

在properties中配置好参数,需要变动的参数放在properties中,然后封装一个微信配置类,便于我们获取值方便开发,以下参数均不可用,请填写自己的应用参数

#微信开放平台配置
wxopen.appid=wke9ef87jke786b62a
wxopen.appsecret=837462892936462920817ab4
#微信通知回调地址
wxopen.redirect_url=https://laomao.utools.club/api/v1/wechat/user/callback

封装微信配置类

把微信相关的参数封装为一个微信配置类,方便开发以及统一管理,配置类中除了properties中的微信行管参数,还在配置类中增加三个值,微信二维码获取地址,access_token获取地址,以及用户信息获取地址,参数值均用%s替换,调用的时候使用String.format进行格式化

@Data
@Configuration
@PropertySource(value = "classpath:application.properties")
public class WeChatConfig {

    /**
     * 开放平台appid
     */
    @Value("${wxopen.appid}")
    private String openAppid;

    /**
     * 开放平台appsecret
     */
    @Value("${wxopen.appsecret}")
    private String openAppsecret;
    
    /**
     * 开放平台回调url
     */
    @Value("${wxopen.redirect_url}")
    private String openRedirectUrl;
    
    /**
     * 微信开放平台二维码连接
     */
    private final static String OPEN_QRCODE_URL = "https://open.weixin.qq.com/connect/qrconnect?appid=%s&redirect_uri=%s&response_type=code&scope=snsapi_login&state=%s#wechat_redirect";
    public String getOpenQrcodeUrl() {
        return OPEN_QRCODE_URL;
    }

    /**
     * 开放平台获取access_token地址
     */
    private final static String OPEN_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code";
    public String getOpenAccessTokenUrl() {
        return OPEN_ACCESS_TOKEN_URL;
    }

    /**
     * 开放平台获取用户信息地址
     */
    private final static String OPEN_USER_INFO_URL = "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=zh-CN";
    public String getOpenUserInfoUrl() {
        return OPEN_USER_INFO_URL;
    }

}

工具类封装

JsonData对数据返回格式进行规范,JwtUtilsJwt生成加密Token ,HttpClientHttp网络请求封装

UserService开发

这里就不贴UserMapper方法了,每个人的业务都不相同,大家自己写就行了

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private WeChatConfig weChatConfig;
    @Autowired
    private UserMapper userMapper;

    /**
     * 保存用户
     *
     * @param code
     * @return
     */
    @Override
    public User saveWeChatUser(String code) {
        String accessTokenUrl = String.format(weChatConfig.getOpenAccessTokenUrl(), weChatConfig.getOpenAppid(), weChatConfig.getOpenAppsecret(), code);
        //获取accesstoken
        Map<String, Object> map = HttpUtils.doGet(accessTokenUrl);
        if (map == null || map.isEmpty()) {
            return null;
        }
        String access_token = (String) map.get("access_token");
        String openid = (String) map.get("openid");

        //如果获取到了openid 那么去数据库查找该用户 如果存在则直接返回该用户,不存在则继续往下执行获取用户信息
        User dbUser = userMapper.findByOpenId(openid);
        if (dbUser != null) {
            return dbUser;
        }

        //获取用户基本信息
        String userInfoUrl = String.format(weChatConfig.getOpenUserInfoUrl(), access_token, openid);
        Map<String, Object> userMap = HttpUtils.doGet(userInfoUrl);
        if (userMap == null || userMap.isEmpty()) {
            return null;
        }

        String nickName = (String) userMap.get("nickname");
        //微信返回是个double类型转成int
        Double sexTemp = (Double) userMap.get("sex");
        int sex = sexTemp.intValue();
        String province = (String) userMap.get("province");
        String city = (String) userMap.get("city");
        String country = (String) userMap.get("country");
        String headimgurl = (String) userMap.get("headimgurl");

        try {
            //解决乱码问题
            nickName = new String(nickName.getBytes("ISO-8859-1"), "UTF-8");
            province = new String(province.getBytes("ISO-8859-1"), "UTF-8");
            city = new String(city.getBytes("ISO-8859-1"), "UTF-8");
            country = new String(country.getBytes("ISO-8859-1"), "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        //封装用户对象
        User user = new User();
        user.setName(nickName);
        user.setHeadImg(headimgurl);
        user.setCity(city);
        user.setOpenid(openid);
        user.setSex(sex);
        user.setCreateTime(new Date());
        userMapper.save(user);

        return user;
    }
}

微信WechatController开发

/**
 * @Description TODO
 * @Author laomao
 **/
@Controller
@RequestMapping("/api/v1/wechat")
public class WechatController {
      @Autowired
    private WeChatConfig weChatConfig;
    @Autowired
    private UserService userService;
    
    /**
     * 拼装微信扫一扫登录url
     *
     * @return
     */
    @GetMapping("login_url")
    @ResponseBody
    public JsonData loginUrl(@RequestParam(value = "access_page", required = true) String access_page) throws UnsupportedEncodingException {

        String redirectUrl = weChatConfig.getOpenRedirectUrl();//获取开放平台重定向地址
        String callbackkUrl = URLEncoder.encode(redirectUrl, "GBK");//对回调地址进行url进行编码
        //对微信扫码地址进行参数替换合成最后的扫码地址
        String qrcodeUrl = String.format(
                weChatConfig.getOpenQrcodeUrl(),
                weChatConfig.getOpenAppid(),
                callbackkUrl,
                access_page);
        return JsonData.buildSuccess(qrcodeUrl);
    }
    
    
        /**
     * 微信开发平台回调接口
     *
     * @param code
     * @param state
     * @param response
     */
    @GetMapping("/user/callback")
    public void wechatUserCallback(@RequestParam(value = "code", required = true) String code,
                                   String state,
                                   HttpServletResponse response) throws IOException {
        User user = userService.saveWeChatUser(code);
        if (user != null) {
            String token = JwtUtils.geneJsonWebToken(user);
            response.sendRedirect(state + "?token=" + token);
        }
    }
    
    
}

总结

微信登录还是非常简单的,主要的内容就是一个回调接口,事先封装好工具类,接下来基本上就是水到渠成

添加新评论

评论列表