Jpa框架下拼接原生sql 并执行

利用jpa的entityManager 执行sql 并执行
其中:
EntityManager.createNativeQuery(SQL)返回的是Object对象
entityManager.createNativeQuery(SQL,WebInfo.class)返回的是映射后的实例对象

Query.getSingleResult() 执行SQL语句,返回一个查询结果,常用的还有以下方法
Query.getResultList() () 执行SQL语句,返回一个List集合
Query.getFirstResult() () 执行SQL语句,返回一个系列结果集合的第一个

直接上例子:

  1. EntityManager.createNativeQuery(SQL)返回的是Object对象
    entityManager.createNativeQuery(SQL,WebInfo.class)返回的是映射后的实例对象
  public List<User> getByCompanyFinanceRoleManager(Long companyID , String authorityName){
        StringBuffer querySql = new StringBuffer("select a.* from art_user a , art_user_authority b where a.id = b.user_id and a.company_id = :companyId " +
                " and b.authority_name =  :authorityName");
        Query query = entityManager.createNativeQuery(querySql.toString() , User.class);
        query.setParameter("companyId" , companyID);
        query.setParameter("authorityName" , authorityName);
        List<User> list = query.getResultList();
        return list;
    }
  1. Query.getSingleResult() 执行SQL语句,返回一个查询结果
  public Long getByFinanceRoleApplicationCount(ApplicationSearchParamDTO param){
        StringBuffer queryCount = new StringBuffer("select count(er.id) from atl_application er , atl_loan_application b where er.application_oid = b.application_oid and er.status not in (1010 ,1011)");
        getSql(queryCount , param);
        Query count = entityManager.createNativeQuery(queryCount.toString() );
        setQueryParam(count , param);
        Object obj = count.getSingleResult();
        Long countNum = ((BigInteger) obj).longValue();
        return countNum;
    }

