首页 技术 正文
技术 2022年11月7日
0 收藏 980 点赞 371 浏览 51813 个字

一、AJAX示例

AJAX全称为“Asynchronous JavaScript And XML”(异步JavaScript和XML) 是指一种创建交互式网页应用的开发技术、改善用户体验,实现无刷新效果。

JavaScript学习总结(一)——延迟对象、跨域、模板引擎、弹出层、AJAX示例

1.1、优点

不需要插件支持

优秀的用户体验

提高Web程序的性能

减轻服务器和带宽的负担

1.2、缺点

浏览器对XMLHttpRequest对象的支持度不足,几乎所有浏览器现在都支持

破坏浏览器“前进”、“后退”按钮的正常功能,可以通过简单的插件弥补

对搜索引擎的支持不足

JavaScript学习总结(一)——延迟对象、跨域、模板引擎、弹出层、AJAX示例

1.3、jQuery AJAX示例

在HTML5中对原生的AJAX核心对象XMLHttpRequest进行升级,也就是XHR2,功能更加强大。

jQuery对AJAX封装的非常好,这里以简单的商品管理为示例使用jQuery完成AJAX应用。

JavaScript学习总结(一)——延迟对象、跨域、模板引擎、弹出层、AJAX示例

Product.java bean:

package com.gomall.bean;/***
* 产品
*
* @author Administrator
*
*/
public class Product {
/** 编号 */
private int id;
/** 名称 */
private String name;
/** 价格 */
private double price;
/** 图片 */
private String picture;
/** 详细 */
private String detail; @Override
public String toString() {
return "Product [id=" + id + ", name=" + name + ", price=" + price + ", picture=" + picture + ", detail="
+ detail + "]";
} public Product(int id, String name, double price, String picture) {
super();
this.id = id;
this.name = name;
this.price = price;
this.picture = picture;
} public Product(int id, String name, double price, String picture, String detail) {
super();
this.id = id;
this.name = name;
this.price = price;
this.picture = picture;
this.detail = detail;
} public int getId() {
return id;
} public void setId(int id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public double getPrice() {
return price;
} public void setPrice(double price) {
this.price = price;
} public String getPicture() {
return picture;
} public void setPicture(String picture) {
this.picture = picture;
} public String getDetail() {
return detail;
} public void setDetail(String detail) {
this.detail = detail;
}
}

IProductService.java:

package com.gomall.service;import java.util.List;import com.gomall.bean.Product;public interface IProductService {    /**获得所有*/
List<Product> getAll(); /**添加
* @return */
boolean add(Product entity); /**根据编号获得产品对象*/
Product findById(int id); /**根据编号获得产品对象
* @return */
boolean deleteById(int id);}

ProductService.java:

package com.gomall.service;import java.util.ArrayList;
import java.util.List;
import java.util.Random;import com.gomall.bean.Product;public class ProductService implements IProductService {
public static ArrayList<Product> products; static {
products = new ArrayList<>();
Random random = new Random();
for (int i = 1; i <= 10; i++) {
Product product = new Product(i, "华为Mate9MHA-AL00/4GB RAM/全网通华为超级闪充技术双后摄设计" + random.nextInt(999), random.nextDouble() * 1000,
"pic(" + i + ").jpg", "产品详细");
products.add(product);
}
} /*
* (non-Javadoc)
*
* @see com.gomall.service.IProductService#getAll()
*/
@Override
public List<Product> getAll() {
return products;
} /*
* (non-Javadoc)
*
* @see com.gomall.service.IProductService#add(com.gomall.bean.Product)
*/
@Override
public boolean add(Product entity) {
try {
entity.setId(products.size() + 1);
entity.setPicture("pic(" + entity.getId() + ").jpg"); // uploadify
// 上传图片
products.add(entity);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
} /*
* (non-Javadoc)
*
* @see com.gomall.service.IProductService#findById(int)
*/
@Override
public Product findById(int id) {
for (Product product : products) {
if (product.getId() == id) {
return product;
}
}
return null;
} /*
* (non-Javadoc)
*
* @see com.gomall.service.IProductService#deleteById(int)
*/
@Override
public boolean deleteById(int id) {
try {
Product product = findById(id);
if (product != null) {
products.remove(product);
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
}

ProductAction.java:

package com.gomall.action;import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.codehaus.jackson.map.ObjectMapper;import com.gomall.bean.Product;
import com.gomall.service.IProductService;
import com.gomall.service.ProductService;@WebServlet("/Product")
public class ProductAction extends HttpServlet {
private static final long serialVersionUID = 1L; public ProductAction() {
super();
} protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
/*模拟网络延时*/
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
String act = request.getParameter("act");
IProductService productService = new ProductService();
/**用于序列化json*/
ObjectMapper mapper = new ObjectMapper();
PrintWriter out=response.getWriter(); if (act.equals("getAll")) {
String json = mapper.writeValueAsString(productService.getAll());
out.append(json);
} else if (act.equals("area")) {
String callback=request.getParameter("callback");
out.append(callback+"('"+new Date()+"')");
} else if (act.equals("getJSONP")) {
String callback=request.getParameter("callback");
String json = mapper.writeValueAsString(productService.getAll());
out.append(callback+"("+json+")");
} else if (act.equals("getAllCORS")) {
/**向响应的头部中添加CORS信息*/
response.addHeader("Access-Control-Allow-Origin", "*");
response.addHeader("Access-Control-Allow-Methods", "GET,POST"); String json = mapper.writeValueAsString(productService.getAll());
out.append(json);
} else if(act.equals("del")){
/**向响应的头部中添加CORS信息*/
response.addHeader("Access-Control-Allow-Origin", "*");
response.addHeader("Access-Control-Allow-Methods", "GET,POST");
int id=Integer.parseInt(request.getParameter("id"));
String json = mapper.writeValueAsString(productService.deleteById(id));
out.append(json);
}
else if(act.equals("add")){
/**向响应的头部中添加CORS信息*/
response.addHeader("Access-Control-Allow-Origin", "*");
response.addHeader("Access-Control-Allow-Methods", "GET,POST");
String name=request.getParameter("name");
double price=Double.parseDouble(request.getParameter("price"));
String detail=request.getParameter("detail");
Product entity=new Product(0, name, price, "",detail);
String json = mapper.writeValueAsString(productService.add(entity));
out.append(json);
}
} protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}

客户端跨域调用:

<!DOCTYPE html>
<html> <head>
<meta charset="UTF-8">
<title>AJAX</title>
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<style type="text/css">
@CHARSET "UTF-8";
* {
margin: 0;
padding: 0;
font-family: microsoft yahei;
font-size: 14px;
} body {
padding-top: 20px;
} .main {
width: 90%;
margin: 0 auto;
border: 1px solid #777;
padding: 20px;
} .main .title {
font-size: 20px;
font-weight: normal;
border-bottom: 1px solid #ccc;
margin-bottom: 15px;
padding-bottom: 5px;
color: blue;
} .main .title span {
display: inline-block;
font-size: 20px;
background: blue;
color: #fff;
padding: 0 8px;
background: blue;
} a {
color: blue;
text-decoration: none;
} a:hover {
color: orangered;
} .tab td,
.tab,
.tab th {
border: 1px solid #777;
border-collapse: collapse;
} .tab td,
.tab th {
line-height: 26px;
height: 26px;
padding-left: 5px;
} .abtn {
display: inline-block;
height: 20px;
line-height: 20px;
background: blue;
color: #fff;
padding: 0 5px;
} .btn {
height: 20px;
line-height: 20px;
background: blue;
color: #fff;
padding: 0 8px;
border: 0;
} .abtn:hover,
.btn:hover {
background: orangered;
color: #fff;
} p {
padding: 5px 0;
} fieldset {
border: 1px solid #ccc;
padding: 5px 10px;
} fieldset legend {
margin-left: 10px;
font-size: 16px;
} .pic {
height: 30px;
width: auto;
}
#divFrom{
display: none;
}
</style>
</head> <body> <div class="main">
<h2 class="title"><span>商品管理</span></h2>
<table border="1" width="100%" class="tab" id="tabGoods">
<tr>
<th>编号</th>
<th>图片</th>
<th>商品名</th>
<th>价格</th>
<th>详细</th>
<th>操作</th>
</tr>
</table>
<p style="color: red" id="message"></p>
<p>
<a href="#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" class="abtn" id="btnSave">添加</a>
<input type="submit" value="删除选择项" class="btn" />
</p>
<div id="divFrom">
<form id="formPdt">
<fieldset>
<legend>添加商品</legend>
<p>
<label for="name">
名称:
</label>
<input type="text" name="name" id="name" />
</p>
<p>
<label for="price">
价格:
</label>
<input type="text" name="price" id="price" />
</p>
<p>
<label for="detail">
详细:
</label>
<textarea id="detail" name="detail" cols="60"></textarea>
</p>
</fieldset>
</form>
</div>
</div> <link rel="stylesheet" type="text/css" href="js/artDialog6/ui-dialog.css" rel="external nofollow" rel="external nofollow" rel="external nofollow" />
<script src="js/jQuery1.11.3/jquery-1.11.3.min.js" type="text/javascript" charset="utf-8"></script>
<script src="js/artDialog6/dialog-min.js" type="text/javascript" charset="utf-8"></script> <!--[if (IE 8)|(IE 9)]>
<script src="js/jquery.transport.xdr.min.js" type="text/javascript" charset="utf-8"></script>
<![endif]-->
<script type="text/javascript">
var app = {
url: "http://localhost:8087/JavaScript001/", //提供服务的域名
add: function() {
var d = dialog({
title: '添加商品',
content: $('#divFrom').html(),
okValue: '添加',
modal:true,
backdropOpacity:0.3,
ok: function() {
var that = this;
$.ajax({
type: "post",
data: $(".ui-dialog #formPdt").serialize() + "&act=add",
success: function(data) {
if(data) {
app.log("添加成功!");
app.loadAll();
that.close();
} else {
app.log("添加失败!");
}
}
});
return false;
},
cancelValue: '关闭',
cancel: function() {
alert('你点了取消按钮')
},
onclose:function(){
alert("关闭了");
}
}); d.show();
},
del: function() {
//closest离当前元素最近的td父元素
id = $(this).closest("td").data("id");
var that = $(this);
$.ajax({
type: "get",
data: {
"id": id,
"act": "del"
},
success: function(data) {
if(data) {
that.closest("tr").remove();
app.log("删除成功!");
} else {
app.log("删除失败!");
}
}
});
},
loadAll: function() {
$.ajax({
type: "get",
data: {
"act": "getAllCORS"
},
success: function(data) {
$("#tabGoods tr:gt(0)").remove();
$.each(data, function(index, obj) {
var tr = $("<tr/>"); //行 $("<td/>").html(obj.id).appendTo(tr); //编号 var imgTd = $("<td/>");
$("<img/>", {
"src": app.url + "images/" + obj.picture,
"class": "pic"
}).appendTo(imgTd); //图片
imgTd.appendTo(tr); $("<td/>").html(obj.name).appendTo(tr);
$("<td/>").html(Math.ceil(obj.price)).appendTo(tr);
$("<td/>").html(obj.detail).appendTo(tr);
$("<td/>").html("<a href='#' class='abtn del'>删除</a>").data("id", obj.id).appendTo(tr);
$("#tabGoods").append(tr);
});
}
});
},
init: function() {
/*动态绑定删除事件*/
$("#tabGoods").on("click", "a.del", {}, app.del);
/*绑定添加事件*/
$("#btnSave").click(app.add);
/*设置全局AJAX默认值*/
$.ajaxSetup({
dataType: "json",
url: app.url + "Product?type=meat-and-filler&format=json",
beforeSend: app.ajaxBefore,
complete: app.clearMsg,
error: function(xhr, textStatus, errorThrown) {
app.log("错误" + textStatus + errorThrown);
}
});
this.loadAll();
},
clearMsg: function() {
this.box.remove();
},
ajaxBefore: function() {
this.box=dialog({
modal:true
});
this.box.show();
},
log: function(msg) {
$("#message").html(msg);
}
}; app.init();
</script>
</body></html>

运行结果:

JavaScript学习总结(一)——延迟对象、跨域、模板引擎、弹出层、AJAX示例

删除:

JavaScript学习总结(一)——延迟对象、跨域、模板引擎、弹出层、AJAX示例

二、延迟对象(Deferred)

deferred对象就是jQuery1.5版以后新增加的回调函数解决方案。

2.0、方法作为参数传递

在静态语言如C#中可以使用委托将方法作为参数传递,C++中可以使用方法指针,因为JavaScript是动态语言,方法作为参数传递非常便捷,示例如下:

示例1:

<!DOCTYPE html>
<html> <head>
<meta charset="UTF-8">
<title></title>
</head> <body>
<script type="text/javascript">
//将方法作为参数带给另一个方法
//C# 委托
//C++ 方法指针
//Java 没有,匿名内部类,接口 function handler(arr, f1) {
for(var i = 0; i < arr.length; i++) {
arr[i] = f1(arr[i]);
}
return arr;
} function add(n) {
return n + 1;
} function sub(n) {
return n - 1;
} var result = handler([1, 2, 3], function(n) {
return n * 3;
});
console.log(result);
</script>
</body></html>

结果:

JavaScript学习总结(一)——延迟对象、跨域、模板引擎、弹出层、AJAX示例

示例2:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<script type="text/javascript">
function hello(f){
console.info("问好:");
var x=100;
f(x);
}; hello(function(n){
console.log("Hello!"+n);
}); hello(function(n){
console.log("你好!"+n);
}); </script>
</body>
</html>

结果:

JavaScript学习总结(一)——延迟对象、跨域、模板引擎、弹出层、AJAX示例

函数自动提升

在Javascript中定义一个函数,有两种写法:

  function foo() { }

  var foo = function () { }

两种写法完全等价。但是在解析的时候,前一种写法会被解析器自动提升到代码的头部,因此违背了函数应该先定义后使用的要求,所以建议定义函数时,全部采用后一种写法。

示例:

<!DOCTYPE html>
<html> <head>
<meta charset="UTF-8">
<title></title>
</head> <body>
<script type="text/javascript">
console.log(typeof f1);
f1(); console.log(typeof f2); //undefined
f2();
var f2 = function() {
console.log('f2');
} //函数自动提升
function f1() {
console.info('f1');
}
</script>
</body></html>

结果:

JavaScript学习总结(一)——延迟对象、跨域、模板引擎、弹出层、AJAX示例

当函数作为参数传递时应该在调用前判断,避免异常,示例:

<!DOCTYPE html>
<html> <head>
<meta charset="UTF-8">
<title></title>
</head> <body>
<script type="text/javascript">
//将方法作为参数带给另一个方法
//C# 委托
//C++ 方法指针
//Java 没有,匿名内部类,接口 function handler(arr, f1) {
if(f1&&typeof f1==="function") {
for(var i = 0; i < arr.length; i++) {
arr[i] = f1(arr[i]);
}
}
else{
throw "未指定参数";
}
return arr;
} function add(n) {
return n + 1;
} function sub(n) {
return n - 1;
} var result = handler([1, 2, 3], function(n) {
return n * 3;
});
console.log(result); result=handler([2, 3, 8],function(){});
console.log(result);
</script>
</body></html>

结果:

JavaScript学习总结(一)——延迟对象、跨域、模板引擎、弹出层、AJAX示例

回调方法在异步请求中的使用:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<script src="../js/jQuery1.12.3/jquery-1.12.3.min.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript"> var fun=function(student){
console.log(student.name);
}; function getStudents(){
//异步
$.getJSON("student.json",function(data){
if(fun)
{
fun(data);
}
});
} var student=getStudents(function(student){
console.log(student.name);
}); </script>
</body>
</html>

结果:

JavaScript学习总结(一)——延迟对象、跨域、模板引擎、弹出层、AJAX示例

2.1、回调函数

先看一个示例:

首先,为什么要使用Deferred?

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>回调</title>
</head>
<body>
<script src="js/jQuery1.11.3/jquery-1.11.3.min.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
var student;
$.get("student.json",function(data){
student=data;
},"json");
alert(student);
</script>
</body>
</html>

student.json文件:{“name”:”tom”,”id”:”01″}

运行结果:

JavaScript学习总结(一)——延迟对象、跨域、模板引擎、弹出层、AJAX示例

因为AJAX是异步执行的,类似高级语言中的多线程,当发起ajax请求时会有网络延迟,而代码并没有在$.get的位置被阻塞,alert先执行,但数据并没有从远程获取到,所以结果是undefined。

其实初学者经常会犯这种错误,如:

