转载:https://www.jianshu.com/p/3bb308c9bbcb

入门

本文将指导您完成一个简单的Dropwizard的Hello World项目。在此过程中,我们将解释各种底层库及其作用,以及Dropwizard中的重要概念,并建议一些组织技术来帮助您的项目能持续健康地增长。

概览

Dropwizard跨越了作为lib库和框架之间的界限。其目标是为生产就绪的Web应用程序所需的所有内容提供高性能,高可靠的实现。并且这些功能被封装到可重用的库中,因此您的应用程序仍然很精简和专注,从而缩短了产品上线时间和维护负担。

用于HTTP的Jetty

因为您的Web应用程序不能没有HTTP,Dropwizard使用Jetty ,一个令人难以置信的调优HTTP服务器直接嵌入到您的项目中。Dropwizard项目没有将应用程序交给复杂的应用程序服务器,而是有一个main方法运行HTTP服务器。将您的应用程序作为一个简单的过程运行,消除了生产中Java的许多令人讨厌的方面(没有PermGen问题,没有应用程序服务器配置和维护,没有神秘的部署工具,没有类加载器问题,没有隐藏的应用程序日志,没有尝试调整单个垃圾收集器与多个应用程序工作负载一起工作)并允许您使用所有现有的Unix进程管理工具。

用于REST的Jersey

为了构建RESTful Web应用程序,我们发现在功能或性能方面没有任何东西胜过Jersey(JAX-RS参考实现)。它允许您编写干净,可测试的类,这些类可以优雅地将HTTP请求映射到简单的Java对象。它支持流输出,矩阵URI参数,条件GET请求等等。

用于JSON的Jackson

在数据格式方面,JSON已成为网络的通用语言,而Jackson则是JVM上的JSON之王。除了快速闪电之外,它还有一个复杂的对象映射器,允许您直接导出域模型。

用于监控的Metrics

指标有助于分析问题,为您提供无与伦比的洞悉您的生产环境中的代码的行为。

其他集成的工具

除了Jetty,Jersey和Jackson之外,Dropwizard还包括一些库,可以帮助您更快速高效地开发。

  • Guava除了高度优化的不可变数据结构外,还提供了越来越多的类来加速Java的开发。
  • Logback和slf4j用于高性能和灵活的日志记录。
  • Hibernate Validator是JSR 349参考实现,它提供了一个简单的声明性框架,用于验证用户输入并生成有用且易于i18n的错误消息。
  • 在Apache的HttpClient的和Jersey客户端库允许都与其他Web服务低收入和高层次的互动。
  • JDBI是使用Java的关系数据库最直接的方法。
  • Liquibase是在整个开发和发布周期中检查数据库模式的好方法,应用高级数据库重构而不是一次性DDL脚本。
  • Freemarker和Mustache是简单的模板系统,适用于面向用户的更多应用程序。
  • Joda Time是一个非常完整,理智的库,用于处理日期和时间。

既然你已经了解到这了,那就让我们深入挖掘吧!

使用Maven进行设置

我们建议您将Maven用于新的Dropwizard应用程序。如果你是一个大型的Ant / Ivy,Buildr, Gradle,SBT,Leiningen或Gant粉丝,这很酷,但我们使用Maven,我们将在使用Maven时通过这个示例应用程序。如果您对Maven如何运作有任何疑问, Maven:The Complete Reference应该有你想要的东西。

你有三种选择:

  1. 使用dropwizard-archetype创建项目:

    mvn archetype:generate -DarchetypeGroupId=io.dropwizard.archetypes -DarchetypeArtifactId=java-simple -DarchetypeVersion=[REPLACE WITH A VALID DROPWIZARD VERSION]
    
  2. 看一下dropwizard-example

  3. 请按照以下教程了解如何将其包含在现有项目中

教程

首先,dropwizard.version使用当前版本的Dropwizard(1.3.5)向POM 添加属性:

<properties><dropwizard.version>INSERT VERSION HERE</dropwizard.version>
</properties>

