瑞吉外卖05-启用、禁用员工账号&&编辑员工信息

瑞吉外卖05-启用、禁用员工账号&&编辑员工信息

需求分析

1. 启用、禁用员工账号需求

2. 编辑员工信息需求

前端代码分析

1. 启用、禁用员工账号前端代码分析

页面按钮动态展示

执行流程分析

2. 编辑员工信息前端代码分析

代码开发

1. 启用、禁用员工账号

“黑马”故意设计的脑残BUG

解决方案

2. 编辑员工信息

项目代码获取地址(免费) 


瑞吉外卖05-启用、禁用员工账号&&编辑员工信息

需求分析

1. 启用、禁用员工账号需求

在员工管理列表页面,可以对某个员工账号进行启用或者禁用操作。账号禁用的员工不能登录系统,启用后的员工可以正常登录。如果某个员工账号状态为正常,则按钮显示为 "禁用",如果员工账号状态为已禁用,则按钮显示为"启用"。

需要注意,只有管理员(admin用户)可以对其他普通用户进行启用、禁用操作,所以普通用户登录系统后启用、禁用按钮不显示

admin 管理员登录

普通用户登录

显然如上述描述的一样,admin 普通员工 在“操作”这一栏的界面是不一样的!!!

2. 编辑员工信息需求

在员工管理列表页面点击 "编辑" 按钮,跳转到编辑页面,在编辑页面回显员工信息并进行修改,最后点击 "保存" 按钮完成编辑操作。

想一想我们在 “1” 里面写的 updateInfo() 方法,是不是可以直接用上?!

前端代码分析

1. 启用、禁用员工账号前端代码分析

页面按钮动态展示

在上述的需求中,我们提到需要实现的效果是 :

只有管理员(admin用户)可以对其他普通用户进行启用、禁用操作,所以普通用户登录系统后启用、禁用按钮不显示

页面中是怎么做到只有管理员admin能够看到启用、禁用按钮的?

我们可以来分析一下前端的代码(resources\backend\page\member\list.html)

触发钩子函数created(),在钩子函数中,会从localStorage中获取到用户登录信息,然后获取到用户名

created() {
  this.init()
  this.user = JSON.parse(localStorage.getItem('userInfo')).username
},

通过Vue指令 v-if 进行判断,如果登录用户为admin将展示 启用/禁用 按钮,否则不展示  

<el-button
  type="text"
  size="small"
  class="delBut non"
  @click="statusHandle(scope.row)"
  v-if="user === 'admin'"
>
  {{ scope.row.status == '1' ? '禁用' : '启用' }}
</el-button>j

执行流程分析

根据上面的代码分析,我们知道,当管理员admin点击 "启用" 或 "禁用" 按钮时,调用方法statusHandle()

@click="statusHandle(scope.row)"

statusHandle() 方法中进行二次确认,然后发起ajax请求,传递id、status参数(给后端)

function enableOrDisableEmployee (params) {
  return $axios({
    url: '/employee',
    method: 'put',
    data: { ...params }
  })
}

最终发起异步请求,请求服务端

请求说明
请求方式PUT
请求路径/employee
请求参数{"id":xxx,"status":xxx}

{...params} : 三点是ES6中出现的扩展运算符。作用是遍历当前使用的对象能够访问到的所有属性,并将属性放入当前对象中。  

2. 编辑员工信息前端代码分析

(1)点击编辑按钮时,页面跳转到add.html,并在url中携带参数 [员工id]

<el-button
        type="text"
        size="small"
        class="blueBug"
        @click="addMemberHandle(scope.row.id)"
        :class="{notAdmin:user !== 'admin'}"
>
    编辑
</el-button>

点击编辑按钮,调用addMemberHandle()方法

addMemberHandle(st) {
    if (st === 'add') {
        window.parent.menuHandle({
            id: '2',
            url: '/backend/page/member/add.html',
            name: '添加员工'
        }, true)
    } else {
        window.parent.menuHandle({
            id: '2',
            url: '/backend/page/member/add.html?id=' + st,
            name: '修改员工'
        }, true)
    }
},

(2)在add.html页面获取 url 中的参数 [员工id]

(3)发送ajax请求,请求服务端,同时提交员工id参数

(4)服务端接收请求,根据员工id查询员工信息,将员工信息以json形式响应给页面

(5)页面接收服务端响应的json数据,通过VUE的数据绑定进行员工信息回显

(6)点击保存按钮,发送ajax请求,将页面中的员工信息以json方式提交给服务端

(7)服务端接收员工信息,并进行处理,完成后给页面响应

(8)页面接收到服务端响应信息后进行相应处理

请求说明
请求方式PUT
请求路径/employee
请求参数{.......} json格式数据

代码开发

1. 启用、禁用员工账号

我们要实现的功能点大致如下:

(1)页面发送ajax请求,将参数(id、status)提交到服务端

(2)服务端Controller接收页面提交的数据并调用Service更新数据

(3)Service调用Mapper操作数据库

Controller层

package com.harmony.reggie.controller.EmployeeController

/**
 * 根据 ID 来修改员工信息
 * @param employee
 * @return
 * @RequestBody主要用来接收前端传递给后端的json字符串中的数据的
 */
@PutMapping
public R<String> updateInfo(HttpServletRequest request,@RequestBody Employee employee) {
    return employeeService.updateInfo(request, employee);
}

@RequestBody 主要用来接收前端传递给后端的JSON字符串中的数据的 

Service层

package com.harmony.reggie.service.impl.EmployeeServiceImpl

@Override
public R<String> updateInfo(HttpServletRequest request, Employee employee) {
    Long empId = (Long)request.getSession().getAttribute("employee");
    employee.setUpdateTime(LocalDateTime.now());
    employee.setUpdateUser(empId);
    employeeMapper.updateById(employee);
    System.out.println(employee);
    return R.success("员工信息修改成功!");
}

注意:

本来这个需要我们只要更改employees表的status属性就行了,但是我们为了代码有更好的复用性,所以这边采用的是传入一个employee实体类对象,更改employees表中指定 id 的字段

这样以后只要有employee对象的任意属性字段的变更操作,调用这个方法就可以了。

“黑马”故意设计的脑残BUG

通过观察控制台输出的SQL发现页面传递过来的员工 id 的值和数据库中的 id不一致,导致状态修改失败。

分页查询时,服务端会将返回的R对象进行JSON序列化,转换为JSON格式的数据。而员工的ID是一个Long类型的数据,而且是一个长度为 19 位的长整型数据, 该数据返回给前端是没有问题的。

问题就出现在前端JS中, js在对长度较长的长整型数据进行处理时, 会损失精度, 从而导致提交的id和数据库中的id不一致。

解决方案

由于在SpringMVC中,将Controller方法返回值转换为json对象,是通过jackson来实现的,涉及到SpringMVC中的一个消息转换器MappingJackson2HttpMessageConverter,所以我们要解决这个问题,就需要对该消息转换器的功能进行拓展

(1)提供对象转换器JacksonObjectMapper,基于Jackson进行Java对象到json数据的转换

/**
 * 对象映射器:基于jackson将Java对象转为json,或者将json转为Java对象
 * 将JSON解析为Java对象的过程称为 [从JSON反序列化Java对象]
 * 从Java对象生成JSON的过程称为 [序列化Java对象到JSON]
 */
public class JacksonObjectMapper extends ObjectMapper {

    public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
    public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
    public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";

    public JacksonObjectMapper() {
        super();
        //收到未知属性时不报异常
        this.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);

        //反序列化时,属性不存在的兼容处理
        this.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);


        SimpleModule simpleModule = new SimpleModule()
                .addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
                .addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
                .addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)))

                .addSerializer(BigInteger.class, ToStringSerializer.instance)
                .addSerializer(Long.class, ToStringSerializer.instance)
                .addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
                .addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
                .addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));

        //注册功能模块 例如,可以添加自定义序列化器和反序列化器
        this.registerModule(simpleModule);
    }
}

在进行JSON数据序列化及反序列化时,LocalDateTime、LocalDate、LocalTime的处理方式,以及BigInteger及Long类型数据,直接转换为字符串(解决办法)

(2)在WebMvcConfig配置类中扩展SpringMVC的消息转换器,在此消息转换器中使用提供的对象转换器进行Java对象到JSON数据的转换 

@Configuration
public class WebMVCConfig extends WebMvcConfigurationSupport {

    // 之前代码 ... 略

    @Override
    protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        // 创建消息转换器对象
        MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
        messageConverter.setObjectMapper(new JacksonObjectMapper());
        converters.add(0, messageConverter);
    }
}

2. 编辑员工信息

之前更新操作我们在“1”中已经写过了,所以这里只要编写一个查询的功能就可以了。

第8步里面,页面接收到服务端响应信息后进行相应处理,也就是说我们在后端要查询出一个employee对象,传给前端用form进行渲染。

/**
 * 查询员工信息
 * @param id
 * @return
 * @PathVariable id在请求路径里面
 */
@GetMapping("/{id}")
public R<Employee> getEmployeeById(@PathVariable Long id) {
    Employee employee = employeeService.getById(id);
    if (employee != null) {
        return R.success(employee);
    }
    return R.error("没有查询出来!");
}

项目代码获取地址(免费) 

瑞吉外卖: 瑞吉外卖项目完整代码,使用Sprinboot,SSM,MP,MySQL,Redis,Nginx等技术。 - Gitee.comicon-default.png?t=M85Bhttps://gitee.com/Harmony_TL/reggie_take_out/tree/reggie_v5_editAndUpEmployee/

posted @ 2022-10-13 23:55  金鳞踏雨  阅读(57)  评论(0编辑  收藏  举报  来源