48、Java Web开发:Servlet与JSP入门指南

Java Web开发:Servlet与JSP入门

Java Web开发:Servlet与JSP入门指南

1. 创建简单的Servlet

在进行了一系列配置工作后,现在可以开始编写代码,创建一个简单的Hello, World!类型的Servlet。

1.1 导入Servlet包

大多数Servlet至少需要访问三个包: javax.servlet javax.servlet.http java.io 。因此,通常从以下导入语句开始:

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

根据Servlet的其他处理需求,可能还需要额外的导入语句。

1.2 继承HttpServlet类

要创建一个Servlet,需要编写一个继承自 HttpServlet 类的类。在Servlet类中,可以重写以下六个方法,具体信息如下表所示:
| 方法 | 调用时机 | 方法签名 |
| — | — | — |
| doDelete | 收到HTTP DELETE请求时 | public void doDelete(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException |
| doGet | 收到HTTP GET请求时 | public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException |
| doPost | 收到HTTP POST请求时 | public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException |
| doPut | 收到HTTP PUT请求时 | public void doPut(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException |
| init() | Servlet首次运行时 | public void init() throws ServletException |
| destroy() | Servlet销毁时 | public void destroy() |

大多数Servlet至少会重写 doGet 方法。当用户在浏览器地址栏中输入Servlet的地址或点击指向该Servlet的链接时,Servlet引擎会调用此方法。 doGet 方法接收两个参数:
- HttpServletRequest 对象:表示用户的传入请求,主要用于检索用户在表单字段中输入的数据。
- HttpServletResponse 对象:表示发送回用户的响应,用于组合发送回用户的输出。

1.3 向网页输出内容

大多数Servlet的主要工作之一是编写HTML输出并发送回用户的浏览器。为此,首先需要调用 HttpServletResponse 类的 getWriter 方法,该方法返回一个与响应对象连接的 PrintWriter 对象,这样就可以使用熟悉的 print println 方法来编写HTML文本。

以下是一个简单的HelloWorld Servlet的 doGet 方法示例:

public void doGet(HttpServletRequest request, HttpServletResponse response)
        throws IOException, ServletException {
    PrintWriter out = response.getWriter();
    out.println("Hello, World!");
}

运行此Servlet时,浏览器将显示文本“Hello, World!”。

1.4 响应HTML内容

在大多数情况下,需要向浏览器发送格式化的HTML,而不是简单的文本。为此,必须首先告诉响应对象输出为HTML格式,可以通过调用 setContentType 方法并将字符串“text/html”作为参数传递来实现。然后,使用 PrintWriter 对象发送HTML。

以下是一个发送HTML响应的基本HelloWorld Servlet示例:

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;

public class HelloWorld extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.println("<html>");
        out.println("<head>");
        out.println("<title>HelloWorld</title>");
        out.println("</head>");
        out.println("<body>");
        out.println("<h1>Hello, World!</h1>");
        out.println("</body>");
        out.println("</html>");
    }
}

运行该Servlet时,将向浏览器发送以下HTML:

<html>
<head>
<title>HelloWorld</title>
</head>
<body>
<h1>Hello, World!</h1>
</body>
</html>

显然,编写Servlet需要对HTML有扎实的理解。以下是一些常用HTML标签的简要说明:
| HTML标签 | 描述 |
| — | — |
| <html> , </html> | 标记HTML文档的开始和结束 |
| <head> , </head> | 标记HTML文档头部的开始和结束 |
| <title> , </title> | 标题元素,标签之间的文本显示在浏览器窗口的标题栏中 |
| <body> , </body> | 标记HTML文档主体的开始和结束,文档内容位于这些标签之间 |
| <h1> , </h1> | 标签之间的文本格式化为一级标题 |
| <h2> , </h2> | 标签之间的文本格式化为二级标题 |
| <h3> , </h3> | 标签之间的文本格式化为三级标题 |
| <form action="url", method="method"> | 标记表单的开始, action 属性指定表单提交的页面、Servlet或JSP的名称, method 属性可以是GET或POST,表示发送到服务器的HTTP请求类型 |
| </form> | 标记表单的结束 |
| <input type="type", name="name"> | 创建输入字段,指定 type="text" 创建文本字段, type="submit" 创建提交按钮, name 属性用于在程序中检索用户输入的数据 |
| &nbsp; | 不间断空格 |

