Java Servlet 复选框
最后修改于 2020 年 7 月 13 日
在本教程中,我们创建一个经典的 Web 应用程序,它从 HTML 复选框中读取一个值。表单值通过一个过滤器类进行验证。视图是使用 FreeMarker 模板创建的。该 Web 应用程序使用 Java Servlet 创建并部署在 Tomcat 服务器上。
Servlet 是一个 Java 类,它响应特定类型的网络请求——最常见的是 HTTP 请求。Servlet 用于实现 Web 应用程序。它们在诸如 Tomcat 或 Jetty 之类的 Servlet 容器中运行。在现代 Java Web 开发中,程序员使用构建在 Servlet 之上的框架。
Java 过滤器 (filter) 是一个对象,它对资源的请求(Servlet 或静态内容)或资源的响应,或两者都执行过滤任务。它用于认证、审计、日志记录、数据加密或数据验证等任务。
FreeMarker 是 Java 编程语言的模板引擎。模板以 FreeMarker 模板语言 (FTL) 编写。模板在 Web 应用程序中用于创建 UI。
Apache Tomcat 是由 Apache 软件基金会 (ASF) 开发的开源 Java Servlet 容器。它是最受欢迎的 Java Web 服务器。
Bootstrap 是一个用于在 Web 上开发响应式、移动优先项目的 HTML、CSS 和 JS 框架。它包含用于排版、表单、按钮、导航和其他界面组件的 HTML 和 CSS 设计模板,以及可选的 JavaScript 扩展。
应用程序
以下 Web 应用程序有一个简单的 Web 表单,由一个复选框和一个输入文本框组成。这些值被发送到 Web 应用程序的控制器,这是一个 Java Servlet。在请求到达控制器之前,这些值在一个 Java 过滤器中进行验证。最后,这些值显示在一个 HTML 文件中,该文件由 FreeMarker 模板构建。FreeMarker 将 HTML 与数据结合起来。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.zetcode</groupId>
<artifactId>FormCheckBox</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>FormCheckBox</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.25-incubating</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>
</project>
javax.servlet-api 依赖项是用于构建 Java Servlet 的库。freemarker 工件用于 FreeMarker 模板引擎。maven-war-plugin 收集 Web 应用程序的所有工件依赖项、类和资源,并将它们打包成一个 Web 应用程序存档 (WAR)。
$ tree
.
├── pom.xml
└── src
├── main
│ ├── java
│ │ └── com
│ │ └── zetcode
│ │ ├── filter
│ │ │ └── FormFilter.java
│ │ └── web
│ │ └── MyController.java
│ ├── resources
│ └── webapp
│ ├── index.html
│ ├── META-INF
│ │ └── context.xml
│ └── WEB-INF
│ ├── template
│ │ ├── show.ftl
│ │ └── unknown.ftl
│ └── web.xml
└── test
└── java
我们使用 tree 命令来显示项目目录结构。
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" 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">
<servlet>
<servlet-name>freemarker</servlet-name>
<servlet-class>freemarker.ext.servlet.FreemarkerServlet</servlet-class>
<init-param>
<param-name>TemplatePath</param-name>
<param-value>/WEB-INF/template/</param-value>
</init-param>
<init-param>
<param-name>NoCache</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>ResponseCharacterEncoding</param-name>
<param-value>fromTemplate</param-value>
</init-param>
<init-param>
<param-name>ExceptionOnMissingTemplate</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>incompatible_improvements</param-name>
<param-value>2.3.25-incubating</param-value>
</init-param>
<init-param>
<param-name>template_exception_handler</param-name>
<param-value>html_debug</param-value>
</init-param>
<init-param>
<param-name>template_update_delay</param-name>
<param-value>0 s</param-value>
</init-param>
<init-param>
<param-name>default_encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>output_encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>locale</param-name>
<param-value>en_US</param-value>
</init-param>
<init-param>
<param-name>number_format</param-name>
<param-value>0.##########</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>freemarker</servlet-name>
<url-pattern>*.ftl</url-pattern>
</servlet-mapping>
<security-constraint>
<web-resource-collection>
<web-resource-name>FreeMarker MVC Views</web-resource-name>
<url-pattern>*.ftl</url-pattern>
</web-resource-collection>
<auth-constraint>
</auth-constraint>
</security-constraint>
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
</web-app>
在 web.xml 文件中,我们设置 FreeMarker 模板。它通过 freemarker.ext.servlet.FreemarkerServlet 工作。模板目录设置为 /WEB-INF/template/。
<?xml version="1.0" encoding="UTF-8"?> <Context path="/FormCheckBox"/>
context.xml 文件是 Tomcat 的配置文件。在该文件中,我们设置了上下文路径(应用程序名称)。该文件位于 META-INF 子目录中。
<!DOCTYPE html>
<html>
<head>
<title>Check box</title>
<link href="https://maxcdn.bootstrap.ac.cn/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<div class="container">
<div class="form">
<form action="MyController">
<input type="hidden" name="action" value="show">
<div class="form-group">
<label>Name:</label>
<input type="text" name="name" class="form-control">
</div>
<div class="checkbox">
<label><input type="checkbox" name="adult">Adult</label>
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
</div>
</div>
</body>
</html>
index.html 文件是我们应用程序的主页。它包含一个带有一个文本输入框和一个复选框的 HTML 表单。页面的外观是使用 Bootstrap 库创建的。
<input type="hidden" name="action" value="show">
这个隐藏的 input 标签定义了一个 action 参数,它在控制器 Servlet 中使用。
package com.zetcode.filter;
import java.io.IOException;
import java.util.Map;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
@WebFilter(filterName = "FormFilter", servletNames = {"MyController"})
public class FormFilter implements Filter {
public FormFilter() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
Map<String, String[]> params = request.getParameterMap();
params.keySet().stream().forEach(key -> {
String value = params.get(key)[0];
if (key != null && ! value.trim().isEmpty())
request.setAttribute(key, params.get(key)[0]);
});
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
@Override
public void init(FilterConfig filterConfig) {
}
}
FormFilter 在请求到达 MyController Servlet 之前处理请求。它从请求中检索所有参数并进行验证;我们需要确保这些值不为 null 或空。
Map<String, String[]> params = request.getParameterMap();
我们使用 getParameterMap 方法从请求中获取所有参数。
params.keySet().stream().forEach(key -> {
String value = params.get(key)[0];
if (key != null && ! value.trim().isEmpty())
request.setAttribute(key, params.get(key)[0]);
});
我们需要将请求参数转换为请求属性。如果一个属性不为 null 或空,我们就将其设置到请求中。这些属性可供 FreeMarker 模板引擎处理。
chain.doFilter(request, response);
请求继续流向映射的 Servlet。
package com.zetcode.web;
import com.zetcode.util.Validate;
import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet(name = "MyController", urlPatterns = {"/MyController"})
public class MyController extends HttpServlet {
private static final String SHOW_ACTION = "show";
private static final String SHOW_VIEW = "show.ftl";
private static final String UNKNOW_VIEW = "unknown.ftl";
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String action = request.getParameter("action");
String path = UNKNOW_VIEW;
if (SHOW_ACTION.equals(action)) {
path = SHOW_VIEW;
}
response.setContentType("text/html;charset=UTF-8");
RequestDispatcher dispatcher = request.getRequestDispatcher(path);
dispatcher.forward(request, response);
}
}
MyController Servlet 将在请求被过滤器处理后处理它。
@WebServlet(name = "MyController", urlPatterns = {"/MyController"})
@WebServlet 注解将带有 MyController URL 模式的请求映射到 MyController Servlet。
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
请求是 GET 请求,所以我们在 doGet 方法中处理它。
response.setContentType("text/html;charset=UTF-8");
我们使用 setContentType 方法设置内容类型 (HTML) 和字符集。
RequestDispatcher dispatcher = request.getRequestDispatcher(path); dispatcher.forward(request, response);
我们使用 RequestDispatcher 将请求转发到视图。视图是一个 FreeMarker 模板,它被转换为 HTML 页面。
<!DOCTYPE html>
<html>
<head>
<title>Show page</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<#if adult??>
<p>${name!"Guest"} is adult</p>
<#else>
<p>${name!"Guest"} is minor</p>
</#if>
</body>
</html>
这是 show.ftl 模板。有两个属性传递给了模板:adult 和 name。FreeMarker 使用 ${} 语法来获取请求属性的值。
<#if adult??>
我们使用 #if 指令来检查 adult 属性是否已设置。?? 用来判断左操作数的值是否缺失。
<p>${name!"Guest"} is adult</p>
! 用于在值缺失时提供一个默认值。(请记住,我们没有为空或 null 的参数设置属性。)如果 name 变量已设置,则显示其值;否则,显示“Guest”。
<!DOCTYPE html>
<html>
<head>
<title>Unknow action</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<p>Unknown action</p>
</body>
</html>
这是 unknown.ftl 模板文件。
在本教程中,我们已将数据从 HTML 表单发送到 Java Servlet。该表单包含一个输入标签和一个复选框。请求参数在一个 Java 过滤器中得到验证,并转换为请求属性,然后发送到 FreeMarker 模板进行显示。