1. Overview
1.概述
In this article, we’re going to illustrate the Activeweb – a full stack web framework from JavaLite – providing everything necessary for the development of dynamic web applications or REST-ful web services.
在本文中,我们将说明Activeweb–来自JavaLite的全栈式Web框架–提供开发动态Web应用程序或REST-ful Web服务所需的一切。
2. Basic Concepts and Principles
2.基本概念和原则
Activeweb leverages “convention over configuration” – which means it’s configurable, but has sensible defaults and doesn’t require additional configuration. We just need to follow a few predefined conventions, like naming classes, methods, and fields in a certain predefined format.
Activeweb利用了 “惯例大于配置”–这意味着它是可配置的,但有合理的默认值,不需要额外的配置。我们只需要遵循一些预定义的惯例,比如以某种预定义的格式命名类、方法和字段。
It also simplifies development by recompiling and reloading the source into the running container (Jetty by default).
它还通过重新编译和重新加载源代码到运行的容器(默认为Jetty)来简化开发。
For dependency management, it uses Google Guice as the DI framework; to learn more about Guice, have a look at our guide here.
对于依赖性管理,它使用Google Guice作为DI框架;要了解更多关于Guice的信息,请看我们的指南。
3. Maven Setup
3.Maven设置
To get started, let’s add the necessary dependencies first:
为了开始工作,让我们先添加必要的依赖性。
<dependency>
<groupId>org.javalite</groupId>
<artifactId>activeweb</artifactId>
<version>1.15</version>
</dependency>
The latest version can be found here.
最新版本可以在这里找到。
Additionally, for testing the application, we’ll need the activeweb-testing dependency:
此外,为了测试应用程序,我们将需要activeweb-testing依赖。
<dependency>
<groupId>org.javalite</groupId>
<artifactId>activeweb-testing</artifactId>
<version>1.15</version>
<scope>test</scope>
</dependency>
Check out the latest version here.
请查看最新版本这里。
4. Application Structure
4.应用结构
As we discussed, the application structure needs to follow a certain convention; here’s what that looks like for a typical MVC application:
正如我们所讨论的,应用程序的结构需要遵循一定的惯例;下面是一个典型的MVC应用程序的情况。
As we can see, controllers, service, config, and models should be located in their own sub-package in the app package.
我们可以看到,controllers、service、config和models应该位于app包中各自的子包中。
The views should be located in WEB-INF/views directory, each having is own subdirectory based on the controller name. For example app.controllers.ArticleController should have an article/ sub-directory containing all the view files for that controller.
视图应该位于WEB-INF/views目录下,每个视图都有基于控制器名称的子目录。例如,app.controllers.ArticleController应该有一个article/子目录,包含该控制器的所有视图文件。
The deployment descriptor or the web.xml should typically contain a <filter> and the corresponding <filter-mapping>. Since the framework is a servlet filter, instead of a <servlet> configuration there is a filter configuration:
部署描述符或web.xml通常应包含一个<过滤器>和相应的<过滤器-映射>。由于该框架是一个Servlet过滤器,所以有一个过滤器配置,而不是一个<servlet>配置。
...
<filter>
<filter-name>dispatcher</filter-name>
<filter-class>org.javalite.activeweb.RequestDispatcher</filter-class>
...
</filter>
...
We also need an <init-param> root_controller to define the default controller for the application – akin to a home controller:
我们还需要一个<init-param> root_controller 来定义应用程序的默认控制器 – 类似于home控制器。
...
<init-param>
<param-name>root_controller</param-name>
<param-value>home</param-value>
</init-param>
...
5. Controllers
5.控制器
Controllers are the primary components of an ActiveWeb Application; and, as mentioned earlier all controllers should be located inside the app.controllers package:
控制器是ActiveWeb应用程序的主要组成部分;如前所述,所有的控制器都应该位于app.controllers包内。
public class ArticleController extends AppController {
// ...
}
Notice that the controller is extending org.javalite.activeweb.AppController.
请注意,该控制器正在扩展org.javalite.activeweb.AppController.。
5.1. Controller URL Mapping
5.1.控制器的URL映射
The controllers are mapped to a URL automatically based on the convention. For example, ArticleController will get mapped to:
控制器会根据惯例自动映射到一个URL。例如,ArticleController将被映射到。
http://host:port/contextroot/article
Now, this would be mapped them to the default a default action in the controller. Actions are nothing but methods inside the controller. Name the default method as index():
现在,这将被映射到控制器中的默认动作。行动只是控制器中的方法。命名默认方法为index():。
public class ArticleController extends AppController {
// ...
public void index() {
render("articles");
}
// ...
}
For other methods or actions append the method name to the URL:
对于其他方法或行动,将方法名称附加到URL中。
public class ArticleController extends AppController {
// ...
public void search() {
render("search");
}
}
The URL:
该网址。
http://host:port/contextroot/article/search
We can even have controller actions based on HTTP methods. Just annotate the method with either of @POST, @PUT, @DELETE, @GET, @HEAD. If we don’t annotate an action, it’s considered a GET by default.
我们甚至可以有基于HTTP方法的控制器动作。只要在方法上标注@POST, @PUT, @DELETE, @GET, @HEAD.如果我们不标注动作,它就被默认为是GET。
5.2. Controller URL Resolution
5.2.控制器的URL解析
The framework uses controller name and the sub-package name to generate the controller URL. For example app.controllers.ArticleController.java the URL:
该框架使用控制器名称和子包名称来生成控制器的URL。例如,app.controllers.ArticleController.java的URL。
http://host:port/contextroot/article
If the controller is inside a sub-package, the URL simply becomes:
如果控制器在一个子包内,URL就简单地变成。
http://host:port/contextroot/baeldung/article
For a controller name having more than a single word (for example app.controllers.PublishedArticleController.java), the URL will get separated using an underscore:
对于一个控制器的名字超过一个字(例如app.controllers.PostedArticleController.java),URL将使用下划线分开。
http://host:port/contextroot/published_article
5.3. Retrieving Request Parameters
5.3.检索请求参数
Inside a controller, we get access to the request parameters using the param() or params() methods from the AppController class. The first method takes a String argument – the name of the param to retrieve:
在控制器中,我们使用param()或params()方法来访问请求参数,这些方法来自AppController类。第一个方法需要一个字符串参数 – 要检索的参数的名称。
public void search() {
String keyword = param("key");
view("search",articleService.search(keyword));
}
And we can use the later to get all parameters if we need to:
而且,如果需要的话,我们可以用后面的方法来获得所有的参数。
public void search() {
Map<String, String[]> criterion = params();
// ...
}
6. Views
6.观点
In ActiveWeb terminology, views are often referred as templates; this is mostly because it uses Apache FreeMarker template engine instead of JSPs. You can read more about FreeMarker in our guide, here.
在ActiveWeb的术语中,视图通常被称为模板;这主要是因为它使用Apache FreeMarker模板引擎而不是JSP。你可以在我们的指南中阅读更多关于FreeMarker 的内容,这里。
Place the templates in WEB-INF/views directory. Every controller should have a sub-directory by its name holding all templates required by it.
将模板放在WEB-INF/views目录下。每个控制器都应该有一个以其名字命名的子目录,存放它所需要的所有模板。
6.1. Controller View Mapping
6.1.控制器视图映射
When a controller is hit, the default action index() gets executed and the framework will choose the WEB-INF/views/article/index.ftl template the from views directory for that controller. Similarly, for any other action, the view would be chosen based on the action name.
当一个控制器被击中时,默认的动作index()被执行,框架将选择WEB-INF/views/article/index.ftltemplate作为该控制器的视图目录。同样的,对于任何其他动作,视图将根据动作名称来选择。
This isn’t always what we would like. Sometimes we might want to return some views based on internal business logic. In this scenario, we can control the process with the render() method from the parent org.javalite.activeweb.AppController class:
这并不总是我们所希望的。有时我们可能想根据内部业务逻辑返回一些视图。在这种情况下,我们可以用来自父org.javalite.activeweb.AppController类的render() 方法来控制这个过程。
public void index() {
render("articles");
}
Note that the location of the custom views should also be in the same view directory for that controller. If it is not the case, prefix the template name with the directory name where the template resides and pass it to the render() method:
注意,自定义视图的位置也应该在该控制器的同一视图目录下。如果不是这样,请在模板名称前加上模板所在的目录名称,并将其传递给render()方法。
render("/common/error");
6.3. Views With Data
6.3.带有数据的视图
To send data to the views, the org.javalite.activeweb.AppController provides the view() method:
为了向视图发送数据,org.javalite.activeweb.AppController 提供了view() 方法。
view("articles", articleService.getArticles());
This takes two params. First, the object name used to access the object in the template and second an object containing the data.
这需要两个参数。首先,用于访问模板中的对象的名称,其次是一个包含数据的对象。
We can also use assign() method to pass data to the views. There is absolutely no difference between view() and assign() methods – we may choose any one of them:
我们也可以使用assign()方法来传递数据给视图。view()和assign()方法之间完全没有区别–我们可以选择其中任何一个。
assign("article", articleService.search(keyword));
Let’s map the data in the template:
让我们来映射模板中的数据。
<@content for="title">Articles</@content>
...
<#list articles as article>
<tr>
<td>${article.title}</td>
<td>${article.author}</td>
<td>${article.words}</td>
<td>${article.date}</td>
</tr>
</#list>
</table>
7. Managing Dependencies
7.管理依赖关系
In order to manage objects and instances, ActiveWeb uses Google Guice as a dependency management framework.
为了管理对象和实例,ActiveWeb使用Google Guice作为一个依赖性管理框架。
Let’s say we need a service class in our application; this would separate the business logic from the controllers.
假设我们的应用程序需要一个服务类;这将把业务逻辑与控制器分开。
Let’s first create a service interface:
让我们首先创建一个服务接口。
public interface ArticleService {
List<Article> getArticles();
Article search(String keyword);
}
And the implementation:
而实施。
public class ArticleServiceImpl implements ArticleService {
public List<Article> getArticles() {
return fetchArticles();
}
public Article search(String keyword) {
Article ar = new Article();
ar.set("title", "Article with "+keyword);
ar.set("author", "baeldung");
ar.set("words", "1250");
ar.setDate("date", Instant.now());
return ar;
}
}
Now, let’s bind this service as a Guice module:
现在,让我们把这个服务作为Guice模块来绑定。
public class ArticleServiceModule extends AbstractModule {
@Override
protected void configure() {
bind(ArticleService.class).to(ArticleServiceImpl.class)
.asEagerSingleton();
}
}
Finally, register this in the application context and inject it into the controller, as required:
最后,在应用程序上下文中注册,并根据需要将其注入控制器。
public class AppBootstrap extends Bootstrap {
public void init(AppContext context) {
}
public Injector getInjector() {
return Guice.createInjector(new ArticleServiceModule());
}
}
Note that this config class name must be AppBootstrap and it should be located in the app.config package.
请注意,这个配置类的名称必须是AppBootstrap,而且应该位于app.config包中。
Finally, here’s how we inject it into the controller:
最后,这里是我们如何将其注入控制器的。
@Inject
private ArticleService articleService;
8. Testing
8.测试
Unit tests for an ActiveWeb application are written using the JSpec library from JavaLite.
ActiveWeb应用程序的单元测试是使用JavaLite的JSpec库编写的。
We’ll use the org.javalite.activeweb.ControllerSpec class from JSpec to test our controller, and we’ll name the test classes following a similar convention:
我们将使用JSpec中的org.javalite.activeweb.ControllerSpec类来测试我们的控制器,并且我们将按照类似的惯例来命名测试类。
public class ArticleControllerSpec extends ControllerSpec {
// ...
}
Notice, that the name is similar to the controller it is testing with a “Spec” at the end.
请注意,这个名字与它所测试的控制器相似,后面有一个 “Spec”。
Here’s the test case:
这里是测试案例。
@Test
public void whenReturnedArticlesThenCorrect() {
request().get("index");
a(responseContent())
.shouldContain("<td>Introduction to Mule</td>");
}
Notice that the request() method simulates the call to the controller, and the corresponding HTTP method get(), takes the action name as an argument.
请注意,request() 方法模拟了对控制器的调用,而相应的HTTP方法get(),将动作名称作为一个参数。
We can also pass parameters to the controller using the params() method:
我们还可以使用params()方法向控制器传递参数。
@Test
public void givenKeywordWhenFoundArticleThenCorrect() {
request().param("key", "Java").get("search");
a(responseContent())
.shouldContain("<td>Article with Java</td>");
}
To pass multiple parameters, we can chain method as well, with this fluent API.
为了传递多个参数,我们也可以通过这个流畅的API,将方法连锁起来。
9. Deploying the Application
9.部署应用程序
It’s possible to deploy the application in any servlet container like Tomcat, WildFly or Jetty. Of course, the simplest way to deploy and test would be using the Maven Jetty plugin:
可以在Tomcat、WildFly或Jetty等任何Servlet容器中部署该应用。当然,最简单的部署和测试方法是使用Maven的Jetty插件。
...
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.4.8.v20171121</version>
<configuration>
<reload>manual</reload>
<scanIntervalSeconds>10000</scanIntervalSeconds>
</configuration>
</plugin>
...
The latest version of the plugin is here.
该插件的最新版本是这里。
Now, finally – we can fire it up:
现在,终于–我们可以启动它了。
mvn jetty:run
10. Conclusion
10.结论
In this article, we learned about the basic concepts and conventions of the ActiveWeb framework. In addition to these, the framework has more features and capabilities than what we have discussed in here.
在这篇文章中,我们了解了ActiveWeb框架的基本概念和惯例。除了这些,该框架还有比我们在这里讨论的更多的特性和能力。
Please refer the official documentation for more details.
请参考官方文件以了解更多细节。
And, as always, the sample code used in the article is available over on GitHub.
而且,像往常一样,文章中使用的示例代码可以在GitHub上找到。