Hibernate + Springboot 实现@Filter过滤器,进行自动添加条件过滤
经过我三天三夜折磨,搞好了这个需求。
首先这个需求一般是通过注解的方式来实现。
所以第一步手写一个注解:
@Target({ElementType.PARAMETER, ElementType.METHOD})//注解放置的目标位置,METHOD是可注解在方法级别上
@Retention(RetentionPolicy.RUNTIME) //注解在哪个阶段执行
@Documented
public @interface DataFilter {
}
第二步,在自己的实体类上面添加一些东西
package com.dapeng.multitentant.entity;
import com.dapeng.multitentant.common.AbstractBaseEntity;
import lombok.Data;
import org.hibernate.annotations.Filter;
import org.hibernate.annotations.FilterDef;
import org.hibernate.annotations.FilterDefs;
import org.hibernate.annotations.ParamDef;
import javax.persistence.*;
@Data
@Entity
@Table(name = "user_test")
@FilterDefs({
@FilterDef(name="tenant",
defaultCondition = "tenant_id = :tenantIdLimit",
parameters = {@ParamDef(name = "tenantIdLimit", type = "string")}
)
})
@Filter(name = "tenant", condition = "tenant_id = :tenantIdLimit")
public class Person extends AbstractBaseEntity {
@Id
@GeneratedValue(strategy= GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
// @TenantId // springboot 3.x支持分区
@Column(name = "tenant_id")
// @Filter(name = "tenant", condition = "tenant_id >= (:tenantIdLimit)")
private String tenantId;
@PrePersist
protected void prePersist(){
System.out.println(tenantId);
}
@Column(name = "name")
private String name;
@Column(name = "age")
private Integer age;
}
第三步,手写切面类(注意@Aspect和@Component),并写上切入点。
package com.dapeng.multitentant.AOP;
import com.dapeng.multitentant.annonation.DataFilter;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.hibernate.Filter;
import org.hibernate.Session;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.util.StringUtils;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
@Aspect
@Component
public class TenantAop {
//EntityManager是JPA中用于增删改查的接口,它的作用相当于一座桥梁,连接内存中的java对象和数据库的数据存储。
//1
@PersistenceContext
private EntityManager entityManager;
/**
* 转换request 请求参数
*
* @param paramMap request获取的参数数组
*/
public Map<String, String> converMap(Map<String, String[]> paramMap) {
Map<String, String> rtnMap = new HashMap<String, String>();
for (String key : paramMap.keySet()) {
rtnMap.put(key, paramMap.get(key)[0]);
}
return rtnMap;
}
@Before("@annotation(dataFilter)")
public void doProcess(JoinPoint joinPoint, DataFilter dataFilter) throws Throwable {
System.out.println("进入切面了~~~~~~~~~~~");
// 从获取RequestAttributes中获取HttpServletRequest的信息
HttpServletRequest request= (HttpServletRequest) RequestContextHolder.getRequestAttributes().resolveReference(RequestAttributes.REFERENCE_REQUEST);
Map<String, String> rtnMap = converMap(request.getParameterMap());
String tenantId = rtnMap.get("tenantId");
if(!StringUtils.isEmpty(tenantId)){
// 固定写法
// 2
Session session = entityManager.unwrap(Session.class);
// 自定义的属性名
// 3
Filter filter = session.enableFilter("tenant");
//自定义属性值名,设置值,该值可以是集合类型,可以是基本类型,这里是集合类型
filter.setParameter("tenantIdLimit", tenantId);
}
}
}
第四步,直接在Controller里面调用自己的方法吧。
package com.dapeng.multitentant.controller;
import com.dapeng.multitentant.annonation.DataFilter;
import com.dapeng.multitentant.entity.Person;
import com.dapeng.multitentant.repository.PersonRepository;
import com.dapeng.multitentant.service.PersonService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.transaction.Transactional;
import java.util.List;
@RestController
@RequestMapping("/people")
public class PersonController {
@Autowired
PersonService service;
@Autowired
PersonRepository repository;
@GetMapping("/list")
@DataFilter
List<Person> all(Person person){
List<Person> byName = repository.findByName(person.getName());
return byName;
}
}
看下面的效果图:
可以看到Hibernate自动帮我们把tenant_id条件加入上去了,的确很方便。不过配置的时候花了我三天时间去搜索相关资料。
1.查询租户ID为1的数据:
2.查询租户ID为1中不存在的数据,并且名字跟别的租户姓名一样。
好了,感谢大家关注,如果上面有错误或者不合适的地方,还请大家多多提醒。感谢~
修改:
2023.9.15日,遇到的问题:
使用注解的时候,发现SQL语句里面并没有添加相对应的过滤条件。
原因可能是:
1.没有使用hql。得使用Repository接口里面的方法。
例如:(这里我注释掉了,应该用框框里面的代码,还有自定义的注解@DataFilter)