Day-03

文章介绍了如何在Java应用中使用自定义注解和AOP切面来实现在新增和更新数据时,自动填充创建时间和更新时间以及创建者和更新者的ID。具体步骤包括定义自定义注解、创建切面类进行方法拦截和反射赋值,并在Mapper接口的方法上使用注解。
摘要由CSDN通过智能技术生成

公共字段填充

需要解决的问题

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

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

实现步骤

1). 自定义注解 AutoFill,用于标识需要进行公共字段自动填充的方法

自定义注解

/**
 * 自定义注解,用于标识某个方法需要进行功能字段自动填充处理
 */
@Target(ElementType.METHOD)    // 注解只作用于方法上
@Retention(RetentionPolicy.RUNTIME)    // 表示注解的生命周期
public @interface AutoFill {
    // 指定数据库操作类型,UPDATE INSERT
    OperationType value();
}
2). 自定义切面类 AutoFillAspect,统一拦截加入了 AutoFill 注解的方法,通过反射为公共字段赋值

AOP

/**
 * 自定义切面,实现公共字段自动填充处理逻辑
 */
@Aspect
@Component
@Slf4j
public class AutoFillAspect {

    /**
     * 指定切入点
     */
    @Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")     // 切入点是com.sky.mapper包下的带任意参数的所有方法,但是此方法上需要有@AutoFill注解标识
    public void autoFillPointCut() {}

    /**
     * 前置通知,在通知中进行公共字段的赋值
     */
    @Before("autoFillPointCut()")
    public void autoFill(JoinPoint joinPoint) {
        log.info("开始进行公共字段的自动填充...");

        // 获取当前被拦截的方法上的数据库操作类型
//        Signature signature = joinPoint.getSignature();    将Signature转为MethodSignature
        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();

        // 根据当前不同的操作类型,为对应的属性通过反射来赋值
        if (operationType == OperationType.INSERT) {
            // 为4个公共字段赋值
            try {
//                Method setCreateTime = entity.getClass().getDeclaredMethod("setCreateTime", LocalDateTime.class);
                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();
            }
        }
    }
}
3). 在 Mapper 的方法上加入 AutoFill 注解

在具有update和insert操作的mapper的方法上加上@AutoFill注解,并指明value属性的具体值。

新增菜品

文件上传

(暂且存在问题)

新增菜品

service层代码
    @Override
    @Transactional   // 需要先在启动类上开始注解事务
    public void saveWithFlavor(DishDTO dishDTO) {

        Dish dish = new Dish();

        BeanUtils.copyProperties(dishDTO, dish);

        // 向菜品表插入1条数据
        dishMapper.insert(dish);

        // 获取insert语句生成的主键值,在Mapper层的SQL语句上,必须先加上<insert id="insert" useGeneratedKeys="true" keyProperty="id">,指定主键自增
        Long dishId = dish.getId();

        List<DishFlavor> flavors = dishDTO.getFlavors();
        if (flavors != null && flavors.size() > 0) {
            flavors.forEach(dishFlavor -> {
                dishFlavor.setDishId(dishId);
            });
            // 向口味表插入n条数据 批量插入
            dishFlavorMapper.insertBatch(flavors);
        }
    }

分页查询菜品

删除菜品

service层代码

    @Override
    @Transactional
    public void deleteBatch(List<Long> ids) {

        // 判断当前菜品是否能够删除---是否存在启售中的菜品
        for (Long id : ids) {
            Dish dish = dishMapper.getById(id);
            if (dish.getStatus().equals(StatusConstant.ENABLE)) {
                // 当前菜品处于启售中的状态,不能删除
                throw new DeletionNotAllowedException(MessageConstant.DISH_ON_SALE);
            }
        }

        // 判断当前菜品是否能够删除---是否被套餐表关联
        List<Long> setmealIds = setmealDishMapper.getSetmealIdsByDishIds(ids);
        if (setmealIds != null && setmealIds.size() > 0) {
            // 当前菜品被套餐关联了,不能删除
            throw new DeletionNotAllowedException(MessageConstant.DISH_BE_RELATED_BY_SETMEAL);
        }

        // 删除菜品表中的菜品数据
        for (Long id : ids) {
            dishMapper.deleteById(id);
            // 删除菜品关联的口味数据
            dishFlavorMapper.deleteByDishId(id);
        }
    }

修改菜品

service层代码

注意先要进行数据回显,再进行修改,两个接口。

  // 修改菜品信息  
    @Override
    public void updateWithFlavor(DishDTO dishDTO) {
        Dish dish = new Dish();
        BeanUtils.copyProperties(dishDTO, dish);

        // 修改菜品表基本信息
        dishMapper.update(dish);

        // 删除原有的口味数据
        dishFlavorMapper.deleteByDishId(dishDTO.getId());

        // 再重新插入口味数据
        List<DishFlavor> flavors = dishDTO.getFlavors();
        if (flavors != null && flavors.size() > 0) {
            flavors.forEach(dishFlavor -> {
                dishFlavor.setDishId(dishDTO.getId());
            });
            // 向口味表中插入n条数据
            dishFlavorMapper.insertBatch(flavors);
        }
    }

启售/停售菜品

service层代码

    // 跟资料略有一点不同
    @Override
    public void startOrStop(Long id, Integer status) {
        // 进行停售操作
        if (status.equals(StatusConstant.DISABLE)) {
            List<Long> setmealIds = setmealDishMapper.getSetmealIdsByDishId(id);
            // 判断是否有关联的套餐数据,如果有则将该套餐也随之停售。
            if (setmealIds != null && setmealIds.size() != 0)
                setmealIds.forEach(setmealId -> {
                setmealMapper.update(
                        Setmeal.builder()
                                .id(setmealId)
                                .status(StatusConstant.DISABLE)
                                .build()
                );
            });
        }
        Dish dish = Dish.builder()
                .id(id)
                .status(status)
                .build();
        dishMapper.update(dish);
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值