Servlet 基础

JSP 的前身就是 Servlet

什么是 Servlet?

Servlet 是在服务器上运行的小程序。一个 Servlet 就是一个 Java 类,并且可以通过“请求 - 响应”编程模型来访问这个驻留在服务器内存里的 Servlet 程序。

Tomcat 容器等级

Tomcat 容器分为四个等级,Servlet 容器管理 Context 容器,一个 Context 对应一个 Web 工程

具体如上图所示: Tomcat 容器 : Container 容器 --> Engine 容器(引擎容器) --> HOST (主机)容器 --> Servlet --> Context

手工编写第一个 Servlet

1、新建一个 MyFirstServletDemo 动态项目,并新建一个 index.jsp 文件

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
</head>
<body>

<a href="servlet/HelloServlet">Get请求HelloServlet</a>

<form action="servlet/HelloServlet" method="post">
    <input type="submit" value="Post请求HelloServlet"/>
</form>
</body>
</html>

2、在src中新建一个servlet包,再定义一个HelloServlet类,并重写 doGet 和 doPost 方法

package servlet;

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 HelloServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // TODO Auto-generated method stub
        System.out.println("处理Get请求……");
        PrintWriter out = resp.getWriter();
        resp.setContentType("text/html; charset=utf-8");
        out.println("<h1>Hello Servlet</h1>");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // TODO Auto-generated method stub
        System.out.println("处理Post请求……");
        PrintWriter out = resp.getWriter();
        resp.setContentType("text/html; charset=utf-8");
        out.println("<h1>Hello Servlet</h1>");
    }

}

3、在 WEB-INF - web.xml 中注册servlet,添加 servlet 和 servlet-mapping 两个标签

<?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" version="3.0">
  <display-name>MyFirstServletDemo</display-name>
  <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>
  
  <servlet>
      <servlet-name>HelloServlet</servlet-name>
      <servlet-class>servlet.HelloServlet</servlet-class>
  </servlet>
  
  <servlet-mapping>
      <servlet-name>HelloServlet</servlet-name>
      <url-pattern>/servlet/HelloServlet</url-pattern>
  </servlet-mapping>
</web-app>

运行查看

 

 从这个例子中,可以大概看出 Servlet 的执行流程

 Servlet 的生命周期

Servlet 生命周期阶段包括:初始化、加载、实例化、服务和销毁

1、初始化阶段,调用 init() 方法;

2、响应客户请求阶段,调用 service() 方法。由 service() 方法根据提交方式选择执行 doGet() 或者 doPost() 方法

3、终止阶段,调用 destroy() 方法

 

 下面用代码演示下 Servlet的生命周期

1、新建一个 testServlet.jsp 页面

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
</head>
<body>
<h1>测试 Servlet 生命周期</h1>

<a href="servlet/TestServlet1">发起Get请求</a>
</body>
</html>

2、新建一个TestServlet1 类,并重写父类的构造方法,初始化方法,doGet方法和销毁方法

package servlet;

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 TestServlet1 extends HttpServlet {

    public TestServlet1() {
        System.out.println("TestServlet1的构造方法被执行……");
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // TODO Auto-generated method stub
        System.out.println("处理Get请求……");
        resp.setContentType("text/html; charset=utf-8");
        PrintWriter out = resp.getWriter();
        out.println("<h1>Test Servlet1<h1>");
    }

    @Override
    public void destroy() {
        // TODO Auto-generated method stub
        System.out.println("TestServlet1的销毁方法被执行……");
    }

    @Override
    public void init() throws ServletException {
        // TODO Auto-generated method stub
        System.out.println("TestServlet1的初始化方法被执行……");
    }

    
    

}

3、修改配置文件

<?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" version="3.0">
  <display-name>MyFirstServletDemo</display-name>
  <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>
  
  <servlet>
      <servlet-name>TestServlet1</servlet-name>
      <servlet-class>servlet.TestServlet1</servlet-class>
  </servlet>
  
  <servlet-mapping>
      <servlet-name>TestServlet1</servlet-name>
      <url-pattern>/servlet/TestServlet1</url-pattern>
  </servlet-mapping>
  
</web-app>

