ZetCode-Servlet-教程-一-

ZetCode Servlet 教程(一)

原文:ZetCode

协议:CC BY-NC-SA 4.0

从 Java Servlet 提供纯文本

原文: http://zetcode.com/articles/javaservlettext/

在 Java Servlet 文本教程中,我们展示了如何从 Java Servlet 返回纯文本。 该 Web 应用已部署在 Tomcat 服务器上。

Servlet 是 Java 类,可响应特定类型的网络请求-最常见的是 HTTP 请求。 Java servlet 用于创建 Web 应用。 它们在 servlet 容器(例如 Tomcat 或 Jetty)中运行。 现代 Java Web 开发使用在 servlet 之上构建的框架。

Apache Tomcat 是由 Apache 软件基金会(ASF)开发的开源 Java Servlet 容器。 它是最流行的 Java Web 服务器。

Java servlet 应用

以下 Web 应用使用 Java Servlet 将纯文本发送到客户端。 从资源目录中的文件中读取文本。

$ tree
.
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── zetcode
    │   │           ├── util
    │   │           │   └── ReadTextUtil.java
    │   │           └── web
    │   │               └── GetText.java
    │   ├── resources
    │   │   └── thermopylae.txt
    │   └── webapp
    │       ├── index.html
    │       └── META-INF
    │           └── context.xml
    └── test
        └── java

这是项目结构。

pom.xml

<?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>ServletPlainText</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>ServletPlainText</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>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>21.0</version>
        </dependency>        

        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.8.0</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>

这是 Maven POM 文件。 我们有三个工件:用于 servlet 的javax.servlet-api,用于 Java JSON 处理的gsonguava通用库。 maven-war-plugin负责收集 Web 应用的所有工件依赖项,类和资源,并将它们打包到 Web 应用存档(WAR)中。

context.xml

<?xml version="1.0" encoding="UTF-8"?>
<Context path="/ServletPlainText"/>

在 Tomcat context.xml文件中,我们定义了上下文路径。 它是 Web 应用的名称。

thermopylae.txt

The Battle of Thermopylae was fought between an alliance of Greek city-states, 
led by King Leonidas of Sparta, and the Persian Empire of Xerxes I over the 
course of three days, during the second Persian invasion of Greece. 

这是要从 Web 应用读取并发送到客户端的文本文件。

GetText.java

package com.zetcode.web;

import com.zetcode.util.ReadTextUtil;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name = "GetText", urlPatterns = {"/GetText"})
public class GetText extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("text/plain;charset=UTF-8");

        ServletOutputStream sout = response.getOutputStream();
        String content = ReadTextUtil.getContents();

        sout.print(content);
    }
}

这是GetText servlet。 它从位于资源目​​录中的文本文件中读取数据,并将文本以纯文本格式发送到客户端。

response.setContentType("text/plain;charset=UTF-8");

我们将响应对象的内容类型设置为text/plain

ServletOutputStream sout = response.getOutputStream();

我们得到了ServletOutputStream,用于将字符文本发送到客户端。

String content = ReadTextUtil.getContents();

我们将文本读入content变量。

sout.print(content);

文本内容被写入作者。

ReadTextUtil.java

package com.zetcode.util;

import com.google.common.base.Charsets;
import com.google.common.io.Files;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;

public class ReadTextUtil {

    public static String getContents()  {

        String data = null;
        String fileName = "thermopylae.txt";

        URL url = ReadTextUtil.class.getClassLoader().getResource(fileName);

        try {
            data = Files.toString(new File(url.toURI()), Charsets.UTF_8);
        } catch (IOException | URISyntaxException ex) {
            Logger.getLogger(ReadTextUtil.class.getName()).log(Level.SEVERE, null, ex);
        }

        return data;
    }
}

ReadTextUtil是用于读取文件内容的工具类。

URL url = ReadTextUtil.class.getClassLoader().getResource(fileName);

我们使用getResource()方法获取文件资源。

data = Files.toString(new File(url.toURI()), Charsets.UTF_8);

我们使用 Guava 的Files.toString()方法一次读取整个文件。

index.html

<!DOCTYPE html>
<html>
    <head>
        <title>Start Page</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
    </head>
    <body>
        <a href="GetText">Get text</a>
    </body>
</html>

这是主页。 它包含一个调用GetText servlet 的链接。

$ curl -I localhost:8084/ServletPlainText/GetText
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: text/plain;charset=UTF-8
Content-Length: 225
Date: Fri, 24 Nov 2017 15:21:57 GMT

我们使用curl命令获取响应的标题。 从服务器输出中,我们可以看到内容类型是文本。

Showing plain text in a browser

图:在浏览器中显示纯文本

该图显示了 Opera 浏览器中的文本。

在本教程中,我们从 Java servlet 发送了文本数据。

您可能也对以下相关教程感兴趣: Java servlet 教程Java servlet JSON 教程Java ServletConfig教程Java Servlet PDF 教程Java HttpServletMappingJava servlet 图像教程Java Servlet HTTP 标头Java 教程

Java Servlet JSON 教程

原文: http://zetcode.com/articles/javaservletjson/

Java servlet JSON 教程显示了如何从 Java servlet 返回 JSON 数据。 我们使用 Gson 库处理 JSON 数据格式。 该 Web 应用已部署在 Tomcat 服务器上。

Apache Tomcat 是由 Apache 软件基金会(ASF)开发的开源 Java Servlet 容器。 它是最流行的 Java Web 服务器。 Gson 是一个开放源代码 Java 库,用于将 Java 对象序列化和反序列化到 JSON 或从 JSON 反序列化。

Java Servlet

Servlet 是 Java 类,可响应特定类型的网络请求-最常见的是 HTTP 请求。 Java servlet 用于创建 Web 应用。 它们在 servlet 容器(例如 Tomcat 或 Jetty)中运行。 现代 Java Web 开发使用在 servlet 之上构建的框架。

JSON 格式

JSON(JavaScript 对象表示法)是一种轻量级的数据交换格式。 人类很容易读写,机器也很容易解析和生成。 JSON 的官方互联网媒体类型为application/json。 JSON 文件扩展名是.json

Java Servlet JSON 应用

以下 Web 应用使用 Java Servlet 将数据(城市列表)以 JSON 格式发送到客户端。

$ tree
.
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── zetcode
    │   │           ├── bean
    │   │           │   └── City.java
    │   │           ├── service
    │   │           │   └── CityService.java
    │   │           └── web
    │   │               └── GetCities.java
    │   └── webapp
    │       └── META-INF
    │           └── context.xml
    └── test
        └── java

这是项目结构。

pom.xml

<?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>ServletJson</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>ServletJson</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>4.0.0</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.8.2</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.6</version>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>

        </plugins>
    </build>
</project>

这是 Maven POM 文件。 我们有两个工件:用于 Java servlet 的javax.servlet-api和用于 Java JSON 处理的gsonmaven-war-plugin负责收集 Web 应用的所有工件依赖项,类和资源,并将它们打包到 Web 应用存档(WAR)中。

context.xml

<?xml version="1.0" encoding="UTF-8"?>
<Context path="/ServletJson"/>

在 Tomcat context.xml文件中,我们定义了上下文路径。 它是 Web 应用的名称。

City.java

package com.zetcode.bean;

import java.util.Objects;

public class City {

    private Long id;
    private String name;
    private int population;

    public City(Long id, String name, int population) {
        this.id = id;
        this.name = name;
        this.population = population;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getPopulation() {
        return population;
    }

    public void setPopulation(int population) {
        this.population = population;
    }

    @Override
    public int hashCode() {
        int hash = 3;
        hash = 97 * hash + Objects.hashCode(this.id);
        hash = 97 * hash + Objects.hashCode(this.name);
        hash = 97 * hash + this.population;
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final City other = (City) obj;
        if (this.population != other.population) {
            return false;
        }
        if (!Objects.equals(this.name, other.name)) {
            return false;
        }
        return Objects.equals(this.id, other.id);
    }
}

这是City bean。 它具有三个属性:id,名称和人口。

GetCities.java

package com.zetcode.web;

import com.zetcode.bean.City;
import com.zetcode.service.CityService;
import com.zetcode.util.JsonConverter;
import java.io.IOException;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name = "GetCities", urlPatterns = {"/GetCities"})
public class GetCities extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("application/json;charset=UTF-8");

        ServletOutputStream out = response.getOutputStream();

        List<City> cities = new CityService().getCities();

        JsonConverter converter = new JsonConverter();
        String output = converter.convertToJson(cities);

        out.print(output);
    }
}

这是GetCities servlet。 它从服务类检索数据,并将它们以 JSON 格式返回给客户端。

response.setContentType("application/json;charset=UTF-8");

我们将响应对象的内容类型设置为application/json

ServletOutputStream out = response.getOutputStream();

我们得到了ServletOutputStream,用于将数据发送到客户端。

List<City> cities = new CityService().getCities();

CityService中,我们可以获得城市列表。

JsonConverter converter = new JsonConverter();
String output = converter.convertToJson(cities);

我们使用JsonConverter将城市列表转换为 JSON 字符串。

out.print(output);

JSON 字符串被写入ServletOutputStream

ICityService.java

package com.zetcode.service;

import com.zetcode.bean.City;
import java.util.List;

public interface ICityService {

    public List<City> getCities();
}

ICityService包含getCities()合同方法。

CityService.java

package com.zetcode.service;

import com.zetcode.bean.City;
import com.zetcode.dao.CityDao;
import com.zetcode.dao.ICityDao;
import java.util.List;

public class CityService implements ICityService {

    ICityDao cityDao;

    public CityService() {

        cityDao = new CityDao();
    }

    @Override
    public List<City> getCities() {

        return cityDao.findAll();
    }
}

CityServicegetCities()方法返回城市对象的列表。 它使用 DAO 对象访问数据。

ICityDao.java

package com.zetcode.dao;

import com.zetcode.bean.City;
import java.util.List;

public interface ICityDao {

    public List<City> findAll();
}

ICityDao包含findAll()合同方法。

CityDao.java

package com.zetcode.dao;

import com.zetcode.bean.City;
import java.util.ArrayList;
import java.util.List;

public class CityDao implements ICityDao {

    @Override
    public List<City> findAll() {

        List<City> cities = new ArrayList<>();

        cities.add(new City(1L, "Bratislava", 432000));
        cities.add(new City(2L, "Budapest", 1759000));
        cities.add(new City(3L, "Prague", 1280000));
        cities.add(new City(4L, "Warsaw", 1748000));
        cities.add(new City(5L, "Los Angeles", 3971000));
        cities.add(new City(6L, "New York", 8550000));
        cities.add(new City(7L, "Edinburgh", 464000));
        cities.add(new City(8L, "Berlin", 3671000));

        return cities;        
    }
}

CityDaoICityDao的实现。 为简单起见,我们不连接数据库。 我们只返回一个城市对象的列表。

JsonConverter.java

package com.zetcode.util;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.zetcode.bean.City;
import java.util.List;

public class JsonConverter {

    private final Gson gson;

    public JsonConverter() {

        gson = new GsonBuilder().create();
    }

    public String convertToJson(List<City> cities) {

        JsonArray jarray = gson.toJsonTree(cities).getAsJsonArray();
        JsonObject jsonObject = new JsonObject();
        jsonObject.add("cities", jarray);

        return jsonObject.toString();
    }
}

JsonConverter将城市列表转换为 JSON 字符串。 我们使用 Gson 库。

index.html

<!DOCTYPE html>
<html>
    <head>
        <title>Home page</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
    </head>
    <body>
        <a href="GetCities">GetCities</a>
    </body>
</html>

主页包含一个调用 servlet 的链接。

使用 curl 创建请求

curl是使用支持的协议之一从服务器传输数据或向服务器传输数据的工具。

$ curl localhost:8084/ServletJson/GetCities
[{"id":1,"name":"Bratislava","population":432000},{"id":2,"name":"Budapest","population":1759000},
{"id":3,"name":"Prague","population":1280000},{"id":4,"name":"Warsaw","population":1748000},
{"id":5,"name":"Los Angeles","population":3971000},{"id":6,"name":"New York","population":8550000},
{"id":7,"name":"Edinburgh","population":464000},{"id":8,"name":"Berlin","population":3671000}]

这是输出。 使用curl命令,我们向GetCities Servlet 发出 HTTP GET 请求。

命名 JSON 数组

如果我们想命名返回的 JSON 数组,可以使用以下代码:

Gson gson = new GsonBuilder().create();
JsonArray jarray = gson.toJsonTree(cities).getAsJsonArray();
JsonObject jsonObject = new JsonObject();
jsonObject.add("cities", jarray);

out.print(jsonObject.toString());

在 Servlet 中,我们将 JSON 数组放入另一个 JSON 对象中,并将属性命名为cities

在本教程中,我们从 Java servlet 发送了 JSON 数据。

您可能也对以下相关教程感兴趣: Java Servlet RESTful 客户端Java Servlet 服务 XML 教程Java Servlet PDF 教程Java RequestDispatcher从 Java servlet 提供纯文本Java servlet 复选框教程Java servlet 图像教程Java Servlet HTTP 标头Java 教程

Java Servlet HTTP 标头

原文: http://zetcode.com/articles/javaservlethttpheaders/

在本教程中,我们讨论 HTTP 标头,并展示如何在 Java Servlet 和 JSP 文件中显示 HTTP 标头。

HTTP 标头字段是超文本传输​​协议(HTTP)中请求和响应消息的标头部分的组成部分。 它们定义 HTTP 事务的操作参数。

HTTP 标头允许客户端和服务器将附加信息与请求或响应一起传递。 它们用于各种任务,例如认证,cookie,缓存,连接管理或内容协商。

例如,User-Agent指定用户 aget(发出请求的客户端应用,例如浏览器),Date指定消息生成的日期和时间。

标头有几种类型:

  • 常规标头 - 适用于请求和响应,但与最终在正文中传输的数据无关。
  • 请求标头 - 包含有关要获取的资源或客户端本身的更多信息。
  • 响应标头 - 包含有关响应的其他信息,例如响应的位置或服务器本身(名称和版本等)。
  • 实体标头 - 包含有关实体主体的更多信息,例如其内容长度或 MIME 类型。

使用 Java Servlet 显示标头字段

在第一个示例中,我们在 servlet 中显示 HTTP 标头。

ShowHeaders.java

package com.zetcode.web;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
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 = "ShowHeaders", urlPatterns = {"/ShowHeaders"})
public class ShowHeaders extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        try (PrintWriter out = response.getWriter()) {

            response.setContentType("text/html");
            out.println("<!DOCTYPE html>");
            out.println("<html lang=\"en\">");
            out.println("<head>");
            out.println("<title>HTTP headers</title>"); 
            out.println("<body>"); 
            out.println("<p>Headers</p>");

            Enumeration<String> headerNames = request.getHeaderNames();

            out.println("<ol>");
            while (headerNames.hasMoreElements()) {
                out.print("<li>");
                String headerName = headerNames.nextElement();
                out.print(headerName + " = ");
                String headerValue = request.getHeader(headerName);
                out.print(headerValue);
                out.println("</li>");
            }
            out.println("</ol>");

            out.println("</body>");
            out.println("</html>");
        }
    }
}

ShowHeaders servlet 找出客户端发送的 HTTP 标头,并将它们发送回 HTML 文件中。

PrintWriter out = response.getWriter()

我们直接写到PrintWriter。 请注意,虽然可以直接写,但现代 Java Web 应用使用 Thymeleaf,FreeMarker 或 JSP 之类的模板来创建 HTML 页面。

response.setContentType("text/html");

响应的内容类型设置为text/html

Enumeration<String> headerNames = request.getHeaderNames();

我们使用getHeaderNames()方法获得标题名称。 它返回字符串的枚举。

String headerName = headerNames.nextElement();

我们使用nextElement()方法从枚举中获取下一个标头名称。

String headerValue = request.getHeader(headerName);

使用getHeader(),我们获得标头值。

在 JSP 文件中显示标头字段

在第二个示例中,我们在 JSP 文件中显示 HTTP 标头。 我们还使用 JSTL 库。

showHeaders.jsp

<%@ taglib prefix='c' uri='http://java.sun.com/jsp/jstl/core' %>
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>HTTP headers</title>
  </head>
  <body>
    <p>HTTP headers:</p>
    <ol>
      <c:forEach var="nextHeader" items="${header}">
          <li><c:out value="${nextHeader.key}" /> = <c:out value="${nextHeader.value}" /></li>
      </c:forEach>
    </ol>
  </body>
</html>

JSP 文件具有header隐式对象,该对象是标头名称及其值的映射。

<c:forEach var="nextHeader" items="${header}">
    <li><c:out value="${nextHeader.key}" /> = <c:out value="${nextHeader.value}" /></li>
</c:forEach>

使用 JSTL 的forEach标记,我们遍历映射并显示标头名称及其值。

在本教程中,我们使用了 HTTP 标头字段。

您可能也对以下相关教程感兴趣: Java RequestDispatcherJava servlet 复选框教程Java servlet 图像教程Servlet FreeMarker JdbcTemplate教程Spring Boot 中的服务图像文件Java 教程jQuery DatePicker教程Stripes 教程

Java Servlet 复选框教程

原文: http://zetcode.com/articles/javaservletcheckbox/

在本教程中,我们创建一个经典的 Web 应用,该应用从 HTML 复选框中读取一个值。 表单值通过过滤器类进行验证。 使用 FreeMarker 模板创建视图。 该 Web 应用是使用 Java Servlet 创建的,并部署在 Tomcat 服务器上。

Servlet 是 Java 类,可响应特定类型的网络请求-最常见的是 HTTP 请求。 Servlet 用于实现 Web 应用。 它们在 Tomcat 或 Jetty 之类的 servlet 容器中运行。 在现代 Java Web 开发中,程序员使用在 Servlet 之上构建的框架。

Java 过滤器是一个对象,它对对资源(servlet 或静态内容)的请求,或对资源的响应,或两者都执行过滤任务。 它用于执行认证,审核,日志记录,数据加密或数据验证之类的任务。

FreeMarker 是 Java 编程语言的模板引擎。 模板以 FreeMarker 模板语言(FTL)编写。 在 Web 应用中使用模板来创建 UI。

Apache Tomcat 是由 Apache 软件基金会(ASF)开发的开源 Java Servlet 容器。 它是最受欢迎的 Java Web 服务器。

Bootstrap 是 HTML,CSS 和 JS 框架,用于在 Web 上开发响应式,移动优先项目。 它包含用于印刷,表单,按钮,导航和其他界面组件的 HTML 和 CSS 设计模板,以及可选的 JavaScript 扩展。

应用

以下 Web 应用具有一个简单的 Web 表单,该表单包含一个复选框和一个输入文本。 值将发送到 Web 应用的控制器,该控制器是 Java servlet。 在请求到达控制器之前,将在 Java 过滤器中验证这些值。 最后,这些值显示在 HTML 文件中,该文件是用 FreeMarker 模板构建的。 FreeMarker 将 HTML 与数据结合在一起。

pom.xml

<?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命令显示项目目录结构。

web.xml

<?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/

context.xml

<?xml version="1.0" encoding="UTF-8"?>
<Context path="/FormCheckBox"/>

context.xml文件是 Tomcat 的配置文件。 在文件内部,我们设置上下文路径(应用名称)。 该文件位于META-INF子目录中。

index.html

<!DOCTYPE html>
<html>
    <head>
        <title>Check box</title>
        <link href="https://maxcdn.bootstrapcdn.com/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标记定义了一个动作参数,该参数在控制器 Servlet 中使用。

FormFilter.java

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。

MyController.java

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 页面。

show.ftl

<!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模板。 两个属性传递给模板:adultname。 FreeMarker 使用${}语法来获取请求属性的值。

<#if adult??>

使用#if指令,我们检查adult属性是否已设置。 ??判断左侧操作数的值是否丢失。

<p>${name!"Guest"} is adult</p>

缺少值时,!用于提供默认值。 (请记住,我们没有为空或null的参数设置属性。)如果设置了name变量,则会显示它;否则,将显示它。 否则,显示"Guest"

unknown.ftl

<!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 模板进行显示。

您可能也对以下相关教程感兴趣: Java RequestDispatcherJava Servlet 图像教程Servlet FreeMarker JdbcTemplate教程在 SpringBoot 中提供图像文件Java 教程jQuery DatePicker教程Stripes 教程

Java servlet 发送图像教程

原文: http://zetcode.com/articles/javaservletimage/

在 Java servlet 发送图像教程中,我们使用 servlet 在 Java 中创建经典的 Web 应用。 Servlet 将图像发送到客户端。 Web 应用已部署在 Jetty 服务器上。

Java Servlet

Servlet 是 Java 类,可响应特定类型的网络请求-最常见的是 HTTP 请求。 Servlet 用于实现 Web 应用。 它们在 Tomcat 或 Jetty 之类的 servlet 容器中运行。 在现代 Java Web 开发中,程序员使用在 Servlet 之上构建的框架。

Eclipse Jetty 是 Java HTTP 服务器和 Java Servlet 容器。 Jetty 可以轻松地嵌入到设备,工具,框架,应用服务器和群集中。

Java servlet 图像示例

以下 Web 应用将图像发送到客户端。 该 Web 应用使用 Java Servlet。

pom.xml

<?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>sendimageservlet</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>12</maven.compiler.source>
        <maven.compiler.target>12</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>

    </dependencies>

    <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.2</version>
            </plugin>

            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>9.4.14.v20181114</version>
            </plugin>
        </plugins>
    </build>

</project>

javax.servlet-api依赖项是用于构建 Java Servlet 的库。 maven-war-plugin收集 Web 应用的所有工件依赖项,类和资源,并将它们打包到 Web 应用存档(WAR)中。 jetty-maven-plugin插件对于使用 Jetty 服务器进行快速开发和测试非常有用。

pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │               SendImageServlet.java
│   ├───resources
│   └───webapp
│       │   index.html
│       └───images
│               sid.jpg
└───test
    └───java

这是项目目录结构。

webapp/index.html

<!DOCTYPE html>
<html>
    <head>
        <title>Servlet image</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
    </head>
    <body>
        <a href="image">Get image</a>
    </body>
</html>

index.html文件是我们应用的主页。 它具有一个链接,该链接调用一个 servlet 来管理图像文件。

com/zetcode/SendImageServlet.java

package com.zetcode;

import javax.servlet.ServletContext;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

@WebServlet(name = "SendImageServlet", urlPatterns = {"/image"})
public class SendImageServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws IOException {

        ServletContext sc = getServletContext();

        try (InputStream is = sc.getResourceAsStream(&quoimg/sid.jpg")) {

            // it is the responsibility of the container to close output stream
            OutputStream os = response.getOutputStream();

            if (is == null) {

                response.setContentType("text/plain");
                os.write("Failed to send image".getBytes());
            } else {

                byte[] buffer = new byte[1024];
                int bytesRead;

                response.setContentType("image/png");

                while ((bytesRead = is.read(buffer)) != -1) {

                    os.write(buffer, 0, bytesRead);
                }
            }
        }
    }
}

SendImageServlet Servlet 将图像文件返回给客户端。

@WebServlet(name = "SendImageServlet", urlPatterns = {"/image"})

