WebDay09-request

一 Request概述

  • 用户通过浏览器访问服务器时,Tomcat将HTTP请求中所有的信息都封装在Request对象中

  • 作用:开发人员可以通过request对象方法,来获取浏览器发送的所有信息.
    在这里插入图片描述
    Request体系结构

	ServletRequest
			|
		HttpServletRequest
			|
		org.apache.catalina.connector.RequestFacade(由tomcat厂商提供实现类)

在这里插入图片描述

二 Request获取Http请求信息

2.1 获取请求行信息

* 例如:
		GET /day09_request/requestDemo1 HTTP/1.1
	     请求方式     请求地址    协议/版本
* 相关API (查阅文档: 是javaee文档)
	1. 获取请求方式 GET【掌握】
			String getMethod()  
            
	2. 获取项目虚拟路径(项目名)/day09_request【掌握】
			String getContextPath()  
			
	3. 获取URI /day09_request/requestDemo1
			统一资源标识符
				(范围广,只要能唯一标识资源的: 本地路径,远程地址
					url 是 uri 的子集
				)  
			String getRequestURI() 
			
	4. 获取URL http://localhost:8080/day09_request/requestDemo1
			统一资源定位符(确定某一个地址:俗称网址) 
			StringBuffer getRequestURL()  
			
	5. 获取协议和版本号	HTTP/1.1
			String getProtocol()
			
	6. 获取客户端ip
			String getRemoteAddr()
@WebServlet("/requestDemo01")
public class RequestDemo01 extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException {

        System.out.println(request.getMethod());//请求方式
        System.out.println(request.getContextPath());//项目虚拟路径
        System.out.println(request.getRequestURI()); //获取请求地址
        System.out.println(request.getRequestURL()); // 获取请求地址全称
        System.out.println(request.getProtocol());//获取协议

        //0:0:0:0:0:0:0:1 -> 本地回环地址的ipv6写法(localhost)
        // 127.0.0.1 -> ipv4写法
        System.out.println(request.getRemoteAddr()); //获取客户端ip

    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}

2.2 获取请求头信息

* 例如:
		Host: localhost:8080(主机: 指的就是tomcat访问地址)	 
        name(请求头属性名,固定不变的) : value(对应的属性值,动态改变)
     	常见请求头: 
        	user-agent (用户的系统版本和浏览器)
        	referer(上一次地址) 
        	如果在浏览器中看不到某个头,就表示这个头所对应的值是null
        
* 相关API1. 获取知道请求头名称对应的值,注:名称不区分大小写
			String getHeader(String name)  
			
	2. 获取所有请求头的名称
			Enumeration<String> getHeaderNames()  
			注:是Iterator迭代器前身(枚举)
/*
* * 相关API:
	1. 获取知道请求头名称对应的值,注:名称不区分大小写
			String getHeader(String name)

	2. 获取所有请求头的名称
			Enumeration<String> getHeaderNames()
			注:是Iterator迭代器前身(枚举 enum)
* */
@WebServlet("/requestDemo02")
public class RequestDemo02 extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException {
        String host = request.getHeader("host");
        System.out.println("主机地址:" + host); // localhost:8080(tomcat的访问地址)

        String agent = request.getHeader("user-agent");
        System.out.println("用户系统和浏览器:" + agent);

        String referer = request.getHeader("referer");
        //注意: 如果直接在浏览器中输入地址访问,就意味着没有上一次访问地址,返回null
        //演示不是null的情况: 通过A地址访问本地址,A地址就是本地址的上一次访问地址
        System.out.println("上一次访问地址:" + referer);
        System.out.println("---------------------------------");

        /*List<String> list = new ArrayList<>();
        Iterator<String> it = list.iterator();
        while(it.hasNext()){ // 判断有没更多的元素
            String element = it.next(); // 获取下一个元素
            System.out.println(element);
        }*/
        //获取所有请求头的名称
        Enumeration<String> en = request.getHeaderNames();
        while(en.hasMoreElements()){// 判断有没更多的元素
            String name = en.nextElement();// 获取下一个元素 (请求头的名称)
            String value = request.getHeader(name); // 请求头名称对应的值
            System.out.println(name + ":" + value);
        }

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req,resp);
    }
}

2.3案例:视频防盗链

在这里插入图片描述

//案例:防盗链
@WebServlet("/requestDemo03")
public class RequestDemo03 extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //播放喜羊羊的地址 http://localhost:8080/day09-request/requestDemo03

        //1.获取上一次访问地址
        String referer = req.getHeader("referer");
        System.out.println(referer);
        //2.判断是否来源于本站
            //如果浏览器直接访问,referer是null
        if(referer != null && referer.startsWith("http://localhost:8080")){
            //是本站
//            System.out.println("正常播放喜羊羊");

            resp.setContentType("text/html;charset=utf-8");//防止响应体乱码
            resp.getWriter().print("正常播放喜羊羊");//明天学习,网页上输出
        }else{
            //不是本站
//            System.out.println("");

            resp.setContentType("text/html;charset=utf-8");//防止响应体乱码
            resp.getWriter().print("不好意思,无法查看,请到官方网站");//明天学习,网页上输出
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}

2.3 获取请求参数(体)【重点…】

  • 不论get还是post请求方式,都可以使用下列方法来获取请求参数

  • get请求参数放在 请求行 url中(get没有请求体)

  • post请求参数放在 请求体

  • 在web课程里面,get和post处理的业务逻辑都是一样的…

* 参数
		username=jack&password=123&hobby=drink&hobby=perm
		格式: name1=value1&name2=value2... (name是可以重复)
* API
	1. 获取指定参数名的值  username=jack
			String getParameter(String name)			
	2. 获取指定参数名的值数组  hobby=drink&hobby=perm
			String[] getParameterValues(String name)
	3. 获取所有参数名和对应值数组,参数名 name(key),值数组 value,封装map集合
			Map<String,String[]> getParameterMap()
				 name , value
			
			
* 中文乱码【重点】
	get:在tomcat8及以上版本,内部URL编码(UTF-8)
	post:编码解码不一致,造成乱码现象
		客户端(浏览器)编码:UTF-8
		服务器默认     解码:ISO-8859-1 拉丁文
		指定解码:void setCharacterEncoding(String env)
			注:这哥们必须在方法内,行首
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>get请求</h1>
    <form action="/day09-request/requestDemo04" method="get">
        用户 <input type="text" name="username" > <br>
        密码 <input type="text" name="password" > <br>
        性别 
            <input type="radio" name="gender" value="male"><input type="radio" name="gender" value="female"><br>
        爱好
        <input type="checkbox" name="hobby" value="smoke"> 抽烟
            <input type="checkbox" name="hobby" value="drink"> 喝酒
                <input type="checkbox" name="hobby" value="perm"> 烫头 <br>
        <input type="submit">
    </form>

    <h1>post请求</h1>
    <form action="/day09-request/requestDemo04" method="post">
        用户 <input type="text" name="username" > <br>
        密码 <input type="text" name="password" > <br>
        性别
        <input type="radio" name="gender" value="male"><input type="radio" name="gender" value="female"><br>
        爱好
        <input type="checkbox" name="hobby" value="smoke"> 抽烟
        <input type="checkbox" name="hobby" value="drink"> 喝酒
        <input type="checkbox" name="hobby" value="perm"> 烫头 <br>
        <input type="submit">
    </form>
</body>
</html>
/*
* * 参数
		username=jack&password=123&hobby=drink&hobby=perm
		格式: name1=value1&name2=value2... (name是可以重复)
* API
	1. 获取指定参数名的值  username=jack
			String getParameter(String name)
	2. 获取指定参数名的值数组  hobby=drink&hobby=perm (爱好)
			String[] getParameterValues(String name)
	3. 获取所有参数名和对应值数组,参数名 name(key),值数组 value,封装map集合
			Map<String,String[]> getParameterMap()
				 name , value

	# post请求参数中文乱码问题
        1. get请求乱码问题, tomcat8以及以上解决了
            参数放在地址栏中(url), url编码(js的方法 encodeURI decodeURL)

        2. post乱码, 参数放在请求体(不一定是中文, 可能提交文件)
                浏览器提交参数: utf-8编码
                tomcat默认: 使用的是 iso-8859-1解码(拉丁文,256个,欧码)

           解决: 我们自己得手动指定 解码 的字符集 utf-8
            //在post请求方式获取参数之前,指定解码字符集
                 request.setCharacterEncoding("utf-8");
* */
@WebServlet("/requestDemo04")
public class RequestDemo04  extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String username = req.getParameter("username"); // 一个name对应一个value
        String password = req.getParameter("password");
        String gender = req.getParameter("gender");
        String[] hobbies = req.getParameterValues("hobby"); // name对应多个value情况
        System.out.println(username + "," + password + "," + gender + "," + Arrays.toString(hobbies));
        System.out.println("--------------------");
        // 获取所有的参数
        // 其中key是name, value是name对应的值
        Map<String, String[]> parameterMap = req.getParameterMap();
        Set<String> keySet = parameterMap.keySet();
        for (String key : keySet) {
            String[] value = parameterMap.get(key);
            System.out.println(key + "=" + Arrays.toString(value));
        }

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8"); //在post请求方式获取参数之前,指定解码字符集
        //post请求, 交给doGet方法执行
        this.doGet(req,resp);
    }
}

2.4 BeanUtils

  • 这哥们apache组织,提供一套工具类,简化参数的封装…
  • 简单来说:将前端提交的数据,直接封装到你想要的JavaBean中

要用BeanUtils 表单项的name属性值 和 javaBean的属性名一致即可

① 导入jar包
在这里插入图片描述
② 使用工具类封装数据

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/day09-request/requestDemo05" method="get">
        用户 <input type="text" name="username" > <br>
        密码 <input type="text" name="password" > <br>
        性别
        <input type="radio" name="gender" value="male"><input type="radio" name="gender" value="female"><br>
        爱好
        <input type="checkbox" name="hobby" value="smoke"> 抽烟
        <input type="checkbox" name="hobby" value="drink"> 喝酒
        <input type="checkbox" name="hobby" value="perm"> 烫头 <br>
        <input type="submit">
    </form>
</body>
</html>
/*
*   需求: 把所有的请求参数都封装到javaBean
*       思考: 如果参数有好多, 手动封装是不是很麻烦
*
*   解决: BeanUtils  工具包 jar (apache)
*       1. 导包: web/WEB-INF下创建lib目录, jar包放里面(两个都要)
*       2. 使用api
*           BeanUtils.populate(Object bean, Map param);
*            a. bean: 一个空的javaBean
*            b. param : 参数集合
*            c. 效果: 将param中的所有参数填充到bean对象中
* */
@WebServlet("/requestDemo05")
public class RequestDemo05 extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       /* String username = req.getParameter("username"); // 一个name对应一个value
        String password = req.getParameter("password");
        String gender = req.getParameter("gender");
        String[] hobbies = req.getParameterValues("hobby"); // name对应多个value情况

        User user = new User();
        user.setUsername(username);
        user.setPassword(password);
        user.setGender(gender);
        user.setHobby(hobbies);
        System.out.println(user);*/
        //获取所有的请求参数
        Map<String, String[]> parameterMap = req.getParameterMap();
        User user = new User(); //空的
        try {
            //将parameterMap中的所有参数填充到user对象中
             /*
            *  populate原理: 反射
            *    0. parameterMap 长这样:
            *       username=[zs]
                    password=[123]
                    gender= [male]
                    hobby= [smoke, drink]

                 1. 遍历   parameterMap
                     一次遍历为例:
                        key = username
                        value = zs
                 2. 反射找方法 (伪代码: 内省)
                      //根据方法名和形参列表找到该类的某个方法
                     Method method =  class对象.getMethod(方法名,形参列表Class对象)
                     // 调用此方法
                     method.invoke(调用方法的对象,参数)
                            //方法名根据map的key推导的
                     Method method = user.getClass().getMethod("setUsername",String.class);
                            //直接用map的value
                     method.invoke(user,value)

                  重点:  方法名根据map的key推导的!!!
                    而map的key 是由表单项的name属性值决定的
                    如果要用BeanUtils, 表单项的name属性值
                            必须和 javaBean的 setXXX的方法名(不包括set)一致!!!
                            软性规范: 属性名 和 setXXX 是一致的
                            
                   -> 结论: 要用BeanUtils 表单项的name属性值 和 javaBean的属性名一致即可   
            * */
            BeanUtils.populate(user, parameterMap);
            System.out.println(user);
            System.out.println("-----");
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");
        this.doGet(req,resp);
    }
}

javaBean其实就是一个标准类

package com.itheima03.param;
import java.util.Arrays;
/*
*   javaBean : java标准类
*       1. public 空参
*       2. private 属性
*       3. public get set方法
*       (三个必须规则,可以多不可少)
* */
public class User {
    private String username;
    private String password;
    private String gender;
    private String[] hobby;
    //一个类不声明任何构造,默认有一个public空参(隐式声明)


    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", gender='" + gender + '\'' +
                ", hobby=" + Arrays.toString(hobby) +
                '}';
    }

    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;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public String[] getHobby() {
        return hobby;
    }

    public void setHobby(String[] hobby) {
        this.hobby = hobby;
    }
}

三 Request其他功能

3.1 请求转发

  • 一种在服务器内部的资源跳转方式
  • 在这里插入图片描述
* API
	1. 通过request对象,获得转发器对象(邮递员)
			 //path是要跳转的资源路径
			RequestDispatcher getRequestDispatcher(String path)
			
	2. 通过转发器对象,实现转发功能
			 // 要记得携带请求和响应
			void forward(ServletRequest request, ServletResponse response)  
			
* 请求转发特点
	1. 浏览器:发了一次请求
	2. 地址栏:没有发生改变
	3. 只能转发到服务器内部资源....
	
* 链式编程
		request.getRequestDispatcher("/bServlet").forward(request,response)

在这里插入图片描述
就好像餐厅点菜,只能在这个餐厅点

3.2 域对象(共享数据)

  • 域对象:一个有作用范围的对象,可以在范围内共享数据

  • web中有四大域对象 : jspContext, request , session, servletContext

  • 共同点: 设置,获取和移除数据的api完全相同, 作用范围不一样

  • request域:代表一次请求的范围,一般用于一次请求中转发的多个资源中共享数据
    在这里插入图片描述
    服务员,厨师之间的交互

* API
	1. 设置数据
			void setAttribute(String name, Object o)
			
	2. 获取数据
			Object getAttribute(String name)
			
	3. 删除数据
			void removeAttribute(String name)
			
			
* 生命周期 : 一次请求到一次响应之间
	1. 何时创建?
			用户发送请求时,创建request
	2. 何时销毁
			服务器返回响应时,销毁request
	3. 作用范围?
			一次请求,可以包含多次转发
@WebServlet("/aServlet")
public class AServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("接收到客户请求,客户要吃巨无霸汉堡");
        System.out.println("单子转发给厨师");

            //域对象 设置数据
        req.setAttribute("extra","客户不吃香菜");
        //请求转发
        //1. 先获取转发器对象(邮递员,并告知要去哪里)
//        RequestDispatcher dispatcher = req.getRequestDispatcher("/bServlet");
        //2. 转发器对象,携带请求和响应转发
//        dispatcher.forward(req,resp);

        //简化(链式)
        req.getRequestDispatcher("/bServlet").forward(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       doGet(req, resp);
    }
}
@WebServlet("/bServlet")
public class BServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("厨师拿到单子,开始做汉堡");
			//域对象获取数据
        String extra = (String) req.getAttribute("extra");

        System.out.println("读取备注:" + extra);

        resp.setContentType("text/html;charset=utf-8"); //解码中文乱码
        resp.getWriter().print("汉堡好了,请吃~~");//网页上输出
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       doGet(req, resp);
    }
}

四 案例:用户登录

需求

实现用户的登录功能

登录成功跳转到SuccessServlet展示:登录成功!xxx,欢迎您

登录失败跳转到FailServlet展示:登录失败,用户名或密码错误

在这里插入图片描述
代码实现
① 创建web项目
在这里插入图片描述
②编写index.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <!--
        post请求方式参数大小无限制,相对安全
        1. 上传文件
        2. 提交表单
        -> 问题: 请求参数中文乱码
   -->
    <h1>登录页面</h1>

    <form action="/day09-login/loginServlet" method="post">
        用户<input type="text" name="username"> <br>
        密码<input type="password" name="password"> <br> <br>
        <input type="submit" value="登录">
    </form>

</body>
</html>

User实体类

// 用户对象
public class User {

    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;
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

LoginServlet

@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //post请求中文乱码
        request.setCharacterEncoding("utf-8");

        //1. 获取请求参数
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        //2. 业务处理(判断用户名和密码是否存在)
            //要登录,必先注册,注册的数据一般放在数据库中(还没学,先用伪数据)
            // 伪数据, 只有一个用户已注册: 用户名jack, 密码123
        if("jack".equalsIgnoreCase(username) && "123".equalsIgnoreCase(password)){
            //a. 账号密码正确 -> 请求转发SuccessServlet
            User user = new User();
            user.setUsername(username);
            user.setPassword(password);

            request.setAttribute("user",user);//域对象设置数据

            request.getRequestDispatcher("/successServlet").forward(request,response);

        }else{
            //b. 账号密码不正确 -> 请求转发FaliedServlet
            request.getRequestDispatcher("/failedServlet").forward(request,response);
        }
    }
}

SuccessServlet

@WebServlet("/successServlet")
public class SuccessServlet extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        System.out.println("登录成功");
            //注意, 如果没有设置,获取是null
        User user = (User) request.getAttribute("user");//域对象获取数据

        response.setContentType("text/html;charset=utf-8");
        response.getWriter().print("恭喜"+user.getUsername()+",登录成功");
    }

}

FailServlet

@WebServlet("/failedServlet")
public class FailedServlet extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        System.out.println("登录失败");

        response.setContentType("text/html;charset=utf-8");
        response.getWriter().print("用户名不存在或密码错误");
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值