如何实现前端给后端传参
在学会了如何去自己手动构造HTTP请求后,我们就要去实现服务器去接收这个HTTP请求然后处理它并且处理后的内容返回,此时就需要使用到我们之前说到故的Tomcat + Servlet来实现了
1、query string获取前端发起的GET请求
首先第一种,后端通过query string的方式去获取前段的GET请求,对于query string 我们在讲解HTTP协议的时候有说起过,就是?
后面加上键值对的形式去构成
那现在的话我们就要通过后端的代码来处理这个请求了
- 首先最重要的就是加要上这个
@WebServlet()
的注解,这个其实就相当于服务端提供给外部的一个标识,前段便可通过这个注解的标识来发送对应的HTTP请求 - 当然在Tomcat服务器接收到这个HTTP请求后,还要去将其解析为【HttpServletRequest 】对象,接着便将其交给Servlet做处理,这里我们使用
getParameter()
就可以通过找寻对应的key来获取相关的value了,最后呢通过resp对象再给到浏览器做响应
@WebServlet("/getParameter") public class GetParameterServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("text/html charset=utf-8"); String userId = req.getParameter("userId"); String classId = req.getParameter("classId"); resp.getWriter().write("userId = " + userId + " classId = " + classId); } }
- 最后我们就可以看到浏览器上显示出了对应的内容
2、form表单获取前端发起的POST请求【⭐】
GET请求发送完后,我们再来试试POST请求,主要是通过form表单来实现
- 这里的HTML代码我们前面在通过form表单构造HTTP请求的时候有写过
<form action="postParameter" method="post"> <input type="text" name="userId"> <input type="text" name="classId"> <input type="submit" value="提交"> </form>
- 那后端这块的逻辑还是和query string差不多,就是重写的方法要为
doPost()
而已,然后的话注解标记记得也做个修改
@WebServlet("/postParameter") public class PostParameterServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("text/html charset=utf-8"); String userId = req.getParameter("userId"); String classId = req.getParameter("classId"); resp.getWriter().write("userId = " + userId + " classId = " + classId); } }
- 看到最后返回的结果还是这样,通过无论是GET还是POST的请求一样都可以进行处理
重点:『图解前后端交互全过程』
对于form表单这种请求来说,可能对于一些初学者不是很好理解,这里我画了两种图,希望可以帮助到你
==网页端与服务端交互请求全过程==
==浏览器与tomcat的两次交互过程==
3、json格式解析获取前端发起的POST请求
如果 POST 请求中的 body 是按照 JSON 的格式来传递,那我们在前后端交互的过程中又会发生怎么微妙的变化呢?
① postman发送HTTP请求
- 首先我们简单一点,使用现有的工具postman去构造一个body为【json】格式的POST请求
- 然后再来到后端这里写Servlet的代码逻辑处理这个POST请求。不过呢,这和我们上面缩写的可不太一样。因为在body中是【json】格式的数据,因此我们无法直接通过某种方法来精准获取里面的内容,那就只有一个办法:全部读出来!
- 那在讲解网络socket的时候,我们有说到过可以用
getInputStream()
去读取管道中的字节流,倒入到容器中,取多少倒多少,最后再转换为String的对象,打印出来的内容即为我们读取到的对象,代码如下👇
@WebServlet("/postParameterP") public class PostParameterPostman extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //在流对象中读取的字节数取决于ContentLength int length = req.getContentLength(); byte[] buffer = new byte[length]; InputStream inputStream = req.getInputStream(); inputStream.read(buffer); //以字节形式读取HTTP报文格式中的数据 String body = new String(buffer, 0, length, "utf-8"); resp.getWriter().write(body); System.out.println(body); } }
最后我们来看一下运行结果吧
② Ajax构造HTTP请求
说完了使用postman来发送HTTP请求,然后我们再用Ajax来试试,前面我们有介绍过了,但是人家搜狗的服务器不处理我们的请求,因此就报出了错误,但现在我们学习了Tomcat和Servlet后,就就可以自己去实现服务端的代码逻辑了
@WebServlet("/postParameterA") public class PostParameterAjax extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("applicaiton/json;charset=utf-8"); String body = readBody(req); resp.getWriter().write(body); } private String readBody(HttpServletRequest req) throws IOException { //首先获取到body主体的内容长度 int length = req.getContentLength(); byte[] body = new byte[length]; InputStream inputStream = req.getInputStream(); inputStream.read(body); //把管道中的数据读入桶中 return new String(body, 0, length, "utf-8"); //再构造String对象返回 } }
- 对于前端的代码,我们要做一些修改,改用按钮点击事件
<button onclick="sendJson()">发送 Json 格式POST请求</button>
- JS的话把Ajax的请求包在
sendJson()
的按钮点击事件中,并且写好对应的5个属性,
<script> function sendJson(){ ajax({ method: 'POST', url: 'postParameterA', contentType: 'application/json;charset=uft-8', body: JSON.stringify({ "userId": 10, "classId": 20 }), callback: function(body, status){ console.log("回调函数会在之后调用"); console.log(body); } }) } console.log("浏览器立即往下执行后续代码"); function ajax(args) { var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function () { // 0: 请求未初始化 // 1: 服务器连接已建立 // 2: 请求已接收 // 3: 请求处理中 // 4: 请求已完成,且响应已就绪 if (xhr.readyState == 4) { args.callback(xhr.responseText, xhr.status) } } xhr.open(args.method, args.url); if (args.contentType) { xhr.setRequestHeader('Content-type', args.contentType); } if (args.body) { xhr.send(args.body); } else { xhr.send(); } } </script>
接下去我们来看看运行结果
- 首先是一开始进入浏览器的样子,可以看到就打印出了我们在最后所写这句话,然后并没有去调用这个
callback()
回调函数,这是因为我们在前端的页面中什么都没有做,即没有向服务器发送HTTP请求,因此也不会触发这个回调函数的调用机制
- 不过在我们点击了这个按钮后,网页端便发送了一个POST请求给到服务端这里,服务端在接收并处理这个HTTP报文后,返回给浏览器做响应,此时这个回调函数便被调用了,打印出了语句和【json】格式的body主体
拓展:Jackson第三方库解析json格式
就上面两种构造json格式的方法,我们在服务器这边只是将整个body给读了出来,但是,但是并没有按照键值对的方式来处理,即无法根据key获取value
- 在前面的【query string】和【form表单】中,我们可以使用
getParameter()
这个方法来获取对应的value值,对于【json】格式的数据,我们可以使用第三方库来解决,这个库有很多,例如gson、fastjson,但是在这里我推荐使用 Jackson - 为什么推荐这个呢?相信学习过Spring MVC的同学都应该清楚,它里面天然就支持处理json格式的数据,就是因为内置了Jackson这个库来解析json格式
第一步: 在中央仓库中搜索 Jackson, 选择 JackSon Databind
第二步: 选择2.12.3版本,找到Maven依赖第三步: 在pom.xml
文件中添加这个Maven依赖
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.12.3</version> </dependency>
第四步:重新创建一个Java类,继承自HttpServlet类,然后使用Jackson中的核心对象ObjectMapper去完成json格式的解析
class Student{ public String userId; public String classId; } @WebServlet("/postParameterJaskson") public class PostParameterJaskson extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 1.使用Jackson使用到的核心对象 ObjectMapper objectMapper = new ObjectMapper(); // 2.使用里面的readValue()方法把里面具有json格式的数据转换为Java对象 Student student = objectMapper.readValue(req.getInputStream(), Student.class); // 3.显示出解析后的数据 System.out.println("userId = " + student.userId + " classId = " + student.classId); resp.getWriter().write("userId = " + student.userId + " classId = " + student.classId); } }
第五步: 在postman中修改对应的WebServer注解,给对应的接口发送HTTP请求,最后获取到服务器和浏览器都观察到解析后的结果
这里讲解一下最后的这段代码,可能有的同学不太理解
- JsonData 这个类用来表示解析之后生成的 JSON 对象. 这个类的属性的名字和类型要和 JSON 字符串的 key 相对应.
- Jackson 库的核心类为
ObjectMapper
. 其中的 readValue() 方法把一个 JSON 字符串转成 Java 对象. 其中的 writeValueAsString() 方法把一个 Java 对象转成 JSON 格式字符串. - readValue 的第二个参数为
JsonData
的 类对象. 通过这个类对象, 在 readValue 的内部就可以借助【反射机制】来构造出 JsonData 对象, 并且根据 JSON 中key 的名字, 把对应的 value 赋值给 JsonData 的对应字段. - 可以来看看这个Jackson库解析【json】格式的全过程,就会很清楚了
总结与提炼
最后来总结一下本文所介绍的内容:book:
- 本文的开端,我们首先了解了如何去构造一个HTTP请求,可以通过form表单、Ajax、postman以及Java Socket的去进行构造,我们主要还是掌握前三种,对于form表单而言最为常见,我介绍了GET请求和POST请求两种,不过对于form表单来说一般发送的还是POST请求居多。
- 知道了如何构造HTTP请求,此时前端就可以在HTTP请求中放置一些内容,后端从这个请求中获取到内容然后处理,那这个前后端的交互就需要有一个接口,它就是【Servlet注解】,前端通过这个
@WebServlet()
里面的参数,决定自己的URL是怎样的;后端呢则通过这个URL来进行精准地接收并做出相应的处理,而且还需根据前端发起的不同请求在不同的方法里做处理(doGet、doPost) - 对于这个前后端的交互逻辑,如果还有不理解的同学可以多去画画图,通过postman去发送各种的HTTP请求,然后通过Fidder抓包进行观察,去清楚双方是如何进行一发一收的这么一个交互逻辑
以上就是本文要介绍的所有内容,感谢您的阅读:rose