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

如何规划建设一个企业网站谁会建设网站

如何规划建设一个企业网站,谁会建设网站,怎么做网站的自然排名,简历电子模版免费下载先简单聊聊SpringMVC如果你们玩知乎#xff0c;很可能会看到我的身影。我经常会去知乎水回答。在知乎有很多初学者都会问的一个问题#xff1a;「我学习SpringMVC需要什么样的基础」我一定会让他们先学Servlet#xff0c;再学SpringMVC的。虽然说我们在现实开发中几乎不会写… 先简单聊聊SpringMVC如果你们玩知乎很可能会看到我的身影。我经常会去知乎水回答。在知乎有很多初学者都会问的一个问题「我学习SpringMVC需要什么样的基础」我一定会让他们先学Servlet再学SpringMVC的。虽然说我们在现实开发中几乎不会写原生Servlet的代码了但我始终认为学完Servlet再学SpringMVC对理解SpringMVC是有好处的。三歪题外话我当时在学SpringMVC之前其实已经接触过另外一个web框架(当然了Servlet也是学了的)那就是「大名鼎鼎」的Struts2。只要是Struts2有的功能SpringMVC都会有。当时初学Struts2的时候用的是XML配置的方式去开发的再转到SpringMVC注解的时候觉得SpringMVC真香。Struts2在2020年已经不用学了学SpringMVC的基础是Servlet只要Servlet基础还行上手SpringMVC应该不成问题。从Servlet到SpringMVC你会发现SpringMVC帮我们做了很多的东西我们的代码肯定是没以前多了。Servlet我们以前可能需要将传递进来的参数手动封装成一个Bean然后继续往下传SpringMVC:现在SpringMVC自动帮我们将参数封装成一个BeanServlet:以前我们要导入其他的jar包去手动处理文件上传的细节SpringMVC现在SpringMVC上传文件用一个MultipartFile对象都给我们封装好了........说白了在Servlet时期我们这些活都能干只不过SpringMVC把很多东西都给屏蔽了于是我们用起来就更加舒心了。在学习SpringMVC的时候实际上也是学习这些功能是怎么用的而已并不会太难。这次整理的SpringMVC电子书其实也是在讲SpringMVC是如何使用的比如说传递一个日期字符串来SpringMVC默认是不能转成日期的那我们可以怎么做来实现。SpringMVC的文件上传是怎么使用的SpringMVC的拦截器是怎么使用的SpringMVC是怎么对参数绑定的......现在「电子书」已经放出来了但是别急重头戏在后面。显然通过上面的电子书是可以知道SpringMVC是怎么用的。但是这在面试的时候人家是不会问你SpringMVC的一些用法的而SpringMVC面试问得最多的就是SpringMVC请求处理的流程是怎么样的。其实也很简单流程就是下面这张图再简化一点可以发现流程不复杂在面试的时候甚至能一句话就讲完了但这够吗这是面试官想要的吗那肯定不是。那我们想知道SpringMVC是做了什么吗想的吧(不管你们想不想反正三歪想看)。由于想要主流程更加清晰一点我会在源码添加部分注释以及删减部分的代码以ResponseBody和RequestBody的Controller代码讲解为主这是线上环境用得最多的DispatcherServlet源码首先我们看看DispatcherServlet的类结构可以清楚地发现实际DispatcherServlet就是Servlet接口的一个子类(这也就是为什么网上这么多人说DispatcherServlet的原理实际上就是Servlet)我们在DispatcherServlet类上可以看到很多熟悉的成员变量(组件)所以看下来我们要的东西DispatcherServlet可全都有。// 文件处理器private MultipartResolver multipartResolver;// 映射器private List handlerMappings;// 适配器private List handlerAdapters;// 异常处理器private List handlerExceptionResolvers;// 视图解析器private List viewResolvers;然后我们会发现它们在initStrategies()上初始化protected void initStrategies(ApplicationContext context) {  initMultipartResolver(context);  initLocaleResolver(context);  initThemeResolver(context);  initHandlerMappings(context);  initHandlerAdapters(context);  initHandlerExceptionResolvers(context);  initRequestToViewNameTranslator(context);  initViewResolvers(context);  initFlashMapManager(context);}请求进到DispatcherServlet其实全部都会打到doService()方法上。我们看看这个doService()方法做了啥protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {    // 设置一些上下文...(省略一大部分)  request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());  request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);  try {      // 调用doDispatch   doDispatch(request, response);  }  finally {   if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {    if (attributesSnapshot ! null) {     restoreAttributesAfterInclude(request, attributesSnapshot);    }   }  } }所以请求会走到doDispatch(request, response);里边我们再进去看看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);         // 找到HandlerExecutionChain         mappedHandler  getHandler(processedRequest);         if (mappedHandler  null || mappedHandler.getHandler()  null) {            noHandlerFound(processedRequest, response);            return;         }         // 得到对应的hanlder适配器         HandlerAdapter ha  getHandlerAdapter(mappedHandler.getHandler());         // 拦截前置处理         if (!mappedHandler.applyPreHandle(processedRequest, response)) {            return;         }         // 真实处理请求         mv  ha.handle(processedRequest, response, mappedHandler.getHandler());         // 视图解析器处理         applyDefaultViewName(processedRequest, mv);                 // 拦截后置处理         mappedHandler.applyPostHandle(processedRequest, response, mv);      }      catch (Exception ex) {         dispatchException  ex;      }   }}这里的流程跟我们上面的图的流程几乎是一致的了。我们从源码可以知道的是原来SpringMVC的拦截器是在MappingHandler的时候一齐返回的返回的是一个HandlerExecutionChain对象。这个对象也不难我们看看public class HandlerExecutionChain { private static final Log logger  LogFactory.getLog(HandlerExecutionChain.class);  // 真实的handler private final Object handler;  // 拦截器List private HandlerInterceptor[] interceptors; private List interceptorList;private int interceptorIndex  -1;}OK整体的流程我们是已经看完了顺便要不我们去看看它是怎么找到handler的三歪带着你们冲我们点进去getHandler()后发现它就把默认实现的Handler遍历一遍然后选出合适的protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { // 遍历一遍默认的Handler实例选出合适的就返回  for (HandlerMapping hm : this.handlerMappings) {    HandlerExecutionChain handler  hm.getHandler(request);    if (handler ! null) {      return handler;    }  }  return null;}再进去getHandler里边看看呗里边又有几层我们最后可以看到它根据路径去匹配走到了lookupHandlerMethod这么一个方法protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {  List matches  new ArrayList();// 获取路径  List directPathMatches  this.mappingRegistry.getMappingsByUrl(lookupPath);// 对匹配的排序找到最佳匹配的if (!matches.isEmpty()) {   Comparator comparator  new MatchComparator(getMappingComparator(request));   Collections.sort(matches, comparator);if (logger.isTraceEnabled()) {    logger.trace(Found   matches.size()   matching mapping(s) for [       lookupPath  ] :   matches);   }   Match bestMatch  matches.get(0);if (matches.size()  1) {if (CorsUtils.isPreFlightRequest(request)) {return PREFLIGHT_AMBIGUOUS_MATCH;    }    Match secondBestMatch  matches.get(1);if (comparator.compare(bestMatch, secondBestMatch)  0) {     Method m1  bestMatch.handlerMethod.getMethod();     Method m2  secondBestMatch.handlerMethod.getMethod();throw new IllegalStateException(Ambiguous handler methods mapped for HTTP path         request.getRequestURL()  : {  m1  ,   m2  });    }   }   handleMatch(bestMatch.mapping, lookupPath, request);return bestMatch.handlerMethod;  }else {return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);  } }找拦截器大概也是上面的一个过程于是我们就可以顺利拿到HandlerExecutionChain了找到HandlerExecutionChain后我们是先去拿对应的HandlerAdaptor。我们也去看看里边做了什么// 遍历HandlerAdapter实例找到个合适的返回protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {  for (HandlerAdapter ha : this.handlerAdapters) {   if (ha.supports(handler)) {    return ha;   }  } }我们看一个常用HandlerAdapter实例RequestMappingHandlerAdapter会发现他会初始化很多的参数解析器其实我们经常用的ResponseBody解析器就被内置在里边private List getDefaultArgumentResolvers() {  List resolvers  new ArrayList();  resolvers.add(new MatrixVariableMethodArgumentResolver());  resolvers.add(new MatrixVariableMapMethodArgumentResolver());  resolvers.add(new ServletModelAttributeMethodProcessor(false));// ResponseBody Requestbody解析器  resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));  resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), t// 等等return resolvers; }得到HandlerAdaptor后随之而行的就是拦截器的前置处理然后就是真实的mv ha.handle(processedRequest, response, mappedHandler.getHandler())。这里边嵌套了好几层我就不一一贴代码了我们会进入ServletInvocableHandlerMethod#invokeAndHandle方法我们看一下这里边做了什么public void invokeAndHandle(ServletWebRequest webRequest,   ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {   // 处理请求  Object returnValue  invokeForRequest(webRequest, mavContainer, providedArgs);  setResponseStatus(webRequest);  if (returnValue  null) {   if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) {    mavContainer.setRequestHandled(true);    return;   }  }   //..   mavContainer.setRequestHandled(false);  try {      // 处理返回值   this.returnValueHandlers.handleReturnValue(     returnValue, getReturnValueType(returnValue), mavContainer, webRequest);  } }处理请求的方法我们进去看看invokeForRequestpublic Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,   Object... providedArgs) throws Exception {     // 得到参数  Object[] args  getMethodArgumentValues(request, mavContainer, providedArgs);     // 调用方法  Object returnValue  doInvoke(args);  if (logger.isTraceEnabled()) {   logger.trace(Method [  getMethod().getName()  ] returned [  returnValue  ]);  }  return returnValue; }我们看看它是怎么处理参数的getMethodArgumentValues方法进去看看private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer,   Object... providedArgs) throws Exception {   // 得到参数  MethodParameter[] parameters  getMethodParameters();  Object[] args  new Object[parameters.length];  for (int i  0; i    MethodParameter parameter  parameters[i];   parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);   GenericTypeResolver.resolveParameterType(parameter, getBean().getClass());   args[i]  resolveProvidedArgument(parameter, providedArgs);   if (args[i] ! null) {    continue;   }      // 找到适配的参数解析器   if (this.argumentResolvers.supportsParameter(parameter)) {    try {     args[i]  this.argumentResolvers.resolveArgument(       parameter, mavContainer, request, this.dataBinderFactory);     continue;    }    //.....  }  return args; }这些参数解析器实际上在HandlerAdaptor内置的那些这里不好放代码所以我截个图吧针对于RequestResponseBodyMethodProcessor解析器我们看看里边做了什么public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,   NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {    // 通过Converters对参数转换  Object arg  readWithMessageConverters(webRequest, parameter, parameter.getGenericParameterType());  String name  Conventions.getVariableNameForParameter(parameter);  WebDataBinder binder  binderFactory.createBinder(webRequest, arg, name);  // ...  mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX  name, binder.getBindingResult());  return arg; }再进去readWithMessageConverters里边看看protected  Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter param,   Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {// ...处理请求头try {   inputMessage  new EmptyBodyCheckingHttpInputMessage(inputMessage);// HttpMessageConverter实例去对参数转换for (HttpMessageConverter converter : this.messageConverters) {    Class converterType  (Class) converter.getClass();if (converter instanceof GenericHttpMessageConverter) {     GenericHttpMessageConverter genericConverter  (GenericHttpMessageConverter) converter;if (genericConverter.canRead(targetType, contextClass, contentType)) {if (logger.isDebugEnabled()) {       logger.debug(Read [  targetType  ] as \  contentType  \ with [  converter  ]);      }if (inputMessage.getBody() ! null) {       inputMessage  getAdvice().beforeBodyRead(inputMessage, param, targetType, converterType);       body  genericConverter.read(targetType, contextClass, inputMessage);       body  getAdvice().afterBodyRead(body, inputMessage, param, targetType, converterType);      }else {       body  null;       body  getAdvice().handleEmptyBody(body, inputMessage, param, targetType, converterType);      }break;     }    }//...各种判断return body; }看到这里有没有看不懂想要退出的感觉了别慌三歪带你们看看这份熟悉的配置 bean classorg.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter  property namemessageConverters   list    ref beanjacksonMessageConverter /   list  property bean bean idjacksonMessageConverterclassorg.springframework.http.converter.json.MappingJackson2HttpMessageConverter  property namesupportedMediaTypes   list    valuetext/html;charsetUTF-8value    valueapplication/json;charsetUTF-8value    valueapplication/x-www-form-urlencoded;charsetUTF-8value   list  property  property nameobjectMapper refjacksonObjectMapper / bean bean idjacksonObjectMapper classcom.fasterxml.jackson.databind.ObjectMapper /我们在SpringMVC想要使用ResponseBody返回JSON格式都会在配置文件上配置上面的配置RequestMappingHandlerAdapter这个适配器就是上面所说的那个内置了RequestResponseBodyMethodProcessor解析器然后MappingJackson2HttpMessageConverter实际上就是HttpMessageConverter接口的实例然后在返回的时候也经过HttpMessageConverter去将参数转换后写给HTTP响应报文。转换的流程大致如图所示img视图解析器后面就不贴了大概的流程就如上面的源码我再画个图来加深一下理解吧最后SpringMVC我们使用的时候非常简便在内部实际上帮我们做了很多(有各种的HandlerAdaptor)SpringMVC的请求流程面试的时候还是面得很多的还是可以看看源码它帮我们做了什么过一遍可能会发现自己能看懂以前的配置了。关注我觉得有点东西就点一下“赞和在看”吧感谢大家的支持了
http://www.pierceye.com/news/781798/

