【苍穹外卖】Day2.5 分类管理

新增分类

页面逻辑

可以看到有俩种选择,可以新增菜品分类以及套餐分类,但是具体的页面逻辑是类似的,所以我们后端处理的时候用的是同样的逻辑

代码开发

我们先定义了实体类Category类,用type字段区分是菜品分类还是套餐分类,其他的信息是无差别的

复制代码
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Category implements Serializable {

    private static final long serialVersionUID = 1L;

    private Long id;

    //类型: 1菜品分类 2套餐分类
    private Integer type;

    //分类名称
    private String name;

    //顺序
    private Integer sort;

    //分类状态 0标识禁用 1表示启用
    private Integer status;

    //创建时间
    private LocalDateTime createTime;

    //更新时间
    private LocalDateTime updateTime;

    //创建人
    private Long createUser;

    //修改人
    private Long updateUser;
}

同样的逻辑,DTO对象接收前端数据,再用对象拷贝,用其他类进行后续操作,这里设置创建时间、修改时间、创建人、修改人,我们先前用AOP+注解的形式实现了自动补全这四个字段,所以这里我们不用再额外写,只需要再mapper方法上面加上@AutoFill注解即可

复制代码
/**
 * 新增分类
 * @param categoryDTO
 */
public void save(CategoryDTO categoryDTO) {
    Category category = new Category();
    //属性拷贝
    BeanUtils.copyProperties(categoryDTO, category);

    //分类状态默认为禁用状态0
    category.setStatus(StatusConstant.DISABLE);

    //设置创建时间、修改时间、创建人、修改人
//        category.setCreateTime(LocalDateTime.now());
//        category.setUpdateTime(LocalDateTime.now());
//        category.setCreateUser(BaseContext.getCurrentId());
//        category.setUpdateUser(BaseContext.getCurrentId());

    categoryMapper.insert(category);
}

分类分页查询

类似于员工分页查询

复制代码
/**
 * 分页查询
 * @param categoryPageQueryDTO
 * @return
 */
public PageResult pageQuery(CategoryPageQueryDTO categoryPageQueryDTO) {
    PageHelper.startPage(
            categoryPageQueryDTO.getPage(),
            categoryPageQueryDTO.getPageSize());
    //下一条sql进行分页,自动加入limit关键字分页
    Page<Category> page = categoryMapper.pageQuery(categoryPageQueryDTO);
    return new PageResult(page.getTotal(), page.getResult());
}

根据类型查询分类

前面的新增菜品分类,可以有俩种选择,菜品和套餐,这里我们可以根据这俩个类型进行查询操作,我们的类别在前面的Category类中是用的type属性辨别的,这里也是如此

这里我们只看SQL语句,需要确保当前分类是启用的,才有可能被查询到,然后用到了动态SQL

复制代码
<select id="list" resultType="Category">
    select * from category
    where status = 1
    <if test="type != null">
        and type = #{type}
    </if>
    order by sort asc,create_time desc
</select>

很重要的一点是,前端项目启动的时候都会先发送一次查询当前所有正在发售的分类,前端会将这些数据保留下面,后续进行操作的时候,会用到这些分类,比如说新增一个菜品的时候,我们需要知道当前有哪些分类,在项目启动的时候发送一次这个请求,可以节省后续的多次请求,同时也可以减少查询负担

根据id删除分类

复制代码
/**
     * 根据id删除分类
     * @param id
     */
public void deleteById(Long id) {
    //查询当前分类是否关联了菜品,如果关联了就抛出业务异常
    Integer count = dishMapper.countByCategoryId(id);
    if(count > 0){
        //当前分类下有菜品,不能删除
        throw new DeletionNotAllowedException(
            MessageConstant.CATEGORY_BE_RELATED_BY_DISH);
    }

    //查询当前分类是否关联了套餐,如果关联了就抛出业务异常
    count = setmealMapper.countByCategoryId(id);
    if(count > 0){
        //当前分类下有菜品,不能删除
        throw new DeletionNotAllowedException(
            MessageConstant.CATEGORY_BE_RELATED_BY_SETMEAL);
    }

    //删除分类数据
    categoryMapper.deleteById(id);
}

