开头那些话
目的
首先鄙人是一名信管人,本科学习的是SSH框架后台java开发(学得一塌糊涂)。平时开发Web项目都是用jsp做页面直出,然后各种form表单提交,action跳转;导致一旦需要更新数据就要刷新页面,哪怕是一小部分地方;很是麻烦,也影响用户体验。我就一直想用一种技术来解决这个问题。所以私底下折腾了一阵子,看了看ajax,发现struts2完美支持ajax,所以写下这篇文章,以供和我有过一样故事的人参考!(ps:平时私底下班上有同学问过我,所以干脆整理出来,做做参考!)
事先准备
这篇文章主要是讲struts2环境下的ajax应用。所以你事先需要在你的Web项目里面导入struts2所有相关jar包,这个学过的人都知道,这里就不多赘述;除此之外还需导入一个额外的jar包,用来支持json数据格式;jar包我会以附件形式发出来。基本上做完这些就可以开始了!
具体实现
具体我会讲两个例子,一个用来讲述ajax请求的具体流程,另一个就与实际应用有关了——根据参数返回对应的数据。
页面代码(HTML+CSS+JS)
先贴代码1(为了方便,我就没有贴jsp代码,其实也就<head>
标签一些配置项而已,读者可以自己复制)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>XHR</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<style>
form, .box {
margin: 50px;
padding: 20px;
}
form div {
margin: 20px 0;
}
.box {
background-color: rgba(0, 0, 0, 0.2);
height: 40px;
width: 300px;
}
</style>
</head>
<body>
<form id="form">
<div><label for="nick">昵称:</label> <input value="jero" name="nick" id="nick" type="text" required></div>
<div><label for="love">爱好:</label> <input value="coding" name="love" id="love" type="text" required></div>
<div>
<button type="button" name="get">Get 提交</button>
<button type="button" name="post">Post 提交</button>
</div>
</form>
<p id="box" class="box"></p>
<script>
var byId = (id) => document.getElementById(id); // ES6 箭头函数
var form = byId('form');
var box = byId('box');
/**
* 表单的数据收集起来
*/
function getData(type) {
var result = [];
var isFill = false;
// 都是文本框的 name
['nick', 'love'].forEach((fieldName) => {
var v = form[fieldName].value;
var obj = {};
if (v) {
obj[fieldName] = v;
result.push(obj);
isFill = true;
} else {
isFill = false;
}
});
if (!isFill) { // 没填的话要返回没填的结果 false
return false;
}
result = JSON.stringify(result);
result = "info" + '=' + encodeURIComponent(result)
return result;
}
function request(type, callback) {
var data = getData(type);
if (!data) { // 没填的话直接警告
return alert("完成表单!");
}
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
callback(JSON.parse(xhr.responseText), xhr);
} else {
console.log(xhr.status);
}
}
xhr.open(type, './xhr' + (type === 'get' ? `?${data}` : '')); // get 的参数直接拼在 url 的末尾
// 模拟 post 请求,必须设置个请求头
if (type === 'post') {
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')//可以自己根据实际情况改变取值
}
xhr.send(type === 'get' ? null : data);
}
/**
* 绑定事件抽象下
*/
function click(btn, callback) {
btn.addEventListener('click', () => {
request(btn.name, (data) => {
var data = JSON.parse(data);
box.innerHTML = `success by ${data[0].type} method!<br>
${data[0].infoStr}`;
console.log(data);
});
});
}
// 绑定事件,代码可以从这里看
click(form.get);
click(form.post)
</script>
</body>
</html>
页面运行效果
上面代码中有几处在这说一下。1.encodeURIComponent()
这个函数是用来把变量转换成url地址中的字符串,避免传值时出现乱码。2.当使用var form = document.getElementById('form')
获取到form表单节点时,我们可以直接使用form.nick
或者form[nick]
来直接获取昵称输入框节点,当然前提是form表单中的元素且设置了name
属性。
然后我们来重点解读下这段代码:
function request(type, callback) {
var data = getData(type);//参数列表字符串
if (!data) { // 没填的话直接警告
return alert('完成表单!');
}
var xhr = new XMLHttpRequest();//生成XHR对象
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
callback(JSON.parse(xhr.responseText), xhr);//数据成功接收后的回调函数
} else {
console.log(xhr.status);
}
}
xhr.open(type, './xhr' + (type === 'get' ? `?${data}` : '')); // get 的参数直接拼在 url 的末尾
// 模拟 post 请求,必须设置个请求头
if (type === 'post') {
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')//可以自己根据实际情况改变取值
}
xhr.send(type === 'get' ? null : data);
}
首先,明确一点这个函数的作用就是发送ajax请求;这里我采用了原生的XHR对象来实现ajax请求,目的是让大家能够深刻理解到ajax 是怎么样一回事;总体来说发送ajax请求分为四步:
一、创建XHR对象
IE7以上以及现在主流的浏览器都支持原生的XHR对象,所以我们可以直接用var xhr = new XMLHttpRequest();
来创建XHR对象,用XHR对象所封装的一些方法来实现ajax请求。至于IE7以下的毒瘤,我是绝对不会做考虑的!如果你硬要做IE7以下的兼容可以参考js红皮书ajax章节。是通过ActiveX对象来创建的!
二、绑定监听函数
xhr.onreadystatechange
实现监听请求响应过程所处的的阶段。主要是通过XHR对象的readyState
属性;属性的取值为:
0-未初始化(未调用open()方法)
1-启动(调用open()方法,未调用send()方法)
2-发送(调用send()方法,但没有得到响应、没有接收到数据)
3-接收(接收到部分数据)
4-完成(得到全部响应数据)
当属性值每发生一次变化,就触发一次readystatechange事件。所以我们可以通过这个属性的值来判断我们所需的数据是否准备就绪。以便及时地将我们所请求的数据渲染到页面中去。
而xhr.status
返回的则是HTTP请求的状态码( 学过网络的同学应该都了解),这就方便我们检测请求是否成功,亦或者判断请求失败的原因。
callback(JSON.parse(xhr.responseText), xhr);
这个则是我们接收到全部数据时所要执行的回调函数,主要用来处理接收的数据,进行页面渲染。大家在实际应用时可以照写,重点是绑定函数中该回调函数的编写,大家则要根据实际需要进行编写。
三、启动请求
xhr.open(type, './xhr' + (type === 'get' ?
?${data}: ''));
第一个参数主要设置请求是使用get方法还是post方法,(ps:最近有文章说了这两者根本没什么区别,在这里我们暂且遵循老套路),第二个则是请求的目标地址,运用了一个三目运算来区分get和post因为get方法的传参是通过将参数放到url一并发送到后台的,所以我们要进行字符串的拼接;而post是通过请求头中的Form Data传递的;如下图:
四、发送请求
xhr.send(type === 'get' ? null : data);
最后一个环节,上面说到的post传参就要在这传入,get则不用,所以在这里同样用了一个三目运算。
基本上,原生的XHR对象实现ajax请求就如上所说;是不是觉得有点复杂?那么不用慌,喜欢“偷懒”的高端程序猿已经帮我们实现了封装;没错就是当初影响世界的jQuery。话不多说,直接上代码:
$.ajax(function() {
url: 'xhr',
type: 'get',
dataType: 'json',//返回数据类型
data: {info: data},//传参
success: function(data) {
/***/
},
error: function() {
console.log('error!');
}
});
jQuery提供了很多种写法,包括更简单的$.getJSON()
;至于我为什么要推荐这种写法,大家可以理解成我很笨,但是其中的含义大家用过就明白了!(吹个小牛皮)
后台代码(action+struts.xml)
上面说了这么多,一是让大家了解原生的是怎样的一个东西,二是因为上述部分是学习后台同学没有接触过的,所以尽可能的讲清楚点;这部分,我想代码一贴出来,大家都懂了!
action
package com.testforajax.demo.action;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import org.apache.struts2.ServletActionContext;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import com.opensymphony.xwork2.ActionSupport;
public class AjaxDemo extends ActionSupport {
private String info;
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
public String execute() throws Exception {
String method = ServletActionContext.getRequest().getMethod();
HashMap<String, String> map = new HashMap<String, String>();
String name;
String love;
JSONArray json = JSONArray.fromObject(info);
name = json.getJSONObject(0).getString("nick");
love = json.getJSONObject(1).getString("love");
json.clear();
String result = name + " very love " + love;
map.put("type", method);
map.put("infoStr", result);
json.add(map);
info = json.toString();
System.out.println(this.info);
return "success";
}
}
struts.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
<!-- XHR演示 -->
<package name="xhrTest" extends="json-default, struts-default">
<action name="xhr" class="com.testforajax.demo.action.AjaxDemo">
<result type="json">
<param name="root">info</param>
</result>
</action>
<!--
<action name="newxhr" class="com.testforajax.demo.action.AjaxDemo2">
<result type="json">
<param name="root">queryId</param>
</result>
</action>
-->
</package>
</struts>
在这里只强调一点,struts2的自动打包传值,一定要保证参数名一致!即你在前台封装json数据格式时,对应的key值要和struts.xml配置文件中<param name="root">info</param>
一致,同时在action类中也要有对应的属性,以及getter和setter。
还有,在使用json数据格式时要做到传参时记得JSON.stringify()
,渲染响应数据时记得JSON.parse()
。封装时,一定要按照标准格式,后台封装的话,推荐我写的那种先用map做处理。
注:由于篇幅的原因,另一个demo我就不展示了,基本上差不多,源代码我会上传,有兴趣可以下载。不便之处还请谅解!
总结
不论你是一名前端爱好者还是一名后端爱好者,掌握了ajax你都会用一种飘飘欲仙的感觉!不管怎么说,希望这篇文章能够让处于困惑的你看到一丝光明!写的不到位或者理解有误的地方还请大牛指教!
最后贴上我的QQ吧,不懂的可以加好友,我尽力帮你!
QQ:623859363