每篇一句
做技术其实你并不需要了解非常多的东西,关键是要深刻。
所以那些刚毕业的小鲜肉说它会高并发、会缓存、会搜索你也不必担心,他们大都属于快餐文化
前言
request
对象封装了来自客户端的所有请求信息。在HTTP协议中,客户端发给服务端的所有信息都是通过request
对象的请求头和请求体来传送的。
Servlet请求参数
servlet的请求参数作为客户端请求的一部分都是以字符串
形式传给servlet容器。
参数以键值对
方式存储,而且一个参数名可以对应多个参数值。ServletRequest
接口的以下4个方法用于访问这些参数信息:
- getParameter:返回
getParameterValues
结果的第一个值 - getParameterNames
- getParameterValues:查询一个参数名对应的所有参数值,然后以String数组返回
- getParameterMap:以Map方式返回所有的请求参数,当然,这个Map以参数名为key,参数值为对应的value
从query字串**和post提交的请求体(是有规范约束的,下面介绍)获得的所有请求数据都会包装进请求参数集合(这是个重要概念,可以理解成一个Map)**中。query字串的数据优先性要高于post提交的数据。
简答的说URL里能够get到就以它的为准,若没有再去看~
Servlet参数可用性(POST请求规范)
我们大多数情况下的一个通识:post方式请求,body体里的内容我们是无法使用getParameter
等方式去获取参数的。
But可能你只知其一,不知其二。其实如果你的POST请求符合下面4个先决条件,也是能够使用getParameter()
- HTTP请求或者是HTTPS请求。
- HTTP的请求方法为POST方式。(不支持PUT)
- 内容类型是
application/x-www-form-urlencoded
。 - Servlet上可使用
getParameter
系列方法了
备注:Servlet规范只约束了POST请求,对于PUT、HEAD等请求方式,它是没有办法的处理的
Demo Show:
先写个Servlet:
@WebServlet(urlPatterns = "/hello")
public class HelloServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String hello = req.getParameter("hello");
System.out.println(hello);
}
}
GET请求:http://localhost:8080/demo_war_war/hello?hello=world
。毫无疑问可以正常的获取到值world
。
get请求可以通过request.getQueryString()获取url后面的字符串。
现在我们来一个POST请求,用POSTMAN
模拟请求:
URL:http://localhost:8080/demo_war_war/hello
Headers:
Body:
这样我们虽然参数是写进body体,但是还是使用req.getParameter("hello")
把world获取出来。
这就是Servlet规范,它只作于POST请求~
若POST请求不是application/x-www-form-urlencoded
,怎么获取body体的内容呢?
下面以我们最常见的application/json
为例。
若还是使用req.getParameter("hello")
,拿得到的结果是null。那怎么破呢?
那就只能这样子了:getInputStream()
它的作用官方有说明:Retrieves the body of the request as binary data
,因此我们只需要把这个流读出来成为字符串,就OK啦~~
IOUtils.toString(request.getInputStream())
/当然你在Spring环境,还可以使用StreamUtils、FileCopyUtils来代替对common-io包的依赖~
这样我们就能拿到请求的字符串,若是个Json格式的串,就可以转换为对象了。这也是Spring MVC中@RequestBody
的基本原理
备注:请注意流都是只能读一次的,避免冲虚读取~~
PUT请求可以像POST这样使用规范吗?
显然Servlet默认是只支持POST请求参数的,若是PUT源生的它是不支持的。
如果你使用的是Spring MVC,并且版本号是5.1.x.RELAESE
或以上版本,福利就有了。它给我们提供了一个FormContentFilter
,它能帮我处理这种情况下的PUT请求(其实还有PATCH
和DELETE
请求),比如如下我使用PUT请求:
并且加上此过滤器(此处,因为我是注解驱动的Web应用,所以用编程的方式添加Filter
):
servletContext.addFilter("formContentFilter", new FormContentFilter()).addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), false, "/*");
**完美。**我们依然可以使用req.getParameter("hello")
拿到world这个值啦~~~ 这是强大的Spring MVC 5.1之后的版本赋予我们的能力~
Attribute属性
不同于请求你参数Parameter,它一般用于多个servlet
之间相互沟通交流数据
- getAttribute
- getAttributeNames
- setAttribute:设置属性值~
一个属性名只能对应一个属性值。
以“java.”和“javax.”开头的属性名已经预留给Servlet规范本身。同样的,“sun.”和“com.sun”也已经预留给Sun微系统公司。 命名方式可参考Spring的命名方式~~~
Servlet与请求路径相关的元素
请求路径由多段重要信息组合而成。以下元素有请求的URI获得并由request对象展示:
Context Path
:**和ServletContext
关联的路径前缀。**如果应用的上下文是Web服务URL命名空间的默认上下文,那么Context Path就是空的。否则,它就以斜杠“/”开始开始的。Servlet Path
:这段路径对应着处理请求的映射路径,它始于斜杠“/”。如果请求匹配于“/*”规则,那么这时的Servlet Path会是空字串。- PathInfo:这段既不是Context Path的一部分,也不是Servlet Path的一部分。它要么为空,要么就是以斜杠“/”作为前导字符的一段字符串
HttpServletRequest下述3个方法用于访问这些信息:
- getContextPath
- getServletPath
- getPathInfo
如上面例子结果为:
System.out.println(req.getContextPath()); // /demo_war_war
System.out.println(req.getServletPath()); // /hello
System.out.println(req.getPathInfo()); // null
requesetURI = contextPath + servletPath + pathInfo。
这是个恒等式(除非请求的URI和路径部分的编码不同)
其它相关规范
相对来说不是非常重要的了,提一句即可
- 路径转换的方法:
ServletContext.getRealPath:获取真实路径
- Cookies:getCookies方法去获取请求对象的cookies数组
- SSL属性: HTTPS等安全协议
- 国际化:getLocale(返回客户端更喜欢使用的locale) getLocales
- 请求数据的编码:
当下很多浏览器都并不指定编码格式(默认都是ISO-8859-1),由服务程序自动决定读取请求数据时的编码方法。
getCharacterEncoding
:用于获取客户端显示指定的编码,一般都是null - 请求对象的生命周期:每个
request请求对象
只在当前servlet
的service
方法域内可用,或者是在filter的doFilter方法域内可用。
还有个Servlet的规范,在这里也说了:
在servlet-2.3
中,Filter会过滤一切请求,包括服务器内部使用forward转发
请求和<%@ include file="/index.jsp"%>
的情况
到了servlet-2.4
中Filter默认下只拦截外部提交的请求,forward和include
这些内部转发都不会被过滤(更别谈SpringMVC的拦截器了,更不会被拦截喽~)。当然你若想让你的Filter拦截到所有,你需要显示的做如下配置:
<filter>
<filter-name>myFilter</filtername>
<filter-class>xxx.MyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>myFilter</filtername>
<url-pattern>/*</url-pattern>
<!-- 拦截模式,不写默认只有REQUEST:只拦截外部的请求 -->
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>EXCEPTION</dispatcher>
</filter-mapping>
总结
上面说的对POST请求的这个规范是Servlet 2.4
就已经出来了,在微服务大行其道的今天,大都是前后端完全分离的架构设计。前后端通讯基本采用更加轻量级的JSON
格式,所以他们的Config-type
一般都是application/json
方式,自然而然就不符合Servlet规范了~
另外其实我们也能感觉到,随着Spring5.0的发布,Servlet的地位已经被撼动了。相信在不久的将来,它将成为历史。但是技术都能触类旁通的,技多不压身~~
希望此文对你有帮助,毕竟,毕竟,毕竟Servlet还是现在的主流~~~未来3-5年依旧
关注A哥
Author | A哥(YourBatman) |
---|---|
个人站点 | www.yourbatman.cn |
yourbatman@qq.com | |
微 信 | fsx641385712 |
活跃平台 | |
公众号 | BAT的乌托邦(ID:BAT-utopia) |
知识星球 | BAT的乌托邦 |
每日文章推荐 | 每日文章推荐 |