@WebServlet批注将具有image URL 模式的请求映射到SendImageServlet servlet。

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws IOException {

该请求是一个 GET 请求,因此我们以doGet()方法为其提供服务。

ServletContext sc = getServletContext();

我们得到ServletContext,其中包含 servlet 用于与其 servlet 容器进行通信的一组方法,例如,获取文件的 MIME 类型,调度请求或写入日志文件。

try (InputStream is = sc.getResourceAsStream(&quoimg/sid.jpg")) {

我们使用getResourceAsStream()获得图像资源流。

OutputStream os = response.getOutputStream();

我们得到 servlet 输出流。 我们将图像数据写入此流。 容器负责关闭 servlet 输出流。

if (is == null) {

    response.setContentType("text/plain");
    os.write("Failed to send image".getBytes());
} else {

如果无法打开图像输入流,则会将错误消息发送回客户端。

response.setContentType("image/png");

图片为 PNG 格式; 因此,我们将响应的内容类型设置为image/png

byte[] buffer = new byte[1024];
int bytesRead;

response.setContentType("image/png");

while ((bytesRead = is.read(buffer)) != -1) {

    os.write(buffer, 0, bytesRead);
}

如果成功打开了图像输入流,我们将读取数据并将其写入 servlet 输出流。 我们将响应内容类型设置为image/png

$ mvn jetty:run

我们运行 Jetty 服务器并导航到localhost:8080

在 Java servlet 发送图像教程中,我们使用了 Java servlet 将图像发送到客户端。

您可能也对以下相关教程感兴趣: Java Servlet 复选框教程Java Servlet PDF 教程Java Servlet 图表教程Servlet FreeMarker JdbcTemplate教程在 Spring Boot 中提供图像文件Java 教程jQuery DatePicker教程

列出 Java Servlet 教程

Java Servlet JQuery 列表教程

原文: http://zetcode.com/articles/javaservletjquerylist/

在 Java Servlet JQuery 列表教程中,我们展示了如何使用 JQuery 从 Java servlet 中获取数据并将其显示在 HTML 列表中。 我们使用 Gson 库处理 JSON 数据格式。 该 Web 应用已部署在 Tomcat 服务器上。

Apache Tomcat 是由 Apache 软件基金会(ASF)开发的开源 Java Servlet 容器。 它是最流行的 Java Web 服务器。

Java Servlet

Servlet 是 Java 类,可响应特定类型的网络请求-最常见的是 HTTP 请求。 Java servlet 用于创建 Web 应用。 它们在 servlet 容器(例如 Tomcat 或 Jetty)中运行。 现代 Java Web 开发使用在 servlet 之上构建的框架。

JSON 格式

JSON(JavaScript 对象表示法)是一种轻量级的数据交换格式。 人类很容易读写,机器也很容易解析和生成。 与 XML 相比,它不那么冗长且更具可读性。 JSON 的官方 Internet 媒体类型为application/json。 JSON 文件扩展名是.json。 JSON 可直接由 JavaScript 使用。

Gson

Gson 是一个开放源代码 Java 库,用于将 Java 对象序列化和反序列化到 JSON 或从 JSON 反序列化。 Gson 由 Google 创建。

Java servlet JQuery 列表示例

以下 Web 应用使用 Java Servlet 将数据(城市列表)以 JSON 格式发送到客户端。 JQuery 用于执行请求并动态构建 HTML 列表。

├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── zetcode
    │   │           ├── bean
    │   │           │   └── City.java
    │   │           ├── service
    │   │           │   └── CityService.java
    │   │           └── web
    │   │               └── GetCities.java
    │   ├── resources
    │   └── webapp
    │       ├── index.html
    │       ├── META-INF
    │       │   └── context.xml
    │       └── WEB-INF
    └── test
        └── java

这是项目结构。

pom.xml

<?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>JavaServleJqueryList</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>JavaServleJqueryList</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>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.8.0</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>

这是 Maven POM 文件。 我们有两个工件:用于 Java servlet 的javax.servlet-api和用于 Java JSON 处理的gsonmaven-war-plugin负责收集 Web 应用的所有工件依赖项,类和资源,并将它们打包到 Web 应用存档(WAR)中。

context.xml

<?xml version="1.0" encoding="UTF-8"?>
<Context path="/JavaServleJqueryList"/>

在 Tomcat context.xml文件中,我们定义了上下文路径。 它是 Web 应用的名称。

City.java

package com.zetcode.bean;

import com.google.gson.annotations.Expose;

public class City {

    private Long id;

    @Expose
    private String name;
    @Expose
    private int population;

    public City() {
    }

    public City(Long id, String name, int population) {
        this.id = id;
        this.name = name;
        this.population = population;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getPopulation() {
        return population;
    }

    public void setPopulation(int population) {
        this.population = population;
    }

    @Override
    public String toString() {
        return "City{" + "id=" + id + ", name=" + name + 
                ", population=" + population + '}';
    }
}

这是City bean。 它具有三个属性:id,名称和人口。 Gson 的@Expose批注指示应公开哪些成员以进行 JSON 序列化或反序列化。 在我们的例子中,我们忽略了 ID,因为它与客户无关。 这样我们可以节省一些带宽。

GetCities.java

package com.zetcode.web;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.zetcode.bean.City;
import com.zetcode.service.CityService;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
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 = "GetCities", urlPatterns = {"/GetCities"})
public class GetCities extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("application/json;charset=UTF-8");

        try (PrintWriter out = response.getWriter()) {

            List<City> cities = CityService.getCities();

            Gson gson = new GsonBuilder()
                    .excludeFieldsWithoutExposeAnnotation()
                    .create();

            out.print(gson.toJson(cities));
        }
    }
}

这是GetCities servlet。 它从服务类检索数据,并将它们以 JSON 格式返回给客户端。

response.setContentType("application/json;charset=UTF-8");

我们将响应对象的内容类型设置为application/json

try (PrintWriter out = response.getWriter()) {

我们得到了PrintWriter,用于将字符文本发送到客户端。

List<City> cities = CityService.getCities();

CityService中,我们可以获得城市列表。

Gson gson = new GsonBuilder()
        .excludeFieldsWithoutExposeAnnotation()
        .create();

我们创建并配置Gson类,这是使用 Gson 的主要类。 excludeFieldsWithoutExposeAnnotation()启用@Expose批注。

out.print(gson.toJson(cities));

使用toJson()方法,我们将 Java 列表转换为 JSON 数组。 数组被写入编写器。 数组未命名。

CityService.java

package com.zetcode.service;

import com.zetcode.bean.City;
import java.util.ArrayList;
import java.util.List;

public class CityService {

    public static List<City> getCities() {

        List<City> cities = new ArrayList<>();

        cities.add(new City(1L, "Bratislava", 432000));
        cities.add(new City(2L, "Budapest", 1759000));
        cities.add(new City(3L, "Prague", 1280000));
        cities.add(new City(4L, "Warsaw", 1748000));
        cities.add(new City(5L, "Los Angeles", 3971000));
        cities.add(new City(6L, "New York", 8550000));
        cities.add(new City(7L, "Edinburgh", 464000));
        cities.add(new City(8L, "Berlin", 3671000));

        return cities;
    }
}

CityServicegetCities()方法返回城市对象的列表。

index.html

<!DOCTYPE html>
<html>
    <head>
        <title>Start Page</title>
        <meta charset="UTF-8">
        <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script> 
    </head>
    <body>

        <button id="mybtn">Get cities</button>

        <div>
            <ul id="output">

            </ul>
        </div>

        <script>
            $('#mybtn').click(function () {

                $.getJSON('GetCities', function (data) {

                    $("ul#output > li").remove();

                    $.each(data, function (key, value) {
                        $("#output").append('<li>' + value['name'] + " " + value['population'] + '</li>');
                    });
                });
            });
        </script>
    </body>
</html>

这是主页。

<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script> 

我们包括 JQuery 库。

<button id="mybtn">Get cities</button>

该按钮执行请求。

<div>
    <ul id="output">

    </ul>
</div>

返回的数据将被写入这些元素内。

$('#mybtn').click(function () {

    $.getJSON('GetCities', function (data) {

        $("ul#output > li").remove();

        $.each(data, function (key, value) {
            $("#output").append('<li>' + value['name'] + " " + value['population'] + '</li>');
        });
    });
});

我们为按钮添加一个点击事件处理器。 $.getJSON()方法使用 GET HTTP 请求从GetCities Servlet 加载 JSON 编码的数据。 使用remove()方法,我们删除以前的元素(如果存在)。 使用$.each(),我们遍历 JSON 数据并将其附加到<li>标签内部的输出中。

Java Servlet JQuery list example

图:Java Servlet JQuery 列表示例

在图中,我们可以看到 HTML 列表中的数据:城市及其人口。

在本教程中,我们使用了 JQuery 从 Java servlet 获取 JSON 数据并构建 HTML 列表。

您可能也对以下相关教程感兴趣: Gson 教程Java servlet JSON 教程从 Java Servlet 提供纯文本Java servlet 复选框教程Java servlet 图像教程Java Servlet HTTP 标头Java 教程

Servlet FreeMarker JdbcTemplate教程 - CRUD 操作

原文: http://zetcode.com/articles/servletfreemarker/

在本教程中,我们将创建一个具有基本 CRUD 操作的简单 Java Web 应用。 我们使用 FreeMarker 模板引擎,Servlet 技术和JdbcTemplate库。 MySQL 用于存储数据。 该应用最终部署在 Tomcat 服务器上。

该教程的资源可从作者的 Github 存储库中获得。

CRUD(创建,读取,更新和删除)是持久性存储的四个基本功能。 对于关系数据库,它们等效于INSERTSELECTUPDATEDELETE语句。

FreeMarker 是 Java 编程语言的流行模板引擎。 模板以 FreeMarker 模板语言(FTL)编写。 模板引擎将静态数据与动态数据结合起来以生成内容。 模板是内容的中间表示。 它指定如何产生输出。

JDBCTemplate是用于简化 JDBC 编程的 Spring 库。 它处理乏味且容易出错的底层细节,例如处理事务,清理资源以及正确处理异常。 它包含在 Spring 的 spring-jdbc 模块中。

管理用户

我们的应用将管理用户。 它允许添加新用户,对其进行修改,删除它并列出所有可用用户。

mysql> CREATE TABLE Users(Id INTEGER PRIMARY KEY AUTO_INCREMENT, 
                          Firstname TEXT, Lastname TEXT, Email TEXT);

我们在 MySQL testdb数据库中创建Users表。

Excerpt from pom.xml

<dependencies>
    <dependency>
        <groupId>javax</groupId>
        <artifactId>javaee-web-api</artifactId>
        <version>7.0</version>
        <scope>provided</scope>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>4.2.6.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>6.0.2</version>
    </dependency>        

    <dependency>
        <groupId>org.freemarker</groupId>
        <artifactId>freemarker</artifactId>
        <version>2.3.25-incubating</version>
    </dependency>                        

</dependencies>

在 Maven pom.xml文件中,我们提供四个依赖项:javaee-web-api是用于开发 Java Web 应用的一组库,spring-jdbc模块包含 JDBCTemplate 库,mysql-connector-java是 MySQL Java 驱动程序,而freemarker是 FreeMarker 库。

context.xml

<?xml version="1.0" encoding="UTF-8"?>
<Context path="/ServletFreemarkerEx">

    <Resource name="jdbc/testdb" 
              auth="Container"
              type="javax.sql.DataSource" 
              username="user7" 
              password="s$cret"              
              driverClassName="com.mysql.jdbc.Driver"
              url="jdbc:mysql://localhost:3306/testdb"
              maxActive="10" 
              maxIdle="4"/>

</Context>

context.xml文件中,我们定义了应用上下文路径(其名称)和一个 MySQL 数据源。

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">

    <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文件中,我们设置了FreemarkerServlet,该文件用于处理 FreeMarker .ftl文件。

User.java

package com.zetcode.bean;

public class User {

    private Long id;
    private String firstName;
    private String lastName;
    private String email;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getEmail() {
        return email;
    }

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

我们有一个User bean,其中包含四个属性:idfirstNamelastNameemail

ServiceLocator.java

package com.zetcode.util;

import java.util.logging.Level;
import java.util.logging.Logger;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

public class ServiceLocator {

    public static DataSource getDataSource(String jndiName) {

        Context ctx = null;
        DataSource ds = null;

        try {
            ctx = new InitialContext();
            ds = (DataSource) ctx.lookup(jndiName);
        } catch (NamingException ex) {
            Logger.getLogger(ServiceLocator.class.getName()).log(
                Level.SEVERE, null, ex);
        }

        return ds;
    }
}

ServiceLocator包含用于查找数据源的代码。 它使用 JNDI API 来完成这项工作。

DatabaseService.java

package com.zetcode.service;

import com.zetcode.bean.User;
import com.zetcode.util.ServiceLocator;
import java.util.List;
import javax.sql.DataSource;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;

public class DatabaseService {

    public static User getUserById(Long id) {

        String sql = "SELECT * FROM Users WHERE Id = ?";

        JdbcTemplate jtm = getJDBCTempate();
        User user = (User) jtm.queryForObject(sql, new Object[]{id},
                new BeanPropertyRowMapper(User.class));

        return user;
    }

    public static void addUser(User user) {

        String sql = "INSERT INTO Users(Firstname, Lastname, Email) VALUES(?, ?, ?)";

        JdbcTemplate jtm = getJDBCTempate();
        jtm.update(sql, new Object[] {user.getFirstName(), 
            user.getLastName(), user.getEmail()});
    }

    public static void deleteUser(Long id) {

        String sql = "DELETE From Users WHERE Id = ?";

        JdbcTemplate jtm = getJDBCTempate();
        jtm.update(sql, new Object[] {id});
    }

    public static void updateUser(User user) {

        String sql = "UPDATE Users SET Firstname=?, Lastname=?, Email=? WHERE Id=?";

        JdbcTemplate jtm = getJDBCTempate();
        jtm.update(sql, new Object[] {user.getFirstName(), 
            user.getLastName(), user.getEmail(), user.getId()});

    }

    public static List<User> getAllUsers() {

        String sql = "SELECT * FROM Users";

        JdbcTemplate jtm = getJDBCTempate();

        List<User> users = (List<User>) jtm.query(sql,
                new BeanPropertyRowMapper(User.class));

        return users;
    }

    private static JdbcTemplate getJDBCTempate() {

        DataSource ds = ServiceLocator.getDataSource("java:comp/env/jdbc/testdb");
        JdbcTemplate jtm = new JdbcTemplate(ds);

        return jtm;
    }
}

DatabaseService中,我们有利用JDBCTemplate库执行数据库操作的方法。

public static User getUserById(Long id) {

    String sql = "SELECT * FROM Users WHERE Id = ?";

    JdbcTemplate jtm = getJDBCTempate();
    User user = (User) jtm.queryForObject(sql, new Object[]{id},
            new BeanPropertyRowMapper(User.class));

    return user;
}

getUserById()方法返回由其 ID 标识的用户。 queryForObject()运行指定的 SQL 语句并返回一个对象。 BeanPropertyRowMapper将返回的行转换为目标类(用户)。

public static List<User> getAllUsers() {

    String sql = "SELECT * FROM Users";

    JdbcTemplate jtm = getJDBCTempate();

    List<User> users = (List<User>) jtm.query(sql,
            new BeanPropertyRowMapper(User.class));

    return users;
}

getAllUsers()方法返回表中的所有用户。 query()方法返回类型列表。

MyController.java

package com.zetcode.web;

import com.zetcode.bean.User;
import com.zetcode.service.DatabaseService;
import java.io.IOException;
import java.util.List;
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 ADD_USER_VIEW = "addUser.ftl";
    private static final String UPDATE_USER_VIEW = "updateUser.ftl";
    private static final String LIST_USERS_VIEW = "listUsers.ftl";

    private static final String USER_ADDED_VIEW = "userAdded.html";
    private static final String USER_DELETED_VIEW = "userDeleted.html";
    private static final String USER_MODIFIED_VIEW = "userUpdated.html";

    private static final String DELETE_ACTION = "deleteUser";
    private static final String ADD_ACTION = "addUser";
    private static final String UPDATE_ACTION = "updateUser";
    private static final String LIST_ACTION = "listUsers";

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("text/html;charset=UTF-8");

        String path = "";

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

        if (DELETE_ACTION.equals(action)) {
            Long userId = Long.parseLong(request.getParameter("userId"));
            DatabaseService.deleteUser(userId);

            path = USER_DELETED_VIEW;
        } else if (ADD_ACTION.equals(action)) {

            path = ADD_USER_VIEW;

        } else if (UPDATE_ACTION.equals(action)) {

            Long userId = Long.parseLong(request.getParameter("userId"));
            User user = DatabaseService.getUserById(userId);
            request.setAttribute("user", user);
            path = UPDATE_USER_VIEW;

        } else if (LIST_ACTION.equals(action)) {

            List<User> users = DatabaseService.getAllUsers();
            request.setAttribute("users", users);
            path = LIST_USERS_VIEW;
        }

        RequestDispatcher dispatcher = request.getRequestDispatcher(path);
        dispatcher.forward(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        String path = "";

        response.setContentType("text/html;charset=UTF-8");

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

        if (ADD_ACTION.equals(action)) {

            User user = new User();
            user.setFirstName(request.getParameter("firstName"));
            user.setLastName(request.getParameter("lastName"));
            user.setEmail(request.getParameter("email"));

            DatabaseService.addUser(user);
            path = USER_ADDED_VIEW;

        } else if (UPDATE_ACTION.equals(action)) {

            User user = new User();
            user.setId(Long.parseLong(request.getParameter("id")));
            user.setFirstName(request.getParameter("firstName"));
            user.setLastName(request.getParameter("lastName"));
            user.setEmail(request.getParameter("email"));

            DatabaseService.updateUser(user);
            path = USER_MODIFIED_VIEW;
        }

        response.sendRedirect(path);
    }
}

MyController是一个控制器类,用于管理传入的请求并委托给特定的服务方法。 我们有两种方法:doGet()处理 HTTP GET 请求,doPost()处理 HTTP POST 请求。

private static final String ADD_USER_VIEW = "addUser.ftl";
private static final String UPDATE_USER_VIEW = "updateUser.ftl";
private static final String LIST_USERS_VIEW = "listUsers.ftl";

这是三个 FreeMarker 模板视图。

private static final String USER_ADDED_VIEW = "userAdded.html";
private static final String USER_DELETED_VIEW = "userDeleted.html";
private static final String USER_MODIFIED_VIEW = "userUpdated.html";

在这里,我们有三个 HTML 视图。 它们用于确认我们的任务。

private static final String DELETE_ACTION = "deleteUser";
private static final String ADD_ACTION = "addUser";
private static final String UPDATE_ACTION = "updateUser";
private static final String LIST_ACTION = "listUsers";

我们有四个不同的操作:删除用户,添加新用户,更新用户以及列出所有用户。

if (DELETE_ACTION.equals(action)) {
    Long userId = Long.parseLong(request.getParameter("userId"));
    DatabaseService.deleteUser(userId);

    path = USER_DELETED_VIEW;
}

收到删除操作后,我们从请求中找到 ID,然后调用DatabaseServicedeleteUser()方法。 然后选择一个视图。

} else if (UPDATE_ACTION.equals(action)) {

    Long userId = Long.parseLong(request.getParameter("userId"));
    User user = DatabaseService.getUserById(userId);
    request.setAttribute("user", user);
    path = UPDATE_USER_VIEW;

}

当我们单击更新链接时,将执行此代码。 从数据库中检索用户,并将User对象添加到请求对象。 UPDATE_USER_VIEW将应用转发到模板文件,该文件具有用于更新用户的形式。 提交表单后,将 POST 请求发送到控制器,并执行其doPost()方法。

} else if (LIST_ACTION.equals(action)) {

    List<User> users = DatabaseService.getAllUsers();
    request.setAttribute("users", users);
    path = LIST_USERS_VIEW;
}

在这里,我们检索所有用户并将用户列表设置为请求对象。 我们选择LIST_USERS_VIEW视图。

response.sendRedirect(path);

遵循发布/重定向/获取模式,我们将重定向到doPost()方法中的视图。 这样可以防止提交多个表单。 (例如,我们可能不小心多次添加了一个用户)。

addUser.ftl

<!DOCTYPE html>
<html>
    <head>
        <title>Add new user</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        </head>
    <body>

        <form action="MyController?action=addUser" method="post"> 

            <label for="fname">First name:</label>
            <input id="fname" type="text" name="firstName">
            <br>

            <label for="lname">Last name:</label>
            <input id="lname" type="text" name="lastName">
            <br>

            <label for="email">Email:</label>
            <input id="email" type="text" name="email">            
            <br>

            <button type="submit">Submit</button>

        </form>

    </body>
</html>

addUser.ftl是一个模板文件,其中包含用于添加新用户的表单。

<form action="MyController?action=addUser" method="post"> 

该表单调用MyController servlet,并将action参数设置为addUser

updateUser.ftl

<!DOCTYPE html>
<html>
    <head>
        <title>Update user</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <style>
            input[readonly] {
                background-color:lightGray;
            }
        </style>
        </head>
    <body>

        <form action="MyController?action=updateUser" method="post"> 

            <label for="id">Id:</label>
            <input id="id" type="text" name="id" readonly value="${user.id}">
            <br>                

            <label for="fname">First name:</label>
            <input id="fname" type="text" name="firstName" value="${user.firstName}">
            <br>

            <label for="lname">Last name:</label>
            <input id="lname" type="text" name="lastName" value="${user.lastName}">
            <br>

            <label for="email">Email:</label>
            <input id="email" type="text" name="email" value="${user.email}">            
            <br>

            <button type="submit">Submit</button>

        </form>

    </body>
</html>

addUser.ftl模板文件包含用于更新特定用户的表单。

<style>
    input[readonly] {
        background-color:lightGray;
    }
</style>

这种 CSS 样式将浅色的只读输入标签的背景绘制为灰色。

<label for="id">Id:</label>
<input id="id" type="text" name="id" readonly value="${user.id}">
<br>   

ID 是一个只读参数。 ${user.id}是一个 FreeMarker 插值,可解析为用户 ID。 在到达updateUser.ftl文件之前,该请求获得一个将要修改的用户对象。

listUsers.ftl

<!DOCTYPE html>
<html>
    <head>
        <title>List users</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        </head>
    <body>
        <table>
            <thead>
                <tr>
                    <th>User Id</th>
                    <th>First Name</th>
                    <th>Last Name</th>
                    <th>Email</th>
                    <th colspan="2">Action</th>
                </tr>
            </thead>
            <tbody>
                <#list users as user>
                    <tr>
                        <td>${user.id}</td>
                        <td>${user.firstName}</td>
                        <td>${user.lastName}</td>
                        <td>${user.email}</td>
                        <td><a href="MyController?action=updateUser&userId=${user.id}">Update</a></td>
                        <td><a href="MyController?action=deleteUser&userId=${user.id}">Delete</a></td>
                    </tr>
                </#list>
            </tbody>
        </table>

        <p>
            <a href="MyController?action=addUser">Add new user</a>
        </p>
    </body>
</html>

listUsers.ftl模板文件列出了Users数据库表中的所有用户。

<#list users as user>

FreeMarker #list指令遍历users集合的所有元素。

<td>${user.id}</td>
<td>${user.firstName}</td>
<td>${user.lastName}</td>
<td>${user.email}</td>

这些 FreeMarker 插值显示用户数据。

<td><a href="MyController?action=updateUser&userId=${user.id}">Update</a></td>  

该链接将更新操作发送到应用控制器; 它还发送要修改的用户的 ID。

<td><a href="MyController?action=deleteUser&userId=${user.id}">Delete</a></td>  

该链接将删除操作发送到应用控制器。 它还发送要删除的用户的 ID。

<a href="MyController?action=addUser">Add new user</a>  

该链接将添加用户操作发送到控制器。

index.html

<!DOCTYPE html>
<html>
    <head>
        <title>Main page</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
    </head>
    <body>
        <a href="MyController?action=listUsers">List all users</a>
    </body>
</html>

这是一个带有链接的主页,该链接将列表用户的操作发送到控制器。

userAdded.html

<!DOCTYPE html>
<html>
    <head>
        <title>User added</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
    </head>
    <body>
        <p>
            New user has been added successfully. 
            <a href="MyController?action=listUsers">List all users</a>
        </p>
    </body>
</html>

该视图通知用户已成功添加到数据库表中。

userDeleted.html

<!DOCTYPE html>
<html>
    <head>
        <title>User deleted</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
    </head>
    <body>
        <p>
            User has been successfully deleted.
            <a href="MyController?action=listUsers">List all users</a>
        </p>
    </body>
</html>

此视图通知用户删除。

userUpdated.html

<!DOCTYPE html>
<html>
    <head>
        <title>User modified</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
    </head>
    <body>
        <p>
            User has been modified successfully. 
            <a href="MyController?action=listUsers">List all users</a>
        </p>
    </body>
</html>

该视图通知用户的修改。

Users web application

图:用户 Web 应用

在上面的屏幕截图中,我们可以看到用户列表。 该应用部署在 NetBeans 内置的 Tomcat 服务器上,该服务器正在监听端口 8084。

在本教程中,我们创建了一个执行 CRUD 操作的 Java Web 应用。 它使用了 FreeMarker,Servlet 和JDBCTemplate。 您可能也对相关教程感兴趣: JdbcTemplate教程FreeMarker 教程Java 教程游戏入门Spark 简介Strips 简介

jQuery 自动补全教程

原文: http://zetcode.com/articles/jqueryautocomplete/

在 jQuery 自动补全教程中,我们展示了如何使用 jQuery 自动补全组件。 自动补全组件显示来自 Java servlet 的过滤数据。 作者的 Github 信息库中提供了本教程的源代码。

jQuery 是一个快速,小型且功能丰富的 JavaScript 库。 通过易于使用的 API(可在多种浏览器中使用),它使 HTML 文档的遍历和操作,事件处理,动画和 Ajax 变得更加简单。 jQuery UI 是在 jQuery 库顶部构建的一组用户界面小部件,效果,交互作用和主题。

AutocompletejQuery UI库的 UI 小部件之一。 当我们键入该字段时,它会提供建议。

JSON(JavaScript 对象表示法)是一种轻量级的数据交换格式。 人类很容易读写,机器也很容易解析和生成。 JSON 的官方互联网媒体类型为application/json。 JSON 文件扩展名是.json。 Java 中有许多库可以处理 JSON 数据格式; 其中一位是 Jackson。

jQuery 自动补全示例

在下面的示例中,我们使用Autocomplete组件选择一个错误名称。 错误名称存储在服务器上的 CSV 文件中。 选定的错误名称将发送并显示在 JSP 页面中。

pom.xml

<?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>AutocompleteEx</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>AutocompleteEx</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>4.0.0</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.9.2</version>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.2</version>
        </dependency>

        <dependency>
            <groupId>com.opencsv</groupId>
            <artifactId>opencsv</artifactId>
            <version>4.0</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 的支持。 com.fasterxml.jackson.corejackson-databind是用于处理 JSON 文件的 Jackson JAR。 opencsv用于处理 CSV 文件。

index.html

<!DOCTYPE html>
<html>
    <head>
        <title>jQuery UI Autocomplete</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <style>
            .ui-autocomplete-loading {
                background: white url("img/anim_16x16.gif") right center no-repeat;
            }
        </style>
        <link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">

        <script src="https://code.jquery.com/jquery-1.12.4.js"></script>
        <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
        <script>
            $(function () {

                $("#bugs").autocomplete({
                    source: "Bugs",
                    minLength: 1,
                });
            });
        </script>
    </head>
    <body>

        <form action="showBug.jsp">

            <div class="ui-widget">
                <label for="bugs">Bugs:</label>
                <input id="bugs" name="bug">
            </div>
            <br>
            <div>
                <input class="ui-widget" type="submit" value="Submit">
            </div>

        </form>

    </body>
</html>

index.html文件中,我们在表单标签中使用Autocomplete组件。 action属性指向showBug.jsp页面,该页面显示所选的错误名称。

<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>

我们包括Autocomplete组件的 JavaScript 库和 CSS 样式。

<script>
    $(function () {

        $("#bugs").autocomplete({
            source: "Bugs",
            minLength: 1,
        });
    });
</script>

Autocomplete组件已创建。 source选项指向Bugs Servlet,该 Servlet 以 JSON 格式返回数据。 minLength选项指定用户在执行搜索之前必须键入的最少字符数。

<input id="bugs" name="bug">

Autocomplete绑定到该输入标签。

showBug.jsp

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Bug</title>
    </head>
    <body>
        <p>
            Chosen bug: <%= request.getParameter("bug")%>
        </p>
    </body>
</html>

showBug.jsp JSP 文件中,打印选定的错误。

bugs.csv

Assasin bug, Avondale spider, Backswimmer, 
Bamboo moth, Banana moth, Bed bug,
Black cocroach, Blue moon, Bumble Bee,
Carpenter Bee, Cattle tick, Cave Weta,
Cicada, Cinnibar, Click beetle, Clothes moth,
Codling moth, Centipede, Earwig, Eucalypt longhorn beetle,
Field Grasshopper, Garden slug, Garden soldier,
German cockroach, German wasp, Giant dragonfly,
Giraffe weevil, Grass grub, Grass looper,
Green planthopper, Green house spider, Gum emperor,
Gum leaf skeletoniser, Hornet, Mealybug,
Mites, Mole Cricket, Monarch butterfly,
Mosquito, Silverfish, Wasp,
Water boatman, Winged weta, Wolf spider,
Yellow Jacket, Yellow Admiral

WEB-INF/bug.csv文件中,我们列出了一个错误名称。 当 Web 应用从客户端收到 GET 请求时,将加载这些名称。

Bugs.java

package com.zetcode.web;

import com.zetcode.service.ReadBugs;
import com.zetcode.util.Utils;
import java.io.IOException;
import java.util.List;
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 = "Bugs", urlPatterns = {"/Bugs"})
public class Bugs extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");

        String term = request.getParameter("term");
        String q = term.toLowerCase();

        List<String> bugsList = ReadBugs.readAll(getServletContext());
        List<String> filteredBugsList = Utils.filterListByTerm(bugsList, q);
        String json = Utils.list2Json(filteredBugsList);

        response.getWriter().write(json);
    }
}

