扩展Struts的三种方式


我见过许多项目开发者实现自己专有的MVC框架。这些开发者并不是因为想实现不同于Struts的某些功能,而是还没有意识到怎么去扩展Struts。通过开发自己的MVC框架,你可以掌控全局,但同时这也意味着你必须付出很大的代价;在项目计划很紧的情况下也许根本就不可能实现。
Struts不但功能强大也易于扩展。你可以通过三种方式来扩展Struts:
1.PlugIn:在应用启动或关闭时须执行某业务逻辑,创建你自己的PlugIn类
2.RequestProcessor:在请求处理阶段一个特定点欲执行某业务逻辑,创建你自己的RequestProcessor。例如:你想继承RequestProcessor来检查用户登录及在执行每个请求时他是否有权限执行某个动作。
3.ActionServlet:在应用启动或关闭或在请求处理阶段欲执行某业务逻辑,继承ActionServlet类。但是必须且只能在PligIn和RequestProcessor都不能满足你的需求时候用。
本文会列举一个简单的Struts应用来示范如何使用以上三种方式扩展Struts。在本文末尾资源区有每种方式的可下载样例源代码。Struts Validation 框架和 Tiles 框架是最成功两个的Struts扩展例子。
我是假设读者已经熟悉Struts框架并知道怎样使用它创建简单的应用。如想 解更多有关Struts的资料请参见资源区。
PlugIn
根据Struts文档,“PlugIn是一个须在应用启动和关闭时需被通知的模块定制资源或服务配置包”。这就是说,你可以创建一个类,它实现PlugIn的接口以便在应用启动和关闭 时做你想要的事。
假如创建 一个web应用,其中使用 Hibernate做为持久化机制;当应用一启动,就需 初始化Hinernate,这样在web应用接收到第一个请求时, Hibernate已被配置完毕并待命。同时在应用关闭时要关闭 Hibernate。跟着以下两步可以实现 Hibernate PlugIn的需求。
1.创建一个实现PlugIn接口的类,如下:
public class HibernatePlugIn implements PlugIn{
        private String configFile;
        // This method will be called at application shutdown time
        public void destroy() {
                System.out.println("Entering HibernatePlugIn.destroy()");
                //Put hibernate cleanup code here
                System.out.println("Exiting HibernatePlugIn.destroy()");
        }
        //This method will be called at application startup time
        public void init(ActionServlet actionServlet, ModuleConfig config)
                throws ServletException {
                System.out.println("Entering HibernatePlugIn.init()");
                System.out.println("Value of init parameter " +
                                    getConfigFile());
                System.out.println("Exiting HibernatePlugIn.init()");
        }
        public String getConfigFile() {
                return name;
        }
        public void setConfigFile(String string) {
                configFile = string;
        }
}
实现PlugIn接口的类必须是实现以下两个方法:
init() 和destroy().。在应用启动时init()被调用,关闭destroy()被调用。Struts允许你传入初始参数给你的PlugIn类;为 传入参数你必须在PlugIn类里为每个参数创建一个类似JavaBean形式的setter方法。在HibernatePlugIn类里,欲传入configFile的名字而不是在应用里将它硬编码进去
2.在struts-condig.xml里面加入以下几行告知Struts这个新的PlugIn
<struts-config>
        ...
        <!-- Message Resources -->
        <message-resources parameter=
          "sample1.resources.ApplicationResources"/>
        <!-- Declare your plugins -->
        <plug-in className="com.sample.util.HibernatePlugIn">
                <set-property property="configFile"
                   value="/ hibernate.cfg.xml"/>
        </plug-in>
