瑞吉外卖-分类管理

公共字段填充

在新增过程中,需要设置以下四个字段,在更新的过程中需要设置后两个字段,每次新增(新增员工,菜单等等)时就需要设置。

image-20220722123847207

而这些代码属于重复部分,可以拿出来,不用反复重写。

1
2
3
4
5
6
7
8
9
10
11
//设置创建时间,在实体类中可以看到时间的类型为:LocalDateTime
employee.setCreateTime(LocalDateTime.now());

//设置更新时间
employee.setUpdateTime(LocalDateTime.now());
//设置创建者
//获取目前登录用户的ID,也就是在session中的id
Long userID = (Long)request.getSession().getAttribute("employee");
employee.setCreateUser(userID);
//设置更新者
employee.setUpdateUser(userID);

在mybatisplus中提供了一种方法,公共字段自动填充功能

image-20220722124156125

实体的代码为:

1
2
3
4
5
6
7
8
9
10
11
12

@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime createTime;

@TableField(fill = FieldFill.UPDATE)
private LocalDateTime updateTime;

@TableField(fill = FieldFill.INSERT)
private Long createUser;

@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updateUser;

元数据对象处理器的代码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
/**
* 自定义元数据对象处理器
*/
@Component
public class MyMateObjectandler implements MetaObjectHandler {

/**
* 新增时,自动填充
* @param metaObject
*/
@Override
public void insertFill(MetaObject metaObject) {

//设置创建时间,在实体类中可以看到时间的类型为:LocalDateTime
metaObject.setValue("createTime", LocalDateTime.now());

//设置更新时间
metaObject.setValue("updateTime", LocalDateTime.now());

//设置创建者
metaObject.setValue("createUser", new Long(1));
//设置更新者
metaObject.setValue("updateUser", new Long(1));

}

/**
* 更新时,自动填充
* @param metaObject
*/
@Override
public void updateFill(MetaObject metaObject) {
//设置更新时间
metaObject.setValue("updateTime", LocalDateTime.now());
//设置更新者
metaObject.setValue("updateUser", new Long(1));

}
}

以上代码有问题,就是修改用户的id是写死的,因为不能定义HttpServletRequest,因此这里使用ThreadLocal的方法解决

因为每发送一次http请求,调用方法的线程都是同一个线程,

image-20220722132157000

使用ThreadLocal:

ThreadLocal 是 Java 里一种特殊变量,它是一个线程级别变量,每个线程都有一个 ThreadLocal 就是每个线程都拥有了自己独立的一个变量,竞态条件被彻底消除了,在并发模式下是绝对安全的变量。

可以通过 ThreadLocal value = new ThreadLocal(); 来使用。

会自动在每一个线程上创建一个 T 的副本,副本之间彼此独立,互不影响,可以用 ThreadLocal 存储一些参数,以便在线程中多个方法中使用,用以代替方法传参的做法。

image-20220722132809091

image-20220722133003977

1、BaseContext.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.zlw.reggie.common;

/**
* 基于ThreadLocal封装的工具类
*/
public class BaseContext {
// 线程是作用域,每个线程保存副本
private static ThreadLocal<Long> threadLocal = new ThreadLocal<>();

public static void setCurrentId(Long id){
threadLocal.set(id);
}

public static Long getId(){
return threadLocal.get();
}

}

2、LoginCheckFilter.java中设置登录用户id为:

1
2
3
4
5
6
7
8
9
10
11
//如果是需要拦截的URI,则判断用户是否登录
//1、用户名不为空,证明已经登录,不需要拦截
if (request.getSession().getAttribute("employee")!=null){
log.info("是拦截路径,用户已经登录,id为:{}",request.getSession().getAttribute("employee"));
long empId = (long) request.getSession().getAttribute("employee");

BaseContext.setCurrentId(empId);

filterChain.doFilter(request,response);
return;
}

3、在MyMetaObjectHandler中获取id为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package com.zlw.reggie.common;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.tomcat.jni.Local;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;

/**
* 自定义元数据对象处理器
*/
@Component
public class MyMateObjectandler implements MetaObjectHandler {

/**
* 新增时,自动填充
* @param metaObject
*/
@Override
public void insertFill(MetaObject metaObject) {

//设置创建时间,在实体类中可以看到时间的类型为:LocalDateTime
metaObject.setValue("createTime", LocalDateTime.now());

//设置更新时间
metaObject.setValue("updateTime", LocalDateTime.now());

//设置创建者
metaObject.setValue("createUser", BaseContext.getId());
//设置更新者
metaObject.setValue("updateUser", BaseContext.getId());

}

/**
* 更新时,自动填充
* @param metaObject
*/
@Override
public void updateFill(MetaObject metaObject) {
//设置更新时间
metaObject.setValue("updateTime", LocalDateTime.now());
//设置更新者
metaObject.setValue("updateUser", BaseContext.getId());

}
}

分类管理

新增分类

将分类的基本框架搭建好:

image-20220722140120670

搭建好之后,梳理一下执行的过程:

image-20220722140755401

新增分类的代码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@RestController
@RequestMapping("/category")
public class CategoryController {

@Autowired
private CategoryService categoryService;

@PostMapping
public R<String> add(@RequestBody Category category){
categoryService.save(category);
return R.success("新增菜品类成功");
}

}

分类的分页管理

分类的分页与员工管理页面的分页一样,代码为:

1
2
3
4
5
6
7
8
9
10
11
@GetMapping ("/page")
public R<Page> page(int page, int pageSize){
Page<Category> pageInfo = new Page<>(page, pageSize);

LambdaQueryWrapper<Category> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.orderByAsc(Category::getSort);

categoryService.page(pageInfo,queryWrapper);

return R.success(pageInfo);
}

删除分类

这里面的删除分类,与普通的删除不同,因为分类或套餐里面包含有很多菜品,所以不能直接删除,要判断里面是否包含菜品,如果里面没有菜品则可以正常删除,。但里面如果有菜品,则要进行判断,因此对删除分类要进行完善。

要判断,菜品分类里面有没有菜品,套餐分类里面有没有套餐

image-20220722151107997

重写删除方法,不能用IService中所提供的方法,代码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@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);
}
}

自定义业务异常类:

1
2
3
4
5
6
7
8
/**
* 自定义业务异常类
*/
public class CustomException extends RuntimeException{
public CustomException(String msg){
super(msg);
}
}

在全局异常捕获中加入捕获自定义业务异常类的代码:

1
2
3
4
@ExceptionHandler(CustomException.class)
public R<String> exceptionHandler(CustomException e){
return R.error(e.getMessage());
}

修改分类

代码为:

1
2
3
4
5
6
7
8
/**
* 分类管理的修改功能
*/
@PutMapping
public R<String> update(@RequestBody Category category){
categoryService.updateById(category);
return R.success("修改成功");
}

瑞吉外卖-分类管理
http://example.com/2022/07/22/瑞吉外卖-day02/
作者
zlw
发布于
2022年7月22日
许可协议