一、公共字段填充
1.1、问题分析
1.2、实现思路
1.3、代码开发
1.3.1、自定义注解
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 INSERT
OperationType value();
}
1.3.2、切面类
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.Signature;
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 ){
//为四个公共字段赋值
try {
//通过反射获得方法
Method setCreatTime = 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 );
//通过反射进行赋值
setCreatTime.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){
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 ();
}
//为两个公共字段赋值
}
}
}
二、新增菜品
2.1、需求分析和设计
2.2、文件上传
1.Controller层
import com.sky.result.Result;
import com.sky.utils.AliOssUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.UUID;
/**
* 通用接口
*/
@RestController
@RequestMapping("/admin/common")
@Slf4j
@Api(tags = "通用接口")
public class CommonController {
@Autowired
private AliOssUtil aliOssUtil;
/**
* 文件上传
* @param file
* @return
*/
@PostMapping("/upload")
@ApiOperation ( "文件上传" )
public Result<String> upload(MultipartFile file){
log.info ( "文件上传,{}",file );
try {
String originalFilename = file.getOriginalFilename ();//获得文件原来的文件名称
//截取原始文件名的后缀
String extension = originalFilename.substring ( originalFilename.lastIndexOf ( "." ) );
//创建新的文件名称
String objectName = UUID.randomUUID ().toString () + extension;
String filePath = aliOssUtil.upload ( file.getBytes (), objectName );
return Result.success (filePath);
} catch (IOException e) {
log.error ( "文件上传失败,{}",e );
}
return Result.error ( "文件上传失败" );
}
}
2.3、新增菜品
1.DishController
/**
* 新增菜品
* @param dishDTO
* @return
*/
@PostMapping
@ApiOperation ( "新增菜品" )
public Result save(@RequestBody DishDTO dishDTO){
log.info ( "新增菜品,{}",dishDTO );
dishService.saveWithFlavor (dishDTO);
return Result.success ();
}
2.DishServiceImlp
/**
* 新增菜品和对应的口味
* @param dishDTO
*/
@Transactional //注解方式的事务管理 操作多张表保证数据的原子性,一致性
@Override
public void saveWithFlavor(DishDTO dishDTO) {
Dish dish = new Dish ();
BeanUtils.copyProperties ( dishDTO,dish );
//向菜品表插入一条数据
dishMapper.insert(dish);
//获取Insert语句生成的主键值
Long dishId = dish.getId ();
//向口味表插入n条数据
List<DishFlavor> flavors = dishDTO.getFlavors ();
if (flavors !=null && flavors.size () >0){
flavors.forEach ( dishFlavor -> dishFlavor.setDishId ( dishId ));
//向口味表插入n条数据
dishFlavorMapper.insertBatch(flavors);
}
3.Mapper
import com.sky.annotation.AutoFill;
import com.sky.dto.DishDTO;
import com.sky.entity.Dish;
import com.sky.enumeration.OperationType;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
@Mapper
public interface DishMapper {
/**
* 根据分类id查询菜品数量
* @param categoryId
* @return
*/
@Select("select count(id) from dish where category_id = #{categoryId}")
Integer countByCategoryId(Long categoryId);
/**
* 修改菜品信息
* @param dishDTO
*/
void updateDish(DishDTO dishDTO);
/**
* 新增菜品
* @param dish
*/
@AutoFill ( OperationType.INSERT )
void insert(Dish dish);
}
import com.sky.entity.DishFlavor;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface DishFlavorMapper {
/**
* 批量插入口味数据
* @param flavors
*/
void insertBatch(List<DishFlavor> flavors);
}
4.XML
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
insert into dish(id,name,category_id,price,image,description,status,create_time,update_time,create_user,update_user)
values(#{id},#{name},#{categoryId},#{price},#{image},#{description},#{status},#{createTime},#{updateTime},#{createUser},#{updateUser})
</insert>
<insert id="insertBatch">
insert into dish_flavor (dish_id,name,value) values
<foreach collection="flavors" item="df" separator=",">
(#{df.dishId},#{df.name},#{df.value})
</foreach>
</insert>
三、菜品分页查询
3.1、需求分析设计
3.2、代码实现
1.Controller
/**
* 菜品分页查询
* @param dishPageQueryDTO
* @return
*/
@ApiOperation ( "菜品分页查询" )
@GetMapping("/page")
public Result<PageResult> dishPageQuery(DishPageQueryDTO dishPageQueryDTO){
log.info ( "分页查询,{}",dishPageQueryDTO );
PageResult pageResult= dishService.dishPageQuery(dishPageQueryDTO);
return Result.success (pageResult);
}
2.Service
/**
* 菜品分页查询
* @param dishPageQueryDTO
* @return
*/
@ApiOperation ( "菜品分页查询" )
@GetMapping("/page")
public Result<PageResult> dishPageQuery(DishPageQueryDTO dishPageQueryDTO){
log.info ( "分页查询,{}",dishPageQueryDTO );
PageResult pageResult= dishService.dishPageQuery(dishPageQueryDTO);
return Result.success (pageResult);
}
3.Mapper
<!--分页查询-->
<select id="dishPageQuery" resultType="com.sky.vo.DishVO">
select d.* ,c.name as categoryName from dish d left outer join category c on d.category_id = c.id
<where>
<if test="name !=null"> and d.name like concat('%',#{name},'%')</if>
<if test="categoryId !=null">and d.category_id =#{categoryId}</if>
<if test="status !=null"> and d.status=#{status}</if>
</where>
order by d.create_time desc
</select>
四、删除菜品
4.1、需求分析与设计
4.2、代码实现
1.Controller层
/**
* 批量删除菜品
* @param ids
* @return
*/
@DeleteMapping
@ApiOperation ( "批量删除菜品" )
public Result delete(@RequestParam List<Long> ids ){
log.info ( "批量删除菜品,{}",ids );
dishService.deleteBatch(ids);
return Result.success ();
}
2.Service层
/**
* 批量删除
* @param ids
*/
@Transactional
@Override
public void deleteBatch(List<Long> ids) {
//判断当前菜品是否能够删除--是否存在起售中的菜品??
for (Long id : ids) {
Dish dish=dishMapper.getById(id);
if (dish.getStatus ()== 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);
}
}
3.Mapper层
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.sky.mapper.SetmealDishMapper">
<!--根据菜品ID查询套餐ID-->
<select id="GetSetmealIdsByDishIds" resultType="java.lang.Long">
select setmeal_id from setmeal_dish where dish_id in
<foreach collection="dishIds" item="dishId" separator="," open="(" close=")">
#{dishId}
</foreach>
</select>
</mapper>
import com.sky.entity.DishFlavor;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface DishFlavorMapper {
/**
* 批量插入口味数据
* @param flavors
*/
void insertBatch(List<DishFlavor> flavors);
/**
* 根据菜品id删除对应的口味数据
* @param dishId
*/
@Delete ( "delete from dish_flavor where dish_id=#{dishId}" )
void deleteByDishId(Long dishId);
}
五、修改菜品
5.1、需求分析设计
5.2、根据ID查询菜品接口开发
service层
/**
* 根据ID查询菜品信息及口味
* @param id
* @return
*/
@Transactional
@Override
public DishVO getById(Long id) {
Dish dish =dishMapper.getById ( id );
List<DishFlavor> flavors = dishFlavorMapper.getFlavor(id);
DishVO dishVO = new DishVO ();
BeanUtils.copyProperties ( dish,dishVO );
dishVO.setFlavors ( flavors );
return dishVO;
}
5.3、修改菜品接口开发
1.Controller层
/**
* 修改菜品信息
* @param dishDTO
* @return
*/
@PutMapping
@ApiOperation ( "修改菜品" )
public Result updateDish(@RequestBody DishDTO dishDTO){
log.info ( "修改菜品,{}",dishDTO );
dishService.updateDish(dishDTO);
return Result.success ();
}
2.Service层
/**
* 修改菜品
* @param dishDTO
*/
@AutoFill ( value = OperationType.UPDATE)
@Override
public void updateDish(DishDTO dishDTO) {
//修改菜品基本信息
Dish dish = new Dish ();
BeanUtils.copyProperties ( dishDTO,dish );
dishMapper.updateDish(dish);
//删除原有的口味数据
dishFlavorMapper.deleteByDishId (dishDTO.getId () );
//重新插入口味数据
List<DishFlavor> flavors = dishDTO.getFlavors ();
if (flavors !=null && flavors.size ()>0){
flavors.forEach ( dishFlavor ->{
dishFlavor.setDishId ( dishDTO.getId () );
} );
dishFlavorMapper.insertBatch ( flavors );
}
}
3.Mapper层
<update id="updateDish">
update dish
<set>
<if test="categoryId !=null">category_id=#{categoryId},</if>
<if test="description !=null">description=#{description},</if>
<if test="id !=null">id =#{id},</if>
<if test="image !=null">image =#{image},</if>
<if test="name !=null">name =#{name},</if>
<if test="price !=null">price =#{price},</if>
<if test="status !=null">status=#{status}</if>
</set>
where id=#{id}
</update>
<insert id="insertBatch">
insert into dish_flavor (dish_id,name,value) values
<foreach collection="flavors" item="df" separator=",">
(#{df.dishId},#{df.name},#{df.value})
</foreach>
</insert>
/**
* 根据菜品id删除对应的口味数据
* @param dishId
*/
@Delete ( "delete from dish_flavor where dish_id=#{dishId}" )
void deleteByDishId(Long dishId);