Spring Security 错误信息 国际化
功能开发中,我们会有这种需求,希望所有的数据返回统一的格式,包含状态码,数据,错误信息,当前时间,比如:
{"code":200,"data":null,"message":"OK","timestamp":1559292578716}
首先我们需要有这么一个类
@Data
public class Result<T> {
    private long timestamp;
    private String message;
    private int code=SUCCESS;
    private T data;
    @Data
    public static class Builder<T> {
        //部分代码略
    }
}
但是我们不能在每一个Controller上的返回格式都定义为Result
Spring Boot 如何在不改变原有的Controller的基础上实现呢?
我们可以借助Spring提供的ResponseBodyAdvice实现
public interface ResponseBodyAdvice<T> {
    boolean supports(MethodParameter var1, Class<? extends HttpMessageConverter<?>> var2);
    @Nullable
    T beforeBodyWrite(@Nullable T var1, MethodParameter var2, MediaType var3, Class<? extends HttpMessageConverter<?>> var4, ServerHttpRequest var5, ServerHttpResponse var6);
}
该接口只有两个方法supports和beforeBodyWrite
- supports 方法返回boolean,判断是否支持Controller的返回类型
- beforeBodyWrite 写出之前的处理,此文中主要依靠此方法,T var1就是Controller返回的对象
写一个我们自己的实现
@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();
    }
}
系统中原有的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(id,"Lucy",18);
        return user;
    }
    @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));
    }
}
分别进行测试
{
    "timestamp": 1559293805111, 
    "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
java.lang.ClassCastException: com.podigua.demo.core.Result cannot be cast to org.springframework.core.io.Resource
三个测试.发现有两个出错, 出错的原因是找不到对应的HttpMessageConverter,HttpMessageConverter 是一组消息转换器,以下列出部分MessageConverter
- StringHttpMessageConverter负责字符串类型的数据的读取或者写出
- ByteArrayHttpMessageConverter负责二进制格式数据的读取或者写出
- ResourceHttpMessageConverter负责资源文件的读取或者写出
- FormHttpMessageConverter负责读取form提交的数据- application/x-www-form-urlencoded
- MappingJacksonHttpMessageConverter负责json格式数据的读取或者写出
原因就是缺少 MappingJackson2HttpMessageConverter和ResourceHttpMessageConverter
我们调整下代码,增加这两个消息转换器
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer  {
	@Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(0, new MappingJackson2HttpMessageConverter());
        converters.add(1, new ResourceHttpMessageConverter());
    }
}
资源类数据,不能按照这种格式返回,最终返回的是文件流,我们调整下代码ResponseAdvisor的beforeBodyWrite方法,若返回值已经是Result类型也不需要处理
@Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
                                  Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request,
                                  ServerHttpResponse response) {
        if (body instanceof Resource) {
            return body;
        }
        if (body instanceof Result) {
            return body;
        }
        return new Result.Builder<>().data(body).build();
    }
若Coltroller抛出了异常呢? 需要AOP捕获异常,并将异常信息与状态码封装为Result的数据即可
项目github地址
点击查看更多内容
					为 TA 点赞
										
				 评论
				共同学习,写下你的评论
评论加载中...
作者其他优质文章
					正在加载中
				
			感谢您的支持,我会继续努力的~
		扫码打赏,你说多少就多少
		赞赏金额会直接到老师账户
		支付方式
		打开微信扫一扫,即可进行扫码打赏哦
	 
                 
             
			 
					