dropwizard-core库添加为依赖项:

<dependencies><dependency><groupId>io.dropwizard</groupId><artifactId>dropwizard-core</artifactId><version>${dropwizard.version}</version></dependency>
</dependencies>

很好,这些足够了。我们现在已经建立了一个Maven项目,现在是时候开始编写真正的代码了。

创建配置类

每个Dropwizard应用程序都有自己的Configuration类的子类,它指定特定的环境参数。这些参数在YAML配置文件中指定,该文件被反序列化为应用程序配置类的实例。

我们将要构建的应用程序是一个高性能的Hello World服务。我们需要至少指定两件事:一个用于说出问候的模板和一个默认名称,以防用户未指定其名称。

这是我们的配置类的样子,这里有完整的示例:

package com.example.helloworld;import io.dropwizard.Configuration;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.hibernate.validator.constraints.NotEmpty;public class HelloWorldConfiguration extends Configuration {@NotEmptyprivate String template;@NotEmptyprivate String defaultName = "Stranger";@JsonPropertypublic String getTemplate() {return template;}@JsonPropertypublic void setTemplate(String template) {this.template = template;}@JsonPropertypublic String getDefaultName() {return defaultName;}@JsonPropertypublic void setDefaultName(String name) {this.defaultName = name;}
}

这里有很多知识点,所以让我们解释一下吧。

当从YAML文件反序列化该类时,它将从YAML对象中提取两个根级别字段:template,我们的Hello World说明的模板,以及defaultName要使用的默认名称。templatedefaultName都标注了@NotEmpty,所以如果YAML配置文件有任何空值或缺少template完全的信息会抛出异常,并且应用程序将无法启动。

templatedefaultName的getter和setter都有注释 @JsonProperty,这允许Jackson既可以从YAML文件反序列化属性,也可以序列化它。

注意

从YAML到您的应用程序Configuration实例的映射由Jackson完成。这意味着您的Configuration类可以使用Jackson的所有对象映射注释。验证@NotEmpty由Hibernate Validator处理,它具有 广泛的内置约束供您使用。

我们的YAML文件将如下所示,完整的示例yml在这里:

template: Hello, %s!
defaultName: Stranger

Dropwizard有许多比这更多的配置参数,但他们都有健全的默认值,这样可以保持你的配置文件小,重点突出。

因此,将YAML文件保存在您计划运行的jar的目录中(见下文)hello-world.yml,因为我们很快就会启动并运行,我们将需要它。接下来,我们正在创建我们的应用程序类!

创建应用程序类

结合项目的Configuration子类,Application子类构成了Dropwizard应用程序的核心。所述Application类启动各bundle和command命令,其提供基本功能在一起(稍后会详细介绍)。但是现在,我们 HelloWorldApplication看起来像这样:

package com.example.helloworld;import io.dropwizard.Application;
import io.dropwizard.setup.Bootstrap;
import io.dropwizard.setup.Environment;
import com.example.helloworld.resources.HelloWorldResource;
import com.example.helloworld.health.TemplateHealthCheck;public class HelloWorldApplication extends Application<HelloWorldConfiguration> {public static void main(String[] args) throws Exception {new HelloWorldApplication().run(args);}@Overridepublic String getName() {return "hello-world";}@Overridepublic void initialize(Bootstrap<HelloWorldConfiguration> bootstrap) {// nothing to do yet}@Overridepublic void run(HelloWorldConfiguration configuration,Environment environment) {// nothing to do yet}}

如您所见,HelloWorldApplication使用应用程序的配置类型HelloWorldConfiguration进行参数化。initialize方法用于在运行应用程序之前配置所需应用程序的各个方面,如bundle,配置源提供程序等。此外,我们还添加了一个static main方法,它将成为我们应用程序的入口点。现在,我们没有实现任何功能,所以我们的run方法有点无聊。让我们解决这个问题!

创建表示类

在我们进入Hello World应用程序的细节之前,我们需要停下来思考一下我们的API。幸运的是,我们的应用程序需要符合行业标准RFC 1149,它规定了Hello World的以下JSON表示:

{"id": 1,"content": "Hi!"
}

id字段是该问候的唯一标识符,并且content是该问候的文本表示。(值得庆幸的是,这是一个相当直接的行业标准。)

要对此表示进行建模,我们将创建一个表示类:

package com.example.helloworld.api;import com.fasterxml.jackson.annotation.JsonProperty;
import org.hibernate.validator.constraints.Length;public class Saying {private long id;@Length(max = 3)private String content;public Saying() {// Jackson deserialization}public Saying(long id, String content) {this.id = id;this.content = content;}@JsonPropertypublic long getId() {return id;}@JsonPropertypublic String getContent() {return content;}
}

这是一个非常简单的POJO,但有一些值得注意的事情。

首先,它是不可改变的。这使得Saying实例在多线程环境以及单线程环境中非常容易推理。其次,它使用JavaBeans标准idcontent属性。这允许Jackson将其序列化为我们需要的JSON。Jackson对象映射代码将id使用返回值填充JSON对象的字段#getId(),同样使用content#getContent()。最后,bean利用验证来确保内容大小不超过3。

注意

这里的JSON序列化由Jackson完成,它支持的不仅仅是像这样的简单JavaBean对象。除了复杂的注释集,您甚至可以编写自定义序列化程序和反序列化程序。

既然我们已经有了表示类,接下来学习下资源。

创建资源类

Jersey资源是Dropwizard应用程序的核心。每个资源类都与URI模板相关联。对于我们的应用程序,我们需要从URI /hello-world返回一个Saying 实例,因此我们的资源类如下所示:

package com.example.helloworld.resources;import com.example.helloworld.api.Saying;
import com.codahale.metrics.annotation.Timed;import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import java.util.concurrent.atomic.AtomicLong;
import java.util.Optional;@Path("/hello-world")
@Produces(MediaType.APPLICATION_JSON)
public class HelloWorldResource {private final String template;private final String defaultName;private final AtomicLong counter;public HelloWorldResource(String template, String defaultName) {this.template = template;this.defaultName = defaultName;this.counter = new AtomicLong();}@GET@Timedpublic Saying sayHello(@QueryParam("name") Optional<String> name) {final String value = String.format(template, name.orElse(defaultName));return new Saying(counter.incrementAndGet(), value);}
}

HelloWorldResource有两个注释:@Path@Produces@Path("/hello-world") 告诉Jersey,这个资源可以在URI上访问/hello-world,并且 @Produces(MediaType.APPLICATION_JSON)让Jersey的内容协商代码知道这个资源产生的表示形式是application/json

HelloWorldResource采用两个参数进行构造:template它用于产生问候语,当用户拒绝告诉我们他们的名字时使用defaultNameAtomicLong为我们提供了一种廉价,线程安全的方法来生成唯一(ish)ID。

警告

资源类由多个线程同时使用。一般来说,我们建议资源是无状态/不可变的,但重要的是要记住上下文。

#sayHello(Optional<String>)是这个类的核心,这是一个相当简单的方法。@QueryParam("name")注解告诉Jersey从请求参数字符串中把name参数赋值给方法中的name参数。如果客户端发送请求 /hello-world?name=DougiesayHello将被调用Optional.of("Dougie"); 如果name查询字符串中没有参数,sayHello则将调用Optional.absent()。(支持Guava的Optional是Dropwizard为Jersey的现有功能添加的一些额外的功能)

注意

如果客户端发送请求/hello-world?name=sayHello将被调用 Optional.of("")。这可能看起来很奇怪,但这遵循标准(应用程序可能具有不同的行为,具体取决于参数是否为空而不存在)。如果你希望/hello-world?name=返回“Hello,Stranger!”,可以用NonEmptyStringParam替换 Optional<String>参数。有关资源参数的更多信息,请参阅 文档

sayHello方法内部,我们递增计数器,使用格式化模板String.format(String,Object...) ,并返回一个Saying新实例。

因为sayHello带有注释@Timed,Dropwizard会自动将其调用的持续时间和速率记录为Metrics Timer。

一旦sayHello返回,Jersey就会获取Saying实例并查找可以将Saying实例写为application/json的转换类。Dropwizard内置了一个这样的转换类,允许使用Java对象生成JSON对象,JSON对象生成Java对象。该转换类生成JSON,客户端会收到200 OK 的内容类型为application/json的响应。

注册资源

不过,在这一切生效之前,我们需要回到HelloWorldApplication并注册这个新的资源类。在run方法中,我们可以从HelloWorldConfiguration实例中读取模板和默认名称 ,创建一个新HelloWorldResource实例,然后将其添加到应用程序的Jersey环境中:

@Override
public void run(HelloWorldConfiguration configuration,Environment environment) {final HelloWorldResource resource = new HelloWorldResource(configuration.getTemplate(),configuration.getDefaultName());environment.jersey().register(resource);
}

当我们的应用程序启动时,我们使用配置文件中的参数创建一个新的资源类实例,并将其交给它Environment,它就像应用程序可以执行的所有操作的注册表。

注意

Dropwizard应用程序可以包含许多资源类,每个资源类都对应于自己的URI。只需添加另一个@Path注释资源类,并使用新类的实例调用register方法即可。

在我们走得太远之前,我们应该为我们的应用添加健康检查。

创建健康检查

运行状况检查为您提供了一种向应用程序添加小测试的方法,以便您验证应用程序在生产中是否正常运行。我们强烈建议您的所有应用程序至少具有一组最小的运行状况检查。

注意

事实上,我们强烈推荐这一点,如果你忽略了为你的项目添加健康检查,Dropwizard会唠叨你。

由于格式化字符串在应用程序运行时不太可能失败(与数据库连接池不同),因此我们必须在这里想一些创意。我们将添加一个运行状况检查,以确保我们可以格式化提供的模板:

package com.example.helloworld.health;import com.codahale.metrics.health.HealthCheck;public class TemplateHealthCheck extends HealthCheck {private final String template;public TemplateHealthCheck(String template) {this.template = template;}@Overrideprotected Result check() throws Exception {final String saying = String.format(template, "TEST");if (!saying.contains("TEST")) {return Result.unhealthy("template doesn't include a name");}return Result.healthy();}
}

TemplateHealthCheck 检查两件事:提供的模板确实是格式良好的格式字符串,模板确实能生成具有给定名称的输出。

如果字符串不是格式良好的格式字符串(例如,有人意外地将Hello,%s%放入 配置文件中),那么String.format(String, Object...)将抛出一个IllegalFormatException ,并且运行状况检查将隐式失败。如果呈现的问候语不包括测试字符串,则运行状况检查将通过返回不健康的Result而显式失败。

添加健康检查

与Dropwizard中的大多数内容一样,我们使用适当的参数创建一个新实例并将其添加到Environment

@Override
public void run(HelloWorldConfiguration configuration,Environment environment) {final HelloWorldResource resource = new HelloWorldResource(configuration.getTemplate(),configuration.getDefaultName());final TemplateHealthCheck healthCheck =new TemplateHealthCheck(configuration.getTemplate());environment.healthChecks().register("template", healthCheck);environment.jersey().register(resource);
}

现在我们快要准备好了!

建立工程的JAR包

我们建议把Dropwizard应用程序构建为“单” JAR文件-一个.jar包含所有的运行应用程序所需的.class文件。这允许您构建单个可部署工件,您可以将其从开发环境升级到测试环境再到生产环境,而无需担心已安装库中的差异。要开始构建我们的Hello World应用程序作为单JAR,我们需要配置一个名为maven-shade的Maven插件。在文件的<build><plugins>部分中pom.xml,添加以下内容:

<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-shade-plugin</artifactId><version>2.3</version><configuration><createDependencyReducedPom>true</createDependencyReducedPom><filters><filter><artifact>*:*</artifact><excludes><exclude>META-INF/*.SF</exclude><exclude>META-INF/*.DSA</exclude><exclude>META-INF/*.RSA</exclude></excludes></filter></filters></configuration><executions><execution><phase>package</phase><goals><goal>shade</goal></goals><configuration><transformers><transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/><transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"><mainClass>com.example.helloworld.HelloWorldApplication</mainClass></transformer></transformers></configuration></execution></executions>
</plugin>

这将配置Maven在其package阶段执行以下操作:

  • 生成一个pom.xml文件,该文件不包含在单JAR中的库的依赖项的内容。
  • 从已签名的JAR中排除所有数字签名。如果不这样做,则Java认为签名无效,并且不会加载或运行您的JAR文件。
  • 整理JAR中META-INF/services的各种条目而不是覆盖它们。(如果没有那些,那么Dropwizard和Jersey都不会工作)
  • com.example.helloworld.HelloWorldApplication设为JAR MainClass。这将允许您使用java -jar运行JAR 。

警告

如果您的应用程序具有必须签名的依赖项(例如,JCA / JCE提供程序或其他可信库),则必须在 该库的maven-shade-plugin配置中添加排除项,并将该JAR包含在类路径中。

警告

由于Dropwizard使用Java ServiceLoader功能来注册和加载扩展,因此maven-shade-plugin的minimizeJar选项将导致应用程序JAR不能正常工作。

版本化您的JAR

Dropwizard也可以使用项目版本,如果它嵌入在JAR的清单中作为 Implementation-Version。要使用Maven嵌入此信息,请将以下内容添加到文件的 <build><plugins>部分pom.xml

<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-jar-plugin</artifactId><version>2.4</version><configuration><archive><manifest><addDefaultImplementationEntries>true</addDefaultImplementationEntries></manifest></archive></configuration>
</plugin>

在尝试确定您在计算机上部署的应用程序版本时,这非常方便。

完成配置后,进入项目目录并运行mvn package(或从IDE 运行package 目标)。你应该看到这样的东西:

[INFO] Including org.eclipse.jetty:jetty-util:jar:7.6.0.RC0 in the shaded jar.
[INFO] Including com.google.guava:guava:jar:10.0.1 in the shaded jar.
[INFO] Including com.google.code.findbugs:jsr305:jar:1.3.9 in the shaded jar.
[INFO] Including org.hibernate:hibernate-validator:jar:4.2.0.Final in the shaded jar.
[INFO] Including javax.validation:validation-api:jar:1.0.0.GA in the shaded jar.
[INFO] Including org.yaml:snakeyaml:jar:1.9 in the shaded jar.
[INFO] Replacing original artifact with shaded artifact.
[INFO] Replacing /Users/yourname/Projects/hello-world/target/hello-world-0.0.1-SNAPSHOT.jar with /Users/yourname/Projects/hello-world/target/hello-world-0.0.1-SNAPSHOT-shaded.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 8.415s
[INFO] Finished at: Fri Dec 02 16:26:42 PST 2011
[INFO] Final Memory: 11M/81M
[INFO] ------------------------------------------------------------------------

恭喜!你已经建立了你的第一个Dropwizard项目!现在是时候运行了!

运行您的应用程序

现在您已经构建了一个JAR文件,现在是时候运行它了。

在项目目录中,运行以下命令:

java -jar target/hello-world-0.0.1-SNAPSHOT.jar

您应该看到如下内容:

usage: java -jar hello-world-0.0.1-SNAPSHOT.jar[-h] [-v] {server} ...positional arguments:{server}               available commandsoptional arguments:-h, --help             show this help message and exit-v, --version          show the service version and exit

Dropwizard接受第一个命令行参数并将其分派给匹配的命令。在这种情况下,唯一可用的命令是server,将您的应用程序作为HTTP服务器运行。该 server命令需要一个配置文件,所以让我们继续为它提供 我们之前保存的YAML文件:

java -jar target/hello-world-0.0.1-SNAPSHOT.jar server hello-world.yml

您应该看到如下内容:

INFO  [2011-12-03 00:38:32,927] io.dropwizard.cli.ServerCommand: Starting hello-world
INFO  [2011-12-03 00:38:32,931] org.eclipse.jetty.server.Server: jetty-7.x.y-SNAPSHOT
INFO  [2011-12-03 00:38:32,936] org.eclipse.jetty.server.handler.ContextHandler: started o.e.j.s.ServletContextHandler{/,null}
INFO  [2011-12-03 00:38:32,999] com.sun.jersey.server.impl.application.WebApplicationImpl: Initiating Jersey application, version 'Jersey: 1.10 11/02/2011 03:53 PM'
INFO  [2011-12-03 00:38:33,041] io.dropwizard.setup.Environment:GET     /hello-world (com.example.helloworld.resources.HelloWorldResource)INFO  [2011-12-03 00:38:33,215] org.eclipse.jetty.server.handler.ContextHandler: started o.e.j.s.ServletContextHandler{/,null}
INFO  [2011-12-03 00:38:33,235] org.eclipse.jetty.server.AbstractConnector: Started BlockingChannelConnector@0.0.0.0:8080 STARTING
INFO  [2011-12-03 00:38:33,238] org.eclipse.jetty.server.AbstractConnector: Started SocketConnector@0.0.0.0:8081 STARTING

您的Dropwizard应用程序现在正在侦听8080应用程序请求和8081 管理请求的端口。如果按^C,应用程序将正常关闭,首先关闭服务器套接字,然后等待处理正在进行的请求,然后关闭进程本身。

大功告成,试一下! http://localhost:8080/hello-world

我们正在产生问候语,真棒。当然你的应用程序能做到的远远不止这些。使用Dropwizard的主要原因之一是它提供的开箱即用的操作工具,所有这些工具都可以在管理端口上 http://localhost:8081/找到。

如果访问指标资源 http://localhost:8081/metrics,则可以看到所有应用程序的指标都表示为JSON对象。

访问线程的资源 http://localhost:8081/threads可以让您快速获得在这个过程中运行的所有线程的线程转储。

提示

当Jetty工作线程处理传入的HTTP请求时,线程名称将设置为请求的方法和URI。在调试性能不佳的请求时,这非常有用。

在健康检查资源运行 健康检查类。你应该看到这样的东西:

* deadlocks: OK
* template: OK

template这是你的TemplateHealthCheck的结果,毫不奇怪地通过了。 deadlocks是一个内置的运行状况检查,它查找死锁的JVM线程并打印出列表(如果找到)。

下一步

嗯,恭喜。您已经准备好用于生产的Hello World应用程序(除了缺少测试),它能够每秒执行30,000-50,000个请求。希望您已经了解了Dropwizard如何将Jetty,Jersey,Jackson和其他稳定,成熟的库结合起来,为开发RESTful Web应用程序提供了一个非凡的平台。

Dropwizard还有很多内容(命令commands,绑定bundles,servlet,高级配置,验证validation,HTTP客户端,数据库客户端,视图等),所有这些都在用户手册中介绍。

官网 https://www.dropwizard.io/1.3.5/docs/getting-started.html

作者:程序员文集
链接:https://www.jianshu.com/p/3bb308c9bbcb
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

Dropwizard官方教程(一) 入门相关推荐

  1. Dropwizard官方教程(二) 核心

    转载:https://www.jianshu.com/p/f76b053705d9 Dropwizard核心 dropwizard-core模块为您提供了大多数应用程序所需的一切. 包括: Jetty ...

  2. 60分钟入门PyTorch,官方教程手把手教你训练第一个深度学习模型(附链接)

    来源:机器之心 本文约800字,建议阅读5分钟. 本文介绍了官方教程入门PyTorch的技巧训练. 近期的一份调查报告显示:PyTorch 已经力压 TensorFlow 成为各大顶会的主流深度学习框 ...

  3. 【译】Spring官方教程:使用STS的入门指南

    原文:Working a Getting Started guide with STS 译者:hanbin 校对:Mr.lzc 这个指南引导您使用 Spring Tool Suite (STS) 去构 ...

  4. python入门教程 官方-Python自学入门?

    如果你是零基础入门 Python 的话,建议初学者至少达到两个目标: 会用,理解. 会用 通过 Python 入门教程,学习 Python 的语法,熟悉 Python 标准库的使用. 目前 Pytho ...

  5. Asp.Net MVC4.0 官方教程 入门指南之一-- 入门介绍

    本教程将为您讲解使用微软的Visual Studio  2012 来建立一个ASP.NET MVC4 Web应用程序所需要的基础知识. 本示例将构建什么样的应用程序? 您将实现一个简单的电影管理应用程 ...

  6. 60分钟入门PyTorch,官方教程手把手教你训练第一个深度学习模型

    点击我爱计算机视觉标星,更快获取CVML新技术 本文转载自机器之心. 近期的一份调查报告显示:PyTorch 已经力压 TensorFlow 成为各大顶会的主流深度学习框架.想发论文,不学 PyTor ...

  7. TensorFlow 中文资源精选,官方网站,安装教程,入门教程,实战项目,学习路径。

    转载至:http://www.nanjixiong.com/thread-122211-1-1.html Awesome-TensorFlow-Chinese TensorFlow 中文资源全集,学习 ...

  8. java编程官方教程_Java编程入门官方教程

    图书特色:关键技能与概念:每章开头列出要介绍的技能和概念 专家解答:以问答形式提供附加信息和实用提示 编程练习:示范如何运用编程技能的紧贴实用的练习 自测题:每章后有一些测试题,以帮助读者扎实掌握Ja ...

  9. java编程入门pdf_Java 8编程入门官方教程(第6版) [(美)Schildt H.] 中文完整pdf扫描版[233MB]...

    Java8编程入门官方教程(第6版)针对新版JavaSE8对内容进行了全面更新.在畅销书作者Herbert Schildt(施密特)的帮助下,可以即刻开始学习Java程序设计的基础知识.<Jav ...

最新文章

  1. 中国科学家Cell重要评述文章: 宏基因组学成为病毒分类新方法
  2. Chrome插件开发进阶
  3. CloudStack各版本新特性
  4. 特征工程(2):特征构建
  5. wxWidgets:wxButton类用法
  6. 10个我最喜欢问程序员的面试问题
  7. mysql-5.7 持久化统计信息详解
  8. C# 委托链、多路广播委托
  9. Java中使用ArrayList的10个示例–教程
  10. 前端学习(2064):vue的生命周期函数有什么
  11. VMware为全球数字化基础架构提供原生安全
  12. Oracle创建函数
  13. 一台计算机重量,一台重量仅为1.85kg的游戏本 机械师F117毒药
  14. 推荐大家一个github上好的电子签名
  15. lch 儿童围棋课堂 初级篇1 ( (李昌镐 著))
  16. 关于新正方教务系统(湖北工程学院)的one day越权漏洞的说明
  17. 玩转Java 8 Stream 系列二进阶(Collectors.mapping 、Collectors.reducing、Collectors.summarizingInt等)
  18. iOS Core Animation 简明系列教程
  19. 【故障|监听】TNS-12518、TNS-00517和 Linux Error:32:Broken pipe
  20. 如何创建 CAB 文件和如何从文件、内存和资源中解压缩 CAB 文件

热门文章

  1. deno issue 事件中的那些quot;作恶者quot;们,前端黑名单又多了一批人
  2. LSTM正在消亡,谁在取代它?
  3. Javascript特效之模拟抽奖程序
  4. Pycharm Error loading package list:Status: 403错误解决方法
  5. Windows server 2012/2016_远程_没有远程桌面授权服务器可以提供许可证
  6. python爬取知乎话题广场_知乎一共有多少个话题?
  7. Unity Scroll View 滑动边界透明度渐变效果
  8. 赫夫曼树 和 赫夫曼树编码
  9. K8S之nodeName
  10. 企业级低代码中“自动化工作流”的5大优势!