簡體   English   中英

如何在 DTO class 中注入 @Component 以實現 Rest controller 中的可重用性?

[英]How to inject @Component in DTO class for reusability in Rest controller?

我在下面有四個 Java 文件的簡單且自給自足的示例。 我的問題是如何使用 @Component 注釋 DTO class 並將其注入 controller class 以供重用? 使用該注釋簡單地注釋ResponseDto.java class 不會做任何事情。

First file is REST controller ( Controller.java ), second file is utility class ( CountriesUtility.java ) containing one list of strings with country codes and one method to check if given argument from the controller, country code, is present in the list of此實用程序 class 中的字符串。 第三個文件是運行此 Spring 應用程序的主應用程序文件 ( DemoForInjectionApplication.java )。 最后一個文件是簡單的 DTO class ( ResponseDTO.java ) 用於創建響應 JSON。

在“ http://localhost:8080/controller/required_fields?country_code=PL ”處的 POST 請求代碼以{ "status": "OK", "data": "Correct country!" }響應並且對於“ { "status": "OK", "data": "Correct country!" } ://localhost:8080/controller/required_fields?country_code=NOSUCHCOUNTRY ”的 POST 請求響應{ "status": "Error", "data": "" }

Controller.java

package com.examplead.demoforinjection;

import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("controller")
public class Controller {

  @PostMapping(value = "/required_fields", produces = MediaType.APPLICATION_JSON_VALUE)
  @ResponseStatus(code = HttpStatus.OK)
  public @ResponseBody ResponseDto requiredFields(@RequestParam(name = "country_code") final String countryCode) {
    /* How can I annotate the DTO class with @Component and inject it into this class for reuse? */
    final ResponseDto responseDto;
    responseDto = new CountriesCurrenciesUtility().isValidCountryAndCurrency(countryCode);
    return responseDto;
  }

}

國家公用事業.java

package com.examplead.demoforinjection;

import java.util.Arrays;
import java.util.List;

public class CountriesCurrenciesUtility {

  private static final List<String> COUNTRIES = Arrays.asList("BE", "GR", "RE", "PL");

  public ResponseDto isValidCountryAndCurrency(final String countryCode) {
    ResponseDto dto = new ResponseDto();

    if (COUNTRIES.contains(countryCode)) {
      dto.setData("Correct country!");
      dto.setStatus("OK");
    } else {
      dto.setData("");
      dto.setStatus("Error");
    }

    return dto;
  }
}

DemoForInjectionApplication.java

package com.examplead.demoforinjection;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoForInjectionApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoForInjectionApplication.class, args);
    }

}

響應DTO.java

package com.examplead.demoforinjection;

import com.fasterxml.jackson.annotation.JsonProperty;

import java.util.Objects;

public class ResponseDto {
  /**
   * Status of the request.
   */
  @JsonProperty()
  private String status;

  /**
   * Data of the request.
   */
  @JsonProperty()
  private String data;

  @Override
  public String toString() {
    return "ResponseDto{" +
      "status='" + status + '\'' +
      ", data='" + data + '\'' +
      '}';
  }

  @Override
  public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    ResponseDto that = (ResponseDto) o;
    return Objects.equals(status, that.status) &&
      Objects.equals(data, that.data);
  }

  @Override
  public int hashCode() {
    return Objects.hash(status, data);
  }

  public String getStatus() {
    return status;
  }

  public void setStatus(String status) {
    this.status = status;
  }

  public String getData() {
    return data;
  }

  public void setData(String data) {
    this.data = data;
  }
}

pom.xml萬一有人想在本地運行它,您需要手動創建包。 This is simple pom file, generated using Spring Initializr with " Rest Repositories WEB " and " Spring Web " dependencies with Java 11.

    <?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.0.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.examplead</groupId>
    <artifactId>demo-for-injection</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo-for-injection</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>11</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

注意:數據傳輸對象不用於注入。 它們用於將數據從一層傳輸到另一層。 根據應用程序中存在的 API,通過 DTO 的響應可能相同或不同。 因此,當需要將數據從一層發送到另一層時,最好創建 DTO 實例。

您可以在ResponseDto上執行@Component

但這是一個糟糕的設計,可能會導致一些不需要的響應。

因此,不建議根據 DTO的工作定義使用@Component注釋 DTO。

你可以按照這個簡單的設計。

修改ResponseDTO.java並保留在 package com.examplead.demoforinjection.dto

package com.examplead.demoforinjection.dto;

import java.io.Serializable;

public class ResponseDto implements Serializable {

  /**
   * default serial version ID
   */  
  private static final long serialVersionUID = 1L;  

  /**
   * Status of the request.
   */
  private String status;

  /**
   * Data of the request.
   */
  private String data;

  @Override
  public String toString() {
    return "ResponseDto{" +
      "status='" + status + '\'' +
      ", data='" + data + '\'' +
      '}';
  }

  public String getStatus() {
    return status;
  }

  public void setStatus(String status) {
    this.status = status;
  }

  public String getData() {
    return data;
  }

  public void setData(String data) {
    this.data = data;
  }

}

修改CountryCurrenciesUtility.java並保留在 package com.examplead.demoforinjection.utility

package com.examplead.demoforinjection.utility;

import java.util.Arrays;
import java.util.List;
import com.examplead.demoforinjection.dto.ResponseDto; 

public final class CountriesCurrenciesUtility {

  private static final List<String> COUNTRIES = Arrays.asList("BE", "GR", "RE", "PL");

  public static ResponseDto isValidCountryAndCurrency(final String countryCode) {
    ResponseDto dto = new ResponseDto();

    if (COUNTRIES.contains(countryCode)) {
      dto.setData("Correct country!");
      dto.setStatus("OK");
    } else {
      dto.setData("No data found.");
      dto.setStatus("Error");
    }

    return dto;
  }
}

Modify Controller.java and keep in the package com.examplead.demoforinjection.controller :

package com.examplead.demoforinjection.controller;

import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.examplead.demoforinjection.dto.ResponseDto;
import com.examplead.demoforinjection.utility.CountriesCurrenciesUtility; 

@RestController
@RequestMapping("controller")
public class Controller {

  @PostMapping(value = "/required_fields", produces = MediaType.APPLICATION_JSON_VALUE)
  public ResponseEntity<ResponseDto> requiredFields(@RequestParam(name = "country_code") final String countryCode) {
    ResponseDto responseDto = CountriesCurrenciesUtility.isValidCountryAndCurrency(countryCode);
    if(responseDto.getStatus().equals("OK")) {
      return new ResponseEntity<ResponseDto>(responseDto, HttpStatus.OK);
    }
    return new ResponseEntity<ResponseDto>(responseDto, HttpStatus.BAD_REQUEST);
  }

}

注意: @RestController包括@ResponseBody@Controller 因此,您不需要單獨使用@ResponseBody

正如公認的答案所述,這不是推薦的做事方式。 但是,有一種方法可以將依賴項注入非托管類(使用“new”運算符創建)。

@org.springframework.beans.factory.annotation.Configurable注解,就是為了這個。

參考:

取決於場景和架構方法,它可以做很多事情。 Anemic domain objects被一些人認為是反模式。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM