天天看点

【企业微信实现】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+企业微信实现全流程