原文: https://howtodoinjava.com/dropwizard/tutorial-and-hello-world-example/

Dropwizard 是用于快速开发 REST API 的开源 Java 框架。 Dropwizard 是一种生态系统,其中包含捆绑到单个程序包中的所有依赖项(例如,Jersey,Jackson 或 Jetty),也可以作为单独的模块添加。 如果不使用 dropwizard,最终将自己收集所有依赖项,由于各种 Java 库之间的版本不匹配,通常会导致类加载问题。 Dropwizard 为您解决了这个问题,并将稳定,成熟的库组合到一个简单,轻巧的程序包中,使您可以专注于完成工作。 让我们逐步使用来学习使用 dropwizard 构建 REST API。

  1. Table of Contents
  2. Libraries included inside dropwizard
  3. Setup dropwizard with maven
  4. Create REST Application Class
  5. Create REST Resource and APIs
  6. Build Resource Representations
  7. Request Validation
  8. Verify REST APIs

您将需要 Java8 来运行此代码中给出的示例,这些示例是使用 dropwizard 1.0.0 版开发的。

dropwizard 中包含的库

将 dropwizard 包含到项目中后,您将获得以下库添加到您的类路径中。

  • Jersey – 用于构建 RESTful Web 应用。
  • Jetty – Dropwizard 使用 Jetty HTTP 库将 HTTP 服务器直接嵌入到您的项目中。
  • Jackson - 用于对象到 JSON 的转换。 它允许直接使用 JAXB 注解导出域模型。
  • Guava – 高度优化的不可变数据结构,可加快开发速度。
  • LogbackSLF4j – 用于高性能和灵活的日志记录。
  • Hiberante 验证器 – 一个简单的声明性框架,用于验证用户输入并生成有用且对 i18n 友好的错误消息。
  • Apache HTTPClient – 用于与其他 Web 服务的高层和高层交互。
  • JDBI - 在 Java 中使用关系数据库的最直接方法。
  • Liquidbase – 在整个开发和发布周期中,始终检查数据库模式。
  • FreeMarker – 模板系统。
  • Mustache – 适用于更多面向用户的应用的简单模板系统。
  • Joda Time –非常完整和理智的库,用于处理日期和时间。

用 Maven 设置 dropwizard

我们的项目将基于maven-archetype-quickstart原型。 您可以使用命令提示符来创建项目,或使用 eclipse 创建简单的 Maven Java 项目

  1. mvn archetype:generate -DgroupId=com.howtodoinjava.demo -DartifactId=DropWizardExample
  2. -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

生成的项目也将具有pom.xml文件。 在此处添加 dropwizard 依赖项。

  1. <properties>
  2. <dropwizard.version>1.0.0</dropwizard.version>
  3. </properties>
  4. <dependencies>
  5. <dependency>
  6. <groupId>io.dropwizard</groupId>
  7. <artifactId>dropwizard-core</artifactId>
  8. <version>${dropwizard.version}</version>
  9. </dependency>
  10. </dependencies>

这将下载所有 jar 文件并将它们添加到您的类路径中。 为了向我们的项目添加构建和程序包支持,我们将使用 maven-shade 插件,它将允许我们将我们的项目及其依赖项完全打包到一个独立的 JAR 文件中(胖/Uber JAR),可以按原样分发和执行。

完整的pom.xml文件如下所示。

  1. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  2. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd;
  3. <modelVersion>4.0.0</modelVersion>
  4. <groupId>com.howtodoinjava.demo</groupId>
  5. <artifactId>DropWizardExample</artifactId>
  6. <version>0.0.1-SNAPSHOT</version>
  7. <packaging>jar</packaging>
  8. <name>DropWizardExample</name>
  9. <url>http://maven.apache.org</url>
  10. <properties>
  11. <dropwizard.version>1.0.0</dropwizard.version>
  12. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  13. </properties>
  14. <dependencies>
  15. <dependency>
  16. <groupId>io.dropwizard</groupId>
  17. <artifactId>dropwizard-core</artifactId>
  18. <version>${dropwizard.version}</version>
  19. </dependency>
  20. </dependencies>
  21. <build>
  22. <finalName>DropWizardExample-${version}</finalName>
  23. <plugins>
  24. <plugin>
  25. <groupId>org.apache.maven.plugins</groupId>
  26. <artifactId>maven-compiler-plugin</artifactId>
  27. <version>3.1</version>
  28. <configuration>
  29. <source>1.8</source>
  30. <target>1.8</target>
  31. </configuration>
  32. </plugin>
  33. <plugin>
  34. <groupId>org.apache.maven.plugins</groupId>
  35. <artifactId>maven-shade-plugin</artifactId>
  36. <version>2.1</version>
  37. <executions>
  38. <execution>
  39. <phase>package</phase>
  40. <goals>
  41. <goal>shade</goal>
  42. </goals>
  43. <configuration>
  44. <transformers>
  45. <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
  46. <mainClass>com.howtodoinjava.rest.App</mainClass>
  47. </transformer>
  48. <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer">
  49. </transformer>
  50. </transformers>
  51. </configuration>
  52. </execution>
  53. </executions>
  54. </plugin>
  55. </plugins>
  56. </build>
  57. </project>

