当前位置: 首页 > news >正文

网站建设 h5 小程序矿坛器材友情交换

网站建设 h5 小程序,矿坛器材友情交换,华为云做网站不能修改页面,外贸英文商城网站建设SpringBoot接口如何对异常进行统一封装,并统一返回呢?以上文的参数校验为例,如何优雅的将参数校验的错误信息统一处理并封装返回呢?为什么要优雅的处理异常如果我们不统一的处理异常,经常会在controller层有大量的异常…
SpringBoot接口如何对异常进行统一封装,并统一返回呢?以上文的参数校验为例,如何优雅的将参数校验的错误信息统一处理并封装返回呢?

为什么要优雅的处理异常

如果我们不统一的处理异常,经常会在controller层有大量的异常处理的代码, 比如:

@Slf4j
@Api(value = "User Interfaces", tags = "User Interfaces")
@RestController
@RequestMapping("/user")
public class UserController {/*** http://localhost:8080/user/add .** @param userParam user param* @return user*/@ApiOperation("Add User")@ApiImplicitParam(name = "userParam", type = "body", dataTypeClass = UserParam.class, required = true)@PostMapping("add")public ResponseEntity<String> add(@Valid @RequestBody UserParam userParam) {// 每个接口充斥着大量的异常处理try {// do something} catch(Exception e) {return ResponseEntity.fail("error");}return ResponseEntity.ok("success");}
}

那怎么实现统一的异常处理,特别是结合参数校验等封装?

实现案例

简单展示通过@ControllerAdvice进行统一异常处理。

@ControllerAdvice异常统一处理

对于400参数错误异常

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {/*** exception handler for bad request.** @param e*            exception* @return ResponseResult*/@ResponseBody@ResponseStatus(code = HttpStatus.BAD_REQUEST)@ExceptionHandler(value = { BindException.class, ValidationException.class, MethodArgumentNotValidException.class })public ResponseResult<ExceptionData> handleParameterVerificationException(@NonNull Exception e) {ExceptionData.ExceptionDataBuilder exceptionDataBuilder = ExceptionData.builder();log.warn("Exception: {}", e.getMessage());if (e instanceof BindException) {BindingResult bindingResult = ((MethodArgumentNotValidException) e).getBindingResult();bindingResult.getAllErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).forEach(exceptionDataBuilder::error);} else if (e instanceof ConstraintViolationException) {if (e.getMessage() != null) {exceptionDataBuilder.error(e.getMessage());}} else {exceptionDataBuilder.error("invalid parameter");}return ResponseResultEntity.fail(exceptionDataBuilder.build(), "invalid parameter");}}

对于自定义异常

/*** handle business exception.** @param businessException*            business exception* @return ResponseResult*/
@ResponseBody
@ExceptionHandler(BusinessException.class)
public ResponseResult<BusinessException> processBusinessException(BusinessException businessException) {log.error(businessException.getLocalizedMessage(), businessException);// 这里可以屏蔽掉后台的异常栈信息,直接返回"business error"return ResponseResultEntity.fail(businessException, businessException.getLocalizedMessage());
}

对于其它异常

/*** handle other exception.** @param exception*            exception* @return ResponseResult*/
@ResponseBody
@ExceptionHandler(Exception.class)
public ResponseResult<Exception> processException(Exception exception) {log.error(exception.getLocalizedMessage(), exception);// 这里可以屏蔽掉后台的异常栈信息,直接返回"server error"return ResponseResultEntity.fail(exception, exception.getLocalizedMessage());
}

Controller接口

(接口中无需处理异常)

@Slf4j
@Api(value = "User Interfaces", tags = "User Interfaces")
@RestController
@RequestMapping("/user")
public class UserController {/*** http://localhost:8080/user/add .** @param userParam user param* @return user*/@ApiOperation("Add User")@ApiImplicitParam(name = "userParam", type = "body", dataTypeClass = UserParam.class, required = true)@PostMapping("add")public ResponseEntity<UserParam> add(@Valid @RequestBody UserParam userParam) {return ResponseEntity.ok(userParam);}
}

运行测试

这里用postman测试下

进一步理解

我们再通过一些问题来帮助你更深入理解@ControllerAdvice。

@ControllerAdvice还可以怎么用?

除了通过@ExceptionHandler注解用于全局异常的处理之外,@ControllerAdvice还有两个用法:

  • @InitBinder注解

用于请求中注册自定义参数的解析,从而达到自定义请求参数格式的目的;

比如,在@ControllerAdvice注解的类中添加如下方法,来统一处理日期格式的格式化

@InitBinder
public void handleInitBinder(WebDataBinder dataBinder){dataBinder.registerCustomEditor(Date.class,new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), false));
}

Controller中传入参数(string类型)自动转化为Date类型

@GetMapping("testDate")
public Date processApi(Date date) {return date;
}
  • @ModelAttribute注解

用来预设全局参数,比如最典型的使用Spring Security时将添加当前登录的用户信息(UserDetails)作为参数。

@ModelAttribute("currentUser")
public UserDetails modelAttribute() {return (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
}

所有controller类中requestMapping方法都可以直接获取并使用currentUser

@PostMapping("saveSomething")
public ResponseEntity<String> saveSomeObj(@ModelAttribute("currentUser") UserDetails operator) {// 保存操作,并设置当前操作人员的ID(从UserDetails中获得)return ResponseEntity.success("ok");
}

@ControllerAdvice是如何起作用的(原理)?

DispatcherServlet中onRefresh方法是初始化ApplicationContext后的回调方法,它会调用initStrategies方法,主要更新一些servlet需要使用的对象,包括国际化处理,requestMapping,视图解析等等。

/*** This implementation calls {@link #initStrategies}.*/
@Override
protected void onRefresh(ApplicationContext context) {initStrategies(context);
}/*** Initialize the strategy objects that this servlet uses.* <p>May be overridden in subclasses in order to initialize further strategy objects.*/
protected void initStrategies(ApplicationContext context) {initMultipartResolver(context); // 文件上传initLocaleResolver(context); // i18n国际化initThemeResolver(context); // 主题initHandlerMappings(context); // requestMappinginitHandlerAdapters(context); // adaptersinitHandlerExceptionResolvers(context); // 异常处理initRequestToViewNameTranslator(context);initViewResolvers(context);initFlashMapManager(context);
}

从上述代码看,如果要提供@ControllerAdvice提供的三种注解功能,从设计和实现的角度肯定是实现的代码需要放在initStrategies方法中。

  • @ModelAttribute和@InitBinder处理

具体来看,如果你是设计者,很显然容易想到:对于@ModelAttribute提供的参数预置和@InitBinder注解提供的预处理方法应该是放在一个方法中的,因为它们都是在进入requestMapping方法前做的操作。

如下方法是获取所有的HandlerAdapter,无非就是从BeanFactory中获取

private void initHandlerAdapters(ApplicationContext context) {this.handlerAdapters = null;if (this.detectAllHandlerAdapters) {// Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.Map<String, HandlerAdapter> matchingBeans =BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);if (!matchingBeans.isEmpty()) {this.handlerAdapters = new ArrayList<>(matchingBeans.values());// We keep HandlerAdapters in sorted order.AnnotationAwareOrderComparator.sort(this.handlerAdapters);}}else {try {HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);this.handlerAdapters = Collections.singletonList(ha);}catch (NoSuchBeanDefinitionException ex) {// Ignore, we'll add a default HandlerAdapter later.}}// Ensure we have at least some HandlerAdapters, by registering// default HandlerAdapters if no other adapters are found.if (this.handlerAdapters == null) {this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);if (logger.isTraceEnabled()) {logger.trace("No HandlerAdapters declared for servlet '" + getServletName() +"': using default strategies from DispatcherServlet.properties");}}
}

我们要处理的是requestMapping的handlerResolver,作为设计者,就很容易出如下的结构

在RequestMappingHandlerAdapter中的afterPropertiesSet去处理advice

@Override
public void afterPropertiesSet() {// Do this first, it may add ResponseBody advice beansinitControllerAdviceCache();if (this.argumentResolvers == null) {List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);}if (this.initBinderArgumentResolvers == null) {List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);}if (this.returnValueHandlers == null) {List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);}
}private void initControllerAdviceCache() {if (getApplicationContext() == null) {return;}List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());List<Object> requestResponseBodyAdviceBeans = new ArrayList<>();for (ControllerAdviceBean adviceBean : adviceBeans) {Class<?> beanType = adviceBean.getBeanType();if (beanType == null) {throw new IllegalStateException("Unresolvable type for ControllerAdviceBean: " + adviceBean);}// 缓存所有modelAttribute注解方法Set<Method> attrMethods = MethodIntrospector.selectMethods(beanType, MODEL_ATTRIBUTE_METHODS);if (!attrMethods.isEmpty()) {this.modelAttributeAdviceCache.put(adviceBean, attrMethods);}// 缓存所有initBinder注解方法Set<Method> binderMethods = MethodIntrospector.selectMethods(beanType, INIT_BINDER_METHODS);if (!binderMethods.isEmpty()) {this.initBinderAdviceCache.put(adviceBean, binderMethods);}if (RequestBodyAdvice.class.isAssignableFrom(beanType) || ResponseBodyAdvice.class.isAssignableFrom(beanType)) {requestResponseBodyAdviceBeans.add(adviceBean);}}if (!requestResponseBodyAdviceBeans.isEmpty()) {this.requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans);}
}
  • @ExceptionHandler处理

@ExceptionHandler显然是在上述initHandlerExceptionResolvers(context)方法中。

同样的,从BeanFactory中获取HandlerExceptionResolver

/*** Initialize the HandlerExceptionResolver used by this class.* <p>If no bean is defined with the given name in the BeanFactory for this namespace,* we default to no exception resolver.*/
private void initHandlerExceptionResolvers(ApplicationContext context) {this.handlerExceptionResolvers = null;if (this.detectAllHandlerExceptionResolvers) {// Find all HandlerExceptionResolvers in the ApplicationContext, including ancestor contexts.Map<String, HandlerExceptionResolver> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerExceptionResolver.class, true, false);if (!matchingBeans.isEmpty()) {this.handlerExceptionResolvers = new ArrayList<>(matchingBeans.values());// We keep HandlerExceptionResolvers in sorted order.AnnotationAwareOrderComparator.sort(this.handlerExceptionResolvers);}}else {try {HandlerExceptionResolver her =context.getBean(HANDLER_EXCEPTION_RESOLVER_BEAN_NAME, HandlerExceptionResolver.class);this.handlerExceptionResolvers = Collections.singletonList(her);}catch (NoSuchBeanDefinitionException ex) {// Ignore, no HandlerExceptionResolver is fine too.}}// Ensure we have at least some HandlerExceptionResolvers, by registering// default HandlerExceptionResolvers if no other resolvers are found.if (this.handlerExceptionResolvers == null) {this.handlerExceptionResolvers = getDefaultStrategies(context, HandlerExceptionResolver.class);if (logger.isTraceEnabled()) {logger.trace("No HandlerExceptionResolvers declared in servlet '" + getServletName() +"': using default strategies from DispatcherServlet.properties");}}
}

我们很容易找到ExceptionHandlerExceptionResolver

同样的在afterPropertiesSet去处理advice

@Override
public void afterPropertiesSet() {// Do this first, it may add ResponseBodyAdvice beansinitExceptionHandlerAdviceCache();if (this.argumentResolvers == null) {List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);}if (this.returnValueHandlers == null) {List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);}
}private void initExceptionHandlerAdviceCache() {if (getApplicationContext() == null) {return;}List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());for (ControllerAdviceBean adviceBean : adviceBeans) {Class<?> beanType = adviceBean.getBeanType();if (beanType == null) {throw new IllegalStateException("Unresolvable type for ControllerAdviceBean: " + adviceBean);}ExceptionHandlerMethodResolver resolver = new ExceptionHandlerMethodResolver(beanType);if (resolver.hasExceptionMappings()) {this.exceptionHandlerAdviceCache.put(adviceBean, resolver);}if (ResponseBodyAdvice.class.isAssignableFrom(beanType)) {this.responseBodyAdvice.add(adviceBean);}}
}

示例源码

https://download.csdn.net/download/DeveloperFire/87554658

推荐阅读

Java面试系列-MySQL

JAVA面试汇总(精选系列)


文章转载自:
http://wanjiapresidency.rkLs.cn
http://wanjiaayd.rkLs.cn
http://wanjiamalayanize.rkLs.cn
http://wanjiaulnocarpal.rkLs.cn
http://wanjiaperipheral.rkLs.cn
http://wanjiarankness.rkLs.cn
http://wanjiagso.rkLs.cn
http://wanjialogogriph.rkLs.cn
http://wanjiabrownnose.rkLs.cn
http://wanjiadaemon.rkLs.cn
http://wanjianeumatic.rkLs.cn
http://wanjiaqueue.rkLs.cn
http://wanjiadies.rkLs.cn
http://wanjiaignorant.rkLs.cn
http://wanjiadepreciation.rkLs.cn
http://wanjiadiscographer.rkLs.cn
http://wanjiahinge.rkLs.cn
http://wanjiaborosilicate.rkLs.cn
http://wanjiamonseigneur.rkLs.cn
http://wanjiaredingote.rkLs.cn
http://wanjiatrichomonad.rkLs.cn
http://wanjiapeopleless.rkLs.cn
http://wanjiatranquillityite.rkLs.cn
http://wanjiadisrelation.rkLs.cn
http://wanjiaarian.rkLs.cn
http://wanjiaarson.rkLs.cn
http://wanjiaambipolar.rkLs.cn
http://wanjiaoccasionalist.rkLs.cn
http://wanjiareassurance.rkLs.cn
http://wanjiadigamist.rkLs.cn
http://wanjiaplanograph.rkLs.cn
http://wanjiadisputable.rkLs.cn
http://wanjiaaposiopesis.rkLs.cn
http://wanjiacoot.rkLs.cn
http://wanjiaanacoluthon.rkLs.cn
http://wanjiahyde.rkLs.cn
http://wanjianarrowness.rkLs.cn
http://wanjiasixth.rkLs.cn
http://wanjiabathometer.rkLs.cn
http://wanjiatelluretted.rkLs.cn
http://wanjiacryptanalysis.rkLs.cn
http://wanjiaoophore.rkLs.cn
http://wanjiaentrap.rkLs.cn
http://wanjiagoldenrain.rkLs.cn
http://wanjiasubvene.rkLs.cn
http://wanjianephoscope.rkLs.cn
http://wanjiaassyriologist.rkLs.cn
http://wanjiaeverywhither.rkLs.cn
http://wanjiaparalanguage.rkLs.cn
http://wanjiafilibuster.rkLs.cn
http://wanjiaszabadka.rkLs.cn
http://wanjiacristate.rkLs.cn
http://wanjiacontemporize.rkLs.cn
http://wanjiaredry.rkLs.cn
http://wanjiasncf.rkLs.cn
http://wanjiatefillin.rkLs.cn
http://wanjiaherpes.rkLs.cn
http://wanjiasurvive.rkLs.cn
http://wanjiaozokerite.rkLs.cn
http://wanjiaafire.rkLs.cn
http://wanjiauremic.rkLs.cn
http://wanjiaastarte.rkLs.cn
http://wanjianudism.rkLs.cn
http://wanjiarevival.rkLs.cn
http://wanjiaundose.rkLs.cn
http://wanjiaasmara.rkLs.cn
http://wanjiaaeroscope.rkLs.cn
http://wanjiaexsert.rkLs.cn
http://wanjiawrought.rkLs.cn
http://wanjiaimperishably.rkLs.cn
http://wanjiacorporately.rkLs.cn
http://wanjiavela.rkLs.cn
http://wanjiadukedom.rkLs.cn
http://wanjiatendentious.rkLs.cn
http://wanjiaseymouriamorph.rkLs.cn
http://wanjiaalgorithmic.rkLs.cn
http://wanjiafilial.rkLs.cn
http://wanjiaovl.rkLs.cn
http://wanjiaelberta.rkLs.cn
http://wanjiadirt.rkLs.cn
http://www.15wanjia.com/news/117878.html

相关文章:

  • 武汉招聘网站制作武汉建站公司
  • 中企动力做的网站山西太原汽车宣传软文
  • wordpress 优惠主机驻马店网站seo
  • 网站没备案如何做淘宝客武汉seo网络优化公司
  • 泰州做网站如何在百度上添加店铺的位置
  • 域名与空间购买后怎么做网站郑州靠谱seo整站优化
  • wordpress 段落背景杭州seo网络公司
  • 日本做任务赚钱的网站友情链接有哪些
  • 网站建设主题seo推广怎么做
  • 网站建设 福州最好的营销策划公司
  • 高端网站建设的公司哪家好信息流优化师招聘
  • 鹰潭做网站的免费网站模板库
  • 久久文化传媒有限公司招聘信息谷歌seo服务商
  • 网站怎样做能排名靠前google广告投放技巧
  • 百度推广整体优化网站网络推广运营优化
  • 2015做哪些网站致富b站视频推广网站动漫
  • 做网站找俊义 合优百度指数的数据怎么导出
  • 团购网站前景广州外贸推广
  • 网站建设演示ppt模板桂平网络推广
  • 亚马逊网站做外贸优化网站价格
  • 优美网站源码五合一网站建设
  • 建设网站免费使用交换链接营销成功案例
  • 专业做网站哪家强长沙网络推广哪家
  • python 视频播放网站开发陕西今日头条新闻
  • 中国中建设计网站seo综合查询是什么意思
  • 网站有权重可以对title做更改郑州关键词优化费用
  • 怎么把网站做的更好求购买链接
  • 新乡网站建设多少钱沈阳企业网站seo公司
  • 网站建设_网站设计 app制作宁波网站制作设计
  • 鞍山做网站优化公司手机搜索引擎排行榜