当前位置: 首页 > news >正文

纯知识干货java学习之问答一

        是不是后端开发的程序员都觉的后端程序很简单,特别是做java的。的确,现在java后端已经是相当成熟了,各种开源产品数不胜数。我接触过很多同事都有此感受。不过在实际开发工作中还是会难免遇到些不容易解决的问题。本专栏主要以问答的形式梳理了作者实际工作中遇到的一些问题方法供各位感兴趣的读者参考学习。

        本文章列举了1个知识点的问答梳理。

        1,如何通过AOP优雅简单的设计一个系统数据权限功能

        基于Java AOP的优雅简单数据权限设计方案
设计原则

            非侵入式:尽量减少对业务代码的影响

            灵活可配置:支持多种数据权限规则

            易于扩展:方便添加新的权限控制方式

            性能高效:减少对系统性能的影响

        核心实现方案
1. 数据权限注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DataPermission {/*** 数据权限类型*/DataPermissionType type() default DataPermissionType.USER;/*** 权限字段名*/String field() default "create_user_id";/*** 表别名(用于JOIN查询)*/String tableAlias() default "";
}

        2. 数据权限类型枚举

public enum DataPermissionType {/*** 只能查看自己的数据*/USER,/*** 查看部门数据*/DEPARTMENT,/*** 查看部门及子部门数据*/DEPARTMENT_AND_CHILD,/*** 查看全部数据*/ALL,/*** 自定义数据权限*/CUSTOM
}

        3. 数据权限上下文

public class DataPermissionContext {private static final ThreadLocal<UserPermission> context = new ThreadLocal<>();public static void setPermission(UserPermission permission) {context.set(permission);}public static UserPermission getPermission() {return context.get();}public static void clear() {context.remove();}
}public class UserPermission {private Long userId;private Long deptId;private List<Long> roleIds;private Set<String> permissions;// 构造方法、getter和setter
}

        4. AOP拦截器实现数据权限控制

@Aspect
@Component
public class DataPermissionAspect {@Autowiredprivate DeptService deptService;@Around("@annotation(dataPermission)")public Object around(ProceedingJoinPoint point, DataPermission dataPermission) throws Throwable {try {// 获取当前用户权限UserPermission userPermission = DataPermissionContext.getPermission();if (userPermission == null) {return point.proceed();}// 构建数据权限SQLString dataFilterSql = buildDataFilterSql(dataPermission, userPermission);// 设置数据权限SQL到当前线程(供MyBatis拦截器使用)DataFilterContext.setFilter(dataFilterSql);return point.proceed();} finally {DataFilterContext.clear();}}private String buildDataFilterSql(DataPermission dataPermission, UserPermission userPermission) {switch (dataPermission.type()) {case USER:return buildUserFilter(dataPermission, userPermission.getUserId());case DEPARTMENT:return buildDeptFilter(dataPermission, userPermission.getDeptId(), false);case DEPARTMENT_AND_CHILD:return buildDeptFilter(dataPermission, userPermission.getDeptId(), true);case ALL:return "";case CUSTOM:return buildCustomFilter(dataPermission, userPermission);default:return "";}}private String buildUserFilter(DataPermission dataPermission, Long userId) {String field = getFieldWithAlias(dataPermission);return field + " = " + userId;}private String buildDeptFilter(DataPermission dataPermission, Long deptId, boolean includeChildren) {String field = getFieldWithAlias(dataPermission);if (includeChildren) {List<Long> deptIds = deptService.getChildDeptIds(deptId);return field + " IN (" + StringUtils.join(deptIds, ",") + ")";} else {return field + " = " + deptId;}}private String buildCustomFilter(DataPermission dataPermission, UserPermission userPermission) {// 自定义权限逻辑,可根据实际需求扩展return "";}private String getFieldWithAlias(DataPermission dataPermission) {String alias = StringUtils.isNotBlank(dataPermission.tableAlias()) ? dataPermission.tableAlias() + "." : "";return alias + dataPermission.field();}
}

        5. MyBatis拦截器实现SQL改写,这是本方法的重点难点之一,也是技巧所在之处

@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
@Component
public class DataPermissionInterceptor implements Interceptor {@Overridepublic Object intercept(Invocation invocation) throws Throwable {StatementHandler statementHandler = (StatementHandler) invocation.getTarget();MetaObject metaObject = SystemMetaObject.forObject(statementHandler);MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");// 获取数据权限过滤条件String dataFilter = DataFilterContext.getFilter();if (StringUtils.isBlank(dataFilter)) {return invocation.proceed();}// 获取原始SQLBoundSql boundSql = (BoundSql) metaObject.getValue("delegate.boundSql");String originalSql = boundSql.getSql();// 判断是否需要添加数据权限if (shouldAddDataPermission(originalSql, mappedStatement.getId())) {String newSql = addDataPermissionToSql(originalSql, dataFilter);metaObject.setValue("delegate.boundSql.sql", newSql);}return invocation.proceed();}private boolean shouldAddDataPermission(String sql, String mappedStatementId) {// 排除不需要数据权限的方法if (mappedStatementId.contains("ByDataPermission")) {return true;}// 根据实际需求判断是否需要添加数据权限return true;}private String addDataPermissionToSql(String originalSql, String dataFilter) {String upperCaseSql = originalSql.toUpperCase();if (upperCaseSql.contains(" WHERE ")) {int whereIndex = upperCaseSql.indexOf(" WHERE ");String beforeWhere = originalSql.substring(0, whereIndex + 7);String afterWhere = originalSql.substring(whereIndex + 7);return beforeWhere + " (" + dataFilter + ") AND " + afterWhere;} else {return originalSql + " WHERE " + dataFilter;}}@Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}@Overridepublic void setProperties(Properties properties) {}
}

        6. 数据权限上下文管理

public class DataFilterContext {private static final ThreadLocal<String> context = new ThreadLocal<>();public static void setFilter(String filter) {context.set(filter);}public static String getFilter() {return context.get();}public static void clear() {context.remove();}
}

        7.使用示例。整合了 action ,service及配置文件代码.

@RestController
@RequestMapping("/api/users")
public class UserController {@GetMapping@DataPermission(type = DataPermissionType.DEPARTMENT_AND_CHILD, field = "dept_id")public List<User> listUsers() {return userService.listUsers();}
}@Service
public class UserServiceImpl implements UserService {@Override@DataPermission(type = DataPermissionType.USER, field = "create_user_id")public List<User> listMyUsers() {return userMapper.selectList(null);}
}public class CustomDataPermissionProvider {public String getCustomFilter() {// 实现自定义数据权限逻辑UserPermission permission = DataPermissionContext.getPermission();if (permission.getPermissions().contains("admin")) {return ""; // 管理员可以看到所有数据} else {return "dept_id IN (SELECT dept_id FROM user_dept WHERE user_id = " + permission.getUserId() + ")";}}
}# application.yml
data-permission:enabled: trueignore-tables: sys_log, sys_config # 不需要数据权限的表ignore-methods: com.example.mapper.UserMapper.selectById # 不需要数据权限的方法

        该方案的优点
非侵入式:通过注解和AOP实现,对业务代码影响小
灵活配置:支持多种数据权限类型,可自定义扩展
易于维护:权限逻辑集中管理,便于维护和修改
性能优化:通过SQL改写实现,减少内存中的数据过滤
可扩展建议
缓存优化:对部门层级等不常变的数据进行缓存
动态数据源:支持多租户场景下的数据隔离
权限继承:支持角色继承和权限组合
可视化配置:提供界面化配置数据权限规则

        欢迎各位读者及同行举出该方案的不足之处,谢谢!!!喜欢该文章的请点个关注,感谢!!!!

        

http://www.dtcms.com/a/477976.html

相关文章:

  • L05_后端_MinIO 安装使用入门指南(实战版)
  • [ SpringBoot ]
  • Nginx 负载均衡调度算法
  • 全链路Controller压测负载均衡
  • FastCRUD:为 FastAPI 量身打造的现代化异步 CRUD 框架,让后端开发更高效
  • 宠物服务到店预约/宠物服务上门预约/商城零售o2o
  • 网站做推广企业wordpress最新模板
  • 云手机长期使用会消耗很多流量吗
  • 自己做的网站服务器开了进不去网站定位要点 有哪些方面
  • figma-developer-mcp
  • BUG() 和 BUG_ON()
  • 牛客周赛 Round 111
  • Vue 3 watch 与 watchEffect ,哪个更好?
  • 建工网站响应式网站发展
  • 企业网站pc优化网站的基本结构
  • 电子静止质量 Electron rest mass
  • DB-GPT实现Text2SQL全流程解析
  • 数据结构--------顺序表
  • 【完整源码+数据集+部署教程】硅藻分类识别系统源码和数据集:改进yolo11-DRBNCSPELAN
  • 【04】VisionMaster入门到精通——模板匹配【高精度匹配、快速匹配】
  • cv里的图像分割任务的部分评价指标
  • 电子商城网站建设与维护桂林市网站建设公司
  • PMP-项目管理-PMBOK第六版_中文版:图表工具
  • 利用淘宝联盟做网站赚取佣金wordpress qq微信登陆
  • Java入门级教程23——配置Nginx服务器、轻量级HTTP服务开发、前后端分离实现完整应用系统
  • 基于微信小程序的校园代取服务平台
  • AI大事记12:Transformer 架构——重塑 NLP 的革命性技术(中)
  • 常用 HTTP 状态码速查表
  • 微信小程序上的图片怎么批量下载?附工具教程
  • CSS 02【基础语法学习】