1.搭建数据库环境
创建数据库
导入sql文件
2.Maven项目搭建
导入依赖
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>org.example</groupId>
<artifactId>reggie</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.76</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.23</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.4.5</version>
</plugin>
</plugins>
</build>
</project>
配置application.yml
server:
port: 8080
spring:
application:
name: reggie
datasource:
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/reggie?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
username: root
password: 128730
mybatis-plus:
configuration:
#在映射实体或者属性时,将数据库中表名和字段名中的下划线去掉,按照驼峰命名法映射
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
# 主键生成策略
id-type: ASSIGN_ID
ReggieApplication 项目启动测试
package com.reggie.takeout;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@Slf4j //打印日志
@SpringBootApplication
public class ReggieApplication {
public static void main(String[] args) {
SpringApplication.run(ReggieApplication.class, args);
log.info("项目启动成功...");
}
}
3.静态资源导入
设置静态资源访问--映射路径 com.reggie.takeout.config
WebMvcConfig
package com.reggie.takeout.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
@Slf4j
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
log.info("静态资源开始映射...");
registry.addResourceHandler("/backend/**").addResourceLocations("classpath:/backend/");
registry.addResourceHandler("/front/**").addResourceLocations("classpath:/front/");
}
}
测试是否映射成功
输入localhost:8080:/backend/index.html
4.登录功能以及退出功能
登录功能
登录需求分析
1.将页面提交的密码进行MD5加密
2.根据用户名查数据库(查不到返回结果)
3.比对密码(密码错误返回结果)
4.查询员工状态,员工状态禁用下不可登录
5.登录成功,写入session中,返回结果。
完善项目包结构
实体类 employee
package com.reggie.takeout.pojo;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* @Description 员工表
* @Author root
*/
@Data
public class Employee{
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 String createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private String updateTime;
@TableField(fill = FieldFill.INSERT)
private Long createUser;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updateUser;
}
mapper
package com.reggie.takeout.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.reggie.takeout.pojo.Employee;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface EmployeeMapper extends BaseMapper<Employee> {
}
service和serviceImpl
package com.reggie.takeout.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.reggie.takeout.pojo.Employee;
public interface EmployeeService extends IService<Employee> {
}
package com.reggie.takeout.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.reggie.takeout.mapper.EmployeeMapper;
import com.reggie.takeout.pojo.Employee;
import com.reggie.takeout.service.EmployeeService;
import org.springframework.stereotype.Service;
@Service
public class EmployeeServiceImpl extends ServiceImpl<EmployeeMapper, Employee> implements EmployeeService {
}
controller
package com.reggie.takeout.conrtoller;
import com.reggie.takeout.service.EmployeeService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Slf4j
@RestController
@RequestMapping("/employee")
public class EmployeeController {
@Autowired
private EmployeeService employeeService=null;
/**
* 登录功能
* @param request
* @param employee
* @return
*/
@PostMapping("/login")
public R login(HttpServletRequest request, @RequestBody Employee employee){
//将页面提交的密码进行MD5加密
String password = employee.getPassword();
password= DigestUtils.md5DigestAsHex(password.getBytes());
//根据用户名查数据库(查不到返回结果)
LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Employee::getUsername,employee.getUsername());
Employee emp = employeeService.getOne(queryWrapper);
//查不到用户名 返回失败
if (emp==null){
return R.error("登录失败");
}
//比对密码(密码错误返回结果)
if (!emp.getPassword().equals(password)){
return R.error("登录失败");
}
//查询员工状态,员工状态禁用下不可登录
if (emp.getStatus()==0){
return R.error("账户已锁定");
}
request.getSession().setAttribute("employee",emp.getId());
return R.success(emp);
}
}
?配置返回通用结果类
此类是个通用结果类,服务端响应的所有结果最终都会包装成此种类型返回给前端
package com.reggie.takeout.common;
import lombok.Data;
import java.util.HashMap;
import java.util.Map;
/**
* 返回通用类
* @author jekong
* @date 2022/4/22
*/
@Data
public class R<T> {
/** 编码:1成功,0和其它数字为失败*/
private Integer code;
/** 信息返回*/
private String msg;
/** 信息返回数据*/
private T data;
/** 动态数据*/
private Map map = new HashMap();
public static <T> R<T> success(T object) {
R<T> r = new R<T>();
r.data = object;
r.code = 1;
return r;
}
public static <T> R<T> error(String msg) {
R r = new R();
r.msg = msg;
r.code = 0;
return r;
}
public R<T> add(String key, Object value) {
this.map.put(key, value);
return this;
}
}
退出功能
点击退出?
?退出 移除session
//退出
@PostMapping("/logout")
public R<String> loginOut(HttpServletRequest request){
request.getSession().removeAttribute("employee");
return R.success("用户退出成功");
}
分析
点击登录
退出之后 userInfo消失
登录过滤器
步骤:
1.创建自定义过滤器LoginCheckFilter 加入注解@WebFilter
2.在SpringBoot启动类加入注解@ServletComponentScan
3.完善过滤器的处理逻辑
获取本次处理请求的URL
判断本次请求是否需要处理
若不需要,直接放行
判断登陆状态,若已经登陆直接放行
若未登陆则返回未登陆结果
LoginCheckFilter
package com.reggie.takeout.filter;
import com.alibaba.fastjson.JSON;
import com.reggie.takeout.common.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.AntPathMatcher;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Slf4j
@WebFilter(filterName = "LoginCheckFilter",urlPatterns = "/*")
public class LoginCheckFilter implements Filter {
//路径匹配器,支持通配符
public static final AntPathMatcher PATH_MATCHER=new AntPathMatcher();
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request=(HttpServletRequest) servletRequest;
HttpServletResponse response=(HttpServletResponse) servletResponse;
//获取本次处理请求的URL
String requestURI = request.getRequestURI();
log.info("拦截到请求{}",requestURI);
//定义不需要处理的请求路径
String urls[]=new String[]{
"/employee/login",
"/employee/logout",
"/backend/**",
"/front/**"
};
//判断本次请求是否需要处理 方法处理
boolean check = check(urls, requestURI);
//若不需要,直接放行
if (check){
log.info("本次请求{}不需要处理,直接放行...",requestURI);
filterChain.doFilter(request,response);
return;
}
//判断登陆状态,若已经登陆直接放行 获取session
if (request.getSession().getAttribute("employee")!=null){
log.info("用户已登录,id为..."+request.getSession().getAttribute("employee"));
filterChain.doFilter(request,response);
return;
}
//若未登陆则返回未登陆结果,通过输出流方式向客户端页面响应数据
//NOTLOGIN来自于backend/js/request.js 响应拦截器
log.info("用户未登录...");
response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN")));
return;
}
/**
*
* @param urls 不需要处理的路径
* @param requestURL 本次请求的路径
* @return
*/
public boolean check(String urls[],String requestURL){
for (String url:urls){
boolean match = PATH_MATCHER.match(url, requestURL);
if (match){
return true;
}
}
//如果遍历完 没有返回true 证明没有匹配上 返回false
return false;
}
}
前端 request.js通过匹配“NOTLOGIN”进行响应 进行页面跳转
5.新增员工
需求:添加员工信息到员工表 用户名username唯一
步骤:
1.页面发送ajax请求,将新增员工页面输入的数据以json的形式提交到服务器
2.服务端Controller接受数据并调用service,Service调用Mapper操作数据库,保存数据
/**
* 新增员工
* @param request
* @param employee
* @return
*/
@PostMapping
public R<String> addEmployee(HttpServletRequest request,@RequestBody Employee employee){
//设置默认密码 使用md5加密
employee.setPassword(DigestUtils.md5DigestAsHex("123456".getBytes()));
//设置创建时间 更新时间
employee.setCreateTime(String.valueOf(LocalDateTime.now()));
employee.setUpdateTime(String.valueOf(LocalDateTime.now()));
//设置创建者 修改者
Long userId = (Long) request.getSession().getAttribute("employee");
employee.setCreateUser(userId);
employee.setUpdateUser(userId);
//调用service
employeeService.save(employee);
log.info("新增员工信息{}",employee.toString());
return R.success("添加成功");
}
全局异常捕获
由于用户名设置了主键唯一,若员工用户名相同就会报错,解决报错有两种方式。
? ? ? ? 1.try catch捕获
? ? ? ? 2.全局的异常捕获
第一种方式后续捕获类似异常需要大量的重复代码,所以使用第二种
GlobalExceptionHandler
package com.reggie.takeout.common;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.sql.SQLIntegrityConstraintViolationException;
/**
* ControllerAdvice 拦截带有RestController Controller注解的类
* ResponseBody 返回json数据
*/
@ControllerAdvice(annotations = {RestController.class, Controller.class})
@ResponseBody
@Slf4j
public class GlobalExceptionHandler {
/**
* 异常处理方法 @ExceptionHandler处理SQLIntegrityConstraintViolationException异常
* @param exception
* @return
*/
@ExceptionHandler(SQLIntegrityConstraintViolationException.class)
public R<String> exceptionHandler(SQLIntegrityConstraintViolationException exception){
log.info(exception.getMessage());
//错误信息 Duplicate entry 'guwen' for key 'idx_username'
if (exception.getMessage().contains("Duplicate entry ")){
String[] split = exception.getMessage().split(" ");//以空格分隔开
//Duplicate entry 'guwen' for key 'idx_username'对应
//0 1 2 3 4 5
String msg="用户"+split[2]+"已存在";
return R.error(msg);
}
return R.error("未知错误");
}
}
测试
?6.员工信息展示
分析
?
步骤:
1.页面发送Ajax请求,将分页查询参数(page,pagesize,name)提交到服务端
2.服务端Controller接收页面提交的数据并调用查询的数据
3.Service调用Mapper操作数据库,查询分页数据
4.Controller将查询到的分页数据响应到页面
5.页面接收到分页的数据并通过ElementUI的Table组件展示到页面上
配置Mybatis-plus分页插件
package com.reggie.takeout.config;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return mybatisPlusInterceptor;
}
}
controller层
/**
*
* @param page 当前页面
* @param pageSize 页面大小
* @param name 需要查询用户的名称
* @return
*/
@GetMapping("/page")
public R<Page> page(int page, int pageSize, String name){
log.info("page={},pageSize={},name={}",page,pageSize,name);
//1.构造分页构造器
Page pageInfo = new Page(page, pageSize);
//2.构造条件
LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.like(StringUtils.hasText(name),Employee::getName,name);
//3.添加排序 按照账户创建时间排序
queryWrapper.orderByAsc(Employee::getCreateTime);
//4.执行查询
employeeService.page(pageInfo,queryWrapper);
return R.success(pageInfo);
}
启用禁用员工账户
管理员可以对普通用户进行账户启用和禁用,普通用户无相关权限,所以对普通用户不显示启用禁用按钮
页面初始化时获取账户用户名
created() {
this.init()
this.user = JSON.parse(localStorage.getItem('userInfo')).username
},
判断登录账户是否是管理员?
<el-button
type="text"
size="small"
class="delBut non"
@click="statusHandle(scope.row)"
v-if="user === 'admin'"
>
{{ scope.row.status == '1' ? '禁用' : '启用' }}
</el-button>
向后端传递json数据,将要启用禁用的员工id与状态传递给后端
//状态修改
statusHandle (row) {
this.id = row.id
this.status = row.status
this.$confirm('确认调整该账号的状态?', '提示', {
'confirmButtonText': '确定',
'cancelButtonText': '取消',
'type': 'warning'
}).then(() => {
enableOrDisableEmployee({ '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 }
})
}
分析:
1. 页面发送ajax请求,将参数(id、status)提交到服务端
2. 服务端Controller接收页面提交的数据并调用Service更新数据
3. Service调用Mapper操作数据库
?Controller
/**
* 根据id修改用户信息
* @param request
* @param employee
* @return
*/
@PutMapping
public R<String> update(HttpServletRequest request,@RequestBody Employee employee){//if (String(res.code) === '1') 返回json
//获取员工id
Long empId = (Long) request.getSession().getAttribute("employee");
//更新 修改者和修改时间
employee.setUpdateUser(empId);
employee.setUpdateTime(String.valueOf(LocalDateTime.now()));
//执行修改
employeeService.updateById(employee);
return R.success("信息修改成功");
}
问题:
?数据库中的id与前端传递的id不相同,是因为涉及一个JS的精度问题,JS识别Long类型只精确到16位,而ID有19位,导致ID精度丢失。
代码修复
步骤:
1.使用JacksonObjectMapper对JSON数据进行转换
2.在WebConfig配置类中扩展SringMVC的消息转换器,镜像Java对象到JSON数据的转换
?JacksonObjectMapper
package com.reggie.takeout.common;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import org.springframework.stereotype.Component;
import java.math.BigInteger;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;
/**
* 对象映射器:基于jackson将Java对象转为json,或者将json转为Java对象
* 将JSON解析为Java对象的过程称为 [从JSON反序列化Java对象]
* 从Java对象生成JSON的过程称为 [序列化Java对象到JSON]
*/
@Component
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)
.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);
}
}
将id更改为字符串,就不会损失精度,并且修改时间格式?
WebMvcConfig
/**
* 扩展MVC消息转化器
* @param converters
*/
@Override
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
log.info("扩展消息转换器...");
//创建消息转换器
MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
//设置对象转换器 底层使用Jackson将java对象转为json
mappingJackson2HttpMessageConverter.setObjectMapper(new JacksonObjectMapper());
//将上面的消息转换器对象追加到MVC框架的转换器集合中
converters.add(0,mappingJackson2HttpMessageConverter);//添加索引,使优先级最高,不然还是会默认使用自带的转换器
}
7.编辑员工信息
分析:
步骤:
1.点击编辑按钮时,页面跳转到add.html,并在url中携带参数员工ID
2.在add.html页面获取url中的参数员工ID
3.发送ajax请求,请求服务端,同时提交员工id参数
4.服务端接收请求,根据员工id查询员工信息,将员工信息以ison形式响应给页面
5.页面接收服务端响应的ison数据,通过VUE的数据绑定进行员工信息回显
6.点击保存按钮,发送aiax请求,将页面中的员工信息以ison方式提交给服务端
7.服务端接收员工信息,并进行处理,完成后给页面响应
8.页面接收到服务端响应信息后进行相应处理
created() {
this.id = requestUrlParam('id')
this.actionType = this.id ? 'edit' : 'add'
if (this.id) {
this.init()
}
},
//获取url地址上面的参数
function requestUrlParam(argname){
var url = location.href
var arrStr = url.substring(url.indexOf("?")+1).split("&")
for(var i =0;i<arrStr.length;i++)
{
var loc = arrStr[i].indexOf(argname+"=")
if(loc!=-1){
return arrStr[i].replace(argname+"=","").replace("?","")
}
}
return ""
}
// 修改页面反查详情接口
function queryEmployeeById (id) {
return $axios({
url: `/employee/${id}`,
method: 'get'
})
}
员工信息回显
Controller
/**
* 根据id查询员工信息
* @param id
* @return
*/
@GetMapping("/{id}")
public R<Employee> getById(@PathVariable Long id){
log.info("根据id查询员工信息...");
Employee employee = employeeService.getById(id);
if (employee!=null){
return R.success(employee);
}
return R.error("没有查询到相关信息");
}
由于修改和添加都是共用了add.html页面,所以修改操作只需要根据id查找到员工信息然后回显到前端即可,保存功能复用了上面的update方法
8.公共字段自动填充
新增员工时需要设置时间,创建人,修改时间,修改人等字段,在编辑员工的时候也要设置这些字段,这些属于公共的字段可以使用MybatisPlus提供的公共字段填充功能,避免代码重复
步骤:
1.实体类的属性上加入@TableField注解,指定自动填充的策略
2.按照框架编写元数据对象处理器,同一字段赋值,实现MetaObjectHandler接口
3.使用ThreadLocal解决无法获取session中的员工ID的问题
3.1编写BaseContext工具类,基于ThreadLocal封装的工具类
3.2在LoginCheckFilter的doFilter方法中调用BaseContext来设置当前登录用户的id
3.3在MyMetaObjectHandler的方法中调用BaseContext获取登录用户的id
ThreadLocal
ThreadLocal并不是一个Thread,而是Thread的局部变量。当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。ThreadLocal为每个线程提供单独一份存储空间,具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外则不能访问。 ?
我们可以在LogainCheckFilter的doFilter方法中获取当前登录用户id,并调用ThreadLocal的set方法来设置当前线程的线程局部变量的值用户ID,然后使用MyMetaObjectHandler的updateFill方法来获取用户ID
实体类
@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;
MyMetaObjectHandler?
package com.reggie.takeout.common;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
@Component
@Slf4j
public class MyMetaObjectHandler implements MetaObjectHandler {
/**
* 插入操作自动填充
* @param metaObject
*/
@Override
public void insertFill(MetaObject metaObject) {
log.info("公共字段insert自动填充");
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) {
log.info("公共字段update自动填充");
metaObject.setValue("updateTime",LocalDateTime.now());
metaObject.setValue("updateUser",BaseContext.getCurrentId());
}
}
BaseContext
package com.reggie.takeout.common;
/**
* 基于ThreadLocal封装工具类,用于保存和获取当前登录用户id
*/
public class BaseContext{
private static ThreadLocal<Long> threadLocal=new ThreadLocal<Long>();
public static void setCurrentId(Long id){
threadLocal.set(id);
}
public static Long getCurrentId(){
return threadLocal.get();
}
}
CheckLoginFilter
//判断登陆状态,若已经登陆直接放行 获取session
if (request.getSession().getAttribute("employee")!=null){
log.info("用户已登录,id为..."+request.getSession().getAttribute("employee"));
Long empId=(Long)request.getSession().getAttribute("employee");
BaseContext.setCurrentId(empId);
filterChain.doFilter(request,response);
return;
}
|