知識庫 / REST RSS 訂閱

Jersey 中 Bean 驗證

Jakarta EE,REST
HongKong
9
03:52 AM · Dec 06 ,2025

1. 概述

本教程將介紹使用開源框架 Jersey 進行 Bean 驗證。

正如我們在之前的文章中所看到,Jersey 是一個用於開發 RESTful Web 服務的開源框架。有關 Jersey 的更多信息,請參閲我們關於使用 Jersey 和 Spring 創建 API 的介紹。

2. 在 Jersey 中使用 Bean 驗證

驗證是指檢查某些數據是否符合預定義的約束。這在大多數應用程序中是一個非常常見的用例。

Java Bean 驗證 框架(JSR-380)已成為 Java 中處理此類操作的默認標準。為了回顧 Java Bean 驗證的基礎知識,請參考我們的上一篇教程。

Jersey 包含一個擴展模塊以支持 Bean 驗證。要使用此功能,我們首先需要在我們的應用程序中進行配置。在下一部分中,我們將看到如何配置我們的應用程序。

3. 應用設置

現在,讓我們基於《Jersey MVC 支持》文章中提供的簡單 Fruit API 示例進行擴展。

3.1. Maven 依賴

首先,讓我們將 Bean Validation 依賴添加到我們的 pom.xml 中:

<dependency>
    <groupId>org.glassfish.jersey.ext</groupId>
    <artifactId>jersey-bean-validation</artifactId>
    <version>3.1.1</version>
</dependency>

我們可以從 Maven Central 獲取最新版本:Maven Central

3.2. 服務器配置

在 Jersey 中,我們通常會在自定義資源配置類中註冊所需的擴展功能。

然而,對於 Bean 驗證擴展,無需進行此項註冊。 幸運的是,這確實是 Jersey 框架自動註冊的少數擴展功能之一。

最後,為了將驗證錯誤發送到客户端,我們將向自定義資源配置添加一個服務器屬性:

public ViewApplicationConfig() {
    packages("com.baeldung.jersey.server");
    property(ServerProperties.BV_SEND_ERROR_IN_RESPONSE, true);
}

4. 驗證 JAX-RS 資源方法

本節將解釋兩種使用約束註解驗證輸入參數的不同方法:

  • 使用內置的 Bean Validation API 約束
  • 創建自定義約束和驗證器

4.1. 使用內置約束標註

讓我們首先看一下內置約束標註:

@POST
@Path("/create")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public void createFruit(
    @NotNull(message = "Fruit name must not be null") @FormParam("name") String name, 
    @NotNull(message = "Fruit colour must not be null") @FormParam("colour") String colour) {

    Fruit fruit = new Fruit(name, colour);
    SimpleStorageService.storeFruit(fruit);
}

在本示例中,我們使用兩個表單參數 Fruit(水果)和 name(名稱)和 colour(顏色)創建了一個新的 Fruit 對象。我們使用了 @NotNull 註解,該註解已包含在 Bean Validation API 中。

這為我們的表單參數施加了一個簡單的非空約束。如果其中一個參數為 null,則註解中聲明的消息將被返回。

當然,我們將通過一個單元測試來演示這一點:

@Test
public void givenCreateFruit_whenFormContainsNullParam_thenResponseCodeIsBadRequest() {
    Form form = new Form();
    form.param("name", "apple");
    form.param("colour", null);
    Response response = target("fruit/create").request(MediaType.APPLICATION_FORM_URLENCODED)
        .post(Entity.form(form));

    assertEquals("Http Response should be 400 ", 400, response.getStatus());
    assertThat(response.readEntity(String.class), containsString("Fruit colour must not be null"));
}

在上述示例中,我們使用 JerseyTest 支持類來測試我們的水果資源。我們發送一個帶有空 colour 的 POST 請求,並檢查響應是否包含預期的消息。

有關內置驗證約束的列表,請參閲 文檔

4.2. 定義自定義約束標註

有時我們需要施加更復雜的約束。 我們可以通過定義自己的自定義標註來實現。

利用我們簡單的 Fruit API 示例,讓我們假設我們需要驗證所有水果都有有效的序列號:

@PUT
@Path("/update")
@Consumes("application/x-www-form-urlencoded")
public void updateFruit(@SerialNumber @FormParam("serial") String serial) {
    //...
}

