# Java Servlet Weld 教程

> 原文： [http://zetcode.com/articles/javaservletweld/](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 库的帮助下使用依赖项注入。

```java
$ 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`

```java
<?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`

```java
<?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`

```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`，`name`和`population`。

`beans.xml`

```java
<?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`

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

```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 对象的方法，该方法是数据库的中间层。

```java
@ManagedBean
public class CityService implements ICityService {

```

`@ManagedBean`是一个可选注解，指示`CityService`将由 Weld 管理。

```java
@Inject
private ICityDao cityDao;

```

使用`@Inject`注解，将`CityDao`注入`cityDao`属性。

`ICityDao.java`

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

```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`对象的列表。

```java
@ManagedBean
public class CityDao implements ICityDao {

```

`CityDao`也是一个托管 bean。

`GetCities.java`

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

```java
@WebServlet(name = "GetCities", urlPatterns = {"/GetCities"})

```

Java 类用`@WebServlet`注解修饰。 它映射到`GetCities` URL 模式。

```java
@Inject
ICityService cityService;

```

使用`@Inject`注解，将`CityService`注入`CityService`属性。

```java
response.setContentType("application/html;charset=UTF-8");

```

Servlet 将以 HTML 输出数据，并且数据的编码设置为 UTF-8。

```java
List<City> cities = cityService.getCities();
request.setAttribute("cities", cities);

```

使用`CityService`的`getCities()`检索所有城市。

```java
request.setAttribute("cities", cities);

```

我们将列表设置为请求。

```java
RequestDispatcher dispatcher = request.getRequestDispatcher("listCities.jsp");
dispatcher.forward(request, response);

```

使用`RequestDispatcher`将处理发送到`listCities.jsp`页面。 它是一个模板文件，该模板文件将数据与 HTML 结合在一起并向客户端生成最终输出。

`listCities.jsp`

```java
<%@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`

```java
<!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 教程](/articles/javaservletservexml/)， [Java Servlet 上传文件](/articles/javaservletuploadfile/)， [Java Log4j 教程](/java/log4j/)， [Java `HttpServletMapping`](/java/httpservletmapping/) ， [Java Servlet RESTful 客户端](/articles/javaservletrestclient/)， [Java `RequestDispatcher`](/java/requestdispatcher/) ，[从 Java Servlet 提供纯文本](/articles/javaservlettext/) ， [Java Servlet 图像教程](/articles/javaservletimage/)或 [Java 教程](/lang/java/)。