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

本文将介绍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")
@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);
    }
}

测试成功运行

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值