2. 运行Servlet

要运行一个Servlet,首先需要将编译后的类文件移动到Tomcat可以运行该Servlet的目录。为了测试,可以将Servlet的类文件移动到 c:\tomcat\webapps\ROOT\WEB-INF\classes 。然后,在浏览器的地址栏中输入如下地址:

http://localhost:8080/servlet/HelloWorld

此外,可能还需要重写 doPost 方法。当用户通过表单请求Servlet时,会调用此方法。在很多情况下,可以在 doPost 方法中调用 doGet 方法,以便以相同的方式处理GET和POST请求。示例代码如下:

public void doPost(HttpServletRequest request, HttpServletResponse response)
        throws IOException, ServletException {
    doGet(request, response);
}
3. 改进的HelloWorld Servlet

前面的HelloWorld Servlet总是发送相同的文本,本质上是一个静态Servlet,这违背了使用Servlet的初衷,因为完全可以提供一个静态HTML页面来实现相同的效果。

以下是一个更具动态性的HelloWorld Servlet示例,它会随机显示六种不同问候语中的一种:

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;

public class HelloServlet extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        String msg = getGreeting();
        out.println("<html>");
        out.println("<head>");
        out.println("<title>HelloWorld Servlet</title>");
        out.println("</head>");
        out.println("<body>");
        out.println("<h1>");
        out.println(msg);
        out.println("</h1>");
        out.println("</body>");
        out.println("</html>");
    }

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

    private String getGreeting() {
        String msg = "";
        int rand = (int)(Math.random() * (6)) + 1;
        switch (rand) {
            case 1:
                return "Hello, World!";
            case 2:
                return "Greetings!";
            case 3:
                return "Felicitations!";
            case 4:
                return "Yo, Dude!";
            case 5:
                return "Whasssuuuup?";
            case 6:
                return "Hark!";
        }
        return null;
    }
}
4. 获取用户输入

如果Servlet是由来自表单的HTTP GET或POST请求调用的,可以调用请求对象的 getParameter 方法来获取用户在每个表单字段中输入的值。例如:

String name = request.getParameter("name");

这里,将名为 name 的表单输入字段中输入的值检索出来并赋值给 String 变量 name

4.1 处理表单

虽然在Servlet中检索用户输入的数据很容易,但创建一个供用户输入数据的表单却比较困难。有两种基本方法可以实现:一种是使用单独的HTML文件创建表单。以下是一个名为 InputServlet.html 的HTML文件示例,它显示一个简单的输入表单:

<html>
<head>
<title>Input Servlet</title>
</head>
<body>
<form action="/servlet/InputServlet" method="post">
Enter your name:&nbsp;
<input type="text" name="Name">
<br><br>
<input type="submit" value="Submit">
</form>
</body>
</html>

该表单的 form 标签中的 action 属性指定了表单提交时调用的Servlet为 /servlet/InputServlet method 属性表示表单通过POST请求提交。表单本身包含一个名为 name 的输入文本字段和一个提交按钮。

以下是一个可以从上述表单中检索数据的Servlet示例:

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class InputServlet extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
        String name = request.getParameter("Name");
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.println("<html>");
        out.println("<head>");
        out.println("<title>Input Servlet</title>");
        out.println("</head>");
        out.println("<body>");
        out.println("<h1>");
        out.println("Hello " + name);
        out.println("</h1>");
        out.println("</body>");
        out.println("</html>");
    }

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

如果用户在 name 输入字段中输入“Calvin Coolidge”,则会生成以下HTML并显示在页面上:

<html>
<head>
<title>HelloWorld</title>
</head>
<body>
<h1>Hello Calvin Coolidge</h1>
</body>
</html>

尽管实际的Servlet功能远不止简单地返回用户输入的信息,但大多数Servlet都遵循这种简单的结构,当然会有一些变化。例如,实际的Servlet会验证输入数据,如果用户输入错误数据或遗漏重要数据,会显示错误消息,并且大多数实际的Servlet会从文件或数据库中检索或更新数据。

5. 在Servlet中使用类

在开发Servlet时,经常需要访问自己创建的其他类,例如从文件或数据库中检索数据的IO类、提供数据验证等常用功能的实用程序或辅助类,甚至可能是表示客户或产品等业务对象的类。要使用这些类,只需将类文件保存到Servlet主目录的 classes 目录中,在本文中,该目录为 c:\tomcat\webapps\ROOT\WEB-INF\classes

以下是一个使用多个类的Servlet示例,它会列出从文本文件中读取的电影列表。该Servlet使用了三个类:
- Movie :表示单个电影的类。

public class Movie {
    public String title;
    public int year;
    public double price;

    public Movie(String title, int year, double price) {
        this.title = title;
        this.year = year;
        this.price = price;
    }
}
  • MovieIO :包含一个名为 getMovies 的静态公共方法,该方法返回一个包含从文件中读取的所有电影的 ArrayList 对象。
import java.io.*;
import java.util.*;

public class MovieIO {
    public static ArrayList<Movie> getMovies() {
        ArrayList<Movie> movies = new ArrayList<Movie>();
        BufferedReader in = getReader("c:\\data\\movies.txt");
        Movie movie = readMovie(in);
        while (movie != null) {
            movies.add(movie);
            movie = readMovie(in);
        }
        return movies;
    }

    private static BufferedReader getReader(String name) {
        BufferedReader in = null;
        try {
            File file = new File(name);
            in = new BufferedReader(new FileReader(file));
        } catch (FileNotFoundException e) {
            System.out.println("The file doesn't exist.");
            System.exit(0);
        } catch (IOException e) {
            System.out.println("I/O Error");
            System.exit(0);
        }
        return in;
    }

    private static Movie readMovie(BufferedReader in) {
        String title;
        int year;
        double price;
        String line = "";
        String[] data;
        try {
            line = in.readLine();
        } catch (IOException e) {
            System.out.println("I/O Error");
            System.exit(0);
        }
        if (line == null) {
            return null;
        } else {
            data = line.split("\t");
            title = data[0];
            year = Integer.parseInt(data[1]);
            price = Double.parseDouble(data[2]);
            return new Movie(title, year, price);
        }
    }
}
  • ListFiles :主Servlet类,它调用 MovieIO.getMovies 方法获取电影的 ArrayList ,然后在页面上显示这些电影。
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;

public class ListMovies extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        String msg = getMovieList();
        out.println("<html>");
        out.println("<head>");
        out.println("<title>List Movies Servlet</title>");
        out.println("</head>");
        out.println("<body>");
        out.println("<h1>Some of My Favorites</h1>");
        out.println("<h3>");
        out.println(msg);
        out.println("</h3>");
        out.println("</body>");
        out.println("</html>");
    }

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

    private String getMovieList() {
        String msg = "";
        ArrayList<Movie> movies = MovieIO.getMovies();
        for (Movie m : movies) {
            msg += m.year + ": ";
            msg += m.title + "<br>";
        }
        return msg;
    }
}

该Servlet的方法功能如下:
- doGet 方法:调用 getMovieList 方法获取包含所有电影列表(以换行标签分隔)的字符串,然后使用一系列 out.println 语句编写HTML以显示该列表。
- doPost 方法:简单地调用 doGet 方法,这样无论通过GET还是POST请求调用Servlet,都能正常工作。
- getMovieList 方法:调用 MovieIO.getMovies 方法获取包含从文件中读取的所有电影的 ArrayList ,然后使用增强的 for 循环检索每个 Movie 对象,将每部电影的年份和标题添加到 msg 字符串中,并用 <br> 标签分隔。

