文档章节

WEB请求处理五:WEB MVC框架请求处理

陶邦仁
 陶邦仁
发布于 2016/07/18 11:26
字数 3492
阅读 308
收藏 3
点赞 0
评论 0

#0 系列目录#

为开发团队选择一款优秀的MVC框架是件难事儿,在众多可行的方案中决择需要很高的经验和水平。你的一个决定会影响团队未来的几年。要考虑方面太多:

  1. 简单易用,以提高开发效率。使小部分的精力在框架上,大部分的精力放在业务上。
  2. 性能优秀,这是一个最能吸引眼球的话题。
  3. 尽量使用大众的框架(避免使用小众的、私有的框架),新招聘来的开发人员有一些这方面技术积累,减低人员流动再适应的影响。

如果你还在为这件事件发愁,本文最适合你了。选择Spring MVC吧。本篇文章主要以Spring MVC为例,基本上市面上的MVC框架处理流程都大同小异,主流程都基本相同。Spring MVC比较成熟、使用也比较广泛,设计理念也非常棒,所以,本文重点以Spring MVC讲解为主。

先说下在整个WEB请求处理过程中,本篇文章讲述的是哪个流程模块。为直观明了,先上一张图,红色部分为本章所述模块:

WEB请求处理过程

#1 Spring MVC核心类与接口# 先来了解一下,几个重要的接口与类。现在不知道他们是干什么的没关系,先混个脸熟,为以后认识他们打个基础。

  1. DispatcherServlet -- 前置控制器

DispatcherServlet -- 前置控制器

Spring提供的前端控制器,所有的请求都有经过它来统一分发。在DispatcherServlet将请求分发给Spring Controller之前,需要借助于Spring提供的HandlerMapping定位到具体的Controller。

  1. HandlerMapping接口 -- 处理请求的映射

HandlerMapping接口的实现类:

SimpleUrlHandlerMapping 通过配置文件,把一个URL映射到Controller DefaultAnnotationHandlerMapping 通过注解,把一个URL映射到Controller类上

HandlerMapping接口 -- 处理请求的映射

  1. HandlerAdapter接口 -- 处理请求的映射

AnnotationMethodHandlerAdapter类,通过注解,把一个URL映射到Controller类的方法上

HandlerAdapter接口 -- 处理请求的映射

  1. Controller接口 -- 控制器

由于我们使用了@Controller注解,添加了@Controller注解的类就可以担任控制器(Action)的职责,所以我们并没有用到这个接口。

Controller接口 -- 控制器

需要为并发用户处理请求,因此实现Controller接口时,必须保证线程安全并且可重用。Controller将处理用户请求,这和Struts Action扮演的角色是一致的。一旦Controller处理完用户请求,则返回ModelAndView对象给DispatcherServlet前端控制器,ModelAndView中包含了模型(Model)和视图(View)。从宏观角度考虑,DispatcherServlet是整个Web应用的控制器;从微观考虑,Controller是单个Http请求处理过程中的控制器,而ModelAndView是Http请求过程中返回的模型(Model)和视图(View)

  1. HandlerInterceptor接口 -- 拦截器

无图,我们自己实现这个接口,来完成拦截的器的工作。

  1. ViewResolver接口的实现类

Spring提供的视图解析器(ViewResolver)在Web应用中查找View对象,从而将相应结果渲染给客户。

UrlBasedViewResolver类 通过配置文件,把一个视图名交给到一个View来处理 InternalResourceViewResolver类,比上面的类,加入了JSTL的支持

ViewResolver接口的实现类

  1. View接口

JstlView类

View接口

  1. LocalResolver接口

LocalResolver接口

  1. HandlerExceptionResolver接口 -- 异常处理

SimpleMappingExceptionResolver实现类

HandlerExceptionResolver接口 -- 异常处理

  1. ModelAndView类

