进行功能开发时,想将Controller的返回值封装成以下格式
{timestamp:1543823794412,code:200,message:"OK",data:result}
其中result为各种类型的值(json,string,object,array)等
待返回数据类型,部分代码如下
public class Result<T> {
public static final int SUCCESS = 200;
public static final int ERROR = 500;
//响应时间
private long timestamp;
//提示信息
private String message;
//状态码
private int code=SUCCESS;
//返回数据
private T data;
}
Controller 代码如下
@RestController
public class DemoController {
@GetMapping("/echo/{name}")
public String echo(@PathVariable("name") String name){
return "hello:"+name;
}
@GetMapping("/user/{id}")
public User getUserById(@PathVariable("id") Long id){
User user=new User();
user.setId(id);
user.setName("Lucy");
user.setAge(18);
return user;
}
}
postman 测试结果如下;这里直接贴结果
| url | result |
|---|---|
| http://localhost:8080/user/1 | {"id": 1, "name": "Lucy","age": 18} |
| http://localhost:8080/echo/kitty | hello:kitty |
若想实现自定义返回数据类型需要借助ResponseBodyAdvice接口
代码如下
@ControllerAdvice
public class ResponseAdvisor implements ResponseBodyAdvice<Object>{
@Override
//判断是否需要拦截
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
return true;
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request,
ServerHttpResponse response) {
return new Result.Builder<>().data(body).build();
}
}
使用postman再次测试,结果如下
{
"timestamp": 1543825204365,
"message": "OK",
"code": 200,
"data": {
"id": 1,
"name": "Lucy",
"age": 18
}
}
java.lang.ClassCastException: com.podigua.demo.core.Result cannot be cast to java.lang.String
此异常与MessageConverter有关。controller层中返回的类型是String,但是在ResponseBodyAdvice实现类中,我们把响应的类型修改成了Result。这就导致了,上面的这段代码在选择处理MessageConverter的时候,依旧根据之前的String类型选择对应String类型的StringMessageConverter。而在StringMessageConverter类型,他只接受String类型的返回类型,我们在ResponseBodyAdvice中将返回值从String类型改成Result类型之后,调用StringMessageConverter方法发生类型强转。Result无法转换成String,所以会发生类型转换异常。
既然是MessageConverter有问题,新增一个可以处理的MessageConverter即可,代码如下
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(0, new MappingJackson2HttpMessageConverter());
}
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/*");
}
}
{
"timestamp": 1543826321331,
"message": "OK",
"code": 200,
"data": "hello:kitty"
}
备注:上一篇文章中将AOP时,捕获了Controller,并封装为Result格式,
若抛出异常时,则会有两个Result对象类似于
{
"timestamp": 1543826321331,
"message": "错误信息",
"code": 500,
"data": {
"timestamp": 1543826321331,
"message": "错误信息",
"code": 500,
"data": null
}
}
这显然不是我们要的结果;所以ResponseAdvisor 需要调整代码
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request,
ServerHttpResponse response) {
if(body instanceof Result) {
return body;
}
return new Result.Builder<>().data(body).build();
}
字符串的问题搞定了,那么Controller提供下载功能的时候呢?
下载功能
@GetMapping("/download")
public ResponseEntity<FileSystemResource> download() {
File file = new File("d:/1.jpg");
HttpHeaders headers = new HttpHeaders();
headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
try {
headers.add("Content-Disposition", "attachment; filename=" + new String(file.getName().getBytes("GB2312"),"ISO-8859-1"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
headers.add("Pragma", "no-cache");
headers.add("Expires", "0");
return ResponseEntity
.ok()
.headers(headers)
.contentLength(file.length())
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(new FileSystemResource(file));
}
其实也是一样的处理方式,再加一个转换器,再调整一下ResponseAdvisor的代码








网友评论