> 文章列表 > JAVAWeb06-动态WEB开发核心Servlet-03

JAVAWeb06-动态WEB开发核心Servlet-03

JAVAWeb06-动态WEB开发核心Servlet-03

1. HttpServletRequest

1.1 HttpServletRequest 介绍

  1. HttpServletRequest 对象代表客户端的请求
  2. 当客户端/浏览器通过 HTTP 协议访问服务器时,HTTP 请求头中的所有信息都封装在这
    个对象中
  3. 通过这个对象的方法,可以获得客户端这些信息。

1.2 HttpServletRequest 类图

JAVAWeb06-动态WEB开发核心Servlet-03
JAVAWeb06-动态WEB开发核心Servlet-03

1.3 HttpServletRequest 常用方法

  1. getRequestURI() 获取请求的资源路径 http://localhost:8080/servlet/loginServlet
  2. getRequestURL() 获 取 请 求 的 统 一 资 源 定 位 符 ( 绝 对 路 径 )http://localhost:8080/servlet/loginServlet
  3. getRemoteHost() 获取客户端的 主机, getRemoteAddr()
  4. getHeader() 获取请求头
  5. getParameter() 获取请求的参数
  6. getParameterValues() 获取请求的参数(多个值的时候使用) , 比如 checkbox, 返回的数组
  7. getMethod() 获取请求的方式 GET 或 POST
  8. setAttribute(key, value); 设置域数据
  9. getAttribute(key); 获取域数据
  10. getRequestDispatcher() 获取请求转发对象, 请求转发的核心对象

1.4 HttpServletRequest 应用实例

  1. 需求: 说明: 在一个表单提交数据给 Servlet , 然后在 Servlet 通过 HttpServletRequest对象获取相关数据
  2. 创建 register_request.html

JAVAWeb06-动态WEB开发核心Servlet-03

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>注册</title>
</head>
<body>
<h1>注册用户</h1>
<form action="http://localhost:8080/servlet/requestMethods"method="post">u: <input type="text" name="username"/><br><br>p: <input type="password" name="pwd"/><br><br>选择你喜欢的老师:<input type="checkbox" name="hobby" value="hsp">韩顺平<input type="checkbox" name="hobby" value="lh">老韩<input type="checkbox" name="hobby" value="spls">顺平老师<br/><br/><input type="submit" value="注册用户"/>
</form>
</body>
</html>
public class HttpServletRequestMethods extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//这里我们使用request对象,获取表单提交的各种数据System.out.println("HttpServletRequestMethods doPost() 被调用..");/  获取和http请求头相关信息*/System.out.println("请求的资源路径URI= " + request.getRequestURI());//http://主机/uriSystem.out.println("请求的统一资源定位符(绝对路径)URL= " + request.getRequestURL());System.out.println("请求的客户端ip 地址= " + request.getRemoteAddr());//本地就是127.0.01//思考题:如发现某个ip 在10s中,访问的次数超过 100次,就封ip//实现思路: 1用一个集合concurrentHashmap[ip:访问次数] 2[线程/定时扫描] 3 做成处理// 获取http请求头的信息,可以指定其他,比如 User-Agent , Host等待 老师就举一个例子System.out.println("http请求头HOST= " + request.getHeader("Host"));// 说明,如果我们希望得到请求的头的相关信息,可以使用request.getHeader("请求头字段")System.out.println("该请求的发起地址是= " + request.getHeader("Referer"));// 请获取访问网站的浏览器是什么?String userAgent = request.getHeader("User-Agent");System.out.println("User-Agent= " + userAgent);// 取出FireFox, 取出最后String[] s = userAgent.split(" ");System.out.println("浏览器=" + s[s.length - 1].split("\\\\/")[0]);//获取 Cookie// 	JSESSIONID=8CBBD23BDE01BAE6705E03C5C8916BD1String cookie = request.getHeader("Cookie");String JSESSIONID = cookie.split("=")[1];System.out.println("取出JSESSIONID= " + JSESSIONID);//课堂练习: 要求同学们取出  Windows NT 10.0  和 Win64// 主要是Get / PostSystem.out.println("http请求方式~= " + request.getMethod());/  获取和请求参数相关信息, 注意要求在返回数据前,获取参数*///解决接收参数的中文乱码问题, 老师提示,写在 getParameter前.request.setCharacterEncoding("utf-8");//1. 获取表单的数据[单个数据]//username=tom&pwd=&hobby=hsp&hobby=splsString username = request.getParameter("username");String pwd = request.getParameter("pwd");//2. 获取表单一组数据String[] hobbies = request.getParameterValues("hobby");System.out.println("username= " + username);System.out.println("pwd= " + pwd);//增强for循环的快捷键 iter->回车即可 , 能使用快捷键,就使用快捷键for (String hobby : hobbies) {System.out.println("hobby=" + hobby);}//推而广之, 如果是 单选 , 下拉框 等等. => 作业布置//返回接收到的信息, 给浏览器回显//本质就是在http响应头,加上 Content-Type: text/html;charset=utf-8//说 text/html 表示返回的数据类型,浏览器会根据这个类型来解析数据// text/plain 表示返回的数据,请浏览器使用文本方式解析// application/x-tar 表示返回的是文件,浏览器就会以下载文件的方式处理response.setContentType("text/html;charset=utf-8");PrintWriter writer = response.getWriter();writer.print("<h1>提交的用户名= " + username + "</h1>");writer.flush();writer.close();}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doPost(request, response);}
}