相关文章:

  • 丰南建设网站知识产权网站模板
  • 海外注册域名的网站给家乡做网站
  • 怎么做带数据库的网站重庆市建设工程信息网络
  • 做网站的越来越少了西宁网站建设多少钱
  • 环翠区网站建设做网站 用 显示器
  • 没学过计算机开始学做网站给别人做网站收多少钱
  • 网站建设的功能都需要有哪些方面大气一点的公司名字
  • 湘潭做网站价格问下磐石网络价格网站
  • 网站备案后可以更换域名吗2345网页游戏
  • 登录浏览器是建设银行移动门户网站广州专业做外贸网站
  • 思明区建设局网站微信 网页版
  • 淘宝客怎么做自己的网站搜索引擎营销案例分析题
  • 给女朋友做网站的素材友情链接是什么意思
  • 成都微信网站建设多少钱南平抖音搜索排名seo软件
  • 做外贸用哪些网站成都房地产开发商排名
  • 网站建设实施计划包括网页关键词优化
  • 建企业网站怎么做单页面网站源码
  • 儿童网站模板微信网站下载
  • 建设网站的市场背景搭建本地网站做色流
  • 湖南岳阳网站建设公司黄页顺企网宾馆在什么网站做推广效果好
  • 做外贸网站 怎么收钱网站自适应手机怎么
  • wordpress分只显示标题网站内容优化关键词布局
  • 校园云网站建设怎么做网站自动响应
  • 怎么做扫码进入网站北京seo计费
  • 网站备案 2016如何找网站
  • 网站开发客户挖掘做网站没签合同
  • 适合大学生做的兼职网站中国企业网信息查询系统
  • 淘宝网站的建设与运营设计思路做网站商铺模板
  • 网站优秀设计方案中国网站制作企业排行榜
  • 南昌建设局网站查询塔吊证怎么查福州seo网站建设