Servlet, HTTP与JSP相关整理

Servlet

Servlet的执行过程

  • Servlet作用处理请求
  • 当浏览器访问一个http://localhost:8080/hello/hello路径, 就向Tomcat发送一个请求
浏览器访问路径全流程

Servlet的生命周期

  • Servlet生命周期分为四个状态: 实例化初始化服务销毁
  • 出生:(实例化-->初始化)第一次访问Servlet就出生(默认情况下)
  • 活着:(服务)应用活着,`Servlet就活着
  • 死亡:(销毁)应用卸载了Servlet就销毁。
/**
 * creater ruirui.ding
 *
 * @Date: 2019/8/4 11:58
 **/
public class HelloServlet implements Servlet {
    // 出生: (实例化) 第一次访问Servlet会调用构造方法
    public HelloServlet() {
        System.out.println("Hello Servlet");
    }
    // 出生: (实例化) 第一次访问会调用Servlet初始化
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        System.out.println("hello world");
    }
    // 销毁: 程序停止了才会调用
    @Override
    public void destroy() {

    }
    // 服务: 作出相应, 每次访问都会调用Service
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        servletResponse.getWriter().write("hello Servlet");
    }

    @Override
    public ServletConfig getServletConfig() {
        return null;
    }
    @Override
    public String getServletInfo() {
        return null;
    }

}

Servlet的创建时机

  • 默认情况下Servlet在第一次使用Servlet的时候才调用构造方法和初始化方法, 也就是访问到对应的页面的时候才会调用构造方法和初始化方法
  • 可以在web.xml中设置load-on-startup为2, Servlet就会在tomcat启动的时候调用构造方法和初始化方法

Servlet实现的三种方式

  • 实现java.servlet.Servlet
    Servlet
  • 继承javax.servet.GenericServlet类(适配器模式)


    适配器模式
  • 继承javax.servlet.http.HttpServlet类(模板方法设计模式)


    模板方法设计模式

Servlet的继承结构

Servlet的继承结构

Servlet映射细节

规则 意义
url-pattern: *.do 以*.字符串为结尾的请求都可以访问 注:不要加/
url-pattern: /* 任意字符串都可以访问
url-pattern /action/*/action开头的请求都可以访问

多种匹配规则同时存在, 匹配的优先级为

绝对匹配-->  /开头匹配 --> 扩展名方式匹配

ServletContext

Context:上下文
ServletContext: 代表的是整个应用。一个应用只有一个ServletContext对象。是单例对象

作用:

域对象:在一定范围内(当前应用),使多个Servlet共享数据。

常用方法

API 注解
void setAttribute(String name,object value); ServletContext对象的map中添加数据
Object getAttribute(String name); ServletContext对象的map中取数据
void rmoveAttribute(String name); 根据name去移除数据

常用方法示例

@WebServlet("/HelloServlet1")
public class HelloServlet1 extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//        super.doGet(req, resp);
        // 获取一个应用的servlet上下文
        ServletContext context = this.getServletContext();
        System.out.println("*************:" + context);
        // 往上下文存入数据
        context.setAttribute("name", ".ding");
        // 在上下文取出数据
        String name = (String)context.getAttribute("name");
        System.out.println("name::" + name);
        // 移除name
        context.removeAttribute("name");
        System.out.println("name2" + (String)context.getAttribute("name"));
    }
}

设置/读取ServletContext配置信息

先在web.xml设置ServletContext里设置全局配置

<context-param>
        <param-name>encoding</param-name>
        <param-value>utf8</param-value>
</context-param>
@WebServlet("/HelloServlet1")
public class HelloServlet1 extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
            throws ServletException, IOException {
        // 获取一个应用的servlet上下文
        ServletContext context = this.getServletContext();
        System.out.println("*************:" + context.getInitParameter("encoding")); 
    }
}

获取资源路径

String getRealPath(String path);
  • 根据资源名称得到资源的绝对路径.
  • 可以得到当前应用任何位置的任何资源。

相关代码实现

@WebServlet("/HelloServlet1")
public class HelloServlet1 extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        // 在Servlet中读取info.properties数据
        String path = this.getServletContext().getRealPath("WEB-INF/" +
                "classes/com/rui/servlet/info.properties");
        System.out.println(path);
        // 创建属性对象
        Properties pro = new Properties();
        // 加载路径下的资源
        pro.load(new FileInputStream(path));
        System.out.println(pro.getProperty("username"));

        //解决乱码
        resp.setHeader("Content-Type", "text/html;charset=utf-8");

        resp.getWriter().write(path);
        resp.getWriter().write("-----");
        resp.getWriter().write(pro.getProperty("username"));
    }
}

在IDEA下如何查看本地资源的路径

本地相对资源的路径

Servlet的转发

将来自HelloServlet1的请求转发到HelloServlet2

  • HelloServlet1的代码
@WebServlet("/HelloServlet1")
public class HelloServlet1 extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        resp.setHeader("Content-Type", "text/html;charset=utf-8");
        RequestDispatcher rd = req.getRequestDispatcher("/HelloServlet2");
        rd.forward(req, resp);
    }
}
  • HelloServlet2的代码
@WebServlet("/HelloServlet2")
public class HelloServlet2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
              throws ServletException, IOException {
        resp.getWriter().write("来自HelloServlet2");
    }
}

HTTP

简介

HTTP协议(HyperText Transfer Protocol,超文本传输协议)是用于从WWW服务器传输超文本到本地浏览器的传输协议。它可以使浏览器更加高效,使网络传输减少。它不仅保证计算机正确快速地传输超文本文档,还确定传输文档中的哪一部分,以及哪部分内容首先显示(如文本先于图形)等。

HTTP请求流程

HTTP请求流程

HTTP的常见请求头

请求头 意义
Accept 浏览器可接受的MIME类型。
Accept-Charset 浏览器可接受的字符集。
Accept-Encoding 浏览器能够进行解码的数据编码方式,比如gzipServlet能够向支持gzip的浏览器返回经gzip编码的HTML页面。许多情形下这可以减少5到10倍的下载时间。
Accept-Language 浏览器所希望的语言种类,当服务器能够提供一种以上的语言版本时要用到。
Authorization 授权信息,通常出现在对服务器发送的WWW-Authenticate头的应答中。
Connection 表示是否需要持久连接。如果Servlet看到这里的值为Keep-Alive或者看到请求使用的是HTTP 1.1HTTP 1.1默认进行持久连接),它就可以利用持久连接的优点,当页面包含多个元素时(例如Applet,图片),显著地减少下载所需要的时间。要实现这一点,Servlet需要在应答中发送一个Content-Length头,最简单的实现方法是:先把内容写入ByteArrayOutputStream,然后在正式写出内容之前计算它的大小。
Content-Length 表示请求消息正文的长度。
Cookie 这是最重要的请求头信息之一
From 请求发送者的email地址,由一些特殊的Web客户程序使用,浏览器不会用到它。
Host 初始URL中的主机和端口。
If-Modified-Since 只有当所请求的内容在指定的日期之后又经过修改才返回它,否则返回304“Not Modified”应答。
Pragma 指定“no-cache”值表示服务器必须返回一个刷新后的文档,即使它是代理服务器而且已经有了页面的本地拷贝。
Referer 包含一个URL,用户从该URL代表的页面出发访问当前请求的页面。
User-Agent 浏览器类型,如果Servlet返回的内容与浏览器类型有关则该值非常有用。

HTTP常见的响应头

Allow 服务器支持哪些请求方法(如GETPOST等)。
Content-Encoding 文档的编码(Encode)方法。只有在解码之后才可以得到Content-Type头指定的内容类型。利用gzip压缩文档能够显著地减少HTML文档的下载时间。JavaGZIPOutputStream可以很方便地进行gzip压缩,但只有Unix上的NetscapeWindows上的IE 4、IE 5才支持它。因此,Servlet应该通过查看Accept-Encoding头(即request.getHeader("Accept-Encoding"))检查浏览器是否支持gzip,为支持gzip的浏览器返回经gzip压缩的HTML页面,为其他浏览器返回普通页面。
Content-Length 表示内容长度。只有当浏览器使用持久HTTP连接时才需要这个数据。如果你想要利用持久连接的优势,可以把输出文档写入 ByteArrayOutputStream,完成后查看其大小,然后把该值放入Content-Length头,最后通过byteArrayStream.writeTo(response.getOutputStream()发送内容。
Content-Type 表示后面的文档属于什么MIME类型。Servlet默认为text/plain,但通常需要显式地指定为text/html。由于经常要设置Content-Type,因此HttpServletResponse提供了一个专用的方法setContentType
Date 当前的GMT时间。你可以用setDateHeader来设置这个头以避免转换时间格式的麻烦。
Expires 应该在什么时候认为文档已经过期,从而不再缓存它?
Last-Modified 文档的最后改动时间。客户可以通过If-Modified-Since请求头提供一个日期,该请求将被视为一个条件GET,只有改动时间迟于指定时间的文档才会返回,否则返回一个304(Not Modified)状态。Last-Modified也可用setDateHeader方法来设置。
Location 表示客户应当到哪里去提取文档。Location通常不是直接设置的,而是通过HttpServletResponse的sendRedirect方法,该方法同时设置状态代码为302
Refresh 表示浏览器应该在多少时间之后刷新文档,以秒计。除了刷新当前文档之外,你还可以通过setHeader("Refresh", "5; URL=http://host/path")让浏览器读取指定的页面。
Server服务器名字 Servlet一般不设置这个值,而是由Web服务器自己设置。
Set-Cookie 设置和页面关联的CookieServlet不应使用response.setHeader("Set-Cookie", ...),而是应使用HttpServletResponse提供的专用方法addCookie
WWW-Authenticate 客户应该在Authorization头中提供什么类型的授权信息?在包含401(Unauthorized)状态行的应答中这个头是必需的。例如,response.setHeader("WWW-Authenticate", "BASIC realm=\"executives\"")

HttpServletResponse

手动实现文件下载

@WebServlet("/HelloServlet1")
public class HelloServlet1 extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        String fileName = "六年级上册数学课件-第四单元《比》(回顾整理)|青岛版(2014秋)  " +
                "(共9张PPT).ppt";
        // 下载文件
        String path = "C:/Users/rui/Desktop/" +
                fileName;
        // 获取文件输入流
        FileInputStream fis = new FileInputStream(path);
        // 对文件名进行encode编码
        fileName = URLEncoder.encode(fileName, "UTF-8");
        // 设置文件下载请求头
        resp.setHeader("Content-disposition", "attachment;filename="
                + fileName);
        // 将文件转成二进制数据
        byte [] bs = new byte[1024];
        // 获取输出流
        ServletOutputStream sos = resp.getOutputStream();
        int len = 0;
        while ((len = fis.read(bs)) != -1) {
            sos.write(bs, 0, len);
        }
        // 关闭资源
        fis.close();
    }
}

设置客户端不需要缓存【pass】

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse response) 
            throws ServletException, IOException {
        //浏览器刷新时就不会有缓存
        response.addHeader("Pragma", "no-cache"); 
        response.setHeader("Cache-Control", "no-cache"); 
        response.setHeader("Expires", "0");
        ValidateCode code = new ValidateCode(WIDTH, HEIGHT, 4, 6);
        
        code.write(response.getOutputStream());
}

自动刷新功能

protected void doGet(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        // TODO Auto-generated method stub
        response.setContentType("text/html;charset=UTF-8");
        //response.setHeader("Refresh", "1");//每隔一秒刷新一次
        
        response.setHeader("Refresh", "5;URL=index.html");//5秒后转到另一页面
        response.getWriter().write("注册成功!5秒后会自动跳转到index.html页面");
}

请求重定向

  • 请求重定向指:一个web资源收到客户端请求后,通知客户端去访问另外一个web资源`,这称之为请求重定向
  • 重定向特点:地址栏会变,并发送2次请求,增加服务器负担
  • 实现方式
