(六)利用ajax和后臺(tái)交互
這一小節(jié),我們主要實(shí)現(xiàn)頁面和后臺(tái)簡(jiǎn)單的數(shù)據(jù)交互,初步掌握這個(gè)交互流程
頁面主要采用ajax技術(shù)往后臺(tái)發(fā)數(shù)據(jù),后臺(tái)就使用上一節(jié)我們寫好的工程代碼(五)最簡(jiǎn)單的springMVC后臺(tái)程序
關(guān)于jquery,ajax這些基礎(chǔ)理論,這里就不多講了,簡(jiǎn)單使用的話,沒什么難度,有需求的請(qǐng)自行百度。
首先,為了這一節(jié)的講解,我們需要新建一些文件和目錄。
1.引入jquery*
這個(gè)簡(jiǎn)單,只需要到j(luò)query官網(wǎng)去把jquery.js文件下回來,引入代碼即可。這里我們?cè)?src/main/webapp 下創(chuàng)建一個(gè)resources文件夾,在這個(gè)文件夾下邊,創(chuàng)建一個(gè)jquery文件夾,把從官網(wǎng)下回來的jquery.js拷貝到這里面,我這里用的是 jqery-3.3.1.js
2.創(chuàng)建一個(gè)hello目錄,在里面創(chuàng)建一個(gè)hello.js和hello.css兩個(gè)文件,暫時(shí)保持空文件,后面再來添加內(nèi)容。
3.在WEB-INF下面創(chuàng)建一個(gè)pages文件夾,然后在這個(gè)文件夾里,創(chuàng)建一個(gè)hello.jsp。
創(chuàng)建完成后,目錄結(jié)構(gòu)如下:

這里我們?yōu)榱搜菔?,做了一個(gè)比較完整的結(jié)構(gòu),hello.jsp是我們需要訪問的頁面,hello.js提供腳本支持,hello.css提供樣式支持,常規(guī)工程也基本就是這樣了,可能就是目錄結(jié)構(gòu)的差異
好了,現(xiàn)在我們?cè)谔顚憙?nèi)容,具體細(xì)節(jié)暫時(shí)不討論,jsp相關(guān)的知識(shí)點(diǎn)請(qǐng)自行百度學(xué)習(xí)。
首先,hello.jsp的代碼如下
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>HelloJsp</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<script type="text/javascript" src="<%=basePath%>resources/jquery/jquery-3.3.1.js"></script>
<script type="text/javascript" src="<%=basePath%>resources/hello/hello.js">
</script>
<script type="text/javascript">
var basePath = "<%=basePath%>";
</script>
<link rel="stylesheet" type="text/css" href="<%=basePath%>resources/hello/hello.css">
</head>
<body>
This is my first jsp page. <br>
<br/>
my hello
<br/>
<div class="mydiv">
<input id="myInput"></input>
<button class="mybutton" id="getButton">Get</button>
</div>
</body>
</html>
這個(gè)頁面部分代碼是自動(dòng)生成的時(shí)候留下的,先不管它,就這樣寫滿足我們的需求即可
其中的
<script type="text/javascript" src="<%=basePath%>resources/jquery/jquery-3.3.1.js"></script>
<script type="text/javascript" src="<%=basePath%>resources/hello/hello.js">
引入了jquery和js
然后,我們?cè)陧撁嫔袭嬃艘粋€(gè)輸入框和一個(gè)按鈕
<div class="mydiv">
<input id="myInput"></input>
<button class="mybutton" id="getButton">Get</button>
</div>
后面的學(xué)習(xí)和測(cè)試,都是圍繞這個(gè)輸入框和按鈕來進(jìn)行。
然后,hello.js這樣寫
$("document").ready(function(){
$("#getButton").click(function(){
let id = $("#myInput").val();
$.ajax({
url:basePath+"/firstGet/"+id,
type:'GET',
dataType:'text',
contentType:'application/json',
success:function(result){
$("#myInput").val(result);
}
})
});
});
簡(jiǎn)單的,典型的,基于jquery的一個(gè)js代碼。
點(diǎn)擊button,向后端服務(wù)器發(fā)送一個(gè)get請(qǐng)求,然后將后端的返回值,填寫到輸入框。
至于ajax的相關(guān)問題,請(qǐng)大家自行百度學(xué)習(xí),這里寫的是很簡(jiǎn)單的。
好了,然后我們?cè)趆ello.css中加入內(nèi)容
.mydiv{
display:flex;
flex-direction:column;
width:400px;
height:600px;
}
.mybutton{
width:100px;
}
不擅長寫樣式,簡(jiǎn)單的寫一下,達(dá)到演示的目的即可。
好,我們的頁面文件已經(jīng)準(zhǔn)備好了,現(xiàn)在修改一下后端代碼。
在上面ajax中,我們發(fā)出去的請(qǐng)求是
url:basePath+"/firstGet/"+id,
在controller中要處理的uri就是 /firstGet/{id} 其中的{id}指的就是我們從input獲取到的id,這個(gè)是目前流行的restful風(fēng)格的寫法,按照以前的寫法已經(jīng)改是/firstGet/id?id=xxx這樣,我們順應(yīng)潮流,按照流行的方式來,當(dāng)然,正是項(xiàng)目肯定不能取 firstGet 這樣的名字,這里為了演示,不用太嚴(yán)謹(jǐn)。
controller需要處理這個(gè),DemoController 代碼修改后如下:
package com.springstart.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class DemoController {
@RequestMapping(value="/hello",method=RequestMethod.GET)
public String myFirstController(){
System.out.println("some one call MyFirstController");
return "hello";
}
@ResponseBody
@RequestMapping(value="/firstGet/{id}",method=RequestMethod.GET)
public String myFirstGet(@PathVariable("id") String id){
System.out.println("from page id:"+id);
return "Right "+id;
}
}
在新的方法上,多了一個(gè)注解 @ResponseBody 這個(gè)是注解的作用是把返回值寫入 HTTP response body 中,便于ajax接收,這也是使用ajax發(fā)送請(qǐng)求接收數(shù)據(jù)的常規(guī)方式。
好了,代碼完成了,加載到tomcat中,跑起來試試。
在瀏覽器中,輸入
http://localhost:8080/springstart/hello
將會(huì)把hello.jsp這個(gè)頁面展示給我們

