• 猿创征文|瑞吉外卖——管理端_员工管理


    个人名片:

    博主酒徒ᝰ.
    专栏瑞吉外卖
    个人简介沉醉在酒中,借着一股酒劲,去拼搏一个未来。
    本篇励志一本好书,就像高级武功秘籍一样,哪怕只是从里面领悟到个一招半势,功力提升起来都是惊人的。

    本项目基于B站黑马程序员Java项目实战《瑞吉外卖》,轻松掌握springboot + mybatis plus开发核心技术的真java实战项目。

    视频链接【黑马程序员Java项目实战《瑞吉外卖》,轻松掌握springboot + mybatis
    plus开发核心技术的真java实战项目】 https://www.bilibili.com/video/BV13a411q753?
    点击观看

    一、页面呈现

    在这里插入图片描述

    分析:employee地址,GET方式,page地址。在?后面有page和pageSize
    数据库中:name为非空,所以此处直接查询数据库中Employee表的所以内容。

    /**
    * 页面呈现——分页查询
    * @param page
    * @param pageSize
    * @return
    */
    @GetMapping("/page")
    public R<Page> page(int page, int pageSize){
        //测试是否可以接收到信息
        //        log.info("page:{},pageSize:{}",page, pageSize);
    
        //分页构造器
        Page<Employee> pageInfo = new Page<>(page, pageSize);
    
        //查询Employee表中全部信息
        LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderByDesc(Employee::getUpdateTime);
        employeeService.page(pageInfo, queryWrapper);
    
        return R.success(pageInfo);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    二、添加员工

    1. 原始操作

    在这里插入图片描述

    分析:Post方式,employee地址
    在这里插入图片描述

    此表格与数据库员工表存在查询,内容不够,缺少的部分如果是非空(都是非空)就需要补全。
    状态码(status)默认为1,无需补。

    /**
    * 添加员工信息
    * @param request
    * @param employee
    * @return
    */
    @PostMapping
    public R<String> employee(HttpServletRequest request, @RequestBody Employee employee){
        //测试信息,对照数据库,查看需要补充哪些信息。
        //log.info("employee:{}",employee);//employee:Employee(id=null, name=88, username=888, password=null, phone=13452525252, sex=1, idNumber=111111111111111111, status=null, createTime=null, updateTime=null, createUser=null, updateUser=null)
        //需要补充password=null, status=null, createTime=null, updateTime=null, createUser=null, updateUser=null
        //设置初始密码 123456
        employee.setPassword(DigestUtils.md5DigestAsHex("123456".getBytes()));
        //设置其它 时间类 当前时间
        employee.setCreateTime(LocalDateTime.now());
        employee.setUpdateTime(LocalDateTime.now());
        //设置其它 名字 用户名(返回之前在登录时保存) 用户名id为Long形式
        Long empId = (Long)request.getSession().getAttribute("employee");
        employee.setCreateUser(empId);
        employee.setUpdateUser(empId);
    
        employeeService.save(employee);
        return R.success("添加员工成功");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    2. 优化操作

    在上述的代码操作下,每一次的添加与修改操作时,我们都需要执行以下代码。

    //设置其它 时间类 当前时间
        employee.setCreateTime(LocalDateTime.now());
        employee.setUpdateTime(LocalDateTime.now());
        //设置其它 名字 用户名(返回之前在登录时保存) 用户名id为Long形式
        Long empId = (Long)request.getSession().getAttribute("employee");
        employee.setCreateUser(empId);
        employee.setUpdateUser(empId);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    这是比较繁琐的,因此,需要进行一些操作来简化开发。 我们需要一个操作,在每一次的添加与修改时,都会自动进行这些操作

    代码示例:

    package com.itheima.reggie.common;
    
    import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.ibatis.reflection.MetaObject;
    import org.springframework.stereotype.Component;
    
    import java.time.LocalDateTime;
    
    @Slf4j
    @Component
    public class MyMetaObjecthandler implements MetaObjectHandler {
    
        /**
         * 插入操作时自动填充
         * @param metaObject
         */
        @Override
        public void insertFill(MetaObject metaObject) {
            metaObject.setValue("createTime", LocalDateTime.now());
            metaObject.setValue("updateTime", LocalDateTime.now());
            Long empId = (Long)request.getSession().getAttribute("employee");
            metaObject.setValue("createUser", emp);
            metaObject.setValue("updateUser", emp);
        }
    
        /**
         * 更新操作时自动填充
         * @param metaObject
         */
        @Override
        public void updateFill(MetaObject metaObject) {
            metaObject.setValue("updateTime", LocalDateTime.now());
            Long empId = (Long)request.getSession().getAttribute("employee");
            metaObject.setValue("updateUser", emp);
        }
    }
    
    
    • 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

    进一步简化:

    这里的设置与获取ID值,必须保证在登录后一定已经设置。我的操作时在之后的登陆过滤器中设置ID。

    package com.itheima.reggie.common;
    
    /**
     * 用户保存和获取当前登录的用户ID,便于在添加与修改人是可以快速获取。
     */
    public class BaseContext {
        private static ThreadLocal<Long> threadLocal = new ThreadLocal<>();
    
        /**
         * 设置id值
         * @param id
         */
        public static void setCurrentId(Long id) {
            threadLocal.set(id);
        }
    
        /**
         * 获取id值
         * @return
         */
        public static Long getCurrentId() {
            return threadLocal.get();
        }
    
    }
    
    
    • 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
    package com.itheima.reggie.common;
    
    import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.ibatis.reflection.MetaObject;
    import org.springframework.stereotype.Component;
    
    import java.time.LocalDateTime;
    
    @Slf4j
    @Component
    public class MyMetaObjecthandler implements MetaObjectHandler {
    
        /**
         * 插入操作时自动填充
         * @param metaObject
         */
        @Override
        public void insertFill(MetaObject metaObject) {
            metaObject.setValue("createTime", LocalDateTime.now());
            metaObject.setValue("updateTime", LocalDateTime.now());
            metaObject.setValue("createUser", BaseContext.getCurrentId());
            metaObject.setValue("updateUser", BaseContext.getCurrentId());
        }
    
        /**
         * 更新操作时自动填充
         * @param metaObject
         */
        @Override
        public void updateFill(MetaObject metaObject) {
            metaObject.setValue("updateTime", LocalDateTime.now());
            metaObject.setValue("updateCreate", BaseContext.getCurrentId());
        }
    }
    
    
    • 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

    三、编辑(修改员工)

    1.回显数据

    在这里插入图片描述

    地址对照数据库可以发现是对照员工表中的id来进行修改的。

    /**
    * 数据回显
    * @param id
    * @return
    */
    @GetMapping("/{id}")
    public R<Employee> huixian(@PathVariable Long id){
        //根据前端传过来的id进行查询信息
        LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Employee::getId, id);
        Employee employee = employeeService.getOne(queryWrapper);
        return R.success(employee);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    功能测试:发现测试出问题了,并没有回显数据。查看日志发现,浏览器的id与数据库中的ID不一样。这是因为数据精度丢失。

    解决办法

    修改id将其变为字符串形式。
    这里用到了之前加入的对象映射器。
    在使用消息转换器将Long类型数据转换为String类型

    /**
     * 消息转换器
     * @param converters the list of configured converters to extend
     */
    @Override
    protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        //创建消息转化器对象
        MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
        //将java对象转为json对象
        messageConverter.setObjectMapper(new JacksonObjectMapper());
        converters.add(0,messageConverter);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    2.修改数据

    在这里插入图片描述

    分析:PUT方法

    /**
     * 修改数据
     * @param employee
     * @return
     */
    @PutMapping
    public R<String> employee(@RequestBody Employee employee){
        employeeService.updateById(employee);
        return R.success("修改成功");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    四、输入框查找

    在这里插入图片描述

    分析:GET方式,相对于页面呈现来说,添加了一个name属性。
    发现与页面呈现使用的都是@GetMapper(“/page”),所以需要在页面呈现中进行修改。
    修改后为:(仅仅添加判断name是否为空的判断)

    /**
     * 页面呈现——分页查询
     * @param page
     * @param pageSize
     * @return
     */
    @GetMapping("/page")
    public R<Page> page(int page, int pageSize, String name){
        //测试是否可以接收到信息
    //    log.info("page:{},pageSize:{},name:{}",page, pageSize, name);
    
        //分页构造器
        Page<Employee> pageInfo = new Page<>(page, pageSize);
    
        //查询Employee表中全部信息
        LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderByDesc(Employee::getUpdateTime);
    
        //输入框查找添加
        if (name != null){
            queryWrapper.like(Employee::getName,name);
        }
    
        employeeService.page(pageInfo, queryWrapper);
    
        return R.success(pageInfo);
    }
    
    • 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

    五、知识点

    1. 消息转换器

    json数据中int转string:这个可以使用快捷键,会省略很多。

    /**
     * 消息转换器
     * @param converters the list of configured converters to extend
     */
    @Override
    protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        //创建消息转化器对象
        MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
        //将java对象转为json对象
        messageConverter.setObjectMapper(new JacksonObjectMapper());
        converters.add(0,messageConverter);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    对象映射器:这个在老师的资料里有,可以选择直接用。

    package com.itheima.reggie.common;
    
    import com.fasterxml.jackson.databind.DeserializationFeature;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.databind.module.SimpleModule;
    import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
    import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
    import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
    import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
    import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
    import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
    import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
    import java.math.BigInteger;
    import java.time.LocalDate;
    import java.time.LocalDateTime;
    import java.time.LocalTime;
    import java.time.format.DateTimeFormatter;
    import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;
    
    /**
     * 对象映射器:基于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);
        }
    }
    
    • 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
    • 51
    • 52
    • 53
    • 54

    2. @pathVariable,@PathParam和RequestParam的区别:

    • @pathVariable:从路径中获取变量,也就是把路径当做变量,路径问号前面
      eg:http://localhost:8080/dish?ids=1413384757047271425中的dish
    • @PathParam从请求里面获取参数,从请求来看,路径问号后面eg:http://localhost:8080/dish?ids=1413384757047271425中的1413384757047271425
    • @RequestParam是从 request
      里面拿取值,是以键值对方式来获取参数值的。获取?后面相同一个属性的多个值。eg:http://localhost:8080/test?name=李四&name1=张三中的张三,李四。

    3. ThreadLocal

    这是一个本地线程,具有隔离性。在这里你需要确保每一个ID的唯一。
    与Synchronized的区别是:
    Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离。

  • 相关阅读:
    小文一篇,说说:where、:has和:is的特殊性吧
    Redis系列2:数据持久化提高可用性
    如何统计数据库的QPS和TPS?
    【LeetCode】【剑指offer】【圆圈中最后剩下的数字】
    工具篇 | 04 | STS
    容器编排学习(六)服务管理与用户权限管理
    java毕业设计课堂管理系统小程序用户端mybatis+源码+调试部署+系统+数据库+lw
    软件测试 | 当面试时被问到“搭建过测试环境吗”, 身为小白要怎么回答?
    xss标签和属性爆破
    2.6 二叉树
  • 原文地址:https://blog.csdn.net/m0_65144570/article/details/126807729