zoukankan      html  css  js  c++  java
  • 【Java EE 学习 69 下】【数据采集系统第一天】【实体类分析和Base类书写】

    之前SSH框架已经搭建完毕,现在进行实体类的分析和Base类的书写。Base类是抽象类,专门用于继承。

    一、实体类关系分析

      既然是数据采集系统,首先调查实体(Survey)是一定要有的,一个调查有多个页面(Page),一个页面有多个问题(Question),所以还要有页面和问题实体。参与完成调查之后一定还会生成若干个答案,所以还有答案实体(Answer),当然还有参与的用户(User),管理员是特殊的User,只需要登陆的时候进行判断即可。

      分析实体类型是比较简单的,最重要的是设计,怎样设计才能满足调查中所需要的各种字段要求?各个实体之间是否有关系,如果有关系是否需要做双向关联(hibernate配置文件中声明)?。

      首先从User实体开始分析,一个用户可以参与多个调查,一个调查可以被多个用户参与,所以User和Survey实体之间是典型的多对多关系。既然有有关系了,那么是否需要做双向关联?我们经常做的是根据User对象拿到该User对象拥有的所有Survey,我们基本上不会用到根据Survey对象取得User对象,所以我们只需要做User到Survey的多对多映射关系即可。以上的分析是错误的。这里的User和Survey之间的关系是创建的关系,而不是参与调查的关系。所以一个用户能够创建多个调查,但是一个调查只能被一个用户创建,所以调查和用户之间是多对一关系。虽然我们会通过User对象获取Survey对象集合,但是我们并不会经常这么做,而且这么做有一个致命的缺点,那就是会增加Session的存储压力。为了减小Session的存储压力,我们只做Survey到User的多对一单向关联,不做User到Survey的多对一关联。

      Survey实体和Page以及User均有关系,但是不做到User的多对多关系的映射。Survey和Page之间是一对多的关系,一个页面只能出现在一个Survey中,但是一个Survey中能够有多个Page。既然两者有关系,是需要做两者的双向关联关系还是单向关联关系?我们会根据Survey对象获取该对象的所有Page,也会根据该Page获取该页面属于哪一个Survey对象,所以我们需要做双向关联关系,即做Survey到Page的一对多映射和做Page到Survey的多对一映射。

      Page实体和Question同理,我们需要做Page到Quesiton的一对多映射,也需要做Question到Page的多对一映射。

      Answer实体暂时不作考虑。

    二、实体属性分析

      1.Question分析(最复杂)

        为了能够使用该Question对象保存住所有九种类型的选项,Quesiton中的属性能够表示出这九种类型。

        九种类型的题型(排列顺序不能改变,因为需要通过该位置获取问题的类别):

          第一类:非矩阵式横向单选按钮、非矩阵式纵向单选按钮、非矩阵式横向复选按钮、非矩阵式纵向复选按钮

          第二类:非矩阵式下拉列表

          第三类:非矩阵式文本框

          第四类:矩阵式单选按钮、矩阵式复选按钮

          第五类:矩阵式下拉列表

     1   private transient Integer questionId;                //问题的ID
     2     /**
     3      * 题型分为0-8一共九种类型
     4      */
     5     private int questionType;            //问题的题型
     6     private String title;            //问题的标题
     7     private String optionText;            //问题的选项
     8     private String[]optionTextArr;                                                //问题选项的集合
     9     
    10     private boolean other;            //其他项
    11     //其他项可能是无、文本框、下拉列表框
    12     private String otherType;        //其他项的样式
    13     private String otherSelectOptions;    //其他项如果是下拉列表框的话使用该项作为内容
    14     private String[] otherSelectOptionArr;                                        //该字段对应着其他项是多选框的情况,这里存放着拆分之后的字符串数组
    15     
    16     private String matrixRowTitles;        //矩阵式行标题集
    17     private String[] matrixRowTitleArr;                                            //矩阵式行标题集数组
    18     private String matrixColTitles;        //矩阵式列标题集
    19     private String[] matrixColTitleArr;                                            //矩阵式列标题集数组
    20     private String matrixSelectOptions;        //矩阵式下拉选项集
    21     private String []matrixSelectOptionArr;                                        //矩阵式下拉列表
    22     
    23     //Question和Page之间是多对一的关系
    24     private Page page;        

          对于每一个问题来说,不可能每个属性都用的到,但是必须要这么写,否则就需要针对每一种提醒设计一种Question实体,那样就麻烦了。

      2.Page

        private transient Integer pageId;            //页面id
        private String title="未命名";        //页面标题
        private String description;    //页面描述
        
        //page和调查之间是多对一的关系
        private transient Survey survey;
        //page和Question之间是一对多的关系
        private Set<Question> questions=new HashSet<Question>();
        private float orderNo;        //排序的优先级,默认值和pageId相同    

        需要说明一个字段是orderNo,该字段的用处是排序,默认值和pageId相同,这个将会在以后的复制/移动页的功能中使用到。

      3.Survey分析(复杂)

     1 private Integer surveyId;            //对应着调查id
     2     private String title="未命名";        //对应着调查名称
     3     private String preText="上一页";        //对应着翻页的上一个提示
     4     private String nextText="下一页";    //对应着下一页的提示
     5     private String exitText="退出";        //对应着退出的提示
     6     private String doneText="完成";    //对应着完成的提示文本
     7     private Date createDate=new Date();    //对应着创建的日期
     8     private String logoPath;            //使用该字段保存图标的位置,保存的是相对位置
     9     //调查和用户之间是多对一的关系
    10     private User user;
    11     //调查和Page之间是一对多的关系
    12     private transient Set<Page>pages=new HashSet<Page>();
    13     
    14     //添加一个调查是否可用的字段,表示打开或者关闭调查
    15     private boolean closed;
    16     
    17     /**
    18      * TODO 在数据库库中没有定义,但是需要在配置文件中定义并带到前端页面中使用
    19      */
    20     private float maxOrderNo;            //最小页序
    21     private float minOrderNo;            //最大页序
    22     
    23     //定义几个常量,方便判断是哪种类型的提交
    24     private  String submit_next="下一页";
    25     private String submit_pre="上一页";
    26     private String submit_done="提交";
    27     private String submit_exit="退出";

      4.Use类分析

    1 private Integer userId;                //用户id
    2     private String password;        //用户密码
    3     private String nickName;        //用户昵称
    4     private String email;            //用户邮件
    5     private Date registerDate;        //用户注册日期
    6     private Set<Role>roles;
    7     private Boolean superAdmin;    //判定是否是超级管理员的标识字段
    8     private long[]rightSum;        //进行权限判定的关键,注意这里一定要使用基本数据类型,否则会有问题,因为包装类型的默认值不是0,是null

        该类在项目初期中只用到了一部分属性,像是基本的userId、password等,剩下的roles、superAdmin、rightSum在权限管理模块中会使用到。

      5.hibernate映射文件略。

    三、Base类书写。

      1.BaseDao书写

         针对每一个实体,我们都需要写一个DAO操作对应的数据库中的表,将所有的DAO中的公共方法抽象出来放到一个抽象类中是一个比较好的方法,这样能够极大的重用代码。当然,我们还需要使用一个接口对该抽象类进行规范。

        DAO接口规范:

     1 package com.kdyzm.dao.base;
     2 
     3 import java.io.Serializable;
     4 import java.util.Collection;
     5 import java.util.List;
     6 
     7 public interface BaseDao <T>{
     8     //写操作
     9     public void saveEntity(T t);
    10     public void updateEntity(T t);
    11     public void saveOrUpdateEntity(T t);
    12     public void deleteEntiry(T t);
    13     
    14     //按照hql批处理
    15     public void batchEntityByHql(String hql,Object ...objects);
    16     
    17     //查询方法
    18     public T getEntityById(Serializable id);
    19     public T loadEntiryById(Serializable id);
    20     public List<T> findEntityByHQL(String hql,Object ...objects);
    21     public Object findUniqueResult(String hql,Object ...objects);
    22     public Collection<T> findAllEntities();
    23     public void executeSql(String sql,Object ...objects);
    24     public Collection<T> findAllEntitiesBySql(String sql,Object ...objects);
    25 }

        实现类(抽象):

      1 package com.kdyzm.dao.base.impl;
      2 
      3 import java.io.Serializable;
      4 import java.lang.reflect.ParameterizedType;
      5 import java.util.Collection;
      6 import java.util.List;
      7 
      8 import javax.annotation.Resource;
      9 
     10 import org.hibernate.Query;
     11 import org.hibernate.SQLQuery;
     12 import org.hibernate.SessionFactory;
     13 
     14 import com.kdyzm.dao.base.BaseDao;
     15 /***
     16  * BaseDaoImpl类必须是抽象类,实现已经定义好的接口
     17  * @author kdyzm
     18  *
     19  * @param <T>
     20  */
     21 @SuppressWarnings("unchecked")
     22 public abstract class BaseDaoImpl<T> implements BaseDao<T> {
     23     //手下需要两个成员变量,这两个成员变量的赋值,一个是通过spring容器管理,一个是通过泛型动态获取
     24     @Resource(name="sessionFactory")
     25     public SessionFactory sessionFactory;
     26     private Class<T> clazz;
     27     
     28     //在默认构造方法中调用相关程序获取真实的泛型类型
     29     public BaseDaoImpl() {
     30         ParameterizedType parameterizedType=(ParameterizedType) this.getClass().getGenericSuperclass();
     31         clazz=(Class<T>) parameterizedType.getActualTypeArguments()[0];
     32     }
     33     @Override
     34     public void saveEntity(T t) {
     35         System.out.println("将要保存"+t);
     36         this.sessionFactory.getCurrentSession().save(t);
     37     }
     38 
     39     @Override
     40     public void updateEntity(T t) {
     41         this.sessionFactory.getCurrentSession().update(t);
     42     }
     43 
     44     @Override
     45     public void saveOrUpdateEntity(T t) {
     46         this.sessionFactory.getCurrentSession().saveOrUpdate(t);
     47     }
     48 
     49     @Override
     50     public void deleteEntiry(T t) {
     51         this.sessionFactory.getCurrentSession().delete(t);
     52     }
     53 
     54     //批量处理更新的方法重点是使用Query对象
     55     @Override
     56     public void batchEntityByHql(String hql, Object... objects) {
     57         Query query=this.sessionFactory.getCurrentSession().createQuery(hql);
     58         for(int i=0;i<objects.length;i++){
     59             query.setParameter(i, objects[i]);
     60         }
     61         query.executeUpdate();
     62     }
     63 
     64     @Override
     65     public T getEntityById(Serializable id) {
     66         return (T) this.sessionFactory.getCurrentSession().get(clazz,id);
     67     }
     68 
     69     @Override
     70     public T loadEntiryById(Serializable id) {
     71         return (T) this.sessionFactory.getCurrentSession().load(clazz, id);
     72     }
     73 
     74     @Override
     75     public List<T> findEntityByHQL(String hql, Object... objects) {
     76         Query query=this.sessionFactory.getCurrentSession().createQuery(hql);
     77         for(int i=0;i<objects.length;i++){
     78             query.setParameter(i, objects[i]);
     79         }
     80         return query.list();
     81     }
     82     @Override
     83     public Object findUniqueResult(String hql, Object... objects) {
     84         Query query=this.sessionFactory.getCurrentSession().createQuery(hql);
     85         for(int i=0;i<objects.length;i++){
     86             query.setParameter(i, objects[i]);
     87         }
     88         return query.uniqueResult();
     89     }
     90     @Override
     91     public Collection<T> findAllEntities(){
     92         String hql="from "+clazz.getSimpleName();
     93         return this.sessionFactory.getCurrentSession().createQuery(hql).list();
     94     }
     95     //直接执行sql语句的方法
     96     @Override
     97     public void executeSql(String sql, Object... objects) {
     98         SQLQuery sqlQuery=this.sessionFactory.getCurrentSession().createSQLQuery(sql);
     99         for(int i=0;i<objects.length;i++){
    100             sqlQuery.setParameter(i, objects[i]);
    101         }
    102         sqlQuery.executeUpdate();
    103     }
    104     //根据sql语句得到List集合的方法
    105     @Override
    106     public Collection<T> findAllEntitiesBySql(String sql, Object... objects) {
    107         SQLQuery sqlQuery=this.sessionFactory.getCurrentSession().createSQLQuery(sql);
    108         for(int i=0;i<objects.length;i++){
    109             sqlQuery.setParameter(i, objects[i]);
    110         }
    111         sqlQuery.addEntity(clazz);
    112         return sqlQuery.list();
    113     }
    114 }

          实现类需要解决的问题:实现所有的公共方法是其功能要求,想要实现这一点,就必须解决一个最重要的问题,如何获取泛型类型,所有的DAO都会提供一个泛型给父类,即BaseDaoImpl,父类必须知道该类型是什么,在构造方法中获取该类型是最合适的:

    //在默认构造方法中调用相关程序获取真实的泛型类型
        public BaseDaoImpl() {
            ParameterizedType parameterizedType=(ParameterizedType) this.getClass().getGenericSuperclass();
            clazz=(Class<T>) parameterizedType.getActualTypeArguments()[0];
        }

        这样clazz对象就保存到了类中的成员变量,其它方法就能够直接使用该对象了。

      2.BaseService书写

        BaseService接口中的方法和DAO中的方法相同,实现类中直接调用DAO中的方法

     1 package com.kdyzm.service.base;
     2 
     3 import java.io.Serializable;
     4 import java.util.Collection;
     5 import java.util.List;
     6 
     7 public interface BaseService<T> {
     8     //写操作
     9     public void saveEntity(T t);
    10     public void updateEntity(T t);
    11     public void saveOrUpdateEntity(T t);
    12     public void deleteEntiry(T t);
    13     
    14     //按照hql批处理
    15     public void batchEntityByHql(String hql,Object ...objects);
    16     
    17     //查询方法
    18     public T getEntityById(Serializable id);
    19     public T loadEntiryById(Serializable id);
    20     public List<T> findEntityByHQL(String hql,Object ...objects);
    21     public Collection<T> findAllEntities();
    22     
    23     public void executeSql(String sql,Object ...objects);
    24     public Collection<T> findAllEntitiesBySQl(String sql,Object ...objects);
    25 }
    com.kdyzm.service.base.BaseService

        BaseServiceImpl实现:实现类中有一个BaseDao<T>类型的成员变量,所有的DAO都实现了BaseDao接口,所以直接使用该接口来引用子类对象是可以的,但是拿到泛型的方式并不是DAO中的实现方式,而是直接由实现类通过set方法传递过来。

        public BaseDao<T> baseDao;
        public void setBaseDao(BaseDao<T> baseDao) {
            this.baseDao = baseDao;
        }    

    四、针对各种DAO和Service的实现类略。

    五、测试

      1.实现加入log4j的配置文件到classpath,方便查看控制台输出。

     1 ### direct log messages to stdout ###
     2 log4j.appender.stdout=org.apache.log4j.ConsoleAppender
     3 log4j.appender.stdout.Target=System.out
     4 log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
     5 log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
     6 
     7 ### direct messages to file hibernate.log ###
     8 #log4j.appender.file=org.apache.log4j.FileAppender
     9 #log4j.appender.file.File=hibernate.log
    10 #log4j.appender.file.layout=org.apache.log4j.PatternLayout
    11 #log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
    12 
    13 ### set log levels - for more verbose logging change 'info' to 'debug' ###
    14 
    15 log4j.rootLogger=warn, stdout
    16 
    17 #log4j.logger.org.hibernate=info
    18 log4j.logger.org.hibernate=info
    19 
    20 ### log HQL query parser activity
    21 #log4j.logger.org.hibernate.hql.ast.AST=debug
    22 
    23 ### log just the SQL
    24 #log4j.logger.org.hibernate.SQL=debug
    25 
    26 ### log JDBC bind parameters ###
    27 log4j.logger.org.hibernate.type=info
    28 #log4j.logger.org.hibernate.type=debug
    29 
    30 ### log schema export/update ###
    31 log4j.logger.org.hibernate.tool.hbm2ddl=debug
    32 
    33 ### log HQL parse trees
    34 #log4j.logger.org.hibernate.hql=debug
    35 
    36 ### log cache activity ###
    37 #log4j.logger.org.hibernate.cache=debug
    38 
    39 ### log transaction activity
    40 #log4j.logger.org.hibernate.transaction=debug
    41 
    42 ### log JDBC resource acquisition
    43 #log4j.logger.org.hibernate.jdbc=debug
    44 
    45 ### enable the following line if you want to track down connection ###
    46 ### leakages when using DriverManagerConnectionProvider ###
    47 #log4j.logger.org.hibernate.connection.DriverManagerConnectionProvider=trace
    log4j.properties

      2.测试类

     1 public class TestUserService {
     2         private static ApplicationContext ac = null ;
     3         
     4         @BeforeClass
     5         public static void iniAC(){
     6             ac = new ClassPathXmlApplicationContext("spring/applicationContext.xml");
     7         }
     8         
     9         @Test
    10         public void insertUser(){
    11             UserService us = (UserService) ac.getBean("userService");
    12             User u = new User();
    13             u.setEmail("kdyzm@foxmail.com");
    14             u.setPassword("123456");
    15             us.saveEntity(u);
    16         }
    17     }

      

  • 相关阅读:
    阿里巴巴研究员叔同:云原生是企业数字创新的最短路径
    【OpenYurt 深度解析】边缘网关缓存能力的优雅实现
    K8s 原生 Serverless 实践:ASK 与 Knative
    一年增加 1.2w 星,Dapr 能否引领云原生中间件的未来?
    源码解读:KubeVela 是如何将 appfile 转换为 K8s 特定资源对象的
    绘本推荐
    油猴Tampermonkey
    lan蓝tern灯
    6岁叛逆期
    留白
  • 原文地址:https://www.cnblogs.com/kuangdaoyizhimei/p/5050368.html
Copyright © 2011-2022 走看看