这是 Java Servlet,它接收带有名为term的参数的 GET 请求。 Servlet 读取错误名称列表,按检索到的术语对其进行过滤,然后将其转换为 JSON 字符串。

response.setContentType("application/json");

我们将响应类型设置为application/json

String term = request.getParameter("term");
String q = term.toLowerCase();

我们得到搜索词并将其更改为小写。

List<String> bugsList = ReadBugs.readAll(getServletContext());
List<String> filteredBugsList = Utils.filterListByTerm(bugsList, q);
String json = Utils.list2Json(filteredBugsList);

这三种方法读取数据,过滤数据并将其转换为 JSON。

response.getWriter().write(json);

最终的 JSON 字符串将发送到客户端。

ReadBugs.java

package com.zetcode.service;

import com.opencsv.CSVReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletContext;

public class ReadBugs {

    public static List<String> readAll(ServletContext context) throws IOException {

        InputStream is = context.getResourceAsStream("/WEB-INF/bugs.csv");

        List<String> bugsList = new ArrayList<>();

        try (CSVReader reader = new CSVReader(new InputStreamReader(is))) {
            String[] nextLine;

            while ((nextLine = reader.readNext()) != null) {

                for (String e : nextLine) {
                    bugsList.add(e.trim());
                }
            }
        }

        return bugsList;
    }
}

readAll()方法从 CSV 文件读取所有错误。 它使用 OpenCSV 库来完成这项工作。 它将列表错误名称返回给调用者。

InputStream is = context.getResourceAsStream("/WEB-INF/bugs.csv");

Servlet 上下文用于确定 CSV 文件的路径。

Utils.java

package com.zetcode.util;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;

public class Utils {

    public static List<String> filterListByTerm(List<String> list, String term) {

        List<String> matching = list.stream()
                .filter(e -> e.toLowerCase().startsWith(term))
                .collect(Collectors.toList());

        return matching;
    }

    public static String list2Json(List<String> list) {

        String json = null;

        try {
            json = new ObjectMapper().writeValueAsString(list);
        } catch (JsonProcessingException ex) {
            Logger.getLogger(Utils.class.getName()).log(Level.SEVERE, null, ex);
        }

        return json;
    }
}

我们有一个Utils类,其中包含两个方法。 一个过滤数据,另一个将列表转换为 JSON。

List<String> matching = list.stream()
        .filter(e -> e.toLowerCase().startsWith(term))
        .collect(Collectors.toList());

使用 Java 8 流 API,我们按搜索词过滤数据。

try {
    json = new ObjectMapper().writeValueAsString(list);
} catch (JsonProcessingException ex) {
    Logger.getLogger(Utils.class.getName()).log(Level.SEVERE, null, ex);
}

使用 Jackson,我们将 Java 列表转换为 JSON 字符串。

jQuery Autocomplete

图:jQuery 自动完成

在本教程中,我们在 Java Web 应用中使用了 jQuery 自动补全。 自动补全组件正在显示有关可用错误名称的建议。 在我们的项目中,我们利用了 Jackson 和 Opencsv 库。

您可能也对以下相关教程感兴趣: Java 教程使用 jsGrid 教程OpenCSV 教程在 JSP 和 PHP 中使用 jQuery DatePicker

Java servlet PDF 教程

原文: http://zetcode.com/articles/javaservletpdf/

Java servlet PDF 教程展示了如何从 Java servlet 返回 PDF 数据。 我们使用 iText 库处理 PDF。 该 Web 应用已部署在 Tomcat 服务器上。

PDF 格式

便携式文档格式(PDF)是用于以独立于应用软件,硬件和操作系统的方式呈现文档的文件格式。 PDF 由 Adobe 发明,现在是国际标准化组织(ISO)维护的开放标准。

Java Servlet

Servlet 是 Java 类,可响应特定类型的网络请求-最常见的是 HTTP 请求。 Java servlet 用于创建 Web 应用。 它们在 servlet 容器(例如 Tomcat 或 Jetty)中运行。 现代 Java Web 开发使用在 servlet 之上构建的框架。

iText

iText 是一个开放源代码库,用于在 Java 中创建和处理 PDF 文件。

Java Servlet PDF 应用

以下 Web 应用使用 Java Servlet 将 PDF 文件发送到客户端。 它从对象列表生成 PDF。

$ tree
.
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── zetcode
    │   │           ├── bean
    │   │           │   └── City.java
    │   │           ├── service
    │   │           │   └── CityService.java
    │   │           ├── util
    │   │           │   └── GeneratePdf.java
    │   │           └── web
    │   │               └── MyServlet.java
    │   └── webapp
    │       ├── index.html
    │       ├── META-INF
    │       │   └── context.xml
    │       └── WEB-INF
    └── test
        └── java

这是项目结构。

pom.xml

<?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>JavaServletPDF</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>JavaServletPDF</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>com.lowagie</groupId>
            <artifactId>itext</artifactId>
            <version>4.2.2</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>

这是 Maven POM 文件。 我们有两个工件:用于 Java 的 servlet 的javax.servlet-api和用于 PDF 生成的itextmaven-war-plugin负责收集 Web 应用的所有工件依赖项,类和资源,并将它们打包到 Web 应用存档(WAR)中。

context.xml

<?xml version="1.0" encoding="UTF-8"?>
<Context path="/JavaServletPdf"/>

在 Tomcat context.xml文件中,我们定义了上下文路径。 它是 Web 应用的名称。

City.java

package com.zetcode.bean;

public class City {

    private Long id;
    private String name;
    private int population;

    public City() {
    }

    public City(Long id, String name, int population) {
        this.id = id;
        this.name = name;
        this.population = population;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getPopulation() {
        return population;
    }

    public void setPopulation(int population) {
        this.population = population;
    }

    @Override
    public String toString() {
        return "City{" + "id=" + id + ", name=" + name + 
                ", population=" + population + '}';
    }
}

这是City bean。 它具有三个属性:idnamepopulation

MyServlet.java

package com.zetcode.web;

import com.zetcode.bean.City;
import com.zetcode.service.CityService;
import com.zetcode.util.GeneratePdf;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name = "MyServlet", urlPatterns = {"/MyServlet"})
public class MyServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("application/pdf;charset=UTF-8");

        response.addHeader("Content-Disposition", "inline; filename=" + "cities.pdf");
        ServletOutputStream out = response.getOutputStream();

        List<City> cities = CityService.getCities();

        ByteArrayOutputStream baos = GeneratePdf.getPdfFile(cities);
        baos.writeTo(out);
    }
}

这是MyServlet servlet。 它从服务类检索数据,从数据生成 PDF 文件,然后将 PDF 文件返回给客户端。

response.setContentType("application/pdf;charset=UTF-8");

我们将响应对象的内容类型设置为application/pdf

response.addHeader("Content-Disposition", "inline; filename=" + "cities.pdf");

Content-Disposition响应标头指示内容应在浏览器中显示为inline,即作为 Web 页面或 Web 页面的一部分,或作为attachment在本地下载和保存。 。 可选的filename伪指令指定传输文件的名称。

ServletOutputStream out = response.getOutputStream();

我们从响应对象获得ServletOutputStream

List<City> cities = CityService.getCities();

CityService中,我们可以获得城市列表。

List<City> cities = CityService.getCities();

CityService中,我们可以获得城市列表。

ByteArrayOutputStream baos = GeneratePdf.getPdfFile(cities);
baos.writeTo(out);

我们根据数据生成 PDF 文件,并将返回的ByteArrayOutputStream写入ServletOutputStream

CityService.java

package com.zetcode.service;

import com.zetcode.bean.City;
import java.util.ArrayList;
import java.util.List;

public class CityService {

    public static List<City> getCities() {

        List<City> cities = new ArrayList<>();

        cities.add(new City(1L, "Bratislava", 432000));
        cities.add(new City(2L, "Budapest", 1759000));
        cities.add(new City(3L, "Prague", 1280000));
        cities.add(new City(4L, "Warsaw", 1748000));
        cities.add(new City(5L, "Los Angeles", 3971000));
        cities.add(new City(6L, "New York", 8550000));
        cities.add(new City(7L, "Edinburgh", 464000));
        cities.add(new City(8L, "Berlin", 3671000));

        return cities;
    }
}

CityServicegetCities()方法返回城市对象的列表。

GeneratePdf.java

package com.zetcode.util;

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.FontFactory;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
import com.zetcode.bean.City;
import java.io.ByteArrayOutputStream;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

public class GeneratePdf {

    public static ByteArrayOutputStream getPdfFile(List<City> cities) {

        Document document = new Document();
        ByteArrayOutputStream bout = new ByteArrayOutputStream();

        try {

            PdfPTable table = new PdfPTable(3);
            table.setWidthPercentage(60);
            table.setWidths(new int[]{1, 3, 3});

            Font headFont = FontFactory.getFont(FontFactory.HELVETICA_BOLD);

            PdfPCell hcell;
            hcell = new PdfPCell(new Phrase("Id", headFont));
            hcell.setHorizontalAlignment(Element.ALIGN_CENTER);
            table.addCell(hcell);

            hcell = new PdfPCell(new Phrase("Name", headFont));
            hcell.setHorizontalAlignment(Element.ALIGN_CENTER);
            table.addCell(hcell);

            hcell = new PdfPCell(new Phrase("Population", headFont));
            hcell.setHorizontalAlignment(Element.ALIGN_CENTER);
            table.addCell(hcell);

            for (City city : cities) {

                PdfPCell cell;

                cell = new PdfPCell(new Phrase(city.getId().toString()));
                cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
                cell.setHorizontalAlignment(Element.ALIGN_CENTER);
                table.addCell(cell);

                cell = new PdfPCell(new Phrase(city.getName()));
                cell.setPaddingLeft(5);
                cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
                cell.setHorizontalAlignment(Element.ALIGN_LEFT);
                table.addCell(cell);

                cell = new PdfPCell(new Phrase(String.valueOf(city.getPopulation())));
                cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
                cell.setHorizontalAlignment(Element.ALIGN_RIGHT);
                cell.setPaddingRight(5);
                table.addCell(cell);
            }

            PdfWriter.getInstance(document, bout);
            document.open();
            document.add(table);

            document.close();

        } catch (DocumentException ex) {

            Logger.getLogger(GeneratePdf.class.getName()).log(Level.SEVERE, null, ex);
        }

        return bout; 
    }
}

GeneratePdf根据提供的数据创建 PDF 文件。

ByteArrayOutputStream bout = new ByteArrayOutputStream();

数据将被写入ByteArrayOutputStreamByteArrayOutputStream实现了一个输出流,其中数据被写入字节数组。

PdfPTable table = new PdfPTable(3);

我们将数据放在表格中; 为此,我们有PdfPTable类。 该表具有三列:ID,名称和人口。

Font headFont = FontFactory.getFont(FontFactory.HELVETICA_BOLD);

我们使用粗体 Helvetica 字体作为表标题。

PdfPCell hcell;
hcell = new PdfPCell(new Phrase("Id", headFont));
hcell.setHorizontalAlignment(Element.ALIGN_CENTER);
table.addCell(hcell);

数据放置在表单元格内,由PdfPCell表示。 setHorizontalAlignment()方法使文本水平对齐。

PdfWriter.getInstance(document, bout);

使用PdfWriter,将文档写入ByteArrayOutputStream

document.open();
document.add(table);

该表将插入到 PDF 文档中。

document.close();

为了将数据写入ByteArrayOutputStream,必须关闭文档。

return bout; 

最后,数据返回为ByteArrayOutputStream

在本教程中,我们从 Java servlet 发送了 PDF 数据。

您可能也对以下相关教程感兴趣: Java RequestDispatcherJava Servlet 图表教程从 Java Servlet 提供纯文本Java Servlet 检查框教程Java servlet 图像教程Java Servlet HTTP 标头Java 教程

servlet 从 WAR 内读取 CSV 文件

原文: http://zetcode.com/articles/warcsv/

在本教程中,我们从WEB-INF目录中的 CSV 文件读取数据。 我们使用 servlet,JSP 文件和 JSTL 库。 Web 应用已部署在 Jetty 上。 OpenCSV 库用于读取 CSV 数据。

CSV

CSV(逗号分隔值)格式是在电子表格和数据库中使用的非常流行的导入和导出格式。

在以下 Web 应用中,我们从 WAR 文件中的 CSV 文件读取数据,并将数据显示在网页中。 标记人口超过一亿的国家。

pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           ├───bean
│   │           │       Country.java
│   │           ├───service
│   │           │       CountryService.java
│   │           └───web
│   │                   ReadCountries.java
│   ├───resources
│   │       countries.csv
│   └───webapp
│           index.jsp
│           listCountries.jsp
│           showError.jsp
└───test
    └───java

这是项目结构。

pom.xml

<?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>readcsvfromwar</artifactId>
    <version>1.0-SNAPSHOT</version>

    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>12</maven.compiler.source>
        <maven.compiler.target>12</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>com.opencsv</groupId>
            <artifactId>opencsv</artifactId>
            <version>4.6</version>
        </dependency>

        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.2</version>
            </plugin>

            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>9.4.14.v20181114</version>
            </plugin>
        </plugins>
    </build>

</project>

该项目使用以下依赖项:avax.servlet-apiopencsvjstl

resources/countries.csv

Name, Population
Slovakia,5429000
Norway,5271000
Croatia,4225000
Russia,143439000
Mexico,122273000
Vietnam,95261000
Sweden,9967000
Iceland,337600
Israel,8622000
Hungary,9830000
Germany,82175700
Japan,126650000

这是countries.csv文件。 它位于src/main/resources目录中。 生成应用后,文件将复制到 WAR 的WEB-INF/classes目录。

com/zetcode/bean/Country.java

package com.zetcode.bean;

import com.opencsv.bean.CsvBindByName;

import java.util.Objects;

public class Country {

    @CsvBindByName
    private String name;

    @CsvBindByName
    private int population;

    public Country() {
    }

    public Country(String name, int population) {

        this.name = name;
        this.population = population;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getPopulation() {
        return population;
    }

    public void setPopulation(int population) {
        this.population = population;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Country country = (Country) o;
        return population == country.population &&
                Objects.equals(name, country.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, population);
    }
}

这是一个Country bean,具有两个属性:namepopulation

@CsvBindByName
private String name;

@CsvBindByNamename属性映射到Name列中的字段。

com/zetcode/CountryService.java

package com.zetcode.service;

import com.opencsv.bean.CsvToBean;
import com.opencsv.bean.CsvToBeanBuilder;
import com.opencsv.bean.HeaderColumnNameMappingStrategy;
import com.zetcode.bean.Country;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Optional;

public class CountryService {

    public static Optional<List<Country>> getListOfCountries() throws IOException {

        List<Country> countries;

        try (InputStream is = CountryService.class.getClassLoader()
                .getResourceAsStream("countries.csv")) {

            if (is == null) {

                return Optional.empty();
            }

            HeaderColumnNameMappingStrategy<Country> strategy
                    = new HeaderColumnNameMappingStrategy<>();
            strategy.setType(Country.class);

            try (var br = new BufferedReader(
                    new InputStreamReader(is, StandardCharsets.UTF_8))) {

                CsvToBean<Country> csvToBean = new CsvToBeanBuilder<Country>(br)
                        .withType(Country.class)
                        .withMappingStrategy(strategy)
                        .withIgnoreLeadingWhiteSpace(true)
                        .build();

                 countries = csvToBean.parse();
            }
        }

        return Optional.of(countries);
    }
}

CountryService从 CSV 文件读取数据。

try (InputStream is = CountryService.class.getClassLoader()
    .getResourceAsStream("countries.csv")) {

我们使用getResourceAsStream()方法将InputStream转换为countries.csv文件。

if (is == null) {

    return Optional.empty();
}

如果未打开输入流,则返回空Optional。 这用于避免null值。

HeaderColumnNameMappingStrategy<Country> strategy
    = new HeaderColumnNameMappingStrategy<>();
strategy.setType(Country.class);

我们使用 OpenCSV 的HeaderColumnNameMappingStrategyCountry bean 映射到 CSV 文件中的行。 每行都转换为一个 bean。 映射是在@CsvBindByName注解的帮助下完成的。

try (var br = new BufferedReader(
        new InputStreamReader(is, StandardCharsets.UTF_8))) {

    CsvToBean<Country> csvToBean = new CsvToBeanBuilder<Country>(br)
            .withType(Country.class)
            .withMappingStrategy(strategy)
            .withIgnoreLeadingWhiteSpace(true)
            .build();

     countries = csvToBean.parse();
}

使用CsvToBeanBuilder,我们解析 CSV 文件并将行转换为Country bean 列表。

com/zetcode/web/ReadCountries.java

package com.zetcode.web;

import com.zetcode.bean.Country;
import com.zetcode.service.CountryService;

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

@WebServlet(name = "ReadCountries", urlPatterns = {"/read"})
public class ReadCountries extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("text/html;charset=UTF-8");

        Optional<List<Country>> countries = CountryService.getListOfCountries();

        String templateName;

        if (countries.isPresent()) {

            request.setAttribute("countries", countries.get());
            templateName = "listCountries.jsp";
        } else {

            templateName = "showError.jsp";
        }

        var dispatcher = request.getRequestDispatcher(templateName);
        dispatcher.forward(request, response);
    }
}

ReadCountries Servlet 中,我们称为getListOfCountries()服务方法。 如果有一些国家,我们将返回的国家列表设置为request对象作为属性。 处理被传送到listCountries.jsp。 如果找不到数据,则返回错误消息。

webapp/listCountries.jsp

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Countries</title>
    <style>
        .marked { color: chocolate }
    </style>
</head>
<body>
<table>

    <thead>
        <tr>
            <th>Country</th>
            <th>Population</th>
        </tr>
    </thead>

    <tbody>

        <c:forEach items="${countries}" var="count">

            <c:if test="${count.population > 100000000}">
                <tr class="marked">
                    <td>
                        <c:out value="${count.name}"/>
                    </td>
                    <td>
                        <fmt:formatNumber type="number" value="${count.population}" />
                    </td>                   
                </tr>
            </c:if>
            <c:if test="${count.population < 100000000}">
                <tr>
                    <td>
                        <c:out value="${count.name}"/>
                    </td>
                    <td>
                        <fmt:formatNumber type="number" value="${count.population}" />
                    </td>                   
                </tr>
            </c:if>
        </c:forEach>

    </tbody>
    </table>
</body>
</html>

listCountries.jsp文件中,我们在 HTML 表中显示数据。

<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

我们使用两个 JSTL 标签库:核心库和格式库。

<c:forEach items="${countries}" var="count">

使用<c:forEach>标签,我们遍历countries对象。

<c:if test="${count.population > 100000000}">
    <tr class="marked">
        <td>
            <c:out value="${count.name}"/>
        </td>
        <td>
            <fmt:formatNumber type="number" value="${count.population}" />
        </td>                   
    </tr>
</c:if>

如果该国家/地区的人口超过一亿,则使用marked类作为行;否则,使用marked类作为行。 它以另一种颜色显示行。 该测试使用 JSTL 的<c:if>标签执行。 <fmt:formatNumber>标签用于格式化该值。

webapp/index.jsp

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>List countries</title>
    </head>
    <body>
        <a href="read">List countries</a>
    </body>
</html>

index.jsp包含一个调用ReadCountries servlet 的链接。 Servlet 从 CSV 文件读取数据,然后将数据以视图的形式返回给浏览器。

webapp/showError.jsp

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Error</title>
    </head>
    <body>
        <p>No countries found</p>
    </body>
</html>

此模板文件显示错误消息。

在本教程中,我们展示了如何读取 WAR 文件中的 CSV 数据。

您可能也对以下相关教程感兴趣: Java 教程Jersey 应用中的 Web URLJava 验证教程OpenCSV 教程

列出所有 Java servlet 教程

Java HttpServletMapping

原文: http://zetcode.com/java/httpservletmapping/

Java HttpServletMapping显示了如何使用 Servlet 4.0 中引入的HttpServletMapping

HttpServletMapping

HttpServletMapping是新的 Servlet 4.0 API,可用于 URL 映射的运行时发现。

Servlet 映射是从HttpServletRequest实例获得的,该实例具有四种方法:

  • getMappingMatch() — 返回匹配的类型
  • getPattern() — 返回激活 servlet 请求的 URL 模式
  • getMatchValue() — 返回匹配的字符串
  • getServletName() — 返回被请求激活的 servlet 类的全限定名

Java HttpServletMapping示例

在下面的示例中,我们使用HttpServletMapping查找有关 URL 映射的信息。 该示例在 Tomcat 上运行。 注意,我们必须选择具有 Servlet 4.0 API JAR 的最新 Tomcat 版本。

$ tree
.
├── nb-configuration.xml
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── zetcode
    │   │           └── MyServlet.java
    │   └── webapp
    │       ├── index.html
    │       ├── META-INF
    │       │   └── context.xml
    │       └── WEB-INF
    └── test
        └── java

这是项目结构。

MyServlet.java

package com.zetcode;

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

@WebServlet(name = "MyServlet", urlPatterns = {"/getMessage"})
public class MyServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("text/plain;charset=UTF-8");

        HttpServletMapping mapping = request.getHttpServletMapping();
        String mapName = mapping.getMappingMatch().name();
        String value = mapping.getMatchValue();
        String pattern = mapping.getPattern();
        String servletName = mapping.getServletName();

        StringBuilder builder = new StringBuilder();
        builder.append("Mapping type: ").append(mapName)
                .append("; Match value: ").append(value)
                .append("; Pattern: ").append(pattern)
                .append("; Servlet name: ").append(servletName);

        ServletOutputStream out = response.getOutputStream();
        out.println(builder.toString());
    }
}

