栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java > SpringBoot

Spring Security 错误信息 国际化

SpringBoot 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring Security 错误信息 国际化

功能开发中,我们会有这种需求,希望所有的数据返回统一的格式,包含状态码,数据,错误信息,当前时间,比如:

{"code":200,"data":null,"message":"OK","timestamp":1559292578716}

首先我们需要有这么一个类

@Data
public class Result {
    private long timestamp;
    private String message;
    private int code=SUCCESS;
    private T data;
    @Data
    public static class Builder {
 //部分代码略
    }
}

但是我们不能在每一个Controller上的返回格式都定义为Result

Spring Boot 如何在不改变原有的Controller的基础上实现呢?
我们可以借助Spring提供的ResponseBodyAdvice实现

public interface ResponseBodyAdvice {
    boolean supports(MethodParameter var1, Class> var2);

    @Nullable
    T beforeBodyWrite(@Nullable T var1, MethodParameter var2, MediaType var3, Class> var4, ServerHttpRequest var5, ServerHttpResponse var6);
}

该接口只有两个方法supports和beforeBodyWrite

  • supports 方法返回boolean,判断是否支持Controller的返回类型
  • beforeBodyWrite 写出之前的处理,此文中主要依靠此方法,T var1就是Controller返回的对象

写一个我们自己的实现

@ControllerAdvice()
public class ResponseAdvisor implements ResponseBodyAdvice {
    @Override
    public boolean supports(MethodParameter returnType, Class> converterType) {
 return true;
    }
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
      Class> 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 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));
    }
}

分别进行测试

  • http://localhost:8080/user/1
{
    "timestamp": 1559293805111, 
    "message": "OK", 
    "code": 200, 
    "data": {
 "id": 1, 
 "name": "Lucy", 
 "age": 18
    }
}
  • http://localhost:8080/echo/lucy
java.lang.ClassCastException: com.podigua.demo.core.Result cannot be cast to java.lang.String
  • http://localhost:8080/download
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> 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> 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地址

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号