第一次写博客。文章有点渣,喜欢就看看,不喜欢路过点个赞。
效果:直接一条语句多种用法
-
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。觉得不错可以收藏。但请不要 不名字改了变成自己的成果呀!