response.sendRedirect()
  • 实现原理:
    302/307状态码和location头即可实现重定向

转发特点:地址栏不会变,客户端发送一次请求

重定向实现

@WebServlet("/HelloServlet1")
public class HelloServlet1 extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        resp.sendRedirect("HelloServlet2");
    }
}
@WebServlet("/HelloServlet2")
public class HelloServlet2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        resp.getWriter().write("HelloServlet2" );
    }
}

HttpServletResponse总结

  • getOutputStreamgetWriter方法分别用于得到输出二进制数据、输出文本数据

  • getOutputStreamgetWriter这两个方法互相排斥,调用了其中的任何一个方法后,就不能再调用另一方法。 会抛异常。

  • Servlet程序向ServletOutputStreamPrintWriter对象中写入的数据将被Servlet引擎从response里面获取,Servlet引擎将这些数据当作响应消息的正文,然后再与响应状态行和各响应头组合后输出到客户端。

  • Serlvetservice方法结束后,Servlet引擎将检查getWritergetOutputStream方法返回的输出流对象是否已经调用过close方法,如果没有,Servlet引擎将调用close方法关闭该输出流对象。

HttpServletRequest

简介

HttpServletRequest对象代表客户端的请求,当客户端通过HTTP协议访问服务器时,HTTP请求头中的所有信息都封装在这个对象中,开发人员通过这个对象的方法,可以获得客户这些信息。

