问题描述
在SpringBoot代码开发中,有时我们要接收的参数甚至有List数组等复杂的参数,而且还是一次接收两张表的参数我们应该如何解决?
模拟场景
书写外卖软件时,有两张表,第一个表记录菜品为dish表,第二个表记录的是菜品的口味为dish_flavor
而添加菜品时则需要一次性存这两张表,而且口味参数还是List
sql代码:
CREATE TABLE `dish` (
`id` BIGINT(20) NOT NULL COMMENT '主键',
`name` VARCHAR(64) COLLATE utf8_bin NOT NULL COMMENT '菜品名称',
`category_id` BIGINT(20) NOT NULL COMMENT '菜品分类id',
`price` DECIMAL(10,2) DEFAULT NULL COMMENT '菜品价格',
`code` VARCHAR(64) COLLATE utf8_bin NOT NULL COMMENT '商品码',
`image` VARCHAR(200) COLLATE utf8_bin NOT NULL COMMENT '图片',
`description` VARCHAR(400) COLLATE utf8_bin DEFAULT NULL COMMENT '描述信息',
`status` INT(11) NOT NULL DEFAULT '1' COMMENT '0 停售 1 起售',
`sort` INT(11) NOT NULL DEFAULT '0' COMMENT '顺序',
`create_time` DATETIME NOT NULL COMMENT '创建时间',
`update_time` DATETIME NOT NULL COMMENT '更新时间',
`create_user` BIGINT(20) NOT NULL COMMENT '创建人',
`update_user` BIGINT(20) NOT NULL COMMENT '修改人',
`is_deleted` INT(11) NOT NULL DEFAULT '0' COMMENT '是否删除',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `idx_dish_name` (`name`)
) ENGINE=INNODB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='菜品管理';
CREATE TABLE `dish_flavor` (
`id` BIGINT(20) NOT NULL COMMENT '主键',
`dish_id` BIGINT(20) NOT NULL COMMENT '菜品',
`name` VARCHAR(64) COLLATE utf8_bin NOT NULL COMMENT '口味名称',
`value` VARCHAR(500) COLLATE utf8_bin DEFAULT NULL COMMENT '口味数据list',
`create_time` DATETIME NOT NULL COMMENT '创建时间',
`update_time` DATETIME NOT NULL COMMENT '更新时间',
`create_user` BIGINT(20) NOT NULL COMMENT '创建人',
`update_user` BIGINT(20) NOT NULL COMMENT '修改人',
`is_deleted` INT(11) NOT NULL DEFAULT '0' COMMENT '是否删除',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=INNODB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='菜品口味关系表';
对应的实体类
/**
菜品
*/
@Data
public class Dish implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
//菜品名称
private String name;
//菜品分类id
private Long categoryId;
//菜品价格
private BigDecimal price;
//商品码
private String code;
//图片
private String image;
//描述信息
private String description;
//0 停售 1 起售
private Integer status;
//顺序
private Integer sort;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
@TableField(fill = FieldFill.INSERT)
private Long createUser;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updateUser;
//是否删除
private Integer isDeleted;
}
/**
菜品口味
*/
@Data
public class DishFlavor implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
//菜品id
private Long dishId;
//口味名称
private String name;
//口味数据list
private String value;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
@TableField(fill = FieldFill.INSERT)
private Long createUser;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updateUser;
//是否删除
private Integer isDeleted;
}
前端添加该菜品的参数
解决方案:
这个时候接收参数就比较复杂了,dish是一条数据,而flavors还是多条数据,所以根据这个接收的参数封装一个另外的实体类,来接收这上面的参数。
使用的是DTO,DTO全称为Data Transfer Object,即数据传输对象,一般用于展示层与服务层之间的数据传输。(简单的是使用实体类直接接收,复杂的要另外封装)
一般将这种另外封装的实体类放在单独的放在dto包下面。上面的showOption参数没有用到暂时分装。
由上面可以看出,List类型的参数数据库也是使用的varchar(500)
实体类也是用的String
并且最后参数传回来也是用引号引着的字符串!!
如果是那种批量删除这种业务,一般传dis=1312413,3123123,321321这种以逗号隔开的参数的话。
1、直接Long[]数组接收,没有什么考究的!
2、使用List集合接收时,需要在List型的参数前面加上@RequestParam,因为List是列表,接收时需要处理一下。
3、直接用String接收,然后调用java的split分离成数组,然后遍历即可。
根据参数重新封装一个类如下:
@Data
public class DishDto extends Dish {//继承了Dish说明属性都继承过来了
//这个就是上面参数的flavors,这个参数比较复杂首先它是一个数组,而且数组里面有两个json,其中json还是name和value
//所以就是使用了DishFlavor类中的name和value
private List<DishFlavor> flavors = new ArrayList<>();
}
然后就可以接收到json数据了,进行Controller操作即可
@PostMapping
public R<String> save(@RequestBody DishDto dishDto){
return null;
}
多张表操作,记得开启事务
首先在启动类加入@EnableTransactionManagement//开启事务的支持
然后你操作的代码方法上加入事务注解,这里我再Service层处理业务,并添加事务!,代码不重要,仅供参考!
@Service
public class DishServiceImpl extends ServiceImpl<DishMapper, Dish> implements DishService {
@Autowired
private DishFlavorService dishFlavorService;
/**
* 新增菜品,同时保存对应的口味数据
* @param dishDto
*/
@Transactional//添加事务
@Override
public void saveWithFlavor(DishDto dishDto) {
//保存菜品的基本信息到菜品表dish
this.save(dishDto);
//DishFlavor当时是直接保存name和value的值时,其它的可以元数据处理器中自己生成,id也是用雪花算法来生成的,
//但是DishFlavor类的dishId是null的,所以要把对应dish类的id存入DishFlavor的dishId中
Long dishId = dishDto.getId();
for(DishFlavor dishFlavor:dishDto.getFlavors()){
dishFlavor.setDishId(dishId);
}
//保存菜品口味数据到菜品口味表dish_flavor
dishFlavorService.saveBatch(dishDto.getFlavors());
}
}