JavaEE5_Request

文章目录

HttpServletRequest概述

我们在创建Servlet时会覆盖service()方法,或doGet()/doPost(),这些方法都有两个参数,一个为代表请求的request和代表响应response。service方法中的request的类型是ServletRequest,而doGet/doPost方法的request的类型是HttpServletRequest,HttpServletRequest是ServletRequest的子接口,功能和方法更加强大的HttpServletRequest。

request对象和response对象的原理

1. request和response对象是由服务器创建的。我们来使用它们
2. request对象是来获取请求消息,response对象是来设置响应消息

request对象和response对象的运行流程
JavaEE5_Request

request对象继承体系结构

ServletRequest		--	接口
	|	继承
HttpServletRequest	-- 接口
	|	实现
org.apache.catalina.connector.RequestFacade 类(tomcat)

reques获取功能

1.获取请求行数据

获取下面请求中的任意信息。
GET /ginger/request?name=zhangsan HTTP/1.1

@WebServlet("/request")
public class RequestServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //http://localhost:8080/ginger/request
        //1. 获取请求方式:GET
        String method = req.getMethod();

        //2. 获取虚拟目录:/ginger
        String contextPath = req.getContextPath();

        //3. 获取Servlet路径:/request
        String servletPath = req.getServletPath();

        //4. 获取get方式请求参数:name=zhangsan
        String queryString = req.getQueryString();

        //5. 获取请求URI:/ginger/request
        String requestURI = req.getRequestURI();

        //6. 获取请求URL:http://localhost:8080/ginger/request
        StringBuffer requestURL = req.getRequestURL();

        //7. 获取协议及版本:HTTP/1.1
        String protocol = req.getProtocol();

        //8. 获取客户机信息:
        //0:0:0:0:0:0:0:1本机地址获取为了IPV6的IP,这现象只有在服务器和客户端都在同抄一台电脑上才会出现
        String remoteHost = req.getRemoteHost();

        String remoteUser = req.getRemoteUser();//null

        //0:0:0:0:0:0:0:1本机地址获取为了IPV6的IP,这现象只有在服务器和客户端都在同抄一台电脑上才会出现
        String remoteAddr = req.getRemoteAddr();

        int remotePort = req.getRemotePort();//54244
    }

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

2. 获取请求头数据

@WebServlet("/request2")
public class RequestServlet2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
   //通过请求头的名称获取请求头的值:Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:75.0) Gecko/20100101 Firefox/75.0
        String header = req.getHeader("user-agent");
        System.out.println(header);

        //获取所有的请求头名称:
        Enumeration<String> headerNames = req.getHeaderNames();
        //Enumeration类似迭代器,遍历就行了。
        while (headerNames.hasMoreElements()){
             //获取所有请求头对应的信息。
            System.out.println(req.getHeader(headerNames.nextElement()));
            
            //获取的请求头信息
            //localhost:8080
            //Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:75.0) Gecko/20100101 Firefox/75.0
            //text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
            //zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
            //gzip, deflate
            //keep-alive
            //JSESSIONID=C91DCF88358233DFDACC8954C8120A0A
            //1
        }
    }

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

3. 获取请求体数据

请求体:只有POST请求方式,才有请求体,在请求体中封装了POST请求的请求参数
步骤:

1. 获取流对象
BufferedReader getReader():获取字符输入流,只能操作字符数据
ServletInputStream getInputStream():获取字节输入流,可以操作所有类型数据
				
2. 再从流对象中拿数据
@WebServlet("/request3")
public class RequestServlet3 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //步骤:
        //1. 获取流对象
            //BufferedReader getReader():获取字符输入流,只能操作字符数据
            //BufferedReader reader = req.getReader();
            //ServletInputStream getInputStream():获取字节输入流,可以操作所有类型数据
            ServletInputStream inputStream = req.getInputStream();

        //2. 再从流对象中拿数据
            //字符流获取数据
           /* String line= null;
            while ((line=reader.readLine())!=null){
                System.out.println(line);
            }*/
             System.out.println("-------------------------");
            //字节流获取数据
            byte[] bys=  new byte[1024*8];
            int len = 0;
            while((len=inputStream.read(bys))!=-1){
                System.out.println(new String(bys,0,len));//username=zhangsan&password=123456
            }
    }

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

