Servlet

Servlet

什么是Servlet

A servlet is a small Java program that runs within a Web server. Servlets receive and respond to requests from Web clients, usually across HTTP, the HyperText Transfer Protocol.

运行在服务器上的Java小程序,通过HTTP协议接收浏览器发送的请求,并且做出响应。

Servlet生命周期

Servlet创建的时机:

用户第一次访问Servlet地址的时候(),Tomcat通过**反射实例化**Servlet对象(servlet-class)(Servlet对象由Tomcat创建)。

image

Servlet的运行过程

image

Servlet的生命周期方法
方法作用运行次数
构造方法实例化Servlet的时候1次
void init(ServletConfig config)初始化方法1次
void service(ServletRequest req, ServletResponse res)服务方法每次请求都会执行
void destroy()销毁1次

Servlet一旦实例化以后就常驻内存,Web服务器关闭或重启才销毁

演示:
image

直接实现Servlet接口,并重写所有的方法

/**
 * Servlet生命周期的方法
 * @author NewBoy
 *
 */
public class Demo1HelloServlet implements Servlet {

    //实例化:构造方法
    public Demo1HelloServlet() {
        System.out.println("1. 执行了构造方法");
    }

    //初始化方法
    @Override
    public void init(ServletConfig config) throws ServletException {
        System.out.println("2. 执行了初始化的方法");
    }

    //返回一个ServletConfig对象
    @Override
    public ServletConfig getServletConfig() {
        return null;
    }

    //服务的方法:每次请求都会执行
    @Override
    public void service(ServletRequest req, ServletResponse res) throws ServletException,
            IOException {
        System.out.println("服务的方法:每次请求都会执行");
    }

    //返回与Servlet有关的一些信息
    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    public void destroy() {
        System.out.println("Servlet销毁");
    }

}
<servlet>
  <servlet-name>demo1</servlet-name>
  <servlet-class>com.itheima.servlet.Demo1HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
  <servlet-name>demo1</servlet-name>
  <!-- / 代表服务器端的根目录:   webapps\day36-servlet\  -->
  <url-pattern>/demo1</url-pattern>
</servlet-mapping>
问:在service方法中输出request和response对象,这两个对象从哪里来的?

image
在Servlet中ServletRequest和ServletResponse是2个接口,Sun没有具体的实现,具体的实现类由Web容器去实现。并且通过service()方法做为参数传递进来。


Servlet的实现类

Servlet继承结构

image

GenericServlet类

Defines a generic, protocol-independent servlet. To write an HTTP servlet for use on the Web, extend HttpServlet instead.

定义了一个通用的,独立于协议的Servlet,实现了2个接口:Servlet、ServletConfig接口,实现了这两个接口中的所有方法,子类是HttpServlet,它是一个抽象类如果我们要写自己的Servlet,建议继承于HttpServlet

HttpServlet类

A subclass of HttpServlet must override at least one method, usually one of these:
doGet, if the servlet supports HTTP GET requests
doPost, for HTTP POST requests

如果我们要写Servlet,继承于HttpServlet,至少要重写下面一个方法:doGet或doPost方法

image

service()方法的源码的简单分析:

//定义了常量
private static final String METHOD_GET = "GET";
private static final String METHOD_POST = "POST";

//HttpServletRequest 是 ServletRequest的子接口, HttpServletResponse是ServletResponse子接口

