西寧平臺網(wǎng)站建設(shè)展示型網(wǎng)站設(shè)計公司
文章目錄
- 需求內(nèi)容:
- 實(shí)現(xiàn):
- 步驟一:導(dǎo)入SpringAOP相關(guān)依賴pom.xml
- 步驟二:自定義兩個注解
- 步驟三:需要用到的實(shí)體類
- **步驟四:切面具體實(shí)現(xiàn)**
- 用法
- 1.需要過濾返回值的方法添加注解@FilterByUser
- 2.數(shù)據(jù)Dto在需要過濾的字段添加@Filter注解,值為數(shù)據(jù)庫中json字段的key
- 3.數(shù)據(jù)庫中添加一條記錄
- 4.完成配置的效果
- **實(shí)現(xiàn)原理描述**
需求內(nèi)容:
在系統(tǒng)已經(jīng)完成的情況下,添加以下權(quán)限:
·城市為“上?!焙汀吧钲凇钡摹安块T一”用戶,只能看到用戶表數(shù)據(jù)中城市為“上?;蛏钲凇鼻也块T為“部門一的子部門”。
所用技術(shù)包含,自定義注解,SpringAOP切面,反射以及其他SpringBoot項(xiàng)目常用
實(shí)現(xiàn):
步驟一:導(dǎo)入SpringAOP相關(guān)依賴pom.xml
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId><version>2.6.6</version></dependency>
步驟二:自定義兩個注解
package cn.fy.anno;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** @author Fy* 自定義注解,在實(shí)體類中有該注解的字段即可以被過濾* @Date 2022年12月14日 11:12:59*/
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Filter {//{"bumen":["部門11","部門12","部門13","部門14"]} 則keyName為 bumen//此處用“bumen”只是為了證明可以和實(shí)體類的dept不同String value() default "";}
package cn.fy.anno;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface FilterByUser {}
步驟三:需要用到的實(shí)體類
1.要查詢要過濾的數(shù)據(jù)實(shí)體類,需繼承2實(shí)體類,或(包含2實(shí)體類中需要查詢的字段,并修改對應(yīng)切面中獲取前端傳遞用戶賬號的方法)
package cn.fy.dto;import cn.fy.anno.Filter;
import lombok.Data;
import java.io.Serializable;
@Data
public class User extends QueryDto implements Serializable {private String userName;@Filter("bumen")//寫成拼音只是為了證明可以與實(shí)體類字段名不一致private String dept;@Filter("chengshi")private String city;
}
2.接收前端傳遞參數(shù)的查詢實(shí)體類
package cn.fy.dto;
import lombok.Data;
@Data
public class QueryDto {int pageIndex;int pageSize;String role;//登錄的用戶賬號String userName;
}
3.權(quán)限數(shù)據(jù)庫表對應(yīng)的實(shí)體類和對應(yīng)Mapper
package cn.fy.dto;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
/*** @author Fy* @since 2023-02-10*/
@Data
@TableName("user_power")
public class UserPower implements Serializable {private static final long serialVersionUID = 1L;@TableId("id")private Integer id;@TableField("user_name")private String userName;@TableField("create_time")private String createTime;@TableField("json")private String json;
}package cn.fy.sql;import cn.fy.dto.UserPower;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;/*** @author Fy* @since 2023-02-10*/
@Mapper
public interface UserPowerMapper extends BaseMapper<UserPower> {}
步驟四:切面具體實(shí)現(xiàn)
package cn.fy.aspect;import cn.fy.anno.Filter;
import cn.fy.dto.UserPower;
import cn.fy.dto.QueryDto;
import cn.fy.sql.UserPowerMapper;
import cn.fy.sql.UserPowerMapper;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;@Component
@Aspect
@Slf4j
public class PowerAspect {@Resourceprivate UserPowerMapper userPowerMapper;//需要限定包的話則自行添加@exectution@Pointcut("@annotation(cn.fy.anno.FilterByUser)")public void pointCut() {}@Around("pointCut()")public Object around(ProceedingJoinPoint joinPoint) {Object reDto = null;Object[] args = joinPoint.getArgs();try {//執(zhí)行方法并獲得返回值reDto = joinPoint.proceed(args);} catch (Throwable throwable) {log.error("", throwable);throw new RuntimeException(throwable);}QueryDto queryDto = null;for (Object arg : args) {if (arg instanceof QueryDto) {queryDto = (QueryDto) arg;break;}}if (queryDto == null) {return reDto;}//此部分為MybatisPlus查詢數(shù)據(jù)庫方法,可自行替換LambdaQueryWrapper<UserPower> queryWrapper = new LambdaQueryWrapper<>();queryWrapper.eq(UserPower::getUserName, queryDto.getUserName());UserPower powerDto = userPowerMapper.selectOne(queryWrapper);log.info(JSON.toJSONString(powerDto));log.info("---查詢時間戳---" + System.currentTimeMillis());JSONObject jsonObject = null;if (powerDto == null) {return reDto;}try {jsonObject = JSON.parseObject(powerDto.getJson());} catch (Exception e) {log.error("", e);}if (jsonObject == null) {return reDto;}try {if (reDto instanceof List) {//是集合List list = (List) reDto;List successList = new ArrayList();//循環(huán)整個集合for (Object o : list) {Field[] fields = o.getClass().getDeclaredFields();List<Boolean> booleanList = new ArrayList<>();for (Field field : fields) {field.setAccessible(true);Filter annotation = field.getAnnotation(Filter.class);if (annotation != null) {String keyName = annotation.value();Object o1 = jsonObject.get(keyName);//如果獲取到了key的話if (!ObjectUtils.isEmpty(o1)) {List list1 = (List) o1;//如果當(dāng)前記錄在記錄中的話booleanList.add(list1.contains(field.get(o)));if (list1.contains(field.get(o))) {log.info("key為" + keyName + ":的值【" + field.get(o) + "】在配置的權(quán)限中");}}}}if (!booleanList.contains(false)) {//證明這個數(shù)據(jù)是對的successList.add(o);}}return successList;} else {return reDto;}} catch (Exception e) {log.error("", e);}return reDto;}}
用法
1.需要過濾返回值的方法添加注解@FilterByUser
2.數(shù)據(jù)Dto在需要過濾的字段添加@Filter注解,值為數(shù)據(jù)庫中json字段的key
3.數(shù)據(jù)庫中添加一條記錄
4.完成配置的效果
原輸出結(jié)果
[User(userName=user163122156, dept=部門11, city=北京),
User(userName=user163122156, dept=部門11, city=上海),
User(userName=user163122156, dept=部門2, city=上海),
User(userName=user163122156, dept=部門11, city=深圳)]
加過濾之后輸出結(jié)果
[User(userName=user163122156, dept=部門11, city=上海)]
實(shí)現(xiàn)原理描述
利用@Aspect注解來對切面進(jìn)行編寫,通過注解形式的切入點(diǎn)表達(dá)式,對加了@FilterByUser注解的方法進(jìn)行過濾。利用@Around注解過濾修改原方法的返回值,在切面中通過反射獲取原方法返回實(shí)體類中加了@Filter注解的字段,通過去查詢數(shù)據(jù)庫對該實(shí)體類中該字段的值進(jìn)行比較過濾,多個@Filter需要全部校驗(yàn)通過才放行該對象,否則直接過濾掉不展示。