標籤:[] 原理 while thread 串匹配 更新ui void jsp頁面 案頭
問題描寫敘述
當我們使用SpringMVC作為服務端的架構時,有時不僅僅要應對web前端(jsp、javascript、Jquery等)的訪問請求,有時還可能須要響應Android和JavaSE(案頭應用)這些client的請求。因此,除了web使用form表單或者ajax作為client擷取Controller響應之外。純Java語言向SpringMVC的Controller提供參數和請求結果也是必須要實現的。web前端使用form和ajax來擷取Controller響應在本篇部落格暫不深究,本篇博課著力於實現純Javaclient來實現請求Controller並擷取響應。(假設不想看以下的方法探索,能夠直接跳到第三部分)
方法探索
確定了須要解決的問題之後。我開始搜尋相關的部落格和問答。發現這樣的問題相關解決方案不是非常多,找了非常多部落格都是牛頭不正確馬嘴,可是還是有一些對解決這個問題有協助的內容,之後又翻了非常久的書,對這個問題的解決方案有了主要的認識。
看網上說的行之有效方法是使用HttpClient來實現這個功能,只是須要匯入HttpClient和HttpCore兩個jar包。當時研究了一下認為可行。
可是在實際操作過程中。在向Android(IDE:Android Studio)build.gradle裡面匯入上述兩個jar包的依賴後,同步的時候Android Studio給出了兩個警告,大意是HttpClient已經到期云云。然後我又專門去查了一個HttpClient這個東西和Android之間的關係,發現Android6.0以及之後的版本號碼放棄了對HttpClient的支援。強行匯入jar包也不行。(據說有人用了非常麻煩的方法匯入成功過 = =)那好嘞。不讓用算了。那就不用唄。看參考書《瘋狂Android講義》對HttpClient還那麼推崇。也是有點醉。
詳細不讓用的原因就不再深究了,接下來就研究使用HttpUrlConnection來解決上述問題吧。
在使用HttpURLConnection的過程中代碼實現照著套路來問題不大。遇到的問題是SpringMVC的Controller怎麼接收資料,接收的資料格式是什嗎?我應該傳什麼類型的資料?
Controller怎麼接收資料這個問題經過前段時間的學習我已經有個大概的認識,SpringMVC的Controller工作原理就是client向 項目地址+Controller前面的value值 這個url發出請求,這個請求會帶有一些參數。而SpringMVC會將請求攜帶的參數轉換為Controller相應value以下的方法的參數,然後在這種方法進行相關的操作再返回client一些參數,至於返回的結果就有幾種可能了。假設上面沒有@ResponseBody凝視,返回的資料有可能是jsp頁面的名字,則web會跳轉到相應的jsp頁面假設是ModelAndView也會跳轉到相應的頁面而假設加上@ResponseBody。那麼返回的就是json類型的資料了,client會接收到Controller返回的參數。那麼,明確了springmvc的工作原理,那麼怎麼使用HttpUrlConnection來訪問Controller就大概清楚了:我們就把請求地址拼接好,然後把攜帶的資料發送過去就能夠等著拿到Controller返回的資料了。
那麼第二個問題就來了。請求的地址清楚了。攜帶的資料應該是什麼格式的呢?
剛開始我以為和傳回值一樣是Json格式的索引值對形式,比方說使用者登入的userName和userPassword,(Controller的參數形式為 doLogin(String userName,String userPassword))開始我以為應該發送json格式資料。可是服務端不鳥我,沒有獲得參數。後來我又試了jsonArray形式也不行,試了map的索引值對形式不行。我就疑惑了究竟是什麼形式的。最後找了半天看了ajax發出相同請求時的http報文結構才知道了資料格式是什麼樣子的。
是這樣的:
中間是一個&串連了兩個參數,索引值中間是=,好吧,最終明確了。當然這是Controller參數為兩個單獨的String值的時候的類型,有一種更好的辦法是直接把Controller的參數設定為一個,然後在Controller裡面解析Json資料,這樣事實上更方便一點,以後還更easy做加密工作,只是眼下改起來太麻煩就不改了吧。如今弄明確了controller是兩個參數的時候是這樣的結構的。至於其他的list。bean以及json類型這裡就不探究了。由於我看到非常多別的博主都講了怎麼轉了。
廢話了這麼多。以下放代碼。
解決這個問題
SpringMVC相應Controller代碼(result單詞拼錯了,懶得改咯):
@RequestMapping(value="/doLogin",method=RequestMethod.POST) @ResponseBody public Map<String,Object> doLogin(String userName,String userPassword,HttpSession httpSession){ String resoult="fail"; User user = userService.getUser(userName); UserDetail userDetail = userDetailService.getUserDetail(userName); if(user!=null){ if(Objects.equals(userDetail.getUserDetailPassword(), userPassword)){ httpSession.setAttribute("currentUser",user); resoult = "success"; } else{ resoult = "wrong"; } } else{ resoult = "unexist"; } Map<String, Object> resoults = new HashMap<String,Object>(); resoults.put("resoult", resoult); return resoults; }
Android端或者java端寫的一個HttpPostUtils工具類
package cn.justwithme.withme.Utils;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.PrintWriter;import java.net.HttpURLConnection;import java.net.MalformedURLException;import java.net.URL;/** * Created by 桐木木 on 2017/2/8. * 發送Http請求。擷取Controller返回的資料 * */public class HttpPostUtils { public static String doPostRequest(String path,Object content){ PrintWriter out = null; BufferedReader in = null; String resoult = ""; try { System.out.println("要發送的資訊是:"+content); /*拼接url,Android這裡須要換上遠程地址,由於Android端沒辦法訪問localhost。java的話本地tomcat執行的話倒是無妨*/ String address = http://localhost:8080/WithMe/"+path; URL url = new URL(address); HttpURLConnection httpURLConnection = (HttpURLConnection)url.openConnection(); //這兩個參數必須加 httpURLConnection.setDoInput(true); httpURLConnection.setDoOutput(true); //設定逾時時間 httpURLConnection.setReadTimeout(10*1000); httpURLConnection.setConnectTimeout(10*1000); httpURLConnection.setRequestMethod("POST"); httpURLConnection.connect(); out = new PrintWriter(httpURLConnection.getOutputStream()); //在輸出資料流中寫入參數 out.print(content); out.flush(); if(httpURLConnection.getResponseCode() == 200){ in = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream(),"utf-8")); String line; while((line=in.readLine())!=null){ resoult+=line; } } System.out.println("server返回的結果是:"+resoult); return resoult; } catch (MalformedURLException e) { System.out.println("URL異常"); e.printStackTrace(); } catch (IOException e) { System.out.println("IO異常"); e.printStackTrace(); }finally { try{ if(out!=null) out.close(); if(in!=null) in.close(); }catch (IOException e) { e.printStackTrace(); } } return null; }}
工具類寫好之後我們分別在Android端和Java端進行一些測試,(在我的服務端我已經注冊過14121047的前提下,你假設僅僅是測試把服務端查詢資料庫校正密碼改成字串匹配就成了)。
Android
LoginActivity.java
package cn.justwithme.withme.Activity;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.support.v7.app.AppCompatActivity;import android.view.View;import android.widget.Button;import android.widget.EditText;import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.JSONObject;import java.util.HashMap;import java.util.Map;import cn.justwithme.withme.R;import cn.justwithme.withme.Utils.HttpPostUtils;public class LoginActivity extends AppCompatActivity { private String result; private Handler mHanlder = new Handler() { @Override public void handleMessage(Message message) { result = (String) message.obj; JSONObject resultJson = JSON.parseObject(result); String finalResult = resultJson.getString("resoult"); System.out.println("結果是:"+finalResult); if(finalResult.equals("success")){ System.out.println("登陸成功"); } else System.out.println("username或密碼錯誤"); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); final EditText userNameInput = (EditText)findViewById(R.id.userName); final EditText passwordInput = (EditText)findViewById(R.id.password); Button login = (Button)findViewById(R.id.login); login.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String userName = userNameInput.getText().toString(); String userPassword = passwordInput.getText().toString(); final Map<String,Object> userInfo = new HashMap<String,Object>(); userInfo.put("userName",userName); userInfo.put("userPassword",userPassword);// UserLogin userInfo = new UserLogin();// userInfo.setUserName(userName);// userInfo.setUserPassword(userPassword); final String user = "userName="+userName+"&userPassword="+userPassword; if(userName!= null && !userName.equals("") && userPassword!=null && !userPassword.equals("")){ /*這裡須要留意的是httpPostUtils請求在Android裡面不能放在主線程裡面,必須建立一個子線程。然後通過Hanlder把子線程的值傳過來更新UI(由於子線程不能直接更改UI)*/ new Thread() { public void run() { String response = HttpPostUtils.doPostRequest("doLogin",user); Message message = Message.obtain(); message.obj = response; mHanlder.sendMessage(message); } }.start(); } else{ System.out.println("username密碼不可為空"); } } }); }}
好吧。這是非常簡陋的代碼,畢竟Androidclient才剛剛開始寫,activity_login.xml就不放了,兩個輸入框一個button而已。能夠再以下查看輸出結果來推斷功能是否實現:
以下是Java的測試代碼,用的工具類和Android用的一樣的。
package httpPost;public class test { public static void main(String[] args){ String test = "userName=14121047&userPassword=14121047"; String ans = HttpPostUtils.doPostRequest("doLogin", test); System.out.println("server返回的資料為:"+ans); }}
測試結果為:
要發送的資訊是:userName=14121047&userPassword=14121047server返回的結果是:{"resoult":"success"}server返回的資料為:{"resoult":"success"}
結束語
當然,我這裡示範的知識一個非常簡單的android和java向springmvc發送請求的範例,可是,既然中間的道理和方法明確了,那之後不管是什麼格式的資料都不是非常難了。
Json資料的那僅僅用一個參數就好了咯,兩個參數都傳了一個參數不是非常easy嗎?要傳bean的先把Bean轉json到服務端再把json轉bean就好了咯。233。。
。(這裡僅僅是討論一下兩個參數怎麼傳。並非不想用json。
)
好好學習,天天向上,加油!
Android(或者Java)通過HttpUrlConnection向SpringMVC請求資料(資料繫結)