02 http,servlet,servletconfig,HttpServletRequest ,HttpServletResponse

Http协议

协议:双方在交互、通讯的时候, 遵守的一种规范、规则。
http协议:针对网络上的客户端 与 服务器端在执行http请求的时候,遵守的一种规范。 其实就是规定了客户端在访问服务器端的时候,要带上哪些东西, 服务器端返回数据的时候,也要带上什么东西。
版本:
    1.0请求数据,服务器返回后, 将会断开连接
    1.1请求数据,服务器返回后, 连接还会保持着。 除非服务器 | 客户端 关掉。 有一定的时间限制,如果都空着这个连接,那么后面会自己断掉。
   
Http请求数据解释

请求的数据里面包含三个部分内容 :请求行 、 请求头 、请求体

*请求行
        POST /examples/servlets/servlet/RequestParamExample HTTP/1.1


        POST : 请求方式 ,以post去提交数据
        /examples/servlets/servlet/RequestParamExample
        请求的地址路径 , 就是要访问哪个地方。
        HTTP/1.1 协议版本
* 请求头
        Accept: application/x-ms-application, image/jpeg, application/xaml+xml,
image/gif, image/pjpeg, application/x-ms-xbap, */*
        Referer: http://localhost:8080/examples/servlets/servlet/RequestParamExample
        Accept-Language: zh-CN
        User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)
        Content-Type: application/x-www-form-urlencoded
        Accept-Encoding: gzip, deflate
        Host: localhost:8080
        Content-Length: 31
        Connection: Keep-Alive
        Cache-Control: no-cache

        Accept: 客户端向服务器端表示,我能支持什么类型的数据。
        Referer : 真正请求的地址路径,全路径
        Accept-Language: 支持语言格式
        User-Agent: 用户代理 向服务器表明,当前来访的客户端信息。
        Content-Type: 提交的数据类型。经过urlencoding编码的form表单的数据
        Accept-Encoding: gzip, deflate : 压缩算法 。
        Host : 主机地址
        Content-Length: 数据长度
        Connection : Keep-Alive 保持连接
        Cache-Control : 对缓存的操作

* 请求体
浏览器真正发送给服务器的数据
        发送的数据呈现的是key=value ,如果存在多个数据,那么使用&
        firstname=zhang&lastname=sansan

Http响应数据解析
请求的数据里面包含三个部分内容 : 响应行 、 响应头 、响应体

    HTTP/1.1 200 OK
    Server: Apache-Coyote/1.1
    Content-Type: text/html;charset=ISO-8859-1
    Content-Length: 673
    Date: Fri, 17 Feb 2010 02:53:02 GMT

    ...

* 响应行
    
        HTTP/1.1 200 OK
        协议版本  
        状态码
            200 : 成功,正常处理,得到数据。
            403  : for bidden  拒绝
            404 : Not Found
            500 : 服务器异常
        OK
            对应前面的状态码  

* 响应头
        Server:  服务器是哪一种类型。  Tomcat
        Content-Type : 服务器返回给客户端你的内容类型
        Content-Length : 返回的数据长度
        Date : 通讯的日期,响应的时间    

Get 和  Post请求区别
* post
1. 数据是以流的方式写过去,不会在地址栏上面显示。  现在一般提交数据到服务器使用的都是POST
2. 以流的方式写数据,所以数据没有大小限制。一定需要一个Content-Lenght的头说明数据的长度有多少
* get
1. 会在地址栏后面拼接数据,所以有安全隐患。 一般从服务器获取数据,并且客户端也不用提交上面数据的时候,可以使用GET
2. 能够带的数据有限, 1kb大小    

Web资源
在http协议当中,规定了请求和响应双方, 客户端和服务器端。与web相关的资源。 有两种分类

* 静态资源
    html 、 js、 css
* 动态资源
    servlet/jsp

servlet:
其实就是一个java程序,运行在我们的web服务器上,用于接收和响应 客户端的http请求。
更多的是配合动态资源来做。 当然静态资源也需要使用到servlet,只不过是Tomcat里面已经定义好了一个 DefaultServlet


Hello Servlet

得写一个Web工程 , 要有一个服务器。
测试运行Web工程

1. 新建一个类, 实现Servlet接口
2. 配置Servlet , 用意: 告诉服务器,我们的应用有这么些个servlet。
    在webContent/WEB-INF/web.xml里面写上以下内容。

  <!-- 向tomcat报告, 我这个应用里面有这个servlet, 名字叫做HelloServlet , 具体的路径是

com.itheima.servlet.HelloServlet -->
  <servlet>
    <servlet-name>HelloServlet</servlet-name>
    <servlet-class>com.itheima.servlet.HelloServlet</servlet-class>
  </servlet>

  <!-- 注册servlet的映射。  servletName : 找到上面注册的具体servlet,  url-pattern: 在地址

栏上的path 一定要以/打头 -->
  <servlet-mapping>
    <servlet-name>HelloServlet</servlet-name>
    <url-pattern>/a</url-pattern>
  </servlet-mapping>

3. 在地址栏上输入 http://localhost:8080/项目名称/a


Servlet的通用写法
  

 Servlet (接口)
        |
        |
    GenericServlet
        |
        |
    HttpServlet (用于处理http的请求)
定义一个类,继承HttpServlet 复写doGet 和 doPost
public class HelloHttpServer extends HttpServlet{
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws

ServletException, IOException {
        // TODO Auto-generated method stub
        super.doGet(req, resp);
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws

ServletException, IOException {
        // TODO Auto-generated method stub
        super.doPost(req, resp);
    }

}


Servlet的生命周期:
生命周期:从创建到销毁的一段时间
生命周期方法:
从创建到销毁,所调用的那些方法。
init方法
在创建该servlet的实例时,就执行该方法。
一个servlet只会初始化一次, init方法只会执行一次
默认情况下是 : 初次访问该servlet,才会创建实例。
service方法
只要客户端来了一个请求,那么就执行这个方法了。
 该方法可以被执行很多次。 一次请求,对应一次service方法的调用
destroy方法
  servlet销毁的时候,就会执行该方法
    1. 该项目从tomcat的里面移除。
    2. 正常关闭tomcat就会执行 shutdown.bat

让Servlet创建实例提前:
默认情况下,只有在初次访问servlet的时候,才会执行init方法。 有的时候,我们可能需要在这个方法里面执行一些初始化工作,甚至是做一些比较耗时的逻辑。
在配置的时候, 使用load-on-startup元素来指定, 给定的数字越小,启动的时机就越早。 一般不写负数, 从2开始即可。

<servlet>
    <servlet-name>HelloServlet</servlet-name>
    <servlet-class>com.fly.servlet.HelloServlet</servlet-class>
    <load-on-startup>2</load-on-startup>
  </servlet>


ServletConfig:
Servlet的配置,通过这个对象,可以获取servlet在配置的时候一些信息

<servlet>
      <servlet-name>ServletConfigName</servlet-name>
      <servlet-class>com.fly.servlet.HelloServletConfig</servlet-class>
      <init-param>
           <param-name>name</param-name>
          <param-value>fly</param-value>
      </init-param>
  </servlet>
public class HelloServletConfig extends HttpServlet{
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws

ServletException, IOException {
        ServletConfig config = getServletConfig(); //得到servlet配置对象 专门用于在配置servlet的信息
        String servletName = config.getServletName(); ////获取到的是配置servlet里面servlet-name 的文本内容
        System.out.println("servletName:"+servletName);
        
        String name = config.getInitParameter("name"); // 可以获取具体的某一个参数
        System.out.println("name:"+name);
        
        Enumeration<String> names = config.getInitParameterNames(); // 可以获取具体的某一个参数
        while (names.hasMoreElements()) {  //遍历取出所有的参数名称
            String key = (String) names.nextElement();
            String value = config.getInitParameter(key);
            System.out.println("key:"+key+"value:"+value);
        }
    /*    servletName:ServletConfigName
        name:fly
        key:namevalue:fly*/

    }
    
}