protected void service(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException {
    // 得到请求的方式
    String method = req.getMethod();
    // 如果是GET方法
    if (method.equals(METHOD_GET)) {
        long lastModified = getLastModified(req);
        //判断是否使用缓存
        if (lastModified == -1) {
            //不使用缓存,调用doGet方法
            doGet(req, resp);
        } else {
            //使用缓存
        }
    //如果是POST方法,则调用doPost()
    } else if (method.equals(METHOD_POST)) {
        doPost(req, resp);
    } else {
        //如果上面所有的方法都没有,报服务器异常(501错误)
        resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
    }
}

结论:以后我们只需要继承于HttpServlet,并且重写doGet或doPost方法。
- doGet用于处理get请求
- doPost用于处理post方法,

如果没有重写相应的方法,则会出现501的错误。

如果在地址栏上直接输入的访问地址或表单使用get方法提交,则调用doGet方法。通过表单post方式提交的,则使用doPost方法


Servlet的访问地址

通常一个Servlet只有一个访问地址,但是可以通过url-patternservlet-mapping给一个Servlet配置多个访问地址。

Servlet映射多个路径
  • 方式1:
    一个servlet-mapping中包含多个url-pattern
<servlet>
    <servlet-name>Demo2MyServlet</servlet-name>
    <servlet-class>com.itheima.servlet.Demo2MyServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>Demo2MyServlet</servlet-name>
    <url-pattern>/demo2</url-pattern>
    <!-- 映射多个url-pattern -->
    <url-pattern>/myservlet</url-pattern>
</servlet-mapping>
  • 方式2:
    一个servlet对应多个servlet-mapping
<servlet>
    <servlet-name>Demo2MyServlet</servlet-name>
    <servlet-class>com.itheima.servlet.Demo2MyServlet</servlet-class>
</servlet>
<!--   一个servlet对应多个servlet-mapping -->
<servlet-mapping>
    <servlet-name>Demo2MyServlet</servlet-name>
    <url-pattern>/demo2</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>Demo2MyServlet</servlet-name>
    <url-pattern>/mydemo</url-pattern>
</servlet-mapping>
的访问方式
配置方式格式说明
完全路径匹配/aaaa/aaa/bbb访问地址与url-pattern中精确匹配,有一个虚拟路径
目录匹配/ccc/* /*通配符访问* 匹配任意多个字符, 不建议使用这种/*,会导致其它所有的资源都无法访问
扩展名匹配*.扩展名匹配某一类扩展名

从格式上分有2种方式:
- 以/开头的方式
- 以.扩展名结尾的方法

问:能不能同时写?

image

无效的url-pattern,不支持这种写法。导致整个web项目加载失败,所有的web资源都无法访问。

面试题:

1) 创建2个Servlet,一个Servlet1,一个Servlet2,在下列情况下,访问哪个Servlet,课后自己测试证明。

请求的URLServlet1的url-patternServlet2的url-pattern响应的Servlet
/abc/a.html/abc/*/*Servlet1
/abc/abc/*/abcServlet2
/abc/a.do/abc/**.doServlet1
/a.do/**.doServlet1
/xxx/yyy/a.do/**.doServlet1

结论:
- 优先级:以/开头优先级高于*.扩展名结尾的格式
- 匹配原则:最佳匹配原则,哪个更加接近就匹配哪个


load-on-startup

作用:

正常来说,一个Servlet是在第一次用户访问的时候加载。如果我们需要在启动时加载某个Servlet,就可以使用这个配置参数

参数的使用说明:
<load-on-startup>1</load-on-startup>

参数是一个整数,数字越小越先加载必须大于等于0,如果是负数,则不起作用,与没有写这个参数是一样的。

<servlet>
  <servlet-name>demo1</servlet-name>
  <servlet-class>com.itheima.servlet.Demo1HelloServlet</servlet-class>
  <!-- 启动时加载 -->
  <load-on-startup>1</load-on-startup>
</servlet>

添加到配置文件中后,不用用户调用才实例化,服务器启动的时候就会加载,不过加载后不用会浪费资源


request接收请求参数

HttpServletRequest得到参数的方法
  • String request.getParameter(参数名)

    • 通过参数名得到参数值,返回String类型
    • 参数名是标签的name
  • String[] request.getParameterValues(参数名)

    • 通过同名参数,得到一组值,返回字符串数组。用于复选框或多选的下拉列表
    • 参数名是标签的name
  • request.setCharacterEncoding(编码)

    • 用于解决POST提交的汉字乱码问题
接收请求参数案例:

表单上有用户名,性别,城市,爱好。使用POST方法提交数据给服务器,在Servlet中使用上面三个方法得到所有的值,并且在页面上输出提交的信息,注意汉字的乱码问题。

<!DOCTYPE html>
<html>
  <head>
    <title>register.html</title>
    <meta charset="utf-8">
  </head>

  <body>
  <h3>用户注册</h3>
    <!-- action提交给servlet -->
    <form action="register" method="post">
    用户名:<input type="text" name="user"/><br/>
   性别: <input type="radio" name="gender" value="男" checked="checked">男 &nbsp;<input type="radio" name="gender" value="女"><br/>
   城市:
   <select name="city">
        <option value="广州">广州</option>
        <option value="深圳">深圳</option>
        <option value="上海">上海</option>
   </select>
   <br/>
   爱好:
   <input type="checkbox" name="hobby" value="上网" >上网 &nbsp;
   <input type="checkbox" name="hobby" value="游泳" >游泳 &nbsp;
   <input type="checkbox" name="hobby" value="旅游" >旅游 &nbsp;
   <hr/>
    <input type="submit"  value="注册">
    </form>
  </body>
</html>
/**
 * 注册用户
 * @author NewBoy
 *
 */
public class RegisterServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();
        //对于post方法,对提交的参数设置汉字编码
        request.setCharacterEncoding("utf-8");

        out.print("<h1>注册成功</h1>");
        //得到一个参数
        out.print("用户名:" + request.getParameter("user") + "<br/>");
        out.print("性别:" + request.getParameter("gender") + "<br/>");
        out.print("城市:" + request.getParameter("city") + "<br/>");
        //得到多个参数
        String[] values = request.getParameterValues("hobby");
        out.print("爱好:" + Arrays.toString(values) + "<br/>");
        out.close();
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }

}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值