在此示例中,參數 serial 必須滿足 @SerialNumber 定義的約束,我們將在下面定義它。

我們首先定義約束標註:

@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = { SerialNumber.Validator.class })
    public @interface SerialNumber {

    String message()

    default "Fruit serial number is not valid";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

接下來,我們將定義驗證器類 SerialNumber.Validator

public class Validator implements ConstraintValidator<SerialNumber, String> {
    @Override
    public void initialize(SerialNumber serial) {
    }

    @Override
    public boolean isValid(String serial, 
        ConstraintValidatorContext constraintValidatorContext) {
        
        String serialNumRegex = "^\\d{3}-\\d{3}-\\d{4}$";
        return Pattern.matches(serialNumRegex, serial);
    }
}

關鍵在於 Validator 類必須實現 ConstraintValidator,其中 T 是我們想要驗證的值的類型,在本例中是 String

最後,我們將在 isValid 方法中實現自定義驗證邏輯。

5. 資源驗證

此外,Bean Validation API 也允許我們使用 @Valid 註解來驗證對象。

在下一部分,我們將解釋使用該註解驗證資源類兩種不同的方法:

  • 首先,請求資源驗證
  • 其次,響應資源驗證

讓我們先添加 @Min 註解到我們的 Fruit 對象中:

@XmlRootElement
public class Fruit {

    @Min(value = 10, message = "Fruit weight must be 10 or greater")
    private Integer weight;
    //...
}

5.1. 請求資源驗證

首先,我們將使用 @Valid 在我們的 FruitResource 類中啓用驗證:

@POST
@Path("/create")
@Consumes("application/json")
public void createFruit(@Valid Fruit fruit) {
    SimpleStorageService.storeFruit(fruit);
}

在上面的示例中,如果我們嘗試創建一個重量小於 10 的水果,將會收到驗證錯誤。

5.2. 響應資源驗證

同樣,在下一個示例中,我們將看到如何驗證響應資源:

@GET
@Valid
@Produces("application/json")
@Path("/search/{name}")
public Fruit findFruitByName(@PathParam("name") String name) {
    return SimpleStorageService.findByName(name);
}

請注意,我們使用相同的 @Valid 註解。但這次我們將其用於資源方法級別,以確保響應有效。

6. 自定義異常處理程序

在這一部分,我們將簡要探討如何創建自定義異常處理程序。 這在我們需要違反特定約束時返回自定義響應時非常有用。

讓我們首先定義我們的 FruitExceptionMapper

public class FruitExceptionMapper implements ExceptionMapper<ConstraintViolationException> {

    @Override
    public Response toResponse(ConstraintViolationException exception) {
        return Response.status(Response.Status.BAD_REQUEST)
            .entity(prepareMessage(exception))
            .type("text/plain")
            .build();
    }

    private String prepareMessage(ConstraintViolationException exception) {
        StringBuilder message = new StringBuilder();
        for (ConstraintViolation<?> cv : exception.getConstraintViolations()) {
            message.append(cv.getPropertyPath() + " " + cv.getMessage() + "\n");
        }
        return message.toString();
    }
}

首先,我們定義了一個自定義異常映射提供者。為此,我們使用 ConstraintViolationException 實現 ExceptionMapper 接口。

因此,當此異常被拋出時,我們的自定義異常映射器實例的toResponse 方法將被調用。

此外,在這個簡單的示例中,我們遍歷所有違反的情況,並將每個屬性和消息附加到響應中發送。

接下來,為了使用我們的自定義異常映射器,我們需要註冊提供者:

@Override
protected Application configure() {
    ViewApplicationConfig config = new ViewApplicationConfig();
    config.register(FruitExceptionMapper.class);
    return config;
}

最後,我們添加一個端點,返回一個無效的 Fruit 以展示異常處理機制:

@GET
@Produces(MediaType.TEXT_HTML)
@Path("/exception")
@Valid
public Fruit exception() {
    Fruit fruit = new Fruit();
    fruit.setName("a");
    fruit.setColour("b");
    return fruit;
}

7. 結論

總而言之,在本教程中,我們探討了 Jersey Bean Validation API 擴展。

首先,我們介紹了 Bean Validation API 如何在 Jersey 中使用。 此外,我們還查看了如何配置一個示例 Web 應用程序。

最後,我們研究了使用 Jersey 進行驗證的多種方法,以及如何編寫自定義異常處理程序。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.