瑞吉外卖笔记系列(2) —— 完善员工的后台系统登录功能,实现员工信息管理

news2024/9/25 23:21:36

本文档主要 完善员工的后台系统登录功能,新增员工,员工信息分页查询,启用/禁用员工账号,编辑员工信息

一、完善后台系统登录功能

1.1 问题分析

目前存在的问题是:理论上,用户必须在 http://localhost:8080/backend/page/login/login.html 登录,才能访问系统首页。但是,现在用户如果不登录,依然可以访问系统的首页 http://localhost:8080/backend/index.html

1.2 解决方案

针对该问题,解决方案主要有:使用过滤器或者拦截器,在过滤器或者拦截器中判断用户是否已经完成登录,如果没有则跳转到登录页面。

本项目选择过滤器这一解决方案 , 实现步骤为:

  1. 创建自定义过滤器 LoginCheckfilter
  2. 在启动类上加入注解 @ServletComponentScan
  3. 完善过滤器实现逻辑

过滤器具体的处理逻辑如下:

  1. 获取本次请求的URI
  2. 判断本次请求是否需要处理
  3. 如果不需要处理,则直接放行
  4. 判断登录状态,如果已登录,则直接放行
  5. 如果未登录则返回未登录结果
    在这里插入图片描述

1.3 前端代码分析

src/main/resources/backend/js/request.js 文件,前端响应拦截器的代码如下:

 // 响应拦截器
  service.interceptors.response.use(res => {
      if (res.data.code === 0 && res.data.msg === 'NOTLOGIN') {// 返回登录页面
        console.log('---/backend/page/login/login.html---')
        localStorage.removeItem('userInfo')
        window.top.location.href = '/backend/page/login/login.html'
      } else {
        return res.data
      }
    }

NOTLOGIN 字符串将会用于 后端的拦截器的实现。

1.4 代码实现

新建 java 类 src/main/java/com/idealzouhu/reggie/filter/LoginCheckFilter.java, 具体代码如下:

/**
 * 检查用户是否已经完成了登录
 */
@Slf4j
@WebFilter(filterName = "loginCheckFilter", urlPatterns = "/*")
public class LoginCheckFilter implements Filter {
    // 路径匹配器,支持通配符
    public static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();

    /**
     * 路径匹配,检测本次请求是否需要放行
     * @param urls
     * @param requestURI
     * @return
     */
    public boolean check(String[] urls, String requestURI){
        for( String url : urls){
            boolean match = PATH_MATCHER.match(url, requestURI);
            if(match){
                return true;
            }
        }
        return false;
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        // 1. 获取本次请求的URI
        String requestURI = request.getRequestURI();
        log.info("拦截到请求: {}",request.getRequestURI());

        // 2. 判断本次请求是否需要处理
        String[] urls = new String[]{        // 定义不需要处理的请求路径;
                "/employee/login",
                "/emplyee/logout",
                "/backend/**",
                "/front/**"
        };
        boolean check = check(urls, requestURI);

        // 3. 如果不需要处理,则直接放行
        if(check){
            log.info("本次请求  {} 不需要处理",request.getRequestURI());
            filterChain.doFilter(request, response);
            return;
        }

        // 4. 判断登录状态,如果已登录,则直接放行
        if(request.getSession().getAttribute("employee") != null){
            log.info("用户已登录,id为:  {} ",request.getSession().getAttribute("employee"));
            filterChain.doFilter(request, response);
            return;
        }

        // 5. 如果未登录则返回未登录结果. 通过输出流方式向客户端页面响应数据
        log.info("用户未登录");
        response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN")));
        return;
    }
}

注意,官方视频在这里少打了一个 return ,导致登录用户存放在session里面会被删掉(即误执行response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN"))) ,间接执行前端代码localStorage.removeItem('userInfo') )。

1.5 功能测试

直接访问 http://localhost:8080/backend/index.html , 看页面是否会跳转到登录页面

二、新增员工

2.1 需求分析

在后台管理系统中, 通过新增员工来添加后台系统用户。

在这里插入图片描述

2.2 数据模型

本质上,将新增的员工数据新增到 employee 表里面
在这里插入图片描述

需要注意,employee 表中对 username 字段加入了唯一约束。因为 username 是员工的登录账号,具备唯一性。
在这里插入图片描述

2.3 前端代码分析

员工列表页面为 src/main/resources/backend/page/member/list.html

 <el-button
          type="primary"
          @click="addMemberHandle('add')"
        >
          + 添加员工
</el-button>

..........

 // 添加
          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)
            }
          }

