Servlet和HTTP

Servlet和HTTP

Servlet的体系结构

Servlet---->GenericServlet---->HttpServlet

  1. GenericServlet:将Servlet接口中的其他方法默认空实现,只将service方法实现,通过extends个可以继承该类并复写service方法
  2. HttpServlet:继承HttpServlet方法,复写doGet和doPost方法,实质是对http协议的封装,简化操作;推荐使用这种方法

Servlet的相关配置

urlPattern:Servlet的访问路径

  1. 一个Servlet可以定义多个访问路径
  2. 路径的定义规则:
    1. /path
    2. /path1/path2
    3. *.path

HTTP

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

  2. 特点

    1. 基于TCP/IP的高级协议
    2. 基于请求--响应模型,请求和响应一一对应
    3. 无状态协议:每次请求之间相互独立
  3. 请求消息数据格式 request

    1. 请求行

      请求方式(常用两种):

      1. GET:请求参数在url后,url长度有限制,不安全
      2. POST:请求参数在请求体中,url长度没有限制

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

      get /page.html HTTP/1.1

    2. 请求头(键值对)

      Host:请求地址

      User-Agent:浏览器版本

      Accept:接受文件类型

      Referer:请求来源;用于防盗链和数据统计

      Connection:连接能否复用

      请求头名称:请求头值

    3. 请求空行

      分割行

    4. 请求体

      正文;传递请求参数

  4. request对象

    1. request和response对象的原理

      1. 流程:服务器根据请求创建对象,tomcat将request和response对象传递到service方法;在service方法中处理业务逻辑并返回;服务器从response中拿到响应消息返回给浏览器
      2. request和response对象由服务器创建
      3. request对象用来获取请求消息
      4. response对象用来设置响应消息
    2. request继承体系

      ServletRequest-->HttpServletRequest-->org.apache.catalina.connector.RequestFacade

    3. request功能

      1. 获取请求消息数据

        1. 请求行

          GET /myproject/demo?name=zhangsan HTTP/1.1

          方法:

          1. 获取请求方式:String getMethod()
          2. **获取虚拟目录:String getContextPath()**
          3. 获取Servlet路径:String getServletPath()
          4. 获取请求参数:String getQueryString()
          5. **获取请求URI:String getRequestURI();String getRequestURL()**
          6. 获取协议和版本:String getProtocol()
          7. **获取客户机IP地址:String getRemoteAddr()**
          
        2. 请求头

          获取请求头:String getHeader(String name)

          迭代器获取所有请求头:Enumeration getHeaderNames()

          获取user-agent、referer等

        3. 请求体

          在POST请求中获取请求体

          1. 获取流对象

            BufferReader getReader():只能操作字符

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

            BufferedReader bufferedReader = req.getReader();
            String line = null;
            while ((line = bufferedReader.readLine()) != null) {
                 System.out.println(line);
            }
            
          2. 在流对象中拿数据

      2. 其他功能

        1. 获取请求参数值的通用方法:

          中文可能出现乱码,Get方式不会乱码,Post可能会乱码,需要添加request.setCharacterEncoding("utf-8")

          1. 获取请求参数值:String getParameter(String name),可直接获取指定的参数
          2. 获取所有请求参数值:String[] getParameterValues(String name)
          3. 获取所有请求参数名称:Enumeration getParameterNames()
          4. 获取所有参数数据的Map集合:Map<String, String[]> getParameterMap();
        2. 请求转发

          1. 步骤:

            1. 通过request对象获取转发器对象:RequestDispatcher getRequesetDispatcher(String path)
            2. 通过RequestDispatcher对象的forward方法进行转发:forward(ServletRequest req, ServletResponse reps)
          2. 特点:

            1. 浏览器地址不变
            2. 只能转发到当前服务器内部的资源
            3. 转发只有一次请求
          3. 数据共享:

            1. 域对象:限制作用范围的对象

              request域:只在一次请求的范围

              1. setAttribute(String name, Object obj) 存储数据
              2. Object getAttribute(String name) 通过key获取value
              3. removeAttribute(String name) 通过key删除key-value
          4. 获取ServletContext

            ServletContext getServletContext()

  5. 综合案例

    1. 简单登录页面的工作流程:

      1. 创建数据库,设置好用户信息表

        create table user
        (
            id int auto_increment primary key,
            username varchar(32) not null,
            password varchar(32) not null,
            constraint username
                unique (username)
        );
        
      2. 在src下创建entity包,用于存放持久类,可通过工具一键生成getter和setter

        package com.lijie.presistence;
        
        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 + '\'' +
                        '}';
            }
        }
        
        
      3. 创建dao包,用于存放数据操作类

        package com.lijie.dao;
        import com.lijie.presistence.User;
        import org.springframework.dao.DataAccessException;
        import org.springframework.jdbc.core.BeanPropertyRowMapper;
        import org.springframework.jdbc.core.JdbcTemplate;
        import com.lijie.utils.jdbcUtil;
        public class userDao {
            private JdbcTemplate template=new JdbcTemplate(jdbcUtil.getDataSource());
            /**
             * 登录方法
             * @param user 只有用户名和密码
             * @return 返回所有信息
             */
            public User login(User user){
                try {
                    String sql="select * from user where username=? and password=?";
                    return template.queryForObject(sql,new BeanPropertyRowMapper<User>(User.class),user.getUsername(),user.getPassword());
                }catch (DataAccessException e){
                    e.printStackTrace();
                    return null;
                }
            }
        }
        
        
      4. 处理好数据库连接,可通过多种方法操作,例如JDBC、hibernate、mybatis等

      5. 编写servlet

        1. 首先需要创建一个登录界面的html文件,插入form元素,设置action和method
        2. action连接到执行用户信息匹配的servlet,按照form表单中提交的信息去数据库中查找,如果返回为空那么就说明信息不匹配,此时转发到"登录失败"的servlet;如果在数据库中却有此条数据,则连同此条数据一起转发到"登录成功"的servlet
    2. JavaBean

      1. 什么是JavaBean?

        标准的Java Class就是JavaBean:

        1. public修饰
        2. 无参构造方法
        3. 成员变量private修饰
        4. 提供public get和set方法
      2. JavaBean功能:封装数据

      3. 概念

        1. 成员变量
        2. 属性:setter和getter方法获取到的值
      4. populate()方法

        ​ BeanUtils.setProperty(entityObject, key, value)

        ​ BeanUtils.populate(entityObject, MapObject)

  6. 响应消息

    1. 数据格式:

      1. 响应行

        1. 组成:协议/版本 状态码 描述

        2. 状态码:

          1XX:客户端问询服务器是否还有数据要传送

          2XX:成功

          3XX:重定向

          4XX:客户端错误

          5XX:服务器端错误

      2. 响应头

        格式:头名称:值

        Content-Type: text/html;charset=UTF-8

        Content-Length:length

        Content-disposition: in-line 以什么格式打开响应体,默认在当前页面中打开,多用于文件下载,以attachment格式打开

      3. 响应空行

      4. 响应体

        响应字符串

    2. 功能:

      1. 设置响应行:setStatus(int status)
      2. 设置响应头:setHeader(String name, String value)
      3. 设置响应体:
        1. 获取输出流
          1. 字符流:PrintWriter gerWriter()
          2. 字节流:ServletOutputStream getOutputStream()
        2. 使用输出流
    3. 案例:

      1. 重定向:response.sendRedirect(String path)

        1. 地址栏发生变化
        2. 可以访问其他站点
        3. 两次请求,不能用response来共享数据

        路径:

        1. 绝对路径:/myproject/servlet 前面的http://locahost:port先省略

        2. 相对路径:./index.html 设置了一个参考位置,以.开头

          规则:确定访问的current page和target page的相对位置关系

          最好通过动态获取虚拟目录,来判断访问路径 request.getContextPath()

      2. 输出字符数据到浏览器:

        1. 在获取流对象之前设置流的默认编码,设置为对应的字符集编码:response.setCharacterEncoding("UTF-8")

        2. 告诉浏览器响应消息所设置的编码:response.setContentType("text/html;charset=utf-8")

        3. PrintWriter printWriter=resp.getWriter();
          printWriter.write("<h1>Hello World!你好</h1>");
          
      3. 输出字节数据到浏览器:

        1. response.setContentType("text/html;charset=utf-8")
        2. ServletOutputStream servletOutputStream = response.getOutputStream();
        3. srevletOutputStram.write("HelloWorld".getBytes("utf-8"))
      4. 验证码案例:

    4. ServletContext对象

      1. 概念:代表整个web应用,可以和程序的容器(服务器)通信
      2. 如何获取:request.getServletContext(); this.getServletContext()
      3. 功能
        1. 获取MIME类型:String getMimeType(String file)

        2. 域对象:共享数据

          1. setAttribute(String name, Object value)
          2. getAttribute(String name)
          3. remobeAttribute(String name)

          作用范围,所有用户请求的数据

        3. 获取文件的服务器路径

    5. 案例:文件下载

      1. 页面显示超链接,点击提示下载框,完成文件下载

      2. content-disposition:attachment;filename=FILENAME

      3. 步骤

        1. 新建imgDownload页面,插入a标签,href通过servlet传递下载文件的filename
        2. 新建servlet,通过request.getParameter得到文件的filename
        3. 通过servletContext.getRealPath()得到文件的真实路径
        4. 新建输入流FileInputStream参数为3得到的realpath
        5. 得到servletContext的mimeType
        6. 设置responseHeader的content-type
        7. 设置responseHeader的content-disposition为attachment
        8. 新建servletOutputSteam通过write方法写文件,可以采用buffer
        9. 完成后需要关闭文件输入流,fileinputStream.close
      4. String filename=req.getParameter("filename");
        ServletContext servletContext = this.getServletContext();
        String realPath = servletContext.getRealPath("/img/" + filename);
        FileInputStream fileInputStream = new FileInputStream(realPath);
        String mimeType = servletContext.getMimeType(filename);
        resp.setHeader("content-type",mimeType);
        resp.setHeader("content-disposition","attachment;filename="+filename);
        ServletOutputStream outputStream = resp.getOutputStream();
        byte[] buff=new byte[1024*8];
        int len=0;
        while ((len=fileInputStream.read(buff))!=-1){
            outputStream.write(buff,0,len);
        }
        fileInputStream.close();
        
      5. 中文文件名如何处理?

        对于不同的user-agent分别处理,对于文件名采用不同的处理方式

posted @ 2020-04-07 13:57  codesucks  阅读(274)  评论(0)    收藏  举报