package com.norteksoft.product.orm.hibernate;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.SessionFactory;
import org.springframework.util.Assert;
import com.norteksoft.mms.form.entity.ListView;
import com.norteksoft.mms.form.service.ListViewManager;
import com.norteksoft.product.orm.Page;
import com.norteksoft.product.util.ContextUtils;
import com.norteksoft.product.util.SearchUtils;
import com.norteksoft.product.web.struts2.Struts2Utils;
/**
* 封装SpringSide扩展功能的Hibernat DAO泛型基类.
*
* 扩展功能包括分页查询,按属性过滤条件列表查询.
* 可在Service层直接使用,也可以扩展泛型DAO子类使用,见两个构造函数的注释.
*
* @param <T> DAO操作的对象类型
* @param <PK> 主键类型
*
*/
public abstract class HibernateDao<T, PK extends Serializable> extends SimpleHibernateDao<T, PK> {
private Log log = LogFactory.getLog(this.getClass());
/**
* 按HQL分页查询.
*
* @param page 分页参数.
* @param hql hql语句.
* @param values 数量可变的查询参数,按顺序绑定.
*
* @return 分页查询结果, 附带结果列表及所有查询时的参数.
*/
public Page<T> findPage(final Page<T> page, final String hql, final Object... values) {
String newHql = addCompanyCondition(hql);
return findPageNoCompanyCondition(page, newHql, values);
}
@SuppressWarnings("unchecked")
public Page<T> findPageNoCompanyCondition(final Page<T> page, final String hql, final Object... values) {
Assert.notNull(page, "page不能为空");
String newHql = createHqlAddOrderBy(hql, page);
Query q = createQuery(newHql, values);
if (page.isAutoCount()) {
int pageNo=page.getPageNo();
int pageSize=page.getPageSize();
long totalCount=getTotalCount(newHql,values);
long z=totalCount/pageSize;
long y=totalCount%pageSize;
long c=pageNo-z;
page.setTotalCount(totalCount);
if(y==0 && c==1){//该页没有数据转到上一页
page.setPageNo(Integer.valueOf(pageNo-1));
}
}
setPageParameter(q, page);
List result = q.list();
page.setResult(result);
return page;
}
private long getTotalCount(String newHql,final Object... values){
String listCode=Struts2Utils.getParameter("_list_code");
if("export_data".equals(Struts2Utils.getParameter("exportParameters"))){//导出查询
return 100000l;
}else if(StringUtils.isNotEmpty(listCode)){
ListViewManager listViewManager = (ListViewManager) ContextUtils.getBean("listViewManager");
if(listViewManager==null){
log.debug(" ListViewManager 为空");
return countHqlResult(newHql, values);
}else{
ListView listView=listViewManager.getListViewByCode(listCode);
if(listView==null){
log.debug(" ListView 为空");
return countHqlResult(newHql, values);
}else{
if(listView.getPagination()){
if(StringUtils.isEmpty(Struts2Utils.getParameter("searchParameters"))){
if(listView.getTotalable()){
return countHqlResult(newHql, values);
}else{
return 100000l;
}
}else{
if(listView.getSearchTotalable()){
return countHqlResult(newHql, values);
}else{
return 100000l;
}
}
}else{
if(listView.getRowNum()==null){
return 20l;
}else{
return listView.getRowNum();
}
}
}
}
}else{
return countHqlResult(newHql, values);
}
}
/**
* 执行count查询获得本次Hql查询所能获得的对象总数.
*
* 本函数只能自动处理简单的hql语句,复杂的hql查询请另行编写count语句查询.
*/
public long countHqlResult(final String hql, final Object... values) {
Long count = 0L;
String fromHql = hql;
//select子句与order by子句会影响count查询,进行简单的排除.
fromHql = "from " + StringUtils.substringAfter(fromHql, "from");
fromHql = StringUtils.substringBefore(fromHql, "order by");
// String countHql = "select count(*) " + fromHql;
String countHql = "select count("+getAlias(fromHql)+".id) " + fromHql;
if(hql.contains(" distinct ")){//判断用户的语句中是否有distinct,如果有则count时也要加上distinct,但会影响速度
countHql = "select count(distinct "+getAlias(fromHql)+".id) " + fromHql;
}
try {
count = findUnique(countHql, values);
} catch (Exception e) {
throw new RuntimeException("hql can't be auto count, hql is:" + countHql, e);
}
return count;
}
/**
* 原生SQL分页查询
* @param page
* @param sql
* @param values
* @return Page
*/
@SuppressWarnings("unchecked")
public Page<Object> findPageBySql(Page<Object> page, String sql, Object... values){
String newSql = sql;//addCompanyCondition(sql);
String sqlOrderBy = createSqlAddOrderBy(newSql, page);
log.debug(" newest query sql :[" + sqlOrderBy + "]");
SQLQuery sqlQuery = getSession().createSQLQuery(sqlOrderBy);
if(values != null){
for(int i = 0; i < values.length; i++){
sqlQuery.setParameter(i, values[i]);
}
}
page.setTotalCount(getTotalCountSql(newSql, values));
List<Object> results = sqlQuery.setFirstResult(page.getFirst()-1).setMaxResults(page.getPageSize()).list();
page.setResult(results);
return page;
}
private long getTotalCountSql(String sql,final Object... values){
String listCode=Struts2Utils.getParameter("_list_code");
if("export_data".equals(Struts2Utils.getParameter("exportParameters"))){//导出查询
return 100000l;
}else if(StringUtils.isNotEmpty(listCode)){
ListViewManager listViewManager = (ListViewManager) ContextUtils.getBean("listViewManager");
if(listViewManager==null){
log.debug(" ListViewManager 为空");
return countSql(sql, values);
}else{
ListView listView=listViewManager.getListViewByCode(listCode);
if(listView==null){
log.debug(" ListView 为空");
return countSql(sql, values);
}else{
if(listView.getPagination()){
if(StringUtils.isEmpty(Struts2Utils.getParameter("searchParameters"))){
if(listView.getTotalable()){
return countSql(sql, values);
}else{
return 100000l;
}
}else{
if(listView.getSearchTotalable()){
return countSql(sql, values);
}else{
return 100000l;
}
}
}else{
if(listView.getRowNum()==null){
return 20l;
}else{
return listView.getRowNum();
}
}
}
}
}else{
return countSql(sql, values);
}
}
public int countSql(String sql, Object... values){
String countQueryString = null;
if(sql.contains(" distinct ")){ // sql语句中包含有 distinct
countQueryString = "select count(*) from (" + removeOrders(sql) +") _default_table";
}else{
countQueryString = " select count(*) " + removeSelect(removeOrders(sql));
}
log.debug(" query count sql :[" + countQueryString + "]");
SQLQuery query = getSession().createSQLQuery(countQueryString);
if(values != null){
for(int i = 0; i < values.length; i++){
query.setParameter(i, values[i]);
}
}
Number count = (Number) query.uniqueResult();
//BigDecimal count = (BigDecimal)query.uniqueResult();
return count.intValue();
}
/**
* 原生SQL查询
* @param sql
* @param values
* @return List
*/
@SuppressWarnings("unchecked")
public List<Object> findBySql(String sql, Object... values){
SQLQuery sqlQuery = getSession().createSQLQuery(sql);
if(values != null){
for(int i = 0; i < values.length; i++){
sqlQuery.setParameter(i, values[i]);
}
}
return sqlQuery.list();
}
/**
* 向hql中设置orderBy条件(可以处理以有order by的hql和没有order by的hql)
* @param hql hql语句
* @param page 分页和排序参数
* @return
*/
protected String createHqlAddOrderBy(final String hql, final Page<T> page) {
String newHql = hql;
if(page.isOrderBySetted()) {
String[] orderByArray = StringUtils.split(page.getOrderBy(), ',');
String[] orderArray = StringUtils.split(page.getOrder(), ',');
Assert.isTrue(orderByArray.length == orderArray.length, "分页多重排序参数中,排序字段与排序方向的个数不相等");
String orderByStr = "";
if(StringUtils.contains(newHql, "order by")){
for (int i = 0; i < orderByArray.length; i++) {
if((i + 1) == orderByArray.length) {
orderByStr += getAlias(hql)+ "." + orderByArray[i].trim() + " " + orderArray[i].trim();
} else {
orderByStr += getAlias(hql)+ "." + orderByArray[i].trim() + " " + orderArray[i].trim() + ", ";
}
}
newHql = StringUtils.substringBefore(newHql, "order by") + "order by " + orderByStr;
}else{
orderByStr = " order by ";
for (int i = 0; i < orderByArray.length; i++) {
if((i + 1) == orderByArray.length) {
orderByStr += getAlias(hql)+ "." + orderByArray[i].trim() + " " + orderArray[i].trim();
} else {
orderByStr += getAlias(hql)+ "." + orderByArray[i].trim() + " " + orderArray[i].trim() + ", ";
}
}
newHql += orderByStr;
}
}
log.debug("newHql =" + newHql);
return newHql;
}
protected String createSqlAddOrderBy(final String sql, final Page<Object> page) {
String newSql = sql;
if(page.isOrderBySetted()) {
String[] orderByArray = StringUtils.split(page.getOrderBy(), ',');
String[] orderArray = StringUtils.split(page.getOrder(), ',');
Assert.isTrue(orderByArray.length == orderArray.length, "分页多重排序参数中,排序字段与排序方向的个数不相等");
StringBuilder orderByStr = new StringBuilder();
if(StringUtils.contains(newSql, "order by")){
for (int i = 0; i < orderByArray.length; i++) {
if(i > 0)orderByStr.append(",");
orderByStr.append(orderByArray[i].trim()).append(" ").append(orderArray[i].trim());
}
//FIXME 破坏了原有的排序序列
newSql = StringUtils.substringBefore(newSql, "order by") + "order by " + orderByStr.toString();
}else{
orderByStr.append(" order by ");
for (int i = 0; i < orderByArray.length; i++) {
if(i > 0)orderByStr.append(",");
orderByStr.append(orderByArray[i].trim()).append(" ").append(orderArray[i].trim());
}
newSql += orderByStr.toString();
}
}
log.debug("add order by sql :[" + newSql + "]");
return newSql;
}
/**
* 设置分页参数到Query对象,辅助函数.
*/
protected Query setPageParameter(final Query q, final Page<T> page) {
q.setFirstResult(page.getFirst() - 1);
q.setMaxResults(page.getPageSize());
return q;
}
/**
* 去除hql的orderby 子句,用于pagedQuery.
*/
private static String removeOrders(String hql) {
Pattern p = Pattern.compile("order\\s*by[\\w|\\W|\\s|\\S]*", Pattern.CASE_INSENSITIVE);
Matcher m = p.matcher(hql);
StringBuffer sb = new StringBuffer();
while (m.find()) {
m.appendReplacement(sb, "");
}
m.appendTail(sb);
return sb.toString();
}
/**
* 去除hql的select 子句,未考虑union的情况,用于pagedQuery.
*/
private static String removeSelect(String hql) {
int beginPos = hql.toLowerCase().indexOf("from");
return hql.substring(beginPos);
}
/**
* 搜索,直接从request中获取参数,
* 参数名字必须为:searchParameters
* @param page
* @param hql
* @param values
* @return
*/
public Page<T> searchPageByHql(final Page<T> page, final String hql, final Object... values) {
log.debug("old search Hql:[" + hql + "]");
Map<String, Object> result = SearchUtils.processSearchParameters(hql, true, values);
log.debug("new search Hql:[" + result.get(SearchUtils.SQL_OR_HQL).toString() + "]");
return this.findPage(page,
result.get(SearchUtils.SQL_OR_HQL).toString(),
(Object[])result.get(SearchUtils.PARAMETERS));
}
/**
* 搜索,直接从request中获取参数,
* 参数名字必须为:searchParameters
* @param page
* @param sql
* @param values
* @return
*/
public Page<Object> searchPageBySql(Page<Object> page, String sql, Object... values){
log.debug("old search Sql:[" + sql + "]");
Map<String, Object> result = SearchUtils.processSearchParameters(sql, false, values);
log.debug("new search Sql:[" + result.get(SearchUtils.SQL_OR_HQL).toString() + "]");
return this.findPageBySql(page,
result.get(SearchUtils.SQL_OR_HQL).toString(),
(Object[])result.get(SearchUtils.PARAMETERS));
}
/**
* 搜索,直接从request中获取参数,
* 参数名字必须为:searchParameters
* @param page
* @param hql
* @param values
* @return
*/
public Page<T> searchPageSubByHql(final Page<T> page, final String hql, final Object... values) {
log.debug("old search Hql:[" + hql + "]");
Map<String, Object> result = SearchUtils.processSearchSubParameters(hql, true, values);
log.debug("new search Hql:[" + result.get(SearchUtils.SQL_OR_HQL).toString() + "]");
return this.findPage(page,
result.get(SearchUtils.SQL_OR_HQL).toString(),
(Object[])result.get(SearchUtils.PARAMETERS));
}
/**
* 搜索,直接从request中获取参数,
* 参数名字必须为:searchParameters
* @param page
* @param sql
* @param values
* @return
*/
public Page<Object> searchPageSubBySql(Page<Object> page, String sql, Object... values){
log.debug("old search Sql:[" + sql + "]");
Map<String, Object> result = SearchUtils.processSearchSubParameters(sql, false, values);
log.debug("new search Sql:[" + result.get(SearchUtils.SQL_OR_HQL).toString() + "]");
return this.findPageBySql(page,
result.get(SearchUtils.SQL_OR_HQL).toString(),
(Object[])result.get(SearchUtils.PARAMETERS));
}
/**
* 用于Dao层子类使用的构造函数.
* 通过子类的泛型定义取得对象类型Class.
* eg.
* public class UserDao extends HibernateDao<User, Long>{
* }
*/
public HibernateDao() {
super();
}
/**
* 用于省略Dao层, Service层直接使用通用HibernateDao的构造函数.
* 在构造函数中定义对象类型Class.
* eg.
* HibernateDao<User, Long> userDao = new HibernateDao<User, Long>(sessionFactory, User.class);
*/
public HibernateDao(final SessionFactory sessionFactory, final Class<T> entityClass) {
super(sessionFactory, entityClass);
}
}