添加员工信息
执行流程
第一步: 用户点击添加员工按钮
跳转到add.html
页面,然后在页面中输入要添加的员工的信息
第二步: 用户点击保存按钮
发送Ajax请求将用户输入的员工信息以json的格式提交到服务端
第三步: 服务端Controller接收页面提交的json格式的数据并转化为java对象, 通过Service调用Mapper将员工信息插入到employee表
中,最后向前端返回通用结果类
id
: 由雪花算法/自动递增机制自动生成username
: 设置唯一性约束, 员工的的登录账户必须是唯一的password
: 默认指定一个密码(身份证后六位,123456等),但是这个密码不能直接在数据库中设为默认值,因为数据库设置的默认值无法加密status
: 设定员工的状态,默认值1表示启用(正常),0表示禁用,直接在数据库中设置默认值不需要加密createTime/updateTime
: 创建/更新员工信息的时间,这个就指定当前时间就好了createUser/updateUser
: 创建/更新员工信息的管理员ID,依靠这个可以溯源避免出现莫名的员工账号
前端页面
add.html
为公共页面,新增员工和编辑员工都是在此页面操作,只不过添加员工时还会显示保存并继续添加按钮
<script>// add.html页面提交的数据模型 ruleForm : {'name': '','phone': '','sex': '男','idNumber': '',username: ''}
</script><el-formref="ruleForm":model="ruleForm":rules="rules":inline="false"label-width="180px"class="demo-ruleForm"><el-form-item label="账号:" prop="username"><el-input v-model="ruleForm.username" placeholder="请输入账号" maxlength="20"/></el-form-item><el-form-itemlabel="员工姓名:"prop="name"><el-inputv-model="ruleForm.name"placeholder="请输入员工姓名"maxlength="20"/></el-form-item><el-form-itemlabel="手机号:"prop="phone"><el-inputv-model="ruleForm.phone"placeholder="请输入手机号"maxlength="20"/></el-form-item><el-form-itemlabel="性别:"prop="sex"><el-radio-group v-model="ruleForm.sex"><el-radio label="男"></el-radio><el-radio label="女"></el-radio></el-radio-group></el-form-item><el-form-itemlabel="身份证号:"prop="idNumber"><el-inputv-model="ruleForm.idNumber"placeholder="请输入身份证号"maxlength="20"/></el-form-item><div class="subBox address"><el-form-item><el-button @click="goBack()">取消</el-button><el-buttontype="primary"<!--发送ajax请求将用户输入的员工信息以json的格式提交到服务端-->@click="submitForm('ruleForm', false)">保存</el-button><el-button<!--如果是添加员工显示该按钮,如果是修改员工则不显示该按钮-->v-if="actionType == 'add'"type="primary"class="continue"@click="submitForm('ruleForm', true)">保存并继续添加</el-button></el-form-item></div>
</el-form>
submitForm函数
调用addEmployee
函数发送Ajax请求将用户输入的员工信息以json的格式提交到服务端,最后接收服务器响应的通用结果类执行Ajax的回调函数
submitForm (formName, st) {this.$refs[formName].validate((valid) => {// 对表单的数据进行校验if (valid) {// 判断是添加还是修改if (this.actionType === 'add') {const params = {...this.ruleForm,sex: this.ruleForm.sex === '女' ? '0' : '1'// 将表单中的男女转换为数据库中对应的0或1}addEmployee(params).then(res => {// 接收服务器Controller响应的结果if (res.code === 1) {this.$message.success('员工添加成功!')if (!st) {this.goBack()} else {// 员工添加失败this.ruleForm = {username: '','name': '','phone': '',// 'password': '',// 'rePassword': '',/'sex': '男','idNumber': ''}}} else {this.$message.error(res.msg || '操作失败')}}).catch(err => {this.$message.error('请求出错了:' + err)})} else {// 修改员工信息......}} else {console.log('error submit!!')return false}})
}// 发起ajax请求新增添加员工
function addEmployee (params) {return $axios({url: '/employee',method: 'post',data: { ...params }})
}
后端处理请求
处理请求路径为/employee
的POST请求将添加的员工信息保存到数据库
@RestController
@RequestMapping("/employee")
public class EmployeeController {@Autowiredprivate EmployeeService employeeService;@PostMappingpublic Result<String> save(HttpServletRequest request, @RequestBody Employee employee) {// 接收的employee对象的id,password,status,createTime属性都还是nulllog.info("新增的员工信息:{}", employee.toString());// 设置默认密码为123456,并采用MD5加密employee.setPassword(DigestUtils.md5DigestAsHex("123456".getBytes()));// 设置createTime和updateTimeemployee.setCreateTime(LocalDateTime.now());employee.setUpdateTime(LocalDateTime.now());// 在session中获取创建人的id设置CreateUser和UpdateUserLong empId = (Long) request.getSession().getAttribute("employee");employee.setCreateUser(empId);employee.setUpdateUser(empId);// 将employee对象存入数据库employeeService.save(employee);// 响应通用的结果封装类return Result.success("添加员工成功");}
}
全局异常处理器
添加员工时存入相同的username(唯一)控制台会报java.sql.SQLIntegrityConstraintViolationException:Duplicate entry...
,有两种方式捕获
- 在Controller方法中对
employeeService.save(employee)
使用try...catch
进行异常捕获,这种方式只能捕获当前代码发生的异常 - 使用
全局异常处理器
可以捕获整个项目中指定类型的异常
创建一个全局异常处理类common/GlobalExceptionHandler
,添加exceptionHandler
方法用来捕获异常,并返回通用错误信息如提示用户名xxx已存在
@Slf4j
// 只有加了@Controller注解的类发生的异常才会捕获
@ControllerAdvice(annotations = {RestController.class,Controller.class})
@ResponseBody
public class GlobalExceptionHandler {// 拦截SQLIntegrityConstraintViolationException异常@ExceptionHandler(SQLIntegrityConstraintViolationException.class)public Result<String> exceptionHandler(SQLIntegrityConstraintViolationException exception) {// 控制台日志输出的异常信息为Duplicate entry 'zhangsan' for key 'employee.idx_username'log.error(exception.getMessage());// 如果异常信息包含Duplicate entry,则说明有条目重复if (exception.getMessage().contains("Duplicate entry")) {// 将字符串按照空格分割得到username(字符串格式是固定的)String[] split = exception.getMessage().split(" ");String username = split[2];// 拼串作为错误信息返回return Result.error("用户名" + username + "已存在");}// 其他错误信息return Result.error("未知错误");}
}
员工信息分页查询
执行流程
第一步: 在加载index.html
页面时自动调用list.html
中的creatued()函数
发送ajax请求,将分页查询需要的参数page,pageSize,name
提交到服务端
- 如果当前就在index.html页面中可以
通过指定查询条件发起Ajax请求查询分页数据
, 请求参数除了携带page,pageSize外
还携带name表示查询条件
- 如果用户点击页数上下翻页的时候也会发起Ajax请求提交
page,pageSize请求参数
查询员工分页数据
第二步: 服务端Controller接收页面提交的参数,通过Service调用Mapper操作数据库查询分页数据,然后将查询到的分页数据响应给页面
第三步: 页面接收到分页数据并通过ElementUI的Table组件
展示到页面上
前端页面
list.html页面
携带分页查询需要的参数page,pageSize,name
发起Ajax请求,然后将服务端的Controller响应的所有员工数据展示到页面
created() {this.init()this.user = JSON.parse(localStorage.getItem('userInfo')).username
},async init () {// json格式的请求参数const params = {page: this.page,pageSize: this.pageSize,name: this.input ? this.input : undefined}await getMemberList(params).then(res => {// 执行回调函数接收服务端Controller响应的所有员工数据if (String(res.code) === '1') {this.tableData = res.data.records || []this.counts = res.data.total}}).catch(err => {this.$message.error('请求出错了:' + err)})function getMemberList (params) {return $axios({url: '/employee/page',method: 'get',params})
}
request全局拦截器
拦截get请求将json格式
的请求参数转化为name=value
的格式拼接到URL上
service.interceptors.request.use(config => {
// 是否需要在响应头中添加token
// const isToken = (config.headers || {}).isToken === false
// if (getToken() && !isToken) {
// config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
// }
// get请求映射params参数
if (config.method === 'get' && config.params) {let url = config.url + '?';for (const propName of Object.keys(config.params)) {const value = config.params[propName];var part = encodeURIComponent(propName) + "=";if (value !== null && typeof(value) !== "undefined") {if (typeof value === 'object') {for (const key of Object.keys(value)) {let params = propName + '[' + key + ']';var subPart = encodeURIComponent(params) + "=";url += subPart + encodeURIComponent(value[key]) + "&";}} else {url += part + encodeURIComponent(value) + "&";}}}url = url.slice(0, -1);config.params = {};config.url = url;
}
return config
}, error => {console.log(error)Promise.reject(error)
})
在list.html
页面中展示数据的时候,将后端响应的Integer类型的status
转化为已禁用或者正常
的字符串
<el-table-column label="账号状态"><template slot-scope="scope">{{ String(scope.row.status) === '0' ? '已禁用' : '正常' }}</template>
</el-table-column>
后端处理请求
第一步: 在config/MybatisPlusConfig
中添加MyBatisPlus的分页插件对象
并交给IoC容器管理
@Configuration
//可以将主类中的扫描Mapper接口的注解移到此处
@MapperScan("com.atguigu.mybatisplus.mapper")
public class MybatisPlusConfig {@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {// 配置MyBatis Plus中插件的对象MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();// 在插件对象中添加内部插件并设置数据库类型interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));return interceptor;}
}
第二步: 查询所有的员工信息并进行分页,Page对象
中封装了查询到的所有员工信息(records属性
)和其他分页信息如total,size属性
@GetMapping("/page")
public Result<Page> page(int page, int pageSize, String name) {log.info("page={},pageSize={},name={}", page, pageSize, name);// 在分页对象中设置分页参数,当前页码数和每页显示的记录数Page<Employee> pageInfo = new Page<>(page, pageSize);// 构造条件构造器LambdaQueryWrapper<Employee> wrapper = new LambdaQueryWrapper<>();// 添加过滤条件,当我们没有输入name查询条件时表示查询所有wrapper.like(!(name == null || "".equals(name)), Employee::getName, name);// wrapper.like(StringUtils.isNotEmpty(name),Employee::getName,name);// 添加排序条件,根据更新时间对查询的结果进行降序排序wrapper.orderByDesc(Employee::getUpdateTime);// 添加分页对象和条件构造器查询所有,最终数据都会被封装到分页对象中employeeService.page(pageInfo, wrapper);// 将Page对象封装到Result对象的data属性中,Page对象的records属性中封装了查询到的员工信息return Result.success(pageInfo);
}
启用/禁用员工账号
执行流程
第一步: 用户点击启用/禁用
按钮时页面发送Ajax的PUT请求
将参数元素所在行的id和status
提交到服务端
第二步: 服务端Controller接收页面提交的数据通过Service调用Mapper操作数据库更新对应id员工的status的值
前端页面
只有管理员(admin)可以对其他所有员工账号进行启用、禁用操作
, 普通用户登录系统后启用、禁用按钮不显示
- 如果某个员工账号状态为正常则按钮显示为
禁用
,如果员工账号状态为已禁用则按钮显示为启用
当加载完list.html页面时获取一下当前登录账号的username并判断是不是admin
,如果是就显示启用/禁用按钮否则不显示
<script>created() {this.init()this.user = JSON.parse(localStorage.getItem('userInfo')).username}
</script><el-buttontype="text"size="small"class="delBut non"@click="statusHandle(scope.row)"v-if="user === 'admin'"
>{{ scope.row.status == '1' ? '禁用' : '启用' }}
</el-button>
用户点完启用禁用按钮
后调用statusHandle函数
弹出提示窗口,点击确定之后调用enableOrDisableEmployee函数
携带当前行的id值与!status
发起PUT请求
statusHandle (row) {// row表示每行数据对应的json对象this.id = row.idthis.status = row.statusthis.$confirm('确认调整该账号的状态?', '提示', {'confirmButtonText': '确定','cancelButtonText': '取消','type': 'warning'}).then(() => {// 对当前状态进行取反操作实现切换禁用/启用状态,如果this.status为1则status为0,如果this.status为0则status为1enableOrDisableEmployee({ 'id': this.id, 'status': !this.status ? 1 : 0 }).then(res => {// 根据服务器响应的结果执行回调函数console.log('enableOrDisableEmployee',res)if (String(res.code) === '1') {this.$message.success('账号状态更改成功!')this.handleQuery()}}).catch(err => {this.$message.error('请求出错了:' + err)})})
}// 修改启用/禁用接口
function enableOrDisableEmployee (params) {return $axios({url: '/employee',method: 'put',data: { ...params }})
}
配置状态转换器
执行完分页查询请求服务器响应给页面的Employee对象的id是正确的,但JS将id渲染到页面上时会丢失精度
,这样获取的页面id就和数据库中id有差异
JS对Long型数据进行处理时会丢失精度导致提交的id和数据库中的id不一致
, 需要服务端在给页面响应json数据时将Long型数据统一转为String字符串
对象转换器
:基于jackson
将Java对象转为json[序列化Java对象到JSON],或者将json转为Java对象[从JSON反序列化Java对象]
第一步: 创建commom/JacksonObjectMapper
继承ObjectMapper
,不需要向工程中导入依赖
public class JacksonObjectMapper extends ObjectMapper {public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";public JacksonObjectMapper() {super();// 收到未知属性时不报异常this.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);// 反序列化时,属性不存在的兼容处理this.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);SimpleModule simpleModule = new SimpleModule().addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT))).addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT))).addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT))).addSerializer(BigInteger.class, ToStringSerializer.instance)// 将Long类型转化为String类型.addSerializer(Long.class, ToStringSerializer.instance)// 将日期类型转化为日期格式的字符串.addSerializer(LocalDateTime.class,new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT))).addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT))).addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));//注册功能模块 例如可以添加自定义序列化器和反序列化器this.registerModule(simpleModule);}
}
第二步: 扩展Mvc框架的消息转换器
,在此消息转换器中使用自己的对象转换器进行java数据到json对象的转换
@Configuration
@Slf4j
public class WebMvcConfig extends WebMvcConfigurationSupport {@Overrideprotected void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/backend/**").addResourceLocations("classpath:/backend/");registry.addResourceHandler("/front/**").addResourceLocations("classpath:/front/");}@Overrideprotected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();// 设置自己的对象转化器,底层使用jackson将java对象转为jsonmessageConverter.setObjectMapper(new JacksonObjectMapper());// 将自己的消息转换器对象追加到mvc框架的转换器集合当中(index设置为0,表示设置在第一个位置,避免被其它转换器接收,从而达不到想要的功能)converters.add(0, messageConverter);}
}
后端处理请求
更新员工记录的status状态
字段的值,该方法也可以修改员工信息的其他字段
@PutMapping
public Result<String> update(@RequestBody Employee employee, HttpServletRequest request) {log.info(employee.toString());Long id = (Long) request.getSession().getAttribute("employee");employee.setUpdateUser(id);employee.setUpdateTime(LocalDateTime.now());employeeService.updateById(employee);return Result.success("员工信息修改成功");
}
编辑员工信息
执行流程
第一步用户点击编辑按钮
跳转到add.html
公共页面中并在URL中携带编辑员工的id
作为请求参数,如果URL中没有携带id表示添加操作
<el-buttontype="text"size="small"class="blueBug"@click="addMemberHandle(scope.row.id)":class="{notAdmin:user !== 'admin'}"
>编辑
</el-button>
<script>addMemberHandle (st) {if (st === 'add'){window.parent.menuHandle({id: '2',url: '/backend/page/member/add.html',name: '添加员工'},true)} else {window.parent.menuHandle({id: '2',url: '/backend/page/member/add.html?id='+st,name: '修改员工'},true)}
}
</script>
第二步: 在add.html
页面中获取URL中携带的员工id,如果获取得到id发起修改员工的Ajax请求,如果获取不到发起添加员工的Ajax请求
created() {this.id = requestUrlParam('id')// id有值表示修改,没有值表示添加this.actionType = this.id ? 'edit' : 'add'if (this.id) {this.init()}
}// 获取url地址上面的参数
function requestUrlParam(argname){var url = location.hrefvar arrStr = url.substring(url.indexOf("?")+1).split("&")for(var i =0;i<arrStr.length;i++){// 查找"id="出现的索引var loc = arrStr[i].indexOf(argname+"=")if(loc!=-1){return arrStr[i].replace(argname+"=","").replace("?","")}}return ""
}
员工信息回显
第一步: 根据编辑员工的id查询员工信息然后以json形式响应给页面
@GetMapping("/{id}")// 使用占位符接收员工的id
public Result<Employee> getById(@PathVariable Long id){log.info("根据id查询员工信息..");Employee employee = employeeService.getById(id);return Result.success(employee);
}
第二步: 在回调函数中接收服务端响应的json数据,并通过Vue的双向绑定功能进行员工信息回显
- 前端接收到服务端响应的json数据之后先判断状态码是否为1,如果是1则说明操作成功,然后将获取到的数据渲染到表单中从而达到回显数据的效果
// created钩子函数中调用的init函数
async init () {queryEmployeeById(this.id).then(res => {console.log(res)if (String(res.code) === '1') {console.log(res.data)this.ruleForm = res.datathis.ruleForm.sex = res.data.sex === '0' ? '女' : '男'// this.ruleForm.password = ''} else {this.$message.error(res.msg || '操作失败')}})
}
更新员工信息
第一步: 用户点击保存按钮
发送Ajax请求将页面中修改后的员工信息以json形式提交给服务端
<el-buttontype="primary"@click="submitForm('ruleForm', false)"
>保存
</el-button>
<script>submitForm (formName, st) {this.$refs[formName].validate((valid) => {if (valid) {// 判断是添加还是修改 if (this.actionType === 'add') {// 添加员工信息的接口addEmployee(params).then(res => {// 接收服务器响应的结果执行回调函数} else { const params = {...this.ruleForm,sex: this.ruleForm.sex === '女' ? '0' : '1'}// 修改员工信息editEmployee(params).then(res => {if (res.code === 1) {this.$message.success('员工信息修改成功!')this.goBack()} else {this.$message.error(res.msg || '操作失败')}}).catch(err => {this.$message.error('请求出错了:' + err)})}} else {console.log('error submit!!')return false}})
}
// 修改员工的接口
function editEmployee (params) {return $axios({url: '/employee',method: 'put',data: { ...params }})
}
</script>
第二步: 服务端将修改后的员工信息
保存到数据库,然后响应成功的结果状态信息
@PutMapping
public Result<String> update(@RequestBody Employee employee, HttpServletRequest request) {log.info(employee.toString());Long id = (Long) request.getSession().getAttribute("employee");employee.setUpdateUser(id);employee.setUpdateTime(LocalDateTime.now());employeeService.updateById(employee);return Result.success("员工信息修改成功");
}
第三步: 页面Ajax请求的回调函数接收到服务端响应的信息后进行相应处理,调用goBack函数
跳转至员工管理页面
goBack(){window.parent.menuHandle({id: '2',url: '/backend/page/member/list.html',name: '员工管理'},false)
}
填充公共字段
添加/修改员工
数据的时候,都需要指定一下创建人,创建时间,修改人,修改时间
等公共字段,在员工表,菜品表,分类表
等其他表中都拥有的字段
使用MybatisPlus
提供的自动填充功能
将这些公共字段在一个地方统一管理,在插入或者更新的时候为指定字段赋予指定的值
实现步骤
第一步: 在实体类的需要自动填充的属性上方加入@TableFiled注解
并指定自动填充的策略
@Data
public class Employee implements Serializable {private static final long serialVersionUID = 1L;private Long id;private String username;private String name;private String password;private String phone;private String sex;private String idNumber;//身份证号码private Integer status;// 插入时填充字段@TableField(fill = FieldFill.INSERT)private LocalDateTime createTime;// 插入和更新时填充字段@TableField(fill = FieldFill.INSERT_UPDATE)private LocalDateTime updateTime;@TableField(fill = FieldFill.INSERT)private Long createUser;@TableField(fill = FieldFill.INSERT_UPDATE)private Long updateUser;
}
第二步: 按照框架要求编写元数据对象处理器common/MyMetaObjectHandle
在此类中实现插入和更新的方法
并统一对公共字段赋值
- 在MyMetaObjectHandler类中不能获得
HttpSession
对象,所以我们需要使用ThreadLocal
存储当前登录用户的Id
方法名 | 功能 |
---|---|
metaObject(元数据) | 封装了需要执行更新和插入的实体类对象,它提供了setValue方法用来完成字段的填充 |
insertFill(MetaObject metaObject) | 在执行插入语句时对指定的公共字段进行填充 |
updateFill(MetaObject metaObject) | 在执行更新语句时对指定的公共字段进行填充 |
@Component
@Slf4j
public class MyMetaObjectHandler implements MetaObjectHandler {@Overridepublic void insertFill(MetaObject metaObject) {log.info("公共字段自动填充(insert)...");log.info(metaObject.toString());metaObject.setValue("createTime", LocalDateTime.now());metaObject.setValue("updateTime", LocalDateTime.now());}@Overridepublic void updateFill(MetaObject metaObject) {log.info("公共字段自动填充(update)...");log.info(metaObject.toString());metaObject.setValue("updateTime", LocalDateTime.now());}
}
ThreadLocal
对于客户端每次发送的Http请求, 服务端都会创建一个对应的线程来处理
- 在一次请求过程中
LocalCheekFilter中的doFilter-->EmployeeController中的update-->MyMetaObjectHandler中的updateFill
处于同一个线程当中
ThreadLocal
并不是一个Thread(线程)而是Thread的局部变量,主要为每个使用该变量的线程提供独立的变量副本
- 使用ThreadLocal维护变量时每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本
- ThreadLocal为每个线程提供单独一份存储空间,具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外则不能访问
方法名 | 功能 |
---|---|
public void set(T value) | 设置当前线程对应的线程局部变量的值 |
public T get() | 返回当前线程所对应的线程局部变量的值 |
第一步: 新建一个基于ThreadLocal的工具类common/BaseContext
,用于存储和获取当前登录用户的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();}
}
第二步: 在LoginCheckFilter
类中使用request.getSession
获取当前登录用户的Id,然后使用BaseContext工具类
将Id值存到ThreadLocal当中,key是当前线程
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {// 判断用户的登录状态,如果已登录,则直接放行if (request.getSession().getAttribute("employee") != null) {log.info("用户已登录,id为{}", request.getSession().getAttribute("employee"));// 在这里获取一下当前线程的idlong id = Thread.currentThread().getId();log.info("doFilter的线程id为:{}", id);// 从session中获取之前我们存的用户IdLong empId = (Long) request.getSession().getAttribute("employee");// 使用BaseContext工具类将用户的Id存到ThreadLocal当中,key是当前线程BaseContext.setCurrentId(empId);filterChain.doFilter(request, response);return;}
}
第三步: 在MyMetaObjectHandler类中使用BaseContext工具类从当前线程中获取对应登录用户的Id,然后填充到对应表中的字段
@Component
@Slf4j
public class MyMetaObjectHandler implements MetaObjectHandler {// 插入操作自动填充@Overridepublic void insertFill(MetaObject metaObject) {log.info("公共字段填充(create)...");metaObject.setValue("createTime", LocalDateTime.now());metaObject.setValue("updateTime", LocalDateTime.now());// 获取当前线程对应的用户Id,然后设置创建人IdmetaObject.setValue("createUser", BaseContext.getCurrentId());metaObject.setValue("updateUser", BaseContext.getCurrentId());}// 更新操作自动填充@Overridepublic void updateFill(MetaObject metaObject) {log.info("公共字段填充(insert)...");metaObject.setValue("updateTime", LocalDateTime.now());// 设置更新人idmetaObject.setValue("updateUser", BaseContext.getCurrentId());}
}