获得客户端信息

API 作用
getRequestURL 返回客户端发出请求时的完整URL。
getRequestURI方法 返回请求行中的资源名部分。
getQueryString 方法 返回请求行中的参数部分。
getRemoteAddr方法 返回发出请求的客户机的IP地址
getRemoteHost方法 返回发出请求的客户机的完整主机名
getRemotePort方法 返回客户机所使用的网络端口号
getLocalAddr方法 返回WEB服务器的IP地址。
getLocalName方法 返回WEB服务器的主机名
getMethod 得到客户机请求方式

获得客户端请求头

  • getHeader(name)
@WebServlet("/HelloServlet1")
public class HelloServlet1 extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        System.out.println(req.getHeader("User-Agent"));
        System.out.println(req.getHeader("Accept"));
    }
}
  • getHeaderNames()
@WebServlet("/HelloServlet1")
public class HelloServlet1 extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        Enumeration<String> e = req.getHeaderNames();
        while(e.hasMoreElements()) {
            String name = e.nextElement();
            System.out.println(name + ":" + req.getHeader(name));
        }
    }
}

OutPut

host:localhost:8080
connection:keep-alive
upgrade-insecure-requests:1
user-agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36
accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
accept-encoding:gzip, deflate, br
accept-language:zh-CN,zh;q=0.9
cookie:JSESSIONID=7BCC931187E41F2598EBE975DDC50F80

