1 HttpServletRequest的功能
HttpServletRequest在JavaWeb中非常重要的一个类。它是Servlet的service()方法的参数之一!所以你必须必须要掌握它!
request的功能可以分为以下几种:
l 封装了请求头数据;
l 封装了请求正文数据,如果是GET请求,那么就没有正文;
l request是一个域对象,可以把它当成Map来添加获取数据;
l request提供了请求转发和请求包含功能。
2 request获取请求头数据
String value = request.getHeader(“请求头名称”);
request对象可以用来获取请求头数据,当然,这些请求数据都是Tomcat封装到request中去的。我们在service()方法中可以直接来获取!
request与请求头相关的方法有:
l String getHeader(String name):获取指定名称的请求头;
l Enumeration getHeaderNames():获取所有请求头名称;
l int getIntHeader(String name):获取值为int类型的请求头。
response.setContentType("text/html;charset=utf-8"); Enumeration names = request.getHeaderNames(); while(names.hasMoreElements()) { String name = (String)names.nextElement(); String value = request.getHeader(name); System.out.println(name +": " + value); response.getWriter().println(name +": " + value + "<br/>"); } |
3 request获取请求相关的其它方法
request中还提供了与请求相关的其他方法,有些方法是为了我们更加便捷的方法请求头数据而设计,有些是与请求URL相关的方法。
l int getContentLength():获取请求正文的字节数,GET请求没有正文,没有正文返回-1;
l String getContentType():获取请求类型,如果请求是GET,那么这个方法返回null;如果是POST请求,那么默认为application/x-www-form-urlencoded,其它类型以后再学;
l String getMethod():返回请求方法,例如:GET
l Locale getLocale():返回当前客户端浏览器支持的Locale。java.util.Locale表示国家和言语,这个东西在国际化中很有用;
l String getCharacterEncoding():获取请求编码,如果没有setCharacterEncoding(),那么返回null。表示使用ISO-8859-1编码;
l void setCharacterEncoding(String code):设置请求编码,只对正文有效!注意,对于GET而言,没有正文!!!所以此方法只能对POST请求中的参数有效!
l String getContextPath():返回上下文路径,例如:/hello
l String getQueryString():返回请求URL中的参数,例如:name=zhangSan
l String getRequestURI():返回请求URI路径,例如:/hello/oneServlet
l StringBuffer getRequestURL():返回请求URL路径,例如:http://localhost/hello/oneServlet,即返回除了参数以外的路径信息;
l String getServletPath():返回Servlet路径,例如:/oneServlet
l String getRemoteAddr():返回当前客户端的IP地址;
l String getRemoteHost():返回当前客户端的主机名,但这个方法的实现还是获取IP地址;
l int getRemotePort():返回客户端的端口号,每次请求都会变;
l String getSchema():返回请求协议,例如:http;
l String getServerName():返回主机名,例如:localhost
l int getServerPort():返回服务器端口号,例如:80
http://localhost:8080/hello/a/b/c/d.jsp?mame=zhangSan
System.out.println("request.getContentLength(): " + request.getContentLength()); System.out.println("request.getContentType(): " + request.getContentType()); System.out.println("request.getContextPath(): " + request.getContextPath()); System.out.println("request.getMethod(): " + request.getMethod()); System.out.println("request.getLocale(): " + request.getLocale());
System.out.println("request.getQueryString(): " + request.getQueryString()); System.out.println("request.getRequestURI(): " + request.getRequestURI()); System.out.println("request.getRequestURL(): " + request.getRequestURL()); System.out.println("request.getServletPath(): " + request.getServletPath()); System.out.println("request.getRemoteAddr(): " + request.getRemoteAddr()); System.out.println("request.getRemoteHost(): " + request.getRemoteHost()); System.out.println("request.getRemotePort(): " + request.getRemotePort()); System.out.println("request.getScheme(): " + request.getScheme()); System.out.println("request.getServerName(): " + request.getServerName()); System.out.println("request.getServerPort(): " + request.getServerPort()); |
4 request.getRemoteAddr():封IP
可以使用request.getRemoteAddr()方法获取客户端的IP地址,然后判断IP是否为禁用IP。这种方式可以很方便的对多次密码的用户处理。
String ip = request.getRemoteAddr(); System.out.println(ip); if(ip.equals("127.0.0.1")) { response.sendError(500,"您的IP已被禁止!"); } else { response.getWriter().print("Hello!"); } |
HttpServletRequest获取参数
1 HttpServletRequest获取参数方法
可以使用HttpServletRequest获取客户端的请求参数,相关方法如下:
l String getParameter(String name):通过指定名称获取参数值;
l String[] getParameterValues(String[] name):通过指定名称获取参数值数组,有可能一个名字对应多个值,例如表单中的多个复选框使用相同的name时;
l Enumeration getParameterNames():获取所有参数的名字;
l Map getParameterMap():获取所有参数对应的Map,其中key为参数名,value为参数值。
2 传递参数的方式
传递参数的方式:GET和POST。
GET:
l 地址栏中直接给出参数:http://localhost/param/ParamServlet?p1=v1&p2=v2;
l 超链接中给出参数:<a href=” http://localhost/param/ParamServlet?p1=v1&p2=v2”>???</a>
l 表单中给出参数:<form method=”GET” action=”ParamServlet”>…</form>
POST:
l 表单中给出参数:<form method=”POST” action=”ParamServlet”>…</form>
无论是GET还是POST,获取参数的方法是相同的。
String s1 = request.getParameter(“p1”);//返回v1
String s2 = request.getParameter(“p2”);//返回v2
<formaction="ParamServlet"method="post"> <inputtype="text"name="p1"/><br/> <inputtype="text"name="p2"/><br/> <inputtype="submit"value="提交"/><br/> </form> <ahref="ParamServlet?p1=v1&p2=v2">Param</a> |
String s1 = request.getParameter("p1"); String s2 = request.getParameter("p2"); response.getWriter().print("p1 = " + s1 +"<br/>"); response.getWriter().print("p2 = " + s2 +"<br/>"); |
Enumeration names = request.getParameterNames(); while(names.hasMoreElements()) { String name = (String)names.nextElement(); String value = request.getParameter(name); System.out.println(name +" = " + value); } |
3 多值参数
例如在注册表单中,如果让用户填写爱好,那么爱好可能就是多个。那么hobby参数就会对应多个值:
<formaction="ParamServlet"method="post"> 上网:<inputtype="checkbox"name="hobby"value="netplay"/><br/> 踢球:<inputtype="checkbox"name="hobby"value="football"/><br/> 看书:<inputtype="checkbox"name="hobby"value="read"/><br/> 编程:<inputtype="checkbox"name="hobby"value="programme"/><br/> <inputtype="submit"value="提交"/><br/> </form> |
//获取所有名为hoby的参数值 String[] hobbies = request.getParameterValues("hobby"); System.out.println(Arrays.toString(hobbies)); |
4 获取所有参数,并封装到Map中
request.getParameterMap()方法返回Map类型,对应所有参数。其中Map的key对应参数的名字;Map的value对应参数的值。
<formaction="ParamServlet"method="post"> 姓名:<inputtype="text"name="name"/><br/> 年龄:<inputtype="text"name="age"/><br/> 性别:<inputtype="text"name="sex"/><br/> <inputtype="submit"value="提交"/><br/> </form> |
Map<String,String[]> map = request.getParameterMap(); Set<String> keys = map.keySet(); for(String key : keys) { String[] value = map.get(key); System.out.println(key +" = " + value[0]); } |
sex = male name = zhangSan age = 23 |
5 BeanUtils:使用Map创建Bean实例
我们知道,可以使用Map来创建Bean实例,我们也知道,可以把表单数据封装到Map中返回。这样我们就可以通过BeanUtils把表单数据封装成Bean实例了。但要注意的是,必须要创建表单中参数的名称与Bean的属性名相同!!!
try { Map<String,String[]> map = request.getParameterMap(); Person person = new Person(); BeanUtils.populate(person, map);[崔1] System.out.println(person); } catch (IllegalAccessException e) { thrownew RuntimeException(e); } catch (InvocationTargetException e) { thrownew RuntimeException(e); } |
6 单值参数,也可以使用request.getParameterValues(String)获取
其实当参数的值是单个的时候,同样可以使用request.getParameterValues(String)方法来获取参数值,不过这个参数返回的值为String[],这时我们需要再去获取数组下标0的元素。
String name = request.getParameterValues(“name”)[0]; |
HttpServletRequest请求转发
1 HttpServletRequest可以当作Map来用
JSP一共四个域对象(多出来一个PageContext,等第八天吧!)
在Servlet中有三个对象是域对象,即在不同范围内传递域变量:
l HttpServletRequest:范围为请求,在同一请求范围内传递属性;
l HttpSession:范围是会话,在同一会话中传递属性。当某个用户打开某一网站的第一个页面开始,直到关闭该网站的所有页面结束,这是一个会话范围;
l ServletContext:范围是Context,即项目。在同一个项目中,只有一个ServletContext。
今天我们要使用的是HttpServletRequest的传递属性功能。
所有域对象都有如下四个方法:
l void setAttribute(String name, Object o):设置属性,其中name为属性值,o为属性值;
l void removeAttribute(String name):移除指定名字的属性;
l Object getAttribute(String name):获取指定名称的属性;
l Enumeration getAttibuteNames():获取所有属性名称。
注意,attribute和parameter不同,attribute是我们自己设置的,而parameter是用户通过表单、超链接中传递过来,然后由Tomcat封装到request中的。说白一点,attribute是在服务器端组件中直接设置的,而parameter是由客户端间接设置的。
2 在同一Servlet中测试域方法
String name = request.getParameter("name")[崔2] ; request.setAttribute("name", name)[崔3] ; String aName = (String)request.getAttribute("name")[崔4] ; System.out.println(aName); |
3 请求转发
通常一个请求往往会涉及到多个Servlet,也就是说一个Servlet不只独立完成一个请求,那么就存在了请求转发的“故事”。例如:登录验证Servlet在完成了验证之后会把请求转发给显示主页的Servlet。
下面是一段“错误的转发”:
publicclass AServletextends HttpServlet { protectedvoid doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("AServlet的工作"); Servlet bServlet = new BServlet(); bServlet.service(req, resp); } } |
publicclass BServletextends HttpServlet { protectedvoid doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("BServlet的工作"); } } |
上面代码中,AServlet会创建BServlet对象,然后去调用BServlet的service()方法。这种方式确实可以调用BServlet,但这种方法的问题就太多太多了。
l AServlet知道的太多了,它居然知道BServlet的存在;
l BServlet由AServlet创建,不在是由Tomcat管理Servlet的生命周期;
所以我们在AServlet中不知道BServlet的存在,在AServlet中只知道一个servletName(对应<servlet-name>),然后使用Tomcat的方式,通过servletName完成转发。
如果在AServlet中需要保存数据给BServlet,那么可以使用request.setAttribute()方法来设置,然后在BServlet中就可以通过request.getAttribute()方法获取了。
在AServlet中获取请求转发器:
RequestDispatcher rd = request.getRequestDispatcher(“/BServlet”);
RequestDispatcher就是请求转发器了,获取它需要使用request对象的getRequestDispatcher()方法,该方法的参数就是BServlet在web.xml文件中的配置名:<servlet-name>BServlet</servlet-name>。
这只是获取了转发器,还没有转发。转发需要调用RequestDispatcher对象的forward()方法,该方法需要传递request和response两个参数。
// AServlet内容 Person person = new Person();[崔5] try { BeanUtils.populate(person, request.getParameterMap());[崔6] } catch (IllegalAccessException e) { thrownew RuntimeException(e); } catch (InvocationTargetException e) { thrownew RuntimeException(e); } request.setAttribute("person", person);[崔7] RequestDispatcher rd = request.getRequestDispatcher("/BServlet");[崔8] rd.forward(request, response);[崔9] |
// BServlet内容 Person person = (Person)request.getAttribute("person");[崔10] response.getWriter().print("BServlet:" + person +"<br/>")[崔11] ; System.out.println("BServlet: " + person)[崔12] ; |
l 一个请求;
l 在一个请求中可能会执行多个Servlet;
l 多个Servlet中可以共享request!
l 多个Servlet中只有最后可以用来向客户端响应;
l 其他Servlet如果响应了,有两种可能:
Ø 数据只写入到缓冲区中,没有到客户端,在转必之前,Tomcat会清空这些数据;
Ø 数据已经发送到客户端,Tomcat会抛出异常,不再转发。
n 缓冲区满了,就会自动发送到客户端;
n 调用response.flushBuffer();
n 调用PrintWriter.flush();
4 请求包含
请求包含与请求转发非常相似,区别在与转发时AServlet中的响应正文会被清除,只会留下BServlet中的响应正文,但请求包含会保留AServlet中的响应。
请求包含需要调用RequestDispatcher对象的include()方法。请求包含基本上与转发是相同的,区别在与请求包含时,在AServlet中存在响应正文会保留下来,而请求转发会清除AServlet所做的响应正文内容。
Person person = new Person(); try { BeanUtils.populate(person, request.getParameterMap()); } catch (IllegalAccessException e) { thrownew RuntimeException(e); } catch (InvocationTargetException e) { thrownew RuntimeException(e); } PrintWriter out = response.getWriter(); //转发之前的响应,不会被发送到客户端浏览器上去。 out.println("AServlet: " + person);[崔13] request.setAttribute("person", person); RequestDispatcher rd = request.getRequestDispatcher("/BServlet"); rd.include(request, response);[崔14] |
Person person = (Person)request.getAttribute("person"); PrintWriter out = response.getWriter(); out.print("BServlet:" + person +"<br/>"); System.out.println("BServlet: " + person); |
AServlet: Person [name=zhangSan, age=23, sex=male] BServlet:Person [name=zhangSan, age=23, sex=male] |
5 理解请求转发和请求包含
细心的童鞋们已经发现了,当从AServlet转发到BServlet后,在客户端的浏览器地址栏中的URL还是AServlet,而不是BServlet。也就是说,请求转发这个“故事”浏览器并不知道!!!
你可以把请求转发当作是一个请求内部调用了多个Servlet的service()方法完成的,而客户端只是发送了一个请求而已。