????第一次写博客。文章有点渣,喜欢就看看,不喜欢路过点个赞。
????效果:直接一条语句多种用法
- ????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; - [email protected]
- ???private String id;
- [email protected](unique = true)
- ???private String phone;// 用户名(手机号)
- ???private String password;
- ???private
int status;// 帐号状态(锁定、停用、正常) - ???private Date lastLogin;
- [email protected](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();
- ???}
- ?
- [email protected]("restriction")
- [email protected]
- ???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;
- ?
- [email protected]
- ??????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);
- ??????}
- ?
- [email protected]
- ??????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; - ???}
- [email protected]
- ???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 { - [email protected]
- ???private DBAdapter dBAdapter;
- [email protected]
- ???public Class<UserInfo> getEntityClass() {
- ??????return UserInfo.class;
- ???}
- [email protected]
- ???public DBAdapter getDBAdapter() {
- ??????return dBAdapter;
- ???}
- }
?
整体就完了。XML部分看DTD。觉得不错可以收藏。但请不要 不名字改了变成自己的成果呀!