从下图中可以看到依次执行的是 构造方法、初始化方法和service方法,当servlet实例已经存在的时候直接调用service方法,而不需要再去执行构造方法和初始化方法。只有当服务器关闭的时候,才会执行销毁方法

 Servlet 容易装载 Servlet的三种情况:

1、Servlet 容器启动时自动装载某些Servlet,实现它只需要在 web.xml 文件中的 <Servlet></Servlet> 之间添加代码:<load-on-start-up>1</load-on-start-up>  数字越小,表示优先级越高

2、在Servlet 容器启动后,客户首次向 Servlet 发送请求

3、Serlvet 类文件被更新后,重新装载 Servlet

其实,上例演示的也就是第2种情况,启动Servlet容器,首次向 Servlet发送请求

现在我们来演示第1种情况,在 servlet包下创建一个 TestServlet2 类

package servlet;

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

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

public class TestServlet2 extends HttpServlet {

    public TestServlet2() {
        System.out.println("TestServlet2的构造方法被执行……");
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // TODO Auto-generated method stub
        System.out.println("处理Get请求……");
        resp.setContentType("text/html; charset=utf-8");
        PrintWriter out = resp.getWriter();
        out.println("<h1>Test Servlet2<h1>");
    }

    @Override
    public void destroy() {
        // TODO Auto-generated method stub
        System.out.println("TestServlet2的销毁方法被执行……");
    }

    @Override
    public void init() throws ServletException {
        // TODO Auto-generated method stub
        System.out.println("TestServlet2的初始化方法被执行……");
    }
    
}

2、修改web.xml 配置文件,在 servlet 标签中加一对 load-on-startup,把TestServlet1的优先级设为2,低于 TestServlet1的优先级1

<?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" version="3.0">
  <display-name>MyFirstServletDemo</display-name>
  <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>
  
  <servlet>
      <servlet-name>TestServlet1</servlet-name>
      <servlet-class>servlet.TestServlet1</servlet-class>
      <load-on-startup>2</load-on-startup>
  </servlet>
  
  <servlet-mapping>
      <servlet-name>TestServlet1</servlet-name>
      <url-pattern>/servlet/TestServlet1</url-pattern>
  </servlet-mapping>
  
  <servlet>
      <servlet-name>TestServlet2</servlet-name>
      <servlet-class>servlet.TestServlet2</servlet-class>
      <load-on-startup>1</load-on-startup>
  </servlet>
  
  <servlet-mapping>
      <servlet-name>TestServlet2</servlet-name>
      <url-pattern>/servlet/TestServlet2</url-pattern>
  </servlet-mapping>
</web-app>

重新启动Tomcat服务器,我们发现服务器先执行的是TestServlet2的构造方法和初始化方法

 现在来实现一个小例子,用户注册完成以后,把用户的注册信息在另一个页面打印出来

 1、reg.jsp

