【苍穹外卖】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);
}

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

相关推荐
侠客行031712 小时前
Mybatis连接池实现及池化模式
java·mybatis·源码阅读
蛇皮划水怪12 小时前
深入浅出LangChain4J
java·langchain·llm
老毛肚14 小时前
MyBatis体系结构与工作原理 上篇
java·mybatis
风流倜傥唐伯虎14 小时前
Spring Boot Jar包生产级启停脚本
java·运维·spring boot
Yvonne爱编码14 小时前
JAVA数据结构 DAY6-栈和队列
java·开发语言·数据结构·python
Re.不晚14 小时前
JAVA进阶之路——无奖问答挑战1
java·开发语言
你这个代码我看不懂14 小时前
@ConditionalOnProperty不直接使用松绑定规则
java·开发语言
fuquxiaoguang15 小时前
深入浅出:使用MDC构建SpringBoot全链路请求追踪系统
java·spring boot·后端·调用链分析
琹箐15 小时前
最大堆和最小堆 实现思路
java·开发语言·算法
__WanG15 小时前
JavaTuples 库分析
java