个人名片:
博主:酒徒ᝰ.
专栏:瑞吉外卖
个人简介:沉醉在酒中,借着一股酒劲,去拼搏一个未来。
本篇励志:真正的程序员不看参考手册,新手和胆小鬼才会看。
本项目基于B站黑马程序员Java项目实战《瑞吉外卖》,轻松掌握springboot + mybatis plus开发核心技术的真java实战项目。
视频链接【黑马程序员Java项目实战《瑞吉外卖》,轻松掌握springboot + mybatis
plus开发核心技术的真java实战项目】 https://www.bilibili.com/video/BV13a411q753?
点击观看
在页面显示中的输入框查询,删除与停售和起售中的批量与单个。都是在原代码基础上进行修改。不能另写代码,会报错。
因为菜品管理太多了,所有分成三部分来写了。这是第一部分。
分析:dish地址,GET方式,page地址,page,pageSize属性
package com.itheima.reggie.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.reggie.common.R;
import com.itheima.reggie.dto.DishDto;
import com.itheima.reggie.entity.Category;
import com.itheima.reggie.entity.Dish;
import com.itheima.reggie.entity.DishFlavor;
import com.itheima.reggie.service.ICategoryService;
import com.itheima.reggie.service.IDishFlavorService;
import com.itheima.reggie.service.IDishService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.websocket.server.PathParam;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;
/**
*
* 菜品管理 前端控制器
*
*
* @author 酒徒
* @since 2022-09-04
*/
@Slf4j
@RestController
@RequestMapping("/dish")
public class DishController {
@Autowired
private IDishService dishService;
@Autowired
private ICategoryService categoryService;
/**
* 页面呈现
* @param page
* @param pageSize
* @return
*/
@GetMapping("/page")
public R<Page> page(int page, int pageSize){
Page<Dish> pageInfo = new Page<>(page, pageSize);
//查询全部
LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.orderByDesc(Dish::getUpdateTime);
dishService.page(pageInfo, queryWrapper);
return R.success(pageInfo);
}
}
这是发现菜品没有图片,这是缺少文件的上传与下载。
分析:common地址,GET方式,download地址,name属性
在controller模块中新建CommonController类。写文件的上传与下载代码。
package com.itheima.reggie.controller;
import com.itheima.reggie.common.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.websocket.server.PathParam;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
/**
*
* 文件的上传与下载 前端控制器
*
*
* @author 酒徒
* @since 2022-09-04
*/
@Slf4j
@RestController
@RequestMapping("/common")
public class CommonController {
@Value("${reggie.path}")
private String basePath;
/**
* 文件下载——图片在页面显示
* @param name
* @param response
*/
@GetMapping("/download")
public void download(@PathParam("name") String name, HttpServletResponse response){
FileInputStream fileInputStream = null;
ServletOutputStream outputStream = null;
try {
//文件输入流 图片文件的地址
fileInputStream = new FileInputStream(new File(basePath + name));
//文件输出流 将本地图片文件输出到浏览器页面
outputStream = response.getOutputStream();
//设置输出是文件的类型
response.setContentType("image/jpeg");//图片类型
//输出图片文件 以读写的方式
int len = 0;
byte[] buff = new byte[1024];
while((len = fileInputStream.read(buff)) != -1){
outputStream.write(buff, 0 ,len);
outputStream.flush();
}
} catch (IOException e) {
throw new RuntimeException(e);
}finally {
try {
outputStream.close();
fileInputStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
完成后仍然发现一个小问题,那就是菜品分类栏不显示。查看日志发现是categoryId对应的分类名称没有查。
这里就需要结合dish表和category表同时使用,也就是DIshDto,在这个类中包括了所有的dish,也拥有categoryname。
/**
* 页面呈现
* @param page
* @param pageSize
* @return
*/
@GetMapping("/page")
public R<Page> page(int page, int pageSize){
Page<Dish> dishPage = new Page<>(page, pageSize);
Page<DishDto> dishDtoPage = new Page<>(page, pageSize);
//查询全部
LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.orderByDesc(Dish::getUpdateTime);
dishService.page(dishPage, queryWrapper);
//获取dish的所有数据
List<Dish> records = dishPage.getRecords();
//将dish的所有数据拷贝到dishDto中
BeanUtils.copyProperties(dishPage, dishDtoPage);
//使用流的形式给每一个dishDto进行categoryname赋值
List<DishDto> list = records.stream().map((item) -> {//item与dish内容相同
DishDto dishDto = new DishDto();
//1.拷贝dish到dishdto中
BeanUtils.copyProperties(item, dishDto);
//2.根据dish中categoryId在category表中查询name,在赋值给dishDto中的categoryName
LambdaQueryWrapper<Category> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Category::getId, item.getCategoryId());
Category category = categoryService.getOne(wrapper);
//设置dishDto中的categoryName值 先判断category是否为空
if (category != null){
dishDto.setCategoryName(category.getName());
}else {
dishDto.setCategoryName("不存在");
}
return dishDto;
}).collect(Collectors.toList());
dishDtoPage.setRecords(list);
return R.success(dishDtoPage);
}
相对于全部查询来说,多了一个name属性。
比较简单,在查询中添加name是否为空的判断。添加如下内容。
if (name != null){
queryWrapper.like(Dish::getName, name);
}
完整代码为:
package com.itheima.reggie.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.reggie.common.R;
import com.itheima.reggie.dto.DishDto;
import com.itheima.reggie.entity.Category;
import com.itheima.reggie.entity.Dish;
import com.itheima.reggie.entity.DishFlavor;
import com.itheima.reggie.service.ICategoryService;
import com.itheima.reggie.service.IDishFlavorService;
import com.itheima.reggie.service.IDishService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.websocket.server.PathParam;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;
/**
*
* 菜品管理 前端控制器
*
*
* @author 酒徒
* @since 2022-09-04
*/
@Slf4j
@RestController
@RequestMapping("/dish")
public class DishController {
@Autowired
private IDishService dishService;
@Autowired
private ICategoryService categoryService;
/**
* 页面呈现
* @param page
* @param pageSize
* @return
*/
@GetMapping("/page")
public R<Page> page(int page, int pageSize, String name){
Page<Dish> dishPage = new Page<>(page, pageSize);
Page<DishDto> dishDtoPage = new Page<>(page, pageSize);
//查询全部
LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>();
if (name != null){
queryWrapper.like(Dish::getName, name);
}
queryWrapper.orderByDesc(Dish::getUpdateTime);
dishService.page(dishPage, queryWrapper);
//获取dish的所有数据
List<Dish> records = dishPage.getRecords();
//将dish的所有数据拷贝到dishDto中
BeanUtils.copyProperties(dishPage, dishDtoPage);
//使用流的形式给每一个dishDto进行categoryname赋值
List<DishDto> list = records.stream().map((item) -> {//item与dish内容相同
DishDto dishDto = new DishDto();
//1.拷贝dish到dishdto中
BeanUtils.copyProperties(item, dishDto);
//2.根据dish中categoryId在category表中查询name,在赋值给dishDto中的categoryName
LambdaQueryWrapper<Category> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Category::getId, item.getCategoryId());
Category category = categoryService.getOne(wrapper);
//设置dishDto中的categoryName值 先判断category是否为空
if (category != null){
dishDto.setCategoryName(category.getName());
}else {
dishDto.setCategoryName("不存在");
}
return dishDto;
}).collect(Collectors.toList());
dishDtoPage.setRecords(list);
return R.success(dishDtoPage);
}
}
分析:category地址,GET方式,list地址,type属性。
先进行测试,用以下代码进行。
@GetMapping("/list")
public R<String> list(@PathParam("type") String type){
log.info("type:{}",type);
return R.success("");
}
type为菜品和套餐的区分:1 菜品分类 2 套餐分类
从页面中可以分析出,需要补充的为菜品分类和文件上传
菜品分类就是categoryName属性。
/**
* 页面显示——菜品分类显示
* @param type
* @param category
* @return
*/
@GetMapping("/list")
public R<List<Category>> list(@PathParam("type") String type, Category category){
//log.info("type:{}",type);
//查询Category表中的所有name
LambdaQueryWrapper<Category> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Category::getType, type);
queryWrapper.orderByDesc(Category::getUpdateTime);
List<Category> list = categoryService.list(queryWrapper);
return R.success(list);
}
分析:common地址,POST方式,upload地址。
/**
* 文件的下载
* @param file
* @return
*/
@PostMapping("/upload")
public R<String> upload(MultipartFile file){
//1.获取文件名,生成新的名字,确保文件名具有唯一性
//获取文件名
String originalFilename = file.getOriginalFilename();
//获取文件后缀名 .jpg类型
String substring = originalFilename.substring(originalFilename.lastIndexOf("."));
//生成一个新的文件名 唯一性
String fileName = UUID.randomUUID().toString();
//2.设置文件存储地址,若不存在,则生成
File dir = new File(basePath + fileName);
if (!dir.exists()){
dir.mkdirs();
}
//3.将前端传过来的文件存到本地
try {
file.transferTo(dir);
} catch (IOException e) {
throw new RuntimeException(e);
}
return R.success(fileName);
}
分析:dish地址,POST方式
第一次直接进行保存,发现出现一些问题。
@PostMapping
public R<String> dish(@RequestBody DishDto dishDto){
log.info("dishDto:{}",dishDto);//dishDto:DishDto(flavors=[DishFlavor(id=null, dishId=null, name=甜味, value=["无糖","少糖","半糖","多糖","全糖"], createTime=null, updateTime=null, createUser=null, updateUser=null, isDeleted=null)], categoryName=null, copies=null)
dishService.save(dishDto);
return R.success("新增菜品成功");
}
没有保存DishFlavor,也就是各种菜品口味信息。
这些保存方法属于业务操作,最好写在service实现类中,增加代码可读性。
这里和视频中的出入比较大(本人写的较为繁琐),建议参考视频学习。
/**
* 添加菜品
* @param request
* @param dishDto
* @return
*/
@PostMapping
public R<String> dish(HttpServletRequest request, @RequestBody DishDto dishDto){
log.info("dishDto:{}",dishDto);//dishDto:DishDto(flavors=[DishFlavor(id=null, dishId=null, name=甜味, value=["无糖","少糖","半糖","多糖","全糖"], createTime=null, updateTime=null, createUser=null, updateUser=null, isDeleted=null)], categoryName=null, copies=null)
//添加创建时间和修改时间
dishDto.setCreateTime(LocalDateTime.now());
dishDto.setUpdateTime(LocalDateTime.now());
//添加创建人和修改人
Long empId = (Long) request.getSession().getAttribute("employee");
dishDto.setCreateUser(empId);
dishDto.setUpdateUser(empId);
dishService.saveDishFlavor(request, dishDto);
return R.success("新增菜品成功");
}
在IDishService中创建saveDishFlavor方法
package com.itheima.reggie.service;
import com.itheima.reggie.dto.DishDto;
import com.itheima.reggie.entity.Dish;
import com.baomidou.mybatisplus.extension.service.IService;
import javax.servlet.http.HttpServletRequest;
/**
*
* 菜品管理 服务类
*
*
* @author 酒徒
* @since 2022-09-04
*/
public interface IDishService extends IService<Dish> {
void saveDishFlavor(HttpServletRequest request, DishDto dishDto);
}
在IDishServiceImpl中实现方法
package com.itheima.reggie.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.itheima.reggie.dto.DishDto;
import com.itheima.reggie.entity.Dish;
import com.itheima.reggie.entity.DishFlavor;
import com.itheima.reggie.mapper.DishMapper;
import com.itheima.reggie.service.IDishFlavorService;
import com.itheima.reggie.service.IDishService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;
/**
*
* 菜品管理 服务实现类
*
*
* @author 酒徒
* @since 2022-09-04
*/
@Slf4j
@Service
public class DishServiceImpl extends ServiceImpl<DishMapper, Dish> implements IDishService {
@Autowired
private IDishFlavorService dishFlavorService;
@Override
@Transactional
public void saveDishFlavor(HttpServletRequest request, DishDto dishDto) {
//保存dish的基本信息到dish表
this.save(dishDto);
//存储dishId
List<DishFlavor> flavors = dishDto.getFlavors();
flavors = flavors.stream().map((item) -> {
//添加创建时间和修改时间
item.setCreateTime(LocalDateTime.now());
item.setUpdateTime(LocalDateTime.now());
//添加创建人和修改人
Long empId = (Long) request.getSession().getAttribute("employee");
item.setCreateUser(empId);
item.setUpdateUser(empId);
item.setDishId(dishDto.getId());
return item;
}).collect(Collectors.toList());
dishFlavorService.saveBatch(flavors);
}
}