京山游俠

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

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

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

          所謂簡化,它具有如下幾個(gè)特點(diǎn):

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

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

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

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

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

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

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

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

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

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

          從上面的描述可以看出,一個(gè)簡化的用戶管理系統(tǒng)最少需要三個(gè)表,即users,roles和groups表,其中users和roles之間為多對一映射,users和groups之間為多對多映射,為了實(shí)現(xiàn)多對多映射,并且用戶加入群的時(shí)候需要管理員批準(zhǔn),需要一個(gè)中間表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í)也是管理員,這里同樣設(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è)計(jì)完數(shù)據(jù)庫,就該設(shè)計(jì)領(lǐng)域?qū)ο罅?,領(lǐng)域?qū)ο蟮脑O(shè)計(jì)方法為先設(shè)計(jì)簡單的POJO,然后再在POJO上添加Hibernate Annotation來配置映射關(guān)系。在進(jìn)行Annotation配置的時(shí)候,可以從以下幾個(gè)方面進(jìn)行思考。

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

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

          再來看看數(shù)據(jù)類型的映射,對于簡單的int、varchar這樣的就不用多說了。而日期時(shí)間類型的映射是一個(gè)重點(diǎn),可以看到,前面的數(shù)據(jù)庫創(chuàng)建語句中,所有需要時(shí)間的地方都使用了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能表示的時(shí)間范圍要小得多,在Java中,java.util.Date和MySQL的timestamp的精度是一致的,只能儲存到整數(shù)秒,而java.sql.Timestamp還保存毫微秒,因此建議使用java.util.Date來映射timestamp列,使用java.sql.Timestamp只是浪費(fèi)。

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

          這里只對幾個(gè)特殊的Annotation做一下注釋:
          1、因?yàn)閯?chuàng)建數(shù)據(jù)表的時(shí)候使用的是users,而實(shí)體類為User,單復(fù)數(shù)不同引發(fā)名稱不一致,因此需要@Table(name="users");
          2、因?yàn)樵摫碇械臄?shù)據(jù)不做物理刪除,所以加上@Undeletable(status="isDeleted"),結(jié)合SpringSide提供的HibernateEntityExtendDao類,可以在調(diào)用remove方法的時(shí)候?qū)sdeleted列設(shè)置為"-1";
          3、創(chuàng)建數(shù)據(jù)表的時(shí)候,所有的列名都是用的小寫字母,因此有的列映射需要明確指定,如@Column(name = "logintime",insertable=false);
          4、對于在創(chuàng)建數(shù)據(jù)表的時(shí)候定義了默認(rèn)值的列,如regtime、regtime、logintime、isdeleted,在向數(shù)據(jù)庫中添加數(shù)據(jù)的時(shí)候,可以不在insert語句中指定這些列,而讓它們使用默認(rèn)值,因此,需要告訴Hibernate在生成insert語句的時(shí)候不要包含這些列,可以使用insertable=false語句,如@Column(name = "regtime",insertable=false);
          5、指定時(shí)間精度,使用@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)載入一個(gè)用戶的資料時(shí),往往需要知道他加入了哪些群,而載入一個(gè)群的資料時(shí),往往需要知道它有哪些用戶,因此,他們之間是一個(gè)雙向的關(guān)系,同時(shí),載入一個(gè)群的資料時(shí),還需要知道它的管理員是誰,因此又同時(shí)存在一個(gè)單向的多對一關(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;
          }


          而整個(gè)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è)計(jì)和配置的代碼能否正常工作。首先,先創(chuàng)建三個(gè)Manager,這三個(gè)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 >


          再下一步,將上面的三個(gè)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 >


          最后一步,編寫一個(gè)Action類,用Spring將上面的三個(gè)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;
          ?
          ?
          // 以下代碼的作用是注入三個(gè)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(
          " 第一個(gè)角色 " );
          ??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(
          " 第一個(gè)用戶組 " );
          ??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,否則運(yùn)行會出錯(cuò),配置文件片斷如下:

          <!-- ?以AspectJ方式?定義?AOP? -->
          ????
          < aop:config? proxy-target-class ="true" >
          ????????
          <!-- ?注意,請把第2個(gè)*號換為項(xiàng)目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ā)實(shí)戰(zhàn)(四):打通數(shù)據(jù)持久層的任督二脈  回復(fù)  更多評論   

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

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

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

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

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

            下一步就是做一個(gè)數(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)建一個(gè)ibdata文件夾,并如下修改配置文件:
            innodb_data_home_dir = ./ibdata
            innodb_log_group_home_dir = ./ibdata
            innodb_data_file_path=ibdata1:50M:autoextend:max:1G

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

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

          2007-01-16 10:23 by limq
          頂一個(gè),不錯(cuò)

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

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

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

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

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

          2007-03-15 17:54 by 000
          0000

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

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

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

          2007-07-30 16:11 by 小白之家
          這個(gè)有點(diǎn)難

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

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

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

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

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

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

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

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

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

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

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

          # re: SpringSide開發(fā)實(shí)戰(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ù)。會報(bào)錯(cuò)的如:
          System Runtime Error:
          Unexpected reflection exception - java.lang.IllegalArgumentException: Cannot invoke com.fh.tms.model.User.setRole - argument type mismatch
          這個(gè)問題可以解決嗎?

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

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

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

          2008-12-07 19:55 by 虎嘯龍吟
          糾正一下建表的幾個(gè)小錯(cuò)誤,正確的如下:
          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)
          );
          主站蜘蛛池模板: 樟树市| 思茅市| 横峰县| 乌兰县| 罗甸县| 普安县| 惠东县| 阿拉尔市| 西丰县| 江永县| 文登市| 广水市| 万载县| 娄烦县| 鲜城| 泉州市| 沁源县| 平武县| 太和县| 宣化县| 长寿区| 凉城县| 赣榆县| 新乡县| 威宁| 穆棱市| 丁青县| 黔西县| 买车| 亳州市| 玉山县| 新绛县| 民和| 香格里拉县| 乌鲁木齐县| 清水河县| 甘孜| 京山县| 霍州市| 旺苍县| 扎兰屯市|