框架为我们做了什么?

1. SpringBoot

1.1 web服务器

Spring Boot 的 web 服务器原理主要基于其嵌入式服务器的概念,这意味着它内嵌了一个 web 服务器,无需部署到外部服务器上。Spring Boot 内嵌了如 TomcatJettyUndertowservlet 容器

1.2 servlet

Servlet(Server Applet)是 Java EE(Java Enterprise Edition)规范的一部分,它是一个运行在服务器端的Java程序,用于生成动态网页。Servlet 容器(如 Tomcat)负责管理 Servlet 的生命周期和执行。以下是 Servlet 编程的基本原理:

  1. Servlet 接口:Servlet 必须实现 javax.servlet.Servlet 接口,该接口定义了五个方法:init(), service(), getServletConfig(), getServletInfo(), 和 destroy()

  2. Servlet 生命周期: Servlet 的生命周期从实例化开始,通过 init() 方法初始化,然后可以接收服务请求,最后通过 destroy() 方法销毁。

  3. 请求处理: Servlet 容器接收到客户端的请求后,会调用 Servlet 的 service() 方法,该方法根据请求的类型(如 GET 或 POST)决定调用 doGet()doPost() 方法。

  4. 多线程:Servlet 容器支持多线程,Servlet 容器可以创建多个 Servlet 实例或使用同一个 Servlet 实例的多个线程来处理并发请求。

  5. Servlet 映射: Servlet 映射定义了 URL 到 Servlet 的映射关系。映射可以在 web.xml 文件中配置,也可以使用注解(如 @WebServlet)。

  6. 请求和响应对象: Servlet 使用 HttpServletRequestHttpServletResponse 对象来与客户端进行交互。HttpServletRequest 包含了请求信息,而 HttpServletResponse 用于构造响应。

  7. 事件监听器: Servlet API 提供了多种事件监听器,如 ServletContextListenerHttpSessionListener 等,它们可以在 Servlet 生命周期的关键时刻执行特定的操作。

  8. 过滤器: Servlet 容器允许开发者实现 javax.servlet.Filter 接口来拦截请求和响应,进行预处理或后处理。

  9. 会话管理: Servlet API 通过 HttpSession 对象支持会话管理,允许在多个页面请求之间保持状态。

  10. 安全: Servlet 容器和 Servlet 可以配置安全性,如使用声明式和编程式安全控制对资源的访问。

  11. Servlet 3.0 异步处理:Servlet 3.0 引入了异步处理机制,允许 Servlet 方法异步执行,不阻塞容器线程,提高应用程序的并发处理能力。

  12. 依赖注入: Servlet 3.0 还支持依赖注入(DI),可以直接在 Servlet 中注入服务和管理 Bean。

Servlet 编程模型为构建基于 Java 的服务器端应用程序提供了一种简单、一致和可扩展的方式。通过 Servlet,开发者可以生成动态内容、处理表单提交、与数据库交互等。

1.3 不依赖框架可以怎么做?

不使用 Spring 框架,您仍然可以使用 Java 的标准库 java.netjavax.servlet 来提供 HTTP 接口。以下是两种常见的方法:

1.3.1 使用 java.net

Java 的 java.net 包提供了基本的网络通信能力,可以用来创建简单的 HTTP 服务器。以下是一个使用 ServerSocketSocket 来处理 HTTP 请求的简单示例:

import java.io.*;
import java.net.*;public class SimpleHttpServer {public static void main(String[] args) throws IOException {ServerSocket serverSocket = new ServerSocket(8080);System.out.println("Server is listening on port 8080...");while (true) {Socket socket = serverSocket.accept();BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));String inputLine;while ((inputLine = in.readLine()) != null) {if (!inputLine.isEmpty()) {break;}}// 简单的请求处理逻辑String response = "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\nHello, World!";out.write(response);out.flush();// 关闭连接in.close();out.close();socket.close();}}
}

这个示例创建了一个在 8080 端口上监听的 HTTP 服务器,对于每个连接,它发送一个简单的响应 “Hello, World!”。

1.3.2 使用 javax.servlet

如果您想使用更接近现代 Web 应用的方法,可以使用 javax.servlet 包来创建一个基于 Servlet 的 HTTP 服务器。以下是一个使用 HttpServletHttpServer 的示例:

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
import java.io.PrintWriter;public class MyServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.setContentType("text/plain");PrintWriter out = response.getWriter();out.println("Hello, World!");}public static void main(String[] args) throws Exception {HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0);Context context = server.createContext("/myapp", (servletRequest, servletResponse) -> {new MyServlet().doGet(servletRequest, servletResponse);});server.start();System.out.println("Server is started at port 8080...");}
}

这个示例创建了一个 Servlet,它在接收到 GET 请求时返回 “Hello, World!”。然后使用 HttpServer 来启动服务器,并定义了 URL 路径 /myapp 来映射到我们的 Servlet。

请注意,这些示例都是非常简单的基础示例,用于演示如何不使用 Spring 框架来提供 HTTP 接口。在实际开发中,您可能需要考虑更多的因素,比如请求解析、路由、错误处理、安全性、并发处理等。对于更复杂的应用,您可能需要使用更高级的 Web 服务器或框架。

2. Gin

2.1 web服务器

Gin 是一个用 Go 语言编写的 Web 框架,以其高性能和快速的开发效率而闻名。Gin 框架本身并不内嵌 Web 服务器,而是使用 Go 标准库中的 net/http 包来处理 HTTP 请求和响应。net/http 包提供了一个非常轻量级的 HTTP 服务器,它足以应对大多数 Web 应用的需求。

以下是 Gin 框架启动服务器的基本步骤:

  1. 创建路由: 使用 Gin 创建路由,定义应用程序的端点和对应的处理函数。

  2. 设置中间件: 可以设置中间件来处理跨域请求、日志记录、请求验证等。

  3. 启动服务器: 使用 gin.Default()gin.New() 创建一个 Gin 实例,然后调用 Run 方法来启动服务器。Run 方法接受一个字符串参数,表示服务器监听的地址和端口。

  4. 监听端口: Gin 使用 http.ListenAndServe 函数来监听指定的端口,等待客户端的连接。

  5. 处理请求: 当客户端发起请求时,Gin 会根据定义的路由规则将请求分发到对应的处理函数。

  6. 响应客户端: 处理函数执行完成后,Gin 会构造 HTTP 响应并发送给客户端。

下面是一个简单的 Gin 应用启动服务器的例子:

package mainimport ("github.com/gin-gonic/gin"
)func main() {router := gin.Default() // 创建一个默认的 Gin 路由器// 定义路由router.GET("/", func(c *gin.Context) {c.JSON(200, gin.H{
{            "message": "hello world"}})})// 启动服务器,默认在 8080 端口监听router.Run(":8080")
}

在这个例子中,Gin 应用定义了一个处理根 URL (/) 的路由,当访问这个路由时,它会返回一个 JSON 响应。然后,使用 router.Run(":8080") 启动服务器,监听 8080 端口。

2.2 不依赖框架如何提供HTTP接口?

在 Go 语言中,即使不使用 Gin 框架,也可以通过标准库 net/http 来提供 HTTP 接口。以下是如何使用 Go 的 net/http 包来创建一个简单的 HTTP 服务器并提供接口的示例:

package mainimport ("fmt""log""net/http"
)// 定义一个处理函数,它响应客户端请求
func myHandler(w http.ResponseWriter, r *http.Request) {// 设置响应的头部,指明返回的内容类型w.Header().Set("Content-Type", "text/plain")// 响应客户端请求fmt.Fprintf(w, "Hello, World! This is a simple HTTP interface.")
}func main() {// 设置路由,将"/"路径的请求映射到myHandler处理函数http.HandleFunc("/", myHandler)// 定义服务器监听的端口port := "8080"// 启动服务器,阻塞等待请求log.Printf("Server starting on port %s", port)if err := http.ListenAndServe(":"+port, nil); err != nil {log.Fatal("ListenAndServe error: ", err)}
}

在这个示例中,我们首先定义了一个 myHandler 函数,它接收 http.ResponseWriter*http.Request 作为参数。http.ResponseWriter 用于构造 HTTP 响应,*http.Request 包含了请求的信息。

然后,我们使用 http.HandleFunc 来设置路由,将根路径(“/”)的请求映射到 myHandler 函数。

最后,我们使用 http.ListenAndServe 来启动服务器,它接受一个端口号和一个处理器(这里是 nil,因为我们已经使用 HandleFunc 设置了处理器)。服务器将阻塞等待请求,并在接收到请求时调用相应的处理函数。

这个简单的服务器将响应所有到根路径的 GET 请求,并返回 “Hello, World! This is a simple HTTP interface.” 文本。

Go 的 net/http 包非常强大,它支持路由、中间件、文件服务、静态文件处理等,可以满足大多数 Web 服务的需求。对于更高级的用例,比如参数解析、JSON 响应、请求验证等,你可能需要编写更多的逻辑或使用第三方库。

3. MyBatis

3.1 MyBatis 原理

MyBatis 是一个半自动的持久层框架,用于在 Java 应用程序中简化数据库操作。它提供了简单的 API 和映射配置,以实现类型安全、对象关系映射(ORM)和 SQL 映射。以下是 MyBatis 的一些核心原理:
(1)SqlSessionFactorySqlSessionFactory 是 MyBatis 的核心对象,负责创建 SqlSession。它通过 XMLConfigBuilderXMLMapperBuilder 加载配置文件和映射文件来构建。

(2)SqlSessionSqlSession 是 MyBatis 工作的主要执行者,提供了执行命令对象(如 update, select, delete, insert)的方法,以及提交和回滚事务的功能。

(3)映射文件:MyBatis 使用 XML 或注解来映射 SQL 语句和 Java 类。这些映射文件定义了 SQL 语句和 Java 对象之间的映射关系。

(4)动态 SQL:MyBatis 支持动态 SQL,允许使用 if、choose、when、otherwise、trim、set 等元素来构建条件 SQL。

(5)参数映射:MyBatis 支持自动将 Java 对象的属性映射到 SQL 语句的参数上。

(6)结果映射:MyBatis 支持将查询结果映射到 Java 对象。可以通过 <resultMap> 元素定义复杂的结果映射。

(7)一级缓存和二级缓存

  • SqlSession 提供了一级缓存,它是会话级别的缓存,用于存储查询结果。
  • MyBatis 还支持二级缓存,它是全局的,可以被多个 SqlSession 共享。

(8)插件机制:MyBatis 允许开发者编写插件来拦截方法的执行,实现自定义逻辑,如分页、审计等。

(9)配置和映射的分离:MyBatis 支持将配置和映射分离,使得 SQL 映射可以独立于配置文件存在。

(10)事务管理:MyBatis 支持声明式事务和编程式事务管理。

(11)MyBatis Generator:MyBatis 提供了代码生成器,可以根据数据库表结构自动生成映射文件和 Java 模型类。

(12)MyBatis 3 增强的映射特性:MyBatis 3 引入了新的映射特性,如 @SelectProvider, @UpdateProvider, @InsertProvider, 和 @DeleteProvider 注解,允许使用 Java 代码提供 SQL 语句。

MyBatis 的设计哲学是提供足够的灵活性,让开发者可以编写高效的 SQL 语句,同时保持代码的简洁性和可维护性。通过 MyBatis,开发者可以避免大量的样板代码,并能够更精细地控制数据库操作。

3.2 不使用框架该怎么做?

使用 Java 的 JDBC API 直接操作数据库。JDBC 是 Java 语言中用来规范客户端程序如何访问数据库的应用程序接口,通过 JDBC 可以连接任何符合 SQL 数据库。

4. Gorm

4.1 Gorm原理

Gorm 是 Go 语言的一个对象关系映射(ORM)库,用于操作各种 SQL 数据库系统。它提供了一个简单易用的 API 来与数据库进行交互,同时隐藏了底层 SQL 语句的复杂性。以下是 Gorm 的一些核心原理:
(1)连接管理:Gorm 管理数据库连接,允许配置多个数据源,并在它们之间进行切换。
(2)自动迁移:Gorm 支持自动迁移功能,可以自动创建或修改数据库表结构以匹配 Go 结构体的定义。
(3)事务处理:提供了事务的支持,可以确保数据的一致性和完整性。
(4)关联处理:支持定义模型之间的关联关系,如一对一、一对多和多对多。
(5)预加载:支持预加载(Eager Loading)关联数据,以减少数据库查询次数。
(6)懒加载:支持懒加载(Lazy Loading)关联数据,按需从数据库加载数据。
(7)条件查询:支持链式调用,可以方便地构建复杂的查询条件。
(8)批量操作:支持批量创建、更新和删除记录。
(9)事务回滚:在发生错误时,可以回滚事务,保证数据操作的原子性。
(10)自定义操作:允许自定义 SQL 语句或使用原生数据库驱动的函数。
(11)日志记录:提供了详细的 SQL 日志记录功能,方便调试。
(12)结果映射:将查询结果映射到 Go 结构体中,简化了结果处理。
(13)插件系统:Gorm 拥有丰富的插件系统,可以扩展其功能,如添加新的数据库类型支持。
(14)接口和抽象:Gorm 提供了一系列接口和抽象,使得替换底层数据库驱动或自定义行为变得简单。
(15)兼容性:支持多种 SQL 数据库,如 MySQL, PostgreSQL, SQLite, SQL Server 等。

Gorm 的工作原理基于以下几个步骤:

  • 定义模型:使用 Go 的结构体定义数据模型,Gorm 会根据这些结构体来生成和操作数据库表。
  • 连接数据库:使用 Gorm 的 gorm.Open() 方法连接到数据库。
  • 创建/更新记录:使用 Create(), Save(), Update() 等方法操作数据库记录。
  • 查询记录:使用 Find(), First(), Scan() 等方法查询数据库。
  • 删除记录:使用 Delete() 方法从数据库中删除记录。
  • 关闭数据库连接:操作完成后,使用 Close() 方法关闭数据库连接。

Gorm 通过简化数据库操作,让开发者能够更专注于业务逻辑,而不是底层的 SQL 语句。同时,它保留了足够的灵活性,允许在需要时执行自定义的 SQL 操作。

4.2 不使用框架该怎么做?

如果不使用 Gorm 框架,你仍然可以使用 Go 语言的 database/sql 标准库来直接与数据库进行交互。以下是不使用 Gorm 框架实现数据库操作的一些基本步骤:
(1)导入包:导入 database/sql 包以及其他可能需要的包,如 fmt 用于格式化输出,log 用于记录日志。
(2)配置数据源:使用正确的驱动和连接字符串配置数据源。
(3)创建数据库连接:使用 sql.Open() 函数创建到数据库的连接。
(4)准备 SQL 语句:使用 db.Prepare() 准备 SQL 语句,这有助于提高性能并防止 SQL 注入。
(5)执行 SQL 语句:使用 Exec(), Query()QueryRow() 执行 SQL 语句。
(6)处理结果:使用 RowsRow 对象来迭代查询结果。
(7)错误处理:检查并处理可能发生的错误。
(8)关闭资源:使用 Close() 方法关闭 Rows, StmtDB 对象以释放资源。
(9)事务处理:使用 Tx 对象管理事务。

下面是一个简单的示例,演示了如何使用 database/sql 包执行一个查询并将结果打印出来:

package main
import ("database/sql""fmt""log"_ "github.com/go-sql-driver/mysql" // 导入 MySQL 驱动
)func main() {// 配置数据源dsn := "username:password@/dbname?charset=utf8&parseTime=True&loc=Local"db, err := sql.Open("mysql", dsn)if err != nil {log.Fatal(err)}defer db.Close()// 测试连接err = db.Ping()if err != nil {log.Fatal(err)}// 准备 SQL 语句rows, err := db.Query("SELECT id, name FROM users")if err != nil {log.Fatal(err)}defer rows.Close()// 处理结果var id intvar name stringfor rows.Next() {err = rows.Scan(&id, &name)if err != nil {log.Fatal(err)}fmt.Printf("ID: %d, Name: %s\n", id, name)}// 检查可能的错误err = rows.Err()if err != nil {log.Fatal(err)}
}

在这个示例中,我们首先导入了 MySQL 的驱动(需要使用 go get 命令安装),然后配置了数据源字符串(DSN),接着创建了数据库连接并测试了连接的有效性。之后,我们准备并执行了一个 SQL 查询,迭代结果集并打印出每行的数据。最后,我们检查并处理了可能发生的错误。

请注意,实际开发中还需要考虑 SQL 注入防护、更复杂的错误处理、日志记录、配置和查询参数化等因素。此外,你可能需要编写额外的代码来处理数据库迁移、模型定义、关联关系等高级功能。

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

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

相关文章

【鸿蒙学习笔记】创建自定义组件

官方文档&#xff1a;创建自定义组件 目录标题 自定义组件的基本结构&#xff11;・struct 自定义组件名 {...}&#xff20;ComponentEntry &#xff11;・ &#xff12;・ &#xff13;・ &#xff14;・ &#xff15;・ &#xff16;・ &#xff17;・ &#xff18;・ &…

Python | Leetcode Python题解之第206题反转链表

题目&#xff1a; 题解&#xff1a; # Definition for singly-linked list. # class ListNode: # def __init__(self, val0, nextNone): # self.val val # self.next next class Solution:def reverseList(self, head: Optional[ListNode]) -> Optio…

VulnHub靶场之DarkHole_1

1 信息收集 1.1 主机发现 arp-scan -l 主机IP地址为&#xff1a;192.168.1.17 1.2 端口和服务扫描 nmap -sS -sV -A -T5 -p- 192.168.1.17 开放22&#xff0c;80端口 1.3 目录扫描 dirsearch -u 192.168.1.17 2 渗透 2.1 访问端口 2.2 注册账号 暴力破解不现实&#…

Python爬取国家医保平台公开数据

国家医保服务平台数据爬取python爬虫数据爬取医疗公开数据 定点医疗机构查询定点零售药店查询医保机构查询药品分类与代码查询 等等&#xff0c;数据都能爬 接口地址&#xff1a;/ebus/fuwu/api/nthl/api/CommQuery/queryFixedHospital 签名参数&#xff1a;signData {dat…

【AI原理解析】-目标检测概述

目录 一、目标检测算法的分类 1. 基于传统方法的目标检测算法 2. 基于深度学习的目标检测算法 二、主要目标检测算法 1. R-CNN系列 2. YOLO系列 3. SSD 4. RetinaNet 三、目标检测算法的特点 四、评估指标 五、应用领域 一、目标检测算法的分类 目标检测算法主要分…

java版本ERP管理系统源码 Spring Cloud ERP_ERP系统_erp软件_ERP管理系统

在当今数字化时代&#xff0c;企业对高效、稳定且易于扩展的管理系统的需求日益增长。为了满足这一需求&#xff0c;我们精心打造了一款基于Java技术的ERP&#xff08;Enterprise Resource Planning&#xff09;管理系统。该系统充分利用了Spring Cloud Alibaba、Spring Boot、…

python-计算矩阵边缘元素之和(赛氪OJ)

[题目描述] 输入一个整数矩阵&#xff0c;计算位于矩阵边缘的元素之和。 所谓矩阵边缘的元素&#xff0c;就是第一行和最后一行的元素以及第一列和最后一列的元素。输入&#xff1a; 输入共 m 1 行。 第一行包含两个整数 m, n (1 < m,n < 100) &#xff0c;分别为矩阵的…

VDS虚拟导播切换台软件

VDS 导播软件是一款功能强大的虚拟导播系统软件&#xff0c;具有全媒体接入、播出内容丰富、调音台、快捷切播与导播键盘、云台控制等特点&#xff0c;同时支持向多个平台直播推流。以下是一些常见的 VDS 导播软件特点&#xff1a; 1. 全媒体接入&#xff1a;支持多种设备和网…

Ubuntu和Windows系统之Mamba_ssm安装

Mamba的论文&#xff1a;https://arxiv.org/abs/2312.00752 Mamba的github&#xff1a;https://github.com/state-spaces/mamba 一、Ubuntu安装 直接新建一个环境是最好的&#xff0c;不然很容易产生各种冲突 # 创建环境和相关包 conda create -n mamba python3.10.13 cond…

