前提
- 擁有一個企業微信
-
按照上兩篇文章,設定了可信域名
自建應用可信域名
阿裡雲完成域名解析
- 使用的是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請求的資訊,都重定向到微信認證接口,進行微信認證。
添加微信認證的相關類和函數
- 剛才我們在攔截器中,重定向了一個url指向背景的oauth2.do方法
-
在該方法中,我們需要向微信官方的連結,發送擷取使用者微信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後的步驟解析:
- 帶code跳轉中,code在request參數中可以擷取,但是這個code不是使用者編号,是配置設定的一個臨時編号;
- 在方法中,getMemberGuidByCode函數,主要就是通過token以及code,擷取實際的使用者資訊的過程。
- 關于具體的擷取token,以及通過code擷取userId的實作方式,網上一搜一大把,臨時代碼封裝的不太好,我就不嫌醜了。
- 截止到此,代碼端的工作就完成了。
企業微信的背景配置以及實作效果
- 企業微信添加自建應用
【企業微信實作】springMVC+企業微信實作全流程 - 自建應用中增加自定義菜單
【企業微信實作】springMVC+企業微信實作全流程 - 自定義菜單中配置按鈕的url
【企業微信實作】springMVC+企業微信實作全流程 - 在企業微信中,點選自建應用下的按鈕
【企業微信實作】springMVC+企業微信實作全流程 - 檢視結果
【企業微信實作】springMVC+企業微信實作全流程