hibernate根据条件动态组装sql/hql语句(仿ibatis动态查询语句功能)

您所在的位置:网站首页 动态sql如何实现 hibernate根据条件动态组装sql/hql语句(仿ibatis动态查询语句功能)

hibernate根据条件动态组装sql/hql语句(仿ibatis动态查询语句功能)

2023-07-15 01:06| 来源: 网络整理| 查看: 265

1.功能需求背景   项目中使用hibernate作为数据持久层框架,主要考虑hibernate在进行一些简单的crud操作时非常便利,不需要和ibatis似的为每个sql操作都写一堆文件,但是同时也带来了一些局限性,如类似ibatis强大的动态查询功能用不了了,但是这个功能在项目中的应用场景又很大,hibernate自身也支持将sql/hql语句写在.hbm.xml映射文件中和元素,但是这个功能只能对那些查询限制条件固定的sql有用,对于需要动态拼接的sql语句,hibernate就显得力不从心了,如何给hibernate插上ibatis动态查询的翅膀,既保留crud的简洁性,又能收获ibatis的特性呢?接下来的文章将会重点介绍 2.设计思路   先看一下ibatis的动态查询时怎么做的               select * from user                                where user_id = #userId#                          order by createTime desc       ibatis在程序实现内部回去解析sql语句中的标签,然后去解析计算,我们在ibatis在实现的时候也参考了这个解决思路,但是否是需要把ibatis里的解析sql的语法都抄到我们的dao框架中呢-显然这样太复杂了,而且ibatis自己的sql元素是和那些resultMap等是绑定在一起用的,而在hibernate是没用这些东西的,要改造这些东西是一项非常浩大的工程,因此这个方案被放弃了

  我们在实现的时候采取了一种非常简洁又功能强大的方式-模板技术!对,就是利用freemarker把sql/hql中的动态拼接条件判断语法都交给freemarker语法去处理,这样既能复用freemarker框架,又保持了我们框架设计的简洁性-不需要自己写过多的处理逻辑,以下是我们需要进行动态处理的sql/hql语句的样例

and t.type=1 and t.type=0 and t.type = ${type} and t.status = ${status} start with t.code = '${code}' connect by nocycle prior t.id = t.parent_id ]]> 这个文件看起来非常类似ibatis的语句了,只是没用ibatis的哪些标签-改成了freemarker语法,没错,我们就是复用freemarker来帮我们解决这些烦杂的判断操作的

这样我们的动态sql程序就可以总结成以下流程

a.系统加载阶段

  这个阶段程序负责将指定路径下的动态sql文件加载到内存中,一次性缓存起来,没错,这些东西只需要加载一次,以后直接读取就行了,没必要每次去查找,缓存也非常简单,一个Map就搞定,key是sql-query或hql-query元素的name属性,value就是与其对应的sql/hql语句

b.程序调用查询阶段

   调用程序通过sql/hql语句的name属性和传入查询参数来得到最终解析出来的语句

我们期望的方法可能是这样的:

public List findByNamedQuery(final String queryName, final Map parameters) 通过queryName从缓存中查找出其对应的sql/hql语句(最原始的,里面带有freemarker语法)

然后通过freemarker模板和传递进去的parameters参数对模板进行解析,得到最终的语句(纯sql/hql)

最后将解析后的sql/hql传递给底层api,返回查询结果

3.实现

  上面介绍了大致的思路,这里介绍具体的代码实现

  3.1DTD定义

      我们是把动态的sql/hql语句放在单独的xml配置文件里的,为了规范xml文档,我们给文档定义了dtd文件,这里我们只定义了两个元素和分别表示sql查询语句和hql查询语句,这两个元素目前自有一个name属性用来唯一标示该语句,如下

然后将其保存为dynamic-hibernate-statement-1.0.dtd,放在classpath下

编写DTD校验器

