Dropwizard简单入门

Dropwizard:一个简洁的RESTful Web框架

Dropwizard跨越了开发库与框架的界限,旨在为Web应用所需的功能提供高性能、可靠的实现。Dropwizard将这些功能抽象为可重用的开发库,因此应用程序可以保持精简与专注,从而大大减少产品面世的时间以及维护负担。

Jetty HTTP库

Web应用都离不开HTTP,Dropwizard使用Jetty HTTP库为项目嵌入HTTP服务器。与复杂的应用服务器不同,Dropwizard项目通过main方法加快HTTP服务器处理。在生产环境独立进程中运行Java应用程序会减少很多麻烦(没有PermGen问题,没有应用服务器配置和维护,没有神秘的部署工具、没有类加载器问题、没有隐藏的应用程序日期、没有多个应用程序负载的垃圾回收器调优)。不仅如此,你还可以使用现成的Unix进程管理工具。

Jersey REST库

我们发现,要构建RESTful Web应用程序,从性能和功能角度考虑JerseyJAX-RS参考实现)是最佳选择。你可以编写整洁、易于测试的类,将HTTP请求映射到简单的Java对象。Jersey REST库支持流输出、URI参数矩阵、条件GET请求等功能。

Jackson JSON库

如果说JSON是Web领域的通用数据格式,那么Jackson就是JVM平台JSON处理的王者。除了处理速度飞快,Jackson还支持复杂的对象映射器,可以直接导出领域模型。

Metrics度量库

Metrics库更加全面,它提供了无论伦比的视角,可以更好地了解代码在生产环境下的行为。

其它开发库

除了JettyJersey 和 Jackson,Dropwizard还包含了很多其它非常有帮助的开发库:

  • Guava:支持不可变数据结构,提供日益丰富的Java工具类加速开发。
  • Logback 和 slf4j 可以提供高效灵活的日志功能。
  • Hibernate ValidatorJSR-349_ 参考实现)提供了简洁、声明式的用户输入验证框架,生成非常有用支持i18n的错误信息。
  • Apache HttpClient 和 Jersey 客户端开发库提供了与其它Web服务的底层和高层交互。
  • JDBI:为Java关系数据库提供了最直接的方式交互。
  • Liquibase:在开发和发布周期中,为数据库schema提供全程检查。支持高层数据库重构,取代了一次性DDL脚本。
  • Freemarker 和 Mustache为面向用的应用程序提供了简单的模板系统。
  • Joda Time:完整强大的时间日期处理开发库。

简单示例

推荐使用Maven构建新的Dropwizard应用,首先,在POM中加入 dropwizard.version 属性及最新版本:

<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>

1. 新建Configuration类

每个DW应用都有他自己的子类:Configuration,这个类指定环境中特定的参数。这些参数在YAML类型的配置文件中被指定,其被反序列化为应用程序配置类的实例并验证。(这句话的意思就是这个配置文件中指定的参数,会被映射到我们项目的一个类)我们将要构建的是一个helloworld高性能服务。我们的一个要求就是我们需要能够在不同的环境中让它说hello,在开始之前我们需要指定至少两个内容:一个说hello的模板 还有一个默认的名字以防用户忘记指定。

package com.example.helloworld;

import com.example.helloworld.core.Template;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.collect.ImmutableMap;
import io.dropwizard.Configuration;
import io.dropwizard.db.DataSourceFactory;
import org.hibernate.validator.constraints.NotEmpty;

import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.util.Collections;
import java.util.Map;

public class HelloWorldConfiguration extends Configuration {
    @NotEmpty
    private String template;

    @NotEmpty
    private String defaultName = "Stranger";

    @Valid
    @NotNull
    private DataSourceFactory database = new DataSourceFactory();

    @NotNull
    private Map<String, Map<String, String>> viewRendererConfiguration = Collections.emptyMap();

    @JsonProperty
    public String getTemplate() {
        return template;
    }

    @JsonProperty
    public void setTemplate(String template) {
        this.template = template;
    }

    @JsonProperty
    public String getDefaultName() {
        return defaultName;
    }

    @JsonProperty
    public void setDefaultName(String defaultName) {
        this.defaultName = defaultName;
    }

    public Template buildTemplate() {
        return new Template(template, defaultName);
    }

    @JsonProperty("database")
    public DataSourceFactory getDataSourceFactory() {
        return database;
    }

    @JsonProperty("database")
    public void setDataSourceFactory(DataSourceFactory dataSourceFactory) {
        this.database = dataSourceFactory;
    }

    @JsonProperty("viewRendererConfiguration")
    public Map<String, Map<String, String>> getViewRendererConfiguration() {
        return viewRendererConfiguration;
    }

    @JsonProperty("viewRendererConfiguration")
    public void setViewRendererConfiguration(Map<String, Map<String, String>> viewRendererConfiguration) {
        final ImmutableMap.Builder<String, Map<String, String>> builder = ImmutableMap.builder();
        for (Map.Entry<String, Map<String, String>> entry : viewRendererConfiguration.entrySet()) {
            builder.put(entry.getKey(), ImmutableMap.copyOf(entry.getValue()));
        }
        this.viewRendererConfiguration = builder.build();
    }
}

当这个类被从YAML配置文件反序列化的时候,他会从YAML对象中获取两个根层次的变量:template 用来说helloworld的模板。defaultName 默认的名字。template和defaultName都用@NotEmpty被注释,所以在YAML配置文件中如果有空值或者忘了其中一者,异常将会被抛出,我们的应用将不会被启动。defaultName和template的get 和set 方法都被@JsonProperty标注,这不止允许jackson从YAML配置文件反序列化,同样允许它序列化。

然后我们创建一个YAML的配置文件,内容如下:

template: Hello, %s!
defaultName: Stranger

2. 新建Application类

结合我们项目中的Configuration子类,我们的Application的子类形成了我们DW的应用的核心,Application的子类把不同的提供各式各样功能的包和命令拉取到了一起。

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);
    }

    @Override
    public String getName() {
        return "hello-world";
    }

    @Override
    public void initialize(Bootstrap<HelloWorldConfiguration> bootstrap) {
        // nothing to do yet
    }

    @Override
    public void run(HelloWorldConfiguration configuration,
                    Environment environment) {
        // nothing to do yet
    }

}

正如我们所看到的,HelloWorldApplication使用应用程序的configuration进行参数化,(因为用了我们的HelloWorldConfiuration,而它是Configuration的子类),initialize方法用于配置应用在正式启动之前所需:包,配置源等,同时我们需要加入一个main方法,这是我们应用的入口,到目前为止,我们并没有实现任何的功能,所以我们的run方法有点无趣,让我们开始丰富它。

3. 新建Representation类

在我们开始继续我们的程序之前,我们需要停下来思考一下我们程序的API。幸运的是,我们的应用需要符合行业标准RFC 1149,它指定了helloworld saying的如下json表达形式:

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

id字段是唯一标识,content是文字内容。下面是representation实现,一个简单的POJO类:

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;
    }

    @JsonProperty
    public long getId() {
        return id;
    }

    @JsonProperty
    public String getContent() {
        return content;
    }
}

这是一个非常简单的POJO,但是有些需要注意的地方。首先,他是不可更改的。这使得saying在多线程环境和单线程环境非常容易被推理。其次,它使用java的JavaBean来保存id和content属性。这允许jackson把他序列化为我们需要的JSON。jackson对象的映射代码将会使用getId()返回的对象来填充JSON对象的id字段,content同理。最后,bean利用验证来确保内容不大于3。

4. 新建Resource类

Jersey资源是DW应用程序的主要内容,每个资源类都与URL相关联(这个很重要,后面有说),对于我们的应用程序来说,我们需要一个resources来通过url:/helloworld来返回新的Saying实例对象。

package com.example.helloworld.resources;

import com.example.helloworld.api.Saying;
import com.google.common.base.Optional;
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;

@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
    @Timed
    public Saying sayHello(@QueryParam("name") Optional<String> name) {
        final String value = String.format(template, name.or(defaultName));
        return new Saying(counter.incrementAndGet(), value);
    }
}

HelloWorldResource有两个声明:@Path和@Produces。@Path("/hello-world")告诉Jersey这个resource可以通过 "/hello-world"URL被访问。

@Produces(MediaType.APPLICATION_JSON)让Jersey的内容协商代码知道这个资源产生的是application/json.

HelloWorldResource构造器接收两个参数,创建saying的template和当用户没有指明名字时的默认名称,AtomicLong为我们提供一种线程安全,简易的方式去生成(ish)ID。sayHello方法是这个类的肉,也是一个非常简单的方法。@QueryParam("name")告诉Jersey把在查询参数中的name映射到方法中的name中。如果一个客户发送请求到:/hello-world?name=Dougie,sayHello 方法将会伴随Optional.of("Dougie")被调用。如果查询参数中没有name,sayHello将会伴随着Optional.absent()被调用。在sayHello方法里面,我们增加计数器的值,使用String.format来格式化模板,返回一个新的Saying实例。因为sayHello被@Timed注释,DW将会自动调用他的持续时间和速率记录为度量定时器。一旦sayHello返回,Jersey将会采用Saying的实例,并寻找一个提供程序类来将Saying实例写为:application/json。

5. 注册Resource

在这些正式工作之前,我们需要到HelloWorldApplication中,并将新的resouce加入其中,在run方法中我们可以读取到HelloWorldConfiguration的template和defaultName实例,创建一个新的HelloWorldResource实例,并将其加入到新的Jersey环境中。我们HelloWorldApplication中新的run方法如下:

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

当我们的应用启动的时候,我们使用配置文件中的参数创建一个新的资源类实例,并传递给environment.

转自:http://blog.csdn.net/qq_23660243/article/details/54406075 以及 http://hao.jobbole.com/dropwizard/

