后台管理系统,每个表有对应的创建者,更新者字段。
当在页面进行操作时,需要先获取将操作者的信息,然后记录到表。
现在用户的信息是存在 session 中,每次执行方法的时候都要从 session 中获取操作者信息,然后将操作者的信息放入更新的对象中,然后插入 /更新到表中。
能否借用 AOP 来完成获取登入用户的信息,然后将操作者信息的属性,通过 AOP 传参给方法,然后在方法中直接通过对象来接收。然后再插入 /更新到表中。
看了 spring AOP 可以通过 args 等方法,向通知传递数据。
那么反过来,aop 可以给需要织入的方法传递数据吗?
或者有什么其他方法可以简化获取用户信息,并记录到表中。
1
lemonEssence 2020-07-17 14:40:14 +08:00
如果你用的是 JPA 的话可以用 JPA 审计, @CreatedBy @LastModifiedBy
|
2
Vimax OP @lemonEssence 谢谢了。用的是 mybatis 呢。
|
3
avk458 2020-07-17 15:19:34 +08:00
提供个获取信息的静态方法,多线程或者异步线程参考 DelegatingSecurityContext
|
4
rockyou12 2020-07-17 15:24:37 +08:00
使用自定义 spel 非常好,不过稍微有点复杂,我之前写的基于 aop 的 rbac 框架就是这样做的,效果如下。
@GetMapping("/{id}") @Audit(resType = ResType.shop, resId = "#id", resOpt = ResOpt.READ) public ShopViewDto getViewById(String id){ ShopViewDto shopViewDto = shopService.selectDetailById(id); return shopViewDto; } 这个 #id 就是读取的方法上的参数,你要读其他的只要反射得出来都可以,甚至是其他 context 里的参数也可以写在 spel 中,但定义 spel 稍微有点复杂 |
5
optional 2020-07-17 15:41:54 +08:00
其实并没有觉得这样算是干净了,java 里那一套,基本只能用楼上说的 spel 表达式来搞,但是后果就是失去了强类型的加持。
aop 当然可以给传递数据,但是这样就不干净了, 最好用 threadlocal 这种放在上下文 context 里。 |
6
cedoo22 2020-07-17 16:41:45 +08:00 via iPhone
之前 用自定义注解 然后 aop 注入到参数里,类似 validation 后加一个验证结果,就是很不面向 Java 编程。
|
9
lewis89 2020-07-17 18:07:35 +08:00
@optional 另外切面跟注解本身 并不是为了干净,而是为了可拔插,注解你想加就加 想移除就移除 不会对软件系统造成任何功能性的影响,类似缓存,你移除缓存注解 不会影响软件原本的业务逻辑行为
|
10
optional 2020-07-17 18:08:26 +08:00
@lewis89 其实我认为问题在 java/jvm 的 annotation 里只能放常量类型,不支持放表达式,否则会好很多。
|
12
optional 2020-07-17 18:09:25 +08:00
哪怕是编译器常量都不行
|
13
optional 2020-07-17 18:11:27 +08:00
@lewis89 aop 本身是个 decorate 模式,这个没有问题问题,问题只支持常量类型,然后为了突破这个,搞出 spel 这种,就很脏。
|
14
magicdu 2020-07-17 18:14:45 +08:00 via Android
mybatisplus 有个 metaobjecthandler
|
15
optional 2020-07-17 18:15:42 +08:00
|
16
magicdu 2020-07-17 18:21:56 +08:00
@magicdu #14
``` /** * 处理新增和更新的基础数据填充,配合 BaseEntity 和 MyBatisPlusConfig 使用 */ @Component public class MetaHandler implements MetaObjectHandler { /** * 新增数据执行 * @param metaObject */ @Override public void insertFill(MetaObject metaObject) { UserDetails user; try { user = SecurityUtils.getUserDetails(); this.setFieldValByName("crtUserName", user.getUsername(), metaObject); this.setFieldValByName("crtUserId", SecurityUtils.getUserId(), metaObject); this.setFieldValByName("updUserName", user.getUsername(), metaObject); this.setFieldValByName("updUserId", SecurityUtils.getUserId(), metaObject); } catch (Exception e) { } this.setFieldValByName("crtTime", new Date(), metaObject); this.setFieldValByName("updTime", new Date(), metaObject); } /** * 更新数据执行 * @param metaObject */ @Override public void updateFill(MetaObject metaObject) { UserDetails user; try { user = SecurityUtils.getUserDetails(); this.setFieldValByName("updUserName", user.getUsername(), metaObject); this.setFieldValByName("updUserId", SecurityUtils.getUserId(), metaObject); } catch (Exception e) { } this.setFieldValByName("updTime", new Date(), metaObject); } } ``` 配合 BaseEntity 和 MyBatisPlusConfig 使用 ``` @Configuration public class MyBatisPlusConfig { /** * 自动填充功能 * @return */ @Bean public GlobalConfig globalConfig() { GlobalConfig globalConfig = new GlobalConfig(); globalConfig.setMetaObjectHandler(new MetaHandler()); return globalConfig; } } ``` |
17
totoro52 2020-07-17 18:33:16 +08:00
我采用的是注解拦截 自写了一个注解类 然后标注需要验证 token 的方法 如果这个方法参数需要一个 user 类的话 就注入一个用户实体类 不知道符不符合楼主的需求
if(method.getAnnotation(TokenAccess.class).userHold()){ for (int i = 0;i<args.length;i++) { // 需要做进一步判断,判断这个方法是否需要这个 user if(args[i]!=null && args[i].getClass() == User.class){ args[i] = user; } } } |
18
EscYezi 2020-07-18 21:31:00 +08:00 via iPhone
请求用过滤器把 session 里面的对象保存好写到 ThreadLocal,然后 aop 直接取 ThreadLocal 里的 user 对象,写表的操作在 aop 里面来调用。
贴中的用 AOP 获取用户对象注入到方法参数里这个不太能理解,写表的操作是由被切的方法执行的?如果是这样的话,参数直接加个 HttpSession 再封一个工具类不就好了 |
19
EscYezi 2020-07-18 21:34:01 +08:00 via iPhone
抱歉抱歉,没有看到是要把用户信息放在属性里.....
|
20
siweipancc 2020-07-20 19:00:14 +08:00 via iPhone
:D 你这个只能在 Around 织入,官方有 demo, 深入的话建议看下 EntityListener 和 Spring Cache 的实现源码。
|