天天看點

【企業微信實作】springMVC+企業微信實作全流程

前提

  1. 擁有一個企業微信
  2. 按照上兩篇文章,設定了可信域名

    自建應用可信域名

    阿裡雲完成域名解析

  3. 使用的是springMVC架構

注意事項;

  1. 其他架構可能需要根據架構自身,對本實作環節進行調整
  2. 本篇文章,意在指導使用者建立完整的企業微信自建應用的調用流程
  3. 所有的細節部分,如果有報錯,可能是由于大家對于springMVC的配置不同,單個細節部分完全可以百度實作。

實作步驟

微信資源請求流轉

【企業微信實作】springMVC+企業微信實作全流程

設定攔截器

在配置檔案中,設定攔截器攔截内容,需要區分微信和平台端,配置方法可以參考下面的圖檔

【企業微信實作】springMVC+企業微信實作全流程

配置的代碼段:

<!-- 配置攔截器 -->
	<mvc:interceptors>
		<mvc:interceptor>
			<mvc:mapping path="/**" />
			<mvc:exclude-mapping path="/www/**" />
			<mvc:exclude-mapping path="/viewer/**" />
			<mvc:exclude-mapping path="/css/**" />
			<mvc:exclude-mapping path="/error/**" />
			<mvc:exclude-mapping path="/index/**" />
			<mvc:exclude-mapping path="/image/**" />
			<mvc:exclude-mapping path="/initlib/**" />
			<mvc:exclude-mapping path="/js/**" />
			<mvc:exclude-mapping path="/weChat/**" />
			<!-- 配置權限攔截器 如果部定義mappingUrl,則預設攔截所有對controller的請求 可以使用正規表達式對url進行比對,進而更細粒度的進行攔截(.*/entryOrJsonController\.do\?action=reg.*) -->
			<bean class="com.pms.system.interceptor.SecurityAndLogInterceptor">
			   <property name="mappingURL" value="edit|del|add|save|lock|assign|batchAssign"/>
			</bean> 
		</mvc:interceptor>
	</mvc:interceptors>
	<!-- OAuth2攔截器 -->
	<mvc:interceptors>
		<mvc:interceptor>
			<!--  對所有的請求攔截使用/** ,對某個子產品下的請求攔截使用:/myPath/*-->
			<mvc:mapping path="/weChat/**" />
			<ref bean="oauth2Interceptor" />
		</mvc:interceptor>
	</mvc:interceptors>
	<bean id="oauth2Interceptor" class="com.hhisp.wechat.interceptor.OAuth2Interceptor">
	</bean>
           

編寫攔截器代碼

攔截器主要是用于在企業應用内部中,對資源請求進行攔截,防止未登入直接跳轉到某一資源下。

在本示例中,微信的攔截器oauth2Interceptor主要完成微信的token擷取,code擷取等功能,并且實作頁面的跳轉。此處相當于一個歸口作用,将所有關于微信的請求,都彙總到一個方法中處理登入認證等通用流程,完成認證流程後,再跳轉到具體的業務頁面進行業務辦理。

package com.hhisp.wechat.interceptor;

import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;

public class OAuth2Interceptor implements HandlerInterceptor {

	/**
	 * 在DispatcherServlet完全處理完請求後被調用
	 * 當有攔截器抛出異常時,會從目前攔截器往回執行所有的攔截器的afterCompletion()
	 */
	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

	}

	/**
	 * 在業務處理器處理請求執行完成後,生成視圖之前執行的動作
	 */
	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object arg2, ModelAndView modelAndView) throws Exception {

	}

	/**
	 * 在業務處理器處理請求之前被調用 如果傳回false 從目前的攔截器往回執行所有攔截器的afterCompletion(),再退出攔截器鍊
	 * 如果傳回true 執行下一個攔截器,直到所有的攔截器都執行完畢 再執行被攔截的Controller 然後進入攔截器鍊,
	 * 從最後一個攔截器往回執行所有的postHandle() 接着再從最後一個攔截器往回執行所有的afterCompletion()
	 */
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
		//String url = request.getRequestURL().toString();
		HttpSession session = request.getSession();
		
		// 先判斷是否有注解
		HandlerMethod handlerMethod = (HandlerMethod) handler;
		Method method = handlerMethod.getMethod();
		OAuthRequired annotation = method.getAnnotation(OAuthRequired.class);
		if (annotation != null) {
			System.out.println("session:"+session.toString());
			Object objUid = session.getAttribute("weChatId");
			if (objUid == null) {
				String resultUrl = request.getRequestURL().toString();
				String param=request.getQueryString();
				if(param!=null){
					resultUrl+= "?" + param;
				}
				try {
					resultUrl = java.net.URLEncoder.encode(resultUrl, "utf-8");
				} catch (UnsupportedEncodingException e) {
					e.printStackTrace();
				}
				//請求的路徑
		        String contextPath=request.getContextPath();
				System.out.println("contextPath !"+contextPath);
				System.out.println("resultUrl !"+resultUrl);
				System.out.println("all!"+contextPath + "/weChat/oauth2/oauth2.do?resultUrl=" + resultUrl);
				response.sendRedirect(contextPath + "/weChat/oauth2/oauth2.do?resultUrl=" + resultUrl);
				return false;
			}

		}
		return true;
	}

}

           

