【学习java-权限管理系统】分析角色资源控制器RoleAuthorityController

一、控制器代码

该控制通过前端传回的角色id,roleId,去查询角色关联的菜单和资源,得到R类型的List<>集合返回给前端

@Slf4j
@Validated
@RestController
@RequestMapping("/roleAuthority")
@Api(value = "RoleAuthority", tags = "角色的资源")
public class RoleAuthorityController extends BaseController {
    @Autowired
    private RoleAuthorityService roleAuthorityService;
    /**
     * 查询指定角色关联的菜单和资源
     */
    @ApiOperation(value = "查询指定角色关联的菜单和资源", notes = "查询指定角色关联的菜单和资源")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "current", value = "当前页", dataType = "long", paramType = "query", defaultValue = "1"),
            @ApiImplicitParam(name = "size", value = "每页显示几条", dataType = "long", paramType = "query", defaultValue = "10"),
    })
    @GetMapping("/{roleId}")
    @SysLog("查询指定角色关联的菜单和资源")
    public R<List<RoleAuthority>> page(@PathVariable Long roleId) {
        return success(roleAuthorityService.list(Wraps.<RoleAuthority>lbQ().eq(RoleAuthority::getRoleId, roleId)));
    }
}

Service层

public interface RoleAuthorityService extends IService<RoleAuthority> {
    boolean saveUserRole(UserRoleSaveDTO userRole);
    boolean saveRoleAuthority(RoleAuthoritySaveDTO roleAuthoritySaveDTO);
}

二、 success方法

suceess()为BaseController的方法,主要作用将各类查询结果进行统一管理,返回给前端,存储了返回数据的一些基本内容
BaseController为各控制器的父类接口,定义了一些通用方法如获取分页对象,统一返回数据形式等

public abstract class BaseController{
    @Resource
    protected HttpServletRequest request;
    @Resource
    protected HttpServletResponse response;
    public <T> R<T> success(T data) {
        return R.success(data);
    }
}

R对象的中success()方法

@Setter
@Getter
@Accessors(chain = true)
public class R<T>{
	@ApiModelProperty(value = "响应数据")
    private T data;
    @ApiModelProperty(value="提示消息")
    private String msg="ok";
    @ApiModelProperty(value = "请求路径")
    private String path;
    @ApiModelProperty(value = "附加参数")
    private Map<String,Object> extra;
    @ApiModelProperty(value = "响应时间戳")
    private long timestamp=System.currentTimeMillis();
    private R(){super();}
    public R(int code,T data,String msg){
        this.code=code;
        this.data=data;
        this.msg=msg;
    } 
    public static <E> R<E> success(E data) {
        return new R<>(SUCCESS_CODE, data, "ok");
    }  
}

三、 IService.list()方法

通过上面的success()方法,会将数据包装成R对象返回,接下来就是将数据分装成list集合返回,IService.list()方法正好可以将查询的内容通过List<>集合返回

//ISerivce部分代码
public interface IService<T> {
    List<T> list(Wrapper<T> queryWrapper);
}

现在,需要构建的就是条件构造抽象类:Wrapper queryWrapper

四、Wraps.lbQ()

4.1Wraps工具类
主要为了缩短代码长度,让构建查询语句复用
该lbQ为泛型方法,指定了具体类型

public class Wraps{
	public static <T> LbqWrapper<T> lbQ(){
		return new LbqWrapper<>();
	}
}

4.2 LbqWrapper
为查询构建器,通过继承Mybatis-plus的一些父类,实现查询方法的构建
SuperEntity为超类基础实体,主要定义了id,createTime,createUser属性,和克隆方法等
首先看最初的查询代码,lbQ()的泛型指定了是RoleAuthority类型

Wraps.<RoleAuthority>lbQ()

因此,此处的T类型得以确定是RoleAuthority,而RoleAuthority有继承了SpuerEntity(RoleAuthority定义了资源id,权限类型,角色id属性,并且继承了SpuerEntity),因此判断成立
将克隆的对象设置到mybatis-plus类AbstractWrapper内(AbstractWrapper用于查询条件封装,生成 sql 的 where 条件)
设置了一些init信息
并且通过replace将属性不为空,并且将%或_替换成"/%","/_"后的T对象返回

