在 Hasor 的體系中開發 Web 應用程序須要至少 Hasor-Core、Hasor-Web 兩個模塊來共同完成。其中 Hasor-Core 爲軟件提供基本支持例如 IoC/Aop , Hasor-Web 提供請求轉發。 html
Hasor 的 Web MVC 支持是 Hasor-Web 軟件包位於「net.hasor.web」的20多個核心類負責提供支持。Hasor 經過這20多個核心類提供了動態註冊 Servlet、Filter 功能。讀者能夠先不深刻它們。 java
本文主要介紹 Controller 插件,該插件位於「net.hasor.plugins.controller」軟件包。這個插件提供咱們 MVC 模式中控制器方面的支持。 git
MVC 模式中有三個主要點,它們分別是:M 模型層、V 視圖層、C 控制器。 github
在開發過程當中一般模型用來編寫業務邏輯;視圖用於展示數據;控制器用於處理請求響應並將數據派發給視圖用於顯示。 web
下面就看一看 Hasor 是如何完成這一切工做的,首先定義一個控制器,在控制器中新增一個userList方法做爲Action,在Action中經過 JdbcTemplate 類查詢數據庫返回一個 List 到 request 屬性中(請求地址:「/mgr/user/userList.do」便可): sql
import net.hasor.plugins.controller.AbstractController; import net.hasor.plugins.controller.Controller; /** * * @version : 2013-12-23 * @author 趙永春(zyc@hasor.net) */ @Controller("/mgr/user") public class UserAction extends AbstractController { @Inject private JdbcTemplate jdbcTemplate; // @Forword public String userList() { ListuserList = jdbcTemplate.queryForList("select * from TB_User", UserBean.class); this.setAttr("userList", userList); return "/mgr/user/userList.jsp"; } }
下面這段代碼的意思是注入一個與默認數據源綁定的數據庫操做接口,使用這個接口操做數據庫時都將針對默認數據源: 數據庫
@Inject private JdbcTemplate jdbcTemplate;下面咱們看一下如何配置默認數據源,Hasor 在使用數據庫方面須要配置文件的支持。下面是例子程序的配置文件:
<?xml version="1.0" encoding="UTF-8"?> <config xmlns="http://project.hasor.net/hasor/schema/main"> <!-- 數據源配置 --> <hasor-jdbc> <dataSourceSet default="localDB"> <!-- 名稱爲 localDB 的內存數據庫,數據庫引擎使用 HSQL --> <dataSource name="localDB" dsFactory="net.hasor.plugins.datasource.factory.C3p0Factory"> <driver>org.hsqldb.jdbcDriver</driver> <url>jdbc:hsqldb:mem:aname</url> <user>sa</user> <password></password> </dataSource> </dataSourceSet> </hasor-jdbc> </config>
從上面這段配置中能夠看出 Hasor 是支持配置多個數據源的,每一個數據源都要有一個具體的名字。若是配置的數據源要做爲默認數據源,須要在「<dataSourceSet default="localDB">」的 default 屬性上標出默認數據源的名字。 api
@Forword 註解的含義是當 Action 執行完畢將請求轉發到 Action 返回值所表示的地址中,下面是展現頁面的 JSP 源碼,您能夠配上 JSTL 標準標籤去優化這個頁面: 安全
<%@page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8" import="java.util.*"%> <!DOCTYPE html> <html lang="zh-CN"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <!-- 如下三個資源,保存在 Jar包中 --> <title>Demo</title> </head> <body> <%List userList= (List)request.getAttribute("userList"); %> <%for (Object user : userList){ %> <%request.setAttribute("user", user); %> <b>UUID</b>:${user.userUUID},<b>loginName</b>:${user.loginName}<br> <%}%> </body> </html>
最後做爲一個 Web 工程 web.xml 的配置文件以下: app
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:javaee="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4"> <listener> <listener-class>net.hasor.web.startup.RuntimeListener</listener-class> </listener> <filter> <filter-name>runtime</filter-name> <filter-class>net.hasor.web.startup.RuntimeFilter</filter-class> </filter> <filter-mapping> <filter-name>runtime</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
-------------------------------------------------------
下面就分析一下 Hasor 是如何進行工做的,首先 Hasor 在啓動初始化階段掃描全部類並將標記了 @Controller 註解的類收集到一塊兒,而後在啓動階段將其經過 Guice 建立出來。在這一過程完成依賴注入。
Hasor 在收集建立控制器類時不會立刻建立 Controller 的實例,它會經過一個代理類(ControllerInvoke)進行延遲加載。ControllerInvoke 類的主要職責就是延遲初始化控制器,並保證控制器在調用時是線程安全的。這個代理類還有一個重要的職責,負責調用最終的 action 方法。
在收集 Controller 過程當中,Hasor 還會根據註解中配置的內容對收集結果進行分組。分組的依據就是@Controller 註解中配置的值。用於標記分組的配置信息被稱爲「命名空間」。每一個命名空間中能夠存有若干 Action 定義,這些 Action 就是具體的類方法。在上面例子中 「userList」方法就是一個 action 定義。
Hasor 會使用 ControllerNameSpace 類保存分組信息,分組的建立和保存所有是由 ControllerServlet 中央 控制器類處理。中央控制器在 Hasor init 過程當中會掃描類路徑並構建這些信息。
因爲處理起來並非很複雜這部分代碼就沒有作過多的封裝設計。
當請求進入中央控制器時,中央控制器會用過字符串匹配方式找到對應的命名空間(ControllerNameSpace)。而後從命名空間中獲取 Action對象(ControllerInvoke) 在經過 invoke 方法調用Action獲取返回值。
Action 返回值對於 Controller 插件來講毫無用處。所以處理 Action 返回值部分的功能就交給了其它插件去實現,至此 Controller 插件要關注的目標就更加單一。
-------------------------------------------------------
有的同窗可能想問,這樣簡單的 MVC 控制器如何實現 Action 攔截器呢?
答案就是經過 Guice 的 Aop,與 JFinal 不依賴 IoC模型不一樣的是 Hasor 須要依賴 IoC/Aop 容器。所以經過掛載 控制器上的 Aop 能夠方便的實現 Action 攔截器。
而實現攔截器的關鍵代碼Controller 插件也不用關心了,這樣就更加使 Controller 插件的工做目標單一。越單一的功能維護起來反而更加簡單輕鬆。
關於Action攔截器 Controller 插件仍是作了一些簡單的封裝,下面是一個Action 攔截器代碼:
class ActionLogInterceptor extends ControllerInterceptor { public Object invoke(ControllerInvocation invocation) throws Throwable { try { HttpServletRequest reqest = invocation.getRequest(); Hasor.logInfo("req:%s.", reqest.getRequestURI()); return invocation.proceed(); } catch (Exception e) { throw e; } } }
在 Hasor 中使用 Action 攔截器有三個方式:
1.只對一個 Action生效的攔截器,聲明這種攔截器須要在 Action 方法上經過 @Aop 註解實現。
2.對一個控制器類中全部 Action 方法生效,這種方式是在類上經過標記 @Aop 註解實現。
3.對全部 Action 方法生效,這種方式須要經過註冊全局 Aop 來實現。
那麼既然如此,就向 Guice 註冊一個全局 Aop 把。
註冊全局Aop 首先咱們要獲得 Guice 的 Binder 接口,而後經過 bindInterceptor 方法註冊一個 Aop 切面。若是你們還記得,前面在有關 Aop 的博文中我已講過如何使用這個方法(http://my.oschina.net/u/1166271/blog/178369)。
接下來就是如何獲取到 Binder 接口。 咱們知道 Hasor 在啓動時須要通過 init 階段,在這階段 Hasor 負責裝載插件。那麼咱們就經過插件獲取 Guice 的 Binder 接口完成這個功能把。下面是代碼:
@Plugin public class ActionLog implements HasorPlugin { public void loadPlugin(ApiBinder apiBinder) { apiBinder.getGuiceBinder().bindInterceptor(AopMatchers.annotatedWith(Controller.class),// AopMatchers.any(), new ActionLogInterceptor()); } }
再次啓動應用程序,在地址欄輸入 「/mgr/user/userList.do」在控制檯就能夠看到輸出的日誌了。
----------------------------------------------------------------
目前的開發代碼存放於(包括Demo程序):
Github: https://github.com/zycgit/hasor
git@OSC: http://git.oschina.net/zycgit/hasor
很是感謝您百忙之中抽出時間來看這一系博文。能夠經過Maven 中央倉庫網站 http://search.maven.org/ 搜索 Hasor 下載 hasor 的相關代碼。