java后端开发(五):前端如何理解后端的对象信息

前端和后端的交互

前文说过,大部分情况下前端可以看作是 数据 的需求方,后端可以看作是 数据 的提供方。比如我就是后端,你问我要A的信息,我返回你下面一串东西:

dGhpcyBpcyBhIGV4YW1wbGU=

你能看懂这是什么吗?

同理,如果前后端不以统一的格式来交互的话,也无法正常解析对方的内容。

目前,前后端通信的"运输工具"就是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格式字符串的

先来看个例子:

@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字符串简要例程

为了有一个直观的转换感受,这里给出一个简要的历程

/**
  * 将对象转换成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 类为:

public 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 的返回值是什么样子的。也可以简单理解,不尝试。

public 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的使用可以自行搜索)。

程序如下:

@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 参数没截出来)

程序运行结果是:

this is url
this is header
this is home name...this is home address

现在,前后端如何交互已经说清楚了,但是前端还有一个额外的地方可以传递参数:

我们的后端URL组成可以是 /web/param/{id} ,这个括号括住的 id 就是第四个可以携带参数的地方,那么代码具体怎么体现呢?

可以自行搜索 路径传参 或者 @PathVariable 注解来试试看。


理解了前后端如何交互后,下一节需要了解前后端交互的常见规范,也就是 restful 规范。接着就可以开始学习如何操作数据库,如何编写和数据库交互的后端应用了。

发布了39 篇原创文章 · 获赞 74 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/zhou307/article/details/101469742