Servlet

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Servlet相关的知识,希望对你有一定的参考价值。

 

1.Servlet的概述

1.1 认识Servlet

技术分享

在Servlet出现之前服务器处理请求的流程是如下图所示的,这样的访问存在着很多的不足之处:

技术分享

技术分享

技术分享

技术分享

Servlet是基于对CGI的改善;

技术分享

  Servletsun公司提供的一种用于开发动态web资源的技术,为了方便web服务器对动态web资源(所谓动态web资源就是可以运行在服务器上的java程序)的管理,sun公司在其api中定义了一个Servlet接口,服务器针对接口进行调用,我们编写的应用程序针对接口进行实现,习惯性地,我们把实现了Servlet接口的java类统称为Servlet

 

  开发人员写好一个java,到底有哪些方法tomcat服务器是不可能知道的,tomcat服务器需要执行我们编写的java类就需要知道我们的java类有哪些方法,然后在适当的时间调用这些方法, 所以我们在写的java程序要想运行在服务器上就必须要实现一个特殊的接口 Servlet.java

interface Servlet { ... }

Servlet 接口中就定义了可以被tomcat服务器调用的java方法,通常来讲,我们将实现了Servlet接口的java类称之为 Servlet,编写好的Servlet需要web.xml文件中做配置才能供外界访问

1.2 Servlet的工作流程

 技术分享

1.3 Servlet接口

技术分享

技术分享

2. 走进Servlet

技术分享

2.1 实现Servlet

下面我们通过一些Servlet实例来查看一下实现接口和继承HttpServlet:

技术分享

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <display-name>ServletPractice</display-name>
  <!--在web容器中配置servlet容器  -->
  <servlet>
      <!--servlet实例名称,可以随便起  -->
      <servlet-name>ServletInterface</servlet-name>
      <!--指定Servlet类名,由包名和类名构成  -->
      <servlet-class>servlet.Interface.ServletInterface</servlet-class>
      <!-- 配置Servlet初始化参数 -->
      <init-param>
          <!--参数名  -->
          <param-name>pName1</param-name>
          <!--参数值  -->
          <param-value>我是初始化参数pName1</param-value>
      </init-param>
      <init-param>
          <param-name>pName2</param-name>
          <param-value>我是初始化参数pName2</param-value>
      </init-param>
  </servlet>
  
  <servlet>
      <servlet-name>ServletExtends</servlet-name>
      <servlet-class>servlet.extend.ServletExtends</servlet-class>
  </servlet>
  
  <servlet>
      <servlet-name>ServletExtendsDemo</servlet-name>
      <servlet-class>servlet.extend.ServletExtendsDemo</servlet-class>
  </servlet>
  <servlet>
      <servlet-name>LoginServlet</servlet-name>
      <servlet-class>servlet.login.LoginServlet</servlet-class>
  </servlet>
  <servlet>
      <servlet-name>FirstServlet</servlet-name>
      <servlet-class>servlet.extend.FirstServlet</servlet-class>
  </servlet>
  
  <!--配置servlet的访问方式  -->
  <servlet-mapping>
      <!--对应要访问的servlet实例名称  -->
      <servlet-name>ServletInterface</servlet-name>
      <!-- 以斜杠开头,把一个路径与一个Servlet绑定在一起 ,访问时,前边的服务器域名+端口号+应用程序路径就是访问路径-->
        <!-- 随便起,必须以斜杠开头! -->
      <url-pattern>/ServletInterface</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
      <servlet-name>ServletExtends</servlet-name>
      <url-pattern>/ServletExtends</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
      <servlet-name>ServletExtendsDemo</servlet-name>
      <url-pattern>/ServletExtendsDemo</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
      <servlet-name>LoginServlet</servlet-name>
      <url-pattern>/LoginServlet</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
      <servlet-name>FirstServlet</servlet-name>
      <url-pattern>/FirstServlet</url-pattern>
  </servlet-mapping>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
</web-app>
package servlet.Interface;

import java.io.IOException;

