【SpringBoot项目】SpringBoot项目-瑞吉外卖【day02】员工管理业务开发

news2025/7/19 15:42:13

文章目录

    • 前言
    • 员工管理业务开发
        • 完善登录功能
            • 问题分析
            • 代码实现
            • 功能测试
        • 新增员工
            • 需求分析
            • 数据模型
            • 代码开发
            • 功能测试
            • 统一处理异常
        • 员工信息分页查询
            • 需求分析
            • 代码开发
            • 功能测试
        • 启用/禁用员工
            • 需求分析
            • 代码实现
            • 测试
        • 编辑员工信息
            • 需求分析
            • 代码实现
            • 功能测试
    • 总结

🌕博客x主页:己不由心王道长🌕!
🌎文章说明:SpringBoot项目-瑞吉外卖【day02】员工管理业务开发🌎
✅系列专栏:SpringBoot项目
🌴本篇内容:对黑马的瑞吉外卖项目的day02进行笔记和项目实现🌴
☕️每日一语:人有退路,就有些许安全感。等到哪一天,你真没了退路,你就发现眼前哪条路都能走,也能通。☕️
🚩 交流社区:己不由心王道长(优质编程社区)

前言

今天是项目开发的第二天。当然,我不是第二天就写好了相应的功能,毕竟能力有限。照猫画虎也得自己思考思考再起笔吧!

员工管理业务开发

完善登录功能

问题分析

前面我们已经完成了后台系统的员工登录功能开发,但是还存在一个问题:用户如果不登录,直接访问系统首页面,照样可以正常访问。
这种设计并不合理,我们希望看到的效果应该是,只有登录成功后才可以访问系统中的页面,如果没有登录则跳转到登录页面。
那么,具体应该怎么实现呢?
答案就是使用过滤器或者拦截器,在过流器成者拦截器中判断用户是否已经完成登录,如果没有登录则跳转到登录页面。
那我们选择过滤器还是拦截器呢?现在不能全都要,所以我这里选择用的是过滤器。在后面优化的时候我们再试试拦截器。

代码实现

实现步骤如下:
一、创建自定义过滤器LoginCheckFilter

见名知意嘛,登录检查过滤器:

package com.example.filter;

/**
 * @author 不止于梦想
 * @date 2022/11/13 17:23
 */
public class LoginCheckFilter {
}

二、在启动类上加入注解@ServletComponentScan:

SpringBootApplication 上使用@ServletComponentScan 注解后
Servlet可以直接通过@WebServlet注解自动注册
Filter可以直接通过@WebFilter注解自动注册
Listener可以直接通过@WebListener 注解自动注册

其实就是组件扫描,而@ServletComponentScan顾名思义就是扫描Servlet技术相关的注解进行注册,并加载成bean。

在这里插入图片描述
在这里要提醒以下,SpringBoot的启动类要在所有其他包的同层或者父层,这样才能扫描到,不然是扫描不到的。

三、完善过滤器处理逻辑
1、获取本次请求的URI
2、判断本次请求是否需要处理
3、如果不需要处理,直接放行
4、需要处理的则判断登录状态,如果已经登录,则直接放行
5、如果未登录则返回登录结果
在这里插入图片描述
上面第五步返回登录结果时不能直接返回,还得看前端代码:

// 响应拦截器
  service.interceptors.response.use(res => {
      console.log('---响应拦截器---',res)
      // 未设置状态码则默认成功状态
      const code = res.data.code;
      // 获取错误信息
      const msg = res.data.msg
      console.log('---code---',code)
      if (res.data.code === 0 && res.data.msg === '未登录') {// 返回登录页面
        // MessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', {
        //     confirmButtonText: '重新登录',
        //     cancelButtonText: '取消',
        //     type: 'warning'
        //   }
        // ).then(() => {
        // })
        console.log('---/backend/page/login/login.html---',code)
        localStorage.removeItem('userInfo')
        window.top.location.href = '/backend/page/login/login.html'
      } else {
        return res.data
      }
    },

上面是一个前端响应拦截器,就是我们发请求,后台处理给的响应信息会被响应拦截器截取。当我们未登录返回登录结果时,应当按照它给的要求格式返回,这样前端的代码才能正确处理并执行正确的操作(好鸡肋,感觉严重耦合在一起)。

这个过程中的难点是判断是否需要处理。那么我们来说说什么情况下需要处理,什么情况下需要放行。

一、前端向后台的controller层发送的请求需要处理。这个毋庸置疑。
二、静态资源应该放行。什么静态资源?所有静态资源,这样岂不是让别人都能看到你的资源了?看到就看到呗,真正有用的数据都要走后端的controller获取,他看到你的页面也没事,你的数据并不会被看到
三、退出、登录请求放行。要退出就已经说明人已经登录了,要登录当然放行,不然就死循环了。

上面分析已经做好了,现在应该把代码整一整

package com.example.filter;

import com.alibaba.fastjson.JSON;
import com.example.commons.R;
import org.springframework.expression.spel.CodeFlow;
import org.springframework.util.AntPathMatcher;

import javax.management.modelmbean.RequiredModelMBean;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.Writer;

/**
 * @author 不止于梦想
 * @date 2022/11/13 17:23
 */
@WebFilter(filterName = "loginFilter" ,urlPatterns = "/*")
public class LoginCheckFilter implements Filter {
    private static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
                         FilterChain filterChain) throws IOException, ServletException {
        //先把请求和响应转换为http格式的,因为这是协议
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
//        1、获取本次请求的URI
        String requestURI = httpServletRequest.getRequestURI();
//        2、定义不需要处理的请求路径
        String[] urls = new String[]{//这里定义需要放行的urls
                "/employee/login",
                "/employee/logout",
                "/backend/**",
                "/front/**"
        };
//        3、如果不需要处理,直接放行
        if (urlCheck(requestURI,urls)) {
            filterChain.doFilter(httpServletRequest,httpServletResponse);
            return;
        }
//        4、需要处理的则判断登录状态,如果已经登录,则直接放行
        if (httpServletRequest.getSession().getAttribute("employee")!=null) {
            filterChain.doFilter(httpServletRequest,httpServletResponse);
            return;
        }
//        5、如果未登录则返回登录结果
        httpServletResponse.getWriter().write(JSON.toJSONString(R.error("未登录")));
    }
    public boolean urlCheck(String url,String[] urls){
        for (String s : urls) {
            if (PATH_MATCHER.match(s,url)) {
                return true;
            }
        }//如果请求与需要放行的请求不匹配,则返回false。
        return false;
    }
}

在第五步,是我们要重点注意的,因为前端的响应拦截器需要的信息是这样的

在这里插入图片描述
统一格式中的error中的code都统一为了0,msg是我们自己可以设置的,前端需要什么,我们就给他返回什么。
在这里插入图片描述

说明:

private static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();

这是一个路径匹配器,我们在设置"/backend/**",这样的路径过滤时,如果遇到/backend/index.html时,路径并不能匹配上,/ ** 是拦截所有的文件夹及里面的子文件夹,但是当前文件夹有静态页面时则不会拦截,而路径匹配器则会让器拦截所有属于它的东西。

功能测试

在这里插入图片描述
在每一步的后面根据实际情况进行日志输出,这样更能观察我们的程序到底走了哪些操作。

现在我不登录直接进行index.html页面试试:
在这里插入图片描述
可以清晰的看到,我只是发了一个index.html页面。我们在进行未登录时直接访问index.html页面,它应该给我判断未登录,然后返回登录界面。但是由于我们开发了所有的静态资源,所以不需要处理,但是在index界面上会自动发一个获取page的controller请求,这时候会判断用户是否已经登录,没有登录则回退到登录界面。

这里逻辑全部正确,就是视图并没有进行跳转,算是一个败笔,暂时没有找出解决办法。

新增员工

需求分析

我们在系统中可以管理员工的信息,可以通过新增员工来添加后台系统的用户。当我们点击【添加员工】按钮则视图进行相应跳转:
在这里插入图片描述
在这里插入图片描述
当我们输入数据以后,会在前端先进行一个格式校验,如手机号码和省份证号:
在这里插入图片描述
手机号码必须是11位数字,身份证则是18位。在以上信息都输入正确以后,点击保存按钮即可,如果保存以后还要继续添加,则点击保存并继续添加。

在这里插入图片描述
在保存、取消等按钮的后面都绑定了单击事件,我们看看保存的单击事件是什么样的。
在这里插入图片描述
过程我已经梳理了大概,所以主角是谁?是addEmployee,在我们单击保存后,由于表单已经绑定了这个事件,那么表单会作为一个数据去调用方法,传给这个方法。
在这里插入图片描述
可以看出来,这个函数其实也是发送一个axios请求,不同的是这个方法带有参数,就是把表单填的数据传给后端的controller,路径是/employee,类型是post。

数据模型

分析好了需求以后,我们看看数据模型,为什么呢?先看再说!!!
在这里插入图片描述
这里没有拿出id,因为id是利用雪花算法自动生成的。
上面的由用户填写的是name(用户名)、username(员工姓名)、phone(电话号码)、sex(性别)、id_number(身份证号)。
其他都是在添加用户时,由后端自动生成的、密码是统一的,后面由员工根据自己的需求进行更改。

代码开发

根据分析和模型,我们现在可以编写相应的方法了:

@PostMapping
    public R<String> addEmployee(HttpServletRequest request,@RequestBody Employee employee){
        log.info("新增员工,信息为 {}"+employee.toString());
        //设置初始密码123456,密码经过md5加密处理
        employee.setPassword(DigestUtils.md5DigestAsHex("123456".getBytes()));
        //设置创建时间
        employee.setCreateTime(LocalDateTime.now());
        //设置更新时间,第一次创建就是第一次更新
        employee.setUpdateTime(LocalDateTime.now());
        //获取当前登录人员信息
        Long empId = (Long) request.getSession().getAttribute("employee");
        //添加创建者信息
       employee.setCreateUser(empId);
       //设置更新人员信息
       employee.setUpdateUser(empId);
       //调用添加方法
        employeeService.save(employee);
        //返回结果
        return R.success("新增员工成功");
    }
功能测试

在这里插入图片描述
可以看到,我们已经测试通过了,但是上面还是存在一些问题的,什么问题?异常的问题

统一处理异常

在这里插入图片描述
报的是后台500错误,我们查看后台
在这里插入图片描述
什么意思,不知道,百度查查:
在这里插入图片描述
说的是username重复了,原来是我们加入数据的时候,用户名重复了,这是不允许的。

所以要处理这种情况,这时候就需要我们的异常处理上场了。我们可以一个一个异常处理,也可以一类异常处理,当然是选择多的啦。

package com.example.commons;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.sql.SQLIntegrityConstraintViolationException;

/**
 * @author 不止于梦想
 * @date 2022/11/14 18:27
 */
@ControllerAdvice(annotations = {Controller.class, RestController.class})
@ResponseBody
@Slf4j
public class GlobalExcption {

    @ExceptionHandler(SQLIntegrityConstraintViolationException.class)
    public R<String> exceptionHandler(SQLIntegrityConstraintViolationException ex){
        //后台输出异常信息
        log.info(ex.getMessage());
        //Duplicate entry '123' for key 'employee.idx_username'
        //如果异常信息包括Duplicate entry,则可以确定是用户名字重复
        if(ex.getMessage().contains("Duplicate entry")){
            //以空格为分隔符分割异常信息
            String[] s = ex.getMessage().split(" ");
            //取出数组中的用户名,返回给客户端,提升他名字重复
            return R.error(s[2]+"已存在");
        }
        //否则,返回未知名错误
        return R.error("未知名错误,请重新输入信息");
    }
}

验证:
在这里插入图片描述

要说明的是,这里的功能还十分的不完善,比如手机号肯定不能重复,如果重复应该提示,该手机号已经绑定,身份证肯定不能重复吧,员工姓名可以重复,同名的人多了去了。这是后台的处理逻辑,那前台的呢?哪里出错你应该在哪提示,并且删除表格里的数据吧?只能说我们不是前端的,不能瞎动前端代码,但是这些代码漏洞很多。

员工信息分页查询

需求分析

系统中的员工很多的时候,如果在一个页面中全部展示出来会显得比较乱,不便于查看,所以一般的系统中都会以分页的方式来展示列表数据。

