目录
管理端开发
准备工作:
前端
双击nginx.exe运行前端项目
后端
接口文档:使用工具Apifox导入api接口文档,这里给的数据是从YAPI导出的
导入初始化工程:common(公共功能模块)、pojo(处理数据的接收、返回,就是为了更好封装数据)、server(处理接口)
加载maven依赖
yml配置:mysql服务地址、密码
JDK版本: 11
数据库
导入sky.sql脚本
启动后端服务运行
员工相关接口开发
分页查询员工信息
@Override public Result<PageResult> pageEmployee(String name, Integer page, Integer pageSize) { // 开启分页查询 PageHelper.startPage(page, pageSize); // 动态条件查询 Page<Employee> employeeList = employeeMapper.pageEmployee(name); PageResult pageResult = new PageResult(employeeList.getTotal(), employeeList.getResult()); return Result.success(pageResult); }
使用PageHelper工具类开启分页查询,PageHelper会在执行sql前进行拦截并且拼接分页sql,然后进行查询时返回数据类型为Page<>,这样返回的该对象会包含总记录数、总页数、当前页码、每页记录数等分页信息。
禁用员工账号
修改员工信息
public void UpdateStatus(Integer status, Long id) { Employee employee = Employee .builder() .id(id).status(status) .build(); employeeMapper.updateStatus(employee); }
虽然可以直接传入禁用和员工id进行禁用,可将其封装为Entity类再进行修改,这样两个Service就可以调用同一个mapper来完成更新。
新增员工
@Override public void save(EmployeeDTO employeeDTO) { Employee employee = new Employee(); BeanUtils.copyProperties(employeeDTO, employee); String password = DigestUtils.md5DigestAsHex(DEFAULT_PASSWORD.getBytes());// 默认密码进行md5加密 employee.setPassword(password); employee.setStatus(StatusConstant.ENABLE); employee.setCreateTime(LocalDateTime.now()); employee.setUpdateTime(LocalDateTime.now()); employee.setCreateUser(BaseContext.getCurrentId()); employee.setUpdateUser(BaseContext.getCurrentId()); employeeMapper.save(employee); }
可以看到这里有大量重复冗余的代码,就是将当前时间和用户id信息传入进employee。并且在以后的更新和新增操作还要重复写这些代码
解决:AOP
// 枚举类 public enum OperationType { /** * 更新操作 */ UPDATE, /** * 插入操作 */ INSERT } //第一步:自定义注解,用于标识需要进行公共字段填充的方法 //元注解,用于指定被注解的元素类型, 这里指方法 @Target(ElementType.METHOD) //在运行时仍然保留,通过反射机制在运行时获取注解信息。意味着在程序运行过程中,可以使用 Java 的反射 API 来检查某个方法是否被 AutoFill 注解标记,以及获取注解中定义的属性值。 @Retention(RetentionPolicy.RUNTIME) public @interface AutoFill { //定义需要自动填充的字段, 数据库操作的类型 update 、insert OperationType value(); } // 第二步:自定义切面类,用于拦截加入自定义注解的方法 @Aspect @Component @Slf4j public class AutoFillAspect { @Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)") public void autoFillPointCut() { } // 在 autoFillPointCut 所定义的切入点的目标方法执行前执行 @Before("autoFillPointCut()") public void autoFill(JoinPoint joinPoint) { log.info("开始进行数据填充....."); // 获取到当前被拦截的方法上的数据库操作类型 MethodSignature signature = (MethodSignature) joinPoint.getSignature(); // 方法签名对象 AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class); // 获得方法上的注解对象 OperationType operationType = autoFill.value(); // 获得数据库操作类型 // 获取到当前被拦截的方法参数 实体对象 Object[] args = joinPoint.getArgs(); if (args == null || args.length == 0) { return; } Object entity = args[0]; // 准备赋值的数据 LocalDateTime now = LocalDateTime.now(); Long currentId = BaseContext.getCurrentId(); try { if (operationType == OperationType.INSERT) { // 为实体对象各个属性赋值 invokeSetMethod(entity, AutoFillConstant.SET_CREATE_TIME, now); invokeSetMethod(entity, AutoFillConstant.SET_CREATE_USER, currentId); invokeSetMethod(entity, AutoFillConstant.SET_UPDATE_TIME, now); invokeSetMethod(entity, AutoFillConstant.SET_UPDATE_USER, currentId); } else if (operationType == OperationType.UPDATE) { // 为实体对象各个属性赋值 invokeSetMethod(entity, AutoFillConstant.SET_UPDATE_TIME, now); invokeSetMethod(entity, AutoFillConstant.SET_UPDATE_USER, currentId); } } catch (Exception e) { log.error("自动填充数据时发生异常", e); } } private void invokeSetMethod(Object entity, String methodName, Object value) throws Exception { Method method = entity.getClass().getDeclaredMethod(methodName, value.getClass()); method.invoke(entity, value); } } // 第三步:在Mapper的方法加上自定义注解 @AutoFill(value = OperationType.UPDATE) void updateStatus(Employee employee); @AutoFill(value = OperationType.INSERT) void save(Employee employee);
Gitee管理代码
远程仓库
Gitee 官网(https://gitee.com/),点右上角 “+” 选 “新建仓库”,复制 HTTPS 或 SSH 地址。
本地仓库
idea点击 “VCS”,选 “Import into Version Control”→“Create Git Repository”,选项目根目录确认。
关联
点击 “VCS”→“Git”→“Remotes”,点 “+”,“Name” 填 “origin”,“URL” 粘贴 Gitee 复制的地址,测试连接后确认。
提交到本地仓库And推送到远程仓库
提交(Commit) 、推送(Push)
分类接口开发
代码功能基本和员工管理类似,不做概述