</struts-config>
ClassName属性是实现PlugIn接口类的全名。为每一个 初始化传入PlugIn类的 初始化参数增加一个<set-property>元素。在这个例子里,传入config文档的名称,所以增加 一个config文档路径的<set-property>元素。
Tiles和Validator框架都是利用PlugIn给 初始化读入配置文件。另外两个你还可以在PlugIn类里做的事情是:
假如应用依赖于某配置文件,那么可以在PlugIn类里检查其可用性,假如配置文件不可用则抛出ServletException。这将导致ActionServlet不可用。
PlugIn接口的init()方法是你改变ModuleConfig方法的最后机会,ModuleConfig方法是描述基于Struts模型静态配置信息的集合。一旦PlugIn被处理完毕,Struts就会将ModuleCOnfig冻结起来。
请求是如何被处理的
ActionServlet是Struts框架里唯一一个Servlet,它负责处理所有请求。它无论何时收到一个请求,都会首先试着为现有请求找到一个子应用。一旦子应用被找到,它会为其生成一个RequestProcessor对象,并调用传入HttpServletRequest和HttpServletResponse为参数的process()方法。
大部分请处理都是在RequestProcessor.process()发生的。Process()方法是以模板方法(Template Method)的设计模式来实现的,其中有完成request处理的每个步骤的方法;所有这些方法都从process()方法顺序调用。例如,寻找当前请求的ActionForm类和检查当前用户是否有权限执行action mapping都有几个单独的方法。这给我们提供 极大的弹性空间。Struts的RequestProcessor对每个请求处理步骤都提供 默认的实现方法。这意味着,你可以重写你感兴趣的方法,而其余剩下的保留默认实现。例如,Struts默认调用request.isUserInRole()检查用户是否有权限执行当前的ActionMapping,但如果你需要从数据库中查找,那么你要做的就是重写processRoles()方法,并根据用户角色返回true 或 false。
首先我们看一下process()方法的默认实现方式,然后我将解释RequestProcessor类里的每个默认的方法,以便你决定要修改请求处理的哪一部分。
public void process(HttpServletRequest request,
                        HttpServletResponse response)
    throws IOException, ServletException {
        // Wrap multipart requests with a special wrapper
        request = processMultipart(request);
        // Identify the path component we will
        // use to select a mapping
        String path = processPath(request, response);
        if (path == null) {
            return;
        }
        if (log.isDebugEnabled()) {
            log.debug("Processing a '" + request.getMethod() +
                      "' for path '" + path + "'");
        }
        // Select a Locale for the current user if requested
        processLocale(request, response);
        // Set the content type and no-caching headers
        // if requested
        processContent(request, response);
        processNoCache(request, response);
        // General purpose preprocessing hook
        if (!processPreprocess(request, response)) {
            return;
       }
        // Identify the mapping for this request
        ActionMapping mapping =
            processMapping(request, response, path);
        if (mapping == null) {
            return;
        }
        // Check for any role required to perform this action
        if (!processRoles(request, response, mapping)) {
            return;
        }
        // Process any ActionForm bean related to this request
        ActionForm form =
            processActionForm(request, response, mapping);
        processPopulate(request, response, form, mapping);
        if (!processValidate(request, response, form, mapping)) {
            return;
        }
        // Process a forward or include specified by this mapping
        if (!processForward(request, response, mapping)) {
            return;
        }
        if (!processInclude(request, response, mapping)) {
            return;
        }
        // Create or acquire the Action instance to
        // process this request
        Action action =
            processActionCreate(request, response, mapping);
        if (action == null) {
            return;
        }
        // Call the Action instance itself
        ActionForward forward =
            processActionPerform(request, response,
                                action, form, mapping);
        // Process the returned ActionForward instance
        processForwardConfig(request, response, forward);
    }
1、processMultipart(): 在这个方法中,Struts读取request以找出contentType是否为multipart/form-data。假如是,则解析并将其打包成一个实现HttpServletRequest的包。当你成生一个放置数据的HTML FORM时,request的contentType默认是application/x-www-form-urlencoded。但是如果你的form的input类型是FILE-type允许用户上载文件,那么你必须把form的contentType改为multipart/form-data。如这样做,你永远不能通过HttpServletRequest的getParameter()来读取用户提交的form值;你必须以InputStream的形式读取request,然后解析它得到值。
2、processPath(): 在这个方法中,Struts将读取request的URI以判断用来得到ActionMapping元素的路径。
3、processLocale(): 在这个方法中,Struts将得到当前request的Locale;Locale假如被配置,将作为org.apache.struts.action.LOCALE属性的值被存入HttpSession。这个方法的附作用是HttpSession会被创建。假如你不想此事发生,可将在struts-config.xml 文件里ControllerConfig的local属性设置为false,如下:
<controller>
        <set-property property="locale" value="false"/>
</controller>
4、processContent():通过调用response.setContentType()设置response的contentType。这个方法首先会试着的得到配置在struts-config.xml里的contentType。默认为text/html,重写方法如下:
<controller>
        <set-property property="contentType" value="text/plain"/>
</controller>
5、processNoCache():Struts将为每个response的设置以下三个header,假如已在struts 的config.xml将配置为no-cache。
response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 1);
假如你想设置为no-cache header,在struts-config.xml中加如以下几行
<controller>
        <set-property property="noCache" value="true"/>
</controller>
6、processPreprocess():这是一个一般意义的预处理hook,其可被子类重写。在RequestProcessor里的实现 什么都没有做,总是返回true。如此方法返回false会中断请求处理。
7、processMapping():这个方法会利用path信息找到ActionMapping对象。ActionMapping对象在struts-config.xml file文件里表示为<action>
<action path="/newcontact" type="com.sample.NewContactAction"
        null)

你可能感兴趣的:(Hibernate,struts,String,扩展,action,Path)