这里先检查是否与菜品进行了关联,是否与套餐进行了关联,若有关联则不能删除。我们菜品和套餐在页面中点击新增操作的时候,都必须关联分类,菜品关联菜品分类等,所以这是我们必须要检验后才能进行删除操作的前提。

启用、禁用分类

业务分析

启用和禁用分类,我们需要前端传递一个状态值status,以便于后端直接用这个值进行修改操作,并且我们同时还要前端传递当前操作分类的id,这样我们可以定位这个分类。所以在Path中有status,在Query中有id

代码实现

相应的方式接收前端传递过来的俩个参数

复制代码
/**
 * 启用、禁用分类
 * @param status
 * @param id
 * @return
 */
@PostMapping("/status/{status}")
@ApiOperation("启用禁用分类")
public Result<String> startOrStop(@PathVariable("status") Integer status, Long id){
    categoryService.startOrStop(status,id);
    return Result.success();
}

Service层代码:

前端只传递了状态值以及分类id,我们要做的数据库操作是修改,所以我们还另外需要俩个值,修改人id以及修改时间,将这四个值封装到Category类中,将这个类传递给相应mapper方法进行数据库操作。

这样的操作可以让层间传递数据更加简便,不需要我们在方法上定义很多数据字段

复制代码
/**
 * 启用、禁用分类
 * @param status
 * @param id
 */
public void startOrStop(Integer status, Long id) {
    Category category = Category.builder()
    .id(id)
    .status(status)
    .updateTime(LocalDateTime.now())
    .updateUser(BaseContext.getCurrentId())
    .build();
    categoryMapper.update(category);
}

修改分类

我们注意到路径与之前的一些是相同的,但是方法不同,但是我们依旧可以调用不同的方法。这就是RESTful 规则。总结的说就是同一条 URL 可以表达多种"动作",靠的就是 HTTP 动词(GET/POST/PUT/DELETE...)来区分语义,而不是把动作再写进 URL

前端页面:

代码开发

因为前端穿的数据很多,所以我们依旧使用DTO对象来接收

用一个对象来接收前端参数的时候,会加入这个对象与前端相同名的数据,能对上的就灌,对不上的就忽略"

这个对象可以比前端传递的数据,拥有更多的属性字段,也可以少(但一般不会,会丢失前端传递的数据)

复制代码
/**
 * 修改分类
 * @param categoryDTO
 */
public void update(CategoryDTO categoryDTO) {
    Category category = new Category();
    BeanUtils.copyProperties(categoryDTO,category);

    //设置修改时间、修改人
//        category.setUpdateTime(LocalDateTime.now());
//        category.setUpdateUser(BaseContext.getCurrentId());

    categoryMapper.update(category);
}

核心代码就是对象拷贝,用前端传递的数据去修改。

相关推荐
lixin5565562 小时前
基于神经网络的音乐生成增强器
java·人工智能·pytorch·python·深度学习·语言模型
宫瑾2 小时前
【C语言】嵌入式C加强学习
java·c语言·学习
结衣结衣.2 小时前
protobuf介绍与快速上手
java·服务器·html
时艰.2 小时前
JVM — Java 类加载机制
java·开发语言·jvm
哪里不会点哪里.3 小时前
Spring MVC 核心原理解析:从请求到响应到底发生了什么?
java·spring·mvc
WKP94183 小时前
线程并行控制CompletableFuture
java·开发语言
九皇叔叔3 小时前
application.yml 文件无 Spring 图标 + 无自动提示
java·spring boot·spring
马猴烧酒.4 小时前
JAVA后端用户登录与鉴权详解
java·数据库·sql
乐之者v4 小时前
软件开发常规流程的版本缩写
java