设计模式——程序员的武功招式

设计模式就是套路&#xff0c;就是武功招式。 碰到什么问题出什么招。 设计模式是软件行业几十年的应对问题的经验总结——武功招式总结。 大成境界是无招胜有招。 但是问题是无限的&#xff0c;对应的招式&#xff0c;你也可以创建&#xff0c;所以现在设计模式还在不断的诞生…

嵌入式Framebuffer面试题精要及参考答案

什么是Framebuffer?简述其在Linux系统中的作用。 Framebuffer,中文译作帧缓冲,是Linux内核提供的一种抽象设备接口,用于允许用户态的应用程序直接访问和操作显示设备的显存,从而实现图形的直接输出。在Linux系统中,Framebuffer扮演着连接硬件显卡和软件应用的关键角色。…

Linux 文件系统检查与修复:使用fsck、e2fsck等命令

Linux文件系统检查与修复&#xff1a;使用fsck、e2fsck等命令 引言 文件系统是操作系统中用于管理和存储文件的关键组件。然而&#xff0c;文件系统在使用过程中可能会出现各种问题&#xff0c;如数据损坏、文件丢失等。为了确保文件系统的完整性和稳定性&#xff0c;我们需要…

java-arraylist 源码分析 1

## 深入分析 Java 中的 ArrayList 源码 ArrayList 是 Java 集合框架中的一个重要类&#xff0c;它基于数组实现&#xff0c;提供了动态数组的功能。ArrayList 是一个非常常用的集合类&#xff0c;因为它在随机访问和遍历方面性能优越。本文将详细分析 ArrayList 的源码&#x…

spring cloud gateway客户端websocket断开连接,服务侧连接没有关闭的问题处理

之前在单体架构项目中使用了websocket主动推送消息的功能&#xff0c;后来改成了微服务架构&#xff0c;结果发现部分消息丢失&#xff0c;没能推送给客户端&#xff1b;深入排查发现服务端无法感知websocket连接状态&#xff0c;但是在单体架构里面是没这个问题的&#xff0c;…

Redis【超详细】

Redis 是一个基于内存的key-value结构的数据库 一、redis的安装 1.1、安装步骤 1&#xff09;安装Redis依赖 Redis是基于c语言编写的&#xff0c;因此需要安装对应的gcc环境 yum install -y gcc tcl 2&#xff09;进入/usr/local/src/目录上传并解压安装包 解压&#xf…

【APK】SDKManager运行后闪退

本地JDK已安装&#xff0c;且配置了环境变量&#xff0c;未安装 android studiio 问题描述&#xff1a;右键以管理员身份运行 SDKManager&#xff0c;终端窗口闪退 问题原因&#xff1a;未找到正确的Java路径 解决办法&#xff1a; 1.修改tools目录下的 android.bat 文件&am…

langchain 入门中篇:数据封装,Memory 封装

数据的处理流程可以看一张图来帮助理解 数据来源可以是网络&#xff0c;可以是邮件&#xff0c;可以是本地文件 经过 Document Loaders 加载&#xff0c;再在 Transform 阶段对文档进行 split, filter, translate, extract metadata 等操作&#xff0c;之后在 Embed 阶段进行向…

Keil用ST-LINK下载STM32程序后不自动运行

之后程序可以运行了&#xff0c;但是串口还没有输出&#xff0c;在debug模式下都是ok的。

加权 KNN 算法的原理与详解

加权kNN&#xff0c;k近邻算法的增强改进版本。 加权KNN算法 近邻算法&#xff08;k-Nearest Neighbors, kNN&#xff09;是一种用于分类和回归的非参数方法。它的基本思想是“看邻居”&#xff0c;即通过查找离目标点最近的 K 个数据点&#xff0c;来判断目标点的类别或数值。…

docker安装elasticesarch-head

安装 Elasticsearch-Head 通常涉及以下步骤&#xff1a; 拉取 Elasticsearch-Head 的 Docker 镜像。 运行 Elasticsearch-Head 容器并连接到 Elasticsearch 实例。 以下是具体的命令&#xff1a; 拉取 Elasticsearch-Head 的 Docker 镜像 docker pull mobz/elasticsearch-…