微信公众平台获取openid在公众号的开发中有很多用途,前段时间为实现用户使用公众号在登录一次以后可以免密登陆而使用了openid。开发过程中遇到了一些问题,在这里向需要且还没有获取到openid的米娜桑分享一下简单的流程及部分代码,和一些问题的解决方式,给初次接触微信openid的朋友们一个参考。目的只在于获取openid,至于优化及应用上诸君请自由发挥。

首先了解openid是什么,一个微信号与一个公众号对应一个固定不变的openid。所以一个微信号在一个公众号下的openid是不变的,如果换了一个对应的公众号,那就是另一个openid了。且只有在微信自带浏览器中打开的项目才可获取到。
准备:

首先你要有一个公众号,还有一个外网可访问的域名,我的公众号类型是企业号,这里就以企业号为例了。获取openid需要的公众号的 appid 和 secret(登陆公众平台 开发----->基本配置中的开发者ID(AppID)和 开发者密码(AppSecret)就是)。其次是设置网页授权域名(登陆公众平台 设置----->公众号设置------>功能设置----->网页授权域名 按步骤操作并设置就好),这个域名就是你获取openid的web项目发布的域名,这里注意服务器请一定跑在80端口。

流程:

1.调用https://open.weixin.qq.com/connect/oauth2/authorize接口获取到code

2.得到code作为一个参数调用https://api.weixin.qq.com/sns/oauth2/access_token接口获取到openid

因为只是简单的获取到openid,这里只放两个servlet与用到的工具类代码:

第一个是获取code用的WxCodeServlt

public class WxCodeServlet extends HttpServlet {

    	public void doGet(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {

    		doPost(request, response);
    	}

    	public void doPost(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {

    		response.setContentType("text/html");
    		response.setCharacterEncoding("UTF-8");
    		request.setCharacterEncoding("UTF-8");
                    //这里要将你的授权回调地址处理一下,否则微信识别不了
     String redirect_uri=URLEncoder.encode("/*你的授权回调地址*/", "UTF-8");
                    //简单获取openid的话参数response_type与scope与state参数固定写死即可
    		StringBuffer url=new StringBuffer("https://open.weixin.qq.com/connect/oauth2/authorize?redirect_uri="+redirect_uri+
    				"&appid="+/*你的appid*/+"&response_type=code&scope=snsapi_base&state=1#wechat_redirect");
    		response.sendRedirect(url.toString());//这里请不要使用get请求单纯的将页面跳转到该url即可


    }

当用户用微信进入我们的网页并调用到WxCodeServlet之后,若参数无误,设置的网页授权域名正确,微信就会重定向页面到我们提交的回调地址,同时我们想要的code也会被传过来

而这个回调地址就是我们的第二个servlet WxOpenIdServlet

public class WxOpenIdServlet extends HttpServlet {

    	private static final long serialVersionUID = 1L;

    	public void doGet(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {

    		response.setContentType("text/html");

    		request.setCharacterEncoding("UTF-8");
    		response.setCharacterEncoding("UTF-8");
    		String code = request.getParameter("code");//获取code
    		Map params = new HashMap();
    		params.put("secret", "/*你的secret*/");
    		params.put("appid", "/*你的appid*/");
    		params.put("grant_type", "authorization_code");
    		params.put("code", code);
    		String result = HttpGetUtil.httpRequestToString(
    				"https://api.weixin.qq.com/sns/oauth2/access_token", params);
    		JSONObject jsonObject = JSONObject.fromObject(result);

    		String openid = jsonObject.get("openid").toString();
    		System.out.println("得到的openid为:"+openid);
    	}


    	public void doPost(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    		doGet(request, response);
    	}
    }

在这里我要补充一下了,一位朋友获取到code后去请求却被微信反悔了一个错误码"errcode":40125,对应的错误是appsecret无效,可是填写的appsecret与公众平台中的appsecret一致。这个问题在开发时我也遇到过,解决方式是重置appsecret,当初也没在意,现在看来这个问题挺频繁的,所以在这里再补充一下。

其中用到了一个工具类HttpGetUtil JSON需要的包这里就不说了

public class HttpGetUtil {

    	public static String httpRequestToString(String url, 
    			Map<String,String> params) {
    		String result = null;
    		try {
    			InputStream is = httpRequestToStream(url,  params);
    			BufferedReader in = new BufferedReader(new InputStreamReader(is,
    					"UTF-8"));
    			StringBuffer buffer = new StringBuffer();
    			String line = "";
    			while ((line = in.readLine()) != null) {
    				buffer.append(line);
    			}
    			result = buffer.toString();
    		} catch (Exception e) {
    			return null;
    		}
    		return result;
    	}

    	private static InputStream httpRequestToStream(String url,
    			Map<String, String> params) {
    		 InputStream is = null;
    	        try {
    	            String parameters = "";
    	            boolean hasParams = false;
    	            for(String key : params.keySet()){
    	                String value = URLEncoder.encode(params.get(key), "UTF-8");
    	                parameters += key +"="+ value +"&";
    	                hasParams = true;
    	            }
    	            if(hasParams){
    	                parameters = parameters.substring(0, parameters.length()-1);
    	            }


    	                url += "?"+ parameters;

    	            URL u = new URL(url);
    	            HttpURLConnection conn = (HttpURLConnection) u.openConnection();
    				conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
    				conn.setRequestProperty("Accept-Charset", "UTF-8");
    				conn.setRequestProperty("contentType", "utf-8");
    	            conn.setConnectTimeout(50000);  
    	            conn.setReadTimeout(50000);
    	            conn.setDoInput(true);
    	            //设置请求方式,默认为GET
    	            conn.setRequestMethod("GET");


    	            is = conn.getInputStream();
    	        } catch (UnsupportedEncodingException e) {
    	            e.printStackTrace();
    	        } catch (MalformedURLException e) {
    	            e.printStackTrace();
    	        } catch (IOException e) {
    	            e.printStackTrace();
    	        }
    	        return is;
    	}

    }

至此如果各个步骤都没有出错的话,当我们的WxCodeServlet被调用后,控制台就能打印出来刚才通过微信打开我们网页并调用到WxCodeServlet的微信用户对应我们公众平台的openid了

注意问题:

1.网页授权域名设置如果与提交的回调地址的域名不对应,微信是无法回调到的。

2.单纯的获取openid使用的授权方式是静态授权,不需要经过用户许可的(用户看不到授权的过程),而想要获取用户的头像昵称等信息是另一种授权(用户端会弹出授权窗口),在此就不介绍了。

3.提交的回调地址格式为 http://xxxx.xxxx.com/xxxxx/WxOpenIdServlet,使用java.net 包里的URLEncoder.encode("url","utf-8")处理后提交

4.如遇到问题,请耐心细心的回头按步骤检查资料信息以及代码。