使用springmvc的controller層獲取到請(qǐng)求的數(shù)據(jù)方式
javaweb應(yīng)用開發(fā),最常用到的就是應(yīng)用之間的信息交互,調(diào)用別的應(yīng)用模塊得到自己想獲取的數(shù)據(jù)信息,然后解析數(shù)據(jù)并進(jìn)行處理返回到上一層。那controller層的方法如何獲取http請(qǐng)求/webservice請(qǐng)求中的參數(shù),或者說請(qǐng)求數(shù)據(jù)呢?
按照我個(gè)人的接觸和理解,把請(qǐng)求可以分為兩大類:
1.頁面請(qǐng)求到后臺(tái)controller層的請(qǐng)求。
2.別的應(yīng)用http/webservice調(diào)用本應(yīng)用中封裝接口的請(qǐng)求。
無論哪種方式的請(qǐng)求,都是http請(qǐng)求(webservice底層也是http請(qǐng)求,待考證),controller層對(duì)請(qǐng)求數(shù)據(jù)的解析是按照json還是xml的依據(jù)就是請(qǐng)求頭content-type,接下來我們就先來詳細(xì)介紹一下。
content-type
content-type請(qǐng)求頭是干嗎的呢,http請(qǐng)求頭有四種類型,分別是通用頭部,請(qǐng)求頭部,響應(yīng)頭部以及內(nèi)容頭部. 首先,我們要弄清楚,content-type是屬于內(nèi)容頭部,既然是內(nèi)容頭部,那這個(gè)請(qǐng)求頭是用來向接收端解釋傳遞的該內(nèi)容主體的,content-type的取值是告訴服務(wù)端,你傳遞過去的內(nèi)容是啥,你應(yīng)該準(zhǔn)備好如何接收和解析。常用的content-type可以分為application/x-www-form-urlencoded , multipart/form-data ,application/json , text/xml四種。
下面一一介紹
1.application/x-www-form-urlencoded
application/x-www-form-urlencoded是常用的表單發(fā)包方式,普通的表單提交(即不帶文件上傳的提交),或者js (例如:post方式)發(fā)包,默認(rèn)都是通過這種方式,提交代碼demo如下:
function searchInfo() { $("#cxjg").datagrid({ url : basepath + 'jijin/getList', queryParams : getParam($("#query").serializeArray()), method : "post" }); function searchInfo(){ $("#cxjg").datagrid({ url:basepath+'jijin/getList', queryParams : {'age':23,'name':'zhangsan'}, method:"post" });
請(qǐng)求頭信息如下所示,可以看到content-type和FormData(表單的數(shù)據(jù)格式)
如何獲取這種數(shù)據(jù)結(jié)構(gòu)的請(qǐng)求?有兩種方式來解決
1.1 String 參數(shù)值=reqeust.getParameter(“參數(shù)名”);
(以springmvc 的controller層的方法為例)
@RequestMapping("/getParam") public String getParamFromRequest(HttpServletRequest request){ String jiJinCode=(String)request.getParameter("jinJinCode"); ... }
1.2 Map<String,String[]> paramMap=request.getParameterMap();
@RequestMapping("/getParam") public String getParamFromRequest(HttpServletRequest request){ Map<String,String[]> paramMap=request.getParameterMap(); StringBuffer inputDate=new StringBuffer(); inputDate.append("<jiJinBean>"); for(Map.Entry<String,String[]> entry :paramMap.entrySet()){ String key=entry.getKey(); String[] values=entry.getValue(); String value=null; if(values.length>0){ value=values[0]; } inputDate.append("<"+key+">"+value+"</"+key+">"); } return inputDate.toString(); }
兩種方法比較來說,第一種適合當(dāng)參數(shù)不多時(shí),可以一個(gè)一個(gè)取。但第二種則是遍歷出所有的請(qǐng)求參數(shù),并生成標(biāo)簽格式,利于自動(dòng)生成報(bào)文格式。
2.multipart/form-data
multipart/form-data用在頁面(提交)發(fā)送文件的POST請(qǐng)求。之所以會(huì)和第一種content-type同是post提交,為啥在這里就變成multipart/form-data了呢?
當(dāng)然程序不會(huì)自動(dòng)識(shí)別是不是文件,而是我們?cè)?lt;form>這個(gè)標(biāo)簽里加上了這句話:
enctype="multipart/form-data",這才是讓請(qǐng)求頭發(fā)生變化的原因!具體代碼demo如下
$("#batchAddInfo").form('submit',{ url:basepath+"jijin/fileUpload", onSubmit:function(){}, success:function(data){ data=eval('('+data+')'); var flag=data.flag; if(flag){ $("#batchDivDialog").window("close"); $.messager.alert('提示',"批量新增成功!"); searchInfo(); }else{ $("#batchDivDialog").window("close"); $.messager.alert('提示',"批量新增失??!"); searchInfo(); } } });
對(duì)應(yīng)的谷歌頁面request調(diào)試信息如下:
這里Content-Type告訴我們,發(fā)包是以multipart/form-data格式來傳輸,另外,還有boundary用于分割數(shù)據(jù)。
這種方式的請(qǐng)求數(shù)據(jù)如何獲???出文件外的表單參數(shù)值當(dāng)然還是和上面一樣——request.getParameter(“parameterName”)來獲取,不一樣的是文件怎么來獲???要用到MultipartHttpServletRequest,這個(gè)MultipartHttpServletRequest 繼承于HttpServletRequest,MultipartRequest。
我們要從這個(gè)子類里面來獲取,具體代碼如下:
@RequestMapping("/fileUpload") public void fileUpload(HttpServletRequest request,HttpServletResponse response){ InputStream is=null; //創(chuàng)建解析器 CommonsMultipartResolver resolver=new CommonsMultipartResolver(request.getSession().getServletContext()); //判斷request是否有文件上傳,即多部請(qǐng)求 if(resolver.isMultipart(request)){ MultipartHttpServletRequest multiRequest=(MultipartHttpServletRequest)request; //獲取多部request中的文件名 Iterator<String> iter=multiRequest.getFileNames(); while(iter.hasNext()){ //取得上傳的文件 MultipartFile file=multiRequest.getFile(iter.next()); if(file!=null){ is=new ByteArrayInputStream(file.getBytes()); } } } Workbook wb=new XSSFWorkbook(is); ... }
3.text/xml
這種請(qǐng)求頭一般出現(xiàn)實(shí)在webservice請(qǐng)求時(shí)才會(huì)有。由于別的應(yīng)用請(qǐng)求我們,所以我們這邊就是服務(wù)端,他們是客戶端。這里無法用瀏覽器模擬,只能給出客戶端和服務(wù)端代碼,然后看如何解析客戶端的請(qǐng)求數(shù)據(jù)。
客戶端代碼
public class AxisClientTest { public static void main(String[] args) throws Exception { String nameSpaceURI = "com.serviceTargetName"; String publishUrl = "http://localhost:8080/springCXFWebserviceDemo01/service/HelloWorldService?wsdl"; Service service = new Service(); // 通過service創(chuàng)建call對(duì)象 Call call = (Call) service.createCall(); // 設(shè)置webservice接口地址 call.setTargetEndpointAddress(new URL(publishUrl)); call.setOperationName(new QName(nameSpaceURI, "sayHello")); call.addParameter("parameterName", XMLType.XSD_STRING, ParameterMode.IN); call.setReturnType(XMLType.XSD_STRING); // 給方法傳遞參數(shù),并且調(diào)用方法 String name = "zhanglifeng"; String temp = getXml(name); // 這里的obj{}是放入幾個(gè)入?yún)?,完全由service提供的接口方法的入?yún)Q定,且順序和你存放的順序一致!一般入?yún)镾tring類型的xml報(bào)文,回參也是xml報(bào)文。 Object[] obj = new Object[] { temp }; String result = (String) call.invoke(obj); } private static String getXml(String name) { StringBuffer sb = new StringBuffer( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); sb.append("<userBean>"); sb.append("<userName>" + name + "</userName>"); sb.append("</userBean>"); return sb.toString(); } }
上面的方法getXml(String name)就是客戶端發(fā)給服務(wù)端的請(qǐng)求:
<?xml version="1.0" encoding="UTF-8"?> <userBean> <userName>" + 入?yún)ⅲ喝嗣?+ </userName> </userBean>
下面我們?cè)倏捶?wù)端,也就是我們這邊接受請(qǐng)求的代碼是啥樣的:
/** * 由于實(shí)現(xiàn)類和接口不在同一個(gè)包中。所以要加上targetNamespace屬性。 * 另外,這里的endpointInterface是實(shí)現(xiàn)類對(duì)應(yīng)接口的全路徑 * @author Administrator */ @WebService(targetNamespace="com.serviceTargetName",endpointInterface="com.zlf.HelloWorld") @Component("HelloWord")//spring注入用 public class HelloWorldImpl implements HelloWorld { @Override public String sayHello(String str) { String username="aaa"; Document document = XMLUtils.parse(str); //首先接口開發(fā)肯定是雙發(fā)都知道此方法要接受的報(bào)文格式的。我們獲取報(bào)文中人名對(duì)應(yīng)的節(jié)點(diǎn)即可。 Node node = document.getElementsByTagName("userName").item(0); if(node !=null){ username=node.getTextContent(); } return "你好,"+username+" 你已成功訪問了webservice服務(wù)端!" ; } }
這里我們是直接拿著入?yún)tr進(jìn)行Documen解析,因?yàn)榭蛻舳说恼?qǐng)求數(shù)據(jù)已經(jīng)綁定到這個(gè)入?yún)⑸狭?。由于我們知道他的?qǐng)求報(bào)文格式是xml的,所以可以進(jìn)行Document轉(zhuǎn)換,然后我們從節(jié)點(diǎn)中取值既可以實(shí)現(xiàn)請(qǐng)求數(shù)據(jù)的解析了。
解析的代碼請(qǐng)查看我以前的文章: 基于cxf和axis兩種框架下的webservice客戶端開發(fā)文的最后就是這個(gè)解析的工具類。
4.application/json
application/json 這個(gè) Content-Type 作為響應(yīng)頭大家肯定不陌生。實(shí)際上,現(xiàn)在越來越多的人把它作為請(qǐng)求頭,用來告訴服務(wù)端消息主體是序列化后的 JSON 字符串。由于 JSON 規(guī)范的流行,除了低版本 IE 之外的各大瀏覽器都原生支持 JSON.stringify,服務(wù)端語言也都有處理 JSON 的函數(shù),使用 JSON 不會(huì)遇上什么麻煩。
JSON 格式支持比鍵值對(duì)復(fù)雜得多的結(jié)構(gòu)化數(shù)據(jù),這一點(diǎn)也很有用。
這個(gè)請(qǐng)求頭還有一個(gè)特殊點(diǎn)就是頁面通過jquery過來的數(shù)據(jù)結(jié)構(gòu)和其他應(yīng)用請(qǐng)求的數(shù)據(jù)結(jié)構(gòu)不一樣,因?yàn)閖query對(duì)json的數(shù)據(jù)做了轉(zhuǎn)換:
"data":{ "mobilenum":"15867426421",'age':23,'name':'zhangsan' } ——>mobilenum=15867426421&age=23&name=zhangsan
然而應(yīng)用沒有發(fā)生轉(zhuǎn)化,還是json結(jié)構(gòu)的數(shù)據(jù)。所以獲取上會(huì)有所不同。這里我們分成頁面和應(yīng)用兩種請(qǐng)求來分別說
4.1 頁面請(qǐng)求的數(shù)據(jù)獲取
4.1.1 頁面js請(qǐng)求如下
數(shù)據(jù)結(jié)構(gòu)為json,且data為var data={}的json類型時(shí)
$.ajax({ type: "post", data:{'mobilenum':'15867426421','age':'23','name':'zhangsan'}, contentType: "application/json; charset=utf-8", url :basepath+'jijin/getList', success: function(data){ ... } });
但是當(dāng)用瀏覽器來看是這樣的:
我們的數(shù)據(jù)結(jié)構(gòu)明顯發(fā)生了變化,由json變成了用&符號(hào)連接的普通傳值方式。所以這時(shí)候獲取參數(shù)值通過:String name=request.getParameter(“name”)這種來獲取。
4.1.2 如果頁面js請(qǐng)求如下
數(shù)據(jù)結(jié)構(gòu)為json,且data為var data=”“的String類型時(shí),controller獲取數(shù)據(jù)則可以和下面的4.2一樣通過注解@RequestBody來綁定到入?yún)⑸稀?/p>
$.ajax( { dataType: "json", type: "POST", data:"{'mobilenum':'15867426421','age':'23','name':'zhangsan'}", contentType: "application/json; charset=utf-8", url :basepath+'jijin/getList', success: function(data){ } }); }
這時(shí)對(duì)應(yīng)的瀏覽器的請(qǐng)求頭信息如下:
可以看到串到后臺(tái)的數(shù)據(jù)結(jié)構(gòu)為json格式的數(shù)據(jù)結(jié)構(gòu),和4.1.1完全不同了。就是因?yàn)閐ata的數(shù)據(jù)類型不同導(dǎo)致的,4.1.1的data是json類型,結(jié)果轉(zhuǎn)成普通的get方式拼接的參數(shù)結(jié)構(gòu),4.1.2的data是String類型,反而保持住了json類型的數(shù)據(jù)結(jié)構(gòu)。從而可以實(shí)現(xiàn)在controller層通過參數(shù)綁定來獲取請(qǐng)求參數(shù)。
4.1總結(jié)
通過上面兩個(gè)比較可以知道,頁面的jquery還是能夠識(shí)別json數(shù)據(jù)的,真是由于識(shí)別才導(dǎo)致數(shù)據(jù)轉(zhuǎn)換而。String類型的字符串沒有轉(zhuǎn)換的意義,而是直接傳給后臺(tái),從而保證了數(shù)據(jù)結(jié)構(gòu)的不變。故:我們真想讓后臺(tái)接受json數(shù)據(jù)結(jié)構(gòu)的參數(shù)話,還是傳String類型的吧!
4.2 當(dāng)別的應(yīng)用調(diào)用我們的服務(wù)
發(fā)送json數(shù)據(jù)的請(qǐng)求時(shí)如何解析(springmvc controller層)?總的來說通過@RequestBody 注解方法的入?yún)?,可以讓?qǐng)求的參數(shù)綁定到該參數(shù)上,然后用Gson轉(zhuǎn)換成json即可獲得jsonObject/實(shí)體類(這里的UserBo),具體代碼如下
@RequestMapping("/url") public void getUrlByPhone(@RequestBody String json,HttpServletRequest request){ Gson gson=new Gson(); UserBo ub=gson.fromJson(json,UserBo.class); //這里還可以通過jackson的ObjectMapper()把String json轉(zhuǎn)成JsonNode,然后用jsonNode.get(fieldName)來獲取各個(gè)json字段。例如: JsonNode node=new ObjectMapper().readTree(json); String name=node.get("name"); ...... }
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- SpringMVC詳解如何映射請(qǐng)求數(shù)據(jù)
- Java超詳細(xì)講解SpringMVC如何獲取請(qǐng)求數(shù)據(jù)
- 關(guān)于SpringMVC請(qǐng)求域?qū)ο蟮臄?shù)據(jù)共享問題
- SpringMVC 重新定向redirect請(qǐng)求中攜帶數(shù)據(jù)方式
- Springmvc獲取前臺(tái)請(qǐng)求數(shù)據(jù)過程解析
- Springmvc處理ajax請(qǐng)求并返回json數(shù)據(jù)
- SpringMVC 跨重定向請(qǐng)求傳遞數(shù)據(jù)的方法實(shí)現(xiàn)
- SpringMVC解析JSON請(qǐng)求數(shù)據(jù)問題解析
- SpringMVC請(qǐng)求數(shù)據(jù)詳解講解
相關(guān)文章
Java數(shù)據(jù)結(jié)構(gòu)之平衡二叉樹的原理與實(shí)現(xiàn)
平衡樹(Balance Tree,BT) 指的是,任意節(jié)點(diǎn)的子樹的高度差都小于等于1。常見的符合平衡樹的有,B樹(多路平衡搜索樹)、AVL樹(二叉平衡搜索樹)等。本文將詳細(xì)介紹平衡二叉樹的概念和實(shí)現(xiàn)原理以及它的實(shí)現(xiàn)2022-01-01在Java的Spring框架的程序中使用JDBC API操作數(shù)據(jù)庫
這篇文章主要介紹了在Java的Spring框架的程序中使用JDBC API操作數(shù)據(jù)庫的方法,并通過示例展示了其存儲(chǔ)過程以及基本SQL語句的應(yīng)用,需要的朋友可以參考下2015-12-12