我们获取映射信息,并将其作为文本数据发送给客户端。

@WebServlet(name = "MyServlet", urlPatterns = {"/getMessage"})

我们设置与@WebServlet声明绑定 servlet 的 URL 模式。

HttpServletMapping mapping = request.getHttpServletMapping();
String mapName = mapping.getMappingMatch().name();
String value = mapping.getMatchValue();
String pattern = mapping.getPattern();
String servletName = mapping.getServletName();

从请求对象中,我们获得getHttpServletMapping()的 servlet 映射。 我们调用所有四个方法。

StringBuilder builder = new StringBuilder();
builder.append("Mapping type: ").append(mapName)
        .append("; Match value: ").append(value)
        .append("; Pattern: ").append(pattern)
        .append("; Servlet name: ").append(servletName);

根据数据,我们构建一个字符串。

ServletOutputStream out = response.getOutputStream();
out.println(builder.toString());

我们将字符串发送给客户。

index.html

<!DOCTYPE html>
<html>
    <head>
        <title>Home Page</title>
        <meta charset="UTF-8">
    </head>
    <body>
        <a href="getMessage">Get message</a>
    </body>
</html>

这是一个主页。 它具有一个调用 servlet 的链接。

HttpServletMapping details

图:HttpServletMapping详细信息

在本教程中,我们展示了如何使用 Servlet 4.0 中引入的新HttpServletMapping API。 您可能也对相关教程感兴趣: Java FileInputStream教程提供 Java ServletJava Servlet 教程Java ServletConfig教程Java 教程

EasyUI datagrid

原文: http://zetcode.com/articles/easyuidatagrid/

在本教程中,我们将展示如何在 EasyUI datagrid 组件中显示来自 Derby 的数据库数据。 我们创建了一个简单的 Java Web 应用,该应用从 Derby 数据库中读取数据并将其发送到客户端浏览器。 数据显示在 datagrid 组件中。

EasyUI

EasyUI 是一个 JavaScript 库,它提供了用于构建现代的,交互式 JavaScript 应用的基本功能。 EasyUI 为前端提供了许多有用的组件。 EasyUI 建立在 JQuery 之上。

Apache Derby 是完全用 Java 实现的开源关系数据库。 它占地面积小,易于部署和安装。 它支持嵌入式和客户端/服务器模式。 它也被称为 Java DB。

cars.sql

CREATE TABLE CARS(ID INTEGER NOT NULL PRIMARY KEY GENERATED ALWAYS AS IDENTITY 
    (START WITH 1, INCREMENT BY 1), NAME VARCHAR(30), PRICE INT);

INSERT INTO CARS(NAME, PRICE) VALUES('Audi', 52642);
INSERT INTO CARS(NAME, PRICE) VALUES('Mercedes', 57127);
INSERT INTO CARS(NAME, PRICE) VALUES('Skoda', 9000);
INSERT INTO CARS(NAME, PRICE) VALUES('Volvo', 29000);
INSERT INTO CARS(NAME, PRICE) VALUES('Bentley', 350000);
INSERT INTO CARS(NAME, PRICE) VALUES('Citroen', 21000);
INSERT INTO CARS(NAME, PRICE) VALUES('Hummer', 41400);
INSERT INTO CARS(NAME, PRICE) VALUES('Volkswagen', 21600);

在我们的示例中,我们使用此数据库表。

<dependencies>
    <dependency>
        <groupId>javax</groupId>
        <artifactId>javaee-web-api</artifactId>
        <version>7.0</version>
        <scope>provided</scope>
    </dependency>

    <dependency>
        <groupId>org.apache.derby</groupId>
        <artifactId>derbyclient</artifactId>
        <version>10.12.1.1</version>
    </dependency>    

    <dependency>
        <groupId>com.googlecode.json-simple</groupId>
        <artifactId>json-simple</artifactId>
        <version>1.1.1</version>
    </dependency>

    <dependency>
        <groupId>org.apache.derby</groupId>
        <artifactId>derbyoptionaltools</artifactId>
        <version>10.12.1.1</version>
    </dependency>

</dependencies>

在项目中,我们使用这四个依赖项。 javaee-web-api是一组用于构建 Java Web 应用的 JAR,derbyclient是 Derby 数据库驱动程序,json-simple是用于 JSON 的库,derbyoptionaltools用于将 SQL 结果集转换为 JSON 。

index.html

<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Cars</title>
        <link rel="stylesheet" type="text/css" href="http://www.jeasyui.com/easyui/themes/default/easyui.css">
        <link rel="stylesheet" type="text/css" href="http://www.jeasyui.com/easyui/themes/color.css">
        <script src="https://code.jquery.com/jquery-3.1.0.min.js"></script>
        <script type="text/javascript" src="http://www.jeasyui.com/easyui/jquery.easyui.min.js"></script>

    </head>
    <body>
        <h2>Cars</h2>

        <table id="dg" title="Cars" class="easyui-datagrid" style="width:700px;height:350px"
               url="GetCars"
               pagination="true"
               rownumbers="true" fitColumns="true" singleSelect="true">
            <thead>
                <tr>
                    <th field="NAME" width="50">Name</th>
                    <th field="PRICE" width="50">Price</th>
                </tr>
            </thead>
        </table>

    </body>
</html>

index.html文件中,我们导入 EasyUI 和 JQuery 库。 我们使用 EasyUI 数据网格组件,该组件通过class属性设置。 url属性指向 Java Servlet,该 Java Servlet 以 JSON 格式返回数据。 行字段的名称必须与从 Servlet 返回的 JSON 数据的字段名称匹配。 JSON 是一种流行的轻量级数据交换格式。

GetCars.java

package com.zetcode.web;

import com.zetcode.service.CarService;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.json.simple.JSONArray;

@WebServlet(name = "GetCars", urlPatterns = {"/GetCars"})
public class GetCars extends HttpServlet {

    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");

        JSONArray ar = CarService.getCarsJSON();

        response.getWriter().write(ar.toJSONString());
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        processRequest(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        processRequest(request, response);
    }
}

GetCars Java servlet 调用服务方法,该方法从 Derby 数据库表中检索数据。

response.setContentType("application/json");

我们将内容类型设置为application/json

JSONArray ar = CarService.getCarsJSON();

getCarsJSON()方法以 JSON 格式返回数据。

response.getWriter().write(ar.toJSONString());

数据发送到客户端。

CarService.java

package com.zetcode.service;

import com.zetcode.web.GetCars;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.derby.optional.api.SimpleJsonUtils;
import org.json.simple.JSONArray;

public class CarService {

    private static JSONArray jarray;

    public static JSONArray getCarsJSON() {

        Connection con = null;
        PreparedStatement pst = null;
        ResultSet rs = null;

        String url = "jdbc:derby://localhost:1527/testdb";

        String user = "app";
        String password = "app";

        try {

            DriverManager.registerDriver(new org.apache.derby.jdbc.ClientDriver());
            con = DriverManager.getConnection(url, user, password);
            pst = con.prepareStatement("SELECT NAME, PRICE FROM Cars");
            rs = pst.executeQuery();

            jarray = SimpleJsonUtils.toJSON(rs);

        } catch (SQLException ex) {

            Logger lgr = Logger.getLogger(GetCars.class.getName());
            lgr.log(Level.SEVERE, ex.getMessage(), ex);

        } finally {

            try {
                if (rs != null) {
                    rs.close();
                }
                if (pst != null) {
                    pst.close();
                }
                if (con != null) {
                    con.close();
                }

            } catch (SQLException ex) {
                Logger lgr = Logger.getLogger(GetCars.class.getName());
                lgr.log(Level.WARNING, ex.getMessage(), ex);
            }
        }

        return jarray;
    }
}

GetCars()方法连接到 Derby 数据库并执行SELECT语句; 返回的数据将转换为 JSON。 JDBC 用于执行 SQL。

pst = con.prepareStatement("SELECT NAME, PRICE FROM Cars");

我们从表中检索两列:名称和价格。

jarray = SimpleJsonUtils.toJSON(rs);

我们使用SimpleJsonUtils.toJSON()方法将结果集转换为 JSON 对象数组。 该方法在 Derby 可选工具库中可用。

Displaying database data in a datagrid

图:在数据网格中显示数据库数据

在本文中,我们展示了如何在数据网格控件中显示 Derby 数据库中的数据库数据。 数据已使用 JSON 格式从数据库发送到 datagrid。

您可能也对以下相关教程感兴趣:数据表 JSON 服务器教程Tomcat Derby 教程Apache Derby 教程使用 jsGrid 教程jQuery 自动完成教程在 EasyUI 数据网格中显示来自 Derby 的数据在 JSP 和 PHP 中使用 jQuery DatePickerJava 教程

Java Servlet RESTFul 客户端

原文: http://zetcode.com/articles/javaservletrestclient/

在 Java Servlet RESTFul 客户端教程中,我们使用 JAX-RS 在 Java Servlet 中创建 RESTFul 客户端。

用于 RESTful Web 服务的 Java API(JAX-RS)是 Java API 规范,它提供了根据代表性状态转移(REST)架构模式创建 Web 服务的支持。

Jersey 是 Java RESTful Web 服务框架和 JAX-RS 参考实现。

Servlet 是 Java 类,可响应特定类型的网络请求-最常见的是 HTTP 请求。 Java servlet 用于创建 Web 应用。 它们在 servlet 容器(例如 Tomcat 或 Jetty)中运行。 现代 Java Web 开发使用在 servlet 之上构建的框架。

Java Servlet 应用

以下 Web 应用向api.randomuser.me站点创建一个请求,该站点是一个随机用户生成器。

Java servlet 使用ClientBuilder创建一个Client,这是用于构建和执行客户端请求以使用返回的响应的流畅 API 的主要入口点。

$ tree
.
├── nb-configuration.xml
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── zetcode
    │   │           ├── model
    │   │           │   ├── Location.java
    │   │           │   ├── Name.java
    │   │           │   ├── Person.java
    │   │           │   └── PersonsList.java
    │   │           ├── service
    │   │           │   └── PersonService.java
    │   │           └── web
    │   │               └── MyServlet.java
    │   ├── resources
    │   └── webapp
    │       ├── index.html
    │       ├── META-INF
    │       │   └── context.xml
    │       ├── show.jsp
    │       └── WEB-INF
    └── test
        └── java

这是项目结构。

pom.xml

<?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>JavaServletRestClient</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>JavaServletRestClient</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>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>           

        <dependency>
            <groupId>org.glassfish.jersey.core</groupId>
            <artifactId>jersey-client</artifactId>
            <version>2.25.1</version>
        </dependency>      

        <dependency>
            <groupId>org.glassfish.jersey.media</groupId>
            <artifactId>jersey-media-json-jackson</artifactId>
            <version>2.22</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>

这是 Maven POM 文件。 我们有四个工件:用于 servlet 的javax.servlet-api,用于标准 JSP 标签库的jstl,用于 RESTFul 核心客户端实现的jersey-client和用于 JSON / Java Bean 数据绑定的jersey-media-json-jackson

context.xml

<?xml version="1.0" encoding="UTF-8"?>
<Context path="/JavaServletRestClient"/>

在 Tomcat context.xml文件中,我们定义了上下文路径。 它是 Web 应用的名称。

在该应用中,我们有三个 bean。 这些 bean 将被响应中的数据填充。

Location.java

package com.zetcode.model;

public class Location {

    private String street;
    private String city;
    private String state;
    private String postcode;

    public String getStreet() {
        return street;
    }

    public void setStreet(String street) {
        this.street = street;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }

    public String getPostcode() {
        return postcode;
    }

    public void setPostcode(String postcode) {
        this.postcode = postcode;
    }

    @Override
    public String toString() {

        StringBuilder sb = new StringBuilder();
        sb.append(street).append(" ")
                .append(city).append(" ")
                .append(state).append(" ")
                .append(postcode);
        return sb.toString();
    }
}

Location存储用户的地址。

Name.java

package com.zetcode.model;

public class Name {

    private String first;
    private String last;
    private String title;

    public String getFirst() {
        return first;
    }

    public void setFirst(String firstName) {
        first = firstName;
    }

    public String getLast() {
        return last;
    }

    public void setLast(String lastName) {
        last = lastName;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    @Override
    public String toString() {

        StringBuilder sb = new StringBuilder();
        sb.append(title).append(" ").append(first)
                .append(" ").append(last);
        return sb.toString();
    } 
}

Name存储用户名详细信息。

Person.java

package com.zetcode.model;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties(ignoreUnknown = true)
public class Person {

    private Name name;
    private Location location;
    private String email;
    private String gender;

    public void setName(Name name) {
        this.name = name;
    }

    public Name getName() {
        return name;
    }    

    public Location getLocation() {
        return location;
    }

    public void setLocation(Location location) {
        this.location = location;
    }

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

    public String getEmail() {
        return email;
    }

    public String getGender() {
        return gender;
    }

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

    @Override
    public String toString() {

        StringBuilder sb = new StringBuilder();
        sb.append("Name: ").append(name)
                .append("Address: ").append(location)
                .append("Email ").append(email)
                .append("Gender: ").append(gender);
        return sb.toString();
    }
}

Person类存储有关用户的数据,包括姓名,地址,电子邮件和性别。

@JsonIgnoreProperties(ignoreUnknown = true)

使用@JsonIgnoreProperties批注,我们告诉 Jackson 忽略Person中未列出的属性。

PersonsList.java

package com.zetcode.model;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import java.util.List;

@JsonIgnoreProperties(ignoreUnknown = true)
public class PersonsList {

    List<Person> results;

    public List<Person> getResults() {
        return results;
    }

    public void setResults(List<Person> result) {
        results = result;
    }
}

这是Person对象的列表。 Web 服务使用数据填充此列表。

MyServlet.java

package com.zetcode.web;

import com.zetcode.model.Person;
import com.zetcode.service.PersonService;
import java.io.IOException;
import java.util.List;
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 = "MyServlet", urlPatterns = {"/MyServlet"})
public class MyServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("text/html;charset=UTF-8");

        List<Person> people = PersonService.fetchPeople(0, 50);

        request.setAttribute("people", people);
        request.getRequestDispatcher("show.jsp").forward(request, response);
    }
}

MyServlet Servlet 调用PersonService.fetchPeople(),它返回Person对象的列表。 该列表将作为属性存储,并且处理将分派到show.jsp页面。 JSP 页面呈现Person对象的列表。

PersonService.java

package com.zetcode.service;

import com.zetcode.model.Person;
import com.zetcode.model.PersonsList;
import java.util.List;

import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;

public class PersonService {

    private static WebTarget resource = ClientBuilder.newBuilder()
            .build().target("https://api.randomuser.me/");

    public static List<Person> fetchPeople(int offset, int num) {
        PersonsList res = resource.queryParam("seed", 1)
                .queryParam("results", num).queryParam("page", 1)
                .request(MediaType.APPLICATION_JSON).get(PersonsList.class);
        return res.getResults();
    }      
}

PersonService包含用于在api.randomuser.me Web 服务上执行查询的fetchPeople()方法。 该服务随机返回用户对象。

private static WebTarget resource = ClientBuilder.newBuilder()
        .build().target("https://api.randomuser.me/");

使用ClientBuilder创建一个 Web 资源目标。 api.randomuser.me网站随机返回用户列表。

public static List<Person> fetchPeople(int offset, int num) {
    PersonsList res = resource.queryParam("seed", 1)
            .queryParam("results", num).queryParam("page", 1)
            .request(MediaType.APPLICATION_JSON).get(PersonsList.class);
    return res.getResults();
}    

我们向网络资源发送查询; 数据存储在PersonsList中。

index.html

<!DOCTYPE html>
<html>
    <head>
        <title>Home Page</title>
        <meta charset="UTF-8">
    </head>
    <body>
        <a href="MyServlet">List people</a>
    </body>
</html>

这是主页。 它包含一个调用MyServlet的链接。

show.jsp

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Show people</title>
    </head>
    <body>
        <table>
            <thead>
                <tr>
                    <th>Title</th>
                    <th>First name</th>
                    <th>Last name</th>
                    <th>Street</th>
                    <th>City</th>
                    <th>State</th>
                    <th>Postcode</th>
                    <th>Email</th>
                    <th>Gender</th>
                </tr>
            </thead>
            <tbody>

                <c:forEach var="per" items="${people}">
                    <tr>
                        <td><c:out value="${per.name.title}"/></td>
                        <td><c:out value="${per.name.first}"/></td>
                        <td><c:out value="${per.name.last}"/></td>
                        <td><c:out value="${per.location.street}"/></td>
                        <td><c:out value="${per.location.city}"/></td>
                        <td><c:out value="${per.location.state}"/></td>
                        <td><c:out value="${per.location.postcode}"/></td>
                        <td><c:out value="${per.email}"/></td>
                        <td><c:out value="${per.gender}"/></td>
                    </tr>
                </c:forEach>
            </tbody>
        </table>
    </body>    
</html>

show.jsp页面使用 JSTL 库中的c:forEachc:out标签在 HTML 表中显示数据。

在本教程中,我们向 Web 服务创建了一个 JAX-RS 客户端请求,该请求会随机生成用户。 该请求是从 Java Servlet 发送的。

您可能也对以下相关教程感兴趣: Java servlet Log4j 教程Java servlet JSON 教程Java Servlet PDF 教程Java servlet 复选框教程Java servlet 图像教程Java Servlet HTTP 标头Java 教程

Java Servlet Log4j 教程

原文: http://zetcode.com/articles/javaservletlog4j/

Java servlet Log4j 教程显示了如何在 Java servlet 中使用 Log4j 进行日志记录。 本教程介绍 Log4j 版本 2。

Java Servlet

Servlet 是 Java 类,可响应特定类型的网络请求-最常见的是 HTTP 请求。 Java servlet 用于创建 Web 应用。 它们在 servlet 容器(例如 Tomcat 或 Jetty)中运行。 现代 Java Web 开发使用在 servlet 之上构建的框架。

Log4j

Apache Log4j 是基于 Java 的日志记录工具。 它是 Apache Software Foundation 的项目。 可以通过 Java 代码或在配置文件中配置 Log4j。 配置文件可以 XML,JSON,YAML 或属性文件格式编写。

Log4j 具有三个主要组件:记录器,附加器和布局。 记录器被命名为目标,可捕获捕获日志消息并将其发送到附加程序。 附加器将日志消息传递到其目的地,例如文件或控制台。 布局用于定义日志消息的格式。

Java servlet 日志记录示例

以下 Web 应用正在使用 Log4j 进行日志记录。 在 Servlet 3.0+应用中,Log4j 可以直接使用。 它在应用部署时自动启动,在应用取消部署时自动关闭。

$ tree
.
├── pom.xml
└── src
    └── main
        ├── java
        │   └── com
        │       └── zetcode
        │           ├── service
        │           │   └── MyService.java
        │           └── web
        │               └── MyServlet.java
        ├── resources
        │   └── log4j2.xml
        └── webapp
            ├── index.html
            ├── META-INF
            │   └── context.xml
            └── WEB-INF

这是项目结构。 Log4j 配置文件位于src/main/resources/目录中。

pom.xml

<?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>JavaServletLog4j</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>JavaServletLog4j</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.apache.logging.log4j</groupId>
            <artifactId>log4j-web</artifactId>
            <version>2.8.2</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>

这是 Maven POM 文件。 我们有两个工件:用于服务器小程序的javax.servlet-api和用于 Web 应用中 Log4j 记录的log4j-webmaven-war-plugin负责收集 Web 应用的所有工件依赖项,类和资源,并将它们打包到 Web 应用存档(WAR)中。

context.xml

<?xml version="1.0" encoding="UTF-8"?>
<Context path="/JavaServletLog4j"/>

在 Tomcat context.xml文件中,我们定义了上下文路径。 它是 Web 应用的名称。

log4j2.xml

<?xml version="1.0" encoding="utf-8"?>
<Configuration status="info">

  <Properties>
    <Property name="logdir">/home/janbodnar/tmp</Property>
    <Property name="layout">%d [%t] %-5p %c- %m%n</Property>
  </Properties>

  <Appenders>

    <RollingFile name="LOCALHOST"
        fileName="${logdir}/localhost.log"
        filePattern="${logdir}/localhost.%d{yyyy-MM-dd}-%i.log">
      <PatternLayout pattern="${layout}"/>
      <Policies>
        <TimeBasedTriggeringPolicy />
        <SizeBasedTriggeringPolicy size="1 MB" />
      </Policies>
      <DefaultRolloverStrategy max="10" />
    </RollingFile>

  </Appenders>

  <Loggers>

    <Logger name="com.zetcode"
        level="info" additivity="false">
      <AppenderRef ref="LOCALHOST" />
    </Logger>

    <Root level="error">
    </Root>    

  </Loggers>
</Configuration>

log4j2.xml中配置 Log4j。 在我们的示例中,我们选择了 XML 文件格式。

<Properties>
  <Property name="logdir">/home/janbodnar/tmp</Property>
  <Property name="layout">%d [%t] %-5p %c - %m%n</Property>
</Properties>

Properties标记中,我们设置了日志目录和布局。 布局定义了日志的格式。

模式布局由转换说明符组成。 每个说明符均以百分号开头,后跟可选的格式修饰符和强制转换字符。 %d输出记录事件的日期。 %t输出生成日志事件的线程的名称。 %-5p输出记录事件的级别,级别名称中至少要包含五个字符,并且这些字符必须对齐。 %c输出发布了记录事件的记录器的名称。 %m打印与日志记录事件关联的应用消息,%n是平台相关的行分隔符或多个字符。

<Appenders>
...
</Appenders>

附加项是定义日志消息保存位置的对象。 有几个可能的目的地,包括控制台,文件,数据库表或原型。

<RollingFile name="LOCALHOST"
    fileName="${logdir}/localhost.log"
    filePattern="${logdir}/localhost.%d{yyyy-MM-dd}-%i.log">
  <PatternLayout pattern="${layout}" />
...
  <DefaultRolloverStrategy max="10" />
</RollingFile>

我们设置日志文件的位置。 我们使用滚动文件附加器,该附加器会自动滚动或归档当前日志文件,并继续记录新文件。 PatternLayout设置日志消息的布局。 如果存档数量达到十个,则DefaultRolloverStrategy会删除较旧的存档。

<Policies>
  <TimeBasedTriggeringPolicy />
  <SizeBasedTriggeringPolicy size="1 MB" />
</Policies>

触发策略在Policies标记中定义。 它们控制发生翻转的条件。 在这里,我们使用两个策略:TimeBasedTriggeringPolicySizeBasedTriggeringPolicyTimeBasedTriggeringPolicy根据最具体的日期和时间模式开始翻转; 就我们而言,如果每小时日志文件的大小达到 1MB,则SizeBasedTriggeringPolicy开始翻转。

<Loggers>

  <Logger name="com.zetcode"
      level="info" additivity="false">
    <AppenderRef ref="LOCALHOST" />
  </Logger>

  <Root level="error">
  </Root>    

</Loggers>

Loggers标签中,我们定义了记录器。 它们被称为日志消息目的地。 每个记录器可以配置不同级别的记录。 我们定义一个具有信息记录级别的记录器。 我们将先前定义的滚动文件附加器附加到此记录器。 在additivity设置为false的情况下,日志消息不会传播到其祖先。

MyServlet.java

package com.zetcode.web;

import com.zetcode.service.MyService;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

@WebServlet(name = "MyServlet", urlPatterns = {"/MyServlet"})
public class MyServlet extends HttpServlet {

    final static Logger logger = LogManager.getLogger(MyService.class);

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        logger.info("MyServlet's doGet() called");

        MyService service = new MyService();
        service.doWork();

        response.setContentType("text/plain;charset=UTF-8");

        PrintWriter out = response.getWriter();
        out.print("MyServlet called");
    }
}

这是MyServlet servlet。 它调用服务方法并将文本数据发送回客户端。

final static Logger logger = LogManager.getLogger(MyService.class);

我们从LogManager获取记录器。

logger.info("MyServlet's doGet() called");

我们记录一条信息级别的消息。

MyService service = new MyService();
service.doWork();

我们称为虚拟服务方法。

PrintWriter out = response.getWriter();
out.print("MyServlet called");

我们将文本数据发送给客户端。

MyService.java

package com.zetcode.service;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class MyService {

    final static Logger logger = LogManager.getLogger(MyService.class);

    public void doWork() {

        logger.info("MyService's doWork() called");
    }
}

MyServicedoWork()方法记录信息级别的消息。

index.html

<!DOCTYPE html>
<html>
    <head>
        <title>Home Page</title>
        <meta charset="UTF-8">
    </head>
    <body>
        <a href="MyServlet">Call Servlet</a>
    </body>
