1.概述

         企业微信集成方案,通过请求微信API的方式,获得当前微信访问用户的ID,然后通过用户ID实现对微信报表的权限管控。

2.  前期准备

        a) 准备企业微信,需要给开发人员管理员权限,官网:https://work.weixin.qq.com/

        b) 创建企业应用小程序,如下图:


读取 企业微信组织架构secret 企业微信组织架构在哪_JavaWeb

      c) 准备好企业微信的企业ID(Corpid),点击我的企业即可查看,如下图:


读取 企业微信组织架构secret 企业微信组织架构在哪_微信集成_02

   d) 准备好应用的AgentId和Secret (CorpSecret),如下图:


读取 企业微信组织架构secret 企业微信组织架构在哪_读取 企业微信组织架构secret_03

  e) 企业微信API,官网:http://work.weixin.qq.com/api/doc#10012

 

3.开始开发

  a)  发送请求到微信API,获得微信验证 用户授权CODE

https://open.weixin.qq.com/connect/oauth2/authorize?appid={CORP_ID}&redirect_uri= {REDIRECT_URI}&response_type=code&scope=SCOPE&agentid={AGENT_ID}&state=STATE#wechat_redirect

    {CORP_ID} = 企业ID

   {REDIRECT_URI} = 请求成功之后,回调的URL。

 

  b)  发送请求到微信API,获得ACCESS_TOKEN(权限验证TOKEN

https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={CORP_ID}&corpsecret={CORPSECRET}
    {CORP_ID} = 企业ID
    {CORPSECRET} = 应用的Secret

  c) 发送请求到微信API,获得微信当前访问的USERID(用户名) 

     https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?access_token={ACCESS_TOKEN}&code={CODE}&agentid={AGENTID}

    {ACCESS_TOKEN} = 之前获得的ACCESS_TOKEN

    {CODE} = 之前获得的 用户授权的CODE

    {AGENTID} = 应用的AgentId

 

4. 代码剖析

   微信API调用类

package action;


import com.opensymphony.xwork2.ActionSupport;
import dto.WeChatUrlConstant;
import net.sf.json.JSONObject;
import org.apache.struts2.ServletActionContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import servlet.WeiXinTools;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.URLEncoder;

/**
 * 微信API调用类
 */
public class WeChatReportAction extends ActionSupport{
   // 输出日志打印
   public static Logger log = LoggerFactory.getLogger(WeChatReportAction.class);

   /**
    * 获得微信授权Code
    */
   public void getWeChatCode(){
      //获得Servlet 请求响应对象
      HttpServletRequest request = ServletActionContext.getRequest();
      HttpServletResponse response = ServletActionContext.getResponse();
      String getCodeUrl="";
      try {
         //拼接请求code链接的url
         getCodeUrl = WeChatUrlConstant.GET_CODE.replace("{CORP_ID}",WeChatUrlConstant.CORP_ID ).replace("{REDIRECT_URI}",URLEncoder.encode("https://wechat.aimatech.com:7777/aima/queryUserInfo.action","UTF-8"));
         //跳转 重定向到获取ceode请求
         response.sendRedirect(getCodeUrl);
      } catch (Exception e) {
         log.error("Default boot user authorization failed!---{}", e);
      }
   }

   /**
    * 获得微信当前访问的用户信息
    */
   public void queryUserInfo(){
      //获得Servlet 请求响应对象
      HttpServletRequest request = ServletActionContext.getRequest();
      HttpServletResponse response = ServletActionContext.getResponse();
      try {
         //通过刚刚重定向的URL  在请求对象中 拿到 用户授权code
         String code = request.getParameter("code");
         //获取ACCESS_TOKEN
         JSONObject accessToken_json = WeiXinTools.sendHttps(WeChatUrlConstant.GET_ACCESS_TOKEN.replace("{CORP_ID}",WeChatUrlConstant.CORP_ID).replace("{CORPSECRET}", WeChatUrlConstant.CORPSECRET), "GET", null);

         String accesstoken = accessToken_json.getString("access_token");
         //获取用户user_id接口
         String url = WeChatUrlConstant.GET_USER_ID.replace("{ACCESS_TOKEN}",accesstoken).replace("{CODE}", code).replace("{AGENTID}", WeChatUrlConstant.AGENT_ID);
         JSONObject josnObj = WeiXinTools.sendHttps(url, "GET", null);
         if(josnObj.containsKey("errmsg")){    //请求调用后,调用失败返回的编码
            log.error("code:==>"+code+"url==>"+url+"==== Failed to get UserId!");
         }
         String userId = (String)josnObj.get("UserId");  //获取用户id
         //日志打印 用户ID
         log.info("UserId:==>"+userId);
         //跳转的URL
         String redirectUrl ="https://wechat.aimatech.com:7777/aima/page/index.html?userId="+userId;
         //跳转  重定向URL
         response.sendRedirect(redirectUrl);
      } catch (Exception e) {
         log.error("Failed to get user information, specific error :"+e.getMessage());
      }
   }

}

  工具类

