1.由于菜品需要上传图片和下载图片即先做文件的上传和下载工作,在这里我用的是阿里云服务器用于图片的上传与下载
a.注册阿里云账号
b.找到对象存储OSS,点击Bucket列表创建Bucket
填写Bucket信息:注意读写权限要改为公共读
这时我把鼠标放到头像上
点击AccessKey管理
选择使用子用户,根据指示进行创建一个AccessKey,这时会得到一对秘钥
c.在项目中先导入依赖包
然后创建一个工具类
/**
* OSS文件上传工具类
*/
public class OSSUtils{
// Endpoint以杭州为例,其它Region请按实际情况填写。
private static String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
// 云账号AccessKey有所有API访问权限,建议遵循阿里云安全最佳实践,创建并使用RAM子账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建。
private static String accessKeyId = "秘钥key";//
private static String accessKeySecret = "秘钥密码";
private static String bucketName = "bucket名称";
//目录名
public static String dir = "目录名";
/**
* 文件上传
* @param inputStream
* @param fileName
*/
public static void upload(InputStream inputStream, String fileName){
OSS oss = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
oss.putObject(bucketName,dir + fileName,inputStream);
oss.shutdown();
}
/**
* 文件下载
* @param filename
* @param response
* @throws IOException
*/
public static void download(String filename, HttpServletResponse response) throws IOException {
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
// 调用ossClient.getObject返回一个OSSObject实例,该实例包含文件内容及文件元信息。
OSSObject ossObject = ossClient.getObject(bucketName, dir+filename);
//通过输出流,输出文件内容
ServletOutputStream outputStream = response.getOutputStream();
//设置输出文件的格式
response.setContentType("/image/jpeg");
InputStream content = ossObject.getObjectContent();
int len=0;
byte[] bytes = new byte[1024];
while((len = content.read(bytes)) != -1){
outputStream.write(bytes,0,len);
outputStream.flush();
}
content.close();
}
}
创建一个CommonController类用于文件的上传和下载
/**
* 文件上传下载
*/
@RestController
@RequestMapping("/common")
@Slf4j
public class CommonController {
/**
* 文件上传
* @param file
* @return
* @throws IOException
*/
@PostMapping("/upload")
public R<String> upload(MultipartFile file) throws IOException {
//获取文件的原生名字
String originalFilename = file.getOriginalFilename();
//获取后缀
String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
//防止图片名称重复,使用UUID生成名字
String fileName = UUID.randomUUID().toString()+suffix;
InputStream inputStream = file.getInputStream();
OSSUtils.upload(inputStream,fileName);
return R.success(fileName);
}
/**
* 文件下载
* @param name
* @param response
*/
@GetMapping("/download")
public void download(String name, HttpServletResponse response) throws Exception {
OSSUtils.download(name,response);
}
}
2.菜品的新增功能
图片上传,下载成功
分析前端传来的参数,我们需要操作两个表,一个菜品表,一个口味表
我们需要自定义一个方法进行新增菜品 (DishDto是一个实体类继承了Dish实体类同时扩展了一些属性)
完善实现类
/**
* 添加菜品并添加响应的口味
* @param dishDto
*/
@Transactional
public void saveDishWithFlavor(DishDto dishDto) {
//添加菜品到数据库中
this.save(dishDto);
//获取菜品的ID
Long dishId = dishDto.getId();
//将菜品Id添加到flavors中
List<DishFlavor> flavors = dishDto.getFlavors();
flavors = flavors.stream().map((item)->{
item.setDishId(dishId);
return item;
}).collect(Collectors.toList());
//将菜品口味添加到口味表中
dishFlavorService.saveBatch(flavors);
}
在Controller中调用
/**
* 新增菜品实现
* @param dishDto
* @return
*/
@PostMapping
public R<String> save(@RequestBody DishDto dishDto){
log.info(dishDto.toString());
dishService.saveDishWithFlavor(dishDto);
return R.success("添加菜品成功");
}
3.实现菜品分页查询展示
分析前端传来的参数(注意我们有可能会根据菜品名称进行查询)
在Controller中实现
/**
* 菜品分页信息查询
* @param page
* @param pageSize
* @param name
* @return
*/
@GetMapping("/page")
public R<Page> page(int page,int pageSize,String name){
//创建一个分页对象
Page<Dish> pageInfo = new Page<>(page,pageSize);
//构建一个条件构造器
LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>();
//封装条件
queryWrapper.like(StringUtils.isNotEmpty(name),Dish::getName,name);
queryWrapper.eq(Dish::getIsDeleted,0);
//构造排序构造器
queryWrapper.orderByDesc(Dish::getSort).orderByDesc(Dish::getUpdateTime);
dishService.page(pageInfo,queryWrapper);
Page<DishDto> dishDtoPage = new Page<>(page,pageSize);
//对象拷贝
BeanUtils.copyProperties(pageInfo,dishDtoPage,"records");
List<Dish> records = pageInfo.getRecords();
List<DishDto> list = records.stream().map((item) ->{
DishDto dishDto = new DishDto();
//获取分类id
Long categoryId = item.getCategoryId();
//根据id查询分类信息
Category category = categoryService.getById(categoryId);
if(category != null){
String categoryName = category.getName();
dishDto.setCategoryName(categoryName);
}
BeanUtils.copyProperties(item,dishDto);
return dishDto;
}).collect(Collectors.toList());
dishDtoPage.setRecords(list);
return R.success(dishDtoPage);
}
4.实现修改菜品的功能,首先我们需要进行实现数据的回显
分析前端传来的参数
由于我们需要把口味也回显故我们需要操作两张表 ,我们需要自定义方法
进行它的实现类完善
/**
* 根据id查询菜品和口味信息
* @param id
* @return
*/
@Override
public DishDto getByIdWithFlavor(Long id) {
DishDto dishDto = new DishDto();
//根据id查询菜品表
Dish dish = this.getById(id);
BeanUtils.copyProperties(dish,dishDto);
//根据id查询口味表
//创建条件构造器
LambdaQueryWrapper<DishFlavor> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(DishFlavor::getDishId,id);
List<DishFlavor> list = dishFlavorService.list(queryWrapper);
if(list != null || list.size() >0){
dishDto.setFlavors(list);
}
return dishDto;
}
在Controller中进行调用
/**
* 获取菜品信息用于回显
* @param id
* @return
*/
@GetMapping("/{id}")
public R<DishDto> getById(@PathVariable Long id){
DishDto dishDto = dishService.getByIdWithFlavor(id);
return R.success(dishDto);
}
接下来进行菜品的更新操作
分析前端传来的参数(可以用一个DishDto实体类进行接收JSON数据)
同样我们也需要操作两张表自定以一个方法
实现类的实现(对于口味表先根据菜品Id进行删除,让后在添加)
/**
* 更新菜品实现
* @param dishDto
*/
@Transactional
public void updateDishWithFlavor(DishDto dishDto) {
//更新菜品表
this.updateById(dishDto);
//根据id删除口味表信息
Long dishId = dishDto.getId();
LambdaQueryWrapper<DishFlavor> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(DishFlavor::getDishId,dishId);
List<DishFlavor> list = dishFlavorService.list(queryWrapper);
if(list != null && list.size() > 0) {
dishFlavorService.remove(queryWrapper);
}
List<DishFlavor> flavors = dishDto.getFlavors();
if(flavors != null && flavors.size() > 0){
//根据id添加口味表信息
flavors = flavors.stream().map((item) ->{
item.setDishId(dishDto.getId());
return item;
}).collect(Collectors.toList());
dishFlavorService.saveBatch(flavors);
}
}
Controller的调用
/**
* 更新菜品实现
* @param dishDto
* @return
*/
@PutMapping
public R<String> update(@RequestBody DishDto dishDto){
//log.info(dishDto.toString());
dishService.updateDishWithFlavor(dishDto);
return R.success("更新菜品成功");
}
5.(批量)停售菜品的实现
分析前端传来的参数(ids有可能为多个所以用List接收)
controller的实现
/**
* 停售菜品
* @param ids
* @return
*/
@PostMapping("/status/0")
public R<String> updateStatusIsStop(@RequestParam List<Long> ids){
for (Long id : ids) {
Dish dish = new Dish();
dish.setId(id);
dish.setStatus(0);
dishService.updateById(dish);
}
return R.success("停售菜品成功");
}
6.(批量)起售菜品的实现
Controller实现
/**
* 启售菜品
* @param ids
* @return
*/
@PostMapping("/status/1")
public R<String> updateStatusIsStart(@RequestParam List<Long> ids){
for (Long id : ids) {
Dish dish = new Dish();
dish.setId(id);
dish.setStatus(1);
dishService.updateById(dish);
}
return R.success("启售菜品成功");
}
7.(批量)删除菜品功能的实现
我们删除菜品表对应的信息(一条)和口味表的信息(多条)自定义一个方法
实现类的实现(菜品需要在停售中才能删除)
/**
* 删除套餐以及关联的菜品
* @param ids
*/
@Transactional
public void deleteWithFlavor(List<Long> ids) {
//根据id查询菜品是否是在售状态,select count(*) from dish where id in (ids) and status =1;
LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.in(Dish::getId,ids);
queryWrapper.eq(Dish::getStatus,1);
int count = this.count(queryWrapper);
//如果在售状态,则不能删除,抛一个业务异常
if(count>0){
throw new CustomExepction("菜品正在售卖中,不能删除");
}
//否则删除
this.removeByIds(ids);
//构造条件构造器
LambdaQueryWrapper<DishFlavor> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.in(DishFlavor::getDishId,ids);
//删除套餐关联的菜品
dishFlavorService.remove(lambdaQueryWrapper);
}
Controller的调用
/**
* 删除与批量删除菜品及口味
* @param ids
* @return
*/
@DeleteMapping
public R<String> deleteAll(@RequestParam List<Long> ids){
dishService.deleteWithFlavor(ids);
return R.success("删除菜品成功");
}