SpringMVC+MongoDB+Maven整合(微信回撥Oauth授權)
2017年第一篇自己在工作中的總結文件。土豪可以打賞哦。
https://git.oschina.net/xshuai/smplat.git 專案在GIT上面了。這裡就是原始碼地址。麻煩看仔細點
- 專案簡述:
使用SpringMVC+Maven搭建,整合MongoDB。入門級整理總結,不足之處多多理解。
- 專案結構:
- XML相關配置
POM.XML
注意: SpringMVC使用的版本4.0.5 其他版本的請自行測試
<!--增加mongodb也會自動增加mongojavadriver--> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-mongodb</artifactId> <version>1.2.0.RELEASE</version> </dependency> <!--相關驅動--> <dependency> <groupId>org.mongodb</groupId> <artifactId>mongo-java-driver</artifactId> <version>2.10.1</version> </dependency>
WEB.XML配置引入相關xml檔案
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml;classpath:mongodb-context.xml</param-value>
</context-param>
SPRING-MVC.XML
注意: SpringMVC配置僅供參考哦
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:util="http://www.springframework.org/schema/util" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:task="http://www.springframework.org/schema/task" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd http://www.springframework.org/schema/mvc/spring-mvc.xsd "> <!-- 配置1: 自動掃描controller包下的所有類,使其認為spring mvc的控制器 --> <context:component-scan base-package="com.bdxc" > <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" /> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service" /> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository" /> </context:component-scan> <!-- 配置靜態資源,直接對映到對應的資料夾,不被DispatcherServlet處理,3.04新增功能,需要重新設定spring-mvc-3.0.xsd --> <mvc:resources mapping="/images/**" location="/images/"/> <mvc:resources mapping="/js/**" location="/js/"/> <mvc:resources mapping="/css/**" location="/css/"/> <mvc:resources mapping="/swf/**" location="/swf/"/> <mvc:resources mapping="/file/**" location="/file/"/> <mvc:resources mapping="/FusionCharts/**" location="/FusionCharts/"/> <mvc:resources mapping="/bootstrap/**" location="/bootstrap/"/> <mvc:resources mapping="/uploads/**" location="/uploads/"/> <mvc:resources mapping="/signs/**" location="/signs/"/> <mvc:resources mapping="/anzhuangbao/**" location="/anzhuangbao/"/> <!-- 配置2: 避免IE執行AJAX時,返回JSON出現下載檔案 --> <bean id="mappingJacksonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> <property name="supportedMediaTypes"> <list> <value>text/html;charset=UTF-8</value> </list> </property> </bean> <!-- 配置3: 保證interceptor中通過handler獲得請求的method物件 --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" /> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter" p:ignoreDefaultModelOnRedirect="true"> <property name="messageConverters"> <list> <ref bean="mappingJacksonHttpMessageConverter" /> </list> </property> </bean> <!-- 配:5:對模型檢視名稱的解析,即在模型檢視名稱新增前後綴 --> <!-- viewResolver 檢視解析器,將檢視名(ModelAndView中的view)解析成URL--> <bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="suffix" value=".jsp" /> <property name="prefix" value="/WEB-INF/"/> <property name="order" value="20"></property> <property name="viewClass" value="org.springframework.web.servlet.view.InternalResourceView" /> </bean> <!-- 配置6: 配置Spring自帶檔案上傳操作類 --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="defaultEncoding"> <value>UTF-8</value> </property> <property name="maxUploadSize"> <value>2147483648</value> <!-- 上傳檔案大小限制為31M,31*1024*1024 --> </property> <property name="maxInMemorySize"> <value>4096</value> </property> </bean> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**" /> <bean class="com.bdxc.plat.system.interceptors.EncodingInterceptor" /> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/" /> <bean class="com.bdxc.plat.system.interceptors.AuthInterceptor" /> </mvc:interceptor> </mvc:interceptors> <!-- 國際化配置 --> <bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver" > <property name="cookieName" value="clientlanguage"/> <property name="cookieMaxAge" value="94608000"/> </bean> </beans>
MONGODB-CONTEXT.XML
這塊會涉及到mongodb是否驗證使用者名稱及密碼的配置
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mongo="http://www.springframework.org/schema/data/mongo" xsi:schemaLocation="http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <!-- 載入mongodb的屬性配置檔案 --> <context:property-placeholder location="classpath:config.properties" /> <!-- 定義mongo物件,對應的是mongodb官方jar包中的Mongo,replica-set設定叢集副本的ip地址和埠 --> <mongo:mongo id="mongo" replica-set="${mongo.hostport}" > <!-- 一些連線屬性的設定 --> <mongo:options connections-per-host="${mongo.connectionsPerHost}" threads-allowed-to-block-for-connection-multiplier="${mongo.threadsAllowedToBlockForConnectionMultiplier}" connect-timeout="${mongo.connectTimeout}" max-wait-time="${mongo.maxWaitTime}" auto-connect-retry="${mongo.autoConnectRetry}" socket-keep-alive="${mongo.socketKeepAlive}" socket-timeout="${mongo.socketTimeout}" slave-ok="${mongo.slaveOk}" write-number="1" write-timeout="0" write-fsync="true" /> </mongo:mongo> <mongo:db-factory dbname="${mongo.dbname}" mongo-ref="mongo"/> <!-- 增加驗證如果沒有的話這塊可以註釋 --> <bean id="userCredentials" class="org.springframework.data.authentication.UserCredentials"> <constructor-arg name="username" value="${mongo.username}"></constructor-arg> <constructor-arg name="password" value="${mongo.password}"></constructor-arg> </bean> <!-- mongo的工廠,通過它來取得mongo例項,dbname為pe的資料庫名,沒有的話會自動建立--> <!-- 可以點選class檢視MongoTemplate類提供的 構造方法就可以看出驗證需要傳遞哪些引數 --> <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate"> <constructor-arg name="mongo" ref="mongo" /> <constructor-arg name="databaseName" value="${mongo.dbname}" /> <!-- 增加驗證如果沒有的話這塊可以註釋 --> <constructor-arg name="userCredentials" ref="userCredentials"/> </bean> <!-- 對映轉換器,掃描back-package目錄下的檔案,根據註釋,把它們作為mongodb的一個collection的對映 --> <mongo:mapping-converter base-package="com.bdx.plat.model" /> <!-- mongodb bean的倉庫目錄,會自動掃描擴充套件了MongoRepository介面的介面進行注入 --> <mongo:repositories base-package="com.bdxc" /> </beans>
- 相關的java內容,看原始碼的構造和api可以有很大幫助哦
MongoTemplate.java可以看到有2個構造方法這樣就根據自己的MongoDB是否有驗證進行xml配置
/**
* Constructor used for a basic template configuration
*
* @param mongo must not be {@literal null}.
* @param databaseName must not be {@literal null} or empty.
*/
public MongoTemplate(Mongo mongo, String databaseName) {
this(new SimpleMongoDbFactory(mongo, databaseName), null);
}
/**
* Constructor used for a template configuration with user credentials in the form of
* {@link org.springframework.data.authentication.UserCredentials}
*
* @param mongo must not be {@literal null}.
* @param databaseName must not be {@literal null} or empty.
* @param userCredentials
*/
public MongoTemplate(Mongo mongo, String databaseName, UserCredentials userCredentials) {
this(new SimpleMongoDbFactory(mongo, databaseName, userCredentials));
}
UserCredentials.java 檢視驗證傳遞的引數 username & password
public class UserCredentials {
public static final UserCredentials NO_CREDENTIALS = new UserCredentials(null, null);
private final String username;
private final String password;
/**
* Creates a new {@link UserCredentials} instance from the given username and password. Empty {@link String}s provided
* will be treated like no username or password set.
*
* @param username
* @param password
*/
public UserCredentials(String username, String password) {
this.username = StringUtils.hasText(username) ? username : null;
this.password = StringUtils.hasText(password) ? password : null;
}
整合MongoDB的內容就這些。後續會將整個程式碼及專案上傳git,訪問路徑會在此博文更新
以下內容是小測試。
基於該框架寫了一個微信的回撥和授權(Oauth),SpringMVC+MongoDB+Maven搭建微信後臺框架,包含了回撥配置和授權Oauth配置 專案結構在最上面有截圖哦。
#基於SpringMVC+MongoDB資料庫做的微信接入等一些常用介面的DEMO
只實現了回撥 和oauth 介面
1. common存放相關基礎程式碼和微信常量
1.1 com/bdxc/plat/common/weixin/WXConstants.java 修改為自己的微信相關的APPID APPSERCET
1.2 com.bdxc.plat.controller存放為請求訪問層程式碼
1.2.1 WXConfigController.java 回撥配置需要用到,GET為回撥。POST 為使用者傳送資訊進行處理並返回
1.2.2 WXOauthController.java Oauth授權獲取使用者資訊的程式碼
2. com.bdxc.plat.vo 存放微信相關的介面基礎物件
3.com.bdxc.plat.util 存放相關工具類程式碼包含微信需要用到的
3.1 com.bdxc.plat.util.weixin 存放微信相關工具類
4.com.bdxc.plat.service.weixin 存放微信使用者給公眾傳送資訊進行處理的方法, 上一級為操作資料的service 不儲存不需要關注
5.com.bdxc.plat.model.weixin 存微信的訊息型別的物件,上一級為資料庫的model 不儲存不需要關注
- 回撥配置程式碼實現
/**
* 回撥配置
* @author 宗瀟帥
* @Title WXConfigController
* @時間 2017-1-4上午11:06:05
*/
@Controller
@RequestMapping(value="/wxconfig")
public class WXConfigController {
private static Logger logger = Logger.getLogger(WXConfigController.class);
@RequestMapping(value="/valid",method={RequestMethod.GET},produces = "application/json;charset=UTF-8")
public void valid(HttpServletRequest request,HttpServletResponse response,PrintWriter out) throws Exception{
System.out.println("回撥請求=======================");
//微信加密簽名
String signature = request.getParameter("signature");
//時間戳
String timestamp = request.getParameter("timestamp");
//隨機數
String nonce = request.getParameter("nonce");
//隨機字串
String echostr = request.getParameter("echostr");
out = response.getWriter();
//通過檢驗signature對請求進行校驗,若校驗成功則原樣返回echostr,表示接入成功,否則接入失敗
if(SignUtil.checkSignature(signature, timestamp, nonce)){
out.print(echostr);
}else{
System.out.println("非微信傳送的GET請求");
}
logger.info("回撥請求傳送的引數為signature"+signature+"n"+"timestamp"+timestamp+"n"+"nonce"+nonce+"n"+"echostr"+echostr);
out.flush();
out.close();
}
@RequestMapping(value="/valid",method={RequestMethod.POST},produces = "application/json;charset=UTF-8")
public void infos(HttpServletRequest request,HttpServletResponse response,PrintWriter out) throws Exception{
/* 訊息的接收、處理、響應 */
// 將請求、響應的編碼均設定為UTF-8(防止中文亂碼)
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
CoreService coreService = new CoreService();
// 呼叫核心業務類接收訊息、處理訊息
String respMessage = coreService.processRequest(request);
logger.info(respMessage);
// 響應訊息
out = response.getWriter();
out.print(respMessage);
out.close();
}
}
- StringUtil程式碼
/**
*
* 請求校驗工具類
*
*/
public class SignUtil {
/**
* 驗證簽名
*
* @param signature
* @param timestamp
* @param nonce
* @return
*/
public static boolean checkSignature(String signature, String timestamp,
String nonce) {
String[] arr = new String[] {WXConstants.TOKEN, timestamp, nonce };
// 將token、timestamp、nonce三個引數進行字典序排序
Arrays.sort(arr);
StringBuilder content = new StringBuilder();
for (int i = 0; i < arr.length; i++) {
content.append(arr[i]);
}
MessageDigest md = null;
String tmpStr = null;
try {
md = MessageDigest.getInstance("SHA-1");
// 將三個引數字串拼接成一個字串進行sha1加密
byte[] digest = md.digest(content.toString().getBytes());
tmpStr = byteToStr(digest);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
content = null;
// 將sha1加密後的字串可與signature對比,標識該請求來源於微信
return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false;
}
}
免費的外網對映https://my.oschina.net/xshuai/blog/597760
- Oauth介面,微信授權登入的程式碼實現
/**
* oauth獲取使用者資訊並儲存到mongodb
* @author 宗瀟帥
* @Title WXOauthController
* @時間 2017-1-4上午11:06:14
*/
@Controller
@RequestMapping(value="/wx")
public class WXOauthController {
private static Logger logger = Logger.getLogger(WXOauthController.class);
@Autowired
private WXUserInfoService wxUserInfoService;
/**
* oauth獲取使用者相關資訊
* @param request
* @param response
* @return
* @throws Exception
*/
@RequestMapping(value="/oauth",method={RequestMethod.POST,RequestMethod.GET})
public String oauth(HttpServletRequest request,HttpServletResponse response) throws Exception{
//接受引數
HttpSession httpSession = request.getSession();
String code = request.getParameter("code");
String scope = request.getParameter("scope");
logger.info("==============[OAuthServlet]獲取網頁授權code="+code);
logger.info("==============[OAuthServlet]獲取網頁跳轉許可權="+scope);
if(null != code && !"".equals(code)){
logger.info("==============[OAuthServlet]獲取網頁授權code不為空,code="+code);
//根據code換取openId
OAuthInfo oa = WeixinUtil.getOAuthOpenId(WXConstants.appId,WXConstants.appSecret,code);
//第一次獲取到存到session裡面 防止使用者重新整理頁面
if(oa!=null){
httpSession.setAttribute("openid", oa.getOpenId());
}else{
//如果使用者是重新整理頁面。則讀取session的openid
Object openid = httpSession.getAttribute("openid");
if(openid!=null){
OAuthInfo authInfo = new OAuthInfo();
String openids = openid.toString();
System.out.println("重新整理頁面留存的openid"+openids);
authInfo.setOpenId(openids);
oa = authInfo;
}else{
//session也為空 建議使用者重新進入頁面
// request.getRequestDispatcher("/warn.jsp").forward(request, response);
return "";
}
}
AccessToken oasign = WXConstants.ACCESS_TOKEN;
WXUserInfo info = WeixinUtil.getWXUserInfo(oasign.getToken(), oa.getOpenId());
if(!"".equals(oa) && null != oa){
logger.info("==============[OAuthServlet]獲取網頁授權openID="+oa.getOpenId());
//儲存資訊
try {
wxUserInfoService.insert(info);
request.setAttribute("openid", oa.getOpenId());
request.setAttribute("nickname", info.getNickname());
request.setAttribute("headimgurl", info.getHeadimgurl());
request.setAttribute("city", info.getCity());
request.getRequestDispatcher("/index.jsp").forward(request, response);
return null;
} catch (Exception e) {
e.printStackTrace();
logger.info("儲存失敗"+e.getMessage());
}
}else{
logger.info("==============[OAuthServlet]獲取網頁授權openId失敗!");
}
}else{
logger.info("==============[OAuthServlet]獲取網頁授權code失敗!");
}
return null;
}
}
基於mongodb做了一個測試,授權登入的使用者進行將相關資訊儲存。簡單實現沒有做任何封裝。使用的是MongoTemplate這個類進行的增刪改查。
測試號關注超過100人就會有問題。因此我全部移除了,想看效果的重新關注測試號,demo的框架換成了上面使用的SpringMVC+MongoDB+Maven整合(微信回撥Oauth授權),因此有些選單點選會有錯誤哦。
第一訪問會提示確認登入的相關資訊。確認登入後就是右邊顯示的相關內容哦。
確認登入後獲取到openid,那就可以拿到使用者的相關資訊了。存在了mongodb資料庫
mongodb是documents 非關係型資料庫。儲存的都是以文字 大家可以理解為json字串
得到的資料如下面程式碼顯示。id是mongodb生成的唯一id
{
"_id" : ObjectId("586cbbe7150f14811ce04546"),
"_class" : "com.bdxc.plat.model.WXUserInfo",
"subscribe" : 1,
"openid" : "o2VKNju8JqCeGVoEWJ1S8Ue_up8E",
"nickname" : "小帥丶",
"sex" : 1,
"language" : "zh_CN",
"city" : "海淀",
"province" : "北京",
"country" : "中國",
"headimgurl" : "http://wx.qlogo.cn/mmopen/Lj9cibm6LlmjNM8CGSYKuMQiaD4tTPwUjD7zVkkn2u6kFqv4zDwtcfHFntHyxtjjmXeicLDqVqQB42vUukxB5Mia8HgoV94gsN02/0",
"subscribe_time" : "1483520921",
"unionid" : "oUmIot2Yo2Mb_8fVW3UVw9AW1w4Y",
"remark" : "",
"groupid" : 0,
"tagid_list" : []
}
本文主要是說mongodb驗證使用者名稱和密碼的xml的配置內容。順便博主拿微信寫了個demo。後續完善後會上傳git。目前有servlet的版本在眾包提供服務哦。https://zb.oschina.net/service/f9918c2f1e643513
土豪可以打賞哦。