修改 web.xml 添加配置

<servlet><servlet-name>HttpServletRequestMethods</servlet-name><servlet-class>com.hspedu.httpservletrequest.HttpServletRequestMethods</servlet-class>
</servlet>
<servlet-mapping><servlet-name>HttpServletRequestMethods</servlet-name><url-pattern>/httpServletRequestMethods</url-pattern>
</servlet-mapping>

完成测试…

1.5 HttpServletRequest 注意事项和细节

说明: 注意事项和细节,在 HttpServletRequestMethods.java 上修改演示即可

  1. 获 取 doPost 参 数 中 文 乱 码 解 决 方 案 , 注 意 setCharacterEncoding(“utf-8”) 要 写 在request.getParameter()前。
  2. 注意:如果通过 PrintWriter writer, 有返回数据给浏览器,建议将获取参数代码写在writer.print() 之前,否则可能获取不到参数值(doPost)
  3. 处理 http 响应数据中文乱码问题
    JAVAWeb06-动态WEB开发核心Servlet-03
  4. 再次理解 Http 协议响应 Content-Type 的含义, 比如 text/plain application/x-tar

1.6 课堂小练习

1、请通过 HttpServletRequest 对象获取到 , 是什么浏览器访问服务器

String userAgent = request.getHeader("User-Agent");
System.out.println("User-Agent= " + userAgent);
// 取出FireFox, 取出最后
String[] s = userAgent.split(" ");
System.out.println("浏览器=" + s[s.length - 1].split("\\\\/")[0]);

2、请想办法获取到 JSESSIONID 的值.

//获取 Cookie
// 	JSESSIONID=8CBBD23BDE01BAE6705E03C5C8916BD1String cookie = request.getHeader("Cookie");
String JSESSIONID = cookie.split("=")[1];
System.out.println("取出JSESSIONID= " + JSESSIONID);

1.7 请求转发

1.7.1 为什么需要请求转发

  1. 目前我们学习的都是一次请求,对应一个 Servlet, 如图
    JAVAWeb06-动态WEB开发核心Servlet-03
  2. 但是在实际开发中,往往业务比较复杂,需要在一次请求中,使用到多个 Servlet 完成一个任务(Servlet 链, 流水作业) 如图:
    JAVAWeb06-动态WEB开发核心Servlet-03

1.7.2 请求转发说明

  1. 实现请求转发:请求转发指一个 web 资源收到客户端请求后,通知服务器去调用另外一个 web 资源进行处理
  2. HttpServletRequest 对象(也叫 Request 对象)提供了一个getRequestDispatcher 方法,该方法返回一个 RequestDispatcher 对象,调用这个对象的 forward 方法可以实现请求转发
  3. request 对象同时也是一个域对象,开发人员通过 request 对象在实现转发时,把数据通过 request 对象带给其它 web 资源处理
  • setAttribute方法
  • getAttribute方法
  • removeAttribute方法
  • getAttributeNames方法

1.7.3 实现请求转发

请求转发原理示意图
JAVAWeb06-动态WEB开发核心Servlet-03

url是不会变化的

1.7.4 请求转发应用实例

● 需求说明/图解, 如果是 tom,提示为管理员,其它是普通用户
JAVAWeb06-动态WEB开发核心Servlet-03
JAVAWeb06-动态WEB开发核心Servlet-03
login.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>登录</title>
</head>
<body>
<form action="http://localhost:8080/servlet/checkServlet" method="post">u: <input type="text" name="username"><br><input type="submit" value="登录">
</form>
</body>
</html>