menuHandle方法的实现在 src/main/resources/backend/index.html 里面,

mounted() {
  window.menuHandle = this.menuHandle
},

 menuHandle(item, goBackFlag) {
            this.loading = true
            this.menuActived = item.id
            this.iframeUrl = item.url
            this.headTitle = item.name
            this.goBackFlag = goBackFlag
            this.closeLoading()
          }

最后,在添加员工的页面 src/main/resources/backend/page/member/add.html,点击保存按钮, 会触发 addEmployee() 方法

 submitForm (formName, st) {
            this.$refs[formName].validate((valid) => {
              if (valid) {
                if (this.actionType === 'add') {
                  const params = {
                    ...this.ruleForm,
                    sex: this.ruleForm.sex === '女' ? '0' : '1'
                  }
                  addEmployee(params).then(res => {
                    if (res.code === 1) {
                      this.$message.success('员工添加成功!')
                      if (!st) {
                        this.goBack()
                      } else {
                        this.ruleForm = {
                          username: '',
                          'name': '',
                          'phone': '',
                          // 'password': '',
                          // 'rePassword': '',/
                          'sex': '男',
                          'idNumber': ''
                        }
                      }

addEmployee() 方法的实现代码在 backend/api/member.js 里面

// 新增---添加员工
function addEmployee (params) {
  return $axios({
    url: '/employee',
    method: 'post',
    data: { ...params }
  })
}

需要注意,我将 url 改成 ‘/employee/addEmployee’

前端代码较为复杂,建议观看原视频业务开发Day2-06-新增员工_梳理程序执行流程_哔哩哔哩_bilibili

2.4 代码开发

在开发代码之前,需要梳理一下整个程序的执行过程:

  1. 页面发送ajax请求,将新增员工页面中输入的数据以json的形式提交到服务端
  2. 服务端Contraller接收页面提交的数据并调用Service将数据进行保存
  3. Service调用Mapper操作数据库,保存数据

![

  1. 在这里插入图片描述

](https://img-blog.csdnimg.cn/direct/33fdd9a32b4148eabc0bb6500e8d3782.png)

在 employee 里面新建方法 ,

  /**
     * 新增员工
     * @param employee
     * @return
     */
    @PostMapping("/addemployee")
    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());

        // 获得当前登录用户的id
        Long empID = (Long) request.getSession().getAttribute("employee");
        employee.setCreateUser(empID);
        employee.setUpdateUser(empID);

        employeeService.save(employee);

        return R.success("新增员工成功");
//        return null;  // 如果返回 null 值,会导致前端页面莫名其妙跳转到 登录页面,并删除登录信息
    }

2.5 功能测试

输入员工信息,点击 “保存”

在这里插入图片描述

在数据库里面,也可以看到相应的信息

在这里插入图片描述

另外,如果我们再次新增用户名为 1235 的用户,后台会报错

java.sql.SQLIntegrityConstraintViolationException: Duplicate entry '1235' for key 'employee.idx_username'

这是因为 username 是员工的登录账号,具备唯一性。

2.6 代码修复

前面的程序还存在一个问题:当新增员工的账号已经存在时,由于 username 具备唯一性,程序会抛出异常

java.sql.SQLIntegrityConstraintViolationException: Duplicate entry '1235' for key 'employee.idx_username'

此时需要我们进行异常捕获,通常有两种处理方式:

  1. 在Controller 方法中加入 try、catch 进行异常捕获
  2. 使用异常处理器进行全局异常捕获 (本文采用这种方式)

创建 src/main/java/com/idealzouhu/reggie/common/GlobalExceptionHandler.java, 实现代码为:

package com.idealzouhu.reggie.common;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import java.sql.SQLIntegrityConstraintViolationException;

/**
 * 全局异常处理
 */
@Slf4j
@ControllerAdvice(annotations = {RestController.class, Controller.class})
@ResponseBody
public class GlobalExceptionHandler {

    /**
     * 处理新增员工账号已经存在时抛出的异常
     * @return
     */
    @ExceptionHandler(SQLIntegrityConstraintViolationException.class)
    public R<String> exceptionHandler(SQLIntegrityConstraintViolationException ex){
        log.error(ex.getMessage());

        if(ex.getMessage().contains("Duplicate entry")){
            String[] split = ex.getMessage().split(" ");
            String msg = split[2] + "已存在";
            return R.error(msg);
        }

        return R.error("未知错误");
    }

}

2.7 总结

  1. 根据产品原型明确业务需求
  2. 重点分析数据的流转过程和数据格式
  3. 通过debug断点调试跟踪程序执行过程

在这里插入图片描述

三、员工信息分页查询

3.1 需求分析

当员工数量较多时,我们需要分页查询员工信息,便于查看。

同时,我们还可以根据员工姓名查询,即按条件分页查询

在这里插入图片描述

其中,参数主要有 page、pagesize,name。name是我们按条件分页查询的条件

在这里插入图片描述

3.2 前端代码分析

(1) List.html

员工列表页面为 src/main/resources/backend/page/member/list.html

<el-pagination
        class="pageList"
        :page-sizes="[10, 20, 30, 40]"   
        :page-size="pageSize"
        layout="total, sizes, prev, pager, next, jumper"
        :total="counts"
        :current-page.sync="page"
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
      ></el-pagination>

...................

data() {
          return {
             input: '',
             counts: 0,
             page: 1,         // 分页查询的默认值
             pageSize: 10,
             tableData : [],
             id : '',
             status : '',
          }
        }
 
 .....................
 
created() {
          this.init()
          this.user = JSON.parse(localStorage.getItem('userInfo')).username
        }
 
 .......
 
   async init () {
            const params = {
              page: this.page,
              pageSize: this.pageSize,
              name: this.input ? this.input : undefined
            }
            await getMemberList(params).then(res => {
              if (String(res.code) === '1') {
                this.tableData = res.data.records || []
                this.counts = res.data.total
              }
            }).catch(err => {
              this.$message.error('请求出错了:' + err)
            })
          },
          handleQuery() {
            this.page = 1;
            this.init();
          }

这部分代码展示了 为什么员工信息查询会每次自动请求。

:page-sizes="[10, 20, 30, 40]" : 对应 分页查询里面的下拉条, 即每页显示多少页。

pageSize: 10: 表示默认值,即每页显示 10 页

(2)getMemberList()

getMemberList() 方法的实现代码在 backend/api/member.js 里面

function getMemberList (params) {
  return $axios({
    url: '/employee/page',
    method: 'get',
    params
  })
}

(3) request.js

我们会发现一个问题:在list.html, page 和pagesize 参数是 json 格式。但是,在URI里面,参数并不是 json 格式,而是 http://localhost:8080/employee/page?page=1&pageSize=10

在 src/main/resources/backend/js/request.js , request拦截器将参数重新组装,放在 URI 的后面

  // request拦截器
  service.interceptors.request.use(config => {
    // get请求映射params参数
    if (config.method === 'get' && config.params) {
      let url = config.url + '?';
      for (const propName of Object.keys(config.params)) {
        const value = config.params[propName];
        var part = encodeURIComponent(propName) + "=";
        if (value !== null && typeof(value) !== "undefined") {
          if (typeof value === 'object') {
            for (const key of Object.keys(value)) {
              let params = propName + '[' + key + ']';
              var subPart = encodeURIComponent(params) + "=";
              url += subPart + encodeURIComponent(value[key]) + "&";
            }
          } else {
            url += part + encodeURIComponent(value) + "&";
          }
        }
      }

3.3 代码开发

在开发代码之前,需要梳理一下整个程序的执行过程:

  1. 页面发送ajax请求,将分页查询参数(page、pageSize、name)提交到服务端
  2. 服务端Controller接收页面提交的数据并调用Service查询数据
  3. Service调用Mapper操作数据库,查询分页数据
  4. Controller将查询到的分页数据响应给页面
  5. 页面接收到分页数据并通过ElementUI的Table组件展示到页面上

为了更好地实现分页查询,我们使用MP提供的分页查询:

(1)配置 MP 分页插件

创建src/main/java/com/idealzouhu/reggie/config/MybatisPlusConfig.java

package com.idealzouhu.reggie.config;

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
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        return mybatisPlusInterceptor;
    }

}

(2)创建 controller 方法

src/main/java/com/idealzouhu/reggie/controller/EmployeeController.java类里面,新建方法

 @GetMapping("/page")
    public R<Page> page(int page, int pageSize, String name){
        log.info("page = {}, pageSize = {}, name={} ", page, pageSize,name);

        // 1. 构造分页查询器
        Page pageInfo = new Page(page, pageSize);

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

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

        return R.success(pageInfo);
    }

3.4 功能测试

直接查看员工信息分页是否正常

四、启用/禁用员工账号

4.1 需求分析

在员工管理列表页面,可以对某个员工账号进行启用或者禁用操作。账号禁用的员工不能登录系统,启用后的员工可以正常登录。

需要注意的是,只有管理员 admin 具备权限,可以对所用员工账号进行启用、禁用操作。所以普通用户登录系统后启用、禁用按钮不显示。

如果某个员工账号状态为正常,则按钮显示为 禁用;如果员工账号状态为已禁用, 则按钮显示为 ”启用“。

在这里插入图片描述

4.2 前端代码分析

(1) List.html

在员工列表页面 src/main/resources/backend/page/member/list.html

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

created() {
          this.init()
          // 获取当前登录员工的账号,并赋值给模型数据
          this.user = JSON.parse(localStorage.getItem('userInfo')).username
        }
        
.................
//状态修改
          statusHandle (row) {
            this.id = row.id
            this.status = row.status
            this.$confirm('确认调整该账号的状态?', '提示', {
              'confirmButtonText': '确定',
              'cancelButtonText': '取消',
              'type': 'warning'
              }).then(() => {
              enableOrDisableEmployee({ 'id': this.id, 'status': !this.status ? 1 : 0 }).then(res => {
                console.log('enableOrDisableEmployee',res)
                if (String(res.code) === '1') {
                  this.$message.success('账号状态更改成功!')
                  this.handleQuery()
                }
              }).catch(err => {
                this.$message.error('请求出错了:' + err)
              })
            })
          }

{{ scope.row.status == '1' ? '禁用' : '启用' }}: 如果员工账号状态scope.row.status为正常(即1),则按钮显示为 禁用;如果员工账号状态为已禁用, 则按钮显示为 启用

v-if="user === 'admin'": 如果登录用户是管理员,则看到 禁用启用按钮。否则的话,则不显示。

statusHandle(): 修改员工状态的 核心函数

(2)enableOrDisableEmployee()

enableOrDisableEmployee() 方法的实现代码在 backend/api/member.js 里面

// 修改---启用禁用接口
function enableOrDisableEmployee (params) {
  return $axios({
    url: '/employee',
    method: 'put',
    data: { ...params }
  })
}

4.2 代码开发

在开发代码之前,需要梳理一下整个程序的执行过程:

  1. 页面发送ajax请求,将参数(id、status)提交到服务端
  2. 服务端Controller接收页面提交的数据并调用Service更新数据
  3. Service调用Mapper操作数据库

本质上,这段代码的作用是更改员工的 status 字段。

4.3 代码修复

问题:”禁用/启用“功能可以运行,但是数据库里面 status 状态并没有更新

**原因:**前端返回过来的json数据里面,员工 id 和其实际 id 不一样。 js 对 long 型数据进行处理时丢失精度,导致提交的 id 和 数据库中的id 不一致。

**解决方案:**在服务端给页面响应 json 数据时进行处理,将 long 型数据统一转为 String 字符串

具体实现步骤:

  1. 提供 对象转换器 JacksonObject , 基于 JackSon 进行 Java 对象到json数据的转换。 创建 src/main/java/com/idealzouhu/reggie/common/JacksonObjectMapper.java , 相应代码如下
/**
 * 对象映射器:基于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. 在 WebMvcConfig 配置类中扩展 Spring MVC 的消息转换器,在此消息转换器中使用提供对象转换器进行 Java 对象到 json 数据的转换。如果不扩展的话,那么项目会使用 Spring MVC 所使用的默认配置器。
/**
     * 扩展 MVC 框架的消息转换器
     * @param converters
     */
    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        log.info("扩展消息转换器");

        // 创建消息转换器对象
        MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();

        // 设置对象转换器, 底层使用 Jackson 将对象转为 json
        messageConverter.setObjectMapper(new JacksonObjectMapper());

        // 将上面的消息转换器对象追加到 MVC 框架的转换器集合中
        converters.add(0, messageConverter);

//        WebMvcConfigurer.super.extendMessageConverters(converters);
    }

我们可以通过调试来观察消息转换器是否添加成功

在这里插入图片描述

我们再次运行启用/禁用 功能,可以很明显观察到 json 对象的变化

在这里插入图片描述

五、编辑员工账号

5.1 需求分析

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

对于编辑员工,如果员工不存在,则是 新增员工。如果员工已存在,则是 编辑员工。因此,对于后端而言,编辑员工和新增员工的代码基本上类似。

5.2 前端代码分析

(1) add.html

注意: add.html 页面为公共页面,新增员工和编辑员工都是在此页面操作

src/main/resources/backend/page/member/add.html 里面,

created() {
  this.id = requestUrlParam('id')
  this.actionType = this.id ? 'edit' : 'add'
  if (this.id) {
    this.init()
  }
}
......
async init () {
            queryEmployeeById(this.id).then(res => {
              console.log(res)
              if (String(res.code) === '1') {
                console.log(res.data)
                this.ruleForm = res.data
                this.ruleForm.sex = res.data.sex === '0' ? '女' : '男'
                // this.ruleForm.password = ''
              } else {
                this.$message.error(res.msg || '操作失败')
              }
            })
          }

this.actionType = this.id ? 'edit' : 'add': id 有值的话,就是编辑员工。否则新增员工

(2)requestUrlParam()

src/main/resources/backend/js/index.js 里,requestUrlParam() 解析 url地址上面的参数。举个例子,http://localhost:8080/backend/page/member/add.html?id=1745800121368453122,该函数会将 id 参数动态提取出来。

//获取url地址上面的参数
function requestUrlParam(argname){
  var url = location.href
//  alert(url)
  var arrStr = url.substring(url.indexOf("?")+1).split("&")
  for(var i =0;i<arrStr.length;i++)
  {
      var loc = arrStr[i].indexOf(argname+"=")
      if(loc!=-1){
          return arrStr[i].replace(argname+"=","").replace("?","")
      }
  }
  return ""
}

(3) queryEmployeeById()

src/main/resources/backend/api/member.js里, queryEmployeeById() 根据员工 id 查询员工信息

// 修改页面反查详情接口
function queryEmployeeById (id) {
  return $axios({
    url: `/employee/${id}`,
    method: 'get'
  })
}

5.2 代码开发

在开发代码之前需要梳理一下操作过程和对应的程序的执行流程:

  1. 点击编辑按钮时,页面跳转到 add.html,并在 url 中携带参数[员工id] (例如 http://localhost:8080/backend/page/member/add.html?id=1745800121368453122
  2. 在 add.html 页面获取 url中的参数[员工id]
  3. 发送 ajax 请求,请求服务端,同时提交员工 id 参数
  4. 服务端接收请求,根据员工 id 查询员工信息,将员工信息以json形式响应给页面
  5. 页面接收服务端响应的json数据,通过VUE的数据绑定进行员工信息回显
  6. 点击保存按钮,发送ajax请求,将页面中的员工信息以json方式提交给服务端
  7. 服务端接收员工信息,并进行处理,完成后给页面响应
  8. 页面接收到服务端响应信息后进行相应处理

src/main/java/com/idealzouhu/reggie/controller/EmployeeController.java 里面, 添加以下代码:

/**
     * 根据id 编辑员工 (事实上,这段代码与下面的功能”启用/禁用员工“一样)
     * @param employee
     * @return
     */
    @PutMapping("/editEmployee")
    public R<String> editEmployee(HttpServletRequest request, @RequestBody Employee employee){
        log.info(employee.toString());

        Long empID = (Long)request.getSession().getAttribute("employee");
        employee.setUpdateUser(empID);
        employee.setUpdateTime(LocalDateTime.now());
        employeeService.updateById(employee);

        return R.success("员工信息修改成功");
    }

/**
     * 根据员工 id 查询信息
     * @param id
     * @return
     */
    @GetMapping("/{id}")
    public R<Employee> getById(@PathVariable Long id){
        log.info("根据员工id({})查询信息:", id);
        Employee employee = employeeService.getById(id);
        if(employee != null){
            return R.success(employee);
        }
        return R.error("没有查询到对应员工信息");
    }

参考资料

idealzouhu/reggie-take-out: 瑞吉外卖项目, 利用SpringBoot + SSM技术栈实现 (github.com)

黑马程序员Java项目实战《瑞吉外卖》bilibili

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

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

相关文章

LeetCode 590. N 叉树的后序遍历

590. N 叉树的后序遍历 给定一个 n 叉树的根节点 root &#xff0c;返回 其节点值的 后序遍历 。 n 叉树 在输入中按层序遍历进行序列化表示&#xff0c;每组子节点由空值 null 分隔&#xff08;请参见示例&#xff09;。 示例 1&#xff1a; 输入&#xff1a;root [1,null,…

数据结构与算法:插入排序希尔排序

数据结构与算法&#xff1a;插入排序&希尔排序 插入排序希尔排序 插入排序 假设现在你有一个有序的数组&#xff0c;你要把一个数据插入到数组中&#xff0c;保证插入后依然有序&#xff0c;要怎么做&#xff1f; 对于人来说&#xff0c;这个问题就像是在整理扑克牌&…

优化 - 重构一次Mysql导致服务器的OOM

概述 优化了一次前后端处理不当导致的CPU的一次爆机行为&#xff0c;当然&#xff0c;这和服务器的配置低也有着密不可分的关系&#xff0c;简单的逻辑学告诉我们&#xff0c;要找到真正的问题&#xff0c;进行解决&#xff0c;CPU爆机的关键点在于前后端两个方面&#xff0c;…

在CentOS中,对静态HTTP服务的性能监控

在CentOS中&#xff0c;对静态HTTP服务的性能监控和日志管理是确保系统稳定运行和及时发现潜在问题的关键。以下是对这一主题的详细探讨。 性能监控 使用工具监控&#xff1a;top、htop、vmstat、iostat等工具可以用来监控CPU、内存、磁盘I/O等关键性能指标。这些工具可以实时…

Linux中常使用的命令之ls、cd、pwd、mkdir、rmdir

ls: 列出目录 cd&#xff1a;切换目录 pwd&#xff1a;显示目前的目录 mkdir&#xff1a;创建一个新的目录 -m &#xff1a;配置文件的权限-p &#xff1a;帮助你直接将所需要的目录(包含上一级目录)递归创建起来&#xff01; rmdir&#xff1a;删除一个空的目录 注意这…

RK3568驱动指南|第十二篇 GPIO子系统-第130章 GPIO的调试方法

瑞芯微RK3568芯片是一款定位中高端的通用型SOC&#xff0c;采用22nm制程工艺&#xff0c;搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码&#xff0c;支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU&#xff0c;可用于轻量级人工…

maya显示方式及视图操作

原始图像&#xff1a; 按数字键2后&#xff08;平滑效果&#xff09;&#xff1a; 按数字键3后&#xff08;平滑效果&#xff0c;无原始外边框&#xff09;&#xff1a; 按数字键4后&#xff08;仅显示边框&#xff09;&#xff1a; 方便选择后面的点、线及面 按数字键5后&…

Pytest测试 —— 如何使用属性来标记测试函数!

在软件开发领域&#xff0c;单元测试是确保代码质量和可维护性的关键一环。随着项目的不断发展&#xff0c;测试用例的管理变得愈发复杂&#xff0c;而一些测试可能需要特殊的处理、环境或者标记。在Python中&#xff0c;我们可以通过使用属性&#xff08;Attribute&#xff09…

大语言模型向量数据库

大语言模型&向量数据库 LARGE LANGUAGE MODELSA. Vector Database & LLM WorkflowB. Vector Database for LLMC. Potential Applications for Vector Database on LLMD. Potential Applications for LLM on Vector DatabaseE. Retrieval-Based LLMF. Synergized Exampl…

解决ELK日志收集中Logstash报错的关键步

ElK执行日志收集的时候logstash报错&#xff1a; Failed to execute action {:action>LogStash::PipelineAction::Create/pipeline_id:main, :exception>“LogStash::ConfigurationError”, :message>“Expected one of [^\r\n], “\r”, “\n” at line 88, column 4…

BikeDNA(九) 特征匹配

BikeDNA&#xff08;九&#xff09; 特征匹配 特征匹配采用参考数据并尝试识别 OSM 数据集中的相应特征。 特征匹配是比较单个特征而不是研究区域网格单元水平上的特征特征的必要前提。 方法 将两个道路数据集中的特征与其数字化特征的方式以及边缘之间潜在的一对多关系进行…

what is BERT?

BERT Introduction Paper 参考博客 9781838821593_ColorImages.pdf (packt-cdn.com) Bidirectional Encoder Representation from Transformer 来自Transformer的双向编码器表征 基于上下文&#xff08;context-based&#xff09;的嵌入模型。 那么基于上下文&#xff08;…

imgaug库指南(19):从入门到精通的【图像增强】之旅

引言 在深度学习和计算机视觉的世界里&#xff0c;数据是模型训练的基石&#xff0c;其质量与数量直接影响着模型的性能。然而&#xff0c;获取大量高质量的标注数据往往需要耗费大量的时间和资源。正因如此&#xff0c;数据增强技术应运而生&#xff0c;成为了解决这一问题的…

“所有伙食开销统计:轻松查看,智能管理你的餐饮支出“

你是否经常为伙食开销感到困扰&#xff0c;不知道如何有效控制和管理&#xff1f;现在&#xff0c;有了我们的伙食开销统计工具&#xff0c;这些问题将得到轻松解决&#xff01; 首先第一步&#xff0c;我们要进入晨曦记账本并在上方功能栏里选择“查看方式”。并在弹出来的列表…

数据结构第十三弹---链式二叉树基本操作(上)

链式二叉树 1、结构定义2、手动创建二叉树3、前序遍历4、中序遍历5、后序遍历6、层序遍历7、计算结点个数8、计算叶子结点个数9、计算第K层结点个数10、计算树的最大深度总结 1、结构定义 实现一个数据结构少不了数据的定义&#xff0c;所以第一步需要定义二叉树的机构。 typ…

API Monitor简易使用教程 监控Windows dll调用 监控Windows API调用 查看函数名,参数类型,参数,返回值

先看效果&#xff0c;可以显示所有dll及windows api的指定函数调用&#xff0c;以及传递的参数查看与修改。 官网下载 也有教程 我验证使用方法 1、API Filter窗口&#xff1a;选定要监听的dll函数或windows API&#xff0c;可以打断点 选中并右键勾上Breakpoint 选 Before C…

MFC为资源对话框添加消息处理函数和初始化控件

现在我VC6新建了一个对话框工程&#xff1b;又在资源添加了一个新的对话框&#xff0c;并为新的对话框添加了名为CTestDlg的类&#xff1b; 在主对话框的cpp文件包含#include "TestDlg.h"&#xff1b; 在主对话框的cpp文件的OnInitDialog()成员函数中&#xff0c;添…

web学习笔记(十五)

目录 1.Date对象 1.1日期对象的概念 1.2Date()方法的使用 1.3Date()常用方法汇总 1.4例题&#xff1a;用函数编写一个倒计时 2.函数 2.1函数的概念 2.2函数的使用 2.3函数的参数 2.4函数的声明 2.5函数的返回值 2.6异步函数 3特殊函数类型 3.1匿名函数 3.2箭头函数…

挖种子小游戏

欢迎来到程序小院 挖种子 玩法&#xff1a;看到种子点击鼠标左键进行挖种子&#xff0c;30秒内看你能够挖多少颗种子&#xff0c;快去挖种子吧^^。开始游戏https://www.ormcc.com/play/gameStart/251 html <canvas id"canvas" width"640" height"…

BSC/平衡记分卡

一、Balanced Score Card BSC即平衡计分卡&#xff08;Balanced Score Card&#xff09;&#xff0c;是常见的绩效考核方式之一&#xff0c;是从财务、客户、内部运营、学习与成长四个角度&#xff0c;将组织的战略落实为可操作的衡量指标和目标值的一种新型绩效管理体系。 是…