为什么需要有这个ServletConfig
servlet 里面需要一个数字或者叫做变量值。 但是这个值不能是固定了。 所以要求使用到这个servlet的公司,在注册servlet的时候,必须要在web.xml里面,声明init-params


===========================================================================
HttpServletRequest 和 HttpServletResponse
Servlet配置方式
1.全路径匹配:
以 / 开始 /a /aa/bb
localhost:8080/项目名称/aa/bb
2.路径匹配 , 前半段匹配:
以 / 开始 , 但是以 * 结束 /a/* /*
其实是一个通配符,匹配任意文字
localhost:8080/项目名称/aa/bb
3.以扩展名匹配:
写法: 没有/ 以 * 开始 *.扩展名 *.aa *.bb

ServletContext:
Servlet 上下文每个web工程都只有一个ServletContext对象。

如何得到对象
    ServletContext context = getServletContext();
作用:
1获取全局配置参数
2获取web工程中的资源
3存取数据,servlet间共享数据 域对象

全局配置参数:
  <!-- 用于配置全局的参数 -->
  <context-param>
  <param-name>name</param-name>
  <param-value>fly</param-value>
  </context-param>
获取全局参数:
ServletContext servletContext = getServletContext();
String name = servletContext.getInitParameter("name");
System.out.println("context-name:"+name);

获取Web应用中的资源:
1. 获取资源在tomcat里面的绝对路径
   

    //获取ServletContent对象
        ServletContext context = getServletContext();
        //获取给定文件在服务器上的绝对路径(文件放在项目结构的WebContent)
        String realPath = context.getRealPath("file/config.properties");
        
        Properties properties = new Properties();
        FileInputStream inputStream = new FileInputStream(realPath);
        properties.load(inputStream);
        String name = properties.getProperty("name");
        System.out.println("name:"+name);
        inputStream.close();


2. getResourceAsStream 获取资源 流对象
 

直接给相对的路径,然后获取流对象。
        ServletContext context = getServletContext();
        
        Properties properties = new Properties();
        //获取web工程下的资源,转化为流对象
        InputStream is = context.getResourceAsStream("file/config.properties");
        properties.load(is);
        String name = properties.getProperty("name");
        System.out.println("name:"+name);
        is.close();


通过classloader去获取web工程下的资源:

//ClassLoader   wtpwebappsxxWEB-INFclassses
//要回到         wtpwebappsxx
InputStream is = this.getClass().getClassLoader().getResourceAsStream("../../file/config.properties");


使用ServletContext存取数据:

//获取表单数据
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        //向客户端输出内容
        PrintWriter writer = response.getWriter();
        if ("abc".equals(username)&&"123".equals(password)) {
            System.out.println("登录成功");
            
            Object object = getServletContext().getAttribute("count");
            int count = 0;
            if (object!=null) {
                count = (int) object;
            }
            getServletContext().setAttribute("count", count+1);
            
//            writer.println("login success");
//            writer.write("login success");
            response.setStatus(HttpServletResponse.SC_FOUND); //302重定向
            response.setHeader("Location", "home.html");
        }else {
            writer.println("login failed");
        }

=====================

    // 取值
        int count = (int) getServletContext().getAttribute("count");
        // 输出到界面
        response.getWriter().write("当前访问次数:第"+count+"次访问");

细节;
 <form action="login" method="get">   相对路径


ServletContext 何时创建, 何时销毁?
服务器启动的时候,会为托管的每一个web应用程序,创建一个ServletContext对象
从服务器移除托管,或者是关闭服务器。
ServletContext 的作用范围:同一个项目。

HttpServletRequest:
这个对象封装了客户端提交过来的一切数据。

1. 可以获取客户端请求头信息

        //得到一个枚举集合  
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String name = (String) headerNames.nextElement();
            String value = request.getHeader(name);
            System.out.println(name+"="+value);
            
        }


2. 获取客户端提交过来的数据

        String name = request.getParameter("name");
        String address = request.getParameter("address");
        System.out.println("name="+name);
        System.out.println("address="+address);


        //name=zhangsan&name=lisi&name=wangwu 一个key可以对应多个值。

        Map<String, String[]> map = request.getParameterMap();
        
        Set<String> keySet = map.keySet();
        Iterator<String> iterator = keySet.iterator();
        while (iterator.hasNext()) {
            String key = (String) iterator.next();
            System.out.println("key="+key + "--的值总数有:"+map.get

(key).length);
            String value = map.get(key)[0];
            String value1 = map.get(key)[1];
            String value2 = map.get(key)[2];
            
            System.out.println(key+" ======= "+ value + "=" + value1 + "="+

value2);
        }


3. 获取中文数据

 客户端提交数据给服务器端,如果数据中带有中文的话,有可能会出现乱码情况,那么可以参照以下方法解决。

* 如果是GET方式
    
    1. 代码转码
            String username = request.getParameter("username");
            String password = request.getParameter("password");
            
            System.out.println("userName="+username+"==password="+password);
            
            //get请求过来的数据,在url地址栏上就已经经过编码了,所以我们取到的就是乱码,
            //tomcat收到了这批数据,getParameter 默认使用ISO-8859-1去解码
            
            //先让文字回到ISO-8859-1对应的字节数组 , 然后再按utf-8组拼字符串
            username = new String(username.getBytes("ISO-8859-1") , "UTF-8");
            System.out.println("userName="+username+"==password="+password);
   直接在tomcat里面做配置,以后get请求过来的数据永远都是用UTF-8编码。
    

    2. 可以在tomcat里面做设置处理 conf/server.xml 加上URIEncoding="utf-8"
 
          <Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1"

redirectPort="8443" URIEncoding="UTF-8"/>

* 如果是POST方式

        //设置请求体里面的文字编码。  get方式,用这行,没用
        request.setCharacterEncoding("UTF-8");
    
        //这行设置一定要写在getParameter之前。


HttpServletResponse:

 负责返回数据给客户端。

输出数据到页面上

    //以字符流的方式写数据    
        //response.getWriter().write("<h1>hello response...</h1>");
        //以字节流的方式写数据
        response.getOutputStream().write("hello response".getBytes());


响应的数据编码问题:

String string = Charset.defaultCharset().name(); string类的getByte()方法使用的码表
// 以字符流输出

 //response.getWriter()
        //1. 指定输出到客户端的时候,这些文字使用UTF-8编码
        response.setCharacterEncoding("UTF-8");
 
        //2. 直接规定浏览器看这份数据的时候,使用什么编码来看。
        response.setHeader("Content-Type", "text/html; charset=UTF-8");
        
        response.getWriter().write("你好...");

//以字节流输出

//response.getOutputStream()

        
        //1. 指定浏览器看这份数据使用的码表
        response.setHeader("Content-Type", "text/html;charset=UTF-8");
        
        //2. 指定输出的中文用的码表
        response.getOutputStream().write("你好..".getBytes("UTF-8"));

//不分情况,一行搞定
response.setContentType("text/html;charset=UTF-8");


下载资源:
1.直接以超链接的方式下载,不写任何代码。 也能够下载东西下来。

    让tomcat的默认servlet去提供下载:
    <a href="download/a.rar">cc.rar</a><br>

 原因是tomcat里面有一个默认的Servlet -- DefaultServlet 。这个DefaultServlet 专门用于处理放在tomcat服务器上的静态资源。

2.

// <a href="DownLoad?download=cc.rar">c.rar</a>
        //获取要现在的文件的名字
        String fileName = request.getParameter("download");
        //获取文件在tomcat的绝对路径
        String path = getServletContext().getRealPath("download/"+fileName);
        //以下载的方式提醒用户,而不是直接展示
        response.setHeader("Content-Disposition", "attachment;filename="+fileName);
        //转化成输出流
        InputStream is = new FileInputStream(path);
        OutputStream os = response.getOutputStream();
        
        int len = 0;
        byte[] b = new byte[1024];
        while((len=is.read(b))!=-1) {
            os.write(b, 0, len);
        }
        os.close();
        is.close();

 中文文件下载
  针对浏览器类型,对文件名字做编码处理 Firefox (Base64) , IE、Chrome ... 使用的是URLEncoder
     

  public static String base64EncodeFileName(String fileName) {
            BASE64Encoder base64Encoder = new BASE64Encoder();
            try {
                return "=?UTF-8?B?"
                        + new String(base64Encoder.encode(fileName
                                .getBytes("UTF-8"))) + "?=";
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            }
        }
       /*
         * 如果文件的名字带有中文,那么需要对这个文件名进行编码处理
         * 如果是IE ,或者  Chrome (谷歌浏览器) ,使用URLEncoding 编码
         * 如果是Firefox , 使用Base64编码
         */
        //获取来访的客户端类型
        String clientType = request.getHeader("User-Agent");
        
        if(clientType.contains("Firefox")){  //包含Firefox
            fileName = DownLoadUtil.base64EncodeFileName(fileName);
        }else{
            //IE ,或者  Chrome (谷歌浏览器) ,
            //对中文的名字进行编码处理
            fileName = URLEncoder.encode(fileName,"UTF-8");
        }

