瑞吉外卖业务开发(3)

简介: 瑞吉外卖业务开发

瑞吉外卖业务开发(2)https://developer.aliyun.com/article/1530403

需求分析

  • 员工列表页面可以对员工账号进行启用和禁用处理,账号禁用的员工不能登录系统,启用后方可登录系统
  • 需要注意的是,只有管理员(admin用户)可以对其他用户进行启用,禁用操作,所以普通用户登录系统后启用,禁用按钮不显示.


    前端有一个名字为user的模型数据来之前存储的用户信息,如果user是admin也就是登录的用户是管理与,那么将显示禁用与启用信息.

代码开发

在开发业务之前需要把用到的类和接口基本结构准备好

  • 实体类category
  • Mapper接口CategoryMapper
  • 业务层接口CategoryService
  • 业务层实现类CategoryServiceImpl
  • 控制层CategoryController

操作流程

1、页面(backend/page/category/list.html)发送ajax请求,将新增分类窗口输入的数据以json形式提交到服务端

2、服务端Controller接收页面提交的数据并调用Service将数据进行保存

3、Service调用Mapper操作数据库,保存数据

可以发现新增菜品分类和新增套餐分类的请求服务端地址和JSon格式相同,所以服务端只要提供一个方法处理即可

@RestController  
@RequestMapping("/category")  
public class CategoryController {  
    @Autowired  
    private CategoryService categoryService;  
   @PostMapping  
    public R<String > save(@RequestBody Category category){  
    log.info("category{}",category);  
    categoryService.save(category);  
    return R.success("新增分类成功");  
}  
}

删除分类

需求分析

在分类管理列表页面,可以对某个分类进行删除操作。需要注意的是当分类关联了菜品或者套餐时,此分类不允许删除。

代码开发

在开发代码之前,需要梳理一下整个程序的执行过程:

1、页面发送ajax请求,将参数(id)提交到服务端

2、服务端Controller接收页面提交的数据并调用Service删除数据

3、Service调用Mapper操作数据库

@DeleteMapping  
public R<String> delete(Long id){  
    categoryService.removeById(id);  
    return R.success("删除成功")  
}

完善

和菜品和套餐已经连接的分类不能进行删除,因为我们没有设置外键,所以要用代码实现

@DeleteMapping  
public R<String> delete(Long ids){  
   categoryService.remove(ids);  
   return R.success("删除成功");  
}

[!note]

要在service中自己定义方法,而且可以调用别的service的方法

public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category> implements CategoryService {  
    @Autowired  
    private DishService dishService;  
    @Autowired  
    private SetmealService setmealService;  
    @Override  
    public void remove(Long id) {  
        LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>();  
        queryWrapper.eq(Dish::getCategoryId,id);  
        int count = dishService.count(queryWrapper);  
        if (count>0){  
            throw new CustomException("当期分类下关联了菜品,不能删除");  
        }  
        LambdaQueryWrapper<Setmeal> queryWrapper1 = new LambdaQueryWrapper<>();  
        queryWrapper1.eq(Setmeal::getCategoryId,id);  
        int count1 = setmealService.count(queryWrapper1);  
  
        if (count1>0){  
            throw new CustomException("当期分类下关联了套餐,不能删除");  
  
        }  
        //查询当前分类是否关联了菜品,如果已经关联,抛出一个业务异常  
        //查询当前分类是否关联了套餐,如果已经关联,抛出一个业务异常  
//正常删除分类  
        super.removeById(id);  
  
    }  
}

文件上传与下载

文件上传介绍

文件上传,也称为upload,是指将本地图片、视频、音频等文件上传到服务器上,可以供其他用户浏览或下载的过程。文件上传在项目中应用非常广泛,我们经常发微博、发微信朋友圈都用到了文件上传功能。

form表单的要求

  • method=“post” 采用post的方式提交数据
  • enctype=multpart/form-data" 采用multipart格式上传文件
  • type=“file” 使用input的file控件上传

举例

<form method="post" action="/common/upload" enctype="multipart/form-data"><input name="myFile" type="file" />
<input type="submit" value="提交" /></form>

服务端要接收客户端页面上传的文件,通常都会使用Apache的两个组件:

  • commons-fileuplolad
  • commons-io
    Spring框架在spring-web包中对文件上传进行了封装,大大简化了服务端代码,我们只需要在Controller的方法中声明一个MultipartFile类型的参数即可接收上传的文件,例如:
@Slf4j  
@RestController  
@RequestMapping("/common")  
public class CommonController {  
    @Value("/${reggie.path}")  
    private String basePath;  
    @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;  
        //创建一个目录对象  
        File dir = new File(basePath);//判断当前目录是否存在  
        if(!dir.exists()){  
        //目录不存在,需要创建  
            dir.mkdirs();  
        }  
        log.info(basePath+fileName);  
        //file是一个临时文件需要指定保存的位置,否则本次请求完成后文件会被自动删除  
        file.transferTo(new File(basePath+ fileName));  
        return R.success(fileName);  
  
    }  

文件下载

@GetMapping("/download")  
public void download(String  name, HttpServletResponse response){  
  
    try {  
        //输入流,通过输入流读取文件内容  
        FileInputStream fileInputStream = new FileInputStream(basePath+name);  
        //输出流,通过输出流把文件写会浏览器,在浏览器展示图片  
        ServletOutputStream outputStream = response.getOutputStream();  
        int len=0;  
        byte[] bytes = new byte[1024];  
        while ((len=fileInputStream.read(bytes))!=-1){  
            outputStream.write(bytes,0,len);  
            outputStream.flush();  
        }  
        response.setContentType("image/jpeg");  
    } catch (Exception e) {  
        e.printStackTrace();  
    }  
}

新增菜品

需求分析

后台系统中可以管理菜品信息,通过新增功能来添加一个新的菜品,在添加菜品时需要选择当前菜品所属的菜品分类,并且需要上传菜品图片,在移动端会按照菜品分类来展示对应的菜品信息。

数据模型

新增菜品,其实就是将新增页面录入的菜品信息插入到dish表,如果添加了口味做法,还需要向dish_flavor表插入数据。所以在新增菜品时,涉及到两个表:

  • dish菜品表
  • dish_flavor菜品口味表

代码开发

准备工作

实体类DishFlavor(直接从课程资料中导入即可,Dish实体前面课程中已经导入过了)

Mapper接口DishFlavorMapper

业务层接口DishFlavorService

业务层实现类DishFlavorServicelmpl

控制层DishController

在开发代码之前,需要梳理一下新增菜品时前端页面和服务端的交互过程:

1、页面(badkend/page/food/add.html)发送ajax请求,请求服务端获取菜品分类数据并展示到下拉框中[

2、页面发送请求进行图片上传,请求服务端将图片保存到服务器

3、页面发送请求进行图片下载,将上传的图片进行回显

4、点击保存按钮,发送ajax请求,将菜品相关数据以json形式提交到服务端

开发新增菜品功能,其实就是在服务端编写代码去处理前端页面发送的这4次请求即可。

导入dto

@Data  
public class DishDto extends Dish {  
  
    private List<DishFlavor> flavors = new ArrayList<>();  
  
    private String categoryName;  
  
    private Integer copies;  
}

[!danger]

DTO,全称为Data Transfer object,即数据传输对象,一般用于展示层与服务层之间的数据传输.

service

@Autowired  
private DishFlavorService dishFlavorService;  
//添加事务控制  
@Transactional  
@Override  
public void saveWithFlavor(DishDto dishDto) {  
//使用本身的save保存菜品
    this.save(dishDto);  
    Long id = dishDto.getId();  
    List<DishFlavor> flavors = dishDto.getFlavors();  
   flavors=  flavors.stream().map((item)->{  
        item.setDishId(id);  
        return item;  
    }).collect(Collectors.toList());  
  //保存口味信息
    dishFlavorService.saveBatch(flavors);  
}

controller

[[springmvc#9.1、@RequestBody]]

@Autowired  
    private DishService dishService;  
    @Autowired  
    private DishFlavorService dishFlavorService;  
@PostMapping  
    public R<String> save(@RequestBody DishDto dishDto){  
        dishService.saveWithFlavor(dishDto);  
        return R.success("新增菜品成功");  
    }

菜品信息分页查询

系统中的菜品数据很多的时候,如果在一个页面中全部展示出来会显得比较乱,不便于查看,所以一般的系统中都会以分页的方式来展示列表数据。

代码开发

梳理交互流程

在开发代码之前,需要梳理一下菜品分页查询时前端页面和服务端的交互过程:

1、页面(backend/page/food/list.html)发送ajax请求,将分页查询参数(page、pageSize、name)提交到服务端,获取分页数据

2、页面发送请求,请求服务端进行图片下载,用于页面图片展示

开发菜品信息分页查询功能,其实就是在服务端编写代码去处理前端页面发送的这2次请求即可。

controller

@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(name!=null,Dish::getName,name);  
 queryWrapper.orderByDesc(Dish::getCreateTime);  
 dishService.page(pageInfo,queryWrapper);  
 return R.success(pageInfo);  
}

但是有个问题

菜品表中的菜品分类字段是分类的id,前端要求的是菜品分类名称,这样才能展示

所以我们要去处理一下

[!note]

因为原本的Dish里面没有categoryName这个属性,所以要借助DishDto,但是如何根据条件把Dto中的categoryName设置成我们需要的值,并且其余Dish有的我们都要有呢,需要先拷贝pageinfo中除了records的数据,(records)s是查询出来的数据列表,并不是我们需要的,需要把records处理好然后放回去,最后返回的是DishDto类型的Page

#工具类/对象拷贝

BeanUtils.copyProperties

controller

@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::getCreateTime);  
     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();  
            //拷贝Dish里面的属性到DishDto  
            BeanUtils.copyProperties(item,dishDto);  
            //查询到分类id  
            Long categoryId = item.getCategoryId();  
            Category category = categoryService.getById(categoryId);  
            //通过分类id查询到分类名称  
            String categoryName = category.getName();  
            dishDto.setCategoryName(categoryName);  
            return  dishDto;  
//最后通过collect收集成集合  
        }).collect(Collectors.toList());  
  
        dishDtoPage.setRecords(list);  
        //最后传回去的DishDto类型的分页信息  
        return R.success(dishDtoPage);  
  
    }