#2 DispatcherServlet初始化过程# 当Web项目启动时,做初始化工作,所以我们大部分是配置在Web.xml里面,这样项目一启动,就会执行相关的初始化工作,下面是Web.xml代码:

    <servlet>  
        <servlet-name>SpringMVCDispatcher</servlet-name>  
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
        <init-param>  
            <param-name>contextConfigLocation</param-name>  
            <param-value>  
                classpath:spring-mvc.xml  
            </param-value>  
        </init-param>  
        <load-on-startup>1</load-on-startup>  
    </servlet>  
    <servlet-mapping>  
        <servlet-name>SpringMVCDispatcher</servlet-name>  
        <url-pattern>*.jhtml</url-pattern>  
    </servlet-mapping>

    <servlet>  
        <servlet-name>HessianDispatcher</servlet-name>  
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
        <init-param>  
            <param-name>contextConfigLocation</param-name>  
            <param-value>  
                classpath:hessian-service.xml  
            </param-value>  
        </init-param>  
        <load-on-startup>1</load-on-startup>  
    </servlet>  
    <servlet-mapping>  
        <servlet-name>HessianDispatcher</servlet-name>  
        <url-pattern>/service/*</url-pattern>  
    </servlet-mapping>  

这里配置了两个DispatcherServlet,后面会介绍到,怎么各自处理,有各自的上下文容器。

最早我们开始学习MVC结构时,就是学servlet,都是继承了HttpServlet 类,也是重新了init、doGet、doPost、destroy方法,我这边就不介绍HttpServlet类,DispatcherServlet也是间接最高继承了HttpServlet,类继承结构如图所示:

DispatcherServlet类继承结构

我们先了解项目启动,DispatcherServlet和父类都做了什么事情呢?这是我们本节的重点。

  1. 第一步:DispatcherServlet继承了FrameworkServlet,FrameworkServlet继承了HttpServletBean,HttpServletBean继承了HttpServlet 类,而HttpServletBean类有一个入口点就是重写了init方法,如图所示:

HttpServletBean重写了init方法

 init方法做了什么事情呢?接下来我们来具体分析:

1)PropertyValues:获取Web.xml里面的servlet的init-param(web.xml)

/** 
   * Create new ServletConfigPropertyValues. 
    * @param config ServletConfig we'll use to take PropertyValues from 
    * @param requiredProperties set of property names we need, where 
    * we can't accept default values 
    * @throws ServletException if any required properties are missing 
    */  
public ServletConfigPropertyValues(ServletConfig config, Set<String> requiredProperties)  
       throws ServletException {  
       Enumeration en = config.getInitParameterNames();  
       while (en.hasMoreElements()) {  
           String property = (String) en.nextElement();  
           Object value = config.getInitParameter(property);  
           addPropertyValue(new PropertyValue(property, value));  
       }   
}  

说明:

 Enumeration en = config.getInitParameterNames();

获取了init-param的param-name和param-value值,并设置配置参数到PropertyValue,如图所示:

获取init-param参数并设置到PropertyValue

2)BeanWrapper:封装了bean的行为,提供了设置和获取属性值,它有对应的BeanWrapperImpl,如图所示:

封装了bean的行为,提供了设置和获取属性值

3)ResourceLoader:接口仅有一个getResource(String location)的方法,可以根据一个资源地址加载文件资源。classpath:这种方式指定SpringMVC框架bean配置文件的来源。

ResourcePatternResolver扩展了ResourceLoader接口,获取资源:

 ResourcePatternResolver resolver =new PathMatchingResourcePatternResolver();
 resolver.getResources("classpath:spring-mvc.xml");

总结:

先通过PropertyValues获取web.xml文件init-param的参数值,然后通过ResourceLoader读取.xml配置信息,BeanWrapper对配置的标签进行解析和将系统默认的bean的各种属性设置到对应的bean属性。

  1. 第二步:在init方法里还调用了initServletBean();这里面又实现了什么。HttpServletBean在为子类提供模版、让子类根据自己的需求实现不同的ServletBean的初始化工作,这边是由HttpServletBean的子类FrameworkServlet来实现的,如图所示:

initServletBean()在子类FrameworkServlet的实现

this.webApplicationContext = initWebApplicationContext();初始化SpringMVC 上下文容器,servlet的上下文容器是ServletContext。对initWebApplicationContext();进行跟踪,查看这个方法做了什么事情?

initServletBean()在子类FrameworkServlet的实现-1 initServletBean()在子类FrameworkServlet的实现-2

protected WebApplicationContext initWebApplicationContext() {  
        //1. 根节点上下文,是通过ContextLoaderListener加载的,服务器启动时,最先加载的  
        WebApplicationContext rootContext =  
                WebApplicationContextUtils.getWebApplicationContext(getServletContext());  
        if (this.webApplicationContext != null) {
            wac = this.webApplicationContext;  
            if (wac instanceof ConfigurableWebApplicationContext) {  
                ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;  
                //2. 要对上下文设置父上下文和ID等  
                if (!cwac.isActive()) {  
                    if (cwac.getParent() == null) {  
                        cwac.setParent(rootContext);  
                    }  
                    configureAndRefreshWebApplicationContext(cwac);  
                }  
            }  
        }  
        //3. Servlet不是由编程式注册到容器中,查找servletContext中已经注册的WebApplicationContext作为上下文  
        if (wac == null) {  
            wac = findWebApplicationContext();  
        }  
        //4. 如果都没找到时,就用根上下文就创建一个上下文有ID  
        if (wac == null) {  
            wac = createWebApplicationContext(rootContext);  
        }  
        //5. 在上下文关闭的情况下调用refesh可启动应用上下文,在已经启动的状态下,调用refresh则清除缓存并重新装载配置信息  
        if (!this.refreshEventReceived) {  
            onRefresh(wac);  
        }  
       //6. 对不同的请求对应的DispatherServlet有不同的WebApplicationContext、并且都存放在ServletContext中  
        if (this.publishContext) {  
            String attrName = getServletContextAttributeName();  
            getServletContext().setAttribute(attrName, wac);  
            if (this.logger.isDebugEnabled()) {  
                this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() +  
                        "' as ServletContext attribute with name [" + attrName + "]");  
            }  
        }  
  
        return wac;  
  }  

总结:

initWebApplicationContext初始化上下文,并作为值放到了ServletContext里,因为不同的DispatherServlet有对应的各自的上下文,而且上下文有设置父上下文和id属性等。上下文项目启动时会调用createWebApplicationContext()方法,如下图所示。

上下文项目启动时会调用createWebApplicationContext()方法

然后会初始化,设置父上下文和id属性等,如图所示:

初始化,设置父上下文和id属性

  1. 获取ContextLoaderListener加载的上下文并标示为根上下文,如果是编程式传入,没初始化,以根节点为父上文,并设置ID等信息,然后初始化。

 > 2) 如果上下文是为空的,Servlet不是由编程式注册到容器中,查找servletContext中已经注册的WebApplicationContext作为上下文,如果都没找到时,就用根上下文就创建一个上下文ID,在上下文关闭的情况下调用refesh可启动应用上下文,在已经启动的状态下,调用refresh则清除缓存并重新装载配置信息。

 > 3) 对不同的请求对应的DispatherServlet有不同的WebApplicationContext、并且都存放在ServletContext中。以servlet-name为key保存在severtContext,前面有配置了两个DispatherServlet,都有各自的上下文容器,如下图所示。

不同请求对应不同DispatherServlet和WebApplicationContext、并且都存放在ServletContext

  1. 第三步:回调函数onRefresh还做了一些提供了SpringMVC各种编程元素的初始化工作, onRefresh在为子类提供模版、让子类根据自己的需求实现不同的onRefresh的初始化工作,这边是由FrameworkServlet的子类DispatcherServlet来实现的,如图所示:

回调函数onRefresh()在子类DispatcherServlet的实现

我们现在来分析SpringMVC组件进行初始化,并封装到DispatcherServlet中:

       //初始化上传文件解析器
        initMultipartResolver(context);
        //初始化本地解析器
        initLocaleResolver(context);
        //初始化主题解析器
        initThemeResolver(context);
        //初始化映射处理器
        initHandlerMappings(context);
        //初始化适配器处理器
        initHandlerAdapters(context);
        //初始化异常处理器
        initHandlerExceptionResolvers(context);
        //初始化请求到视图名翻译器
        initRequestToViewNameTranslator(context);
        //初始化视图解析器
        initViewResolvers(context);