package servlet;

import net.sf.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.*;
import java.io.*;
import java.net.ConnectException;
import java.net.URL;
import java.net.URLConnection;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

/**
 * 工具类
 * 主要功能:<br>
 * 1、recv():将微信公众平台发来的reuquest请求转换成一个具体的接收消息类<br>
 * 2、send():消息的发送<br>
 * 3、builderSendByRecv():根据接收消息类构建一个发送消息类<br>
 * @author 魏友元
 *
 */
public final class WeiXinTools {
   private static Logger log = LoggerFactory.getLogger(WeiXinTools.class);
   private static double x_pi = 3.14499265358979324 * 3000.0 / 180.0;
   /**
    * 校验类
    * @param token
    * @param signature
    * @param timestamp
    * @param nonce
    * @return
    */
   public static boolean access(String token,String signature,String timestamp,String nonce) {
      List<String> ss = new ArrayList<String>();
      ss.add(timestamp);
      ss.add(nonce);
      ss.add(token);
      
      Collections.sort(ss);
      
      StringBuilder builder = new StringBuilder();
      for(String s : ss) {
         builder.append(s);
      }
      return signature.equalsIgnoreCase(HashKit.sha1(builder.toString()));
   }
   
   
   /**
    * 调用接口,在这里做数据处理
    * @param url 请求的接口路径
    * @param obj 需要发送的消息数据封装类
    * @param methodType 请求方式(POST、GET)
    * @return
    */
   public static String sendTemp(String url,Object obj,String methodType) {  
       String result = "";  
       // 将消息对象转换成json字符串  
       String dataJson = JSONObject.fromObject(obj).toString();
       // 调用对应的接口 
       JSONObject jsonObject = sendHttps(url, methodType, dataJson);
     
       if (null != jsonObject) {  
           if (null != jsonObject.getString("errcode")&&!jsonObject.getString("errcode").equals("")) {  
               result = jsonObject.getString("errcode");  
           }  
       }  
     
       return result;  
   } 
   
    /** 
     * 发起https请求并获取结果 
     *  
     * @param requestUrl 请求地址 
     * @param requestMethod 请求方式(GET、POST) 
     * @param outputStr 提交的数据 
     * @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值) 
     */  
    public static JSONObject sendHttps(String requestUrl, String requestMethod, String outputStr) {
        JSONObject jsonObject = null;
        StringBuffer buffer = new StringBuffer();  
        try {  
            // 创建SSLContext对象,并使用我们指定的信任管理器初始化  
            TrustManager[] tm = { new MyX509TrustManager() };  
            SSLContext sslContext = SSLContext.getInstance("TLS");  
            sslContext.init(new KeyManager[0], tm, new java.security.SecureRandom());  
            // 从上述SSLContext对象中得到SSLSocketFactory对象  
            SSLSocketFactory ssf = sslContext.getSocketFactory();  
            
            URL url = new URL(requestUrl);  
            HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();  
            httpUrlConn.setSSLSocketFactory(ssf);  
            httpUrlConn.setHostnameVerifier(new HostnameVerifier() {
            public boolean verify(String s, SSLSession sslsession) {
               return true;//全部通过
            }
         });
  
            httpUrlConn.setDoOutput(true);  
            httpUrlConn.setDoInput(true);  
            httpUrlConn.setUseCaches(false);  
            // 设置请求方式(GET/POST)  
            httpUrlConn.setRequestMethod(requestMethod);  
            httpUrlConn.setRequestProperty("Accept", "text/xml,text/javascript,text/html");
            httpUrlConn.setRequestProperty("User-Agent", "top-sdk-java");
            
            if ("GET".equalsIgnoreCase(requestMethod)){
               httpUrlConn.connect();
            }
  
            // 当有数据需要提交时  
            if (null != outputStr) {  
                OutputStream outputStream = httpUrlConn.getOutputStream();  
                // 注意编码格式,防止中文乱码  
                outputStream.write(outputStr.getBytes("UTF-8"));  
                outputStream.close();  
            }  
  
            // 将返回的输入流转换成字符串  
            InputStream inputStream = httpUrlConn.getInputStream();  
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "UTF-8");  
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);  
  
