day06 Request Response
- rw 读写模板的设置
- day05 Request Response
- 1. HttpServletResponse 简介
- 2. response 实现文件下载
- 3. response 输出随机认证码图片 - 涉及了控制浏览器不留缓存 - 常用汉字码表
- 4. JavaScript 编码 点验证码换一张图片
- 5. 实用技术 - 用 response 的 refresh 控制浏览器定时刷新
- 6. 实用技术 - 用 Expires 头控制浏览器缓存
- 7. response实现请求重定向和response的一些细节
- 8. response 的 getOutputStream 和 getWriter 不能同时调用,他们竟然互相排斥
- 9. request 简介
- 10. request 获取请求头和请求数据
- 11. 通过表单收集客户机数据 - 多种 form 数据项类型展示
- 12. request乱码(试验失败,待解决)
- 13. request 实现请求转发和 mvc 设计模式 - 涉及到 forward 转发时的幺蛾子 - 不能转发2次
- 14. request 实现页面包含 include 代替 forward (此技术不用,通常由 jsp 处理包含,而不是由 servlet 处理)
- 15. web 工程中各类地址的写法
- 16. 利用 referer 防盗链
Author:相忠良
Email: ugoood@163.com
起始于:April 18, 2018
最后更新日期:April 22, 2018
声明:本笔记依据传智播客方立勋老师 Java Web 的授课视频内容记录而成,中间加入了自己的理解。本笔记目的是强化自己学习所用。若有疏漏或不当之处,请在评论区指出。谢谢。
涉及的图片,文档写完后,一次性更新。
day05 Request Response
Web服务器收到客户端的http请求,会针对每一次请求,分别创建一个用于代表请求的 request 对象,和代表响应的 response 对象:
- 要想获取客户机提交过来的数据,只需找 request 对象;
- 要向客户机输出数据,只需找 response 对象就行了。
1. HttpServletResponse 简介
HttpServletResponse
响应,它封装了向客户机 发送数据、发送响应头和发送响应状态码 的方法。例如:
setStatus(int)
setHeader(String, String)
getWriter()
getOutputStream()
1.1 Response 的 OutputStream 输出中文的问题
程序已什么码表输出了,程序就一定要控制浏览器以什么码表打开。
1.用 响应头 的方式控制浏览器的码表,如下:
// servlet 中用 OutputStream 输出中文的问题
public class ResponseDemo1 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 通过response对象为浏览器指定码表
// 程序已什么码表输出了,程序就一定要控制浏览器以什么码表打开
response.setHeader("Content-type", "text/html;charset=UTF-8");
String data = "中国";
OutputStream out = response.getOutputStream();
out.write(data.getBytes("UTF-8")); // 以该码表输出
}
}
2.用 html 的<meta>
方式控制浏览器的码表,此方法 没有 向浏览器发送响应头。如下(我试验失败):
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String data = "中国";
OutputStream out = response.getOutputStream();
out.write("<meta http-equiv='content-type' content='text/html;charset=UTF-8'>"
.getBytes());
out.write(data.getBytes("UTF-8"));
}
1.2 Response 的 Writer 输出中文(只能写字符串)
public class ResponseDemo2 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 设置 response 码表
response.setCharacterEncoding("UTF-8");
// 设置浏览器应查的码表
response.setHeader("content-type", "text/html;charset=UTF-8");
String data = "中国";
PrintWriter out = response.getWriter();
out.write(data);
}
}
上述代码设置浏览器码表,也可这样写:response.setContentType("text/html;charset=UTF-8");
,且这句话也修改了 response 的码表。
2. response 实现文件下载
准备:项目WebRoot
目录下建立download
目录,并在该目录中预先放入1.jpg
和日本妞.jpg
文件。
分别下载这两个文件的代码:
注意:如果文件名为中文,则文件名需经过 url 编码,下面代码中有体现:
// 以下载方式打开
public class ResponseDemo3 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// String path = this.getServletContext().getRealPath("/download/1.jpg");
String path = this.getServletContext().getRealPath("/download/日本妞.jpg");
String filename = path.substring(path.lastIndexOf("\\") + 1);
// 发送响应头,通知浏览器以下载方式打开,且文件名是 filename
// response.setHeader("content-disposition", "attachment;filename="
// + filename);
// 如果文件名为中文,则文件名需经过 url 编码
response.setHeader("content-disposition", "attachment;filename="
+ URLEncoder.encode(filename, "UTF-8"));
InputStream in = null;
OutputStream out = null;
try {
in = new FileInputStream(path);
int len = 0;
byte[] buffer = new byte[1024];
out = response.getOutputStream();
while ((len = in.read(buffer)) > 0) {
out.write(buffer, 0, len);
}
} finally {
if (in != null) {
try {
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (out != null) {
try {
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
3. response 输出随机认证码图片 - 涉及了控制浏览器不留缓存 - 常用汉字码表
刷新按钮作用:不管服务器有没有缓存,都向服务器发请求。就是把上一次的申请再干一次。
下面代码涉及了 控制浏览器不留缓存。
// 验证码, 谷歌浏览器不支持,IE支持本程序
public class ResponseDemo4 extends HttpServlet {
// ctrl + shift + x 小写变大写
public static final int WIDTH = 120;
public static final int HEIGHT = 35;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
BufferedImage image = new BufferedImage(WIDTH, HEIGHT,
BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
// 1. 设置背景色
setBackGround(g);
// 2. 设置边框
setBorder(g);
// 3. 画干扰线
drawRandomLine(g);
// 4. 写随机数
drawRandomNum((Graphics2D) g);
// 5. 图形写给浏览器
response.setContentType("image/jpeg");
// 发头控制浏览器不要缓存
response.setDateHeader("expries", -1);
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Pragma", "no-cache");
ImageIO.write(image, "jpg", response.getOutputStream());
}
private void drawRandomNum(Graphics2D g) {
g.setColor(Color.RED);
g.setFont(new Font("宋体", Font.BOLD, 20));
// unicode 汉字码表范围 [\u4e00-\u9fa5]
// 常用汉字
String base = "\u4e00\u4e86\u662f\u6211\u4e0d\u5728\u4eba\u4eec\u6709\u6765\u4ed6\u8fd9\u4e0a\u7740\u4e2a\u5730\u5230\u5927\u91cc\u8bf4\u5c31\u53bb\u5b50\u5f97\u4e5f\u548c\u90a3\u8981\u4e0b\u770b\u5929\u65f6\u8fc7\u51fa\u5c0f\u4e48\u8d77\u4f60\u90fd\u628a\u597d\u8fd8\u591a\u6ca1\u4e3a\u53c8\u53ef\u5bb6\u5b66\u53ea\u4ee5\u4e3b\u4f1a\u6837\u5e74\u60f3\u751f\u540c\u8001\u4e2d\u5341\u4ece\u81ea\u9762\u524d\u5934\u9053\u5b83\u540e\u7136\u8d70\u5f88\u50cf\u89c1\u4e24\u7528\u5979\u56fd\u52a8\u8fdb\u6210\u56de\u4ec0\u8fb9\u4f5c\u5bf9\u5f00\u800c\u5df1\u4e9b\u73b0\u5c71\u6c11\u5019\u7ecf\u53d1\u5de5\u5411\u4e8b\u547d\u7ed9\u957f\u6c34\u51e0\u4e49\u4e09\u58f0\u4e8e\u9ad8\u624b\u77e5\u7406\u773c\u5fd7\u70b9\u5fc3\u6218\u4e8c\u95ee\u4f46\u8eab\u65b9\u5b9e\u5403\u505a\u53eb\u5f53\u4f4f\u542c\u9769\u6253\u5462\u771f\u5168\u624d\u56db\u5df2\u6240\u654c\u4e4b\u6700\u5149\u4ea7\u60c5\u8def\u5206\u603b\u6761\u767d\u8bdd\u4e1c\u5e2d\u6b21\u4eb2\u5982\u88ab\u82b1\u53e3\u653e\u513f\u5e38\u6c14\u4e94\u7b2c\u4f7f\u5199\u519b\u5427\u6587\u8fd0\u518d\u679c\u600e\u5b9a\u8bb8\u5feb\u660e\u884c\u56e0\u522b\u98de\u5916\u6811\u7269\u6d3b\u90e8\u95e8\u65e0\u5f80\u8239\u671b\u65b0\u5e26\u961f\u5148\u529b\u5b8c\u5374\u7ad9\u4ee3\u5458\u673a\u66f4\u4e5d\u60a8\u6bcf\u98ce\u7ea7\u8ddf\u7b11\u554a\u5b69\u4e07\u5c11\u76f4\u610f\u591c\u6bd4\u9636 \u8fde\u8f66\u91cd\u4fbf\u6597\u9a6c\u54ea\u5316\u592a\u6307\u53d8\u793e\u4f3c\u58eb\u8005\u5e72\u77f3\u6ee1\u65e5\u51b3\u767e\u539f\u62ff\u7fa4\u7a76\u5404\u516d\u672c\u601d\u89e3\u7acb\u6cb3\u6751\u516b\u96be\u65e9\u8bba\u5417";
int x = 5; // 从这开始写
for (int i = 0; i < 4; i++) {
// -30 -- 30度旋转设定
int degree = new Random().nextInt() % 30;
String ch = base.charAt(new Random().nextInt(base.length())) + "";
g.rotate(degree * Math.PI / 180, x, 20); // 设置旋转弧度
g.drawString(ch, x, 20);
g.rotate(-degree * Math.PI / 180, x, 20);
x += 30;
}
}
private void drawRandomLine(Graphics g) {
g.setColor(Color.GREEN);
// 4-5条干扰线
for (int i = 0; i < 5; i++) {
int x1 = new Random().nextInt(WIDTH);
int y1 = new Random().nextInt(HEIGHT);
int x2 = new Random().nextInt(WIDTH);
int y2 = new Random().nextInt(HEIGHT);
g.drawLine(x1, y1, x2, y2);
}
}
private void setBorder(Graphics g) {
g.setColor(Color.BLUE);
g.drawRect(1, 1, WIDTH - 2, HEIGHT - 2);
}
private void setBackGround(Graphics g) {
g.setColor(Color.WHITE);
g.fillRect(0, 0, WIDTH, HEIGHT);
}
}
4. JavaScript 编码 点验证码换一张图片
涉及2文件:src/ResponseDemo4
(上节有了)和WebRoot/register.html
。
register.html代码如下:
我实践的结果是,小手 cursor:hand
在 IE 和 Chrome 下都不显示。
<!DOCTYPE html>
<html>
<head>
<title>register.html</title>
<script type="text/javascript">
function changeImage(img) {
/* 点图片,能换一张,而不受缓存影响 */
img.src = img.src + "?" + new Date().getTime();
}
</script>
</head>
<body>
<form action="">
用户名:<input type="text" name="username"><br /> 密码:<input
type="password" name="password"><br /> 认证码:<input type="text"
name="checkcode">
<!-- 小手点验证码 -->
<img src="/day06/servlet/ResponseDemo4" onclick="changeImage(this)"
alt="换一张" style="cursor:hand"><br /> <input type="submit"
value="注册">
</form>
</body>
</html>
浏览器输入http://localhost:8080/day06/register.html
查看结果。
5. 实用技术 - 用 response 的 refresh 控制浏览器定时刷新
1.控制浏览器3秒刷新代码:
public class ResponseDemo5 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setHeader("refresh","3"); // 每3秒刷新
String data = new Random().nextInt(10000) + "";
response.getWriter().write(data);
}
}
2.登录成功后,跳转代码:
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 假设这是处理登录的sevlet
// 假设程序运行到此,用户登录成功了
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
response.setHeader("refresh", "3;url='/day06/index.jsp'");
response.getWriter().write("恭喜你登录成功,浏览器将在3秒后,跳到首页,若没跳,请点<a href=''>超链接</a>");
}
3.登录成功后,实用的自动跳转技术: 用到,想法还是 servlet 不适合输出数据,数据在 servlet 中产生后,应传给一个jsp文件,由jsp修饰格式后,再输出,代码如下:
涉及2文件,ResponseDemo5
和WebRoot/message.jsp
,分别如下:
// 控制浏览器刷新,跳转实用代码
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
// 假设这是处理登录的sevlet
// 假设程序运行到此,用户登录成功了,要跳转,实用代码
// 用 <meta> 模拟 响应头 让jsp传给浏览器
// 因为 sevlet 不适合输出数据,数据需jsp修饰后输出才是王道!故而才用<meta>模拟响应头
String message = "<meta http-equiv='refresh' content='3;url=/day06/index.jsp'>恭喜你登录成功,浏览器将在3秒后,跳到首页,若没跳,请点<a href=''>超链接</a>";
this.getServletContext().setAttribute("message", message);
// 让jsp负责输出数据,需再建立一个message.jsp文件
this.getServletContext().getRequestDispatcher("/message.jsp")
.forward(request, response);
}
WebRoot/message.jsp
,下面代码注意把encoding改为UTF-8:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://"
+ request.getServerName() + ":" + request.getServerPort()
+ path + "/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>My JSP 'message.jsp' starting page</title>
</head>
<body>
<!-- 代码从这开始 -->
<%
String message = (String) application.getAttribute("message");
out.write(message);
%>
</body>
</html>
6. 实用技术 - 用 Expires 头控制浏览器缓存
本节故事是:控制浏览器缓存某个东西1个小时。背景是有些内容几乎无变化,这就得控制客户浏览器缓存这个内容,否则服务器会累死。
办法就是 通过服务器向浏览器发送控制缓存的响应头。
实例:客户访问index.jsp
,点击“查看图书”超链接,然后跳转到ResponseDemo6
,显示图书内容aaaaaaaaaa
。因为图书内容不怎么变化,故需用expires
头控制缓存。
WebRoot/index.jsp
代码如下:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>My JSP 'index.jsp' starting page</title>
</head>
<body>
<a href="/day06/servlet/ResponseDemo6">查看图书</a>
</body>
</html>
ResponseDemo6
代码如下,注意用System.currentTimeMillis()
获取当前时间,若直接用1000*3600
是不行的:
// 控制缓存
public class ResponseDemo6 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
// 注意 System.currentTimeMillis() 获取当前时间
response.setDateHeader("expires",
System.currentTimeMillis() + 1000 * 3600); // 缓存1小时
String data = "aaaaaaaaaaaaaa";
response.getWriter().write(data);
}
}
7. response实现请求重定向和response的一些细节
请求重定向:你管我借钱,我没有,我让你找别人。
特点:重定向后,浏览器地址栏内容会发生变化,且浏览器相当于发送服务器2次请求。
请求重定向能不用尽量不要用,它加重了服务器负担(2次请求)。
什么时候必须用请求重定向?
- 登录,登录后跳到首页。地址栏发生变化,让用户知道他/她到首页上去了;
- 购物,网上购物成功后,应该重定向到购物车显示页面(不要用转发技术)。
实例代码:
// 实现请求重定向
public class ResponseDemo7 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
/*
response.setStatus(302);
response.setHeader("location", "/day06/index.jsp");
*/
response.sendRedirect("/day06/index.jsp"); // 这句=上面2句
}
}
浏览器输入http://localhost:8080/day06/servlet/ResponseDemo7
查看地址栏变化及结果。
8. response 的 getOutputStream 和 getWriter 不能同时调用,他们竟然互相排斥
如题,代码如下:
public class ResponseDemo8 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
response.getOutputStream();
response.getWriter();
}
}
上面代码运行时要抛异常:
java.lang.IllegalStateException: getOutputStream() has already been called for this response
org.apache.catalina.connector.Response.getWriter(Response.java:609)
org.apache.catalina.connector.ResponseFacade.getWriter(ResponseFacade.java:211)
cn.wk.response.ResponseDemo8.doGet(ResponseDemo8.java:16)
javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
方立勋老师挺有意思,他课堂上说,学生们以后开发时肯定会犯上面所说的错,并报异常,这种异常见不到,不算是合格的开发人员。看到这,我就呵呵了,相忠良肯定不会犯这错误^^,玩笑话啦。
方老师说,有如下情况:
public class ResponseDemo8 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
response.getOutputStream();
this.getServletContext.getRequestDispatcher("/servlet/ResponseDemo9").forward(request, response);
// 上面是转发,不是重定向哦,转发时客户浏览器地址栏是不变的!
}
}
public class ResponseDemo9 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
response.getWriter();
}
}
转着转着就懵逼了,报了那个java.lang.IllegalStateException
异常。
重定向就不会抛这种异常,因为那是2次请求,有2个 response! 转发是1次请求,只有1个response对象!
通过 response 对象弄出的流,我们不需关,web容器帮我们关。但若不是通过 response 弄出的流,咱自己得关,服务器不管!
9. request 简介
HttpServletRequest
对象代表客户端的请求,当客户端通过 HTTP 协议访问服务器时,HTTP 请求头中的所有信息都封装在这个对象中,开发人员通过这个对象的方法,可或得客户的这些信息。 request 里肯定有代表客户请求的请求行,请求头和请求数据的相关方法。通过 servlet API 查看之。
URI: /news/1.html 它能标识任意资源,URI是爸爸,URL是崽。开发中 URI 用的比 URL 多。
URL: http://www.sina.com/news/1.html 它只能标识互联网上的资源
例子:
// request 简单示例
public class RequestDemo1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
System.out.println(request.getRequestURI());
System.out.println(request.getRequestURL());
System.out.println(request.getQueryString());
System.out.println("---------------------");
System.out.println(request.getRemoteAddr()); // client ip
System.out.println(request.getRemoteHost()); // client host name
System.out.println(request.getLocalAddr()); // WEB 服务器的 ip
System.out.println(request.getLocalName()); // WEB 服务器的主机名
System.out.println(request.getRemotePort());
System.out.println(request.getMethod()); // 返回 GET POST 等
}
}
浏览器中输入http://localhost:8080/day06/servlet/RequestDemo1?name=aaa&pass=666
查看结果为:
/day06/servlet/RequestDemo1
http://localhost:8080/day06/servlet/RequestDemo1
name=aaa&pass=666
---------------------
0:0:0:0:0:0:0:1
0:0:0:0:0:0:0:1
0:0:0:0:0:0:0:1
0:0:0:0:0:0:0:1
51607
GET
0:0:0:0:0:0:0:1
这个事,访问时localhost换成127.0.0.1就行了,具体情况网上查。据说通常发生在客户机和服务器在同一台机器上。感觉这个结论不靠谱。
并且,客户机浏览器的 port 也不像方老师所说的随机,我机器上的表现却是固定的,但也不完全固定,无论 chrome 还是 ie。
10. request 获取请求头和请求数据
// request 获取头相关的方法
public class RequestDemo2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
String headValue = request.getHeader("Accept-Encoding");
System.out.println(headValue);
System.out.println("---------------------");
Enumeration e = request.getHeaders("Accept-Encoding");
while (e.hasMoreElements()) {
String value = (String) e.nextElement();
System.out.println(value);
}
System.out.println("---------------------");
e = request.getHeaderNames();
while (e.hasMoreElements()) {
String name = (String) e.nextElement();
String value = request.getHeader(name);
System.out.println(name + " = " + value);
}
}
}
浏览器输入http://localhost:8080/day06/servlet/RequestDemo2
,我机器控制台的输出是:
gzip, deflate, br
---------------------
gzip, deflate, br
---------------------
host = localhost:8080
connection = keep-alive
cache-control = max-age=0
upgrade-insecure-requests = 1
user-agent = Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36
accept = text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
accept-encoding = gzip, deflate, br
accept-language = zh-CN,zh;q=0.9
cookie = _ga=GA1.1.1376610490.1484797437; _gid=GA1.1.1268285374.1524302785
注意:不同浏览器(IE 和 Chrome)发出的请求头根本不一样,差别还挺大的。
10.1 用户带数据给服务器的方式,两种:超链接中或表单,重要例子
本节案例很重要!
该案例涉及3个文件和2个工具包:RequestDemo2
,WebRoot/test.html
,cn.wk.User
普通java类,commons-beanutils-1.7.0.jar
和commons-logging-1.1.1.jar
工具包。
test.html
代码:
<!DOCTYPE html>
<html>
<head>
<title>带数据给RequestDemo2.html</title>
<meta name="keywords" content="keyword1,keyword2,keyword3">
<meta name="description" content="this is my page">
<meta name="content-type" content="text/html; charset=UTF-8">
</head>
<body>
<!-- 带数据方式1 -->
<a href="/day06/servlet/RequestDemo2?username=xxx">点点</a>
<!-- 带数据方式2 -->
<form action="/day06/servlet/RequestDemo2" method="post">
用户名1:<input type="text" name="username"><br/>
用户名2:<input type="text" name="username"><br/>
密码:<input type="text" name="password"><br/>
<input type="submit" value="提交"><br/>
</form>
</body>
</html>
cn.wk.User
普通java类代码:
package cn.wk;
public class User {
//因为变态的弄了2个username,所以String[],正常不会这样干
private String[] username;
private String password;
public String[] getUsername() {
return username;
}
public void setUsername(String[] username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
RequestDemo2 代码,里面有很重要的东西,涉及了 BeanUtils 工具包的使用:
// request 获取请求头 和 请求数据
public class RequestDemo2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
System.out.println("-------获取数据方式1---------");
String value = request.getParameter("username");
if (value != null && !value.trim().equals("")) {
System.out.println(value);
}
System.out.println("-------获取数据方式2---------");
String[] values = request.getParameterValues("username");
for (int i = 0; value != null && i < values.length; i++)
System.out.println(values[i]);
System.out.println("-----最重要的获取数据方式3 用BeanUtils.populate()----");
// 使用对象 封装浏览器送来的数据
Map<String, String[]> map = request.getParameterMap();
User user = new User();
try {
BeanUtils.populate(user, map); // map集合数据填充bean
// BeanUtils.copyProperties(dest, orig); bean的拷贝
} catch (Exception e) {
e.printStackTrace();
}
// 服务器必须以debug方式启动, 才能观察断点
System.out.println(user); // 这打断点,观察是否传入进user对象
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(req, resp);
}
}
浏览器输入http://localhost:8080/day06/test.html
,页面中输入数据后提交,再查看控制台结果。我的test.html
页面出乱码了。
11. 通过表单收集客户机数据 - 多种 form 数据项类型展示
下面的2行没解决我的乱码问题
eclipse导入项目后HTML文件都是乱码的(原UTF-8,现GBK)
windows->perferences->General->Content Types->Text->HTML,然后将Default encoding设置为utf-8即可。
乱码问题困扰着我。
WebRoot/form.html
代码如下 (多种 form 数据项类型展示):
<!DOCTYPE html>
<html>
<head>
<title>form.html</title>
<meta name="keywords" content="keyword1,keyword2,keyword3">
<meta name="description" content="this is my page">
<meta name="content-type" content="text/html; charset=UTF-8">
</head>
<!-- 常用的 表单输入项 类型 -->
<body>
<form action="/day06/servlet/RequestDemo3" method="post">
用户名:<input type="text" name="username"><br/>
密码:<input type="password" name="password"><br/>
性别:
<input type="radio" name="gender" value="male">男
<input type="radio" name="gender" value="female">女<br/>
所在地:
<select name="city">
<option value="beijing">北京</option>
<option value="shanghai">上海</option>
<option value="chaihe">柴河</option>
</select>
<br/>
爱好:
<input type="checkbox" name="likes" value="sing">唱歌
<input type="checkbox" name="likes" value="dance">跳舞
<input type="checkbox" name="likes" value="basketball">篮球
<input type="checkbox" name="likes" value="football">足球
<br/>
备注:<textarea rows="6" cols="60" name="description"></textarea><br/>
大头照:<input type="file" name="image"><br/>
<!-- 隐藏输入项 用户不可见 但表单提交时 一同提交 -->
<input type="hidden" name="id" value="12356">
<input type="submit" value="提交"><br/>
</form>
</body>
</html>
RequestDemo3
代码:
用户提交的数据一定先检查后使用!
public class RequestDemo3 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println(request.getParameter("username"));
System.out.println(request.getParameter("password"));
System.out.println(request.getParameter("gender"));
System.out.println(request.getParameter("city"));
// 数据一定 先检查 后使用
String[] likes = request.getParameterValues("likes"); // 遍历时小心likes为空
for (int i = 0; likes != null && i < likes.length; i++) {
System.out.println(likes[i]);
}
System.out.println(request.getParameter("description"));
// 大头照涉及文件上传和下载,在这先不处理
System.out.println(request.getParameter("id"));
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
浏览器输入http://localhost:8080/day06/form.html
可能有乱码,填入数据提交,控制台查看结果。
12. request乱码(试验失败,待解决)
涉及2文件,WebRoot/form3.html
和RequestDemo4
,我机器上本实验做的不成功。
WebRoot/form3.html
如下,2个表单,上面的用post方法,下面的用get方法:
另一个纳闷的事是<meta name="content-type" content="text/html; charset=UTF-8">
对浏览器码表的设置对我机器不起作用,不知为啥!
<!DOCTYPE html>
<html>
<head>
<title>form3.html</title>
<meta name="keywords" content="keyword1,keyword2,keyword3">
<meta name="description" content="this is my page">
<meta name="content-type" content="text/html; charset=UTF-8">
</head>
<body>
<form action="/day06/servlet/RequestDemo4" method="post">
用户名:<input type="text" name="username"><br/>
<input type="submit" value="提交"><br/>
</form>
<form action="/day06/servlet/RequestDemo4" method="get">
用户名:<input type="text" name="username"><br/>
<input type="submit" value="提交"><br/>
</form>
</body>
</html>
// post 提交方式 乱码解决
request.setCharacterEncoding("UTF-8"); //只对post有效
String username = request.getParameter("username");
System.out.println(username);
我机器下面代码无法去除乱码:
// get 提交方式 乱码解决
String username = request.getParameter("username");
username = new String(username.getBytes("iso-8859-1"), "UTF-8");
System.out.println(username);
超链接提交的中文也只能手工处理(因为也是get提交,按上面get提交乱码解决方式处理):
<a href="/day06/servlet/RequestDemo4?username=中国">点点</a>
13. request 实现请求转发和 mvc 设计模式 - 涉及到 forward 转发时的幺蛾子 - 不能转发2次
request 域
MVC思想 (model->javabean view -> jsp controller -> servlet)
RequestDemo6 生成数据,用 request 转发给 /WebRoot/message.jsp 文件显示:
下面例子简单,但非常重要。另外,不能转发两次!详细情节看下面代码:
forward请求转发的特点:
- 客户端只发1次请求,而服务器端有多个资源调用;
- 客户端浏览器地址栏无变化。
// 请求转发,以及使用request域对象把数据带给转发资源
public class RequestDemo6 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// MVC思想 (model->javabean view -> jsp controller -> servlet)
String data = "aaaaaaa";
req.setAttribute("data", data);
// request也可实现转发
if (true) {
req.getRequestDispatcher("/message.jsp").forward(req, resp);
return; // return保证了以后不会再次转发了
}
// 但不能再次转发
// 将抛异常 java.lang.IllegalStateException: Cannot forward after response
// has been committed
req.getRequestDispatcher("/index.jsp").forward(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doGet(req, resp);
}
}
/WebRoot/message.jsp 的代码,里面涉及了 EL 表达式,jsp中用 EL 表达式取出数据输出:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>My JSP 'message.jsp' starting page</title>
</head>
<body>
${data} <!-- EL 表达式 -->
<!-- 下面写法也可,推荐用 EL -->
<%
String data = (String)request.getAttribute("data");
out.write(data);
%>
</body>
</html>
forward细节:forward 时,会清空response中的数据,如下:
// forward细节: forward时,会清空response中的数据
public class RequestDemo7 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String data = "aaaaaaa";
resp.getWriter().write(data);
req.getRequestDispatcher("/index.jsp").forward(req, resp); //会覆盖上面的resp向浏览器送出的信息
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doGet(req, resp);
}
}
14. request 实现页面包含 include 代替 forward (此技术不用,通常由 jsp 处理包含,而不是由 servlet 处理)
如题,代码如下,本例涉及1个servlet,2个jsp:
public class RequestDemo8 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
req.getRequestDispatcher("/public/head.jsp").include(req, resp);
resp.getWriter().write("hahahahaha<br/>");
req.getRequestDispatcher("/public/foot.jsp").include(req, resp);
}
}
/public/head.jsp
:
<body>
head <br>
</body>
/public/foot.jsp
:
<body>
foot <br>
</body>
浏览器输入http://localhost:8080/day06/servlet/RequestDemo8
,输出结果为:
head
hahahahaha
foot
15. web 工程中各类地址的写法
写地址的原则:
- 以
/
开头; - 若地址是写给服务器用的,
/
就代表当前 web 应用; - 若地址是写给浏览器用的,
/
就代表网站;
我认为,第1条有用,其他2条无所谓。
// 用地址的地方
public class ServletDemo1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// 1.
req.getRequestDispatcher("/").forward(req, resp);
// 2.
resp.sendRedirect("");
// 3.
this.getServletContext().getRealPath("");
// 4.
this.getServletContext().getResourceAsStream("");
// 5.
/*
* <a href="">点点</a>
*
* <form action="/day06/form1.html">
*
* </form>
* */
}
}
16. 利用 referer 防盗链
// 防盗链
public class RequestDemo9 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 判断 来访者从哪个页面来的
String referer = request.getHeader("referer");
// 符合盗链者条件
if (referer == null || !referer.startsWith("http://localhost")) {
response.sendRedirect("/day06/index.jsp");
return;
}
String data = "凤姐日记";
response.getWriter().write(data);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
day06 Request Response的更多相关文章
- request response
request 和 response 这两个对象是出现在service方法中.service方法是用来接收请求处理请求,完成响应的. 接受请求指的就是request对象 完成响应指的就 ...
- request \response 总结
request&response request 1.获得信息的方法 1> 获得请求首行信息的方法 *getMethod *getContextP ...
- track message forwards, avoiding request loops, and identifying the protocol capabilities of all senders along the request/response chain
https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html The TRACE method is used to invoke a remote, ...
- Ng Http Request/response格式转换
angular作为Single Page Application推荐的交互方式当然是基于json的ajax调用.但今天要说的是当你不幸工作在一个遗留或者不可控制的服务上,而这服务是基于非json提交方 ...
- 过滤器中的chain.doFilter(request,response)
Servlet中的过滤器Filter是实现了javax.servlet.Filter接口的服务器端程序,主要的用途是过滤字符编码.做一些业务逻辑判断等.其工作原理是,只要你在web.xml文件配置好要 ...
- 对chain.doFilter(request,response)的理解
他的作用是将请求转发给过滤器链上下一个对象.这里的“下”指的是哪里 ? 指的是下一个filter,如果没有filter那就是你请求的资源. 一般filter都是一个链,web.xml 里面配置了几个就 ...
- chain.doFilter(request,response)含义
过滤器的生命周期一般都要经过下面三个阶段: 初始化 当容器第一次加载该过滤器时,init() 方法将被调用.该类在这个方法中包含了一个指向 Filter Config 对象的引用.我们的过滤器实际上并 ...
- controlling the variance of request response times and not just worrying about maximizing queries per second
http://highscalability.com/blog/2010/11/4/facebook-at-13-million-queries-per-second-recommends-minim ...
- ZeroMQ之Request/Response (Java)
自己最开始是在cloud foundry中接触过消息服务器(nats),或者说是消息中间件,也算是初步知道了一个消息服务器对于分布式的网络系统的重要性,后来自己也曾想过在一些项目中使用它,尤其是在一些 ...
随机推荐
- windows7.0旗舰版安装后控制面板自带的Microsoft程序
1.不要卸载,否则会出现安装其他软件时缺少动态链接库
- C# word文档转换成PDF格式文档
最近用到一个功能word转pdf,有个方法不错,挺方便的,直接调用即可,记录下 方法:ConvertWordToPdf(string sourcePath, string targetPath) so ...
- 超简单的jQuery前台分页,不需导包
今天我们介绍一个不需要导分页包的,非常容易上手的分页+模糊查询功能.接下来先介绍分页功能: 首先第一步,你要有个要去分页的列表.我这里敲了个简单的图书管理,作为展示的基础,它的列表为异步提交,由两部分 ...
- PHP环境配置(1)
Apache下载 Apache下载地址:http://httpd.apache.org/download.cgi 第一步:点击Files for Microsoft Windows 第二步:点击Apa ...
- 解决cors跨域的filter
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.Ordered; im ...
- SourceTree 03 - 跳过账号登录直接进入主界面
SourceTree系列第1篇 SourceTree 01 - git 客户端介绍(http://www.cnblogs.com/geaosu/p/8807666.html) SourceTree系列 ...
- 使用 C# (.NET Core) 实现命令设计模式 (Command Pattern)
本文的概念内容来自深入浅出设计模式一书. 项目需求 有这样一个可编程的新型遥控器, 它有7个可编程插槽, 每个插槽可连接不同的家用电器设备. 每个插槽对应两个按钮: 开, 关(ON, OFF). 此外 ...
- iOS 私有API调用
最近自己在做一个小程序,想实现一个一键设置手机壁纸的功能.但在iOS公开的API里找不到相关的方法,只能从私有API入手. 网上有不少教程,不过都不是很详细.从google和https://stack ...
- 用 k8s 管理机密信息 - 每天5分钟玩转 Docker 容器技术(155)
应用启动过程中可能需要一些敏感信息,比如访问数据库的用户名密码或者秘钥.将这些信息直接保存在容器镜像中显然不妥,Kubernetes 提供的解决方案是 Secret. Secret 会以密文的方式存储 ...
- javaIO操作之字节输入流--InputStream
/** *<li> InputStream类中定义的方法: * <li>读取的数据保存在字节数组中,返回读取的字节数组的长度:public int read(byte[] b) ...