CheckServlet.java

public class CheckServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {System.out.println("CheckServlet 被调用..");//根据用户名来确定该用户是什么身份String username = request.getParameter("username");//注意:如果是同一个request对象(请求转发),那么可以在不同的servlet中,是getParameter//这里使用tom去点,而不是username去点,是因为username如果为空,会出现空指针异常if ("tom".equals(username)) { //分配request.setAttribute("role", "管理员");} else {request.setAttribute("role", "普通用户");}//获取分发器//解读  1. /manageServlet写的是 要转发的servlet的url//     2. / 会被解析成 /servlet//     3. forward(request, response) 表示把当前servlet的request对象和response对象,传递给下一个servlet使用RequestDispatcher requestDispatcher =request.getRequestDispatcher("/manageServlet");requestDispatcher.forward(request, response);}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doPost(request, response);}
}

ManageServlet.java

public class ManageServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {System.out.println("ManageServlet 被调用..");String username = request.getParameter("username");String role = (String) request.getAttribute("role");//输出信息response.setContentType("text/html;charset=utf-8");PrintWriter writer = response.getWriter();writer.print("用户名: " + username + "<br/>");writer.print("角色 : " + role);writer.flush();writer.close();}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doPost(request, response);}
}

完成测试: 注意看浏览器的请求次数和数据通信情况.

1.7.5 请求转发注意事项和细节

  1. 浏览器地址不会变化(地址会保留在第 1 个 servlet 的 url)
  2. 在同一次 HTTP 请求中,进行多次转发,仍然是一次 HTTP 请求
  3. 在同一次 HTTP 请求中,进行多次转发,多个 Servlet 可以共享 request 域/对象的数据(因为始终是同一个 request 对象)
  4. 可以转发到 WEB-INF 目录下(后面做项目使用)
  5. 不能访问当前 WEB 工程外的资源
    在前面的案例基础上演示一把
    JAVAWeb06-动态WEB开发核心Servlet-03
  6. 因为浏览器地址栏会停止在第一个 servlet ,如果你刷新页面,会再次发出请求(并且会带数据), 所以在支付页面情况下,不要使用请求转发,否则会造成重复支付[演示]

1.8 课后作业

1、下面是一个表单,前面我们使用过,完成如下功能
JAVAWeb06-动态WEB开发核心Servlet-03

  1. 编写一个 RegisterServlet , 能够接收到提交的各种数据
  2. 并把接收到的数据返回给浏览器, 并显示(回显)
  3. 注意处理中文乱码问题
  4. 暂不处理文件提交
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>表单综合案例</title>
</head>
<body>
<form action="http://localhost:8080/servlet/registerServlet" method="post">用户注册信息<br/>用户名称: <input type="text" name="username"><br/>用户密码: <input type="password" name="pwd1"><br/>确认密码: <input type="password" name="pwd2"><br/>选择你喜欢的运动项目:<input type="checkbox" name="sport" value="篮球">篮球<br/><input type="checkbox" name="sport" value="足球" checked>足球<br/><input type="checkbox" name="sport" value="手球" checked>手球<br/>请选择性别 :<input type="radio" name="gender" value="male"><br/><input type="radio" name="gender" value="female"><br/>请选择城市:<select name="city"><option>--选择--</option><option value="cd">成都</option><option value="bj">北京</option><option value="sh">上海</option></select><br/>自我介绍:<textarea name="info" rows="6" cols="20"></textarea><br/>选择你的文件(头像)<input type="file" name="myfile"><br/><input type="submit" value="提交"/> <input type="reset" value="重置"/>
</form>
</body>
</html>
public class RegisterServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {System.out.println("RegisterServlet 被调用...");request.setCharacterEncoding("utf-8");String username = request.getParameter("username");String pwd1 = request.getParameter("pwd1");String pwd2 = request.getParameter("pwd2");//获取 checkboxString[] sports = request.getParameterValues("sport");//对 sports 处理String sportsStr = "";for (String sport : sports) {sportsStr += sport + " ";}//获取 radioString gender = request.getParameter("gender");//获取 selectString city = request.getParameter("city");//获取 textareaString info = request.getParameter("info");//返回给浏览器,回显response.setContentType("text/html;charset=utf-8");PrintWriter writer = response.getWriter();writer.print("username= " + username + "<br/>");writer.print("pwd1= " + pwd1 + "<br/>");writer.print("pwd2= " + pwd2 + "<br/>");writer.print("喜欢的运动= " + sportsStr + "<br/>");writer.print("gender= " + gender + "<br/>");writer.print("city= " + city + "<br/>");writer.print("info= " + info + "<br/>");writer.flush();writer.close();}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doPost(request, response);}
}

