복붙노트

[SPRING] @PathVariable DomainObject에서 String으로 변환 하시겠습니까? (ControllerLinkBuilder.methodOn 사용)

SPRING

@PathVariable DomainObject에서 String으로 변환 하시겠습니까? (ControllerLinkBuilder.methodOn 사용)

Spring의 ControllerLinkBuilder.methodOn ()을 String이 아닌 타입으로 호출하려고하는데, 항상 실패합니다. 그리고 어떤 종류의 변환기를 사용할 지, 어디에 등록 할 지 모르겠습니다.

내 컨트롤러는 다음과 같습니다.

@RestController
@RequestMapping("/companies")
class CompanyController {

    @RequestMapping(value="/{c}", method=RequestMethod.GET)
    void getIt(@PathVariable Company c) {
        System.out.println(c);
        Link link = linkTo(methodOn(getClass()).getIt(c));
    }

}

System.out.println (c)는 잘 작동합니다. 내 Company Domain 객체가 DB에서 가져옵니다. (나는 DomainClassConverter를 사용하고있다)

하지만 다른 방법으로는 작동하지 않습니다 : ConverterNotFoundException : 형식을 변환 할 수있는 변환기가 없습니다. @PathVariable Company에서 String을 입력하십시오.

Converter 만 필요합니까? 그리고 어디에서 등록해야합니까? WebMvcConfigurationSupport의 addFormatters (FormatterRegistry 레지스트리) 메서드 내에서 무언가를 시도했지만 동일한 오류가 표시되었습니다. 그러나 결국 나는 정확히 내가 무엇을 시도했는지 확신 할 수 없다.