import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class ServletInterface implements Servlet{

    @Override
    public void destroy() {
        //Servlet销毁前会被调用
        System.out.println("Servlet销毁前调用!");
    }

    @Override
    public ServletConfig getServletConfig() {
        // 返回一个 ServletConfig对象,它包含了servlet的初始化和起始参数
        System.out.println("不是Servlet生命周期的方法,作用是创建一个Servlet容器!");
        return null;
    }

    @Override
    public String getServletInfo() {
        // 返回有关servlet的信息,例如作者、版本、版权。
        System.out.println("不是生命周期方法,不常用的方法!");
        return null;
    }

    @Override
    public void init(ServletConfig arg0) throws ServletException {
        // 创建Servlet实例之后,马上调用,被servlet 容器调用以指明一个servlet被放进服务中。
        String name = arg0.getServletName();
        System.out.println("返回该servlet实例的名称。"+name);
        String str = arg0.getInitParameter("pName");
        System.out.println("返回一个包含给定名字的初始化参数,若此参数不存在就返回一个空值。"+str);
        String str1 = arg0.getInitParameter("pName2");
        System.out.println("返回一个包含给定名字的初始化参数,若此参数不存在就返回一个空值。"+str1);
        System.out.println("init方法是在服务器装入Servlet容器时执行的,负责初始化Servlet容器对象。可以配置服务器,以在启动服务器或客户机首次访问Servlet时装入Servlet。无论有多少客户机访问Servlet,都不会重复执行init()。");
        
    }

    @Override
    public void service(ServletRequest arg0, ServletResponse arg1)
            throws ServletException, IOException {
        // 被servlet container调用以允许servlet响应一个请求。
        System.out.println("每次处理请求时,tomcat都会调用这个方法。(请求处理方法)");
        
    }

}

技术分享

技术分享

index.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">
    
    <title>My JSP ‘index.jsp‘ starting page</title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="This is my page">
    <!--
    <link rel="stylesheet" type="text/css" href="styles.css">
    -->
  </head>
  
  <body>
<h1>POST请求</h1>
<form action="/ServletPractice/ServletExtends" method="post">
<input type="submit" value="发送POST请求"/>
</form>
  </body>
</html>

 

package servlet.extend;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;

public class ServletExtends extends HttpServlet{
    
    //重写service方法
    @Override
    public void service(ServletRequest arg0, ServletResponse arg1)
            throws ServletException, IOException {
        System.out.println("重写service方法,此方法在每次处理请求时调用");
    }
}

技术分享

技术分享

技术分享

从上面我们看到实现接口的话需要对接口中的所有方法进行实现,而实际开发中,我们需要的仅是有限的几个方法,所以实现接口会造成代码冗余,不可取;而继承类,则只需对所需方法进行重写即可,简单,实用;

package servlet.extend;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class ServletExtendsDemo extends HttpServlet{
    //重写doGet方法,被server调用 (通过service方法) 以允许一个 servlet处理一个 GET请求
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        System.out.println("重写doGet方法");
    }
    
}

 技术分享

技术分享

 一个登陆小案例:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>My JSP ‘form1.jsp‘ starting page</title>
    
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="This is my page">
    <!--
    <link rel="stylesheet" type="text/css" href="styles.css">
    -->

  </head>
  
  <body>
<h1>登录案例</h1>
<!-- action必须是项目名+Servlet路径 -->
<form action="/ServletPractice/LoginServlet" method="post">
用户名:<input type="text" name="username"/>
<input type="submit" value="登录"/>
</form>
  </body>
