gpt4 book ai didi

java - 我应该使用模型类还是有效负载类来序列化 json 响应

转载 作者:塔克拉玛干 更新时间:2023-11-01 23:01:03 27 4
gpt4 key购买 nike

我正在使用带有 mysql 的 spring boot 创建一个 Restful API。这是我如何返回 json 响应的示例。

首先我有一个模型:

@Entity
public class Movie extends DateAudit {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private Date releaseDate;
private Time runtime;
private Float rating;
private String storyline;
private String poster;
private String rated;

@OneToMany(mappedBy = "movie", cascade = CascadeType.ALL, orphanRemoval = true)
private List<MovieMedia> movieMedia = new ArrayList<>();

@OneToMany(mappedBy = "movie", cascade = CascadeType.ALL, orphanRemoval = true)
private List<MovieReview> movieReviews = new ArrayList<>();

@OneToMany(mappedBy = "movie", cascade = CascadeType.ALL, orphanRemoval = true)
private List<MovieCelebrity> movieCelebrities = new ArrayList<>();

// Setters & Getters
}

和相应的存储库:

@Repository
public interface MovieRepository extends JpaRepository<Movie, Long> {
}

我还有一个有效负载类 MovieResponse,它表示电影而不是 Movie 模型,例如,如果我需要额外的字段或我需要返回特定字段。

public class MovieResponse {

private Long id;
private String name;
private Date releaseDate;
private Time runtime;
private Float rating;
private String storyline;
private String poster;
private String rated;
private List<MovieCelebrityResponse> cast = new ArrayList<>();
private List<MovieCelebrityResponse> writers = new ArrayList<>();
private List<MovieCelebrityResponse> directors = new ArrayList<>();

// Constructors, getters and setters

public void setCelebrityRoles(List<MovieCelebrityResponse> movieCelebrities) {
this.setCast(movieCelebrities.stream().filter(movieCelebrity -> movieCelebrity.getRole().equals(CelebrityRole.ACTOR)).collect(Collectors.toList()));
this.setDirectors(movieCelebrities.stream().filter(movieCelebrity -> movieCelebrity.getRole().equals(CelebrityRole.DIRECTOR)).collect(Collectors.toList()));
this.setWriters(movieCelebrities.stream().filter(movieCelebrity -> movieCelebrity.getRole().equals(CelebrityRole.WRITER)).collect(Collectors.toList()));
}
}

如您所见,我将电影名人列表分为 3 个列表( Actor 、导演和编剧)

并将 Movie 映射到 MovieResponse 我正在使用 ModelMapper 类:

public class ModelMapper {

public static MovieResponse mapMovieToMovieResponse(Movie movie) {

// Create a new MovieResponse and Assign the Movie data to MovieResponse
MovieResponse movieResponse = new MovieResponse(movie.getId(), movie.getName(), movie.getReleaseDate(),
movie.getRuntime(),movie.getRating(), movie.getStoryline(), movie.getPoster(), movie.getRated());

// Get MovieCelebrities for current Movie
List<MovieCelebrityResponse> movieCelebrityResponses = movie.getMovieCelebrities().stream().map(movieCelebrity -> {

// Get Celebrity for current MovieCelebrities
CelebrityResponse celebrityResponse = new CelebrityResponse(movieCelebrity.getCelebrity().getId(),
movieCelebrity.getCelebrity().getName(), movieCelebrity.getCelebrity().getPicture(),
movieCelebrity.getCelebrity().getDateOfBirth(), movieCelebrity.getCelebrity().getBiography(), null);

return new MovieCelebrityResponse(movieCelebrity.getId(), movieCelebrity.getRole(),movieCelebrity.getCharacterName(), null, celebrityResponse);
}).collect(Collectors.toList());

// Assign movieCelebrityResponse to movieResponse
movieResponse.setCelebrityRoles(movieCelebrityResponses);
return movieResponse;
}
}

最后是我在 Controller 中调用的 MovieService 服务:

@Service
public class MovieServiceImpl implements MovieService {

private MovieRepository movieRepository;

@Autowired
public void setMovieRepository(MovieRepository movieRepository) {
this.movieRepository = movieRepository;
}

public PagedResponse<MovieResponse> getAllMovies(Pageable pageable) {

Page<Movie> movies = movieRepository.findAll(pageable);

if(movies.getNumberOfElements() == 0) {
return new PagedResponse<>(Collections.emptyList(), movies.getNumber(),
movies.getSize(), movies.getTotalElements(), movies.getTotalPages(), movies.isLast());
}

List<MovieResponse> movieResponses = movies.map(ModelMapper::mapMovieToMovieResponse).getContent();
return new PagedResponse<>(movieResponses, movies.getNumber(),
movies.getSize(), movies.getTotalElements(), movies.getTotalPages(), movies.isLast());
}
}

所以这里的问题是:我有一个用于 json 序列化的有效负载类的每个模型都可以使用吗?或者有更好的方法。
伙计们,我的代码有什么问题请随时发表评论。

最佳答案

不久前我遇到过这种困境,这是我的思考过程。我这里有https://stackoverflow.com/questions/44572188/microservices-restful-api-dtos-or-not

只公开域对象的优点

  1. 您编写的代码越少,产生的错误就越少。

    • 尽管我们的代码库中有大量(有争议的)测试用例,但我遇到了由于从域到 DTO 或反之亦然的字段复制遗漏/错误而导致的错误。
  2. 可维护性 - 更少样板代码。

    • 如果我必须添加新属性,我当然不必添加域、DTO、映射器和测试用例。不要告诉我这可以使用像 dozer 或 mapStruct 这样的反射 beanCopy 实用程序来实现,它会破坏整个目的。
    • 我知道 Lombok、Groovy、Kotlin,但这只会让我头疼。
  3. 表现
    • 我知道这属于“过早的性能优化是万恶之源”的范畴。但这仍然会节省一些 CPU 周期,因为不必为每个请求再创建(以及稍后的垃圾收集)一个对象(至少)

缺点

  1. 从长远来看,DTO 将为您提供更大的灵 active

    • 如果我需要这种灵 active 就好了。至少,到目前为止我遇到的都是通过 http 进行的 CRUD 操作,我可以使用几个 @JsonIgnores 来管理它。或者,如果有一个或两个字段需要使用 Jackson Annotation 无法完成的转​​换,正如我之前所说,我可以编写自定义逻辑来处理这个问题。
  2. 域对象因注解而变得臃肿。

    • 这是一个合理的担忧。如果我使用 JPA 或 MyBatis 作为我的持久化框架,域对象可能有那些注释,那么也会有 Jackson 注释。如果你使用的是 Spring Boot,你可以通过使用像 mybatis.configuration.map-underscore-to-camel-case: true 这样的应用程序范围的属性来摆脱困境。 , spring.jackson.property-naming-strategy: SNAKE_CASE

短篇小说,至少在我的情况下,缺点并没有超过优点,因此通过将新的 POJO 作为 DTO 来重复我自己没有任何意义。更少的代码,更少的错误机会。因此,继续公开 Domain 对象并且没有单独的“ View ”对象。

免责声明:这可能适用于您的用例,也可能不适用。这个观察是根据我的用例(基本上是一个具有 15 个端点的 CRUD api)

关于java - 我应该使用模型类还是有效负载类来序列化 json 响应,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52235902/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com