HttpServletRequest和HttpServletResponse
在前几篇博客中介绍了servlet,也详细描述了自定义的类继承HttpServlet作为一个标准类的原因。
这篇来分析一下doGet和doPost方法中的参数
doGet/Post方法,见名知意,表示的是对get/post请求的处理
因为post的请求方式太过于少见,只用于表单提交数据的请求当中
最常用的是get方式的请求。
因为一个标准servlet类中存在着doPost和doGet方法
所以提供一种小技巧:在doPost方法中调用doGet方法,一劳永逸。
另外需要进行补充的是:在Tomcat8及其之后的版本中,对于get的请求方式,Tomcat使用的是utf-8进行解析的;对于post请求方式,Tomcat采用的是ISO-8859-1的方式来进行解析,所以,如果要是使用表单的请求方法是post进行请求的,那么在接收请求参数之前,需要先指定解析方式,然后再去进行获取参数。否则乱码
获取请求行中的信息
思想良久:还是将请求方式的总结写在前面
我将请求方式分为两种:
-
第一种:超链接
http://www.baidu.com?username=guang&password=guang http://localhost:8080/guang/login?username=guang&password=guang
如果请求参数有多个,那么使用&来进行分隔
在请求地址后面加上?参数1=参数值1&参数2=参数2&....
表单方式的get方式提交
<form action="/xxx" method="get"> 姓名:<input type="text name="username"/><br> 密码:<input type="password" name="password"/><br> 性别:<input type="radio" name="sex" value="man"/>男 <input name="radio" name="sex" value="famale"/>女<br> 爱好:<input type="checkbox" name="hobby" value="sing">唱 <input type="checkbox" name="hobby" value="skip">跳 <input type="checkbox" name="bobby" value="rap">rap<br> <input type="submit" value="提交" /> </form>
总结:对于get方式作为请求参数需要满足的条件:
在请求地址后面加上?参数1=参数值1&参数2=参数2&....
参数在请求行中
-
第二种:表单
表单形式的post方式进行提交
<form action="/xxx" method="get"> 姓名:<input type="text name="username"/><br> 密码:<input type="password" name="password"/><br> 性别:<input type="radio" name="sex" value="man"/>男 <input type="radio" name="sex" value="famale"/>女<br> 爱好:<input type="checkbox" name="hobby" value="sing">唱 <input type="checkbox" name="hobby" value="skip">跳 <input type="checkbox" name="bobby" value="rap">rap<br> <input type="submit" value="提交" /> </form>
总结:对于post方式提交表单来说,满足的参数是:
①在表单中;②必须拥有name和value值;③请求地址
需要进行解释的三点:
-
对于text和password,value就是我们输入的内容
-
对于radio和checkbox,需要保证上面的三个条件之外,还需要保证name都是一样的,不然
对于radio来说,不再是单选,而是可以进行多选的;对于checkbox来说,提交的name不一致了,那么参数的名称也就不同了。
-
如果在action中仍然携带了参数,那么这个参数是无效的,不会发送这样的参数
<form aciton="www.baidu.com?name=guang>
在发送参数的时候,不会写在name=guang这个参数信息过去的。
正式开始进行讲解:
对于一个请求协议包而言,分为了三大部分:
通过对比可以发现,post方式有请求体,而get方式没有请求体。
那么对于post方式的请求体是什么?放的是请求的参数信息,可以放的比较多的请求数据。
对于post请求来说,放的参数信息都在请求行中
先来看下请求协议包中都有着哪些东西:
- 在请求行中的信息:
Request URL: https://www.baidu.com/?username=guang&password=guang
request Method: GET
Remote Address: 14.215.177.39:443
- 请求URI和URL
- 请求参数
- 请求方式
- 请求时候本机地址
对于使用java方法来进行操作
- getMethod();获取请求方式
- getRemoteAddr():是哪台计算机发起请求的,IP地址是多少
- **getContextPath()😗*获得部署到服务器上的项目名称
- **getRequestURI()😗*获得请求地址,不带项目名
- **getRequestURL():**获得请求地址,带项目名字
再次进行提醒的是前端发送多来的参数都是字符串。如果需要解析,请使用对应的方式来进行解析
最常见的是两种:整数和日期
对于请求头来说:
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)
Chrome/84.0.4147.135 Safari/537.36
- Accept:告知服务器,我能就收什么样的数据格式,也就是传输过来的数据进行解码的格式
- Accept-Encoding:压缩算法,不常用
- Accept-Language:浏览器接收的语言是中文
- User-Agent:客户端的信息全部暴露出来了。使用的操作系统版本号,多少位操作系统,什么浏览器等等
因为这里的数据还没有使用到,所以在这里就不再过多的进行解释!
对于post方式提交的数据来说,请求参数在请求体中,我用的是谷歌浏览器,这种看不到,所以这里无法进行展示,但是,可以猜测出来这里的数据
username=liguang&password=guang
综合比较而言,我们更常用的是获取得到请求的参数!!!
所以下面着重来讲解这个地方。
来啦老弟!
HttpServletRequest
见名知意,http协议的servlet的请求处理,我们着重分析的是获取得到参数,这里有各种各样的方法来进行操作。
我觉得在这里有必要对HttpServletRequest和HttpServletResponse做一个生命周期的介绍。
HttpServletRequest继承体系
在servlet的继承体系中,Servlet接口、GenericServlet类
void service(ServletRequest var1, ServletResponse var2)
但是在HttpServlet的doGet和doPost方法中
void doGet(HttpServletRequest req, HttpServletResponse resp)
void doPost(HttpServletRequest req, HttpServletResponse resp)
我的理解是更好的处理HTTP请求和响应
获取参数
查看HttpServletRequest中的常用的方法:
法名 | 描述 |
---|---|
String getParameter(String name) | 获得指定参数名对应的值。如果没有则返回null,如果有多个获得第一个。 例如:username=jack。(有弊端存在,比如说checkbox中的数据)_ |
String[] getParameterValues(String name) | 获得指定参数名对应的所有的值。此方法专业为复选框提供的。 例如:hobby=抽烟&hobby=喝酒&hobby=敲代码 |
Map<String,String[]> getParameterMap() | 获得所有的请求参数。key为参数名,value为key对应的所有的值。(常用) |
String getQueryString() | 直接获取得到所有的请求参数的字符串(post请求为null) |
创建一个新的servlet来进行测试:
public class OneServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 先将解析方式改还成utf-8来进行解析
// 获取得到请求参数
String queryString = req.getQueryString();
System.out.println(queryString);
}
}
在web.xml中进行配置
<servlet>
<servlet-name>oneservlet</servlet-name>
<servlet-class>guang.servlet.OneServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>oneservlet</servlet-name>
<url-pattern>/one</url-pattern>
</servlet-mapping>
第一种:
String getQueryString()方法(做做测试玩玩还是可以的)
测试一:在浏览器的地址栏中输入:
http://localhost:8080/test/one
在控制台中显示的信息:
null
因为没有什么参数
测试二:在浏览器中的地址栏中输入:
http://localhost:8080/test/one?username=guang
在控制台显示的是:
username=guang
测试三:使用表单来进行提交
使用get方式
<p>使用get方式提交</p>
<form action="./one" method="get">
姓名:<input type="text name="username"/><br>
密码:<input type="password" name="password"/><br>
性别:<input type="radio" name="sex" value="man"/>男
<input type="radio" name="sex" value="famale"/>女<br>
爱好:<input type="checkbox" name="hobby" value="sing">唱
<input type="checkbox" name="hobby" value="skip">跳
<input type="checkbox" name="bobby" value="rap">rap<br>
<input type="submit" value="提交" />
</form>
控制台显示信息:
username=%E5%B9%BF%E5%9C%BA%E8%88%9E&password=guangchangwu&sex=famale&hobby=sing&hobby=skip
这里的username我输入的是一个中文。在这边是无法进行显示中文。
使用post方式
<p>使用post方式提交</p>
<form action="./one" method="post">
姓名:<input type="text name="username"/><br>
密码:<input type="password" name="password"/><br>
性别:<input type="radio" name="sex" value="man"/>男
<input type="radio" name="sex" value="famale"/>女<br>
爱好:<input type="checkbox" name="hobby" value="sing">唱
<input type="checkbox" name="hobby" value="skip">跳
<input type="checkbox" name="bobby" value="rap">rap<br>
<input type="submit" value="提交" />
</form>
控制台信息:
null
小结:对于getQueryString方法来说,如果是get的请求方式,可以获取得到请求参数;如果是post的请求方式,那么获取得到的结果是null。
第二种
-
String getParameter(String name)
测试代码如下:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 先设置解析数据的方式 request.setCharacterEncoding("utf-8"); // 根据参数名字来获取得到参数 String value = request.getParameter("username"); System.out.println(value); }
在地址栏中输入的信息:
http://localhost:8080/test/two?username=guang
在控制台中的信息显示:
guang
第三种
-
String[] getParameterValues(String name)
根据参数和方法名称发现,这里应该使用表单中的数据来进行提交的
测试代码:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 获取得到参数值 String[] hobbies = request.getParameterValues("hobby"); for (String hobby : hobbies) { System.out.println(hobby); } }
表单方式提交:
<form action="./three" method="get"> 姓名:<input type="text" name="username" /><br> 密码:<input type="password" name="password"/><br> 性别:<input type="radio" name="sex" value="man"/>男 <input type="radio" name="sex" value="famale"/>女<br> 爱好:<input type="checkbox" name="hobby" value="sing">唱 <input type="checkbox" name="hobby" value="skip">跳 <input type="checkbox" name="hobby" value="rap">rap<br> <input type="submit" value="提交" /> </form> </body>
控制台信息:
sing skip rap
第四种
- Map<String,String[]> getParameterMap()
同上,这里采用的是map集合而已
测试代码:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 根据参数名字来获取得到参数值
Map<String, String[]> parameterMap = request.getParameterMap();
Set<Map.Entry<String, String[]>> entries = parameterMap.entrySet();
for (Map.Entry<String, String[]> entry : entries) {
String key = entry.getKey();
// 获取得到的是一个数组
String[] value = entry.getValue();
System.out.print(key+"=");
// 循环遍历数组中的内容
for (int i = 0; i < value.length; i++) {
System.out.print(" "+value[i]);
}
System.out.println();
}
}
表单方式提交:
<p>使用get方式提交</p>
<form action="./four" method="get">
姓名:<input type="text" name="username" /><br>
密码:<input type="password" name="password"/><br>
性别:<input type="radio" name="sex" value="man"/>男
<input type="radio" name="sex" value="famale"/>女<br>
爱好:<input type="checkbox" name="hobby" value="sing">唱
<input type="checkbox" name="hobby" value="skip">跳
<input type="checkbox" name="hobby" value="rap">rap<br>
<input type="submit" value="提交" />
</form>
控制台信息:
username= 光
password= fdsafds
sex= man
hobby= sing skip rap
使用post方式进行测试:
username= 光
password= guang
sex= man
hobby= sing skip rap
其他方法:
- String getContextPath():获取得到当前的项目路径
- Cookie[] getCookie():获取所有的cookie,可以实现循环遍历
- String getMethod():获取得到请求的方式
- StringBuffer getRequestURL():获取得到URL。【返回值类型是StringBuffer】
- String getRequestURI():获取得到的是URI。获取的是请求的资源路径
- String getServletPath(); 得到servlet的路径
- Session getSession():获取得到session
演示一下:
代码:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/**
* - String getContextPath():获取得到当前的项目路径
* - Cookie[] getCookie():获取所有的cookie,可以实现循环遍历
* - String getMethod():获取得到请求的方式
* - StringBuffer getRequestURL():获取得到URL。【返回值类型是StringBuffer】
* - String getRequestURI():获取得到的是URI。获取的是请求的资源路径
* - String getServletPath(); 得到servlet的路径
* - Session getSession():获取得到session
*/
String contextPath = request.getContextPath();
System.out.println("contextPath:"+contextPath);
System.out.println("------------------");
Cookie[] cookies = request.getCookies();
for (int i = 0; i < cookies.length; i++) {
System.out.println("cookie["+i+"]:"+cookies[i]);
}
System.out.println("------------------");
String method = request.getMethod();
System.out.println("method:"+method);
System.out.println("------------------");
StringBuffer requestURL = request.getRequestURL();
String requestURI = request.getRequestURI();
System.out.println("requestURL:"+requestURL);
System.out.println("requestURI:"+requestURI);
System.out.println("------------------------");
String servletPath = request.getServletPath();
System.out.println("servletPath:" + servletPath);
HttpSession session = request.getSession();
System.out.println("session:" + session);
}
演示效果:
contextPath:/test // 项目名字,也就是当前context项目的路径
------------------
cookie[0]:javax.servlet.http.Cookie@1302b6a
cookie[1]:javax.servlet.http.Cookie@ff7c53c
cookie[2]:javax.servlet.http.Cookie@bc8401a
------------------
method:GET // 请求的方式
------------------
requestURL:http://localhost:8080/test/five //统一资源定位符,计算机中的唯一标志。这里当然不是,在本机
requestURI:/test/five // 当前资源在当前计算机中的路径
------------------------
servletPath:/five // 也就是我们配置的servlet的别名,这里是servlet的路径
session:org.apache.catalina.session.StandardSessionFacade@4ecacf07
请求转发
首先需要明白的是请求转发是什么意思?
请求:向Tomcat进行申请,想要访问的资源。
转发:将要访问的资源返回到客户端去。
示例:
requset.getRequestDispatcher("/WEB-INF/register.html").forward(requset,response);
为什么使用的是request来记性请求转发呢?为什么后面又要使用到了request和response?
向Tomcat申请资源,那么申请的动作,根据字面上的理解,当然是由request来进行请求完成的。
对于转发来讲,那么就是需要由response将申请的资源打包(响应协议包),让Tomcat推送到前端去。
请求转发静态资源原理分析:
请求转发动态资源原理分析:
首先说明两点:
- 第一:
在测试动态资源请求转发的时候,发现了一点!就是在Tomcat接收到请求重新创建了一个对象之后,新的request对象和之前的request中的数据都是一样的(基本类型是数据,引用类型是地址)。所以在一次动态资源的请求转发过程中,多个request对象保留着的有着相同的数据!称之为request对象的数据共享
- 第二:
发现在进行动态资源的请求转发中,response的的地址值一直没有发生改变!说明了在对于一次请求中,request的对象的值是可以发生变化的,但是对于response来说,是不会发生改变的。非常容易理解!因为在请求转发中,请求中根本没有用到response,只有在转发的时候才用到了response。
相信到了这里也应该明白了重定向和请求转发的区别了。
总结:请求转发共享数据适用在servlet之间!jsp也是servlet!
可以来看一下,我的电脑中
C:\Users\guang\.IntelliJIdea2018.2\system\tomcat\Unnamed_Javaweb\work\Catalina\localhost\test\org\apache\jsp
对应的文件:
查看下里面的关键性代码:
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
final javax.servlet.jsp.PageContext pageContext;
javax.servlet.http.HttpSession session = null;
final javax.servlet.ServletContext application;
final javax.servlet.ServletConfig config;
javax.servlet.jsp.JspWriter out = null;
final java.lang.Object page = this;
javax.servlet.jsp.JspWriter _jspx_out = null;
javax.servlet.jsp.PageContext _jspx_page_context = null;
try {
response.setContentType("text/html;charset=UTF-8");
pageContext = _jspxFactory.getPageContext(this, request, response,
null, true, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;
out.write("\r\n");
out.write("\r\n");
out.write("<html>\r\n");
out.write("<head>\r\n");
out.write(" <title>首页</title>\r\n");
out.write("</head>\r\n");
out.write("<body>\r\n");
out.write(" <form action=\"./myservlet\" method=\"post\">\r\n");
out.write(" 姓名:<input type=\"text\" name=\"name\"><br>\r\n");
out.write(" 年龄:<input type=\"text\" name=\"age\"><br>\r\n");
out.write(" 性别:<input type=\"radio\" name=\"sex\" value=\"man\">男<input type=\"radio\" name=\"sex\" value=\"woman\">女<br>\r\n");
out.write(" 爱好: <input type=\"checkbox\" name=\"hobby\" value=\"抽烟\">抽烟<br>\r\n");
out.write(" <input type=\"checkbox\" name=\"hobby\" value=\"唱歌\">唱歌<br>\r\n");
out.write(" <input type=\"checkbox\" name=\"hobby\" value=\"烫头\">烫头<br>\r\n");
out.write(" <input type=\"checkbox\" name=\"hobby\" value=\"喝酒\">喝酒<br>\r\n");
out.write(" <input type=\"submit\" value=\"提交\">\r\n");
out.write(" </form>\r\n");
out.write("</body>\r\n");
out.write("</html>\r\n");
} catch (java.lang.Throwable t) {
if (!(t instanceof javax.servlet.jsp.SkipPageException)){
out = _jspx_out;
if (out != null && out.getBufferSize() != 0)
try {
if (response.isCommitted()) {
out.flush();
} else {
out.clearBuffer();
}
} catch (java.io.IOException e) {}
if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
else throw new ServletException(t);
}
} finally {
_jspxFactory.releasePageContext(_jspx_page_context);
}
}
将上面的代码拆分:
final javax.servlet.jsp.PageContext pageContext; //
javax.servlet.http.HttpSession session = null;
final javax.servlet.ServletContext application;
final javax.servlet.ServletConfig config;
javax.servlet.jsp.JspWriter out = null;
final java.lang.Object page = this;
javax.servlet.jsp.JspWriter _jspx_out = null;
javax.servlet.jsp.PageContext _jspx_page_context = null;
try中的
_jspx_page_context = pageContext;
输入数据中就是一个个的将HTML中的语句进行输出,这也是jsp后来不火的原因了!
说明:
这里的推导,是我偶然之间进行测试得到的结果。请教了不少大佬,然后经过自己的猜测,推理出来最后的答案。
如果有问题,请及时联系我
request共享数据域
根据我的理解,我认为是这样的一套流程
共享数据的方法:
-
Object getAttribute(String name) ; 取数据
-
void setAttribute(String name,Object object) ; 存数据
-
void removeAttribute(String name) ; 移除request中的数据
request存值的时候,可以存任何类型的值。
key是String
value是Object
这里就类似于HashMap了
HashMap<String,Object> map = new HashMap<>();
map.put(name1,Object);------------request.setAttribute(String,Ojbect);
Object obj = map.get(name1); ---------------request.getAttribute(String);
所以这里也就是为什么需要进行强制转换的原因了!!
HttpServletResponse
见名知意,http协议的servlet的响应处理
Response作用
操作的响应行、响应头、响应体
1、操作响应行
状态码。(但是意义不怎么大)
2、操作响应头
重定向问题
response.sendRedirect("重定向的路径")
这里的路径可以是context内部中的资源,也可以是外部的资源。
用的比较的少。
3、操作响应体
告知浏览器用什么方式来进行解析响应包中的二进制数据
第一种:text/html;charset=utf=8【text/html的格式解析】
第二种:application/json 【json格式的数据解析】
response.setContentType("text/html;charset=utf-8");
response.setContentType("application/json");
何类型的值。
key是String
value是Object
这里就类似于HashMap了
HashMap<String,Object> map = new HashMap<>();
map.put(name1,Object);------------request.setAttribute(String,Ojbect);
Object obj = map.get(name1); ---------------request.getAttribute(String);
所以这里也就是为什么需要进行强制转换的原因了!!
HttpServletResponse
见名知意,http协议的servlet的响应处理
Response作用
操作的响应行、响应头、响应体
1、操作响应行
状态码。(但是意义不怎么大)
2、操作响应头
重定向问题
response.sendRedirect("重定向的路径")
这里的路径可以是context内部中的资源,也可以是外部的资源。
用的比较的少。
3、操作响应体
告知浏览器用什么方式来进行解析响应包中的二进制数据
第一种:text/html;charset=utf=8【text/html的格式解析】
第二种:application/json 【json格式的数据解析】
response.setContentType("text/html;charset=utf-8");
response.setContentType("application/json");