복붙노트

[SPRING] Spring 데이터 REST : 컨트롤러에서 리파지토리 메서드 재정의

SPRING

Spring 데이터 REST : 컨트롤러에서 리파지토리 메서드 재정의

나는 Spring에서 런타임에 구현을 생성하는 다음 REST 저장소를 가지고있다.

@RepositoryRestResource
public interface FooRepository extends CrudRepository<Foo, Long> {

}

즉, save (), find (), exists () 및 REST를 통해 사용 가능하고 노출 된 다른 메소드를 갖게됩니다.

이제, 나는이 방법들 중 하나를 오버라이드하고 싶다. 예 : save (). 이를 위해 다음과 같이 해당 메서드를 노출하는 컨트롤러를 만듭니다.

@RepositoryRestController
@RequestMapping("/foo")
public class FooController {

    @Autowired
    FooService fooService;


    @RequestMapping(value = "/{fooId}", method = RequestMethod.PUT)
    public void updateFoo(@PathVariable Long fooId) {
        fooService.updateProperly(fooId);
    }

}

문제 : 이 컨트롤러를 활성화하면 Spring에 의해 구현 된 다른 모든 메소드가 더 이상 노출되지 않습니다. 예를 들어, 더 이상 / foo / 1에 GET 요청을 할 수 없습니다.

의문: 다른 자동 생성 된 Spring 메서드를 유지하면서 REST 메서드를 재정의하는 방법이 있습니까?

추가 정보 :

그래서 그것은 상자에서 작동해야하지만 불행히도하지 않는 것 같습니다.

