同样的新增的话我们也是分成两种,
共同点:
返回值都是只需要一个Result.success就可以了
接受前端的格式都是json格式,所以需要requestbody
1.不需要连接其他表的
传统方法,在service层把各种数据拼接给new出来的employee从而实现到数据库的保存
示例代码:
@Override
public void save(EmployeeDTO employeeDTO) {// 获取当前用户IDLong currentUserId = BaseContext.getCurrentId();// 使用builder流构建Employee对象Employee employee = Employee.builder().username(employeeDTO.getUsername()).password(DigestUtils.md5DigestAsHex(PasswordConstant.DEFAULT_PASSWORD.getBytes())).name(employeeDTO.getName()).phone(employeeDTO.getPhone()).sex(employeeDTO.getSex()).idNumber(employeeDTO.getIdNumber()).createTime(LocalDateTime.now()) // 设置创建时间.updateTime(LocalDateTime.now()) // 设置修改时间.createUser(currentUserId) // 设置创建人.updateUser(currentUserId) // 设置修改人.status(1) // 设置默认状态为启用.build();// 保存到数据库employeeMapper.save(employee);
}
但是我们对于所有的增加和修改方法我们都需要需要记录时间和操作人,就需要用到切面编程
自定义切面注解如下
package com.sky.annotation;import com.sky.enumeration.OperationType;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** 自定义注解,用于标识某个方法需要进行功能字段自动填充处理*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {//数据库操作类型:UPDATE INSERTOperationType value();
}
package com.sky.aspect;import com.sky.annotation.AutoFill;
import com.sky.constant.AutoFillConstant;
import com.sky.context.BaseContext;
import com.sky.enumeration.OperationType;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.time.LocalDateTime;/*** 自定义切面,实现公共字段自动填充处理逻辑*/
@Aspect
@Component
@Slf4j
public class AutoFillAspect {/*** 切入点*/@Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")public void 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();//根据当前不同的操作类型,为对应的属性通过反射来赋值if(operationType == OperationType.INSERT){//为4个公共字段赋值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();}}}
}
service层代码如下
@Override
public void save(EmployeeDTO employeeDTO) {Employee employee = new Employee();// 使用 BeanUtils 复制相同字段的属性BeanUtils.copyProperties(employeeDTO, employee);// 设置默认密码(需要手动设置)employee.setPassword(DigestUtils.md5DigestAsHex(PasswordConstant.DEFAULT_PASSWORD.getBytes()));// 设置默认状态为启用(需要手动设置)employee.setStatus(1);// 保存到数据库employeeMapper.save(employee);
}
//简单的总结一下切面编程的大体逻辑
controller很简单往后传dto就行
Service层进行处理
1.新建实体类用于传给数据库保存
2.将dto的内容复制到实体类里面。:BeanUtils.copyProperties(categoryDTO,category);
3.补充一些实体类里面没有的内容,然后直接交给数据库就行
mapper层的使用@Autofill注解进行拼接插入
数据库直接简单的保存就可以了
@AutoFill(OperationType.INSERT)@Insert("INSERT INTO employee (name, username, password, phone, sex, id_number, status, create_time, update_time, create_user, update_user) " +"VALUES (#{name}, #{username}, #{password}, #{phone}, #{sex}, #{idNumber}, #{status}, #{createTime}, #{updateTime}, #{createUser}, #{updateUser})")void save(Employee employee);
2.需要把前端接受的数据传到两张表的做法
1.Controller层就接受dto就好了然后直接调用service层的方法
示例代码:
//新增菜品
@PostMapping
public Result save(@RequestBody DishDTO dishDTO)
{dishServcice.save(dishDTO);return Result.success();
}
2.service层的话就是首先建立一个实体类,把接受到的dto保存到实体类中,然后的话就是向实体类里面加东西,然后直接把实体类加入到mapper层的一个表里面,不过这里要注意
1.@Autofill推荐在Mapper层里面加入
2.然后的话应为第二张表需要拿到第一表插入数据库里面自动生成的主键,所以的话就是我们需要在第一张表插入的时候加上一个返回主键的语句,然后的话我们在插入第二张表的前面的时间就需要先把拿到主键赋值给第二张表的关联键
这里补充说明一下,前端是不会给后端传来主键的,因为主键是在插入数据库的时候自动生成的
示例代码:
public void save(DishDTO dishDTO) {Dish dish = new Dish();BeanUtils.copyProperties(dishDTO, dish);dish.setStatus(StatusConstant.ENABLE);// 保存菜品dishMapper.save(dish);// 保存口味,设置 dishIddishDTO.getFlavors().forEach(flavor -> flavor.setDishId(dish.getId()));dishFlavorMapper.saveFlavors(dishDTO.getFlavors());
}
两个mapper层
@AutoFill(OperationType.INSERT)
@Insert("insert into dish(category_id, name, price, status, description, image, create_time, update_time, create_user, update_user) " +"values (#{categoryId}, #{name}, #{price}, #{status}, #{description}, #{image}, #{createTime}, #{updateTime}, #{createUser}, #{updateUser})")
@Options(useGeneratedKeys = true, keyProperty = "id")
void save(Dish dish);
@Insert({"<script>","insert into dish_flavor (dish_id, name, value) values ","<foreach collection='flavors' item='flavor' separator=','>","(#{flavor.dishId}, #{flavor.name}, #{flavor.value})","</foreach>","</script>"
})
void saveFlavors(List<DishFlavor> flavors);