查询接口
@PostMapping("/page")
@ApiOperation("分页查询")
public R page(@RequestBody RequestPageForm requestPageForm) {
//定义查询条件
EntityWrapper<ViAllocateinfoEntity> ew = new EntityWrapper<ViAllocateinfoEntity>();
// 非日期数据存在filter.rules
//list集合如果为null的话,说明没有进行初始化。这时list集合调用任何的方法都会抛出空异常。list.size( )==0说明list集合已经被new过,但是里面没有值。
//判断时一定要注意先后顺序,如果连list集合都没有,直接判断list.size( )是否为0,是会报NullPointerException异常的。
//size( )可以用isEmpty()来代替,size( )返回集合有几个元素,isEmpty()判断集合是否有元素,都可以用来判断集合有无元素。
if (null != requestPageForm.getFilter().getRules() && requestPageForm.getFilter().getRules().size() > 0) {
//for(目标对象类型 目标对象 : 遍历对象)
//foreach通过迭代器遍历集合,因为Collection继承了Iterable接口
//foreach在遍历集合的时候不能对集合进行操作,但是如果对元素进行操作后在下一次循环之前就跳出循环,就不会发生异常。
for (RulesForm rulesForm : requestPageForm.getFilter().getRules()) {
//"equals"用于判断两个变量或实例所指向的内存空间的值是不是相同
//"=="用于判断两个变量或实例是不是指向同一个内存空间
if (null != rulesForm.getData() && "eq".equals(rulesForm.getOp())) {
//return null == data || data.length() == 0 ?null : data.trim();
//trim()用于去除掉字符串两端的空格
//避免用户输入时可能会有空格的干扰
if (StringUtil.isEmpty(rulesForm.getData())) {
//构造条件语句
//ew.xx(作为条件的属性,对应属性的值)
ew.eq(rulesForm.getField(), rulesForm.getData());
}
}
}
}
//日期数据存在filters
if (null != requestPageForm.getFilters() && requestPageForm.getFilters().size() > 0) {
for (FiltersForm filtersForm : requestPageForm.getFilters()) {
if (null != filtersForm.getTerm() && StringUtil.isEmpty(filtersForm.getTerm())) {
if ("ge".equals(filtersForm.getOp())) {
ew.ge(filtersForm.getField(), filtersForm.getTerm().trim() + " 00:00:00");
} else if ("le".equals(filtersForm.getOp())) {
ew.le(filtersForm.getField(), filtersForm.getTerm().trim() + " 23:59:59");
}
}
}
}
//输出条件语句
System.out.println(ew.getSqlSegment());
//AND (uploadtime >= #{ew.paramNameValuePairs.MPGENVAL1} AND uploadtime <= #{ew.paramNameValuePairs.MPGENVAL2})
ew.orderBy("allocatetime", false);
// 页面分页信息
Map<String, Object> params = new HashMap<String, Object>();
params.put("pagesize", requestPageForm.getPageSize());
params.put("pageindex", requestPageForm.getPageIndex());
PageUtils page = viAllocateinfoService.queryPage(params, ew);
// 返回结果
Map<String, Object> map = new HashMap<>();
map.put("count", page.getTotalCount());
map.put("data", page.getList());
return R.ok(map);
}
持久层构造SQL语句
//这里的@Param为mappper.xml指明在mapper接口对应的参数
List<ViIntofiletaskView> selectListView(@Param("ew") Wrapper<ViIntofiletaskEntity> wrapper);
<where> 1=1 ${ew.sqlSegment}</where>
/**
* SQL 片段
*/
@Override
public String getSqlSegment() {
/*
* 无条件
*/
//sql:AND (条件列= #{ew.paramNameValuePairs.MPGENVAL1}) [ORDER BY 列名 DESC] 。。。。。
String sqlWhere = sql.toString();
if (StringUtils.isEmpty(sqlWhere)) {
return null;
}
/*
* 根据当前实体判断是否需要将WHERE替换成 AND 增加实体不为空但所有属性为空的情况
*/
return isWhere != null ? (isWhere ? sqlWhere : sqlWhere.replaceFirst("WHERE", AND_OR)) : sqlWhere.replaceFirst("WHERE", AND_OR);
}
过滤数据权限的注解类
//注解的使用范围,METHOD:用于描述方法
@Target(ElementType.METHOD)
/*
* RetentionPolicy.RUNTIME : 注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在
* 一般如果需要在运行时去动态获取注解信息,那只能用 RUNTIME 注解
*/
@Retention(RetentionPolicy.RUNTIME)
/*
* 表明这个注释是由 javadoc记录的,在默认情况下也有类似的记录工具。
* 如果一个类型声明被注释了文档化,它的注释成为公共API的一部分。
*/
@Documented
public @interface DataFilter {
/** 部门ID */
String deptId() default "departid";
/** true:拥有数据权限 */
boolean toDept() default false;
/** 入库部门ID */
String toDeptId() default "todepartid";
}
过滤数据权限切面类
//把当前类标识为一个切面供容器读取
@Aspect
//@Component用于注解那些不属于@Controller、@Services等的类
/*@Component与@Bean的区别:
* @Component的作用就相当于XML配置,将类注册为Bean,启动项目时扫描组件,自动配置Bean。
* @Bean需要在配置类中使用,即类上需要加上@Configuration注解。
*但是两者的结果是一样的,即注册和装配Bean,之所以有了@Component还要@Bean是因为,如果想要将第三方库中的组件装配到自己的应用中,是没办法在它的类上添加@Component注解的,因此就要用@Bean结合@Configuration来装配。
*/
@Component
public class DataFilterAspect {
@Autowired
private SysUserDepartService sysUserDepartService;
@Autowired
private SysUserService sysUserService;
@Pointcut("@annotation(com.lunz.annotation.DataFilter)")
public void dataFilterCut() {
}
@Before("dataFilterCut()")
public void dataFilter(JoinPoint point) throws Throwable {
//获取目标方法的入参
//Object[] getArgs():获取传入目标方法的参数对象
Object params = point.getArgs()[0];
//instanceof 这个关键字标识对比值是否是list类型,当然这边也可以是对象,后面的类型也是是其他的,map,String等等都可以
//目标方法必须要有入参,而且入参的类型为Map类型,但是这里对Map里的内容并没有进行非空判断,所以入参可以为空的map集合
if (params != null && params instanceof Map) {
//shiro的方法,获取正在登陆的用户的信息
SysUserEntity user = GetLoginUserUtil.getUserInfo();
//如果没有用户登录,就在请求里找 userId
if (null == user) {
HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
Long userId = Long.valueOf(request.getAttribute("userId").toString());
user = sysUserService.selectById(userId);
}
Map map = (Map) params;
map.put(Constant.SQL_FILTER, getFilter(user, point));
return;
}
throw new RRException("数据权限接口,只能是Map类型参数,且不能为NULL");
}
/**
* 获取数据过滤的SQL
*
* @param user
* @param point
* @return
*/
private String getFilter(SysUserEntity user, JoinPoint point) {
//getSignature():获取封装了署名信息的对象,在该对象中可以获取到目标方法名,所属类的Class等信息
//通过反射机制,获取目标方法签名
MethodSignature signature = (MethodSignature) point.getSignature();
//获取目标方法上的注解里的方法对象
DataFilter dataFilter = signature.getMethod().getAnnotation(DataFilter.class);
EntityWrapper<SysUserDepartEntity> ew = new EntityWrapper<>();
ew.eq("user_id", user.getId());
ew.eq("deleted", Constant.IsOrNot.NOT.getValue());
List<SysUserDepartEntity> list = sysUserDepartService.selectList(ew);
// 部门ID列表,过滤数据
Set<Long> deptIdList = new HashSet<>();
deptIdList = list.stream().map(SysUserDepartEntity::getDepartId).collect(Collectors.toSet());
StringBuilder sqlFilter = new StringBuilder();
//StringBuilder.append(String str):将字符串连接
//与String相比,不用产生新的对象,只需要将原来的对象进行多次修改
//与StringBuffer类相比,不是线程安全的(不能同步访问),但是更有速度优势,在不要求线程安全的情况下,多使用StringBuilder类
sqlFilter.append(" (");
if (deptIdList.size() > 0) {
//将集合以符号为间隔组装成新的字符串
sqlFilter.append(dataFilter.deptId()).append(" in(").append(StringUtils.join(deptIdList, ",")).append(")");
}
if (dataFilter.toDept()) {
sqlFilter.append(" or ").append(dataFilter.toDeptId()).append(" in(")
.append(StringUtils.join(deptIdList, ",")).append(")");
}
sqlFilter.append(")");
//(departid in(xxx,xxx,······))
//(departid in(xxx,xxx,·····) or todepartid in(xxx,xxx,·····))
return sqlFilter.toString();
}
}
过滤数据权限运用
@Override
//DataFilter切面,用于过滤数据权限,需要传入一个map,它会返回一个带有SQL语句的map
//通过部门id过滤数据权限
@DataFilter
public List<ViSendtaskinfoView> selectListView(Map<String, Object> params, Wrapper<ViSendtaskinfoEntity> wrapper) {
//addFilterIfNeed(boolean need, String sqlWhere, Object... params)根据判断条件来添加条件语句部分,使用 andIf() 替代
return baseMapper.selectListView(wrapper.addFilterIfNeed(null != params.get(Constant.SQL_FILTER),
//SQL_FILTER = "sql_filter":数据权限过滤
(String) params.get(Constant.SQL_FILTER)));
}
@Override
//通过入库部门id过滤数据权限
@DataFilter(toDept = true)
public PageUtils queryPage(Map<String, Object> params, Wrapper<ViAllocateinfoEntity> wrapper) {
Page<ViAllocateinfoView> page = new Query<ViAllocateinfoView>(params).getPage();
page.setRecords(baseMapper.selectListView(page, wrapper.addFilterIfNeed(null != params.get(Constant.SQL_FILTER),
(String) params.get(Constant.SQL_FILTER))));
PageUtils pageUtil = new PageUtils(page);
return pageUtil;
}