我是Mybatis-plus重度依赖患者,本着能不写sql语句就不写的原则,损失性能获得只属于我自己的便捷,所以诞生了以下需求:
返回给前端的VO需要消减部分隐私数据
正常情况下,写一个VO,写句sql语句,这不就来了吗,但我是谁?非著名懒狗,一个VO我就要写1+条sql,那以后VO越来越多了怎么办?我直接返回PO不好吗,大不了自己写逻辑消减数据,反正不用写sql语句了
所以我就想,我自定义一个注解,名字叫@AccessPO,在返回PO的时候,消减有注解的数据不就行了吗,于是诞生了以下代码
- @Target(ElementType.FIELD) //作用在属性上
- @Retention(RetentionPolicy.RUNTIME)
- public @interface AccessPO {
- /**
- * 0全不可见 1用户可见 2商户可见
- */
-
- int type() default 2;
-
- public static final int ALL_NOT = 0;
- public static final int USER = 1;
- public static final int MERCHANT = 2;
-
- }
- 复制代码
type用于权限控制,不同的接口返回不同的数据,每种角色需要消减的数据也不同
注解有了,怎么在返回的时候消减呢?那就在修改一下我的Result类
基于Springboot返回的类都会被转为json,本质是一个Map,不停的put数据,返回给前端即可
- public class R extends HashMap
{ - private static final long serialVersionUID = 1L;
-
- public R() {
- put("code", 0);
- put("msg", "success");
- }
-
-
- public static R error(String msg) {
- return error(400, msg);
- }
-
- public static R error(int code, String msg) {
- R r = new R();
- r.put("code", code);
- r.put("msg", msg);
- return r;
- }
-
- public static R ok(String msg) {
- R r = new R();
- r.put("code", 200);
- r.put("msg", msg);
- return r;
- }
- ```
- public R put(String key, Object value) {
- super.put(key, value);
- return this;
- }
- ...
- 复制代码
怎么消减对应字段呢?用反射获取到对象,遍历一下字段,消减有注解的字段吧
- private Map<String, Object> getAccessFields(Object value) throws IllegalAccessException {
- final Class> clazz = value.getClass();
- final Field[] fields = clazz.getDeclaredFields();
- Map<String, Object> map = new HashMap<>();
- for (int i = 1; i < fields.length; i++) {
- fields[i].setAccessible(true);
- if (!fields[i].isAnnotationPresent(AccessPO.class)) {
- map.put(fields[i].getName(), fields[i].get(value));
- }
- }
- return map;
- }
- 复制代码
获取到类的Class对象,获取所有字段(不包括父类),循环遍历是否存在注解,若不存在则加入待返回的Map中
好像可以了,那我type里面权限控制不是白写了吗?再修改一下
添加一些判断身份函数,调用的时候先调用他们,就知道要删减哪些字段咯
-
- private int access = 2;
-
- public int isAccess() {
- return access;
- }
-
- public void setAccess(int access) {
- this.access = access;
- }
-
- public R user() {
- this.setAccess(1);
- return this;
- }
-
- public R merchant() {
- this.setAccess(2);
- return this;
- }
-
- 复制代码
身份控制,在
Result对象中新建一个access的字段,用来判断当前的权限是如何如何,消减对应的字段
再修改getAccessFields()
- private Map<String, Object> getAccessFields(Object value) throws IllegalAccessException {
- final Class> clazz = value.getClass();
- final Field[] fields = clazz.getDeclaredFields();
- Map<String, Object> map = new HashMap<>();
- for (int i = 1; i < fields.length; i++) {
- fields[i].setAccessible(true);
- if (fields[i].isAnnotationPresent(AccessPO.class)) {
- final AccessPO accessVO = fields[i].getDeclaredAnnotation(AccessPO.class);
- final int type = accessVO.type();
- if (this.access == type) {
- map.put(fields[i].getName(), fields[i].get(value));
- }
- } else {
- map.put(fields[i].getName(), fields[i].get(value));
- }
- }
- return map;
- }
- 复制代码
如果获取到的注解的type值等于当前
Result的权限,则说明身份一致,若为0,1/2都无法匹配,所以全部不见
这样就能完成PO的字段消减了,但还要还有一点问题,如果我要返回一个List,这该怎么办,那就再加两个函数区分一下单个对象和集合
- public R data(String key, Object value) throws IllegalAccessException {
- final Map<String, Object> map = getAccessFields(value);
- super.put(key, map);
- return this;
- }
-
- public R list(String key, List value) throws IllegalAccessException {
- List<Map<String, Object>> list = new ArrayList<>();
- for (Object v : value) {
- list.add(getAccessFields(v));
- }
- super.put(key, list);
- return this;
- }
- 复制代码
遍历List,对单个元素进行消减然后获取Map即可,相信SpringBoot转Json的强大
这样就大功告成了,现在返回给前端数据,只需要查询出PO,然后直接R.ok().user().data(data).list(list).put("xxx","xxx")就行了
当然在系统中,也不可能一个VO没有嘛,毕竟VO也是很方便的,那就有了一个新需求,我现在有一个VO是由几个PO组成的,可能需要返回VO或者VOLIST,那就继续加函数
- public R voList(String key, List list) throws IllegalAccessException {
- List<Map<String, Map<String, Object>>> r = new ArrayList<>();
- for (Object vo : list) {
- Map<String, Map<String, Object>> map = new HashMap<>();
- final Class> clazz = vo.getClass();
- final Field[] fields = clazz.getDeclaredFields();
- for (Field field : fields) {
- field.setAccessible(true);
- Object o = field.get(vo);
- map.put(o.getClass().getSimpleName().toLowerCase(Locale.ROOT), getAccessFields(o));
- }
- r.add(map);
- }
- super.put(key, r);
- return this;
- }
-
- public R vo(String key, Object vo) throws IllegalAccessException {
- Map<String, Map<String, Object>> r = new HashMap<>();
- final Class> clazz = vo.getClass();
- final Field[] fields = clazz.getDeclaredFields();
- for (Field field : fields) {
- field.setAccessible(true);
- Object o = field.get(vo);
- r.put(o.getClass().getSimpleName().toLowerCase(Locale.ROOT), getAccessFields(o));
- }
- super.put(key, r);
- return this;
- }
- 复制代码
VOList的实现思路和list一样,区别是通过反射获取所有的field,再执行解析vo的方法
VO,一个PO是一个Map,那一个VO就是Map,使用getSimpleName().toLowerCase(Locale.ROOT)来获取小写类名当key 然后反射解析出所有的PO,循环求得Map插入即可

在需求不多的情况下,还是挺方便的,只需要加注解即可完成字段隐藏,没有完美的使用数据库,直接获取整个PO的话会比手写sql多一点点压力,还是更建议手写sql
所以这篇文章就当作学习注解和反射的使用了,其实也能拓展一下,通用化一下作为mybatisplus的插件,这样性能就嘎嘎好了,使用也很方便,什么时候写呢?下次一定