1. Введение:
В предыдущих статьях рассказывалось о перехватчике MyBatis, здесь я расскажу о проблеме, возникшей в моем собственном проекте, а затем быстро решу ее с помощью пользовательского перехватчика.
2. Технологии, используемые в проекте:
SpringBoot, MyBatis.....
3. Бизнес-требования:
Функцию «Разрешение данных» необходимо добавить в недавний проект. Так называемый «авторитет данных» означает, что разные пользователи видят разные диапазоны данных при запросе данных определенной таблицы.Некоторые пользователи могут видеть данные всех хранилищ, а некоторые пользователи могут видеть данные только некоторых хранилищ. необходимо настроить различные разрешения на просмотр области данных для пользователей с разными ролями. Например, есть поле «идентификатор магазина» магазина в «таблице информации о продукте». Пользователь может видеть, какие данные о продуктах магазина оцениваются в соответствии с настроенными разрешениями данных. Например, пользователь А может видеть информацию о продукте. данные 3-х магазинов. Пользователь Б может видеть информацию о товарах 4-х магазинов. Конкретная реализация заключается в добавлении условия tableName.shopId IN (shopId1, shopId2,.....) к условию WHERE соответствующего оператора запроса SQL. (PS: более дюжины таблиц в системе имеют поле «идентификатор магазина», поэтому необходимо добавить более дюжины функций с разрешениями данных).
4. План реализации:
Существует два конкретных метода реализации:
(1) Добавьте соответствующий код в каждое место, где необходимо добавить разрешения на данные.
Если наша система только начала развиваться, необходимо добавить соответствующие функции с разрешениями данных, такими как сбор данных о продукте, мы можем написать это в бизнес-коде:
public List<GoodsInformation> searchGoodsInformation(Integer userId) {
List<Integer> shopIds = authService.getIds(userId); // 调用权限服务获取用户所能看到的门店
// 1. 如果 shopIds 为空,就是可以查询所有门店数据
......
// 2. 如果 shopIds 不为空,就在查询语句中加上 tableName.shopId IN (shopId1, shopId2,.....)
......
}
Вышеупомянутые две операции 1 и 2 могут быть помещены в MyBatis и оцениваться по if, чтобы можно было повторно использовать оператор запроса.
(2) с помощью перехватчиков добавить способ MyBatis для АОП
Если наш проект разрабатывается на более позднем этапе, в настоящее время продукт говорит добавить функцию разрешения данных более чем на дюжину страниц запросов в системе, Мы немного обманываемся, когда слышим это. Если мы будем следовать методу 1, нам потребуется изменить бизнес-код и оператор запроса в MyBatis, что отнимет много времени.
На самом деле, когда мы анализируем код в методе 1, мы можем обнаружить, что:Получение коллекции магазина на основе userId — это общий код, поскольку все функции доступа к данным оцениваются на основе shopId, поэтому этот общий код можно реализовать с помощью AOP, чтобы не было необходимости модифицировать бизнес-код, разбросанный по разным пакетам. Также добавить в разные таблицыtableName.shopId IN (shopId1, shopId2,.....) Это условие, за исключением того, что имя таблицы и имя поля могут быть разными (некоторые называются shopId, некоторые называются shop и т. д.),IN (shopId1, shopId2,.....) Это точно то же самое, поэтому мы можем настроить перехватчик MyBatis, изменив оператор запроса и добавив необходимые нам условия. Среди них мы можем использовать пользовательские аннотации для настройки различных имен таблиц и имен полей.
Реализация:
Поместите идентификатор пользователя в пользовательский threadlocal
@ControllerAdvice
public class ApplicationControllerAdvice {
@ModelAttribute
public void addAttributes(@RequestParam(required = false) String userId) { if(userId != null) {
UserContext userContext = new UserContext();
userContext.setUserId(userId);
// 将 userId 放入 threadlocal 中
userContextHolder.userContextThreadLocal.set(userContext);
}
}
}
Затем определите аспект AOP, получите коллекцию shopIds и информацию о tableName и поле в пользовательской аннотации к методу в соответствии с userId и сохраните ее в threadlocal:
@Before(value = "execution(* my.study.dataauthplugin.demo.*(..)) && @annotation(dataAuthentication)") public void getDataAuth(DataAuthentication dataAuthentication) throws Throwable {
UserContext uc = UserContextHolder.userContextThreadLocal.get();
if (uc != null && !"".equals(uc.getUserId()) && dataAuthentication != null) {
// 获取 shopId 集合
List<Integer> ids = authService.getIds(uc.getUserId());
if (ids != null && !ids.isEmpty()) {
List<String> fields = new ArrayList<>();
List<String> tableNames = new ArrayList<>();
// 获取自定义注解中的 tableNames 和 fields
SqlSignature[] signatures = dataAuthentication.value();
if(signatures.length > 0) {
for (int i = 0; i < signatures.length; i++) {
fields.add(signatures[i].field());
tableNames.add(signatures[i].tableName());
}
}
// 将 shopIds ,fields,tableNames 存入 threadlocal 中
uc.init(ids, fields, tableNames);
}
}
}
}
Затем определите подключаемый модуль MyBatis и измените соответствующий оператор запроса в соответствии со значением в threadlocal.
Конкретную реализацию см.GitHub.com/Цянь Хунсин…
(3) Создан ли прокси-объект этого плагина вDataAuthenticationPlugin Решение принимается в методе плагина . При фактическом перехвате перехвата суждение о перехвате не выносится, что отличается от идеи реализации плагина подкачки PageHelper о том, следует ли перехватывать. Дополнительные сведения см. в описании метода doIntercept класса SqlUtil.
5. Понимание:
Нам необходимо глубоко изучить сопутствующие технологии, используемые в наших собственных проектах. Например, MyBatis предоставляет механизм расширения, такой как подключаемые модули, поэтому мы должны в полной мере использовать его для повышения эффективности разработки и расширения возможностей бизнеса.
Люди говорят, что говорить о технологиях вне бизнеса — это чушь собачья! Сказав это, если вы хотите лучше поддерживать бизнес, что вы можете использовать для поддержки бизнеса без глубокого изучения технологий, используемых в бизнесе? Лично я считаю необходимым глубоко изучить технический исходный код.Хотя он временно недоступен, постоянно читая технический исходный код, он также может предоставить нам лучшее решение для разработки бизнес-кода.