感覺不對(duì)呢,我們寫的css明明是 flex-column,沒有生效呢
在輸入框中輸入一個(gè)數(shù)字,然后點(diǎn) Get,沒有反應(yīng)
這個(gè)時(shí)候,需要進(jìn)行頁面調(diào)試了,在Chrome或者Firefox中按F12(IE不怎么用不知道),調(diào)出調(diào)試頁面,在console一欄可以看到報(bào)錯(cuò)了

沒找到j(luò)query,css,js文件
這個(gè)就是涉及一個(gè)問題,我們?cè)趙eb.xml中對(duì)
DispatcherServlet設(shè)置的攔截規(guī)則是/,表示攔截一切請(qǐng)求,那么對(duì)靜態(tài)資源的請(qǐng)求,也會(huì)被攔截,這樣就找不到對(duì)應(yīng)的controller來處理,從而報(bào)了404找不到的錯(cuò)誤。對(duì)于這個(gè)問題,比較簡(jiǎn)潔的解決辦法有兩個(gè)
1.在resources/config/mymvc.xml中添加一個(gè)配置
<mvc:default-servlet-handler />
這句話的內(nèi)在意思比較復(fù)雜,完全可以寫一篇文章來說明,需要深入了解的自行百度,就這樣配置后,就可以訪問到靜態(tài)資源了。
2.在resources/config/mymvc.xml中添加一個(gè)配置
<mvc:resources location="/resources/" mapping="/resources/**"></mvc:resources>
這個(gè)配置直接定位到resources,resources下面的文件都被注冊(cè)為資源,這樣servlet就會(huì)處理了。這個(gè)配置方式定位精確,resources之外的靜態(tài)資源,依然不能訪問。
上面兩個(gè)方法都有效,以實(shí)際需求為準(zhǔn)。
加上這個(gè)配置之后,重新啟動(dòng)tomcat,依然訪問
http://localhost:8080/springstart/hello
結(jié)果。。。訪問不了了。。。
因?yàn)樵黾恿松厦娴呐渲煤?,默認(rèn)加載的來處理注解@RequestMapping的handler就沒有了,這樣就無法處理這個(gè)注解,也就無法將http請(qǐng)求URI對(duì)應(yīng)到我們的controller上面去
需要增加一個(gè)注解
<mvc:annotation-driven />
啟用對(duì) @RequestMapping的處理,這樣就可以了,而這個(gè)配置,一般在spring mvc項(xiàng)目中,都是需要的。
目前到這里,mymvc.xml的內(nèi)容如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<context:component-scan base-package="com.springstart.*"></context:component-scan>
<mvc:annotation-driven />
<mvc:default-servlet-handler />
<!-- <mvc:resources location="/resources/" mapping="/resources/**"></mvc:resources> -->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/" />
<property name="suffix" value=".jsp" />
</bean>
</beans>
這樣,啟動(dòng)tomcat,就可以訪問到hello.jsp了

