论坛首页 Java企业应用论坛

Seam 使用心得(二)接口实现

浏览 4141 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2007-12-19   最后修改:2009-11-13
Java里提倡使用面向接口编程以减弱组件之间的耦合,在上一篇里已经定义了
@Local
public interface Register {
	public String register();
}

这一节里面将实现这个接口来通过测试。

现在应用系统有很多良好的分层方法,但是我还是喜欢Evans的领域驱动设计的方法。
1,视图层将使用RichFaces。
2,使用无状态SessionBean作为Facade对领域逻辑进行封装。
3,领域层实现核心业务逻辑,主要包括有实体,值对象,仓库,服务等。

源文件目录结构大致如下:
src
  |----action  (SLSB)
  |----model  (Service, Entity, Repository, Vo)
  |----test
view
  |----css
  |----js
……

经过简单的分析model层向facade暴露UserView接口
package org.qpt.domain.user;
import org.qpt.domain.user.User.RegState;
/**
 * 用户接口
 * @author xiaoqiu
 */
public interface UserView {
    String getConfirmPwd();
    String getEmail();
    String getName();
    String getPwd();
    /**
     * 注册一个新用户
     * @param ur 用户仓库接口
     * @return 注册结果状态码(共5种状态,上一节已经提到过)
     */
    RegState register(UserRepository ur);
    void setConfirmPwd(String confirmPwd);
    void setEmail(String email);
    void setName(String name);
    void setPwd(String pwd);
}


注:因为EJB2严重的依赖于容器的基础设施,如果在实体bean中包含业务逻辑,将很难进行测试,所以实体bean只能作为数据容器,而背离面向对象的分析和设计方法。但是EJB3已经可以对实体进行透明持久化,并且很容易在容器外进行测试,所以就用User实体实现UserView接口,这里用户注册的并没有跨越多个实体,只涉及用户实体,所以包含了业务方法register的User类代码如下:

/**
 * 用户实体
 * 
 * @author xiaoqiu
 */
@Entity
@Name("user")
@Scope(SESSION)
@Table(name = "users")
public class User implements Serializable, UserView {

    private static final long serialVersionUID = 3836699581343986461L;
    @Id
    @NotNull
    @Length(min = 6, max = 15)
    private String name;
    @NotNull
    @Length(min = 6, max = 15)
    private String pwd;
    @Transient
    private String confirmPwd;
    @NotNull
    @Email
    private String email;
    @Transient
    private String confirmEmail;

    public enum RegState {
        EXISTS_EMAIL, EXISTS_NAME, PWD_NOT_EQ_IN_TWICE, EMAIL_NOT_EQ_IN_TWICE, SUCCESS
    }

    @Override
    public RegState register(UserRepository ur) {
        if (!pwd.equals(confirmPwd)) {
            return PWD_NOT_EQ_IN_TWICE;
        } else if (!email.equals(confirmEmail)) {
            return EMAIL_NOT_EQ_IN_TWICE;
        } else if (ur.findByProperty("name", name)) {
            return EXISTS_NAME;
        } else if (ur.findByProperty("email", email)) {
            return EXISTS_EMAIL;
        } else {
            ur.save(this);
            return SUCCESS;
        }
    }

……
get&set method
}

考虑到视图层RichFaces和hibernate验证结合可以进行很简单的零脚本ajax验证,所以本例子里面使用了hibernate验证。
由于register方法需要用的UserRepository来访问数据库,所以现在来看一下UserRepository接口。通过隔离基础设施,这就是GOF设计模式中著名的Strategy模式,由于Java语言想要在实体中注入UserRepository在技术上存在困难,所以把UserRepository作为方法的参数传递我个人认为也是一种较为简洁的方法,而且通过接口的隔离不会和基础设施产生强烈的耦合,UserRepository代码如下:

/**
 * 用户仓库接口
 * @author xiaoqiu
 */