/** * hibernate动态sql dtd解析器 * @author WangXuzheng * */ public class DynamicStatementDTDEntityResolver implements EntityResolver, Serializable{ private static final long serialVersionUID = 8123799007554762965L; private static final Logger LOGGER = LoggerFactory.getLogger( DynamicStatementDTDEntityResolver.class ); private static final String HOP_DYNAMIC_STATEMENT = "http://www.haier.com/dtd/"; public InputSource resolveEntity(String publicId, String systemId) { InputSource source = null; // returning null triggers default behavior if ( systemId != null ) { LOGGER.debug( "trying to resolve system-id [" + systemId + "]" ); if ( systemId.startsWith( HOP_DYNAMIC_STATEMENT ) ) { LOGGER.debug( "recognized hop dyanmic statement namespace; attempting to resolve on classpath under com/haier/openplatform/dao/hibernate/" ); source = resolveOnClassPath( publicId, systemId, HOP_DYNAMIC_STATEMENT ); } } return source; } private InputSource resolveOnClassPath(String publicId, String systemId, String namespace) { InputSource source = null; String path = "com/haier/openplatform/dao/hibernate/" + systemId.substring( namespace.length() ); InputStream dtdStream = resolveInHibernateNamespace( path ); if ( dtdStream == null ) { LOGGER.debug( "unable to locate [" + systemId + "] on classpath" ); if ( systemId.substring( namespace.length() ).indexOf( "2.0" ) > -1 ) { LOGGER.error( "Don't use old DTDs, read the Hibernate 3.x Migration Guide!" ); } } else { LOGGER.debug( "located [" + systemId + "] in classpath" ); source = new InputSource( dtdStream ); source.setPublicId( publicId ); source.setSystemId( systemId ); } return source; } protected InputStream resolveInHibernateNamespace(String path) { return this.getClass().getClassLoader().getResourceAsStream( path ); } protected InputStream resolveInLocalNamespace(String path) { try { return ConfigHelper.getUserResourceAsStream( path ); } catch ( Throwable t ) { return null; } } }

3.2编写sql文件

and t.type=1 and t.type=0 and t.type = ${type} and t.status = ${status} start with t.code = '${code}' connect by nocycle prior t.id = t.parent_id ]]> 3.3加载动态sql文件

这里我们将加载sql/hql语句的程序独立到一个单独的类中,以便独立扩展

这里一共3个方法,分表标示获取系统中sql/hql语句的map(key:语句名称,value:具体的)

