你的位置:首页 > Java教程

[Java教程]Hibernate 拥有 Mybits 的SQL/HQL特性 (注解、XML两不误)


    第一次写博客。文章有点渣,喜欢就看看,不喜欢路过点个赞。

    效果:直接一条语句多种用法

  1.     FROM User A
  2.    WHERE
  3.    1=1
  4.    <#if id??>
  5.       <#if like??>
  6.          and A.id like '%'||:id||'%'
  7.       <#else>
  8.          and A.id=:id
  9.       </#if>
  10.    </#if>

    先来原理 HQL/SQL + Freemarker 模版生成查询语句。

    1:把SQL/HQL写在

    2:编写文件扫描器(缺)

    3:读取解释

    4:按实体类空间缓存查询语句

    5:直接使用

注意:不要直接复制,先弄懂流程,因为这源于旧版本及测试包来写的,也省略了部分代码,因此包路径有问题。程序也不完整,缺了的自己让大家自己去思考实现。基本上依赖Spring,不依赖Spring注入的可以考虑用代理模式注入(反射/生成字节码(javassist/asm)/CGLIB等)

1:为了方便先定义约束Query.dtd

  1. <??>
  2. <!ELEMENT QueryList (Alias*,Query*)>
  3. <!--<!ELEMENT Context (CachePool,Bean*,Intercept*,ScanToPack*,CloneModel)>-->
  4. <!ELEMENT Alias EMPTY><!--别名-->
  5. <!ELEMENT Query (#PCDATA)><!--sql/hql-->
  6.  
  7. <!--QueryList-->
  8. <!ATTLIST QueryList package CDATA #REQUIRED>
  9. <!--Alias-->
  10. <!ATTLIST Alias name CDATA #REQUIRED><!--实体类全名-->
  11. <!ATTLIST Alias Alias CDATA #REQUIRED><!--SQL/HQL 语句中的实体类别名-->
  12. <!--Query-->
  13. <!ATTLIST Query name CDATA #REQUIRED><!--实体类全名-->
  14. <!ATTLIST Query type (HQL|SQL) #REQUIRED><!--语句类型:HQL/SQL-->
  15. <!ATTLIST Query freemarkFormat (false|true) #REQUIRED><!--是否使用FREEMARK标签格式化-->
  16. <!ATTLIST Query resultType CDATA #IMPLIED><!--实体类全名-->
  17. <!ATTLIST Query Alias (true|false) #REQUIRED><!--是否使用了类别名-->

2:建个实体类user.class

  1. package project.master.user;
  2. //import、getting、setting 省略
  3. @Entity
  4. public class User extends AbstractEntity {
  5.    private static final long serialVersionUID = 1L;
  6.    @Id
  7.    private String id;
  8.    @Column(unique = true)
  9.    private String phone;// 用户名(手机号)
  10.    private String password;
  11.    private int status;// 帐号状态(锁定、停用、正常)
  12.    private Date lastLogin;
  13.    @Column(updatable = false, nullable = false)
  14.    private Date createDate = new Date();
  15. }

3:建立对应的

  1. <?1.0" encoding="UTF-8"?>
  2. <!DOCTYPE QueryList SYSTEM "Query.dtd">
  3. <QueryList package="project.master.user.User">
  4.    <Alias name="project.master.user.User" Alias="User" />
  5.    <Alias name="project.freehelp.common.entity.Dictionary" Alias="Dictionary" />
  6.    <Query name="list" type="HQL" freemarkFormat="true" Alias="true">
  7.       <![CDATA[
  8.          FROM User A
  9.          WHERE
  10.          1=1
  11.          <#if id??>
  12.             <#if like??>
  13.                and A.id like '%'||:id||'%'
  14.             <#else>
  15.                and A.id=:id
  16.             </#if>
  17.          </#if>
  18.          <!-- 各字段判断省略 -->
  19.       ]]>
  20.    </Query>
  21.    <Query name="AAX" type="HQL" freemarkFormat="true" Alias="true">
  22.       <!--测试 -->
  23.       SELECT A.phone,(SELECT D.value FROM Dictionary D WHERE D.id='1') as xValue FROM User A
  24.    </Query>
  25.    <Query name="checkUser" type="HQL" freemarkFormat="false" Alias="true">
  26.       SELECT COUNT(1) FROM User A WHERE A.phone=:phone
  27.    </Query>
  28.    <Query name="login" type="HQL" freemarkFormat="false" Alias="true">
  29.        FROM User A WHERE A.phone=:phone and A.password=:password
  30.    </Query>
  31. </QueryList>

4:解析缓存

  1. package com.cheuks.bin.db.manager;
  2. //import 省略
  3. public class QueryFactory implements QueryType {
  4.  
  5.    private final Map<String, Template> FORMAT_XQL = new ConcurrentHashMap<String, Template>();
  6.    private final Map<String, String> UNFORMAT_XQL = new ConcurrentHashMap<String, String>();
  7.    private final Configuration freemarkerConfiguration = new Configuration(Configuration.VERSION_2_3_0);
  8.    private StringTemplateLoader stringTemplateLoader = new StringTemplateLoader();
  9.    private String files;
  10.    public QueryFactory() {
  11.       super();
  12.       freemarkerConfiguration.setTemplateLoader(stringTemplateLoader);
  13.    }
  14.    public synchronized void put(String name, String XQL, boolean isFormat) throws TemplateNotFoundException, MalformedTemplateNameException, ParseException, IOException {
  15.       if (null == name || null == XQL)
  16.          return;
  17.       if (isFormat) {
  18.          stringTemplateLoader.putTemplate(name, XQL);
  19.          FORMAT_XQL.put(name, freemarkerConfiguration.getTemplate(name));
  20.       } else {
  21.          UNFORMAT_XQL.put(name, XQL);
  22.       }
  23.    }
  24.  
  25.    public String getXQL(String name, boolean isFormat, Map<String, Object> params) throws TemplateException, IOException {
  26.       // if (!isScan)
  27.       // scan();
  28.       if (!isFormat)
  29.          return UNFORMAT_XQL.get(name);
  30.       Template tp = FORMAT_XQL.get(name);
  31.       if (null == tp)
  32.          return null;
  33.       StringWriter sw = new StringWriter();
  34.       tp.process(params, sw);
  35.       return sw.toString();
  36.    }
  37.  
  38.    @SuppressWarnings("restriction")
  39.    @javax.annotation.PostConstruct
  40.    private void scan() {
  41.       try {
  42.          Set<String> o = null;
  43.          o = Scan.doScan(files);//扫描所有 *.queue.
  44.          
  45.       } catch (Exception e) {
  46.          e.printStackTrace();
  47.       }
  48.    }
  49.  
  50.    public String getFiles() {return files;}
  51.    public QueryFactory setFiles(String files) {this.files = files; return this;}
  52.  
  53.    public void throws ParserConfigurationException, SAXException, IOException {
  54.       Iterator<String> it = urls.iterator();
  55.       SAXParserFactory factory = SAXParserFactory.newInstance();
  56.       SAXParser parser = factory.newSAXParser();
  57.       new
  58.       
  59.       //读取
  60.       new EntityResolver() {
  61.          public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
  62.             return new InputSource(this.getClass().getClassLoader().getResourceAsStream("dtd/Query.dtd"));
  63.          }
  64.       });
  65.       while (it.hasNext()) {
  66.          String str = it.next();
  67.          InputSource is = new InputSource(Thread.currentThread().getContextClassLoader().getResourceAsStream(str));
  68.          is.setEncoding("utf-8");
  69.          
  70.          
  71.       }
  72.    }
  73.  
  74.    class extends DefaultHandler {
  75.       // private boolean isHQL = false;
  76.       private boolean format = false;
  77.       private boolean alias = false;
  78.       private String packageName = null;
  79.       private String name = null;
  80.       Map<String, String> aliases = new HashMap<String, String>();
  81.       private String value;
  82.  
  83.       @Override
  84.       public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
  85.          if (qName.equals(QUERY_LIST)) {
  86.             packageName = attributes.getValue(PACKAGE);
  87.          } else if (qName.equals(QUERY)) {
  88.             // isHQL = attributes.getValue(TYPE).equals("HQL");
  89.             name = attributes.getValue(NAME);
  90.             format = Boolean.valueOf(attributes.getValue(FREEMARK_FORMAT));
  91.             alias = Boolean.valueOf(attributes.getValue(ALIAS));
  92.          } else if (qName.equals(ALIAS)) {
  93.             aliases.put(attributes.getValue(ALIAS), attributes.getValue(NAME));
  94.          }
  95.          super.startElement(uri, localName, qName, attributes);
  96.       }
  97.  
  98.       @Override
  99.       public void characters(char[] ch, int start, int length) throws SAXException {
  100.          value = new String(ch, start, length).replaceAll("(\n|\t)", "");
  101.          if (value.length() > 0) {
  102.             try {
  103.                put(String.format("%s.%s", packageName, name).toLowerCase(), alias ? alias(value) : value, format);//生成缓存
  104.             } catch (Exception e) {
  105.             }
  106.          }
  107.  
  108.       }
  109.  
  110.       private String alias(String str) {
  111.          if (alias)
  112.             for (Entry<String, String> en : aliases.entrySet())
  113.                str = str.replaceAll(en.getKey(), en.getValue());
  114.          return str;
  115.       }
  116.  
  117.    }
  118. }

 

5:定义 DBAdapter接口。

  1.     public interface DBAdapter {
  2.  
  3.    public DBAdapter setSessionFactory(String name);
  4.  
  5.    public <T> List<T> getList(Class<?> c) throws Throwable;
  6.  
  7.    /***
  8.     * query模板查询
  9.     */
  10.    public <T> List<T> getListByXqlQueryName(String queryName, boolean isHQL, boolean isFormat, Map<String, Object> params) throws Throwable;
  11.  
  12.    /***
  13.     * 模板查询
  14.     */
  15.    public <T> List<T> getListByXqlQueryName(String queryName, boolean isHQL, Object... params) throws Throwable;
  16.  
  17.    public <T> List<T> getListByXqlQueryName(String queryName, boolean isHQL, int page, int size, Object... params) throws Throwable;
  18.  
  19.    /***
  20.     * query模板查询 * @param queryName 查询语句名
  21.    public <T> List<T> getListByXqlQueryName(String queryName, boolean isHQL, boolean isFormat, Map<String, Object> params, int page, int size) throws Throwable;
  22.  
  23.    public String queryNameFormat(Class<?> entry, String queryName);
  24. }

6:写实现(AbstractHibernateDBAdapter、HibernateSingleDBAdapter)

AbstractHibernateDBAdapter

  1. package com.cheuks.bin.db.manager;
  2. @SuppressWarnings({ "rawtypes", "unchecked" })
  3. public abstract class AbstractHibernateDBAdapter implements DBAdapter {
  4.  
  5.    private QueryFactory queryFactory;
  6.  
  7.    public abstract Session getSession();
  8.  
  9.    public <T> List<T> getList(Class<?> c) throws Throwable {
  10.       return getList(c, -1, -1);
  11.    }
  12.  
  13.    public <T> List<T> getList(Class<?> c, int page, int size) throws Throwable {
  14.       Query query = getSession().createQuery(String.format("FROM %s a", c.getSimpleName()));
  15.       List list = page > 0 ? page(query, page, size).list() : query.list();
  16.       return null == list ? null : list;
  17.    }
  18.  
  19.    public <T> List<T> getListByXqlQueryName(String queryName, boolean isHQL, Object... params) throws Throwable {
  20.       return getListByXqlQueryName(queryName, isHQL, -1, -1, params);
  21.    }
  22.  
  23.    public <T> List<T> getListByXqlQueryName(String queryName, boolean isHQL, int page, int size, Object... params) throws Throwable {
  24.       String xql = queryFactory.getXQL(queryName, false, null);
  25.       Query query = fillParams(isHQL ? getSession().createQuery(xql) : getSession().createSQLQuery(xql), params);
  26.       List list = page > 0 ? page(query, page, size).list() : query.list();
  27.       return null == list ? null : list;
  28.    }
  29.  
  30.    public <T> List<T> getListByXqlQueryName(String queryName, boolean isHQL, boolean isFormat, Map<String, Object> params) throws Throwable {
  31.       return getListByXqlQueryName(queryName, isHQL, isFormat, params, -1, -1);
  32.    }
  33.  
  34.    public <T> List<T> getListByXqlQueryName(String queryName, boolean isHQL, boolean isFormat, Map<String, Object> params, int page, int size) throws Throwable {
  35.       String xql = queryFactory.getXQL(queryName, isFormat, params);
  36.       Query query = fillParams(isHQL ? getSession().createQuery(xql) : getSession().createSQLQuery(xql), params);
  37.       List list = page > 0 ? page(query, page, size).list() : query.list();
  38.       return null == list ? null : list;
  39.    }
  40.  
  41.    protected Query fillParams(Query q, Object... o) {
  42.       if (null == o || null == q) {
  43.          return q;
  44.       }
  45.       for (int i = 0, len = o.length; i < len; i++) {
  46.          q.setParameter(i, o[i]);
  47.       }
  48.       return q;
  49.    }
  50.  
  51.    protected Query fillParams(Query q, Map<String, ?> o) {
  52.       if (null == o || null == q) {
  53.          return q;
  54.       }
  55.       for (Entry<String, ?> en : o.entrySet())
  56.          try {
  57.             q.setParameter(en.getKey(), en.getValue());
  58.          } catch (Exception e) {
  59.          }
  60.       return q;
  61.    }
  62.  
  63.    protected Query page(Query q, int pageNum, int size) {
  64.       if (pageNum >= 0 && size >= 0) {
  65.          q.setFirstResult(size * (pageNum - 1));
  66.          q.setMaxResults(size);
  67.       }
  68.       return q;
  69.    }
  70.  
  71.    public String queryNameFormat(Class<?> entry, String queryName) {
  72.       return String.format("%s.%s", entry.getName(), queryName).toLowerCase();
  73.    }
  74.  
  75.    public QueryFactory getQueryFactory() {
  76.       return queryFactory;
  77.    }
  78.  
  79.    public AbstractHibernateDBAdapter setQueryFactory(QueryFactory queryFactory) {
  80.       this.queryFactory = queryFactory;
  81.       return this;
  82.    }
  83. }

 

HibernateSingleDBAdapter

  1. package com.cheuks.bin.db.manager;
  2.  
  3. public class HibernateSingleDBAdapter extends AbstractHibernateDBAdapter {
  4.    //待注入 sessionFactory
  5.    private SessionFactory sessionFactory;
  6.    public HibernateSingleDBAdapter setSessionFactory(String name) {
  7.       return this;
  8.    }
  9.    @Override
  10.    public Session getSession() {
  11.       return sessionFactory.getCurrentSession();
  12.    }
  13.    public SessionFactory getSessionFactory() {
  14.       return sessionFactory;
  15.    }
  16.    public HibernateSingleDBAdapter setSessionFactory(SessionFactory sessionFactory) {
  17.       this.sessionFactory = sessionFactory;
  18.       return this;
  19.    }
  20. }

 

7:注入

    <!-- QueryFile 注入 -->

    <bean id="queryFactory" class="com.cheuks.bin.db.manager.QueryFactory">

        <property name="files" value="*.query. />

    </bean>

    <!--Single DBAdapter 注入 -->

    <bean id="dBAdapter" class="com.cheuks.bin.db.manager.HibernateSingleDBAdapter">

        <property name="sessionFactory" ref="sessionFactory" />

        <property name="queryFactory" ref="queryFactory" />

    </bean>

 

 

8:使用 AbstractDao 、UserDao

AbstractDao

  1. package com.cheuks.bin.db.manager.dao;
  2. public abstract class AbstractDao<entity, ID extends Serializable> implements BaseDao<entity, ID> {
  3.  
  4.    public abstract Class<entity> getEntityClass();
  5.  
  6.    public abstract DBAdapter getDBAdapter();
  7.  
  8.    public List<entity> getList(int page, int size) throws Throwable {
  9.       return getDBAdapter().getList(getEntityClass(), page, size);
  10.    }
  11.  
  12.    public List<entity> getList(Map<String, Object> params, int page, int size) throws Throwable {
  13.       return getDBAdapter().getListByXqlQueryName(getDBAdapter().queryNameFormat(getEntityClass(), "list"), true, true, params, page, size);
  14.    }
  15.  
  16.    public <T> List<T> getList(String queryName, Map<String, Object> params, boolean isFromat, int page, int size) throws Throwable {
  17.       return getDBAdapter().getListByXqlQueryName(getDBAdapter().queryNameFormat(getEntityClass(), queryName), true, isFromat, params, page, size);
  18.    }
  19.  
  20.    public <T> List<T> getListCustomQueryName(String queryName, Map<String, Object> params, boolean isFromat, int page, int size) throws Throwable { return getDBAdapter().getListByXqlQueryName(queryName.toLowerCase(), true, isFromat, params, page, size);
  21.    }
  22.  
  23.    public List<entity> getListEntity(String queryName, Map<String, Object> params, boolean isFromat, int page, int size) throws Throwable {
  24.       return getDBAdapter().getListByXqlQueryName(getDBAdapter().queryNameFormat(getEntityClass(), queryName), true, isFromat, params, page, size);
  25.    }
  26.  
  27.    public List<entity> getListEntityCustomQueryName(String queryName, Map<String, Object> params, boolean isFromat, int page, int size) throws Throwable {
  28.       return getDBAdapter().getListByXqlQueryName(queryName.toLowerCase(), true, isFromat, params, page, size);
  29.    }
  30. }

UserDao

  1. package project.freehelp.common.dao.impl;
  2. @Component
  3. public class UserInfoDaoImpl extends AbstractDao<UserInfo, String> implements UserInfoDao {
  4.    @Autowired
  5.    private DBAdapter dBAdapter;
  6.    @Override
  7.    public Class<UserInfo> getEntityClass() {
  8.       return UserInfo.class;
  9.    }
  10.    @Override
  11.    public DBAdapter getDBAdapter() {
  12.       return dBAdapter;
  13.    }
  14. }

 

整体就完了。