1)initHandlerMappings初始化映射处理器:

private void initHandlerMappings(ApplicationContext context) {  
      this.handlerMappings = null;  
      if (this.detectAllHandlerMappings) {  
          Map<String, HandlerMapping> matchingBeans =  
                BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);  
          if (!matchingBeans.isEmpty()) {  
              this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());  
              // We keep HandlerMappings in sorted order.  
              OrderComparator.sort(this.handlerMappings);  
          }  
      }  
      else {  
          try {  
              HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);  
              this.handlerMappings = Collections.singletonList(hm);  
          }  
          catch (NoSuchBeanDefinitionException ex) {  
          }  
      }  
      if (this.handlerMappings == null) {  
          this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);  
          if (logger.isDebugEnabled()) {  
              logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");  
          }  
      }  
}  

说明:

1)detectAllHandlerMappings默认是true,根据类型匹配机制查找上下文及父容器上下文中所有类型为HandlerMapping的bean,将它们作为该类型组件,并放到ArrayList<HandlerMapping>中。

 > 2)detectAllHandlerMappings如果是false时,查找key为handlerMapping的HandlerMapping类型的bean为该类组件,而且 Collections.singletonList只有一个元素的集合。  >

3)List<HandlerMapping> 是为空的话,使用BeanNameUrlHandleMapping实现类创建该类的组件。

initHandlerMapping会初始化了handlerMethods请求方法的映射,HandlerMapping是处理请求的映射的如图所示:

initHandlerMapping初始化handlerMethods请求方法的映射

2)initHandlerAdapters适配器处理器:

private void initHandlerAdapters(ApplicationContext context) {  
        this.handlerAdapters = null;  
  
        if (this.detectAllHandlerAdapters) {  
            Map<String, HandlerAdapter> matchingBeans =  
                    BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);  
            if (!matchingBeans.isEmpty()) {  
                this.handlerAdapters = new ArrayList<HandlerAdapter>(matchingBeans.values());  
                // We keep HandlerAdapters in sorted order.  
                OrderComparator.sort(this.handlerAdapters);  
            }  
        }  
        else {  
            try {  
                HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);  
                this.handlerAdapters = Collections.singletonList(ha);  
            }  
            catch (NoSuchBeanDefinitionException ex) {  
                            }  
        }  
        if (this.handlerAdapters == null) {  
            this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);  
            if (logger.isDebugEnabled()) {  
                logger.debug("No HandlerAdapters found in servlet '" + getServletName() + "': using default");  
            }  
        }  
  }

initHandlerAdapters适配器处理器初始化原理跟initHandlerMappings初始化映射处理器一样。

当DispatcherServlet初始化后,就会自动扫描上下文的bean,根据名称或者类型匹配的机制查找自定义的组件,找不到则使用DispatcherServlet。Properties定义默认的组件。

HttpServletBean、FrameworkServlet、DispatcherServlet三个不同的类层次,SpringMVC对三个以抽象和继承来实现不用的功能,分工合作,实现了解耦的设计原则。

我们在回顾一下,各自做了什么事情:

  1. HttpServletBean 主要做一些初始化的工作,将web.xml中配置的参数设置到Servlet中。比如servlet标签的子标签init-param标签中配置的参数。
  2. FrameworkServlet 将Servlet与Spring容器上下文关联。其实也就是初始化FrameworkServlet的属性webApplicationContext,这个属性代表SpringMVC上下文,它有个父类上下文,既web.xml中配置的ContextLoaderListener监听器初始化的容器上下文。
  3. DispatcherServlet 初始化各个功能的实现类。比如异常处理、视图处理、请求映射处理等。

#3 DispatcherServlet处理请求过程# Spring MVC请求处理流程图 Spring MVC请求处理时序图

