[心缘地方]同学录
首页 | 功能说明 | 站长通知 | 最近更新 | 编码查看转换 | 代码下载 | 常见问题及讨论 | 《深入解析ASP核心技术》 | 王小鸭自动发工资条VBA版
登录系统:用户名: 密码: 如果要讨论问题,请先注册。

[整理]seam_2_x_web_development读书笔记

上一篇:[整理]间接实现javascript以byref形式调用vbscript的function
下一篇:[备忘]SQL Server Lock Wait Types,SQL server锁的机制

添加日期:2010/4/13 7:42:26 快速返回   返回列表 阅读6366次
==============================================
Seam Page Flow

1.简单导航
在方法中直接返回URL
public String run(){
    return "/result.seam"
}
2.JSF风格导航

典型的JSF程序中,在faces-config.xml中定义page flow。
如:
<navigation-rule>
   <from-view-id>/myPage.jsp</from-view-id>
   <navigation-case>
      <from-outcome>success</from-outcome>
      <to-view-id>/success.jsp</to-view-id>
   </navigation-case>
   <navigation-case>
      <from-outcome>fail</from-outcome>
      <to-view-id>/failure.jsp</to-view-id>
   </navigation-case>
</navigation-rule>
<!—This navigaion rule defines global page flow -->
<navigation-rule>
   <navigation-case>
      <from-outcome>logout</from-outcome>
      <to-view-id>/logout.jsp</to-view-id>
   </navigation-case>
</navigation-rule>

Seam使用类似的机制,但是是在WEB-INF/的pages.xml中定义。
优点:可以传递参数,可以使用EL表达式。

可以拆分为多个xxx.page.xml,和JSP文件放在一起?

<?xml version="1.0" encoding="UTF-8"?>
<pages xmlns="http://jboss.com/products/seam/pages"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://jboss.com/products/seam/pages 
        http://jboss.com/products/seam/pages-2.1.xsd">
  <page view-id="/vacations.jsp">
    <navigation from-action= 
        "#{vacationManagerAction.selectVacationType}">
      <rule if-outcome="city">
        <redirect view-id="/city.jsp" />
      </rule>
    </navigation>
  </page>
</pages>

Page可以是范围的指定
<page view-id="/*">
<page view-id="/secure/*">

可以使用表达式
<rule if="#{destination.minimumBudget lt 100.0}">
  <redirect view-id="/insufficientfunds.jsp" />
</rule>

还可以捕捉异常
<exception class="com.davidsalter.HolidayException">
  <redirect view-id="/error.jsp">
    <message severity="ERROR">
      Whoops. Better make sure we write some better tests !
    </message>
  </redirect>
</exception>

但需要web.xml中有这一段才好使。
<filter>
  <filter-name>Seam Filter</filter-name>
    <filter-class>
      org.jboss.seam.servlet.SeamFilter
    </filter-class>
</filter>
<filter-mapping>
  <filter-name>Seam Filter</filter-name>
  <url-pattern>*.seam</url-pattern>
</filter-mapping>

渲染页面之前,执行action
<page view-id="/vacations.jsp"
  action="#{vacationManagerAction.beforeRender}">
</page>

可以执行多个
<page view-id="/vacations.jsp">
  <action execute="#{vacationManagerAction.beforeRender}" />
  <action execute="#{vacationManagerAction.doMore}" />
</page>

3.Seam jPDL导航
JBPM Process Defnition Language (jPDL)
================================================================================
Facelets
在JSF生存周期里负责管理Restore View和Render Response阶段

优点:模板,性能,EL function,XHTML,无脚本
(1)模板
<ui:composition/> 用在模板中,进行定义
<ui:insert/> 用在模板client中,即使用模板的地方
<ui:define/> 用在模板中,进行定义

<ui:composition xmlns="http://www.w3.org/1999/xhtml" 
   xmlns:ui="http://java.sun.com/jsf/facelets" 
   xmlns:f="http://java.sun.com/jsf/core" 
   xmlns:h="http://java.sun.com/jsf/html" 
   template="../layout/template.xhtml">   
  <ui:define name="body">     
    … HTML Content Defined Here
  </ui:define>   
  <ui:define name="footer">     
    … HTML Content Defined Here
  </ui:define>
</ui:composition>

<body>     
    <div class="body">
       <ui:insert name="body"/>
    </div>     
    <div class="footer">
       <ui:insert name="footer"/>
    </div>     
  </body>

传递参数:
<ui:include src="footer.xhtml" >
  <ui:param name="vacation" value="#{vacation}">
  <ui:param name="vacationPlanner" value="David">
</ui:include>

(3)EL function
在JSF页面中可以使用 JSF Expression Language (EL),
在FaceLets中,还可以使用EL function。
<h:inputText id="#{someText}" value="#{trim[someText]}">
</h:inputText>
使用了trim方法()

facelets支持的EL称为Unifed Expression Language。
http://java.sun.com/products/jsp/reference/techart/unifiedEL.html

(4)XHTML
facelets的页面是用xhtml形式的。
可以使用namespaces。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
   xmlns:ui="http://java.sun.com/jsf/facelets"
   xmlns:h="http://java.sun.com/jsf/html"
   xmlns:f="http://java.sun.com/jsf/core">

</html>
facelets默认会处理xhtml中的注释,并在页面源码中显示出来。
可以skip注释。
web.xml中
<context-param>
   <param-name>facelets.SKIP_COMMENTS</param-name>
   <param-value>true</param-value>
</context-param>

(5)无脚本
JSP中的这种写法在facelets中是不可以的,这样保证了view和业务逻辑的分离。
<% if validate() { %>
<b> Valid </b>
<% } else { %>
<b> Invalid</b>
<% } %>

配置方法:
facelets网站
https://facelets.dev.java.net

jsf-facelets.jar放在工程的classpath中。

web.xml中追加
<context-param>
    <param-name>javax.faces.DEFAULT_SUFFIX</param-name>
    <param-value>.xhtml</param-value>
  </context-param>

faces-config.xml中:
<application>
  <view-handler>
    com.sun.facelets.FaceletViewHandler
  </view-handler>  
 </application> 
==============================================
Seam Gen:
Seam提供的一个命令行的工具,可以生成Seam工程,for eclipse或netbean
<SEAM_HOME>/seam.bat

setup    Runs the setup wizard, which asks the user about the project 
that they are working on, such as which database drivers to use, 
the package name for classes, and so on. The answers are stored 
within the <SEAM_HOME>/seam-gen/build.properties fle.
The details specifed within this fle defne the current project.

create-project     Creates a Seam project using the defnitions stored within the 
<SEAM_HOME>/seam-gen/build.properties fle.

update-project     Updates the current project to use the latest Seam JAR fles.

delete-project     Deletes the current project.

archive     Builds the current project as either a WAR or a EAR fle, 
depending upon the project confguration options.

deploy         Deploys the current project to JBoss.

undeploy     Undeploys the current project from JBoss.

explode     Deploys the current project to JBoss as an exploded archive.

restart     Restarts the currently-exploded project.

unexploded     Undeploys the currently-exploded project.

new-action     Creates a new Seam action class.

new-form     Creates a new Seam action form and action class.

new-conversation     Creates a new Seam conversation.

new-entity     Creates a new Seam entity class.

generate-model     Reverse engineers the current project's database, and genera
JPA entity classes from it.

generate-ui     Creates entity management pages (create, update, delete) fo
existing Seam entity classes.

generate     Creates entity management pages and JPA entity classes by 
reverse engineering the current project's database.
=========================================
Seam Debug
seam-debug.jar需要在classpath里
http://xxx/xx/debug.seam
=========================================
TestNG
Seam内置了TestNG
http://www.testng.org

例:
package mytests;
import org.testng.annotations.*
public class ATest {
    @Test (groups= {"examples"})
    public void runATest() {
        assert getString().equals("some value");
    }
}

groups这个测试属于哪个组,可选的。

如果方法执行完毕,没有异常,就表示成功。
注意使用assert。
http://java.sun.com/j2se/1.4.2/docs/guide/lang/assert.html

支持前处理,后处理
@AfterSuite / @BeforeSuite
@AfterGroups / @BeforeGroups
@AfterTest / @BeforeTest
@AfterClass / @BeforeClass
@AfterMethod / @BeforeMethod

@BeforeClass
    public void setUp() {
        // Setup initialization data.
           this.intVal=17;
    }
将在这个类的第一个Test方法之前执行