web.xml

<servlet>
<servlet-name>RegisterServlet</servlet-name>
<servlet-class>com.hspedu.servlet.request.homework.RegisterServlet</servlet-class
>
</servlet>
<servlet-mapping>
<servlet-name>RegisterServlet</servlet-name>
<url-pattern>/registerServlet</url-pattern>
</servlet-mapping>

2、请编写一个 Servlet, 可以获取到浏览器所在电脑的操作系统版本和位数(32 还是 64), 显示在页面即可

public class ComputerServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//System.out.println("ComputerServlet ..");//可以获取到浏览器所在电脑的操作系统版本和位数(32还是64), 显示在页面即可//分析一把 http请求头//User-Agent// 	Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:97.0) Gecko/20100101 Firefox/97.0//  我们要 Windows NT 10.0 和 Win64// 老师解读// (1) Windows NT 10.0; Win64; x64; rv:97.0// (2) Windows NT 10.0 和 Win64// (3) 老师回顾使用正则表达式String userAgent = request.getHeader("User-Agent");//java基础 正则表达式String regStr = "\\\\((.*)\\\\)";Pattern compile = Pattern.compile(regStr);Matcher matcher = compile.matcher(userAgent);matcher.find();// 因为我们的userAgent只有一组 ()String group = matcher.group(0);// (Windows NT 10.0; Win64; x64; rv:97.0)String group1 = matcher.group(1);// Windows NT 10.0; Win64; x64; rv:97.0String[] operInfos = group1.split(";");System.out.println("操作系统=" + operInfos[0]);//Windows NT 10.0System.out.println("操作系统位数=" + operInfos[1].trim());// Win64}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doPost(request, response);}
}

解法2:使用字符串分割

public class Servlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {String user_agent = request.getHeader("User-Agent");String browser = user_agent.split(";")[0].split("\\\\(")[1];String version = user_agent.split(";")[2];System.out.println("browser:"+browser+",version"+version);response.setContentType("text/html;charset=utf-8");PrintWriter writer = response.getWriter();writer.write("操作系统:"+browser+"<br/>");writer.write("位数:"+version+"<br/>");writer.flush();writer.close();}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doGet(request,response);}
}

2. HttpServletResponse

2.1 HttpServletResponse 介绍

  1. 每次 HTTP 请求,Tomcat 会创建一个 HttpServletResponse 对象传递给 Servlet 程序去使用。
  2. HttpServletRequest 表示请求过来的信息,HttpServletResponse 表示所有响应的信息,如果需要设置返回给客户端的信息,通过 HttpServletResponse 对象来进行设置即可
    JAVAWeb06-动态WEB开发核心Servlet-03

2.2 HttpServletResponse 类图

JAVAWeb06-动态WEB开发核心Servlet-03

2.3 向客户端返回数据方法

JAVAWeb06-动态WEB开发核心Servlet-03

  1. 字节流 getOutputStream(); 常用于下载(处理二进制数据)
  2. 字符流 getWriter(); 常用于回传字符串
  3. (细节:)两个流同时只能使用一个。 使用了字节流,就不能再使用字符流,反之亦然,否则就会报错

2.4 向客户端返回数据应用实例

  1. 需求:浏览器请求 , 返回 hello, world
  2. 代 码 实 现 :
    创 建ResponseServlet_.java
public class ResponseServlet_ extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException,IOException {/* 解读:1. setContentType 会设置服务器和客户端都用 utf-8 字符集,还设置了响应头2. setContentType 要在获取流对象(getWriter)之前调用才有效*/response.setContentType("text/html;charset=utf-8");PrintWriter writer = response.getWriter();writer.println("<h1>hello, world~</h1>");writer.println("<h1>hi, boss</h1>");writer.flush();writer.close();}
}
  1. 在 web.xml 中完成配置.
  2. 完成测试
    JAVAWeb06-动态WEB开发核心Servlet-03

2.5 向客户端返回数据注意事项和细节

  1. 处理中文乱码问题-方案 1
    JAVAWeb06-动态WEB开发核心Servlet-03
  2. 处理中文乱码问题-方案 2
    JAVAWeb06-动态WEB开发核心Servlet-03

2.6 请求重定向