public void getSql(StringBuffer querySql , ApplicationSearchParamDTO param ){
        //公司oid
        if (!StringUtils.isEmpty(param.getCompanyOID())) {
            querySql.append(" and er.company_oid = :companyOID ");
        }
        //申请人oid
        if (CollectionUtils.isNotEmpty(param.getApplicantOIDs())){
            querySql.append(" and er.applicant_oid in ( :applicantOID ) ");
        }
        if (!StringUtils.isEmpty(param.getBusinessCode())){
            querySql.append(" and b.business_code like CONCAT('%' , :businessCode , '%') ");
        }
        if (CollectionUtils.isNotEmpty(param.getDepartmentOIDs()) && CollectionUtils.isNotEmpty(param.getFinanceRoleCorporationOids()) && CollectionUtils.isEmpty(param.getCorporationOIDs())) {
            querySql.append(" and ( b.department_oid in ( :departmentOID ) or er.corporation_oid in ( :corporationOID ) OR b.department_oid is null OR er.corporation_oid is null )");
        }else if(CollectionUtils.isNotEmpty(param.getDepartmentOIDs()) && CollectionUtils.isEmpty(param.getCorporationOIDs())){
            querySql.append(" and ( b.department_oid in ( :departmentOID ) OR b.department_oid is null ) ");
        }else if(CollectionUtils.isNotEmpty(param.getFinanceRoleCorporationOids()) && CollectionUtils.isEmpty(param.getCorporationOIDs())){
            querySql.append(" and ( er.corporation_oid in ( :corporationOID ) OR er.corporation_oid is null ) ");
        }
        if (CollectionUtils.isNotEmpty(param.getCorporationOIDs())){
            querySql.append(" and er.corporation_oid in ( :corporationOID ) ");
        }
        //开始时间
        if (param.getStartDate() != null) {
            querySql.append(" and er.last_modified_date >= :startDate ");
        }
        //结束时间
        if (param.getEndDate() != null) {
            querySql.append(" and er.last_modified_date <= :endDate ");
        }
        //单据类型
        if (CollectionUtils.isNotEmpty(param.getType())) {
            querySql.append(" and er.type in ( :type ) ");
        }
        //单据状态
        if (CollectionUtils.isNotEmpty(param.getStatus())) {
            querySql.append(" and er.status in ( :status )");
        }
       /* //申请单oid
        if (CollectionUtils.isNotEmpty(param.getApplicationOIDs())) {
            querySql.append(" and er.application_oid in ( :applicationOID )");
        }*/

        //反选
        if(CollectionUtils.isNotEmpty(param.getExcludedApplicationOIDs())){
            querySql.append(" and er.application_oid not in ( :excludedApplicationOID )");
        }
    }
  1. Query.getResultList()
    public List<DepartmentDTO> getDepartmentsOfReportLine(UUID reportLineOID) {
        String sql = "SELECT d.department_oid, d.`name` FROM art_department d INNER JOIN art_report_obj ro on ro.obj_oid = d.department_oid AND ro.obj_type = '2' "
            + "and ro.report_line_oid = '" + reportLineOID + "'";
        Query query = entityManager.createNativeQuery(sql);
        List<DepartmentDTO> list = new ArrayList<>();
        List<Object[]> rtList = query.getResultList();
        for (Object[] objects : rtList) {
            DepartmentDTO departmentDTO = new DepartmentDTO();
            departmentDTO.setDepartmentOID(UUID.fromString(objects[0].toString()));
            departmentDTO.setName(objects[1].toString());
            list.add(departmentDTO);
        }
        return list;
    }
    ```

直接参考例子,拼接正确sql 即可。


如果觉得本篇文章帮到你的话, 请关注我新建的公众号: **程序员BenJi **
定期分享优质的知识思维导图,帮助大家建立结构化的知识体系,欢迎关注~
<think>嗯,用户问的是关于JPA SQL注入的Demo。首先,我得回忆一下JPA的基本机制。JPA通常使用JPQL进行查询,而JPQL本身是参数化的,应该能防止SQL注入。不过,如果开发者在拼接查询字符串的时候不小心,还是可能有漏洞。比如,用户输入直接被拼接到JPQL语句里,那就会有风险。 接下来,我需要想一个简单的例子。比如,用户登录功能,使用JPA的createQuery方法,如果用户名和密码是直接拼接的,就会导致注入。这时候,攻击者输入' OR '1'='1之类的,可能绕过验证。 然后,正确的做法应该使用参数绑定,也就是setParameter方法。这样输入会被转义,避免注入。需要对比错误和正确的代码示例,让用户清楚区别。 另外,可能用户还想知道原生SQL的情况。即使使用原生查询,如果用拼接,同样会有注入风险。所以即使是用NativeQuery,也要用参数化。 还要提醒用户,虽然JPA框架有防护,但编写代码时还是要注意,不要随意拼接字符串。特别是动态查询的时候,比如使用JPA Criteria API会更安全。 最后,总结一下,预防措施包括使用参数化查询、避免拼接、进行输入验证,以及使用安全的API。这样用户就能明白如何避免SQL注入的问题了。</think>### JPA SQL 注入示例及防护原理 #### 1. SQL 注入场景(错误示例) 假设存在以下 JPA 代码片段,**直接拼接用户输入**到 JPQL 查询中: ```java // 危险写法:直接拼接参数 String username = request.getParameter("username"); String jpql = "SELECT u FROM User u WHERE u.username = '" + username + "'"; TypedQuery<User> query = entityManager.createQuery(jpql, User.class); List<User> result = query.getResultList(); ``` **攻击示例**: 如果用户输入 `admin' OR '1'='1`,生成的 JPQL 语句为: $$ SELECT u FROM User u WHERE u.username = 'admin' OR '1'='1' $$ 此时会返回所有用户数据,导致未授权访问。 --- #### 2. 安全写法(参数绑定) 通过 JPA 的参数化查询防止注入: ```java // 安全写法:使用命名参数绑定 String jpql = "SELECT u FROM User u WHERE u.username = :username"; TypedQuery<User> query = entityManager.createQuery(jpql, User.class) .setParameter("username", username); // 自动转义特殊字符 ``` --- #### 3. 原生 SQL 查询的风险 即使使用原生 SQL,仍需避免拼接: ```java // 错误示例:原生 SQL 拼接 String sql = "SELECT * FROM users WHERE username = '" + username + "'"; Query query = entityManager.createNativeQuery(sql, User.class); ``` **正确写法**: ```java String sql = "SELECT * FROM users WHERE username = ?1"; Query query = entityManager.createNativeQuery(sql, User.class) .setParameter(1, username); ``` --- #### 4. 防护措施总结 | 方法 | 作用 | |---------------------|--------------------------------------------------------------------| | 参数化查询 | 强制使用 `setParameter()` 绑定输入 | | 输入验证 | 白名单校验(如邮箱格式、数字范围等) | | JPA Criteria API | 类型安全的动态查询(推荐复杂场景使用) | | 避免动态拼接 | 禁止将用户输入直接插入 JPQL/SQL 字符串 | --- #### 5. 测试验证方法 1. 输入特殊字符:`'`、`"`、`;`、`--` 2. 观察是否返回异常数据或报错 3. 使用工具扫描:SQLMap、OWASP ZAP 通过遵循 JPA 的安全实践,可有效避免 99% 的 SQL 注入风险。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值