해결법

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

    1.설명서의 예제를주의 깊게 살펴보십시오. 클래스 수준의 요청 매핑을 명시 적으로 금지하지 않지만 메서드 수준의 요청 매핑을 사용합니다. 이것이 바람직한 행동인지 버그인지 확실하지 않지만, 여기에 언급 된 것처럼 이것이 이것이 작동하도록 만드는 유일한 방법이라는 것을 알고있는 한.

    설명서의 예제를주의 깊게 살펴보십시오. 클래스 수준의 요청 매핑을 명시 적으로 금지하지 않지만 메서드 수준의 요청 매핑을 사용합니다. 이것이 바람직한 행동인지 버그인지 확실하지 않지만, 여기에 언급 된 것처럼 이것이 이것이 작동하도록 만드는 유일한 방법이라는 것을 알고있는 한.

    컨트롤러를 다음과 같이 변경하십시오.

    @RepositoryRestController
    public class FooController {
    
        @Autowired
        FooService fooService;
    
        @RequestMapping(value = "/foo/{fooId}", method = RequestMethod.PUT)
        public void updateFoo(@PathVariable Long fooId) {
            fooService.updateProperly(fooId);
        }
    
        // edited after Sergey's comment
        @RequestMapping(value = "/foo/{fooId}", method = RequestMethod.PUT)
        public RequestEntity<Void> updateFoo(@PathVariable Long fooId) {
            fooService.updateProperly(fooId);
    
            return ResponseEntity.ok().build(); // simplest use of a ResponseEntity
        }
    }
    
  2. ==============================

    2.Account 엔티티가 있다고 가정 해 보겠습니다.

    Account 엔티티가 있다고 가정 해 보겠습니다.

    @Entity
    public class Account implements Identifiable<Integer>, Serializable {
    
        private static final long serialVersionUID = -3187480027431265380L;
    
        @Id
        private Integer id;
        private String name;
    
        public Account(Integer id, String name) {
            this.id = id;
            this.name = name;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        @Override
        public Integer getId() {
            return id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    

    / accounts에 CRUD 엔드 포인트를 표시하는 AccountRepository를 사용하는 경우 :

    @RepositoryRestResource(collectionResourceRel = "accounts", path = "accounts")
    public interface AccountRepository extends CrudRepository<Account, Integer> {
    } 
    

    AccountRepository : 기본 GET 끝점 양식을 재정의하는 AccountController.

    @RepositoryRestController
    public class AccountController {
        private PagedResourcesAssembler<Account> pagedAssembler;
    
        @Autowired
        public AccountController(PagedResourcesAssembler<Account> pagedAssembler) {
            this.pagedAssembler = pagedAssembler;
        }
    
        private Page<Account> getAccounts(Pageable pageRequest){
            int totalAccounts= 50;
            List<Account> accountList = IntStream.rangeClosed(1, totalAccounts)
                                                 .boxed()
                                                 .map( value -> new Account(value, value.toString()))
                                                 .skip(pageRequest.getOffset())
                                                 .limit(pageRequest.getPageSize())
                                                 .collect(Collectors.toList());
            return new PageImpl(accountList, pageRequest, totalAccounts);
        }
    
        @RequestMapping(method= RequestMethod.GET, path="/accounts", produces = "application/hal+json")
        public ResponseEntity<Page<Account>> getAccountsHal(Pageable pageRequest, PersistentEntityResourceAssembler assembler){
            return new ResponseEntity(pagedAssembler.toResource(getAccounts(pageRequest), (ResourceAssembler) assembler), HttpStatus.OK);
        }
    

    ? GET / accounts? size = 5 & page = 0을 호출하면 mock 구현을 사용하는 다음과 같은 결과가 출력됩니다.

    {
      "_embedded": {
        "accounts": [
          {
            "name": "1",
            "_links": {
              "self": {
                "href": "http://localhost:8080/accounts/1"
              },
              "account": {
                "href": "http://localhost:8080/accounts/1"
              }
            }
          },
          {
            "name": "2",
            "_links": {
              "self": {
                "href": "http://localhost:8080/accounts/2"
              },
              "account": {
                "href": "http://localhost:8080/accounts/2"
              }
            }
          },
          {
            "name": "3",
            "_links": {
              "self": {
                "href": "http://localhost:8080/accounts/3"
              },
              "account": {
                "href": "http://localhost:8080/accounts/3"
              }
            }
          },
          {
            "name": "4",
            "_links": {
              "self": {
                "href": "http://localhost:8080/accounts/4"
              },
              "account": {
                "href": "http://localhost:8080/accounts/4"
              }
            }
          },
          {
            "name": "5",
            "_links": {
              "self": {
                "href": "http://localhost:8080/accounts/5"
              },
              "account": {
                "href": "http://localhost:8080/accounts/5"
              }
            }
          }
        ]
      },
      "_links": {
        "first": {
          "href": "http://localhost:8080/accounts?page=0&size=5"
        },
        "self": {
          "href": "http://localhost:8080/accounts?page=0&size=5"
        },
        "next": {
          "href": "http://localhost:8080/accounts?page=1&size=5"
        },
        "last": {
          "href": "http://localhost:8080/accounts?page=9&size=5"
        }
      },
      "page": {
        "size": 5,
        "totalElements": 50,
        "totalPages": 10,
        "number": 0
      }
    }
    

    완벽을 기하기 위해 POM을 다음 상위 항목과 종속 항목으로 구성 할 수 있습니다.

    <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>1.5.2.RELEASE</version>
        </parent>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.data</groupId>
                <artifactId>spring-data-rest-webmvc</artifactId>
                <version>2.6.1.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-jpa</artifactId>
            </dependency>
            <dependency>
                <groupId>com.h2database</groupId>
                <artifactId>h2</artifactId>
            </dependency>
        </dependencies>
    
  3. ==============================

    3.Java 8을 사용하는 경우에는 깔끔한 해결책을 발견했습니다. 인터페이스에서 기본 메소드 만 사용하십시오.

    Java 8을 사용하는 경우에는 깔끔한 해결책을 발견했습니다. 인터페이스에서 기본 메소드 만 사용하십시오.

    @RepositoryRestResource
    public interface FooRepository extends CrudRepository<Foo, Long> {
        default <S extends T> S save(S var1) {
            //do some work here
        }
    }
    
  4. ==============================

    4.내가 찾은 업데이트 만 내 목숨을 구했어. 이 대답에서 @ mathias-dpunkt에 의해 훌륭하게 말한 것처럼 https://stackoverflow.com/a/34518166/2836627

    내가 찾은 업데이트 만 내 목숨을 구했어. 이 대답에서 @ mathias-dpunkt에 의해 훌륭하게 말한 것처럼 https://stackoverflow.com/a/34518166/2836627

    따라서 기본 경로가 "/ api"이고 @RepositoryRestController를 사용하는 경우

    @RequestMapping에서 "/ api"를 생략해야합니다.

  5. from https://stackoverflow.com/questions/36773171/spring-data-rest-override-repository-method-on-the-controller by cc-by-sa and MIT license