request与response对象.
1.
request代表请求对象
response代表的响应对象。
学习它们我们可以操作http请求与响应。
2.request,response体系结构.
在我们Servlet中使用的request与response
HttpServletRequest接口------>父接口 ServletRequest
HttpServletResponse接口----->父接口 ServletResponse
在tomcat中它采用门面模式对requst,response进行操作.
对外提供使用的是 RequestFacade ResponseFacade这两个类,
但是直正完成功能的是 Reqeust,Response类.
关于reqeust,response总结:
1.它的作用:
request代表的是http请求对象,通过reqeust可以获取Http请求信息.
response代表的是http响应对象,通过response可以设置响应信息。
2.在我们的servlet中使用的request,response是怎样来的?
它是tomcat服务器帮助创建的,通过service方法传递到了我们的servle中。tomcat在创建request对象时,就将http请求中的信息封装到request中.
3.它们的体系结构
ServletReqeust------>HttpServletReqeust-------->具体的实现类是由服务器创建的。tomcat中是 RequestFacade
ServletResponse----->HttpServletResponse------->具体的实现类是由服务器创建的。tomcat中是 ResponseFacade
-------------------------------------------------------------------------------------------------------------------
HttpServletResponse对象.
它代表的是response响应对象,可以通过这个对象去操作http响应信息.
1.响应行
响应行中重要的是状态码.
response对象可以通过 setStatus(int num)方法去操作.
2.响应头
setHeader()
addHeader()
setDateHeader();
setIntHeader();
3.响应正文
操作响应头
示例1:通过response去实现重定向.
设置状态码为302 设置location为指定的值.
response.setStatus(302);
response.setHeader("location",url);
注意:url是客户端路径。如果不写协议,那么要以/开头。这里是绝对路径
基本格式是/工程名/资源路径.
在开发中我们一般不使用上面的方式完成重定向,使用 response.sendRedirect(url);
原理 302+Lcoation
* 特点: 客户端发出2次请求
* 地址栏改变
* request 域中的数据不能共享
示例2:通过response来控制响应头,完成指定时间跳转到指定页面.
//带协议路径
//response.setHeader("refresh", "3;url=http://localhost/day10/index.html");
//不带协议路径
response.setHeader("refresh", "3;url=/day10/index.html");
在开发中如果要完成跳转操作,一般很少在服务器端完成,在客户端通过html就可以完成跳转换操作.
<meta http-equiv="refresh" content="5;url=/day10/index.html">
如果要想在页面上显示时间变化,那么可以通过js完成操作.
<script type="text/javascript">
var time = 5;
var span;
var interval;
window.onload = function() {
span = document.getElementById("num");
span.innerHTML = time;
interval=window.setInterval("show()", 1000);
};
function show() {
time--;
if(time==0){
window.clearInterval(interval);
return;
}
span.innerHTML = time;
}
</script>
--------------------------------------------------------------------------------------------
实例3控制浏览器禁止缓存当前文档内容
禁止使用缓存:通过三个header设置.
response.setHeader("Cache-Control ", "no-cache");
response.setHeader("Pragma", "no-cache");
response.setDateHeader("Expires", -1);
-------------------------------------------------------------------------
获得向客户端进行数据输出的流对象:
通过response可以获取输出流
response.getWriter(); 获取字符输出流.
response.getOutputStream();获取字节输出流。
我们通过输出流,操作http响应中的响应正文。
1.获取到的字节流与字符流的类型。
字符流 PrintWriter out=response.getWriter();
字节流 ServletOutputStream sos=response.getOutputStream();
2.字符流与字节流选择
操作文本:字符流.
如果信息没有改变,只是做copy操作,就选择字节流。
操作二进制:图片,音频。。。使用字节流。
我们需要手动在浏览器上显示信息时,一般会使用字符流。
注意事项
1.在一个servlet中只能选择使用一种流,不能两个一起使用,因为它们是排斥的。
2.在servlet中使用完流后,流可以不关闭,tomcat服务器会自动检查,关闭流.
3.我们可以通过response获取输出流,向浏览器写一个页面。但是会出现乱码问题.
response.setContentType("text/html;charset=utf-8");
当用字节流输出时,我们为防止乱码,要设置两次编码格式:
response.setContentType("text/html;charset=UTF-8");
os.write(str.getBytes("UTF-8"));
而用字符流输出时,一次就可以(这一句相当于两句)
response.setContentType("text/html;charset=UTF-8");
------------------------------------------------------------------------------
http响应操作----response对象.
1.操作行 状态码 response.setStatus();
2.操作头 response.setHeader()
3.操作正文 response.getWriter() response.getOutputStream();
关于设置编码 response.setContentType("text/html;charset=utf-8");
小问题:
PrintWriter out=response.getWriter();
out.print(); 它的底层就是使用write实现的,但是如果参数是数字,会将数字转换成字符串输出
out.write(); 如果参数是数字,会找到这个数值对应的unicode码输出。
区别?
建议使用print();
------------------------------------------------------------------------------------------------------------
response示例----动态验证码(代码不要求,要求会使用)à防止恶意注册与刷机。
--------------------------------------------------------------------------------------------------------------------------------
request对象
request获取http请求信息.
1.获取http请求行中信息.
-1.获取请求方式
request.getMethod() ///GET POSt
-2.获取请求路径
request.getRequestURI(); //day10/requestDemo1 统一资源标识符
request.getRequestURL(); //http://localhost/day10/requestDemo1 统一资源定位符,统一资源标识符包含了统一资源定位符.定位符是唯一的定位了一个位置。
-3.获取请求协议
request.getProtocol();
2.关于reqeust获取客户机信息.
-1.得到客户机ip地址.
request.getRemoteAddr();
-2.获取get请求时,请求参数.(了解)
request.getQueryString();
-3.获取请求资源路径
getContextPath(); 这个方法得到的是工程名,其实是虚拟目录名称.
/day10/requestDemo1
/day10---->工程名或虚拟目录.
/requestDemo1---->它代表的是资源路径
通过request.getRequestURI()-request.getContextPath();就得到了资源路径。
我们做url级别权限控制时,需要得到访问的资源路径。
3.获取http请求头
long getDateHeader(String name)--如果value值是Date类型
String getHeader(String name)--根据name获取value值
Enumeration getHeaderNames() --获取所有的name值,返回的是Enumeration
Enumeration getHeaders(String name) --在http请求头中可能出现,一个name 对应多个value,这时可以使用getHeaders()。
int getIntHeader(String name) --如果value是int类型 我们在开发中应用比较多的是 getHeader()方法
4.request获取请求参数
-1.String getParameter(String name)
根据请求参数中的name值获取对应的value值.
-2.String[] getParameterValues(String name);
操作多个值的组件,例如 checkbox。
-3.Enumeration getParameterNames();
获取请求参数中的所有name的值.
-4.Map<String,String[]> getParameterMap()
得到请求参数的name与value的map映射
获取请求参数,它可以针对于post/get请求。
5.关于请求参数的校验. 客户端验证与服务端验证
数据提交到服务器,我们在开发中在客户端需要进行校验.使用的是js
我们在服务器端也需要进行校验使用java代码.
我们需要在服务器端对获取的请求参数进行校验.
1.非空校验
2.规则校验
-----------------------------------------------------------------------------
6.关于获取请求参数编码问题
响应编码----response.setContentType("text/html;charset=utf-8");
请求编码:
请求参数出现乱码的原因?
1.在页面上我们的编码是utf-8,那么我们传递到服务器时,请求参数中如果存在中文,那么就会以utf-8进行编码.
2.tomcat服务器本身默认编码是iso-8859-1,它得到请求参数时,以iso8859-1进行了解码操作.
3.我们在servlet中获取请求参数时,得到的就是乱码.
解决乱码!!
我们通过request.getParameter()去获取请求参数时,得到的是乱码,这时可以将数据以iso8859-1进行编码,在以utf-8进行解码.
对于post请求我们可以通过简化方式操作.
request.setCharacterEncoding("utf-8");
如果请求方式是get,只能手动转换码 –》tomcat默认请求编码格式iso8859-1,所以我们只能先用iso8859-1解码,然后在用utf-8编码。
-----------------------------------------------------------------------------------------------------
7.request域对象.
ServletContext就一个域对象.
request的创建与销毁.
当请求来的时候,tomcat服务器会创建request,response对象。
当响应产生,request对象销毁。
也就是说,每一次请求都是一个新的request。
request也是一个域对象,它也可以存取删除数据。
setAttribute()
getAttribute()
removeAttribute();
问题: request域的作用范围是什么
请求转发----在服务器内部进行跳转。这时我们这几个servlet就共享同一个request对象,这就是request域作用范围。我们使用请求转发可以让多个servlet之间共享同一个request,那么我们如果想要在多个servlet之间进行信息传递,可以使用setAttribute().
在开发中使用请求转发
如果我们在request域中存储了信息,到其它的页面时,需要得到这个信息,这时我们就需要进行请求转发.
请求转换的代码
request.getRequestDispatcher("url").forward(request,response);
注意:url是服务器端路径。要以/开头。这里是绝对路径,基本格式是/资源路径.
请求转发与重定向的区别?
1.请求转换是服务器内部跳转,所有地址栏上的路径不会改变.重定向是浏览器在次发送请求,地址栏上的路径会发生改变.
2.请求转发只发送一次请求。重定向会发送两次请求.
3.请求转发只能在当前应用内部跳转.重定向可以在内部跳转也可以跳出当前应用.
4.请求转发时,因为是内部跳转。它的路径写法是 /资源路径。重定向,它的路径需要写 /工程名/资源路径.
5.请求转发,可以共享reqeust。重定向不可能,因为每一次都是一个新的request。 6.请求转换是通过reqeust发起 request.getRequestDispatcher().forward();
重定向 response发起 response.sendRedirect();
----------------------------------------------------------------------------------------------------
请求转发与包含 重定向
- 在实现包含时,会先将被包含进来的页面中的头信息清空。
- 在请求转发和重定向前,服务器会把response中的数据先全部清空。
- 请求转发,可以实现request域中数据共享,原因是一次请求。
4种获得表单数据 封装数据的方法
package cn.zl.request.web; import java.beans.PropertyDescriptor; import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Enumeration; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.beanutils.BeanUtils; import cn.zl.request.domain.User; /* * 4种得到浏览器表单方法 * */ public class UserServlet1 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1.用request接收数据 封装到user中 使用getParameter //requestTest1(request); //反射的方式 暴力设置属性 //requestTest2(request); //javaBean内省的方式 geter seter 操作属性 //requestTest3(request); //首先遍历map集合 然后使用工具BeanUtils 的setProperty设置javaBean的属性与值 //requestTest4(request); //借用BeanUtiles操作页面提交的参数 跟方便 更简洁 推荐使用 requestTest5(request); } private void requestTest5(HttpServletRequest request) { User user = new User();//封装前 System.out.println("封装前:"+user); //封装过程 //引入了一个新知识点 BeanUtils try { //传入一个对象 与一个map集合 BeanUtils.populate(user, request.getParameterMap()); } catch (Exception e) { e.printStackTrace(); } System.out.println("封装后:"+user); } private void requestTest4(HttpServletRequest request) { User user=new User(); //用getParameterMap得到所有的参数值与参数名 Map<String,Object[]> map=request.getParameterMap(); //遍历 map集合 得到的key就是参数名 value是所对应的值 可能有多个 for (Map.Entry<String, Object[]> entry : map.entrySet()) { String paramet=entry.getKey(); Object []objs=entry.getValue(); try { BeanUtils.setProperty(user, paramet, objs); } catch (Exception e) { e.printStackTrace(); } } System.out.println("封装后:"+user); } private void requestTest3(HttpServletRequest request) { User user = new User();//封装前 System.out.println("封装前:"+user); //封装过程 //1.服务器接收客户端发过来请求数据 ,如果 页面上请求很多时,可以用getParameterNames();得到所有的请求参数名 Enumeration<String> enumsss = request.getParameterNames(); while(enumsss.hasMoreElements()){ String paramet = enumsss.nextElement();//取出其中的一个参数名name="username" <input type="text" name="username" > String []parametValues = request.getParameterValues(paramet);//得到这个参数所对应的一组值 //封装到对象user中 ,此时的paramName 一定要与User的属性保持一致 //内省 try { PropertyDescriptor pd =new PropertyDescriptor(paramet, user.getClass());//属性描述器 第一个参数是指哪个属性 第二个参数是哪个Class Method method = pd.getWriteMethod();//通过属性描述器,得到setter方法 getWriteMethod:获得应该用于写入属性值的方法。 if(parametValues!=null && parametValues.length>1){ method.invoke(user, (Object)parametValues);//参考反射Main方法, setUsername(String []username) }else { method.invoke(user, parametValues[0]);//只有一个参数,不要包装 } } catch (Exception e) { e.printStackTrace(); } } System.out.println("封装后:"+user); } private void requestTest2(HttpServletRequest request) { //2.利用反射 User user = new User(); Enumeration<String> enums=request.getParameterNames(); while (enums.hasMoreElements()) { String paramet = (String) enums.nextElement(); String []parametValues=request.getParameterValues(paramet); Class clazz=user.getClass(); try { Field f=clazz.getDeclaredField(paramet);//利用反射得到user对象的私有的paramet属性 f.setAccessible(true);//暴力反射 这样就可以操作这个私有属性 if(parametValues!=null&¶metValues.length>1) { f.set(user, (Object)parametValues); //(Object)parametValues 这样写的原因是如果parametValues是一个数组的话 //反射会自动拆分它,这样会使有多个参数,而用object包装后 对象就不会拆分 这样就能保证方法正确性 }else { f.set(user, parametValues[0]);//只有一个参数 可以不包装 } } catch (Exception e) { e.printStackTrace(); } } System.out.println("封装后User"+user); } private void requestTest1(HttpServletRequest request) { //1.服务器接收客户端发过来请求数据 String username = request.getParameter("user");//username来自于表单<input type="text" name="username" >name的名字 String password []= request.getParameterValues("pwd");//得到一组值 User user = new User();//封装前 System.out.println("封装前:"+user); //封装过程 user.setUser(username); user.setPwd(password); System.out.println("封装后:"+user); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doGet(request, response); } }
获得表单参数
所使用javaBean
package cn.zl.request.domain; import java.util.Arrays; public class User { private String user; private String pwd[]; public User() { } @Override public String toString() { return "User [user=" + user + ", pwd=" + Arrays.toString(pwd) + "]"; } public String getUser() { return user; } public void setUser(String user) { this.user = user; } public String[] getPwd() { return pwd; } public void setPwd(String[] pwd) { this.pwd = pwd; } }
user对象