时间: 2024-08-02 09:28:35

Dropwizard简单入门的相关文章

正则表达式简单入门

 正则表达式简单入门    正则表达式在平常编程中有着大量的应用,对于任何一个想学习编程的人来说,正则表达式是一个必须掌握的知识. 废话不多说,下面先对正则表达式做一个简单的入门介绍,在后续的文章中,将会进行详细的介绍.    一.元字符 元字符一共有12个:$ ( ) [ { ? + * . ^ \ | 元字符有特殊的含义,如果要使用其字面值,则必须对其进行转义. 如: \$  \*  \( 等等 二.控制字符或不可打印字符 \a  警报 \e  退出 \f  换页 \n  换行 \r 

程序员,一起玩转GitHub版本控制,超简单入门教程 干货2

本GitHub教程旨在能够帮助大家快速入门学习使用GitHub,进行版本控制.帮助大家摆脱命令行工具,简单快速的使用GitHub. 做全栈攻城狮-写代码也要读书,爱全栈,更爱生活. 更多原创教程请关注头条号.每日更新.也可以添加小编微信:fullstackCourse.一起交流,获取最新全栈教程信息.因为FQ原因,不能下载客户端的同仁,可以关注后回复“GitHub客户端”获取安装软件. 上篇教程:GitHub这么火,程序员你不学学吗? 超简单入门教程 干货 GitHub概念部分出现了一丝纰漏.为

iBatis简单入门教程

iBatis 简介: iBatis 是apache 的一个开源项目,一个O/R Mapping 解决方案,iBatis 最大的特点就是小巧,上手很快.如果不需要太多复杂的功能,iBatis 是能够满足你的要求又足够灵活的最简单的解决方案,现在的iBatis 已经改名为Mybatis 了. 官网为:http://www.mybatis.org/ 搭建iBatis 开发环境: 1 .导入相关的jar 包,ibatis-2.3.0.677.jar .mysql-connector-java-5.1.6

Asp.Net MVC学习总结(一)——Asp.Net MVC简单入门

出处:http://www.cnblogs.com/SeeYouBug/p/6401737.html 一.MVC简单入门 1.1.MVC概念 视图(View) 代表用户交互界面,对于Web应用来说,可以概括为HTML界面,但有可能为XHTML.XML和Applet. 模型(Model) 表示用户对其数据的操作的一个封转.可以分为视图模型(view model)和领域模型(domain models),视图模型就是在视图与控制器之间传输数据的一个封转,而领域模型就是业务逻辑,后台数据模型等的一个集

Java日志系统---Logger之简单入门

Java 中自带的日志系统,今天抽空了解了一点,算是入了门,所以将自己的一些心得记录下来,以备日后查看,有兴趣的朋友,看到此文章,觉得有错误或需要添加的地方,请在下方评论留言,大家可以共同进步,谢谢:) Java中关于日志系统的API,在 java.util.logging 包中,在这个包中,Logger类很重要. Logger类是用来记录 某个级别的日志消息: 级别共分为以下几类,从上倒下,级别依次下降: SEVERE(严重)------级别最高 WARNING(警告) INFO CONFIG

响应式网页设计简单入门(强烈推薦!!!!)

响应式网页设计简单入门 Overview: 构造基本的HTML页面 动态加载样式表 Viewport 字体缩放 侧边栏 导航菜单 图片自适应 其他 总结 说到响应式网页设计(Responsive web design),最近在谷歌加上碰到个奇葩贴子,通过一个原始到无法再简单的网页Motherfucking Website及满屏幕的fuck道出了网页设计的真谛,这孩子不是个激进分子就是个报复社会型的货没错,虽然整篇文章就像是泼妇骂街,但我特么是笑着读完的.. 统计了下全文共用Fuck (包括fuc

Android HttpGet() 请求简单入门实例

HttpClient httpclient = new DefaultHttpClient(); String url = "http://example.com"; List<NameValuePair> params = new ArrayList<NameValuePair>(); params.add( new BasicNameValuePair( "param", "value" ) ); URI uri =

delphi指针简单入门

delphi指针简单入门:         看一个指针用法的例子:     1         var     2             X,   Y:   Integer;       //   X   and   Y   整数类型     3             P:   ^Integer;           //   P   指向整数类型的指针     4         begin     5             X   :=17; //   给   X   赋值     6

windows简单入门(1)

1.1 windows系统的关机 退出所有正在运行的程序,然后点击"关闭计算机"键关机,下面是"关闭计算机"的操作方法:                    图1-2 图1-1 1.2鼠标的操作 ① 鼠标指向一个图标 操作:移动鼠标,将其指针放到屏幕上某一对象上或位置 举例:将鼠标指针从屏幕中的某一处移动到"我的电脑"上,这样就指向了"我的电脑". ② 单击鼠标 操作:将鼠标指向某一对象后,快速按一下鼠标左键,并立即释放,这