Administrator
发布于 2026-02-16 / 7 阅读
0
0

苍穹外卖Day2

今天的学习任务:认识项目的结构,熟悉三层架构,并实践开发员工管理模块的功能:新增员工,员工分页查询,禁用和启用员工和修改员工的功能实现。并导入了分类管理模块,为之后的学习打下基础。

项目结构和前置知识

项目结构

苍穹外卖的后端,用的是maven分模块管理:

不同于tlias这种基础的项目,把各种东西都塞在一个模块中显得庞杂紊乱,苍穹外卖实现的是分模块组织项目:

sky-server:

实现三层架构,程序的主体部分,程序运行和处理业务的主要担当。


sky-pojo:

定义实体类。但是与小型项目所有的实体类定义在一个pojo包下并且功能没有明确区分不同,该包下根据不同实体的职责定义了 三种实体:

DTO:data transport object,负责数据传输的对象。用于执行登录等功能时封装和传输数据。

ENTITY:负责封装各种实体数据的对象,传统意义上的plain old java object。包含比如员工,菜品等实体的数据字段定义。

VO:Value Object ,值对象。展示用的数据。负责给前端展示,让人看到。


sky-common:

定义了一些公共类。常量类,异常类,工具类等。比如JwtUtils负责产生jwt令牌用于登录。

通过模块分层,可以更好的管理项目并明确各个类和功能模块的职责,便于掌握项目结构,利于维护和迭代开发。

网络请求

四种网络请求:get,post,put,delete

请求类型

对应功能

形象比喻

GET

获取数据。从服务器索取资源,不修改服务器内容。

翻阅菜单看有什么菜。

POST

提交数据。通常用于创建新资源(如注册账号)。

填写点餐单并交给服务员。

PUT

更新数据。上传新内容替换掉服务器上的旧内容。

换掉整盘菜,重新做一份新的。

PATCH

局部更新。只修改资源的一小部分。

这道菜太咸了,加点糖调味。

DELETE

删除数据。请求服务器删除指定资源。

撤销这个订单。

重要的是理解post和put功能的区别。

维度

POST

PUT

主要功能

创建资源(无 ID)

创建或替换资源(有 ID)

幂等性

(重复请求会产生副作用)

(重复请求结果一致)

资源位置

由服务器定义并在响应头返回

由客户端在 URL 中明确指定

使用频率

极高(几乎所有表单提交)

中等(多用于资源管理、文件上传)

重要的响应码:200,401,500,404

200:响应成功

401:未认证

500:内部服务器错误

404:资源不存在

三层架构

mapper/dao:负责与数据库交互

service:处理数据。接收controller数据和请求传给mapper层,并把mapper的结果处理以后交给controller

controller:负责交互。接收请求并返回结果。

精髓:各司其职、单向依赖。有利于分层解耦,提高代码复用性,助于维护。

员工模块开发

该开发过程在资料对应ppt和视频中有讲解。这里只讲要点。

新增员工

需求:实现往数据库中插入员工信息,要求遵循约束:账号唯一,手机号和身份证合法,默认密码为123456

实现要点:

在执行sql语句时,如果发生冲突导致出现异常,比如员工的用户名重复了,违反唯一约束就会导致抛出异常。不做处理则在前端用户不知道发生了什么。我们要自定义错误处理(ExceptionHandler)捕获错误信息并响应给前端。

对应的dto中没有操作者的id。我们这里通过ThreadLocal获得操作者的id,传给封装新员工信息的对象。ThreadLocal是Java线程中的一种局部变量。ThreadLocal为每个线程提供一份单独的存储空间,具有线程隔离的效果,不同的线程之间不会相互干扰。通过它,我们可以从请求头中的jwt令牌获取当前操作者的id。

员工分页查询

需求:把员工按照一页十条数据展示在员工管理页面。分页时可以依据员工姓名查询。

实现要点:使用PageHelper插件,以及对应dto进行查询。注意结果的封装:

@Override
public PageResult page(EmployeePageQueryDTO employeePageQueryDTO) {
    //调用PageHelper 开始分页
    PageHelper.startPage(employeePageQueryDTO.getPage(), employeePageQueryDTO.getPageSize());

    //执行查询
    List<Employee> empList = employeeMapper.pageQuery(employeePageQueryDTO);

    //解析和封装结果
    Page<Employee> page = (Page<Employee>)empList;
    return new PageResult(page.getTotal(), page.getResult());

}

同时我们注意到,返回到前端日期的格式奇怪。这是因为我们没有配置好日期的返回格式。spring默认返回的是iso格式的日期,形如:2022-09-02T00:29:04 。但是,在接口测试中观察到,返回日期的格式为: [ 2026, 2, 15, 13, 56, 31 ] 。这是因为为了生成接口文档,配置类继承了WebMvcConfigurationSupport并实现注册自定义拦截器。使用了 extends WebMvcConfigurationSupport,Spring Boot 内部的条件注解 @ConditionalOnMissingBean(WebMvcConfigurationSupport.class) 就会生效。结果就是:Spring 停止自动配置 JSON 转换器,改用定义的(或者空的)转换器。

所以我们需要在自定义的WebMvcConfiguration配置类中扩展spring MVC的消息转换器,统一日期的格式。

/**
     * 扩展mvc框架的消息转换器
     * @param converters
     */
    protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        log.info("开始扩展消息转换器...");

        //创建一个消息转化器对象
        MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        //设置对象转换器,可以将Java对象转为json字符串
        converter.setObjectMapper(new JacksonObjectMapper());

        //将我们自己的转换器放入spring MVC框架的容器中
        converters.add(0,converter);
    }

禁用/启用员工

需求:可以在员工管理界面禁止和启用员工,管理员工的登录权限。被禁止的员工无法登录。

实现要点:修改员工的status字段实现。这里我们可以在mapper层实现一个通用的更新员工字段的接口,拼接动态sql,从而减少开发的时间和维护成本。

<update id="update" parameterType="com.sky.entity.Employee">
        update employee
        <set>
            <if test="username != null">
                username = #{username},
            </if>
            <if test="password != null">
                password = #{password},
            </if>
            <if test="name != null">
                name = #{name},
            </if>
            <if test="phone != null">
                phone = #{phone},
            </if>
            <if test="sex != null">
                sex = #{sex},
            </if>
            <if test="idNumber != null">
                id_number = #{idNumber},
            </if>
            <if test="status != null">
                status = #{status},
            </if>
            <if test="updateTime != null">
                update_time = #{updateTime},
            </if>
            <if test="updateUser != null">
                update_user = #{updateUser}
            </if>
        </set>
        where id = #{id}
    </update>

修改员工

需求:更新已有的员工信息。

实现要点:首先实现根据id查询回显员工的接口,然后实现修改员工的接口复用之前写好的动态sql即可。

导入分类管理模块

把官方资料中提供的文件复制到项目的对应目录即可。注意:最好根据mapper层->service层->controller层这一顺序导入。这样不会引起报错。


评论