一、控制器代码
该控制通过前端传回的角色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;
}
}
整个流程终于分析完毕,接下来准备更新一个流程图,以及用到的技术