해결법

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

    1.나는 같은 문제가 있었다. 그것은 버그 다. 모든 컨트롤러에서 복사하여 붙여 넣기를 원하지 않으면 WebMvcConfigurationSupport에서 이와 같은 것을 시도 할 수 있습니다. 그것은 나를 위해 작동합니다.

    나는 같은 문제가 있었다. 그것은 버그 다. 모든 컨트롤러에서 복사하여 붙여 넣기를 원하지 않으면 WebMvcConfigurationSupport에서 이와 같은 것을 시도 할 수 있습니다. 그것은 나를 위해 작동합니다.

    @Override
    public void addFormatters(final FormatterRegistry registry) {
        super.addFormatters(registry);
    
        try {
            Class<?> clazz = Class.forName("org.springframework.hateoas.mvc.AnnotatedParametersParameterAccessor$BoundMethodParameter");
            Field field = clazz.getDeclaredField("CONVERSION_SERVICE");
            field.setAccessible(true);
            DefaultFormattingConversionService service = (DefaultFormattingConversionService) field.get(null);
            for (Converter<?, ?> converter : beanFactory.getBeansOfType(Converter.class).values()) {
                service.addConverter(converter);
            }
        }
        catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }
    
  2. ==============================

    2."해결책"을 찾았습니다. 그것은 봄 학급으로부터 많은 복사 & 붙이기를 요구합니다, 그러나 적어도 작동합니다!

    "해결책"을 찾았습니다. 그것은 봄 학급으로부터 많은 복사 & 붙이기를 요구합니다, 그러나 적어도 작동합니다!

    기본적으로 org.springframework.hateoas.mvc.AnnotatedParametersParameterAccessor를 복사하고 두 줄을 변경해야했습니다.

    class AnnotatedParametersParameterAccessor {
        ...
        static class BoundMethodParameter {
            // OLD: (with this one you can't call addConverter())
            // private static final ConversionService CONVERSION_SERVICE = new DefaultFormattingConversionService();
            // NEW:
            private static final FormattingConversionService CONVERSION_SERVICE = new DefaultFormattingConversionService();
    
            ...
    
            public BoundMethodParameter(MethodParameter parameter, Object value, AnnotationAttribute attribute) {
                ...
                // ADD:
                CONVERSION_SERVICE.addConverter(new MyNewConverter());
        }
    
        ...
    }
    

    이 클래스는 ControllerLinkBuilderFactory에 의해 사용됩니다. 그래서 나는 그것도 복사 & 붙여 넣기했다.

    그리고이 하나는 ControllerLinkBuilder에서 사용합니다. 복사하여 붙여 넣기.

    내 변환기 그냥 myDomainObject.getId () 않습니다. toString () :

    public class MyNewConverter implements Converter<Company, String> {
        @Override
        public String convert(Company source) {
            return source.getId().toString();
        }   
    }
    

    이제 컨트롤러 안의 복사 & 붙여 넣기 ControllerLinkBuilder를 사용할 수 있으며 예상대로 작동합니다!

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

    3.Spring hateoas에서 링크를 렌더링하는 프레임 워크를 개발했으며 주석 매개 변수 (@PathVariable 및 @RequestParam) 및 임의의 매개 변수 유형을 지원합니다.

    Spring hateoas에서 링크를 렌더링하는 프레임 워크를 개발했으며 주석 매개 변수 (@PathVariable 및 @RequestParam) 및 임의의 매개 변수 유형을 지원합니다.

    이러한 임의의 타입을 렌더링하기 위해서는 com.github.osvaldopina.linkbuilder.argumentresolver.ArgumentResolver 인터페이스를 구현하는 스프링 빈을 생성해야한다.

    인터페이스에는 3 가지 방법이 있습니다.

    ArgumentResolver를 사용하여 methodParameter를 처리 할 수 ​​있는지 여부를 확인하는 데 사용됩니다. 예 :

    public boolean resolveFor(MethodParameter methodParameter) {
        return UserDefinedType.class.isAssignableFrom(methodParameter.getParameterType());
    }
    

    이 ArgumentResover가 UserDefinedType에 사용되도록 정의합니다.

    메소드와 연관된 uriTemplate에 적절한 템플릿 부분을 포함시키는 데 사용됩니다. 예 :

    @Override
    public void augmentTemplate(UriTemplateAugmenter uriTemplateAugmenter, MethodParameter methodParameter) {
        uriTemplateAugmenter.addToQuery("value1");
        uriTemplateAugmenter.addToQuery("value2");
    
    }
    

    uri 템플리트에 두 개의 조회 매개 변수 (value1 및 value2)를 추가합니다.

    템플릿에서 템플릿 변수의 값을 설정합니다. 예 :

    @Override
    public void setTemplateVariables(UriTemplate template, MethodParameter methodParameter, Object parameter, List<String> templatedParamNames) {
        if (parameter != null && ((UserDefinedType) parameter).getValue1() != null) {
            template.set("value1", ((UserDefinedType) parameter).getValue1());
        }
        else {
            template.set("value1", "null-value");
        }
    
        if (parameter != null && ((UserDefinedType) parameter).getValue2() != null) {
            template.set("value2", ((UserDefinedType) parameter).getValue2());
        }
        else {
            template.set("value2", "null-value");
        }
    }
    

    UserDefinedType 인스턴스를 가져오고이를 사용하여 augmentTemplate 메서드에 정의 된 템플릿 변수 value1 및 value2를 설정합니다.

    ArgumentResolver 전체 예제는 다음과 같습니다.

    @Component
    public class UserDefinedTypeArgumentResolver implements ArgumentResolver {
    
        @Override
        public boolean resolveFor(MethodParameter methodParameter) {
            return UserDefinedType.class.isAssignableFrom(methodParameter.getParameterType());
        }
    
        @Override
        public void augmentTemplate(UriTemplateAugmenter uriTemplateAugmenter, MethodParameter methodParameter) {
            uriTemplateAugmenter.addToQuery("value1");
            uriTemplateAugmenter.addToQuery("value2");
    
        }
    
        @Override
        public void setTemplateVariables(UriTemplate template, MethodParameter methodParameter, Object parameter, List<String> templatedParamNames) {
            if (parameter != null && ((UserDefinedType) parameter).getValue1() != null) {
                template.set("value1", ((UserDefinedType) parameter).getValue1());
            }
            else {
                template.set("value1", "null-value");
            }
    
            if (parameter != null && ((UserDefinedType) parameter).getValue2() != null) {
                template.set("value2", ((UserDefinedType) parameter).getValue2());
            }
            else {
                template.set("value2", "null-value");
            }
        }
    }
    

    다음 링크 빌더의 경우 :

       linksBuilder.link()
                .withRel("user-type")
                .fromControllerCall(RootRestController.class)
                .queryParameterForUserDefinedType(new UserDefinedType("v1", "v2"));
    

    다음 방법으로

    @RequestMapping("/user-defined-type")
    @EnableSelfFromCurrentCall
    public void queryParameterForUserDefinedType(UserDefinedType userDefinedType) {
    
    }
    

    다음 링크를 생성합니다.

    {
        ...
        "_links": {
            "user-type": {
            "href": "http://localhost:8080/user-defined-type?value1=v1&value2=v2"
        }
        ...
    }
    

    }

  4. ==============================

    4.봄 부팅에 전체 구성. 프랑코 고투소 (Franco Gotusso)의 답변과 마찬가지로 자세한 내용을 제공합니다. ```

    봄 부팅에 전체 구성. 프랑코 고투소 (Franco Gotusso)의 답변과 마찬가지로 자세한 내용을 제공합니다. ```

    / **  *이 설정 파일은 Spring Hateoas의 버그를 수정합니다.  * https://github.com/spring-projects/spring-hateoas/issues/118을 확인하십시오.  * /

    @구성 요소 공용 클래스 MvcConfig는 WebMvcConfigurerAdapter {

    @Autowired
    private ApplicationContext applicationContext;
    
    @Override
    public void addFormatters(final FormatterRegistry registry) {
        super.addFormatters(registry);
    
        try {
            Class<?> clazz = Class.forName("org.springframework.hateoas.mvc."
                    + "AnnotatedParametersParameterAccessor$BoundMethodParameter");
            Field field = clazz.getDeclaredField("CONVERSION_SERVICE");
            field.setAccessible(true);
            DefaultFormattingConversionService service =
                    (DefaultFormattingConversionService) field.get(null);
            for (Formatter<?> formatter : applicationContext
                    .getBeansOfType(Formatter.class).values()) {
                service.addFormatter(formatter);
            }
            for (Converter<?, ?> converter : applicationContext
                    .getBeansOfType(Converter.class).values()) {
                service.addConverter(converter);
            }
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }
    

    }

    ```

  5. from https://stackoverflow.com/questions/22240155/converter-from-pathvariable-domainobject-to-string-using-controllerlinkbuilde by cc-by-sa and MIT license