Spring Data Rest自定义方法返回String

时间:2015-11-13 07:30:46

标签: spring spring-data spring-data-rest

我需要一个Spring Data Rest上的自定义方法,它有一些输入并返回一个String。

@BasePathAwareController
@RequestMapping(value = "/businessActions")
public class BusinessActionController implements ResourceProcessor<RepositoryLinksResource> {


    /**
     * This BusinessAction's purpose is: Generiert für ein Modell das entsprechende Barrakuda-File.
     * It returns one String.
     */
    @RequestMapping(value = "/modellGenerieren", method = RequestMethod.GET)
    public String modellGenerieren(@Param(value="project") String project) throws IOException {
        // Get project by id from repository and map to string.
        return "asdf\n";
    }
}

通过使用@BasePathAwareController端点将返回"asdf\n",我想要的输出将是:

asdf
<new line>

我能够仅使用@Controller来生成此输出,但这会破坏基本路径的意识,我需要在此Controller的其他方法中使用PersistentEntityResourceAssembler - 然后无法注入汇编程序。

2 个答案:

答案 0 :(得分:3)

底线

可以通过以下映射和配置来解决:

// The OP's original controller with a small tweak
@BasePathAwareController
@RequestMapping("/businessActions")
public class MyCustomRestEndpoint {

    // Let's specify the #produces type as text/plain (rather than the Spring Data REST JSON default)
    @GetMapping(value = "/modellGenerieren", produces = MediaType.TEXT_PLAIN_VALUE)
    public @ResponseBody ResponseEntity<String> modellGenerieren(@Param(value="project") String project) throws IOException {
        // Get project by id from repository and map to string.
        return ResponseEntity.ok("A String!");
    }

}

@Configuration
public class PlainTextConfiguration implements RepositoryRestConfigurer {

    // Allow for plain String responses from Spring via the `text/plain` content type
    @Override
    public void configureHttpMessageConverters(List<HttpMessageConverter<?>> messageConverters)
    {
        StringHttpMessageConverter converter = new StringHttpMessageConverter();
        converter.setSupportedMediaTypes(configureMediaTypes());

        messageConverters.add(converter);

    }

    private List<MediaType> configureMediaTypes() {
        List<MediaType> mediaTypes = new ArrayList<>();
        mediaTypes.add(MediaType.TEXT_PLAIN);
        mediaTypes.add(MediaType.parseMediaType("text/plain;charset=iso-8859-1"));
        mediaTypes.add(MediaType.parseMediaType("text/plain;charset=UTF-8"));
        mediaTypes.add(MediaType.parseMediaType("text/plain;charset=UTF-16"));
        return mediaTypes;
    }

}

并在发出请求时指定ACCEPT标头(这是关键!):

GET http://localhost:8080/api/businessActions/modellGenerieren
Content-Type: text/plain
Accept: text/plain

这将产生以下响应:

GET http://localhost:8080/api/businessActions/modellGenerieren

HTTP/1.1 200 OK
Date: Mon, 24 Dec 2018 06:21:10 GMT
Content-Type: text/plain;charset=iso-8859-1
Accept-Charset: ... <large charset>
Content-Length: 9

A String!

Response code: 200 (OK); Time: 151ms; Content length: 9 bytes

原因

经调查,看来您似乎永远无法返回未加引号的String的原因是由于BasePathAwareHandlerMapping#lookupHandlerMethod函数的行为。

lookupHandlerMethod基本上假设在对方法进行请求时,允许的媒体类型是通过ACCEPT标头中的HTTP请求进行的。否则,它默认为默认媒体类型(可使用RepositoryRestConfigurer#configureRepositoryRestConfiguration配置)。

Spring Data REST 的默认介质类型的默认值为application/jsonapplication/hal+json(取决于该默认值see here)。这就是为什么在结果字符串中仅看到application/json内容类型带有双引号""的原因。 String使用Jackson转换器(用引号将Strings括起来)而不是String转换器进行转换。

研究之后,我同意你的看法,这似乎是一个奇怪的假设。也就是说,框架不应该假设所有请求都始终以所需的媒体类型显式指定ACCEPT头(至少,我个人并不总是希望看到它),否则应该假设所有请求都应只能是默认媒体类型,仅是因为像您这样的用例。

在没有深入研究文档的情况下,@BasePathAwareController似乎暗示着在利用Spring Data REST时可以使用的不仅仅是标准Spring Data Rest实体。

即使未指定ACCEPT标头,我也会亲自将Produces类型返回给客户端-如果我要编写一些代码来修改BasePathAwareHandlerMapping,我会添加关于我的评论行的以下内容:

@Override
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {

    ...

    if (!defaultFound) {
        mediaTypes.add(configuration.getDefaultMediaType());
    }

    // Lookup the Handler Method for this request
    // If no media types are specific in the ACCEPT header of this request...
    // Then look and see if the method has a #produces specified and define that as the ACCEPT type

    super.lookupHandlerMethod(lookupPath, new CustomAcceptHeaderHttpServletRequest(request, mediaTypes));
}

答案 1 :(得分:0)

我有同样的问题。而且我还没有完全解决它。但我希望这些额外的信息至少对您有所帮助:

在Spring和spring-data-rest中有4条注释,它们都是恕我直言的,杂乱无章。 (例如,请参见此Bug

Spring Data Rest controllers: behaviour and usage of @BasePathAwareController, @RepositoryRestController, @Controller and @RestController

如果使用@BasePathAwareController,则可以从Spring-data-rest获得所有魔力(请参阅SDR Doc)=>但是,您将无法返回简单的String。 (至少到目前为止我还没有找到方法。)

如果您使用@RestController,则端点与SDR完全无关。

如果您想向@RestController公开与其他SDR API相同的路径前缀,则可以使用以下方法:

@RestController
@RequestMapping("${spring.data.rest.base-path}")
public class MyCustomRestEndpoint { ... }

这将从 application.properties

中读取路径前缀
spring.data.rest.base-path=/api/v17

然后您可以返回一个纯字符串。

但是,如果您使用OP所说的@BasePathAwareController,因为您需要PersistentEntityResourceAssembler,则无法返回纯字符串。