SpringBoot如何设置404、500返回统一格式json
作者:qykhhr
这篇文章主要介绍了SpringBoot如何设置404、500返回统一格式json问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
SpringBoot默认访问不存在资源就会出现404
解决后:
主要是添加下面配置:
# 自定义 #出现错误时, 直接抛出异常 spring.mvc.throw-exception-if-no-handler-found=true #不要为我们工程中的资源文件建立映射 spring.web.resources.add-mappings=false
全局处理异常:
package com.qykhhr.dujiaoshouservice.exceptionhandler; import com.qykhhr.dujiaoshouservice.util.R; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import java.sql.SQLIntegrityConstraintViolationException; /** * 异常处理机制 * 先找到特定异常处理机制,如果没有就会调用Exception异常处理机制 */ @ControllerAdvice @Slf4j public class GlobalExceptionHandler { /** * 指定出现什么异常来执行这个方法 * @param e * @return */ @ExceptionHandler(Exception.class) @ResponseBody public R error(Exception e){ e.printStackTrace(); if (e instanceof SQLIntegrityConstraintViolationException){ return R.error().message("数据库主键冲突,如是本人,请联系管理员"); }else if (e instanceof org.springframework.web.servlet.NoHandlerFoundException){ return R.error().message("找不到资源,/(ㄒoㄒ)/~~"); } return R.error().message("内部服务器错误,/(ㄒoㄒ)/~~!"); } /** * 自定义异常处理 * @param e * @return */ @ExceptionHandler(DujiaoshouException.class) @ResponseBody public R error(DujiaoshouException e){ log.error(e.getMessage()); e.printStackTrace(); return R.error().code(e.getCode()).message(e.getMsg()); } }
统一结果返回:
package com.qykhhr.dujiaoshouservice.util; import lombok.Data; import java.util.HashMap; import java.util.Map; /** * 统一返回结果的类 * @author 雨林 */ @Data public class R { private Boolean success; private Integer code; private String message; private Map<String,Object> data = new HashMap<>(); // 把构造方法私有化,只能使用提供的静态方法 private R(){ } // 成功静态方法 public static R ok(){ R r = new R(); r.setSuccess(true); r.setCode(ResultCode.SUCCESS); r.setMessage("成功"); return r; } // 失败静态方法 public static R error(){ R r = new R(); r.setSuccess(false); r.setCode(ResultCode.ERROR); r.setMessage("失败"); return r; } public R message(String message){ this.setMessage(message); return this; } public R code(Integer code){ this.setCode(code); return this; } public R data(Map<String, Object> map){ this.setData(map); return this; } public R data(String key, Object value){ this.data.put(key, value); return this; } }
我有发现了一个问题,因为我配置了映射,当我访问upload请求找不到文件时,依旧返回了SpingBoot的默认404页面。
我的理解就是访问/upload请求时,SpringBoot会自动到映射的文件夹里面去寻找文件,就会以为这个请求已经被处理了,就不会报找不到处理的异常。而是报除了/error请求的错误。
upload.image.path=/util/images/ upload.apk.path=/util/apk/ upload.crash.exception.file.path=/util/crash/
/** * 资源映射路径,只能配置一个映射 */ @Configuration public class MyWebMvcConfigurer extends WebMvcConfigurerAdapter { @Value("${upload.file.path}") private String uploadPath; @Value("${upload.image.path}") private String uploadImagePath; @Value("${upload.crash.exception.file.path}") private String uploadCrashExceptionFilePath; @Value("${upload.apk.path}") private String uploadApkPath; /** * 将D:\\upload下的文件映射到当前项目/upload/下 * @param registry */ @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/favicon.ico").addResourceLocations("classpath:/static/"); //addResourceHandler()里配置需要映射的文件夹,此处代表映射文件夹user下的所有资源。 //addResourceLocations()配置文件夹在系统中的路径,使用绝对路径,格式为“file:你的路径/” 后面的 / 必须加上,否则映射失效 // registry.addResourceHandler("/upload/**").addResourceLocations("file:D:/dujiaoshouapp/"); // registry.addResourceHandler("/upload/**").addResourceLocations("file:"+uploadPath); registry.addResourceHandler("/upload/images/**").addResourceLocations("file:"+uploadImagePath); registry.addResourceHandler("/upload/crash/**").addResourceLocations("file:"+uploadCrashExceptionFilePath); registry.addResourceHandler("/upload/apk/**").addResourceLocations("file:"+uploadApkPath); } }
解决
可以看到SpringBoot最终保留了/error请求作为后备,未解决的请求都会走到/error路径里面,我们可以定义一个拦截器,拦截这个/error请求,转到我们自己定义的请求里面。
@Component public class ExceptionInterceptor implements HandlerInterceptor { @Autowired private RedisTemplate redisTemplate; @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { if (modelAndView != null){ // 防止出现空指针 // 请求转到 / modelAndView.setViewName("/"); } } }
然后在WebConfig里面配置上拦截器
@Configuration public class MyWebMvcConfigurer extends WebMvcConfigurerAdapter { @Autowired private ExceptionInterceptor exceptionInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(exceptionInterceptor); super.addInterceptors(registry); }
最后再定义一个Controller,处理 / 请求
package com.qykhhr.dujiaoshouservice.controller; import com.qykhhr.dujiaoshouservice.util.R; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @Slf4j public class ExceptionController { @RequestMapping("/") public R error() { log.info("处理 /error 请求"); return R.error().message("访问资源无效!"); } }
可以看到访问的结果:
OK,我们现在完全是统一的返回格式了~!
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。