这篇博客我们主要想介绍的是 jQuery
跨域、分页以及 jQuery
的插件机制,掌握了上述的三个知识点,我们就能够对 jQuery
的使用以及 MySQL
数据库分页有更好的掌握,这样我们也就有了更多的技能用来解决问题,解决方法多了问题也就简单了,因此还是要努力学习更多的知识,掌握了技能最基本的使用以及原理之后,我们也能去学习更多深入的知识,这样的学习就能形成良好的循环。
1.跨域
这里我们就来介绍关于跨域的一些知识了,主要是想说明跨域是什么,如何解决跨域以及跨域的原理是什么,首先来看看什么是跨域。
1.1 跨域是什么
首先我们要先知道,跨域到底是什么?其实跨域指的就是部署在不同域中的项目需要相互进行访问,那怎样才能算是不同的域呢?就是当协议、域名和端口号这三者中任意一个不相同的时候,就是不同的域了,一般情况下,为了安全,不同域中的资源是不允许相互访问的,这个我们可以进行演示一下。
想要演示跨域的情况的话,我们可以在 Eclipse
配置两个 Tomcat
服务器,比如说一个 Tomcat7
,然后另外一个 Tomcat6
,如果我们在部署到 Tomcat6
中的项目访问 Tomcat7
中部署项目的资源时,我们就能看到跨域的情况了,这里我们在 Tomcat7
中部署的就是之前使用过的 jqueryAjax
项目,而在 Tomcat6
中部署的则是我们这次新创建的 jqueryCrossDomain
项目。
在 Eclipse
中配置好 Tomcat6
之后,如果在启动 Tomcat7
之后直接启动 Tomcat6
的话,就会发现会报错,这是因为 Tomcat6
和 Tomcat7
都是默认的配置,所以端口号配置的都是一样的,一起启动的话就会报端口已被占用的错误,因此我们就需要修改 Tomcat6
配置的端口号,修改起来也非常简单,因为我们之前已经在 Eclipse
中配置好了 Tomcat6
,如果还不会配置的,可以先看一下我之前关于 Tomcat
服务器的文章,这里我们在 Eclipse
中的 Server
视图是可以看到我们配置的 Tomcat
服务器的,我们需要修改的话就可以双击对应的服务器,然后就能看到一些属性的设置了,我们现在需要修改的是端口号,就可以选择右侧的 Ports
这个选项了,点击之后可以看到有 3
个端口的设定了,默认的值为 8005
,8080
和 8009
,这里我们直接修改为 9005
,9080
和 9009
这三个值就好了,然后一起启动两个 Tomcat
服务器就没问题了。需要注意的一点就是,现在 Tomcat7
中设置的端口号为 8080
,而 Tomcat6
中设置的端口号则为 9080
。
为了看到跨域的情况,我们可以在 jqueryCrossDomain
工程中新建一个 html
文件,然后在其中写上一段 JavaScript
代码。
<script type="text/javascript">
$.post("http://localhost:8080/jqueryAjax/demo6.html", function() {
});
</script>
代码的意思就是,当我们使用浏览器打开该 html
文件时,这个页面就会向 jqueryAjax
工程的 demo6.html
页面发送请求,因为 demo6.html
是在另外一个工程中,因此这个请求就是跨域请求了,那页面中会是什么效果呢?其实页面中是没有内容展示的,打开浏览器的控制台,我们就能看到相关提示信息了,也就是浏览器是禁止跨域访问操作的。
1.2 跨域解决方案
在说如何解决跨域访问的限制之前,我们需要先了解一下为什么需要跨域访问,举个例子来进行说明,在我们之前的系统中,可能一个项目会包含多个模块,比如用户管理模块,订单管理模块等,每个模块可能都会有自己的前端页面进行信息的展示,当然有时候一个模块的页面也会需要访问另一个模块,因为都是在同一个项目当中,所以都是没有问题的,但是随着项目规模的逐步扩大,可能就需要将原先的模块抽离出来单独作为一个个的项目,这时候原来一个模块的页面再去访问别的模块就变成了跨域操作,但是这种访问又是必须的,所以我们需要解决浏览器的跨域访问限制。
解决跨域一共有下面 3
种方案,我们下面会详细进行说明。
1.代理方案;
2.jsonp模式;
3.XHR2。
我们先说代理模式,代理模式其实就是不在前端页面中直接访问别的域中的资源,而是像往常一样,还是使用前端页面访问同一项目中的后端代码,比如 Servlet
,然后再由后端的 Servlet
去访问别的域中的资源,最后交由前端进行显示,其实这种方式就相当于是将前端跨域转换为了后端跨域。
再看 jsonp
模式,其实是 JSON with Padding
的缩写,即为 json
的一种使用模式,这种方式是可以进行跨域访问的,一般来说,浏览器基于同源策略,是不允许跨域访问的,但是 HTML
的 <script>
元素是一个例外,而 jsonp
模式就是根据 <script>
元素的开放策略来实现跨域的,我们下面也可以进行演示,这种方式当然就是我们要介绍的重点了。
XHR2
这种方式是 XMLHttpRequest Level 2
的缩写,它是由 HTML5
提供的方法,一般用于在移动开发中。
下面我们就简单地演示一下 jsonp
模式这种方式,其实它是基于 <script>
标签的开放策略而来的,因此我们就可以验证一下 <script>
的使用。
需要做的就是,我们先在 jqueryAjax
工程的 WebContent
目录下面新建一个 js
文件夹,然后再到其中新建一个 JavaScript
文件 my.js
,里面的内容就为:
alert("I am fine");
然后再到 jqueryCrossDomain
工程中新建一个 HMTL
页面,里面最重要的内容就是这个 script
标签了。
<script type="text/javascript" src="http://localhost:8080/jqueryAjax/js/my.js">
然后我们就可以启动两个项目,然后访问 jqueryCrossDomain
项目中这个新建的页面,这时候我们就可以在浏览器中看到弹出的字符串了,为了做对比,我们还可以使用另外一种方式来访问 jqueryAjax
项目当中的 js
文件,那便是:
<script type="text/javascript">
$.post("http://localhost:8080/jqueryAjax/js/my.js", function() {
});
</script>
使用这种方式,我们是看不到字符的打印的,而且打开浏览器的控制台,也会看到相关禁止跨域访问的提示信息,这也就可以证实,使用 <script>
标签是能够实现跨域资源的访问的。
1.3 $.ajax()解决跨域问题
下面我们就来看如何使用 jQuery
解决跨域问题,其实在 jQuery
中有 3
种方式可以解决跨域问题,分别为:
$.ajax()
$.getJSON()
$.getScript()
我们先看如何使用 $.ajax()
来解决跨域问题,我们可以通过改写 jqueryAjax
工程里面的展示商品信息的例子来学习使用跨域,其实修改的重点就在于数据的传输格式要改为 jsonp
格式的,下面先看页面中的主要代码:
<script type="text/javascript">
$(function() {
$("#link").toggle(function() {
var url = "http://localhost:8080/jqueryAjax/productServlet";
$.ajax({
url: url,
type: "get",
dataType: "jsonp",
success: function(data) {
$("#content").html("");
var json = eval(data);
var tab=$("<table border='1'><tr><td>编号</td><td>名称</td><td>数量</td><td>价格</td></tr></table>");
for(var i=0;i<json.length;i++){
var obj = json[i];
var tr = $("<tr><td>"+obj.id+"</td><td>"+obj.name+"</td><td>"+obj.count+"</td><td>"+obj.price+"</td></tr>");
tab.append(tr);
}
$("#content").append(tab);
$("#content").show();
}
});
}, function() {
$("#content").hide();
});
});
</script>
</head>
<body>
<a href="javascript:void(0)" id="link">显示商品信息</a>
<div id="content"></div>
</body>
这时候我们点击页面中的显示按钮,就可以在浏览器中看到所发送的请求了,现在发送的请求为:
http://localhost:8080/jqueryAjax/productServlet?callback=jQuery183003895450973838832_1552226608487&_=1552226611490
最明显的区别就是请求中加入了一个 callback
参数,该参数对应的参数值我们先不用管,这就是使用了 jsonp
模式最大的区别了,就是会多一个 callback
参数,但是我们在页面中是没有商品信息展示的,但是上面请求确实是有数据响应回来的,那这是为什么呢?既然已经有数据响应了,为什么没有展示到页面中呢?这里就需要说一下 json
和 jsonp
数据的格式区别了:
json格式:[{key:value},{key:value}]
jsonp格式:callback(json)
jsonp
格式的数据则是需要使用请求参数中 callback
参数对应的参数值将 json
数据包起来,然后再进行返回,这样就能够正常显示了,当然这个处理是需要我们在后台代码中处理的,其实也十分简单:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 防止乱码
response.setCharacterEncoding(StandardCharsets.UTF_8.name());
String cb = request.getParameter("callback");
Product product = new Product();
product.setId(1);
product.setName("收音机");
product.setCount(10);
product.setPrice(20);
product.setProductDate(new Date());
Product tvProduct = new Product();
tvProduct.setId(2);
tvProduct.setName("电视机");
tvProduct.setCount(30);
tvProduct.setPrice(200);
tvProduct.setProductDate(new Date());
List<Product> products = new ArrayList<>();
products.add(product);
products.add(tvProduct);
String json = JSONObject.toJSONString(products);
response.getWriter().write(cb + "(" + json + ")");
}
修改的地方就是先获取得到 callback
参数对应的参数值,然后再使用该参数值将之前的 json
数据包裹起来,最后返回就好了。
当然我们现在会发现请求中 callback
参数对应的参数值似乎太长了,因为这个是随机生成的,其实我们也是可以指定的,那就是使用 jsonpCallback
参数,比如:
$.ajax({
url: url,
type: "get",
dataType: "jsonp",
jsonpCallback: "cb",
success: function(data) {
$("#content").html("");
var json = eval(data);
var tab=$("<table border='1'><tr><td>编号</td><td>名称</td><td>数量</td><td>价格</td></tr></table>");
for(var i=0;i<json.length;i++){
var obj = json[i];
var tr = $("<tr><td>"+obj.id+"</td><td>"+obj.name+"</td><td>"+obj.count+"</td><td>"+obj.price+"</td></tr>");
tab.append(tr);
}
$("#content").append(tab);
$("#content").show();
}
});
这样的话,我们在发送请求时请求中 callback
参数对应的参数值就是 cb
了,确实可以让请求的 url
简洁不少。
1.4 jsonp解决跨域原理
上面我们已经使用 $.ajax()
方法实现了跨域资源的访问,那它实现的原理是什么呢?我们已经知道 $.ajax()
是基于 jsonp
模式实现跨域的,那我们就来看看 jsonp
模式实现跨域的原理是怎样的。
jsonp
模式实现跨域主要是基于 script
标签的开放策略,在上面的内容中我们就知道使用 script
是可以访问跨域资源的,那我们在这里就可以写一个方法,就是用于创建 script
标签元素的,然后为新创建的标签元素设定各种属性,例如 type
和 src
属性,当然为了灵活,这个 src
属性我们可以设置为传入的,然后再将该创建的元素标签添加到页面中,这个新建的标签元素就可以执行了,也就可以访问得到跨域的资源了,这里还有需要说明的一点就是,因为跨域请求的 url
中都会有 callback
参数,因此我们需要设定一个与该 callback
参数对应参数值名称相同的回调函数,这样我们就可以在回调函数中处理响应回来的数据了。完整的代码如下:
<script type="text/javascript">
// 原理就是我们使用js代码在页面中添加一个<script>标签
// 定义函数,作用为添加script标签
function addScript(src){
// 创建一个script标签
var script = document.createElement("script");
// 设置script标签属性
script.setAttribute("type","text/javascript");
script.src = src;
// 将script标签添加到页面中
document.body.appendChild(script);
}
$(function(){
addScript("http://localhost:8080/jqueryAjax/productServlet?callback=cb")
});
// 设置回调函数
function cb(data){
var jsonObj = eval(data);
alert(jsonObj[0].name)
}
</script>
这就是 jsonp
模式实现跨域的原理了,当然上面的代码只是该原理的最简单实现了,jQuery
提供的几个方法实现中代码肯定是更加完善的,但是就是因为上面的代码简单,所以我们就可以通过它更容易地掌握相应的原理。
1.5 $.getJSON()解决跨域问题
我们下面再来介绍使用 $.getJSON()
方法来解决跨域问题,其实使用 $.getJSON()
方法就相当于是使用 $.ajax()
解决跨域问题的简化,因此使用起来是更加简单的,下面先看代码:
var url = "http://localhost:8080/jqueryAjax/productServlet?callback=?";
$.getJSON(url, function(data) {
$("#content").html("");
var json = eval(data);
var tab=$("<table border='1'><tr><td>编号</td><td>名称</td><td>数量</td><td>价格</td></tr></table>");
for(var i=0;i<json.length;i++){
var obj = json[i];
var tr = $("<tr><td>"+obj.id+"</td><td>"+obj.name+"</td><td>"+obj.count+"</td><td>"+obj.price+"</td></tr>");
tab.append(tr);
}
$("#content").append(tab);
$("#content").show();
});
是不是很简单,就跟我们之前使用 $.post()
方法是一样的,不过有一点需要特别注意的就是,请求的 url
中一定要带 callback
参数,而且该参数的参数值一定要设置为 ?
,在真正发送请求时,这个 ?
号是会被替换的,我们可以看一下真实发送请求的 url
:
http://localhost:8080/jqueryAjax/productServlet?callback=jQuery18307803852774240552_1552230739083&_=1552230742301
1.6 $.getScript()解决跨域问题
jQuery
中还有最后一个用于解决跨域问题的方法没有介绍了,那就是 $.getScript()
了,该方法主要是用于载入跨域的 js
文件,我们可以使用该方法来替换使用 script
标签访问跨域的 js
文件的,使用 script
标签时,代码应该为:
<script type="text/javascript" src="http://localhost:8080/jqueryAjax/js/my.js">
在使用 $.getScript()
方法的时候,就可以这样使用了。
$.getScript("http://localhost:8080/jqueryAjax/js/my.js",function(){
});
2.分页
下面我们开始介绍一个使用非常频繁的技术,那就是分页了,当我们使用搜索引擎时,输入一个关键字,可能会有很多条信息返回,这时候页面中的显示就是分页显示的,因为一页全部显示的话,数据量太大可能会导致显示非常不友好,而采用分页的话,则会使页面显示更加友好,查找需要的消息也更加好定位。
2.1 分页的分类
分页的实现的话,可以分为两类:
1.物理分页
2.逻辑分页
物理分页是一次查询一个页面容量的数据进行显示,比如一页显示 10
条数据,那我们每次查询数据库时就会查对应页面的 10
条记录,当然不同的数据库实现起来会不一样,MySQL
数据库是使用 limit
关键字实现的,而 Oracle
则是使用 rownum
关键字来实现的;逻辑分页则是一次将数据全部查询出来,然后使用游标查看对应页面的数据,Java
中对应的接口则是 ResultSet
,即查询数据库所得的结果集。
2.2 分页的原理
要想了解分页的原理,我们可以从前端发送请求,然后后台接受请求并进行处理这个流程来说,首先,要想分页显示数据的话,我们需要在前端将当前页码和每页显示条数传到后台,也就是告诉后端应该返回哪一页的数据,而后端在处理请求之后,则应该将当前页的数据返回,而除了当前页的数据之外,在前端进行展示时,我们还需要知道总页数,这样的话我们就还需要查出总的记录条数,然后算出总页数来,这就是进行分页展示请求的整个流程了。
而在这个请求的过程中,我们需要一些必备的要素,比如当前页数,每页显示条数,总记录条数,总页数以及当前页的数据。
在 MySQL
数据库中,我们分页则是使用的 limit
关键字,使用样式则是:
select * from 表名 limit num1,num2
num1
表示的则是从第几行开始查询,默认是从 0
行开始的,而 num2
则是表示要查询多少条数据,因此计算 num1
时,我们则可以使用 (页码-1)*每页条数
进行计算,因此可以抽象为以下公式:
select * from 表名 limit (页码-1)*每页条数,每页显示条数
3.jQuery插件机制
jQuery
插件其实就是对 jQuery
功能的增强,让其中的 jQuery
对象拥有更多的方法,我们在介绍 jQuery
插件之前,首先先介绍一下 serialize()
和 serializeArray()
方法。
3.1 serialize()和serializeArray()方法
首先来看一下这两个方法的作用:
serialize():将表单元素中的内容序列化为字符串
serializeArray():将表单元素中的内容序列化为json数据
在平时的开发中,当页面中有一个表单时,我们需要异步提交这个表单里面的数据时,应该怎么办呢?最直接的办法可能是获取到每个输入框中输入的值,然后再拼接到请求体中进行发送,但是当表单中元素比较多时,这样操作就会十分麻烦了,那有没有什么简便的方法呢?是有的,那就是 serialize()
方法了,首先先假设页面中有如下表单:
<form action="">
用户名:<input type="text" name="userName" value="kobe"/><br>
密码:<input type="password" name="password" value="lakers"/>
</form>
那我们就可以使用如下代码获取表单中元素输入的值了:
$(function(){
var key = $("form").serialize();
alert(key);
});
得到的结果就是 userName=kobe&password=lakers
了,也是我们在发送请求时所需要的格式了,所以就可以满足我们的要求了,那使用 serializeArray()
方法又会得到什么结果呢?可以使用如下的代码:
$(function(){
var key = $("form").serializeArray();
console.info(key);
});
得到的结果如下:
[{name: "userName", value: "kobe"},{name: "password", value: "lakers"}]
很明显这种 json
格式不是我们所需要的,我们所需要的 json
格式应该是这样的:
{"userName": "kobe","password": "lakers"}
所以我们就需要将现在得到格式的 json
数据转换为我们需要格式的,这个我们在下面进行介绍。
3.2 插件机制
下面开始介绍 jQuery
的插件机制,jQuery
的插件机制有两种模式,一种是对 jQuery
对象本身的扩展,另一种则是对 jQuery
选中数据集对象的扩展,分别如下:
jQuery.extend(object)
jQuery.fn.extend(object)
说明一下,使用 jQuery.extend(object)
方法进行的扩展,则是对 jQuery
对象本身的扩展,扩展之后的使用方式则是和 $.post()
方法使用类似的;而使用 jQuery.fn.extend(object)
方法进行的扩展,则是对 jQuery
选中数据集对象的扩展,扩展之后的使用方式则是和 $("#form").serialize()
方法使用类似的。
下面我们使用具体的例子来对这两种扩展方式进行说明,首先看 jQuery.extend(object)
方式的:
$.extend({
maxValue:function(a,b){
return a>b?a:b;
},
minValue:function(a,b){
return a>b?b:a;
}
});
$(function(){
alert($.maxValue(10,20));
alert($.minValue(10,20));
});
上面的代码就相当于是为 jQuery
对象本身扩展了两个数中求较大值和较小值的方法了,而在下面的代码也可以看出调用扩展的方法也是十分简单的。
现在再看使用 jQuery.fn.extend(object)
方式进行扩展的,我们就扩展将表单元素中的内容序列号为 json
数据,之前使用 serializeArray()
方法得到的虽然也是 json
格式的数据,但是它的格式并不是我们想要的,因此我们需要扩展一个方法,将目前使用 serializeArray()
方法得到的 json
数据转换成我们需要的:
$.fn.extend({
serializeJson:function(){
var json = {};
var msg = this.serializeArray();
$(msg).each(function(){
json[this.name] = this.value;
});
return json;
}
});
这样的话,就得到我们所需要格式的数据了。
{userName: "kobe", password: "lakers"}
但是需要注意的一点就是,目前表单元素中只有两个输入框,当有别的表单元素,比如多选框时,上面的代码就不能奏效了,因此我们还需要优化上面的代码,首先表单元素可能为:
<form action="">
用户名:<input type="text" name="userName" value="kobe"/><br>
密码:<input type="password" name="password" value="lakers"/><br>
爱好:<input type="checkbox" name="hobby" value="eat" checked="checked">吃
<input type="checkbox" name="hobby" value="drink" checked="checked">喝
<input type="checkbox" name="hobby" value="play" checked="checked">玩
</form>
如果还是使用上面的代码的话,我们得到的结果为:
{userName: "kobe", password: "lakers", hobby: "play"}
这样的肯定就是不符合要求的了,因为爱好那三个选择框是都选择了的,但是最后获取到的值却只有最后一个,显然是不对的,我们想要的格式应该是这样的:
{userName: "kobe", password: "lakers", hobby: ["eat", "drink", "play"]}
那我们就应该优化之前的代码了,优化后的代码如下:
$.fn.extend({
serializeJson:function(){
var json = {};
var msg = this.serializeArray();
$(msg).each(function(){
if(json[this.name]){
// json中对应的键已经存在
if(json[this.name].push){
// json中相关键对应的值为数组
json[this.name].push(this.value);
}else{
// json中相关键对应的值不是数组
json[this.name] = [json[this.name]];
json[this.name].push(this.value);
}
}else{
// json中对应的键不存在
json[this.name] = this.value;
}
});
return json;
}
});
这样我们就能得到我们所期望格式的数据了,以后我们再想获得表单元素序列化后的 json
数据,就可以直接使用这个 serializeJson()
方法了,使用方法为:
var json = $("form").serializeJson();
4.总结
关于 jQuery
的知识在这里就总结完了,知识有很多,学习的时候重点还是在于多使用,用的多了自然也就熟悉了,其实写博客整理知识的目的也十分简单,就是当自己需要用到某些知识点,而又记得不是很清楚时,可以随时回来进行查询,整理一遍的话自己的印象也会更加深刻,因此还是应该坚持下去,越坚持越有力量。