创建 REST 应用类

应用类是任何 dropwizard 应用的入口点。 它需要扩展io.dropwizard.Application类并实现initialize(Bootstrap<Configuration>)run(Configuration, Environment)方法。 他们准备应用的运行时环境。

要调用run方法,您需要具有public static void main(String[] args) {}方法,当您将应用作为 jar 文件运行时,该方法将由java -jar命令调用。

  1. package com.howtodoinjava.rest;
  2. import io.dropwizard.Application;
  3. import io.dropwizard.Configuration;
  4. import io.dropwizard.setup.Bootstrap;
  5. import io.dropwizard.setup.Environment;
  6. import org.slf4j.Logger;
  7. import org.slf4j.LoggerFactory;
  8. import com.howtodoinjava.rest.controller.EmployeeRESTController;
  9. public class App extends Application<Configuration> {
  10. private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
  11. @Override
  12. public void initialize(Bootstrap<Configuration> b) {
  13. }
  14. @Override
  15. public void run(Configuration c, Environment e) throws Exception {
  16. LOGGER.info("Registering REST resources");
  17. e.jersey().register(new EmployeeRESTController(e.getValidator()));
  18. }
  19. public static void main(String[] args) throws Exception {
  20. new App().run(args);
  21. }
  22. }

为了执行 JAR 文件,我们在命令中添加服务器参数,该参数启动嵌入式 HTTP 服务器(Jetty)以运行我们的服务。

  1. java -jar target\DropWizardExample.jar server

Dropwizard 的嵌入式 Jetty 服务器将默认尝试绑定到端口 80808081 。 服务器使用端口 8080 来向应用提供传入的 HTTP 请求,而 Dropwizard 的管理界面则使用 8081 端口。

我们还导入了必要的LoggerLoggerFactory类,以构造可用于日志记录需求的Logger实例。

创建 REST 资源和 API

现在,当您添加了应用引导类后,现在可以添加包含 REST API 的 REST 资源。 在此示例中,我创建并创建了员工管理应用 - 因此它具有用于创建/更新/删除员工记录的 API。 此类将负责处理 HTTP 请求并生成 JSON 响应。

由于类路径中包含 Jersey,因此我们将使用它来构建 REST API。

  1. package com.howtodoinjava.rest.controller;
  2. import java.net.URI;
  3. import java.net.URISyntaxException;
  4. import java.util.ArrayList;
  5. import java.util.Set;
  6. import javax.validation.ConstraintViolation;
  7. import javax.validation.Validator;
  8. import javax.ws.rs.DELETE;
  9. import javax.ws.rs.GET;
  10. import javax.ws.rs.POST;
  11. import javax.ws.rs.PUT;
  12. import javax.ws.rs.Path;
  13. import javax.ws.rs.PathParam;
  14. import javax.ws.rs.Produces;
  15. import javax.ws.rs.core.MediaType;
  16. import javax.ws.rs.core.Response;
  17. import javax.ws.rs.core.Response.Status;
  18. import com.howtodoinjava.rest.dao.EmployeeDB;
  19. import com.howtodoinjava.rest.representations.Employee;
  20. @Path("/employees")
  21. @Produces(MediaType.APPLICATION_JSON)
  22. public class EmployeeRESTController {
  23. private final Validator validator;
  24. public EmployeeRESTController(Validator validator) {
  25. this.validator = validator;
  26. }
  27. @GET
  28. public Response getEmployees() {
  29. return Response.ok(EmployeeDB.getEmployees()).build();
  30. }
  31. @GET
  32. @Path("/{id}")
  33. public Response getEmployeeById(@PathParam("id") Integer id) {
  34. Employee employee = EmployeeDB.getEmployee(id);
  35. if (employee != null)
  36. return Response.ok(employee).build();
  37. else
  38. return Response.status(Status.NOT_FOUND).build();
  39. }
  40. @POST
  41. public Response createEmployee(Employee employee) throws URISyntaxException {
  42. // validation
  43. Set<ConstraintViolation<Employee>> violations = validator.validate(employee);
  44. Employee e = EmployeeDB.getEmployee(employee.getId());
  45. if (violations.size() > 0) {
  46. ArrayList<String> validationMessages = new ArrayList<String>();
  47. for (ConstraintViolation<Employee> violation : violations) {
  48. validationMessages.add(violation.getPropertyPath().toString() + ": " + violation.getMessage());
  49. }
  50. return Response.status(Status.BAD_REQUEST).entity(validationMessages).build();
  51. }
  52. if (e != null) {
  53. EmployeeDB.updateEmployee(employee.getId(), employee);
  54. return Response.created(new URI("/employees/" + employee.getId()))
  55. .build();
  56. } else
  57. return Response.status(Status.NOT_FOUND).build();
  58. }
  59. @PUT
  60. @Path("/{id}")
  61. public Response updateEmployeeById(@PathParam("id") Integer id, Employee employee) {
  62. // validation
  63. Set<ConstraintViolation<Employee>> violations = validator.validate(employee);
  64. Employee e = EmployeeDB.getEmployee(employee.getId());
  65. if (violations.size() > 0) {
  66. ArrayList<String> validationMessages = new ArrayList<String>();
  67. for (ConstraintViolation<Employee> violation : violations) {
  68. validationMessages.add(violation.getPropertyPath().toString() + ": " + violation.getMessage());
  69. }
  70. return Response.status(Status.BAD_REQUEST).entity(validationMessages).build();
  71. }
  72. if (e != null) {
  73. employee.setId(id);
  74. EmployeeDB.updateEmployee(id, employee);
  75. return Response.ok(employee).build();
  76. } else
  77. return Response.status(Status.NOT_FOUND).build();
  78. }
  79. @DELETE
  80. @Path("/{id}")
  81. public Response removeEmployeeById(@PathParam("id") Integer id) {
  82. Employee employee = EmployeeDB.getEmployee(id);
  83. if (employee != null) {
  84. EmployeeDB.removeEmployee(id);
  85. return Response.ok().build();
  86. } else
  87. return Response.status(Status.NOT_FOUND).build();
  88. }
  89. }

为了模仿数据库,我创建了EmployeeDB类,该类将员工记录和更新存储在内存中。

  1. package com.howtodoinjava.rest.dao;
  2. import java.util.ArrayList;
  3. import java.util.HashMap;
  4. import java.util.List;
  5. import com.howtodoinjava.rest.representations.Employee;
  6. public class EmployeeDB {
  7. public static HashMap<Integer, Employee> employees = new HashMap<>();
  8. static{
  9. employees.put(1, new Employee(1, "Lokesh", "Gupta", "India"));
  10. employees.put(2, new Employee(2, "John", "Gruber", "USA"));
  11. employees.put(3, new Employee(3, "Melcum", "Marshal", "AUS"));
  12. }
  13. public static List<Employee> getEmployees(){
  14. return new ArrayList<Employee>(employees.values());
  15. }
  16. public static Employee getEmployee(Integer id){
  17. return employees.get(id);
  18. }
  19. public static void updateEmployee(Integer id, Employee employee){
  20. employees.put(id, employee);
  21. }
  22. public static void removeEmployee(Integer id){
  23. employees.remove(id);
  24. }
  25. }

建立资源表示

表示是保存数据并序列化为 JSON 的内容。 它是 RESTful 应用的模型。 当将 Jersey 与 Jackson 结合使用时,构建资源表示形式所需的全部就是 – 遵循 Java bean 标准的简单 POJO。 Jackson 根据每个类的设置器方法及其返回类型来递归构造 JSON 字符串。