6. 理解Java Server Pages(JSP)

在前面的章节中,学习了如何通过 response.out 访问的 PrintWriter 对象将HTML数据直接写入页面来创建Servlet。虽然这种技术可行,但有一个主要缺点:必须手动将HTML编写为一堆字符串常量。如果HTML有错误,直到运行Servlet才能发现。而且,在 out.println 语句中手工编写HTML并不是创建吸引人的网页的最有效方法。

Java Server Pages(通常简称为JSP)应运而生。JSP是一种在特殊标签中嵌入Java Servlet代码的HTML文件。运行JSP时,所有HTML会自动作为响应的一部分发送,同时还会发送JSP文件中嵌入的Java代码所创建的任何HTML。因此,JSP省去了编写大量 out.println 语句的麻烦。

6.1 JSP的基本概念

Java Server Page是一个保存为扩展名为 .jsp 而不是 .htm .html 的HTML文档。与Servlet类文件不同,JSP文件可以存储在Web服务器可访问的任何目录中。

当用户首次请求JSP文件时,JSP文件会通过一个翻译程序进行处理,该程序将文件转换为Java Servlet程序并进行编译。原始JSP文件中的所有HTML会转换为 out.print 语句,将HTML发送到响应中,JSP文件中的Java语句会合并到Servlet程序中。然后,执行Servlet程序并将结果发送回浏览器。需要注意的是,这种转换只在首次请求JSP时进行,之后,每当用户请求该JSP时,会直接运行Servlet。

6.2 JSP元素

创建JSP时,需要将特殊的JSP元素与普通HTML混合使用。可以包含以下四种类型的JSP元素:
- 指令(Directives) :指令是影响从JSP页面构建Servlet方式的选项设置。指令可以指定Servlet所需的导入语句、指定Servlet是否线程安全,以及在Servlet中包含其他源文件等。
- 表达式(Expressions) :表达式可以是任何Java表达式。表达式会被求值,必要时转换为字符串,并将结果插入到文档中。表达式的形式如下:

<%= expression %>
  • 脚本片段(Scriptlets) :脚本片段是直接插入到为JSP生成的Servlet代码中的一系列Java语句。在脚本片段中可以执行几乎任何操作,包括 if 语句、循环和调用其他方法。甚至可以使用 out.println 向页面添加输出,输出会插入到脚本片段出现的位置。脚本片段的形式如下:
<% statements %>
  • 声明(Declarations) :声明是放置在Servlet类中任何方法之外的Java代码。使用声明可以创建类变量或定义可以由脚本片段或表达式调用的方法。声明的形式如下:
<%! statements %>

目前版本的Tomcat(5.5.4)不支持Java 1.5的新特性,除非进行一系列额外的配置。为了避免麻烦,在本章中避免使用Java 1.5的特性,希望下一版本的Tomcat能更好地支持Java 1.5。

Java Web开发:Servlet与JSP入门指南

7. 使用JSP指令

JSP指令是一种特殊的标签,用于为JSP页面提供全局信息,影响JSP页面的翻译和编译过程。常见的JSP指令有 page include taglib ,下面分别介绍它们的使用方法。

7.1 page指令

page 指令用于定义JSP页面的全局属性,如页面的编码、内容类型、导入的包等。其语法如下:

<%@ page attribute1="value1" attribute2="value2" ... %>

常见的 page 指令属性及说明如下表所示:
| 属性 | 描述 |
| — | — |
| contentType | 指定响应的MIME类型和字符编码,例如 "text/html; charset=UTF-8" |
| language | 指定JSP页面使用的编程语言,通常为 "java" |
| import | 导入Java包和类,多个包或类之间用逗号分隔 |
| session | 指定该页面是否使用会话,值为 true false |
| errorPage | 指定当页面发生错误时跳转的页面 |

以下是一个使用 page 指令的示例:

<%@ page contentType="text/html; charset=UTF-8" language="java" import="java.util.*" %>
<html>
<head>
<title>Page Directive Example</title>
</head>
<body>
<h1>Hello, JSP!</h1>
</body>
</html>
7.2 include指令

include 指令用于在JSP页面中包含另一个文件的内容,被包含的文件可以是JSP页面、HTML文件或文本文件。其语法如下:

<%@ include file="filename" %>

以下是一个使用 include 指令的示例:

<html>
<head>
<title>Include Directive Example</title>
</head>
<body>
<%@ include file="header.html" %>
<h1>Main Content</h1>
<%@ include file="footer.html" %>
</body>
</html>
7.3 taglib指令

taglib 指令用于引入自定义标签库,以便在JSP页面中使用自定义标签。其语法如下:

<%@ taglib uri="taglibURI" prefix="tagPrefix" %>

其中, uri 指定标签库的URI, prefix 指定标签的前缀。

8. 使用JSP表达式

JSP表达式用于将Java表达式的值插入到HTML页面中。表达式会被求值,必要时转换为字符串,并将结果插入到文档中。其语法如下:

<%= expression %>

以下是一个使用JSP表达式的示例:

<%@ page contentType="text/html; charset=UTF-8" language="java" %>
<html>
<head>
<title>JSP Expression Example</title>
</head>
<body>
<p>当前时间是:<%= new java.util.Date() %></p>
</body>
</html>

在上述示例中, <%= new java.util.Date() %> 会将当前时间插入到HTML页面中。

9. 使用JSP脚本片段

JSP脚本片段是直接插入到为JSP生成的Servlet代码中的一系列Java语句。在脚本片段中可以执行几乎任何操作,包括 if 语句、循环和调用其他方法。其语法如下:

<% statements %>

以下是一个使用JSP脚本片段的示例:

<%@ page contentType="text/html; charset=UTF-8" language="java" %>
<html>
<head>
<title>JSP Scriptlet Example</title>
</head>
<body>
<%
    int sum = 0;
    for (int i = 1; i <= 10; i++) {
        sum += i;
    }
%>
<p>1到10的和是:<%= sum %></p>
</body>
</html>

在上述示例中,脚本片段中计算了1到10的和,并将结果存储在变量 sum 中,然后使用JSP表达式将结果输出到页面上。

10. 使用JSP声明

JSP声明是放置在Servlet类中任何方法之外的Java代码。使用声明可以创建类变量或定义可以由脚本片段或表达式调用的方法。其语法如下:

<%! statements %>

以下是一个使用JSP声明的示例:

<%@ page contentType="text/html; charset=UTF-8" language="java" %>
<html>
<head>
<title>JSP Declaration Example</title>
</head>
<body>
<%!
    public int factorial(int n) {
        if (n == 0 || n == 1) {
            return 1;
        } else {
            return n * factorial(n - 1);
        }
    }
%>
<p>5的阶乘是:<%= factorial(5) %></p>
</body>
</html>

在上述示例中,使用JSP声明定义了一个计算阶乘的方法 factorial ,然后在JSP表达式中调用该方法计算5的阶乘并输出结果。

11. JSP开发流程总结

下面是一个使用mermaid格式的流程图,展示了JSP的开发流程:

graph LR
    A[创建JSP文件] --> B[编写HTML和JSP元素]
    B --> C[部署到Web服务器]
    C --> D[用户请求JSP页面]
    D --> E{首次请求?}
    E -- 是 --> F[翻译为Servlet并编译]
    E -- 否 --> G[直接运行Servlet]
    F --> G
    G --> H[执行Servlet并返回结果]
    H --> I[显示页面]

通过以上步骤,你可以创建出功能丰富、动态交互的Web页面。在实际开发中,可以根据具体需求灵活运用Servlet和JSP的各种特性,结合数据库、文件系统等,开发出更加复杂和强大的Web应用程序。希望本文能帮助你快速入门Servlet和JSP开发,祝你在Web开发的道路上取得成功!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值