</html>

主页包含一个调用MyServlet的链接。

$ cat localhost.log 
2017-11-14 16:50:30,157 [http-nio-8084-exec-5] INFO  com.zetcode.service.MyService- MyServlet's doGet() called
2017-11-14 16:50:31,044 [http-nio-8084-exec-5] INFO  com.zetcode.service.MyService- MyService's doWork() called

这是已记录消息的示例输出。

在本教程中,我们已经在 Java Web 应用中使用 Log4j 完成了一些日志记录。

您可能也对以下相关教程感兴趣: Java Log4j 教程Java Servlet RESTful 客户端Java Servlet 上传文件Java RequestDispatcher从 Java servlet 提供纯文本Java servlet 复选框教程Java servlet 图像教程Java Servlet HTTP 标头Java 教程

Java Servlet 图表教程

http://zetcode.com/articles/javaservletchart/

Java Servlet 图表教程展示了如何使用 JFreeChart 创建图表并将其提供给 Servlet。 该示例生成一个饼图。

Servlet是 Java 类,可响应特定类型的网络请求-最常见的是 HTTP 请求。 Servlet 用于以 Java 实现 Web 应用。 它们在 Tomcat 或 Jetty 之类的 servlet 容器中运行。 如今,Java Web 程序员使用基于 Servlet 构建的框架来开发应用。

Jetty 是 HTTP 服务器和 Servlet 容器,能够通过独立或嵌入式实例提供静态和动态内容。

JFreeChart 是流行的 Java 图表库。 它允许创建各种交互式和非交互式图表。

Java Servlet 图表示例

下面的示例使用 JFreeChart 库创建一个饼图,并将其提供给 Java Servlet。

pom.xml

<?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>servletchart</artifactId>
    <version>1.0-SNAPSHOT</version>

    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>12</maven.compiler.source>
        <maven.compiler.target>12</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.jfree</groupId>
            <artifactId>jfreechart</artifactId>
            <version>1.5.0</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.2</version>
            </plugin>

            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>9.4.14.v20181114</version>
            </plugin>
        </plugins>
    </build>

</project>

javax.servlet-api依赖项是用于构建 Java Servlet 的库。 jfreechart是 JFreeChart 库的依赖项。

maven-war-plugin收集 Web 应用的所有工件依赖项,类和资源,并将它们打包到 Web 应用存档(WAR)中。 jetty-maven-plugin允许我们与mvn jetty:run一起运行嵌入式 Jetty 服务器。

pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           └───web
│   │                   DoChart.java
│   ├───resources
│   └───webapp
│           index.html
└───test
    └───java

这是项目结构。

webapp/index.html

<!DOCTYPE html>
<html>
    <head>
        <title>Chart</title>
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta charset="UTF-8">
    </head>
    <body>
        <a href="showChart">Show chart</a>
    </body>
</html>

index.html文件中,我们有一个调用 servlet 的链接,该 servlet 服务于饼图。

com/zetcode/web/DoChart.java

package com.zetcode.web;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtils;
import org.jfree.chart.JFreeChart;
import org.jfree.data.general.DefaultPieDataset;

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

@WebServlet(name = "DoChart", urlPatterns = {"/showChart"})
public class DoChart extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws IOException {

        response.setContentType("image/png");

        OutputStream os = response.getOutputStream();

        JFreeChart chart = getChart();
        int width = 500;
        int height = 350;

        ChartUtils.writeChartAsPNG(os, chart, width, height);
    }

    public JFreeChart getChart() {

        var dataset = new DefaultPieDataset();

        dataset.setValue("Croatia", 22);
        dataset.setValue("Bohemia", 34);
        dataset.setValue("Bulgaria", 18);
        dataset.setValue("Spain", 5);
        dataset.setValue("Others", 21);

        JFreeChart chart = ChartFactory.createPieChart("Popular destinations",
                dataset, true, false, false);

        chart.setBorderVisible(false);

        return chart;
    }
}

DoChart Servlet 将饼图返回给客户端。

@WebServlet(name = "DoChart", urlPatterns = {"/showChart"})

@WebServlet批注将具有showChart URL 模式的请求映射到DoChart servlet。

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws IOException {

该请求是一个 GET 请求,因此我们以doGet()方法为其提供服务。

response.setContentType("image/png");

该图表用作 PNG 格式的图像; 因此,我们将响应的内容类型设置为image/png

OutputStream os = response.getOutputStream();

response对象获得OutputStream。 我们通过写 servlet 的OutputStream将图表提供给客户端。

ChartUtils.writeChartAsPNG(os, chart, width, height);

ChartUtils.writeChartAsPNG()将图表转换为 PNG 文件,并将其写入输出流。

public JFreeChart getChart() {

    var dataset = new DefaultPieDataset();

    dataset.setValue("Croatia", 22);
    dataset.setValue("Bohemia", 34);
    dataset.setValue("Bulgaria", 18);
    dataset.setValue("Spain", 5);
    dataset.setValue("Others", 21);

    JFreeChart chart = ChartFactory.createPieChart("Popular destinations",
            dataset, true, false, false);

    chart.setBorderVisible(false);

    return chart;
}

getChart()方法中,我们生成图表。 DefaultPieDataset包含饼图的数据。

JFreeChart chart = ChartFactory.createPieChart("Popular destinations",
        dataset, true, false, false);

使用ChartFactory.createPieChart()创建饼图。

条形图

以下代码是发送条形图的替代解决方案。

public JFreeChart getChart() {

    DefaultCategoryDataset dataset = new DefaultCategoryDataset();
    dataset.setValue(46, "Gold medals", "USA");
    dataset.setValue(38, "Gold medals", "China");
    dataset.setValue(29, "Gold medals", "UK");
    dataset.setValue(22, "Gold medals", "Russia");
    dataset.setValue(13, "Gold medals", "South Korea");
    dataset.setValue(11, "Gold medals", "Germany");

    JFreeChart barChart = ChartFactory.createBarChart(
            "Olympic gold medals in London",
            "",
            "Gold medals",
            dataset,
            PlotOrientation.VERTICAL,
            false, true, false);

    return barChart;
}

使用ChartFactory.createBarChart()创建条形图。

$ mvn jetty:run

运行 Jetty 服务器并导航到localhost:8080

在本教程中,我们使用了 Java Servlet 中的 JFreeChart 库创建饼图并将其提供给客户端。

您可能也对以下相关教程感兴趣: JFreeChart 教程Java 教程

列出所有 Java Servlet 教程

Java ServletConfig教程

原文: http://zetcode.com/articles/javaservletconfig/

Java ServletConfig教程展示了如何使用ServletConfig将初始化数据传递给 Servlet。

ServletConfig是 servlet 容器使用的 servlet 配置对象,用于在初始化期间将信息传递给 servlet。 Servlet 容器为 Web 应用中的每个 Servlet 创建一个ServletConfig

Java Servlet

Servlet 是 Java 类,可响应特定类型的网络请求-最常见的是 HTTP 请求。 Java servlet 用于创建 Web 应用。 它们在 servlet 容器(例如 Tomcat 或 Jetty)中运行。 现代 Java Web 开发使用在 servlet 之上构建的框架。

Pure.css

Pure.css 是一组小型的响应式 CSS 模块,可以在每个 Web 项目中使用。 该库是由 Yahoo 创建的。

Java ServletConfig示例

在以下 Web 应用中,我们有一个简单的 Web 表单。 我们向 Servlet 发送了一个名称参数。 如果参数为空,则通过ServletConfig读取初始化参数。 在示例中,我们还使用 Yahoo 的 Pure.css 库。

$ tree
.
├── nb-configuration.xml
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── zetcode
    │   │           └── web
    │   │               └── MyServlet.java
    │   └── webapp
    │       ├── index.html
    │       ├── META-INF
    │       │   └── context.xml
    │       └── WEB-INF
    └── test
        └── java

这是项目结构。

pom.xml

<?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>JavaServletConfigEx</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>JavaServletConfigEx</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>
    </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>

这是 Maven pom.xml文件。 javax.servlet-api工件用于 Java Servlet。 maven-war-plugin负责收集 Web 应用的所有工件依赖项,类和资源,并将它们打包到 Web 应用存档(WAR)中。

context.xml

<?xml version="1.0" encoding="UTF-8"?>
<Context path="/JavaServletConfigEx"/>

在 Tomcat context.xml文件中,我们定义了上下文路径。 它是 Web 应用的名称。

index.html

<!DOCTYPE html>
<html>
    <head>
        <title>Home Page</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="https://unpkg.com/purecss@1.0.0/build/pure-min.css">
    </head>
    <body>
        <form class="pure-form" action="MyServlet">
            <fieldset>
                <legend>Enter your name</legend>

                <input type="text" name="name">
                <button type="submit" class="pure-button pure-button-primary">Submit</button>
            </fieldset>
        </form>
    </body>
</html>

这是主页。 它包含一个HTML表格。 提交表单后,处理将发送到MyServlet

<link rel="stylesheet" href="https://unpkg.com/purecss@1.0.0/build/pure-min.css">

我们包括 Pure.css 库。

<form class="pure-form" action="MyServlet">

form标记使用 Pure.css 库中的pure-form类。 action属性指向MyServlet

<input type="text" name="name">

用户输入的名称值将作为name参数发送到 servlet。

<button type="submit" class="pure-button pure-button-primary">Submit</button>

提交按钮使用pure-buttonpure-button-primary类。

MyServlet.java

package com.zetcode.web;

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

@WebServlet(name = "MyServlet", urlPatterns = {"/MyServlet"}, initParams = {
    @WebInitParam(name = "name", value = "Guest")})
public class MyServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("text/plain;charset=UTF-8");

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

        if (name.isEmpty()) {

            ServletConfig sc = getServletConfig();

            name = sc.getInitParameter("name");
        }

        ServletOutputStream os = response.getOutputStream();
        os.println("Hello " + name);
    }
}

MyServlet从请求中读取name属性并生成输出。 输出为纯文本。

@WebServlet(name = "MyServlet", urlPatterns = {"/MyServlet"}, initParams = {
    @WebInitParam(name = "name", value = "Guest")})

使用@WebInitParam,将name参数初始化为"Guest"值。

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

我们从请求对象和修剪空间读取name参数。

if (name.isEmpty()) {

    ServletConfig sc = getServletConfig();

    name = sc.getInitParameter("name");
}

如果用户未输入任何值,我们将使用ServletConfig读取name初始化参数。 使用getServletConfig()检索ServletConfig。 使用getInitParameter()检索参数。

ServletOutputStream os = response.getOutputStream();
os.println("Hello " + name);

我们将文本消息写入ServletOutputStream

在本教程中,我们使用ServletConfig来读取 Java Servlet 中的初始化参数。

您可能也对以下相关教程感兴趣: Java Servlet RESTful 客户端Java Servlet PDF 教程Java RequestDispatcher从 servlet 提供纯文本Java Servlet 上传文件Java servlet 图像教程Java Servlet HTTP 标头Java 教程

Java Servlet 读取网页

http://zetcode.com/articles/javaservletreadwebpage/

Java Servlet 读取网页教程向您展示了如何使用 Servlet 在 Java Web 应用中读取网页。

Java Servlet

Servlet 是响应网络请求的 Java 类。 Java servlet 用于构建 Web 应用。 它们在 servlet 容器(例如 Tomcat 或 Jetty)中运行。 现代 Java Web 开发使用的框架是在 Servlet 之上构建的,包括 Spring 和 Vaadin。

Apache Commons Validator 是用于验证数据的 Java 库。 我们使用此库来验证正确的 URL 值。

Java Servlet 读取网页示例

在下面的示例中,我们读取带有InputStream的网页,并向客户端显示该页面的 HTML 代码。 网页的名称是从 HTML 表单的input标签发送的。

$ tree
.
├── nb-configuration.xml
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── zetcode
    │   │           ├── service
    │   │           │   └── WebPageReader.java
    │   │           └── web
    │   │               └── ReadWebpage.java
    │   └── webapp
    │       ├── index.html
    │       ├── META-INF
    │       │   └── context.xml
    │       └── WEB-INF
    └── test
        └── java

这是项目结构。

<dependencies>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>
        <scope>provided</scope>

    </dependency>

    <dependency>
        <groupId>commons-validator</groupId>
        <artifactId>commons-validator</artifactId>
        <version>1.6</version>
    </dependency>        

</dependencies>

我们需要这两个 Maven 依赖项。 javax.servlet-api工件用于 servlet。 commons-validator依赖项用于数据验证。

context.xml

<?xml version="1.0" encoding="UTF-8"?>
<Context path="/JavaServletReadWebpage"/>

在 Tomcat context.xml文件中,我们定义了上下文路径。 它是 Web 应用的名称。

ReadWebPage.java

package com.zetcode.web;

import com.zetcode.service.WebPageReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name = "ReadWebPage", urlPatterns = {"/ReadWebPage"})
public class ReadWebpage extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("text/plain;charset=UTF-8");

        String page = request.getParameter("webpage");

        String content = new WebPageReader().setWebPageName(page).getWebPageContent();

        ServletOutputStream os = response.getOutputStream();
        os.write(content.getBytes(StandardCharsets.UTF_8));
    }
}

ReadWebPage Servlet 读取给定网页的内容,并将文本发送给客户端。

response.setContentType("text/plain;charset=UTF-8");

响应为纯文本,文本编码为 UTF-8。

String page = request.getParameter("webpage");

我们使用getParameter()从请求参数获取网页的名称。

String content = new WebPageReader().setWebPageName(page).getWebPageContent();

WebPageReader用于获取网页的内容。

ServletOutputStream os = response.getOutputStream();
os.write(content.getBytes(StandardCharsets.UTF_8));

我们通过ServletOutputStream将数据发送给客户端。

WebPageReader.java

package com.zetcode.service;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import org.apache.commons.validator.routines.UrlValidator;

public class WebPageReader {

    private String webpage;
    private String content;

    public WebPageReader setWebPageName(String name) {

        webpage = name;
        return this;
    }

    public String getWebPageContent() {

        try {

            boolean valid = validateUrl(webpage);

            if (!valid) {

                content = "Invalid URL; use http(s)://www.example.com format";
                return content;
            }

            URL url = new URL(webpage);

            try (InputStream is = url.openStream();
                    BufferedReader br = new BufferedReader(
                            new InputStreamReader(is, StandardCharsets.UTF_8))) {

                content = br.lines().collect(
                      Collectors.joining(System.lineSeparator()));
            }

        } catch (IOException ex) {

            content = String.format("Cannot read webpage %s", ex);
            Logger.getLogger(WebPageReader.class.getName()).log(Level.SEVERE, null, ex);
        }

        return content;
    }

    private boolean validateUrl(String webpage) {

        UrlValidator urlValidator = new UrlValidator();

        return urlValidator.isValid(webpage);
    }
}

WebPageReader读取网页的内容。

private boolean validateUrl(String webpage) {

    UrlValidator urlValidator = new UrlValidator();

    return urlValidator.isValid(webpage);
}

在阅读网页之前,我们使用 Apache Commons Validator 库中的UrlValidator验证 URL。

URL url = new URL(webpage);

try (InputStream is = url.openStream();
        BufferedReader br = new BufferedReader(
                new InputStreamReader(is, StandardCharsets.UTF_8))) {

    content = br.lines().collect(
            Collectors.joining(System.lineSeparator()));
}

通过InputStream读取网页。 数据被加载到String中。 或者,我们可以使用 JSoup 库。

index.html

<!DOCTYPE html>
<html>
    <head>
        <title>Home page</title>
        <meta charset="UTF-8">
    </head>
    <body>
        <form action="ReadWebPage">

            <label for="page">Enter a web page name:</label>
            <input  type="text" id="page" name="webpage">

            <button type="submit">Submit</button>

        </form>
    </body>
</html>

主页包含表单,该表单将要阅读的网页发送到应用。 请注意,必须以完整的http(s)://www.example.com格式输入网页。

Java read web page

图:Java 阅读网页

在屏幕截图中,我们可以看到一个简单网页的内容。

在本教程中,我们创建了一个 Java Servlet 应用,该应用读取所选网页的内容,并将 HTML 以纯文本格式发送回客户端。

您可能也对以下相关教程感兴趣: Java 阅读网页Java Servlet 上传文件Java Log4j 教程Java Servlet RESTful 客户端Java RequestDispatcher从 Java servlet 提供纯文本Java servlet 图像教程Java 教程

嵌入式 Tomcat

原文: https://zetcode.com/web/embeddedtomcat/

在本教程中,我们将展示如何与嵌入式 Tomcat 服务器一起使用。 Tomcat 可以在嵌入式模式下运行; 这意味着无需构建 WAR 文件并将其部署在独立的 Tomcat 服务器中。 本教程中的示例是使用 Maven 构建的。

Tomcat

Apache Tomcat 是 Java Servlet,JavaServer Pages,Java Expression Language 和 Java WebSocket 技术的开源实现。

Apache Maven 是一个软件项目管理和理解工具。 该项目在名为pom.xml的 XML 文件中描述。 它包含对其他外部模块和组件的项目依赖关系,构建顺序,目录和所需的插件。

创建一个 servlet

在下面的示例中,我们创建一个带有嵌入式 Tomcat 服务器的命令行 Java 应用。 该应用附加一个简单的 servlet。

Project structure

图:项目结构

该图显示了 NetBeans 中的项目结构。 注意,我们使用的是 Java Maven 控制台应用,而不是 Maven Web 应用。

pom.xml

<?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>EmbeddedTomcatEx</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <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>
        <tomcat.version>9.0.0.M6</tomcat.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
        </dependency>         
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-core</artifactId>
            <version>${tomcat.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-logging-juli</artifactId>
            <version>${tomcat.version}</version>
        </dependency>

    </dependencies>    

    <build>    
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>appassembler-maven-plugin</artifactId>
                <version>1.1.1</version>
                <configuration>
                    <assembleDirectory>target</assembleDirectory>
                    <programs>
                        <program>
                            <mainClass>com.zetcode.embedded.EmbeddedTomcatEx</mainClass>
                            <name>webapp</name>
                        </program>
                    </programs>
                </configuration>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>assemble</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>    
    </build>

</project>

Maven pom.xml包含嵌入式 Tomcat 服务器和用于构建应用的汇编程序插件的依赖项。 由于我们只有 Servlet,因此 JSP 容器的依赖关系未包含在此应用中。

EmbeddedTomcatEx.java

package com.zetcode.embedded;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.Writer;
import org.apache.catalina.Context;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.startup.Tomcat;

public class EmbeddedTomcatEx {

    public static void main(String[] args) throws LifecycleException,
            InterruptedException, ServletException {

        Tomcat tomcat = new Tomcat();
        tomcat.setPort(8082);

        Context ctx = tomcat.addContext("/", new File(".").getAbsolutePath());

        Tomcat.addServlet(ctx, "Embedded", new HttpServlet() {
            @Override
            protected void service(HttpServletRequest req, HttpServletResponse resp) 
                    throws ServletException, IOException {

                Writer w = resp.getWriter();
                w.write("Embedded Tomcat servlet.\n");
                w.flush();
                w.close();
            }
        });

        ctx.addServletMapping("/*", "Embedded");

        tomcat.start();
        tomcat.getServer().await();
    }
}

EmbeddedTomcatEx是 Java 控制台应用,其中包括嵌入式 Tomcat 服务器。

Tomcat tomcat = new Tomcat();
tomcat.setPort(8082);

Tomcat 在端口 8082 上启动。默认端口为 8080;默认端口为 8080。 NetBeans 将 8084 用于其内置的 Tomcat 服务器。 我们选择了另一个端口,以免发生冲突。

Context ctx = tomcat.addContext("/", new File(".").getAbsolutePath());

每个应用都映射到上下文。 使用addContext()方法,我们创建了一个不支持 JSP 文件并且没有web.xml文件的应用。 我们使用根上下文路径和当前工作目录作为文档库。

Tomcat.addServlet(ctx, "Embedded", new HttpServlet() {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) 
            throws ServletException, IOException {

        Writer w = resp.getWriter();
        w.write("Embedded Tomcat servlet.\n");
        w.flush();
        w.close();
    }
});

通过addServlet()方法添加了一个新的 servlet。 该 servlet 仅以一些 ASCII 文本作为响应。

ctx.addServletMapping("/*", "Embedded");

servlet 映射控制如何访问名为 Embedded 的 servlet。 对于我们的示例,所有 URL 最终都会调用我们的 servlet。

tomcat.start();
tomcat.getServer().await();

Tomcat 服务器已启动。

$ curl localhost:8082/
Embedded Tomcat servlet.

我们运行该应用并使用curl工具对其进行测试。

JSP 文件

在第二个示例中,我们使用嵌入式 Tomcat 服务器来提供 JSP 文件。

pom.xml

