我需要一个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
- 然后无法注入汇编程序。
答案 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/json
或application/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)
如果使用@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
,则无法返回纯字符串。