Spring MVC请求处理流程描述:

  1. 用户向服务器发送请求,请求被Spring 前端控制Servelt DispatcherServlet捕获; 2. DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI)。然后根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain对象的形式返回; 3. DispatcherServlet 根据请求获得Handler,选择一个合适的HandlerAdapter。(附注:如果成功获得HandlerAdapter后,此时将开始执行拦截器的preHandler(...)方法)
  2. 提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)。 在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:        HttpMessageConveter:将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息;        数据转换:对请求消息进行数据转换。如String转换成Integer、Double等;        数据根式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等;        数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中;
  3. Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象;
  4. 根据返回的ModelAndView,选择一个适合的ViewResolver(必须是已经注册到Spring容器中的ViewResolver)返回给DispatcherServlet; 7. ViewResolver 结合Model和View,来渲染视图;
  5. 将渲染结果返回给客户端;

HttpServlet提供了service方法用于处理请求,service使用了模板设计模式,在内部对于http get方法会调用doGet方法,http post方法调用doPost方法:

HttpServlet提供了service方法用于处理请求

进入processRequest方法看下: processRequest方法-1 processRequest方法-2 其中注册的监听器类型为ApplicationListener接口类型。继续看DispatcherServlet覆写的doService方法: DispatcherServlet覆写的doService方法

最终就是doDispatch方法。doDispatch方法功能简单描述一下:

  1. 首先根据请求的路径找到HandlerMethod(带有Method反射属性,也就是对应Controller中的方法);
  2. 然后匹配路径对应的拦截器,有了HandlerMethod和拦截器构造个HandlerExecutionChain对象。HandlerExecutionChain对象的获取是通过HandlerMapping接口提供的方法中得到;
  3. 有了HandlerExecutionChain之后,通过HandlerAdapter对象进行处理得到ModelAndView对象;
  4. HandlerMethod内部handle的时候,使用各种HandlerMethodArgumentResolver实现类处理HandlerMethod的参数,使用各种HandlerMethodReturnValueHandler实现类处理返回值;
  5. 最终返回值被处理成ModelAndView对象,这期间发生的异常会被HandlerExceptionResolver接口实现类进行处理;

© 著作权归作者所有

共有 人打赏支持
陶邦仁
粉丝 1569
博文 420
码字总数 1483822
作品 0
海淀
技术主管
Spring MVC

Spring MVC一、什么是 Spring MVC Spring MVC 属于 SpringFrameWork 的后续产品,已经融合在 Spring Web Flow 里面,是一个强大灵活的 Web 框架。Spring MVC 提供了一个 DispatcherServlet ...

任任任任师艳
2017/11/20
0
0
Spring MVC静态资源url映射处理

今天发现网上有些坑爹的博客,估计博主自己也没要用过,就写了出来,害得我折腾半天。鉴于避免其他同学出现类似的情况,写出来,也请大家指正。 优雅REST风格的资源URL不希望带 .html 或 .d...

钟声已经敲响
2016/10/10
503
0
【Java框架】Java EE框架常见的面试题

一、什么是Spring? 1、Spring的核心是一个轻量级(Lightweight)的容器(Container)。 2、Spring是实现IoC(Inversion of Control)容器和非入侵性(No intrusive)的框架。 3、Spring提供...

林元煌
2017/07/31
0
0
Spring MVC介绍

我们知道MVC是一种经典的模式,把视图、控制器以及数据分开,解耦了各模块之间的关系。Spring Web MVC是基于Java实现的Web MVC设计模式,是一个请求驱动类型的轻量级Web框架,也就是借助MVC...

博为峰教研组
2016/11/23
18
0
Spring MVC入门

2.1、Spring Web MVC是什么Spring Web MVC是一种基于Java的实现了Web MVC设计模式的请求驱动类型的轻量级Web框架,即使用了MVC架构模式的思想,将web层进行职责解耦,基于请求驱动指的就是使...

bluecoffee
2016/09/09
35
0
Spring MVC入门 —— 学SpringMVC

2.1、Spring Web MVC是什么 Spring Web MVC是一种基于Java的实现了Web MVC设计模式的请求驱动类型的轻量级Web框架,即使用了MVC架构模式的思想,将web层进行职责解耦,基于请求驱动指的就是...

qq58edf1d989a2d
2017/04/13
0
0
1:spring mvc 概述

什么是mvc 什么是spring mvc Spring MVC 是一种基于 Java 的实现了 Web MVC 设计模式的请求驱动类型的轻量级 Web 框架, 即使用了MVC 架构模式的思想,将 web 层进行职责解耦, 基于请求驱动...

小杰java
2017/10/18
0
0
spring注解解释

1、@controller 控制器(注入控制器分发)2、@service 服务(注入服务)3、@repository dao(实现dao访问)4、@component (把普通pojo实例化到spring容器中,相当于配置文件中的) pring2.5...

yjm199
2017/02/06
0
0
Spring MVC 框架入门-Hello World 实例

Spring MVC 框架入门-Hello World 实例 下面的例子是如何使用Spring MVC框架,编写一个简单的web Hello World应用程序。开发工具是用的 Eclipse IDE,按照以下步骤使用Spring Web框架开发动态...

zhaoliang1131
2016/08/18
0
0
Spring MVC 到底是如何工作的?

本文由码农网 – 小峰原创翻译,转载请看清文末的转载要求,欢迎参与我们的付费投稿计划! 这篇文章将深入探讨Spring框架的一部分——Spring Web MVC的强大功能及其内部工作原理。 这篇文章的...

码农网
2017/11/23
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

OSChina 周一乱弹 —— 你的朋友圈有点生锈了

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @Devoes :分享Trademark的单曲《Only Love (电视剧《妙手仁心 II》插曲)》: 《Only Love (电视剧《妙手仁心 II》插曲)》- Trademark 手机党少...

小小编辑
55分钟前
54
5
【面试题】盲人坐飞机

有100位乘客乘坐飞机,其中有一位是盲人,每位乘客都按自己的座位号就坐。由于盲人看不见自己的座位号,所以他可能会坐错位置,而自己的座位被占的乘客会随便找个座位就坐。问所有乘客都坐对...

garkey
今天
1
0
谈谈神秘的ES6——(二)ES6的变量

谈谈神秘的ES6——(二)ES6的变量 我们在《零基础入门JavaScript》的时候就说过,在ES5里,变量是有弊端的,我们先来回顾一下。 首先,在ES5中,我们所有的变量都是通过关键字var来定义的。...

JandenMa
今天
1
0
arts-week1

Algorithm 594. Longest Harmonious Subsequence - LeetCode 274. H-Index - LeetCode 219. Contains Duplicate II - LeetCode 217. Contains Duplicate - LeetCode 438. Find All Anagrams ......

yysue
今天
1
0
NNS拍卖合约

前言 关于NNS的介绍,这里就不多做描述,相关的信息可以查看NNS的白皮书http://doc.neons.name/zh_CN/latest/nns_background.html。 首先nns中使用的竞价货币是sgas,关于sgas介绍可以戳htt...

红烧飞鱼
今天
1
0
Java IO类库之管道流PipeInputStream与PipeOutputStream

一、java管道流介绍 在java多线程通信中管道通信是一种重要的通信方式,在java中我们通过配套使用管道输出流PipedOutputStream和管道输入流PipedInputStream完成线程间通信。多线程管道通信的...

老韭菜
今天
0
0
用Python绘制红楼梦词云图,竟然发现了这个!

Python在数据分析中越来越受欢迎,已经达到了统计学家对R的喜爱程度,Python的拥护者们当然不会落后于R,开发了一个个好玩的数据分析工具,下面我们来看看如何使用Python,来读红楼梦,绘制小...

猫咪编程
今天
1
0
Java中 发出请求获取别人的数据(阿里云 查询IP归属地)

1.效果 调用阿里云的接口 去定位IP地址 2. 代码 /** * 1. Java中远程调用方法 * http://localhost:8080/mavenssm20180519/invokingUrl.action * @Title: invokingUrl * @Description: * @ret......

Lucky_Me
今天
1
0
protobuf学习笔记

相关文档 Protocol buffers(protobuf)入门简介及性能分析 Protobuf学习 - 入门

OSC_fly
昨天
0
0
Mybaties入门介绍

Mybaties和Hibernate是我们在Java开发中应用的比较多的两个ORM框架。当然,目前Mybaties正在慢慢取代Hibernate,这是因为相比较Hibernate而言Mybaties性能更好,响应更快,更加灵活。我们在开...

王子城
昨天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部