springboot苍穹外卖实战:五、公共字段自动填充(aop切面实现)+新增菜品功能+oss

公共字段自动填充

不足

比起瑞吉外卖中的用自定义元数据类型+mybatisplus的实现,这里使用的是aop切面实现,会麻烦许多,建议升级为mp。

定义好数据库操作类型

sky-common中已经定义好,OperationType。

自定义注解 AutoFill

com.sky.annotation.AutoFill

java 复制代码
/**
 * 自定义注解,用于标识某个方法需要进行功能字段自动填充处理
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {
    //数据库操作类型:UPDATE INSERT
    OperationType value();
}

自定义切面 AutoFillAspect

com.sky.aspect.AutoFillAspect

java 复制代码
@Slf4j
public class AutoFillAspect {
    /**
     * 切入点
     */
    @Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")
    public void autoFillPointCut(){}

    /**
     * 前置通知,在通知中进行公共字段的赋值
     */
    @Before("autoFillPointCut()")
    public void autoFill(JoinPoint joinPoint){
        //可先进行调试,是否能进入该方法 提前在mapper方法添加AutoFill注解
        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();

        /*步骤四:根据当前不同的操作类型,为对应的属性通过反射来赋值。
        之所以不直接通过set等方法赋值,是因为获取到的实体类对象可能不一样。譬如这里该项目就可能为员工或者菜品
        使用set方法需要强转为某个实体类对象。
        */
        if(operationType == OperationType.INSERT){
            try{
                Method setCreateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
                Method setCreateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
                Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
                Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);

                //通过反射为对象属性赋值
                setCreateTime.invoke(entity,now);
                setCreateUser.invoke(entity,currentid);
                setUpdateTime.invoke(entity,now);
                setUpdateUser.invoke(entity,currentid);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        else if(operationType == OperationType.UPDATE) {
            //为2个公共字段赋值
            try {
                Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
                Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);

                //通过反射为对象属性赋值
                setUpdateTime.invoke(entity, now);
                setUpdateUser.invoke(entity, currentid);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
   }
}

在mapper上增加自定义注解autofill

com.sky.mapper.CategoryMapper

java 复制代码
    @AutoFill(value = OperationType.INSERT)
    void insert(Category category);

    @AutoFill(value = OperationType.UPDATE)
    void update(Category category);

com.sky.mapper.EmployeeMapper

java 复制代码
 	@AutoFill(value = OperationType.INSERT)
    void insert(Employee employee);

 	@AutoFill(value = OperationType.UPDATE)
    void update(Employee employee);

删除/注释掉业务层原先为公共字段赋值的语句

com.sky.service.impl.CategoryServiceImpl

java 复制代码
/**
 * 分类业务层
 */
@Service
@Slf4j
public class CategoryServiceImpl implements CategoryService {

    @Autowired
    private CategoryMapper categoryMapper;
    @Autowired
    private DishMapper dishMapper;
    @Autowired
    private SetmealMapper setmealMapper;

    /**
     * 新增分类
     * @param categoryDTO
     */
    public void save(CategoryDTO categoryDTO) {
        Category category = new Category();
        //属性拷贝
        BeanUtils.copyProperties(categoryDTO, category);

        //分类状态默认为禁用状态0
        category.setStatus(StatusConstant.DISABLE);

        //设置创建时间、修改时间、创建人、修改人
//        category.setCreateTime(LocalDateTime.now());
//        category.setUpdateTime(LocalDateTime.now());
//        category.setCreateUser(BaseContext.getCurrentId());
//        category.setUpdateUser(BaseContext.getCurrentId());

        categoryMapper.insert(category);
    }

    /**
     * 分页查询
     * @param categoryPageQueryDTO
     * @return
     */
    public PageResult pageQuery(CategoryPageQueryDTO categoryPageQueryDTO) {
        PageHelper.startPage(categoryPageQueryDTO.getPage(),categoryPageQueryDTO.getPageSize());
        //下一条sql进行分页,自动加入limit关键字分页
        Page<Category> page = categoryMapper.pageQuery(categoryPageQueryDTO);
        return new PageResult(page.getTotal(), page.getResult());
    }

    /**
     * 根据id删除分类
     * @param id
     */
    public void deleteById(Long id) {
        //查询当前分类是否关联了菜品,如果关联了就抛出业务异常
        Integer count = dishMapper.countByCategoryId(id);
        if(count > 0){
            //当前分类下有菜品,不能删除
            throw new DeletionNotAllowedException(MessageConstant.CATEGORY_BE_RELATED_BY_DISH);
        }

        //查询当前分类是否关联了套餐,如果关联了就抛出业务异常
        count = setmealMapper.countByCategoryId(id);
        if(count > 0){
            //当前分类下有菜品,不能删除
            throw new DeletionNotAllowedException(MessageConstant.CATEGORY_BE_RELATED_BY_SETMEAL);
        }

        //删除分类数据
        categoryMapper.deleteById(id);
    }

    /**
     * 修改分类
     * @param categoryDTO
     */
    public void update(CategoryDTO categoryDTO) {
        Category category = new Category();
        BeanUtils.copyProperties(categoryDTO,category);

//        //设置修改时间、修改人
//        category.setUpdateTime(LocalDateTime.now());
//        category.setUpdateUser(BaseContext.getCurrentId());

        categoryMapper.update(category);
    }

    /**
     * 启用、禁用分类
     * @param status
     * @param id
     */
    public void startOrStop(Integer status, Long id) {
        Category category = Category.builder()
                .id(id)
                .status(status)
//                .updateTime(LocalDateTime.now())
//                .updateUser(BaseContext.getCurrentId())
                .build();
        categoryMapper.update(category);
    }

    /**
     * 根据类型查询分类
     * @param type
     * @return
     */
    public List<Category> list(Integer type) {
        return categoryMapper.list(type);
    }
}

com.sky.service.impl.EmployeeServiceImpl

java 复制代码
@Service
public class EmployeeServiceImpl implements EmployeeService {

    @Autowired
    private EmployeeMapper employeeMapper;

    /**
     * 员工登录
     *
     * @param employeeLoginDTO
     * @return
     */
    public Employee login(EmployeeLoginDTO employeeLoginDTO) {
        String username = employeeLoginDTO.getUsername();
        String password = employeeLoginDTO.getPassword();

        //1、根据用户名查询数据库中的数据
        Employee employee = employeeMapper.getByUsername(username);

        //2、处理各种异常情况(用户名不存在、密码不对、账号被锁定)
        if (employee == null) {
            //账号不存在
            throw new AccountNotFoundException(MessageConstant.ACCOUNT_NOT_FOUND);
        }

        //密码比对
        //后端md5加密
        password = DigestUtils.md5DigestAsHex(password.getBytes());
        if (!password.equals(employee.getPassword())) {
            //密码错误
            throw new PasswordErrorException(MessageConstant.PASSWORD_ERROR);
        }

        if (employee.getStatus() == StatusConstant.DISABLE) {
            //账号被锁定
            throw new AccountLockedException(MessageConstant.ACCOUNT_LOCKED);
        }
        System.out.println("password"+password);
        System.out.println("username"+username);
        //3、返回实体对象
        return employee;
    }


    /**
     * 员工登录
     *
     * @param employeeDTO
     * @return
     */
    public void save(EmployeeDTO employeeDTO) {
        Employee employee = new Employee();
        BeanUtils.copyProperties(employeeDTO, employee);

        employee.setStatus(StatusConstant.ENABLE);
        employee.setPassword(DigestUtils.md5DigestAsHex(PasswordConstant.DEFAULT_PASSWORD.getBytes()));

//        employee.setCreateTime(LocalDateTime.now());
//        employee.setUpdateTime(LocalDateTime.now());
//
//        employee.setCreateUser(BaseContext.getCurrentId());
//        employee.setUpdateUser(BaseContext.getCurrentId());

        employeeMapper.insert(employee);
    }

    /**
     * 分页查询
     * @param employeePageQueryDTO
     * @return
     */
    public PageResult pageQuery(EmployeePageQueryDTO employeePageQueryDTO) {
        PageHelper.startPage(employeePageQueryDTO.getPage(),employeePageQueryDTO.getPageSize());
        Page<Employee> page = employeeMapper.pageQuery(employeePageQueryDTO);
        long total = page.getTotal();
        List<Employee> records = page.getResult();
        return new PageResult(total, records);
    }

    /**
     * 启用禁用员工账号
     */
    public void startOrStop(Integer status, Long id){
        Employee employee = Employee.builder()
                        .id(id)
                        .status(status)
                        .build();
        employeeMapper.update(employee);
    }

    /**
     * 根据id查员工
     * @param id
     * @return
     */
    public Employee getById(Long id){
        Employee employee = employeeMapper.getById(id);
        employee.setPassword("****");
        return employee;
    }

    /**
     * 编辑员工
     * @param employeeDTO
     */
    public void update(EmployeeDTO employeeDTO){
        Employee employee = new Employee();
        BeanUtils.copyProperties(employeeDTO, employee);
//        employee.setUpdateTime(LocalDateTime.now());
//        employee.setUpdateUser(BaseContext.getCurrentId());

        employeeMapper.update(employee);
    }
}

新增菜品

接口设计

不懂为什么要设计成逻辑外键,而不是物理外键。

业务规则:

  • 菜品名称必须是唯一的
  • 菜品必须属于某个分类下,不能单独存在
  • 新增菜品时可以根据情况选择菜品的口味
  • 每个菜品必须对应一张图片

oss(两种方式)

https://www.bilibili.com/video/BV1m84y1w7Tb的p147-p149就可以了。

bucket名称是唯一性的,所以很有可能出现"该名称已存在或已被其他占用"的情况,换个名字就好了。


相关推荐
St_Ludwig8 分钟前
C语言 蓝桥杯某例题解决方案(查找完数)
c语言·c++·后端·算法·游戏·蓝桥杯
小叶lr10 分钟前
idea 配置 leetcode插件 代码模版
java·leetcode·intellij-idea
qq_4298565715 分钟前
idea启动服务报错Application run failed
java·ide·intellij-idea
瑞雨溪16 分钟前
java中的this关键字
java·开发语言
supercool719 分钟前
SpringBoot(9)-Dubbo+Zookeeper
spring boot·dubbo·java-zookeeper
vener_21 分钟前
LuckySheet协同编辑后端示例(Django+Channel,Websocket通信)
javascript·后端·python·websocket·django·luckysheet
J不A秃V头A24 分钟前
Redisson 中开启看门狗(watchdog)机制
java·分布式锁·看门狗
草字27 分钟前
uniapp input限制输入负数,以及保留小数点两位.
java·前端·uni-app
李迟28 分钟前
某Linux发行版本无法使用nodejs程序重命名文件问题的研究
java·linux·服务器
MapleLea1f40 分钟前
26届JAVA 学习日记——Day14
java·开发语言·学习·tcp/ip·程序人生·学习方法