zoukankan      html  css  js  c++  java
  • 非常棒的Java REST服务器栈

    Dropwizard 是一个开源的Java框架,用于开发OPS友好、高性能的基于REST的后端。它是由Yammer开发的,来驱动基于JVM的后端。

    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方法。
     
    @Override
    public 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: OK
     
     
    6、创建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 Content
    Date: Sun, 10 Nov 2013 14:08:03 GMT
    Content-Type: application/json
     
    7、更新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/。
  • 相关阅读:
    sql server 纵横表的转换
    url参数的编码解码Demo
    SqlServer 列的增加和删除
    asp.net下ajax.ajaxMethod使用方法(转)
    js中document.all 的用法
    cookie跨域,跨目录访问及单点登录。
    错误记录:html隐藏域的值存字符串时出错
    .NET下用C#实现邮箱激活功能
    js与C#服务端 json数据交互
    sqlserver数据可空插入报错
  • 原文地址:https://www.cnblogs.com/skyay/p/4347413.html
Copyright © 2011-2022 走看看