Hibernate 拥有 Mybits 的SQL/HQL特性 (注解、XML两不误)
第一次写博客。文章有点渣,喜欢就看看,不喜欢路过点个赞。
效果:直接一条语句多种用法
- FROM User A
- WHERE
- 1=1
- <#if id??>
- <#if like??>
- and A.id like '%'||:id||'%'
- <#else>
- and A.id=:id
- </#if>
- </#if>
先来原理 HQL/SQL + Freemarker 模版生成查询语句。
1:把SQL/HQL写在XML。
2:编写文件扫描器(缺)
3:读取解释XML
4:按实体类空间缓存查询语句
5:直接使用
注意:不要直接复制,先弄懂流程,因为这源于旧版本及测试包来写的,也省略了部分代码,因此包路径有问题。程序也不完整,缺了的自己让大家自己去思考实现。基本上依赖Spring,不依赖Spring注入的可以考虑用代理模式注入(反射/生成字节码(javassist/asm)/CGLIB等)
1:为了方便先定义约束Query.dtd
- <?xml version="1.0" encoding="UTF-8"?>
- <!ELEMENT QueryList (Alias*,Query*)>
- <!--<!ELEMENT Context (CachePool,Bean*,Intercept*,ScanToPack*,CloneModel)>-->
- <!ELEMENT Alias EMPTY><!--别名-->
- <!ELEMENT Query (#PCDATA)><!--sql/hql-->
- <!--QueryList-->
- <!ATTLIST QueryList package CDATA #REQUIRED>
- <!--Alias-->
- <!ATTLIST Alias name CDATA #REQUIRED><!--实体类全名-->
- <!ATTLIST Alias Alias CDATA #REQUIRED><!--SQL/HQL 语句中的实体类别名-->
- <!--Query-->
- <!ATTLIST Query name CDATA #REQUIRED><!--实体类全名-->
- <!ATTLIST Query type (HQL|SQL) #REQUIRED><!--语句类型:HQL/SQL-->
- <!ATTLIST Query freemarkFormat (false|true) #REQUIRED><!--是否使用FREEMARK标签格式化-->
- <!ATTLIST Query resultType CDATA #IMPLIED><!--实体类全名-->
- <!ATTLIST Query Alias (true|false) #REQUIRED><!--是否使用了类别名-->
2:建个实体类user.class
- package project.master.user;
- //import、getting、setting 省略
- @Entity
- public class User extends AbstractEntity {
- private static final long serialVersionUID = 1L;
- @Id
- private String id;
- @Column(unique = true)
- private String phone;// 用户名(手机号)
- private String password;
- private int status;// 帐号状态(锁定、停用、正常)
- private Date lastLogin;
- @Column(updatable = false, nullable = false)
- private Date createDate = new Date();
- }
3:建立对应的XML (User.query.xml)
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE QueryList SYSTEM "Query.dtd">
- <QueryList package="project.master.user.User">
- <Alias name="project.master.user.User" Alias="User" />
- <Alias name="project.freehelp.common.entity.Dictionary" Alias="Dictionary" />
- <Query name="list" type="HQL" freemarkFormat="true" Alias="true">
- <![CDATA[
- FROM User A
- WHERE
- 1=1
- <#if id??>
- <#if like??>
- and A.id like '%'||:id||'%'
- <#else>
- and A.id=:id
- </#if>
- </#if>
- <!-- 各字段判断省略 -->
- ]]>
- </Query>
- <Query name="AAX" type="HQL" freemarkFormat="true" Alias="true">
- <!--测试 -->
- SELECT A.phone,(SELECT D.value FROM Dictionary D WHERE D.id='1') as xValue FROM User A
- </Query>
- <Query name="checkUser" type="HQL" freemarkFormat="false" Alias="true">
- SELECT COUNT(1) FROM User A WHERE A.phone=:phone
- </Query>
- <Query name="login" type="HQL" freemarkFormat="false" Alias="true">
- FROM User A WHERE A.phone=:phone and A.password=:password
- </Query>
- </QueryList>
4:解析缓存XML
- package com.cheuks.bin.db.manager;
- //import 省略
- public class QueryFactory implements QueryType {
- private final Map<String, Template> FORMAT_XQL = new ConcurrentHashMap<String, Template>();
- private final Map<String, String> UNFORMAT_XQL = new ConcurrentHashMap<String, String>();
- private final Configuration freemarkerConfiguration = new Configuration(Configuration.VERSION_2_3_0);
- private StringTemplateLoader stringTemplateLoader = new StringTemplateLoader();
- private String files;
- public QueryFactory() {
- super();
- freemarkerConfiguration.setTemplateLoader(stringTemplateLoader);
- }
- public synchronized void put(String name, String XQL, boolean isFormat) throws TemplateNotFoundException, MalformedTemplateNameException, ParseException, IOException {
- if (null == name || null == XQL)
- return;
- if (isFormat) {
- stringTemplateLoader.putTemplate(name, XQL);
- FORMAT_XQL.put(name, freemarkerConfiguration.getTemplate(name));
- } else {
- UNFORMAT_XQL.put(name, XQL);
- }
- }
- public String getXQL(String name, boolean isFormat, Map<String, Object> params) throws TemplateException, IOException {
- // if (!isScan)
- // scan();
- if (!isFormat)
- return UNFORMAT_XQL.get(name);
- Template tp = FORMAT_XQL.get(name);
- if (null == tp)
- return null;
- StringWriter sw = new StringWriter();
- tp.process(params, sw);
- return sw.toString();
- }
- @SuppressWarnings("restriction")
- @javax.annotation.PostConstruct
- private void scan() {
- try {
- Set<String> o = null;
- o = Scan.doScan(files);//扫描所有 *.queue.xml
- xmlExplain(o);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- public String getFiles() {return files;}
- public QueryFactory setFiles(String files) {this.files = files; return this;}
- public void xmlExplain(Set<String> urls) throws ParserConfigurationException, SAXException, IOException {
- Iterator<String> it = urls.iterator();
- SAXParserFactory factory = SAXParserFactory.newInstance();
- SAXParser parser = factory.newSAXParser();
- xmlHandler handler = new xmlHandler();
- XMLReader xmlReader = parser.getXMLReader();
- //读取XML
- xmlReader.setEntityResolver(new EntityResolver() {
- public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
- return new InputSource(this.getClass().getClassLoader().getResourceAsStream("dtd/Query.dtd"));
- }
- });
- while (it.hasNext()) {
- String str = it.next();
- InputSource is = new InputSource(Thread.currentThread().getContextClassLoader().getResourceAsStream(str));
- is.setEncoding("utf-8");
- xmlReader.setContentHandler(handler);
- xmlReader.parse(is);
- }
- }
- class xmlHandler extends DefaultHandler {
- // private boolean isHQL = false;
- private boolean format = false;
- private boolean alias = false;
- private String packageName = null;
- private String name = null;
- Map<String, String> aliases = new HashMap<String, String>();
- private String value;
- @Override
- public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
- if (qName.equals(QUERY_LIST)) {
- packageName = attributes.getValue(PACKAGE);
- } else if (qName.equals(QUERY)) {
- // isHQL = attributes.getValue(TYPE).equals("HQL");
- name = attributes.getValue(NAME);
- format = Boolean.valueOf(attributes.getValue(FREEMARK_FORMAT));
- alias = Boolean.valueOf(attributes.getValue(ALIAS));
- } else if (qName.equals(ALIAS)) {
- aliases.put(attributes.getValue(ALIAS), attributes.getValue(NAME));
- }
- super.startElement(uri, localName, qName, attributes);
- }
- @Override
- public void characters(char[] ch, int start, int length) throws SAXException {
- value = new String(ch, start, length).replaceAll("(\n|\t)", "");
- if (value.length() > 0) {
- try {
- put(String.format("%s.%s", packageName, name).toLowerCase(), alias ? alias(value) : value, format);//生成缓存
- } catch (Exception e) {
- }
- }
- }
- private String alias(String str) {
- if (alias)
- for (Entry<String, String> en : aliases.entrySet())
- str = str.replaceAll(en.getKey(), en.getValue());
- return str;
- }
- }
- }
5:定义 DBAdapter接口。
- public interface DBAdapter {
- public DBAdapter setSessionFactory(String name);
- public <T> List<T> getList(Class<?> c) throws Throwable;
- /***
- * query模板查询
- */
- public <T> List<T> getListByXqlQueryName(String queryName, boolean isHQL, boolean isFormat, Map<String, Object> params) throws Throwable;
- /***
- * 模板查询
- */
- public <T> List<T> getListByXqlQueryName(String queryName, boolean isHQL, Object... params) throws Throwable;
- public <T> List<T> getListByXqlQueryName(String queryName, boolean isHQL, int page, int size, Object... params) throws Throwable;
- /***
- * query模板查询 * @param queryName 查询语句名
- public <T> List<T> getListByXqlQueryName(String queryName, boolean isHQL, boolean isFormat, Map<String, Object> params, int page, int size) throws Throwable;
- public String queryNameFormat(Class<?> entry, String queryName);
- }
6:写实现(AbstractHibernateDBAdapter、HibernateSingleDBAdapter)
AbstractHibernateDBAdapter
- package com.cheuks.bin.db.manager;
- @SuppressWarnings({ "rawtypes", "unchecked" })
- public abstract class AbstractHibernateDBAdapter implements DBAdapter {
- private QueryFactory queryFactory;
- public abstract Session getSession();
- public <T> List<T> getList(Class<?> c) throws Throwable {
- return getList(c, -1, -1);
- }
- public <T> List<T> getList(Class<?> c, int page, int size) throws Throwable {
- Query query = getSession().createQuery(String.format("FROM %s a", c.getSimpleName()));
- List list = page > 0 ? page(query, page, size).list() : query.list();
- return null == list ? null : list;
- }
- public <T> List<T> getListByXqlQueryName(String queryName, boolean isHQL, Object... params) throws Throwable {
- return getListByXqlQueryName(queryName, isHQL, -1, -1, params);
- }
- public <T> List<T> getListByXqlQueryName(String queryName, boolean isHQL, int page, int size, Object... params) throws Throwable {
- String xql = queryFactory.getXQL(queryName, false, null);
- Query query = fillParams(isHQL ? getSession().createQuery(xql) : getSession().createSQLQuery(xql), params);
- List list = page > 0 ? page(query, page, size).list() : query.list();
- return null == list ? null : list;
- }
- public <T> List<T> getListByXqlQueryName(String queryName, boolean isHQL, boolean isFormat, Map<String, Object> params) throws Throwable {
- return getListByXqlQueryName(queryName, isHQL, isFormat, params, -1, -1);
- }
- public <T> List<T> getListByXqlQueryName(String queryName, boolean isHQL, boolean isFormat, Map<String, Object> params, int page, int size) throws Throwable {
- String xql = queryFactory.getXQL(queryName, isFormat, params);
- Query query = fillParams(isHQL ? getSession().createQuery(xql) : getSession().createSQLQuery(xql), params);
- List list = page > 0 ? page(query, page, size).list() : query.list();
- return null == list ? null : list;
- }
- protected Query fillParams(Query q, Object... o) {
- if (null == o || null == q) {
- return q;
- }
- for (int i = 0, len = o.length; i < len; i++) {
- q.setParameter(i, o[i]);
- }
- return q;
- }
- protected Query fillParams(Query q, Map<String, ?> o) {
- if (null == o || null == q) {
- return q;
- }
- for (Entry<String, ?> en : o.entrySet())
- try {
- q.setParameter(en.getKey(), en.getValue());
- } catch (Exception e) {
- }
- return q;
- }
- protected Query page(Query q, int pageNum, int size) {
- if (pageNum >= 0 && size >= 0) {
- q.setFirstResult(size * (pageNum - 1));
- q.setMaxResults(size);
- }
- return q;
- }
- public String queryNameFormat(Class<?> entry, String queryName) {
- return String.format("%s.%s", entry.getName(), queryName).toLowerCase();
- }
- public QueryFactory getQueryFactory() {
- return queryFactory;
- }
- public AbstractHibernateDBAdapter setQueryFactory(QueryFactory queryFactory) {
- this.queryFactory = queryFactory;
- return this;
- }
- }
HibernateSingleDBAdapter
- package com.cheuks.bin.db.manager;
- public class HibernateSingleDBAdapter extends AbstractHibernateDBAdapter {
- //待注入 sessionFactory
- private SessionFactory sessionFactory;
- public HibernateSingleDBAdapter setSessionFactory(String name) {
- return this;
- }
- @Override
- public Session getSession() {
- return sessionFactory.getCurrentSession();
- }
- public SessionFactory getSessionFactory() {
- return sessionFactory;
- }
- public HibernateSingleDBAdapter setSessionFactory(SessionFactory sessionFactory) {
- this.sessionFactory = sessionFactory;
- return this;
- }
- }
7:注入xml
<!-- QueryFile 注入 -->
<bean id="queryFactory" class="com.cheuks.bin.db.manager.QueryFactory">
<property name="files" value="*.query.xml" />
</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
- package com.cheuks.bin.db.manager.dao;
- public abstract class AbstractDao<entity, ID extends Serializable> implements BaseDao<entity, ID> {
- public abstract Class<entity> getEntityClass();
- public abstract DBAdapter getDBAdapter();
- public List<entity> getList(int page, int size) throws Throwable {
- return getDBAdapter().getList(getEntityClass(), page, size);
- }
- public List<entity> getList(Map<String, Object> params, int page, int size) throws Throwable {
- return getDBAdapter().getListByXqlQueryName(getDBAdapter().queryNameFormat(getEntityClass(), "list"), true, true, params, page, size);
- }
- public <T> List<T> getList(String queryName, Map<String, Object> params, boolean isFromat, int page, int size) throws Throwable {
- return getDBAdapter().getListByXqlQueryName(getDBAdapter().queryNameFormat(getEntityClass(), queryName), true, isFromat, params, page, size);
- }
- 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);
- }
- public List<entity> getListEntity(String queryName, Map<String, Object> params, boolean isFromat, int page, int size) throws Throwable {
- return getDBAdapter().getListByXqlQueryName(getDBAdapter().queryNameFormat(getEntityClass(), queryName), true, isFromat, params, page, size);
- }
- public List<entity> getListEntityCustomQueryName(String queryName, Map<String, Object> params, boolean isFromat, int page, int size) throws Throwable {
- return getDBAdapter().getListByXqlQueryName(queryName.toLowerCase(), true, isFromat, params, page, size);
- }
- }
UserDao
- package project.freehelp.common.dao.impl;
- @Component
- public class UserInfoDaoImpl extends AbstractDao<UserInfo, String> implements UserInfoDao {
- @Autowired
- private DBAdapter dBAdapter;
- @Override
- public Class<UserInfo> getEntityClass() {
- return UserInfo.class;
- }
- @Override
- public DBAdapter getDBAdapter() {
- return dBAdapter;
- }
- }
整体就完了。XML部分看DTD。觉得不错可以收藏。但请不要 不名字改了变成自己的成果呀!
浙公网安备 33010602011771号