获得客户端请求参数(客户端提交的数据)

API 作用
getParameter(name) 获取一个参数的值
getParameterValues(String name) 获取一个参数对应的多个值, 返回一个数组
getParameterNames() 一次性获取所有参数的名字, 返回一个Enumeration
getParameterMap 返回一个Map<String, String[]> , 前面为参数, 后面为参数对应的值, 存在一个数组中.
getInputStream 以字节读取请求参数

HttpRequestServlet应用

@WebServlet("/HelloServlet1")
public class HelloServlet1 extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        String userName = req.getParameter("username");
        String password = req.getParameter("password");
        System.out.println(userName + ";" + password);
    }
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="/HelloServlet1">
    用户名: <input type="text" name="username"><br>
    密码: <input type="password" name="password"><br>
    <input type="submit" value="登录"></input>
</form>
</body>
</html>

实现请求转发

  • 请求转发指一个web资源收到客户端请求后,通知服务器去调用另外一个web资源进行处理。
  • request对象提供了一个getRequestDispatcher方法,该方法返回一个RequestDispatcher对象,调用这个对象的forward方法可以实现请求转发。
  • request对象同时也是一个域对象,开发人员通过request对象在实现转发时,把数据通过request对象带给其它web资源处理。
    • setAttribute方法
    • getAttribute方法
    • removeAttribute方法
    • getAttributeNames方法
@WebServlet("/HelloServlet1")
public class HelloServlet1 extends HttpServlet {

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

        req.getRequestDispatcher("/egg.jsp").forward(req,resp);
    }
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<div>hahahhahahahah</div>
</body>
</html>

那么访问HelloServlet1, 就自动转到egg.jsp

重定向机制的运作流程
1、用户在浏览器端输入特定URL,请求访问服务器端的某个组件
2、服务器端的组件返回一个状态码为302的响应结果。
3、当浏览器端接收到这种响应结果后,再立即自动请求访问另一个web组件
4、浏览器端接收到来自另一个web组件的响应结果。

HttpServeltResponse的sendRedirect(String location)用于重定向

转发和重定向的区别
  • 域对象:session,request,page。。。
  • 域:区间、范围
  • 重定向:以前的request中存放的变量全部失效,并进入一个新的request作用域。
  • 转发:以前的request中存放的变量不会失效,就像把两个页面拼到了一起。

include(), forward(), sendRedirect()的区别

  • 假定第一次请求的为servlet1,处理转发的为servlet2

  • include()方法将请求转发给servlet2servle2对该请求做出了的响应并入到原来的servlet1响应对象中,原来的servlet1还可以继续输出响应信息。

  • forward方法将请求转发给其他的servlet2servlet2负责对请求做出响应,而原先的servlet1的执行则终止。

  • sendRedict()则是在浏览器请求servlet1之后,重新告诉浏览器将请求重新定位到servlet, 会进行两次服务器请求。

JSP

1. JSP概述

  • JSP全称是Java Server Pages,它和servle技术一样,都是SUN公司定义的一种用于开发动态web资源的技术。JSP/Servlet规范。JSP实际上就是Servlet。

  • JSP这门技术的最大的特点在于,写jsp就像在写html,但它相比html而言,html只能为用户提供静态数据,而Jsp技术允许在页面中嵌套java代码,为用户提供动态数据。

  • JSP本质就是一个Servlet

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容