1.同域与跨域概念
同域概念:
请求的协议//域名:端口如果都相同则是同域请求.除此之外都是跨域请求.
例子1:
端口不同跨域
例子2:
域名不同跨域
例子3:
协议不同跨域
同域与跨域的测试
1.在jt-manage中发起ajax请求是同域的请求.可以正确获取数据
$(function(){
$.get("http://manage.jt.com/test.json",function(data){
alert(data.name);
})
})
2.在jt-web中 发起http://manage.jt.com/test.json这个url请求是跨域请求 不能正确获取数据,
$(function(){
$.get("http://manage.jt.com/test.json",function(data){
alert(data.name);
})
})
3.但是浏览器中的消息显示数据已经正确获取了? 为什么数据不显示?
4.为什么不能跨域
答:由于浏览器安全性的考虑.不允许处理跨域请求的数据.违反了http协议
5.跨域问题解决
答:javascript中的src属性可以访问任何的资源.http协议对其没有任何的约束.所以可以借助src属性实现跨域的需求.
要求:
- js的函数的名称必须与返回数据的函数名称一致
- 返回值的数据必须是json数据.
例子:
1.js的函数
2.远程返回值
6.原有跨域的问题
因为利用src的漏洞可以实现跨域的请求,但是必须有前台条件.前台函数方法,必须有返回值的方法名称必须一致.否则跨域失败.
改进:
- 将函数的名称通过参数callback进行传递
- 后台动态的获取函数的名称之后进行数据的封装
2.JSONP
1.介绍
JSONP(JSON with Padding)是JSON的一种“使用模式”,可用于解决主流浏览器的跨域数据访问的问题。由于同源策略,一般来说位于 server1.example.com 的网页无法与不是 server1.example.com的服务器沟通,而 HTML 的<script> 元素是一个例外。利用 <script> 元素的这个开放策略,网页可以得到从其他来源动态产生的 JSON 资料,而这种使用模式就是所谓的 JSONP。用 JSONP 抓到的资料并不是 JSON,而是任意的JavaScript,用 JavaScript 直译器执行而不是用 JSON 解析器解析。
2.利用JQuery中的AJAx实现跨域
$.ajax({
url:"http://manage.jt.com/web/testJSONP",
type:"get",
dataType:"jsonp", //表示返回值的数据类型
//jsonp: "1801", //指定参数名称
//jsonpCallback: "hello", //指定回调函数名称
success:function (data){
alert(data.id);
//转化为字符串使用
//var obj = eval("("+data+")");
//alert(obj.name);
}
});
/*
参数说明:
url:表示远程请求的路径
type:get 表示提交方式是get请求
dataType:"jsonp" 返回数据类型 必须写为JSONP
jsonp:参数名称 一般默认为callback
jsonpCallback 手动指定函数名称 可以省略不写 ajax有默认值
*/
3.业务逻辑
后台controller
@Controller
public class JSONPController {
@RequestMapping("/web/testJSONP")
@ResponseBody
public String testJSONP(String callback){
String json = "{\"id\":\"1\",\"name\":\"tom\"}";
return callback +"("+ json +")";
}
}
JSONP工具类引用
@RequestMapping("/web/testJSONP")
@ResponseBody
public MappingJacksonValue testJSONP(String callback){
User user = new User();
user.setId(1);
user.setName("tomcat猫");
//创建对象 添加返回值数据
MappingJacksonValue jacksonValue =
new MappingJacksonValue(user);
//设置函数名称
jacksonValue.setJsonpFunction(callback);
return jacksonValue;
}
3.json
1.介绍
2.json格式
1.Array格式
2.Object格式
{"key":”value”,”key2”:”value2”}
3.嵌套格式
说明:JSON串可以进行无限层级的嵌套
值(value)可以是双引号括起来的字符串(string)、数值(number)、true、false、 null、对象(object)或者数组(array)。这些结构可以嵌套
["value1","value2",{id:1,name:"tom",hobby:["吃","喝","嫖","赌"]}]
在线解析:https://www.bejson.com/jsonviewernew/
3.实战:商品分类页面分析
1.页面:
1.最外层的数据是一个Array格式的JSON并且名称为data [{},{},{}]
2.array格式中的元素是一个对象格式
3.对象格式中有3个属性分别 url/name/itemCats
4.一级标题下有多个二级标题所以使用array格式进行封装
5.二级标题array格式中的对象依然有url/name/itamcats属性
结果:封装一级标题的对象和封装二级标题的对象是一样的
6.二级标题下进行封装三级标题所以使用Array格式封装
7.三级标题使用字符串的形式直接拼接,返回即可.
当鼠标移入商品分类列表时.会发出JSONP请求.
url:http://manage.jt.com/web/itemcat/all?callback=category.getDataService
2.业务逻辑
后台controller
@Controller
@RequestMapping("/web")
public class WebItemCatController {
@Autowired
private ItemCatService itemCatService;
@RequestMapping("/itemcat/all")
@ResponseBody
public MappingJacksonValue findItemCatAll(String callback){
//获取三级商品分类列表
ItemCatResult itemCatResult = itemCatService.findItemCatResult();
MappingJacksonValue jacksonValue = new
MappingJacksonValue(itemCatResult);;
jacksonValue.setJsonpFunction(callback);
return jacksonValue;
}
}
后台service
/**
*实现三级商品分类
* 难点:
* 1.数据如何查询???
* 解决方法:采用Map数据结构.进行数据的封装
*/
@Override
public ItemCatResult findItemCatResult() {
ItemCat tempItemCat = new ItemCat();
tempItemCat.setStatus(1);
//1.查询全部的商品分类信息
List<ItemCat> tempItemCatList =
itemCatMapper.select(tempItemCat);
//2.定义商品分类的Map集合 主要作用层级结构封装
Map<Long,List<ItemCat>> map = new HashMap<Long,List<ItemCat>>();
//3.循环遍历实现商品分类的划分
for (ItemCat itemCat : tempItemCatList) {
if(map.containsKey(itemCat.getParentId())){
//证明map中已经存在父级Id
map.get(itemCat.getParentId()).add(itemCat);
}else{
//表示map中没有父级,我是第一个父级元素的子类
List<ItemCat> pList = new ArrayList<ItemCat>();
pList.add(itemCat);
map.put(itemCat.getParentId(), pList);
}
}
//4准备一级商品分类List集合 14
List<ItemCatData> itemCatList1 = new ArrayList<ItemCatData>();
//5.封装一级商品分类信息
for (ItemCat itemCat1 : map.get(0L)) {
ItemCatData itemCatData1 = new ItemCatData();
itemCatData1.setUrl("/products/"+itemCat1.getId()+".html");
itemCatData1.setName("<a href='"+itemCatData1.getUrl()+"'>"+itemCat1.getName()+"</a>");
//准备二级商品分类集合信息
List<ItemCatData> itemCatList2 = new ArrayList<ItemCatData>();
for (ItemCat itemCat2 : map.get(itemCat1.getId())) {
ItemCatData itemCatData2 = new ItemCatData();
itemCatData2.setUrl("/products/"+itemCat2.getId());
itemCatData2.setName(itemCat2.getName());
//定义三级商品分类菜单
List<String> itemCatList3 = new ArrayList<String>();
for (ItemCat itemCat3 : map.get(itemCat2.getId())) {
itemCatList3.add("/products/"+itemCat3.getId()+"|"+itemCat3.getName());
}
itemCatData2.setItems(itemCatList3);
itemCatList2.add(itemCatData2);
}
itemCatData1.setItems(itemCatList2);
itemCatList1.add(itemCatData1);
if(itemCatList1.size()>13){
break;
}
};
ItemCatResult itemCatResult = new ItemCatResult();
itemCatResult.setItemCats(itemCatList1);
return itemCatResult;
}
商品分类缓存实现
/**
* 1.数据先从缓存中获取
* 2.如果有数据
* 则利用工具类将json转化为对象
* 3.如果没有数据
* 则第一次查询数据库,之后将数据转化为JSON数据保存到
* redis中.
*/
public ItemCatResult findItemCatByCache(){
String key = "ITEM_CAT_ALL";
String jsonData = jedisCluster.get(key);
try {
if(StringUtils.isEmpty(jsonData)){
ItemCatResult result = findItemCatResult();
String json = objectMapper.writeValueAsString(result);
jedisCluster.set(key, json);
return result;
}else{
//缓存中有数据
ItemCatResult result =
objectMapper.readValue(jsonData,ItemCatResult.class);
return result;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
1.没有添加缓存的速度
2.添加缓存的速度