Test控制文件,一组相关的测试
xxxTest.xml,一般放在default package或单独的package里
如:
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="MySuite" verbose="2" parallel="false">
  <test name="MyTest">
    <classes>
      <class name="myPackage.MyTest" />
    </classes>
  </test>
</suite>
测试类太多的话,可以指定package
<suite name="MySuite" verbose="2" parallel="false">
  <test name="MyTest">
    <packages>
      <package name="myTestPackage" />
    </packages>
  </test>
</suite>

执行的话,使用 ant test命令。
============================================================
结合测试
SeamGen生成的工程有个 bootstrap 目录,里面有内嵌的JBoss服务器。
用Seam做结合测试的时候,是部署到这里。

从 org.jboss.seam.mock.SeamTest类
得到一个匿名类,它继承了 org.jboss.seam.mock.FacesRequest。
可以模仿JSF的不同生命周期。
-------------------------------------------
protected void applyRequestValues()
This method is called during the apply request value phase of the JSF life cycle.

protected void invokeApplication()
This method is called during the invoke application phase of the JSF life cycle.

protected void processValidations()
This method is called during the process validations phase of the JSF life cycle.

protected void  renderResponse()
This method is called during the render response phase of the JSF life cycle.
-------------------------------------------
import org.jboss.seam.mock.SeamTest;
import org.testng.annotations.Test;
public class MyTest extends SeamTest {
 @Test(groups={"ui"})
 public void testMe() throws Exception {
  new FacesRequest() {
   @Override
   protected void processValidations() throws Exception {
    // Perform Tests
   }      
   @Override
   protected void updateModelValues() throws Exception {
    // Perform Tests
   }
   @Override
   protected void invokeApplication() throws Exception {
    // Perform Tests
   }
     
   @Override
   protected void renderResponse() throws Exception {
    // Perform Tests
   }
 }.run();
}
在Override的方法中可以get,set,validate Seam组件的属性,调用Seam组件的方法。
-----------------------------------------------------
protected Object getValue(…)
Gets a value from a JSF expression such as #{destination.minimumBudget}.

protected void  setValue(…)
Sets the value of a JSF expression.

protected Boolean validateValue(…)
Validates an expression based upon the JSF validations present.

protected Object invokeMethod(…)
Invokes a JSF method binding such as {vacationManagerAction.selectVacationType}.
----------------------------------------------------
例子:
package com.davidsalter.vacationplanner.actions.test;
import org.jboss.seam.mock.SeamTest;
import org.testng.annotations.Test;
import com.davidsalter.vacationplanner.model.Destination;
public class VacationTest extends SeamTest {
    @Test(groups={"ui"})
    public void testCityVacation() throws Exception {
        new FacesRequest() {
            @Override
            protected void processValidations() throws Exception {
                validateValue("#{destination.destinationType}", 
                Destination.DestinationType.CITY);
                validateValue("#{destination.minimumBudget}", 200.0);
                assert !isValidationFailure();
        }      
        @Override
        protected void updateModelValues() throws Exception {
            setValue("#{destination.destinationType}",
                Destination.DestinationType.CITY);
            setValue("#{destination.minimumBudget}", 200.0);
         }
        @Override
        protected void invokeApplication() {
            assert invokeMethod("#{vacationManagerAction.selectVacationType}").equals("/city.xhtml");
        }
        @Override
        protected void renderResponse() {
            assert getValue("#{destination.minimumBudget}"). 
            toString().equals("200.0");
        }      
        }.run();
    }
============================================================
测试Seam组件
只想测试组件,而不想有JSF的生命周期。
从org.jboss.seam.mock.SeamTest继承我们的测试类,
创建匿名org.jboss.seam.mock.ComponentTest类的实例。
声明testComponents()方法。
------------------------
import org.jboss.seam.mock.SeamTest;
import org.testng.annotations.Test;
public class MyTest extends SeamTest {
  @Test(groups={"component"})
  public void testMe() throws Exception {
    new ComponentTest() {
      @Override
      protected void testComponents() throws Exception {
        // Perform tests.
   }
  }.run();
------------------------
例:
package com.davidsalter.vacationplanner.actions.test;
import org.jboss.seam.mock.SeamTest;
import org.testng.annotations.Test;
import com.davidsalter.vacationplanner.model.Destination;
public class VacationManagerActionTest extends SeamTest {   
  @Test
  public void testSelectVacationType() throws Exception {
    new ComponentTest() {
      @Override
      protected void testComponents() throws Exception {
        setValue("#{destination.destinationType}", 
            Destination.DestinationType.ACTION);
        assert invokeMethod("#{vacationManagerAction. 
            selectVacationType}").equals("danger");
      }
    }.run();
  }
}
------------------------
Mock Seam组件
在测试中,有时很难真正模仿Seam组件的功能,比如操作用户数据库。
可以用Mock对象来实现,
用组件优先级的方式。

定义Seam组件时,默认是APPLICATION,
内置的优先级,从低到高
--------------------
Built in (Install.BUILT_IN)
Framework (Install.FRAMEWORK)
Application (Install.APPLICATION)
Deployment (Install.DEPLOYMENT)
Mock (Install.MOCK)
--------------------
Seam只会实例化优先级最高的那个。
@Install(precedence=Install.MOCK)

例:
---------------------------
package com.davidsalter.vacationplanner.actions;
import org.jboss.seam.annotations.Install;
import org.jboss.seam.annotations.Name;
@Name("vacationManagerAction")
@Install(precedence=Install.MOCK)
public class MockVacationManagerAction {
  public String selectVacationType() throws Exception {
    return "danger";
  }
}
---------------------------
================================================
RiceFaces
基于JSF框架的UI组件,有Ajax支持。
 http://www.jboss.org/jbossrichfaces/downloads/

添加Jar文件到WEB-INF/lib目录下。

richfaces-api-3.2.1.jar 
richfaces-impl-3.2.1.jar
richfaces-ui-3.2.1.jar

web.xml追加
<context-param>
  <param-name>org.richfaces.SKIN</param-name>
  <param-value>blueSky</param-value>
</context-param>
几种内置的皮肤,区分大小写,在 richfaces-impl.jar的META-INF/skin目录下。
--------------------
DEFAULT
Plain
emeraldTow
blueSky
wine
japanCherr
ruby
classic
deepMarine
--------------------

xhtml中使用追加namespace
<ui:composition xmlns="http://www.w3.org/1999/xhtml"         
    xmlns:s="http://jboss.com/products/seam/taglib"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:rich="http://richfaces.org/rich"
    template="layout/template.xhtml">
========================================================
数据持久化

Java Persistence API (JPA)是一个标准,有不同的实现,如Hibernate和TopLink。
Seam默认使用Hibernage,但也可以用TopLink或其他的。

Data Source文件位于
<Jboss_home>/server/default/deploy
*-ds.xml,一个文件里可以定义多个。
----------------
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE datasources
  PUBLIC "-//JBoss//DTD JBOSS JCA Config 1.5//EN"
  "http://www.jboss.org/j2ee/dtd/jboss-ds_1_5.dtd">
<datasources>
  <local-tx-datasource>
    <jndi-name>DataDatasource</jndi-name>
    <connection-url>jdbc:hsqldb:.</connection-url>
    <driver-class>org.hsqldb.jdbcDriver</driver-class>
    <user-name>sa</user-name>
    <password></password>
  </local-tx-datasource>
</datasources>
-------------------------

persistence.xml 
例:
-------------------------
?xml version="1.0" encoding="UTF-8"?>
<!-- Persistence deployment descriptor for dev profile -->
<persistence xmlns="http://java.sun.com/xml/ns/persistence"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence 
    http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"  
    version="1.0">
  <persistence-unit name="Data">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <jta-data-source>java:/DataDatasource</jta-data-source>
    <properties>
      <property name="hibernate.dialect"  
          value="org.hibernate.dialect.HSQLDialect"/>
      <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
      <property name="hibernate.show_sql" value="true"/>
      <property name="hibernate.format_sql" value="true"/>
      <property name="jboss.entity.manager.factory.jndi.name" 
          value="java:/DataEntityManagerFactory"/>
    </properties>
  </persistence-unit>
</persistence>
-------------------------


@Entity
类不能是final的
有get,set方法。
不能有private的无参数构造方法。
---------------------
@Entity
@Name("customer")
@Table(name="CUSTOMER_TABLE")
public class Customer {
  // .. Omitted for brevity 
  @Id
  @GeneratedValue
  @Column(name="CUSTOMER_ID")
  public Long getId() {
    return id;
  }
------------------------

@Stateful
@Name("customerManager")
public class CustomerManagerAction implements CustomerManager {
  @PersistenceContext
  private EntityManager em;

  public void saveCustomer (Customer customer) {
    em.persist(customer);
  }
  @Destroy
  @Remove
  public void destroy() {
  }
}
----------------------------

private List<Customer>customers;
public void getCustomers() {
  customers = em.createQuery("select customer from 
     Customer customer order by  
     customer.secondName").getResultList();
}
----------------------------
注解为DataModel,自动Out为JSF的DataModel,可以用在页面的List中

package com.davidsalter.data.actions;
import com.davidsalter.data.entity.Customer;
import javax.ejb.Remove;
import javax.ejb.Stateful;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.jboss.seam.annotations.Destroy;
import org.jboss.seam.annotations.Factory;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.datamodel.DataModel;
import org.jboss.seam.annotations.datamodel.DataModelSelection;
@Stateful
@Name("customerManager")
public class CustomerManagerAction implements CustomerManager {
  @PersistenceContext
  private EntityManager em;

  @DataModel
  private List<Customer> customers;

  @DataModelSelection("customers")
  private Customer selectedCustomer;

  @Factory
  public void getCustomers() {
    customers = em.createQuery(
        "select customer from Customer customer 
         order by customer.secondName").getResultList();
  }
  @Destroy
  @Remove
  public void destroy() {
  }
}
--------------------------------
Entity之间的关系映射

One-to-one relationships
One-to-many relationships
Many-to-one relationships
Many-to-many relationships

Entity的CURD
----------------------
@PersistenceContext
EntityManager em

em.remove(customer);
-------------------------
@PersistenceContext
EntityManager em

Customer customer = em.find(Customer.class, customerId);
customer.setSecondName(secondName);
-------------------------

Seam提供Home和Query对象,可以在Facelets中直接执行CURD操作。

====================================================
Seam Conversations

通常的Scope:
Servlet中局部变量
Session
Application,Servlet中全局Static变量
--------

Seam中的7中Scope:
-----
Stateless,无状态,用完就扔。
Event,只在单个Request中有效。
Page,在Render page过程中有效,所有用来render page的方法中有效。AJAX postbacks 也是Page Scope的,从页面开始渲染,到下一个页面被渲染之前。
Conversation,组件的默认Scope,默认周期是从request开始到页面渲染完毕。
Session 即HTTP Session
Business Process,jBPM定义的business process.
Application,组件成为servlet的全局变量
-------
例:
------------
import org.jboss.seam.annotations.Scope;
import static org.jboss.seam.ScopeType.CONVERSATION;
@Name("vacation")
@Scope(CONVERSATION)
public class Vacation {
}
------------

Conversation分为临时conversation和long-running conversation.
一个时刻只能有一个long-running的!!
long-running需要手工起动,不会自动起动。
    
--------------
@Stateful
@Name("hitCount")
@Scope(ScopeType.CONVERSATION)
public class HitCountManager implements HitCount {
    @Begin
    public String start() {
    }
}
----------------
第一次被调用时,首先创建的是临时的conversation,遇到@Begin后,将临时的提升为long-running的。
如果用户浏览页面,调用到另外一个有 @Begin(join=true)的方法,
将使用当前的long-running conversation。
如果另外一个是@Begin,那么将报错,因为已经有一个long-running的了。

当前运行的conversation,可以通过内置的conversation组件查看。
如:
ID:<h:outputText value="#{conversation.id}"/>
Long running?:<h:outputText value="#{conversation.longRunning}"/>
Nested?:<h:outputText value="#{conversation.nested}"/>


页面被访问时,自动Begin long-running Conversation.
<page view-id="/conversation.xhtml">
    <begin-conversation join="true" />
</page>

@End
如果是nested的话,从Stack中取出上一层conversation,并使用
如果不是nested的,结束当前convsation.
---------------
@Stateful
@Name("hitCount")
@Scope(ScopeType.CONVERSATION)
public class HitCountManager implements HitCount {
    @Begin(join=true)
    public String start() {
        return"/conversation.xhtml";
    }
    @End
    public String end() {
        return"/home.xhtml";
    }
}
-----------------
页面被调用时,自动结束conversation.
<page view-id="/autoEnd.xhtml">
    <end-conversation />
</page>

比如出异常时:
<exception class="javax.persistence.OptimisticLockException">
    <end-conversation/>
    <redirect view-id="/error.xhtml">
        <message>Another user changed the same data, please 
            try again</message>
    </redirect>
</exception>
---------------------------------
Propagating conversations,传播conversation

下面这两句不会传播conversation
<h:outputLink value="/newpage.xhtml" />
<h:commandLink value="Click Me" action="#{form.clicked}">
可以用<s:link>代替,它会自动传播conversation,<s:button>也是。
<s:link view="/conversationPage.xhtml" value="Next Page"/>

可以用propagation属性,决定怎么传播。
----
begin – A new conversation is begun upon clicking the link
join – An existing conversation is joined upon clicking the link
none – The link acts as a standard <a /> tag, ignoring any  
conversational status
end – The current long-running conversation is terminated
------

components.xml中可以定义传递时使用的名字
<core:manager conversation-id-parameter="cid"/>
xxx.seam?cid=2

超时时间,毫秒
<core:manager conversation-timeout="60000"/>

conversation超时时,组件中有@Destroy和@Remove的方法自动被执行。
@Destroy
@Remove
public void destroy() {
  // Perform any clean up.
}

在conversation内操作时,Seam会同步访问,避免线程的问题。
有时,如Ajax请求,可能会同时处理多个请求。
并发的request的超时时间:
<core:manager concurrent-request-timeout="500" />
默认500毫秒,一般足够了。太大的话,可能有性能问题。


Standard Seam conversation ID
http://localhost:8080.conversation/findVacation?cid=10
Natural conversation Seam ID
http://localhost:8080/conversation/findVacation?vacationId=10
Natural Seam conversation ID after URL rewriting
http://localhost:8080/conversation/Vacation/10

pages.xml中
<conversation 
   name="findVacation"
   parameter-name="vacationId"
   parameter-value="#{vacationManager.vacation.vacationid}"/>

<page view-id="/find.xhtml" conversation="findVacation">
    <begin-conversation join="true" />
</page>
=====================================================
Seam Remoting

WEB-INF/web.xml
--------------------------
<servlet>
  <servlet-name>Seam Resource Servlet</servlet-name>
  <servlet-class>
    org.jboss.seam.servlet.SeamResourceServlet
  </servlet-class>
</servlet>
<servlet-mapping>
  <servlet-name>Seam Resource Servlet</servlet-name>
  <url-pattern>/seam/resource/*</url-pattern>
</servlet-mapping>
--------------------------
使用@WebRemote

@Name("helloWorld")
public class HelloWorld implements HelloWorldAction {
  @WebRemote 
  public String sayHello() {
    return "Hello world !!";
  }
--------------------------
Session Bean必须定义在接口上,而不是实现上。

import javax.ejb.Local;
import org.jboss.seam.annotations.remoting.WebRemote;
@Local
public interface HelloWorldAction {
  @WebRemote
  public String sayHello();
  @WebRemote
  public String sayHelloWithArgs(String name);
}

import javax.ejb.Stateless;
import org.jboss.seam.annotations.Name;
@Stateless
@Name("helloWorld")
public class HelloWorld implements HelloWorldAction {
  public String sayHello() {
    return "Hello world !!";
  }
  public String sayHelloWithArgs(String name) {
    return "Hello "+name;
  }
}
------------------------------
<script type="text/javascript" src="/HelloWorld/seam/resource/ 
    remoting/resource/remote.js">
</script>
<script type="text/javascript" src="/HelloWorld/seam/resource/ 
    remoting/interface.js?helloWorld">

调用多个组件的话
<script type="text/javascript" src="/HelloWorld/seam/resource/ 
    remoting/interface.js?helloWorld&mySecondComponent& 
    myThirdComponent">

这样更简单:
<s:remote include="helloWorld"/>
自动生成对应的javascript

多个组件的:
<s:remote include="helloWorld, mySecondComponent, 
     myThirdComponent" />

调用:
 <script type="text/javascript">
   function sayHello() {
     var callback = function(result) {
     document.getElementById("helloResult").innerHTML=result;
     };
   Seam.Component.getInstance("helloWorld").sayHello(callback);
   }
 </script>

使用conversation:
Seam.Remoting.getContext().setConversationId(# {conversation.id});

Remoting的Debug:
WEB-INF/components.xml 
--------------------
<component name="org.jboss.seam.remoting.remoting">
    <property name="debug">true</property>
</component>


<remoting:remoting debug="true" />
--------------------
会弹出一个popup窗口,显示提交和返回的信息,

写log
Seam.Remoting.log("This is a debug message");
Seam.Remoting.log("Value:"+name);

改变please wait信息:
function sayHello() {
  Seam.Remoting.log("setting the loading message");
  Seam.Remoting.loadingMessage = "Hold on a moment...";
  // .. rest of code removed for brevity.
}
=======================================
AJAX4JSF现在是RiceFaces的一部分了。

对于Ajax请求,Seam会排队存取conversation。
如果在指定的时间内没有等到使用conversation,将创建一个临时conversation.
这个等待的时间长度在 components.xml 中定义
<core:manager concurrent-request-timeout="500" />
500毫秒
========================================
Security 安全

用户验证:
components.xml中指定验证方法。
<security:identity authenticate-method="#{authenticator.authenticate}" remember-me="true"/>
这个方法返回true,表示验证成功。


在user的@Entity中可以使用一些Seam的注解,这些注解是Seam identity manager API使用的。
-----------------------------------------
@Name The name of the Seam component that we are creating. This annotation is used in the same fashion as discussed earlier in this book.

@UserPassword(hash="none") This feld is used to store the user's password  using the hashing algorithm specifed by the  hash attribute.
Seam supports both MD5 and SHA1 hashing algorithms, as well as no password hashing for 
unencrypted passwords.
@UserPassword(hash="none")
@UserPassword(hash="md5")
@UserPassword(hash="sha")

@UserPrincipal This feld is used to store the user's username.

@UserEnabled This feld stores a Boolean fag indicating whether the user account is enabled (TRUE) or not (FALSE).

@UserFirstName This feld stores the user's frst name.

@UserLastName This feld stores the user's Surname.
-----------------------------------------
<page vide-id="/userList.xhtml" login-required="true" />
<page view-id="/secure/*" login-required="true" />

<pages xmlns= 
          "http://jboss.com/products/seam/pages"
       xmlns:xsi= 
          "http://www.w3.org/2001/XMLSchema-instance"       
       xsi:schemaLocation= 
          "http://jboss.com/products/seam/pages
           http://jboss.com/products/seam/pages-2.1.xsd"
       login-view-id="/login.xhtml">
------------------------------------------
<h:form id="login">
  <rich:panel>
    <f:facet name="header">Login</f:facet>
    <h:panelGrid columns="2">
      <h:outputLabel for="username">Username</h:outputLabel>
      <h:inputText id="username"
        value="#{credentials.username}"/>
      <h:outputLabel for="password">Password</h:outputLabel>
      <h:inputSecret id="password"
        value="#{credentials.password}"/>
      <h:outputLabel for="rememberMe">Remember me</h:outputLabel>
      <h:selectBooleanCheckbox id="rememberMe"
        value="#{identity.rememberMe}"/>
    </h:panelGrid>
  </rich:panel>
  <h:commandButton value="Login" action="#{identity.login}"/>
</h:form>
---------------------------------------
登录成功后,跳转到用户访问的页面。
componets.xml追加即可。
<event type="org.jboss.seam.security.notLoggedIn">
  <action execute="#{redirect.captureCurrentView}"/>
</event>
<event type="org.jboss.seam.security.loginSuccessful">
  <action execute="#{redirect.returnToCapturedView}"/>
</event>
---------------------------------------
用户登录成功,失败等会触发事件,可以进行相应的处理,如写LOG
@Observer("event name")
public void handleEvent() {
}
-------------
Org.jboss.seam.security.loginSuccessful The user has successfully logged in to the application
Org.jboss.seam.security.loginFailed The user has failed to log in to the application
Org.jboss.seam.security.alreadyLoggedIn The user has attempted to log in to the application when they are already logged in
Org.jboss.seam.security.notLoggedIn The user has attempted to access a secured resource and is not logged in
Org.jboss.seam.security.notAuthorized The user is logged in and has attempted to access a secured resource but does not have the appropriate role
Org.jboss.seam.security.loggedOut The user has logged out of the application
----------------
 @Observer("org.jboss.seam.security.loginSuccessful")
 public void onSuccessFulLogin() {
   LoginAudit audit = new LoginAudit();
   audit.setStatus("Success");
   audit.setUserName(credentials.getUsername());
   entityManager.persist(audit);
 }
 @Observer("org.jboss.seam.security.loginFailed")
 public void onFailedLogin() {
   LoginAudit audit = new LoginAudit();
   audit.setStatus("Fail");
   audit.setUserName(credentials.getUsername());
   entityManager.persist(audit);
 }
----------------------
登录时,要用户回答问题:
首先,需要配置(org.jboss.seam.servlet.SeamResourceServlet),web.xml?参照前面。
问题图片:
<h:graphicImage value="/seam/resource/captcha"/>
用户回答:
<h:inputText id="captchaInput"  
             value="#{captcha.response}" 
             required="true">
    <s:validate />
</h:inputText>
问题message:
<h:message for="captchaInput"/>

问题可以自定义:
package com.davidsalter.seamsecurity;
import java.util.Random;
import org.jboss.seam.annotations.Create;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.captcha.Captcha;
import org.jboss.seam.captcha.CaptchaResponse;
@Name("org.jboss.seam.captcha.captcha")
public class SubtractCaptcha extends Captcha {
  @Override
  @Create
  public void init() {
    Random random = new Random(1234567890);
    int firstNum = random.nextInt(100);
    int secondNum = random.nextInt(100);
    this.setChallenge(firstNum+"-"+secondNum);
    this.setCorrectResponse(""+(firstNum-secondNum));
  }
  @Override
  @CaptchaResponse(message="Math isn't your strong point is it?")
  public String getResponse() {
    return super.getResponse();
  }
}
===========================
The Seam identity manager API
实现标准的验证接口

components.xml中指定用户和角色。
<security:jpa-identity-store 
  user-class="com.davidsalter.seamsecurity.entity.User"
  role-class="com.davidsalter.seamsecurity.entity.Role"
 />
创建用户和角色
IdentityManager.createUser(String username, String password);
IdentityManager.grantRole(String username, String rolename);

.............
=============================
OpenID
多个web application都可以通过OpenID来验证,一次登录多个application.

4步:
(1)Confgure an OpenID phase listener
(2)Ensure that the correct JAR fles are on the application's classpath
(3)Write a logon form
(4)Confgure page redirection after an OpenID logon

(1)faces-config.xml 
<lifecycle>
  <phase-listener>
    org.jboss.seam.security.openid.OpenIdPhaseListener
  </phase-listener>
</lifecycle>

(2)
htmlparser.jar
openid4java.jar
openxri-client.jar
openxri-syntax.jar
可能需要commons-codec.jar,它在Jboss5的common/lib下。
(3)登录页面,只需要openID,不需要密码。
ID是类似于URL形式的: http://MySeamID.myopenid.com

<h:outputLabel for="username">Open ID</h:outputLabel>
<h:inputText id="openid" value="#{openid.id}"/>
<h:commandButton value="Login using OpenID"  
    action="#{openid.login}"/>

(4)OpenID登录成功后,自动转到我们webapplication的openid.xhtml上。
这是个虚拟的页面,不必存在。
<page view-id="/openid.xhtml">
  <navigation evaluate="#{openid.loginImmediately()}">
    <rule if-outcome="true">
      <redirect view-id="/secure/securePage.xhtml">
      </redirect>
    </rule>
    <rule if-outcome="false">
      <redirect view-id="/home.xhtml">
      </redirect>
    </rule>
  </navigation>
</page>
用户的openID可以这样显示:#{openid.validatedId}

 

评论 COMMENTS
没有评论 No Comments.

添加评论 Add new comment.
昵称 Name:
评论内容 Comment:
验证码(不区分大小写)
Validation Code:
(not case sensitive)
看不清?点这里换一张!(Change it here!)
 
评论由管理员查看后才能显示。the comment will be showed after it is checked by admin.
CopyRight © 心缘地方 2005-2999. All Rights Reserved