(六)利用ajax和后台交互
这一小节,我们主要实现页面和后台简单的数据交互,初步掌握这个交互流程
页面主要采用ajax技术往后台发数据,后台就使用上一节我们写好的工程代码(五)最简单的springMVC后台程序
关于jquery,ajax这些基础理论,这里就不多讲了,简单使用的话,没什么难度,有需求的请自行百度。
首先,为了这一节的讲解,我们需要新建一些文件和目录。
1.引入jquery*
这个简单,只需要到jquery官网去把jquery.js文件下回来,引入代码即可。这里我们在 src/main/webapp 下创建一个resources文件夹,在这个文件夹下边,创建一个jquery文件夹,把从官网下回来的jquery.js拷贝到这里面,我这里用的是 jqery-3.3.1.js
2.创建一个hello目录,在里面创建一个hello.js和hello.css两个文件,暂时保持空文件,后面再来添加内容。
3.在WEB-INF下面创建一个pages文件夹,然后在这个文件夹里,创建一个hello.jsp。
创建完成后,目录结构如下:
这里我们为了演示,做了一个比较完整的结构,hello.jsp是我们需要访问的页面,hello.js提供脚本支持,hello.css提供样式支持,常规工程也基本就是这样了,可能就是目录结构的差异
好了,现在我们在填写内容,具体细节暂时不讨论,jsp相关的知识点请自行百度学习。
首先,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>
这个页面部分代码是自动生成的时候留下的,先不管它,就这样写满足我们的需求即可
其中的
<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
然后,我们在页面上画了一个输入框和一个按钮
<div class="mydiv">
<input id="myInput"></input>
<button class="mybutton" id="getButton">Get</button>
</div>
后面的学习和测试,都是围绕这个输入框和按钮来进行。
然后,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);
}
})
});
});
简单的,典型的,基于jquery的一个js代码。
点击button,向后端服务器发送一个get请求,然后将后端的返回值,填写到输入框。
至于ajax的相关问题,请大家自行百度学习,这里写的是很简单的。
好了,然后我们在hello.css中加入内容
.mydiv{
display:flex;
flex-direction:column;
width:400px;
height:600px;
}
.mybutton{
width:100px;
}
不擅长写样式,简单的写一下,达到演示的目的即可。
好,我们的页面文件已经准备好了,现在修改一下后端代码。
在上面ajax中,我们发出去的请求是
url:basePath+"/firstGet/"+id,
在controller中要处理的uri就是 /firstGet/{id}
其中的{id}
指的就是我们从input获取到的id,这个是目前流行的restful
风格的写法,按照以前的写法已经改是/firstGet/id?id=xxx
这样,我们顺应潮流,按照流行的方式来,当然,正是项目肯定不能取 firstGet 这样的名字,这里为了演示,不用太严谨。
controller需要处理这个,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;
}
}
在新的方法上,多了一个注解 @ResponseBody 这个是注解的作用是把返回值写入 HTTP response body 中,便于ajax接收,这也是使用ajax发送请求接收数据的常规方式。
好了,代码完成了,加载到tomcat中,跑起来试试。
在浏览器中,输入
http://localhost:8080/springstart/hello
将会把hello.jsp这个页面展示给我们
感觉不对呢,我们写的css明明是 flex-column,没有生效呢
在输入框中输入一个数字,然后点 Get,没有反应
这个时候,需要进行页面调试了,在Chrome或者Firefox中按F12(IE不怎么用不知道),调出调试页面,在console一栏可以看到报错了
没找到jquery,css,js文件
这个就是涉及一个问题,我们在web.xml中对
DispatcherServlet
设置的拦截规则是/
,表示拦截一切请求,那么对静态资源的请求,也会被拦截,这样就找不到对应的controller来处理,从而报了404找不到的错误。对于这个问题,比较简洁的解决办法有两个
1.在resources/config/mymvc.xml中添加一个配置
<mvc:default-servlet-handler />
这句话的内在意思比较复杂,完全可以写一篇文章来说明,需要深入了解的自行百度,就这样配置后,就可以访问到静态资源了。
2.在resources/config/mymvc.xml中添加一个配置
<mvc:resources location="/resources/" mapping="/resources/**"></mvc:resources>
这个配置直接定位到resources,resources下面的文件都被注册为资源,这样servlet就会处理了。这个配置方式定位精确,resources之外的静态资源,依然不能访问。
上面两个方法都有效,以实际需求为准。
加上这个配置之后,重新启动tomcat,依然访问
http://localhost:8080/springstart/hello
结果。。。访问不了了。。。
因为增加了上面的配置后,默认加载的来处理注解@RequestMapping
的handler就没有了,这样就无法处理这个注解,也就无法将http请求URI对应到我们的controller上面去
需要增加一个注解
<mvc:annotation-driven />
启用对 @RequestMapping
的处理,这样就可以了,而这个配置,一般在spring mvc项目中,都是需要的。
目前到这里,mymvc.xml的内容如下:
<?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>
这样,启动tomcat,就可以访问到hello.jsp了
设定的flex样式,也生效了,按f12,没有报错。
在输入框输入字符串,点击 Get,输入框会回显Right加上输入的字符串。
最基本的一个交互功能完成。
前面我们写的ajax里面有一个
type:'GET',
表示我们这个请求是一个get请求
在controller中,我们对应的处理方法有注解method=RequestMethod.GET
,就是处理GET的请求。
关于请求的类型,大致常规的有 GET
POST
PUT
DELETE
,还有一些其他的,常规的开发过程很难用到,暂时不谈。
一般说来
GET
表明根据请求链接,从服务器获取一定的信息
DELETE
表明删除一定信息
POST
和PUT
不好区分,都是给服务端发送信息过去,服务端的处理方式有一些差异。
POST
每次给过来的信息都会存起来,POST
两次,就存两条记录
PUT
每次给过来的信息以更新方式存起来,不管执行多少次,只影响一条记录。
这里就要引入一个概念 幂等
,在http请求这一块, 幂等
表达的就是同一个请求,不管执行多少次,对服务器的影响都是相同的,或者指一次和多次请求某一个资源应该具有同样的结果。
举例来说
GET
,get一个name=Jack的人的id,只要没有人修改数据库,不管我们执行多少次,返回的id都是一样的,这是 幂等
DELETE
,delete name=Jack,执行1次或多次,数据库里这条记录都会被删除,这是 幂等
PUT
,put表示更新,将name=Jack的年龄变更为20岁,不管执行多少次,数据库里这个人的年龄都会变成20,这是 幂等
POST
,执行1次后数据库多一条记录,执行2次后,数据库多两条记录,这个不是幂等
好了,这些都是理论和常规用法。你当然也可以用get达到post的效果,这就非主流啦。
另外,页面开发这一块还涉及到浏览器版本问题,有些旧版本的浏览器不支持除GET
和POST
以外的方法,这一点在实际项目中可能需要考虑。
我们这里增加一个POST方法的演示,跟get方法很类似,只是数据不放在请求链接里。
首先在jsp页面增加一个post按钮
<div class="mydiv">
<input id="myInput"></input>
<button class="mybutton" id="getButton">Get</button>
<button class="mybutton" id="POSTButton">POST</button>
</div>
在js中,增加对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中增加一个处理这个post请求的方法
@ResponseBody
@RequestMapping(value="/firstPost",method=RequestMethod.POST)
public String myFirstPost(@RequestBody String msg){
System.out.println("from page msg:"+msg);
return "Good "+msg;
}
这里我们在参数体重增加了一个 @RequestBody
注解,要获取POST过来的数据,同时类型是 application/json
,就可以用这个注解来获取,我们把传过来的字符串写到msg里,很方便。
好了,基本的交互我们完成了,下一章会对post和get进行一个详细的讲解。
本章代码上传至 sprintStart github springStart_basic_2,请自行下载。