            function getStudentById(id){
$.get("students.do",{"id":id},function(stu){
return stu;
},"json");
}

上面的代码是有问题的,原因如前面的示例是一样的。怎么解决,如果你认为是异步带来的问题,当然通过同步是可以解决的,如:

            $.ajax({
type:"get",
url:"student.json",
async:false, /*非异步,同步*/
success:function(data){
student=data;
}
});

结果:

JavaScript学习总结(一)——延迟对象、跨域、模板引擎、弹出层、AJAX示例

如果将所有的ajax请求修改为同步的,则ajax的好处就大打折扣了,如果即要异步又要解决上面的问题,可以使用回调方法。

示例:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>回调</title>
</head>
<body>
<script src="js/jQuery1.11.3/jquery-1.11.3.min.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
/*callback是一个当ajax请求成功时的回调方法*/
function getStudent(callback) {
$.get("student.json", function(data) {
callback(data);
}, "json");
} /*调用getStudent函数,传入参数,参数也是一个函数*/
getStudent(function(stu){
alert(stu.id);
}); /*把一个方法作为参数传递给另一个方法可以认为是委托,如C++中的函数指针类似*/
getStudent(function(stu){
alert(stu.name);
});
</script>
</body>
</html>

结果:

JavaScript学习总结(一)——延迟对象、跨域、模板引擎、弹出层、AJAX示例

从这里看回调很完美,其实不然,实际开发中要复杂得多,如当第一个ajax请求完成才可以完成第二个,当第二个完成才可以完成第三个,可能最一个请求要等前面的所有请求都成功时才允许执行或才有条件执行,如

使用ajax编辑用户信息,先加载用户对象,再加载省,加载市,加县,可能代码会这样写:

            $.get("url1",function(){
$.get("url2",function(){
$.get("url3",function(){
...
});
});
});

当回调越来越多,嵌套越深,代码可读性就会越来越差。如果注册了多个回调,那更是一场噩梦,幸好从jQuery1.5开始出现了延迟对象(deferred),可以解决这个问题。

2.2、deferred.done

$.ajax()操作完成后,如果使用的是低于1.5.0版本的jQuery,返回的是XHR对象,你没法进行链式操作;如果高于1.5版,返回的是deferred对象,可以进行链式操作。

JavaScript学习总结(一)——延迟对象、跨域、模板引擎、弹出层、AJAX示例

当延迟成功时调用一个函数或者数组函数,功能与原success类似。

语法:deferred.done(doneCallbacks[,doneCallbacks])

返回值:Deferred Object

该参数可以是一个函数或一个函数的数组。当延迟成功时,doneCallbacks被调用。回调执行是依照他们添加的顺序。一旦deferred.done()返回延迟对象,延迟对象的其它方法也可以链接到了这里,包括增加.done()方法。当延迟解决,doneCallbacks执行使用参数提供给 http://tomcat.apache.org/tomcat-7.0-doc/config/filter.html

依赖:

<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <groupId>com.zhangguo.cors</groupId>
<artifactId>TestCors</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging> <name>TestCors Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties> <dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!-- JSTL -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- Servlet核心包 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
<!--JSP -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-catalina</artifactId>
<version>8.5.33</version>
</dependency>

<!-- jackson -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.5.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.5.2</version>
</dependency> </dependencies> <build>
<finalName>TestCors</finalName>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.0.0</version>
</plugin>
<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.20.1</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.0</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>

添加过滤器,尽量添加在最前面:

<filter>
<filter-name>CorsFilter</filter-name>
<filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
<init-param>
<param-name>cors.allowed.origins</param-name>
<param-value>https://www.apache.org</param-value>
</init-param>
<init-param>
<param-name>cors.allowed.methods</param-name>
<param-value>GET,POST,HEAD,OPTIONS,PUT</param-value>
</init-param>
<init-param>
<param-name>cors.allowed.headers</param-name>
<param-value>Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers</param-value>
</init-param>
<init-param>
<param-name>cors.exposed.headers</param-name>
<param-value>Access-Control-Allow-Origin,Access-Control-Allow-Credentials</param-value>
</init-param>
<init-param>
<param-name>cors.support.credentials</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>cors.preflight.maxage</param-name>
<param-value>10</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CorsFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

如果使用了Spring MVC,请开启Spring对OPTIONS的支持:

<init-param>
<param-name>dispatchOptionsRequest</param-name>
<param-value>true</param-value>
</init-param>

客户端:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>跨域</title>
</head>
<body>
<script src="../js/jquery-1.11.3.min.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
$.ajax({
type:"PUT",
url:"http://localhost:8080/mvc08/u",
contentType:"application/json;charset=utf-8",
dataType:"json",
success:function(data){
console.log(data);
}
});
</script>
</body></html>

服务器:

package com.zhangguo.springmvc08.action;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;@WebServlet(name = "UserServlet", value = "/u")
public class UserServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
} protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter().write("{\"name\":\"Book\"}");
} @Override
protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
} @Override
protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
} @Override
protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}

结果:

JavaScript学习总结(一)——延迟对象、跨域、模板引擎、弹出层、AJAX示例

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1"> <!--welcome pages-->
<welcome-file-list>
<welcome-file>users/tom</welcome-file>
</welcome-file-list> <!--配置springmvc DispatcherServlet(中心控制器)-->
<servlet>
<servlet-name>springMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<!--Sources标注的文件夹下需要新建一个spring文件夹-->
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:spring/spring-mvc.xml</param-value>
</init-param>
<init-param>
<param-name>dispatchOptionsRequest</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
<servlet-mapping>
<servlet-name>springMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping> <filter>
<filter-name>CORS</filter-name>
<filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class>
<init-param>
<param-name>cors.allowOrigin</param-name>
<param-value>http://127.0.0.1:8020</param-value>
</init-param>
<init-param>
<param-name>cors.supportedMethods</param-name>
<param-value>POST,GET,OPTIONS,DELETE,PUT</param-value>
</init-param>
<init-param>
<param-name>cors.supportedHeaders</param-name>
<param-value>Content-Type,Accept,Origin,XRequestedWith,ContentType,LastModified</param-value>
</init-param>
<init-param>
<param-name>cors.exposedHeaders</param-name>
<param-value>SetCookie</param-value>
</init-param>
<init-param>
<param-name>cors.supportsCredentials</param-name>
<param-value>true</param-value>
</init-param>
</filter> <filter-mapping>
<filter-name>CORS</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping> <filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>

3.4.4、Servlet支持CORS

通过修改请求头部门信息可以实现Servlet完成复杂跨域功能,示例如下:

后台:

package com.zhangguo.springmvc08.action;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;@WebServlet(name = "ProductServlet", value = "/pdt")
public class ProductServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
} protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获得所有头部信息
Enumeration<String> items=request.getHeaderNames();
String headers="Content-Type,Accept,Origin,XRequestedWith,ContentType,LastModified,Content-Type,ContentType,content-type";
while(items.hasMoreElements()){
headers+=","+items.nextElement();
}
//设置允许CORS的域名,如果是所有则使用*
response.addHeader("Access-Control-Allow-Origin", "http://127.0.0.1:8020");
response.addHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, TRACE, OPTIONS,PUT,DELETE");
response.addHeader("Access-Control-Request-Headers", "Origin,X-Requested-With,Content-Type,Accept");
response.addHeader("Access-Control-Allow-Credentials", "true");
response.getWriter().write("{\"name\":\"Book\"}");
} @Override
protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.addHeader("Access-Control-Allow-Headers", "Content-type");
doGet(req, resp);
} @Override
protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
} @Override
protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}

这里在实际使用中有遇到,所有支持的头部一时可能不能完全写出来,而又不想在这一层做过多的判断,没关系,事实上通过request的header可以直接取到Access-Control-Request-Headers,直接把对应的value设置到Access-Control-Allow-Headers即可

前台:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>跨域</title>
</head>
<body>
<script src="../js/jquery-1.11.3.min.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
$.ajax({
type:"PUT",
url:"http://localhost:8080/mvc08/pdt",
contentType:"application/json;charset=utf-8",
dataType:"json",
success:function(data){
console.log(data);
}
});
</script>
</body></html>

结果:

JavaScript学习总结(一)——延迟对象、跨域、模板引擎、弹出层、AJAX示例

3.4.5、Spring MVC4.2+ CORS注解

Spring MVC4.2 及以上增加了对CORS的支持

一个应用可能会有多个 CORS 配置,并且可以设置每个 CORS 配置针对一个接口或一系列接口或者对所有接口生效。

对第一种情况,如果想要对某一接口配置 CORS,可以在方法上添加 CrossOrigin 注解:

@CrossOrigin(origins = {"http://localhost:9000", "null"})
@RequestMapping(value = "/test", method = RequestMethod.GET)
public String greetings() {
return "{\"project\":\"just a test\"}";
}

第二种情况,如果想对一系列接口添加 CORS 配置,可以在类上添加注解,对该类声明所有接口都有效:

@CrossOrigin(origins = {"http://localhost:8080", "null"})
@RestController
public class HomeController{
}

第三种情况,添加全局配置,则需要添加一个配置类:

@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:9000", "null")
.allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE")
.maxAge(3600)
.allowCredentials(true);
}
}

可以通过添加 Filter 的方式,配置 CORS 规则,并手动指定对哪些接口有效。

@Beanpublic FilterRegistrationBean corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true); config.addAllowedOrigin("http://localhost:9000");
config.addAllowedOrigin("null");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config); // CORS 配置对所有接口都有效
FilterRegistrationBean bean = newFilterRegistrationBean(new CorsFilter(source));
bean.setOrder(0);
return bean;
}

也可以修改配置文件:

    <mvc:cors>
<mvc:mapping path="/**"
allowed-origins="http://127.0.0.1:8020"
allowed-methods="POST,GET, OPTIONS,DELETE,PUT"
allowed-headers="Content-Type,ContentType,Access-Control-Allow-Headers, Authorization, X-Requested-With"
allow-credentials="true"/>
</mvc:cors>

员工管理的跨域综合示例

后台REST服务:

package com.zhangguo.springmvc08.controller;import com.zhangguo.springmvc08.entity.User;
import com.zhangguo.springmvc08.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;@RestController
@RequestMapping(path = "/emps")
public class EmpController extends BaseController { @Autowired
UserService userService; @RequestMapping(path = "")
public AjaxState getAllEmps(HttpServletRequest request, HttpServletResponse response) {
List<User> users=userService.queryAllUsers();
boolean result=users!=null;
return new AjaxState(result?"success":"error",users,result?"获得数据成功!":"获得数据失败!");
} @RequestMapping(path = "/{id}", method = RequestMethod.GET)
public AjaxState getEmpById(@PathVariable int id) {
User user=userService.getUserById(id);
boolean result=user!=null;
return new AjaxState(result?"success":"error",user,result?"获得数据成功!":"获得数据失败!");
} @RequestMapping(path = "", method = RequestMethod.POST)
public AjaxState addEmp(@RequestBody User user) {
boolean result=userService.addUser(user);
return new AjaxState(result?"success":"error",user,result?"添加成功!":"添加失败");
} @RequestMapping(path = "", method = RequestMethod.PUT)
public AjaxState updateEmp(@RequestBody User user) {
boolean result=userService.editUser(user);
return new AjaxState(result?"success":"error",user,result?"修改成功!":"修改失败");
} @RequestMapping(path = "/{id}", method = RequestMethod.DELETE)
public AjaxState deleteEmpById(@PathVariable int id) {
Boolean result=userService.deleteUser(id);
return new AjaxState(result?"success":"error",id,result?"删除成功!":"删除失败");
}}class AjaxState{
public String state;
public Object data;
public String message; public AjaxState(String state, Object data, String message) {
this.state = state;
this.data = data;
this.message = message;
} public AjaxState(){}
}

Spring配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd"> <!--启用spring的一些annotation -->
<context:annotation-config/> <!-- 自动扫描该包,使SpringMVC认为包下用了@controller注解的类是控制器 -->
<context:component-scan base-package="com.zhangguo.springmvc08">
</context:component-scan> <!--HandlerMapping 无需配置,springmvc可以默认启动--> <!--静态资源映射-->
<mvc:default-servlet-handler/>
<!--如果发现是静态资源的请求,就将该请求转由Web应用服务器默认的Servlet处理,如果不是静态资源的请求,才由DispatcherServlet继续处-->
<!--本项目把静态资源放在了WEB-INF的statics目录下,资源映射如下-->
<!--<mvc:resources mapping="/css/**" location="/WEB-INF/statics/css/"/>-->
<!--<mvc:resources mapping="/js/**" location="/WEB-INF/statics/js/"/>-->
<!--<mvc:resources mapping="/image/**" location="/WEB-INF/statics/image/"/>--> <!--但是项目部署到linux下发现WEB-INF的静态资源会出现无法解析的情况,但是本地tomcat访问正常,因此建议还是直接把静态资源放在webapp的statics下,映射配置如下-->
<!--<mvc:resources mapping="/css/**" location="/statics/css/"/>-->
<!--<mvc:resources mapping="/js/**" location="/statics/js/"/>-->
<!--<mvc:resources mapping="/image/**" location="/statics/images/"/>--> <mvc:cors>
<mvc:mapping path="/**"
allowed-origins="http://127.0.0.1:8020"
allowed-methods="POST,GET, OPTIONS,DELETE,PUT"
allowed-headers="Content-Type,ContentType,Access-Control-Allow-Headers, Authorization, X-Requested-With"
allow-credentials="true"/>
</mvc:cors> <!-- 配置注解驱动 可以将request参数与绑定到controller参数上 -->
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg value="UTF-8"/>
</bean>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
<property name="failOnEmptyBeans" value="false"/>
</bean>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven> <!-- 对模型视图名称的解析,即在模型视图名称添加前后缀(如果最后一个还是表示文件夹,则最后的斜杠不要漏了) 使用JSP-->
<!-- 默认的视图解析器 在上边的解析错误时使用 (默认使用html)- -->
<bean id="defaultViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/views/"/><!--设置JSP文件的目录位置-->
<property name="suffix" value=".jsp"/>
</bean> <!-- springmvc文件上传需要配置的节点-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="20971500"/>
<property name="defaultEncoding" value="UTF-8"/>
<property name="resolveLazily" value="true"/>
</bean>
</beans>

前端:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<title>员工管理</title>
</head>
<body>
<h2>员工管理</h2>
<table border="1" width="100%" id="tabEmps">
<tr>
<th>编号</th>
<th>姓名</th>
<th>生日</th>
<th>地址</th>
<th>电话</th>
<th>操作</th>
</tr>
</table>
<p class="loading" style="display: none;">
<img src="img/loading.gif" align="absmiddle">努力加载中...
</p>
<form id="formEmps">
<fieldset>
<legend>用户信息</legend>
<p>
<label for="name">姓名:</label>
<input name="name" id="name" type="text" required="required" maxlength="32"/>
</p>
<p>
<label for="birthday">生日:</label>
<input name="birthday" id="birthday" type="date" required="required" maxlength="8"/>
</p>
<p>
<label for="address">地址:</label>
<input name="address" id="address" type="text" required="required" maxlength="128"/>
</p>
<p>
<label for="phone">电话:</label>
<input name="phone" id="phone" type="text" required="required" maxlength="11"/>
</p>
<p>
<input id="id" type="hidden" name="id" value=""/>
<button type="button" id="btnSubmit">保存</button>
</p>
</fieldset>
</form>
<p class="message">
</p>
<script src="../js/jquery-1.11.3.min.js"></script>
<script>
var app = {
url: "http://localhost:8080/mvc08/emps",
init: function () {
$("#btnSubmit").click(app.save);
$("#tabEmps").on("click", ".del", app.delete);
$("#tabEmps").on("click", ".edit", app.edit);
this.binddata();
},
ajax: function (actionType, callback, path, data) {
$.ajax({
url: app.url + (path || ""),
contentType: "application/json;charset=utf-8",
data: JSON.stringify(data) || "{}",
type: actionType || "get",
dataType: "json",
success: function (data) {
if (data && data.state == "success") {
app.info(data.message);
} else if (data && data.state == "error") {
app.info(data.message);
} else {
app.info(data);
}
if (callback) {
callback(data);
}
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
app.info(textStatus + errorThrown);
},
beforeSend: function () {
$(".loading").show(200);
}
,
complete: function () {
$(".loading").hide(200);
}
})
;
},
binddata: function () {
$("#tabEmps tr:gt(0)").remove();
this.ajax("get", function (data) {
$.each(data.data, function (index, emp) {
var tr = $("<tr/>").data("emp", emp).appendTo("#tabEmps");
$("<td/>").text(emp.id).appendTo(tr);
$("<td/>").text(emp.name).appendTo(tr);
$("<td/>").text(emp.birthday).appendTo(tr);
$("<td/>").text(emp.address).appendTo(tr);
$("<td/>").text(emp.phone).appendTo(tr);
$("<td/>").html("<a class='del' href='#'>删除</a> | <a class='edit' href='#'>编辑</a>").appendTo(tr);
});
});
},
getEmp: function () {
return {
"id": $("#id").val(),
"name": $("#name").val(),
"birthday": $("#birthday").val(),
"address": $("#address").val(),
"phone": $("#phone").val()
};
},
save: function () {
var emp = app.getEmp();
if (emp.id) {
$("#id").val("");
app.update(emp);
} else {
app.add(emp);
}
},
add: function (emp) {
app.ajax("POST", function (data) {
app.binddata();
}, "", emp);
},
update: function (emp) {
app.ajax("Put", function (data) {
app.binddata();
}, "", emp);
},
delete: function () {
if (confirm("删除吗?")) {
var tr = $(this).closest("tr");
var emp = tr.data("emp");
app.ajax("DELETE", function (data) {
tr.remove();
}, "/" + emp.id);
}
},
edit:function(){
var emp = $(this).closest("tr").data("emp");
$("#id").val(emp.id);
$("#name").val(emp.name);
$("#birthday").val(emp.birthday);
$("#address").val(emp.address);
$("#phone").val(emp.phone);
},
info: function (msg) {
$(".message")[0].innerHTML += msg + "<br/>";
}
}; app.init();
</script>
</body>
</html>

运行结果:

JavaScript学习总结(一)——延迟对象、跨域、模板引擎、弹出层、AJAX示例

 其它跨域示例:

.Net服务器一般处理程序代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;namespace jQuery601_DotNet.Action
{
/// <summary>
/// FindUserById 的摘要说明
/// </summary>
public class FindUserById : IHttpHandler
{ public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
context.Response.Headers.Add("Access-Control-Allow-Origin","*");
context.Response.Headers.Add("Access-Control-Allow-Methods", "GET,POST");
String name = "";
int id = Convert.ToInt32(context.Request.Params["id"]);
if (id == )
{
name = "Mark";
}
else if (id == )
{
name = "Jack";
}
context.Response.Write(name);
} public bool IsReusable
{
get
{
return false;
}
}
}
}

客户端脚本:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>6.4.9、跨域AJAX请求</title>
</head>
<body>
<h2>6.4.9、跨域AJAX请求</h2>
<h2 id="message"></h2>
<button type="button" id="btnAjax">ajax请求</button>
<script type="text/javascript" src="js/jQuery/jquery.min.js"></script>
<script type="text/javascript">
$("#btnAjax").click(function() {
$.get("http://localhost:12833/Action/FindUserById.ashx",{"id":1001},function(data){
log(data);
},"text");
}); function log(msg) {
$("#message")[0].innerHTML += msg + "<br/>";
}
</script>
</body>
</html>

运行结果:

JavaScript学习总结(一)——延迟对象、跨域、模板引擎、弹出层、AJAX示例

从上图可以看到实现跨域且为异步请求。

Java Servlet后台脚本:

package com.gomall.action;import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.codehaus.jackson.map.ObjectMapper;import com.gomall.service.IProductService;
import com.gomall.service.ProductService;@WebServlet("/Product")
public class Product extends HttpServlet {
private static final long serialVersionUID = 1L; public Product() {
super();
} protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
String act = request.getParameter("act");
IProductService productService = new ProductService();
ObjectMapper mapper = new ObjectMapper();
PrintWriter out=response.getWriter(); if (act.equals("getAll")) {
String json = mapper.writeValueAsString(productService.getAll());
out.append(json);
} else if (act.equals("area")) {
String callback=request.getParameter("callback");
out.append(callback+"('"+new Date()+"')");
} else if (act.equals("getJSONP")) {
String callback=request.getParameter("callback");
String json = mapper.writeValueAsString(productService.getAll());
out.append(callback+"("+json+")");
} else if (act.equals("getAllCORS")) {
/**向响应的头部中添加内容*/
response.addHeader("Access-Control-Allow-Origin", "*");
response.addHeader("Access-Control-Allow-Methods", "GET,POST"); String json = mapper.writeValueAsString(productService.getAll());
out.append(json);
}
} protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}

客户端代码:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>AJAX</title>
</head>
<body>
<script src="js/jQuery1.11.3/jquery-1.11.3.min.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
$.get("http://localhost:8087/JavaScript001/Product?act=getAllCORS",function(data){
alert(data);
});
</script>
</body>
</html>

运行结果:

JavaScript学习总结(一)——延迟对象、跨域、模板引擎、弹出层、AJAX示例

JavaScript学习总结(一)——延迟对象、跨域、模板引擎、弹出层、AJAX示例

3.4.6、IE8实现CORS跨域的问题

a)、如果认为每次需要修改HTTP头部比较麻烦,在java中可以使用过滤器,.Net可以使用Module或HttpHandler全局注册(注册到Web.Config中,部署时还需要注意)。

b)、如果需要考虑IE8实现CORS则要插件支持,因为IE8并没有完全支持CORS。

插件名称:javascript-jquery-transport-xdr

github: https://github.com/gfdev/javascript-jquery-transport-xdr

示例代码:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>AJAX</title>
</head>
<body>
<script src="js/jQuery1.11.3/jquery-1.11.3.min.js" type="text/javascript" charset="utf-8"></script>
<!--[if (IE 8)|(IE 9)]>
<script src="js/jquery.transport.xdr.min.js" type="text/javascript" charset="utf-8"></script>
<![endif]--> <script type="text/javascript">
$.get("http://localhost:8087/JavaScript001/Product?act=getAllCORS&type=meat-and-filler&format=json",{},function(data){
alert(data);
},"json");
</script>
</body>
</html>

运行结果:

JavaScript学习总结(一)——延迟对象、跨域、模板引擎、弹出层、AJAX示例

3.4.7、.Net Core跨域

方法一、修改Web.config文件

<system.webServer>
  <httpProtocol>
  <!--跨域设置-->
    <customHeaders>
    <remove name="Access-Control-Allow-Origin" />
    <remove name="Access-Control-Allow-Headers" />
    <remove name="Access-Control-Allow-Methods" />
    <add name="Access-Control-Allow-Origin" value="*" />
    <add name="Access-Control-Allow-Headers" value="Content-Type" />
    <add name="Access-Control-Allow-Methods" value="*" />
    </customHeaders>
  </httpProtocol>
</system.webServer>

方法二、手动修改HttpResponse对象的头部信息,与Java一样

方法三、使用Microsoft.AspNetCore.Cors

#region 程序集 Microsoft.AspNetCore.Cors, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
// C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.aspnetcore.cors\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Cors.dll
#endregionusing System;
using Microsoft.AspNetCore.Cors.Infrastructure;namespace Microsoft.AspNetCore.Cors
{
//
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class EnableCorsAttribute : Attribute, IEnableCorsAttribute
{
//
// 摘要:
// Creates a new instance of the Microsoft.AspNetCore.Cors.EnableCorsAttribute with
// the default policy name defined by Microsoft.AspNetCore.Cors.Infrastructure.CorsOptions.DefaultPolicyName.
public EnableCorsAttribute();
//
// 摘要:
// Creates a new instance of the Microsoft.AspNetCore.Cors.EnableCorsAttribute with
// the supplied policy name.
//
// 参数:
// policyName:
// The name of the policy to be applied.
public EnableCorsAttribute(string policyName); //
public string PolicyName { get; set; }
}
}

1)、using Microsoft.AspNetCore.Cors;

2)、使用特性    [EnableCors]

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;namespace WebApplication1.Controllers
{
[Route("api/[controller]")]
[ApiController]
[EnableCors]
public class TaskController : ControllerBase
{}
}

配置Startup.cs文件:

        public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddDefaultPolicy(
builder =>
{ builder.WithOrigins("http://www.163.com",
"http://www.cnblogs.com");
}); options.AddPolicy("AnotherPolicy",
builder =>
{
builder.WithOrigins("http://www.baidu.com")
.AllowAnyHeader()
.AllowAnyMethod();
}); }); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
            services.AddCors(p => p.AddDefaultPolicy(
adp => adp.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin().AllowCredentials())
);

3.5、小结

当然除了兼容老浏览器的jsonp跨域与HTML5中的CORS跨域还有很多其它办法如利用iframe和location.hash、window.name实现的跨域数据传输、使用HTML5 postMessage、利用flash等办法。个人认为CORS应该才是未来主要的跨域选择,其它的方法都只是hack。

四、弹出层

前面AJAX示例中添加功能如果放在一个弹出层中布局会更加紧凑一些,像登录,提示信息经常会需要弹出层。

常见的弹出层有:FancyBox,LightBox,colorBox,artDialog,BlockUI,Layer等,这里介绍腾讯开源的artDialog,轻量,实用。

JavaScript学习总结(一)——延迟对象、跨域、模板引擎、弹出层、AJAX示例

artDialog是一个设计得十分巧妙的对话框组件,小巧身材却拥有丰富的接口与漂亮的外观。

特点是自适应内容、优雅的接口、细致的体验、跨平台兼容、轻量实用。

项目源码: https://github.com/aui/artDialog

帮助信息: http://img0.zz91.com/huanbao/mblog/artDialog-5.0.4

文档与示例: http://aui.github.io/artDialog/doc/index.html

AngularJS 版本: https://github.com/aui/angular-popups

使用方法:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>artDialog</title>
</head>
<body>
<button onclick="btn_dialog()">
弹出框
</button>
<button onclick="btn_loading()">
加载中
</button>
<script src="js/jQuery1.11.3/jquery-1.11.3.js" type="text/javascript" charset="utf-8"></script>
<script src="js/artDialog6/dialog-min.js" type="text/javascript" charset="utf-8"></script>
<link rel="stylesheet" type="text/css" href="js/artDialog6/ui-dialog.css" rel="external nofollow" rel="external nofollow" rel="external nofollow" />
<script type="text/javascript">
function btn_dialog() {
var d = dialog({
title: '消息',
content: '风吹起的青色衣衫,夕阳里的温暖容颜,你比以前更加美丽,像盛开的花<br>——许巍《难忘的一天》',
okValue: '确 定',
ok: function() {
var that = this;
setTimeout(function() {
that.title('提交中..');
}, 2000);
return false;
},
cancelValue: '取消',
cancel: function() {
alert('你点了取消按钮')
}
}); d.show();
} function btn_loading(){
dialog({
modal:true
}).show();
}
</script>
</body></html>

运行结果:

JavaScript学习总结(一)——延迟对象、跨域、模板引擎、弹出层、AJAX示例

JavaScript学习总结(一)——延迟对象、跨域、模板引擎、弹出层、AJAX示例

属性:

 // 对齐方式
//align: 'bottom left', // 是否固定定位
//fixed: false, // 对话框叠加高度值(重要:此值不能超过浏览器最大限制)
//zIndex: 1024, // 设置遮罩背景颜色
backdropBackground: '#000', // 设置遮罩透明度
backdropOpacity: 0.7, // 消息内容
content: '<span class="ui-dialog-loading">Loading..</span>', // 标题
title: '', // 对话框状态栏区域 HTML 代码
statusbar: '', // 自定义按钮
button: null, // 确定按钮回调函数
ok: null, // 取消按钮回调函数
cancel: null, // 确定按钮文本
okValue: 'ok', // 取消按钮文本
cancelValue: 'cancel', cancelDisplay: true, // 内容宽度
width: '', // 内容高度
height: '', // 内容与边界填充距离
padding: '', // 对话框自定义 className
skin: '', // 是否支持快捷关闭(点击遮罩层自动关闭)
quickClose: false, // css 文件路径,留空则不会使用 js 自动加载样式
// 注意:css 只允许加载一个
cssUri: '../css/ui-dialog.css',

事件:

/**
* 显示对话框
* @name artDialog.prototype.show
* @param {HTMLElement Object, Event Object} 指定位置(可选)
*/ /**
* 显示对话框(模态)
* @name artDialog.prototype.showModal
* @param {HTMLElement Object, Event Object} 指定位置(可选)
*/ /**
* 关闭对话框
* @name artDialog.prototype.close
* @param {String, Number} 返回值,可被 onclose 事件收取(可选)
*/ /**
* 销毁对话框
* @name artDialog.prototype.remove
*/ /**
* 重置对话框位置
* @name artDialog.prototype.reset
*/ /**
* 让对话框聚焦(同时置顶)
* @name artDialog.prototype.focus
*/ /**
* 让对话框失焦(同时置顶)
* @name artDialog.prototype.blur
*/ /**
* 添加事件
* @param {String} 事件类型
* @param {Function} 监听函数
* @name artDialog.prototype.addEventListener
*/ /**
* 删除事件
* @param {String} 事件类型
* @param {Function} 监听函数
* @name artDialog.prototype.removeEventListener
*/ /**
* 对话框显示事件,在 show()、showModal() 执行
* @name artDialog.prototype.onshow
* @event
*/ /**
* 关闭事件,在 close() 执行
* @name artDialog.prototype.onclose
* @event
*/ /**
* 销毁前事件,在 remove() 前执行
* @name artDialog.prototype.onbeforeremove
* @event
*/ /**
* 销毁事件,在 remove() 执行
* @name artDialog.prototype.onremove
* @event
*/ /**
* 重置事件,在 reset() 执行
* @name artDialog.prototype.onreset
* @event
*/ /**
* 焦点事件,在 foucs() 执行
* @name artDialog.prototype.onfocus
* @event
*/ /**
* 失焦事件,在 blur() 执行
* @name artDialog.prototype.onblur
* @event
*/

