posts - 14,  comments - 37,  trackbacks - 0
          appfuse 的web包下有這么幾個包
          org.appfuse.webapp.action:
          org.appfuse.webapp.filter:
          org.appfuse.webapp.listerner:
          org.appfuse.webapp.taglib:
          org.appfuse.webapp.util
          jsf 它有自己的配制文件  位于/ WEB-INF/faces-config.xml。在appfuse 的此文件中我們可以看到在
          faces-config 下幾種標記
          application,navigation-rule,managed-bean,render-kit..
          在application 下面定義了一個元素:
          <variable-resolver>org.springframework.web.jsf.DelegatingVariableResolver </variable-resolver>


          這個是為了與spring集成而加進來的, 在之前jsf 與spring 的集成是通過:
          ApplicationContext ctx =FacesContextUtils.getWebApplicationContext( FacesContext.getCurrentInstance());
          的方式在jsf的
          managed-bean里調用spring配置文件中的bean.或者通過jsf-spring這個項目開發的第三方軟件的方式.現
          在通過spring的提供
          的VariableResolver,我們在jsf的f配制文件里就可以像spring的配制文件一樣在它里邊配置類與類的依
          賴關系.比如:
          <managed-bean>
                  
          <managed-bean-name>userList</managed-bean-name>
                  
          <managed-bean-class>org.appfuse.webapp.action.UserList </managed-bean-class>
                  
          <managed-bean-scope>request</managed-bean-scope> 
                  
          <managed-property>
                      
          <property-name>userManager</property-name>
                      
          <value>#{userManager}</value> 
                  
          </managed-property>
              
          </managed-bean> 

          可以看到managed-bean的屬性中的userManager 的值為#{userManager} 表示jsf這個managed-bean的屬性
          userManager是spring
          配制文件中的名為 "userManager"的bean.可以看到通過這種方法把spring的IOC的理念引入了JSF中 .
          在application 下還有locale-config和message-bundle標簽是和這個應用的國際化文件相關的配制.在這
          里表示國際化文件名為
          ApplicationResources.默認是英文.支持en,es,fr,nl,pt_BR,zh_CN這幾種locale.
          然后是<navigation-rule>例如:
          <navigation-rule>
                  
          <from-view-id>/users.jsp</from-view-id>
                  
          <navigation-case>
                      
          <from-outcome>add</from-outcome>
                      
          <to-view-id>/userProfile.jsp</to-view-id>
                  
          </navigation-case>
              
          </navigation-rule>

              這個是定義頁面導航的相關配置. 上述配制的含義為 如果當前是 user.jsp頁面.此時如果頁面轉發
          的名為add,就會返回userProfile.jsp
              頁面.
              然后是<managed-bean>例如.
              
          <managed-bean>
                  
          <managed-bean-name>basePage</managed-bean-name>
                  
          <managed-bean-class>org.appfuse.webapp.action.BasePage</managed-bean-class> 
                  
          <managed-bean-scope>request</managed-bean-scope>
              
          </managed-bean>

          它定義了jsf中所使用的bean.在JSF中我們可以把一個html元素與一個managed-bean的某個屬性相綁定.也
          可以把某個按鈕的觸發事件與
          一個managed-bean的某個方法相關聯.相對于struts來說,個人認為JSF更簡單了.而且處理業務的時候我們
          可以更好的利用面向對象的觀點
          頁面之間的關系被映射成與它相綁定的類與類之間的關系.與它相比struts有點面向過程的意味.與JSF類
          似的框架是tapestry. tapestry是通過
          一個單獨的xml格式的配制文件來配置html元素與類的屬性的關系.而jsf是在頁面的直接通過JSF標簽屬性
          來綁定,總之他們都是面向組件,事件
          觸發的,而struts則是表單提交的方式,而且提交的數據局限于有限的幾種格式.比如不能在form里定義
          date類型的屬性.(date類型form提交不過去)
          除非像appfuse的struts版本那樣定義一個action然后在它里邊加上
          static {
                  ConvertUtils.register(
          new CurrencyConverter(), Double.class);
                  ConvertUtils.register(
          new DateConverter(), Date.class );
           

          然后所有的action從它繼承.  在jsf 不存在這個問題.可以直接把managed-bean 的一個類型為date 或
          double的屬性與一個表單元素綁定.
          還有一個名為render-kit 的元素.它里邊定義了一個renderer.這個是jsf定義的裝飾器.
                
          <renderer>
                   
          <description>Replacement renderer for h:outputLabel</description>
                   
          <component-family>javax.faces.Output</component-family> 
                   
          <renderer-type>javax.faces.Label</renderer-type>
                   
          <renderer-class>org.appfuse.webapp.action.LabelRenderer</renderer-class>
                
          </renderer>

                對于jsf 的所有輸出的label 都通過用戶定義的LabeRenderer來修飾. 打開
          org.appfuse.webapp.action.LabelRenderer
                這個類我們會看到這個是用來修飾表單中的那些必填項的標簽的。
          org.appfuse.webapp.action包下主要是:managed-bean
          CountryModel是一個和國家相關的類.在它里邊聲明了一個內部類.
          LabelValueComparator實現Comparator接口.此類有一個帶一個參數的構造函數.和一個類型為Comparator
          的屬性c
          .實現了Comparator接口的compare方法.它的構造函數為 LabelValueComparator(Locale locale),具體的
          實現為
          c = Collator.getInstance (locale);Collator 執行國別敏感的 String比較.在compare  里的實現是
          c.compare(lhs.getLabel(), rhs.getLabel());可以看到比較的元素是label.
          CountryModel里還有一個方法.getCountries(Locale locale)這個方法是把操作系統所有的有效的locale
          放到一個l類型為
          ArrayList的集合countries里., 然后通過它定義的那個內部類的比較規則把countries里的元素進行比較
          排序.最后把這個結果
          集放到一個Map里.在JSF中Map中的元素可以被select 組件直接使用.
          BasePage是定義的一個基本的類,它定義了managed-bean 應該有的共同的屬性。其他的一些bean繼承它

          在它的構造函數里把JSF的上下文賦給了他自己的上下文變量facesContext.通過facesContext可以取得一
          些jsp/servlet 所
          擁有的對象,如request,response.
          它還有一個名為setFacesContext的方法,這個主要是在測試的時候設置bean的上下文。
          setUserManager 方法主要是設置這個bean 的userManager對象。當然在這里主要是為了與在faces-
          config.xml 里的屬性
          userManager對應。例如:
          <managed-bean>
                  
          <managed-bean-name>userList</managed-bean-name>
                  
          <managed-bean-class> org.appfuse.webapp.action.UserList</managed-bean-class> 
                  
          <managed-bean-scope>request</managed-bean-scope>
                  
          <managed-property>
                      
          <property-name>userManager</property-name> 
                      
          <value>#{userManager}</value> 
                  
          </managed-property>
            
          </managed-bean>

              userList是繼承于BsePage的。所以它也有setUserManager方法。在這里配置屬性userManager
              的值為#{userManager},具體的實現還有通過setUserManager (UserManager userManager)這個方法
              來實現的。    setMailEngine(),setMessage(),setTemplateName()與setUserManager ()類似。
              getRequest(),getSession(),getResponse(),getServletContext(),都是直接或間接通過
          facesContext 取得的。
              getParameter() 此方法就是從request范圍內取根據輸入參數名取出對象。
              getBundleName()和getBundle()兩個合起來完成一件事情就是通過jstl的方式,根據locale 來取得
          ResourceBundle
              對象。因為jsf相關的操作比較復雜。
          具體實現是這樣的。在web.xml里 配制了如下上下文參數
          <context-param>
                  
          <param-name>javax.servlet.jsp.jstl.fmt.localizationContext </param-name>
                  
          <param-value>ApplicationResources</param-value> 
          </context-param>

          然后在BasePage里定義了如下一些東東。
          public static final String jstlBundleParam = "javax.servlet.jsp.jstl.fmt.localizationContext
          ";(就是前面定義的參數名)
          然后就是方法getBundleName()它是通過getServletContext().getInitParameter(jstlBundleParam);來
          把參數的值取出來。
          它返回的就是<param-value>中指定的ApplicationResources。然后通過getBundle()方法根據locale來取
          得ResourceBundle
          ResourceBundle.getBundle (getBundleName(), getRequest().getLocale());.當然這些ResourceBundle
          文件是放在/WEB-INF/
          classes/下的.
          getText(String key) 就是在前面取得的ResourceBundle里根據key來取得對應的值.
          getText(String key, Object arg)的作用就是針對有{0},{1},{2},{3} 這種信息處理的.通過key從
          ResourceBundle里取到信息值 ,然后
          通過arg 對象填寫里邊的參數.
          例如 key 的值為 "{0} 為無效信用卡號"。arg 為"12345" 最后的返回"12345 為無效信用卡號"
          addMessage(String key, Object arg)這個方法是因為jsf有缺陷.當程序重定向后消息就丟失了,所以在
          這里appfuse
          自己寫了一個方法.它從session里找"messages"對象, 如果沒有找到就新建一個arrayList賦給messages.
          然后通過getText(key, arg)把消息取出后添加
          到messages里.然后把它放到session 的messages里.
          addMessage(String key) 就是addMessage(key, null);
          addError(String key, Object arg)和addError(String key)類似于上面的兩個方法.只是放在session
          范圍內的"errors"里.
          boolean hasErrors()就是判斷在session范圍內有沒有"errors"對象.
          sendUserMessage(User user, String msg, String url)調用在service包中定義的MailEngine類的相關
          方法發送郵件信息
          getConfiguration()方法是從 ServletContext范圍里找"Constants.CONFIG"對象放到Map里返回.
          getCountries()調用在CoutryModel中定義的方法,把國家信息放到一個Map返回.
          FileUpload類是與上傳文件相關的類.它有name 和file兩個屬性.以及和他們對應的get和set方法.這兩個
          屬性是與前臺html
          元素綁定的.當然綁定是通過與他們對應的get 和set方法來實現的.
          在這個類中還有一個名為upload()的方法.此方法用來處理上傳文件事件.把上傳的文件放到/resource/"
          用戶名"/下.
          個人認為這個方法寫的有問題..比如我們上傳一個文件上傳不上去.tomcat會報錯.主要原因是這行代碼:
          OutputStream bos =new FileOutputStream(uploadDir + file.getName());其中uploadDir是我們定義的
          資源存放位置,后邊的哪個
           file.getName()其實是包含路徑的.所以會報類似如下的錯誤:
          Caused by: java.io.FileNotFoundException: H:\apache-tomcat-5.5.12\apache-tomcat-
          5.5.12\webapps\myapp\resources\mraible\D:\costviewdetail.jsp (文件名、目錄名或卷標語法不正確
          。)
          修改如下:
          OutputStream bos = new FileOutputStream(uploadDir + this.getName());就是文件名設為我們填寫的
          重命名名稱.
          還有兩個地方要同時修改。
           request.setAttribute ("location", dirPath.getAbsolutePath() + Constants.FILE_SEP
          +this.getName());                     
          request.setAttribute("link", link + this.getName());
          都是把 file.getName()替換成 this.getName()。
                    
           LabelRenderer就是前邊提到的裝飾器。
           具體工作原理如下,先把組件的所有屬性取出來,然后找它的for屬性。放到String id里。然后根據此
          id,找相應的
           輸入組件。如果找到。而且此組件的類型為required 則輸出一個 "*" 一個空格"&nbsp;"然后開始輸出
          此label標簽
           如果程序這個component 指定了class就以指定的class顯示label如果沒有指定class就以requreid 的
          class顯示
           此label.然后判斷input是否為空,如果不為空把input.getClientId(context)的值放到String
          renderedId里,否則把
           component.getClientId(context) 賦給 renderedId。然后輸出把 renderedId作為for的屬性值輸出。
          最后輸出value
           的值。
           encodeEnd方法的操作如下,字符串marker里寫 ":"如果label的value字段為空。marker賦值"" 然后輸
          出marker.然后結束
           label輸出。
           
           總之這個裝飾器的作用是如果label中的for 所指的對象的是required 的就在它顯示的value前輸出* 空
          格。它也允許輸出value
           為空的label.
           還有一個hasMessages()的方法,用來判斷這個label是否有message.
           passwordHint 負責處理與密碼提示相關的操作它繼承于BasePage。
          它有一個username 屬性以及對應的get和set方法。可以把它和頁面元素綁定。
          還有個名為execute的方法。它負責向用戶發送郵件。
          這個類在faces-config.xml中的配置為
          <managed-bean>
                  
          <managed-bean-name>passwordHint</managed-bean-name> 
                  
          <managed-bean-class>org.jsfdemo.webapp.action.PasswordHint</managed-bean-class>
                  
          <managed-bean-scope>request</managed-bean-scope>
                  
          <managed-property>
                    
          <property-name>username</property-name> 
                    
          <value>#{param.username}</value>
                  
          </managed-property>
                  
          <managed-property>
                      
          <property-name>userManager</property-name>
                      
          <value>#{userManager}</value> 
                  
          </managed-property>
                  
          <managed-property>
                      
          <property-name>mailEngine</property-name>
                      
          <value>#{mailEngine}</value>
                  
          </managed-property> 
                  
          <managed-property>
                      
          <property-name>message</property-name>
                      
          <value>#{mailMessage}</value>
                  
          </managed-property>
                  
          <managed-property> 
                      
          <property-name>templateName</property-name>
                      
          <value>accountCreated.vm</value>
                  
          </managed-property>
              
          </managed-bean>

          這個bean存在的范圍為request然后,依賴注入userManager mailEngine message
          templateName,前三個是在spring中配置的bean.最后一個是在/WEB-INF/classes下
          定義的模板。
          Reload 繼承于BasePage 它有一個名為execute的方法。此方法在內部調用StartupListerner的
          靜態方法setupContext(),然后添加一條reload.successded 消息。然后返回"mainMenu"
          SignupForm 繼承BasePage 它有user 和roleManager兩個屬性。以及對應的set和get方法。
          roleManger屬性沒有get方法。
          還有getCountry() 和setCountry(String)這兩個方法處理的是user中的address中的country字段
          save()方法的具體流程如下。它先調用從BasePage里繼承的getConfiguration()方法。從servletContext
          里的Constants.CONFIG里把相關的信息放到一個Map里。然后再從Map里的Constants.ENC_ALGORITHM里取

          算法名放到algorithm里。如果算法名為空。則algorithm="SHA"。調用StringUtil的encodePassword方法
          加密用戶的密碼,加密算法為algorithm。然后把用戶的密碼設為這個加密后的值。然后把用戶的enable
          字段
          設為true.用戶的角色設為Constants.USER_ROLE .然后調用userManager把這個用戶存到數據庫中。
          在session范圍內設一個registed屬性。通過acegi security框架提供的authentication的一個具體實現

          UsernamePasswordAuthentictionToken(,)和用戶的用戶名和密碼,創建一個Authentication對象auth.
          然后通過WebApplicationContextUtils獲得ApplicationContext對象ctx.通過ctx獲得bean
          "authenticationManager"
          賦予類型為ProviderManager的authenticationManager對象。然后調用authenticationManager的
          doAuthentication()
          方法驗證auth.把此方法返回的authentication對象放到SecurityContextHolder擁有的SecurityContext
          對象的authentication
          屬性里。然后調用從BasePage里繼承的方法sendUserMessage給用戶發送確認信息。返回"mainMenu".在
          faces-config.xml
          中與此bean對應的相關配置類似于passwordHit.
          UserForm這個類繼承了類BasePage.它有屬性roleManager,from,username,user,availableRoles以及與它
          們對應的
          set和get方法。
          cancel()方法
          它通過StringUtils這個類提供的equals方法來比較request范圍內的"from"是否等于list.如果是,返
          回"mainMenu".否則返回cancel.
          edit()方法
          如果屬性值username不為空,通過userManager的getUser方法,以username為主鍵取user放到屬性user里

          否則以request.getRemoteUser()為主鍵取user.其他情況new 一個User對象。然后給這個對象添加一個角
          色Constants.USER_ROLE
          如果不是剛剛新建的用戶,user.setConfirmPassword(user.getPassword ());
          通過AuthenticationTrustResolver的實現類創建一個AuthenticationTrustResolver對象resovlver.
          通過SecurityContextHolder對象獲得SecurityContext 對象ctx.
          如果ctx不為null.從它里邊取出authentication對象。然后通過resolver 判斷此authentication對象的
          類型是否是rememberMe。
          如果是,在session里設置屬性cookieLogin的值為true.然后調用從超類那里繼承的addMessage方法添加
          一條"userProfile.cookieLogin"
          的消息。然后返回"editProfile".
          save()方法
          通過屬性user獲得用戶密碼password。通過getParameter("userForm:originalPassword")獲得用戶原來
          的密碼,
          通過getConfiguration().get(Constants.ENCRYPT_PASSWORD);取得保存在ServletContext范圍內的屬性
          Constants.CONFIG的值放在一個Map
          里,然后從此Map中取與屬性Constants.ENCRYPT_PASSWORD對應的值。如果這個值為true.而且從request
          范圍取得的與encryptPass屬性相
          對應的值也為true.或者password和originalPassword不等,則從servletContext范圍內,取得與
          Constants.CONFIG對應的Map.從此Map中取得與
          Constants.ENC_ALGORITHM對應的值賦予algorithm.如果algorithm為null,algorithm為SHA.
          然后調用StringUtil.encodePassword (password, algorithm)加密passoword賦給user的password屬性。
          通過getRequest().getParameterValues("userForm:userRoles")獲得用戶的角色集放到UserRolesl里。
          然后以UserRoles中的值為主鍵,
          循環取出Role對象賦予此用戶。
          然后調用userManager.saveUser(user).把此用戶保存到數據庫里。如果 此步出現錯誤,添加一條錯誤信
          息,返回"editProfile".
          判斷request范圍內的參數from的值是否為list.
          如果不是
           在session里把user賦給屬性Constants.USER_KEY(userform)。添加一條"user,saved"消息。返
          回"mainMenu"
          否則
           如果從request范圍內的parameter里取得的"userForm:version"值為"",添加一條消息addMessage("
          user.added", user.getFullName());
           XXXXX 添加成功。調用sendUserMessage給此用戶發郵件。返回list.
           否則
            添加一條 類似 XXXX被修改的消息,然后返回 "editProfile".
          delete()方法。
           根據getUser().getUsername()值通過userManager刪除此用戶。添加一條此用戶被刪除的消息。返
          回"list".
          getFrom()方法。
          如果用戶名不為空,或request參數"editUser:add"不為空,或者參數"from"等于"list" ,返回list.
          返回"";
          Map getAvailableRoles() 方法。
          如果此bean的屬性availableRoles為null. 從servletContext里取出屬性Constants.AVAILABLE_ROLES 的
          值。然后把
          它轉換成Map.賦予avaibleRoles.
          返回avaibleRoles.
          getUserRoles方法。
          把user 的Roles集合中的所有Role的名字放到一個字符數組里,返回。
          它在faces-config.xml中的定義如下:
            
          <managed-bean>
                  
          <managed-bean-name>userForm</managed-bean-name>
                  
          <managed-bean-class> org.appfuse.webapp.action.UserForm</managed-bean-class>
                  
          <managed-bean-scope>request</managed-bean-scope>
                  
          <managed-property>
                    
          <property-name>username</property-name> 
                    
          <value>#{param.username}</value>
                  
          </managed-property>
                  
          <managed-property>
                      
          <property-name>userManager</property-name>
                      
          <value>#{userManager}</value> 
                  
          </managed-property>
                  
          <managed-property>
                      
          <property-name>roleManager</property-name>
                      
          <value>#{roleManager}</value>
                  
          </managed-property> 
                  
          <managed-property>
                      
          <property-name>mailEngine</property-name>
                      
          <value>#{mailEngine}</value>
                  
          </managed-property>
                  
          <managed-property> 
                      
          <property-name>message</property-name>
                      
          <value>#{mailMessage}</value>
                  
          </managed-property>
                  
          <managed-property>
                      
          <property-name>templateName</property-name> 
                      
          <value>accountCreated.vm</value>
                  
          </managed-property>
              
          </managed-bean>
              UserList繼承于BasePage,它只定義了一個方法。
            
              public List getUsers() {
                  return userManager.getUsers(null);
              }
              返回所有用戶。
          org.appfuse.webapp.filter
          這個包下定義了一些過濾器
          首先是GZIPFilter繼承實現了spring提供的抽象類OncePerRequestFilter(每一次請求執行一次的過濾器)

          doFilterInternal方法。 這個類的作用是通過gzip來壓縮輸出流。
          private boolean isGZIPSupported(HttpServletRequest)
          通過request獲得TableTagParameters.PARAMETER_EXPORTING的屬性值。放到字符串exporting里。
          如果exporting不為null.說明此時是用displayTag以execel或xml或pdf的格式往外輸出表格內容。此時不
          應該
          壓縮輸出流。所以返回false.
          通過request獲得http 頭中的"accept-encoding"的屬性值。如果此值中有gzip這個字符串,support就為
          true.其他情況為false
          通過request獲得http 頭中的"user-agent"屬性值。如果此值是以httpunit開頭 返回false.(此時是進行
          頁面測試,不需要壓縮輸出流)。
          返回support.
          doFilterInternal(HttpServletRequest request, HttpServletResponse response,  FilterChain
          chain)
          調用前邊的方法判斷是否需要壓縮輸出流。
          如果需要
           新建 一個GZIPResponseWrapper(HttpServletResponse).對象把response 做為參數傳過去。 然后調用
            chain.doFilter (request, wrappedResponse);
             wrappedResponse.finishResponse();
          否則
           chain.doFilter (request, response);
           
          GZIPResponseStream繼承于ServletOutputStream.是實現對response進行 gzip 壓縮的最終實現類。
           GZIPResponseWrapper繼承了HttpServletResponseWrapper.是對GZIPResponseStream的一個包裝。
          類LocaleRequestWrapper繼承了HttpServletRequestWrapper。它有一個不可被繼承的屬性
          preferredLocale。
          在它的構造函數里把參數userLocale的值賦給preferredLocale.
          重構了getLocale()方法。如果preferredLocale 不為空,返回它,否則調用父類的方法。
          重構了父類的getLocales()方法。如果preferredLocale不為空,調用父類的方法取得Locales后放到一個
          列表里
          如果此列表中有preferredLocale.從列表中把它刪除把preferredLocale添加到此列表的開頭。返回.
          否則調用父類的getLocales()方法。
          LocaleFilter 繼承實現了OncePerRequestFilter 的doFilterInternal方法。
          在此方法中,先request獲得locale對象賦給字符串locale.如果locale不為null,通過字符串locale生成
          一個Locale賦給preferredLocale.
          然后獲取一個session對象 request.getSession(false);
           request.getSession (boolean)的參數有true和false兩個值,true為如果如果沒有相同的session則創
          建。如果有則覆蓋,
           false則沒有則創建有則不創建。
          如果preferredLocale為null,
           從Session范圍取得屬性Constants.PREFERRED_LOCALE_KEY的值賦予preferredLocale。
          如果preferredLocale不為null
           在Session范圍設置屬性Constants.PREFERRED_LOCALE_KEY 的值為preferredLocale。
           通過jstl的的Config在session范圍內設置fmt的local為preferredLocale.
                          Config.set(session, Config.FMT_LOCALE, preferredLocale);
          如果preferredLocale 不為null,request的類型是LocaleRequestWrapper。
          給request賦值new LocaleRequestWrapper(request, preferredLocale)。
          把spring的LocaleCOntextHolder的屬性Locale設為preferredLocale.
          然后是
           chain.doFilter(request, response);
           LocaleContextHolder.setLocaleContext(null);
          MessageFilter實現了Filter接口。
          實現了doFilter 方法。在此方法中,從session里取屬性messages的值。如果取到值,把這個值放到
          reques范圍內messages里.
          從session里刪掉這條屬性。
          對session范圍內的errors屬性執行類似操作。然后調用  chain.doFilter(req, res);
          重構init 和destroy方法,在這兩個方法里不執行任何代碼。
          org.appfuse.webapp.listener 這個包下是和監聽相關的類。
          StartupListener 這個類繼承于spring的ContextLoaderListener類,實現了ServletContextListener接
          口。
          方法setupContext
          通過   WebApplicationContextUtils.getRequiredWebApplicationContext(context) 獲得spring的上下
          文句柄ctx。
          通過ctx獲得bean "lookupManager"賦予LookupManager 對象mgr.然后把mgr.getAllRoles()做為
          Constants.AVAILABLE_ROLES的
          屬性值放到context里。
          覆蓋了父類的contextinitialized方法。
          首先調用父類的對應方法。然后根據輸入的參數ServletContextEvent獲得ServletContext對象。然后從
          它里邊獲取Constants.CONFIG
          對應的屬性值。放到Map  config里。通過
          WebApplicationContextUtils.getRequiredWebApplicationContext(context);獲得spring上下文
          ctx. 通過ctx獲得bean "authenticationManager".賦予ProviderManager對象實例provider.
          然后循環判斷provider 的屬性providers.如果它包含一個類型為RememberMeAuthenticationProvider的
          實例,就在config里放一條屬性
          "rememberMeEnabled",值為Boolean.TRUE.
          判斷是否在spring的配置文件里定義了名為"passwordEncoder"
          如果有 把encryptPassword賦值true.然后在config里添加屬性Constants.ENCRYPT_PASSWORD,值為
          Boolean.TRUE.如果spring配置文件
          中定義的"passwordEncoder" 的類型是Md5PasswordEncoder. algorithm 賦值MD5,其他情況下賦值SHA.
          然后在config 里添加一條屬性
          Constants.ENC_ALGORITHM .值為algorithm.
          然后把config做為Constants.CONFIG.的值放到context里。
          最后前邊介紹的setupContext(context)方法。
          總之這個類的作用就是在servletContext 根據實際情況設置 Constants.CONFIG屬性值。
          UserCounterlistener 這個類實現了ServletContextListener 和HttpSessionAttributeListener接口。
          它有幾個不可被繼承的屬性 COUNT_KEY,USERS_KEY,EVENT_KEY.有兩個被transient修飾的屬性
          log和ServletContext 修飾的屬性.(被transient修飾的屬性在對象序列化的過程中是不被包括的,比如
          把對象序列化保存到硬盤中的
          過程中,此屬性是不被保存的)。
          還有兩個私有屬性, counter(int 型數據)和users(Set 集合).
          實現了HttpSessionAttributeListener接口的 attributeAdded方法. 在這個方法中,程序先判斷參數
          event(類型為HttpSessionBindingEvent)
          的名字是否等于屬性EVENT_KEY的值
          (HttpSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY).
          如果相等,取event的值.然后賦給SecurityContext 對象securityContext.根據它取得authentication 屬
          性,把authentication對象中的principal
          賦給 User對象user.然后調用addUsername方法添加此用戶.
          實現了HttpSessionAttributeListener的attributeRemoved方法,在這個方法中先判斷event的名字是否為
          EVENT_KEY.如果是把event的值
          賦予SecurityContext對象securityContext.然后通過它取得儲存在它的屬性authentication中的
          principal對象賦予User對象user.然后調用
          removeUsername方法刪除此對象.
          實現了HttpSessionAttributeListener的attributeReplaced方法,但是在此方法中沒有任何代碼.
          公共方法contextInitialized(ServletContextEvent sce) 此方法被synchronized關鍵字修飾,表示此方
          法是線程互斥的.在
          此方法中,先通過
          輸入參數ServletContextEvent,獲得ServletContext對象.然后在ServletContext里添加屬性COUNT_KEY,
          值為counter的字符串形式表達.
          公共方法contextDestroyed,此方法是被synchronized 關鍵字修飾的,在此方法中給屬性
          servletContext,users 賦值null,counter 賦值0.
          friend 方法 incrementUserCounter() 此方法也是線程互斥的,它servletContext里把COUNT_KEY取出加
          一后再放回。(不寫范圍表達的方法就是friend,范圍是本包和子類)
          friend 方法decrementUserCounter 它的作用是把servletContext里的COUNT_KEY減一后再放回,當然它
          也是線程互斥的。
          friend 方法addUsername  此方法的作用是把把用戶添加到servletContext范圍內與屬性USERS_KEY對應
          的HashMap里。然后調用incrementUserCounter方法。這個方法也是線程互斥的。
          friend方法removeUsername 此方法的作用是把用戶從servletContext范圍內與屬性USER_KEY對應的
          HashMap中刪掉。然后調用decrementUserCounter方法。
          org.jsfdemo.webapp.taglib包下是appfuse自定義標簽相對應的類.
          首先看一下這個自定義標簽的tld文件 appfuse.tld.(這個文件會根據你的項目名而定)
          在這個文件里首先配置了兩個監聽類StartupListener 和UserCounterListener.
          然后定義了一個constants的tag.與這個tag對應的<tag-class>是ConstantsTag,對應的<tei-class>是
          ConstantsTei.并且定義了這個tag有三個屬性className,scope,var.
          其實這個標簽的作用是把一個了類放到scope指定的范圍里。
          類ConstantsTag繼承了TagSupport類
          它有clazz ,scope,var 三個屬性以及對應的set和get方法,通過這些可以讓標簽的屬性與具體的tag類的
          屬性關聯起來。即
          此自定義標簽的class ,scope 和var屬性與這里的clazz ,scope,var 對應。
          它有一個靜態的 不可被繼承的Map scopes.然后通過一個static 塊來初始化它如下:
          static {
                  scopes.put(
          "page"new Integer(PageContext.PAGE_SCOPE));
                  scopes.put(
          "request"new Integer(PageContext.REQUEST_SCOPE ));
                  scopes.put(
          "session"new Integer(PageContext.SESSION_SCOPE));
                  scopes.put(
          "application"new Integer(PageContext.APPLICATION_SCOPE));
              }

          因為使用的是jdk1.5所以這種寫法沒有錯誤 :)。
          getScope(String scopeName) 這個方法的作用就是通過從上邊定義的那個scopes里取與scopeName對應的
          值。返回的數據
          類型是int.
          覆蓋了TagSupport的 doStartTag方法,此方法的作用是把class 屬性指定的類中的var指定的屬性保存在
          scope所指定的范圍內。
          如果class 為空class的默認值是Constants。scope如果為空默認值是PageContext.PAGE_SCOPE,var如果
          為空則保存全部聲明的屬性。
          然后返回 SKIP_BODY(因為這個標簽沒有真文,所以不需要和正文發生交互,也不會判斷正文,所以返回
          SKIP_BODY).
          覆蓋了父類的release方法,在此方法中釋放占用資源。個人認為它的這個方法有誤(appfuse 1.9 jsf
          )應該是scope = null;而不是
          scope = Constants.class.getName();
          類ConstantsTei 繼承了TagExtraInfo 覆蓋了getVariableInfo方法。
            注: 通過擴展類javax.servlet.jsp.TagExtraInfo定義tag extra info類。一個TagExtraInfo必須實
          現getVariableInfo方法以返回包含下列信息的VariableInfo對象數組:
            變量名 ,變量類 ,變量是否引用新對象 , 變量可用性 。
            Web容器向getVariableInfo方法傳遞包含每一個標簽屬性的屬性-值元組的名為data的參數。這些屬性
          可以用于為VariableInfo對象提供腳本變量名和類。
          所以這個類是與腳本變量有關的。這個方法的作用是把class指定的類的var屬性,作為一個腳本變量返回
          。如果var為空,就對全部變量進行處理。
          返回的腳本變量的類型為String. 變量可以引用新對象,變量可用的范圍是VariableInfo.AT_END(在結束
          標簽之后直到頁面的結束 ).
           
          org.appfuse.webapp.util
          此包下是一些在web開發過程中用到的實用類。
          FacesUtils 類,這個類的所有方法都是靜態的。
          getServletContext() 通過Facescontext對象獲得servletContext對象。
          getJsfEl(String value) 這個 方法的作用是 返回 "#{" + value + "}";
          Application getApplication()
          這個方法通過 FactoryFinder 獲取application對象。
          FactoryFinder提供了查找在jsf API中定義的所有factory對象的算法。如果在 system 中有一個屬性與
          想要查找的factory同名,它的值就做為你想要查找的factory返回.在system 中沒有找到,如果在你的
          web 應用的資源路徑里找faces.properties文件。如果文件中包含與所要查找對象同名的屬性,這個屬性
          就做為這個factory執行類的名字。最后如果存在META-INF/services/{factory-class-name}資源文件(比
          如在lib包里的jar文件中)。讀此文件的第一行做為factory實現類的名字。
          factory Name有這么幾種
          APPLICATION_FACTORY------與ApplicationFactory對應的屬性名.
          FACES_CONTEXT_FACTORY----FacesContextFactory對應的屬性名.
          LIFECYCLE_FACTORY--------LifecycleFactory對應的屬性名.
          RENDER_KIT_FACTORY-------RenderKitFactory對應的屬性名.
          TREE_FACTORY-------------TreeFactory對應的屬性名.
          在這里通過FactoryFinder.getFactory(FactoryFinder.APPLICATION_FACTORY)獲得ApplicationFactory
          對象.然后再通過它獲得Application對象.
          getValueBinding(String el) 這個方法如下:
          return getApplication().createValueBinding(el);
          這個類是根據輸入的對象名創建一個ValueBinding對象.比如在jsf的配置文件里定義了一個managed bean
          "userBean",通過以下方式getValueBinding("#{userBean}")就創建了一個ValueBinding對象,通過此對象
          可以獲得userBean實例.
          getELValue(String el)這個方法如下:
          getValueBinding(el).getValue(FacesContext.getCurrentInstance());
          此方法就是獲得與el相對應的實例.
            
          getManagedBean(String beanName) 此方法代碼大體如下:
          getValueBinding(getJsfEl(beanName)).getValue( FacesContext.getCurrentInstance());
          :)就是通過前面定義的一系列方法獲得與beanName對應的 Managed bean實例.
          resetManagedBean 這個方法的作用是刪除與beanName對應的Managed bean.具體如下:
          getValueBinding(getJsfEl(beanName)).setValue(FacesContext.getCurrentInstance(),null); 
          setManagedBeanInSession(String beanName,Object managedBean)這個方法的作用是
          把managedBean 放到session范圍內的屬性beanName里。
          getRequestParameter(String name)  從 request范圍取得與parameter對應的參數。
          addInfoMessage(String clientId,String msg)給一個特定的客戶(由clientId指定)添加一條jsf消息,
          消息的安全程度是FacesMessage.SEVERITY_INFO.
          addInfoMessage(String msg) 這個方法就是添加一條jsf消息。如下:
          addInfoMessage(null, msg);
          addErrorMessage(String clientId, String msg)和 addErrorMessage(String msg)與前邊類似分別是給
          特定客戶添加一條錯誤消息和添加一條錯誤消息。
          evalInt(String el)
          這個方法是判斷參數el是不是某個對象的 jsf 表達,
          如果是,通過el構建ValueBinding對象,進而獲得此el對應的對象.如果是Integer 直接返回,否則把它轉換
          成Integer返回
          否則 返回Integer(el);
          還有 getRequest(),getResponse(),getSession()方法.
           RequestUtil 類的所有方法也是靜態的。
          setCookie(HttpServletResponse response, String name, String value, String path)
          這個是用來發送cookie的。以參數name 和value構建一個cookie,它是非安全的,路徑設為path.生命期為30天。然后添加到response里。
          getCookie(HttpServletRequest request, String name) 根據name 從參數request里找到相應的cookie.
          deleteCookie(HttpServletResponse response, Cookie cookie, String path)
          通過把生命周期設為0的方式刪除一個cookie.
          getAppURL(HttpServletRequest request)
          這個方法是通過request來獲得應用的URL.
          posted on 2007-07-12 10:43 冰封的愛 閱讀(1180) 評論(0)  編輯  收藏 所屬分類: J2EE
          <2025年7月>
          293012345
          6789101112
          13141516171819
          20212223242526
          272829303112
          3456789

          常用鏈接

          留言簿(3)

          隨筆檔案

          文章分類

          文章檔案

          相冊

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 太白县| 始兴县| 儋州市| 澳门| 海原县| 海伦市| 武隆县| 广河县| 北辰区| 卢氏县| 大竹县| 保山市| 讷河市| 迁安市| 内丘县| 伽师县| 岗巴县| 延川县| 贵州省| 拉孜县| 南岸区| 杨浦区| 青河县| 荣成市| 乌拉特前旗| 镇赉县| 岳池县| 孝义市| 孝昌县| 分宜县| 揭东县| 宣威市| 甘孜| 霞浦县| 建始县| 筠连县| 贵阳市| 那曲县| 景东| 大庆市| 克东县|