Java项目实战跟练day10——springboot + mybatis plus开发
新增菜品
新增菜品,是将新增页面录入的菜品信息插入到dish表,如果添加了口味做法,还需要向dish_flavor表插入数据。所以新增菜品涉及两个表:菜品表dish、菜品口味表dish flavor
step1创建类和接口等基本结构:
实体类 DishFlavor
Mapper接口 DishFlavorMapper
业务层接口 DishFlavorService
业务层实现类 DishFlavorServicelmpl
控制层 DishController
DishFlavor.java
/**
菜品口味
*/
@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;
}
DishFlavorMapper.java
@Mapper
public interface DishFlavorMapper extends BaseMapper<DishFlavor> {
}
DishFlavorService.java
@Service
public interface DishFlavorService extends IService<DishFlavor> {
}
DishFlavorServicelmpl.java
@Service
public class DishFlavorServicelmpl extends ServiceImpl<DishFlavorMapper,DishFlavor> implements DishFlavorService {
}
前后端交互思路:
1、页面(backend/page/food/add.html)发送ajax请求,请求服务端获取菜品分类数据并展示到下拉框中;
2、页面发送请求进行图片上传,请求服务端将图片保存到服务器;
3、页面发送请求进行图片下载,将上传的图片进行回显;
4、点击保存按钮,发送ajax请求,将菜品相关数据以json形式提交到服务端。
新增菜品功能,其实就是处理前端页面发送的这4次请求即可。
前端代码
request1
this.getDishList()
// 获取菜品分类
getDishList () {
getCategoryList({ 'type': 1 }).then(res => {
if (res.code === 1) {
this.dishList = res.data
} else {
this.$message.error(res.msg || '操作失败')
}
})
},
// 获取菜品分类列表
const getCategoryList = (params) => {
return $axios({
url: '/category/list',
method: 'get',
params
})
}
后端代码实现:
CategoryController.java
/**
* 菜品列表按条件查询
* @param category
*/
@GetMapping("/list")
public R<List<Category>> list(Category category){
log.info("接收的分类类型为:{}",category);
//条件构造器
LambdaQueryWrapper<Category> queryWrapper = new LambdaQueryWrapper<>();
//添加条件
queryWrapper.eq(category.getType()!=null,Category::getType,category.getType());
//添加排序条件
//优先按照sort序号排序,再按照更新时间排序
queryWrapper.orderByDesc(Category::getSort).orderByDesc(Category::getUpdateTime);
List<Category> list = categoryService.list(queryWrapper);
return R.success(list);
}
页面展示:
request2\3
通过文件上传下载已实现
前端代码
request4
通过addDish方法实现新增菜品
submitForm(formName, st) {
this.$refs[formName].validate((valid) => {
if (valid) {
let params = {...this.ruleForm}
// params.flavors = this.dishFlavors
params.status = this.ruleForm ? 1 : 0
params.price *= 100
params.categoryId = this.ruleForm.categoryId
params.flavors = this.dishFlavors.map(obj => ({ ...obj, value: JSON.stringify(obj.value) }))
delete params.dishFlavors
if(!this.imageUrl){
this.$message.error('请上传菜品图片')
return
}
if (this.actionType == 'add') {
delete params.id
addDish(params).then(res => {
if (res.code === 1) {
this.$message.success('菜品添加成功!')
if (!st) {
this.goBack()
} else {
this.dishFlavors = []
// this.dishFlavorsData = []
this.imageUrl = ''
this.ruleForm = {
'name': '',
'id': '',
'price': '',
'code': '',
'image': '',
'description': '',
'dishFlavors': [],
'status': true,
categoryId: ''
}
}
} else {
this.$message.error(res.msg || '操作失败')
}
}).catch(err => {
this.$message.error('请求出错了:' + err)
})
} else {
delete params.updateTime
editDish(params).then(res => {
if (res.code === 1) {
this.$message.success('菜品修改成功!')
this.goBack()
} else {
this.$message.error(res.msg || '操作失败')
}
}).catch(err => {
this.$message.error('请求出错了:' + err)
})
}
} else {
return false
}
})
},
// 新增接口
const addDish = (params) => {
return $axios({
url: '/dish',
method: 'post',
data: { ...params }
})
}
由上可以看出,新增菜品时前端上送数据包括两种实体类,由此引入数据传输对象DTO,全称Data Transfer Objiect,一般用于展示层与服务层之间的数据传输。
后端代码:
DishDto .java
@Data
public class DishDto extends Dish {
private List<DishFlavor> flavors = new ArrayList<>();
}
DishService .java
@Service
public interface DishService extends IService<Dish> {
//新增菜品,同时插入菜品对应的口味数据,需要操作两张表:dish、dish_flavor
public void saveWithFlavor(DishDto dishDto);
}
DishServicelmpl .java
@Slf4j
@Service
public class DishServicelmpl extends ServiceImpl<DishMapper, Dish> implements DishService {
@Autowired
private DishFlavorService dishFlavorService;
/**
* 新增菜品,同时保存对应的口味数据
* @param dishDto
*/
/**
* Transactional-->事务管理,需在项目启动类上辅以注解EnableTransactionManagement使用
* 1)放在接口实现类或接口实现方法上,而不是接口类中。
* 2)访问权限:public的方法才起作用。@Transactional 注解应该只被应用到public方法上
*/
@Transactional
public void saveWithFlavor(DishDto dishDto) {
//保存菜品的基本信息到菜品表dish
this.save(dishDto);
//菜品id,因为前端上送的flavor数据中不包含dishId,需从DishDto中取
Long dishId = dishDto.getId();
//菜品口味
List<DishFlavor> flavors = dishDto.getFlavors();
flavors = flavors.stream().map((item) -> {
item.setDishId(dishId);
return item;
}).collect(Collectors.toList());
//保存菜品口味数据到菜品口味表dish_flavor
dishFlavorService.saveBatch(flavors);
}
}
DishController .java
@Controller
@RestController
@Slf4j
@RequestMapping("/dish")
public class DishController {
@Autowired
private DishService dishService;
@Autowired
private DishFlavorService dishFlavorService;
/**
* 新增菜品
* @param dishDto
* @return
*/
@PostMapping
public R<String> addDish(@RequestBody DishDto dishDto){
log.info(dishDto.toString());
dishService.saveWithFlavor(dishDto);
return R.success("新增菜品成功");
}
}
执行此功能,控制台输出SQL语句如下:
分页查询菜品信息
前后端交互思路:
1、页面(backend/page/food/list.html)发送ajax请求,将分页查询参数(page、pageSize、name)提交到服务端,获取分页数据;
2、页面发送请求,请求服务端进行图片下载,用于页面图片展示;
开发菜品信息分页查询功能,其实就是处理前端页面发送的这2次请求即可。
前端代码:
await getDishPage(params).then(res => {
if (String(res.code) === '1') {
this.tableData = res.data.records || []
this.counts = res.data.total
}
}).catch(err => {
this.$message.error('请求出错了:' + err)
})
// 查询列表接口
const getDishPage = (params) => {
return $axios({
url: '/dish/page',
method: 'get',
params
})
}
模拟发送请求:
后端代码
DishController.java
/**
* 分页查询菜品信息
* @param page
* @param pageSize
* @return
*/
@GetMapping("/page")
public R<Page> page(int page, int pageSize,String name){
log.info("菜品分页信息:page={},pageSize={},name={}",page,pageSize,name);
//构建分页构造器
Page pageInfo = new Page(page,pageSize);
//构建条件构造器
LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>();
//添加过滤条件
// queryWrapper.like(!StringUtils.isEmpty(name), Dish::getName,name);
queryWrapper.like(name!=null, Dish::getName,name);
//添加排序条件
queryWrapper.orderByDesc(Dish::getSort).orderByDesc(Dish::getUpdateTime);
//执行查询
dishService.page(pageInfo,queryWrapper);
return R.success(pageInfo);
}
效果展示:
注意要点:
因前端列表中的菜品分类需获取到categoryName字段,但后端只返回categoryId字段。
<el-table-column
prop="categoryName"
label="菜品分类"
></el-table-column>
菜品分类要想正常展示,需作处理,保证前端页面返回DishDto类型的数据:
DishController.java
/**
* 分页查询菜品信息
* @param page
* @param pageSize
* @param name
* @return
*/
@GetMapping("/page")
public R<Page> page(int page, int pageSize,String name){
log.info("菜品分页信息:page={},pageSize={},name={}",page,pageSize,name);
//构建分页构造器
Page<Dish> pageInfo = new Page(page,pageSize);
Page<DishDto> dishDtoPage = new Page(page,pageSize);
//构建条件构造器
LambdaQueryWrapper<Dish> queryWrapper1 = new LambdaQueryWrapper<>();
//添加过滤条件
// queryWrapper.like(!StringUtils.isEmpty(name), Dish::getName,name);
queryWrapper1.like(name!=null, Dish::getName,name);
//添加排序条件
queryWrapper1.orderByDesc(Dish::getSort).orderByDesc(Dish::getUpdateTime);
//执行查询
dishService.page(pageInfo,queryWrapper1);
//对象拷贝
BeanUtils.copyProperties(pageInfo,dishDtoPage,"records");
List<Dish> records = pageInfo.getRecords();
List<DishDto> list = records.stream().map((item)->{
DishDto dishDto = new DishDto();
BeanUtils.copyProperties(item,dishDto);
Long categoryId = item.getCategoryId();//获取分类id
Category category = categoryService.getById(categoryId);//通过id获取分类对象
if(category!=null){
String categoryName = category.getName();
dishDto.setCategoryName(categoryName);
}
return dishDto;
}).collect(Collectors.toList());
dishDtoPage.setRecords(list);
return R.success(dishDtoPage);
}
注意dto的用法!!!