文章目录
🌕博客x主页:🌕!
🌎文章说明:SpringBoot项目-瑞吉外卖【day02】定制设计定制设计员工管理业务开发🌎
✅系列专栏:
🌴本篇内容:定制设计对黑马的瑞吉外卖项目的day02定制设计进行笔记和项目实现🌴
☕️每日一语:人有退路,定制设计就有些许安全感。定制设计等到哪一天,定制设计你真没了退路,定制设计你就发现眼前哪条路都能走,也能通。☕️
🚩 交流社区:(定制设计优质编程社区)
前言
定制设计今天是项目开发的第二天。当然,定制设计我不是第二天就写好了定制设计相应的功能,定制设计毕竟能力有限。定制设计照猫画虎也得自己思考定制设计思考再起笔吧!
员工管理业务开发
定制设计完善登录功能
问题分析
定制设计前面我们已经完成了后定制设计台系统的员工登录功能开发,定制设计但是还存在一个问题:定制设计用户如果不登录,定制设计直接访问系统首页面,定制设计照样可以正常访问。
定制设计这种设计并不合理,定制设计我们希望看到的效果应该是,定制设计只有登录成功后才可以定制设计访问系统中的页面,定制设计定制设计如果没有登录则跳转到登录页面。
那么,定制设计具体应该怎么实现呢?
定制设计答案就是使用过滤器或者,定制设计在过流器成者拦截器中定制设计判断用户是否已经完成登录,如果没有登录则跳转到登录页面。
定制设计那我们选择过滤器还是拦截器呢?定制设计现在不能全都要,定制设计所以我这里选择用的是过滤器。定制设计在后面优化的时候我们定制设计再试试拦截器。
代码实现
定制设计实现步骤如下:
一、定制设计创建自定义过滤器LoginCheckFilter
定制设计见名知意嘛,定制设计登录检查过滤器:
package com.example.filter;/** * @author 定制设计不止于梦想 * @date 2022/11/13 17:23 */public class LoginCheckFilter {}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
二、定制设计在启动类上加入注解@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 } },
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
上面是一个前端响应拦截器,就是我们发请求,后台处理给的响应信息会被响应拦截器截取。当我们未登录返回登录结果时,应当按照它给的要求格式返回,这样前端的代码才能正确处理并执行正确的操作(好鸡肋,感觉严重耦合在一起)。
这个过程中的难点是判断是否需要处理。那么我们来说说什么情况下需要处理,什么情况下需要放行。
一、前端向后台的controller层发送的请求需要处理。这个毋庸置疑。二、静态资源应该放行。什么静态资源?所有静态资源,这样岂不是让别人都能看到你的资源了?看到就看到呗,真正有用的数据都要走后端的controller获取,他看到你的页面也没事,你的数据并不会被看到三、退出、登录请求放行。要退出就已经说明人已经登录了,要登录当然放行,不然就死循环了。
- 1
- 2
- 3
上面分析已经做好了,现在应该把代码整一整
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; }}
- 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
- 55
- 56
- 57
- 58
- 59
- 60
在第五步,是我们要重点注意的,因为前端的响应拦截器需要的信息是这样的
统一格式中的error中的code都统一为了0,msg是我们自己可以设置的,前端需要什么,我们就给他返回什么。
说明:
private static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();
- 1
这是一个路径匹配器,我们在设置"/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("新增员工成功"); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
功能测试
可以看到,我们已经测试通过了,但是上面还是存在一些问题的,什么问题?异常的问题
统一处理异常
报的是后台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@Slf4jpublic 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("未知名错误,请重新输入信息"); }}
- 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
验证:
要说明的是,这里的功能还十分的不完善,比如手机号肯定不能重复,如果重复应该提示,该手机号已经绑定,身份证肯定不能重复吧,员工姓名可以重复,同名的人多了去了。这是后台的处理逻辑,那前台的呢?哪里出错你应该在哪提示,并且删除表格里的数据吧?只能说我们不是前端的,不能瞎动前端代码,但是这些代码漏洞很多。
员工信息分页查询
需求分析
系统中的员工很多的时候,如果在一个页面中全部展示出来会显得比较乱,不便于查看,所以一般的系统中都会以分页的方式来展示列表数据。
首先我们要看的是,当我们点击登录并且进入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; }}
- 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
有了分页插件,现在我们使用分页方法就会被拦截,并进行处理
先创建分页构造器
代码如下:
@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); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
这里在页面展示顺序的时候,是按照更新时间降序输出的
功能测试
看看,不指定姓名能不能查询:
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("员工信息修改失败");
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
测试
测试没有报错,但是有问题,什么问题?看到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); }}
- 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
有了对象转换器之后,在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); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
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("没有查询到用户"); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
功能测试
当我们点击修改大朗时,跳转页面:
现在我更改其手机号码:13512345678
注意看:这个选项…
ok兄弟们,看它看它,已经完成了,证明我们的程序没有错误。
总结
这是本次项目的第二天,由于各种关系,其实我没有在第二天就写好,而是推迟了一天,在第三天晚上才把第二天的内容整理好,为什么这么慢呢?一是时间不充裕,尤其是现在临近期末,也得为期末早做打算。还有就是,咱写代码,总得自己思考吧。不能把老师的抄了就是自己的啦。
在做这个项目中,可以发现,基本上都是crud,但是有的地方又需要想象力。比如全局处理异常,要想想出现什么情况下用到它,这些都是需要经验的,而项目就是积累经验的过程,所以兄弟们,咱项目得好好做。