菜品管理业务开发
文件上传与下载
文件上传
介绍
服务端要接收客户端页面上传的文件,通常都会使用Apache的两个组件
1.commons-file upload
2.commons-io
Spring框架在spring-web包中对文件上传进行了封装。只需要在Controller的方法中声明一个MultipartFile类型的参数即可接受上传的文件
代码实现- @Value("${reggie.path}")
- private String basePath;
- @PostMapping("/upload")
- public R<String> upload(MultipartFile file){
- //file是一个临时文件,需要把他转存到指定文件,否则本次请求完成后会被删除
- log.info("上传的文件{}",file.toString());
- //原始文件名
- String originalFilename = file.getOriginalFilename();
- String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
- //使用uuid重新生成文件名,防止文件名重复造成文件被覆盖
- String fileName = UUID.randomUUID().toString()+suffix;
- //创建一个目录对象
- File dir = new File(basePath);
- //判断当前目录是否存在
- if (!dir.exists()){
- //目录不存在 创建目录
- dir.mkdirs();
- }
- try {
- file.transferTo(new File(basePath+fileName));
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- return R.success(fileName);
- }
复制代码 upload方法里的形参名要保证与前端提交的表单名一致
在yml配置文件中定义路径变量path
文件下载
代码实现
- @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){//len:m每次读取的有效字节数当len=-1表示读取到文件末尾
- outputStream.write(bytes,0,len);//**写出指定长度字节数组**:`write(byte[] b, int off, int len)` ,每次写出从off索引开始,len个字节,
- outputStream.flush();
- }
- outputStream.close();
- fileInputStream.close();
- } catch (FileNotFoundException e) {
- throw new RuntimeException(e);
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
复制代码 新增菜品功能
需求分析
后台系统中可以管理菜品信息,通过新增功能来添加一个新的菜品,在添加菜品时需要选择当前菜品所属菜品分类,并且需要上传菜品图片,在移动端会按照菜品分类来展示对应的菜品信息
数据模型
代码开发
准备工作:
实体类DishFlavor
Mapper接口DishFlavorMapper
业务层接口DishFlavorService
业务层实现类 DishFlavorServicelmpl控制层 DishController
交互过程:
1、页面(backend/page/food/ add.html)发送ajax请求,请求服务端获取菜品分类数据并展示到下拉框中- /**
- *
- * @param category
- * @return
- */
- @GetMapping("/list")
- public R<List<Category>> list(Category category){
- //条件构造器
- LambdaQueryWrapper<Category> queryWrapper = new LambdaQueryWrapper<>();
- queryWrapper.eq(category.getType()!=null,Category::getType,category.getType());
- queryWrapper.orderByAsc(Category::getSort).orderByDesc(Category::getUpdateTime);
- List<Category> list = categoryService.list(queryWrapper);
- return R.success(list);
- }
复制代码
2、页面发送请求进行图片上传,请求服务端将图片保存到服务器
3、页面发送请求进行图片下载,将上传的图片进行回显
4、点击保存按钮,发送ajax请求,将菜品相关数据以json形式提交到服务端
前端提交的json数据与dish实体类不是一一对应,需要定义dishDao类来接受数据
DTO:全称为Data Transfer Object,即数据传输对象,一般用于展示层和服务层之间的数据传输- @Data
- public class DishDto extends Dish {
- private List<DishFlavor> flavors = new ArrayList<>();
- private String categoryName;
- private Integer copies;
- }
复制代码 菜品信息分页查询
代码开发-梳理交互
1、页面(backend/page/food/list.html)发送ajax请求,将分页查询参数(page、pageSize,name)
提交到服务端,获取分页数据
2、页面发送请求,请求服务端进行图片下载,用于页面图片展示
代码实现
- /**
- * 菜品分页查询
- * @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);
- Page<DishDto> dishDtoPage = new Page<>();
- //构造查询构造器对象
- LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>();
- queryWrapper.like(name!=null,Dish::getName,name);
- queryWrapper.orderByDesc(Dish::getUpdateTime);
- dishService.page(pageInfo,queryWrapper);
- //对象拷贝
- 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);
- if (category!=null){
- String categoryName = category.getName();
- dishDto.setCategoryName(categoryName);
- }
- return dishDto;
- }).collect(Collectors.toList());
- dishDtoPage.setRecords(list);
- return R.success(dishDtoPage);
- }
复制代码 前端渲染页面需要categoryName参数。实体类dish中无对应属性,所以不能直接将获取到的pageInfo响应给客户端。再声明泛型为DishDao的Page对象。将pageInfo中的属性拷贝到dishDaoPage中返回给客户端,但由于pageInfo中的records属性中寸的是dish对象,需要单独处理,将records中的dish对象转换为dishDao对象存到新集合中。最后将dishDaoPage返回给前端。
修改菜品
需求分析
在菜品管理列表页面点击修改按钮,跳转到修改菜品页面,在修改页面回显菜品相关信息并进行修改,点击确定按钮完成相关操作
代码实现
页面的回显信息中包含菜品口味,因此服务端应向客户端返回dishDto类型的数据,在dishService中声明getByIdWithFlavor方法,根据id查询菜品信息以及菜品口味信息封装成dishDto对象,返回- @Override
- public DishDto getByIdWithFlavor(Long id) {
- Dish dish = this.getById(id);
- DishDto dishDto = new DishDto();
- BeanUtils.copyProperties(dish,dishDto);
- //查询当前菜品的口味信息
- LambdaQueryWrapper<DishFlavor> queryWrapper = new LambdaQueryWrapper<>();
- queryWrapper.eq(DishFlavor::getDishId,dish.getId());
- List<DishFlavor> list = dishFlavorService.list(queryWrapper);
- dishDto.setFlavors(list);
- return dishDto;
- }
复制代码 调用dishSer中的getByIdWithFlavor方法,将返回值响应给客户端,实现数据回显- @GetMapping("/{id}")
- public R<DishDto> get(@PathVariable Long id){
- DishDto byIdWithFlavor = dishService.getByIdWithFlavor(id);
- return R.success(byIdWithFlavor);
- }
复制代码 将修改后的数据保存到数据库中,需要分别更新菜品表和菜品口味表。
菜品口味表的更新分两步,第一步先将当前口味表中对应的数据删除,再添加客户端提交过来的数据实现数据更新- @Override
- public void updateWithFlavor(DishDto dishDto) {
- //更新dish表基本信息
- this.updateById(dishDto);
- //清理当前菜品口味对应数据-----dishFlavor表对应的删除操作
- LambdaQueryWrapper<DishFlavor> queryWrapper = new LambdaQueryWrapper<>();
- queryWrapper.eq(DishFlavor::getDishId,dishDto.getId());
- dishFlavorService.remove(queryWrapper);
- //添加提交过来的口味数据
- List<DishFlavor> flavors = dishDto.getFlavors();
- flavors = flavors.stream().map((item)->{
- item.setDishId(dishDto.getId());
- return item;
- }).collect(Collectors.toList());
- dishFlavorService.saveBatch(flavors);
- }
复制代码- /**
- * 修改菜品
- * @param dishDto
- * @return
- */
- @PutMapping
- public R<String> update(@RequestBody DishDto dishDto){
- log.info(dishDto.toString());
- dishService.updateWithFlavor(dishDto);
- return R.success("修改菜品成功");
- }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |