前端和后端的交互
前文说过,大部分情况下前端可以看作是 数据 的需求方,后端可以看作是 数据 的提供方。比如我就是后端,你问我要A的信息,我返回你下面一串东西:
1
2dGhpcyBpcyBhIGV4YW1wbGU=
你能看懂这是什么吗?
同理,如果前后端不以统一的格式来交互的话,也无法正常解析对方的内容。
目前,前后端通信的"运输工具"就是HTTP,它由三部分组成,如下图:
这三部分表示我们可以将数据放置的地方,当前端去向后端通信的时候,它可以在这三个空间中挑选放置数据的地方。URL一般来说是放置需要使用后端哪个功能,以及使用该功能时后端所需的一些必要参数;而header一般来说是放置一些和通信本身有关的信息;body 空间最大,可以放置的数据最多,一般用来放置我们的业务数据。
前端-后端的通信是 请求-响应 式的通信方式,后端收到前端响应后,只能利用HTTP的 Header 和 body 部分进行传参,因为 URL 是标识后端功能项的。
又因为HTTP这个协议也就是这个运输工具内部的仓储构造,导致这三个部分不能随意放置,要遵循一定的规范。
URL的放置规范如下:
后端功能地址 ? 参数名=参数值 & 参数名=参数值
通过 ?
来标识后面的就是要携带的数据,数据与数据之间以 &
隔开,每个数据都是一个键值对,键名就是参数名,键值就是 =
后面的数值。
Header的放置规范如下:
参数名:参数值
也是键值对的形式。
那么 body 的呢?body由于主要放是业务数据,甚至是网站代码,body里面的数据格式很灵活。
所以首先要在 Header 中放置一个键值对:
Content-Type: 格式名称
Content-Type
表示 body 里面的格式是什么格式的,比如文本格式,比如图片格式,比如json格式等等。
目前,由于JSON格式的易读性和比较简洁,综合下来是大部分情况下的最佳选项,所以前端后端的交互,在 body 层面就是 以JSON格式 进行交互。
后端的对象是如何转换成JSON格式字符串的
先来看个例子:
1
2
3
4
5
6
7
8
9
10@RestController @RequestMapping("/web") public class TestController { @GetMapping("/jsonstr") public Home getHome() { return new Home("家庭", "湖边"); } }
这段代码的请求结果是:
我们的后端对象返回给前端的实际上就是一段文本信息,格式是JSON格式。那你奇怪吗?为什么 Home
对象就能变成JSON格式的字符串输出,这是谁处理的呢?
答案是 springMVC
,这个框架帮助我们处理了将对象装换成JSON格式字符串的工作。在真正调用我们的 getHome()
方法时,我们的整个框架栈进行了许多的其他处理;在我们的 getHome()
方法返回时,我们的框架栈同样做了很多其他的处理。
又由于后端返回给前端信息,基本上都是从 HTTP的 body 中以 JSON字符串的形式返回的。所以 JSON 格式的理解非常重要,同样的,对象如何转成JSON字符串也要大致理解下。
后端对象转JSON字符串简要例程
为了有一个直观的转换感受,这里给出一个简要的历程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102/** * 将对象转换成JSON字符串的处理类 */ public class JsonMapper { public static void main(String[] args) { JsonMapper mapper = new JsonMapper(); Home home = new Home("thing", "hangzhou"); String jsonStr = mapper.parseJson(home); System.out.println(jsonStr); People people = new People("男", "周"); String jsonStr2 = mapper.parseJson(people); System.out.println(jsonStr2); } /** * 将传入的对象中的具有 getter方法的属性及其值转变为 JSON 字符串进行输出 * 简单处理,默认所有成员都具有 getter方法。 * @param obj 传入的对象 * @return JSON字符串 */ public String parseJson(Object obj) { StringBuilder builder = new StringBuilder("{"); BeanProperty[] properties = getBeanProperty(obj); // 构造JSON字符串 for (BeanProperty property : properties) { builder.append(""").append(property.getName()).append("":""); try { builder.append(property.getGetter().invoke(obj).toString()).append("","); } catch (IllegalAccessException | InvocationTargetException e) { e.printStackTrace(); } } builder = builder.replace(builder.length() - 1, builder.length(), "}"); return builder.toString(); } /** * 将对象转换成 BeanProperty 数组 * 每个 BeanProperty 都包含了对象中的一个属性的名字和其对应的getter方法 * @param obj 对象 * @return BeanProperty[] 数组 */ private BeanProperty[] getBeanProperty(Object obj) { Class c = obj.getClass(); // 获取对象中的成员属性 Field[] fields = c.getDeclaredFields(); BeanProperty[] beanProperties = new BeanProperty[fields.length]; // 获取对象本身包含的方法 Method[] methods = c.getDeclaredMethods(); // 遍历成员,根据成员信息获取对应的getter方法; for (int i = 0; i < fields.length; i++) { Field field = fields[i]; for (Method method : methods) { if (method.getName().toLowerCase().equals("get" + field.getName().toLowerCase())) { BeanProperty beanProperty = new BeanProperty(field.getName(), method); beanProperties[i] = beanProperty; break; } } } return beanProperties; } /** * 对象中的属性类 * 包含每个属性的名称,每个属性对应的 getter 方法 */ private class BeanProperty { private String name; private Method getter; BeanProperty(String name, Method getter) { this.name = name; this.getter = getter; } String getName() { return name; } void setName(String name) { this.name = name; } Method getGetter() { return getter; } void setGetter(Method getter) { this.getter = getter; } } }
运行结果为:
{“name”:“thing”,“address”:“hangzhou”}
{“sex”:“男”,“name”:“周”}
其中,Home 类为:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31public class Home { private String name; private String address; public Home() { } public Home(String name, String address) { this.name = name; this.address = address; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } }
可以看出,转换的规则其实很简单:
将成员变量名当成 JSON 的 键名,将getter方法获取到的值当作 键 对应的数值。
springMVC的转换,也就是最上面第一段程序的例子,其有几个特殊点。感兴趣的话可以试试将 Home 改成如下的代码,再看看 /web/jsonstr 的返回值是什么样子的。也可以简单理解,不尝试。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53public class Home { private String name; private String address; private String lon; public String ele = "0.01"; private static String staticStr = "static"; public Home() { } public Home(String name, String address) { this.name = name; this.address = address; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public String getLat() { return "lat"; } public String getStaticStr() { return staticStr; } public static String getStaticString() { return "static1"; } public static String getStatics() { return "ssss"; } }
后端接收前端数据的三个空间
三个空间分别是文章开头说的 url, header, body。
这里我们使用 postman 来作为HTTP客户端,去请求我们的程序API。(关于postman的使用可以自行搜索)。
程序如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17@RestController @RequestMapping("/web") public class TestController { @GetMapping("/jsonstr") public Home getHome() { return new Home("家庭", "湖边"); } @PostMapping("/param") public void url(String u, @RequestHeader String h, @RequestBody Home home) { System.out.println(u); System.out.println(h); System.out.println(home.getName() + "..." + home.getAddress()); } }
其中, u 表示 参数携带在 url 里面(url 中的 ?
后边的参数);加了 @RequestHeader
字段的参数是请求头传参;加了 @RequestBody
的参数是 body 传参;
其中,Body传参相当于把 JSON字符串转换成 java 对象,其实原理也类似。
postman请求如下:(Header 参数没截出来)
程序运行结果是:
1
2
3
4this is url this is header this is home name...this is home address
现在,前后端如何交互已经说清楚了,但是前端还有一个额外的地方可以传递参数:
我们的后端URL组成可以是 /web/param/{id}
,这个括号括住的 id 就是第四个可以携带参数的地方,那么代码具体怎么体现呢?
可以自行搜索 路径传参 或者 @PathVariable
注解来试试看。
理解了前后端如何交互后,下一节需要了解前后端交互的常见规范,也就是 restful
规范。接着就可以开始学习如何操作数据库,如何编写和数据库交互的后端应用了。
最后
以上就是感动小鸭子最近收集整理的关于java后端开发(五):前端如何理解后端的对象信息的全部内容,更多相关java后端开发(五):前端如何理解后端内容请搜索靠谱客的其他文章。
发表评论 取消回复