首先我们要看的是,当我们点击登录并且进入index.html之后,页面会发送一个controller的请求查询page,还记得吧?
在这里插入图片描述
并且是通过这个请求走过滤器的controller判断路径判断是否已经登录,没有登录则回退到登录页面,但是现在不研究这个,要研究的是它发送的page请求。

无非就是下面几种情况
在这里插入图片描述
而它们都会走/employee/page这个controller路径。
需要注意的是,我们发送请求时,不一定会按条件查,比如我们不一定输入员工姓名。但是这个请求发送的时候,对应的页码和每页的条数是一定存在的,你不指定也有默认值。

整个过程梳理:
在这里插入图片描述

接下来看看前端的代码:
在这里插入图片描述
当我们进入到index界面,并且是在员工管理界面时,会自动加载一个页面,页面url如图,我们跟进去。
在这里插入图片描述

创建了一个vue,并且绑定了member-app,并且初始化一个init方法。
在这里插入图片描述
我们看看这个init方法
在这里插入图片描述
方法就是这个getMemberList,一样的,跟过去看看它要干嘛。
在这里插入图片描述
放松一个axios请求,方式是get方式,传入params参数,路径是/employee/page。
params参数有page、pageSize、name。

梳理思路:
员工管理界面,当我们进去的时候会有默认提供的参数请求后台并且查询数据,我们也可以手动的选择我们的查询条件,比如按姓名并且同时有每页多少条记录,或者直接点击第几页,输入每页多少条数。总得来说,就是按姓名不一定有,但是第几页和每页多少条记录是必然存在的。所以编写代码的时候要判断是否有姓名。

代码开发

上面已经把前端请求需要的东西和思路都理清了一遍,现在编写代码。
因为这里用的分页,而我们使用的MP为我们提供了分页插件,我们需要编写一个拦截器去拦截分页请求

package com.example.config;

/**
 * @author 不止于梦想
 * @date 2022/11/14 20:15
 */

import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 配置MP的分页插件
 */
@Configuration//声明为配置类
public class MybatisPlusConfig {

    @Bean//交给Spring容器管理
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        //创建MybatisPlus拦截器
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        //添加分页拦截器
        mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        //返回分页拦截器
        return mybatisPlusInterceptor;
    }
}

有了分页插件,现在我们使用分页方法就会被拦截,并进行处理
先创建分页构造器
在这里插入图片描述
代码如下:

@GetMapping("/page")
    public R<Page> page(int page,int pageSize,String name){
        log.info("page = {},pageSize = {},name = {}" ,page,pageSize,name);
        //构造分页构造器
        Page pageInfo = new Page(page,pageSize);

        //构造条件构造器
        LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper();
        //添加过滤条件
        queryWrapper.like(StringUtils.isNotEmpty(name),Employee::getName,name);
        //添加排序条件
        queryWrapper.orderByDesc(Employee::getUpdateTime);

        //执行查询
        employeeService.page(pageInfo,queryWrapper);

        return R.success(pageInfo);
    }

这里在页面展示顺序的时候,是按照更新时间降序输出的

功能测试

看看,不指定姓名能不能查询:
在这里插入图片描述
pageSize是10,但是明显不对,这应该是前端的问题,我们再看看。
在这里插入图片描述
不对的时候记得清理一下缓存就好了,啊哈哈。
在这里插入图片描述
不过缓存清理了,可能你的页面图片又没有了,好迷茫。

启用/禁用员工

需求分析

在员工管理列表页面,可以对某个员工账号进行启用或者禁用操作。账号禁用的员工不能登录系统,启用后的员工可以正常登录。
需要注意,只有管理员(admin用户)可以对其他普通用户进行启用、禁用操作,所以普通用户警录系统后启用禁用按钮不显示。
在这里插入图片描述
管理员admin登录系统可以对所有员工账号进行启用、禁用操作如果某个员工账号状态为正常,则按钮显示为“禁用”,如果员工账号状态为已禁用,则按钮显示为“启用(只有禁用了你才需要启用,只有启用的状态你才能禁用)。

