<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    京山游俠

    專注技術(shù),拒絕扯淡
    posts - 50, comments - 868, trackbacks - 0, articles - 0
      BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

    在這里,將創(chuàng)建一個簡化的用戶管理模塊,演示怎樣利用SpringSide提供的數(shù)據(jù)持久層的功能,包括怎樣通過Hibernate的Annotation來配置多對一映射和多對多映射。

    大家都知道,現(xiàn)在最流行用戶管理模型的是RBAC,也就是基于角色的訪問控制模型,在這種模型中,可以劃分多個層次,如用戶-角色-資源、用戶-角色-權(quán)限-資源、用戶-角色-角色組-權(quán)限-資源、用戶-角色-角色組-權(quán)限-操作-資源等等,因此,想要創(chuàng)建一個完善而復(fù)雜的用戶管理模塊,是相當(dāng)具有難度的。在Web2.0時代,有一個很重要的開發(fā)思想,那就是先讓程序跑起來,以后再逐步添加復(fù)雜的功能。因此,在這里只創(chuàng)建一個簡化的用戶管理模塊。

    所謂簡化,它具有如下幾個特點:

    1.在認(rèn)證方式中,選擇基于用戶名和密碼的認(rèn)證,用戶需要提供用戶名、密碼和昵稱,用戶名和昵稱都要求不能重復(fù),用戶名不能包含中文,且不能夠被修改,昵稱可以為中文,也可以被修改。密碼使用MD5加密。

    2.不包含用戶的真實信息,如姓名、年齡、性別、職業(yè)、地址、郵編等等,因為如果包含這些字段,那么還需要包含更多的額外字段來讓用戶決定是否公開這些信息,因此,去掉這些東西,可以簡化開發(fā)過程,讓網(wǎng)站能夠盡快的跑起來。

    3.聯(lián)系方式只需要用戶提供它的電子郵箱和QQ號碼。

    4.如果用戶密碼丟失,可以通過密碼提示問題找回,隨機(jī)產(chǎn)生的新密碼會發(fā)到用戶的電子郵箱。

    5.省略用戶的個性化設(shè)置,如個性化簽名、自定義頭像等。

    6.要能夠記錄用戶的注冊時間和最后登錄時間。

    7.要具有完善的積分和排名機(jī)制。

    8.用戶刪除的時候不做物理刪除,只標(biāo)記為該用戶不可用。

    8.具有簡化的角色和權(quán)限管理機(jī)制,這里的簡化主要有以下幾點:每個用戶只能屬于一個角色,即多對一關(guān)系,而不是傳統(tǒng)的多對多關(guān)系;角色不需要分組;沒有專門的資源抽象層;在角色表中只使用一個字段來表示該角色具有的權(quán)限,權(quán)限以數(shù)字表示,以逗號分開,如“1,2”,“1,3,15”等等。

    9.用戶可以創(chuàng)建群和加入群,為了簡化,群的創(chuàng)始人即為管理員,并不可改變,用戶加入群需要管理員批準(zhǔn),一個用戶可以加如多個群,即多對多關(guān)系。

    從上面的描述可以看出,一個簡化的用戶管理系統(tǒng)最少需要三個表,即users,roles和groups表,其中users和roles之間為多對一映射,users和groups之間為多對多映射,為了實現(xiàn)多對多映射,并且用戶加入群的時候需要管理員批準(zhǔn),需要一個中間表users_groups。下面是在MySQL中創(chuàng)建數(shù)據(jù)表的語句。

    創(chuàng)建用戶表:

    create ? table ?users(
    id?
    int ? not ? null ?auto_increment? primary ? key ,
    name?
    varchar ( 20 )? not ? null ,
    password?
    char ( 32 )? not ? null ,
    monicker?
    varchar ( 30 )? not ? null ,
    question?
    varchar ( 30 )? not ? null ,
    answer?
    varchar ( 30 )? not ? null ,
    email?
    varchar ( 40 )? not ? null ,
    qq?
    varchar ( 12 )? not ? null ,
    roleid?
    int ? not ? null ,
    score?
    int ? not ? null ? default ? ' 0 ' ,
    regtime?
    timestamp ? not ? null ? default ? CURRENT_TIMESTAMP ,
    logintime?
    timestamp ? not ? null ? default ? ' 2007-01-01?00:00:00 ' ,
    isdeleted?
    varchar ( 2 )? not ? null ? default ? ' 0 ' ,
    index (username),
    index (monicker));


    為了加快查找用戶的速度,在用戶名和昵稱列上創(chuàng)建了索引。

    創(chuàng)建角色表:

    create ? table ?roles(
    id?
    int ? not ? null ?auto_increment? primary ? key ,
    name?
    varchar ( 20 )? not ? null ,
    privilegesFlag?
    varchar ( 255 ),
    index (rolename)
    );


    創(chuàng)建群組表:

    create ? table ?groups(
    id?
    int ? not ? null ?auto_increment? primary ? key ,
    name?
    varchar ( 40 )? not ? null ,
    creatorid?
    int ? not ? null ,
    createtime?
    timestamp ? not ? null ? default ? CURRENT_TIMESTAMP ,
    isdeleted?
    varchar ( 2 )? not ? null ? default ? ' 0 ' ,
    index (groupname));


    creatorid代表組的創(chuàng)始人,同時也是管理員,這里同樣設(shè)置群組不做物理刪除。

    創(chuàng)建用戶群組多對多映射輔助表:

    create ? table ?users_groups(
    id?
    int ? not ? null ?auto_increment? primary ? key ,
    userid?
    int ? not ? null ,
    groupid?
    int ? not ? null ,
    jointime?
    timestamp ,
    status?
    tinyint ,
    index (userid),
    index (groupid)
    );


    其中status列代表用戶是否通過了管理員的批準(zhǔn),為了加快查找速度,在userid和groupid列上建立索引。

    設(shè)計完數(shù)據(jù)庫,就該設(shè)計領(lǐng)域?qū)ο罅耍I(lǐng)域?qū)ο蟮脑O(shè)計方法為先設(shè)計簡單的POJO,然后再在POJO上添加Hibernate Annotation來配置映射關(guān)系。在進(jìn)行Annotation配置的時候,可以從以下幾個方面進(jìn)行思考。

    1、使用什么樣的數(shù)據(jù)類型映射數(shù)據(jù)庫中的列類型?
    2、對象之間是一對一、一對多還是多對多關(guān)系?
    3、關(guān)聯(lián)的對象之間哪一個作為主控方?
    4、對象之間的關(guān)聯(lián)是單向的還是雙向的?

    首先來看看users和roles之間的關(guān)系,考慮到加載一個用戶數(shù)據(jù)的時候,往往同時需要知道他屬于哪個角色,而加載一個角色的時候,就沒有必要知道它管理哪些用戶了,因此,它們是簡單的單向關(guān)系,是多對一映射。當(dāng)出現(xiàn)多對一映射的時候,永遠(yuǎn)都應(yīng)該選擇多的這一方作為主控方,道理很簡單,打個比方,讓一個國家元首記住全國人民的名字基本是不可能的,而讓全國人民記住國家元首的名字就很簡單了。因此,這里User作為主控方,Role作為被控方。

    再來看看數(shù)據(jù)類型的映射,對于簡單的int、varchar這樣的就不用多說了。而日期時間類型的映射是一個重點,可以看到,前面的數(shù)據(jù)庫創(chuàng)建語句中,所有需要時間的地方都使用了timestamp列類型,使用timestamp列類型的唯一目的就是為了能夠使用default CURRENT_TIMESTAMP語句,使用date和datetime類型就不行,在MySQL中,timestamp只能表示從'1970-01-01 00:00:00'到2037年的范圍。

    MySQL中的timestamp和java.sql.Timestamp表現(xiàn)不一致,在MySQL中,timestamp和datetime類型精度是一樣的,都只能儲存到整數(shù)秒,而timestamp比datetime能表示的時間范圍要小得多,在Java中,java.util.Date和MySQL的timestamp的精度是一致的,只能儲存到整數(shù)秒,而java.sql.Timestamp還保存毫微秒,因此建議使用java.util.Date來映射timestamp列,使用java.sql.Timestamp只是浪費。

    MySQL和Java在時間上面還有一個沖突,那就是MySQL支持全零的時間,如'0000-00-00 00:00:00',而Java不支持,因此如果在定義users表的logintime列時使用logintime timestamp not null default '0000-00-00 00:00:00',那么在使用Hibernate來獲取User對象的時候就會出錯,所以在創(chuàng)建數(shù)據(jù)庫的時候要選擇一個合法的默認(rèn)時間,如'2007-01-01 00:00:00'。

    下面請看User.java的代碼:

    package ?com.xkland.domain;

    import ?java.io.Serializable;
    import ?java.util.Date;
    import ?org.springside.core.dao.extend.Undeletable;
    import ?org.hibernate.annotations.Cache;
    import ?org.hibernate.annotations.CacheConcurrencyStrategy;
    import ?javax.persistence. * ;

    @Entity
    @Table(name
    = " users " )
    @Undeletable(status
    = " isDeleted " )
    public ? class ?User? implements ?Serializable? {
    ?
    private ?Integer?id;
    ?
    private ?String?name;
    ?
    private ?String?password;
    ?
    private ?String?monicker;
    ?
    private ?String?question;
    ?
    private ?String?answer;
    ?
    private ?String?email;
    ?
    private ?String?qq;
    ?
    private ?Role?role;
    ?
    private ?Integer?score;
    ?
    private ?Date?regTime;
    ?
    private ?Date?loginTime;
    ?
    private ?Byte?isDeleted;
    ?
    ?@Id
    ?@GeneratedValue(strategy?
    = ?GenerationType.AUTO)
    ?
    public ?Integer?getId()? {
    ??
    return ?id;
    ?}

    ?
    public ? void ?setId(Integer?id)? {
    ??
    this .id? = ?id;
    ?}

    ?
    ?
    public ?String?getName()? {
    ??
    return ?name;
    ?}

    ?
    public ? void ?setName(String?name)? {
    ??
    this .name? = ?name;
    ?}

    ?
    ?
    public ?String?getPassword()? {
    ??
    return ?password;
    ?}

    ?
    public ? void ?setPassword(String?password)? {
    ??
    this .password? = ?password;
    ?}

    ?
    ?
    public ?String?getMonicker()? {
    ??
    return ?monicker;
    ?}

    ?
    public ? void ?setMonicker(String?monicker)? {
    ??
    this .monicker? = ?monicker;
    ?}

    ?
    ?
    public ?String?getQuestion()? {
    ??
    return ?question;
    ?}

    ?
    public ? void ?setQuestion(String?question)? {
    ??
    this .question? = ?question;
    ?}

    ?
    ?
    public ?String?getAnswer()? {
    ??
    return ?answer;
    ?}

    ?
    public ? void ?setAnswer(String?answer)? {
    ??
    this .answer? = ?answer;
    ?}

    ?
    ?
    public ?String?getEmail()? {
    ??
    return ?email;
    ?}

    ?
    public ? void ?setEmail(String?email)? {
    ??
    this .email? = ?email;
    ?}

    ?
    ?
    public ?String?getQq()? {
    ??
    return ?qq;
    ?}

    ?
    public ? void ?setQq(String?qq)? {
    ??
    this .qq? = ?qq;
    ?}

    ?
    ?@ManyToOne
    ?@JoinColumn(name
    = " roleid " )
    ?
    public ?Role?getRole()? {
    ??
    return ?role;
    ?}

    ?
    public ? void ?setRole(Role?role)? {
    ??
    this .role? = ?role;
    ?}

    ?
    ?@Column(name
    = " score " ,insertable = false )
    ?
    public ?Integer?getScore()? {
    ??
    return ?score;
    ?}

    ?
    public ? void ?setScore(Integer?score)? {
    ??
    this .score? = ?score;
    ?}

    ?
    ?@Column(name?
    = ? " regtime " ,insertable = false )
    ?@Temporal(TemporalType.TIMESTAMP)
    ?
    public ?Date?getRegTime()? {
    ??
    return ?regTime;
    ?}

    ?
    public ? void ?setRegTime(Date?regTime)? {
    ??
    this .regTime? = ?regTime;
    ?}

    ?
    ?@Column(name?
    = ? " logintime " ,insertable = false )
    ?@Temporal(TemporalType.TIMESTAMP)
    ?
    public ?Date?getLoginTime()? {
    ??
    return ?loginTime;
    ?}

    ?
    public ? void ?setLoginTime(Date?loginTime)? {
    ??
    this .loginTime? = ?loginTime;
    ?}

    ?
    ?@Column(name?
    = ? " isdeleted " ,insertable = false )
    ?
    public ?Byte?getIsDeleted()? {
    ??
    return ?isDeleted;
    ?}

    ?
    public ? void ?setIsDeleted(Byte?isDeleted)? {
    ??
    this .isDeleted? = ?isDeleted;
    ?}
    ?
    }

    這里只對幾個特殊的Annotation做一下注釋:
    1、因為創(chuàng)建數(shù)據(jù)表的時候使用的是users,而實體類為User,單復(fù)數(shù)不同引發(fā)名稱不一致,因此需要@Table(name="users");
    2、因為該表中的數(shù)據(jù)不做物理刪除,所以加上@Undeletable(status="isDeleted"),結(jié)合SpringSide提供的HibernateEntityExtendDao類,可以在調(diào)用remove方法的時候?qū)sdeleted列設(shè)置為"-1";
    3、創(chuàng)建數(shù)據(jù)表的時候,所有的列名都是用的小寫字母,因此有的列映射需要明確指定,如@Column(name = "logintime",insertable=false);
    4、對于在創(chuàng)建數(shù)據(jù)表的時候定義了默認(rèn)值的列,如regtime、regtime、logintime、isdeleted,在向數(shù)據(jù)庫中添加數(shù)據(jù)的時候,可以不在insert語句中指定這些列,而讓它們使用默認(rèn)值,因此,需要告訴Hibernate在生成insert語句的時候不要包含這些列,可以使用insertable=false語句,如@Column(name = "regtime",insertable=false);
    5、指定時間精度,使用@Temporal(TemporalType.TIMESTAMP);
    6、指定users表通過roleid和roles表進(jìn)行多對一映射,使用@ManyToOne和@JoinColumn(name="roleid")

    Role.java則比較簡單,如下:

    package ?com.xkland.domain;

    import ?java.io.Serializable;

    import ?javax.persistence.Entity;
    import ?javax.persistence.GeneratedValue;
    import ?javax.persistence.GenerationType;
    import ?javax.persistence.Id;
    import ?javax.persistence.Table;

    @Entity
    @Table(name
    = " roles " )
    public ? class ?Role? implements ?Serializable? {
    ?
    private ?Integer?id;
    ?
    private ?String?name;
    ?
    private ?String?privilegesFlag;
    ?
    ?@Id
    ?@GeneratedValue(strategy?
    = ?GenerationType.AUTO)
    ?
    public ?Integer?getId()? {
    ??
    return ?id;
    ?}

    ?
    public ? void ?setId(Integer?id)? {
    ??
    this .id? = ?id;
    ?}

    ?
    ?
    public ?String?getName()? {
    ??
    return ?name;
    ?}

    ?
    public ? void ?setName(String?name)? {
    ??
    this .name? = ?name;
    ?}

    ?
    ?
    public ?String?getPrivilegesFlag()? {
    ??
    return ?privilegesFlag;
    ?}

    ?
    public ? void ?setPrivilegesFlag(String?privilegesFlag)? {
    ??
    this .privilegesFlag? = ?privilegesFlag;
    ?}

    }


    下一步再來看看users和groups之間的映射關(guān)系,不難想象,當(dāng)載入一個用戶的資料時,往往需要知道他加入了哪些群,而載入一個群的資料時,往往需要知道它有哪些用戶,因此,他們之間是一個雙向的關(guān)系,同時,載入一個群的資料時,還需要知道它的管理員是誰,因此又同時存在一個單向的多對一關(guān)系。在多對多關(guān)系中,設(shè)定User為主控方,所以需要在User.java中添加如下代碼?

    private ?List < Group > ?groups;
    @ManyToMany(targetEntity
    = User. class ,
    ?cascade
    = {CascadeType.PERSIST,?CascadeType.MERGE} )
    @JoinTable(name
    = " users_groups " ,
    ?joinColumns
    = {@JoinColumn(name = " userid " )} ,
    ?inverseJoinColumns
    = {@JoinColumn(name = " groupid " )} )
    public ?List < Group > ?getGroups()? {
    ?
    return ?groups;
    }

    public ? void ?setGroups(List < Group > ?groups)? {
    ?
    this .groups? = ?groups;
    }


    而整個Group.java的代碼如下:

    package ?com.xkland.domain;

    import ?java.io.Serializable;
    import ?java.util.Date;
    import ?java.util.List;
    import ?org.springside.core.dao.extend.Undeletable;
    import ?org.hibernate.annotations.Cache;
    import ?org.hibernate.annotations.CacheConcurrencyStrategy;
    import ?javax.persistence. * ;

    @Entity
    @Table(name
    = " groups " )
    @Undeletable(status
    = " isDeleted " )
    public ? class ?Group? implements ?Serializable? {
    ????
    private ?Integer?id;
    ????
    private ?String?name;
    ????
    private ?User?creator;
    ????
    private ?Date?createTime;
    ????
    private ?String?isDeleted;
    ????
    ????
    private ?List < User > ?users;

    ????@Id
    ????@GeneratedValue(strategy?
    = ?GenerationType.AUTO)
    ????
    public ?Integer?getId()? {
    ????????
    return ?id;
    ????}

    ????
    public ? void ?setId(Integer?id)? {
    ????????
    this .id? = ?id;
    ????}

    ????
    ????
    public ?String?getName()? {
    ????????
    return ?name;
    ????}

    ????
    public ? void ?setName(String?name)? {
    ????????
    this .name? = ?name;
    ????}

    ????
    ????@ManyToOne(cascade
    = {CascadeType.PERSIST,?CascadeType.MERGE} )
    ????@JoinColumn(name
    = " creatorid " )
    ????
    public ?User?getCreator()? {
    ????????
    return ?creator;
    ????}

    ????
    public ? void ?setCreator(User?creator)? {
    ????????
    this .creator? = ?creator;
    ????}

    ????
    ????@Column(name
    = " createtime " ,insertable = false )
    ????@Temporal(TemporalType.TIMESTAMP)
    ????
    public ?Date?getCreateTime()? {
    ????????
    return ?createTime;
    ????}

    ????
    public ? void ?setCreateTime(Date?createTime)? {
    ????????
    this .createTime? = ?createTime;
    ????}


    ????@Column(name
    = " isdeleted " ,insertable = false )
    ????
    public ?String?getIsDeleted()? {
    ????????
    return ?isDeleted;
    ????}

    ????
    public ? void ?setIsDeleted(String?isDeleted)? {
    ????????
    this .isDeleted? = ?isDeleted;
    ????}


    ????@ManyToMany(cascade
    = {CascadeType.PERSIST,?CascadeType.MERGE} ,
    ????????????mappedBy
    = " groups " ,
    ????????????targetEntity
    = User. class )
    ????
    public ?List < User > ?getUsers()? {
    ????????
    return ?users;
    ????}

    ????
    public ? void ?setUsers(List < User > ?users)? {
    ????????
    this .users? = ?users;
    ????}


    }

    ?

    好了,該開始測試了,看看經(jīng)過前面設(shè)計和配置的代碼能否正常工作。首先,先創(chuàng)建三個Manager,這三個Manager都繼承自org.springside.core.dao.extend.HibernateEntityExtendDao,至于HibernateEntityExtendDao的功能,請參考SpringSide的文檔。代碼如下:
    UserManager.java:

    package ?com.xkland.manager;

    import ?org.springside.core.dao.extend.HibernateEntityExtendDao;
    import ?com.xkland.domain.User;

    public ? class ?UserManager? extends ?HibernateEntityExtendDao < User > ? {
    ?
    }



    RoleManager.java:

    package ?com.xkland.manager;

    import ?org.springside.core.dao.extend.HibernateEntityExtendDao;
    import ?com.xkland.domain.Role;

    public ? class ?RoleManager? extends ?HibernateEntityExtendDao < Role > ? {
    ?
    }


    GroupManager.java:

    package ?com.xkland.manager;

    import ?org.springside.core.dao.extend.HibernateEntityExtendDao;
    import ?com.xkland.domain.Group;

    public ? class ?GroupManager? extends ?HibernateEntityExtendDao < Group > ? {

    }


    下一步,將User.class、Role.class、Group.class等領(lǐng)域?qū)ο筇砑拥絪rc\main\resources\config\hibernate.cfg.xml中,如下:

    <! DOCTYPE?hibernate-configuration?PUBLIC
    ????????"-//Hibernate/Hibernate?Configuration?DTD?3.0//EN"
    ????????"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"
    >

    < hibernate-configuration >
    ????
    < session-factory >
    ????????
    < mapping? class ="com.xkland.domain.Role" />
    ????????
    < mapping? class ="com.xkland.domain.User" />
    ????????
    < mapping? class ="com.xkland.domain.Group" />
    ????
    </ session-factory >
    </ hibernate-configuration >


    再下一步,將上面的三個Manager類交給Spring管起來,配置src\main\resources\spring\serviceContext.xml,如下:

    <? xml?version="1.0"?encoding="UTF-8" ?>
    <! DOCTYPE?beans?PUBLIC?"-//SPRING//DTD?BEAN?2.0//EN"?"http://www.springframework.org/dtd/spring-beans-2.0.dtd" >
    < beans? default-lazy-init ="true" ?default-autowire ="byName" >
    ????
    < bean? id ="roleManager" ?class ="com.xkland.manager.RoleManager" />
    ????
    < bean? id ="userManager" ?class ="com.xkland.manager.UserManager" />
    ????
    < bean? id ="groupManager" ?class ="com.xkland.manager.GroupManager" />
    </ beans >


    最后一步,編寫一個Action類,用Spring將上面的三個Manager注入到Action中,測試能否順利的操作數(shù)據(jù)庫。Action類的代碼如下:

    package ?com.xkland.action;

    import ?org.apache.struts.action.Action;
    import ?org.apache.struts.action.ActionForward;
    import ?org.apache.struts.action.ActionForm;
    import ?org.apache.struts.action.ActionMapping;
    import ?javax.servlet.http.HttpServletRequest;
    import ?javax.servlet.http.HttpServletResponse;
    import ?com.xkland.manager. * ;
    import ?com.xkland.domain. * ;

    public ? class ?WelcomeAction? extends ?Action? {
    ?
    private ?RoleManager?roleManager;
    ?
    private ?UserManager?userManager;
    ?
    private ?GroupManager?groupManager;
    ?
    ?
    // 以下代碼的作用是注入三個Manager
    ? public ? void ?setUserManager(UserManager?userManager)? {
    ??
    this .userManager? = ?userManager;
    ?}


    ?
    public ? void ?setRoleManager(RoleManager?roleManager)? {
    ??
    this .roleManager? = ?roleManager;
    ?}

    ?
    ?
    public ? void ?setGroupManager(GroupManager?groupManager) {
    ??
    this .groupManager? = ?groupManager;
    ?}

    ?
    ?
    public ?ActionForward?execute(
    ???ActionMapping?mapping,
    ???ActionForm?form,
    ???HttpServletRequest?request,
    ???HttpServletResponse?response
    ???)
    {
    ??
    ??
    // 以下代碼測試能否添加role
    ??Role?role? = ? new ?Role();
    ??role.setName(
    " 第一個角色 " );
    ??role.setPrivilegesFlag(
    " 1,2,3,4, " );
    ??roleManager.save(role);
    ??
    ??
    // 以下代碼測試能否添加user
    ??User?user? = ? new ?User();
    ??user.setAnswer(
    " aa " );
    ??user.setEmail(
    " aa " );
    ??user.setQq(
    " aa " );
    ??user.setName(
    " abcdefg " );
    ??user.setPassword(
    " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa " );
    ??user.setQuestion(
    " aa " );
    ??user.setMonicker(
    " abcdefg " );
    ??user.setRole(roleManager.get(
    1 ));
    ??userManager.save(user);
    ??
    ??
    // 以下代碼測試能否添加group
    ??Group?group? = ? new ?Group();
    ??group.setName(
    " 第一個用戶組 " );
    ??group.setCreator(user);
    ??groupManager.save(group);
    ??
    ??
    // 以下代碼測試將user和group建立關(guān)聯(lián)
    ??user? = ?userManager.get( 1 );
    ??group?
    = ?groupManager.get( 1 );
    ??user.getGroups().add(group);
    ??group.getUsers().add(user);
    ??userManager.save(user);
    ??groupManager.save(group);
    ??
    ??
    // 重定向到
    ?? return ? new ?ActionForward( " /welcome.jsp " );
    ?}

    }



    怎樣配置Action這里就不用多嘴了,請參考SpringSide的文檔。這里還要說一句,一定要記得修改src\main\resources\spring\applicationContext.xml中的事務(wù)配置中的package,否則運行會出錯,配置文件片斷如下:

    <!-- ?以AspectJ方式?定義?AOP? -->
    ????
    < aop:config? proxy-target-class ="true" >
    ????????
    <!-- ?注意,請把第2個*號換為項目package? -->
    ????????
    < aop:advisor? pointcut ="execution(*?*..manager.*Manager.*(..))" ?advice-ref ="txAdvice" />
    ????????
    < aop:advisor? pointcut ="execution(*?org.springside.core.dao.*Dao.*(..))" ?advice-ref ="txAdvice" />
    ????
    </ aop:config >

    ????
    <!-- ?基本事務(wù)定義,使用transactionManager作事務(wù)管理,默認(rèn)get*方法的事務(wù)為readonly,其余方法按默認(rèn)設(shè)置.
    ?????????????默認(rèn)的設(shè)置請參考Spring文檔事務(wù)一章.?
    -->
    ????
    < tx:advice? id ="txAdvice" >
    ????????
    < tx:attributes >
    ????????????
    < tx:method? name ="get*" ?read-only ="true" />
    ????????????
    < tx:method? name ="find*" ?read-only ="true" />
    ????????????
    < tx:method? name ="*" />
    ????????
    </ tx:attributes >
    ????
    </ tx:advice >


    ?如果有興趣,還可以把hibernate.show_sql設(shè)置為true,以便觀察Hibernate生成的SQL語句,如下圖:
    29.JPG


    評論

    # re: SpringSide開發(fā)實戰(zhàn)(四):打通數(shù)據(jù)持久層的任督二脈  回復(fù)  更多評論   

    2007-01-05 17:15 by cc[匿名]
    so fast!
    加油,跟著你的springside系列文章學(xué)到了很多東西!

    # re: SpringSide開發(fā)實戰(zhàn)(四):打通數(shù)據(jù)持久層的任督二脈  回復(fù)  更多評論   

    2007-01-05 18:59 by suwu
    非常好,明白多了。。。。。

    # re: SpringSide開發(fā)實戰(zhàn)(四):打通數(shù)據(jù)持久層的任督二脈  回復(fù)  更多評論   

    2007-01-08 00:02 by willlim
    你真棒,希望你能繼續(xù)寫這么好的文章,會跟著一起學(xué)習(xí)的

    # 再談一下數(shù)據(jù)庫的備份策略  回復(fù)  更多評論   

    2007-01-09 17:48 by 海邊沫沫
      開發(fā)一個Web系統(tǒng),在決定好使用什么開發(fā)技術(shù)和使用什么應(yīng)用服務(wù)器之后,接下來的事情就應(yīng)該考慮數(shù)據(jù)怎樣儲存的問題了。使用數(shù)據(jù)庫自然是不二的選擇,在這里,我選擇MySQL 5.0以上的版本。數(shù)據(jù)庫中僅存儲文本信息和上傳的圖片保存為什么文件名和屬于哪個用戶,而圖片文件則一律保存在硬盤上。

      首先,我把MySQL的數(shù)據(jù)目錄改到一個單獨的磁盤分區(qū),這樣,當(dāng)我重裝應(yīng)用軟件的時候就不會影響到數(shù)據(jù)。先在E:/盤創(chuàng)建一個目錄MySQL_Data,然后打開MySQL安裝目錄下的my.ini文件,修改修改[mysqld]節(jié)的配置:
      datadir="E:/MySQL_Data/"

      下一步就是做一個數(shù)據(jù)備份的策略,既然我已經(jīng)決定要把所有數(shù)據(jù)永久保存,那么數(shù)據(jù)備份就是非常重要的一件事情了,只有經(jīng)常備份,才能防止意外造成數(shù)據(jù)丟失。我做的備份策略是這樣的:
      1.數(shù)據(jù)庫引擎選擇InnoDB,盡管它比MyISAM引擎要慢3-5倍,但是它是事務(wù)安全的,而且在服務(wù)器異常崩潰后,再次重啟服務(wù)器可以自動修復(fù)受損的數(shù)據(jù)表,這樣修改配置文件:
      default-storage-engine=INNODB
      2.創(chuàng)建專門的文件夾來儲存InnoDB的表空間文件和日志文件,在數(shù)據(jù)目錄下創(chuàng)建一個ibdata文件夾,并如下修改配置文件:
      innodb_data_home_dir = ./ibdata
      innodb_log_group_home_dir = ./ibdata
      innodb_data_file_path=ibdata1:50M:autoextend:max:1G

      這里我們先創(chuàng)建一個表空間文件,初始大小為50M,并可以自動增長,最大文件大小限制為1G,達(dá)到最大值之后,我們可以再添加一個表空間文件。
      3.固定時間備份,比如客流量不大的時候,可以每周備份一次,客流量大的時候可以每天備份一次。第一次備份時,使用mysqldump做一個完全備份,以后的備份,可以進(jìn)行增量備份。增量備份的時候,需要啟用二進(jìn)制日志,我們這樣修改配置:
      log-bin=./bin_log/binlog
      也就是在數(shù)據(jù)目錄下專門創(chuàng)建一個目錄bin_log來保存二進(jìn)制日志文件。另外,我們希望只記錄我們工作的這個數(shù)據(jù)庫的二進(jìn)制日志,而忽略其它的數(shù)據(jù)庫。配置文件這樣修改:
      binlog-do-db=dbname

    # re: SpringSide開發(fā)實戰(zhàn)(四):打通數(shù)據(jù)持久層的任督二脈[未登錄]  回復(fù)  更多評論   

    2007-01-16 10:23 by limq
    頂一個,不錯

    # re: SpringSide開發(fā)實戰(zhàn)(四):打通數(shù)據(jù)持久層的任督二脈  回復(fù)  更多評論   

    2007-01-18 00:13 by billbai
    辛苦了哈!很好的,我也正想試下這個,有沒有自動生成實體文件的,不用手工寫的

    # re: SpringSide開發(fā)實戰(zhàn)(四):打通數(shù)據(jù)持久層的任督二脈  回復(fù)  更多評論   

    2007-01-22 12:56 by 劉金龍
    這個東西沒有什么技術(shù)含量,只不過hibernate充分利用了Annotation特性而已,建議好好研究一下標(biāo)簽,呵呵

    # 8771100  回復(fù)  更多評論   

    2007-03-15 17:54 by 000
    0000

    # re: SpringSide開發(fā)實戰(zhàn)(四):打通數(shù)據(jù)持久層的任督二脈  回復(fù)  更多評論   

    2007-05-20 15:52 by feifei
    我啥都不說了```````、頂````

    # re: SpringSide開發(fā)實戰(zhàn)(四):打通數(shù)據(jù)持久層的任督二脈  回復(fù)  更多評論   

    2007-07-30 16:11 by 小白之家
    這個有點難

    # re: SpringSide開發(fā)實戰(zhàn)(四):打通數(shù)據(jù)持久層的任督二脈  回復(fù)  更多評論   

    2007-07-30 16:17 by 小白之家
    能給源碼打個包,look一下嗎?

    # re: SpringSide開發(fā)實戰(zhàn)(四):打通數(shù)據(jù)持久層的任督二脈  回復(fù)  更多評論   

    2007-10-17 23:46 by liuxiaoxia_555@163.com
    這樣做的話,在刪除group的時候會出錯啊!能說說怎么能刪除group的同時把user保留!而只是把usergroup表中的數(shù)據(jù)刪掉?

    # re: SpringSide開發(fā)實戰(zhàn)(四):打通數(shù)據(jù)持久層的任督二脈  回復(fù)  更多評論   

    2007-10-18 11:48 by 海邊沫沫
    樓上的說得有道理,我在寫測試代碼的時候只考慮到了添加,而沒有考慮到刪除。至于會不會出錯,我認(rèn)為不會,多對多關(guān)系刪除一方的時候不會刪除另外一方吧。

    就算確實會出錯,我們也可以在Hibernate中使用hql語句或SQL語句來直接操縱數(shù)據(jù)庫。

    # re: SpringSide開發(fā)實戰(zhàn)(四):打通數(shù)據(jù)持久層的任督二脈  回復(fù)  更多評論   

    2007-12-15 17:27 by Relax Lin
    太強(qiáng)拉,,,,,,,,,頂

    # re: SpringSide開發(fā)實戰(zhàn)(四):打通數(shù)據(jù)持久層的任督二脈  回復(fù)  更多評論   

    2008-01-18 17:48 by nicholas85211
    很透徹

    # re: SpringSide開發(fā)實戰(zhàn)(四):打通數(shù)據(jù)持久層的任督二脈  回復(fù)  更多評論   

    2008-06-28 15:29 by wzz
    測試可以用 user.setRole(roleManager.get( 1 ));。但是在Form頁面中怎么辦呢?form中傳過來的是String類型的數(shù)據(jù)啊,不是Role型的數(shù)據(jù)。會報錯的如:
    System Runtime Error:
    Unexpected reflection exception - java.lang.IllegalArgumentException: Cannot invoke com.fh.tms.model.User.setRole - argument type mismatch
    這個問題可以解決嗎?

    # re: SpringSide開發(fā)實戰(zhàn)(四):打通數(shù)據(jù)持久層的任督二脈  回復(fù)  更多評論   

    2008-08-13 08:09 by 笑笑笑笑笑笑笑
    re: SpringSide開發(fā)實戰(zhàn)(四):

    # re: SpringSide開發(fā)實戰(zhàn)(四):打通數(shù)據(jù)持久層的任督二脈  回復(fù)  更多評論   

    2008-12-07 19:55 by 虎嘯龍吟
    糾正一下建表的幾個小錯誤,正確的如下:
    create table users(
    id int not null auto_increment primary key ,
    username varchar ( 20 ) not null ,
    password char ( 32 ) not null ,
    monicker varchar ( 30 ) not null ,
    question varchar ( 30 ) not null ,
    answer varchar ( 30 ) not null ,
    email varchar ( 40 ) not null ,
    qq varchar ( 12 ) not null ,
    roleid int not null ,
    score int not null default ' 0 ' ,
    regtime timestamp not null default CURRENT_TIMESTAMP ,
    logintime timestamp not null default ' 2007-01-01 00:00:00 ' ,
    isdeleted varchar ( 2 ) not null default ' 0' ,
    index (username),
    index (monicker)
    );

    create table roles(
    id int not null auto_increment primary key ,
    rolename varchar ( 20 ) not null ,
    privilegesFlag varchar ( 255 ),
    index (rolename)
    );

    create table groups(
    id int not null auto_increment primary key ,
    groupname varchar ( 40 ) not null ,
    creatorid int not null ,
    createtime timestamp not null default CURRENT_TIMESTAMP ,
    isdeleted varchar ( 2 ) not null default ' 0' ,
    index (groupname)
    );

    create table users_groups(
    id int not null auto_increment primary key ,
    userid int not null ,
    groupid int not null ,
    jointime timestamp ,
    status tinyint ,
    index (userid),
    index (groupid)
    );
    主站蜘蛛池模板: 亚洲成AV人片一区二区密柚| 午夜精品射精入后重之免费观看 | 很黄很色很刺激的视频免费| 亚洲自偷自偷精品| 99精品视频在线观看免费专区| 亚洲ⅴ国产v天堂a无码二区| 久久久久久AV无码免费网站 | 国产成A人亚洲精V品无码性色| a视频在线免费观看| 亚洲精品无码久久久久sm| 99免费在线视频| 亚洲av色福利天堂| 99视频免费播放| 亚洲人和日本人jizz| 91视频国产免费| 亚洲欧美日韩综合久久久久| 日本成人免费在线| 青草青草视频2免费观看| 亚洲女同成人AⅤ人片在线观看| 亚洲阿v天堂在线2017免费| 亚洲日本va在线视频观看| 精品四虎免费观看国产高清午夜| 亚洲AV本道一区二区三区四区| 18观看免费永久视频| 亚洲乱码一区av春药高潮| 成人免费视频小说| 精品在线视频免费| 久久综合亚洲色HEZYO国产| 免费人成激情视频在线观看冫| 亚洲欧洲免费视频| 久久久高清免费视频| 亚洲精品理论电影在线观看| 全部免费国产潢色一级| 好湿好大好紧好爽免费视频| 亚洲AV无码国产在丝袜线观看| 日韩在线播放全免费| 亚洲日本VA午夜在线电影| 婷婷亚洲天堂影院| 国产成年无码久久久免费| 亚洲熟妇av一区二区三区下载| 在线观看免费宅男视频|