Spring Web MVC DispatcherServlet详解—官方原版

news2024/10/7 7:41:02

一、概述

 Spring Web MVC是基于Servlet API构建的原始Web框架,从一开始就包含在Spring框架中。正式名称“SpringWebMVC”来自其源模块(Spring-webmvc)的名称,但它更常见的名称是“SpringMVC”。

与Spring Web MVC并行,Spring Framework 5.0引入了一个反应式堆栈Web框架,其名称“Spring WebFlux”也基于其源模块(Spring-WebFlux)。

二、DispatcherServlet

Spring MVC和其他许多Web框架一样,是围绕前端控制器模式设计的,其中一个中央 Servlet,即 DispatcherServlet,为请求处理提供了一个共享算法,而实际工作则由可配置的委托组件执行。这种模式很灵活,支持多样化的工作流程。
DispatcherServlet和任何Servlet一样,需要使用Java配置或web.xml根据Servlet规范进行声明和映射。反过来,DispatcherServlet使用Spring配置来发现请求映射、视图解析、异常处理等所需的委托组件。
以下Java配置示例注册并初始化DispatcherServlet,该Servlet由Servlet容器自动检测

public class MyWebApplicationInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletContext) {

        // Load Spring web application configuration
        AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
        context.register(AppConfig.class);

        // Create and register the DispatcherServlet
        DispatcherServlet servlet = new DispatcherServlet(context);
        ServletRegistration.Dynamic registration = servletContext.addServlet("app", servlet);
        registration.setLoadOnStartup(1);
        registration.addMapping("/app/*");
    }
}

1.上下文(Context)层次结构

DispatcherServlet 期望有一个 WebApplicationContext(普通 ApplicationContext 的扩展)用于自己的配置。WebApplicationContext 有一个与 ServletContext 和与之相关的 Servlet 的链接。它也被绑定到 ServletContext,这样应用程序就可以使用 RequestContextUtils 上的静态方法来查询 WebApplicationContext,如果他们需要访问它的话。

对于许多应用程序,有一个单一的 WebApplicationContext 是简单的,也是足够的。也可以有一个上下文层次结构,一个根 WebApplicationContext 被多个 DispatcherServlet(或其他 Servlet)实例共享,每个实例都有自己的子 WebApplicationContext 配置。

根(root) WebApplicationContext 通常包含基础设施Bean,例如需要在多个 Servlet 实例中共享的数据存储库和业务服务。这些Bean有效地被继承,并且可以在 Servlet 特定的子 WebApplicationContext 中被重写(也就是重新声明),该 WebApplicationContext 通常包含给定 Servlet 的本地Bean。下面的图片显示了这种关系:

 下面的例子配置了一个 WebApplicationContext 的层次结构:

public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class<?>[] { RootConfig.class };
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[] { App1Config.class };
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/app1/*" };
    }
}

以下示例显示了等效的web.xml:

<web-app>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/root-context.xml</param-value>
    </context-param>

    <servlet>
        <servlet-name>app1</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/app1-context.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>app1</servlet-name>
        <url-pattern>/app1/*</url-pattern>
    </servlet-mapping>

</web-app>

2. 特殊的 Bean 类型

DispatcherServlet 委托给特殊的Bean来处理请求并呈现适当的响应。我们所说的 "特殊Bean" 是指实现框架契约的Spring管理的 Object 实例。这些实例通常有内置的约定,但你可以自定义它们的属性,并扩展或替换它们。

下表列出了由 DispatcherServlet 检测到的特殊Bean类:

Bean 类型说明

HandlerMapping

将一个请求和一个用于前后处理的拦截器列表一起映射到一个处理程序(handler)。该映射基于一些标准,其细节因 HandlerMapping 的实现而异。

两个主要的 HandlerMappin 实现是 RequestMappingHandlerMapping(支持 @RequestMapping 注解的方法)和 SimpleUrlHandlerMapping(维护 URI path pattern 到处理程序(handler)的明确注册)。

HandlerAdapter

帮助 DispatcherServlet 调用映射到请求的处理程序(handler),不管处理程序实际上是如何被调用的。例如,调用一个有注解的controller需要解析注解的问题。HandlerAdapter 的主要目的是将 DispatcherServlet 从这些细节中屏蔽掉。

ViewResolver

解决异常的策略,可能将它们映射到处理程序、HTML error 视图或其他目标。

ViewResolver

将处理程序返回的基于 String 的逻辑视图名称解析为实际的 View(视图),并将其渲染到响应。

LocaleResolver, LocaleContextResolver

解析客户端使用的 Locale,可能还有他们的时区,以便能够提供国际化的视图

ThemeResolver

解析你的web应用可以使用的主题(theme)--例如,提供个性化的布局。

MultipartResolver

在一些 multipart 解析库的帮助下,解析一个 multipart 请求(例如,浏览器表单文件上传)的抽象。

 FlashMapManager

存储和检索 "输入" 和 "输出" FlashMap,可用于将属性从一个请求传递到另一个请求,通常跨越重定向。

3. 网页MVC配置

应用程序可以声明在 特殊的 Bean 类型 中列出的处理请求所需的基础设施 Bean。 DispatcherServlet 检查 WebApplicationContext 中的每个特殊Bean。如果没有匹配的Bean类型,它将回到 DispatcherServlet.properties 中所列的默认类型。 在大多数情况下,MVC 配置 是最好的起点。它用Java或XML声明所需的Bean,并提供一个更高级别的配置回调(callback)API来定制它。 

4. Servlet 配置

在Servlet环境中,你可以选择以编程方式配置Servlet容器,作为一种选择,或者与 web.xml 文件相结合。下面的例子注册了一个 DispatcherServlet

import org.springframework.web.WebApplicationInitializer;

public class MyWebApplicationInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext container) {
        XmlWebApplicationContext appContext = new XmlWebApplicationContext();
        appContext.setConfigLocation("/WEB-INF/spring/dispatcher-config.xml");

        ServletRegistration.Dynamic registration = container.addServlet("dispatcher", new DispatcherServlet(appContext));
        registration.setLoadOnStartup(1);
        registration.addMapping("/");
    }
}

WebApplicationInitializer 是Spring MVC提供的一个接口,它可以确保你的实现被检测到并自动用于初始化任何Servlet 3容器。WebApplicationInitializer 的一个抽象基类实现名为 AbstractDispatcherServletInitializer,通过覆盖指定 Servlet 映射(mapping)和 DispatcherServlet 配置位置的方法,使得注册 DispatcherServlet 更加容易。

对于使用基于Java的Spring配置的应用程序,建议这样做,如下例所示:

public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[] { MyWebConfig.class };
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }
}

如果你使用基于XML的Spring配置,你应该直接从 AbstractDispatcherServletInitializer 扩展,如下例所示:

public class MyWebAppInitializer extends AbstractDispatcherServletInitializer {

    @Override
    protected WebApplicationContext createRootApplicationContext() {
        return null;
    }

    @Override
    protected WebApplicationContext createServletApplicationContext() {
        XmlWebApplicationContext cxt = new XmlWebApplicationContext();
        cxt.setConfigLocation("/WEB-INF/spring/dispatcher-config.xml");
        return cxt;
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }
}

AbstractDispatcherServletInitializer 还提供了一种方便的方法来添加 Filter 实例,并让它们自动映射到 DispatcherServlet,正如下面的例子所示:

public class MyWebAppInitializer extends AbstractDispatcherServletInitializer {

    // ...

    @Override
    protected Filter[] getServletFilters() {
        return new Filter[] {
            new HiddenHttpMethodFilter(), new CharacterEncodingFilter() };
    }
}

每个 filter 都根据其具体类型添加了一个默认名称(name),并自动映射到 DispatcherServlet

AbstractDispatcherServletInitializer 的 isAsyncSupported protected 方法提供了一个单一的地方来启用对 DispatcherServlet 和所有映射到它的 filter 的异步支持。默认情况下,这个标志被设置为 true

最后,如果你需要进一步定制 DispatcherServlet 本身,你可以复写 createDispatcherServlet 方法。

5. 流程(Processing)

DispatcherServlet 处理请求的方式如下:

在 WebApplicationContext 中声明的 HandlerExceptionResolver Bean被用来解决请求处理过程中抛出的异常。这些异常解析器允许自定义处理异常的逻辑

对于HTTP缓存支持,处理程序可以使用 WebRequest 的 checkNotModified 方法。你可以通过在 web.xml 文件的 Servlet 声明中添加 Servlet 初始化参数(init-param 元素)来定制单个 DispatcherServlet 实例。下表列出了支持的参数:

  • WebApplicationContext 被搜索并作为一个属性(attribute)绑定在请求(request)中,controller和进程中的其他元素可以使用。它默认被绑定在 DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE key 下。

  • locale 解析器被绑定到请求上,以便让流程中的元素在处理请求(渲染视图、准备数据等)时解析要使用的 locale。如果你不需要locale解析,你就不需要 locale 解析器(resolver)。

  • theme 解析器被绑定在请求上,以让诸如视图等元素决定使用哪个主题。如果你不使用主题,你可以忽略它。

  • 如果你指定了一个 multipart file 解析器,请求将被检查为 multipart file。如果发现了multipart,该请求将被包裹在一个 MultipartHttpServletRequest 中,以便由流程中的其他元素进一步处理。

  • 一个适当的处理程序(handler)被搜索到。如果找到一个处理程序,与该处理程序相关的执行链(预处理程序、后处理程序和 controller)被运行,以准备渲染的模型(model)。另外,对于有注解的 controller,响应可以被渲染(在 HandlerAdapter 中)而不是返回一个视图。

  • 如果有 model 返回,视图就会被渲染。如果没有返回 model(也许是由于预处理器或后处理器拦截了请求,也许是出于安全原因),就不会渲染视图,因为该请求可能已经被满足了。

Table 1. DispatcherServlet 初始化参数
参数说明

contextClass

实现 ConfigurableWebApplicationContext 的类,将由该Servlet实例化和本地配置。默认情况下,使用 XmlWebApplicationContext

contextConfigLocation

传递给上下文实例(由 contextClass 指定)的字符串,表示可以在哪里找到上下文。该字符串可能由多个字符串组成(使用逗号作为分隔符)以支持多个上下文。如果多个上下文位置的bean被定义了两次,那么最新的位置优先。

namespace

WebApplicationContext 的命名空间。默认为 [servlet-name]-servlet

throwExceptionIfNoHandlerFound

当一个请求没有找到处理程序(handler)时,是否会抛出 NoHandlerFoundException。然后可以用 HandlerExceptionResolver(例如,通过使用 @ExceptionHandler controller 方法)来捕获该异常,并像其他一样处理。

默认情况下,这被设置为 false,在这种情况下,DispatcherServlet 将响应状态设置为404(NOT_FOUND)而不引发异常。

请注意,​ 如果 default servlet handling 也被配置了, ​未解析的请求总是被转发到 default servlet,并且永远不会出现404。

 6. 路径匹配(Path Matching)

Servlet API将完整的请求路径作为 requestURI 公开,并进一步将其细分为 contextPathservletPath 和 pathInfo,其值因Servlet的映射方式而异。从这些输入中,Spring MVC 需要确定用于映射处理程序(handler)的查找路径,如果适用的话,应该排除 contextPath 和任何 servletMapping 前缀。

servletPath 和 pathInfo 是经过解码的,这使得它们不可能直接与完整的 requestURI 进行比较以得出 lookupPath,这使得有必要对 requestURI 进行解码。然而,这也引入了自己的问题,因为路径可能包含编码的保留字符,如 "/" 或 ";",在它们被解码后又会改变路径的结构,这也会导致安全问题。此外,Servlet容器可能会在不同程度上对 servletPath 进行规范化处理,这使得它进一步无法对 requestURI 进行 startsWith 比较。

这就是为什么最好避免依赖基于前缀的 servletPath 映射类型所带来的 servletPath。如果 DispatcherServlet 被映射为带有 "/" 的默认 Servlet,或者没有 "/*" 的前缀,并且Servlet容器是4.0以上的,那么Spring MVC就能够检测到Servlet映射类型,并完全避免使用 servletPath 和 pathInfo。在3.1的Servlet容器上,假设有相同的Servlet映射类型,可以通过MVC配置中的 路径(Path)匹配,提供一个 alwaysUseFullPath=true 的 UrlPathHelper 来实现。

幸运的是,默认的Servlet映射 "/" 是一个不错的选择。然而,仍然有一个问题,即 requestURI 需要被解码,以便能够与 controller 映射(mapping)进行比较。这也是不可取的,因为有可能对改变路径结构的保留字符进行解码。如果这些字符不被期望,那么你可以拒绝它们(就像Spring Security HTTP 防火墙),或者你可以将 UrlPathHelper 配置为 urlDecode=false,但 controller 映射需要与编码后的路径相匹配,这可能并不总是很好。此外,有时 DispatcherServlet 需要与另一个Servlet共享URL空间,可能需要按前缀进行映射。

在使用 PathPatternParser 和解析的pattern时,上述问题得到了解决,因为它可以替代 AntPathMatcher 的字符串路径匹配。PathPatternParser 从5.3版本开始就可以在Spring MVC中使用,并且从6.0版本开始默认启用。AntPathMatcher 需要对查找路径进行解码或对 controller 映射进行编码,与此不同的是,经过解析的 PathPattern 与称为 RequestPath 的路径的解析表示相匹配,一次一个路径段。这允许对路径段的值进行单独解码和消毒,而不存在改变路径结构的风险。Parsed PathPattern 还支持使用 servletPath 前缀映射,只要使用Servlet路径映射,并且前缀保持简单,即没有编码的字符

7. 拦截

所有 HandlerMapping 的实现都支持 handler 拦截器,当你想对某些请求应用特定的功能时,这些拦截器是非常有用的—​例如,检查一个 principal。拦截器必须实现 org.springframework.web.servlet 包中的 HandlerInterceptor,它有三个方法,应该可以提供足够的灵活性来进行各种预处理和后处理:

  • preHandle(..): 在实际 handler 运行之前
  • postHandle(..): handler 运行后
  • fterCompletion(..): 在整个请求完成后

preHandle(..) 方法返回一个boolean值。你可以使用这个方法来中断或继续执行链的处理。当这个方法返回 true 时,handler 执行链继续进行。当它返回 false 时, DispatcherServlet 认为拦截器本身已经处理了请求(例如,渲染了一个适当的视图),并且不继续执行其他拦截器和执行链中的实际 handler。

关于如何配置拦截器的例子,请参见MVC配置部分的 拦截器。你也可以通过使用个别 HandlerMapping 实现的setters来直接注册它们。

postHandle 方法在 @ResponseBody 和 ResponseEntity 方法中用处不大,因为这些方法的响应是在 HandlerAdapter 中和 postHandle 之前写入和提交的。这意味着对响应进行任何修改都太晚了,比如添加一个额外的 header。对于这种情况,你可以实现 ResponseBodyAdvice,并把它声明为一个 Controller Advice Bean,或者直接在 RequestMappingHandlerAdapter 上配置它

8. Exceptions

如果在请求映射过程中发生异常或从请求处理程序(如 @Controller)抛出异常, DispatcherServlet 会委托给处理程序异常解析器(HandlerExceptionResolver)Bean链来解析异常并提供替代处理,这通常是一个错误响应。

下表列出了可用的 HandlerExceptionResolver 实现:

HandlerExceptionResolver说明

SimpleMappingExceptionResolver

异常类名称和错误视图名称之间的映射。对于在浏览器应用程序中渲染错误页面非常有用。

​DefaultHandlerExceptionResolver

解析由Spring MVC引发的异常,并将其映射到HTTP状态码。也请参见替代的 ResponseEntityExceptionHandler 和​ Error 响应(Response)。

ResponseStatusExceptionResolver

解析带有 @ResponseStatus 注解的异常,并根据注解中的值将其映射到HTTP状态码。

ExceptionHandlerExceptionResolver

通过调用 @Controller 或 @ControllerAdvice 类中的 @ExceptionHandler 方法来解析异常

解析器(Resolver)链

你可以通过在Spring配置中声明多个 HandlerExceptionResolver Bean并根据需要设置它们的 order 属性来形成一个异常解析器链。order 属性越高,异常解析器的定位就越靠后。 HandlerExceptionResolver 的约定,它可以返回: 一个指向错误视图的 ModelAndView。 如果异常在解析器中被处理,则是一个空(empty)的 ModelAndView。 如果异常仍未被解决,则为 null,供后续的解析器尝试,如果异常仍在最后,则允许冒泡到Servlet容器中。 MVC 配置 自动为默认的Spring MVC异常、@ResponseStatus 注解的异常以及 @ExceptionHandler 方法的支持声明了内置解析器。你可以自定义该列表或替换它 

容器错误页面(Error Page)

如果一个异常仍然没有被任何 HandlerExceptionResolver 解析,因此,任其传播,或者如果响应状态被设置为错误状态(即4xx,5xx),Servlet容器可以在HTML中渲染一个默认的错误页面。为了定制容器的默认错误页面,你可以在 web.xml 中声明一个错误页面映射。下面的例子显示了如何做到这一点:

<error-page>
    <location>/error</location>
</error-page>

鉴于前面的例子,当一个异常冒出来或者响应有错误状态时,Servlet容器在容器内向配置的URL(例如,/error)进行 ERROR 调度。然后由 DispatcherServlet 进行处理,可能会将其映射到一个 @Controller,它可以被实现为返回一个带有model的错误视图名称或渲染一个JSON响应,如下例所示:

@RestController
public class ErrorController {

    @RequestMapping(path = "/error")
    public Map<String, Object> handle(HttpServletRequest request) {
        Map<String, Object> map = new HashMap<>();
        map.put("status", request.getAttribute("jakarta.servlet.error.status_code"));
        map.put("reason", request.getAttribute("jakarta.servlet.error.message"));
        return map;
    }
}

9. 视图(View)解析

Spring MVC定义了 ViewResolver 和 View 接口,让你在浏览器中渲染模型,而不需要绑定到特定的视图技术。ViewResolver 提供了视图名称和实际视图之间的映射。View 解决了在移交给特定视图技术之前的数据准备问题。

下表提供了关于 ViewResolver 层次结构的更多细节:

Table 3. ViewResolver 实现
ViewResolver说明

AbstractCachingViewResolver

AbstractCachingViewResolver 的子类会缓存它们所解析的视图实例。缓存可以提高某些视图技术的性能。你可以通过将 cache 属性设置为 false 来关闭缓存。此外,如果你必须在运行时刷新某个视图(例如,当 FreeMarker 模板被修改时),你可以使用 removeFromCache(String viewName, Locale loc) 方法。

UrlBasedViewResolver

ViewResolver 接口的简单实现,无需明确的映射定义就能实现逻辑视图名称与URL的直接解析。如果你的逻辑名称与你的视图资源的名称直接匹配,而不需要任意的映射,这就很合适。

InternalResourceViewResolver

UrlBasedViewResolver 的方便子类,支持 InternalResourceView(实际上是Servlets和JSP)和子类,如 JstlView。你可以通过使用 setViewClass(..) 为这个解析器生成的所有视图指定视图类。

FreeMarkerViewResolver

UrlBasedViewResolver 的方便子类,支持 FreeMarkerView 和它们的自定义子类。

ContentNegotiatingViewResolver

ViewResolver 接口的实现,根据请求文件名或 Accept 头来解析视图。

BeanNameViewResolver

ViewResolver 接口的实现,它将视图名称解释为当前应用程序上下文中的bean名称。这是一个非常灵活的变体,可以根据不同的视图名称混合和匹配不同的视图类型。每个这样的 View 都可以被定义为Bean,例如在XML或配置类中。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/412692.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【AIGC】GitHub Copilot 免费注册及在 PyCharm 中的安装使用

欢迎关注【youcans的 AIGC 学习笔记】原创作品 《GitHub Copilot 免费注册及在 VS Code 中的安装使用》 《GitHub Copilot 免费注册及在 PyCharm 中的安装使用》 GitHub Copilot 免费注册及在 PyCharm 中的安装使用1. GitHub Copilot 功能介绍2. 用户注册与申请2.1 个人订阅 Gi…

经典算法50例-无敌五十剑-算法五十重天

这里写目录标题1.汉诺塔2.费式数列3.巴斯卡三角形4.三色棋5.老鼠走迷官&#xff08;一&#xff09;6.老鼠走迷官&#xff08;二&#xff09;7.骑士走棋盘8.八皇后9.八枚银币10.生命游戏11.字串核对12.双色、三色河内塔13.背包问题14.蒙地卡罗法求 PI15.Eratosthenes筛选求质数1…

LeetCode——遍历序列构造二叉树

105从前序与中序遍历序列构造二叉树 给定两个整数数组 preorder 和 inorder &#xff0c;其中 preorder 是二叉树的先序遍历&#xff0c; inorder 是同一棵树的中序遍历&#xff0c;请构造二叉树并返回其根节点。 示例 1: 输入: preorder [3,9,20,15,7], inorder [9,3,15,2…

3.12、生成者消费者模型

3.12、生成者消费者模型1.生产者消费者模型介绍2.一个没有实现线程同步的生产者消费者模型1.生产者消费者模型介绍 生产者消费者模型是一种多线程的设计模式&#xff0c;用于解决生产者和消费者之间的同步和协作问题。 在生产者消费者模型中&#xff0c;生产者和消费者通过共享…

代码随想录算法训练营第五十五天 | 392.判断子序列、115.不同的子序列

打卡第55天。 今日任务 392.判断子序列115.不同的子序列 392.判断子序列 给定字符串 s 和 t &#xff0c;判断 s 是否为 t 的子序列。 字符串的一个子序列是原始字符串删除一些&#xff08;也可以不删除&#xff09;字符而不改变剩余字符相对位置形成的新字符串。&#xf…

哪个品牌的蓝牙耳机便宜耐用?内行公认四大便宜耐用的蓝牙耳机

蓝牙耳机发展至今&#xff0c;品牌众多&#xff0c;且各品牌旗下拥有无数不同价格的耳机&#xff0c;各自的主打优势又不一样。那么&#xff0c;哪个品牌的蓝牙耳机便宜耐用&#xff1f;下面&#xff0c;我来给大家推荐四款便宜耐用的蓝牙耳机&#xff0c;一起来看看吧。 一、…

【数据结构】第九站:树和二叉树

目录 一、树的概念及结构 1.树的概念 2.树的相关概念 3.树的表示 二、二叉树的概念及结构 1.概念 2.特殊的二叉树 3.二叉树的性质 三、二叉树的存储结构 一、树的概念及结构 1.树的概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个…

Redis缓冲区溢出及解决方案

缓冲区(buffer)&#xff0c;是内存空间的一部分。也就是说&#xff0c;在内存空间中预留了一定的存储空间&#xff0c;这些存储空间用来缓冲输入或输出的数据&#xff0c;这部分预留的空间就叫做缓冲区。 一、Redis缓冲区溢出影响 在Redis中&#xff0c;主要有三个场景用到了…

数据资产目录建设方法

以信息技术为核心的第四次经济革命使得全球经济进入到数字化转型时期&#xff0c;对于今天的企业来说&#xff0c; 数字化转型已经不是可做可不做的自选题&#xff0c; 而是必须付诸行动的必选题。 从数字化转型的实践经验中我们可以得知&#xff0c;企业的数据资产是企业数字…

Flink CDC 在京东的探索与实践

摘要&#xff1a;本文整理自京东资深技术专家韩飞&#xff0c;在 Flink Forward Asia 2022 数据集成专场的分享。本篇内容主要分为四个部分&#xff1a; 京东自研 CDC 介绍京东场景的 Flink CDC 优化业务案例未来规划点击查看直播回放和演讲 PPT 一、京东自研 CDC 介绍 京东自研…

pdf转换成word怎么转换?这个方法一学就会!

在日常工作和生活中&#xff0c;我们常常会遇到需要将PDF文件转换为Word文档的情况。这个过程有时候会令人感到麻烦和心累&#xff0c;需要特殊操作才能完成。但实际上&#xff0c;通过选择正确的方法&#xff0c;文件格式转换只需要几秒钟的时间。如果你感到不可思议&#xff…

ChatGPT-4 来了,附国内体验地址

chatgpt4是什么&#xff1f; 2022年12月&#xff0c;openAI发布了chatgpt模型&#xff0c;这个属于GPT-3.5系列模型中的一个。上个月&#xff0c;openAI又发布了超级升级版的GPT-4模型。所以&#xff0c;你想问的chatgpt4模型是指代GPT-4模型。 相比前一个版本&#xff0c;它…

智能硬件蓝牙配网方案概要

智能硬件开发系列 Google Protobuf 实践使用开发智能硬件蓝牙配网方案概要JNI开发必学C基础JNI开发必学C使用实践Android Studio 4.0.NDK项目开发详细教学Android NDK与JNI的区别有何不同&#xff1f;Android Studio 4.0.NDK .so库生成打包Android JNI的深度进阶学习Android S…

【Leetcode】题库-爽刷简单题(1)

目录 写在前面&#xff1a; 题目&#xff1a;67. 二进制求和 - 力扣&#xff08;Leetcode&#xff09; 解题思路&#xff1a; 代码&#xff1a; 过过过过过过啦&#xff01;&#xff01;&#xff01;&#xff01; 题目&#xff1a;83. 删除排序链表中的重复元素 - 力扣&a…

linux之jdk1.8环境安装与配置和Maven安装与配置

文章目录一、jdk1.8环境安装1、官网下载&#xff1a;<https://www.oracle.com/java/technologies/downloads/#java8>2、在usr文件夹下新建一个java文件夹3、解压完成后&#xff0c;将文件jdk文件传入到java目录下二、配置环境&#xff08;重点&#xff09;1、按 i 进行编…

docker环境下搭建rocketmq集群

rocketmq是一个分布式消息中间件&#xff0c;分布式的意思就是多台机器可以通过网络连接协同工作&#xff0c;因此rocketmq可以运行在多台机器上&#xff0c;以达到超越单机的服务能力。rocketmq的架构图如下所示 我们首先搭建一个最小的rocketmq集群&#xff0c;需要启动一个n…

MySQL安装配置与连接Navicat

本文详细记录win11系统MySQL安装配置与Navicat连接过程&#xff0c;每个知识点都解释了&#xff0c;不止安好了&#xff0c;你还学懂了&#xff01;你不知道选择哪个版本&#xff0c;不知道参数啥意思&#xff0c;不知道哪种安装方式好&#xff1f;这里都有答案&#xff01;&am…

最大二叉树

1题目 给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建: 创建一个根节点&#xff0c;其值为 nums 中的最大值。 递归地在最大值 左边 的 子数组前缀上 构建左子树。 递归地在最大值 右边 的 子数组后缀上 构建右子树。 返回 nums 构建的 最…

六、Locust之TaskSets详解

​ TaskSets是一种结构化测试分层网站/系统的方法。你可以在这里阅读更多关于它的信息。 1.TaskSet class ​ 如果你正在对一个以分层方式构建的网站进行性能测试&#xff0c;有章节和子章节&#xff0c;以同样的方式构建你的负载测试可能是有用的。 ​ 为了这个目的&#x…

全终端办公电子邮件集成方案

面临挑战 应用场景复杂&#xff0c;经常需要在不同终端进行切换&#xff0c;多屏、跨屏及移动办公要求高&#xff1b; 业务系统较多&#xff0c;需要同时支持多种业务的开展&#xff0c;对第三方应用集成及协同办公要求高&#xff1b; 对邮件系统的稳定及高效性要求高&#x…