查询接口和查看详情接口代码分析

本文详细分析了查询接口的实现过程,包括在持久层构造SQL语句以获取数据,通过过滤数据权限的注解类和切面类进行权限控制,以及如何在实际应用中实施这些过滤机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

查询接口

    @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;
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值