ZetCode

Servlets 和 Java Server Pages

最后修改于 2024 年 1 月 27 日

Servlet 是一个生成动态内容的 Java Web 组件。Servlet 由 Jetty 或 Tomcat 等容器管理;它们是用于基于请求-响应编程模型构建 Web 应用程序的类。Java Server Pages (JSP) 技术允许我们轻松创建同时包含静态和动态组件的 Web 内容。JSP 由 JSP 编译器编译成 servlet。

本章将介绍如何在 Jetty 中设置 servlets 和 Java Server Pages。

处理 POST 请求

HTTP POST 请求将数据从客户端发送到服务器。HTML 表单使用 POST 方法将数据发送到服务器。

在我们的示例中,一个 servlet 处理客户端发送的数据。它检索值并将它们发送回客户端。

 tree
.
├── build.xml
└── src
    ├── com
    │   └── zetcode
    │       └── MyServlet.java
    └── web
        ├── index.html
        └── WEB-INF
            └── web.xml

5 directories, 4 files

我们的项目目录看起来是这样的。

index.html
<!DOCTYPE html>
<html>
<body>

<form id="contact" method="post" action="process.do">
 
<label for="name">Name:</label>
<input type="text" name="name">
<br> 
<label for="age">Age:</label>
<input type="text" name="age">
 
<input type="submit" value="Submit">
 
</form>
 
</body>
</html>

index.html 文件包含一个 HTML 表单。它有两个 input 标签用于从用户获取数据。稍后可以从请求参数中检索值,这些参数的名称与 input 的 name 属性匹配。form 标签的 action 属性提供了一个 URL 模式,该模式映射到一个特定的 servlet 进行处理。

web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
         http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    
</web-app>

web.xml 是空的。URL 到 servlet 的映射是使用注解创建的。实际上,在我们的示例中不需要该文件。但是,由于并非所有功能都可以被注解替换,因此 web.xml 文件包含在较大的项目中。

MyServlet.java
package com.zetcode;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.annotation.WebServlet;

@WebServlet(urlPatterns = "/process.do")
public class MyServlet extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/plain");
        response.setStatus(HttpServletResponse.SC_OK);
        response.getWriter().format("Name: %s%n", request.getParameter("name"));
        response.getWriter().format("Age: %s%n", request.getParameter("age"));
    }
}

这是我们处理 servlet 的代码。

@WebServlet(urlPatterns = "/process.do")

WebServlet 注解将 com.zetcode.MyServlet 映射到 /process.do URL 模式。

response.getWriter().format("Name: %s%n", request.getParameter("name"));

我们使用 getParameter 方法从请求对象中检索 name 值。name 参数对应于 input 标签的 name 属性。

build.xml
<?xml version="1.0" encoding="UTF-8"?>

<project name="ProcessForm" default="compile">
  
    <property name="name" value="myform"/>
    <property environment="env"/>
    <property name="src.dir" value="src"/>
    <property name="web.dir" value="${src.dir}/web"/>
    <property name="build.dir" location="${web.dir}/WEB-INF/classes"/>
    <property name="jetty.lib.dir" location="${env.JETTY_HOME}/lib"/>
    <property name="dist.dir" location="dist"/>
    <property name="deploy.path" location="${env.JETTY_BASE}/webapps"/>
  
    <path id="compile.classpath">
        <fileset dir="${jetty.lib.dir}"/>
    </path>
  
    <target name="init">
        <mkdir dir="${build.dir}"/>
        <mkdir dir="${dist.dir}"/>
    </target>     
  
    <target name="compile" depends="init">
        <javac srcdir="${src.dir}" destdir="${build.dir}" 
               includeantruntime="false">
            <classpath refid="compile.classpath"/>
        </javac>
        <echo>Compilation completed</echo>
    </target>
  
    <target name="archive" depends="compile">
        <war destfile="${dist.dir}/${name}.war" 
             webxml="${web.dir}/WEB-INF/web.xml">
            <fileset dir="${web.dir}"/>
        </war>
        <echo>Archive created</echo>
    </target> 
  
    <target name="clean" depends="init">
        <delete dir="${build.dir}"/>
        <delete dir="${dist.dir}"/>
        <echo>Cleaning completed</echo>
    </target>  
    
    <target name="deploy" depends="archive">
        <copy file="${dist.dir}/${name}.war" overwrite="true" 
              todir="${deploy.path}"/>
        <echo>Archive deployed</echo>
    </target>    
    
</project>

这是 Ant 构建文件。

$ curl --data "name=Robert&age=33" localhost:8080/myform/process.do
Name: Robert
Age: 33

我们使用 curl 工具发出 POST 请求,servlet 以这两行进行响应。

自定义 404 错误页面

本示例设置了一个自定义 JSP 页面,用于显示 HTTP 404 错误。404 或 Not Found 错误消息是 HTTP 标准响应代码,表示客户端已成功与给定服务器通信,但服务器找不到所请求的内容。

$ tree
.
├── build.xml
└── src
    ├── com
    │   └── zetcode
    │       └── MyServlet.java
    └── web
        ├── error404.jsp
        └── WEB-INF
            └── web.xml

5 directories, 4 files

这是项目目录的内容。

error404.jsp
<%@ page language="java" isErrorPage="true" contentType="text/html; 
    charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<title>Error page</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
    <button onclick="history.back()">Back to Previous Page</button>
    <h1>404 Page Not Found.</h1>
    <p><b>Error code:</b> ${pageContext.errorData.statusCode}</p>
    <p><b>Request URI:</b> 
    ${pageContext.request.scheme}://${header.host}${pageContext.errorData.requestURI}
    </p>
</body>
</html>

如果 Jetty 找不到请求的页面,将显示此 JSP 页面。

MyServlet.java
package com.zetcode;

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

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/plain");
        response.setStatus(HttpServletResponse.SC_OK);
        response.getWriter().println("MyServlet called");
    }
}

创建了一个简单的 servlet。该 servlet 将一个纯消息发送回客户端。

web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
         http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    
    <display-name>MyServlet</display-name>
    
    <servlet id="jsp">
        <servlet-name>jsp</servlet-name>
        <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
        <init-param>
            <param-name>fork</param-name>
            <param-value>false</param-value>
        </init-param>
        <init-param>
            <param-name>keepgenerated</param-name>
            <param-value>true</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>    
    
    <servlet>
        <servlet-name>MyServlet</servlet-name>
        <servlet-class>com.zetcode.MyServlet</servlet-class>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>MyServlet</servlet-name>
        <url-pattern>/myservlet.do</url-pattern>
    </servlet-mapping>
    
    <servlet-mapping>
        <servlet-name>jsp</servlet-name>
        <url-pattern>*.jsp</url-pattern>
    </servlet-mapping>    
    
    <error-page>
        <error-code>404</error-code>
        <location>/error404.jsp</location>
    </error-page>    
    
</web-app>

web.xml 文件注册了一个处理 JSP 页面的 JspServlet,注册了我们的 MyServlet,并将 error404.jsp 文件映射到 404 错误。

build.xml
<?xml version="1.0" encoding="UTF-8"?>

<project name="CustomErrorPage" default="compile">
  
    <property name="name" value="customerror"/>
    <property environment="env"/>
    <property name="src.dir" value="src"/>
    <property name="web.dir" value="${src.dir}/web"/>
    <property name="build.dir" location="${web.dir}/WEB-INF/classes"/>
    <property name="lib.dir" location="${env.JETTY_HOME}/lib"/>
    <property name="dist.dir" location="dist"/>
    <property name="deploy.path" location="${env.JETTY_BASE}/webapps"/>
  
    <path id="compile.classpath">
        <fileset dir="${lib.dir}"/>
    </path>
  
    <target name="init">
        <mkdir dir="${build.dir}"/>
        <mkdir dir="${dist.dir}"/>
    </target>     
  
    <target name="compile" depends="init">
        <javac srcdir="${src.dir}" destdir="${build.dir}" 
               includeantruntime="false">
            <classpath refid="compile.classpath"/>
        </javac>
        <echo>Compilation completed</echo>
    </target>
  
    <target name="archive" depends="compile">
        <war destfile="${dist.dir}/${name}.war" 
             webxml="${web.dir}/WEB-INF/web.xml">
            <fileset dir="${web.dir}"/>
        </war>
        <echo>Archive created</echo>
    </target> 
  
    <target name="clean" depends="init">
        <delete dir="${build.dir}"/>
        <delete dir="${dist.dir}"/>
        <echo>Cleaning completed</echo>
    </target>  
    
    <target name="deploy" depends="archive">
        <copy file="${dist.dir}/${name}.war" overwrite="true" 
              todir="${deploy.path}"/>
        <echo>Archive deployed</echo>
    </target>    
    
</project>

这是 Ant 构建文件。

$ java -jar $JETTY_HOME/start.jar --add-to-start=http,deploy,jsp,jstl,annotations

这些模块必须在 Jetty 基础环境中启用。

$ java -jar $JETTY_HOME/start.jar
$ curl localhost:8080/customerror/myservlet.do
MyServlet called

我们启动 Jetty 并发出一个有效请求。

$ curl localhost:8080/customerror/servlet.do
<!DOCTYPE html>
<html>
<head>
<title>Error page</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
    <button onclick="history.back()">Back to Previous Page</button>
    <h1>404 Page Not Found.</h1>
    <p><b>Error code:</b> 404</p>
    <p><b>Request URI:</b> https://:8080/customerror/servlet.do</p>
</body>
</html>

尝试访问不存在的资源会导致 Jetty 发送我们的自定义 404 错误页面。

在本章的 Jetty 教程中,我们使用了 Java servlets 和 JSPs。

作者

我叫 Jan Bodnar,我是一名热情的程序员,拥有丰富的编程经验。我自 2007 年以来一直在撰写编程文章。迄今为止,我已撰写了 1400 多篇文章和 8 本电子书。我在编程教学方面有十多年的经验。

列出所有Java教程