之前用的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等,感兴趣的可以去官网学习