@Local
public interface UserRepository {
    void save(User user);
    User findByName(String name);
    List<User> findAllUser();
    /**
     * 找出该属性是否存在当前值
     * @param name 属性名
     * @param value 属性值
     * @return 该属性存在这个值返回true,否则返回false
     */
    boolean findByProperty(String name, String value);
}


在本例里面UserRepository的实现使用的JPA,这个接口的实现相当容易所以它的实现类UserRepositoryJPAImp代码就不贴出来了,可以直接看提供的源码。

model层的接口已经实现完毕,接下来实现facade,代码如下:
@Stateless
@Name("register")
public class RegisterBean implements Register {

    @Logger
    private Log log;
    @In
    FacesMessages facesMessages;
    @In
    private UserView user;
    @In("userRepository")
    UserRepository ur;

    public String register() {
        RegState state = user.register(ur);
        switch (state) {
            case PWD_NOT_EQ_IN_TWICE:
                log.info("the register state is " + state);
                facesMessages.addFromResourceBundle("myapp.register.pwd.noteq");
                break;
            case EMAIL_NOT_EQ_IN_TWICE:
                log.info("the register state is " + state);
                facesMessages.addFromResourceBundle("myapp.register.email.noteq");
                break;
            case EXISTS_NAME:
                log.info("the register state is " + state);
                facesMessages.addFromResourceBundle("myapp.register.name.exists");
                break;
            case EXISTS_EMAIL:
                log.info("the register state is " + state);
                facesMessages.addFromResourceBundle("myapp.register.email.exists");
                break;
            case SUCCESS:
                log.info("register a new user #{user.name}" + "\nthe register state is " + state);
                facesMessages.addFromResourceBundle("myapp.register.success");
                break;
        }
        return state.toString();
    }
}

这里facade是很薄的一层,不能包含任何业务逻辑,它主要根据model返回的状态是向显示层发送信息,使用facesMessages组件就可以很容易向Richfaces发送ajax验证的响应信息,并且事务处理统一在facade层进行,由于使用EJB,所以就可以使用容器提供的事务管理。

上述类的结构如下图所示:
facade: Register-->RegisterBean-->UserView&UserRepository
domain:UserView-->User(Eneity)<-->UserRepository-->UserRepositoryJPAImp
至此为止,注册用户所需要的全部接口都已经实现,现在就可以用seam test命令来运行上一节写好的测试代码了。
   发表时间:2007-12-24  
如何把一个SESSION BEAN注入到另外一个SESSION BEAN中阿?
@In(value="chatroomAction")
    ChatRoomAction chatroomAction;
这个代码老是报错:
Could not set field value by reflection: DepartMentAction.chatroomAction on: com.ctazc.zs.web.action.newuser.DepartMentAction with value: class org.javassist.tmp.java.lang.Object_$$_javassist_6
0 请登录后投票
   发表时间:2007-12-24  
我在运用时候,我直接在coponents.xml里写了数据库session hs

<core:manager conversation-timeout="120000"
                  concurrent-request-timeout="500"
                  conversation-id-parameter="cid"/>
                 
                 
    <persistence:hibernate-session-factory name="hibernateSessionFactory"/>
   
    <persistence:managed-hibernate-session name="hs"
                                    session-factory="#{hibernateSessionFactory}"
                                    auto-create="true"/>   
   
    <transaction:hibernate-transaction session="#{hs}"/>


如果我在DAOImpl里引用这个hs,

  public class userDAO {
       @In  private Session hs

        public void saveUser(User user) {
    hs.save(user);
       }
}

那么
这个hs是空的,也就是说的不到数据库的链接

而在托管bean里却能得到,这是为什么
 

 

0 请登录后投票
   发表时间:2007-12-28  
这几天有时间的话准备写一下 第三章 视图与导航,但是有一个RichFaces的问题一直没解决-_-!,那就是我原本打算在 离开用户名输入框 的时候触发一个Ajax事件验证是否存在用户名,但是发现这样会报异常,只能在提交的时候触发Ajax事件验证用户名是否重复……

不知道哪位遇到过
0 请登录后投票
   发表时间:2008-01-24  
DDD领域驱动设计结合seam不错。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics