Response/Request
HttpServletResponse
向客户端发送数据 ---->实体内容
发送响应头 -----> 头信息
发送响应状态码 ----> 状态行
状态码(Status Code)
setStatus(int)
常用状态码:200、302、304、404、500
302 重定向
resp.setStatus(302);
resp.setHeader("Location",url); // 客户端url : / ----> http://localhost:8080
头信息 (Header Info)
addHeader(String,String) : // 调用addHeader 不会覆盖原来值,会拼成一个多值属性
* 如果不是多值,只有一个值,addHeader 效果 同 setHeader
setHeader(String,String) : // 调用setHeader 新的值会覆盖掉旧的值
获得向客户端进行数据输出的流对象
字节流数据输出
OutputStream out = response.getOutputStream();
字符流数据输出
PrintWriter pw = response.getWriter();
提供了两个和编码设置相关的方法
指定body内容的类型
setContentType("text/html")
指定输出数据的编码格式
setCharacterEncoding("gb2312");
默认情况下,编码格式是ISO-8859-1
响应乱码问题
1、不设置编码 采用 ISO-8859-1编码 不支持中文
2、设置编码 setCharaterEncoding gbk ----> 浏览器是如果不以gbk方式查看,是不是还会有乱码
* 保证服务器端中文正确编码 --- > 不能确定浏览器打开的查看编码集
3、指定浏览器查看编码 setContentType
*setContentType 原意 是用来设定 输出到浏览器端 文档的MIME类型
*setContentType 指定浏览器查看编码集
*setContentType 设置了 charset 将会覆盖 setCharacterEncoding的效果
setContentType("text/html;charset=utf-8");
等价于
setCharacterEncoding("utf-8");
setContentType("text/html");
IO使用缓存效率更高!!! 为什么?
如果不使用缓存
1、使用客户端连接(使用CPU)
2、写出一个字节 (IO操作,释放CPU)
3、使用客户端连接
4、写出一个字节
使用缓存
1、使用客户端连接(使用CPU)
2、一次性写出 1024B
假如缓存8K ,什么情况下缓存会输出
1、flushBuffer
2、当8K缓存写满时
reset() // 重置 HTTP 响应 状态码 头信息 实体内容
resetBuffer() // 重置实体内容 不会重置头信息和状态码
getBufferSize() // 获取缓存大小 默认缓存8K
setBufferSize() // 设置缓存大小 只能往大设置 不能往小设置
isCommitted() // 判断响应的信息(状态码、头信息、实体内容)是否输出的浏览器端
false 表示信息没有输出到浏览器
true 表示信息已经输出到浏览器
通常<meta> 具有设置Http响应头信息的效果
meta和setHeader区别
1、setHeader是真正意义上设置Http响应头信息,在服务器端生成http响应时生效
2、<meta>不是真正设置http响应头信息,在浏览器解析时生效
3、如果我同时写了
resp.setHeader("Content-Type", "text/html; charset=UTF-8");
resp.getWriter().println("<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>");
第二句<meta> 将没有效果
resp.getWriter().println("中文测试信息");
resp.getOutputStream().write(1);
不能一起使用
resp.setHeader("refresh", "3"); // 3秒刷新当前页面
resp.setHeader("refresh", "3;url=xxx"); // 3秒刷新,跳转到xxx页面
<meta http-equiv="refresh" content="3;url=/day7/index.html">
setHeader(String,String) // 其实用来设置字符串类型头信息
setIntHeader(String,int) // 用来设置数字类型头信息
setDateHeader(String,long) // 毫秒数 用来设置日期类型头信息
expires: Fri, 02 Jan 1970 00:00:00 GMT
当你使用毫秒时,所有时间都从1970.1.1 00:00:00计时
如果你想使用setHeader 设置过期时间 时间的值写成:Fri, 02 Jan 1970 00:00:00 GMT
resp.setHeader("expires","2011-10-30"); // 不行
当过期时间设置成过去时,意味着已经过期,没有缓存
long time = System.currentTimeMillis();
long time2 = new Date().getTime();
resp.setDateHeader("expires", time + 1000 * 60 * 60 * 24);
expires: Sun, 30 Oct 2011 02:49:38 GMT
如果想页面不缓存
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
resp.setHeader("pragma","no-cache");
resp.setHeader("cache-control","no-cache");
resp.setDateHeader("exires",-1); // resp.setHeader("exires","-1");
cache 304区别
cache 根本不走服务器
304 到了服务器 服务器让你找缓存
下载文件:
1、可见文件的下载
使用链接直接实现
什么样的文件可以下载:浏览器不识别的文件格式
如果浏览器识别文件格式,直接打开
2、不可见文件的下载
如果你有一个文件,想收费--- 不可见
如果文件格式浏览器识别 不能用链接
*一定设置文件的MIMEType ---- getServletContext().getMimeType()
如果文件格式浏览器识别
设置一个头信息 Content-Disposition : attachment;filename=xxx ---- 以附件形式下载
中文名称的文件 乱码
需要对中文文件名单独编码 URLEncoder //URLEncoder.encode(name, "utf-8") ---- 对中文名称文件名编码
*字节流 字符流 什么时候选用?
网络传输、文件复制 当你不需要知道文件里面写的是什么的时候 ----> 字节流
当你想分析文件,写中文的时候 --- > 字符流
验证码图片
就是在你登陆或者注册的时候,下面显示的那个看不清楚的图片
为什么有验证码:防止机器人,恶意登陆、注册
graphics.setColor(Color.YELLOW); // 指定当前笔颜色
修饰字的显示
字体:宋体、黑体、仿宋、楷体
样式:加粗、斜体、下划线
大小:20 、40
画线
宽120
高40
随机生成的点
x 0-120
y 0-40
旋转
Graphics2D graphics2D = (Graphics2D) graphics; // 必须使用Graphics2D,才能旋转
theta 弧度
360度 = 2Pi弧度
1弧度 = 180/Pi度
1度 = Pi/180 弧度
*旋转角度不要大于45
响应的重定向
原理
resp.setStatus(302);
resp.setHeader("location", "/day7/index.html"); // 客户端路径
等价于
resp.sendRedirect("/day7/index.html");
URL和URI区别
URL完整路径
http://www.itcast.cn/index.html
file:///c:/info.txt
URI资源路径
index.html
./index.jsp
../aaa/bb/login.html
URI包括URL
req.getRequestURL():http://localhost:8080/day7/request1
req.getRequestURI():/day7/request1
req.getQueryString():null ------- ?name=zhangsan&pwd=123
客户机ip ----客户机主机名 === 客户机端口(随机的取1024后任意端口)
127.0.0.1------127.0.0.1-----2385
服务器IP ---- 服务器名称
127.0.0.1====localhost
method:GET
通过request getHeader
getHeaders // 主要用来获得多值头信息字段
获取
Accept: */*
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727)
Host: 127.0.0.1:8080
Connection: Keep-Alive
getIntHead(name)方法 --- int 用来获取头信息的值为int的属性
getDateHead(name)方法 --- long(日期对应毫秒) 用来获取头信息的值为日期类型的属性
request获取请求参数
// Post乱码解决
req.setCharacterEncoding("utf-8");
// 获得单值数据 getParameter
String username = req.getParameter("username");
*当调用getParameter获取一个多值属性?------ 获得第一个值
获得多值属性
String[] hobby = req.getParameterValues("hobby");
System.out.println(Arrays.toString(hobby));
通过getParameterNames 遍历所有请求数据
Enumeration<String> names = req.getParameterNames();
while (names.hasMoreElements()) {
String name = names.nextElement();
System.out.println("变量名称:" + name);
String[] values = req.getParameterValues(name);// 得到这个变量对应的所有值
System.out.println("值:" + Arrays.toString(values));
}
getParameterMap --- Map<String,String[]> // 获得请求数据的Map结构
作业:通过BeanUtils populate 将Map数据存入User对象
username != null && username.trim().length() > 0 // 这是一个验证非空的常见写法,这是一个短路程序屏蔽了空指针异常
username != null // username 在请求中没有这个字段时,调用getParameter 返回null
username.trim().length() > 0 用户没有输入,或者可能输入的是空格
get方式乱码的导致原因
1、regist.html 输入了一个中文 :无敌
2、浏览器对无敌进行了编码:URL编码 URLEncoder username=%E6%97%A0%E6%95%8C
utf-8 %E6%97%A0%E6%95%8C
3、服务器tomcat接受了%E6%97%A0%E6%95%8C数据,分析请求,提取数据
4、将数据提取为String 存入Request对象-------byte[] - String 默认解码方式 ISO-8859-1
5、req.getParameter("username")
* "".getBytes() // 不传入编码集的时候,默认编码集:系统字符集gbk
练习:
http://localhost:8080/myweb?name=zhangsan+lisi
req.getParameter("name") ---> 输出什么:zhangsan lisi
常用转义规则
空格换成加号(+)
+换成%2B
正斜杠(/)分隔目录和子目录 换成%2F
问号(?)分隔URL和查询 换成%3F
百分号(%)制定特殊字符 换成%25
#号指定书签 换成%23
&号分隔参数 换成%26
利用域传递对象:ServletContext ----- 所有Servlet共享
setAttribute
getAttribute
removeAttribute
利用request数据域传递对象 ----- 同一个请求内数据可以共同访问
setAttribute(String,Object)
getAttribute(String) ---- Object 类型丢失
removeAttribute
什么情况下会使用request域传递对象?
当服务器端有两个资源需要共享数据时!
客户端页面 ----- 请求 ----- 服务器端程序 ----- 响应 ----- 客户端页面
客户端页面 ------请求 ----- 服务器端A程序 ----- 转发 ----- 服务器端B程序 ---- 响应 ---- 客户端页面
当你的服务器端的功能太过复杂时,你想将功能分开
Servlet
// 将users对象存入request域
req.setAttribute("users", users);
// 通过RequestDispatcher 转发
req.getRequestDispatcher("/users.jsp").forward(req, resp);
JSP
java.util.List users = (java.util.List)request.getAttribute("users");
System.out.println(users.size());
如果在调用forward方法之前,在Servlet程序中写入的部分内容已经被真正地传送到了客户端 isCommited,forward方法将抛出IllegalStateException异常
练习
resp.getWriter().print("xxx");
resp.flushBuffer(); // isCommited --- true
req.getRequestDispatcher().forward ... // 出现异常
当你使用request域传递对象的时候,共享同一个request才能共享request域中的数据
转发:一个request
重定向:两个request
转发和重定向的区别
转发:
1、一次请求、一次响应
2、只能访问本站
3、/ 指带 当前web应用根目录
4、URL不变
5、共享request域中的对象
重定向
1、两次请求、两次响应
2、可以访问任何站点
3、/ 指带 当前服务器的根目录
4、URL改变
5、不能共享request域中的对象
include
开放网站的时候:很多个页面都有一部分数据重复的
对于这些固定不动的部分,你可以include动态编程
// 包含页面top.html
req.getRequestDispatcher("top.html").include(req, resp);
// 包含页面 content.html
req.getRequestDispatcher("content.html").include(req, resp);
// 包含页面 footer.html
req.getRequestDispatcher("footer.html").include(req, resp);
现在可以通过Servlet访问页面 有三种方式给你选择 forward sendRedirect include
当isCommited为true 哪种 可以使用:include