wash

          #

          Kid Language Specification

          Kid is a simple XML based template language that uses embedded Python to do cool stuff. The syntax was inspired by a number of existing template languages, namely XSLT, TAL, and PHP.

          This document describes the template language and will be most useful as reference to those developing Kid templates. For information about using templates from Python, the command line, or in web environments, see the .

          1   Synopsis

          <?python
          title = "A Kid Test Document"
          fruits = ["apple", "orange", "kiwi", "M&M"]
          from platform import system
          ?>
          <html xmlns:py="http://purl.org/kid/ns#">
            <head>
              <title py:content="title">This is replaced.</title>
            </head>
            <body>
              <p>These are some of my favorite fruits:</p>
              <ul>
                <li py:for="fruit in fruits">
                  I like ${fruit}s
                </li>
              </ul>
              <p py:if="system() == 'Linux'">
                Good for you!
              </p>
            </body>
          </html>
          

          Yields something like this:

          <?xml version="1.0" encoding="utf-8"?>
          <html>
            <head>
              <title>A Kid Test Document</title>
            </head>
            <body>
              <p>These are some of my favorite fruits:</p>
              <ul>
                <li>I like apples</li>
                <li>I like oranges</li>
                <li>I like kiwis</li>
                <li>I like M&amp;Ms</li>
              </ul>
              <p>
                Good for you!
              </p>
            </body>
          </html>
          

          2   The Kid Namespace

          All attributes described in this document must belong to the following namespace:

          http://purl.org/kid/ns#
          

          The namespace prefix py is used throughout this document to indicate that an item belongs to the Kid/Python namespace.

          3   Embedding Code Blocks (<?python?>)

          The <?python?> processing instruction (PI) contains Python code and MAY occur anywhere that is legal for processing instructions to occur in an XML document.

          The rules for executing code found in a <?python?> PI is as follows:

          1. <?python?> PIs located outside of the document element (e.g. root element) contain Document Level code. This code SHOULD be executed in a global, shared scope for the document. The code SHOULD be executed once when the template is loaded and shared between multiple invocations of the template.
          2. <?python?> PIs located within the document element contain Local Level code. This code is executed each time the document is processed with a local scope specific to the invocation and the shared document level global scope.

          Document Level and Local Level code work exactly like Module Level and Function Level code in normal Python modules. For example, the following Kid template:

          <?python
          x = 0
          y = 0
          ?>
          <html xmlns:py="http://purl.org/kid/ns#">
            <?python
            x = 1
            if x == 1:
              x = 10
            ?>
            <p py:content="x"/>
            <?python
            global y
            y = 30
            ?>
            <p py:content="y"/>
          </html>
          

          May be considered equivalent to the following Python module:

          x = 0
          y = 0
          def expand(handler):
            handler.startDocument()
            handler.startElement('html')
            x = 1
            if x == 1:
              x = 10
            handler.element('p', content=x) # output p element with x as value
            global y
            y = 30
            handler.element('p', content=y) # output p element with value of y
            handler.endElement('html')
            handler.endDocument()
          

          <?python?> PIs may contain any legal Python language construct including functions, classes, lamda forms, etc.

          <?python
          class Adder:
            def __init__(self, x, y):
              self.x = x
              self.y = y
            def doit(self):
              return self.x + self.y
          
          foo = Adder(x=400, y=20)
          x = foo.doit()
          ?>
          

          Single line <?python?> PIs are okay too:

          <?python x = 10 ?>
          

          4   Content Producing Constructs

          There are multiple methods of generating content output from a template: py:content, py:replace, py:attrs, and ${} substitution. Each of these syntaxes have the same rules for what types of objects may result from the Python expression they contain.

          str, unicode
          The string is inserted as XML CDATA. That is, it is non-parsable character data that does not contain markup. The following characters are encoded as XML entities when serialized: '<', '&'. Attribute values containing content also encode the quote character: '"'.
          ElementTree.Element

          When an ElementTree.Element is referenced from a content producing construct, the item is inserted into the document literally, i.e. it is not encoded as text, but becomes part of the output structure.

          The XML() and document() functions can be used to turn a string into structured content and to retrieve an XML document from a URL, respectively.

          Note that attribute values MUST NOT reference structured content. This applies to py:attrs and using ${} substitution in attribute values.

          sequence
          If a sequence type (list, tuple, or other iterable) is referenced, the rules are applied to each of the items in the sequence. For example, you could reference a list containing an Element and a string.
          Other
          If the result of evaluating the expression is any other type, an attempt is made to coerce the value to unicode as if by calling unicode(expr) and processing continues as if the object were a string or unicode object initially.

          5   Python Expression Substitution (${expr})

          Attributes not belonging to the Kid namespace and text content MAY embed Python expressions by enclosing the expression within a dollar sign followed by curly braces: ${expr}. The result of evaluating the expression(s) is substituted with the rest of the attribute value or text content following rules defined for Content Producing Constructs.

          <?python
          verb = 'ran'
          noun = 'store'
          ?>
          <a title="I ${verb} to the ${noun}">...
          

          ... would result in:

          <a title="I ran to the store">...
          

          If an attribute value consists purely of substitution expressions and all expressions evaluate to None, the attribute is removed. This can be avoided by using expr or '' to force a zero length string to be returned instead of None. For example:

          <?python
          # set something to None
          x = None
          ?>
          <a title="${x}">...
          

          ... would result in:

          <a>...
          

          However, this:

          <?python x = None?>
          <a title="${x or ''}">...
          

          ... results in:

          <a title="">...
          

          5.1   Identifier Shortcut ($name)

          For simple expressions consisting entirely variable names and object access operators (.), the curly braces may be omitted:

          <a  title="$title">
             Dots are allowed too: $object.another.attribute
          </a>
          

          However, it is good practice to use the curly brace form as it sets the substitution off from the other text a bit more providing a stronger visual clue as to what's going on.

          5.2   Escaping ($$)

          $$ is an escape. $${bla} will output ${bla}.

          6   Default Imports

          All templates have a few default imports for convenience.

          6.1   XML() function

          Expression substitution, py:content, and py:replace encode strings as text. That is, text is encoded according to the rules of the XML specification, which includes, among other things, replacing the literal characters < and & with their encoded counterparts (&lt; &amp;). If you have XML stored as a string and want it to be output as XML and not encoded text, you need to pass the string to the XML function.

          For example, let's say there is a function, hello, that returns XML data that should be embedded in template output (let's say it returns <hello>world</hello>). Consider the following:

          <p>${hello()}</p>
          

          The result would be:

          <p>&lt;hello>world&lt;hello></p>
          

          Calling the XML function would have given us the result we intended:

          <p>${XML(hello())}</p>
          
          <p><hello>world</hello></p>
          

          6.2   document() function

          The document function loads an XML document from a file or URL allowing it to be embedded in template output:

          <div py:content="document('header.html')"></div>
          

          The document function resolves paths relative to the current template file (if the template location is available).

          7   Attribute Language

          7.1   Repetition/Iteration (py:for)

          <element py:for="target_list in expression_list" />
          

          Works exactly like the Python for statement.

          The py:for attribute may appear on any element to signify that the element should be processed multiple times, once for each value in the sequence specified:

          <?python
          bottles = range(1, 101)
          bottles.reverse()
          ?>
          <p py:for="num in bottles">
             <span py:content="num">X</span> bottles of beer on the wall,
             <span py:content="num">X</span> bottles of beer on the wall,
             take one down, pass it around, <span py:content="num - 1">X - 1</span>
             bottles of beer on the wall.
          </p>
          

          The py:for attribute is the first attribute to be processed if present. All other py: attributes are processed for each iteration of the loop.

          7.2   Conditionals (py:if)

          <element py:if="expr" />
          

          The py:if attribute may appear on any element to signify that the element and its decendant items should be output only if the boolean expression specified evaluates to true in Python:

          <p py:if="5 * 5 == 25">
            Python seems to be handling multiplication okay.
          </p>
          

          The py:if attribute is processed after the py:for attribute and is evaluated for each iteration. If the result of evaluating expr as a boolean expression is false in Python, no further py: attributes are processed for the current iteration or, if not in a py:for, at all.

          Note

          Evaluated as a boolean expression in Python, None, False, [], (), {}, 0, and '' are all considered to be false.

          7.3   Dynamic Content (py:content)

          <element py:content="expr" />
          

          This attribute MAY appear on any element to signify that the decendant items of the element are to be replaced with the result of evaluating expr.

          <p py:content="time.strftime('%C %c')">The Time</p>
          

          Results in:

          <p>Tues, Jun 26, 2004 02:03:53 AM</p>
          

          py:content is a Content Producing Construct and can output both character and structured data.

          7.4   Replacing Content (py:replace)

          <element py:replace='expr' />
          

          py:replace is shorthand for specifying a py:content and a py:strip="True" on the same element:

          <?python
          x = 10
          ?>
          <p><span py:replace="x">...</span></p>
          

          ... results in:

          <p>10</p>
          

          ... and is equivelant to specifying:

          <?python #
          x = 10
          ?>
          <p><span py:strip="" py:content="x">...</span></p>
          

          The py:replace attribute is processed after the py:for and py:if attributes. py:strip and py:content attributes are not processed and are discarded.

          py:replace is a Content Producing Construct and can output both character and structured data.

          7.5   Stripping Tags (py:strip)

          <element py:strip="expr" />
          

          The py:strip attribute may apppear on any element to signify that the containing element should not be output. If the attribute value is blank (no expr at all) or if the result expr is a boolean expression that evaluates to true, the element is not output, but all descendant elements are processed normally. If expr is not blank and the result of evaluating expr as a boolean expression is false, processing continues as if the attribute did not exist.

          The py:strip attribute MAY appear on an element with any other kid attribute. However, if both a py:replace and a py:strip exist on the same element, the py:strip attribute is ignored and discarded.

          The py:strip attribute is processed after the py:for and py:if attributes. If omission is eminent, the py:content attribute is processed normally but attribute interpolation does not occur.

          7.6   Dynamic Attributes (py:attrs)

          <element py:attrs="expr" />
          

          The py:attrs attribute may appear on any element to specify a set of attributes that should be set on the element when it is processed. The expression specified MUST evaluate to one of the following types of values:

          dict
          A dictionary with keys specifying attribute names and values specifying attribute values. These are added to the attributes of the current element by calling element.attrib.update(mapping), where element is an ElementTree Element object and mapping is the dictionary returned from the expression. Outer curly braces are not necessary to write down.
          list
          A list of tuples of the form (name, value) is also acceptable. Each item of the list is added to the current set of attributes by iterating over the list and calling element.set(name, value).
          keyword arguments
          The attributes can also be specified as comma separated keyword arguments of the form name=value.

          The following lines:

          <elem py:attrs="{'a':1, 'ns:b':2}" />
          <elem py:attrs="'a':1, 'ns:b':2" />
          <elem py:attrs="(('a',1), ('ns:b',2))" />
          <elem py:attrs="a=1, ns:b=2" />
          

          will all produce the same output:

          <elem a="1" ns:b="2" />
          

          Note that attributes whose values are None will be removed. If a blank attribute is desired, an empty string should be used.

          If the expression specified is an empty dictionary or an empty list, the attributes are not modified in any way.

          py:attrs is a Content Producing Construct, but can output only character data.

          7.7   Named Template Functions (py:def)

          <element py:def="template_name(arg_list)" />
          

          The py:def attribute may appear on any element to create a "Named Template Function". Markup contained within an py:def element is not output during normal template expansion but can be referenced from other Content Producing Constructs to insert the markup at the point referenced.

          Like normal Python functions, Named Template Functions have an optional argument list that may use all of the jazzy features of Python argument lists like variable and keyword arguments.

          Named Template Functions are invoked exactly like normal Python functions. They are generally invoked from Content Producing Constructs like py:content or ${} substitution.

          <ul py:def="display_list(seq)">
             <li py:for="item in seq" py:content="item" />
          </ul>
          
          <table py:def="display_dict(mapping)">
             <tr>
                 <th>Key</th>
                 <th>Value</th>
             </tr>
             <tr py:for="key, value in mapping.items()">
                 <td py:content="key" />
                 <td py:content="value" />
             </tr>
          </table>
          

          Here we've defined two Named Template Functions: display_list and display_dict. The first function takes a sequence and the second a mapping. We can invoke these functions from the same template by invoking them from a content producing construct:

          <body>
             ${display_list(['apple', 'orange', 'kiwi'])}
          
             <div py:replace="display_dict({'x' : 'y', 'p' : 'q'})">
              Key/Value Table replaces this text
             </div>
          </body>
          

          7.8   Match Templates (py:match)

          <element py:match="expr" />
          

          The py:match attribute may appear on any element to create a "Match Template". Markup contained within a Match Template element is not output during normal template expansion. Instead, these constructs set up filters for expansion output that are capable of transforming content as it is generated.

          Match Templates are generally used to insert content dynamically based on patterns in template expansion or to provide "custom tag" functionality similar to that found in JSP taglibs or XSLT.

          A Match Template has two parts: the match expression part (expr) and the body part (the element and it's descendants).

          Match Templates are processed as follows:

          1. Each element that is output from a template goes through the Match Template Filter.
          2. The Match Template Filter visits each of the Match Templates defined in the current template and the templates the current template extends in the order that they are defined and evaluates the associated match expression.
          3. If the match expression returns true as a boolean expression, the match template's body is expanded and replaces the original element and all of its descendants.

          In both the match expression and in the match template's body, the item name is bound to the Element that is being output. However, there are some limitations to what can be accessed at each phase:

          1. During match expression evaluation, only the item Element and none of its descendants are available. This means that match expressions are limited to testing matches based on the immediate Element's tag and attributes [1].
          2. During match template expansion (that is, when the match expression is true), the element's descendants are available and may be referenced from Content Producing Constructs to output bits and pieces of the matched items structure.
          [1] This is due to the streaming nature of the Kid processor. During normal template expansion, the entire tree is never fully retained in memory.

          7.8.1   Example

          The following simple example shows how to create a custom tag <greeting> that outputs one of two provided values based on the time of day the template is expanded:

          <?xml version="1.0" encoding="utf-8"?>
          <?python
          from time import localtime
          def timeofday():
              """Get time of day ('am' or 'pm')"""
              return localtime().tm_hour < 12 and 'am' or 'pm'
          ?>
          <html xmlns:py="http://purl.org/kid/ns#">
            <!-- define the greeting match template -->
            <span py:match="item.tag == 'greeting'"
                  py:replace="item.get(timeofday())">
            </span>
          
            <head>
              <title>Time of day demo</title>
            </head>
            <body>
              <p>
                Good <greeting am="Morning!" pm="Afternoon" />
              </p>
            </body>
          </html>
          

          An important thing to note is that the py:match expression and the match template body have access to the <greeting> element via the variable item. The item.get(timeofday()) bit retrieves the value of the am attribute or the pm attribute based on what is returned from the timeofday function.

          At 9:00 AM, output from this template would look like this:

          <html>
            <head>
              <title>Time of day demo</title>
            </head>
            <body>
              <p>
                Good Morning!
              </p>
            </body>
          </html>
          

          The obvious question at this point is how to reuse Match Templates? The example above demonstrates the use of a Match Template from the same main template but it is often desirable to have "libraries" of Match Templates that could be used by multiple individual templates. The answer is to have the main template extend a common template containing the Match Templates needed. We can rewrite the above example as two separate templates: main.kid and common.kid.

          The common template would look like this:

          <?xml version="1.0" encoding="utf-8"?>
          <?python
          from time import localtime
          def timeofday():
              """Get time of day ('am' or 'pm')"""
              return localtime().tm_hour < 12 and 'am' or 'pm'
          ?>
          <html xmlns:py="http://purl.org/kid/ns#">
            <!-- define the greeting match template -->
            <span py:match="item.tag == 'greeting'"
                  py:replace="item.get(timeofday())">
            </span>
          </html>
          

          And the main template would look like this:

          <?xml version="1.0" encoding="utf-8"?>
          <html py:extends="'common.kid'">
            <head>
              <title>Time of day demo</title>
            </head>
            <body>
              <p>
                Good <greeting am="Morning!" pm="Afternoon" />
              </p>
            </body>
          </html>
          

          When a template extends another template (or set of templates), all of the Match Templates and Named Template Functions of the extended templates are available as if they were defined locally.

          Warning

          Match templates are an experimental feature. Syntax and semantics may change significantly or be removed entirely in future release. Actually, this statement applies to many aspects of Kid but this one is especially unstable.

          7.9   Template Reuse (py:extends)

          <root py:extends="template1, template2, ...">
          

          The py:extends attribute may appear on the root element to specify that the template should inherit the Named Template Functions and Match Templates defined in another template (or set of templates). If a py:extends attribute is specified, it MUST be on the root element of the document.

          The py:extends may contain a list of Python expressions separated by commas that reference templates. The rules for what types of values may be specified are:

          string

          The name of a template file, relative to the current template file.

          Example:

          <html py:extends="'common.kid'" />
          
          module or Template class

          The py:extends variable references a module or a Template class. If a module is referenced, an attempt is made to find a class named Template belonging to the that module.

          Example:

          <?python
          import common
          ?>
          <html py:extends="common" ...
          

          Multiple templates may be referenced by separating each by a comma. The following example references templates common and forms, imported using the import hooks and a template filename named other.kid:

          <?python
          import common, forms
          ?>
          <html py:extends="common, forms, 'other.kid'" ...
          

          7.9.1   Example

          For example, there is a template named common.kid that defines a template function, display_errors, and a match template that converts <b> elements to <strong> elements with uppercase content:

          <html xmlns:py="http://purl.org/kid/ns#">
          
            <ul py:def="display_errors(errors)">
              <li py:for="error in errors" py:content="error" />
            </ul>
          
            <strong py:match="item.tag == 'b'"
              py:content="item.text.upper()" />
          
          </html>
          

          The functions and match templates may be imported into another template by referencing them with py:extends:

          <html py:extends="'common.kid'"
                xmlns:py="http://purl.org/kid/ns#">
            <head>
              <title>Errors</title>
            </head>
            <body>
              <p>The following <b>errors</b> were found:</p>
              ${ display_errors(["Field is required", "Must be phone number.."]) }
            </body>
          </html>
          

          The <b>errors</b> item is transformed to <strong>ERRORS</strong> and the error list is displayed. Both the match template and the named template function are available in the derived template as if they were defined locally.

          8   Processing Order

          The order that py: attributes are processed is as follows:

          1. py:def
          2. py:match
          3. py:for
          4. py:if
          5. py:replace
          6. py:strip
          7. py:attrs
          8. py:content

          Attribute substitution occurs after all other

          posted @ 2005-12-26 16:11 wash 閱讀(170) | 評論 (0)編輯 收藏

          cherrypy documentation

               摘要: . Application developer reference AbstractCherryPy lets developers use Python to develop web applications, just as they would use Python for any other type of application. Building a web appli...  閱讀全文

          posted @ 2005-12-26 09:02 wash 閱讀(1383) | 評論 (0)編輯 收藏

          turbo gears get start

               摘要: Your model objects represent the data that your application is working with. Your controller pulls in information coming from the user's web browser. It uses that information to update information i...  閱讀全文

          posted @ 2005-12-21 09:24 wash 閱讀(263) | 評論 (0)編輯 收藏

          webworks chapter 1 -夏昕Webwork2 Developer’s Guide Version 1.0


          ServletDispatcher 接受到Servlet Container 傳遞過來的請求,將進行一下幾個動作:
          1. 從請求的服務名(/login.action)中解析出對應的Action名稱(login)
          2. 遍歷HttpServletRequest、HttpSession、ServletContext 中的數據,并將其復制到
          Webwork的Map實現中,至此之后,所有數據操作均在此Map結構中進行,從
          而將內部結構與Servlet API相分離。
          至此,Webwork 的工作階段結束,數據將傳遞給XWork 進行下一步處理。從這里也可以看到Webwork和xwork之間的切分點,Webwork為xwork提供了一個面向Servlet 的協議轉換器,將Servlet 相關的數據轉構轉換成xwork所需要的通用數據格式,而xwork將完成實際的服務調度和功能實現。
          這樣一來,以xwork為核心,只需替換外圍的協議轉換組件,即可實現不同技術平臺之間的切換(如將面向Servlet的Webwork替換為面向JMS的協議轉換器實現,即可在保留應用邏輯實現的情況下,實現不同外部技術平臺之間的移植)。
          3. 以上述信息作為參數,調用ActionProxyFactory創建對應的ActionProxy實例。
          ActionProxyFactory 將根據Xwork 配置文件(xwork.xml)中的設定,創建
          ActionProxy實例,ActionProxy中包含了Action的配置信息(包括Action名稱,
          對應實現類等等)。
          4. ActionProxy創建對應的Action實例,并根據配置進行一系列的處理程序。包括
          執行相應的預處理程序(如通過Interceptor 將Map 中的請求數據轉換為Action
          所需要的Java 輸入數據對象等),以及對Action 運行結果進行后處理。
          ActionInvocation 是這一過程的調度者。而com.opensymphony.xwork.
          DefaultActionInvocation 則是XWork 中對ActionInvocation 接口的標準實現,如
          果有精力可以對此類進行仔細研讀,掌握了這里面的玄機,相信XWork的引擎
          就不再神秘。
          下面我們來看配置文件:
          xwork.xml:
          <!DOCTYPE xwork PUBLIC "-//OpenSymphony Group//XWork 1.0//EN"
          "<
          xwork>
          <include file="webwork-default.xml" /> ⑴
          <package name="default" extends="webwork-default"> ⑵
          <action name="login" ⑶
          class="net.xiaxin.webwork.action.LoginAction">
          <result name="success" type="dispatcher"> ⑷
          <param name="location">/main.jsp</param>
          </result>
          <result name="loginfail" type="dispatcher">
          <param name="location">/index.jsp</param>
          </result>
          <interceptor-ref name="params" /> ⑸
          <interceptor-ref name="model-driven"/> ⑹
          </action>
          </package>
          </xwork>
          ⑴ include
          通過include 節點,我們可以將其他配置文件導入到默認配置文件xwork.xml 中。
          從而實現良好的配置劃分。
          這里我們導入了Webwork 提供的默認配置webwork-default.xml(位于
          webwork.jar 的根路徑)。
          ⑵ package
          XWork中,可以通過package對action進行分組。類似Java 中package和class的
          關系。為可能出現的同名Action提供了命名空間上的隔離。
          同時,package還支持繼承關系。在這里的定義中,我們可以看到:
          extends="webwork-default"
          "webwork-default"是webwork-default.xml文件中定義的package,這里通
          過繼承,"default" package 自動擁有"webwork-default" package 中的所有
          定義關系。這個特性為我們的配置帶來了極大便利。在實際開發過程中,我們可以根據自身的應用特點,定義相應的package模板,并在各個項目中加以重用,無需再在重復繁瑣的配置過程中消耗精力和時間。
          此外,我們還可以在Package節點中指定namespace,將我們的action分為若干個
          邏輯區間。如:
          <package name="default" namespace="/user"
          extends="webwork-default">
          就將此package中的action定義劃歸為/user 區間,之后在頁面調用action的時候,
          我們需要用/user/login.action 作為form action 的屬性值。其中的/user/就指定了此
          action的namespace,通過這樣的機制,我們可以將系統內的action進行邏輯分類,
          從而使得各模塊之間的劃分更加清晰。
          ⑶ action
          Action配置節點,這里可以設定Action的名稱和對應實現類。
          ⑷ result
          通過result 節點,可以定義Action 返回語義,即根據返回值,決定處理模式以及
          響應界面。
          這里,返回值"success"(Action 調用返回值為String 類型)對應的處理模式為
          "dispatcher"。
          可選的處理模式還有:
          1. dispatcher
          本系統頁面間轉向。類似forward。
          2. redirect
          瀏覽器跳轉。可轉向其他系統頁面。
          3. chain
          將處理結果轉交給另外一個Action處理,以實現Action的鏈式處理。
          4. velocity
          將指定的velocity模板作為結果呈現界面。
          5. xslt
          將指定的XSLT 作為結果呈現界面。
          隨后的param節點則設定了相匹配的資源名稱。
          ⑷ interceptor-ref
          設定了施加于此Action的攔截器(interceptor)。關于攔截器,請參見稍后的“XWork攔截器體系”部。
          interceptor-ref定義的是一個攔截器的應用,具體的攔截器設定,實際上是繼
          承于webwork-default package,我們可以在webwork-default.xml 中找到
          對應的"params"和"model-driven"攔截器設置:
          <interceptors>
          ……
          <interceptor name="params"class="com.opensymphony.xwork.interceptor.ParametersInt
          erceptor" />
          <interceptor name="model-driven"
          class="com.opensymphony.xwork.interceptor.ModelDrivenIn
          terceptor" />
          ……
          </interceptors>
          "params"大概是Webwork 中最重要、也最常用的一個Interceptor。上面曾經將
          MVC工作流程劃分為幾個步驟,其中的第一步:
          “將Web 頁面中的輸入元素封裝為一個(請求)數據對象”
          就是通過"params"攔截器完成。Interceptor 將在Action 之前被調用,因而,
          Interceptor 也成為將Webwork傳來的MAP 格式的數據轉換為強類型Java 對象的
          最佳實現場所。
          "model-driven"則是針對Action 的Model驅動模式的interceptor 實現。具體描
          述請參見稍后的“Action驅動模式”部分很可能我們的Action 都需要對這兩個interceptor 進行引用。我們可以定義一個interceptor-stack,將其作為一個interceptor 組合在所有Action 中引用。如,上面的配置文件可修改為:
          <xwork>
          <include file="webwork-default.xml" />
          <package name="default" extends="webwork-default">
          <interceptors>
          <interceptor-stack name="modelParamsStack">
          <interceptor-ref name="params" />
          <interceptor-ref name="model-driven" />
          </interceptor-stack>
          </interceptors>
          <action name="login" class="net.xiaxin.webwork.action.LoginAction">
          <result name="success" type="dispatcher">
          <param name="location">/main.jsp</param>
          </result>
          <result name="loginfail" type="dispatcher">
          <param name="location">/index.jsp</param>
          </result>
          <interceptor-ref name="modelParamsStack" />
          </action>
          </package>
          </xwork>
          通過引入interceptor-stack,我們可以減少interceptor 的重復申明。
          下面是我們的Model對象:
          LoginInfo.java:
          public class LoginInfo {
          private String password;
          private String username;
          private List messages = new ArrayList();
          private String errorMessage;
          public List getMessages() {
          return messages;
          }
          public String getErrorMessage() {
          return errorMessage;
          }
          public void setErrorMessage(String errorMessage) {
          this.errorMessage = errorMessage;
          }
          public String getPassword() {
          return password;
          }
          public void setPassword(String password) {
          this.password = password;
          }
          public String getUsername() {
          return username;
          }
          public void setUsername(String username) {
          this.username = username;
          }
          }
          很簡單,這只是一個純粹的值對象(Value-Object)。這里,它扮演著模型(Model)的角色,并與Action的輸入輸出密切相關。與Spring MVC中的Command對象不同,Webwork 中的Model對象,扮演著承上啟下的角色,它既是Action的輸入參數,又包含了Action處理的結果數據。
          換句話說,輸入的Http請求參數,將被存儲在Model對象傳遞給Action進行處理,Action處理完畢之后,也將結果數據放置到Model 對象中,之后,Model 對象與返回界面融合生成最后的反饋頁面。也正由于此,筆者建議在實際開發中采用Model-Driven 模式,而非Property-Driven 模式(見稍后“Action驅動模式”部分),這將使得業務邏輯更加清晰可讀。
          對應的Action代碼
          public class LoginAction implements Action, ModelDriven {
          private final static String LOGIN_FAIL="loginfail";
          LoginInfo loginInfo = new LoginInfo();
          public String execute() throws Exception {
          if ("erica".equalsIgnoreCase(loginInfo.getUsername())
          && "mypass".equals(loginInfo.getPassword())) {
          //將當前登錄的用戶名保存到Session
          ActionContext ctx = ActionContext.getContext();
          Map session = ctx.getSession();
          session.put("username",loginInfo.getUsername());
          //出于演示目的,通過硬編碼增加通知消息以供顯示
          loginInfo.getMessages().add("message1");
          loginInfo.getMessages().add("message2");
          loginInfo.getMessages().add("message3");
          return SUCCESS;
          }else{
          loginInfo.setErrorMessage("Username/Password Error!");
          return LOGIN_FAIL;
          }
          }
          public Object getModel() {
          return loginInfo;
          }
          }
          可以看到,LoginAction實現了兩個接口:
          1. Action
          Action接口非常簡單,它指定了Action的入口方法(execute),并定義了
          幾個默認的返回值常量:
          public interface Action extends Serializable {
          public static final String SUCCESS = "success";
          public static final String NONE = "none";
          public static final String ERROR = "error";
          public static final String INPUT = "input";
          public static final String LOGIN = "login";
          public String execute() throws Exception;
          }
          private final static String LOGIN_FAIL="loginfail";
          LoginInfo loginInfo = new LoginInfo();
          public String execute() throws Exception {
          if ("erica".equalsIgnoreCase(loginInfo.getUsername())
          && "mypass".equals(loginInfo.getPassword())) {
          //將當前登錄的用戶名保存到Session
          ActionContext ctx = ActionContext.getContext();
          Map session = ctx.getSession();
          session.put("username",loginInfo.getUsername());
          //出于演示目的,通過硬編碼增加通知消息以供顯示
          loginInfo.getMessages().add("message1");
          loginInfo.getMessages().add("message2");
          loginInfo.getMessages().add("message3");
          return SUCCESS;
          }else{
          loginInfo.setErrorMessage("Username/Password Error!");
          return LOGIN_FAIL;
          }
          }
          public Object getModel() {
          return loginInfo;
          }
          }
          可以看到,LoginAction實現了兩個接口:
          1. Action
          Action接口非常簡單,它指定了Action的入口方法(execute),并定義了
          幾個默認的返回值常量:
          public interface Action extends Serializable {
          public static final String SUCCESS = "success";
          public static final String NONE = "none";
          public static final String ERROR = "error";
          public static final String INPUT = "input";
          public static final String LOGIN = "login";
          public String execute() throws Exception;
          }
          SUCCESS、NONE、ERROR、INPUT、LOGIN 幾個字符串常量定義了常用的
          幾類返回值。我們可以在Action 實現中定義自己的返回類型,如本例中的
          LOGIN_FAIL定義。
          而execute方法,則是Action的入口方法,XWork將調用每個Action的execute
          方法以完成業務邏輯處理。
          2. ModelDriven
          ModelDriven接口更為簡潔:
          public interface ModelDriven {
          Object getModel();
          }
          ModelDriven僅僅定義了一個getModel方法。XWork在調度Action時,將通
          過此方法獲取Model 對象實例,并根據請求參數為其設定屬性值。而此后的
          頁面返回過程中,XWork 也將調用此方法獲取Model 對象實例并將其與設定
          的返回界面相融合。
          注意這里與Spring MVC 不同,Spring MVC 會自動為邏輯處理單元創建
          Command Class實例,但Webwork不會自動為Action創建Model對象實例,
          Model 對象實例的創建需要我們在Action 代碼中完成(如LoginAction 中
          LoginInfo對象實例的創建)。
          另外,如代碼注釋中所描述,登錄成功之后,我們隨即將username保存在Session之中,這也是大多數登錄操作必不可少的一個操作過程。
          這里面牽涉到了Webwork中的一個重要組成部分:ActionContext。
          ActionContext為Action提供了與容器交互的途徑。對于Web 應用而言,與容器的交互大多集中在Session、Parameter,通過ActionContext我們在代碼中實現與Servlet API無關的容器交互。
          如上面代碼中的:
          ActionContext ctx = ActionContext.getContext();
          Map session = ctx.getSession();
          session.put("username",loginInfo.getUsername());
          同樣,我們也可以操作Parameter:
          ActionContext ctx = ActionContext.getContext();
          Map params = ctx.getParameters();
          String username = ctx.getParameters("username");
          上述的操作,將由XWork根據當前環境,調用容器相關的訪問組件(Web 應用對應的就是Webwork)完成。上面的ActionContext.getSession(),XWork 實際上將通過Webwork提供的容器訪問代碼“HttpServletRequest.getSession()”完成。
          注意到,ActionContext.getSession返回的是一個Map類型的數據對象,而非HttpSession。這是由于WebWork對HttpSession進行了轉換,使其轉變為與Servlet API無關的Map對象。通過這樣的方式,保證了Xwork 所面向的是一個通用的開放結構。從而使得邏輯層與表現層無關。增加了代碼重用的可能。此外, 為了提供與Web 容器直接交互的可能。WebWork 還提供了一個ServletActionContext實現。它擴展了ActionContext,提供了直接面向Servlet API的容器訪問機制。
          我們可以直接通過ServletActionContext.getRequest 得到當前HttpServletRequest 對象的引用,從而直接與Web 容器交互。
          獲得如此靈活性的代價就是,我們的代碼從此與ServletAPI 緊密耦合,之后系統在不同平臺之間移植就將面臨更多的挑戰(同時單元測試也難于進行)。
          平臺移植的需求并不是每個應用都具備。大部分系統在設計階段就已經確定其運行平臺,且無太多變更的可能。不過,如果條件允許,盡量通過ActionContext 與容器交互,而不是平臺相關的ServletActionContext,這樣在順利實現功能的同時,也獲得了平臺遷移上的潛在優勢,何樂而不為。
          登錄成功界面:
          main.jsp:
          <%@ taglib prefix="ww" uri="webwork"%>
          <html>
          <body>
          <p align="center">Login Success!</p>
          <p align="center">Welcome!
          <ww:property value="#session['username']"/>
          </p>
          <p align="center">
          <b>Messages:</b><br>
          <ww:iterator value="messages" status="index">
          <ww:if test="#index.odd == true">
          !<ww:property/><br>
          </ww:if>
          <ww:else>
          *<ww:property/><br>
          </ww:else>
          </ww:iterator>
          </p>
          </body>
          </html>
          這里我們引入了Webwork的taglib,如頁面代碼第一行的申明語句。
          下面主要使用了三個tag:
          ? <ww:property value="#session['username']"/>
          讀取Model對象的屬性填充到當前位置。
          value指定了需要讀取的Model對象的屬性名。
          這里我們引用了LoginAction在session中保存的’username’對象。
          由于對應的Model(LoginInfo)中也保存了username 屬性。下面的語句與之
          效果相同:
          <ww:property value="username"/>
          與JSP2 中的EL類似,對于級聯對象,這里我們也可以通過“.”操作符獲得
          其屬性值,如value="user.username"將得到Model 對象中所引用的user
          對象的username 屬性(假設LoginInfo中包含一個User 對象,并擁有一個名
          為“username”的屬性)。
          關于EL的內容比較簡單,本文就不再單獨開辟章節進行探討。
          Webwork中包括以下幾種特殊的EL表達式:
          2 parameter[‘username’] 相當于request.getParameter(“username”);
          2 request[‘username’] 相當于request.getAttribute(“username”);
          2 session[‘username’] 從session中取出以“username”為key的值
          2 application[‘username’] 從ServletContext中取出以“username”為key
          的值
          注意需要用“#”操作符引用這些特殊表達式。
          另外對于常量,需要用單引號包圍,如#session['username'] 中的
          'username'。
          ? <ww:iterator value="messages" status="index">
          迭代器。用于對java.util.Collection、java.util.Iterator、java.util.Enumeration,、
          java.util.Map、Array類型的數據集進行循環處理。
          其中,value屬性的語義與<ww:property>中一致。
          而status屬性則指定了循環中的索引變量,在循環中,它將自動遞增。
          而在下面的<ww:if>中,我們通過“#”操作符引用這個索引變量的值。
          索引變量提供了以下幾個常用判定方法:
          2 first 當前是否為首次迭代
          2 last 當前是否為最后一次迭代
          2 odd 當前迭代次數是否奇數
          2 even 當前迭代次數是否偶數
          ? <ww:if test="#index.odd == true">和<ww:else>
          用于條件判定。
          test屬性指定了判定表達式。表達式中可通過“#”操作符對變量進行引用。
          表達式的編寫語法與java 表達式類似。
          類似的,還有<ww:elseif test="……">。

          登錄失敗界面
          實際上,這個界面即登錄界面index.jsp。只是由于之前出于避免干擾的考慮,隱藏了index.jsp中顯示錯誤信息的部分。
          完整的index.jsp如下:
          <%@ page pageEncoding="gb2312"
          contentType="text/html;charset=gb2312"%>
          <%@ taglib prefix="ww" uri="webwork"%>
          <html>
          <body>
          <form action="/login.action">
          <p align="center">
          登錄<br>
          <ww:if test="errorMessage != null">
          <font color="red">
          <ww:property value="errorMessage"/>
          </font>
          </ww:if>
          </p>
          用戶名:
          <input type="text" name="model.username" />
          <br>
          密碼:
          <input type="password" name="model.password" />
          <br>
          <p align="center">
          <input type="submit" value="提交" name="B1"/>
          <input type="reset" value="重置" name="B2"/>
          </p>
          </form>
          </body>
          </html>
          這里首先我們進行判斷,如果Model中的errorMessage不為null,則顯示錯誤信息。這樣,在用戶第一次登錄時,由于Model對象尚未創建,errorMessage自然為null,錯誤信息不會顯示,即得到了與之前的index.jsp同樣的效果。

          posted @ 2005-10-08 11:23 wash 閱讀(545) | 評論 (0)編輯 收藏

          僅列出標題
          共2頁: 上一頁 1 2 
          主站蜘蛛池模板: 柳河县| 龙胜| 建平县| 五家渠市| 成都市| 嘉禾县| 唐海县| 台湾省| 海丰县| 邢台市| 涿鹿县| 昌乐县| 义马市| 高台县| 浮山县| 盐城市| 长沙市| 安阳县| 高密市| 翼城县| 阿勒泰市| 独山县| 宜阳县| 洪泽县| 开江县| 武宣县| 连山| 绥江县| 明溪县| 尼勒克县| 理塘县| 吴桥县| 枞阳县| 景泰县| 鄯善县| 方正县| 清丰县| 太康县| 百色市| 乌恰县| 色达县|