DropWizard--轻量级REST开发框架初次搭建

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/linfujian1999/article/details/76713875

之前用的IDE是spring的STS,这次还是选它;
Maven来导入dropwizard及管理项目;

这里的例子完全是按照dropwizard官网 入门实例来做的,官网讲的比较详细和规范,建议英文好的童鞋可以不用看这篇,去官网看一下。

一、
首先打开我的IDE,并构建maven项目,官网上说了构建的三种可替换方式,我这里用了我自己的构建方式,

新建一个maven project,选择 add Archetype,依次Group id、Artifact id及version。
这里写图片描述

点击确认后在maven的archetype中多了一个上述的类型。

二、
ok,选择上述的archetype,依次填入你要构建的项目的groupId(我的是com.example)、artifactId(我的helloworld)以及项目name(我的是HelloWorld,这个名字会是分别加上appliacation和configuration的你的启动类和配置类的名字 ,如下图中的HelloWorldApplication和HelloWorldConfiguration两个类),随即导入一个新的dropwizard maven管理的项目,大体结构如下:

这里写图片描述

其实maven管理的优点在于:你导入dropwizard的archetype后,整个项目的结构及pom文件中所依赖的package及plugins都不用你自己去添加了,真的省了好多事情,所以和springboot一样被叫做轻量级框架嘛。

三、配置pom.xml
官网上详细讲述了pom.xml的配置,但是这里pom的所有配置从你构建maven应用后都自动给你配置好了,当然如果你不满意可以自行填删,这里根据官网的介绍讲一下pom的几个组成及作用:

<?xml version="1.0" encoding="UTF-8"?>
<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/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <prerequisites>
        <maven>3.0.0</maven>
    </prerequisites>

    <groupId>com.example</groupId>
    <artifactId>helloworld</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>HelloWorld</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <dropwizard.version>1.0.0</dropwizard.version> //版本号后边会引用
        <mainClass>com.example.helloworld.HelloWorldApplication</mainClass> //这个mainClass后边会引用
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>io.dropwizard</groupId>
                <artifactId>dropwizard-bom</artifactId>
                <version>${dropwizard.version}</version>//引用
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>//导入dropwizard的核心部分
            <groupId>io.dropwizard</groupId>
            <artifactId>dropwizard-core</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            //正常导出的是war文件,这里为了导出jar文件(fat jar),需要添加这个plugin。
            <plugin>
                <artifactId>maven-shade-plugin</artifactId>
                <version>2.4.1</version>
                <configuration>
 //创建一个无依赖的pom文件,Produce a pom.xml file which doesn’t include dependencies for the libraries whose contents are included in the fat JAR.                  <createDependencyReducedPom>true</createDependencyReducedPom> 

                     //将mainClass设置为JAR的mainClass,可以对jar文件运行java -jar
                    <transformers>
                        <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
                        <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                            <mainClass>${mainClass}</mainClass>
                        </transformer>
                    </transformers>
                    <!-- exclude signed Manifests -->
                    <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>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <artifactId>maven-jar-plugin</artifactId>
                <version>2.6</version>
                <configuration>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <mainClass>${mainClass}</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
            //将自动配置的compiler plugin部分去掉,编译的时候会报错,原因可能是本地编译器版本和该plugin不一致,这部分不需要
            <!-- <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.3</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin> -->
            <plugin>
                <artifactId>maven-source-plugin</artifactId>
                <version>2.4</version>
                <executions>
                    <execution>
                        <id>attach-sources</id>
                        <goals>
                            <goal>jar</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <artifactId>maven-javadoc-plugin</artifactId>
                <version>2.10.3</version>
                <executions>
                    <execution>
                        <id>attach-javadocs</id>
                        <goals>
                            <goal>jar</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

    <reporting>
        <plugins>
            <plugin>
                <artifactId>maven-project-info-reports-plugin</artifactId>
                <version>2.8.1</version>
                <configuration>
                    <dependencyLocationsEnabled>false</dependencyLocationsEnabled>
                    <dependencyDetailsEnabled>false</dependencyDetailsEnabled>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-javadoc-plugin</artifactId>
                <version>2.10.3</version>
            </plugin>
        </plugins>
    </reporting>
</project>

以上的pom文件是构建dropwizard project自动生成的,约定大于配置,但需删掉compiler的plugin,其余的保留即可。

四、开始例子,
例子大致是提供一个输出模板,格式是 ‘Hello, %s’,假如request中没有name这个parameter时,默认输出‘Hello, Stranger’。假如request中有name=fujian这种时,输出‘Hello,fujian’。以restful的形式发送请求,返回json格式数据。

首先,我们需要一个class类,它是对最终输入结果的封装,输出结果为 “id”:1,”content”: “hello,stranger”,所以构建一个saying class,这里是放到api这个package目录下的:

package com.example.helloworld.api;

import org.hibernate.validator.constraints.Length;
import com.fasterxml.jackson.annotation.JsonProperty;

public class Saying {

    private long id;

    //规定内容最大长度3
    @Length(max = 3)
    private String content;

    public Saying() {

    }

    public Saying(long id, String content) {
        this.id = id;
        this.content = content;
    }
    //jsonproperty注释可以将实体类映射到json格式数据,将两者关联起来
    @JsonProperty
    public long getId() {
        return id;
    }

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

ok,上边的封装类有了,因为dropwizard是个轻量级的rest框架,下边就开始写request过来对应的资源了,在resources这个package目录下,

package com.example.helloworld.resources;

import java.util.Optional;
import java.util.concurrent.atomic.AtomicLong;
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 com.codahale.metrics.annotation.Timed;
import com.example.helloworld.api.Saying;

//javax.ws.rs.*属于java扩展类的restful library
//@Path注释映射request请求的url
@Path("/hello-world")
//@Produces说明输出的为json格式数据
@Produces(MediaType.APPLICATION_JSON)
public class HelloWorldResource {

    private final String template;
    private final String defaultName;
    private final AtomicLong counter;

    //这里构造该resource类时传入template和defaultName,后边会讲到是从configuration中拿到这两个参数的
    public HelloWorldResource(String template, String defaultName) {
        this.template = template;
        this.defaultName = defaultName;
        this.counter = new AtomicLong();
    }

    //@GET说明是个GET请求,@Timed说明从接受请求到返回结果是有时间限制的,具体可以自行查找
    @GET
    @Timed
    public Saying sayHello(@QueryParam("name") Optional<String> name) {
        final String value = String.format(template, name.orElse(defaultName));//name是个Optional,可有可无,无时使用defaultName
        return new Saying(counter.incrementAndGet(), value);//每次请求返回一个id唯一的json data
    }
}

上边的resource class 有了,按照dropwizard的风格,需要将其在HelloWorldApplication的run方法中注册。

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

ok,可以看到实例化resource时,从configuration中取得template和defaultName,那么就看一下configuration这个类吧:

package com.example.helloworld;

import io.dropwizard.Configuration;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.hibernate.validator.constraints.*;
import javax.validation.constraints.*;

public class HelloWorldConfiguration extends Configuration {

    @NotEmpty
    private String template;

    @NotEmpty
    private String defaultName =  "Stranger";

    //jsonproperty注释主要是为了和json格式数据映射起来
    @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;
    }
}

这个配置类主要把json格式的template和defaultName映射起来,set方法是从json文件中提取相关部分到该类。这里有一点需要注意:该应用用maven打包成jar文件后,与该类相映射的json文件(hello-world.yml)与jar文件放到同一目录下,这样就能将yml中的json数据映射进来了,hello-world.yml如下:

template: hello %s!
defaultName: stranger

以上是针对resource资源的请求,官网的例子中还设计到了template这个模板合法性的检查,一并介绍下:

这个TemplateHealthCheck 类是在health package下的。

package com.example.helloworld.health;

import com.codahale.metrics.health.HealthCheck;

//继承HealthCheck抽象类,需实现check()抽象方法
public class TemplateHealthCheck  extends HealthCheck {

    private final String template;

    public TemplateHealthCheck(String template) {
        this.template = template;
    }
    @Override
    protected Result check() throws Exception {
        final String  saying = String.format(template, "TEST");
        //这里实际上检查了两点:1)TEST是否能写入template,即模板的创建性是否合理;2)是否包括TEST,即是否能正确输出含有目的name的template
        if(!saying.contains("TEST")) {
            return Result.unhealthy("template doesn't contain a name");

        }
        return Result.healthy();
    }

}

当然与resource一样,需要注册到Application的run方法中:

这里与resource的注册一并写出来:

package com.example.helloworld;

import com.example.helloworld.health.TemplateHealthCheck;
import com.example.helloworld.resources.HelloWorldResource;

import io.dropwizard.Application;
import io.dropwizard.setup.Bootstrap;
import io.dropwizard.setup.Environment;

public class HelloWorldApplication extends Application<HelloWorldConfiguration> {

    public static void main(final String[] args) throws Exception {
        new HelloWorldApplication().run(args);
    }

    @Override
    public String getName() {
        return "HelloWorld";
    }

    @Override
    public void initialize(final Bootstrap<HelloWorldConfiguration> bootstrap) {
        // TODO: application initialization
    }

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

}

ok,梳理下,上边主要分成两个部分的构建:
1)resource类的构建:过来的类似‘/hello-world?name=fujian’请求,返回json格式的数据;
2)healthCheck会校验yml文件中template的合法性

五、maven打包及本地运行

这里写图片描述

在该应用的本地目录下target目录中会有一个打包jar文件,同目录下还有hello-world.yml,
这里写图片描述

在target目录下打开本地命令行,

输入

java -jar helloworld-0.0.1-SNAPSHOT.jar server hello-world.yml

即可启动内嵌jetty 应用服务器,并可在8080端口访问/hello-world?name=fujian or /hello-world;在8081端口打开管理端部分,运行healthCheck


到此结束。这是框架的起步,官网 还介绍了在框架基础上集成一些重要的功能,如JDBI、hibernate、authentic等,感兴趣的可以去官网学习

猜你喜欢

转载自blog.csdn.net/linfujian1999/article/details/76713875