10.26 瑞吉外卖 DAY1

1.头 所学内容出处

【黑马程序员2022新版SSM框架教程_Spring+SpringMVC+Maven高级+SpringBoot+MyBatisPlus企业实用开发技术】 https://www.bilibili.com/video/BV1Fi4y1S7ix?p=31&share_source=copy_web&vd_source=c8ae4150b2286ee39a13a79bbe12b843

2.所学内容概述

了解软件开发整体介绍

image-20231002072009979

image-20231002072033394

开发环境的搭建

数据库环境的搭建

课件提供了sql文件,可以直接source 导入mysql中 早就习以为常了

Maven项目创建

也很简单,普通的maven项目,复习导入坐标和yaml文件,因为不是直接创建的springBoot 项目,所以要创建Boot程序入口

3.1 后台登录开发

先创建一个实体类和mapper以及service

再封装一个R作为返回的结果类
给EmployeeController类添加一个login方法

  • @RequestBody 主要用于接收前端传递给后端的json字符串(请求体中的数据)
  • HttpServletRequest 作用:如果登录成功,将员工对应的id存到session一份,这样想获取一份登录用户的信息就可以随时获取出来
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
JAVA

@Slf4j
@RestController
@RequestMapping("/employee")
public class EmployeeController {
@Autowired
private EmployeeService employeeService;
@PostMapping("/login")
public R<Employee> login(HttpServletRequest request, @RequestBody Employee employee){//接收前端的json数据,这个json数据是在请求体中的
// 1、将页面提交的密码password进行md5加密处理
String password = employee.getPassword();//从前端用户获取到登录时候的密码
password = DigestUtils.md5DigestAsHex(password.getBytes()); //加密
// 2、根据页面提交的用户名username查询数据库
LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper<>(); //泛型需要填写Employee
queryWrapper.eq(Employee::getUsername,employee.getUsername()); //eq用lambda::
//在设计数据库的时候我们对username使用了唯一索引,所以这里可以使用getOne方法
Employee emp = employeeService.getOne(queryWrapper);
// 3、如果没有查询到则返回登录失败结果
if (emp == null){
return R.error("用户不存在");
}
// 4、密码比对,如果不一致则返回登录失败结果
if (! emp.getPassword().equals(password)){
return R.error("密码错误");
}
// 5、查看员工状态,如果为已禁用状态,则返回员工已禁用结果
if (emp.getStatus() == 0){
return R.error("用户已被禁用");
}
// 6、登录成功,将员工id存入Session并返回登录成功结果
request.getSession().setAttribute("employee",emp.getId());
//把从数据库中查询到的用户返回出去
return R.success(emp);
}
//员工退出
@PostMapping("logout")
public R<String> logout(HttpServletRequest request){
//清除Session中当前登录员工的id
request.getSession().removeAttribute("employee");
return R.success("退出成功");
}
}

3.2后台系统退出功能

这个比较简单 点击按钮退出到登陆页面就行了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
JAVA

/**
* 退出功能
* ①在controller中创建对应的处理方法来接受前端的请求,请求方式为post;
* ②清理session中的用户id
* ③返回结果(前端页面会进行跳转到登录页面)
* @return
*/
@PostMapping("/logout")
public R<String> logout(HttpServletRequest request){
//清理session中的用户id
request.getSession().removeAttribute("employee");
return R.success("退出成功");
}

3. BUG点

难点(关键代码或关键配置,BUG截图+解决方案)

3.3 完善登录功能

之前的登陆功能是有个bug的,像之前web的一个登陆案例,直接输入地址的话,就可以跳过登录页面,达到不登录就能进入需要登录的 页面,之前web是用过滤器的,现在用拦截器解决这个小bug

要先在启动项上面加入@ServletComponentScan注解 识别bean

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
JAVA

/**
* 检查用户是否已经完成登陆
* filterName过滤器名字
* urlPatterns拦截的请求,这里是拦截所有的请求
*/
@WebFilter(filterName = "LongCheckFilter", urlPatterns = "/*")
@Slf4j
public class LoginCheckFilter implements Filter {
//路径匹配器,支持通配符
public static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();
@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();
//定义不需要处理的请求路径 比如静态资源(静态页面我们不需要拦截,因为此时的静态页面是没有数据的)
String[] urls = new String[]{
"/employee/login",
"/employee/logout",
"/backend/**",
"/front/**"
};
log.info("拦截到的请求:{}",requestURI);
//2、判断本次请求是否需要处理
boolean check = check(urls, requestURI);
//3、如果不需要处理,则直接放行
if (check){
//对请求进行放行
filterChain.doFilter(request,response);
return;
}
//4、判断登录状态,如果已登录,则直接放行
Object employee = request.getSession().getAttribute("employee"); //用户登录状态
if (employee != null){
log.info("用户已登录,用户id为:{}",employee);
//对请求进行放行
filterChain.doFilter(request,response);
return;
}
log.info("用户未登录");
//5、如果未登录则返回未登录结果,通过输出流方式向客户端页面响应数据,具体响应什么数据,看前端的需求,然后前端会根据登陆状态做页面跳转
response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN")));
}

public boolean check(String[] urls, String requestURI){
for (String url: urls){
boolean match = PATH_MATCHER.match(url, requestURI);
if (match){
return true;
}
}
return false;
}
}

4.扩展学习部分

5.总结

刚进入瑞吉外卖,下载了一些资料,没找到老师的官方的ppt文档,就CSDN去搜的,第一天的任务不是很难,主要是帮助回看一下springboot的部分,算是小复习,就做了一个登录和退出,还有个登录的小BUG,基本都是后台的代码,前端的一些功能都做好了,后端加bean,调用一下响应和请求就好了,比较基础的还是。学习方法就是看老师过一遍功能如何实现,如何测试,然后就自己试着去敲,慢慢做出来,这样学,进度可能会有些慢,但是能搞清楚每一块是干嘛的,每个注解和类的作用和功能。

10.27 瑞吉外卖 DAY2

1.头:日期、所学内容出处

【黑马程序员2022新版SSM框架教程_Spring+SpringMVC+Maven高级+SpringBoot+MyBatisPlus企业实用开发技术】 https://www.bilibili.com/video/BV1Fi4y1S7ix?p=31&share_source=copy_web&vd_source=c8ae4150b2286ee39a13a79bbe12b843

2.所学内容概述💻

添加员工

执行流程分析

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

具体实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
JAVA

@PostMapping
public R<String> save(HttpServletRequest request, @RequestBody Employee employee) {
log.info("新增的员工信息:{}", employee.toString());
//设置默认密码123456 MD5加密
employee.setPassword(DigestUtils.md5DigestAsHex("123456".getBytes()));
////设置createTime和updateTime
employee.setCreateTime(LocalDateTime.now());
employee.setUpdateTime(LocalDateTime.now());

// //根据session来获取创建人的id
Long empId = (Long) request.getSession().getAttribute("employee");

//设置id
employee.setCreateUser(empId);
employee.setUpdateUser(empId);

//存入数据库
employeeService.save(employee);
return R.success("添加员工成功");
}

完善全局异常处理

现在的代码其实是有BUG存在的,username不能重复,因为在建表的时候设定了unique,只能存在唯一的username,如果存入相同的username则会报错
java.sql.SQLIntegrityConstraintViolationException: Duplicate entry ‘Kyle’ for key ‘employee.idx_username’
看的出来报错类是SQLIntegrityConstraintViolationException

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
JAVA

@Slf4j
@RestControllerAdvice
@ControllerAdvice
public class GlobalExceptionHandler {

@ExceptionHandler(SQLIntegrityConstraintViolationException.class)
public R<String> exceptionHandler(SQLIntegrityConstraintViolationException sqlBug){
log.error(sqlBug.getMessage());
//包含Duplicate entry是说明有条目重复
if (sqlBug.getMessage().contains("Duplicate entry")){
//对字符串切片
String[] error = sqlBug.getMessage().split(" ");
//Duplicate entry 'zhangsan' for key 'employee.idx_username'
//这句日志信息 下标为2的刚好是用户名 返回对应用户名的报错信息就好了
String username = error[2];
log.error(username +"用户已存在");
return R.error(username +"用户已存在");
}
return R.error("未知错误");
}
}

员工信息分页查询

添加MP自带的分页插件 前段时间刚写过分页 还是很熟悉的

1
2
3
4
5
6
7
8
9
10
11
JAVA
@Configuration
public class MybatisPlusConfig {

@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return mybatisPlusInterceptor;
}
}

看前端代码利用检查功能,发现是get请求 /page 利用Rest规范 写业务逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
JAVA

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

//构造条件构造器
LambdaQueryWrapper<Employee> wrapper = new LambdaQueryWrapper<>();

//添加过滤条件(当我们没有输入name时,就相当于查询所有了)
wrapper.like(StringUtils.isNotEmpty(name),Employee::getName,name);

//并对查询的结果进行降序排序,根据更新时间
wrapper.orderByDesc(Employee::getUpdateTime);

//执行查询
employeeService.page(pageInfo,wrapper);
return R.success(pageInfo);
}

可以修改显示一页多少行,直接在前端的comment包中的list.html中修改

启用/禁用 员工账户

其实很简单对于后端来说,权限问题只有管理员才能使用,这样的功能是在前端实现的,后端的话只要点击按钮的时候注入对应的Rest请求,就好了。
启用、禁用员工账号,本质上就是一个更新操作,也就是对status状态字段进行操作在Controller中创建update方法,此方法是一个通用的修改员工信息的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
JAVA

@PutMapping
public R<String> Update(HttpServletRequest request, @RequestBody Employee employee){
log.info(employee.toString());

Long empId = (Long) request.getSession().getAttribute("employee"); //获取id
employee.setUpdateUser(empId); //设置更新用户id
employee.setUpdateTime(LocalDateTime.now()); //更新时间为当前时间
employeeService.updateById(employee);/ /调用update方法

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

出现了问题,ajdx返回的id值是和实际的id值不一致,是js对Long类型的数据处理时候丢失了精度
json数据时进行处理,将Long型数据统一转为String字符串
直接把课件中的 对象映射器JacksonObjectMapper 复制到common包中
扩展Mvc框架中的消息转换器

1
2
3
4
5
6
7
8
9
JAVA
@Override
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
//设置对象转化器,底层使用jackson将java对象转为json
messageConverter.setObjectMapper(new JacksonObjectMapper());
//将上面的消息转换器对象追加到mvc框架的转换器集合当中(index设置为0,表示设置在第一个位置,避免被其它转换器接收,从而达不到想要的功能)
converters.add(0, messageConverter);
}

编辑员工信息

先跟着老师的文档分析了前端代码是如何实现页面的 回显什么也是前端所实现的。

我所实现的服务端接受请求,并根据员工id查询员工信息,并将员工信息以json形式响应给页面

1
2
3
4
5
6
7
8
9
10
JAVA
@GetMapping("/{id}")
public R<Employee> getById(@PathVariable Long id){
log.info("根据id查询员工信息...");
Employee employee = employeeService.getById(id);
if (employee != null){
return R.success(employee);
}
return R.error("没有此用户的信息");
}

服务端接受员工信息,并进行处理,完成后给页面响应
由于修改员工信息也是发送的PUT请求,与之前启用/禁用员工账号是一致的,而且前面我们已经写过了PUT请求的Controller层
所以当我们点击保存按钮时,调用submitForm函数,而在submitForm函数中我们又调用了editEmployee函数,发送PUT请求,实现修改功能,直接就调用前面启动/禁用员工账户的update方法了,所以只用实现根据id查询员工信息就行了

公共字段填充

前面我们已经完成了对员工数据的添加与修改,在添加/修改员工数据的时候,都需要指定一下创建人、创建时间、修改人、修改时间等字段,而这些字段又属于公共字段,不仅员工表有这些字段,在菜品表、分类表等其他表中,也拥有这些字段。所以下面做菜单页面的时候为了方便,降低耦合度,可以把这些字段称为公共字段。

实现方式

创建一个类 实现MyMetaObjectHandler 接口 利用ThreadLocal中的方法实现对id的获取
前面更新和插入时候 对时间和用户id的修改 可以注释掉了

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
JAVA


@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
//插入的时候
@Override
public void insertFill(MetaObject metaObject) {
log.info("公共字段自动填充(insert)....");
log.info(metaObject.toString());
metaObject.setValue("createTime", LocalDateTime.now());
metaObject.setValue("updateTime", LocalDateTime.now());
metaObject.setValue("createUser",BaseContext.getCurrentId());
metaObject.setValue("updateUser",BaseContext.getCurrentId());
}

//更新的时候
@Override
public void updateFill(MetaObject metaObject) {
log.info("公共字段自动填充(update)....");
log.info(metaObject.toString());
metaObject.setValue("updateTime", LocalDateTime.now());
metaObject.setValue("updateUser",BaseContext.getCurrentId());
}
}

3. BUG点

难点(关键代码或关键配置,BUG截图+解决方案)
今天基本没什么bug,小bug就是导入包的时候导入错了,导致对应类的方法没找到,但是很快就反应过来了。

4.扩展学习部分

5.总结

今天学习难度一般,学习状态极佳,静下心来完成了项目对员工的基本功能实现,发现所用到的很多方法都是之前所没有接触和学过的,也有一些小技巧是前面某个案例所使用的,像分页什么的,因为在赶进度,想快点把项目做完,基本都是二倍数过一遍视频,了解原理,代码使用,然后就开始自己敲了,感觉这个项目前端方面其实比较难,我现在做来,后端处理一下请求就好了,一些复杂的功能都是前端所实现的,最后做了一个公共字段的自动填充,其实有点麻烦的,而且不是很理解,用到了多线程解决,自己其实是看一遍视频,自己就能实现了,也大致明白这样做的原因。

10.28 github hexo 个人博客搭建

1.头:日期、所学内容出处

b站以及QQ请教 还有github博客讲解

2.所学内容概述

实现流程

开始需要安装ndoejs
然后npm 下载hexo 和hexo-cli
github创建自己仓库,用git命令绑定
hexo也绑定仓库
npm可以找别人的主题模版 下载到global仓库
分析代码 看主题步骤 跟着做
hexo clean 清理缓存
hexo g 上传文件
hexo s 启动服务
hexo d 上传到github仓库 直接到页面

目前的笔记页面效果如下,还有很多地方需要完善,想到什么等闲下来再去做好,已经知道一些地方的原理了。

image-20231002072109466

image.png

image-20231002072125643

3. BUG点

难点(关键代码或关键配置,BUG截图+解决方案)
看报错信息以为是butterfly的源文件被我不小心修改了,然后我去github中把之前备份的拉下来,重写添加了一遍,还是报错,那唯一和初始不同的地方只有,yml文件了,然后拿默认的和原本的对比,发现在添加社交图标的时候,qq和微信的图标标注了,但是后面没输入信息。把两个注释掉,就没报错了,但是很奇怪,因为之前yml文件报错,都会说哪一行报错,这个应该是骗过了js的编译。

image-20231002072147023

4.扩展学习部分

5.总结

今天搞了一天的个人博客的小开发,昨天看到一个大佬记的笔记,发现页面很好看也很清楚,但是不知道是什么笔记网站,然后问他,发现是利用github和hexo搭建的自己的网站,可以放md文件,一些笔记可以梳理,我觉得这样很好,今天就搞了出来,大致基本都弄出来了,还没有美化,过程还是有很多磕磕绊绊的,尤其是npm下载的时候,太吃网络了,之前一直下不下来,有点看运气,github有时候也访问不进去。等项目做完了,美化一下,把自己之前的笔记,都上传到自己的博客网站,个人网站已经建好了,因为还没实现typora上传图片,这样会导致自己的笔记,图片会丢失,所以明天把上传问题解决一下。
页面如下 把去年学的一点笔记当作实验了效果还可以
https://u7-u7.github.io/

10.29 分类管理功能实现

1.头:日期、所学内容出处

【黑马程序员2022新版SSM框架教程_Spring+SpringMVC+Maven高级+SpringBoot+MyBatisPlus企业实用开发技术】 https://www.bilibili.com/video/BV1Fi4y1S7ix?p=31&share_source=copy_web&vd_source=c8ae4150b2286ee39a13a79bbe12b843

2.所学内容概述

今天先完成了公共字段的自动填充 对更新时间和创建时间,这样对后面菜品和菜单,套餐等等页面功能实现就不需要再写一遍了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
JAVA

@Component
@Slf4j
//利用MetaObjectHandler类 实现还是很简单 易懂的
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
log.info("公共字段自动填充(insert)...");
log.info(metaObject.toString());
metaObject.setValue("createTime", LocalDateTime.now());
metaObject.setValue("updateTime", LocalDateTime.now());
}

@Override
public void updateFill(MetaObject metaObject) {
log.info("公共字段自动填充(update)...");
log.info(metaObject.toString());
metaObject.setValue("createTime", LocalDateTime.now());
metaObject.setValue("updateTime", LocalDateTime.now());
}
}

完成了菜品的基本增删改查的操作(代码比较多,就不放在笔记中去了,需要注意的点也在代码中注解了),难度不是很大,在之前员工中一样,实现方法的流程都是差不多的,分析页面请求,看前端代码,写后端代码。

在删除功能完善的时候,又创建了一个自定义异常类 在删除不能删除的信息的时候,抛出自定义运行类的异常

1
2
3
4
5
6
7
8
9
10
11
12
JAVA
public class CustomException extends RuntimeException{ //运行时异常
public CustomException(String msg){
super(msg);
}
}
JAVA
@ExceptionHandler(CustomException.class)
public Result<String> exceptionHandler(CustomException exception) {
log.error(exception.getMessage());
return Result.error(exception.getMessage());
}

3. BUG点

难点(关键代码或关键配置,BUG截图+解决方案)

删除页面显示 删除成功 但是数据依旧存在 不知道原因 看返回的日志中id=null 也就是根本没有获取到id的值。

image-20231002072201985

发现前端 发送post 请求的时候 页面是?ids id后面带了一个s 应该前端的问题,把方法内参数id修改成ids 没问题了。这个请求的设置在js目录下面的category.js 19行 上面写着ids 应该是打错了 因为我看老师的代码是id

image-20231002072217084

4.扩展学习部分

把之前hexo中图片无法显示的问题,解决了,申请了一个免费的图库,之前原本尝试过gitee图库和bilibili图库,不知道为什么到了hexo中是不显示的,gitee图库,typora一直都验证不到,插件下载总是失败,具体原因也不知道。使用的自定义web图床也只能上传2000张图片,等到放不下了,就要考虑换图床了。

image-20231002072228219

image-20221031082701258

5.总结

今天学习内容简单,因为今天是周末,在寝室学习的,学习效率就一般了,下午还去练车了,基本只学了一上午到2点,学习内容很简单,基本都是自己独立完成的,看业务需求是对菜单功能完善,自己去前端页面看请求方式,进行需求分析一下,自己就能打出来了,出了点小插曲,好在顺利解决了,解决bug的过程还是蛮顺利的,也明白了参数名对代码的影响,一定要统一好。然后在晚上又去把博客图片无法显示的问题解决了一下,过两天还是换一个图床比较好。

10.31 菜品和套餐功能实现

1.头:日期、所学内容出处

【黑马程序员2022新版SSM框架教程_Spring+SpringMVC+Maven高级+SpringBoot+MyBatisPlus企业实用开发技术】 https://www.bilibili.com/video/BV1Fi4y1S7ix?p=31&share_source=copy_web&vd_source=c8ae4150b2286ee39a13a79bbe12b843

2.所学内容概述

对菜品和套餐基本功能的实现,因为有的参数是实体类不满足接收的参数,需要创建导入Dto层的类,封装页面提交数据。其实就是把不能接受的参数,重写一下方法,封装为list,再循环赋值,就好了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
JAVA

@Service
public class DishServiceImpl extends ServiceImpl<DishMapper, Dish> implements DishService {
@Autowired
private DishFlavorService dishFlavorService;

@Override
public void saveWithFlavor(DishDto dishDto) {
//将菜品数据保存到dish表
this.save(dishDto);
//获取dishId
Long dishId = dishDto.getId();
//将获取到的dishId赋值给dishFlavor的dishId属性
List<DishFlavor> flavors = dishDto.getFlavors();
for (DishFlavor dishFlavor : flavors) {
dishFlavor.setDishId(dishId);
}
//同时将菜品口味数据保存到dish_flavor表
dishFlavorService.saveBatch(flavors);
}
}

注意点!!!

多表操作的时候需要在方法上面加@Transactional,我比较偷懒就直接在业务层Impl类上面加了。然后运行类上面加@EnableTransactionManagement

3. BUG点

难点(关键代码或关键配置,BUG截图+解决方案)

难点写在扩展学习部分了

4.扩展学习部分

因为在视频中和博客中,对有一个列表的stream().map加lambda的方式,一下子没怎么懂,然后就去看了视频,对代码的解释,以及作用,看弹幕,很多人用增强for循环做了出来,因为暑假学了scala,看了一会他的代码也大致的懂了,然后自己去用for循环,发现写出来似乎更方便,而且可读性高,效率倒是还没有去测试过,不过这种小项目,应该相差不大,效率分析过了应该是lambda快很多,用stream流。那一块lambda也是今天的难点所在。

两种方式对比

  • stream流
  • 增强for
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
JAVA

@GetMapping("/page")
public Result<Page> page(int page, int pageSize, String name) {
Page<Setmeal> pageInfo = new Page<>(page, pageSize);
Page<SetmealDto> dtoPage = new Page<>(page, pageSize);
LambdaQueryWrapper<Setmeal> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.like(name != null, Setmeal::getName, name);
queryWrapper.orderByDesc(Setmeal::getUpdateTime);
setmealService.page(pageInfo, queryWrapper);
BeanUtils.copyProperties(pageInfo, dtoPage, "records");
List<Setmeal> records = pageInfo.getRecords();
//stream流 调用records中元素 拷贝给新建的setmealDto 再通过collect转换为list
List<SetmealDto> list = records.stream().map((item) -> {
SetmealDto setmealDto = new SetmealDto();
BeanUtils.copyProperties(item, setmealDto);
Long categoryId = item.getCategoryId();
Category category = categoryService.getById(categoryId);
if (category != null) {
setmealDto.setCategoryName(category.getName());
}
return setmealDto;
}).collect(Collectors.toList());
dtoPage.setRecords(list);
return Result.success(dtoPage);
}

5.总结

今天学习难度稍难,而且下午练了回车,但是今日的学习状态极佳,一股脑扎进去敲代码。今天的难点其实是在多表操作中,因为在菜品功能和套餐中,都有调用另外一个关联表的操作,就需要用LambdaQueryWrapper进行公共字段匹配,有点像sql中的多表连接,但是是用java实现的,和left join这样差不多,LambdaQueryWrapper就是类似于on,实现连接条件,还有一个lambda对列表的处理,分页查询那边,代码量有点太大了,但是如果分析好步骤,自己也是可以敲出来的。其他的修改和删除操作,也比之前的稍难点,需要自定义在业务层写方法,进行一个自定义处理,因为有些条件是需要添加的,很多categoryId是需要后面添加的。总体来说今天学习的内容还是很丰富的,早上做文件上传和下载,把java基础的流又算复习了一遍,明天状态好的话,项目的简单实现应该就完成了,再花个两三天把redis和优化解决。

11.1 移动端功能的实现

1.头:日期、所学内容出处

【黑马程序员2022新版SSM框架教程_Spring+SpringMVC+Maven高级+SpringBoot+MyBatisPlus企业实用开发技术】 https://www.bilibili.com/video/BV1Fi4y1S7ix?p=31&share_source=copy_web&vd_source=c8ae4150b2286ee39a13a79bbe12b843

2.所学内容概述

移动端功能实现(过段时间,会写在自己博客中,笔记内容就不放了,代码很多)

https://u7-u7.github.io/这里会放代码,以及流程梳理

修改手机验证 为邮箱

教程是用手机发送一个虚假的请求验证码输入验证,但是手机号要真正实现是要钱的,突然记得之前自己学过邮箱的发送,然后自己去改成了自己的邮箱,把邮箱的SMTP打开,是可以发送的,自己改前端代码的时候有点问题,去CSDN搜到了邮箱的正则匹配的表达式,然后页面把手机号都改成了邮箱,验证码也实现了,但是发现验证码是用equals的这样大小写一定要统一,我们日常使用是不用的,就改成了不区分大小写,倒是不难。

准备工作

导入坐标

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
XML

<!-- https://mvnrepository.com/artifact/javax.activation/activation -->
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.mail/mail -->
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.7</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-email -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-email</artifactId>
<version>1.4</version>
</dependency>

发送邮箱的工具类 带测试

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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
JAVA

package com.itheima.reggie.Utils;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Properties;

import javax.mail.Authenticator;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMessage.RecipientType;

public class MailUtils {
public static void main(String[] args) throws MessagingException {
//可以在这里直接测试方法,填自己的邮箱即可
sendTestMail("1452582554@qq.com", new MailUtils().achieveCode());
}

public static void sendTestMail(String email, String code) throws MessagingException {
// 创建Properties 类用于记录邮箱的一些属性
Properties props = new Properties();
// 表示SMTP发送邮件,必须进行身份验证
props.put("mail.smtp.auth", "true");
//此处填写SMTP服务器
props.put("mail.smtp.host", "smtp.qq.com");
//端口号,QQ邮箱端口587
props.put("mail.smtp.port", "587");
// 此处填写,写信人的账号
props.put("mail.user", "1452582554@qq.com");
// 此处填写16位STMP口令
props.put("mail.password", "vxccjkvvlrokgigh");
// 构建授权信息,用于进行SMTP进行身份验证
Authenticator authenticator = new Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
// 用户名、密码
String userName = props.getProperty("mail.user");
String password = props.getProperty("mail.password");
return new PasswordAuthentication(userName, password);
}
};
// 使用环境属性和授权信息,创建邮件会话
Session mailSession = Session.getInstance(props, authenticator);
// 创建邮件消息
MimeMessage message = new MimeMessage(mailSession);
// 设置发件人
InternetAddress form = new InternetAddress(props.getProperty("mail.user"));
message.setFrom(form);
// 设置收件人的邮箱
InternetAddress to = new InternetAddress(email);
message.setRecipient(RecipientType.TO, to);
// 设置邮件标题
message.setSubject("u7's Blog 邮件测试");
// 设置邮件的内容体
message.setContent("尊敬的用户:你好!\n注册验证码为:" + code + "(有效期为一分钟,请勿告知他人)", "text/html;charset=UTF-8");
// 最后当然就是发送邮件啦
Transport.send(message);
}

public static String achieveCode() { //由于数字 1 、 0 和字母 O 、l 有时分不清楚,所以,没有数字 1 、 0
String[] beforeShuffle = new String[]{"2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F",
"G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a",
"b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v",
"w", "x", "y", "z"};
List<String> list = Arrays.asList(beforeShuffle);//将数组转换为集合
Collections.shuffle(list); //打乱集合顺序
StringBuilder sb = new StringBuilder();
for (String s : list) {
sb.append(s); //将集合转化为字符串
}
return sb.substring(4, 8);
}
}

修改拦截器

1
2
3
4
5
6
7
8
9
JAVA
String[] urls = new String[]{
"/employee/login",
"/employee/logout",
"/backend/**",
"/front/**",
"/user/sendMsg",//移动端发送短信
"/user/login"
};

判断用户是否登录

1
2
3
4
5
6
7
8
9
JAVA
//判断用户是否登录
if(request.getSession().getAttribute("user") != null){
log.info("用户已登录,用户id为:{}",request.getSession().getAttribute("user"));
Long userId = (Long)request.getSession().getAttribute("user");
BaseContext.setCurrentId(userId);
filterChain.doFilter(request,response);
return;
}

修改的前段页面 (把手机号都先改成邮箱登录) 然后修改 front中的login.html 判断手机号的正则表达式换成判断邮箱的正则表达式 ^\w+([-+.]\w+)@\w+([-.]\w+).\w+([-.]\w+)*$(上网搜的)

发送验证码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
JAVA

@PostMapping("/sendMsg")
//请求体/user/sendMsg
public R<String> sendMsg(@RequestBody User user, HttpSession session) throws MessagingException {

String phone = user.getPhone();
if (!phone.isEmpty()) {
//随机生成一个验证码
String code = MailUtils.achieveCode();
log.info(code);
//这里的phone其实就是邮箱,code是我们生成的验证码
MailUtils.sendTestMail(phone, code);
//验证码存session,方便后面拿出来比对
session.setAttribute(phone, code);
return R.success("验证码发送成功");
}
return R.error("验证码发送失败");
}

邮箱收到了就成功了就可以写login登录的实现了 顺利完成

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
JAVA

@PostMapping("/login")
public R<User> login(@RequestBody Map map, HttpSession session) {
log.info(map.toString());
//获取邮箱
String phone = map.get("phone").toString();
//获取验证码
String code = map.get("code").toString();
//从session中获取验证码
String codeInSession = session.getAttribute(phone).toString();
String codeInSessionUpp = codeInSession.toUpperCase(); //全部变成大写
//比较这用户输入的验证码和session中存的验证码是否一致
String upperCase = code.toUpperCase(); //全部变成大写 这样输入验证码就不需要大小写了
if (upperCase.equals(codeInSessionUpp)) {
//如果输入正确,判断一下当前用户是否存在
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
//判断依据是从数据库中查询是否有其邮箱
queryWrapper.eq(User::getPhone, phone);
User user = userService.getOne(queryWrapper);
//如果不存在,则创建一个,存入数据库
if (user == null) {
user = new User();
user.setPhone(phone);
userService.save(user);

user.setName("用户" + codeInSession);
}
//存个session,表示登录状态
session.setAttribute("user",user.getId());
//并将其作为结果返回
return R.success(user);
}
return R.error("登录失败");
}

3. BUG点

难点(关键代码或关键配置,BUG截图+解决方案)

输入验证码以后,就自动又跳会登录页面,浏览器没有login 的请求,看日志跳到了最后的用户未登录,说明check没有匹配上,检查代码,发现拦截器的数组中,“/user/login” 少了一个/,加上以后顺利解决了问题

image-20231002072244145

客户端list查询找的时候,因为调用的是同一个请求,但是我一直没有显示,找不到原因,后面发现自己写的list代码和老师的有一些区别,有一块条件判断的时候,我少加了一个 不等于null的判断,导致我的type在前端显示是null

1
2
JAVA
wrapper.eq(category.getType() != null,Category::getType,category.getType());

4.扩展学习部分

移动端补充一些视频未完善的功能(自己写的) 过段时间把这几个功能的实现以及流程 思路 写进来

历史订单功能

需要先添加一个OrderDto层 然后直接在OrderController编写方法

  • orderDto
  • OrderController
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
JAVA

@Data
public class OrdersDto extends Orders {

private String userName;

private String phone;

private String address;

private String consignee;

private List<OrderDetail> orderDetails;

}

登出功能

  • 登出功能比较简单,跟之前的管理端是一样的

  • 请求路径/user/loginout,请求方式为POST

    要在UserController写方法

1
2
3
4
5
6
7
JAVA
//登出功能
@PostMapping("/loginout")
public R<String> loginout(HttpServletRequest httpServletRequest){
httpServletRequest.getSession().removeAttribute("user"); //获取登录状态的Attribute
return R.success("退出成功");
}

修改/删除地址

数据回显

  • 修改第一步和之前一样完成数据回显 同样看前端请求
  • /addressBook/{id}请求方式是GET 在AddressBookController中写方法
1
2
3
4
5
6
7
8
9
JAVA
@GetMapping("{id}")
public R<AddressBook> getById(@PathVariable Long id){
AddressBook byId = addressBookService.getById(id);
if (byId == null){
throw new CustomException("地址信息不存在");
}
return R.success(byId);
}

修改地址

请求网址: http://localhost/addressBook
请求方法: PUT

  • 直接在AddressBookController写Put方法
1
2
3
4
5
6
7
8
9
JAVA
@PutMapping
public R<String> updateAdd(@RequestBody AddressBook addressBook) {
if (addressBook == null) {
throw new CustomException("地址信息不存在,请刷新重试");
}
addressBookService.updateById(addressBook); //调用MP方法
return R.success("地址修改成功");
}

删除地址

请求网址: http://localhost/addressBook?ids=1579828298672885762
请求方法: DELETE

  • 直接在AddressBookController写Delete方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
JAVA

@DeleteMapping
public R<String> delete(@RequestParam Long ids){
//删除地址
if (ids == null) {
throw new CustomException("地址信息不存在,请刷新重试");
}
AddressBook addressBook = addressBookService.getById(ids);
if (addressBook == null) {
throw new CustomException("地址信息不存在,请刷新重试");
}
addressBookService.removeById(ids);
return R.success("删除成功");
}

减号按钮

  • 加入购物车以后,前端是给了一个减号的按钮,平常自己点外卖也有使用,大概功能就是点一下数量-1 0的时候菜品就会消失

请求网址: http://localhost/shoppingCart/sub
请求方法: POST

有返回json数据

1
2
3
4
JSON
{ dishId: null,
setmealId: "1579044544635232258"
}
  • 思路:通过这两个ID 实现对套餐和菜品的number属性的修改 最后为0的话调用删除操作
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
JAVA

@PostMapping("/sub")
public R<ShoppingCart> deleteSub(@RequestBody ShoppingCart shoppingCart) {
Long dishId = shoppingCart.getDishId();
Long setmealId = shoppingCart.getSetmealId();
LambdaQueryWrapper<ShoppingCart> lambdaQueryWrapper = new LambdaQueryWrapper<>();
//只查询当前用户ID的购物车
lambdaQueryWrapper.eq(ShoppingCart::getUserId, BaseContext.getCurrentId());
if (dishId != null) {
//匹配出菜品数据
lambdaQueryWrapper.eq(ShoppingCart::getDishId, dishId);
ShoppingCart dishCart = shoppingCartService.getOne(lambdaQueryWrapper);
dishCart.setNumber(dishCart.getNumber() - 1);
Integer number = dishCart.getNumber();
if (number > 0) {
shoppingCartService.updateById(dishCart);
} else {
shoppingCartService.removeById(dishCart.getId());
}

return R.success(dishCart);
}
if (setmealId != null) {
//通过setmealId查询购物车套餐数据
lambdaQueryWrapper.eq(ShoppingCart::getSetmealId, setmealId);
ShoppingCart setmealCart = shoppingCartService.getOne(lambdaQueryWrapper);
//将查出来的数据的数量-1
setmealCart.setNumber(setmealCart.getNumber() - 1);
Integer currentNum = setmealCart.getNumber();
//然后判断
if (currentNum > 0) {
//大于0则更新
shoppingCartService.updateById(setmealCart);
} else if (currentNum == 0) {
//等于0则删除
shoppingCartService.removeById(setmealCart.getId());
}
return R.success(setmealCart);
}
return R.error("系统繁忙,请稍后再试");
}

点图片查看套餐的详情

这个前端其实是写好了的,阿贾克斯请求在api也看得到 先看下请求

请求网址: http://localhost/setmeal/dish/1579044544635232258
请求方法: GET

是通过id可以实现的 restFul风格

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
JAVA

@GetMapping("/dish/{id}")
public R<List<DishDto>> showSetmealDish(@PathVariable Long id) {
//条件构造器
LambdaQueryWrapper<SetmealDish> dishLambdaQueryWrapper = new LambdaQueryWrapper<>();
//手里的数据只有setmealId
dishLambdaQueryWrapper.eq(SetmealDish::getSetmealId, id);
//查询数据
List<SetmealDish> records = setmealDishService.list(dishLambdaQueryWrapper);
List<DishDto> dtoList = records.stream().map((item) -> {
DishDto dishDto = new DishDto();
//copy数据
BeanUtils.copyProperties(item,dishDto);
//查询对应菜品id
Long dishId = item.getDishId();
//根据菜品id获取具体菜品数据,这里要自动装配 dishService
Dish dish = dishService.getById(dishId);
BeanUtils.copyProperties(dish,dishDto); //这里不写也没事 但是我想验证数据
return dishDto;
}).collect(Collectors.toList());
return R.success(dtoList);
}

5.总结

今天的学习难度较难,因为之前做了三四天的客户端的功能完善,功能实现方法什么,自己基本就知道,所以移动端的差不多的功能一天就完成了,很多都是跟客户端大差不大。难点在刚开始的时候,自己把教程的手机号接受验证码验证改成了邮箱(写在扩展学习了),还有后面的购物车和用户下单的代码也是挺难的,看了老师敲了一遍理解完,才尝试去敲。在下午练完车以后 ,快到晚自习了,把移动端的基本功能都实现了。但是自己发现很多功能都没完善,去前端页面是能看到请求的,就想自己尝试完善一下,晚自习将视频中没完善的功能给完善了,大概五六个功能,自己后台代码写掉了。

11.2 瑞吉外卖完结

1.头:日期、所学内容出处

【黑马程序员2022新版SSM框架教程_Spring+SpringMVC+Maven高级+SpringBoot+MyBatisPlus企业实用开发技术】 https://www.bilibili.com/video/BV1Fi4y1S7ix?p=31&share_source=copy_web&vd_source=c8ae4150b2286ee39a13a79bbe12b843

2.所学内容概述

上午把管理端老师未完善的功能去完善了一下,下午和晚上花时间,将项目重新回顾梳理了一下。自己用自己的手机操作了一下,客户端的功能是没有问题的。

3. BUG点

难点(关键代码或关键配置,BUG截图+解决方案)

在扩展学习写批量启售/停售的时候,运行时候就报错,刚开始不知道啥原因,注解掉写的方法,就没报错了,问题在自己写的allStatus方法,以为是把return写到循环体中了,放外面还是报错,翻译报错信息,有一条说DishController什么已存在,奥就发现因为启售和停售的请求是一样的,只是请求体不一样,所以@PostMapepr里面我写的其实是一样的,可能这样会导致匹配不到,就把原本写的单独启售和停售注释了(批量启售/停售也适用单独的),问题解决了,功能也实现了

image-20231002072258868

4.扩展学习部分

  • 后台系统端的额外功能实现(代码后续补上) 批量的删除 和 启停售
  • 两个重要的功能批量修改和删除,使用批量的时候,单独的修改和删除也是能成功的 自己去CSDN搜到了LambdaUpdateWrapper这个类对删除和修改,代码会优化很多

菜品批量启售/停售

查看前端请求

请求网址: http://localhost/dish/status/0?ids=1578942037036703745
请求方法: POST

和之前修改状态一样,前端已经对status取反了,所以直接用发送的status更新状态

  • 单独
  • 批量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
JAVA

@PostMapping("/status/{status}")
public Result<String> status(@PathVariable Integer status, Long ids) {
log.info("status:{},ids:{}", status, ids);
Dish dish = dishService.getById(ids);
if (dish != null) {
//直接用它传进来的这个status改就行
dish.setStatus(status);
dishService.updateById(dish);
return Result.success("售卖状态修改成功");
}
return Result.error("系统繁忙,请稍后再试");
}

菜品批量删除

查看前端请求

请求网址: http://localhost/dish?ids=1578674689490825217
请求方法: DELETE

同样要判断菜品是不是停售状态

我直接写批量的了,区别就在queryWrapper.in 和传入的参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
JAVA

@DeleteMapping
public R<String> allDelete(@RequestParam List<Long> ids){
log.info("删除的ids:{}", ids);
LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.in(Dish::getId, ids);
queryWrapper.eq(Dish::getStatus, 1);
int count = dishService.count(queryWrapper);
if (count > 0) {
throw new CustomException("删除列表中存在启售状态商品,无法删除");
}
dishService.removeByIds(ids);
return R.success("删除成功");
}

套餐批量启售/停售

查看请求

请求网址: http://localhost/setmeal/status/1?ids=1580361600576114689
请求方法: POST

和菜品操作的基本一样

1
2
3
4
5
6
7
8
9
10
JAVA
@PostMapping("/status/{status}")
@CacheEvict(value = "setmealCache", allEntries = true)//后面的加入缓存 现在忽略
public R<String> status(@PathVariable String status, @RequestParam List<Long> ids) {
LambdaUpdateWrapper<Setmeal> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.in(Setmeal::getId, ids);
updateWrapper.set(Setmeal::getStatus, status);
setmealService.update(updateWrapper);
return R.success("批量操作成功");
}

套餐修改

和其他修改操作一样 需要先数据回显 再修改

看请求

回显的请求 请求网址: http://localhost/setmeal/1580361496716759041
请求方法: GET

修改的请求 网址: http://localhost/setmeal
请求方法: PUT

  • 回显操作
  • 修改操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
JAVA

@GetMapping("/{id}") //用SetmealDto
public R<SetmealDto> getById(@PathVariable Long id){
Setmeal setmeal = setmealService.getById(id);
SetmealDto setmealDto = new SetmealDto();
//拷贝数据
BeanUtils.copyProperties(setmeal,setmealDto);
LambdaQueryWrapper<SetmealDish> queryWrapper = new LambdaQueryWrapper<>();
//配setmealId
queryWrapper.eq(SetmealDish::getSetmealId,id);
List<SetmealDish> list = setmealDishService.list(queryWrapper);
setmealDto.setSetmealDishes(list);
return R.success(setmealDto);
}

查看订单明细

查看肯定是get请求 但是这个请求比较多

请求网址: [http://localhost/order/page?page=1&pageSize=10&number=1580166484741677057&beginTime=2022-10-19 00%3A00%3A00&endTime=2022-11-16 23%3A59%3A59](http://localhost/order/page?page=1&pageSize=10&number=1580166484741677057&beginTime=2022-10-19 00%3A00%3A00&endTime=2022-11-16 23%3A59%3A59)
请求方法: 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
27
28
29
30
31
32
33
34
35
JAVA

@GetMapping("/page")
public R<Page> page(int page, int pageSize, Long number, String beginTime, String endTime) {
//获取当前id
Page<Orders> pageInfo = new Page<>(page, pageSize);
Page<OrdersDto> ordersDtoPage = new Page<>(page, pageSize);
//条件构造器
LambdaQueryWrapper<Orders> queryWrapper = new LambdaQueryWrapper<>();
//按时间降序排序
queryWrapper.orderByDesc(Orders::getOrderTime);
//订单号
queryWrapper.eq(number != null, Orders::getId, number);
//时间段,大于开始,小于结束
queryWrapper.gt(!StringUtils.isEmpty(beginTime), Orders::getOrderTime, beginTime)
.lt(!StringUtils.isEmpty(endTime), Orders::getOrderTime, endTime);
orderService.page(pageInfo, queryWrapper);
List<OrdersDto> list = pageInfo.getRecords().stream().map((item) -> {
OrdersDto ordersDto = new OrdersDto();
//获取orderId,然后根据这个id,去orderDetail表中查数据
Long orderId = item.getId();
LambdaQueryWrapper<OrderDetail> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(OrderDetail::getOrderId, orderId);
List<OrderDetail> details = orderDetailService.list(wrapper);
BeanUtils.copyProperties(item, ordersDto);
//之后set一下属性
ordersDto.setOrderDetails(details);
return ordersDto;
}).collect(Collectors.toList());
BeanUtils.copyProperties(pageInfo, ordersDtoPage, "records");
ordersDtoPage.setRecords(list);
//日志输出看一下
log.info("list:{}", list);
return R.success(ordersDtoPage);
}

修改订单状态

  • 这个需要看下前端写的js文件 先看下请求和返回json

请求网址: http://localhost/order
请求方法: PUT

  • 返回的json 和 js文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
JSON
{
status: 3,
id: "1580166484741677057"
}
JS

switch(row.status){
case 1:
str = '待付款'
break;
case 2:
str = '正在派送'
break;
case 3:
str = '已派送'
break;
case 4:
str = '已完成'
break;
case 5:
str = '已取消'
break;
}

因为返回值已经写好了 我们只要传入参数就好了

1
2
3
4
5
6
7
8
9
10
11
12
13
JAVA

@PutMapping
public R<String> changeStatus(@RequestBody Map<String, String> map) {
int status = Integer.parseInt(map.get("status"));
Long orderId = Long.valueOf(map.get("id"));
log.info("修改订单状态:status={},id={}", status, orderId);
LambdaUpdateWrapper<Orders> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(Orders::getId, orderId);
updateWrapper.set(Orders::getStatus, status);
orderService.update(updateWrapper);
return R.success("订单状态修改成功");
}

5.总结

今天学习状态还不错,但是学习时间有点少了,对自己今天的任务要求也不重,上午完善完老师没写的功能,晚上自己梳理了一遍,以及对自己博客的美化工作,早上第一次做批量启售和停售的时候,出现了一点小插曲,解决完以后,后面的批量删除以及菜单的功能,实现起来也很顺利。本来想加入公司项目的但是好像接口都差不多写完了,计划还是往后面学,项目部署也去学一下,计划挂到服务器里面,再把git和Redis过一遍,这周之前把部署的任务完成了,然后去开始Cloud了打算。