<%@ page language="java" import="java.util.*" contentType="text/html; charset=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 'reg.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">
    -->
    <style type="text/css">
     .label{
           20%    
     }
     .controler{
           80%    
     }
   </style>  
   <script type="text/javascript" src="js/Calendar3.js"></script>
  </head>
  
  <body>
    <h1>用户注册</h1>
    <hr>
    <form name="regForm" action="servlet/RegServlet" method="post" >
              <table border="0" width="800" cellspacing="0" cellpadding="0">
                <tr>
                    <td class="lalel">用户名:</td>
                    <td class="controler"><input type="text" name="username" /></td>
                </tr>
                <tr>
                    <td class="label">密码:</td>
                    <td class="controler"><input type="password" name="mypassword" ></td>
                    
                </tr>
                <tr>
                    <td class="label">确认密码:</td>
                    <td class="controler"><input type="password" name="confirmpass" ></td>
                    
                </tr>
                <tr>
                    <td class="label">电子邮箱:</td>
                    <td class="controler"><input type="text" name="email" ></td>
                    
                </tr>
                <tr>
                    <td class="label">性别:</td>
                    <td class="controler"><input type="radio" name="gender" checked="checked" value="Male">男<input type="radio" name="gender" value="Female">女</td>
                    
                </tr>
               
                <tr>
                    <td class="label">出生日期:</td>
                    <td class="controler">
                      <input name="birthday" type="text" id="control_date" size="10"
                      maxlength="10" onclick="new Calendar().show(this);" readonly="readonly" />
                    </td>
                </tr>
                <tr>
                    <td class="label">爱好:</td>
                    <td class="controler">
                    <input type="checkbox" name="favorite" value="nba"> NBA &nbsp;
                      <input type="checkbox" name="favorite" value="music"> 音乐 &nbsp;
                      <input type="checkbox" name="favorite" value="movie"> 电影 &nbsp;
                      <input type="checkbox" name="favorite" value="internet"> 上网 &nbsp;
                    </td>
                </tr>
                <tr>
                    <td class="label">自我介绍:</td>
                    <td class="controler">
                        <textarea name="introduce" rows="10" cols="40"></textarea>
                    </td>
                </tr>
                <tr>
                    <td class="label">接受协议:</td>
                    <td class="controler">
                        <input type="checkbox" name="isAccept" value="true">是否接受霸王条款
                    </td>
                </tr>
                <tr>
                    <td colspan="2" align="center">
                        <input type="submit" value="注册"/>&nbsp;&nbsp;
                        <input type="reset" value="取消"/>&nbsp;&nbsp;
                    </td>
                </tr>
              </table>
            </form>
  </body>
</html>

2、web.xml

<?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>getServletUserInfo2</display-name>
  <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>
  
  <servlet>
      <servlet-name>RegServlet</servlet-name>
      <servlet-class>servlet.RegServlet</servlet-class>
  </servlet>
  
  <servlet-mapping>
      <servlet-name>RegServlet</servlet-name>
      <url-pattern>/servlet/RegServlet</url-pattern>
  </servlet-mapping>
</web-app>

3、JavaBean Users.java

package user;

import java.util.Date;

/**
 * 用户类
 * @author wupeng
 *
 */
public class Users {

    private String username; // 用户名
    private String mypassword; // 密码
    private String gender; // 性别
    private String email; // 邮箱
    private Date birthday; // 出生日期
    private String[] favorites; // 爱好
    private String introduce; // 自我介绍
    private boolean flag; // 是否接受协议
    
    
    public Users() {
        
    }


    public String getUsername() {
        return username;
    }


    public void setUsername(String username) {
        this.username = username;
    }


    public String getMypassword() {
        return mypassword;
    }


    public void setMypassword(String mypassword) {
        this.mypassword = mypassword;
    }


    public String getGender() {
        return gender;
    }


    public void setGender(String gender) {
        this.gender = gender;
    }


    public String getEmail() {
        return email;
    }


    public void setEmail(String email) {
        this.email = email;
    }


    public Date getBirthday() {
        return birthday;
    }


    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }


    public String[] getFavorites() {
        return favorites;
    }


    public void setFavorites(String[] favorites) {
        this.favorites = favorites;
    }


    public String getIntroduce() {
        return introduce;
    }


    public void setIntroduce(String introduce) {
        this.introduce = introduce;
    }


    public boolean isFlag() {
        return flag;
    }


    public void setFlag(boolean flag) {
        this.flag = flag;
    }
    
    

}

4、RegServlet.java

package servlet;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

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

import user.Users;

public class RegServlet extends HttpServlet {

    public RegServlet() {
        // TODO Auto-generated constructor stub
    }

    @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
        req.setCharacterEncoding("utf-8");
        
        Users u = new Users();
        