            String str = null;  
            while ((str = bufferedReader.readLine()) != null) {  
                buffer.append(str);  
            }  
            bufferedReader.close();  
            inputStreamReader.close();  
            // 释放资源  
            inputStream.close();  
            inputStream = null;  
            httpUrlConn.disconnect();
            if(buffer!=null&&!buffer.equals("")&&buffer.toString().indexOf("{")==0){
               jsonObject = JSONObject.fromObject(buffer.toString());
            }
        } catch (ConnectException ce) {  
            log.error("Weixin server connection timed out.");  
        } catch (Exception e) {  
            log.error("https request error:{}", e);  
        }  
        return jsonObject;  
    }
    
    /**
     * 向指定 URL 发送POST方法的请求
     * 
     * @param url
     *            发送请求的 URL
     * @param param
     *            请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
     * @return 所代表远程资源的响应结果
     */
    public static String sendPost(String url, String param) {
        BufferedReader in = null;
        OutputStreamWriter out =null;
        String result = "";
        try {
            URL realUrl = new URL(url);
            // 打开和URL之间的连接
            URLConnection conn = realUrl.openConnection();
            // 设置通用的请求属性
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("Accept-Language", "zh-CN,zh;q=0.8");
            conn.setRequestProperty("user-agent",
                    "Mozilla/5.0 (iPhone; CPU iPhone OS 7_1_2 like Mac OS X) AppleWebKit/537.51.2 (KHTML, like Gecko) Mobile/11D257 MicroMessenger/6.0.2 NetType/WIFI");
            // 发送POST请求必须设置如下两行
            conn.setDoOutput(true);
            conn.setDoInput(true);
            // 获取URLConnection对象对应的输出流
            out = new OutputStreamWriter(conn.getOutputStream(), "UTF-8");  
            // 发送请求参数
            out.write(param);
            // flush输出流的缓冲
            out.flush();
            // 定义BufferedReader输入流来读取URL的响应
            in = new BufferedReader(new InputStreamReader(conn.getInputStream(),"UTF-8"));
            String line;
            while ((line = in.readLine()) != null) {
                result += line;
            }
        } catch (Exception e) {
            System.out.println("发送 POST 请求出现异常!"+e);
            e.printStackTrace();
        }
        //使用finally块来关闭输出流、输入流
        finally{
            try{
                if(out!=null){
                    out.close();
                }
                if(in!=null){
                    in.close();
                }
            }
            catch(IOException ex){
                ex.printStackTrace();
            }
        }
        return result;
    }
    
    /**
     * 向指定URL发送GET方法的请求
     * 
     * @param url
     *            发送请求的URL
     * @param param
     *            请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
     * @return URL 所代表远程资源的响应结果
     */
    public static String sendGet(String url, String param) {
        String result = "";
        BufferedReader in = null;
        try {
           String urlNameString = url;
           if(param!=null && !param.equals("")){
              if(url.indexOf("?")!=-1){
                 urlNameString = urlNameString + "&" + param;
              }else{
                 urlNameString = urlNameString + "?" + param;
              }
           }
            URL realUrl = new URL(urlNameString);
            // 打开和URL之间的连接
            URLConnection connection = realUrl.openConnection();
            // 设置通用的请求属性
//            connection.setRequestProperty("accept", "*/*");
//            connection.setRequestProperty("connection", "Keep-Alive");
//            connection.setRequestProperty("user-agent",
//                    "Mozilla/5.0 (iPhone; CPU iPhone OS 7_1_2 like Mac OS X) AppleWebKit/537.51.2 (KHTML, like Gecko) Mobile/11D257 MicroMessenger/6.0.2 NetType/WIFI");
            // 建立实际的连接
            connection.connect();
            // 定义 BufferedReader输入流来读取URL的响应
            in = new BufferedReader(new InputStreamReader(connection.getInputStream(),"UTF-8"));
            String line;
            while ((line = in.readLine()) != null) {
                result += line;
            }
        } catch (Exception e) {
           log.error("发送GET请求出现异常!" + e);
        }
        //log.info("get请求获取的数据1:---->"+result);
        return result;
    }
    
   
    
   /**
     * 向指定URL发送GET方法的请求
     * 
     * @param url
     *            发送请求的URL
     * @param param
     *            请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
     * @return URL 所代表远程资源的响应结果
     */
    public static InputStream getImg(String url, String param) {
        InputStream in = null;
        try {
           String urlNameString = url;
           if(param!=null && !param.equals("")){
              if(url.indexOf("?")!=-1){
                 urlNameString = urlNameString + "&" + param;
              }else{
                 urlNameString = urlNameString + "?" + param;
              }
           }
            URL realUrl = new URL(urlNameString);
            // 打开和URL之间的连接
            URLConnection connection = realUrl.openConnection();
            // 设置通用的请求属性
            connection.setRequestProperty("accept", "*/*");
            connection.setRequestProperty("connection", "Keep-Alive");
            // 建立实际的连接
            connection.connect();
            in = connection.getInputStream();
        } catch (Exception e) {
            System.out.println("下载图片请求出现异常!" + e);
            e.printStackTrace();
        }
        return in;
    }
    /**
     * 文件存储
     * @param fileName 文件名 
     * @param inputStream 文件输入流 
     * @return
     */
    public static String uploadFile(String fileName,InputStream inputStream){
       byte[] data = new byte[1024];
      int len = 0;
       FileOutputStream fileOutputStream = null;
       String saveU ="";
       try {
          String tempPath="c:/wxScanUpload/"+new SimpleDateFormat("yyyyMMdd").format(new Date());
         
         File file=new File(tempPath);
         if(!file.exists() && !file.isDirectory()){
            file.mkdirs();
         }
          String name=fileName+".jpg";
          saveU=tempPath+"/"+name;
            fileOutputStream = new FileOutputStream(saveU);
            while ((len = inputStream.read(data)) != -1) {
               fileOutputStream.write(data, 0, len);
            }
          } catch (IOException e) {
              e.printStackTrace();
          } finally {
              if (inputStream != null) {
                  try {
                      inputStream.close();
                  } catch (IOException e) {
                      e.printStackTrace();
                  }
              }
              if (fileOutputStream != null) {
                  try {
                      fileOutputStream.close();
                  } catch (IOException e) {
                      e.printStackTrace();
                  }
              }
          }
      return saveU;
    }
    
   /**
    * 表情转换
    * @param emoji
    * @return
    */
    public static String getEmoji(int emoji){
       return String.valueOf(Character.toChars(emoji)); 
    }
    
   /**
    *中国正常坐标系GCJ02协议的坐标,转到 百度地图对应的 BD09 协议坐标
    * @param lat 维度
    * @param lng 经度
    * 返回经度+纬度的字符串 例如 119.2321,31.12321
    */
   public static String Convert_GCJ02_To_BD09(double lat,double lng){
      double x = lng, y = lat;
      double z =Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * x_pi);
      double theta = Math.atan2(y, x)+ 0.000003 * Math.cos(x * x_pi);
      lng = z * Math.cos(theta)+ 0.0065;
      lat = z * Math.sin(theta) + 0.006;
      return lng+","+lat;
   }
   /**
    *中国正常坐标系GCJ02协议的坐标,转到 百度地图对应的 BD09 协议坐标
    * @param lat 维度
    * @param lng 经度
    * 返回纬度+经度的字符串 例如 31.12321,119.2321
    */
   public static String Convert_GCJ02_To_BD09_1(double lat,double lng){
      double x = lng, y = lat;
      double z =Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * x_pi);
      double theta = Math.atan2(y, x)+ 0.000003 * Math.cos(x * x_pi);
      lng = z * Math.cos(theta)+ 0.0065;
      lat = z * Math.sin(theta) + 0.006;
      return lat+","+lng;
   }
   /**
    *百度地图对应的 BD09 协议坐标,转到 中国正常坐标系GCJ02协议的坐标
    * @param lat 维度
    * @param lng 经度
    */
   public static String Convert_BD09_To_GCJ02(double lat, double lng){
      double x = lng - 0.0065, y = lat - 0.006;
      double z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_pi);
      double theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_pi);
      lng = z * Math.cos(theta);
      lat = z * Math.sin(theta);
      return lat+","+lng;
   }
   
}