設(shè)定的flex樣式,也生效了,按f12,沒有報(bào)錯(cuò)。
在輸入框輸入字符串,點(diǎn)擊 Get,輸入框會(huì)回顯Right加上輸入的字符串。
最基本的一個(gè)交互功能完成。
前面我們寫的ajax里面有一個(gè)
type:'GET',
表示我們這個(gè)請(qǐng)求是一個(gè)get請(qǐng)求
在controller中,我們對(duì)應(yīng)的處理方法有注解method=RequestMethod.GET,就是處理GET的請(qǐng)求。
關(guān)于請(qǐng)求的類型,大致常規(guī)的有 GET POST PUT DELETE,還有一些其他的,常規(guī)的開發(fā)過程很難用到,暫時(shí)不談。
一般說來
GET 表明根據(jù)請(qǐng)求鏈接,從服務(wù)器獲取一定的信息
DELETE 表明刪除一定信息
POST 和PUT不好區(qū)分,都是給服務(wù)端發(fā)送信息過去,服務(wù)端的處理方式有一些差異。
POST 每次給過來的信息都會(huì)存起來,POST兩次,就存兩條記錄
PUT 每次給過來的信息以更新方式存起來,不管執(zhí)行多少次,只影響一條記錄。
這里就要引入一個(gè)概念 冪等,在http請(qǐng)求這一塊, 冪等表達(dá)的就是同一個(gè)請(qǐng)求,不管執(zhí)行多少次,對(duì)服務(wù)器的影響都是相同的,或者指一次和多次請(qǐng)求某一個(gè)資源應(yīng)該具有同樣的結(jié)果。
舉例來說
GET ,get一個(gè)name=Jack的人的id,只要沒有人修改數(shù)據(jù)庫,不管我們執(zhí)行多少次,返回的id都是一樣的,這是 冪等
DELETE,delete name=Jack,執(zhí)行1次或多次,數(shù)據(jù)庫里這條記錄都會(huì)被刪除,這是 冪等
PUT ,put表示更新,將name=Jack的年齡變更為20歲,不管執(zhí)行多少次,數(shù)據(jù)庫里這個(gè)人的年齡都會(huì)變成20,這是 冪等
POST,執(zhí)行1次后數(shù)據(jù)庫多一條記錄,執(zhí)行2次后,數(shù)據(jù)庫多兩條記錄,這個(gè)不是冪等
好了,這些都是理論和常規(guī)用法。你當(dāng)然也可以用get達(dá)到post的效果,這就非主流啦。
另外,頁面開發(fā)這一塊還涉及到瀏覽器版本問題,有些舊版本的瀏覽器不支持除GET和POST以外的方法,這一點(diǎn)在實(shí)際項(xiàng)目中可能需要考慮。
我們這里增加一個(gè)POST方法的演示,跟get方法很類似,只是數(shù)據(jù)不放在請(qǐng)求鏈接里。
首先在jsp頁面增加一個(gè)post按鈕
<div class="mydiv">
<input id="myInput"></input>
<button class="mybutton" id="getButton">Get</button>
<button class="mybutton" id="POSTButton">POST</button>
</div>
在js中,增加對(duì)post按鈕的處理
$("#POSTButton").click(function(){
let id = $("#myInput").val();
$.ajax({
url:basePath+"/firstPost",
data:id,
type:'POST',
dataType:'text',
contentType:'application/json',
success:function(result){
$("#myInput").val(result);
}
})
});
在controller中增加一個(gè)處理這個(gè)post請(qǐng)求的方法
@ResponseBody
@RequestMapping(value="/firstPost",method=RequestMethod.POST)
public String myFirstPost(@RequestBody String msg){
System.out.println("from page msg:"+msg);
return "Good "+msg;
}
這里我們?cè)趨?shù)體重增加了一個(gè) @RequestBody注解,要獲取POST過來的數(shù)據(jù),同時(shí)類型是 application/json,就可以用這個(gè)注解來獲取,我們把傳過來的字符串寫到msg里,很方便。
好了,基本的交互我們完成了,下一章會(huì)對(duì)post和get進(jìn)行一個(gè)詳細(xì)的講解。
本章代碼上傳至 sprintStart github springStart_basic_2,請(qǐng)自行下載。