瑞吉外卖业务开发(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