本节内容:
- HttpServletRequest概述
- request的运行流程
- 通过抓包工具抓取Http请求
- 通过request获得请求行
- 通过request获得请求头
- 通过request获得请求体
- request的其他功能
- 示例:注册
- 示例:登录
一、HttpServletRequest概述
我们在创建Servlet时会覆盖service()方法,或doGet()/doPost(),这些方法都有两个参数,一个为代表请求的request和代表响应response。
service方法中的request的类型是ServletRequest,而doGet/doPost方法的request的类型是HttpServletRequest,HttpServletRequest是ServletRequest的子接口,功能和方法更加强大。
二、request的运行流程
三、通过抓包工具抓取Http请求
request代表请求,我们可以通过该对象分别获得Http请求的请求行,请求头和请求体。
注意:GET方式是没有请求体的。现阶段只有表单,并且表单的方法是post的是POST提交,其他都是GET提交。
四、通过request获得请求行
获得客户端的请求方式:String getMethod()
获得请求的资源:
- String getRequestURI():所有的资源地址,比如C:a.txt,还有相对地址
- StringBuffer getRequestURL():一般情况指的是网络资源,比如http
- String getContextPath():获取web应用的名称
- String getQueryString():获取get方式提交url地址后的参数字符串,比如username=zhangsan&password=123
- request.getRemoteAddr():获得访问的客户端IP地址
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> <form action="/WEB15/line" method="get"> <!-- get和post都测试下--> <input type="text" name="username"><br> <input type="password" name="password"><br> <input type="submit" value="提交"><br> </form> </body> </html>
public class LineServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1、获得请求方式 String method = request.getMethod(); System.out.println("method:"+method); //2、获得请求的资源相关的内容 String requestURI = request.getRequestURI(); StringBuffer requestURL = request.getRequestURL(); System.out.println("uri:"+requestURI); // /WEB15/line System.out.println("url:"+requestURL); // http://localhost:8080/WEB15/line //获得web应用的名称 String contextPath = request.getContextPath(); System.out.println("web应用:"+contextPath); // /WEB15 //地址后的参数的字符串 String queryString = request.getQueryString(); System.out.println(queryString); // GET方式才有值,POST方式提交为null //3、获得客户机的信息---获得访问者IP地址 String remoteAddr = request.getRemoteAddr(); System.out.println("IP:"+remoteAddr); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
五、通过request获得请求头
- long getDateHeader(String name)
- String getHeader(String name):header都是键值对。
- Enumeration getHeaderNames():获取所有header头的名字。返回类型是枚举。
- Enumeration getHeaders(String name):某些头可能有多个值。基本不用,因为基本不会有同名的头。
- int getIntHeader(String name)
public class HeaderServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1、获得指定的头 String header = request.getHeader("User-Agent"); System.out.println(header); //2、获得所有的头的名称和值 Enumeration<String> headerNames = request.getHeaderNames(); //Enumeration,枚举类型,你可以认为它是一个集合,现在用的不多了 while(headerNames.hasMoreElements()){ String headerName = headerNames.nextElement(); String headerValue = request.getHeader(headerName); System.out.println(headerName+":"+headerValue); } } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
referer头的作用:执行该此访问(请求)的的来源。即这次请求来源于哪个资源。
【示例】:在页面中写一个a标签,一点击访问HeaderServlet。header中就有referer。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> <a href="/WEB15/referer">访问headerServlet资源</a> </body>
public class HeaderServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1、获得指定的头 String header = request.getHeader("User-Agent"); System.out.println(header); //2、获得所有的头的名称和值 Enumeration<String> headerNames = request.getHeaderNames(); //Enumeration,枚举类型,你可以认为它是一个集合,现在用的不多了 while(headerNames.hasMoreElements()){ String headerName = headerNames.nextElement(); String headerValue = request.getHeader(headerName); System.out.println(headerName+":"+headerValue); } } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
浏览器访问http://localhost:8080/WEB15/form.html,点击a标签,查看eclipse控制台打印的header结果,发现有个refer:
referer:http://localhost:8080/WEB15/form.html
【示例】:利用referer头做防盗链。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> <a href="/WEB15/referer">访问headerServlet资源</a> <form action="/WEB15/line" method="get"> <input type="text" name="username"><br> <input type="password" name="password"><br> <input type="submit" value="提交"><br> </form> </body> </html>
public class RefererServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //对该新闻的来源的进行判断 String header = request.getHeader("referer"); if(header!=null&&header.startsWith("http://localhost")){ //企业里面可以把localhost换成域名 //是从我自己的网站跳转过来的 可以看新闻 response.setContentType("text/html;charset=UTF-8"); response.getWriter().write("中国确实已经拿到100块金牌...."); }else{ response.getWriter().write("你是盗链者,可耻!!"); } } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
六、通过request获得请求体
请求体中的内容是通过post提交的请求参数,格式是:
username=zhangsan&password=123&hobby=football&hobby=basketball
以上面参数为例,通过一下方法获得请求参数:
- String getParameter(String name)
- String[] getParameterValues(String name)
- Enumeration getParameterNames()
- Map<String,String[]> getParameterMap()
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> <form action="/WEB15/content" method="post"> <!-- post和get都试下,后台写代码都是可以获取到请求参数的> <input type="text" name="username"><br> <input type="password" name="password"><br> <input type="checkbox" name="hobby" value="zq">足球 <input type="checkbox" name="hobby" value="pq">排球 <input type="checkbox" name="hobby" value="ppq">乒乓球<br> <input type="submit" value="提交"><br> </form> </body> </html>
public class ContentServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1、获得单个表单值 String username = request.getParameter("username"); System.out.println(username); String password = request.getParameter("password"); System.out.println(password); //2、获得多个表单的值 --比如checkbox的多值情况 String[] hobbys = request.getParameterValues("hobby"); for(String hobby:hobbys){ System.out.println(hobby); } //3、获得所有的请求参数的名称 Enumeration<String> parameterNames = request.getParameterNames(); while(parameterNames.hasMoreElements()){ System.out.println(parameterNames.nextElement()); } System.out.println("------------------"); //4、获得所有的参数 参数封装到一个Map<String,String[]> /* username [zhangsan] password [123] hobby [football,basketball] */ Map<String, String[]> parameterMap = request.getParameterMap(); for(Map.Entry<String, String[]> entry:parameterMap.entrySet()){ System.out.println(entry.getKey()); for(String str:entry.getValue()){ System.out.println(str); } System.out.println("---------------------------"); } } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
【注意】:get请求方式的请求参数,上述的方法一样可以获得。
七、request的其他功能
1. request是一个域对象
request对象也是一个存储数据的区域对象,所以也具有如下方法:
- setAttribute(String name, Object o)
- getAttribute(String name)
- removeAttribute(String name)
注意:request域的作用范围:一次请求中。每次访问都会产生新的request和response对象。
2. request完成请求转发
先获得请求转发器 --path是转发的地址
RequestDispatcher getRequestDispatcher(String path)
在通过转发器对象的forward方法转发
requestDispathcer.forward(ServletRequest request, ServletResponse response)
public class Servlet1 extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //想request域中存储数据 request.setAttribute("name", "tom"); //servlet1 将请求转发给servlet2 RequestDispatcher dispatcher = request.getRequestDispatcher("/servlet2"); //执行转发的方法 dispatcher.forward(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
public class Servlet2 extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //从request域中取出数据 Object attribute = request.getAttribute("name"); response.getWriter().write("hello haohao..."+attribute); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
ServletContext域与Request域的生命周期比较?
ServletContext域:
创建:服务器启动
销毁:服务器关闭
域的作用范围:整个web应用
request域:
创建:访问时创建request
销毁:响应结束request销毁
域的作用范围:一次请求中
转发与重定向的区别?
1)重定向是两次请求,转发是一次请求
2)重定向地址栏的地址变化,转发地址不变
3)重新定向可以访问外部网站(比如可以重定向到百度),转发只能访问内部资源(转发给内部的地址)。
4)转发的性能要优于重定向
客户端地址与服务器端地址的写法?
客户端地址:是客户端去访问服务器的地址,属于服务器外部的地址,就是从外部访问服务器资源。特点:需要写上web应用名称。
- 直接输入地址
- 重定向
服务器端地址:服务器内部资源的跳转的地址,特点:不需要写web应用的名称。
- 转发
八、示例:注册
表:
CREATE TABLE `user` ( `uid` varchar(50) NOT NULL, `username` varchar(20) DEFAULT NULL, `password` varchar(20) DEFAULT NULL, `name` varchar(20) DEFAULT NULL, `email` varchar(30) DEFAULT NULL, `telephone` varchar(20) DEFAULT NULL, `birthday` varchar(20) DEFAULT NULL, `sex` varchar(10) DEFAULT NULL, `state` int(11) DEFAULT NULL, `code` varchar(64) DEFAULT NULL, PRIMARY KEY (`uid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
页面:
<div class="container" style=" 100%; background: url('image/regist_bg.jpg');"> <div class="row"> <div class="col-md-2"></div> <div class="col-md-8" style="background: #fff; padding: 40px 80px; margin: 30px; border: 7px solid #ccc;"> <font>会员注册</font>USER REGISTER <form class="form-horizontal" style="margin-top: 5px;" action="/WEB15_request/register" method="post"> <div class="form-group"> <label for="username" class="col-sm-2 control-label">用户名</label> <div class="col-sm-6"> <input type="text" class="form-control" id="username" name="username" placeholder="请输入用户名"> </div> </div> <div class="form-group"> <label for="inputPassword3" class="col-sm-2 control-label">密码</label> <div class="col-sm-6"> <input type="password" class="form-control" id="inputPassword3" name="password" placeholder="请输入密码"> </div> </div> <div class="form-group"> <label for="confirmpwd" class="col-sm-2 control-label">确认密码</label> <!-- 确认密码不需要传到数据库 --> <div class="col-sm-6"> <input type="password" class="form-control" id="confirmpwd" placeholder="请输入确认密码"> </div> </div> <div class="form-group"> <label for="inputEmail3" class="col-sm-2 control-label">Email</label> <div class="col-sm-6"> <input type="email" class="form-control" id="inputEmail3" name="email" placeholder="Email"> </div> </div> <div class="form-group"> <label for="usercaption" class="col-sm-2 control-label">姓名</label> <div class="col-sm-6"> <input type="text" class="form-control" id="usercaption" name="name" placeholder="请输入姓名"> </div> </div> <div class="form-group opt"> <label for="inlineRadio1" class="col-sm-2 control-label">性别</label> <div class="col-sm-6"> <label class="radio-inline"> <input type="radio" name="sex" id="inlineRadio1" value="male"> 男 </label> <label class="radio-inline"> <input type="radio" name="inlineRadioOptions" id="inlineRadio2" value="female"> 女 </label> </div> </div> <div class="form-group"> <label for="date" class="col-sm-2 control-label">出生日期</label> <div class="col-sm-6"> <input type="date" class="form-control" name="birthday"> </div> </div> <div class="form-group"> <label for="date" class="col-sm-2 control-label">验证码</label> <div class="col-sm-3"> <input type="text" class="form-control"> </div> <div class="col-sm-2"> <img src="./image/captcha.jhtml" /> </div> </div> <div class="form-group"> <div class="col-sm-offset-2 col-sm-10"> <input type="submit" width="100" value="注册" name="submit" style="background: url('./images/register.gif') no-repeat scroll 0 0 rgba(0, 0, 0, 0); height: 35px; 100px; color: white;"> </div> </div> </form> </div> <div class="col-md-2"></div> </div> </div>
处理注册的Servlet:
public class RegisterServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //设置request的编码,request编码默认也是ISO-8859-1 ---只适合post方式 request.setCharacterEncoding("UTF-8"); //get方式乱码解决,该方式也适用POST方式。但是表单一般都是POST方式提交 //String username = request.getParameter("username");//乱码 //先用iso8859-1编码 在使用utf-8解码 //username = new String(username.getBytes("iso8859-1"),"UTF-8"); //1、获取数据 //String username = request.getParameter("username"); //System.out.println(username); //String password = request.getParameter("password"); //..... //2、将散装的封装到javaBean,这种比较麻烦,一般都不用,用BeanUtils工具 //User user = new User(); //user.setUsername(username); //user.setPassword(password); //使用BeanUtils进行自动映射封装。依赖两个包commons-beanutils-1.8.3.jar和commons-logging-1.1.1.jar //BeanUtils工作原理:将map中的数据 根据key与实体的属性的对应关系封装 //只要key的名字与实体的属性 的名字一样 就自动封装到实体中 Map<String, String[]> properties = request.getParameterMap(); //如果是get方式提交的,要循环这个Map,去解码编码,防止中文乱码 User user = new User(); try { BeanUtils.populate(user, properties); } catch (IllegalAccessException | InvocationTargetException e) { e.printStackTrace(); } //到目前为止,user对象已经封装好了。但是user表有个uid字段,它是个主键 //手动封装uid----使用uuid产生随机不重复的字符串32位--但是java代码生成后是36位 user.setUid(UUID.randomUUID().toString()); //3、将参数传递给一个业务操作方法 try { regist(user); } catch (SQLException e) { e.printStackTrace(); } //4、认为注册成功跳转到登录页面 response.sendRedirect(request.getContextPath()+"/login.jsp"); } //注册的方法 public void regist(User user) throws SQLException{ //操作数据库 QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource()); String sql = "insert into user values(?,?,?,?,?,?,?,?,?,?)"; runner.update(sql,user.getUid(),user.getUsername(),user.getPassword(),user.getName(), user.getEmail(),null,user.getBirthday(),user.getSex(),null,null); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
http请求提交时,post方式提交时数据在请求体,get方式提交时数据是请求行中。request对请求行和请求体的处理是不一样的。
解决post提交方式的乱码:request.setCharacterEncoding("UTF-8");
解决get提交的方式的乱码:
parameter = new String(parameter.getbytes("iso8859-1"),"utf-8");
九、示例:登录
转发:
<body> <!-- 引入header.jsp --> <jsp:include page="/header.jsp"></jsp:include> <div class="container" style=" 100%; height: 460px; background: #FF2C4C url('images/loginbg.jpg') no-repeat;"> <div class="row"> <div class="col-md-7"> <!--<img src="./image/login.jpg" width="500" height="330" alt="会员登录" title="会员登录">--> </div> <div class="col-md-5"> <div style=" 440px; border: 1px solid #E7E7E7; padding: 20px 0 20px 30px; border-radius: 5px; margin-top: 60px; background: #fff;"> <font>会员登录</font>USER LOGIN <div><%=request.getAttribute("loginInfo")==null?"":request.getAttribute("loginInfo") %>></div> <form class="form-horizontal" action="/WEB15_request/login" method="post"> <div class="form-group"> <label for="username" class="col-sm-2 control-label">用户名</label> <div class="col-sm-6"> <input type="text" class="form-control" id="username" name="username" placeholder="请输入用户名"> </div> </div> <div class="form-group"> <label for="inputPassword3" class="col-sm-2 control-label">密码</label> <div class="col-sm-6"> <input type="password" class="form-control" id="inputPassword3" name="password" placeholder="请输入密码"> </div> </div> <div class="form-group"> <label for="inputPassword3" class="col-sm-2 control-label">验证码</label> <div class="col-sm-3"> <input type="text" class="form-control" id="inputPassword3" placeholder="请输入验证码"> </div> <div class="col-sm-3"> <img src="./image/captcha.jhtml" /> </div> </div> <div class="form-group"> <div class="col-sm-offset-2 col-sm-10"> <div class="checkbox"> <label> <input type="checkbox"> 自动登录 </label> <label> <input type="checkbox"> 记住用户名 </label> </div> </div> </div> <div class="form-group"> <div class="col-sm-offset-2 col-sm-10"> <input type="submit" width="100" value="登录" name="submit" style="background: url('./images/login.gif') no-repeat scroll 0 0 rgba(0, 0, 0, 0); height: 35px; 100px; color: white;"> </div> </div> </form> </div> </div> </div> </div> <!-- 引入footer.jsp --> <jsp:include page="/footer.jsp"></jsp:include> </body>
public class LoginServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); //1、获得用户名和密码 String username = request.getParameter("username"); String password = request.getParameter("password"); //2、调用一个业务方法进行该用户查询 User login = null; try { login = login(username,password); } catch (SQLException e) { e.printStackTrace(); } //3、通过user是否为null判断用户名和密码是否正确 if(login!=null){ //代表用户名和密码正确 //登录成功 跳转到网站的首页 response.sendRedirect(request.getContextPath()); //重定向 }else{ //代表用户名或密码错误 //跳回当前login.jsp //使用转发 转发到login.jsp 向request域中存储错误信息 request.setAttribute("loginInfo", "用户名或密码错误"); request.getRequestDispatcher("/login.jsp").forward(request, response); //转发,转发时可以往request域中存些内容 } } public User login(String username,String password) throws SQLException{ QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource()); String sql = "select * from user where username=? and password=?"; User user = runner.query(sql, new BeanHandler<User>(User.class), username,password); return user; } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }