1. 概述
Java生态系统中有许多Web框架,例如Spring、Play和Grails。但是,没有一个框架可以声称是完全不可变和面向对象的。
在本教程中,我们将探索Takes框架并使用其常见功能(如路由、请求/响应处理和单元测试)创建一个简单的Web应用程序。
2. Takes
Takes是一个不可变的Java 8 Web框架,既不使用null也不使用公共静态方法。
此外,该框架不支持可变类、强制类型转换或反射。因此,它是一个真正的面向对象框架。
Takes不需要配置文件即可进行设置。除此之外,它还提供JSON/XML响应和模板等内置功能。
3. 设置
首先,我们将最新的Maven依赖添加到pom.xml中:
<dependency>
<groupId>org.takes</groupId>
<artifactId>takes</artifactId>
<version>1.19</version>
</dependency>
然后,让我们创建实现Take接口的TakesHelloWorld类:
public class TakesHelloWorld implements Take {
@Override
public Response act(Request req) {
return new RsText("Hello, world!");
}
}
Take接口提供了框架的基本功能,每个Take都充当请求处理程序,通过act方法返回响应。
在这里,当向TakesHelloWorld发出请求时,我们使用RsText类来呈现纯文本“Hello,world!”作为响应。
接下来,我们将创建TakesApp类来启动Web应用程序:
public class TakesApp {
public static void main(String... args) {
new FtBasic(new TakesHelloWorld()).start(Exit.NEVER);
}
}
在这里,我们使用了提供Front接口基本实现的FtBasic类来启动Web服务器并将请求转发给TakesHelloWorld。
Takes使用ServerSocket类实现了自己的无状态Web服务器,默认情况下,它在端口80上启动服务器。但是,我们可以在代码中定义端口:
new FtBasic(new TakesHelloWorld(), 6060).start(Exit.NEVER);
或者,我们可以使用命令行参数–port传递端口号。
然后,让我们使用Maven命令编译类:
mvn clean package
现在,我们准备在IDE中将TakesApp类作为简单的Java应用程序运行。
4. 运行
我们还可以将TakesApp类作为单独的Web服务器应用程序运行。
4.1 Java命令行
首先,编译我们的类:
javac -cp "takes.jar:." cn.tuyucheng.taketoday.takes.*
然后,我们可以使用Java命令行运行该应用程序:
java -cp "takes.jar:." cn.tuyucheng.taketoday.takes.TakesApp --port=6060
4.2 Maven
或者,我们可以使用exec-maven-plugin插件通过Maven运行它:
<profiles>
<profile>
<id>reload</id>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>start-server</id>
<phase>pre-integration-test</phase>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>cn.tuyucheng.taketoday.takes.TakesApp</mainClass>
<cleanupDaemonThreads>false</cleanupDaemonThreads>
<arguments>
<argument>--port=${port}</argument>
</arguments>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
现在,我们可以使用Maven命令运行我们的应用程序:
mvn clean integration-test -Preload -Dport=6060
5. 路由
该框架提供TkFork类来将请求路由到不同的take。
例如,让我们向我们的应用程序添加一些路由:
public static void main(String... args) {
new FtBasic(
new TkFork(
new FkRegex("/", new TakesHelloWorld()),
new FkRegex("/contact", new TakesContact())
), 6060
).start(Exit.NEVER);
}
这里,我们使用了FkRegex类来匹配请求路径。
6. 请求处理
框架在org.takes.rq包中提供了一些装饰器类来处理HTTP请求。
例如,我们可以使用RqMethod接口来提取HTTP方法:
public class TakesHelloWorld implements Take {
@Override
public Response act(Request req) throws IOException {
String requestMethod = new RqMethod.Base(req).method();
return new RsText("Hello, world!");
}
}
类似地,RqHeaders接口可用于获取请求标头:
Iterable<String> requestHeaders = new RqHeaders.Base(req).head();
我们可以使用RqPrint类来获取请求的主体:
String body = new RqPrint(req).printBody();
同样,我们可以使用RqFormSmart类来访问表单参数:
String username = new RqFormSmart(req).single("username");
7. 响应处理
Takes还在org.takes.rs包中提供了许多有用的装饰器来处理HTTP响应。
响应装饰器实现了Response接口的head和body方法。
例如,RsWithStatus类使用状态码呈现响应:
Response resp = new RsWithStatus(200);
可以使用head方法验证响应的输出:
assertEquals("[HTTP/1.1 200 OK], ", resp.head().toString());
类似地,RsWithType类使用内容类型呈现响应:
Response resp = new RsWithType(new RsEmpty(), "text/html");
这里,RsEmpty类呈现空响应。
同样,我们可以使用RsWithBody类来呈现带有主体的响应。
因此,让我们创建TakesContact类并使用讨论的装饰器来呈现响应:
public class TakesContact implements Take {
@Override
public Response act(Request req) throws IOException {
return new RsWithStatus(
new RsWithType(
new RsWithBody("Contact us at https://www.tuyucheng.com"),
"text/html"), 200);
}
}
类似地,我们可以使用RsJson类来呈现JSON响应:
@Override
public Response act(Request req) {
JsonStructure json = Json.createObjectBuilder()
.add("id", rs.getInt("id"))
.add("user", rs.getString("user"))
.build();
return new RsJson(json);
}
8. 异常处理
该框架包含Fallback接口来处理异常情况,它还提供了一些实现来处理回退场景。
例如,让我们使用TkFallback类来处理HTTP 404并向用户显示一条消息:
public static void main(String... args) throws IOException, SQLException {
new FtBasic(
new TkFallback(
new TkFork(
new FkRegex("/", new TakesHelloWorld()),
// ...
),
new FbStatus(404, new RsText("Page Not Found"))), 6060
).start(Exit.NEVER);
}
在这里,我们使用了FbStatus类来处理定义的状态码的回退。
类似地,我们可以使用FbChain类来定义回退组合:
new TkFallback(
new TkFork(
// ...
),
new FbChain(
new FbStatus(404, new RsText("Page Not Found")),
new FbStatus(405, new RsText("Method Not Allowed"))
)
), 6060
).start(Exit.NEVER);
另外,我们可以实现Fallback接口来处理异常:
new FbChain(
new FbStatus(404, new RsText("Page Not Found")),
new FbStatus(405, new RsText("Method Not Allowed")),
new Fallback() {
@Override
public Opt<Response> route(RqFallback req) {
return new Opt.Single<Response>(new RsText(req.throwable().getMessage()));
}
}
)
9. 模板
让我们将Apache Velocity与我们的Takes Web应用程序集成以提供一些模板功能。
首先,我们将添加velocity-engine-core Maven依赖:
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.2</version>
</dependency>
然后,我们将使用RsVelocity类来定义模板字符串和act方法中的绑定参数:
public class TakesIndex implements Take {
@Override
public Response act(Request req) throws IOException {
return new RsHtml(
new RsVelocity("${username}", new RsVelocity.Pair("username", "Tuyucheng")));
);
}
}
在这里,我们使用RsHtml类来呈现HTML响应。
另外,我们可以使用带有RsVelocity类的速度模板:
new RsVelocity(this.getClass().getResource("/templates/index.vm"),
new RsVelocity.Pair("username", username))
);
10. 单元测试
该框架通过提供创建虚假请求的RqFake类来支持任何Take的单元测试:
例如,让我们使用JUnit为TakesContact类编写一个单元测试:
String resp = new RsPrint(new TakesContact().act(new RqFake())).printBody();
assertEquals("Contact us at https://www.tuyucheng.com", resp);
11. 集成测试
我们可以使用JUnit和任何HTTP客户端测试整个应用程序。
该框架提供了FtRemote类,可以在随机端口上启动服务器,并为Take的执行提供远程控制。
例如,让我们编写一个集成测试并验证TakesContact类的响应:
new FtRemote(new TakesContact()).exec(
new FtRemote.Script() {
@Override
public void exec(URI home) throws IOException {
HttpClient client = HttpClientBuilder.create().build();
HttpResponse response = client.execute(new HttpGet(home));
int statusCode = response.getStatusLine().getStatusCode();
HttpEntity entity = response.getEntity();
String result = EntityUtils.toString(entity);
assertEquals(200, statusCode);
assertEquals("Contact us at https://www.tuyucheng.com", result);
}
});
在这里,我们使用Apache HttpClient向服务器发出请求并验证响应。
12. 总结
在本教程中,我们通过创建一个简单的Web应用程序探索了Takes框架。
首先,我们看到了在Maven项目中快速设置框架并运行应用程序的一种方法。
然后,我们研究了一些常见的功能,如路由、请求/响应处理和单元测试。
最后,我们探讨了框架提供的单元和集成测试的支持。
Post Directory
