Java服務端的Web組件(JavaEE)提供動態(tài)擴展能力允許你在web容器或者應用服務器中運行你的程序,就像Servlet這個名字的意思,接收客戶端的請求返回響應,在MVC架構中充當控制器的角色,Servlet的響應通過視圖組件--JSP來渲染,下圖展示了一個典型的MVC架構的Java應用。
http://wiki.jikexueyuan.com/project/gradleIn-action/images/dag15.png" alt="" />
WAR(web application archive)用來捆綁Web組件、編譯生成的class文件以及其他資源文件如部署描述符、HTML、JavaScript和CSS文件,這些文件組合在一起就形成了一個Web應用,要運行Java Web應用,WAR文件需要部署在一個服務器環(huán)境---Web容器。
Gradle提供拆箱插件用來打包WAR文件以及部署Web應用到本地的Servlet容器,接下來我們就來學習怎么把Java應用編程Web應用。
添加Web組件
接下來我們將創(chuàng)建一個Servlet,ToDoServlet,用來接收HTTP請求,執(zhí)行CRUD操作,并將請求傳遞給JSP。你需要寫一個todo-list.jsp文件,這個頁面知道怎么去渲染todo items,提供一些UI組件比如按鈕和指向CURD操作的鏈接,下圖是用戶檢索和渲染todo items的流程:
http://wiki.jikexueyuan.com/project/gradleIn-action/images/dag16.png" alt="" />
Web 控制器
下面這個就是web 控制器ToDoServlet,用來處理所有的URL請求:
package com.manning.gia.todo.web;
public class ToDoServlet extends HttpServlet {
private ToDoRepository toDoRepository = new InMemoryToDoRepository();
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String servletPath = request.getServletPath();
String view = processRequest(servletPath, request);
RequestDispatcher dispatcher = request.getRequestDispatcher(view);
dispatcher.forward(request, response);
}
private String processRequest(String servletPath, HttpServletRequest request) {
if(servletPath.equals("/all")) {
List<ToDoItem> toDoItems = toDoRepository.findAll();
request.setAttribute("toDoItems", toDoItems);
return "/jsp/todo-list.jsp";
}
else if(servletPath.equals("/delete")) {
(...)
}
(...)
return "/all";
}
}
對于每一個接收的請求,獲取Servlet路徑,基于CRUD操作在processRequest方法中處理請求,然后通過請求分派器請求傳遞給todo-list.jsp。
使用War和Jetty插件
Gradle支持構建和運行Web應用,接下來我將介紹兩個web應用開發(fā)的插件War和Jetty,War插件繼承了Java插件用來給web應用開發(fā)添加一些約定、支持打包War文件。Jetty是一個很受歡迎的輕量級的開源Web容器,Gradle的Jetty插件繼承War插件,提供部署應用程序到嵌入的容器的任務。
既然War插件繼承了Java插件,所有你在應用了War插件后無需再添加Java插件,即使你添加了也沒有負面影響,應用插件是一個非冪等的操作,因此對于一個指定的插件只運行一次。添加下面這句到你的build.gradle腳本中: apply plugin: 'war'
除了Java插件提供的約定外,你的項目現在多了Web應用的源代碼目錄,將打包成war文件而不是jar文件,Web應用默認的源代碼目錄是src/main/webapp,如果所有的源代碼都在正確的位置,你的項目布局應該是類似這樣的:
http://wiki.jikexueyuan.com/project/gradleIn-action/images/dag17.png" alt="" /> http://wiki.jikexueyuan.com/project/gradleIn-action/images/dag18.png" alt="" />
你用來實現Web應用的幫助類不是java標準的一部分,比如javax.servlet.HttpServlet,在運行build之前,你應該確保你聲明了這些外部依賴,War插件引入了兩個新的依賴配置,用于Servlet依賴的配置是providedCompile,這個用于那些編譯器需要但是由運行時環(huán)境提供的依賴,你現在的運行時環(huán)境是Jetty,因此用provided標記的依賴不會打包到WAR文件里面,運行時依賴比如JSTL這些在編譯器不需要,但是運行時需要,他們將成為WAR文件的一部分。
dependencies {
providedCompile 'javax.servlet:servlet-api:2.5'
runtime 'javax.servlet:jstl:1.1.2'
}
build Web項目和Java項目一樣,運行gradle build后打包的WAR文件在目錄build/libs下,輸出如下:
$ gradle build
:compileJava
:processResources UP-TO-DATE
:classes
:war
:assemble
:compileTestJava UP-TO-DATE
:processTestResources UP-TO-DATE
:testClasses UP-TO-DATE
:test
:check
:build
War插件確保打包的WAR文件符合JAVA EE規(guī)范,war任務拷貝web應用源目錄src/main/webapp到WAR文件的根目錄,編譯的class文件保存在WEB-INF/classes,運行時依賴的庫放在WEB-INF/libs,下面顯示了WAR文件todo-webapp-0.1.war的目錄結構:
http://wiki.jikexueyuan.com/project/gradleIn-action/images/dag19.png" alt="" />
假設你把所有的靜態(tài)文件放在static目錄,所有的web組件放在webfiles,目錄結構如下:
http://wiki.jikexueyuan.com/project/gradleIn-action/images/dag20.png" alt="" />
//Changes web application source directory
webAppDirName = 'webfiles'
//Adds directories css and jsp to root of WAR file archive
war {
from 'static'
}
在嵌入的Web容器中運行
嵌入式的Servlet容器完全不知到你的應用程序知道你提供準確的classpath和源代碼目錄,你可以手工編程提供,Jetty插件給你完成了所有的工作,你只需要添加下面一條命令: apply plugin: 'jetty'
運行Web應用需要用到的任務是jettyRun,啟動Jetty容器并且無需創(chuàng)建WAR文件,這個命令的輸出應該類似這樣的:
$ gradle jettyRun
:compileJava
:processResources UP-TO-DATE
:classes
> Building > :jettyRun > Running at http://localhost:8080/todo-webapp-jetty
最后一行Jetty插件給你提供了一個URL用來監(jiān)聽HTTP請求,打開瀏覽器輸入這個鏈接就能看到你編寫的Web應用了。
Jetty插件默認監(jiān)聽的端口是8080,上下文路徑是todo-webapp-jetty,你也可以自己配置成想要的:
jettyRun {
httpPort = 9090
contextPath = 'todo'
}
這樣你就把監(jiān)聽端口改成了9090,上下文目錄改成了todo。