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