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

蓬莱网站建设关于企业网站建设

蓬莱网站建设,关于企业网站建设,wordpress动态链接,wordpress 4.4.15最近在新项目的开发过程中#xff0c;遇到了个问题#xff0c;需要将一些异常的业务流程返回给前端#xff0c;需要提供给前端不同的响应码#xff0c;前端再在次基础上做提示语言的国际化适配。这些异常流程涉及业务层和控制层的各个地方#xff0c;如果每个地方都写一些…最近在新项目的开发过程中遇到了个问题需要将一些异常的业务流程返回给前端需要提供给前端不同的响应码前端再在次基础上做提示语言的国际化适配。这些异常流程涉及业务层和控制层的各个地方如果每个地方都写一些重复代码显得很冗余。 然后查询解决方案时发现了ControllerAdvice这个注解可以对业务异常进行统一处理。经过仔细了解后发现这个注解还有更多的用处都很实用。 1 ControllerAdvice介绍 ControllerAdvice一般和三个以下注解一块使用起到不同的作用, ExceptionHandler: 该注解作用于方法上可以捕获到controller中抛出的一些自定义异常统一进行处理一般用于进行一些特定的异常处理。InitBinder:该注解作用于方法上,用于将前端请求的特定类型的参数在到达controller之前进行处理从而达到转换请求参数格式的目的。ModelAttribute该注解作用于方法和请求参数上在方法上时设置一个值可以直接在进入controller后传入该参数。 2 ControllerAdvice应用场景 2.1ExceptionHandler统一处理业务异常 RestControllerAdvice Slf4j public class GlobalExceptionHandler { // 这里就是对各个层返回的异常进行统一捕获处理 ExceptionHandler(value BusinessException.class) public ResponseDataVoid bizException(BusinessException e){log.error(业务异常记录,e);return ResponseData.error(e.getCode(),e.getMessage()); } } //业务异常处代码示例 if(CollectionUtil.isNotEmpty(companies)){ // 通过BusinessExceptionEnum枚举对业务异常进行统一管理 throw new BusinessException(BusinessExceptionEnum.ERROR_10003); }需要注意的是如果这里有多个ExceptionHandler,按照异常类的层次体系越高层的异常优先级越低。 2.2InitBinder做日期格式的统一处理 RestControllerAdvice Slf4j public class GlobalExceptionHandler { // 将前端传入的字符串时间格式转换为LocalDate时间 InitBinderprotected void initBinder(WebDataBinder binder) { //将前端传入的字符串格式时间数据转为LocalDate格式的数据binder.registerCustomEditor(LocalDate.class, new PropertyEditorSupport() {Overridepublic void setAsText(String text) throws IllegalArgumentException {setValue(LocalDate.parse(text, DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)));}}); //将前端传入的字符串格式时间数据转为LocalDateTime格式的数据binder.registerCustomEditor(LocalDateTime.class, new PropertyEditorSupport() {Overridepublic void setAsText(String text) throws IllegalArgumentException {setValue(LocalDateTime.parse(text, DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)));}}); //将前端传入的字符串格式时间数据转为LocalTim格式的数据binder.registerCustomEditor(LocalTime.class, new PropertyEditorSupport() {Overridepublic void setAsText(String text) throws IllegalArgumentException {setValue(LocalTime.parse(text, DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));}});} } // controller进行参数绑定 public ResponseDataListWorkCalendarVo listWorkCalendar(RequestParam LocalDate date){}2.3 ModelAttribute提前绑定全局user对象 // 这里ModelAttribute(loginUser)标注的modelAttribute()方法表示会在Controller方法之前将user设置到contoller里的已绑定参数里ModelAttribute(loginUser)public User setLoginUser(HttpServletRequest request) {return LoginContextUtils.getLoginUser(request);} // 使用PostMapping(/list)public ResponseDataIPageEmployeeVo listEmployee(ModelAttribute(loginUser) User user, RequestBody EmployeeSearch employeeSearch){return ResponseData.success(employeeService.listEmployee(user, employeeSearch));}3 ControllerAdvice作用原理探究 在探究ControllerAdvice如何生效时不得不提到springMvc绕不过的DispatcherServlet这个类是SpringMVC统一的入口所有的请求都通过它里面的一些初始化方法如下。 public class DispatcherServlet extends FrameworkServlet {// ......protected void initStrategies(ApplicationContext context) {initMultipartResolver(context);initLocaleResolver(context);initThemeResolver(context);initHandlerMappings(context); //请求处理的adapterinitHandlerAdapters(context); // 异常响应处理的resolverinitHandlerExceptionResolvers(context);initRequestToViewNameTranslator(context);initViewResolvers(context);initFlashMapManager(context);}// ...... }3.1initBinder和ModelAttribute的作用原理 initBinder和ModelAttribute都是请求过程中的处理我们知道springMvc通过HandlerApapter定位到具体的方法进行请求处理因此查看HandlerHaper的实现类发现RequestMappingHandlerAdapter比较符合我们的目标 点进去RequestMappingHandlerAdapter后发现里面的一个方法如下 Overridepublic void afterPropertiesSet() {// Do this first, it may add ResponseBody advice beans // 这里会添加ResponseBody advice beansinitControllerAdviceCache();if (this.argumentResolvers null) {ListHandlerMethodArgumentResolver resolvers getDefaultArgumentResolvers();this.argumentResolvers new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);}if (this.initBinderArgumentResolvers null) {ListHandlerMethodArgumentResolver resolvers getDefaultInitBinderArgumentResolvers();this.initBinderArgumentResolvers new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);}if (this.returnValueHandlers null) {ListHandlerMethodReturnValueHandler handlers getDefaultReturnValueHandlers();this.returnValueHandlers new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);}} // 这里找到contollerAdvice注解的类缓存里面的方法 private void initControllerAdviceCache() {if (getApplicationContext() null) {return;} // 找到ControllerAdvice注解标注的类ListControllerAdviceBean adviceBeans ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());ListObject requestResponseBodyAdviceBeans new ArrayList();for (ControllerAdviceBean adviceBean : adviceBeans) {Class? beanType adviceBean.getBeanType();if (beanType null) {throw new IllegalStateException(Unresolvable type for ControllerAdviceBean: adviceBean);} // 找到所有ModelAttribute标注的方法进行缓存就可以使用了SetMethod attrMethods MethodIntrospector.selectMethods(beanType, MODEL_ATTRIBUTE_METHODS);if (!attrMethods.isEmpty()) {this.modelAttributeAdviceCache.put(adviceBean, attrMethods);} // 找到所有initBinder注解标注的方法进行缓存就可以使用了SetMethod 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);} // ......日志处理}3.2ExceptionHandler注解的作用原理 相同的思路ExceptionHandler是响应时的处理因此需要找到对应的Resolver进入initHandlerExceptionResolvers(context)方法, 属性填充后会进行afterPropertiesSet方法这个方法可以用在一些特殊情况中也就是某个对象的某个属性需要经过外界得到比如说查询数据库等方式这时候可以用到spring的该特性只需要实现InitializingBean。 Overridepublic void afterPropertiesSet() {// Do this first, it may add ResponseBodyAdvice beansinitExceptionHandlerAdviceCache();if (this.argumentResolvers null) {ListHandlerMethodArgumentResolver resolvers getDefaultArgumentResolvers();this.argumentResolvers new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);}if (this.returnValueHandlers null) {ListHandlerMethodReturnValueHandler handlers getDefaultReturnValueHandlers();this.returnValueHandlers new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);}}private void initExceptionHandlerAdviceCache() {if (getApplicationContext() null) {return;}ListControllerAdviceBean adviceBeans ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());for (ControllerAdviceBean adviceBean : adviceBeans) {Class? beanType adviceBean.getBeanType();if (beanType null) {throw new IllegalStateException(Unresolvable type for ControllerAdviceBean: adviceBean);} // 这里找到ExceptionHandler注解标注的方法进行缓存后面就可以使用了ExceptionHandlerMethodResolver resolver new ExceptionHandlerMethodResolver(beanType);if (resolver.hasExceptionMappings()) {this.exceptionHandlerAdviceCache.put(adviceBean, resolver);}if (ResponseBodyAdvice.class.isAssignableFrom(beanType)) {this.responseBodyAdvice.add(adviceBean);}} // ......日志处理}在启动spring时debug发现最终也会走到这里对ExceptionHander注解的方法已经缓存 当Controller抛出异常时DispatcherServlet通过ExceptionHandlerExceptionResolver来解析异常而ExceptionHandlerExceptionResolver又通过ExceptionHandlerMethodResolver 来解析异常 ExceptionHandlerMethodResolver 最终解析异常找到适用的ExceptionHandler标注的方法是这里 Nullablepublic Method resolveMethodByExceptionType(Class? extends Throwable exceptionType) {Method method this.exceptionLookupCache.get(exceptionType);if (method null) {method getMappedMethod(exceptionType);this.exceptionLookupCache.put(exceptionType, method);}return (method ! NO_MATCHING_EXCEPTION_HANDLER_METHOD ? method : null);}4 用具体的调用过程验证上面的推测 本部分通过对DispatcherServlet的调用过程跟踪梳理出ControllerAdvice的作用原理以InitBinder主节点生效过程为例。 首选是dispathServlet在初始化过程中初始化RequestMappingHandlerAdapter过程中打断点发现initBinder已经缓存进来了。 然后是dispatcherServlet的调用流程图验证下是initBinder注解是否生效。 DispatcherServlet 通过doService()方法开始调用,主要逻辑包括 设置 request 通过doDispatch() 进行请求分发处理。 doDispatch() 的主要过程是通过 HandlerMapping 获取 Handler再找到用于执行它的 HandlerAdapter执行 Handler 后得到 ModelAndView ModelAndView 是连接“业务逻辑层”与“视图展示层”的桥梁。 4.1 DispathcerServlet的doDispatch方法 在入口处找到要执行的HandlerAdapter调用handle方法继续 protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {HttpServletRequest processedRequest request;HandlerExecutionChain mappedHandler null;boolean multipartRequestParsed false;WebAsyncManager asyncManager WebAsyncUtils.getAsyncManager(request);try {ModelAndView mv null;Exception dispatchException null;try {processedRequest checkMultipart(request);multipartRequestParsed (processedRequest ! request);// Determine handler for the current request. // 找到执行链,根据请求路径匹配到controller的方法mappedHandler getHandler(processedRequest);if (mappedHandler null) {noHandlerFound(processedRequest, response);return;}// Determine handler adapter for the current request. // 找到对应的HandlerAdapter,执行链中的handler类型为HandlerMethod的.HandlerAdapter ha getHandlerAdapter(mappedHandler.getHandler());// Process last-modified header, if supported by the handler.String method request.getMethod();boolean isGet HttpMethod.GET.matches(method);if (isGet || HttpMethod.HEAD.matches(method)) {long lastModified ha.getLastModified(request, mappedHandler.getHandler());if (new ServletWebRequest(request, response).checkNotModified(lastModified) isGet) {return;}}if (!mappedHandler.applyPreHandle(processedRequest, response)) {return;}// Actually invoke the handler. 真正进行处理的地方mv ha.handle(processedRequest, response, mappedHandler.getHandler());if (asyncManager.isConcurrentHandlingStarted()) {return;}applyDefaultViewName(processedRequest, mv);mappedHandler.applyPostHandle(processedRequest, response, mv);..........}4.2 RequestmappingHanderApapter对initBInder注解缓存方法进行处理 找到对应的handlerAdapter后进入invokeHandlerMethod()方法,在这里通过构建WebDataBinderFactory对initBinder注解进行构建供后续使用具体逻辑如下。 通过getDataBinderFactory()方法从之前缓存的Map initBinderAdviceCache中生成binderFactory Nullableprotected ModelAndView invokeHandlerMethod(HttpServletRequest request,HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {ServletWebRequest webRequest new ServletWebRequest(request, response);try { //根据initBinder注解,获取对应的factory主要成员是InvocableHandlerMethod就包括之前缓存的。WebDataBinderFactory binderFactory getDataBinderFactory(handlerMethod);ModelFactory modelFactory getModelFactory(handlerMethod, binderFactory); // 创建可调用的对象进行调用逻辑处理ServletInvocableHandlerMethod invocableMethod createInvocableHandlerMethod(handlerMethod);if (this.argumentResolvers ! null) {invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);}if (this.returnValueHandlers ! null) {invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);} // binderFactory设置进invocableMethodinvocableMethod.setDataBinderFactory(binderFactory);invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);ModelAndViewContainer mavContainer new ModelAndViewContainer();mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));modelFactory.initModel(webRequest, mavContainer, invocableMethod);mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);AsyncWebRequest asyncWebRequest WebAsyncUtils.createAsyncWebRequest(request, response);asyncWebRequest.setTimeout(this.asyncRequestTimeout);WebAsyncManager asyncManager WebAsyncUtils.getAsyncManager(request);asyncManager.setTaskExecutor(this.taskExecutor);asyncManager.setAsyncWebRequest(asyncWebRequest);asyncManager.registerCallableInterceptors(this.callableInterceptors);asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);if (asyncManager.hasConcurrentResult()) {Object result asyncManager.getConcurrentResult();mavContainer (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];asyncManager.clearConcurrentResult();LogFormatUtils.traceDebug(logger, traceOn - {String formatted LogFormatUtils.formatValue(result, !traceOn);return Resume with async result [ formatted ];});invocableMethod invocableMethod.wrapConcurrentResult(result);} // 继续进行处理invocableMethod.invokeAndHandle(webRequest, mavContainer);if (asyncManager.isConcurrentHandlingStarted()) {return null;}return getModelAndView(mavContainer, modelFactory, webRequest);}finally {webRequest.requestCompleted();}} // 生成WebDataBinderFactory的具体逻辑 private WebDataBinderFactory getDataBinderFactory(HandlerMethod handlerMethod) throws Exception {Class? handlerType handlerMethod.getBeanType();SetMethod methods this.initBinderCache.get(handlerType);if (methods null) {methods MethodIntrospector.selectMethods(handlerType, INIT_BINDER_METHODS);this.initBinderCache.put(handlerType, methods);}ListInvocableHandlerMethod initBinderMethods new ArrayList();// Global methods first 获取之前项目启动缓存的initMethodthis.initBinderAdviceCache.forEach((controllerAdviceBean, methodSet) - {if (controllerAdviceBean.isApplicableToBeanType(handlerType)) {Object bean controllerAdviceBean.resolveBean();for (Method method : methodSet) {initBinderMethods.add(createInitBinderMethod(bean, method));}}});for (Method method : methods) {Object bean handlerMethod.getBean();initBinderMethods.add(createInitBinderMethod(bean, method));}return createDataBinderFactory(initBinderMethods);}经过上面的处理发现initBinder标注的注解方法已经成功缓存进bindFactory。 4.3 继续调用getMethodArgumentValues进行后续处理 继续往下跟踪进入InvocableHandlerMethod的invokeForRequest方法里面有getMethodArgumentValues方法会对请求参数进行处理。 最终使用AbstractNamedValueMethodArgumentResolver的resolveArgument方法对请求字符串格式数据进行处理 // 请求Controller方法如下 public ResponseDataIPageCompanyVo listCompany(HttpServletRequest servletRequest, RequestBody CompanySearch companySearch, RequestParam LocalDate localDate){getLoginUser(servletRequest);return ResponseData.success(companyService.listCompany(companySearch));}protected Object[] getMethodArgumentValues(NativeWebRequest request, Nullable ModelAndViewContainer mavContainer,Object... providedArgs) throws Exception { // 得到方法的参数列表MethodParameter[] parameters getMethodParameters();if (ObjectUtils.isEmpty(parameters)) {return EMPTY_ARGS;}Object[] args new Object[parameters.length]; // 循环如处理请求参数for (int i 0; i parameters.length; i) {MethodParameter parameter parameters[i];parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);args[i] findProvidedArgument(parameter, providedArgs);if (args[i] ! null) {continue;}if (!this.resolvers.supportsParameter(parameter)) {throw new IllegalStateException(formatArgumentError(parameter, No suitable resolver));}try { // 真正进行参数处理的地方args[i] this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);}catch (Exception ex) {// Leave stack trace for later, exception may actually be resolved and handled...if (logger.isDebugEnabled()) {String exMsg ex.getMessage();if (exMsg ! null !exMsg.contains(parameter.getExecutable().toGenericString())) {logger.debug(formatArgumentError(parameter, exMsg));}}throw ex;}}return args;}// 最终会使用AbstractNamedValueMethodArgumentResolver来进行处理 public final Object resolveArgument(MethodParameter parameter, Nullable ModelAndViewContainer mavContainer,NativeWebRequest webRequest, Nullable WebDataBinderFactory binderFactory) throws Exception {NamedValueInfo namedValueInfo getNamedValueInfo(parameter);MethodParameter nestedParameter parameter.nestedIfOptional(); // 得到请求参数名称为localdateObject resolvedName resolveEmbeddedValuesAndExpressions(namedValueInfo.name);if (resolvedName null) {throw new IllegalArgumentException(Specified name must not resolve to null: [ namedValueInfo.name ]);} // 获取请求的locadate的值此时为字符串格式yyyy-mm-ddObject arg resolveName(resolvedName.toString(), nestedParameter, webRequest);if (arg null) {if (namedValueInfo.defaultValue ! null) {arg resolveEmbeddedValuesAndExpressions(namedValueInfo.defaultValue);}else if (namedValueInfo.required !nestedParameter.isOptional()) {handleMissingValue(namedValueInfo.name, nestedParameter, webRequest);}arg handleNullValue(namedValueInfo.name, arg, nestedParameter.getNestedParameterType());}else if (.equals(arg) namedValueInfo.defaultValue ! null) {arg resolveEmbeddedValuesAndExpressions(namedValueInfo.defaultValue);} // 这里就会使用bindFactory进行处理if (binderFactory ! null) {WebDataBinder binder binderFactory.createBinder(webRequest, null, namedValueInfo.name);try { // 经过这里进行处理输入的string类型就会转为LocalDate了arg binder.convertIfNecessary(arg, parameter.getParameterType(), parameter);}catch (ConversionNotSupportedException ex) {throw new MethodArgumentConversionNotSupportedException(arg, ex.getRequiredType(),namedValueInfo.name, parameter, ex.getCause());}catch (TypeMismatchException ex) {throw new MethodArgumentTypeMismatchException(arg, ex.getRequiredType(),namedValueInfo.name, parameter, ex.getCause());}// Check for null value after conversion of incoming argument valueif (arg null namedValueInfo.defaultValue null namedValueInfo.required !nestedParameter.isOptional()) {handleMissingValueAfterConversion(namedValueInfo.name, nestedParameter, webRequest);}}handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);return arg;}最后附上上面调用过程中一些类的介绍 以上就是ControllerAdivce的全介绍。通过对源码的学习加深了对HTTP请求过程的理解。 参考:https://blog.csdn.net/zmm__1377445292/article/details/116158554 作者京东物流 付鹏嘎 来源京东云开发者社区 自猿其说Tech
http://www.hkea.cn/news/14449304/

相关文章:

  • 河南平台网站建设设计有关wordpress教学的网站
  • 桂林新站优化一键生成vi设计
  • 设计软件免费下载官方网站利于优化的网站要备案吗
  • 做网站网站彩票算犯法吗深圳外包公司网站
  • 广西建设厅官方网站无视隐私的十大软件
  • 茂名网站建设公司企业网址
  • 自助建站优化网络门店管理系统
  • 国内的c2c网站有哪些商标logo设计图案
  • 国外有哪些做建筑材料的网站app网站公司
  • pc网站开发使用什么布局好logo图案免费
  • 网站策划书市场分析昭通建设局网站
  • 艺术家网站建设中企业网站建设的策划初期的一些误区网站建设英语怎么说
  • 网站总是在建设中网页设计与制作模板及素材
  • 做网站大约需要多少钱百度精准推广
  • 大连网站建设ewaylife专门做有机食品的网站
  • 微信高端网站建设app开发 深圳
  • 《网站开发与应用》大作业网络营销师培训课程
  • 什么网站简单北京seo关键词优化收费
  • 网站建设的项目计划wordpress nonce
  • 网络编辑做营销网站seo
  • 厦门网站制作案例县城网站怎样做经验
  • 网站设计与网页设计的区别宁波网络推广制作
  • 名字设计网站google推广seo
  • 平阴网站建设免费做金融网站有哪些
  • 个人网站设计企业php笔记网站
  • 手机建站免费网站怎么做seo优化
  • 旅游交友的网站建设网站网站做代理违法吗
  • 天津市工程建设交易管理中心网站网络科技公司一般做什么
  • 视频图站主题 wordpress电子商务网站建设预算
  • 网站建设产品手册网站建设及网站推广