基于Struts2和hibernate的WebSocket聊天室的实现教程三:Hibernate个人信息管理

来源:互联网 发布:数据加密 编辑:程序博客网 时间:2024/06/07 02:42

本文将介绍struts2和hibernate在项目中的实际应用

建立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")@DynamicInsertpublic 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);    }}

测试成功运行

阅读全文
0 0