/** * 动态sql/hql语句组装器 * @author WangXuzheng * */ public interface DynamicHibernateStatementBuilder { /** * hql语句map * @return */ public Map getNamedHQLQueries(); /** * sql语句map * @return */ public Map getNamedSQLQueries(); /** * 初始化 * @throws IOException */ public void init() throws IOException; }默认的加载器-将指定配置文件中的sql/hql语句加载到内存中 /** * @author WangXuzheng * */ public class DefaultDynamicHibernateStatementBuilder implements DynamicHibernateStatementBuilder, ResourceLoaderAware { private static final Logger LOGGER = LoggerFactory.getLogger(DefaultDynamicHibernateStatementBuilder.class); private Map namedHQLQueries; private Map namedSQLQueries; private String[] fileNames = new String[0]; private ResourceLoader resourceLoader; private EntityResolver entityResolver = new DynamicStatementDTDEntityResolver(); /** * 查询语句名称缓存,不允许重复 */ private Set nameCache = new HashSet(); public void setFileNames(String[] fileNames) { this.fileNames = fileNames; } @Override public Map getNamedHQLQueries() { return namedHQLQueries; } @Override public Map getNamedSQLQueries() { return namedSQLQueries; } @Override public void init() throws IOException { namedHQLQueries = new HashMap(); namedSQLQueries = new HashMap(); boolean flag = this.resourceLoader instanceof ResourcePatternResolver; for (String file : fileNames) { if (flag) { Resource[] resources = ((ResourcePatternResolver) this.resourceLoader).getResources(file); buildMap(resources); } else { Resource resource = resourceLoader.getResource(file); buildMap(resource); } } //clear name cache nameCache.clear(); } @Override public void setResourceLoader(ResourceLoader resourceLoader) { this.resourceLoader = resourceLoader; } private void buildMap(Resource[] resources) throws IOException { if (resources == null) { return; } for (Resource resource : resources) { buildMap(resource); } } @SuppressWarnings({ "rawtypes" }) private void buildMap(Resource resource) { InputSource inputSource = null; try { inputSource = new InputSource(resource.getInputStream()); XmlDocument metadataXml = MappingReader.INSTANCE.readMappingDocument(entityResolver, inputSource, new OriginImpl("file", resource.getFilename())); if (isDynamicStatementXml(metadataXml)) { final Document doc = metadataXml.getDocumentTree(); final Element dynamicHibernateStatement = doc.getRootElement(); Iterator rootChildren = dynamicHibernateStatement.elementIterator(); while (rootChildren.hasNext()) { final Element element = (Element) rootChildren.next(); final String elementName = element.getName(); if ("sql-query".equals(elementName)) { putStatementToCacheMap(resource, element, namedSQLQueries); } else if ("hql-query".equals(elementName)) { putStatementToCacheMap(resource, element, namedHQLQueries); } } } } catch (Exception e) { LOGGER.error(e.toString()); throw new SysException(e); } finally { if (inputSource != null && inputSource.getByteStream() != null) { try { inputSource.getByteStream().close(); } catch (IOException e) { LOGGER.error(e.toString()); throw new SysException(e); } } } } private void putStatementToCacheMap(Resource resource, final Element element, Map statementMap) throws IOException { String sqlQueryName = element.attribute("name").getText(); Validate.notEmpty(sqlQueryName); if (nameCache.contains(sqlQueryName)) { throw new SysException("重复的sql-query/hql-query语句定义在文件:" + resource.getURI() + "中,必须保证name的唯一."); } nameCache.add(sqlQueryName); String queryText = element.getText(); statementMap.put(sqlQueryName, queryText); } private static boolean isDynamicStatementXml(XmlDocument xmlDocument) { return "dynamic-hibernate-statement".equals(xmlDocument.getDocumentTree().getRootElement().getName()); } }配置一下 classpath*:/**/*-dynamic.xml                                                  dao层代码 /** * Hibernate实现的DAO层 * @param DAO操作的对象类型 * @param 主键类型 * @author WangXuzheng * */ public class SimpleHibernateDAO implements BaseDAO,InitializingBean{ private static final Logger LOGER = LoggerFactory.getLogger(SimpleHibernateDAO.class); protected SessionFactory sessionFactory; protected Class entityClass; /** * 模板缓存 */ protected Map templateCache; protected DynamicHibernateStatementBuilder dynamicStatementBuilder; /** * 通过子类的泛型定义取得对象类型Class. * eg. * public class UserDao extends SimpleHibernateDao */ public SimpleHibernateDAO() { this.entityClass = Reflections.getSuperClassGenricType(getClass()); } /** * 取得sessionFactory. */ public SessionFactory getSessionFactory() { return sessionFactory; } /** * 采用@Autowired按类型注入SessionFactory, 当有多个SesionFactory的时候在子类重载本函数. */ public void setSessionFactory(final SessionFactory sessionFactory) { this.sessionFactory = sessionFactory; } public void setDynamicStatementBuilder(DynamicHibernateStatementBuilder dynamicStatementBuilder) { this.dynamicStatementBuilder = dynamicStatementBuilder; } /** * 取得当前Session. */ public Session getSession() { return sessionFactory.getCurrentSession(); } /** * 保存新增或修改的对象. */ @Override public void save(final T entity) { Validate.notNull(entity, "entity不能为空"); getSession().save(entity); LOGER.debug("save entity: {}", entity); } /** * 删除对象. * * @param entity 对象必须是session中的对象或含id属性的transient对象. */ @Override public void delete(final T entity) { if(entity == null){ return; } getSession().delete(entity); LOGER.debug("delete entity: {}", entity); } /** * 按id删除对象. */ @Override public void delete(final ID id) { Validate.notNull(id, "id不能为空"); delete(get(id)); LOGER.debug("delete entity {},id is {}", entityClass.getSimpleName(), id); } /** * 按id获取对象. */ @SuppressWarnings("unchecked") @Override public T get(final ID id) { Validate.notNull(id, "id不能为空"); return (T) getSession().get(entityClass, id); } /** * 按id列表获取对象列表. */ public List get(final Collection ids) { return find(Restrictions.in(getIdName(), ids)); } /** * 获取全部对象. */ @Override public List getAll() { return find(); } /** * 获取全部对象, 支持按属性行序. */ @SuppressWarnings("unchecked") public List getAll(String orderByProperty, boolean isAsc) { Criteria c = createCriteria(); if (isAsc) { c.addOrder(Order.asc(orderByProperty)); } else { c.addOrder(Order.desc(orderByProperty)); } return c.list(); } /** * 按属性查找对象列表, 匹配方式为相等. */ public List findBy(final String propertyName, final Object value) { Criterion criterion = Restrictions.eq(propertyName, value); return find(criterion); } /** * 按属性查找唯一对象, 匹配方式为相等. */ @SuppressWarnings("unchecked") @Override public T findUniqueBy(final String propertyName, final Object value) { Criterion criterion = Restrictions.eq(propertyName, value); return ((T) createCriteria(criterion).uniqueResult()); } /** * 按HQL查询对象列表. * * @param values 数量可变的参数,按顺序绑定. */ @SuppressWarnings("unchecked") public List findByHQL(final String hql, final Object... values) { return createHQLQuery(hql, values).list(); } /** * 按HQL查询对象列表,并将对象封装成指定的对象 * * @param values 数量可变的参数,按顺序绑定. */ @SuppressWarnings("unchecked") public List findByHQLRowMapper(RowMapper rowMapper,final String hql, final Object... values) { Validate.notNull(rowMapper, "rowMapper不能为空!"); List result = createHQLQuery(hql, values).list(); return buildListResultFromRowMapper(rowMapper, result); } protected List buildListResultFromRowMapper(RowMapper rowMapper, List result) { List rs = new ArrayList(result.size()); for(Object[] obj : result){ rs.add(rowMapper.fromColumn(obj)); } return rs; } /** * 按SQL查询对象列表. * * @param values 数量可变的参数,按顺序绑定. */ @SuppressWarnings("unchecked") public List findBySQLRowMapper(RowMapper rowMapper,final String sql, final Object... values) { Validate.notNull(rowMapper, "rowMapper不能为空!"); List result = createSQLQuery(sql, values).list(); return buildListResultFromRowMapper(rowMapper, result); } /** * 按SQL查询对象列表,并将结果集转换成指定的对象列表 * * @param values 数量可变的参数,按顺序绑定. */ @SuppressWarnings("unchecked") public List findBySQL(final String sql, final Object... values) { return createSQLQuery(sql, values).list(); } /** * 按HQL查询对象列表. * * @param values 命名参数,按名称绑定. */ @SuppressWarnings("unchecked") public List findByHQL(final String hql, final Map values) { return createHQLQuery(hql, values).list(); } /** * 按HQL查询对象列表,并将结果集封装成对象列表 * * @param values 命名参数,按名称绑定. */ @SuppressWarnings("unchecked") public List findByHQLRowMapper(RowMapper rowMapper,final String hql, final Map values) { Validate.notNull(rowMapper, "rowMapper不能为空!"); List result = createHQLQuery(hql, values).list(); return buildListResultFromRowMapper(rowMapper, result); } /** * 按SQL查询对象列表. * @param sql SQL查询语句 * @param values 命名参数,按名称绑定. */ @SuppressWarnings("unchecked") public List findBySQL(final String sql, final Map values) { return createSQLQuery(sql, values).list(); } /** * 查询在xxx.hbm.xml中配置的查询语句 * @param queryName 查询的名称 * @param parameters 参数 * @return */ public List findByNamedQuery(final String queryName, final Map parameters) { StatementTemplate statementTemplate = templateCache.get(queryName); String statement = processTemplate(statementTemplate,parameters); if(statementTemplate.getType() == StatementTemplate.TYPE.HQL){ return this.findByHQL(statement); }else{ return this.findBySQL(statement); } } /** * 查询在xxx.hbm.xml中配置的查询语句 * @param rowMapper * @param queryName 查询的名称 * @param parameters 参数 * @return */ public List findByNamedQuery(RowMapper rowMapper,final String queryName, final Map parameters) { StatementTemplate statementTemplate = templateCache.get(queryName); String statement = processTemplate(statementTemplate,parameters); if(statementTemplate.getType() == StatementTemplate.TYPE.HQL){ return this.findByHQLRowMapper(rowMapper,statement); }else{ return this.findBySQLRowMapper(rowMapper,statement); } } /** * 按SQL查询对象列表,并将结果集封装成对象列表 * @param sql SQL查询语句 * @param values 命名参数,按名称绑定. */ @SuppressWarnings("unchecked") public List findBySQLRowMapper(RowMapper rowMapper,final String sql, final Map values) { Validate.notNull(rowMapper, "rowMapper不能为空!"); List result = createSQLQuery(sql, values).list(); return buildListResultFromRowMapper(rowMapper, result); } /** * 按HQL查询唯一对象. * * @param values 数量可变的参数,按顺序绑定. */ @SuppressWarnings("unchecked") public X findUniqueByHQL(final String hql, final Object... values) { return (X) createHQLQuery(hql, values).uniqueResult(); } /** * 按SQL查询唯一对象. * * @param values 数量可变的参数,按顺序绑定. */ @SuppressWarnings("unchecked") public X findUniqueBySQL(final String sql, final Object... values) { return (X) createSQLQuery(sql, values).uniqueResult(); } /** * 按HQL查询唯一对象. * * @param values 命名参数,按名称绑定. */ @SuppressWarnings("unchecked") public X findUniqueByHQL(final String hql, final Map values) { return (X) createHQLQuery(hql, values).uniqueResult(); } /** * 按HQL查询唯一对象. * @param sql sql语句 * @param values 命名参数,按名称绑定. */ @SuppressWarnings("unchecked") public X findUniqueBySQL(final String sql, final Map values) { return (X) createSQLQuery(sql, values).uniqueResult(); } /** * 执行HQL进行批量修改/删除操作. * * @param values 数量可变的参数,按顺序绑定. * @return 更新记录数. */ public int batchExecuteHQL(final String hql, final Object... values) { return createHQLQuery(hql, values).executeUpdate(); } /** * 执行SQL进行批量修改/删除操作. * * @param sql sql语句 * @param values 数量可变的参数,按顺序绑定. * @return 更新记录数. */ public int batchExecuteSQL(final String sql, final Object... values) { return createSQLQuery(sql, values).executeUpdate(); } /** * 执行HQL进行批量修改/删除操作. * * @param values 命名参数,按名称绑定. * @return 更新记录数. */ public int batchExecuteHQL(final String hql, final Map values) { return createHQLQuery(hql, values).executeUpdate(); } /** * 执行SQL进行批量修改/删除操作. * * @param values 命名参数,按名称绑定. * @return 更新记录数. */ public int batchExecuteSQL(final String sql, final Map values) { return createSQLQuery(sql, values).executeUpdate(); } /** * 根据查询HQL与参数列表创建Query对象. * 与find()函数可进行更加灵活的操作. * * @param values 数量可变的参数,按顺序绑定. */ public Query createHQLQuery(final String queryString, final Object... values) { Query query = getSession().createQuery(queryString); if (values != null) { for (int i = 0; i < values.length; i++) { query.setParameter(i, values[i]); } } return query; } /** * 根据查询SQL与参数列表创建Query对象. * 与find()函数可进行更加灵活的操作. * @param sqlQueryString sql语句 * * @param values 数量可变的参数,按顺序绑定. */ public Query createSQLQuery(final String sqlQueryString, final Object... values) { Query query = getSession().createSQLQuery(sqlQueryString); if (values != null) { for (int i = 0; i < values.length; i++) { query.setParameter(i, values[i]); } } return query; } /** * 根据查询HQL与参数列表创建Query对象. * 与find()函数可进行更加灵活的操作. * * @param values 命名参数,按名称绑定. */ public Query createHQLQuery(final String queryString, final Map values) { Query query = getSession().createQuery(queryString); if (values != null) { query.setProperties(values); } return query; } /** * 根据查询SQL与参数列表创建Query对象. * 与find()函数可进行更加灵活的操作. * @param queryString SQL语句 * @param values 命名参数,按名称绑定. */ public Query createSQLQuery(final String queryString, final Map values) { Query query = getSession().createSQLQuery(queryString); if (values != null) { query.setProperties(values); } return query; } /** * 按Criteria查询对象列表. * * @param criterions 数量可变的Criterion. */ @SuppressWarnings("unchecked") public List find(final Criterion... criterions) { return createCriteria(criterions).list(); } /** * 按Criteria查询唯一对象. * * @param criterions 数量可变的Criterion. */ @SuppressWarnings("unchecked") public T findUnique(final Criterion... criterions) { return (T) createCriteria(criterions).uniqueResult(); } /** * 根据Criterion条件创建Criteria. * 与find()函数可进行更加灵活的操作. * * @param criterions 数量可变的Criterion. */ public Criteria createCriteria(final Criterion... criterions) { Criteria criteria = getSession().createCriteria(entityClass); for (Criterion c : criterions) { criteria.add(c); } return criteria; } /** * 初始化对象. * 使用load()方法得到的仅是对象Proxy, 在传到View层前需要进行初始化. * 如果传入entity, 则只初始化entity的直接属性,但不会初始化延迟加载的关联集合和属性. * 如需初始化关联属性,需执行: * Hibernate.initialize(user.getRoles()),初始化User的直接属性和关联集合. * Hibernate.initialize(user.getDescription()),初始化User的直接属性和延迟加载的Description属性. */ public void initProxyObject(Object proxy) { Hibernate.initialize(proxy); } /** * Flush当前Session. */ public void flush() { getSession().flush(); } /** * 为Query添加distinct transformer. * 预加载关联对象的HQL会引起主对象重复, 需要进行distinct处理. */ public Query distinct(Query query) { query.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY); return query; } /** * 为Criteria添加distinct transformer. * 预加载关联对象的HQL会引起主对象重复, 需要进行distinct处理. */ public Criteria distinct(Criteria criteria) { criteria.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY); return criteria; } /** * 取得对象的主键名. */ public String getIdName() { ClassMetadata meta = getSessionFactory().getClassMetadata(entityClass); return meta.getIdentifierPropertyName(); } /** * 判断对象的属性值在数据库内是否唯一. * * 在修改对象的情景下,如果属性新修改的值(value)等于属性原来的值(orgValue)则不作比较. */ public boolean isPropertyUnique(final String propertyName, final Object newValue, final Object oldValue) { if (newValue == null || newValue.equals(oldValue)) { return true; } Object object = findUniqueBy(propertyName, newValue); return (object == null); } @Override public void update(T object) { getSession().update(object); } @SuppressWarnings("unchecked") @Override public T load(ID id) { return (T) getSession().load(this.entityClass, id); } /** * 将list转化为数组 * @param list * @return */ protected Criterion[] list2Array(List list){ if(list == null){ return new Criterion[0]; } Criterion[] result = new Criterion[list.size()]; for(int i = 0; i < list.size(); i++){ result[i] = list.get(i); } return result; } @Override public void afterPropertiesSet() throws Exception { templateCache = new HashMap(); if(this.dynamicStatementBuilder == null){ this.dynamicStatementBuilder = new NoneDynamicHibernateStatementBuilder(); } dynamicStatementBuilder.init(); Map namedHQLQueries = dynamicStatementBuilder.getNamedHQLQueries(); Map namedSQLQueries = dynamicStatementBuilder.getNamedSQLQueries(); Configuration configuration = new Configuration(); configuration.setNumberFormat("#"); StringTemplateLoader stringLoader = new StringTemplateLoader(); for(Entry entry : namedHQLQueries.entrySet()){ stringLoader.putTemplate(entry.getKey(), entry.getValue()); templateCache.put(entry.getKey(), new StatementTemplate(StatementTemplate.TYPE.HQL,new Template(entry.getKey(),new StringReader(entry.getValue()),configuration))); } for(Entry entry : namedSQLQueries.entrySet()){ stringLoader.putTemplate(entry.getKey(), entry.getValue()); templateCache.put(entry.getKey(), new StatementTemplate(StatementTemplate.TYPE.SQL,new Template(entry.getKey(),new StringReader(entry.getValue()),configuration))); } configuration.setTemplateLoader(stringLoader); } protected String processTemplate(StatementTemplate statementTemplate,Map parameters){ StringWriter stringWriter = new StringWriter(); try { statementTemplate.getTemplate().process(parameters, stringWriter); } catch (Exception e) { LOGER.error("处理DAO查询参数模板时发生错误:{}",e.toString()); throw new SysException(e); } return stringWriter.toString(); } }我们的SimpleHibernateDAO实现了InitializingBean,在其afterProperties方法中我们将调用DynamicHibernateStatementBuilder把语句缓存起来 上层方法调用示例-这个已经非常类似ibatis了 public List getDescendants(Long userId,String code) { Map values = new HashMap(); values.put("userId", String.valueOf(userId)); values.put("code", code); values.put("type", String.valueOf(ResourceTypeEnum.URL_RESOURCE.getType())); values.put("status", String.valueOf(ResourceStatusEnum.ACTIVE.getStatus())); return this.findByNamedQuery(new ResourceRowMapper(),"resource.getDescendants", values); }


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3