完整:
       

// <a href="DownLoad?download=cc.rar">c.rar</a>
        //获取要现在的文件的名字
        String fileName = request.getParameter("download");
        //防止有中文
        fileName = new String(fileName.getBytes("ISO-8859-1"),"UTF-8");
        
        //获取文件在tomcat的绝对路径
        String path = getServletContext().getRealPath("download/"+fileName);
        /*
         * 如果文件的名字带有中文,那么需要对这个文件名进行编码处理
         * 如果是IE ,或者  Chrome (谷歌浏览器) ,使用URLEncoding 编码
         * 如果是Firefox , 使用Base64编码
         */
        //获取来访的客户端类型
        String clientType = request.getHeader("User-Agent");//包含Firefox
        if (clientType.contains("Firefox")) {
            fileName = DownLoadUtil.base64EncodeFileName(fileName);
        }else {
            //对中文的名字进行编码处理
            fileName = URLEncoder.encode(fileName,"UTF-8");
        }
        //以下载的方式提醒用户,而不是直接展示
        response.setHeader("Content-Disposition", "attachment;filename="+fileName);
        //转化成输出流
        InputStream is = new FileInputStream(path);
        OutputStream os = response.getOutputStream();
        
        int len = 0;
        byte[] b = new byte[1024];
        while((len=is.read(b))!=-1) {
            os.write(b, 0, len);
        }
        os.close();
        is.close();
View Code
原文地址:https://www.cnblogs.com/fly-book/p/9911293.html