看看前端代码吧:
在这里插入图片描述
当点击后面的禁用/启用按钮时,先调用一个statusHandle函数,并传入scope.row作为参数,在传参前前端判断你的账号是否时admin用户,是的话则弹出一个对话框,就判断你当前要调整的用户的状态,当前的用户是启用的,那么参数传的就是禁用,与之对应的是当前用户已经被禁用,那么参数就是启用(只有已经被禁用的用户需要启用),然后执行函数:
在这里插入图片描述
弹出一个选择框:
在这里插入图片描述
你选择了确定,那么久根据你传的参数对该用户进行相应的禁用和启用:
重点是enableOrDisableEmployee方法和它传入的参数:
在这里插入图片描述
这里通过传入被操作对象的id和被操作对象的状态的取反结果。
然后执行以下function:

在这里插入图片描述
发送一个put请求,并且路径是/employee,带传入的参数。

返回值是相应的状态码,我们的controller返回值应该是R
在这里插入图片描述

代码实现

前面忘了说,其实我们能不能看见后面操作有编辑,前端已经帮我们判断了,不是admin用户,你看都看不到。

@PutMapping
    public R<String> updateStatus(HttpServletRequest request,@RequestBody Employee employee) {
        /**
         * 就是一个判断语句,当id值相等时,把数据库的status,
         * 修改为参数的status,参数的status已经跟原本的status取反了。
         * 这里要注意的是,我们每次修改信息的时候,都会把修改人的信息和修改时间也进行更新,所以需要HttpServletRequest
         * 来获取当前操作人的session,从而获取修改人的id。
         */
        log.info(employee.toString());
        //获取操作人id
        Long empId = (Long) request.getSession().getAttribute("employee");
        //设置修改人
        employee.setUpdateUser(empId);
        //设置修改时间
        employee.setUpdateTime(LocalDateTime.now());
        //调用方法,修改user
        boolean b = employeeService.saveOrUpdate(employee);
        //判断修改是否成功
        if(b){
            return R.success("员工信息修改成功");
        }
        return R.error("员工信息修改失败");
测试

在这里插入图片描述
测试没有报错,但是有问题,什么问题?看到Parameters,是不是看起来跟我们的原有数据不一样?
因为长度太长了,前端处理时丢失精度了。怎么解决?
我们可以在服务端给页面响应json数据时进行处理,将long型数据统一转为String字符串,
这里直接引用官方的
JacksonObjectMapper:

package com.example.commons;

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);
    }
}

有了对象转换器之后,在mvc配置文件种配置即可:

@Override
    protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        log.info("扩展消息转换器...");
        //创建消息转换器对象
        MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
        //设置对象转换器,底层使用Jackson将Java对象转为json
        messageConverter.setObjectMapper(new JacksonObjectMapper());
        //将上面的消息转换器对象追加到mvc框架的转换器集合中
        converters.add(0,messageConverter);
    }

add(0,messageConverter);表示我们自定义的转换器放在转换器首部位置,优先使用我们自定义的转换器。

再测试:
在这里插入图片描述
在这里插入图片描述
可以看到id已经正常的传过来了,至于其中原理,以后再慢慢深究吧,会用再说。

编辑员工信息

需求分析

在这里插入图片描述
当我们点击编辑时,程序应该通过被修改的用户的id,去后台调用查询方法然后在上面的页面进行回显。当我们点击保存的时候,其实就是一个更新方法,前面我们已经写过一个通用的更新方法。就是update方法。所以这里我们只需要编写一个通过id查询用户的方法即可。我们看看前端代码:

在这里插入图片描述
下面是函数:st是判断当前要走的方法,如果st不等于add,则进行修改操作。在add.html上并且携带被修改对象的id。
在这里插入图片描述
当我们点击编辑的时候,走的应该是修改员工,所以这个方法不用写了。
需要写的时通过id查询员工。
点击编辑跳出以下信息,说明我们需要回显的数据是通过request方法,并且携带参数的。
在这里插入图片描述

代码实现

上面已经分析清楚了,现在把代码完善:
selectById

  @RequestMapping("/{id}")
    public R<Employee> selectById(@PathVariable Long id){
        log.info("查询用户id");
        Employee employee = employeeService.getById(id);
        if(employee!=null){
            return R.success(employee);
        }
        return R.error("没有查询到用户");
    }
功能测试

当我们点击修改大朗时,跳转页面:
在这里插入图片描述