2.6.1 请求重定向介绍

  1. 请求重定向指:一个 web 资源收到客户端请求后,通知客户端去访问另外一个 web资源,这称之为请求重定向
  2. 请求重定向原理示意图
    JAVAWeb06-动态WEB开发核心Servlet-03

2.6.2 请求重定向应用实例

  1. 需 求 : 演 示 请 求 重 定 向 的 使 用 当 访 问 DownServlet 下 载 文 件 , 重 定 向 到DownServletNew 下载文件
    JAVAWeb06-动态WEB开发核心Servlet-03
  2. 创 建 DownServlet.java
public class DownServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// System.out.println("DownServlet 被调用");// response.setContentType("application/x-tar;charset=utf-8");// PrintWriter writer = response.getWriter();// writer.print("hi");// writer.flush();// writer.close();//完成了自己业务//发出请求重定向-> DownServletNew//听老师解读//1. sendRedirect 本质就会 返回 302 状态码 Location: /servlet/downServletNew//2. 因此 302和 /servlet/downServletNew 是浏览器解析,而不是服务器//3. 浏览器在解析 /servlet/downServletNew => http://localhost:8080/servlet/downServletNewresponse.sendRedirect("/servlet/downServletNew");}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doPost(request,response);}
}
  1. 创 建 DownServletNew.java
public class DownServletNew extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {System.out.println("DownServletNew 被调用...");response.setContentType("application/x-tar;charset=utf-8");PrintWriter writer = response.getWriter();writer.print("下载天龙八部..");writer.flush();writer.close();}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doPost(request,response);}
}
  1. 在 web.xml 中完成 servlet 配置

  2. 完成测试

2.6.3 请求重定向注意事项和细节

  1. 最佳应用场景:网站迁移,比如原域名是 www.hsp.com 迁移到 www.hsp.cn ,但是百度抓取的还是原来网址.
  2. 浏览器地址会发生变化,本质是两次 http 请求.
  3. 不能共享 Request 域中的数据,本质是两次 http 请求,会生成两个 HttpServletRequest对象
  4. 不能重定向到 /WEB-INF 下的资源
  5. 可以重定向到 Web 工程以外的资源, 比如 到 www.baidu.com 【在前面的案例演示】
  6. 重定向有两种方式, 推荐使用第 1 种.
    JAVAWeb06-动态WEB开发核心Servlet-03
    JAVAWeb06-动态WEB开发核心Servlet-03
  7. 动态获取到 application context
String contextPath = getServletContext().getContextPath();
System.out.println("contextPath= " + contextPath);
response.sendRedirect(contextPath + "/downServletNew");

2.7 课后作业

1、看具体需求
JAVAWeb06-动态WEB开发核心Servlet-03
JAVAWeb06-动态WEB开发核心Servlet-03

  1. 编写一个 MyPayServlet , 能够接收到提交的数据
  2. 编写一个简单的支付页面 pay.html(如图)
  3. 如果支付金额大于 100, 则重定向到 payok.html, 否则重定向到原来的 pay.html

pay.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>支付页面</title>
</head>
<body>
<h1>支付页面</h1>
<!--注意:这里action="/servlet/myPayServlet"的第一/被浏览器解析从浏览器地址栏的主机-->
<form action="/servlet/myPayServlet" method="post">用户编号: <input type="text" name="userid"><br/>支付金额: <input type="text" name="money"><br/><input type="submit" value="点击支付">
</form>
</body>
</html>

payok.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>支付成功</title>
</head>
<body>
<h1>恭喜你,支付成功~</h1>
</body>
</html>

WebUtils.java

/* 编写一个转换string->int的方法,处理异常*/
public class WebUtils {public static int parseString(String str) {int num = 0;//try-catch : ctrl+alt+t//如果不知道老师在说什么? 回去看到java基础 - 异常try {num = Integer.parseInt(str);} catch (NumberFormatException e) {//这个异常不会throw 给 tomcatSystem.out.println("输入的str格式不正确...");}return num;}
}

MyPayServlet.java

public class MyPayServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//System.out.println("MyPayServlet 被调用...");//得到金额String money = request.getParameter("money");System.out.println("money= " + money.getClass());//转成int//处理一下这个异常int iMoney = WebUtils.parseString(money);ServletContext servletContext = getServletContext();if(iMoney > 100) {//重定向到payok.html//servletContext.getContextPath() 就是 /servletresponse.sendRedirect(servletContext.getContextPath() + "/payok.html");} else {response.sendRedirect(servletContext.getContextPath() + "/pay.html");}}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doPost(request, response);}
}