繁体   English   中英

如何在 Spring Data JPA 查询中将字符串转换为 IP 地址

[英]How to cast string to IP Address in Spring Data JPA Query

我有一个表,其中包含 IP 地址范围,在它们自己的列中具有起始值和结束值。 这些列的类型为 varchar。 我需要查询数据库以获取范围涵盖该 IP 地址的行。

这是我的查询与 PGSQL 完美配合:

select * from ip_whitelist iw where iw.ip_address::inet <= '1.1.1.54'::inet and iw.ip_address_end::inet >= '1.1.1.54'::inet

1.1.1.54 在这里只是一个虚拟值,它将被我的 JPA 查询中的一个变量替换:

这是我尝试通过 JPA 存储库运行此查询的方式:

@Query("select ip from AllowedIp ip where CAST(ip.ipAddress AS inet) <= CAST((?1) AS inet) and CAST(ip.ipAddressEnd AS inet) >= CAST((?1) AS inet)")
List<AllowedIp> findDuplicatesByIP(String ipAddress);

我的问题是我需要在此 JPA 查询中将ipAddressipAddressEnd列转换为inet ,以便我可以使用 <= 和 >= 运算符来搜索范围是否已经涵盖给定的 IP。 当我尝试启动 Tomcat 应用程序时,上面提到的 JPA 查询抛出错误。 这是堆栈跟踪:

    Caused by: java.lang.IllegalArgumentException: org.hibernate.QueryException: Could not resolve requested type for CAST : inet [select ip from com.uxl.dataobjects.domain.AllowedIp ip where CAST(ip.ipAddress AS inet) <= CAST((?1) AS inet) and CAST(ip.ipAddressEnd AS inet) >= CAST((?1) AS inet)]
        at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1750)
        at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1677)
        at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1683)
        at org.hibernate.jpa.spi.AbstractEntityManagerImpl.createQuery(AbstractEntityManagerImpl.java:331)
        at sun.reflect.GeneratedMethodAccessor69.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:344)
        at com.sun.proxy.$Proxy152.createQuery(Unknown Source)
        at org.springframework.data.jpa.repository.query.SimpleJpaQuery.validateQuery(SimpleJpaQuery.java:86)
        ... 101 more
    Caused by: org.hibernate.QueryException: Could not resolve requested type for CAST : inet [select ip from com.uxl.dataobjects.domain.AllowedIp ip where CAST(ip.ipAddress AS inet) <= CAST((?1) AS inet) and CAST(ip.ipAddressEnd AS inet) >= CAST((?1) AS inet)]
        at org.hibernate.QueryException.generateQueryException(QueryException.java:137)
        at org.hibernate.QueryException.wrapWithQueryString(QueryException.java:120)
        at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:234)
        at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:158)
        at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:131)
        at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:93)
        at org.hibernate.engine.query.spi.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:167)
        at org.hibernate.internal.AbstractSessionImpl.getHQLQueryPlan(AbstractSessionImpl.java:301)
        at org.hibernate.internal.AbstractSessionImpl.createQuery(AbstractSessionImpl.java:236)
        at org.hibernate.internal.SessionImpl.createQuery(SessionImpl.java:1836)
        at org.hibernate.jpa.spi.AbstractEntityManagerImpl.createQuery(AbstractEntityManagerImpl.java:328)
        ... 107 more
    Caused by: org.hibernate.QueryException: Could not resolve requested type for CAST : inet
        at org.hibernate.hql.internal.ast.tree.CastFunctionNode.resolve(CastFunctionNode.java:87)
        at org.hibernate.hql.internal.ast.HqlSqlWalker.processCastFunction(HqlSqlWalker.java:1097)
        at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.functionCall(HqlSqlBaseWalker.java:2748)
        at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.expr(HqlSqlBaseWalker.java:1342)
        at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.exprOrSubquery(HqlSqlBaseWalker.java:4686)
        at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.comparisonExpr(HqlSqlBaseWalker.java:4252)
        at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.logicalExpr(HqlSqlBaseWalker.java:2104)
        at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.logicalExpr(HqlSqlBaseWalker.java:2029)
        at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.whereClause(HqlSqlBaseWalker.java:796)
        at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.query(HqlSqlBaseWalker.java:597)
        at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.selectStatement(HqlSqlBaseWalker.java:301)
        at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.statement(HqlSqlBaseWalker.java:249)
        at org.hibernate.hql.internal.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:278)
        at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:206)
        ... 115 more

我探索过但没有奏效的可能解决方案:

  1. 将字符串 IP 转换为 java 中的 InetAddress 数据类型。 这是行不通的,因为表列仍为字符串类型,因此仍需要对其进行强制转换才能使用运算符。
  2. 在 Java 中获取所有行和过滤器。 虽然这可能有效,但这似乎是一个不切实际的解决方案,更不用说糟糕的做法了。
  3. 我找到了Vlad Mihalcea 的使用自定义休眠类型的指南,并在我的项目中包含了该包。 但是,我无法弄清楚如何在我的查询中使用它进行转换,因为它主要用于列数据类型为 Inet 的实体。 就我而言,表中的列是 varchar 类型。

有人可以告诉我我做错了什么吗? 任何关于我如何让它运行的建议将不胜感激。

编辑 1:添加了我尝试过的另一个可能的解决方案。

经过一番研究,我意识到答案一直存在。 这不是一个理想的解决方案,但在 Hibernate 本身支持 inet 数据类型之前,现在已经足够了。

解决方案是在@Query 中使用nativeQuery = true参数。 所以最终的查询变成:

@Query(nativeQuery = true, value = "select * from ip_whitelist where CAST(ip_address AS inet) <= CAST((?1) AS inet) and CAST(ip_address_end AS inet) >= CAST((?1) AS inet)")

内置的 cidr 和 inet 类型会做你想做的事并提供合适的操作符,有关 postgres 中的转换的更多详细信息,请使用此链接

SELECT '192.168.1.19'::inet << '192.168.1.0/24'::cidr 

上面的查询可以帮助您直接提供 ip 地址,如果需要进行转换,请使用以下有助于这些转换的链接

https://www.postgresql.org/message-id/Pine.LNX.4.20.0107211126100.4270-100000@Larry.bks

https://www.postgresql.org/message-id/F28A2B83DFE0D411A7B3006097487147468FDB%40sv7007.scania.se

https://www.postgresql.org/docs/9.1/datatype-net-types.html#:~:text=PostgreSQL%20offers%20data%20types%20to,functions%20(见%20Section%209.12)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM