Ajax&JSON 4|学习笔记

简介: 快速学习Ajax&JSON 4

开发者学堂课程【高校精品课-上海交通大学 -互联网应用开发技术Ajax&JSON 4】学习笔记,与课程紧密联系,让用户快速学习知识。

课程地址:https://developer.aliyun.com/learning/course/76/detail/15765


Ajax&JSON 4


内容介绍:

一、Uses of JSON

二、JSON Processing in the Java EE

三、Using the Streaming API

四、An example

五、Postman

六、过渡

 

一、Uses of JSON

这个代码不是大家想象中的 JSON 对象,比如有 author,然后再是 title,然后是什么书,一本书完了之后再是第二本,然后整个扩散,不是这么写的。

写的是一个匿名的内容,可以理解为写了个object,它内容是一个二维数组,它每一位数组里放的是若干个字符串,所以刚才看到的是两个 JSON 的对象,但是也可以直接放,比如1,2,3,4,5,就是你定义的任何一种 JSON 的类型,各种类型之一,比如 JSON 的对象、字符、数字,都可以成为它的数组,所以你们看到传到前端的是这样的,

图片48.png

这是个二维的数组,每一个数组里的元素就是这样一个内容。这是怎么来的呢?

图片49.png

每拿到一个 book 对象,把里面的 title、author、language 这些全部追加到定义的数组里,它就是个数组,整个数组写好后,再把它又丢到一个 ArrayList 里,ArrayList 里面本身就放的是一个数据,所以它整个是个二维数组。如果想做的更好,当然传输的数据量会多,应该像上面说的这种形式,就是有 author、title,把它都标记清楚它是些什么。

所谓的组装或者解析 Json 有两种模式,它对应的就很像 XML 的解析,讲 XML 解析提到了两种模式,一种是整个内存里面把 Json 的数据表示出来,表示成一棵树,然后在这棵树里面去遍历它,来回的访问它。

还有一种方式跟 XML 的 DOM 一样,必须先建好这棵树,所以一开始可能会消耗一点时间或者内存,把这棵树建好之后,在里面访问它树上的节点,还有一种是每一次按顺序访问 JSON 对象的元素,每读到一个元素的时候,它就会产生一个事件,这个事件就会触发解析器,所以可以到里面做一些处理,这对应的是 XML 里面 SAX 模式。它不需要一开始把所有的 JSON 的数据一次性的加载到内存里进行处理,它只需要从开头开始遍历,每当读到一个对象、一个元素,比如包括它是个 name,还是个 key,还是个数组的开始,它就会触发相应的事件,这个事件会带给一些现场的信息,比如得到的是什么元素,然后根据这个事件来决定要做什么,这两种方式都可以。

 

二、JSON Processing in the Java EE

先说在 Java 这端怎么做。在 Java 这端,Java 定义标准的 API 来做 Json 处理的,它定义在这里面,

- The javax.json package contains a reader interface, a writer interface,and a model builder interface for the object model. This package also contains other utility classes and Java types for JSON elements.

- The javax.json.stream package contains a parser interface and a generator interface for the streaming model.

但要注意,这个 API 实现各有不同,可以看到有一些类,它可能自己去实现了Json,它没有遵循这个 API,所以反复说 Json 的操作在后端和前端可能要看用的什么库,按照这个库进行操作。Java 本身提供了一个标准的 API,这个API 里面就包含了 json 的 reader,还有 writer 之类的公式,主要是一个是在做基于对象的处理,一个是基于流失的处理。

先举个例子,如果用这种对象模型就是一次性 Json 要把它建立好,然后把它发走,该怎么做?先讲一个方向,一种是先有了一个 Json 的字符串,要把它读进来,构建一个对象模型,可以使用像这里看到的,

import java.io.FileReader;

import javax.json.Json;

import javax.json.JsonReader;

import javax.json.JsonStructure;

...

JsonReader reader = Json.createReader(new FileReader("jsondata.txt"));

JsonStructure jsonst = reader.read();