        String username, mypassword, gender, email, introduce, isAccept;
        Date birthday;
        String[] favorites;
        
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        
        try {
            username = req.getParameter("username");
            mypassword = req.getParameter("mypassword");
            gender = req.getParameter("gender");
            email = req.getParameter("email");
            introduce = req.getParameter("introduce");
            birthday = sdf.parse(req.getParameter("birthday"));
            if(req.getParameterValues("isAccpet")!=null)
            {
              isAccept = req.getParameter("isAccept");
            }
            else
            {
              isAccept = "false";
            }
            favorites = req.getParameterValues("favorite");
            
            // 把用户信息存到对象u中
            u.setUsername(username);
            u.setMypassword(mypassword);
            u.setGender(gender);
            u.setEmail(email);
            u.setIntroduce(introduce);
            u.setBirthday(birthday);
            if ("true".equals(isAccept)) {
                u.setFlag(true);
            } else {
                u.setFlag(false);
            }
            u.setFavorites(favorites);
            
            // 把注册成功的用户信息保存到 session 中
            req.getSession().setAttribute("regUser", u);
            
            // 服务器转发到注册成功页面
            req.getRequestDispatcher("../userinfo.jsp").forward(req, resp);
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    

}

5、userinfo.jsp

<%@ page language="java" import="java.util.*,java.text.*" contentType="text/html; charset=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 'userinfo.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">
    -->
    <style type="text/css">
     .title{
          30%;    
         background-color: #CCC;
         font-weight: bold;
     }
     .content{
         70%;
         background-color: #CBCFE5;
     }
     
   </style>  
  </head>
  
  <body>
    <h1>用户信息</h1>
    <hr>
    <center>
    
    <jsp:useBean id="regUser" class="user.Users" scope="session" />
    
     <table width="600" cellpadding="0" cellspacing="0" border="1">
        <tr>
          <td class="title">用户名:</td>
          <td class="content">&nbsp;<jsp:getProperty property="username" name="regUser"/></td>
        </tr>
        <tr>
          <td class="title">密码:</td>
          <td class="content">&nbsp;<jsp:getProperty property="mypassword" name="regUser"/></td>
        </tr>
        <tr>
          <td class="title">性别:</td>
          <td class="content">&nbsp;<jsp:getProperty property="gender" name="regUser"/></td>
        </tr>
        <tr>
          <td class="title">E-mail:</td>
          <td class="content">&nbsp;<jsp:getProperty property="email" name="regUser"/></td>
        </tr>
        <tr>
          <td class="title">出生日期:</td><td class="content">&nbsp;
             <% 
               SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
               String date = sdf.format(regUser.getBirthday());
             %> 
             <%=date%>
          </td>
        </tr>
        <tr>
          <td class="title">爱好:</td>
          <td class="content">&nbsp;
              <%
                  String[] favorites = regUser.getFavorites();
                  for (String f:favorites) {
            %>
            <%=f %>"&nbsp;&nbsp;"
            <% 
                  }
              %>
          </td>
        </tr>
        <tr>
          <td class="title">自我介绍:</td>
          <td class="content">&nbsp;<jsp:getProperty property="introduce" name="regUser"/></td>
        </tr>
        <tr>
          <td class="title">是否介绍协议:</td>
          <td class="content">&nbsp;<jsp:getProperty property="flag" name="regUser"/></td>
        </tr>
     </table>
    </center>
  </body>
</html>

页面输出:

 

Servlet 路径跳转

1、index.jsp 中的路径跳转

<a href="request.jsp?username=科比">测试URL传参数</a>

<!-- 使用相对路径访问 Servlet -->
<!-- /servlet/HelloServelt 第一个/ 表示服务器的根目录 -->
<a href="servlet/HelloServlet">访问HelloServlet</a>

<!-- 使用绝对路径访问Servlet,可以使用 path 变量:path变量表示项目的根目录 -->
<a href="<%=path %>/servlet/HelloServlet">访问HelloServlet</a>

<!-- 表单中 action的 URL地址写法,与超链接方式完全相同 -->

2、web.xml 中 url-pattern

<servlet-mapping>
    <servlet-name>HelloServlet</servlet-name>
    <!-- url-pattern 处必须以 / 开头,这里的 / 表示项目的根目录  -->
    <url-pattern>/servlet/HelloServlet</url-pattern>
</servlet-mapping>

3、servlet 跳转

// 请求重定向方式跳转到 test.jsp,当前路径是 ServletPathDirection/servlet
// response.sendRedirect("test.jsp");
// 使用 request.getContextPath 获得上下文对象
// response.sendRedirect(request.getContextPath + "/test.jsp");

// 服务器内部跳转,这里的斜线表示项目的根目录
request.getRequestDispatcher("/test.jsp").forward(request, response);
原文地址:https://www.cnblogs.com/rogerwu/p/8535338.html