现在我更改其手机号码:13512345678
注意看:这个选项…
在这里插入图片描述
ok兄弟们,看它看它,已经完成了,证明我们的程序没有错误。

总结

这是本次项目的第二天,由于各种关系,其实我没有在第二天就写好,而是推迟了一天,在第三天晚上才把第二天的内容整理好,为什么这么慢呢?一是时间不充裕,尤其是现在临近期末,也得为期末早做打算。还有就是,咱写代码,总得自己思考吧。不能把老师的抄了就是自己的啦。
在做这个项目中,可以发现,基本上都是crud,但是有的地方又需要想象力。比如全局处理异常,要想想出现什么情况下用到它,这些都是需要经验的,而项目就是积累经验的过程,所以兄弟们,咱项目得好好做。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/8296.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

VS2022 性能提升:更快的 C++ 代码索引

基于 Visual Studio 2022 17.3 版本的性能提升&#xff0c;我们在新的 17.4 版本中添加了更多的小优化&#xff0c;且听我慢慢道来。 不论你是一个工作在大型代码库下的游戏开发者&#xff0c;或者你在解决方案中有非常多的 C 工程&#xff0c;在 Visual Studio 2022 17.4 中&…

【附源码】计算机毕业设计JAVA家装建材网

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; Springboot mybatis Maven Vue 等等组成&#xff0c;B/…

浅析DNS劫持及应对方案

DNS是网络连接中的重要一环&#xff0c;它与路由系统共同组成互联网上的寻址系统&#xff0c;如果DNS遭遇故障&#xff0c;“导航系统”失效&#xff0c;网络连接就会出现无法触达或到达错误地址的情况。由于的DNS重要作用及天生脆弱性&#xff0c;导致DNS自诞生之日起&#xf…

React源码解读之任务调度

React 设计体系如人类社会一般&#xff0c;拨动时间轮盘的那一刻&#xff0c;你便成了穿梭在轮片中的一粒细沙&#xff0c;角逐过程处处都需要亮出你的属性&#xff0c;你重要吗&#xff1f;你无可替代吗&#xff1f;你有特殊权限吗&#xff1f;没有&#xff0c;那不好意思&…

Autosar模块介绍:AutosarOS(5)

上一篇 | 返回主目录 | 下一篇 AutosarOS&#xff1a;错误处理、跟踪与调试&#xff08;5&#xff09;1 钩子例程2 错误处理&#xff08;ErrorHook&#xff09;3 系统启动&#xff08;StartupHook&#xff09;4 系统关闭&#xff08;ShutdownHook&#xff09;5 系统保护&#x…

【面试题】margin负值问题

margin-top和margin-left负值&#xff0c;元素向上、向左移动&#xff1b;margin-right负值&#xff0c;右侧元素左移&#xff0c;自身不受影响&#xff1b;margin-bottom负值&#xff0c;下方元素上移&#xff0c;自身不受影响&#xff1b; 1. margin top left为负数 <st…

0095 贪心算法,普利姆算法

import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; /* * 贪心算法 * 1.指在对问题进行求解时&#xff0c;在 每一步 选择中都采取最好或最优的选择&#xff0c;希望能够导致结果是最好或最优的算法 * 2.所得到的结果不一定是最优结果&…

【SSH远程登录长时间连接后容易出现自动断开的解决方案】

SSH远程登录长时间连接后容易出现自动断开的解决方案0 问题描述1 方法一1.1 打开ssh_config文件1.2 在文件中添加以下内容1.3 重启ssh2 方法二2.1 打开sshd_config文件2.2 在文件中添加以下内容2.3 重启ssh0 问题描述 使用SSH连接远程服务器的时候 报出 client_loop send disc…

时序分析 48 -- 时序数据转为空间数据 (七) 马尔可夫转换场 python 实践(下)

时序分析 48 – 时序数据转为空间数据 (七) 马尔可夫转换场 python 实践&#xff08;下&#xff09; … 接上 从MTF到图模型 从MTF中我们可以生成图 &#x1d43a;(&#x1d449;,&#x1d438;)&#x1d43a;(&#x1d449;,&#x1d438;)G(V,E) &#xff0c;节点V和时间…

Redis从理论到实战:使用Redis实现商铺查询缓存(逐步分析缓存更新策略)

文章目录一、什么是缓存二、缓存的作用三、添加商户缓存四、分析缓存更新策略1、删除缓存还是更新缓存&#xff1f;2、如何保证缓存与数据库的操作同时成功或失败&#xff1f;3、先操作缓存还是先操作数据库&#xff1f;加油加油&#xff0c;不要过度焦虑(#^.^#) 一、什么是缓存…

ThreadLocal为什么会出现内存泄漏,你真的知道吗?

目录 1 前言 2 ThreadLocal进行线程隔离的小示例 3 原因 1 前言 大家想要搞清楚这个问题&#xff0c;就必须知道内存泄漏和内存溢出的区别 内存泄漏&#xff1a;不就被使用的对象或者变量无法被回收 内存溢出&#xff1a;没有剩余的空间来创建新的对象 2 ThreadLocal进行…

Java中的字符串

&#x1f649; 作者简介&#xff1a; 全栈领域新星创作者 &#xff1b;天天被业务折腾得死去活来的同时依然保有对各项技术热忱的追求&#xff0c;把分享变成一种习惯&#xff0c;再小的帆也能远航。 &#x1f3e1; 个人主页&#xff1a;xiezhr的个人主页 java中的字符串一、简…

C++:重定义:符号重定义:变量重定义

概述&#xff1a;在上一篇我们知道 通过 #ifndef....#defin....#endif &#xff0c; 这个解决头文件重复包含的问题 C&#xff1a;重定义&#xff1a;class类型重定义_hongwen_yul的博客-CSDN博客 避免头文件的重复包含可以有效的避免变量的重复定义&#xff0c;其实不光变量…

[附源码]java毕业设计基于web旅游网站的设计与实现

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

使用Docker开发GO应用程序

根据Stack Overflow的2022开发者调查&#xff0c;Go&#xff08;或Golang&#xff09;是最受欢迎和最受欢迎的编程语言之一。由于与许多其他语言相比&#xff0c;Go的二进制大小更小&#xff0c;开发人员经常使用Go进行容器化应用程序开发。 Mohammad Quanit在他的社区全能课程…

小程序vant-tabbar使用示例,及报错处理

小程序vant-tabbar使用示例&#xff0c;及报错处理1. 配置信息2. 添加 tabBar 代码文件3. 编写 tabBar 代码custom-tab-bar/index.tscustom-tab-bar/index.jsoncustom-tab-bar/index.wxml使小程序使用vant-tabbar组件时&#xff0c;遇到以下报错&#xff1a;Couldn’t found th…

Java基于springboot+vue的儿童玩具销售购物网站 多商家

爱玩儿是所有孩子的天性。尤其是在婴幼儿阶段。选择一个好的玩具&#xff0c;不仅能够让孩子玩儿的开心&#xff0c;而且有助于孩子智力的开发。很多家长在选择玩具的时候&#xff0c;不知道选择什么样的玩具。且当前玩具市场的玩具鱼目混杂&#xff0c;种类繁多&#xff0c;而…

SAR信号处理基础1——线性调频信号

关键字&#xff1a;线性调频信号&#xff0c;LFM信号&#xff0c;chirp信号&#xff0c;驻定相位原理&#xff08;POSP&#xff09;&#xff0c;泰勒展开&#xff0c;Taylor展开&#xff0c;脉冲压缩&#xff0c;匹配滤波&#xff0c;sinc&#xff0c;分辨率&#xff0c;峰值旁…

QProgressDialog.close()失败,进度条关闭感觉失败了,无法彻底关闭

开发环境&#xff1a;我是在deepin&#xff08;深度&#xff09;系统下开发的&#xff0c;在我本机上&#xff0c;一点问题也没有&#xff0c;但是我移植到了ubantu的机子上&#xff0c;就偶尔出现出个问题&#xff0c;出现了一个模态框&#xff0c;需要重启软件才能关闭。 问题…

Vue的computed和watch的区别是什么?

一、computed介绍 computed 用来监控自己定义的变量&#xff0c;该变量在 data 内没有声明&#xff0c;直接在 computed 里面定义&#xff0c;页面上可直接使用。 //基础使用 {{msg}} <input v-model"name" /> //计算属性 computed:{msg:function(){return …