非常棒的Java REST服务器栈
Dropwizard提供同类最佳的Java库到一个嵌入式应用程序包。它由以下部分组成:
嵌入式Jetty:每一个应用程序被打包成一个jar(而不是war)文件,并开始自己的嵌入式Jetty容器。没有任何war文件和外部servlet容器。
JAX-RS:Jersey(JAX-RS的参考实现)是用来写基于REST的Web服务的。
JSON:REST服务用的是JSON,Jackson库用来做所有的JSON处理。
日志:使用Logback和SLF4J完成。
Hibernate验证:Dropwizard使用Hibernate验证API进行声明性验证。
指标:Dropwizard支持监控使用标准库,它在监控代码方面有无与伦比的洞察力。
1、配置maven以导入jar包。<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.shekhar</groupId> <artifactId>blog</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>blog</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>com.yammer.dropwizard</groupId> <artifactId>dropwizard-core</artifactId> <version>0.6.2</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>1.7</source> <target>1.7</target> </configuration> </plugin> </plugins> </build></project>2、创建配置类每个Dropwizard应用程序都有一个配置类,它指定特定的环境参数。文章后面会将如主机、端口和数据库名之类的MongoDB的配置参数添加给它。这个类扩展了 com.yammer.dropwizard.config.Configuration类。import com.yammer.dropwizard.config.Configuration; public class BlogConfiguration extends Configuration{ }3、创建服务类该Dropwizard项目由一个服务类自举。这个类将各种提供基本功能的捆绑和命令集合在一块,它还启动嵌入式Jetty服务器并延伸com.yammer.dropwizard.Service。import com.yammer.dropwizard.Service;import com.yammer.dropwizard.config.Bootstrap;import com.yammer.dropwizard.config.Environment; public class BlogService extends Service<BlogConfiguration> { public static void main(String[] args) throws Exception { new BlogService().run(new String[] { "server" }); } @Override public void initialize(Bootstrap<BlogConfiguration> bootstrap) { bootstrap.setName("blog"); } @Override public void run(BlogConfiguration configuration, Environment environment) throws Exception { } }上面的这些服务类可以:有一个作为服务入口点的main方法。在main方法里面,创建BlogService的实例,并调用run方法。我们将服务器命令作为参数传递,服务器命令将启动嵌入式Jetty服务器。初始化方法在服务运行方法之前被调用。接下来,服务运行时将调用它的run方法,文章后面会将JAX-RS源加到这个方法里。4、写IndexResource写一个当GET请求指向“/” URL时会被调用的源,创建一个新的JAX-RS源(此资源将列出所有的博客),如下:import java.util.Arrays;import java.util.List; import javax.ws.rs.GET;import javax.ws.rs.Path;import javax.ws.rs.Produces;import javax.ws.rs.core.MediaType; import com.yammer.metrics.annotation.Timed; @Path("/")public class IndexResource { @GET @Produces(value = MediaType.APPLICATION_JSON) @Timed public List<Blog> index() { return Arrays.asList(new Blog("Day 12: OpenCV--Face Detection for Java Developers", "https://www.openshift.com/blogs/day-12-opencv-face-detection-for-java-developers")); }}上面这段代码是一个标准的JAX-RS资源类。它添加@ Path注释和定义index()方法,这个index()会返回一个博客集合,这些博客将被转换为JSON文档。上面提到IndexResource是用博客表示的。下面这段则表明该博客使用Hibernate验证器注解,以确保内容是有效的。例如,使用@URL注释,以确保只有合法的URL存储在MongoDB数据库。import java.util.Date;import java.util.UUID; import org.hibernate.validator.constraints.NotBlank;import org.hibernate.validator.constraints.URL; public class Blog { private String id = UUID.randomUUID().toString(); @NotBlank private String title; @URL @NotBlank private String url; private final Date publishedOn = new Date(); public Blog() { } public Blog(String title, String url) { super(); this.title = title; this.url = url; } public String getId() { return id; } public String getTitle() { return title; } public String getUrl() { return url; } public Date getPublishedOn() { return publishedOn; }}接下来,在服务类的run方法注册IndexResource。用下面的方式更新BlogService run方法。@Overridepublic void run(BlogConfiguration configuration, Environment environment) throws Exception { environment.addResource(new IndexResource());}现在,可以将BlogService类作为一个主程序来运行(右键点击>运行方式> Java应用程序),这将启动嵌入式Jetty容器,我们可以看到程序在 http://localhost:8080/ 里运行。$ curl http://localhost:8080 [{"id":"9bb43d53-5436-4dac-abaa-ac530c833df1","title":"Day 12: OpenCV--Face Detection for Java Developers","url":"https://www.openshift.com/blogs/day-12-opencv-face-detection-for-java-developers","publishedOn":1384090975372}]The administrative interface is available at http://localhost:8081/.现在可以通过点击“指标(Metrics)”检查IndexResource的指标,该数据是可用的JSON格式。"com.shekhar.blog.IndexResource" : { "index" : { "type" : "timer", "duration" : { "unit" : "milliseconds", "min" : 17.764, "max" : 17.764, "mean" : 17.764, "std_dev" : 0.0, "median" : 17.764, "p75" : 17.764, "p95" : 17.764, "p98" : 17.764, "p99" : 17.764, "p999" : 17.764 }, "rate" : { "unit" : "seconds", "count" : 1, "mean" : 7.246537731991882E-4, "m1" : 2.290184897291144E-12, "m5" : 3.551918562683463E-5, "m15" : 2.445031498756583E-4 } } },5、配置MongoDB在pom.xml 里加入 mongo-jackson-mapper 的依赖。<dependency> <groupId>net.vz.mongodb.jackson</groupId> <artifactId>mongo-jackson-mapper</artifactId> <version>1.4.2</version></dependency>用MongoDB数据库的详细信息(如主机、端口和数据库名等)更新BlogConfiguration类。import javax.validation.constraints.Max;import javax.validation.constraints.Min; import org.codehaus.jackson.annotate.JsonProperty;import org.hibernate.validator.constraints.NotEmpty; import com.yammer.dropwizard.config.Configuration; public class BlogConfiguration extends Configuration { @JsonProperty @NotEmpty public String mongohost = "localhost"; @JsonProperty @Min(1) @Max(65535) public int mongoport = 27017; @JsonProperty @NotEmpty public String mongodb = "mydb";}接下来,创建一个名为MongoManaged的新类,它将允许你在应用程序启动和停止时管理程序资源。这样就实现了com.yammer.dropwizard.lifecycle.Managed。import com.mongodb.Mongo;import com.yammer.dropwizard.lifecycle.Managed; public class MongoManaged implements Managed { private Mongo mongo; public MongoManaged(Mongo mongo) { this.mongo = mongo; } @Override public void start() throws Exception { } @Override public void stop() throws Exception { mongo.close(); } }在上面的代码中,关闭了stop方法中的MongoDB连接。下一步,写一个MongoHealthCheck来检查MongoDB的连接与否。import com.mongodb.Mongo;import com.yammer.metrics.core.HealthCheck; public class MongoHealthCheck extends HealthCheck { private Mongo mongo; protected MongoHealthCheck(Mongo mongo) { super("MongoDBHealthCheck"); this.mongo = mongo; } @Override protected Result check() throws Exception { mongo.getDatabaseNames(); return Result.healthy(); } }现在,更新BlogService类,将MongoDB的配置包含进来。package com.shekhar.blog; import com.mongodb.Mongo;import com.yammer.dropwizard.Service;import com.yammer.dropwizard.config.Bootstrap;import com.yammer.dropwizard.config.Environment; public class BlogService extends Service<BlogConfiguration> { public static void main(String[] args) throws Exception { new BlogService().run(new String[] { "server" }); } @Override public void initialize(Bootstrap<BlogConfiguration> bootstrap) { bootstrap.setName("blog"); } @Override public void run(BlogConfiguration configuration, Environment environment) throws Exception { Mongo mongo = new Mongo(configuration.mongohost, configuration.mongoport); MongoManaged mongoManaged = new MongoManaged(mongo); environment.manage(mongoManaged); environment.addHealthCheck(new MongoHealthCheck(mongo)); environment.addResource(new IndexResource()); } }上面这段代码:使用BlogConfiguration对象创建了一个新的Mongo实例。一个新的MongoManaged实例被创建并添加到环境中。健康检查被添加。运行该应用程序作为主程序。你可以到本地的 http://localhost:8081/healthcheck 健康检查页面去检验MongoDB是否在运行,如果MongoDB没有运行,会看到一个异常堆栈跟踪。! MongoDBHealthCheck: ERROR! can't call something : Shekhars-MacBook-Pro.local/192.168.1.101:27017/admin com.mongodb.MongoException$Network: can't call something : Shekhars-MacBook-Pro.local/192.168.1.101:27017/admin at com.mongodb.DBTCPConnector.call(DBTCPConnector.java:227) at com.mongodb.DBApiLayer$MyCollection.__find(DBApiLayer.java:305) at com.mongodb.DB.command(DB.java:160) at com.mongodb.DB.command(DB.java:183) at com.mongodb.Mongo.getDatabaseNames(Mongo.java:327) at com.shekhar.blog.MongoHealthCheck.check(MongoHealthCheck.java:17) at com.yammer.metrics.core.HealthCheck.execute(HealthCheck.java:195) at Caused by: java.io.IOException: couldn't connect to [Shekhars-MacBook-Pro.local/192.168.1.101:27017] bc:java.net.ConnectException: Connection refused at com.mongodb.DBPort._open(DBPort.java:228) at com.mongodb.DBPort.go(DBPort.java:112) at com.mongodb.DBPort.call(DBPort.java:79) at com.mongodb.DBTCPConnector.call(DBTCPConnector.java:218) ... 33 more * deadlocks: OK现在启动MongoDB,可以看到:* MongoDBHealthCheck: OK* deadlocks: OK6、创建BlogResource现在写BlogResource类,它负责创建博客条目。import java.util.ArrayList;import java.util.List; import javax.validation.Valid;import javax.ws.rs.Consumes;import javax.ws.rs.GET;import javax.ws.rs.POST;import javax.ws.rs.Path;import javax.ws.rs.Produces;import javax.ws.rs.core.MediaType;import javax.ws.rs.core.Response; import net.vz.mongodb.jackson.DBCursor;import net.vz.mongodb.jackson.JacksonDBCollection; import com.yammer.metrics.annotation.Timed; @Path("/blogs")@Produces(value = MediaType.APPLICATION_JSON)@Consumes(value = MediaType.APPLICATION_JSON)public class BlogResource { private JacksonDBCollection<Blog, String> collection; public BlogResource(JacksonDBCollection<Blog, String> blogs) { this.collection = blogs; } @POST @Timed public Response publishNewBlog(@Valid Blog blog) { collection.insert(blog); return Response.noContent().build(); }}下一步,更新BlogService run方法,将BlogResource也加进来。 @Override public void run(BlogConfiguration configuration, Environment environment) throws Exception { Mongo mongo = new Mongo(configuration.mongohost, configuration.mongoport); MongoManaged mongoManaged = new MongoManaged(mongo); environment.manage(mongoManaged); environment.addHealthCheck(new MongoHealthCheck(mongo)); DB db = mongo.getDB(configuration.mongodb); JacksonDBCollection<Blog, String> blogs = JacksonDBCollection.wrap(db.getCollection("blogs"), Blog.class, String.class); environment.addResource(new IndexResource()); environment.addResource(new BlogResource(blogs)); }将BlogService类作为一个Java应用程序运行。为了测试BlogResource,做一个curl请求:$ curl -i -X POST -H "Content-Type: application/json" -d '{"title":"Day 12: OpenCV--Face Detection for Java Developers","url":"https://www.openshift.com/blogs/day-12-opencv-face-detection-for-java-developers"}' http://localhost:8080/blogs HTTP/1.1 204 No ContentDate: Sun, 10 Nov 2013 14:08:03 GMTContent-Type: application/json7、更新IndexResource现在,更新IndexResource index()方法来从MongoDB获取所有的博客文件。import java.util.ArrayList;import java.util.List; import javax.ws.rs.GET;import javax.ws.rs.Path;import javax.ws.rs.Produces;import javax.ws.rs.core.MediaType; import net.vz.mongodb.jackson.DBCursor;import net.vz.mongodb.jackson.JacksonDBCollection; import com.yammer.metrics.annotation.Timed; @Path("/")public class IndexResource { private JacksonDBCollection<Blog, String> collection; public IndexResource(JacksonDBCollection<Blog, String> blogs) { this.collection = blogs; } @GET @Produces(value = MediaType.APPLICATION_JSON) @Timed public List<Blog> index() { DBCursor<Blog> dbCursor = collection.find(); List<Blog> blogs = new ArrayList<>(); while (dbCursor.hasNext()) { Blog blog = dbCursor.next(); blogs.add(blog); } return blogs; } }更新BlogService run方法将博客集合传递给IndexResource。 @Override public void run(BlogConfiguration configuration, Environment environment) throws Exception { Mongo mongo = new Mongo(configuration.mongohost, configuration.mongoport); MongoManaged mongoManaged = new MongoManaged(mongo); environment.manage(mongoManaged); environment.addHealthCheck(new MongoHealthCheck(mongo)); DB db = mongo.getDB(configuration.mongodb); JacksonDBCollection<Blog, String> blogs = JacksonDBCollection.wrap(db.getCollection("blogs"), Blog.class, String.class); environment.addResource(new IndexResource(blogs)); environment.addResource(new BlogResource(blogs)); }将BlogService类作为一个Java应用程序运行。为了测试BlogResource,做一个curl请求:$ curl http://localhost:8080 [{"id":"527f9806300462bbd300687e","title":"Day 12: OpenCV--Face Detection for Java Developers","url":"https://www.openshift.com/blogs/day-12-opencv-face-detection-for-java-developers","publishedOn":1384093702592}]8、部署到云端这里有一篇文章,教你如何在OpenShift部署Dropwizard应用,打开http://dmly.github.io/blog/2013/05/01/diy-java-app-server-on-openshift-so-far-so-good/。非常棒的Java REST服务器栈的更多相关文章
- [转]Java工程师技术栈--成神之路
一.基础篇 1.1 JVM 1.1.1. Java内存模型,Java内存管理,Java堆和栈,垃圾回收 http://www.jcp.org/en/jsr/detail?id=133http://if ...
- Java堆、栈和常量池以及相关String的详细讲解(经典中的经典) (转)
原文链接 : http://www.cnblogs.com/xiohao/p/4296088.html 一:在JAVA中,有六个不同的地方可以存储数据: 1. 寄存器(register). 这是最快的 ...
- 一个简单的Java web服务器实现
前言 一个简单的Java web服务器实现,比较简单,基于java.net.Socket和java.net.ServerSocket实现: 程序执行步骤 创建一个ServerSocket对象: 调用S ...
- Java堆、栈和常量池
摘录自 http://www.cnblogs.com/xiohao/p/4296088.html 1. 栈(stack)与堆(heap)都是Java用来在RAM中存放数据的地方.与C++不同,Java ...
- Java堆、栈和常量池以及相关String的详细讲解
一:在JAVA中,有六个不同的地方可以存储数据: 1. 寄存器(register). 这是最快的存储区,因为它位于不同于其他存储区的地方——处理器内部.但是寄存器的数量极其有限,所以寄存器由编译器根据 ...
- Java堆和栈详解
Java把内存分成两种,一种叫做栈内存,一种叫做堆内存 在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配.当在一段代码块中定义一个变量时,java就在栈中为这个变量分配内存空间 ...
- java堆、栈、堆栈的区别
1.栈(stack)与堆(heap)都是Java用来在Ram中存放数据的地方.与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆. 2. 栈的优势是,存取速度比堆要快,仅次于直接位于CP ...
- Java从服务器上获取时间,动态在jsp页面显示
Java获取服务器时间,动态显示到jsp页面,大家都是到Java只能获取一次,到页面的时间是静态的,不过通过js和Java的合作,巧妙地实现此功能 本人是给电视做系统,客户要求页面能显示时间,因为电视 ...
- 常用Java Web 服务器
Java Web应用程序需要部署在Java web服务器中运行,常用的Java Web服务器有Tomcat.GlassFish.WebLogic.JBoss.WebSphere.Jetty.JRun等 ...
随机推荐
- IOS回调机制——代理,通知中心以及Block
Xcode5.0正式版 IOS7和Xcode5正式版在昨天正式可以下载.IOS7不多说了,交互设计,界面风格,操作的简化程度都属于比较领先的水平. 这里来说说Xcode5正式版,和以前的Xcode5测 ...
- Sql Server 2005的1433端口打开和进行远程连接
参考地址:http://topic.csdn.net/u/20090828/16/e693935a-99b7-4090-a6bc-0123c91183eb.html 1.如何打开sql server ...
- 《Algorithms 4th Edition》读书笔记——2.4 优先队列(priority queue)-Ⅱ
2.4.2初级实现 我们知道,基础数据结构是实现优先队列的起点.我们可以是使用有序或无序的数组或链表.在队列较小时,大量使用两种主要操作之一时,或是所操作元素的顺序已知时,它们十分有用.因为这些实现相 ...
- POJ 3046 Ant Counting DP
大致题意:给你a个数字,这些数字范围是1到t,每种数字最多100个,求问你这些a个数字进行组合(不包含重复),长度为s到b的集合一共有多少个. 思路:d[i][j]——前i种数字组成长度为j的集合有多 ...
- 第11讲- Android中进程及其优先级
第11讲Android中进程及其优先级 进程与线程: 进程:操作系统结构的基础,资源分配的最小单元,一个操作系统包括多个进程: 线程:线程存在于进程当中,是操作系统调试执行的最小单元,一个进程包括多个 ...
- sleep()函数的的意义
===============WINDOWS平台下:====================== 关于VOID Sleep(DWORD dwMilliseconds);函数,许多人都觉得,它是告诉系统 ...
- 迭代 Iterate
迭代:指按照某种顺序逐个访问列表中的每一项.比如:for语句 逐个访问: lst = ['q', 'i', 'w', 's', 'i', 'r'] for i in lst: print (i), # ...
- (HYSBZ)BZOJ 1588 营业额统计
营业额统计 Time Limit: 5000MS Memory Limit: 165888KB 64bit IO Format: %lld & %llu Description 营业额 ...
- 安卓Menu键的问题
近期开发中有须要Menu键,结果发现了一个非常尴尬的问题.我的測试机上有Menu键.可是測试平板上没有,队友的測试机上竟然也没有Menu键.这着实有些尴尬... 上网谷歌之后才发现问题所在: 仅仅有在 ...
- iOS开发之让你的应用“动”起来
概览在 iOS中随处都可以看到绚丽的动画效果,实现这些动画的过程并不复杂,今天将带大家一窥iOS动画全貌.在这里你可以看到iOS中如何使用图层精简非交互 式绘图,如何通过核心动画创建基础动画.关键帧动 ...