练习分类业务
对于分类业务,以同样的操作完成CRUD。只需注意分类包括菜品类和套餐类
提示:
三层架构Controller,Service,Mapper
-
Get
- Page
- LambdaQuerryMapper
- page
-
Post
- @RequestBody
- Service.save
-
Put
-
get
-
put
- updateById
-
-
Delete
- removeById
-
代码
查询
前端的分页查询请求:DET /category/page?page=1&pageSize=10
自下而上创建 实体类 Category→ Mapper→Service → Controller
其他没啥特别的,直接看Controller:
//CategoryController.java @RestController @RequstMapping("/category") @Slf4j public class CategoryController(){ @Autowired private CategorService categoryService; @GetMapping("page") // 对于get请求,直接使用同名变量即可获取参数 public R<Page> page(int page,int pageSize){ Page<Category> pageInfo = new page(page,pageSize); LambdaQuerryWrapper querryWrapper = new LambdaQuerryWrapper<>(); querryWrapper.orderByAsc(Category::getSort); categoryServive.page(pageInfo,querryWrapper); return R.success(pageInfo); } }新增
请求POST /category body中携带json对象
@PostMapping public R<String> save(@RequestBody Category category){ log.info("category:{}",category); categoryService.save(category); return R.success("新增分类成功"); }通过
@RequestBody即可拿到body中的json数据修改
同上
@PutMapping public R<String> save(@RequestBody Category category){ log.info("category:{}",category); categoryService.update(category); return R.success("新增分类成功"); }删除
简单的删除同理:
请求:DELETE /categoty?id=xxx
@DeleteMapping public R<String> delete(Long id){ categoryService.removeById(id); return R.success("删除成功"); }但这样粗暴的删除明显不合适。在接收一个删除请求时,应该先根据id查询该分类下有无关联。当关联了其他餐品和套餐时,不可删除,而要抛出一个异常提示。以下是对该方法的实际优化:
自定义异常
全局异常类:
common下自定义异常类
//CustomException.java
public class CustomException extends RuntimeException{
public CustomException(String message) {
super(message);
}
}
和全局异常处理器
//GlobalExceptionHandler.java
public class GlobalExceptionHandler {
@ExceptionHandler(CustomException.class)
public R<String> exceptionHandler(CustomException ex) {
log.error(ex.getMessage());
return R.error(ex.getMessage());
}
}
-
完整的删除功能
使用这个异常即可实现完整的删除
在Controller层不能直接DeleteByID,需要调用我们自定义的一个remove方法,在service实现
//CategoryController.java delete(id){ service.remove(id); return R.success("成功"); }servie层实现
//CategoryServiceImpl.java @Override public void remove(Long id){ LambdaQueryWrapper<Dish> dishLambdaQueryWrapper = new LambdaQueryWrapper<>(); dishLambdaQueryWrapper.eq(Dish::getCategoryId, id);//条件查询 int count = dishService.count(dishLambdaQueryWrapper); System.out.println("查询关联情况"); if (count > 0) { throw new CustomException("当前分类关联的菜品"); } LambdaQueryWrapper<Setmeal> setMealLambdaQueryWrapper = new LambdaQueryWrapper<>(); setMealLambdaQueryWrapper.eq(Setmeal::getCategoryId, id); count = setMealService.count(setMealLambdaQueryWrapper); if (count > 0){ throw new CustomException("当前分类关联了套餐"); } System.out.printf("无关联,执行删除%d",id); super.removeById(id); }
菜品业务的多表联查
查询—这是一个经典的多表联查案例
和上面不同的是,菜品表没有直接的“分类名称”字段,需要通过“分类id“去分类表中查到该菜品对应的分类名称。然后把我们所需的数据组装成一个新的数据转换层对象DishDto,把这些Dto记录放入Page容器中返回。
创建Dto
//DishDto.java
public class DishDto extends Dish{
private List<DishFlavor> flavors =new ArrayList<>();
private String categoryName;
private Integer copies;
}
Dto分页查询
/**
* 菜品管理的分页查询
*/
@GetMapping("/page")
public R<Page> page(int page, int pageSize, String name){
Page<DishDto> dishDtoPage = new Page<>(); //这是最终的Dto结果对象
//先正常查dish表
//构造分页构造器对象
Page<Dish> pageInfo = new Page<>(page,pageSize);
//条件构造器
LambdaQueryWrapper<Dish> queryWrapper=new LambdaQueryWrapper<>();
//添加过滤条件
//当name不为空时对Dish表的name进行模糊匹配 %name%
queryWrapper.like(name!=null,Dish::getName,name);
//添加排序条件
queryWrapper.orderByDesc(Dish::getUpdateTime);
dishService.page(pageInfo,queryWrapper);
//dish查询结束
//把已有的dish的结果装入DtoPgae,忽略records,因为records要单独处理
BeanUtils.copyProperties(pageInfo,dishDtoPage,"records");
//多表联查的核心操作:取出records,用每一项记录中的id查Category表,把该项record和查出的分类名装入 dot,所有的dto作为List封装进DtoPage.
List<Dish> records = pageInfo.getRecords();
List<DishDto> list = records.stream().map((item)->{
DishDto dishDto = new DishDto();
BeanUtils.copyProperties(item,dishDto);
Long categoryId = item.getCategoryId();
Category category=categoryService.getById(categoryId);
if(category!=null){
String categoryName=category.getName();
dishDto.setCategoryName(categoryName);
}
return dishDto;
}).collect(Collectors.toList());
dishDtoPage.setRecords(list);
return R.success(dishDtoPage);
}
调用dishService.page后,pageInfo已经有了一些基础信息。然后使用
BeanUtils.copyProperties(pageInfo,dishDtoPage,"records");
将pageInfo的属性值复制到dishDtoPage中,忽略records字段
- BeanUtils.copyProperties原型
public static void copyProperties(Object source, Object target, String... ignoreProperties)- 快速复制新对象,省去大量set 和 get调用。
- 赋值还是创建
- 可选参数用于忽略某些字段
map映射:records.stream.map()
-
获取原分页结果作为List
-
创建一个新的List
-
遍历映射
- list.stream.map((item)→{ return }).collect(Collectors.toList());
-
copy:dish→dto
-
从dish的categoryid字段定位到category对象,取出分类名加入到Dto的CategoryName字段
将所有映射结果collect为一个List
文件传输
前端基于form表单的文件上传
form表单
- method=“post”
- enctype=“multipart/form-date/”
后端接
指定一个路径
//CommonController.java
@Value(${reggie.path})
还是一个请求路径的事,Post就完了
注意一下前端的参数名,这里是 “filename”
//CommonController.java
@RestController
@RequestMapping("/commom")
public class CommonController{
@PostMapping("/upload")
public Resulet<String> uploadFile(MultipartFile filename){
String originalFilename = file.getOriginalFilename();
String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
String filename = UUID.randomUUID() + suffix;
File dir = new File(basePath);
if(!dir.exists()){
dir.mkdirs();
}
try{
file.transferTo(new File(basePath+filename));
}catch (IOException e) {
e.printStackTrace();
}
return R.success(filename);
}
}
前端要
发请求:Get /common/download?name=${Response.data}
后端给
/**
* 文件下载,图片回显浏览器
*/
@GetMapping("/download")
public void download(String name, HttpServletResponse response){
try {
//输入流,通过输入流读取文件内容
FileInputStream fileInputStream = new FileInputStream(new File(basePath+name));
//输出流,通过输出流将文件写回浏览器,在浏览器展示图片
ServletOutputStream outputStream = response.getOutputStream();
response.setContentType("image/jpeg");//设置响应的文件类型
int len = 0;
byte[] bytes = new byte[1024];
while ((len = fileInputStream.read(bytes)) != -1){//用while循环一直写,写到-1证明写完了
outputStream.write(bytes,0,len);
outputStream.flush();
}
//关闭资源
outputStream.close();
fileInputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
菜品的增删改查不在赘述,自行练习吧。