修改菜品

需求分析

在菜品管理列表页面,点击修改按钮,跳转到修改菜品页面,在修改页面回显菜品相关信息并进行修改,最后点金确定按钮完成菜品修改

代码开发

1、页面发送ajax请求,请求服务端获取分类数据,用于菜品分类下拉框中数据展示

2、页面发送ajax请求,请求服务端,根据id查询当前菜品信息,用于菜品信息回显

3、页面发送请求,请求服务端进行图片下载,用于页图片回显

4、点击保存按钮,页面发送ajax请求,将修改后的菜品相关数据以json形式提交到服务端

开发修改菜品功能,其实就是在服务端编写代码去处理前端页面发送的这4次请求即可。

service中自定义查询来完成查询的功能

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;  
}

controller

因为我们要同时返回菜品信息和口味信息,但是这两个表是单独的,我们的dto中包含了我们需要的属性,完成dto的封装需要查询到dish信息和flavor信息然后封装进去返回

@GetMapping("/{id}")  
public R<DishDto> get(@PathVariable Long id){  
    DishDto byIdWithFlavor = dishService.getByIdWithFlavor(id);  
    return R.success(byIdWithFlavor);  
}


瑞吉外卖业务开发(4)https://developer.aliyun.com/article/1530409

相关文章
|
24天前
|
运维 前端开发 测试技术
瑞吉外卖业务开发(1)
瑞吉外卖业务开发
19 3
|
24天前
|
JSON 前端开发 Java
瑞吉外卖业务开发(2)
瑞吉外卖业务开发
23 3
|
24天前
|
JSON 前端开发 安全
瑞吉外卖业务开发(4)
瑞吉外卖业务开发
15 2
|
26天前
|
供应链 安全 数据挖掘
外卖跑腿系统开发详情丨校园外卖跑腿系统开发指南
开发外卖跑腿系统旨在服务于外卖平台和跑腿服务商,实现用户下单、骑手接单及订单管理等功能。系统包括用户端应用(注册、下单、支付等)、商家管理(菜单更新、订单处理)、骑手端应用(任务接收、配送)以及实时订单管理。此外,系统支持多种支付方式、订单结算、评价反馈机制、数据统计报表和客户服务,确保交易安全、提升效率并优化用户体验。
|
SQL 缓存 JSON
瑞吉外卖笔记
这是一份写给自己的笔记,主要记录瑞吉外卖项目中自己没有了解过的知识点。我将按照功能来分别解析
679 1
|
9月前
|
负载均衡 Java 数据库连接
瑞吉外卖项目
瑞吉外卖项目
68 0
|
9月前
|
存储 安全 数据挖掘
外卖跑腿/同城跑腿/校园跑腿/同城配送外卖系统开发规则玩法/案例设计/逻辑方案/需求程序/源码
外卖跑腿、同城跑腿、校园跑腿和同城配送外卖系统开发,是指开发一个用于管理和协调外卖送餐和快递物品的平台或应用程序。该系统能够连接顾客、骑手和商家,提供顾客下单、骑手接单、派送商品等功能。
|
SQL 前端开发 Java
学习瑞吉外卖项目
以当前热门的外卖点餐为业务基础,业务真实、实用、广泛。基于流行的Spring Boot、mybatis plus等技术框架进行开发。 第一天: 设计产品原型。 新建数据库,导入sql文件。
|
前端开发
瑞吉外卖项目(超详细)
新增套餐 在开发业务功能前,先将需要用到的类和接口基本结构创建好: 实体类SetmealDish
|
Java 数据库连接 mybatis
瑞吉外卖项目(超详细)
公共字段自动填充 Mybatis Plus公共字段自动填充,也就是在插入或者更新的时候为指定字段赋予指定的值,使用它的好处就是可以统一对这些字段进行处理,避免了重复代码。 实现步骤: 1、在实体类的属性上加入@TableField注解,指定自动填充的策略 2、按照框架要求编写元数据对象处理器,在此类中统一为公共字段赋值,此类需要实现MetaObjectHandler接口