目录
一、实现菜品管理批量删除单个删除
1、问题分析
删除多个时这是前端传过来的信息,可以通过字符串用“,”切割变成一个字符串数组,再把数组内的数据转成Long型存入集合中,这时就可以通过mybatisplus提供的批量删除方法实现批量删除和单个删除了
2、代码实现
/**
* 单个删除和批量删除的实现
* @param ids
* @return
*/
@DeleteMapping
//1397850851245600769,1397851668262465537前端传入的数据
public R<String> delete( String ids){
String[] strs= ids.split(",");
List<Long> id = new ArrayList<>();
for (String i :strs){
id.add(Long.parseLong(i));
}
dishService.removeByIds(id);
return R.success("删除成功");
}
}
测试成功
二、实现菜品管理批量停/启售
1、问题分析
删除多个时这是前端传过来的信息,可以通过字符串用“,”切割变成一个字符串数组,再把数组遍历把实体类传给mybatisplus的根据id修改方法
2、代码实现
@PostMapping("/status/{status}")
public R<String> update(@PathVariable Integer status,String ids){
String[] id= ids.split(",");
for(String i: id){
Dish dish = dishService.getById(i);
dish.setStatus(status);
dishService.updateById(dish);
}
;
return R.success("菜品修改成功");
}
测试成功
三、文件的上传
1、分析
2、代码实现
@Slf4j
@RestController
@RequestMapping("/common")
public class CommonController {
//YML中的配置路径
@Value("${reggie.path}")
private String basePath;
//文件上传
@PostMapping("/upload")
//MultipartFile file就是文件上传参数,file必须和浏览器发来的name一致
public R<String> upload(MultipartFile file){
//file 是一个临时文件,需要转存到指定位置,否则请求完成后临时文件会删除
log.info("file:{}",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){
e.printStackTrace();
}
return R.success(fileName);
}
}
3、测试
测试成功
4、不熟练的技术点
1、
2、//指定文件位置 file.transferTo(new File());
3、在yml配置路径并引用
4、获取原始文件名
file.getOriginalFilename();
5、生成随机名
UUID.randomUUID()
6、对文件的操作
四、文件的下载
1、问题分析
查看前端页面,文件上传后调用这个方法
可以查到到参数和链接地址name也就是我们文件上传时候的文件名
2、代码实现
@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){
outputStream.write(bytes,0,len);
outputStream.flush();
}
}catch (Exception e){
e.printStackTrace();
}
}
测试成功
3、不熟练的技术点
对文件的操作,io流。
复习:
3.1异常:
Exception 在开发和调试阶段,都得使用printStackTrace抛出。
finally配合try...catch....使用,不管结果如果最后都会执行funally
try {
read("a.txt");
} catch (FileNotFoundException e) {
//抓取到的是编译期异常 抛出去的是运行期
throw new RuntimeException(e);
} finally {
System.out.println("不管程序怎样,这里都将会被执行。");
}
3.2file
1、
public File(String pathname)
:通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例。-
public File(String parent, String child)
:从父路径名字符串和子路径名字符串创建新的 File实例。 -
public File(File parent, String child)
:从父抽象路径名和子路径名字符串创建新的 File实例。
2、
-
public String getAbsolutePath()
:返回此File的绝对路径名字符串。 -
public String getPath()
:将此File转换为路径名字符串。 -
public String getName()
:返回由此File表示的文件或目录的名称。 -
public long length()
:返回由此File表示的文件的长度。
3、
-
public boolean exists()
:此File表示的文件或目录是否实际存在。 -
public boolean isDirectory()
:此File表示的是否为目录。 -
public boolean isFile()
:此File表示的是否为文件。
4、
-
public boolean createNewFile()
:当且仅当具有该名称的文件尚不存在时,创建一个新的空文件。 -
public boolean delete()
:删除由此File表示的文件或目录。 -
public boolean mkdir()
:创建由此File表示的目录。 -
public boolean mkdirs()
:创建由此File表示的目录,包括任何必需但不存在的父目录。
5、
-
public String[] list()
:返回一个String数组,表示该File目录中的所有子文件或目录。 -
public File[] listFiles()
:返回一个File数组,表示该File目录中的所有的子文件或目录。
3.3IO
FileInputStream fis = new FileInputStream("read.txt"); // 文件中为abcde
// 定义变量,作为有效个数
int len ;
// 定义字节数组,作为装字节数据的容器
byte[] b = new byte[2];
// 循环读取
while (( len= fis.read(b))!=-1) {
// 每次读取后,把数组变成字符串打印
System.out.println(new String(b));
//输出结果:
//ab
//cd
//ed
System.out.println(new String(b,0,len));// len 每次读取的有效字节个数
//输出结果:
//ab
//cd
//e
}
// 关闭资源
fis.close();
五、新增菜品
1、问题分析
需要的表
2、代码实现
2.1回显功能
/**
* 根据条件查询分类数据
* 这里作用是菜品回显
* @param category
* @return
*/
@GetMapping("/list")
public R<List<Category>> list(Category category){
//这里是通过type字段来查询,所以这里只要和tpye对着查询就好了
//条件构造器
LambdaQueryWrapper<Category> queryWrapper = new LambdaQueryWrapper<>();
//添加等值查询条件,字符串判断非空StringUtils.isNotEmpty(),基本数据判断非空!=null
queryWrapper.eq(category.getType()!=null,Category::getType,category.getType());
//添加排序条件
queryWrapper.orderByDesc(Category::getSort).orderByDesc(Category::getUpdateTime);
//
List<Category> list = categoryService.list(queryWrapper);
return R.success(list);
}
测试成功
2.2新增功能(复习时候特意看一下)
这里是同时对两个表进行了接收处理,要怎么实现呢?
通过DTO来对两个表进行封装
@Data
public class DishDto extends Dish {
private List<DishFlavor> flavors = new ArrayList<>();
private String categoryName;
private Integer copies;
}
在DishServiceImpl里声明方法
public interface DishService extends IService<Dish> {
public void saveWithFlavor(DishDto dishDto);
}
在DishServiceImpl进行处理
@Autowired
private DishFlavorService dishFlavorService;
/**
* 新增菜品,同时保存对应的口味数据
*
* @param dishDto
*/
@Transactional
//通过dishdto将数据分别保存到两个表中
public void saveWithFlavor(DishDto dishDto) {
//保存菜品的基本信息到菜品表dish
this.save(dishDto);
//此时我们还未获取到DishFlavors表中的dishId。那么我们可以通过dto中的列表来传入
//获取到菜品id,这里是dish表中的id
Long dishId = dishDto.getId();//菜品id
//菜品口味,将dish表中的id传给flavors表
List<DishFlavor> flavors = dishDto.getFlavors();
flavors = flavors.stream().map((item) -> {
item.setDishId(dishId);
return item;
//这里是以列表返回
}).collect(Collectors.toList());
//将id和用户输入的数据保存菜品口味数据到菜品口味表dish_flavor
// saveBatch传列表
dishFlavorService.saveBatch(flavors);
}
多表处理添加事务
DishServiceImpl添加 @Transactional注解
运行类中添加@EnableTransactionManagement注解
在controller层中调用
@PostMapping
public R<String> save(@RequestBody DishDto dishDto){
log.info(dishDto.toString());
dishService.saveWithFlavor(dishDto);
return R.success("新增菜品成功");
}
3、测试
测试成功
六、实现菜品管理中的分页功能
1、问题分析
前面已经问题分析过类似的了这里就不分析了
2、代码实现
@GetMapping("/page")
public R<Page> page(int page, int pageSize,String name) {
//构造分页构造器
Page pageInfo = new Page(page, pageSize);
//构造条件构造器
LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper();
//通过name查询
queryWrapper.eq(StringUtils.isNotEmpty(name),Dish::getName,name);
//添加排序条件查询
queryWrapper.orderByDesc(Dish::getSort);
//mybatis-plus自带的分页
dishService.page(pageInfo, queryWrapper);
return R.success(pageInfo);
}
3、测试
测试发现有一个字段并不显示
4、问题处理(复习重点看)
这时候发现少了一个字段为展示,这时候应该如何处理呢?
使用dishdto进行两表的数据关联
在service的实现类中进行数据处理
代码实现:
@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(源,拷贝到的对象,忽略的字段);records是内容的列表
//records这里忽略的原因是dishDto中的内容属性和dish中的不同,不能直接拷过去
BeanUtils.copyProperties(pageInfo,dishDtoPage,"records");
//把分页中的内容传回给dish列表
List<Dish> records = pageInfo.getRecords();
//通过流的形式遍历刚获得的内容,处理完成后用DishDto列表接收
List<DishDto> list = records.stream().map((item) -> {
//创建DishDto对象
DishDto dishDto = new DishDto();
//将内容先拷贝过去给这个DishDto对象
BeanUtils.copyProperties(item,dishDto);
//获取分类id,两表具有的相同字段分类id,可通过分类id来查询数据
Long categoryId = item.getCategoryId();//分类id
//根据id查询分类对象
Category category = categoryService.getById(categoryId);
//如果不为空通过查询的信息来获取菜品分类,将菜品分类名传给DishDto
if(category != null){
String categoryName = category.getName();
dishDto.setCategoryName(categoryName);
}
return dishDto;
//将内容收集成列表
}).collect(Collectors.toList());
dishDtoPage.setRecords(list);
return R.success(dishDtoPage);
}
七、修改菜品
1、需求分析
回显
修改
2、代码实现
2.1回显代码
DishService
public DishDto getByIdWithFlavor(Long id);
DishServiceImpl
/**
* 根据id来查询菜品喜喜和口味信息
* @param id
* @return
*/
@Override
public DishDto getByIdWithFlavor(Long id) {
//查询菜品基本信息从dish表查询
Dish dish = this.getById(id);
DishDto dishDto = new DishDto();
BeanUtils.copyProperties(dish,dishDto);
//查询当前菜品对应的口吻信息,从dish_flavor查询
LambdaQueryWrapper<DishFlavor> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(DishFlavor::getDishId,dish.getId());
List<DishFlavor> flavers = dishFlavorService.list(queryWrapper);
dishDto.setFlavors(flavers);
return dishDto;
}
DishController
/**
* 根据id来查询菜品信息和口吻信息
* @param id
* @return
*/
@GetMapping("/{id}")
public R<DishDto> update(@PathVariable Long id){
DishDto dishDto = dishService.getByIdWithFlavor(id);
return R.success(dishDto);
}
测试成功
2.2修改代码
Service
//更新菜品信息,同时更新口味
public void updateWithFlavor(DishDto dishDto);
ServiceImpl
/**
* 更新菜品信息,同时更新口味
* @param dishDto
*/
@Override
public void updateWithFlavor(DishDto dishDto) {
//更新dish表的信息
this.updateById(dishDto);
//清除口味信息
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);
}
Controller
@PutMapping
public R<String> update(@RequestBody DishDto dishDto){
log.info(dishDto.toString());
dishService.updateWithFlavor(dishDto);
return R.success("菜品修改成功");
}
3、测试
测试成功并且功能实现