JavaWeb - Servlet详解、HTTP协议、Request

1.Servlet的体系结构

  Servlet - - 接口

     |

  GenericServlet - - 抽象类

       |

    HttpServlet - - 抽象类

  * GenericServlet:将Servlet接口中其他的方法做了默认空实现,只将service()方法做了抽象

    *将来定义Servlet类时,可以继承GenericServlet,实现service()方法即可

  * HttpServlet:对http协议的一种封装,简化操作

    1. 定义类继承HttpServlet

    2. 复写doGet/doPost方法

 

2.Servlet相关配置

  1.urlpattern:Servlet访问路径

    1. 一个Servlet可以定义多个访问路径:@WebServlet({"/demo1","/d1","ddd1"})

    2. 路径定义规则:

      1. /xxx

      2. /xxx/xxx:多层路径

      3. *.do

 

3.HTTP

  * 概念:Hyper Text Transfer Protocol 超文本传输协议

    * 传输协议:定义了客户端和服务器端通信时,发送数据的格式

    * 特点:

      1. 基于TCP/IP的高级协议

      2. 默认端口:80

      3. 基于请求响应模型的:一次请求对应一次响应

      4. 无状态的:每次请求之间相互独立,不能交互数据

    * 历史版本:

      * 1.0:每一次请求响应都会建立新的连接

      * 1.1:复用连接

  * 请求消息数据格式

    1.请求行

      请求方式 请求url 请求协议/版本

      GET /login.html HTTP/1.1

      * 请求方式:

        * HTTP协议有7中请求方式,常用的有2种

          * GET:

            1. 请求参数在请求行中,在url后

            2. 请求的url长度是有限制的

            3. 不太安全

          * POST

            1. 请求参数在请求体中

            2. 请求的url长度没有限制

            3. 相对安全

    2.请求头:客户端浏览器告诉服务器一些信息

      请求头名称:请求头值

      * 常见的请求头:

        1. User - Agent:浏览器告诉服务器,我访问你使用的浏览器版本信息

          * 可以在服务器端获取该头的信息,解决浏览器兼容性问题

        2. Referer:告诉服务器,我(当前请求)从哪里来?

          *作用:

            1. 防盗链

            2. 统计工作

    3.请求空行

      空行,用与分割POST请求的请求头和请求体的

    4.请求体(正文):封装POST请求消息的请求参数的 (GET请求没有)

    * 字符串格式:

    

 

  * 响应消息数据格式

 

4.Request

  1. request对象和response对象的原理

    1. request和response是由服务器创建的。我们来使用它们

    2. request对象是来获取请求消息,response对象是来设置响应消息

 

 

 

  2. request对象继承体系结构:

    ServletRequest  - - 接口

       |    继承

    HttpServletRequest  - - 接口

       |    实现

    org.apache.catalina.connector.RequestFacade 类(tomcat)

  3. request功能:

    1. 获取请求消息数据

      1. 获取请求行数据

        * GET /Web_servlet/demo02?name=zhangsan HTTP/1.1

        * 方法:

          1. 获取请求方式:GET

            * String getMethod()

          2. (*)获取虚拟目录:/Web_servlet

            * String getContextPath()

          3. 获取Servlet路径:/demo02

            * String getServletPath()

          4. 获取get方式的请求参数:name=zhangsan

            * String getQueryString()

          5. (*)获取请求的URI:/Web_servlet/demo02

            * String getRequestURI():/Web_servlet/demo02

            * StringBuffer getRequestURL(): http://localhost/Web_servlet/demo02

            * URI:统一资源标识符 : /Web_servlet/demo02  如:共和国

            * URL:统一资源定位符 :http://localhost/Web_servlet/demo02 如:中华人民共和国

          6. 获取协议及版本:HTTP/1.1

            * String getProtocol()

          7. 获取客户机的IP地址:

            * String getRemoteAddr()

      2. 获取请求头数据

        * String getHeader(String name):通过请求头的名称来获取请求头的值

 

        String referer = request.getHeader("referer");
        if(referer!=null){
            if(referer.contains("youku")){
                response.setContentType("text/html;charset=utf-8");
                response.getWriter().write("正在播放优酷高清电影");
            }else{
                response.setContentType("text/html;charset=utf-8");
                response.getWriter().write("想看高清电影来优酷吧");
            }
        }    

 

 

 

        * Enumeration<String> getHeaderNames(String name):获取所有的请求头名称

      3. 获取请求体数据

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

        * 步骤:

          1. 获取流对象

            * BufferedReader getReader():获取字符输入流,只能操作字符数据

 

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        BufferedReader br = request.getReader();
        String line;
        while ((line = br.readLine())!=null){
            System.out.println(line);
        }
    }    

 

 

 

            * ServletInputStream getInputStream():获取字节输入流,可以操作所有类型的数据

              *在文件上传知识点中讲解

          2. 再从流对象中拿数据

    2. 其他功能

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

        1. String getParameter(String name):根据参数名称来获取参数值   username=zhangsan&password=123

        2. String【】 getParameterValues(String name):根据参数名称获取参数值的数组   hobby=study&hobby=game  多用于复选框

        3. Enumeration<String> getParameterNames():获取所有请求的参数名称

        4. Map<String,Sring[ ]> getParameterMap():获取所有参数的map集合

 