代碼詳解:

整篇代碼中,要實作的功能就是最後一句話,相當于将所有wechat請求的資訊,都重定向到微信認證接口,進行微信認證。

【企業微信實作】springMVC+企業微信實作全流程

添加微信認證的相關類和函數

  1. 剛才我們在攔截器中,重定向了一個url指向背景的oauth2.do方法
  2. 在該方法中,我們需要向微信官方的連結,發送擷取使用者微信Code的請求,并且将擷取code後重定向的url送出給微信官方連結。

    具體代碼如下:

import com.hhisp.wechat.pojo.AccessToken;
import com.hhisp.wechat.utils.Constants;
import com.hhisp.wechat.utils.QiYeUtil;
import com.hhisp.wechat.utils.Result;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.UnsupportedEncodingException;

@Controller
@RequestMapping("/weChat/oauth2")
public class OAuth2Controller {
	
	/**
	 * 構造參數并将請求重定向到微信API擷取登入資訊
	 * 
	 * @param resultUrl
	 * @return
	 */
	@RequestMapping(value = { "/oauth2.do", "/oauth2" })
	public String Oauth2API(HttpServletRequest request, @RequestParam String resultUrl) {
		// 此處可以添加擷取持久化的資料,如企業号id等相關資訊
		String CropId = 自有企業微信ID;
		String redirectUrl = "";
		if (resultUrl != null) {
			String backUrl = Constants.BEFORE_URL + "/weChat/oauth2/oauth2url.do?oauth2url=" + resultUrl;
			redirectUrl = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + corpid + "&redirect_uri=" + redirect_uri
				+ "&response_type=code&scope=snsapi_base&state=sunlight#wechat_redirect";;
		}
		return "redirect:" + redirectUrl;
	}
}
           

擷取微信賬号

上面,我們向微信官方送出了一個請求code的連結,并且告訴微信官方,我們擷取了code後,需要定向的目的url是什麼

接下來,在這個url的處理函數中,需要擷取微信官方傳回的code,并且根據code,處理相關的業務邏輯,進而跳轉到具體的業務頁面

/**
	 * 根據code擷取Userid後跳轉到需要帶使用者資訊的最終頁面
	 * 
	 * @param request
	 * @param code
	 *            擷取微信重定向到自己設定的URL中code參數
	 * @param oauth2url
	 *            跳轉到最終頁面的位址
	 * @return
	 */
	@RequestMapping(value = { "/oauth2url.do" })
	public String Oauth2MeUrl(HttpServletRequest request, @RequestParam String code, @RequestParam String oauth2url,String activityId) {
		AccessToken accessToken = QiYeUtil.getAccessToken(Constants.CORPID,Constants.SECRET);
		HttpSession session = request.getSession();
		if (accessToken != null && accessToken.getToken() != null) {
			String weChatId = getMemberGuidByCode(accessToken.getToken(), code, Constants.AGENTID);
			if (weChatId != null) {
				session.setAttribute("weChatId", weChatId);
				System.out.println("weChatId"+weChatId);
				System.out.println("session after set wid"+session.toString());
			}
		}
		if(StringUtils.isNotEmpty(activityId)){
			return "redirect:" + oauth2url+ "&activityId=" + activityId;
		}
		// 這裡簡單處理,存儲到session中
		return "redirect:" + oauth2url;
	}
		/**
	 * 調用接口擷取使用者資訊
	 * 
	 * @param token
	 * @param code
	 * @param agentId
	 * @return
	 */
	public String getMemberGuidByCode(String token, String code, int agentId) {
		Result<String> result = QiYeUtil.oAuth2GetUserByCode(token, code, agentId);
		if (result.getErrcode() == "0") {
			if (result.getObj() != null) {
				// 此處可以通過微信授權用code擷取的Userid查詢自己本地伺服器中的資料
				return result.getObj();
			}
		}
		return "";
	}
           

擷取code後的步驟解析:

  1. 帶code跳轉中,code在request參數中可以擷取,但是這個code不是使用者編号,是配置設定的一個臨時編号;
  2. 在方法中,getMemberGuidByCode函數,主要就是通過token以及code,擷取實際的使用者資訊的過程。
  3. 關于具體的擷取token,以及通過code擷取userId的實作方式,網上一搜一大把,臨時代碼封裝的不太好,我就不嫌醜了。
  4. 截止到此,代碼端的工作就完成了。

企業微信的背景配置以及實作效果

  1. 企業微信添加自建應用
    【企業微信實作】springMVC+企業微信實作全流程
  2. 自建應用中增加自定義菜單
    【企業微信實作】springMVC+企業微信實作全流程
  3. 自定義菜單中配置按鈕的url
    【企業微信實作】springMVC+企業微信實作全流程
  4. 在企業微信中,點選自建應用下的按鈕
    【企業微信實作】springMVC+企業微信實作全流程
  5. 檢視結果
    【企業微信實作】springMVC+企業微信實作全流程