</html>
package servlet.login;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class LoginServlet extends HttpServlet{
    
    
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        // tomcat默认使用iso,而iso不支持中文
        /*
         * 我们需要做两件事:
         * 1. 让tomcat使用utf-8编码发送数据!
         * 2. 告诉浏览器我们使用的是utf-8
         * 以上两件事一个方法调用即可,设置Content-Type这个响应头即可
         */
        resp.setHeader("Content-Type", "text/html;charset=UTF-8");
        /*
         * 1. 使用request获取请求参数,参数名username
         * 2. 判断是否为itcast
         *   3. 是itcast:使用response设置状态码为404,指定错误信息;
         *   4. 不是itcast:使用response设置响应体为:<h1>登录成功</h1>
         */
        // 使用request获取请求参数
        String username = req.getParameter("username");
        if(username.equals("itcast")){
//            resp.setStatus(404);
            resp.sendError(404, "用户名不正确");
        }else {
            //设置响应体
            PrintWriter pw = resp.getWriter();//获取用户响应字符数据的输出流!
            pw.print("<h1>登录成功</h1>");
            pw.close();
        }
    }
}

技术分享

技术分享

技术分享

技术分享

2.2 配置<servlet>

2.2.1 <servlet>的配置

技术分享

技术分享

技术分享

2.2.2 <servlet-mapping>的配置

技术分享

技术分享

下面可一个实例:

package servlet.extend;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class FirstServlet extends HttpServlet {
    /*以get方式访问页面时执行该函数
     * 执行doGet()函数之前会先执行getLastModified()方法,如果浏览器发现返回的数值,与上次返回的数值相同,则认为该文档没有更新,浏览器采用缓存而不执行doGet()
     * 如果getLastModified()返回-1,则认为是时刻更新的,总是执行该函数*/
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        /*void log(java.lang.String msg) 
              将指定的消息写到一个servlet日志文件,由servlet的名字预先挂起。  */
        this.log("执行doGet()....");
        this.execute(req, resp);
    }
    //以post方式访问页面时,执行该方法,执行前不会执行getLastModified()
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        this.log("执行doPost()....");
        this.execute(req, resp);
    }
    /*返回该servlet生成的文档的更新时间,对get访问方式有效,返回的时间相对于1970年1月1日08:00:00的毫秒数,如果是-1则默认为是实时更新,默认返回的是-1*/
    @Override
    protected long getLastModified(HttpServletRequest req) {
        this.log("getLastModified()....");
        return -1;
    }
    //执行方法
    private void execute(HttpServletRequest request,HttpServletResponse response) throws IOException{
        //设置请求和响应的编码方式
        request.setCharacterEncoding("utf-8");
        response.setCharacterEncoding("utf-8");
        //获取访问该servlet的URL
        String url = request.getRequestURI();
        //获取访问该servlet的访问方式
        String method = request.getMethod();
        //客户端提交的指定参数的值,返回一个请求参数的字符串值。若该参数不存在,则返回一个空值。
        String value = request.getParameter("param");
        //设置响应的文档类型
        response.setContentType("text/html");
        //设置响应体
        PrintWriter pw = response.getWriter();//获取用户响应字符数据的输出流!
        pw.println("<!DOCTYPE html>");
        pw.println("<html>");
        pw.println("<head><title>Servlet入门</title></head>");
        pw.println("<body>");
        pw.println("<form action = ‘"+url+"‘ method = ‘get‘>"
                +"<input type = ‘text‘ name=‘param‘ value=‘param string‘>"
                +"<input type=‘submit‘ value=‘以Get方式查询页面‘"+url+">"
                +"</form>");
        pw.println("<form action = ‘"+url+"‘ method = ‘post‘>"
                +"<input type = ‘text‘ name=‘param‘ value=‘param string‘>"
                +"<input type=‘submit‘ value=‘以Post方式查询页面‘"+url+">"
                +"</form>");
        //由客户端浏览器读取该文档的更新时间
        pw.println("<script>document.write(‘本页面最后的访问时间:‘+document.lastModified);</script>");
        pw.println("</body>");
        pw.println("</html>");
        pw.close();
    }
}

 技术分享

 技术分享

技术分享

技术分享

3. Request&&Response

技术分享

 

以上是关于Servlet的主要内容,如果未能解决你的问题,请参考以下文章

servlet和filter的区别

Java基础——JSP

java---servlet与filter的联系与区别

servlet,filter,listener,intercepter区别

Tomcat根据JSP生成Servlet机制解析

servlet,过滤器,监听器,拦截器的区别