基于Struts2和hibernate的WebSocket聊天室的实现教程三:Hibernate个人信息管理
2017-11-21 12:15
579 查看
本文将介绍struts2和hibernate在项目中的实际应用
我有想过几种方法,比如文件存储,会话存储..但我在实际上操作大都不太可行。于是这次还是简单的把聊天记录储存到mysql数据库中…..
好的,接下来我们要建两个实体类。User和ChatRecord类。
User类用来保存用户信息,一般来说有这么几个属性:
但是我们要使用hibernate进行dao层操作,因此在这个实体类中要配置一对多关系映射。毕竟一个用户的聊天记录一般不止一个,与当前用户对应的聊天记录应该是0…*
所以我们还要增加一个属性
当然为了方便实例化这个对象,我们还需要设计构造方法
使用注解配置实体类的方法也特别简单,这里简单解释一下代码中使用到的注解的作用
@Entity 标注当前类为实体类
@Table 建立与数据库中表的连接
我们一般不在属性前使用注解,这里我们在get方法前添加注解
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
声明数据库表主键,设置数据自增。这里的strategy有多种策略,一般我们使用上面这种
@Column 配置列,保持类型与java类型一致
@Column(name = “registerTime”,columnDefinition = “timestamp default CURRENT_TIMESTAMP”) 对数据库对应列的类型自定义,并且设置默认值。这里是默认使用当前时间。
insertable=false表明在插入数据时无需传入当前注解配置的属性(这里指loginTime)
@OneToMany(cascade = {CascadeType.ALL}, fetch = FetchType.EAGER,mappedBy=”sender”) 配置一对多关系映射,cascadeType设置级联操作,,mappedBy=”sender”注明外键。在ChatRecord类中我们将创建这个sender属性与之对应。
这个时候,User类的代码应该是这样的:
同理,在ChatRecord类中我们也这样设计:
@DynamicInsert 动态插入数据
@ManyToOne(cascade = CascadeType.ALL) 多对一映射
@JoinColumn(name=”senderId”) 设置外键(数据库将显示senderId这一列,但是在通过hibernate查询的时候会查询出整个sender对象)
由于我们在第一篇文章中添加hibernate.cfg.xml的时候直接指定了数据库为chatroom,为此我们必须保证mysql中有这个数据库。
所以我们在mysql命令行中使用这句命令创建数据库并且要防止中文乱码,注意事项传送门:
好的,后面的表什么的就不用我们自己创建了,hibernate在运行时会自动创建。
最后还有一步,我们需要在hibernate.cfg.xml中注册这两个实体类,如下图
我们在util包中建立HibernateUtil类帮助我们获取session
在dao包里面,添加HibernateDao作为基类,以方便代码复用。
同时,我们为这两个实体类建立接口,如下图所示
BaseDaoImpl类实际上只是单纯的继承了HibernateDao这个基类,为什么要建立这个BaseDaoImpl呢,实际上是为了便于对父类进行补充和修改。如下:
在ChatRecordDao接口中,没有其他的什么需求需要自定义数据库操作方法,使用常规的CRUD方法即可。于是这个接口这样定义:
在impl包中需要实现这个接口,虽然是个空的:
但是在UserDao中,我们要补充一个方法,用于用户注册和查询
在impl包中这样实现接口
上面的代码中我们使用到了hql,是Hibernate方便我们自定义sql操作而定义的。
下面我们测试HIbernate是否正常工作。
有的话就双击
没有的话双击shift打开database界面
选择mysql连接
连接
第一次连接可能没有驱动包,让IDE自动帮你下载即可。
连接成功以后
我们在test包中新建测试类
测试成功运行
建立pojo类,使用注解配置hibernate映射
在需求分析的时候我们知道需要保存用户的聊天记录,那么怎么保存呢?我有想过几种方法,比如文件存储,会话存储..但我在实际上操作大都不太可行。于是这次还是简单的把聊天记录储存到mysql数据库中…..
好的,接下来我们要建两个实体类。User和ChatRecord类。
User类用来保存用户信息,一般来说有这么几个属性:
private int id ;//用户id主键 private String name;//用户名 private String avatar;//头像路径 private int sex;//0 for male 1 for female private Timestamp registerTime;//注册时间 private Timestamp loginTime;//登录时间
但是我们要使用hibernate进行dao层操作,因此在这个实体类中要配置一对多关系映射。毕竟一个用户的聊天记录一般不止一个,与当前用户对应的聊天记录应该是0…*
所以我们还要增加一个属性
private Set<ChatRecord> chatRecords =new HashSet<>();
当然为了方便实例化这个对象,我们还需要设计构造方法
public User() { } public User(String name, String avatar, int sex) { this.name = name; this.avatar = avatar; this.sex = sex; }
使用注解配置实体类的方法也特别简单,这里简单解释一下代码中使用到的注解的作用
@Entity 标注当前类为实体类
@Table 建立与数据库中表的连接
我们一般不在属性前使用注解,这里我们在get方法前添加注解
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
声明数据库表主键,设置数据自增。这里的strategy有多种策略,一般我们使用上面这种
@Column 配置列,保持类型与java类型一致
@Column(name = “registerTime”,columnDefinition = “timestamp default CURRENT_TIMESTAMP”) 对数据库对应列的类型自定义,并且设置默认值。这里是默认使用当前时间。
insertable=false表明在插入数据时无需传入当前注解配置的属性(这里指loginTime)
@OneToMany(cascade = {CascadeType.ALL}, fetch = FetchType.EAGER,mappedBy=”sender”) 配置一对多关系映射,cascadeType设置级联操作,,mappedBy=”sender”注明外键。在ChatRecord类中我们将创建这个sender属性与之对应。
这个时候,User类的代码应该是这样的:
package cn.zipple.entity; import javax.persistence.*; import java.sql.Timestamp; import java.util.HashSet; import java.util.Set; /** * Created by zipple on 2017/11/13. * 用户实体 */ @Entity @Table(name = "users") public class User { private int id ; private String name; private String avatar;//头像路径 private int sex;//0 for male 1 for female private Timestamp registerTime; private Timestamp loginTime; private Set<ChatRecord> chatRecords =new HashSet<>(); @Id @GeneratedValue(strategy = GenerationType.IDENTITY) public int getId() { return id; } public void setId(int id) { this.id = id; } @Column(name = "name") public String getName() { return name; } public void setName(String name) { this.name = name; } @Column(name = "avatar") public String getAvatar() { return avatar; } public void setAvatar(String avatar) { this.avatar = avatar; } @Column(name = "gender") public int getSex() { return sex; } public void setSex(int sex) { this.sex = sex; } @Column(name = "registerTime",columnDefinition = "timestamp default CURRENT_TIMESTAMP") public Timestamp getRegisterTime() { return registerTime; } public void setRegisterTime(Timestamp registerTime) { this.registerTime = registerTime; } @Column(name = "loginTime",insertable = false) public Timestamp getLoginTime() { return loginTime; } public void setLoginTime(Timestamp loginTime) { this.loginTime = loginTime; } @OneToMany(cascade = {CascadeType.ALL}, fetch = FetchType.EAGER,mappedBy="sender") public Set<ChatRecord> getChatRecords() { return chatRecords; } public void setChatRecords(Set<ChatRecord> chatRecords) { this.chatRecords = chatRecords; } public User() { } public User(String name, String avatar, int sex) { this.name = name; this.avatar = avatar; this.sex = sex; } }
同理,在ChatRecord类中我们也这样设计:
@DynamicInsert 动态插入数据
@ManyToOne(cascade = CascadeType.ALL) 多对一映射
@JoinColumn(name=”senderId”) 设置外键(数据库将显示senderId这一列,但是在通过hibernate查询的时候会查询出整个sender对象)
package cn.zipple.entity; import org.hibernate.annotations.DynamicInsert; import javax.persistence.*; import java.sql.Timestamp; /** * Created by zipple on 2017/11/13. * 聊天记录 */ @Entity @Table(name = "chatRecord") @DynamicInsert public class ChatRecord { private int id; private User sender; private int receiver;//指定id private String content; private Timestamp time; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) public int getId() { return id; } public void setId(int id) { this.id = id; } //不需要懒加载 @ManyToOne(cascade = CascadeType.ALL) @JoinColumn(name="senderId") public User getSender() { return sender; } public void setSender(User sender) { this.sender = sender; } @Column(name = "receiverId") public int getReceiver() { return receiver; } public void setReceiver(int receiver) { this.receiver = receiver; } @Column(name = "content",columnDefinition = "LONGTEXT") public String getContent() { return content; } public void setContent(String content) { this.content = content; } @Column(name = "time",columnDefinition = "timestamp default CURRENT_TIMESTAMP") public Timestamp getTime() { return time; } public void setTime(Timestamp time) { this.time = time; } public ChatRecord() { } public ChatRecord(User sender, int receiver, String content) { this.sender = sender; this.receiver = receiver; this.content = content; this.time=new Timestamp(System.currentTimeMillis()); } }
由于我们在第一篇文章中添加hibernate.cfg.xml的时候直接指定了数据库为chatroom,为此我们必须保证mysql中有这个数据库。
所以我们在mysql命令行中使用这句命令创建数据库并且要防止中文乱码,注意事项传送门:
CREATE DATABASE IF NOT EXISTS chatroom DEFAULT CHARSET utf8 COLLATE utf8_general_ci;
好的,后面的表什么的就不用我们自己创建了,hibernate在运行时会自动创建。
最后还有一步,我们需要在hibernate.cfg.xml中注册这两个实体类,如下图
编写DAO层方法
使用Hibernate的方法也特别简单,先加载hibernate.cfg.xml这个文件,然后获取SessionFactory获取session,建立事务,进行CRUD,再提交事务即可。详情请点击我们在util包中建立HibernateUtil类帮助我们获取session
package cn.zipple.util; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.boot.MetadataSources; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; /** * Created by zipple on 2017/10/12. * hibernate 工具类 */ public class HibernateUtil { /** * 连接数据库 * @return 返回session */ public static Session getHibernateSession(){ StandardServiceRegistry serviceRegistry=new StandardServiceRegistryBuilder().configure().build(); SessionFactory sessionFactory=new MetadataSources(serviceRegistry).buildMetadata().buildSessionFactory(); return sessionFactory.openSession(); } }
在dao包里面,添加HibernateDao作为基类,以方便代码复用。
package cn.zipple.dao; import cn.zipple.util.HibernateUtil; import org.hibernate.Session; import org.hibernate.Transaction; import java.util.List; /** * Created by zipple on 2017/10/12. * 父类提供基本的公共操作 */ public class HibernateDao { /** * 增加一条记录 * @param object 持久化类 */ public void save(Object object){ Session session = HibernateUtil.getHibernateSession(); Transaction tr =session.beginTransaction(); // session.save(object); session.saveOrUpdate(object); tr.commit(); session.close(); } /** * 删除记录 * @param object 持久化类 */ public void del(Object object){ Session session = HibernateUtil.getHibernateSession(); Transaction tr =session.beginTransaction(); session.delete(object); tr.commit(); session.close(); } /** * 修改对象信息 * @param object 持久化对象 */ public void upd(Object object){ Session session = HibernateUtil.getHibernateSession(); Transaction tr =session.beginTransaction(); session.merge(object);//使用merge防止从数据库中查询出来的持久化对象再被查询一次,从而导致异 // 常:illegally attempted to associate a proxy with two open Sessions //向修改过后的对象 合并 //session.saveOrUpdate(stu); tr.commit(); session.close(); } /** * 获取数据库中所有对象 * @param extra 额外条件--附加条件 * @return 返回对象列表 */ public List getAllObject(String entityClass,String extra){ Session session = HibernateUtil.getHibernateSession(); String hql = "from "+entityClass+extra; System.out.println("hql:"+hql); List studentList = session.createQuery(hql).list(); session.close(); return studentList; } /** * 根据id获取对象 * @param id id * @return 返回对象 */ public Object getObjetcById(int id){ Session session = HibernateUtil.getHibernateSession(); Transaction tr =session.beginTransaction(); session.close(); Object obj = session.get(Object.class, id); tr.commit(); session.close(); return obj; } }
同时,我们为这两个实体类建立接口,如下图所示
BaseDaoImpl类实际上只是单纯的继承了HibernateDao这个基类,为什么要建立这个BaseDaoImpl呢,实际上是为了便于对父类进行补充和修改。如下:
package cn.zipple.dao.impl; import cn.zipple.dao.HibernateDao; /** * Created by zipple on 2017/11/13. * 基类 */ public class BaseDaoImpl extends HibernateDao { }
在ChatRecordDao接口中,没有其他的什么需求需要自定义数据库操作方法,使用常规的CRUD方法即可。于是这个接口这样定义:
package cn.zipple.dao; /** * Created by zipple on 2017/11/13. */ public interface ChatRecordDao { }
在impl包中需要实现这个接口,虽然是个空的:
package cn.zipple.dao.impl; import cn.zipple.dao.ChatRecordDao; /** * Created by zipple on 2017/11/18. */ public class ChatRecordDaoImpl extends BaseDaoImpl implements ChatRecordDao { }
但是在UserDao中,我们要补充一个方法,用于用户注册和查询
package cn.zipple.dao; import cn.zipple.entity.User; /** * Created by zipple on 2017/11/13. */ public interface UserDao { /** * 根据用户名获取用户对象 * @param username 用户名 * @return 返回对象 */ User getUserByUsername(String username); }
在impl包中这样实现接口
package cn.zipple.dao.impl; import cn.zipple.dao.UserDao; import cn.zipple.entity.User; import cn.zipple.util.HibernateUtil; import org.hibernate.Session; import org.hibernate.query.Query; import java.util.List; /** * Created by zipple on 2017/11/13. */ public class UserDaoImpl extends BaseDaoImpl implements UserDao { @Override public User getUserByUsername(String username) { Session session = HibernateUtil.getHibernateSession(); String hql = "from User where name =:username";//User代表的是User实体类而不是表名 Query query = session.createQuery(hql); query.setParameter("username",username); System.out.println("hql:"+hql); List userList = query.list(); session.close(); if (userList.size()!=0){ return (User) userList.get(0); } return null; } }
上面的代码中我们使用到了hql,是Hibernate方便我们自定义sql操作而定义的。
下面我们测试HIbernate是否正常工作。
Intellij连接数据库
首先我们检查IDE右侧边栏是否有database一项,如图有的话就双击
没有的话双击shift打开database界面
选择mysql连接
连接
第一次连接可能没有驱动包,让IDE自动帮你下载即可。
连接成功以后
我们在test包中新建测试类
package cn.zipple.test; import cn.zipple.dao.impl.BaseDaoImpl; import cn.zipple.entity.ChatRecord; import cn.zipple.entity.User; import cn.zipple.util.Constant; /** * Created by zipple on 2017/11/13. * 测试 */ public class UserTest { private BaseDaoImpl baseDao = new BaseDaoImpl(); public static void main(String[] args) { System.out.println("测试hibernate是否正常工作"); new UserTest().testAdd(); } private void testAdd(){ User user1 = new User("邹博","01.jpg", Constant.MALE); User user2 = new User("李欣雨","02.jpg", Constant.FEMALE); System.out.println("储存用户1"); baseDao.save(user1);//先保存没有维护关系的那一方 System.out.println("储存用户2"); baseDao.save(user2); ChatRecord temp = new ChatRecord(user1,user2.getId(),"这是第一条测试信息"); System.out.println("储存聊天信息"); baseDao.save(temp); } }
测试成功运行
相关文章推荐
- 基于Struts2和hibernate的WebSocket聊天室的实现教程五:聊天机制
- 基于Struts2和hibernate的WebSocket聊天室的实现教程一:环境搭建
- 基于Struts2和hibernate的WebSocket聊天室的实现教程六:界面原型及通信请求
- 基于Struts2和hibernate的WebSocket聊天室的实现教程二:发送在线列表
- 基于Struts2和hibernate的WebSocket聊天室的实现教程四:实现登录接口
- Acegi+hibernate 动态实现基于角色的权限管理
- 基于SpringSecurity3.x, JasperReport5.x等技术实现仿金蝶权限管理的企业信息管理系统
- Apache Shiro+SpringMVC+Hibernate Search+Hibernate+Bootstrap企业信息管理系统基础框架搭建整合实例代码教程
- struts2通过基于XML的配置实现校验没有提示信息
- 开源一个基于Flex4+C#的个人信息管理程序
- web即时通信2--基于Spring websocket实现web聊天室
- SpringMVC学习系列(12) 完结篇 之 基于Hibernate+Spring+Spring MVC+Bootstrap的管理系统实现
- SpringMVC学习系列(12) 完结篇 之 基于Hibernate+Spring+Spring MVC+Bootstrap的管理系统实现
- SpringMVC学习系列(12) 完结篇 之 基于Hibernate+Spring+Spring MVC+Bootstrap的管理系统实现
- SpringMVC学习系列(12) 完结篇 之 基于Hibernate+Spring+Spring MVC+Bootstrap的管理系统实现
- Acegi+hibernate 动态实现基于角色的权限管理
- Unity3D教程:实现基于Socket通讯的公共聊天室
- 项目视频讲解_基于SpringSecurity3.x, JasperReport5.x等技术实现仿金蝶权限管理的企业信息管理系统
- SpringMVC(12)完结篇 基于Hibernate+Spring+Spring MVC+Bootstrap的管理系统实现
- 基于MIS通用管理组件的GIS信息管理平台设计与实现 推荐