gradle下Eureka 源码编译安装部署

最近在折腾springCloud,所以第一步就是安装部署Eureka,在网上找了几篇文章折腾了半天,终于搞定,怕以后忘记继续踩坑,所以把这两篇纪录下来。
转载地址:http://www.cnblogs.com/lifuping/p/5663127.html
Netflix开源的Eureka 是使用Gradle 构建的,所以我们也使用Gradle来编译它

所需环境
Eclipse , Gradle , Tomcat ,git 这些插件如果己经安装可直接跳过到Eureka 服务器的步骤

Eclispe
下载官网 https://www.eclipse.org/ 下载下来安装即可,过程省略
本人使用的是:Version: Neon Release (4.6.0) 版本

Gradle
1、下载Gradle https://services.gradle.org/distributions/gradle-2.14-all.zip
2、添加环境变量GRADLE_HOME,添加值为 C:\gradle-2.9-bin\gradle-2.9;(注意根据自己的实际安装路径修改)
3、PATH环境变量中添加%GRADLE_HOME%/bin;
4、验证,命令行中输入gradle -v,查看是否配置正确,正确会输出gradle的版本信息;

Gradle eclipse 插件:
1.eclipse中依次打开“Help”–》“Eclipse Marketplace”,在搜索栏中输入“buildship”进行搜索;

2.点击install,等待安装完成,按照提示重启eclipse即可。
3.安装成功后,可以在Window–>Show View–>Others…中和File–>New–> Other…中看到增加的Gradle选项。
4、设置Eclipse 中Gradle User Home 为环境变量中的路径。

Git
本人使用Eclipse 自带的Git 插件,所以无需再安装,如果不使用Eclispe的也可以自己下载安装,过程省略

Eureka 服务器

从 github 获取 Eureka 源码:
1、eclipse ->import

2、

3、 输入: https://github.com/Netflix/eureka.git

按下一步完成源码下载

4、将Eureka 以Gradle 方式导入eclipse

5、指定git下载eureka源码的目录

6、导入完成后如下图所示

7、 正式编译 Eureka

安装过Gradle eclipse 插件就会显示 Gradle Tasks , 如果没显示就在window—>show view –>other中就面版显示出来

右键运行war 打包, 打包可能会出现 nebula.netflixoss 插件找不到,修改如下三处就能下载该插件

还有可能出现其它插件找不到,修改如下

再次运行war 打包,这时应该可以打包成功

按照源码编译方式打包并没有将 jsp ,css 等打包进去,部署完后访问http://localhost:8080/eureka 可能无法看到eureka 界面,
所以还需要修改eureka-server 这个工程,将resources 也跟eureka-server 一起打包

Eureka 部署到Tomcat

将war 包的名称修改一下 如下图,放入 tomcat webapps 下,

启动tomcat , 启动过程中有可能报异常 Cannot execute request on any known server 这个是正常的,启动的时候会去找其他的 server,
找不到,过一会就自己启动了,等待五分钟左右,访问 http://localhost:8080/eureka

说明 Eureka Server 部署成功

1. 查看 Linux 相关信息 版本查看# cat /etc/issueCentOS release 6.5 (Final) 位数查看# getconf LONG_BIT64 第 2 – 4 步是 Eureka Server war 包的构建,如果你嫌自己构建麻烦可以去 http://mvnrepository.com/artifact/com.netflix.eureka/eureka-server 下载一个,比如作者下载的是 eureka-server-1.1.134.war,然后跳过 2 – 4 步直接进入第 5 步。 2. 安装 git# yum install git 查看安装结果# git –versiongit version 1.7.1# which git/usr/bin/git 3. 安装 gradle 安装 Gradle 要求实现好了 JDK(关于 Linux 上 JDK 的安装参考《如何在 64 位 linux 机器上安装 jdk1.6?》)。Gradle 自带 Groovy 库,已有安装好的 Groovy 将被 Gradle 忽视。 然后去官网下载 gradle-1.12-bin.zip(大小 41 MB)到 /root/kdf 目录:http://www.gradle.org/downloads# unzip gradle-1.12-bin.zip# cp -r ~/kdf/gradle-1.12 /usr/local/gradle-1.12# vi /etc/profile 在末尾添加以下几行:[plain] view plain copy
print?

《gradle下Eureka 源码编译安装部署》 在CODE上查看代码片
《gradle下Eureka 源码编译安装部署》 派生到我的代码片

export GRADLE_HOME=/usr/local/gradle-1.12
export PATH=$PATH:$GRADLE_HOME/bin

    保存退出,然后执行**# source /etc/profile**        验证环境变量:**# echo $PATH**/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin:/usr/java/jdk1.7.0_60/bin:/usr/local/gradle-1.12/bin        验证 gradle 是否安装成功:**# gradle -v**------------------------------------------------------------Gradle 1.12------------------------------------------------------------Build time:   2014-04-29 09:24:31 UTCBuild number: noneRevision:     a831fa866d46cbee94e61a09af15f9dd95987421Groovy:       1.8.6Ant:          Apache Ant(TM) version 1.9.3 compiled on December 23 2013Ivy:          2.2.0JVM:          1.7.0_60 (Oracle Corporation 24.60-b09)OS:           Linux 2.6.32-431.el6.x86_64 amd64        输出结果中显示了我们安装的 Gradle 的版本以及本地环境配置信息,证明安装成功。        **4. 构建 Eureka 服务器**        从 github 获取 Eureka 源码:**# git clone https://github.com/Netflix/eureka.git**        在存放源码的路径下执行以下命令以构建 Eureka 服务器:**# cd eureka/# ./gradlew clean build**        成功后在 ./eureka-server/build/libs/ 目录下找到 war 包。        **5. 安装 tomcat**        安装 Eureka 服务器要求事先安装好了 Tomcat。去 [http://tomcat.apache.org/](http://tomcat.apache.org/) 下载你想要的版本,比如作者下载的是 [apache-tomcat-6.0.41.tar.gz](http://mirrors.hust.edu.cn/apache/tomcat/tomcat-6/v6.0.41/bin/apache-tomcat-6.0.41.tar.gz),大小 7 MB。**# tar zxvf apache-tomcat-6.0.41.tar.gz# cp -r apache-tomcat-6.0.41 /usr/local/tomcat# /usr/local/tomcat/bin/startup.sh**        其他电脑客户端访问 http://serverIP:8080,如果小猫没出来,在服务器执行**# curl http://localhost:8080**        有 Tomcat 管理界面 HTML 文字输出,说明没有开放服务器防火墙 8080 端口,开放该端口或者直接关掉防火墙。        **6. 部署 Eureka server# /usr/local/tomcat/bin/shutdown.sh# cp eureka-server-1.1.134.war /usr/local/tomcat/webapps/eureka.war# /usr/local/tomcat/bin/startup.sh**        Tomcat 启动以后,其他电脑客户端访问 http://serverIP:8080/eureka,404。查看 /usr/local/tomcat/logs/catalina.out,发现有警告信息:2014-07-03 09:47:00,614 WARN  com.netflix.config.util.ConfigurationUtils:165 [main] [loadFromPropertiesFile] Unable to load properties fileorg.apache.commons.configuration.ConfigurationException: Unable to load the configuration from the URL file:/usr/local/tomcat/webapps/eureka/WEB-INF/classes/eureka-${environment}-${region}.properties at org.apache.commons.configuration.DefaultFileSystem.getInputStream(DefaultFileSystem.java:84) at org.apache.commons.configuration.AbstractFileConfiguration.load(AbstractFileConfiguration.java:323) at org.apache.commons.configuration.AbstractFileConfiguration.load(AbstractFileConfiguration.java:234) at org.apache.commons.configuration.AbstractFileConfiguration.<init>(AbstractFileConfiguration.java:197) at org.apache.commons.configuration.PropertiesConfiguration.<init>(PropertiesConfiguration.java:285) at com.netflix.config.util.OverridingPropertiesConfiguration.<init>(ConfigurationUtils.java:267) at com.netflix.config.util.ConfigurationUtils.loadFromPropertiesFile(ConfigurationUtils.java:160) at com.netflix.config.util.ConfigurationUtils.getConfigFromPropertiesFile(ConfigurationUtils.java:196) at com.netflix.config.util.ConfigurationUtils.getPropertiesFromFile(ConfigurationUtils.java:214) at com.netflix.config.ConfigurationManager.getPropertiesFromFile(ConfigurationManager.java:431) at com.netflix.config.ConfigurationManager.loadCascadedProperties(ConfigurationManager.java:288) at com.netflix.config.ConfigurationManager.loadCascadedPropertiesFromResources(ConfigurationManager.java:268) at com.netflix.eureka.DefaultEurekaServerConfig.init(DefaultEurekaServerConfig.java:93) at com.netflix.eureka.DefaultEurekaServerConfig.<init>(DefaultEurekaServerConfig.java:75) at com.netflix.eureka.EurekaBootStrap.initEurekaEnvironment(EurekaBootStrap.java:130) at com.netflix.eureka.EurekaBootStrap.contextInitialized(EurekaBootStrap.java:88) at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4210) at org.apache.catalina.core.StandardContext.start(StandardContext.java:4709) at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:799) at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:779) at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:583) at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:943) at org.apache.catalina.startup.HostConfig.deployWARs(HostConfig.java:778) at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:504) at org.apache.catalina.startup.HostConfig.start(HostConfig.java:1317) at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:324) at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:142) at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1065) at org.apache.catalina.core.StandardHost.start(StandardHost.java:822) at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1057) at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:463) at org.apache.catalina.core.StandardService.start(StandardService.java:525) at org.apache.catalina.core.StandardServer.start(StandardServer.java:754) at org.apache.catalina.startup.Catalina.start(Catalina.java:595) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:289) at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:414)Caused by: java.io.FileNotFoundException: /usr/local/tomcat/webapps/eureka/WEB-INF/classes/eureka-${environment}-${region}.properties (No such file or directory) at java.io.FileInputStream.open(Native Method) at java.io.FileInputStream.<init>(FileInputStream.java:146) at java.io.FileInputStream.<init>(FileInputStream.java:101) at sun.net.www.protocol.file.FileURLConnection.connect(FileURLConnection.java:90) at sun.net.www.protocol.file.FileURLConnection.getInputStream(FileURLConnection.java:188) at java.net.URL.openStream(URL.java:1037) at org.apache.commons.configuration.DefaultFileSystem.getInputStream(DefaultFileSystem.java:80) ... 39 more        这是找不到 eureka-${environment}-${region}.properties 配置文件**# /usr/local/tomcat/bin/shutdown.sh # vi /usr/local/tomcat/webapps/eureka/WEB-INF/classes/eureka-server.properties**        将最后一行 @next=eureka-${environment}-${region}.properties        去掉。        此外,/usr/local/tomcat/logs/catalina.out 在上述警告后边还有以下错误:2014-07-03 09:47:01,920 ERROR com.netflix.discovery.DiscoveryClient:1015 [main] [makeRemoteCall] Can't get a response from http://localhost/eureka/v2/apps/Can't contact any eureka nodes - possibly a security group issue?com.sun.jersey.api.client.ClientHandlerException: org.apache.http.conn.HttpHostConnectException: Connection to http://localhost refused at com.sun.jersey.client.apache4.ApacheHttpClient4Handler.handle(ApacheHttpClient4Handler.java:184) at com.sun.jersey.api.client.filter.GZIPContentEncodingFilter.handle(GZIPContentEncodingFilter.java:120) at com.sun.jersey.api.client.Client.handle(Client.java:648) at com.sun.jersey.api.client.WebResource.handle(WebResource.java:670) at com.sun.jersey.api.client.WebResource.access$200(WebResource.java:74) at com.sun.jersey.api.client.WebResource$Builder.get(WebResource.java:503) at com.netflix.discovery.DiscoveryClient.getUrl(DiscoveryClient.java:1389) at com.netflix.discovery.DiscoveryClient.makeRemoteCall(DiscoveryClient.java:960) at com.netflix.discovery.DiscoveryClient.makeRemoteCall(DiscoveryClient.java:909) at com.netflix.discovery.DiscoveryClient.getAndStoreFullRegistry(DiscoveryClient.java:757) at com.netflix.discovery.DiscoveryClient.fetchRegistry(DiscoveryClient.java:653) at com.netflix.discovery.DiscoveryClient.<init>(DiscoveryClient.java:237) at com.netflix.discovery.DiscoveryClient.<init>(DiscoveryClient.java:169) at com.netflix.discovery.DiscoveryManager.initComponent(DiscoveryManager.java:84) at com.netflix.eureka.EurekaBootStrap.initEurekaEnvironment(EurekaBootStrap.java:159) at com.netflix.eureka.EurekaBootStrap.contextInitialized(EurekaBootStrap.java:88) at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4210) at org.apache.catalina.core.StandardContext.start(StandardContext.java:4709) at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:799) at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:779) at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:583) at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:943) at org.apache.catalina.startup.HostConfig.deployWARs(HostConfig.java:778) at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:504) at org.apache.catalina.startup.HostConfig.start(HostConfig.java:1317) at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:324) at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:142) at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1065) at org.apache.catalina.core.StandardHost.start(StandardHost.java:822) at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1057) at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:463) at org.apache.catalina.core.StandardService.start(StandardService.java:525) at org.apache.catalina.core.StandardServer.start(StandardServer.java:754) at org.apache.catalina.startup.Catalina.start(Catalina.java:595) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:289) at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:414)Caused by: org.apache.http.conn.HttpHostConnectException: Connection to http://localhost refused at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:190) at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:151) at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:125) at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:640) at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:479) at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:906) at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:827) at com.sun.jersey.client.apache4.ApacheHttpClient4Handler.handle(ApacheHttpClient4Handler.java:170) ... 39 moreCaused by: java.net.ConnectException: Connection refused at java.net.PlainSocketImpl.socketConnect(Native Method) at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:339) at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:200) at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:182) at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392) at java.net.Socket.connect(Socket.java:579) at org.apache.http.conn.scheme.PlainSocketFactory.connectSocket(PlainSocketFactory.java:127) at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:180) ... 46 more        这是 Tomcat 默认端口是 8080,而 Eureka 默认为 80。本文示例暂时用 8080,所以**# vi /usr/local/tomcat/webapps/eureka/WEB-INF/classes/eureka-client.properties**        将 eureka.port=80 改为 eureka.port=8080。**# vi /usr/local/tomcat/webapps/eureka/WEB-INF/classes/eureka-client-test.properties**        将eureka.serviceUrl.defaultZone=http://localhost/eureka/v2/eureka.serviceUrl.default.defaultZone=http://localhost/eureka/v2/        改为eureka.serviceUrl.defaultZone=http://localhost:8080/eureka/v2/eureka.serviceUrl.default.defaultZone=http://localhost:8080/eureka/v2/        重启 Tomcat**# /usr/local/tomcat/bin/startup.sh# tail -f /usr/local/tomcat/logs/catalina.out**        或者直接查看 catalina.out,发现有以下错误:2014-07-03 14:33:05,484 ERROR com.netflix.discovery.DiscoveryClient:1015 [main] [makeRemoteCall] Can't get a response from http://localhost:8080/eureka/v2/apps/Can't contact any eureka nodes - possibly a security group issue?com.sun.jersey.api.client.ClientHandlerException: java.net.SocketTimeoutException: Read timed out at com.sun.jersey.client.apache4.ApacheHttpClient4Handler.handle(ApacheHttpClient4Handler.java:184) at com.sun.jersey.api.client.filter.GZIPContentEncodingFilter.handle(GZIPContentEncodingFilter.java:120) at com.sun.jersey.api.client.Client.handle(Client.java:648) at com.sun.jersey.api.client.WebResource.handle(WebResource.java:670) at com.sun.jersey.api.client.WebResource.access$200(WebResource.java:74) at com.sun.jersey.api.client.WebResource$Builder.get(WebResource.java:503) at com.netflix.discovery.DiscoveryClient.getUrl(DiscoveryClient.java:1389) at com.netflix.discovery.DiscoveryClient.makeRemoteCall(DiscoveryClient.java:960) at com.netflix.discovery.DiscoveryClient.makeRemoteCall(DiscoveryClient.java:909) at com.netflix.discovery.DiscoveryClient.getAndStoreFullRegistry(DiscoveryClient.java:757) at com.netflix.discovery.DiscoveryClient.fetchRegistry(DiscoveryClient.java:653) at com.netflix.discovery.DiscoveryClient.<init>(DiscoveryClient.java:237) at com.netflix.discovery.DiscoveryClient.<init>(DiscoveryClient.java:169) at com.netflix.discovery.DiscoveryManager.initComponent(DiscoveryManager.java:84) at com.netflix.eureka.EurekaBootStrap.initEurekaEnvironment(EurekaBootStrap.java:159) at com.netflix.eureka.EurekaBootStrap.contextInitialized(EurekaBootStrap.java:88) at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4210) at org.apache.catalina.core.StandardContext.start(StandardContext.java:4709) at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:799) at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:779) at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:583) at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:1079) at org.apache.catalina.startup.HostConfig.deployDirectories(HostConfig.java:1002) at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:506) at org.apache.catalina.startup.HostConfig.start(HostConfig.java:1317) at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:324) at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:142) at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1065) at org.apache.catalina.core.StandardHost.start(StandardHost.java:822) at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1057) at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:463) at org.apache.catalina.core.StandardService.start(StandardService.java:525) at org.apache.catalina.core.StandardServer.start(StandardServer.java:754) at org.apache.catalina.startup.Catalina.start(Catalina.java:595) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:289) at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:414)Caused by: java.net.SocketTimeoutException: Read timed out at java.net.SocketInputStream.socketRead0(Native Method) at java.net.SocketInputStream.read(SocketInputStream.java:152) at java.net.SocketInputStream.read(SocketInputStream.java:122) at org.apache.http.impl.io.AbstractSessionInputBuffer.fillBuffer(AbstractSessionInputBuffer.java:166) at org.apache.http.impl.io.SocketInputBuffer.fillBuffer(SocketInputBuffer.java:90) at org.apache.http.impl.io.AbstractSessionInputBuffer.readLine(AbstractSessionInputBuffer.java:281) at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:92) at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:62) at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:254) at org.apache.http.impl.AbstractHttpClientConnection.receiveResponseHeader(AbstractHttpClientConnection.java:289) at org.apache.http.impl.conn.DefaultClientConnection.receiveResponseHeader(DefaultClientConnection.java:252) at org.apache.http.impl.conn.AbstractClientConnAdapter.receiveResponseHeader(AbstractClientConnAdapter.java:219) at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:300) at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:127) at org.apache.http.impl.client.DefaultRequestDirector.tryExecute(DefaultRequestDirector.java:712) at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:517) at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:906) at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:827) at com.sun.jersey.client.apache4.ApacheHttpClient4Handler.handle(ApacheHttpClient4Handler.java:170) ... 39 more        这个正常的,启动的时候会去找其他的 server,找不到,过一会就自己启动了(这时候我们去访问 http://serverIP:8080 应该看不到那只小猫)。        等待五分钟左右,访问 http://serverIP:8080,可以看到小猫页面。访问 http://serverIP:8080/eureka/,看到以下界面:
    原文作者:蹦跶君
    原文地址: https://www.jianshu.com/p/c3e725119802
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