public class LbqWrapper<T> extends AbstractLambdaWrapper<T, LbqWrapper<T>>
        implements Query<LbqWrapper<T>, T, SFunction<T, ?>> {
    public LbqWrapper() {
        this(null);
    }
    public LbqWrapper(T entity) {
        //instanceof用来判断一个对象是为一个类的实例
        if (entity instanceof SuperEntity) {
            //克隆出一个对象
            T cloneT = (T) ((SuperEntity) entity).clone();
            super.setEntity(cloneT);
            super.initNeed();
            this.entity = (T) replace(cloneT);
        } else {
            super.setEntity(entity);
            super.initNeed();
            this.entity = (T) replace(entity);
        }
    }
    public static Object replace(Object source) {
        if (source == null) {
            return null;
        }
        Object target = source;

        Class<?> srcClass = source.getClass();
        Field[] fields = srcClass.getDeclaredFields();
        for (Field field : fields) {
            String nameKey = field.getName();
            //获取源对象中的属性值
            Object classValue = getClassValue(source, nameKey);
            if (classValue == null) {
                continue;
            }
            String srcValue = classValue.toString();
            //比较两个属性值,不相等的时候进行赋值
            if (srcValue.contains("%") || srcValue.contains("_")) {
                String tarValue = srcValue.replaceAll("\\%", "\\\\%");
                tarValue = tarValue.replaceAll("\\_", "\\\\_");
                setClassValue(target, nameKey, tarValue);
            }
        }
        return target;
    }
 }

五、eq(RoleAuthority::getRoleId, roleId)

上述代码已经将查询需要构建的对象创建好,接下来直接执行查询方法
方法还是在LbqWrapper类中
eq为AbstractWrapper (用于查询条件封装,生成 sql 的 where 条件)中的方法
eq代表等于

: eq("name", "老王")--->name = '老王'

LbqWrapper中还做了空值判断


public class LbqWrapper<T> extends AbstractLambdaWrapper<T, LbqWrapper<T>>
        implements Query<LbqWrapper<T>, T, SFunction<T, ?>> {
    private static final long serialVersionUID = -6842140106034506889L;
    //查询字段
    private SharedString sqlSelect = new SharedString();
    //是否跳过空值(项目扩展)
    private boolean skipEmpty = true;
    @Override
    public LbqWrapper<T> eq(SFunction<T, ?> column, Object val) {
        return super.eq(this.checkCondition(val), column, val);
    }
    //空值校验,传入空字符串("")时, 视为: 字段名 = ""
	private boolean checkCondition(Object val) {
        if (val instanceof String && this.skipEmpty) {
        	//返回结果要true正常执行
            return StringUtils.isNotEmpty((String) val);
        }
        if (val instanceof Collection && this.skipEmpty) {
            //返回结果true正常执行,所以加!
            return !((Collection) val).isEmpty();
        }
        return val != null;
    }
}

eq需要两个参数eq(SFunction<T, ?> column, Object val)
再来看下控制器中是怎么定义的

 return success(roleAuthorityService.list(Wraps.<RoleAuthority>lbQ().eq(RoleAuthority::getRoleId, roleId)));

其中RoleAuthority::getRoleId的意思就相当于:
1.实例化一个Employee对象
RoleAuthority roleAuthority= new RoleAuthority;
2.调用对象roleAuthority的get方法,这里调用的是getEmpCardNo:
roleAuthority.getRoleId();

也就完成了eq需要的关联,getRoleId="roleId"

六、RoleAuthority

最后再来看这个entity,已经通过mybatis-plus和数据库关联起来了
因此最终mybatis-plus底层通过eq前端传来的roleId,将所有资源与用户关联起来,并进行一系列的数据清洗,判断,将用户拥有的菜单RoleAuthority(一个菜单包含了很多资源),封装进List集合,返回给前端

@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
@TableName("pd_auth_role_authority")
@ApiModel(value = "RoleAuthority", description = "角色的资源")
public class RoleAuthority extends SuperEntity<Long> {

    private static final long serialVersionUID = 1L;

    /**
     * 资源id
     * #pd_auth_resource
     * #pd_auth_menu
     */
    @ApiModelProperty(value = "资源id")
    @NotNull(message = "资源id不能为空")
    @TableField("authority_id")
    private Long authorityId;

    /**
     * 权限类型
     * #AuthorizeType{MENU:菜单;RESOURCE:资源;}
     */
    @ApiModelProperty(value = "权限类型")
    @NotNull(message = "权限类型不能为空")
    @TableField("authority_type")
    private AuthorizeType authorityType;

    /**
     * 角色id
     * #pd_auth_role
     */
    @ApiModelProperty(value = "角色id")
    @NotNull(message = "角色id不能为空")
    @TableField("role_id")
    private Long roleId;


    @Builder
    public RoleAuthority(Long id, LocalDateTime createTime, Long createUser,
                         Long authorityId, AuthorizeType authorityType, Long roleId) {
        this.id = id;
        this.createTime = createTime;
        this.createUser = createUser;
        this.authorityId = authorityId;
        this.authorityType = authorityType;
        this.roleId = roleId;
    }
}

整个流程终于分析完毕,接下来准备更新一个流程图,以及用到的技术

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值