reques其他功能

JavaEE5_Request

1. 获取请求参数通用方式:不论get还是post请求方式都可以使用下列方法来获取请求参数

中文乱码问题:
	get方式:tomcat 8 已经将get方式乱码问题解决了
	 		如果是tomcat低于8还是要解决乱码	
	 		String name = new String(name.getBytrs("ISO8859-1"),"UTF-8");
	 post方式:会乱码
		 解决:在获取参数前,设置request的编码request.setCharacterEncoding("utf-8");
@WebServlet("/request4")
public class RequestServlet4 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    	//get提交方式
        //1. String getParameter(String name):根据参数名称获取参数值
        //结果:张三
        String username = req.getParameter("username");

        //2. String[] getParameterValues(String name):根据参数名称获取参数值的数组
        //结果:疾风剑豪 影流之主
        String[] hobbys = req.getParameterValues("hobby");
        for (String hobby : hobbys) { System.out.println(hobby); }

        //3. Enumeration<String> getParameterNames():获取所有请求的参数名称
        //结果:host  user-agent  accept  accept-language accept-encoding  connection  referer cookie  upgrade-insecure-requests
        Enumeration<String> headerNames = req.getHeaderNames();
        //遍历获取到的参数名称数组
        while (headerNames.hasMoreElements()) { System.out.println(headerNames.nextElement()); }

        //4. Map<String,String[]> getParameterMap():获取所有参数的map集合。
        //结果:username:张三   password:1234567    hobby:格雷福斯 疾风剑豪 影流之主
        Map<String, String[]> parameterMap = req.getParameterMap();
        //获取键值对对象集合并遍历
        for (Map.Entry<String, String[]> me : parameterMap.entrySet()) {
            String key = me.getKey();
            String[] values = me.getValue();
            System.out.print(key+":");
            for (String value : values) {
                System.out.print(value+" ");
            }
            System.out.println();
        }
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }
}

2. 请求转发:一种在服务器内部的资源跳转方式

请求转发图解
JavaEE5_Request

步骤:
	1. 通过request对象获取请求转发器对象:RequestDispatcher getRequestDispatcher(String path)
	2. 使用RequestDispatcher对象来进行转发:forward(ServletRequest request, ServletResponse response)
特点:
		1. 浏览器地址栏路径不发生变化
		2. 只能转发到当前服务器内部资源中。
		3. 转发是一次请求

@WebServlet("/request5")
public class RequestServlet5 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1. 通过request对象获取请求转发器对象:RequestDispatcher getRequestDispatcher(String path)
        //RequestDispatcher requestDispatcher = req.getRequestDispatcher("/request4");
       
        //2. 使用RequestDispatcher对象来进行转发:forward(ServletRequest request, ServletResponse response)
        //requestDispatcher.forward(req, resp);

        //连式编程
        req.getRequestDispatcher("/request4").forward(req,resp );
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }
}

结果:

转发到了demo04........

3. 共享数据

域对象:一个有作用范围的对象,可以在范围内共享数据
request域:代表一次请求的范围,一般用于请求转发的多个资源*享数据

@WebServlet("/request6")
public class RequestServlet6 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1. void setAttribute(String name,Object obj):存储数据
        req.setAttribute("11111","法外狂徒");
        req.setAttribute("22222","影流之主" );

        //3. void removeAttribute(String name):通过键移除键值对
        req.removeAttribute("22222");

        //转发到request5
        req.getRequestDispatcher("/request5").forward(req,resp );
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }
}

从reqeust6转发到request5

@WebServlet("/request5")
public class RequestServlet5 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //2. Object getAttitude(String name):通过键获取值
        Object obj1 = req.getAttribute("11111");
        Object obj2 = req.getAttribute("22222");
        System.out.println(obj1);
        System.out.println(obj2);
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }
}

结果

法外狂徒
null

4. 获取ServletContext

@WebServlet("/request7")
public class RequestServlet7 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取ServletContext两种方式
        ServletContext servletContext = req.getServletContext();
        ServletContext servletContext1 = this.getServletContext();
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }
}

路径写法

路径分类

  1. 相对路径:通过相对路径不可以确定唯一资源
 	 如:./index.html
	 不以/开头,以.开头路径

	 规则:找到当前资源和目标资源之间的相对位置关系
		 ./:当前目录
		 ../:后退一级目录
  1. 绝对路径:通过绝对路径可以确定唯一资源
 	如:http://localhost:8080/ginger/response3		/ginger/response3
	以/开头的路径

	规则:判断定义的路径是给谁用的?判断请求将来从哪儿发出
			 给客户端浏览器使用:需要加虚拟目录(项目的访问路径)
				 建议虚拟目录动态获取:request.getContextPath()
				 <a> , <form> 重定向...
		     给服务器使用:不需要加虚拟目录
				 转发路径

相对路径和绝对路径一般都是通过需求来判断路径写法。
相对路径演示
定义一个html页面

<body>
        <h3>相对路径就是当前资源路径相对于目标资源路径的相对位置关系</h3>
        <p>
            当前资源:localhost.html
            http://localhost:8080/ginger/localhost.html
        </p>
        <p>
            目标资源:/response3
            http://localhost:8080/ginger/response3
        </p>
        <!--response3代表./response3-->
        <a href="response3">response3</a><br>
        <!--html/location2.html代表./html/location2.html-->
        <a href="html/location2.html">location2.html</a>

</body>

并访问页面
JavaEE5_Request

点击response3
JavaEE5_Request
点击location2.html
JavaEE5_Request
绝对路径演示
重定向在response有演示
转发在上面有演示

获取user-agent和referer请求头并演示兼容和盗链

user-agent头应用演示

@WebServlet("/request8")
public class RequestServlet8 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //演示获取请求头数据:user-agent
        String agent = req.getHeader("User-Agent");
        if(agent.contains("Chrome")){
            //谷歌
            System.out.println("谷歌访问的......");
        }else if(agent.contains("Firefox")){
            //火狐
            System.out.println("火狐访问的......");
        }
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }
}

使用火狐访问结果:

火狐访问的......

referer头应用演示
假设这是腾讯平台

@WebServlet
public class RequestServlet9 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //演示获取请求头数据:referer表示该请求时从哪里来
        String referer = req.getHeader("referer");
        System.out.println(referer);
        if(referer!=null){
            //查看该访问连接中是否包含自己的项目路径。
            if (referer.contains("/ginger")) {
                //正常访问
                resp.setContentType("text/html;charset=utf-8");
                resp.getWriter().write("播放电影....");
            } else {
                //盗链
                resp.setContentType("text/html;charset=utf-8");
                resp.getWriter().write("想看电影吗?来腾讯吧...");
            }
        }
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }
}

结果:我就是输出了一个该请求是从哪里来的

http://localhost/gaoqing/

假设创建新一个模块演示,表示其它的平台。(到时候会跳转到腾讯平台)
在该模块中写一个html页面用于访问腾讯平台
JavaEE5_Request
访问该页面
JavaEE5_Request
访问结果
JavaEE5_Request

案例:用户登录

画图分析:
JavaEE5_Request

我的项目结构
JavaEE5_Request
dao代码

public class UserDaoImpl {
    private JdbcTemplate jt = new JdbcTemplate(JDBCUtils.getDaSource());

    public User login(User user) {
        try {
            //定义sql语句
            String sql = "select * from User where username=? and password=?";
            User u = jt.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class),
                    user.getUsername(), user.getPassword());
            return user;
        } catch (DataAccessException e) {
            return null;
        }
    }
}

pojo代码

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 + '\'' +
                '}';
    }
}

servlet代码

@WebServlet("/failServlet")
public class FailServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=utf-8");
        resp.getWriter().write("登录失败了,用户名或者密码错误。。。。");
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }
}
@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取用户名和密码
        //String username = req.getParameter("username");
        //String password = req.getParameter("password");
        //创建用户对象
        //User user = new User();
        //user.setUsername(username);
        //user.setPassword(password);
        //获取所有请求参数
        Map<String, String[]> map = req.getParameterMap();

        //使用BeanUtils简化封装
        User user =new  User();
        try {
            BeanUtils.populate(user,map);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

        //调用dao方法
        UserDaoImpl udi = new UserDaoImpl();
        User u = udi.login(user);
        //根据返回User对象是否为空,转发到成功或者失败页面。
        if (u != null) {
            req.setAttribute("user", u);
            //转发到登录成功页面
            req.getRequestDispatcher("/successServlet").forward(req, resp);
        } else {
            //转发到登录失败页面
            req.getRequestDispatcher("/failServlet").forward(req, resp);
        }
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }
}
@WebServlet("/successServlet")
public class SuccessServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        User user = (User)req.getAttribute("user");
        //防止中文乱码
        resp.setContentType("text/html;charset=utf-8");
        resp.getWriter().write("尊敬的"+user.getUsername()+"恭喜你登录成功!!!!!");
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }
}

test代码

public class UserDaoTest {
    @Test
    public void userDaoTest() {
        JdbcTemplate jt = new JdbcTemplate(JDBCUtils.getDaSource());
        User user = new User();
        user.setUsername("ginger");
        user.setPassword("123456");

        //定义sql语句
        String sql = "select * from User where username=? and password=?";
        User u = jt.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class),
                user.getUsername(), user.getPassword());
        System.out.println(u);
    }
}

utils代码

public class JDBCUtils {
    private static DataSource ds;
    //静态代码块用于初始化数据
    static{
        try {
            //1.加载配置文件
            Properties pro =  new Properties();
            //使用ClassLoader加载配置文件,获取字节输入流
            InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties");
            pro.load(is);
            //2.初始化连接池对象
           ds = DruidDataSourceFactory.createDataSource(pro);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static DataSource getDaSource() {
        return ds;
    }

    public  static Connection getConnection() throws SQLException {
        return ds.getConnection();
    }
}

druid.properties

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///mydatabases
username=root
password=root
initialSize=5
maxActive=10
maxWait=3000

html页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
	<!--login.html中form表单的action路径的写法-->
	<!--虚拟目录+Servlet的资源路径-->
    <form action="/login/loginServlet">
        用户名:<input type="text" placeholder="请输入用户名" name="username"><br>
        密码:<input type="password" placeholder="请输入密码" name="password"><br>
        <input type="submit" value="提交">
    </form>
</body>
</html>

代码测试
访问页面正确输入用户名和密码
JavaEE5_Request
转发到登录成功页面JavaEE5_Request

访问页面错误输入用户名和密码
JavaEE5_Request
转发到登录失败页面
JavaEE5_Request

BeanUtils工具类,简化数据封装

用于封装JavaBean的
1. JavaBean:标准的Java类
	1. 要求:
		1. 类必须被public修饰
		2. 必须提供空参的构造器
		3. 成员变量必须使用private修饰
		4. 提供公共setter和getter方法
	2. 功能:封装数据

2. 概念:
	成员变量:不是属性
	属性:setter和getter方法截取后的产物
		例如:getUsername() --> Username--> username

3. 方法:
	1. setProperty()
	2. getProperty()
	3. populate(Object obj , Map map):将map集合的键值对信息,封装到对应的JavaBean对象中

证明成员变量不是属性

public class PropertyTest {
   @Test
    public void propertyTest() throws InvocationTargetException, IllegalAccessException {
        User user = new User();
        //假设成员变量就是属性
        //根据属性设置值
        BeanUtils.setProperty(user,"age" ,18);
        System.out.println(user);//User{age=0}通过结果看出来成员变量不是属性

        //证明截取settr和gettr是属性
       //根据属性设置值
       BeanUtils.setProperty(user,"hahaha" ,20 );
       System.out.println(user);//User{age=20}通过结果看出来截取调用settr和gettr才是属性。
    }
}

User类

public class User {
    private  int age;
	//一般情况下都是setAget,下面写法想证明成员变量不是属性。
    public void setHahaha(int age){
        this.age = age;
    }
	//一般情况下都是getAget,下面写法想证明成员变量不是属性。
    public int getHahaha(){
        return age;
    }
    @Override
    public String toString() {
        return "User{" +
                "age=" + age +
                '}';
    }
}
上一篇:HttpServletRequest 获取用户真实IP地址


下一篇:HTTPServletRequest