瑞吉外卖06-公共字段自动填充

本文介绍如何利用MybatisPlus实现公共字段自动填充,通过ThreadLocal获取当前登录用户ID,并应用于瑞吉外卖项目的具体实践。

瑞吉外卖06-公共字段自动填充

需求分析

问题描述

解决方案

对于createTime、updateTime字段

对于createUser、updateUser字段 

代码实现

知识点分析

ThreadLocal

本次功能代码实现(免费) 


需求分析

问题描述

前面我们已经完成了后台系统的员工管理功能的开发,在新增员工时需要设置创建时间、创建人、修改时间、修改人等字段,在编辑员工时需要设置修改时间、修改人等字段。

这些字段属于公共字段,也就是也就是在我们的系统中很多表中都会有这些字段。

我们可以先来看看表结构

employee 表

setmeal_dish 表

上述的这两张表都有(创建时间、创建人、修改时间、修改人)字段。

我们之前处理这些字段都是直接对其进行getter、setter操作,例如:

新增员工业务 

在新增数据时, 将createTime、updateTime 设置为当前时间, createUser、updateUser设置为当前登录用户ID

编辑员工信息业务  

在更新数据时, 将updateTime 设置为当前时间, updateUser设置为当前登录用户ID

如果都按照上述的操作方式来处理这些公共字段,需要在每一个业务方法中进行操作,编码相对冗余、繁琐,那能不能对于这些公共字段在某个地方统一处理,来简化开发呢?  

解决方案

对于createTime、updateTime字段

Mybatis Plus 公共字段自动填充,也就是在插入或者更新的时候为指定字段赋予指定的值,使用它的好处就是可以统一对这些字段进行处理,避免了重复代码

字段名赋值时机说明
createTime插入(INSERT)当前时间
updateTime插入(INSERT) , 更新(UPDATE)当前时间
createUser插入(INSERT)当前登录用户ID
updateUser插入(INSERT) , 更新(UPDATE)当前登录用户ID

实现步骤

(1)在实体类的属性上加入 @TableField 注解,指定自动填充的策略

(2)按照框架要求编写元数据对象处理器,在此类中统一为公共字段赋值,此类需要实现MetaObjectHandler接口

对于createUser、updateUser字段 

在自动填充createUser和updateUser时,设置的用户id是动态获取当前登录用户的id

如何获取??? 

用户登录成功后我们将用户id存入了HttpSession中,所以我们直接从Session对象中获取就行了。

但是,我们在实现MetaObjectHandler接口的类中是不能直接获得HttpSession对象的,所以我们需要通过其他方式来获取登录用户id。

客户端发送的每次http请求,对应的在服务端都会分配一个新的线程来处理,在处理过程中涉及到下面类中的方法都属于相同的一个线程,所以我们自然可以想到用ThreadLocal来解决!!!

代码实现

给employee类加上@TableField注解

编写BaseContext工具类 

/**
 * 基于ThreadLocal封装的工具类,用于保存、获取当前用户登入的ID
 */
public class BaseContext {

    // 作用域是每一个线程之内,每一个请求都是一个新的线程!!!
    private static ThreadLocal<Long> threadLocal = new ThreadLocal<>();

    public static void setCurrentId(Long id) {
        threadLocal.set(id);
    }

    public static Long getCurrentId() {
        return threadLocal.get();
    }
}

注释掉 EmployeeServiceImpl类中的getter、setter方法

在过滤器 LoginCheckFilter类里的session对象中获取员工的ID

在MyMetaObjectHandler中设置值

/**
 * MetaObjectHandler  元数据处理器
 */
@Component
@Slf4j
public class MyMetaObjectHandler implements MetaObjectHandler {

    /**
     * 插入时自动填充
     * @param metaObject
     */
    @Override
    public void insertFill(MetaObject metaObject) {
        metaObject.setValue("createTime", LocalDateTime.now());
        metaObject.setValue("updateTime", LocalDateTime.now());
        metaObject.setValue("createUser", BaseContext.getCurrentId());
        metaObject.setValue("updateUser", BaseContext.getCurrentId());
    }

    /**
     * 更新时自动填充
     * @param metaObject
     */
    @Override
    public void updateFill(MetaObject metaObject) {
        metaObject.setValue("updateTime", LocalDateTime.now());
        metaObject.setValue("updateUser", BaseContext.getCurrentId());
    }
}

知识点分析

ThreadLocal

ThreadLocal是解决线程安全问题一个很好的思路,它通过为每个线程提供一个独立的变量副本解决了变量并发访问的冲突问题。

在很多情况下,ThreadLocal比直接使用synchronized同步机制解决线程安全问题更简单,更方便,且结果程序拥有更高的并发性。

最常用的就是get()、set()、remove()方法了。

具体的ThreadLocal源码分析请见本人的主页的其它文章!

本次功能代码实现(免费) 

瑞吉外卖: 瑞吉外卖项目完整代码,使用Sprinboot,SSM,MP,MySQL,Redis,Nginx等技术。 - Gitee.comhttps://gitee.com/Harmony_TL/reggie_take_out/tree/reggie_v6_Autofill/

### 外卖系统登录管理功能详解 #### 登录界面设计 登录界面作为用户进入系统的首要接触点,需简洁明了并具备必要的安全措施。通常该界面会包含用户名/手机号码输入框、密码输入框以及验证码验证区域。为了提升用户体验,在界面上还应设有“记住账号”选项和“忘记密码?”链接。 #### 用户认证流程 当用户提交其凭证信息后,服务器端会对这些数据进行校验。具体来说: - 验证提供的账户名是否存在; - 对比数据库中的哈希化存储的密码与前端传来的经过相同算法处理后的字符串是否一致[^1]; - 若开启图形或短信验证码机制,则还需进一步确认此额外的安全层。 如果以上所有检查均通过,则允许用户成功登陆,并为其创建一个临时的身份令牌(Token),用于维持当前会话期间的操作权限验证。 #### 权限控制策略 对于不同角色类型的使用者——比如管理员、店员或是顾客——各自拥有不同的操作范围。因此,在每次请求资源时都要依据所持有的身份级别来判断是否有权执行特定行为。这涉及到RBAC (基于角色的访问控制)模型的应用,即预先设定好各类人员可触及的功能模块列表[^2]。 #### 安全考量事项 考虑到网络安全的重要性,除了常规的数据加密传输外,还需要定期更新密钥库以防泄露风险;设置合理的Session过期时间防止长时间未活动被恶意利用;另外就是防范SQL注入攻击等常见的Web漏洞威胁。 ```python def login(user_input, password_hashed): user = User.query.filter_by(username=user_input).first() if not user or not check_password(password_hashed, user.password): raise ValueError('Invalid credentials') session['user_id'] = user.id return generate_token(user) def protect_route(func): @wraps(func) def decorated_view(*args, **kwargs): token = request.headers.get('Authorization') try: data = decode_token(token) current_user = load_user(data['id']) if not has_permission(current_user.role, func.__name__): abort(403) g.user = current_user return func(*args, **kwargs) except Exception as e: abort(401) return decorated_view ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

金鳞踏雨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值