복붙노트

[SPRING] 커스텀 컨트롤러 메소드를위한 Spring Boot에서 HAL 직렬화 사용

SPRING

커스텀 컨트롤러 메소드를위한 Spring Boot에서 HAL 직렬화 사용

spring-boot-startter-data-rest를 사용하여 Spring Boot로 RESTful API를 구현하려고한다. 계정, 거래, 카테고리 및 사용자 등 일부 항목이 있습니다. 일반적인 항목입니다.

기본적으로 생성 된 API를 통해 http : // localhost : 8080 / transactions에서 객체를 검색하면 모든 트랜잭션이 잘 진행됩니다. 모든 트랜잭션과 함께 JSON 객체로 목록을 가져옵니다.

{
  "amount": -4.81,
  "date": "2014-06-17T21:18:00.000+0000",
  "description": "Pizza",
  "_links": {
    "self": {
      "href": "http://localhost:8080/transactions/5"
    },
    "category": {
      "href": "http://localhost:8080/transactions/5/category"
    },
    "account": {
      "href": "http://localhost:8080/transactions/5/account"
    }
  }
}

그러나 이제 전체 데이터베이스 테이블을 직렬화하지 않으려 고하므로 그 URL의 최신 트랜잭션 만 검색하는 것이 목표입니다. 그래서 나는 컨트롤러를 썼다.

@Controller
public class TransactionController {
    private final TransactionRepository transactionRepository;

    @Autowired
    public TransactionController(TransactionRepository transactionRepository) {
        this.transactionRepository = transactionRepository;
    }

    // return the 5 latest transactions
    @RequestMapping(value = "/transactions", method = RequestMethod.GET)
    public @ResponseBody List<Transaction> getLastTransactions() {
        return  transactionRepository.findAll(new PageRequest(0, 5, new Sort(new Sort.Order(Sort.Direction.DESC, "date")))).getContent();
    }
}

http : // localhost : 8080 / transactions에 액세스하려고하면

java.lang.IllegalStateException: Cannot call sendError() after the response has been committed

사용자와 계정 간의 순환 참조 때문입니다. User의 계정 목록에 @JsonBackReference 주석을 추가하여이 문제를 해결하면 트랜잭션 목록을 검색 할 수 있지만이 "클래식"형식 만 사용할 수 있습니다.

{
  "id": 5,
  "amount": -4.5,
  "date": "2014-06-17T21:18:00.000+0000",
  "description": "Pizza",
  "account": {
    "id": 2,
    "name": "Account Tilman",
    "owner": {
      "id": 1,
      "name": "Tilman"
    },
    "categories": [
      {
        "id": 1,
        "name": "Groceries"
      },
      {
        "id": 2,
        "name": "Restaurant"
      }
    ],
    "users": [
      {
        "id": 1,
        "name": "Tilman"
      }
    ]
  },
  "category": {
    "id": 2,
    "name": "Restaurant"
  }
}

더 이상 HAL 링크가 없으며 모든 것이 곧 잭슨에 의해 직렬화됩니다. 나는 추가를 시도했다.

@EnableHypermediaSupport(type = HypermediaType.HAL)

엔티티 클래스들에 전달했는데 그걸로 어디서나 나에게 다가 가지 않았다. 난 단지 내 컨트롤러가 생성 된 API와 동일한 객체를 반환하고, 모든 참조가 직렬화되는 대신 HAL _link를 사용하기를 원합니다. 이견있는 사람?

편집하다: 좋아, 두 번 생각한 후에 @EnableHypermediaSupport 주석을 구성에 추가해야한다는 것을 알았습니다. 이것은 순환 참조의 문제를 해결하고 사용자로부터 @JsonBackReference를 제거 할 수 있습니다. 그러나 객체 자체의 속성 만 직렬화되고 _links 섹션은 없습니다.

{
    "amount": -4.81,
    "date": "2014-06-17T21:18:00.000+0000",
    "description": "Pizza"
}

나는 모든 엔티티에 대해 ResourceSupport를 확장하는 래퍼 클래스를 작성할 수 있다는 것을 알고 있지만 이것은 무의미한 것처럼 보입니다. Spring-hateoas는 자동으로 생성 된 REST 인터페이스의 _link 섹션을 사용하여 마술처럼 표현을 생성 할 수 있으므로 사용자 정의 컨트롤러에서 동일한 표현을 반환하는 방법이 있어야합니다. 맞습니까?

해결법

  1. ==============================

    1.여기에 많은 측면이 있습니다.

    여기에 많은 측면이 있습니다.

  2. ==============================

    2.쿼리 결과를 제한하거나 결과를 정렬하기 위해 자체 컨트롤러를 만들 필요가 없습니다. 저장소에 쿼리 메소드를 작성하십시오.

    쿼리 결과를 제한하거나 결과를 정렬하기 위해 자체 컨트롤러를 만들 필요가 없습니다. 저장소에 쿼리 메소드를 작성하십시오.

    public interface TransactionRepository extends MongoRepository<Transaction, String> {
    
        List<Transaction> findFirst10ByOrderByDateDesc();
    
    }
    

    Spring Data REST는이를 자동으로 / transactions / search / findFirst10ByOrderByDateDesc의 메소드 자원으로 익스포트합니다.

  3. ==============================

    3.컨트롤러에서 PersistentEntityResourceAssembler를 사용하려면 @RepositoryRestController로 표시해야합니다.

    컨트롤러에서 PersistentEntityResourceAssembler를 사용하려면 @RepositoryRestController로 표시해야합니다.

    @RestController
    @RequestMapping("/categories")
    @RepositoryRestController
    public class CategoryController implements ValidableController {
    
    // dependencies
    
    @RequestMapping(method = POST, consumes = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<PersistentEntityResource> create(@Valid @RequestBody CategoryForm category,
                                                           BindingResult validation,
                                                           PersistentEntityResourceAssembler resourceAssembler)
    {
        validate(validation);
        Category entity = categoryConverter.convert(category);
        entity = categoryService.save(entity);
        return ResponseEntity.ok(resourceAssembler.toFullResource(entity));
    }
    

    꽤 멋진 HAL 스타일의 응답을 만든다.

    {
    "createdTime": "2018-07-24T00:55:32.854",
    "updatedTime": "2018-07-24T00:55:32.855",
    "name": "cfvfcdfgdfdfdfs32",
    "options": [
        "aaa",
        "bbb"
    ],
    "_links": {
        "self": {
            "href": "http://localhost:8080/shop/categories/34"
        },
        "category": {
            "href": "http://localhost:8080/shop/categories/34{?projection}",
            "templated": true
        },
        "products": {
            "href": "http://localhost:8080/shop/categories/34/products"
        },
        "categories": {
            "href": "http://localhost:8080/shop/categories/34/categories{?projection}",
            "templated": true
        },
        "parent": {
            "href": "http://localhost:8080/shop/categories/34/parent{?projection}",
            "templated": true
        }
    }
    

    }

  4. from https://stackoverflow.com/questions/31758862/enable-hal-serialization-in-spring-boot-for-custom-controller-method by cc-by-sa and MIT license