构建易于扩展的REST风格的后端
什么是Dropwizard?Dropwizard?是一个开源的Java框架,用于开发OPS友好、高性能的基于REST的后端。它是由Yammer开发的,来驱动基于JVM的后端。 Dropwizard提供同类最佳的Java库到一个嵌入式应用程序包。它由以下部分组成:
除了上面提到的这几个,Dropwizard还使用了一些其他的库,你可以在这里找到完整的列表。 为什么是Dropwizard? 我决定学Dropwizard的原因有以下几点:
Github库 今天的演示应用程序的代码在GitHub上有:day13-dropwizard-mongodb-demo-app。 必备条件
Eclipse的安装很容易,只需要解压下载下来的包即可。如果是在Linux或者Mac机器上,开个命令行窗口,输入如下命令: $ tar -xzvf eclipse-jee-kepler-R-*.tar.gz Windows下,你解压到哪里,那里就会有一个eclipse文件夹,这样就可以直接操作了,当然你也可以创建执行文件的快捷方式到桌面。 第1步:创建一个新的Maven项目 打开Eclipse IDE,然后到项目工作区(project workspace)。要创建一个新的项目,转到? 第2步:更新pom.xml 现在更新 <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>
第3步:创建配置类 每个Dropwizard应用程序都有一个配置类,它指定特定的环境参数。文章后面会将如主机、端口和数据库名之类的MongoDB的配置参数添加给它。这个类扩展了? import com.yammer.dropwizard.config.Configuration; public class BlogConfiguration extends Configuration{ } 第4步:创建服务类 该Dropwizard项目由一个服务类自举。这个类将各种提供基本功能的捆绑和命令集合在一块,它还启动嵌入式Jetty服务器并延伸 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 { } } 上面的这些服务类可以:
第5步:写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资源类。它添加 上面提到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 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方法。 @Override public void run(BlogConfiguration configuration,Environment environment) throws Exception { environment.addResource(new IndexResource()); } 现在,可以将BlogService类??作为一个主程序来运行 $ curl http://localhost:8080 [{"id":"9bb43d53-5436-4dac-abaa-ac530c833df1","title":"Day 12: OpenCV--Face Detection for Java Developers",136); font-style:italic">"url":"https://www.openshift.com/blogs/day-12-opencv-face-detection-for-java-developers",136); font-style:italic">"publishedOn":1384090975372}] 现在可以通过点击 "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 } } }, 第6步:配置MongoDB 在 <dependency> <groupId>net.vz.mongodb.jackson</groupId> <artifactId>mongo-jackson-mapper</artifactId> <version>1.4.2</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 extends Configuration { @JsonProperty @NotEmpty public String mongohost = "localhost"; @JsonProperty @Min(1) @Max(65535) public int mongoport = 27017; @JsonProperty @NotEmpty public String mongodb = "mydb"; } 接下来,创建一个名为 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 mongodb.Mongo; yammer.dropwizard.Service; config.Bootstrap; 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()); } } 上面这段代码:
运行该应用程序作为主程序。你可以到本地的? ! 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/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/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: OK 第7步:创建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 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 Content Date: Sun,10 Nov 2013 14:08:03 GMT Content-Type: application/json 第8步:更新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(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,String.class); environment.addResource(new IndexResource(blogs)); environment.addResource(new BlogResource(blogs)); } "527f9806300462bbd300687e",153)">1384093702592}] 第9步:部署到云端这里有一篇文章,教你如何在OpenShift部署Dropwizard应用,点击这里。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |