programing

Spring MVC + Spring Data Rest를 혼합하면 홀수 MVC 응답이 발생합니다.

elecom 2023. 9. 5. 19:41
반응형

Spring MVC + Spring Data Rest를 혼합하면 홀수 MVC 응답이 발생합니다.

두 개의 JPA 엔티티가 있습니다. 하나는 SDR 내보낸 저장소, 다른 하나는 Spring MVC 컨트롤러 및 내보내지 않은 저장소입니다.

MVC 노출 엔티티는 SDR 관리 엔티티에 대한 참조를 가지고 있습니다.코드 참조는 아래를 참조하십시오.

이 문제는 검색할 때 발생합니다.UserUserControllerSDR 관리 엔티티가 직렬화되지 않고 Spring이 응답에 HATOAS 참조를 사용하려고 하는 것 같습니다.

이것이 무엇입니까?GET.User다음과 같은 모양:

{
  "username": "foo@gmail.com",
  "enabled": true,
  "roles": [
    {
      "role": "ROLE_USER",
      "content": [],
      "links": [] // why the content and links?
    }
    // no places?
  ]
}

어떻게 하면 쉽게 반품할 수 있습니까?UserSDR 관리 엔티티가 내장된 컨트롤러의 엔티티?

Spring MVC 관리

독립체

@Entity
@Table(name = "users")
public class User implements Serializable {

    // UID

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @JsonIgnore
    private Long id;

    @Column(unique = true)
    @NotNull
    private String username;

    @Column(name = "password_hash")
    @JsonIgnore
    @NotNull
    private String passwordHash;

    @NotNull
    private Boolean enabled;

    // No Repository
    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
    @NotEmpty
    private Set<UserRole> roles = new HashSet<>();

    // The SDR Managed Entity
    @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @JoinTable(name = "user_place", 
        joinColumns = { @JoinColumn(name = "users_id") }, 
        inverseJoinColumns = { @JoinColumn(name = "place_id")})
    private Set<Place> places = new HashSet<>();

    // getters and setters
}

레포

@RepositoryRestResource(exported = false)
public interface UserRepository extends PagingAndSortingRepository<User, Long> {
    // Query Methods
}

컨트롤러

@RestController
public class UserController {

    // backed by UserRepository
    private final UserService userService;

    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }

    @RequestMapping(path = "/users/{username}", method = RequestMethod.GET)
    public User getUser(@PathVariable String username) {
        return userService.getByUsername(username);
    }

    @RequestMapping(path = "/users", method = RequestMethod.POST)
    public User createUser(@Valid @RequestBody UserCreateView user) {
        return userService.create(user);
    }

    // Other MVC Methods
}

SDR 관리

독립체

@Entity
public class Place implements Serializable {

    // UID

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @NotBlank
    private String name;

    @Column(unique = true)
    private String handle;

    @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true)
    @JoinColumn(name = "address_id")
    private Address address;

    @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true)
    @JoinColumn(name = "contact_info_id")
    private ContactInfo contactInfo;

    // getters and setters
}

레포

public interface PlaceRepository extends PagingAndSortingRepository<Place, Long> {
    // Query Methods
}

요약하자면, Spring Data REST 및 Spring HATEOAS는 ObjectMapper를 하이잭킹하고 리소스 간의 관계를 리소스를 포함하지 않고 링크로 표현하고자 합니다.

일대일 관계를 가진 엔티티를 다른 엔티티와 함께 사용합니다.

@Entity
public class Person {
    private String firstName;
    private String lastName;
    @OneToOne private Address address;
}

SDR/HATEOAS에서 주소를 링크로 반환합니다.

{
    "firstName": "Joe",
    "lastName": "Smith",
    "_links": {
        "self": { "href": "http://localhost:8080/persons/123123123" },
        "address": { "href": "http://localhost:8080/addresses/9127391273" }
    }
}

기본 형식은 클래스 경로에 있는 내용에 따라 변경될 수 있습니다.SDR과 HATEOAS를 포함할 때 기본값인 HAL이 이 예를 들어 HAL이라고 생각합니다.해당 구성에 따라 다르지만 유사할 수 있습니다.

은 봄은이할것다입니을것▁when다▁will▁do 때 이것을 할 것입니다.AddressSDR에서 관리합니다. SDR에서 관리하지 않으면 전체 주소 개체가 응답에 포함됩니다.당신이 보고 있는 행동은 그것만으로도 설명이 될 것 같습니다.

역할

에 대한 정보를 UserRole하지만 당신의 코드에 따르면 외부에서 관리되지 않는 것으로 보입니다.User등록된 Spring Data 저장소가 없습니다.만약 이것이 그것이 내장된 이유라면, '연결'할 다른 저장소가 없습니다.

content그리고.links언더롤은 스프링이 그것을 시리즈화하려고 노력하는 것처럼 보입니다.Page으로.일반적으로.content 및 "는 다음과 같이 표시됩니다.links 리소스에 자체' 또는 다른 리소스에 대한 링크가 있습니다.저는 무엇이 그것을 유발하는지 확신할 수 없습니다.

장소

Place는 자체적인 Spring Data 저장소를 보유하고 있으므로 관리 엔티티로 취급되며 내장된 것이 아니라 에 연결됩니다.저는 당신이 찾고 있는 것이 투영이라고 의심합니다.투영에 대한 Spring 문서를 확인하십시오.다음과 같이 표시됩니다.

@Projection(name = "embedPlaces", types = { User.class })
interface EmbedPlaces {
    String getUsername();
    boolean isEnabled();
    Set<Place> getPlaces();
}

그러면 사용자 이름, 활성화된 역할 및 역할이 직렬화되고 다른 모든 항목이 생략됩니다.저는 아직 개인적으로 프로젝션을 사용한 적이 없기 때문에 얼마나 잘 작동하는지 장담할 수 없지만 설명서에는 이것이 해결책입니다.

편집: 이 작업은 리소스를 만들거나 업데이트하는 경우에도 적용됩니다.Spring은 리소스를 URL로 예상합니다. 따라서 사용자/주소 예를 들어, 내가 새로운 사용자를 생성할 때 내 몸은 다음과 같이 보일 수 있습니다.

{
    "firstName": "New",
    "lastName": "Person",
    "address": "http://localhost:8080/addresses/1290312039123"
}

방대한, 방대한, 방대한, 방대한, 방대한 대부분의 "REST" API는 REST가 아니며 SDR/HATEOAS는 REST에 대해 확고한 견해를 가지고 있기 때문에 이러한 사실을 잊기 쉽습니다(예: REST여야 합니다).

컨트롤러에서 @ResponseEntity를 잘 사용한 다음 ResponseEntity에서 사용자 개체를 설정할 수 있습니다.

아래의 예를 참조하십시오.

ResponseEntity<User> respEntity = new ResponseEntity<User>(user, HttpStatus.OK);

그럼 고객 쪽에서 전화해 보세요restTemplate.getForEntity

아래의 restTemplate 설명서를 참조하십시오.

http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/client/RestTemplate.html#getForObject-java.lang.String-java.lang.Class-java.lang.Object ...-

언급URL : https://stackoverflow.com/questions/37232377/mixing-spring-mvc-spring-data-rest-results-in-odd-mvc-responses

반응형