package web.request;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Map;
import java.util.Set;

@WebServlet("/RequestDemo02")
public class RequestDemo02 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //post获取请求参数

        //根据请求参数的名称获取值
        String username_value = request.getParameter("username");
        System.out.println("post方法.....");
        System.out.println(username_value);

        //获取所有参数的名称
        Enumeration<String> parameterNames = request.getParameterNames();
        while (parameterNames.hasMoreElements()){
            String name = parameterNames.nextElement();
            System.out.println(name);
            String name_value = request.getParameter(name);
            System.out.println(name_value);
            System.out.println("--------");
        }

        //获取所有参数的map集合
        Map<String, String[]> parameterMap = request.getParameterMap();
        Set<String> keySet = parameterMap.keySet();
        for (String name : keySet) {
            System.out.println(name);
            //根据key键获取值
            String[] values = parameterMap.get(name);
            for (String value : values) {
                System.out.println(value);
            }
            System.out.println("=========================");
        }
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //get获取请求参数
        this.doPost(request,response);
    }
}
获取示范

         * 中文乱码问题:

          * get方式:tomcat 8 已经将get方式乱码问题解决了

          * post方式:会乱码

            解决:在获取参数前,设置请求参数的编码 request.setCharacterEncoding("utf-8");

 

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

        1. 步骤

          1. 通过request对象获取请求转发器对象:RequestDispatcher getRequestDispatcher(String path)

          2. 使用RequestDispatcher对象来进行转发: forward(ServletRequest request,ServletRespnse response)

        2.特点:(面试题)

          1. 浏览器地址栏路径没有发生变化

          2. 只能转发到当前的服务器内部资源中

          3. 转发是一次请求,即使跳转多个资源,使用的是同一次请求

      3. 共享数据

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

        * request域:代表一次请求的范围,一般用于请求转发的多个资源中共享数据

        * 方法:

          1. void setAttribute(String name,Object obj):存储数据

          2. Object getAttribute(String name):通过键获取值

          3. void removeAttribute(String name):通过键移除键值对

      4. 获取ServletContext

        * ServletContext getServletContext()

 

##案例:用户登录

  需求:

    1.编写login.html登录页面       username & password 两个输入框
       2.使用Druid数据库连接池技术,操作mysql,day14数据库中user表
       3.使用JdbcTemplate技术封装JDBC
       4.登录成功跳转到SuccessServlet展示:登录成功!用户名,欢迎您
       5.登录失败跳转到FailServlet展示:登录失败,用户名或密码错误

 

   * 开发步骤

    1. 创建项目,写好login.html页面,导入配置文件,jar包

    2. 创建数据库环境

CREATE DATABASE case_login;
USE case_login;
CREATE TABLE USER(
    id INT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(32) UNIQUE NOT NULL,
    PASSWORD VARCHAR(32) NOT NULL
);

 

    3. 在src目录下创建domain包,创建User类(实体类)

package domain;

/*
* 用户的实体类
* */
public class User {
    private int id;
    private String username;
    private String password;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    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{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}
User类

 

    4. 在src目录下创建dao包(用于操作数据库),创建UserDao类,提供login的方法 

    5. 编写checkServlet类 

    6. login.html中form表单的action的写法: 虚拟目录+资源路径

    7. BeanUtils工具类,简化数据封装

      * 用于封装JavaBean

      1. JavaBean:标准的Java类

        1.要求:

          1. 类必须被public修饰

          2. 必须提供空参的构造器

          3. 成员变量必须使用private修饰

          4. 提供公共setter和getter方法

        2.功能:封装数据

      

      2. 概念:

        成员变量:

        属性:setter和getter方法截取后的产物,既其方法名

          例如:getUsername() - - > Username - - > username

      3. 方法:

        1. setProperty():操作的是其属性,既方法setHehe中的Hehe,Hehe可以指向成员变量

        2. getProperty()

        3. populate(Object,map):将map集合的键值对信息,封装到对应的JavaBean对象中

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>login</title>
</head>
<body>
<form action="/case_login/checkServlet" method="post">
    <input type="text" name="username" placeholder="请输入用户名">
    <input type="password" name="password" placeholder="请输入密码">
    <input type="submit" value="登录">
</form>
</body>
</html>
login页面

 

CREATE DATABASE case_login;
USE case_login;
CREATE TABLE USER(
    id INT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(32) UNIQUE NOT NULL,
    PASSWORD VARCHAR(32) NOT NULL
);
数据库建立操作

 

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/case_login
username=root
password=woaini1314
initialSize=5
maxActive=10
maxWait=3000
druid数据库连接池配置

 

package domain;

/*
* 用户的实体类
* */
public class User {
    private int id;
    private String username;
    private String password;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    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{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}
domain包下的JavaBean对象user

 

package util;

/*
*JDBC工具类 使用Druid连接池
* */

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

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 getDataSource(){
        return ds;
    }

    /*
    * 获取连接Connection对象
    * */
    public static Connection getConnection() throws SQLException {
        return ds.getConnection();
    }
}
util包下JDBC工具类JDBCUtils

 

package dao;

import domain.User;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import util.JDBCUtils;

/*
* 操作数据库中user表的类
* */
public class UserDao {
    //声明JDBCTemplate对象共用
    private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
    /**
     * 登录方法
     * @param loginUser 只有用户名和密码
     * @return user 包含用户全部数据,没有查询到则返回null
     */
    public User login(User loginUser){
        try {
            //loginUser是网页上登录传过来的user对象,返回的user对象是数据库中含有全部信息的user对象

            //1. 编写sql
            String sql = "select * from user where username = ? and password = ?";

            //2. 调用query方法
            User user = template.queryForObject(sql,
                    new BeanPropertyRowMapper<User>(User.class),
                    loginUser.getUsername(), loginUser.getPassword());

            return user;
        } catch (DataAccessException e) {
            e.printStackTrace();
            return null;
        }
    }

}
dao包下用于操作数据库的UserDao类

 

package test;

import dao.UserDao;
import domain.User;
import org.junit.Test;

public class UserDaoTest {
    @Test
    public void testLogin(){
        User loginuser = new User();
        loginuser.setUsername("chris");
        loginuser.setPassword("woaini1314");
        UserDao dao = new UserDao();
        User user = dao.login(loginuser);
        System.out.println(user);
    }
}
test包下用于测试的UserDaoTest类

 

package web.servlet;

import dao.UserDao;
import domain.User;
import org.apache.commons.beanutils.BeanUtils;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;

@WebServlet("/checkServlet")
public class checkServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.设置编码
        request.setCharacterEncoding("utf-8");
        //2.获取请求参数
        //String username = request.getParameter("username");
        //String password = request.getParameter("password");

        //3.封装user对象
        //User login_user = new User();
        //login_user.setUsername(username);
        //login_user.setPassword(password);

        // Bean高级方法
        //2.获取所有请求参数
        Map<String, String[]> map = request.getParameterMap();
        //3.1创建User对象
        User login_user = new User();
        //3.2使用apache包下的BeanUtils封装
        try {
            BeanUtils.populate(login_user,map);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

        //4.调用UserDao的login方法
        UserDao dao = new UserDao();
        User user = dao.login(login_user);//此处的user是从数据库返回的user

        //5.判断user
        if(user==null){
            //登录失败
            request.getRequestDispatcher("/failServlet").forward(request,response);
        }else {
            //登录成功
            //存储数据
            request.setAttribute("user",user);

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


    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request,response);
    }
}
Servlet包下的checkServlet主检验逻辑类

 

package web.servlet;

import domain.User;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/successServlet")
public class successServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取request域中共享的user对象
        User user = (User) request.getAttribute("user");
        //给页面写一句话
        if(user!=null){
            //设置编码
            response.setContentType("text/html;charset=utf-8");

            //输出
            response.getWriter().write("登录成功!"+user.getUsername()+"欢迎您");
        }

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request,response);
    }
}
Servlet包下登录成功的successServlet

 

package web.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/failServlet")
public class failServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //给页面写一句话

        //设置编码
        response.setContentType("text/html;charset=utf-8");

        //输出
        response.getWriter().write("用户名密码错误,登录失败");
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request,response);
    }
}
Servlet包下登录失败的failServlet

 

posted @ 2020-07-16 09:37  五号世界  阅读(303)  评论(0编辑  收藏  举报