该插件使用比较简单,可以看示例与源代码。

五、模板引擎

在AJAX示例中javascript中有大量的html字符串,html中有一些像onclick样的javascript,这样javascript中有html,html中有javascript,代码的偶合度很高,不便于修改与维护,使用模板引擎可以解决问题。

模板引擎(这里特指用于Web开发的模板引擎)是为了使用户界面与业务数据(内容)分离而产生的,它可以生成特定格式的文档,用于网站的模板引擎就会生成一个标准的HTML文档。前后端都有模板引擎,比如T4、FreeMarker、Velocity,这里主要讲前端模板引擎:

JavaScript学习总结(一)——延迟对象、跨域、模板引擎、弹出层、AJAX示例

上图是常见的一些前端模板引擎,速度相对快的是artTemplate,与artDialog是同一个作者,当然一个好的模板引擎不仅是速度还有很多方面都关键。

源码与帮助: https://github.com/aui/artTemplate

5.1、Hello World

示例代码:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>artTemplate</title>
</head>
<body>
<div id="result">
</div>
<script src="js/artTemplate3/template.js" type="text/javascript" charset="utf-8"></script>
<script type="text/html" id="template1">
{{if isShow}}
<h2>姓名:{{name}}</h2>
<ul>
{{each hobbies as hobby index}}
<li>
{{index+1}} {{hobby}}
</li>
{{/each}}
</ul>
{{/if}}
</script>
<script type="text/javascript">
var data={
isShow:true,
name:"Tom",
hobbies:["看书","上网","运动","电影","购物"]
};
//用数据与模板渲染(render)出结果
var html=template("template1",data);
document.getElementById("result").innerHTML=html;
</script>
</body>
</html>

运行结果:

JavaScript学习总结(一)——延迟对象、跨域、模板引擎、弹出层、AJAX示例

生成的代码:

<h2>姓名:Tom</h2>
<ul>
<li>
1 看书
</li>
<li>
2 上网
</li>
<li>
3 运动
</li>
<li>
4 电影
</li>
<li>
5 购物
</li>
</ul>

5.2、方法

当前最新的版本是4.2与3.x版本有一些区别,4.x版本的方法与选项如下:

// 模板名
filename: null,
// 模板语法规则列表
rules: [nativeRule, artRule],
// 是否开启对模板输出语句自动编码功能。为 false 则关闭编码输出功能
// escape 可以防范 XSS 攻击
escape: true,
// 启动模板引擎调试模式。如果为 true: {cache:false, minimize:false, compileDebug:true}
debug: detectNode ? process.env.NODE_ENV !== 'production' : false,
// bail 如果为 true,编译错误与运行时错误都会抛出异常
bail: true,
// 是否开启缓存
cache: true,
// 是否开启压缩。它会运行 htmlMinifier,将页面 HTML、CSS、CSS 进行压缩输出
// 如果模板包含没有闭合的 HTML 标签,请不要打开 minimize,否则可能被 htmlMinifier 修复或过滤
minimize: true,
// 是否编译调试版
compileDebug: false,
// 模板路径转换器
resolveFilename: resolveFilename,
// 子模板编译适配器
include: include,
// HTML 压缩器。仅在 NodeJS 环境下有效
htmlMinifier: htmlMinifier,
// HTML 压缩器配置。参见 https://github.com/kangax/html-minifier
htmlMinifierOptions: {
collapseWhitespace: true,
minifyCSS: true,
minifyJS: true,
// 运行时自动合并:rules.map(rule => rule.test)
ignoreCustomFragments: []
},
// 错误事件。仅在 bail 为 false 时生效
onerror: onerror,
// 模板文件加载器
loader: loader,
// 缓存中心适配器(依赖 filename 字段)
caches: caches,
// 模板根目录。如果 filename 字段不是本地路径,则在 root 查找模板
root: '/',
// 默认后缀名。如果没有后缀名,则会自动添加 extname
extname: '.art',
// 忽略的变量。被模板编译器忽略的模板变量列表
ignore: [],
// 导入的模板变量
imports: runtime

方法:

与3.x版本类似,但config方法被取消,更多新查看如下链接

https://aui.github.io/art-template/zh-cn/docs/api.html

方法:

1)、template(id, data)

根据 id 渲染模板。内部会根据document.getElementById(id)查找模板。

如果没有 data 参数,那么将返回一渲染函数。

2)、template.compile(source, options)

将返回一个渲染函数。演示

3)、template.render(source, options)

将返回渲染结果。

4)、template.helper(name, callback)

添加辅助方法,让模板引擎调用自定义的javascript方法。

5)、template.config(name, value)

JavaScript学习总结(一)——延迟对象、跨域、模板引擎、弹出层、AJAX示例

示例代码:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>artTemplate</title>
</head>
<body>
<div id="result">
</div>
<script src="js/artTemplate3/template.js" type="text/javascript" charset="utf-8"></script>
<script type="text/html" id="template1">
$$if isShow##
<h2>姓名:$$name##</h2>
<ul>
$$include "template2"## <!--包含模板2-->
</ul>
$$/if##
</script> <script type="text/html" id="template2">
$$each hobbies as hobby index##
<li>
$$index+1## $$#hobby## <!--默认会转义,加#号不转义-->
</li>
$$/each##
</script>
<script type="text/javascript">
var data={
isShow:true,
name:"Tom",
hobbies:["看书","上网","运动","<b>电影</b>","<i>购物</i>"]
};
//逻辑语法开始标签
template.config("openTag","$$");
//逻辑语法结束标签
template.config("closeTag","##");
//不转义
template.config("escape",false);
//用数据与模板渲染(render)出结果
var html=template("template1",data);
document.getElementById("result").innerHTML=html;
</script>
</body>
</html>

运行结果:

JavaScript学习总结(一)——延迟对象、跨域、模板引擎、弹出层、AJAX示例

4.x示例:

<!DOCTYPE html>
<html> <head>
<meta charset="UTF-8">
<title>模板引擎</title>
</head> <body>
<div id="div1"> </div>
<script src="../js/artTemplate4/lib/template-web.js" type="text/javascript" charset="utf-8"></script> <script type="text/html" id="t1">
<div>
{{if isShow}}
<h2>{{name}}的爱好列表</h2>
<table width="50%" border="1">
<tr>
<th>序号</th>
<th>名称</th>
<th>操作</th>
</tr>
{{each hobbies obj i}}
<tr>
<td>{{i+1}}</td>
<td>{{obj}}</td>
<td>
<a href="#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" data-index="{{i}}" class="del">删除</a>
</td>
</tr>
{{/each}}
</table>
{{/if}}
</div>
</script> <script type="text/javascript">
var data = {
isShow: true,
name: "张学友",
hobbies: ["看书", "<b>上网</b>", "运动", "电影", "购物"]
}; var src = document.getElementById("t1");
var html = template.render(src.innerHTML, data, {
escape: false
});
console.log(html);
document.getElementById("div1").innerHTML = html;
</script>
</body></html>

