在 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 的相关代码。