场景描述
今天需要写查询服务器上某一个文件是否存在,整个Controller注解为@RestController
代码大致如下
@ApiOperation(value = "查询文件是否存在")
@RequestMapping(value = "/query/{filename:.+}", method = RequestMethod.GET)
public JSONData query(@PathVariable String filename){
String filePath= appProperties.getFilePath() + filename;
boolean exist = false;
File file = new File(filePath);
if(file.exists()){
exist = true;
}
Map data = Maps.newHashMap();
data.put("exist",exist);
return JSONData.builder().msg(EnumResponseMsg.RESP_SUCCESS_0000.getMsg()).
code(EnumResponseMsg.RESP_SUCCESS_0000.getCode()).data(data).success(true).build();
}
PathVariable 填abcd.txt, URI为 /query/abcd.txt
利用swagger-ui 跑接口返回代码 406。
报错分析
注解@RestController意味着要把对象转换成json格式返回给请求端,有可能是缺少jackson相关的jar(例如jackson-core-asl-x.x.x.jar,jackson-mapper-asl-x.x.x.jar),springboot 的pom.xml应该是引用过这些jar的。况且其他的get也有返回内容,并没有出现406,问题应该不在这。
后面查到资料springmvc 以.html结尾的请求是不会返回JSON数据,很有可能以 .txt 结尾也是这个原因。
后查询资料证实:Spring Boot的MVC默认配置中使用的 ViewResolver 为 ContentNegotiatingViewResolver,该视图解析器的功能是根据要请求的文档类型,来查找不同的视图以返回对应格式的文档。请求的文档类型要可以从请求头中的Accept中获取,也可以通过URI后缀名得到,如/login.html即为请求HTML格式的文档,这两种方式分别对应着两种不同的Strategy(策略),默认为根据URI后缀名。
解决方法
初步定位是上述原因,那么怎么解决呢?
方法一、避免以.txt结尾的URL去访问,改变我们的@RequestMapping的value。我这边的情况不太适用。
方法二、继承WebMvcConfigurerAdapter 重写configureContentNegotiation方法禁用后缀方式进行内容协商
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(false);
}
}
这种方式更适合我这边的场景,前后端分离,不需要后缀方式,干脆禁用掉。