任何java.util.List类型的实例都将转换为 JSON 数组。

  1. package com.howtodoinjava.rest.representations;
  2. import javax.validation.constraints.NotNull;
  3. import javax.validation.constraints.Pattern;
  4. import org.hibernate.validator.constraints.Length;
  5. import org.hibernate.validator.constraints.NotBlank;
  6. public class Employee {
  7. @NotNull
  8. private Integer id;
  9. @NotBlank @Length(min=2, max=255)
  10. private String firstName;
  11. @NotBlank @Length(min=2, max=255)
  12. private String lastName;
  13. @Pattern(regexp=".+@.+\\.[a-z]+")
  14. private String email;
  15. public Employee(){
  16. }
  17. public Employee(Integer id, String firstName, String lastName, String email) {
  18. this.id = id;
  19. this.firstName = firstName;
  20. this.lastName = lastName;
  21. this.email = email;
  22. }
  23. public Integer getId() {
  24. return id;
  25. }
  26. public void setId(Integer id) {
  27. this.id = id;
  28. }
  29. public String getFirstName() {
  30. return firstName;
  31. }
  32. public void setFirstName(String firstName) {
  33. this.firstName = firstName;
  34. }
  35. public String getLastName() {
  36. return lastName;
  37. }
  38. public void setLastName(String lastName) {
  39. this.lastName = lastName;
  40. }
  41. public String getEmail() {
  42. return email;
  43. }
  44. public void setEmail(String email) {
  45. this.email = email;
  46. }
  47. @Override
  48. public String toString() {
  49. return "Emplyee [id=" + id + ", firstName=" + firstName + ", lastName="
  50. + lastName + ", email=" + email + "]";
  51. }
  52. }

如果在某些情况下需要,可以通过将@JsonIgnore注解添加到其设置器来防止该属性成为 JSON 表示的一部分。

请求验证

接受PUTPOST请求时,您需要在请求正文中验证用户提交的实体内容。 Dropwizard 为此使用 Hiberate 验证器。 添加验证需要执行以下步骤。

  1. 在表示形式类中添加验证注解

  1. @NotNull
  2. private Integer id;
  3. @NotBlank @Length(min=2, max=255)
  4. private String firstName;
  5. @NotBlank @Length(min=2, max=255)
  6. private String lastName;
  7. @Pattern(regexp=".+@.+\\.[a-z]+")
  8. private String email;
  1. 在应用的 REST 资源中注入Environment.getValidator()

  1. @Override
  2. public void run(Configuration c, Environment e) throws Exception
  3. {
  4. LOGGER.info("Registering REST resources");
  5. e.jersey().register(new EmployeeRESTController(e.getValidator()));
  6. }
  1. 在 REST 资源中使用验证器

  1. public class EmployeeRESTController {
  2. private final Validator validator;
  3. public EmployeeRESTController(Validator validator) {
  4. this.validator = validator;
  5. }
  6. @POST
  7. public Response createEmployee(Employee employee) throws URISyntaxException
  8. {
  9. Set<ConstraintViolation<Employee>> violations = validator.validate(employee);
  10. Employee e = EmployeeDB.getEmployee(employee.getId());
  11. if (violations.size() > 0) {
  12. ArrayList<String> validationMessages = new ArrayList<String>();
  13. for (ConstraintViolation<Employee> violation : violations) {
  14. validationMessages.add(violation.getPropertyPath().toString() + ": " + violation.getMessage());
  15. }
  16. return Response.status(Status.BAD_REQUEST).entity(validationMessages).build();
  17. }
  18. //Create Employee code here
  19. }
  20. }

验证 REST API

现在,当我们创建并添加了 REST API 的验证后,让我们对其进行测试。

构建应用 uber jar 文件

  1. > mvn clean package

在 Jetty 服务器中启动应用

  1. > java -jar target\DropWizardExample-0.0.1-SNAPSHOT.jar server

访问 URI http://localhost:8080/employees

这将返回员工集合和相关的响应头。

Dropwizard 教程 – HelloWorld 示例 - 图1

Dropwizard – GET 请求示例 – 1

访问 URI http://localhost:8080/employees/1

这将返回 ID 为 1 的员工记录。

Dropwizard 教程 – HelloWorld 示例 - 图2

Dropwizard – GET 请求示例 – 2

使用无效的请求数据发送 HTTP PUT http://localhost:8080/employees/1

您将收到验证消息。

Dropwizard 教程 – HelloWorld 示例 - 图3

Dropwizard – 验证示例

使用正确的数据发送 HTTP PUT http://localhost:8080/employees/1

员工记录将成功更新。

Dropwizard 教程 – HelloWorld 示例 - 图4

Dropwizard – PUT 请求示例

同样,您可以测试其他 API 和方案。

源码下载

在评论部分让我知道您的问题。

学习愉快!