结果:

JavaScript学习总结(一)——延迟对象、跨域、模板引擎、弹出层、AJAX示例

5.3、与AJAX结合应用

示例脚本:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>商品管理</title>
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<style type="text/css">
@CHARSET "UTF-8";
* {
margin: 0;
padding: 0;
font-family: microsoft yahei;
font-size: 14px;
} body {
padding-top: 20px;
} .main {
width: 90%;
margin: 0 auto;
border: 1px solid #777;
padding: 20px;
} .main .title {
font-size: 20px;
font-weight: normal;
border-bottom: 1px solid #ccc;
margin-bottom: 15px;
padding-bottom: 5px;
color: blue;
} .main .title span {
display: inline-block;
font-size: 20px;
background: blue;
color: #fff;
padding: 0 8px;
background: blue;
} a {
color: blue;
text-decoration: none;
} a:hover {
color: orangered;
} .tab td,
.tab,
.tab th {
border: 1px solid #777;
border-collapse: collapse;
} .tab td,
.tab th {
line-height: 26px;
height: 26px;
padding-left: 5px;
} .abtn {
display: inline-block;
height: 20px;
line-height: 20px;
background: blue;
color: #fff;
padding: 0 5px;
} .btn {
height: 20px;
line-height: 20px;
background: blue;
color: #fff;
padding: 0 8px;
border: 0;
} .abtn:hover,
.btn:hover {
background: orangered;
color: #fff;
} p {
padding: 5px 0;
} fieldset {
border: 1px solid #ccc;
padding: 5px 10px;
} fieldset legend {
margin-left: 10px;
font-size: 16px;
} .pic {
height: 30px;
width: auto;
} #divFrom {
display: none;
}
</style>
</head> <body> <div class="main">
<h2 class="title"><span>商品管理</span></h2>
<table border="1" width="100%" class="tab" id="tabGoods">
<tr>
<th>编号</th>
<th>图片</th>
<th>商品名</th>
<th>价格</th>
<th>详细</th>
<th>操作</th>
</tr>
</table>
<p style="color: red" id="message"></p>
<p>
<a href="#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" class="abtn" id="btnSave">添加</a>
<input type="submit" value="删除选择项" class="btn" />
</p>
<div id="divFrom">
<form id="formPdt">
<fieldset>
<legend>添加商品</legend>
<p>
<label for="name">
名称:
</label>
<input type="text" name="name" id="name" />
</p>
<p>
<label for="price">
价格:
</label>
<input type="text" name="price" id="price" />
</p>
<p>
<label for="detail">
详细:
</label>
<textarea id="detail" name="detail" cols="60"></textarea>
</p>
</fieldset>
</form>
</div>
</div> <link rel="stylesheet" type="text/css" href="js/artDialog6/ui-dialog.css" rel="external nofollow" rel="external nofollow" rel="external nofollow" />
<script src="js/artTemplate3/template.js" type="text/javascript" charset="utf-8"></script>
<script src="js/jQuery1.11.3/jquery-1.11.3.min.js" type="text/javascript" charset="utf-8"></script>
<script src="js/artDialog6/dialog-min.js" type="text/javascript" charset="utf-8"></script>
<!--[if (IE 8)|(IE 9)]>
<script src="js/jquery.transport.xdr.min.js" type="text/javascript" charset="utf-8"></script>
<![endif]-->
<script type="text/html" id="tmpl">
{{each list as pdt}}
<tr>
<td>{{pdt.id}}</td>
<td><img src="http://localhost:8087/JavaScript001/images/{{pdt.picture}}" class="pic"></td>
<td>{{pdt.name}}</td>
<td>{{pdt.price | round:'¥'}}</td>
<td>{{pdt.detail}}</td>
<td>
<a href="#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" class="abtn del" data-id={{pdt.id}}>删除</a>
</td>
</tr>
{{/each}}
</script>
<script type="text/javascript">
var app = {
url: "http://localhost:8087/JavaScript001/", //提供服务的域名
add: function() {
var d = dialog({
title: '添加商品',
content: $('#divFrom').html(),
okValue: '添加',
modal: true,
backdropOpacity: 0.3,
ok: function() {
var that = this;
$.ajax({
type: "post",
data: $(".ui-dialog #formPdt").serialize() + "&act=add",
success: function(data) {
if(data) {
app.log("添加成功!");
app.loadAll();
that.close();
} else {
app.log("添加失败!");
}
}
});
return false;
},
cancelValue: '关闭',
cancel: function() {
alert('你点了取消按钮')
},
onclose: function() {
alert("关闭了");
}
}); d.show();
},
del: function() {
id = $(this).data("id");
var that = $(this);
$.ajax({
type: "get",
data: {
"id": id,
"act": "del"
},
success: function(data) {
if(data) {
that.closest("tr").remove();
app.log("删除成功!");
} else {
app.log("删除失败!");
}
}
});
},
loadAll: function() {
$.ajax({
type: "get",
data: {
"act": "getAllCORS"
},
success: function(data) {
$("#tabGoods tr:gt(0)").remove();
$("#tabGoods").append(template("tmpl",{list:data}));
}
});
},
init: function() {
/*动态绑定删除事件*/
$("#tabGoods").on("click", "a.del", {}, app.del);
/*绑定添加事件*/
$("#btnSave").click(app.add);
/*设置全局AJAX默认值*/
$.ajaxSetup({
dataType: "json",
url: app.url + "Product?type=meat-and-filler&format=json",
beforeSend: app.ajaxBefore,
complete: app.clearMsg,
error: function(xhr, textStatus, errorThrown) {
app.log("错误" + textStatus + errorThrown);
}
}); //为模板引擎定义辅助函数
template.helper("round",function(value,mark){
return (mark||"")+Math.round(value);
}); this.loadAll();
},
clearMsg: function() {
this.box.remove();
},
ajaxBefore: function() {
this.box = dialog({
modal: true
});
this.box.show();
},
log: function(msg) {
$("#message").html(msg);
}
}; app.init();
</script>
</body>
</html>

运行结果:

JavaScript学习总结(一)——延迟对象、跨域、模板引擎、弹出层、AJAX示例

六、示例下载

coding: https://coding.net/u/zhangguo5/p/javascript001/git

服务器: https://coding.net/u/zhangguo5/p/javascript001_java/git

github:  https://github.com/zhangguo5/javascript01

https://git.dev.tencent.com/zhangguo5/javascriptpro.git

第二版:

前端:https://git.coding.net/zhangguo5/javascript_01.git

后台:https://git.coding.net/zhangguo5/SpringMVC08.git

七、视频

http://www.bilibili.com/video/av17173253/

https://www.bilibili.com/video/av16991874/

八、作业

8.1、请完成一个简单的分布式应用,使用Java作为服务器对外发布服务,PC客户端实现“品牌或商品”的管理,移动端实现如下列表:

  • a)、分析出数据库的设计,建库、建表 (MySQL)
  • b)、创建后台项目,实现5个服务,可以使用RETSFul (IDEA)
  • c)、创建PC Web项目(HBuilder),使用AJAX消费后台提供的5个服务 ,完成增加、删除、修改、查询功能
  • d)、创建App项目(HBuilder),先完成页面的静态布局,使用AJAX调用服务
  • e)、注意跨域、可以选择三方的UI框架,但界面需完全一样
  • f)、在PC Web中,添加,删除,编辑、详细功能请使用artDialog弹出层
  • g)、在PC Web与App中请使用artTemplate渲染页面HTML

JavaScript学习总结(一)——延迟对象、跨域、模板引擎、弹出层、AJAX示例

系统结构如下:

JavaScript学习总结(一)——延迟对象、跨域、模板引擎、弹出层、AJAX示例

参考网站:https://m.dianping.com/

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,487
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,903
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,736
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,486
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:8,126
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:5,287