读入一个表示 Json 数据的字符串,可能把它写到了一个文本文件里,读入进来的时候是用的 Json 里面的 createreader 方法读起来,读进来之后就得到了 Jsonstructure,就可以访问里面的内容,这是看到的一种方法,这种方法读下的 jsonstructure 有可能是个单一对象,有可能是个数组,反正都是 jsonstructure 的一个类。

怎么去组装出一个 json 对象?这里给了个例子,

import javax.json.Json;

import javax.json.JsonObject;

...

JsonObject model = Json.createObjectBuilder()

.add("firstName", "Duke")

.add("lastName", "Java")

.add("age", 18)

.add("streetAddress", "100 Internet Dr")

.add("city", "Java Town")

.add("state", "JA")

.add("postalCode", "12345")

.add("phoneNumbers", Json.createArrayBuilder()

.add(Json.createObjectBuilder()

.add("type", "mobile")

.add("number", "111-111-1111"))

.add(Json.createObjectBuilder()

.add("type", "home")

.add("number", "222-222-2222"))

.build();

通过这个结构创建一个 json 对象的空间器,然后去 add firstName,这是装进去的名字对,在 phonenumbers 这个地方,它本身又包含了这个数组,所以它的值是用 Json 的 createArray 创建的 Builder 数组,Array 里面包含了两个 Json 对象,所以用它们去创建。这个 json 对象里有 type 是 mobile,它的 number 是111-111-1111,上面的是移动电话的,底下的是家庭电话。带这种结构去写能看清楚层次的关系,看出来这是一个层次结构,这就是在组装 json 对象,在 Java 这端想把对象组出来,组到最后六个一项,能得到一个 json 的 object,就是从无到有创建出 object,这些值可以像刚才写的例子代码里面类似的,可以从 Java 对象里面通过 get 方法得到,设备这些 name,于是就得到这样的 json 对象。

如果给了 json 的对象,要知道刚才方向是在组装 json 对象,底下是说在前面 read 出来 json 的对象,怎么知道里面的内容?

public static void navigateTree(JsonValue tree, String key) {

if (key!= null)

System.out.print("Key "+ key+":");

switch(tree.getValueType()) {

case OBJECT:

System.out.println("OBJECT");

JsonObject object = (JsonObject) tree;

for (String name : object.keySet())

navigateTree(object.get(name), name);

break;

case ARRAY:

System.out.println("ARRAY");

JsonArray array = (JsonArray)tree;

for (JsonValue val : array)

navigateTree(val, null);

break;

比如这里写了一个 navigateTree 方法,就是要便利 json 对象,便利过程是假设在对象里面,要不断的用递归的方式去访问,所以先看值的类型是什么。Json 的对象一开始进来就是一对大括号,这种类型就是 object,所以如果碰到是 object,在这里做一些处理,比如输出一下 object,把 tree 强制转换成一个 jsonObject,然后遍历它里面所有的 key。这里面有一组名字对,把它所有的名全部拿出来遍历,遍历时一开始如果是对象,就把里面所有的名字拿出来,对于每一个名字,再去判断它到底是一个具体的值,还是又像这里一样,它又是个 json 对象或者又是个数组,数组里面又是个阶层对象。它既然是棵树,所以以递归的方式去处理,如果它拿出来的名字本身对应的后面又是一棵子树,就再去遍历它,递归的调用去遍历,但是这次遍历是在遍历 name 之下的所有东西,怎么告诉它是 name 之下所有东西?首先,在上面 get name,把 name 对应的值拿出来,其次,遍历的时候从 name 开始遍历,这就是 key 的由来。一开始进来 key 肯定是空的,从根开始,如果这是一棵子树,有了这个 key,并且把 Key 下面对应的子树拿出来遍历,如果是子数,key!= null 条件就满足,它就会写出提示"Key "+ key+":"。这是对于如果是子树的情况是怎么样来的,如果进去不是子树,比如在这里一开始进来,发现后面这是一个数组,对于数组,把这棵要遍历的子树变成 JsonArray,就是里面会有一组 Json,对里面的每一个 Json 仍然去遍历它,这时候它们是在数组里的一组 Json 对象,所以 navigateTree 没有 key 的概念,它们都在 key 底下挂上,它们组合起来是 key 的元素,所以在这里面遍历它 key 就是空的。

继续调用,

case STRING:

JsonString st = (JsonString) tree;

System.out.println("STRING " + st.getString();

break;

case NUMBER:

JsonNumber num = (JsonNumber) tree;

System.out.printIn("NUMBER " + num.toString();

break;

case TRUE:

case FALSE:

case NULL:

System.out.printIn(tree.getValueType().toString());

break;

}

}

它的后面直接跟着的是个字符串,直接取字符串的值出来打印,如果是数字,直接取数字值输出,如果是 true、false、null 这三类,就直接输出 System.out.printIn(tree.getValueType().toString ()),然后结束。这就是6种类型加上它能带嵌套的定义 Java object,这就是遍历它里面所有内容的一种方法。

把一个对象组出来了,怎么把它真正写出去?

StringWriter stWriter = new StringWriter();

try (JsonWriter jsonWriter = Json.createWriter(stWriter))

{

jsonWriter.writeObject(model);

}

String jsonData = stWriter.toString();

System.out.println(jsonData);

创建 Json.createWriter(stWriter)),把刚才定义的模型就这样写出去,可以把它写成一个字符串,然后把字符串一次性的打印出来,或者是传到前方去,这个代码和刚才写的不一样,刚才在例子里用的是 fastjson,这里面用的是 Java Json 的 API 的默认实现,这两个 API 有点不一样,大体意思是差不多的。


三、Using the Streaming API

刚才的 object 类型的 API,底下是 streaming 类型的 API,

JsonParser parser = Json.createParses(new StringReader(jsonData));

while (parser.hasNext()){

JsonParser.Event event = parser.next();

switch(event){

case START_ARRAY:

case END_ARRAY:

case START_OBJECT:

case END_OBJECT:

case VALUE_FALSE:

case VALUE_NULL:

case VALUE_TRUE:

System.out.printIn(event.toString();

break;

case KEY_ NAME:

System.out.print(event.toString() + "" + parser.getString() +"-");

break;

case VALUE_STRING:

case VALUE_NUMBER:

System.out.println(event.toString() + "" + parser.getString();

break;

}

也就是说,我没有一次性把整个的数据全部拿出来建一个对象,而是不断的引流的方式处理,所以仍然是在读这份 json 数据,但是会去看它有没有碰到下一个事件,只要碰到,就是还没有读完,不断的激发的产生事件,取出事件来看这个事件是一个数组的开始,还是数组的结尾,是对象的开始,还是对象的结尾,是碰到了一个 false,碰到了一个 null,还是碰到了 true,凡是这些情况直接把事件输出,如果碰到了 key_name,就是读到了一个键值对,读到了这个键,就要去输出,首先输出 event.toString(),然后把键的名字取出来输出,就是这个事件先输出 key_name,然后再输出 key 的名字。上面这些就是直接打印的 case 里面的,碰上键,要把键具体内容输出一遍,键的后面它的类型是 true、false、null 或者是数组,或者是 string,或者是 number,只要输出是字符串或者是数字,我也跟前面的 Key 一样输出一下,碰到的字符串或者数字,因为它没有变化,false 就是 false,没有额外的东西要写,这样大家看到的循环,只要它一直没有处理到 json 对象的末尾,它就不断的会有实现激发,不断的会看到有这些当中的某一个被触发,就会产生这样的输出,就会把 json 里面所有的内容输出。我们写的比较简单,逻辑就是直接去输出,如果有复杂逻辑,这地方就要写一个语句块去处理,或者写个调研函数去处理,拿到的这个内容想干什么也是自己的视角。

靠它来生成,用 streaming 方式生成,跟刚才看到的用对象的方式生成基本一样,它只是写法有点不一样,

FileWriter writer = new FileWriter("test.txt");

JsonGenerator gen = Json.createGenerator(writer);

gen.writeStartObject()

.write("firstName", "Duke")

.write("lastName", "Java")

.write("age", 18)

.write("streetAddress", "100 Internet Dr")

.write("city", "Java Town")

.write("state", "JA")

.write("postalCode", "12345")

.writeStartArray("phoneNumbers")

.writeStartObject()

.write("type", "mobile")

.write("number", "111-111-1111")

.writeEnd()

.writeStartObject()

.write("type", "home")

.write("number", "222-222-2222")

.writeEnd()

.writeEnd()

.writeEnd();

gen.close();

它不是在 add 完了之后,直接 build,它先 start 一个 object,然后去 write,完了之后它所有东西全部都是一个对号,就是一括号,然后对起来,比如这里在 start Array,这边就要去结束这个 Array,这边在 start Object,这边就要去 end 掉它,这里 start object,这块就是 end,end 和 start 是对应出现的,里面具体内容就是键去对,跟刚才没有本质区别,但是从这个代码可以看出来,它就是一点一点的往里写,到最后 end 结束,直接关闭就写完了,所有东西操作完了。前面这个看到的是在告诉它,在 add 进去,最后六个这个动作才真正去生成 model 里面的内容,所以前面的工作认为在准备,全部准备完了,在内存准备完了,它一次性产生 json 对象,而后面这个相当于它一次写出一点,最后写完了,就结束了,所以这是它 streaming 的一个 API。


四、An example

现在讲的全是在 Java 这段,看一个例子,前后台拼起来的例子,

......

<form action="" style="margin-top: 15px;">

<table>

<tr>

<td align="right">First Name:</td>

<td><input type="text" name="firstname" id="firstname" size=20 /></td>

</tr>

......

<tr>

<td align="right">Phone Number 1:</td>

<td>

<input type="text" name="phoneNumber1" id="phoneNumber1" size=20 />

<select name="phoneType1" id=" phoneType1">

<option value="Home">Home</option>

<option value="Mobile">Mobile</option>

</select>

</td>

</tr>

......

</table>

<p>

<button type="button" onclick="ajaxRequest()">Create a JSON Object</button>

</p>

<textarea id="textarea" cols="70" rows="20"></textarea>

</form>

......

在前台有一个 form,里面有一个表,这个表填 first name,last name 等等,还有 phone number,phone numbers 本身又包含了刚才看到两个 phone number,不管怎样,这是一个 form,这个 form 上填了很多东西,它底下有一个按钮,这是一个 button,button 在按下的时候,我们希望它能够去调用我们写的 ajax 的函数,然后做通信。注意 form 底下有一个 textarea,就是一个文本域,看一下它的样子,

图片50.png

整个里面所有的内容在一个 form 里,点击create a JSON 对象的时候,它就会发一个 ajax 请求,这个 ajax 请求在干什么?

var infoMsg = new Object();

infoMsg.firstname = document.getElementByld("firstname").value;

......

var phone = new Object();

var phoneTypel = document.getElementByld("phoneType1").

options[document.getElementByld("phoneType1").selectedIndex].text;

var phoneNumber1 = document.getElementByld("phoneNumber1 ").value;

phone[phoneType1] = phoneNumber1;

var phoneType2 = document.getElementByld("phoneType2").

options[document.getElementByld("phoneType2").selectedIndex].text;

var phoneNumber2 = document.getElementByld(" phoneNumber2").value;

phone[phoneType2] = phoneNumber2;

infoMsg.phoneNumbers = phone;

var jsonstr = JSON.stringify(infoMsg);

xmlHttpRequest.open("POST","JsonServlet",true);

xmlHttpRequest.setRequestHeader("Content-type","application/x www-form-urlencoded");

xmlHttpRequest.onreadystatechange = ajaxCal;

xmlHttpRequest.send("content=" + jsonstr);

console += "Sent: " + jsonstr + "\n";

document.getElementByla("textarea").InnerHTML = console;

这是在 justscript 这一端,它先创建新的对象 infoMsg,然后它的firstname 就是到这个页面上去抓 ID 叫 firstname 的 input 里面的值,所以抓了它的值,以此类推,Last name、age、Street Address、City、State、ZIP code 这些都是这样处理的,但是到 phoneNumber 有点差异,新创建一个 phone 对象、Phone type,因为有两个 phone,phone type1 元素里面它选的那个值,什么意思呢?

图片51.png

这地方可以选这是 home 还是 mobile。phone type1的值应该是这里面选出来的值,所以这个标签里的 option 里选中的 option 对应的文本是什么。因为 option 里面也许索引是0和1,0对应的是 home,1对应的是 mobile,把文本取出来就是 phone 的 type,phone number 是在文本框里填进东西,底下是另外一个 phone,这个 phone 把它定义成 object,在底下可以看到做动作时在 phone 把它当一个 map 来使用,在里面 Type1的键对应的值是它,Type2 对应的值是它,然后就把 phone 组出来了,把 phone 整个作为前面对象叫 phone numbers 的属性。

全部做好之后 infoMsg 对象已经组好了,用 JSON.stringify 这个函数把它转成 JSON 的字符串,这时就是纯文本的 JSON 字符串,这个字符串是对着这样的位置去发一个 POST 的请求,在发出去之后会说当状态发生变化的时候毁掉另外一个函数 ajaxCall,在发送的时候要告诉是 post,所以可以带参数,参数是 "content=" + jsonstr,就是前面填的字符串。

填进去之后要注意在 console 上输出,也就是 sent +什么数据。在这个位置上,

图片52.png

这个叫 console,要输出信息。随便选一个,比如填了一些信息,一点 Create a JSON,

图片53.png

前面这些就是刚才看到的,最后一句话说把东西发走了,这就是看到的它发出去的东西,因为在 phone numbers 只填了一个,另外一个没填,所以这个地方只有一个,它是对着 JsonServlet 位置发的,所以后台的 Java 代码实际上就是在这个位置上监听,

图片54.png

有一个 servlet,看到 servlet 监听的就是刚才看到的 JsonServlet 位置,它在干什么呢?

图片55.png

看它的逻辑,拿到请求之后,从里面把 content 取出来,解析 content,response 会生成一个 out,out 里调用 build Json 之后产生的结果,看这两个函数分别在做什么,

图片56.png

ParseJson 用的是刚才的 API,就是用 Json 的 createRreader 对着 content 读进来内容,读进来这个对象就在这了,之后要去调用 printTree 的方法,把里面的内容打印出来,printTree 就是刚才写的函数稍微加了一点辅助信息,printTree 给了一个 json 对象,开始看到的给的是从 content 里读出来的 json 对象,

图片57.png

拿过来之后看值的类型是否跟刚才写的一样。如果是对象,把这个数拿出来,为了让输出带缩进,就是现在是第几层,一开始第0层,所以第0层就在这里循环,前面多加几个空格,第1层就有1个空格,第2层有2个空格,跟刚才不一样。System.out . println(LeveL +" "+ tree.getValueType().toString()+ " "+ key+ "--")它会说去输出层数,加空格加当前这棵树它的值的类型等于是一开始进来,当然是第0层,它的类型是 object,后面地方加上它的 key,一开始进来是没有 key 的,因为整个对象没有 key,所以直接输出了减号减号。再往后,对于里面所有的 key,就是进来以后的,像 first name、last name、age 这些,不断拿到,每个都递归调用 printTree 函数,然后把当前的每一个拿到的名字作为下一次遍历的起始,level 要加1,name,就是每一个键是什么,余下的递归了。

先看简单的,

图片58.pngFalse、true 或者是空,实际上什么都没干,直接把这3个东西拿出来转成字符串,按照前面它是第几层的前面加几个空格方式给它输出。如果是 number 或者是字符串,它也是直接先打印出来空格,打印它是第几层的,它的类型是什么,它是字符串还是 number,加上它的 key 和 key 对应的值。

图片59.png

所以这里看到 firstname 和 lastname chen 都能给推示出来,因为 age 没有填,所以它这块是空的。

比较复杂是 array,

图片60.png

如果是 array,它也是拿出来之后先是下面加空格,然后输出它的类型 array,后面是 key,对应 array 里的每一个元素都定位调用一下。但是现在只要递归调用,它的 level 要加1,于是后端就把整个 Json 对象遍历了一遍,这是前台组装了一个 Json 对象发到后台,后台把它发出来了这样一个过程。

protected void processRequest(HttpServletRequest request,

HttpServletResponse response)

throws ServletException, l0Exception {

String content = request.getParameter("content");

parseJson(content);

PrintWriter out = response.getWriter();

out.println(buildJson();

}

public void parseJson(String content) {

try (JsonReader reader =

Json.createReader(new StringReader(content))) {

parsed = reader.readObject();

}

this.printTree(parsed, 0, "");

}

这是刚才看到的后台的代码。

public String buildJson() {

JsonObject model = Json.createObjectBuilder()

.add("firstName", "Tom")

.add("lastName", "Jerry")

.add("age", 10)

.add("streetAddress", "Disney Avenue")

.add("city", "los angles")

.add("state", "CA")

.add("postalCode", "12345")

.add("phoneNumbers", Json.createArrayBuilder()

.add(Json.createObjectBuilder()

.add("number'", "911")

.add("type", "HOME"))

.add(Json.createObjectBuilder()

.add("number", "110")

.add("type", "OFFICE")))

.build();

后台紧跟的第二个函数是 buildJson,前台发了一个 Json 到后台,后台拿到之后把它打印出来。要实现双向通行,所以后台也主应一个 Json 对象发回到前台。比如在这里用刚才的东西创建一个新的 model,add firstname 就是 Tom,lastname 就是 Jerry,age 等等都加进去。在这个地方有个电话号码,一个是家庭电话911,OFFICE 电话110,这样 build 之后,json 对象就有了。

StringWriter stWriter = new StringWriter();

try (JsonWriter jsonWriter = Json.createWriter(stWriter)) {

jsonWriter.writeObject(model);

}

return stWriter.toString();

然后把它写回到前台,有两种方式,一种是上面这样的,底下看起来稍微麻烦,用的对象不一样,

/* Write formatted JSON Output */

Map<String,String> config = new HashMap<>();

config.put(JsonGenerator.PRETTY_ PRINTING, "");

JsonWriterFactory factory = Json.createWriterFactory(config);

StringWriter stWriterF = new StringWriter();

try (JsonWriter jsonWriterF = factory.createWriter(stWriterF)) {

jsonWriterF.writeObject(model);

}

return stWriterF.toString();

}

但不管怎么说把它写出去,转成整个 Jason 对象,最终都是把它转成了一个字符串。转成字符串之后看到刚才代码里 buildJson,组装好了这样的 json 对象 build 以后,把它写出到字符串里。

图片61.png

上面这种方法或者底下这个方法都可以。这块它已经注释掉了,所以相当于用的是底下这个方法,把底下的注释掉就相当于用上面的方法。它就是在返回一个字符串,返回这个字符串是拿到字符串以后,把它写到响应里就发回去了,于是就发回到了前端,可以看到前端收到了这个 json 对象,

图片62.png

这就是在后端组装的对象,

图片63.png

所以前端确实收到了,这就是完成了一次后端组装以后往回发的过程。运行起来是这个效果,

图片64.png

前端拿到之后怎么处理呢?

这个脚本是说,当有响应回来时来调 ajaxCall 函数,函数做得比较简单,

图片65.png

就是把返回的文本,注意用的是原生的 ajax,没有用任何的框架,把返回的原文本替换到 console 的控制台上,让它里面的内容 Council 本身等于现在的内容加上 Received,从后台发回来的文本的内容,等于说把它追加到 console 里,拿 console 替换到文本域里的内容,

所以在这边看到了上面是发出去的内容,发出去之后回来的是拿上面发出的内容加上 received,后面是接收到的内容,前端在做解析的时候再怎么解析是前端的事情,要做的就是把它转成 Json 对象之后,前端有 Json 的库去调用它。具体的代码就像刚才看到的树的例子一样,把前端的东西拿到之后,这个数据就看自己怎么用,因为得到了 json 对象,这是看到的前后端互相之间通,后端收到前端发过来的东西,

图片66.png

前端通过这里填进去组装出来一个 Json 对象发到了后端,

图片67.png

后端把它解析出来,后端产生一个 Json 对象把它传到前端,前端把它给解释出来,所以这就是在做 Json 的处理的时候,实际上是 Java 这端和 Js 这端两端都要去做,一发一收,如果是双向的就要既有收又有发。

如果是这样的情况,Ajax 是帮我们搞定前后端的交互。要提高用户体验,无论是要拿下订单还是要抓取用户的数据,都要从 Ajax 来,但是真正的数据无论是把订单数据发到后端,还是要从后端拿回来 book 的数据,都应该是 Json,用 Jason 来描述。Json 本质是 Java 语言,就是 javascript 语言,是没有办法把 Java 的一个 object 直接通过网络传到这边来,然后 javascript 能处理。反过来也一样,能在网上处理的只能是纯文本,所以确实可以不需要一定要用 Json,用 X-mail 或者任意一种自定义的东西都可以。但问题是 Json,无论是 Java 还是 javascript 都有很多库,就像组 Json 对象这种事情,看起来简单,自己写一个组装的逻辑也不难,但是用库会简单很多,所以用 Java 或者 JS,靠 Json 的格式去组装,用现有的库去组装,它会变得比较简单,就容易实现。X-mail 也有很多现成的库,确实也可以,但它的数据量比 Json 相比要多。两个都不用自定义,自定义就意味着这个格式的正确与否完全取决于自己,完全没有必要、不需要这样做,所以前后端传 Json 是一个比较理想的方式。

现在来看,从前端到后端完整的一个数据交互的过程是什么?前端要把它在各个控件里的东西抓取出来,组成一个 Json,就是在 input 里先组成一个 Json,然后发到后端,后端的 Java 这一端拿到之后把它转成一个Java的对象,对象转完之后,比如是在下订单,那它还得写到数据库里,如果是反过来数据库里的数,通过 caplet 把它表示成了 Java 的一个对象,这个对象会通过 Json 的方式、Json 的库转成一个 Json,然后发回到前台,前台拿到 Json 以后解析出 Json 包含的信息再去展示,完整的是这样一个过程,写的代码应该有这样的东西,完整的路径是这样来实现的。所以在使用 Json 时要考虑它应该是这样的,后端的代码用之前讲的,用 ORE 映射已经有了实体层,有很多 repository 层,repository 是从工具里面自动生成的,比如 GPA 或者 hamlet。

为什么在这上面还要有 DAO 层?如果数据不是全从官营数据库里来的,一部分在官营数据库里,一部分在其他数据库里,但是合起来完整的概念需要一个 dao 层,dao 这一层之上才是真正接收请求、去做处理的代码。接收请求现在给的代码全是 sevlet,真实的情况下在写大作业的时候都用框架,要么用了 Spring,要么用了其他的框架,比如接下来要讲的 struts。这两个框架都把 servlet 包装变成一边叫 Action,一边叫 controller。但它的道理和 servlet 类似,都是对它的包装,有了它之后应该是去处理前端的请求,真正到后面应该去调哪些 dao 能实现它的逻辑,不是跟后端的 dao 一一对应的,所以中间插入了一层 service,service 在处理真正的业务逻辑,而前端的 controller 或者 action 是在处理过来的请求应该怎么去接收,怎么去到调用后台的服务去实现它,所以这就出来了反反复复看到的那个分层结构,从前端的 controller 到 service 再到 repository,再到实体,这样分层是怎么来的。

前面的课是在解决 Gntity、repository、DAO,DAO只解决了一半,因为还没讲非关系性数据库。如果在没有 Spring、struts、controller、Action、service 这些框架的基础上,代码就写个 servlet,到目前为止都是出现 servlet。最终形态是底下这样,所以现在要过渡到 controller,谈谈这些替代掉 servlet 的东西是怎么写的,这就是接下来的内容 MVC 的架构。

 

五、Postman

接口测试,如果在写代码的时候不想总是在浏览器里跑,也可以用 postman,选它用什么方法,发请求出去底下就会出来响应,比如对着 JsonServlet 跑,get 一下,其他不动,可以看一下返回的结果,

图片68.png

出异常了,不允许这样直接跑,可能在里面加东西了,不能这样加,

图片69.png

如果这块没有什么其他问题,它会返一个结果。

在调试程序的时候,如果觉得总是从网页上访问比较麻烦,也可以用 postman。

图片70.png

这地方写了用 postman 访问时每个位置表示什么意思,这只是工具问题,觉得还不如网页直观就不用。

 

六、过渡

过渡到 MVC 架构,从 STRUTS 来讲。STRUTS 要解决的就是看到的 MVC 框架,使用 MVC 框架实现业务逻辑,就要涉及到什么是 MVC。MVC 是 Model-View-Controller 这三个词的缩写,View 就是看到的东西,就是我给你发送了一个请求,你给我一个响应,让我在这个响应里面看到什么。

Controller 是请求来了之后应该怎么去调度它,所以看到一个请求要求往购物车里放东西,Controller 拿到之后就会把这个请求转给某个后台的服务去做处理,这就是业务逻辑,它在执行真正的把物品放到购物车里的逻辑,把它放进去之后,它会告诉用户会返什么样的页面,返回的页面就会抓 Model 里的内容出来,然后 Model里的内容发生变化会通知到它,它抓回来之后就可以去看到里面的内容,一个管呈现,一个管业务的逻辑,一个管像业务的流程。就是过来一个东西到底是哪个逻辑来处理,比如要支付,比如后台有两个 Model,一个是用信用卡,一个是用现金,到底是用现金还是信用卡是靠 Controller 来控制,就是接到请求之后来决定调用谁。它俩只管给它数据,它就用它逻辑方式去处理,处理完之后结果就会有比如是支付成功了或者是支付失败了,结果会保留在 Model 里。

Controller 就会去决定,对于用户如果支付成功了,让他看到页面 A,如果支付失败了,让看到页面 B,然后它会把 A 让用户去呈现,经过串联比如用信用卡支付,调到信用卡支付上,成功之后就看 A,A 就会去抓取信用卡支付的 Model 里的数据,比如什么原因成功了,这时候 A 和 credit card 建立关联,如果调度到了 cash 现金支付里,A 就会去抓 cash 里它成功或失败的原因去呈现,所以三者之间是解耦的,一个 View 没有说一定要去抓某一个 Model 里的东西,它会看当时动态分配过来是谁去处理的,就到谁那里去抓这个信息过来。

Model 也没有说和具体的业务要请求绑定,完全是靠 Controller 分发,Controller 居中在做调度,本身不实现业务逻辑。到底怎么用信用卡支付或用 cash 支付,这件事情是 Model 自己去做,我只管去调用,具体逻辑自己去写,三者之间职责非常明确, 而且 View 和 Model 之间实现了一次解耦,这就是它的概念。

这样讲很空洞,要靠实际的例子来看,有一个实现这种架构的框架—— Struts,Struts 虽然比较老,但用它来讲会比较明白 MVC 的概念,讲完 Struts 回头再去看 Spring MVC,就会觉得异常的简单,所以先从 Struts 入手。

相关文章
|
XML JSON 数据可视化
数据集学习笔记(二): 转换不同类型的数据集用于模型训练(XML、VOC、YOLO、COCO、JSON、PNG)
本文详细介绍了不同数据集格式之间的转换方法,包括YOLO、VOC、COCO、JSON、TXT和PNG等格式,以及如何可视化验证数据集。
3564 1
数据集学习笔记(二): 转换不同类型的数据集用于模型训练(XML、VOC、YOLO、COCO、JSON、PNG)
|
JSON 前端开发 JavaScript
JavaWeb基础8——Filter,Listener,Ajax,Axios,JSON
Filter过滤器、Listener监听器、AJAX、 同步、异步优点和使用场景、Axios异步框架、JSON、js和JSON转换、案例,Axios + JSON 品牌列表查询和添加
JavaWeb基础8——Filter,Listener,Ajax,Axios,JSON
|
XML JSON 前端开发
JSON与AJAX:网页交互的利器
JSON与AJAX:网页交互的利器
150 0
|
XML JSON 前端开发
Ajax – JSON入门指南
Ajax – JSON入门指南
187 1
|
XML JSON 前端开发
第十一篇JavaScript JSON与AJAX
第十一篇JavaScript JSON与AJAX
111 0
|
JSON 前端开发 JavaScript
jQuery ajax读取本地json文件 三级联动下拉框
jQuery ajax读取本地json文件 三级联动下拉框
171 0
|
XML JSON 前端开发
|
XML JSON 前端开发