<?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>EmbeddedTomcatEx2</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <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>
        <tomcat.version>9.0.0.M6</tomcat.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
        </dependency>         
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-core</artifactId>
            <version>${tomcat.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-logging-juli</artifactId>
            <version>${tomcat.version}</version>
        </dependency>

        <dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-jasper</artifactId>
            <version>${tomcat.version}</version>
        </dependency>

        <dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-jasper-el</artifactId>
            <version>${tomcat.version}</version>
        </dependency>

        <dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-jsp-api</artifactId>
            <version>${tomcat.version}</version>
        </dependency>        

    </dependencies>    

    <build>

        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>appassembler-maven-plugin</artifactId>
                <version>1.1.1</version>
                <configuration>
                    <assembleDirectory>target</assembleDirectory>
                    <programs>
                        <program>
                            <mainClass>com.zetcode.embedded.EmbeddedTomcatEx2</mainClass>
                            <name>webapp</name>
                        </program>
                    </programs>
                </configuration>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>assemble</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>    
    </build>
    <name>EmbeddedTomcatEx2</name>
</project>

在此pom.xml文件中,我们还包括嵌入式 Tomcat JSP 容器的依赖项:tomcat-jaspertomcat-jasper-eltomcat-jsp-api

index.jsp

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <title>JSP file</title>
        <meta charset="UTF-8">
    </head>
    <body>
        <p>
            This is a simple JSP file.            
        </p>
    </body>
</html>

这是嵌入式 Tomcat 服务器提供的简单 JSP 文件。

EmbeddedTomcatEx2.java

package com.zetcode.embedded;

import javax.servlet.ServletException;
import java.io.File;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.startup.Tomcat;

public class EmbeddedTomcatEx2 {

    public static void main(String[] args) throws LifecycleException,
            InterruptedException, ServletException {

        String docBase = "src/main/webapp/";

        Tomcat tomcat = new Tomcat();
        tomcat.setPort(8082);

        tomcat.addWebapp("/", new File(docBase).getAbsolutePath());

        tomcat.start();
        tomcat.getServer().await();
    }
}

该应用提供一个 JSP 文件。 该文件位于src/main/webapp子目录中。

tomcat.addWebapp("/", new File(docBase).getAbsolutePath());

这次我们使用addWebapp()将应用添加到 Tomcat 服务器。

$ curl localhost:8082/

<!DOCTYPE html>
<html>
    <head>
        <title>JSP file</title>
        <meta charset="UTF-8">
    </head>
    <body>
        <p>
            This is a simple JSP file.            
        </p>
    </body>
</html>

当我们访问应用时,我们得到了这个。

这是嵌入式 Tomcat 教程。 使用嵌入式 Tomcat,我们提供了一个 servlet 和一个 JSP 文件。 我们已经使用了 Apache Tomcat,Maven 和 NetBeans。 您可能还需要查看一些相关的教程:嵌入式 Jetty 的 Jersey 应用Jetty 教程Java 教程SQL 查询标记教程

Java Servlet 分页

原文: http://zetcode.com/articles/javaservletpagination/

Java servlet 分页教程显示了如何使用 Java servlet 进行分页。 在示例中,Bootstrap 用于 UI。

分页

分页是将内容分为几页的过程。 用户具有用于通过特定页面链接访问这些页面的导航界面。 导航通常包括上一个/下一个和第一个/最后一个链接。 当数据库中有大量数据或一页中显示许多项时,将使用分页。

Java Servlet

Servlet 是 Java 类,可响应特定类型的网络请求-最常见的是 HTTP 请求。 Java servlet 用于创建 Web 应用。 它们在 servlet 容器(例如 Tomcat 或 Jetty)中运行。 现代 Java Web 开发使用在 servlet 之上构建的框架。

Bootstrap

Bootstrap 是 Twitter 的一个 UI 库,用于创建响应式,移动优先的 Web 应用。

Java Servlet 分页示例

在以下应用中,我们从 MySQL 数据库加载数据并将其显示在表中。 有一个导航系统可以遍历数据库表中的所有数据。 在将数据显示在表中之前,用户可以选择表将显示多少行。

除了从数据库表中获取数据之外,我们还需要知道数据库表中所有行的数量,每页的记录数以及要在导航中显示的页面数。 SQL 语句可以计算出数据库中所有行的数量。 用户以 HTML 格式选择每页的记录数。 最后,从其他两个值计算分页中的页数。

countries_mysql.sql

CREATE TABLE Countries(ID BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT, 
    Name VARCHAR(100), Population INT);

INSERT INTO Countries(Name, Population) VALUES('China', 1382050000);
INSERT INTO Countries(Name, Population) VALUES('India', 1313210000);
INSERT INTO Countries(Name, Population) VALUES('USA', 324666000);
INSERT INTO Countries(Name, Population) VALUES('Indonesia', 260581000);
INSERT INTO Countries(Name, Population) VALUES('Brazil', 207221000);
INSERT INTO Countries(Name, Population) VALUES('Pakistan', 196626000);
INSERT INTO Countries(Name, Population) VALUES('Nigeria', 186988000);
INSERT INTO Countries(Name, Population) VALUES('Bangladesh', 162099000);
INSERT INTO Countries(Name, Population) VALUES('Nigeria', 186988000);
INSERT INTO Countries(Name, Population) VALUES('Russia', 146838000);
INSERT INTO Countries(Name, Population) VALUES('Japan', 126830000);
INSERT INTO Countries(Name, Population) VALUES('Mexico', 122273000);
INSERT INTO Countries(Name, Population) VALUES('Philippines', 103738000);
INSERT INTO Countries(Name, Population) VALUES('Ethiopia', 101853000);
INSERT INTO Countries(Name, Population) VALUES('Vietnam', 92700000);
INSERT INTO Countries(Name, Population) VALUES('Egypt', 92641000);
INSERT INTO Countries(Name, Population) VALUES('Germany', 82800000);
INSERT INTO Countries(Name, Population) VALUES('the Congo', 82243000);
INSERT INTO Countries(Name, Population) VALUES('Iran', 82800000);
INSERT INTO Countries(Name, Population) VALUES('Turkey', 79814000);
INSERT INTO Countries(Name, Population) VALUES('Thailand', 68147000);
INSERT INTO Countries(Name, Population) VALUES('France', 66984000);
INSERT INTO Countries(Name, Population) VALUES('United Kingdom', 60589000);
INSERT INTO Countries(Name, Population) VALUES('South Africa', 55908000);
INSERT INTO Countries(Name, Population) VALUES('Myanmar', 51446000);
INSERT INTO Countries(Name, Population) VALUES('South Korea', 68147000);
INSERT INTO Countries(Name, Population) VALUES('Colombia', 49129000);
INSERT INTO Countries(Name, Population) VALUES('Kenya', 47251000);
INSERT INTO Countries(Name, Population) VALUES('Spain', 46812000);
INSERT INTO Countries(Name, Population) VALUES('Argentina', 43850000);
INSERT INTO Countries(Name, Population) VALUES('Ukraine', 42603000);
INSERT INTO Countries(Name, Population) VALUES('Sudan', 41176000);
INSERT INTO Countries(Name, Population) VALUES('Algeria', 40400000);
INSERT INTO Countries(Name, Population) VALUES('Poland', 38439000);

该 SQL 脚本在 MySQL 中创建Countries表。

$ tree
.
├── nb-configuration.xml
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── zetcode
    │   │           ├── bean
    │   │           │   └── Country.java
    │   │           ├── service
    │   │           │   ├── CountryService.java
    │   │           │   └── ICountryService.java
    │   │           └── web
    │   │               └── ReadCountries.java
    │   ├── resources
    │   └── webapp
    │       ├── index.html
    │       ├── listCountries.jsp
    │       ├── META-INF
    │       │   └── context.xml
    │       └── WEB-INF
    └── test
        └── java

这是项目结构。

pom.xml

<?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>JavaServletPagination</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>JavaServletPagination</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.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.45</version>
        </dependency>        

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</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>

这是 Maven POM 文件。 javax.servlet-api工件用于 servlet。 spring-jdbc依赖项用于JdbcTemplate库,该库简化了 Java 中的数据库编程。 mysql-connector-java是 Java 语言的 MySQL 驱动程序。 jstl依赖项为 JSP 页面提供了一些附加功能。 maven-war-plugin负责收集 Web 应用的所有工件依赖项,类和资源,并将它们打包到 Web 应用存档(WAR)中。

context.xml

<?xml version="1.0" encoding="UTF-8"?>
<Context path="/JavaServletPagination"/>

在 Tomcat context.xml文件中,我们定义了上下文路径。 它是 Web 应用的名称。

Country.java

package com.zetcode.bean;

public class Country {

    private String name;
    private int population;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getPopulation() {
        return population;
    }

    public void setPopulation(int population) {
        this.population = population;
    }
}

Country bean 从Countries数据库表中保留一行。

ReadCountries.java

package com.zetcode.web;

import com.zetcode.bean.Country;
import com.zetcode.service.CountryService;
import java.io.IOException;
import java.util.List;
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 = "ReadCountries", urlPatterns = {"/ReadCountries"})
public class ReadCountries extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("text/html;charset=UTF-8");

        int currentPage = Integer.valueOf(request.getParameter("currentPage"));
        int recordsPerPage = Integer.valueOf(request.getParameter("recordsPerPage"));

        CountryService countryService = new CountryService();

        List<Country> countries = countryService.findCountries(currentPage, 
                recordsPerPage);

        request.setAttribute("countries", countries);

        int rows = countryService.getNumberOfRows();

        int nOfPages = rows / recordsPerPage;

        if (nOfPages % recordsPerPage > 0) {
            nOfPages++;
        }

        request.setAttribute("noOfPages", nOfPages);
        request.setAttribute("currentPage", currentPage);
        request.setAttribute("recordsPerPage", recordsPerPage);

        RequestDispatcher dispatcher = request.getRequestDispatcher("listCountries.jsp");
        dispatcher.forward(request, response);
    }
}

ReadCountries Servlet 确定将从请求属性中检索多少数据,并从数据库表中读取指定的行数。

@WebServlet(name = "ReadCountries", urlPatterns = {"/ReadCountries"})

Java 类用@WebServlet注解修饰。 它映射到ReadCountries URL 模式。

response.setContentType("text/html;charset=UTF-8");

Servlet 将以 HTML 输出数据,并且数据的编码设置为 UTF-8。

int currentPage = Integer.valueOf(request.getParameter("currentPage"));
int recordsPerPage = Integer.valueOf(request.getParameter("recordsPerPage"));

从请求中我们得到两个重要的值:当前页和每页的记录数。

CountryService countryService = new CountryService();

List<Country> countries = countryService.findCountries(currentPage, 
        recordsPerPage);

request.setAttribute("countries", countries);

CountryService是用于连接到数据库并读取数据的服务类。 检索国家列表并将其设置为请求的属性。 稍后将由目标 JSP 页面使用。

int rows = countryService.getNumberOfRows();

int nOfPages = rows / recordsPerPage;

if (nOfPages % recordsPerPage > 0) {
    nOfPages++;
}

我们使用getNumberOfRows()服务方法从数据库表中获取所有行的数目。 我们计算导航中的页面数。

request.setAttribute("noOfPages", nOfPages);
request.setAttribute("currentPage", currentPage);
request.setAttribute("recordsPerPage", recordsPerPage);

页数,当前页和每页的记录数是我们建立分页所需的值。

RequestDispatcher dispatcher = request.getRequestDispatcher("listCountries.jsp");
dispatcher.forward(request, response);

处理被转发到listCountries.jsp页面。

ICountryService.java

package com.zetcode.service;

import com.zetcode.bean.Country;
import java.util.List;

public interface ICountryService  {

    public List<Country> findCountries(int currentPage, int numOfRecords);
    public int getNumberOfRows();
}

ICountryService包含两种签约方法:findCountries()getNumberOfRows()

CountryService.java

package com.zetcode.service;

import com.zetcode.bean.Country;
import java.sql.SQLException;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.SimpleDriverDataSource;

public class CountryService implements ICountryService {

    @Override
    public List<Country> findCountries(int currentPage, int recordsPerPage)  {

        List<Country> countries = null;

        int start = currentPage * recordsPerPage - recordsPerPage;

        try {
            String sql = "SELECT * FROM Countries LIMIT ?, ?";

            SimpleDriverDataSource ds = new SimpleDriverDataSource();
            ds.setDriver(new com.mysql.jdbc.Driver());
            ds.setUrl("jdbc:mysql://localhost:3306/testdb");
            ds.setUsername("testuser");
            ds.setPassword("test623");

            JdbcTemplate jtm = new JdbcTemplate(ds);
            countries = jtm.query(sql, new Object[] {start, recordsPerPage}, 
                    new BeanPropertyRowMapper(Country.class));

        } catch (SQLException ex) {
            Logger.getLogger(CountryService.class.getName()).log(Level.SEVERE, 
                null, ex);
        }

        return countries;
    }    

    @Override
    public int getNumberOfRows() {

        int numOfRows = 0;

        try {
            String sql = "SELECT COUNT(Id) FROM Countries";

            SimpleDriverDataSource ds = new SimpleDriverDataSource();
            ds.setDriver(new com.mysql.jdbc.Driver());
            ds.setUrl("jdbc:mysql://localhost:3306/testdb");
            ds.setUsername("testuser");
            ds.setPassword("test623");

            JdbcTemplate jtm = new JdbcTemplate(ds);
            numOfRows = jtm.queryForObject(sql, Integer.class);

        } catch (SQLException ex) {
            Logger.getLogger(CountryService.class.getName()).log(Level.SEVERE, 
                null, ex);
        }

        return numOfRows;
    }
}

CountryService包含两种合同方法的实现。

String sql = "SELECT * FROM Countries LIMIT ?, ?";

SQL LIMIT子句用于获取当前页面的行数。

JdbcTemplate jtm = new JdbcTemplate(ds);
countries = jtm.query(sql, new Object[] {start, recordsPerPage}, 
        new BeanPropertyRowMapper(Country.class));

JdbcTemplate用于执行 SQL 语句。 在BeanPropertyRowMapper的帮助下,行自动映射到Country bean。

String sql = "SELECT COUNT(Id) FROM Countries";

通过此 SQL 语句,我们从数据库表中获取行数。

index.html

<!DOCTYPE html>
<html>
<head>
    <title>Home page</title>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css">        
</head>

<body class="m-3">

<h1>Show countries</h1>

<form action="ReadCountries">

    <input type="hidden" name="currentPage" value="1">

    <div class="form-group col-md-4">

        <label for="records">Select records per page:</label>

        <select class="form-control" id="records" name="recordsPerPage"> 
            <option value="5">5</option> 
            <option value="10" selected>10</option>
            <option value="15">15</option>
        </select>

    </div>

    <button type="submit" class="btn btn-primary">Submit</button>

</form>

<script src="https://code.jquery.com/jquery-3.1.1.slim.min.js" ></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.4.0/js/tether.min.js" ></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/js/bootstrap.min.js" ></script>

</body>
</html>

这是主页。 它包含一个 HTML 表单,用于通过select标签选择每页的记录数。 该表单使用 Bootstrap 库中的样式类。 提交表单后,处理将发送到ReadCountries Servlet。

<input type="hidden" name="currentPage" value="1">

该表单包含一个隐藏的input标记,该标记将currentPage参数设置为 1。

<select class="form-control" id="records" name="recordsPerPage"> 
    <option value="5">5</option> 
    <option value="10" selected>10</option>
    <option value="15">15</option>
</select>

select标签允许每页选择 5、10 或 15 条记录。

<button type="submit" class="btn btn-primary">Submit</button>

提交按钮执行表单。

listCountries.jsp

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Countries</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css">
</head>

<body class="m-3">

<div class="row col-md-6">
    <table class="table table-striped table-bordered table-sm">
        <tr>
            <th>Name</th>
            <th>Population</th>
        </tr>

        <c:forEach items="${countries}" var="country">
            <tr>
                <td>${country.getName()}</td>
                <td>${country.getPopulation()}</td>    
            </tr>
        </c:forEach>
    </table>
</div>

<nav aria-label="Navigation for countries">
    <ul class="pagination">
        <c:if test="${currentPage != 1}">
            <li class="page-item"><a class="page-link" 
                href="ReadCountries?recordsPerPage=${recordsPerPage}&currentPage=${currentPage-1}">Previous</a>
            </li>
        </c:if>

        <c:forEach begin="1" end="${noOfPages}" var="i">
            <c:choose>
                <c:when test="${currentPage eq i}">
                    <li class="page-item active"><a class="page-link">
                            ${i} <span class="sr-only">(current)</span></a>
                    </li>
                </c:when>
                <c:otherwise>
                    <li class="page-item"><a class="page-link" 
                        href="ReadCountries?recordsPerPage=${recordsPerPage}&currentPage=${i}">${i}</a>
                    </li>
                </c:otherwise>
            </c:choose>
        </c:forEach>

        <c:if test="${currentPage lt noOfPages}">
            <li class="page-item"><a class="page-link" 
                href="ReadCountries?recordsPerPage=${recordsPerPage}&currentPage=${currentPage+1}">Next</a>
            </li>
        </c:if>              
    </ul>


<script src="https://code.jquery.com/jquery-3.1.1.slim.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.4.0/js/tether.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/js/bootstrap.min.js"></script>

</body>
</html>

listCountries.jsp在表格和分页系统中显示数据。 Bootstrap 用于使 UI 响应并看起来不错。

<table class="table table-striped table-bordered table-sm">

tabletable-stripedtable-borderedtable-sm都是 Bootstrap 类。

<c:forEach items="${countries}" var="country">
    <tr>
        <td>${country.getName()}</td>
        <td>${country.getPopulation()}</td>    
    </tr>
</c:forEach>

使用 JSTL 的forEach标签,我们可以显示当前页面的所有数据。

<c:if test="${currentPage != 1}">
    <li class="page-item"><a class="page-link" 
        href="ReadCountries?recordsPerPage=${recordsPerPage}&currentPage=${currentPage-1}">Previous</a>
    </li>
</c:if>

使用c:if标签,我们仅在存在前一个链接时显示它。 在链接中,我们将recordsPerPagecurrentPage值传递给请求对象。

<c:forEach begin="1" end="${noOfPages}" var="i">
    <c:choose>
        <c:when test="${currentPage eq i}">
            <li class="page-item active"><a class="page-link">
                    ${i} <span class="sr-only">(current)</span></a>
            </li>
        </c:when>
        <c:otherwise>
            <li class="page-item"><a class="page-link" 
                href="ReadCountries?recordsPerPage=${recordsPerPage}&currentPage=${i}">${i}</a>
            </li>
        </c:otherwise>
    </c:choose>
</c:forEach>

使用forEach标签,我们显示所有页面链接。

Java Servlet Pagination

图:Java Servlet 分页

该示例显示了一个装有数据和分页系统的表。 当前选择的页面突出显示。

在本教程中,我们展示了如何使用 Java Servlet 在 Web 应用中创建分页系统。

您可能也对以下相关教程感兴趣: Java Servlet 上传文件Java Log4j 教程Java Servlet RESTful 客户端Java RequestDispatcher从 Java servlet 提供纯文本Java servlet 图像教程Java 教程

Java Servlet Weld 教程

原文: http://zetcode.com/articles/javaservletweld/

Java Servlet Weld 教程展示了如何在带有 Weld 的 Java Servlet 中使用依赖注入。 我们将 Weld 与 Tomcat Web 服务器一起使用。

依赖注入

依赖项注入(DI)是一种技术,其中一个对象提供另一个对象的依赖项。 对于 Java 应用,它是一个特定的库,可以将依赖项注入到类中。 DI 的主要优点是耦合松散且易于使用。 DI 使类更具凝聚力,因为它们的职责更少。

Java EE 通过引入上下文和依赖注入(CDI)规范来标准化依赖注入。 它是依赖项注入和上下文生命周期管理的标准。

@Inject注解

@Inject注解用于将依赖项注入 Java 类。 可以使用@ManagedBean注解来装饰要注入的依赖项。

焊接

Weld 是 Java EE 平台的 CDI 的参考实现。 Weld 已集成到许多 Java EE 应用服务器中,例如 WildFly,JBoss,GlassFish 等。 Weld 也可以在普通的 servlet 容器(Tomcat,Jetty)或 Java SE 中使用。

Java Servlet Weld 示例

在以下 Web 应用中,我们创建一个 servlet,该 servlet 返回 HTML 文件中的城市对象列表。 在应用中,我们在 Weld 库的帮助下使用依赖项注入。

$ tree
.
├── nb-configuration.xml
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── zetcode
    │   │           ├── bean
    │   │           │   └── City.java
    │   │           ├── dao
    │   │           │   ├── CityDao.java
    │   │           │   └── ICityDao.java
    │   │           ├── service
    │   │           │   ├── CityService.java
    │   │           │   └── ICityService.java
    │   │           └── web
    │   │               └── GetCities.java
    │   └── webapp
    │       ├── index.html
    │       ├── listCities.jsp
    │       ├── META-INF
    │       │   └── context.xml
    │       └── WEB-INF
    │           └── beans.xml
    └── test
        └── java

这是项目结构。

pom.xml

<?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>JavaServletWeld</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>JavaServletWeld</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>4.0.0</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>

        <dependency>
            <groupId>org.jboss.weld.servlet</groupId>
            <artifactId>weld-servlet-shaded</artifactId>
            <version>3.0.2.Final</version>
        </dependency>        

    </dependencies>

    <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.0</version>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>

        </plugins>
    </build>

</project>

这是 Maven POM 文件。 javax.servlet-api工件用于 servlet。 weld-servlet-shaded依赖项使 Weld 可以在 Servlet 容器中运行。 jstl将 JSTL 库添加到项目中。 JSTL 包括一组用于 JSP 应用的有用标签。 maven-war-plugin负责收集 Web 应用的所有工件依赖项,类和资源,并将它们打包到 Web 应用存档(WAR)中。

context.xml

<?xml version="1.0" encoding="UTF-8"?>
<Context path="/JavaServletWeld">

    <Resource name="BeanManager" 
               auth="Container"
               type="javax.enterprise.inject.spi.BeanManager"
               factory="org.jboss.weld.resources.ManagerObjectFactory" />

</Context>

在 Tomcat context.xml文件中,我们定义上下文路径并注册 Weld 的BeanManager工厂。

City.java

package com.zetcode.bean;

import java.util.Objects;

public class City {

    private Long id;
    private String name;
    private int population;

    public City(Long id, String name, int population) {
        this.id = id;
        this.name = name;
        this.population = population;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getPopulation() {
        return population;
    }

    public void setPopulation(int population) {
        this.population = population;
    }

    @Override
    public int hashCode() {
        int hash = 3;
        hash = 97 * hash + Objects.hashCode(this.id);
        hash = 97 * hash + Objects.hashCode(this.name);
        hash = 97 * hash + this.population;
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final City other = (City) obj;
        if (this.population != other.population) {
            return false;
        }
        if (!Objects.equals(this.name, other.name)) {
            return false;
        }
        return Objects.equals(this.id, other.id);
    }
}

City bean 保存城市对象的数据。 它具有三个属性:idnamepopulation

beans.xml

<?xml version="1.0"?>
<beans 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/beans_1_1.xsd"
       version="1.1" bean-discovery-mode="all">

</beans>

WEB-INF目录中,我们有一个空的beans.xml文件。 它是 CDI 的部署描述符。 它可用于配置拦截器,装饰器和其他内容。 即使没有配置,我们也需要添加一个空的beans.xml来注册 CDI。

ICityService.java

package com.zetcode.service;

import com.zetcode.bean.City;
import java.util.List;

public interface ICityService {

    public List<City> getCities();
}

ICityService包含getCities()合同方法。

CityService.java

package com.zetcode.service;

import com.zetcode.bean.City;
import com.zetcode.dao.ICityDao;
import java.util.List;
import javax.annotation.ManagedBean;
import javax.inject.Inject;

@ManagedBean
public class CityService implements ICityService {

    @Inject
    private ICityDao cityDao;

    @Override
    public List<City> getCities() {

        return cityDao.findAll();
    }
}

CityService包含ICityService接口的实现。 服务类调用 DAO 对象的方法,该方法是数据库的中间层。

@ManagedBean
public class CityService implements ICityService {

@ManagedBean是一个可选注解,指示CityService将由 Weld 管理。

@Inject
private ICityDao cityDao;

使用@Inject注解,将CityDao注入cityDao属性。

ICityDao.java

package com.zetcode.dao;

import com.zetcode.bean.City;
import java.util.List;

public interface ICityDao {

    public List<City> findAll();
}

这里我们有 DAO findAll()合约方法。

CityDao.java

package com.zetcode.dao;

import com.zetcode.bean.City;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.ManagedBean;

@ManagedBean
public class CityDao implements ICityDao {

    @Override
    public List<City> findAll() {

        List<City> cities = new ArrayList<>();

        cities.add(new City(1L, "Bratislava", 432000));
        cities.add(new City(2L, "Budapest", 1759000));
        cities.add(new City(3L, "Prague", 1280000));
        cities.add(new City(4L, "Warsaw", 1748000));
        cities.add(new City(5L, "Los Angeles", 3971000));
        cities.add(new City(6L, "New York", 8550000));
        cities.add(new City(7L, "Edinburgh", 464000));
        cities.add(new City(8L, "Berlin", 3671000));

        return cities;        
    }
}

CityDao包含findAll() DAO 方法的实现。 为简单起见,我们不连接数据库,而只是返回City对象的列表。

@ManagedBean
public class CityDao implements ICityDao {

CityDao也是一个托管 bean。

GetCities.java

package com.zetcode.web;

import com.zetcode.bean.City;
import com.zetcode.service.ICityService;
import java.io.IOException;
import java.util.List;
import javax.inject.Inject;
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 = "GetCities", urlPatterns = {"/GetCities"})
public class GetCities extends HttpServlet {

    @Inject
    ICityService cityService;

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("application/html;charset=UTF-8");

        List<City> cities = cityService.getCities();
        request.setAttribute("cities", cities);

        RequestDispatcher dispatcher = request.getRequestDispatcher("listCities.jsp");
        dispatcher.forward(request, response);
    }
}

GetCities servlet 调用城市服务的getCities()方法和响应与包含在 HTML 表中的所有城市中的 HTML 页面。

@WebServlet(name = "GetCities", urlPatterns = {"/GetCities"})

Java 类用@WebServlet注解修饰。 它映射到GetCities URL 模式。

@Inject
ICityService cityService;

使用@Inject注解,将CityService注入CityService属性。

response.setContentType("application/html;charset=UTF-8");

Servlet 将以 HTML 输出数据,并且数据的编码设置为 UTF-8。

List<City> cities = cityService.getCities();
request.setAttribute("cities", cities);

使用CityServicegetCities()检索所有城市。

request.setAttribute("cities", cities);

我们将列表设置为请求。

RequestDispatcher dispatcher = request.getRequestDispatcher("listCities.jsp");
dispatcher.forward(request, response);

使用RequestDispatcher将处理发送到listCities.jsp页面。 它是一个模板文件,该模板文件将数据与 HTML 结合在一起并向客户端生成最终输出。

listCities.jsp

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Cities</title>
    </head>
    <body>
        <h2>Cities</h2>

        <table>
            <thead>
                <tr>
                    <th>Id</th>
                    <th>Name</th>
                    <th>Population</th>
                </tr>
            </thead>

            <tbody>
                <c:forEach items="${cities}" var="city">
                <tr>
                    <td>${city.id}</td>
                    <td>${city.name}</td>
                    <td>${city.population}</td>
                </tr>
                </c:forEach>   
            </tbody>
        </table>
    </body>
</html>

listCities.jsp使用c:forEach标签从提供的数据生成 HTML 表。

index.html

<!DOCTYPE html>
<html>
    <head>
        <title>Home page</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
    </head>
    <body>
        <a href="GetCities">GetCities</a>
    </body>
</html>

这是主页。 它包含一个调用 servlet 的链接。

在本教程中,我们展示了如何在 Java Servlet Web 应用中包含 Weld 库以及如何使用它来管理依赖项。

您可能也对以下相关教程感兴趣: Java Servlet 服务 XML 教程Java Servlet 上传文件Java Log4j 教程Java HttpServletMappingJava Servlet RESTful 客户端Java RequestDispatcher从 Java Servlet 提供纯文本Java Servlet 图像教程Java 教程

Java Servlet 上传文件

原文: http://zetcode.com/articles/javaservletuploadfile/

Java Servlet 上传文件显示了如何使用 Servlet 技术在 Java Web 应用中上传单个文件。

Java Servlet

Servlet 是 Java 类,可响应特定类型的网络请求-最常见的是 HTTP 请求。 Java servlet 用于创建 Web 应用。 它们在 servlet 容器(例如 Tomcat 或 Jetty)中运行。 现代 Java Web 开发使用在 servlet 之上构建的框架。

HTML 表单编码类型

POST 请求有三种编码 HTML 表单方法:

  • application/x-www-form-urlencoded
  • multipart/form-data
  • text/plain

application/x-www-form-urlencoded是默认编码。 这些值编码在由&分隔的键值元组中。 =字符用于键和值之间。 非字母数字字符采用百分比编码。 此编码类型不适用于二进制文件。

multipart/form-data用于非 acsii 数据和二进制文件。 input元素的type属性设置为file

text/plain用于调试。

Java Servlet 上传文件示例

在以下应用中,我们有一个 Web 表单来选择要上传到服务器的文件。 该表单调用 Java servlet,该 servlet 读取文件并将其保存到目录中。

上传目录

/var/www目录是 Debian Linux 中 Web 内容的标准目录。

$ ls -ld /var/www/upload/
drwxrwxr-x 2 www-data www-data 4096 Dec  3 14:29 /var/www/upload/

我们将文件上传到/var/www/upload目录。 www-data组中的用户可以修改目录文件。 因此,运行 Web 服务器的用户必须在此组中。

应用

这是一个 Maven Web 应用。 它部署在 Tomcat 上。

$ tree
.
├── nb-configuration.xml
├── pom.xml
└── src
    └── main
        ├── java
        │   └── com
        │       └── zetcode
        │           └── FileUploadServlet.java
        └── webapp
            ├── index.html
            └── META-INF
                └── context.xml

这是项目结构。

pom.xml

<?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>JavaServletFileUploadEx</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>JavaServletFileUploadEx</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>
    </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>

这是 Maven POM 文件。 javax.servlet-api工件用于 servlet。 maven-war-plugin负责收集 Web 应用的所有工件依赖项,类和资源,并将它们打包到 Web 应用存档(WAR)中。

context.xml

<?xml version="1.0" encoding="UTF-8"?>
<Context path="/JavaServletFileUploadEx"/>

在 Tomcat context.xml文件中,我们定义了上下文路径。 它是 Web 应用的名称。

FileUploadServlet.java

package com.zetcode;

import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;

@WebServlet(name = "FileUploadServlet", urlPatterns = {"/FileUploadServlet"},
      initParams = { @WebInitParam(name = "path", value = "/var/www/upload/") })
@MultipartConfig
public class FileUploadServlet extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {

        response.setContentType("text/plain;charset=UTF-8");    

        ServletOutputStream os = response.getOutputStream();

        ServletConfig sc = getServletConfig();
        String path = sc.getInitParameter("uploadpath");

        Part filePart = request.getPart("myfile");

        String fileName = filePart.getSubmittedFileName(); 
        InputStream is = filePart.getInputStream();

        Files.copy(is, Paths.get(path + fileName),
                StandardCopyOption.REPLACE_EXISTING);

        os.print("File successfully uploaded");
    }
}

FileUploadServlet将文件上传到/var/www/upload目录。

@WebServlet(name = "FileUploadServlet", urlPatterns = {"/FileUploadServlet"},
     initParams = { @WebInitParam(name = "uploadpath", value = "/var/www/upload/") })

使用@WebServlet批注,我们将 servlet 映射到/FileUploadServlet URL 模式,并定义了初始的uploadpath变量。

@MultipartConfig

servlet 也用@MultipartConfig装饰。 @MultipartConfig批注指示 servlet 期望使用multipart/form-data MIME 类型进行请求。

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws IOException, ServletException {

POST 请求由doPost()方法处理。

ServletOutputStream os = response.getOutputStream();

我们使用getOutputStream()方法获得 servlet 输出流。

ServletConfig sc = getServletConfig();
String path = sc.getInitParameter("uploadpath");

我们检索初始参数。 这是我们要上传文件的目录。

Part filePart = request.getPart("myfile");

使用getPart()方法检索文件部分。

String fileName = filePart.getSubmittedFileName(); 
InputStream is = filePart.getInputStream();

我们得到零件的文件名和输入流。

Files.copy(is, Paths.get(path + fileName),
        StandardCopyOption.REPLACE_EXISTING);

使用Files.copy(),将文件复制到目标目录。

os.print("File successfully uploaded");

最后,我们将消息写回客户端。

index.html

<!DOCTYPE html>
<html>
    <head>
        <title>Uploading a file</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="stylesheet" href="https://unpkg.com/purecss@1.0.0/build/pure-min.css">
    </head>
    <body>
        <form class="pure-form pure-form-stacked" method="post" action="FileUploadServlet" 
              enctype="multipart/form-data">
            <fieldset>
                <legend>File:</legend>
                <input type="file" name="myfile">
                <button type="submit" class="pure-button pure-button-primary">Upload</button>
            </fieldset>
        </form>
    </body>
</html>

这是选择要上传文件的主页。 它包含一个 HTML 表单。 提交表单后,处理将发送到FileUploadServlet

<link rel="stylesheet" href="https://unpkg.com/purecss@1.0.0/build/pure-min.css">

我们包括 Pure.css 库,用于创建负责任的页面。

<form class="pure-form pure-form-stacked" method="post" action="FileUploadServlet" 
        enctype="multipart/form-data">

method属性为 post,因为我们将数据发送到服务器。 action属性指定处理请求的 servlet 的名称。 enctype属性指定multipart/form-data编码类型,这是使用 HTML 格式上传文件所必需的。

<input type="file" name="myfile">

input标签的type属性使用户可以选择一个文件。

<button type="submit" class="pure-button pure-button-primary">Upload</button>

这是提交按钮。

在本教程中,我们展示了如何使用 Java Servlet 上传单个文件。

您可能也对以下相关教程感兴趣: Java Servlet 分页Java Log4j 教程Java Servlet RESTful 客户端Java RequestDispatcher从 Java servletJava servlet 图像教程Java 教程提供纯文本

Java Servlet 提供 XML

原文: http://zetcode.com/articles/javaservletservexml/

Java Servlet 服务 XML 展示了如何从 Java Servlet 服务 XML 数据。 数据存储在 MySQL 表中。 该 Web 应用已部署在 Tomcat Web 服务器上。

XML 格式

可扩展标记语言(XML)是一种流行的人类可读和机器可读的标记语言。 XML 的设计目标强调互联网的简单性,通用性和可用性。 它是一种文本数据格式,并通过 Unicode 对不同的人类语言提供了强大的支持。 XML 最初是为大规模电子出版而设计的,被广泛用于在软件组件,系统和企业之间交换各种数据。

XML 是由万维网联盟(W3C)开发的行业标准。 它不受任何编程语言或软件供应商的束缚。 XML 是可扩展的,与平台无关的,并且支持国际化。

JAXB

用于 XML 绑定的 Java 架构(JAXB)提供了 API 和工具,可自动执行 XML 文档和 Java 对象之间的映射。 JAXB 允许将 XML 内容解组为 Java 表示形式,访问和更新 Java 表示形式,并将 XML 内容的 Java 表示形式编组为 XML 内容。

Java Servlet

Servlet 是 Java 类,可响应特定类型的网络请求-最常见的是 HTTP 请求。 Java servlet 用于创建 Web 应用。 它们在 servlet 容器(例如 Tomcat 或 Jetty)中运行。 现代 Java Web 开发使用在 servlet 之上构建的框架。

Java Servlet 服务 XML 示例

在下面的 Web 应用中,我们从 MySQL 表加载数据并将其显示为 XML 到客户端。 我们使用 JAXB 解析器将 Java 类转换为 XML。

cars_mysql.sql

-- SQL for the Cars table

CREATE TABLE Cars(Id BIGINT PRIMARY KEY AUTO_INCREMENT, Name VARCHAR(150), 
    Price INTEGER);
INSERT INTO Cars(Name, Price) VALUES('Audi', 52642);
INSERT INTO Cars(Name, Price) VALUES('Mercedes', 57127);
INSERT INTO Cars(Name, Price) VALUES('Skoda', 9000);
INSERT INTO Cars(Name, Price) VALUES('Volvo', 29000);
INSERT INTO Cars(Name, Price) VALUES('Bentley', 350000);
INSERT INTO Cars(Name, Price) VALUES('Citroen', 21000);
INSERT INTO Cars(Name, Price) VALUES('Hummer', 41400);
INSERT INTO Cars(Name, Price) VALUES('Volkswagen', 21600);

该 SQL 脚本在 MySQL 中创建Cars表。

$ tree
.
├── nb-configuration.xml
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── zetcode
    │   │           ├── converter
    │   │           │   └── CarsXmlConverter.java
    │   │           ├── dao
    │   │           │   ├── CarsDAO.java
    │   │           │   └── ICarsDAO.java
    │   │           ├── model
    │   │           │   ├── Car.java
    │   │           │   └── CarList.java
    │   │           ├── service
    │   │           │   ├── CarsService.java
    │   │           │   └── ICarsService.java
    │   │           ├── util
    │   │           │   └── ServiceLocator.java
    │   │           └── web
    │   │               ├── GetCar.java
    │   │               └── GetCars.java
    │   ├── resources
    │   └── webapp
    │       ├── index.html
    │       ├── META-INF
    │       │   └── context.xml
    │       └── WEB-INF
    └── test
        └── java

这是项目结构。

pom.xml

<?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>JavaServletServeXml</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>JavaServletServeXml</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>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.45</version>
        </dependency>        

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </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>

这是 Maven POM 文件。 javax.servlet-api工件用于 servlet。 spring-jdbc依赖项用于JdbcTemplate库,该库简化了 Java 中的数据库编程。 mysql-connector-java是 Java 语言的 MySQL 驱动程序。 maven-war-plugin负责收集 Web 应用的所有工件依赖项,类和资源,并将它们打包到 Web 应用存档(WAR)中。

context.xml

<?xml version="1.0" encoding="UTF-8"?>
<Context path="/JavaServletServeXml">

    <Resource name="jdbc/testdb" 
              auth="Container"
              type="javax.sql.DataSource" 
              username="user12" 
              password="s$cret"              
              driverClassName="com.mysql.jdbc.Driver"
              url="jdbc:mysql://localhost:3306/testdb"              
              maxActive="10" 
              maxIdle="4"/>

</Context>

在 Tomcat context.xml文件中,我们定义了上下文路径和 MySQL 数据源。

Car.java

package com.zetcode.model;

import java.util.Objects;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

@XmlRootElement(name = "car")
@XmlType(propOrder = {"id", "name", "price"})
public class Car {

    private Long id;
    private String name;
    private int price;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 79 * hash + Objects.hashCode(this.id);
        hash = 79 * hash + Objects.hashCode(this.name);
        hash = 79 * hash + this.price;
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Car other = (Car) obj;
        if (this.price != other.price) {
            return false;
        }
        if (!Objects.equals(this.name, other.name)) {
            return false;
        }
        return Objects.equals(this.id, other.id);
    }
}

Car bean 从Cars数据库表中保留一行。

@XmlRootElement(name = "car")
@XmlType(propOrder = {"id", "name", "price"})

使用@XmlRootElement注解,我们设置元素的名称。 @XmlType用于设置元素标签的生成顺序。

CarList.java

package com.zetcode.model;

import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(namespace = "com.zetcode")
@XmlAccessorType(XmlAccessType.FIELD)
public class CarList {

    @XmlElementWrapper(name = "cars")
    @XmlElement(name = "car")
    private List<Car> cars;

    public List<Car> getCars() {
        return cars;
    }

    public void setCars(List<Car> cars) {
        this.cars = cars;
    }
}

CarList是一个帮助器类,其中包含 JAXB 映射注解,以在 XML 输出中的汽车标签周围创建包装器。

@XmlElementWrapper(name = "cars")

@XmlElementWrapper注解在列表中的元素周围创建了一个包装。

@XmlElement(name = "car")

@XmlElement注解设置包装元素的名称。

ServiceLocator.java

package com.zetcode.util;

import java.util.logging.Level;
import java.util.logging.Logger;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

public class ServiceLocator {

    public static DataSource getDataSource(String jndiName) {

        Context ctx = null;
        DataSource ds = null;

        try {
            ctx = new InitialContext();
            ds = (DataSource) ctx.lookup(jndiName);
        } catch (NamingException ex) {
            Logger.getLogger(ServiceLocator.class.getName()).log(
                Level.SEVERE, null, ex);
        }

        return ds;
    }
}

ServiceLocator通过给定的 JNDI 名称查找数据源,并将其返回给调用方。

ICarsService.java

package com.zetcode.service;

import com.zetcode.model.Car;
import java.util.List;

public interface ICarsService {

    public Car findCarById(long id);
    public List<Car> findAllCars();
}

ICarsService包含两种服务合同方法:findCarById()findAllCars()

CarsService.java

package com.zetcode.service;

import com.zetcode.dao.CarsDAO;
import com.zetcode.model.Car;
import java.util.List;

public class CarsService implements ICarsService {

    private CarsDAO carsDao;

    public CarsService() {

        carsDao = createDao();
    }

    @Override
    public Car findCarById(long id) {

        Car car = carsDao.findById(id);
        return car;
    }

    @Override
    public List<Car> findAllCars() {

        List<Car> cars = carsDao.findAll();
        return cars;
    }

    private CarsDAO createDao() {

        carsDao = new CarsDAO();
        return carsDao;
    }
}

CarsService包含ICarsService接口的实现。 服务类调用 DAO 对象的方法,该对象是数据库的中间层。

ICarsDAO.java

package com.zetcode.dao;

import com.zetcode.model.Car;
import java.util.List;

public interface ICarsDAO {

    public Car findById(long id);
    public List<Car> findAll();
}

在这里,我们有 DAO 合同方法。

CarsDAO.java

package com.zetcode.dao;

import com.zetcode.model.Car;
import com.zetcode.util.ServiceLocator;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.sql.DataSource;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;

public class CarsDAO implements ICarsDAO {

    private JdbcTemplate jtm;

    public CarsDAO() {

        createJdbcTemplate();
    }

    @Override
    public Car findById(long id) {

        String sql = "SELECT * FROM Cars WHERE Id=?";

        Car car = new Car();

        try {
            car = (Car) jtm.queryForObject(sql, new Object[]{id},
                    new BeanPropertyRowMapper(Car.class));
        } catch (EmptyResultDataAccessException ex) {
            Logger.getLogger(CarsDAO.class.getName()).log(
                    Level.SEVERE, null, ex);
        }

        return car;
    }

    @Override
    public List<Car> findAll() {

        String sql = "SELECT * FROM Cars";

        List<Car> cars = new ArrayList<>();

        try {
            cars = jtm.query(sql,
                    new BeanPropertyRowMapper(Car.class));

        } catch (EmptyResultDataAccessException ex) {
            Logger.getLogger(CarsDAO.class.getName()).log(
                    Level.SEVERE, null, ex);
        }

        return cars;
    }

    private JdbcTemplate createJdbcTemplate() {

        DataSource ds = ServiceLocator.getDataSource("java:comp/env/jdbc/testdb");
        jtm = new JdbcTemplate(ds);
        return jtm;
    }
}

CarsDAO包含 DAO 方法的实现。 我们使用 Spring 的JdbcTemplate模块访问数据库。

private JdbcTemplate createJdbcTemplate() {

    DataSource ds = ServiceLocator.getDataSource("java:comp/env/jdbc/testdb");
    jtm = new JdbcTemplate(ds);
    return jtm;
}

createJdbcTemplate()方法中,我们查找数据源并创建JdbcTemplate

CarsXmlConverter.java

package com.zetcode.converter;

import com.zetcode.model.Car;
import com.zetcode.model.CarList;
import java.io.ByteArrayOutputStream;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;

public class CarsXmlConverter {

    private ByteArrayOutputStream bos;

    public ByteArrayOutputStream convertList(List<Car> cars) {

        bos = new ByteArrayOutputStream();

        try {
            JAXBContext context = JAXBContext.newInstance(CarList.class);
            Marshaller m = context.createMarshaller();
            m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);

            CarList carsList = new CarList();
            carsList.setCars(cars);

            m.marshal(carsList, bos);

        } catch (JAXBException ex) {
            Logger.getLogger(CarsXmlConverter.class.getName()).log(Level.SEVERE, null, ex);
        }

        return bos;
    }

    public ByteArrayOutputStream convertObject(Car car) {

        bos = new ByteArrayOutputStream();

        try {
            JAXBContext context = JAXBContext.newInstance(Car.class);
            Marshaller m = context.createMarshaller();
            m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
            m.marshal(car, bos);

        } catch (JAXBException ex) {
            Logger.getLogger(CarsXmlConverter.class.getName()).log(Level.SEVERE, null, ex);
        }

        return bos;
    }
}

CarsXmlConverter包含将 Java 类转换为 XML 数据的方法。

public ByteArrayOutputStream convertList(List<Car> cars) {

该方法返回ByteArrayOutputStream

JAXBContext context = JAXBContext.newInstance(CarList.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);

创建了 JAXB 编组器。

CarList carsList = new CarList();
carsList.setCars(cars);

m.marshal(carsList, bos);

我们将 Java 表示形式编组为ByteArrayOutputStream

GetCars.java

package com.zetcode.web;

import com.zetcode.converter.CarsXmlConverter;
import com.zetcode.model.Car;
import com.zetcode.service.CarsService;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
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 = "GetCars", urlPatterns = {"/GetCars"})
public class GetCars extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("application/xml;charset=UTF-8");

        CarsService carsService = new CarsService();
        List<Car> cars = carsService.findAllCars();

        CarsXmlConverter xmlConverter = new CarsXmlConverter();

        try (ByteArrayOutputStream bos = xmlConverter.convertList(cars)) {
            OutputStream os = response.getOutputStream();
            bos.writeTo(os);
        }
    }
}

GetCars Servlet 将Cars表中的所有数据作为 XML 数据返回。

@WebServlet(name = "GetCars", urlPatterns = {"/GetCars"})

Java 类用@WebServlet注解修饰。 它映射到GetCars URL 模式。

response.setContentType("application/xml;charset=UTF-8");

Servlet 将以 XML 输出数据,并且数据的编码设置为 UTF-8。

CarsService carsService = new CarsService();
List<Car> cars = carsService.findAllCars();

使用CarsServicefindAllCars(),我们从数据库中检索所有汽车。

CarsXmlConverter xmlConverter = new CarsXmlConverter();

try (ByteArrayOutputStream bos = xmlConverter.convertList(cars)) {
    OutputStream os = response.getOutputStream();
    bos.writeTo(os);
}

我们使用CarsXmlConverter将数据转换为 XML,并将字节写入ServletOutputStream

GetCar.java

package com.zetcode.web;

import com.zetcode.converter.CarsXmlConverter;
import com.zetcode.model.Car;
import com.zetcode.service.CarsService;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
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 = "GetCar", urlPatterns = {"/GetCar"})
public class GetCar extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        long id = Long.parseLong(request.getParameter("carId"));

        response.setContentType("application/xml;charset=UTF-8");

        CarsService carsService = new CarsService();
        Car car = carsService.findCarById(id);

        CarsXmlConverter xmlConverter = new CarsXmlConverter();

        try (ByteArrayOutputStream bos = xmlConverter.convertObject(car)) {
            OutputStream os = response.getOutputStream();
            bos.writeTo(os);
        }
    }
}

GetCar Servlet 以 XML 格式返回一辆汽车。

index.html

<!DOCTYPE html>
<html>
    <head>
        <title>Home page</title>
        <meta charset="UTF-8">
    </head>
    <body>

        <a href="GetCars">Get cars</a>
        <br>
        <a href="GetCar?carId=5">Get car with id 5</a>

    </body>
</html>

这是主页。 它包含两个链接。 一个检索所有汽车,另一个检索具有 ID 5 的汽车。

在本教程中,我们创建了一个 Java Web 应用,该应用从 MySQL 数据库中选择数据,将其转换为 XML,然后将 XML 数据返回给客户端。

您可能也对以下相关教程感兴趣: Java Servlet 焊接教程Java Servlet 上传文件Java Log4j 教程Java Servlet RESTful 客户端Java RequestDispatcher从 Java Servlet 提供纯文本Java Servlet 图像教程Java 教程

Java Servlet 教程

原文: http://zetcode.com/articles/javaservlet/

Java Servlets 教程展示了如何在 Java 中创建简单的 servlet。 我们使用 Java 注解和 XML 文件创建 servlet。

Java Servlet

Servlet 是响应网络请求的 Java 类。 这主要是一个 HTTP 请求。 Java servlet 用于创建 Web 应用。 它们在 servlet 容器(例如 Tomcat 或 Jetty)中运行。 现代 Java Web 开发使用在 servlet 之上构建的框架。 例如,Spring 或 Vaadin 框架使用 servlet。

javax.servletjavax.servlet.http包提供用于编写 ​​servlet 的接口和类。

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.1.0</version>
    <scope>provided</scope>
</dependency>

这些示例使用此 Maven 依赖项。 javax.servlet-api提供 Servlet API。 provided范围使依赖项在编译时可用,并指示它在运行时已可用。 包含在 Servlet 容器(Tomcat,Jetty)中。

Java Servlet 注解示例

在下面的示例中,我们使用@WebServlet批注创建 Java Servlet。 从 Servlet 3.0 规范开始可以使用@WebServlet批注。 注解在部署时由容器处理。

$ tree
.
├── nb-configuration.xml
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── zetcode
    │   │           └── web
    │   │               └── MyServlet.java
    │   ├── resources
    │   └── webapp
    │       ├── index.html
    │       ├── META-INF
    │       │   └── context.xml
    │       └── WEB-INF
    └── test
        └── java

这是项目结构。

context.xml

<?xml version="1.0" encoding="UTF-8"?>
<Context path="/JavaServletAnnotation"/>

在 Tomcat context.xml文件中,我们定义了上下文路径。 它是 Web 应用的名称。

MyServlet.java

package com.zetcode.web;

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

@WebServlet(name = "MyServlet", urlPatterns = {"/MyServlet"})
public class MyServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("text/plain;charset=UTF-8");

        ServletOutputStream out = response.getOutputStream();

        out.print("This is MyServlet");
    }
}

MyServlet Servlet 将一条简单的文本消息返回给客户端。

@WebServlet(name = "MyServlet", urlPatterns = {"/MyServlet"})

Java 类用@WebServlet注解修饰。 它映射到MyServlet URL 模式。

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {

GET 请求调用doGet()方法。 该方法接收HttpServletRequestHttpServletResponse对象。

response.setContentType("text/html;charset=UTF-8");

Servlet 将以纯文本格式输出数据,并且数据的编码设置为 UTF-8。

ServletOutputStream out = response.getOutputStream();

通过getOutputStream()方法,我们获得了 servlet 输出流。

out.print("This is MyServlet");

我们使用print()方法编写一条短信。

index.html

<!DOCTYPE html>
<html>
    <head>
        <title>Home page</title>
        <meta charset="UTF-8">
    </head>
    <body>
        <a href="MyServlet">Call MyServlet</a>
    </body>
</html>

在主页中,我们有一个调用 servlet 的链接。

Java Servlet XML 示例

在第二个示例中,我们在web.xml部署描述符中定义了两个 servlet。 在 Servlet 3.0 规范之前,这是定义 Java Servlet 的唯一方法。

$ tree
.
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── zetcode
    │   │           └── web
    │   │               ├── FirstServlet.java
    │   │               └── SecondServlet.java
    │   └── webapp
    │       ├── index.html
    │       ├── META-INF
    │       │   └── context.xml
    │       └── WEB-INF
    │           └── web.xml
    └── test
        └── java

这是项目结构。

context.xml

<?xml version="1.0" encoding="UTF-8"?>
<Context path="/JavaServletXML"/>

我们定义上下文路径。

web.xml

<?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>FirstServlet</servlet-name>
        <servlet-class>com.zetcode.web.FirstServlet</servlet-class>
    </servlet>

    <servlet>
        <servlet-name>SecondServlet</servlet-name>
        <servlet-class>com.zetcode.web.SecondServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>FirstServlet</servlet-name>
        <url-pattern>/FirstServlet</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>SecondServlet</servlet-name>
        <url-pattern>/SecondServlet</url-pattern>
    </servlet-mapping>

    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>

</web-app>

web.xml文件中,我们定义了两个 Servlet:FirstServletSecondServletweb.xml位于WEB-INF目录中。

<servlet>
<servlet-name>FirstServlet</servlet-name>
<servlet-class>com.zetcode.web.FirstServlet</servlet-class>
</servlet>

我们定义名称和 servlet 类。

<servlet-mapping>
    <servlet-name>FirstServlet</servlet-name>
    <url-pattern>/FirstServlet</url-pattern>
</servlet-mapping>

我们将 servlet 映射到 URL 模式。

FirstServlet.java

package com.zetcode.web;

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

public class FirstServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("text/plain;charset=UTF-8");

        ServletOutputStream out = response.getOutputStream();

        out.print("This is First Servlet");
    }
}

这是第一个 servlet。

SecondServlet.java

package com.zetcode.web;

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

public class SecondServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("text/plain;charset=UTF-8");

        ServletOutputStream out = response.getOutputStream();

        out.print("This is Second Servlet");
    }
}

这是第二个 servlet。

index.html

<!DOCTYPE html>
<html>
    <head>
        <title>Home page</title>
        <meta charset="UTF-8">
    </head>
    <body>

        <p>
            Call <a href="FirstServlet">First Servlet</a>
        </p>

        <p>
            Call <a href="SecondServlet">Second Servlet</a>
        </p>    

    </body>
</html>

在主页中,我们有两个链接来调用两个 servlet。

在本教程中,我们展示了如何创建简单的 Java Servlet。

您可能也对以下相关教程感兴趣: Java Servlet 上传文件Java Log4j 教程Java Servlet RESTful 客户端Java RequestDispatcher从 Java servlet 提供纯文本Java servlet 图像教程Java 教程

JSTL forEach标签

原文: http://zetcode.com/articles/jstlforeach/

JSTL forEach教程展示了如何使用 JSTL 库中的forEach标签。

JSTL

JavaServerPages 标准标记库(JSTL)是有用的 JSP 标记的集合,这些标记提供了许多 JSP 应用所共有的核心功能。

forEach标签

JSTL <c:foreach>标签是基本的迭代标签。 它遍历各种 Java 集合类型。

<c:foreach>标记包含以下属性:

  • items - 要迭代的项目集合
  • begin - 起始项目的索引
  • end - 结束项目的索引
  • step - 迭代步骤
  • var - 迭代中当前项目的变量

forEach taglib 声明

<c:foreach>标记属于核心 JSTL 标记。

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

要使用标签,我们需要包含此声明。

JSTL Maven 依赖项

要使用 JSTL 库,我们需要以下 Maven 依赖项:

<dependency>
    <groupId>jstl</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
</dependency>

forEach标签示例

以下 JSP 页面包含<c:foreach>标记。 除了<c:foreach>标签之外,我们还使用<c:out>显示变量。

index.jsp

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>JSP Page</title>
    </head>
    <body>
        <c:forEach var="counter" begin="1" end="8">
            <c:out value="${counter}"/>
        </c:forEach>
    </body>
</html>

该示例在输出中显示值1..8

forEach标签示例 II

下一个 JSP 示例读取从链接发送的参数。

index.html

<!DOCTYPE html>
<html>
    <head>
        <title>Start Page</title>
        <meta charset="UTF-8">
    </head>
    <body>

        <a href="target.jsp?name=Jane&age=23&occupation=accountant">Show page</a>

    </body>
</html>

index.html页面包含一个链接,该链接将三个参数发送到target.jsp页面。

target.jsp

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>JSP Page</title>
    </head>
    <body>
        <c:forEach var="par" items="${param}">

            <c:out value="${par.key}"/>: <c:out value="${par.value}"/> <br>

        </c:forEach>
    </body>
</html>

JSP 页面在隐式param对象(它是一个映射)中接收参数。

<c:forEach var="par" items="${param}">

    <c:out value="${par.key}"/>: <c:out value="${par.value}"/> <br>

</c:forEach>

我们遍历映射并打印键/值对。

forEach标签示例 III

HTML <select>是提供选项菜单的控件。 借助其multiple属性,用户可以从控件中选择多个值。

index.html

<!DOCTYPE html>
<html>
    <head>
        <title>Languages</title>
        <meta charset="UTF-8">
    </head>
    <body>

        <form action="target.jsp">
            <div>Select languages:</div>

            <select name="languages" size="7" multiple="multiple">
                <option value='Ada'>Ada</option>
                <option value='C'>C</option>
                <option value='C++'>C++</option>
                <option value='Cobol'>Cobol</option>
                <option value='Eiffel'>Eiffel</option>
                <option value='Objective-C'>Objective-C</option>
                <option value='Java'>Java</option>
            </select>

            <button type="submit">Submit</button>

        </form>

    </body>
</html>

我们创建一个<select>控件,其中包含七个值。 当我们提交表单时,选定的值将发送到target.jsp文件。

target.jsp

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Languages</title>
    </head>
    <body>
        <c:forEach items="${paramValues.languages}" var="lang">
            <c:out value="${lang}"/>
        </c:forEach>
    </body>
</html>

可从隐式paramValues对象(它是一个映射)获得<select>控件的值。 关键是请求参数名称(languages),值在字符串数组中。

<c:forEach items="${paramValues.languages}" var="lang">
    <c:out value="${lang}"/>
</c:forEach>

我们遍历数组并打印其元素。

forEach标签示例 IV

以下示例在 HTML 表中显示数据。

index.html

<!DOCTYPE html>
<html>
    <head>
        <title>Start Page</title>
        <meta charset="UTF-8">
    </head>
    <body>
        <p>
            <a href="MyServlet">Show all cities</a>
        </p>
    </body>
</html>

index.html页面中,我们有一个调用MyServlet的链接。 Servlet 使用服务方法加载数据,并分派到 JSP 页面。

City.java

package com.zetcode.bean;

public class City {

    private Long id;
    private String name;
    private int population;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public City(Long id, String name, int population) {
        this.id = id;
        this.name = name;
        this.population = population;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getPopulation() {
        return population;
    }

    public void setPopulation(int population) {
        this.population = population;
    }
}

这是City类; 它包含idnamepopulation属性。

MyServlet.java

package com.zetcode.web;

import com.zetcode.bean.City;
import com.zetcode.service.CityService;
import java.io.IOException;
import java.util.List;
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 = "MyServlet", urlPatterns = {"/MyServlet"})
public class MyServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("text/html;charset=UTF-8");

        List<City> cities = CityService.getAllCities();

        request.setAttribute("cities", cities);

        request.getRequestDispatcher("showCities.jsp").forward(request, response);
    }
}

Servlet 使用CityService.getAllCities()读取数据,使用setAttribute()将列表对象设置为属性,然后转发到showCities.jsp

CityService.java

package com.zetcode.service;

import com.zetcode.bean.City;
import java.util.ArrayList;
import java.util.List;

public class CityService {

    public static List<City> getAllCities() {

       List<City> cities = new ArrayList<>();

        cities.add(new City(1L, "Bratislava", 432000));
        cities.add(new City(2L, "Budapest", 1759000));
        cities.add(new City(3L, "Prague", 1280000));
        cities.add(new City(4L, "Warsaw", 1748000));
        cities.add(new City(5L, "Los Angeles", 3971000));
        cities.add(new City(6L, "New York", 8550000));
        cities.add(new City(7L, "Edinburgh", 464000));
        cities.add(new City(8L, "Berlin", 3671000));

        return cities;
    }
}

getAllCities()方法返回城市列表。

showCities.jsp

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Cities</title>
    </head>
    <body>
        <h2>Cities</h2>

        <table>
            <thead>
                <tr>
                    <th>Id</th>
                    <th>Name</th>
                    <th>Population</th>
                </tr>
            </thead>

            <tbody>
                <c:forEach items="${cities}" var="city">
                <tr>
                    <td>${city.id}</td>
                    <td>${city.name}</td>
                    <td>${city.population}</td>
                </tr>
                </c:forEach>   
            </tbody>
        </table>
    </body>
</html>

showCities.jsp中,我们在带有<c:forEach>标签的 HTML 表格中显示城市。

<td>${city.id}</td>
<td>${city.name}</td>
<td>${city.population}</td>

使用点运算符从城市对象读取属性。

在本教程中,我们介绍了 JSTL 库中的<c:forEach>标签。

您可能也会对以下相关教程感兴趣: Java servlet JSON 教程Java servlet 复选框教程Java servlet 图像教程Java Servlet HTTP 标头Java 教程

使用 jsGrid 组件

原文: http://zetcode.com/articles/jsgridservlet/

在本教程中,我们从 Derby 数据库检索数据并将其显示在 jsGrid 组件中。 数据以 JSON 格式从 Derby 发送到 jsGrid。 作者的 Github 信息库中提供了本教程的源代码。

jsGrid 是基于 jQuery 的轻量级客户端数据网格控件。 它支持基本的网格操作,如插入,编辑,过滤,删除,排序和分页。 jsGrid 组件允许自定义其外观和子组件。

jQuery 是一个快速,小型且功能丰富的 JavaScript 库。 通过易于使用的 API(可在多种浏览器中使用),它使 HTML 文档的遍历和操作,事件处理,动画和 Ajax 变得更加简单。

Apache Derby 是完全用 Java 实现的开源关系数据库。 Derby 占用空间小,易于部署和安装。 它有两种模式:嵌入式和客户端/服务器。 也称为 Java DB。

JSON(JavaScript 对象表示法)是一种轻量级的数据交换格式。 人类很容易读写,机器也很容易解析和生成。 JSON 的官方互联网媒体类型为application/json。 JSON 文件扩展名是.json

在我们的应用中,我们将使用以下四种 HTTP 方法:

  • GET - 读取资源
  • POST - 创建新资源
  • PUT — 修改资源
  • DELETE — 删除资源

这些 HTTP 动词将调用相应的 Java servlet 方法。

cars.sql

CREATE TABLE CARS(ID INTEGER NOT NULL PRIMARY KEY GENERATED ALWAYS AS IDENTITY 
    (START WITH 1, INCREMENT BY 1), NAME VARCHAR(30), PRICE INT);

INSERT INTO CARS(NAME, PRICE) VALUES('Audi', 52642);
INSERT INTO CARS(NAME, PRICE) VALUES('Mercedes', 57127);
INSERT INTO CARS(NAME, PRICE) VALUES('Skoda', 9000);
INSERT INTO CARS(NAME, PRICE) VALUES('Volvo', 29000);
INSERT INTO CARS(NAME, PRICE) VALUES('Bentley', 350000);
INSERT INTO CARS(NAME, PRICE) VALUES('Citroen', 21000);
INSERT INTO CARS(NAME, PRICE) VALUES('Hummer', 41400);
INSERT INTO CARS(NAME, PRICE) VALUES('Volkswagen', 21600);

在示例中,我们使用CARS数据库表,该表位于 Derby testdb数据库中。

<dependencies>
    <dependency>
        <groupId>javax</groupId>
        <artifactId>javaee-web-api</artifactId>
        <version>7.0</version>
        <scope>provided</scope>
    </dependency>

    <dependency>
        <groupId>org.apache.derby</groupId>
        <artifactId>derbyclient</artifactId>
        <version>10.12.1.1</version>
    </dependency>    

    <dependency>
        <groupId>com.googlecode.json-simple</groupId>
        <artifactId>json-simple</artifactId>
        <version>1.1.1</version>
    </dependency>

    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>19.0</version>
    </dependency>

    <dependency>
        <groupId>org.apache.derby</groupId>
        <artifactId>derbyoptionaltools</artifactId>
        <version>10.12.1.1</version>
    </dependency>        

</dependencies>

这些是我们项目中使用的依赖项。 javaee-web-api是一组用于创建 Java Web 应用的 JAR。 derbyclient是 Derby 的数据库驱动程序。 json-simple库用于处理 JSON 数据。 本项目使用guava的辅助方法。 derbyoptionaltools包含一个帮助程序方法,该方法将数据库结果集转换为 JSON 格式。

index.html

<!DOCTYPE html>
<html>
    <head>
        <title>jsGrid example</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <meta name="viewport" content="width=device-width">
        <link href="css/style.css" rel="stylesheet">
        <link href="http://js-grid.com/css/jsgrid.min.css" rel="stylesheet">
        <link href="http://js-grid.com/css/jsgrid-theme.min.css" rel="stylesheet">        
    </head>
    <body>

        <div id="jsGrid"></div>

        <script src="http://code.jquery.com/jquery-1.11.3.min.js"></script>
        <script src="http://js-grid.com/js/jsgrid.min.js"></script>
        <script src="js/sample.js"></script>
    </body>
</html>

index.html文件中,我们包含 jQuery 和 jsGrid 库。

<div id="jsGrid"></div>

jsGrid 作为div标签包含在内。

style.css

html {
    height: 100%;
}

body {
    height: 100%;
    font-family: Verdana, Georgia;
}

为了显示 jsGrid 组件的完整大小,我们需要设置<body><html>标签的高度。

sample.js

$(function () {

    $.ajax({
        type: "GET",
        url: "/JsGridEx/ManageCars"
    }).done(function () {

        $("#jsGrid").jsGrid({
            height: "60%",
            width: "50%",
            inserting: true,
            editing: true,
            sorting: true,
            paging: true,
            autoload: true,
            pageSize: 10,
            controller: {
                loadData: function (filter) {
                    return $.ajax({
                        type: "GET",
                        url: "/JsGridEx/ManageCars",
                        data: filter
                    });
                },
                insertItem: function (item) {
                    return $.ajax({
                        type: "POST",
                        url: "/JsGridEx/ManageCars",
                        data: item
                    });
                },
                updateItem: function (item) {
                    return $.ajax({
                        type: "PUT",
                        url: "/JsGridEx/ManageCars",
                        data: item
                    });
                },
                deleteItem: function (item) {
                    return $.ajax({
                        type: "DELETE",
                        url: "/JsGridEx/ManageCars",
                        data: item
                    });
                }
            },
            fields: [
                {name: "NAME", title: "Name", type: "text", width: 60},
                {name: "PRICE", title: "Price", type: "text",  width: 50},
                {type: "control"}
            ]
        });

    });
});

sample.js文件中,我们创建并配置 jsGrid 组件。

inserting: true,
editing: true,
sorting: true,
paging: true,

我们的 jsGrid 组件可以插入,编辑和排序数据,还支持分页。

loadData: function (filter) {
    return $.ajax({
        type: "GET",
        url: "/JsGridEx/ManageCars",
        data: filter
    });
}

loadData()函数在ManageCars Servlet 上发出 HTTP GET 方法。

insertItem: function (item) {
    return $.ajax({
        type: "POST",
        url: "/JsGridEx/ManageCars",
        data: item
    });
}

当我们插入新项目时,将在ManageCars Servlet 上发出 HTTP POST 方法。

updateItem: function (item) {
    return $.ajax({
        type: "PUT",
        url: "/JsGridEx/ManageCars",
        data: item
    });
}

更新项目会在ManageCars Servlet 上生成 HTTP PUT 方法。

deleteItem: function (item) {
    return $.ajax({
        type: "DELETE",
        url: "/JsGridEx/ManageCars",
        data: item
    });
}

删除项目会在ManageCars Servlet 上生成 HTTP DELETE 方法。

fields: [
    {name: "NAME", title: "Name", type: "text", width: 60},
    {name: "PRICE", title: "Price", type: "text",  width: 50},
    {type: "control"}
]

jsGrid 组件具有三个两列:NAMEPRICE。 它们必须与 JSON 中返回的键完全匹配。

ManageCars.java

package com.zetcode.web;

import com.zetcode.service.CarService;
import com.zetcode.util.Utils;
import java.io.IOException;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.json.simple.JSONArray;

@WebServlet(name = "ManageCars", urlPatterns = {"/ManageCars"})
public class ManageCars extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");

        JSONArray ar = CarService.getCarsJSON();

        response.getWriter().write(ar.toJSONString());
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException {

        String name = request.getParameter("NAME");
        int price = Integer.valueOf(request.getParameter("PRICE"));

        CarService.insertCar(name, price);

        getServletContext().log("Car " + name + " inserted");
    }

    @Override
    protected void doPut(HttpServletRequest request, HttpServletResponse response)
            throws ServletException {

        Map<String, String> dataMap = Utils.getParameterMap(request);

        String carName = dataMap.get("NAME");
        int carPrice = Integer.valueOf(dataMap.get("PRICE"));

        CarService.updateCar(carName, carPrice);

        getServletContext().log("Car " + carName + " updated" + carPrice);
    }

    @Override
    protected void doDelete(HttpServletRequest request, HttpServletResponse response)
            throws ServletException {

        Map<String, String> dataMap = Utils.getParameterMap(request);

        String carName = dataMap.get("NAME");

        CarService.deleteCar(carName);

        getServletContext().log("Car:" + carName + " deleted");
    }
}

ManageCars是 Java Servlet,其中包含 HTTP GET,POST,PUT 和 DELETE 方法的相应方法。

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {

    response.setContentType("application/json");
    response.setCharacterEncoding("UTF-8");

    JSONArray ar = CarService.getCarsJSON();

    response.getWriter().write(ar.toJSONString());
}

响应于 HTTP GET 方法,调用doGet()方法。 它调用CarServicegetCarsJSON()方法,该方法从 CARS 表中返回所有汽车。 数据以 JSON 格式发送回客户端。

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException {

    String name = request.getParameter("NAME");
    int price = Integer.valueOf(request.getParameter("PRICE"));

    CarService.insertCar(name, price);

    getServletContext().log("Car " + name + " inserted");
}

doPost()方法中,我们从请求中检索NAMEPRICE参数,然后使用CarService.insertCar()方法将它们插入数据库中。 当我们收到一个 HTTP POST 方法时,doPost()方法被调用,期望添加新的资源。

@Override
protected void doPut(HttpServletRequest request, HttpServletResponse response)
        throws ServletException {

    Map<String, String> dataMap = Utils.getParameterMap(request);

    String carName = dataMap.get("NAME");
    int carPrice = Integer.valueOf(dataMap.get("PRICE"));

    CarService.updateCar(carName, carPrice);

    getServletContext().log("Car " + carName + " updated" + carPrice);
}

doPut()方法中,我们从请求中检索NAMEPRICE参数,然后使用CarService.updateCar()方法将它们插入数据库中。 当我们接收到 HTTP PUT 方法时,会期望doPut()方法被调用,期望对资源进行修改。

@Override
protected void doDelete(HttpServletRequest request, HttpServletResponse response)
        throws ServletException {

    Map<String, String> dataMap = Utils.getParameterMap(request);

    String carName = dataMap.get("NAME");

    CarService.deleteCar(carName);

    getServletContext().log("Car:" + carName + " deleted");
}

doDelete()方法中,我们从请求中检索NAME参数,并使用CarService.deleteCar()方法删除汽车。 当我们收到一个 HTTP DELETE 方法,期望删除资源时,将调用doDelete()方法。

CarService.java

package com.zetcode.service;

import com.zetcode.util.Utils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.sql.DataSource;
import org.apache.derby.optional.api.SimpleJsonUtils;
import org.json.simple.JSONArray;

public class CarService {

    private static final Logger LOG = Logger.getLogger(CarService.class.getName());
    private static JSONArray jarray;

    public static void updateCar(String name, int price) {

        Connection con = null;
        PreparedStatement pst = null;

        try {

            DataSource ds = Utils.getDataSource();
            con = ds.getConnection();
            pst = con.prepareStatement("UPDATE CARS SET NAME=?, PRICE=? WHERE NAME=?");
            pst.setString(1, name);
            pst.setInt(2, price);
            pst.setString(3, name);
            pst.executeUpdate();

        } catch (SQLException ex) {

            Logger lgr = Logger.getLogger(CarService.class.getName());
            lgr.log(Level.SEVERE, ex.getMessage(), ex);

        } finally {

            try {
                if (pst != null) {
                    pst.close();
                }
                if (con != null) {
                    con.close();
                }

            } catch (SQLException ex) {

                LOG.log(Level.WARNING, ex.getMessage(), ex);
            }
        }
    }

    public static void deleteCar(String name) {

        Connection con = null;
        PreparedStatement pst = null;

        try {

            DataSource ds = Utils.getDataSource();
            con = ds.getConnection();
            pst = con.prepareStatement("DELETE FROM CARS WHERE Name=?");
            pst.setString(1, name);
            pst.executeUpdate();

        } catch (SQLException ex) {

            LOG.log(Level.SEVERE, ex.getMessage(), ex);

        } finally {

            try {
                if (pst != null) {
                    pst.close();
                }
                if (con != null) {
                    con.close();
                }

            } catch (SQLException ex) {

                LOG.log(Level.WARNING, ex.getMessage(), ex);
            }
        }
    }

    public static void insertCar(String name, int price) {

        Connection con = null;
        PreparedStatement pst = null;

        try {

            DataSource ds = Utils.getDataSource();
            con = ds.getConnection();
            pst = con.prepareStatement("INSERT INTO CARS(NAME, PRICE) "
                    + "VALUES(?, ?)");
            pst.setString(1, name);
            pst.setInt(2, price);
            pst.executeUpdate();

        } catch (SQLException ex) {

            LOG.log(Level.SEVERE, ex.getMessage(), ex);

        } finally {

            try {
                if (pst != null) {
                    pst.close();
                }
                if (con != null) {
                    con.close();
                }

            } catch (SQLException ex) {

                LOG.log(Level.WARNING, ex.getMessage(), ex);
            }
        }
    }

    public static JSONArray getCarsJSON() {

        Connection con = null;
        PreparedStatement pst = null;
        ResultSet rs = null;

        try {

            DataSource ds = Utils.getDataSource();
            con = ds.getConnection();
            pst = con.prepareStatement("SELECT NAME, PRICE FROM Cars");
            rs = pst.executeQuery();

            jarray = SimpleJsonUtils.toJSON(rs);

        } catch (SQLException ex) {

            LOG.log(Level.SEVERE, ex.getMessage(), ex);

        } finally {

            try {
                if (rs != null) {
                    rs.close();
                }
                if (pst != null) {
                    pst.close();
                }
                if (con != null) {
                    con.close();
                }

            } catch (SQLException ex) {

                LOG.log(Level.WARNING, ex.getMessage(), ex);
            }
        }

        return jarray;
    }
}

CarService包含用于数据检索和修改的方法。 我们使用标准的 JDBC 代码。 Java 数据库连接(JDBC)是 Java 编程语言的应用编程接口(API),它定义了客户端如何访问数据库。

DataSource ds = Utils.getDataSource();
con = ds.getConnection();
pst = con.prepareStatement("DELETE FROM CARS WHERE Name=?");
pst.setString(1, name);
pst.executeUpdate();

在这里,我们创建数据源并建立与 Derby 数据库的新连接。 我们执行DELETE SQL 语句。

DataSource ds = Utils.getDataSource();
con = ds.getConnection();
pst = con.prepareStatement("INSERT INTO CARS(NAME, PRICE) "
        + "VALUES(?, ?)");
pst.setString(1, name);
pst.setInt(2, price);
pst.executeUpdate();

这是用于插入新车的 JDBC 代码。

DataSource ds = Utils.getDataSource();
con = ds.getConnection();
pst = con.prepareStatement("SELECT NAME, PRICE FROM Cars");
rs = pst.executeQuery();

jarray = SimpleJsonUtils.toJSON(rs);

getCarsJSON()方法中,我们得到一个结果集,并使用SimpleJsonUtils.toJSON()将其转换为JSONArray。 该方法是derbyoptionaltools的一部分。

Utils.java

package com.zetcode.util;

import com.google.common.base.Splitter;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.http.HttpServletRequest;
import javax.sql.DataSource;
import org.apache.derby.jdbc.ClientDataSource;

public class Utils {

    public static DataSource getDataSource() {

        ClientDataSource ds = new ClientDataSource();

        ds.setDatabaseName("testdb");
        ds.setUser("app");
        ds.setPassword("app");
        ds.setServerName("localhost");
        ds.setPortNumber(1527);

        return ds;
    }

    public static Map<String, String> getParameterMap(HttpServletRequest request) {

        BufferedReader br = null;
        Map<String, String> dataMap = null;

        try {

            InputStreamReader reader = new InputStreamReader(
                    request.getInputStream());
            br = new BufferedReader(reader);

            String data = br.readLine();

            dataMap = Splitter.on('&')
                    .trimResults()
                    .withKeyValueSeparator(
                            Splitter.on('=')
                            .limit(2)
                            .trimResults())
                    .split(data);

            return dataMap;

        } catch (IOException ex) {
            Logger.getLogger(Utils.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException ex) {
                    Logger.getLogger(Utils.class.getName()).log(Level.WARNING, null, ex);
                }
            }
        }

        return dataMap;
    }
}

Utils是一个帮助程序类,它包含两个方法:getDataSource()getParameterMap()

public static DataSource getDataSource() {

    ClientDataSource ds = new ClientDataSource();

    ds.setDatabaseName("testdb");
    ds.setUser("app");
    ds.setPassword("app");
    ds.setServerName("localhost");
    ds.setPortNumber(1527);

    return ds;
}

getDataSource()创建并返回一个 Derby 数据源。

InputStreamReader reader = new InputStreamReader(
        request.getInputStream());
br = new BufferedReader(reader);

String data = br.readLine();

dataMap = Splitter.on('&')
        .trimResults()
        .withKeyValueSeparator(
                Splitter.on('=')
                .limit(2)
                .trimResults())
        .split(data);

return dataMap;

doGet()doPost()方法不同,doPut()doDelete()无法使用getParameter()方法检索请求参数。 我们必须从流中获取它们。 为此,我们使用番石榴的Splitter类。 解析参数并在映射中返回。

jsGrid component

图:jsGrid 组件

在本教程中,我们使用了 jsGrid 组件。 我们已使用从 Derby 数据库检索的数据填充了该组件。 数据以 JSON 格式从数据库发送。

您可能也对以下相关教程感兴趣: Java 教程jQuery DatePicker 教程Datatables JSON 服务器教程Apache Derby 教程

posted @ 2024-10-24 18:17  绝不原创的飞龙  阅读(3)  评论(0编辑  收藏  举报