文章目录
????博客x主页:己不由心王道长????!
????文章说明:SpringBoot项目-瑞吉外卖【day01】????
✅系列专栏:SpringBoot项目
????本篇内容:对黑马的瑞吉外卖项目的day01进行笔记和项目实现????
☕️每日一语:人有退路,就有些许安全感。等到哪一天,你真没了退路,你就发现眼前哪条路都能走,也能通。☕️
???? 交流社区:己不由心王道长(优质编程社区)
前言
从今天开始,正式进入项目阶段。本次的项目是跟着黑马的瑞吉外卖项目走的,有借鉴和使用,也有自己的观点和实现。由于本课程用到了很多前端知识(了解),所以关于前端分析的时候,我应该会选择跳过或者简略一看;大家学有余力或者对前端已经轻车熟路的可以自己看看黑马的视频。本次的项目并没有从前端到后台都自己进行搭建,虽然我也很向往这个,但是还是在学精后端再去深入前端吧,我也没有余力,只是后端的内容就已经让我头大了。还有就是,本次内容只是对于黑马视频的day01,我一定会坚持把整个项目都拿下的,感兴趣的小伙伴可以点点订阅,专栏已在头部给出。
最后,博主水平实在有限,如果有错误的地方还望各位大佬批评指正。万分感谢。
软件开发整体介绍
软件开发流程
软件开发整体流程如下:
角色分工:
角色分工我个人认为挺有趣,难度应该从下到上吧,我们后端的开发工程师应该对应软件开发流程中的编码、然后往下依次对应。
软件环境:
关于软件环境,我们在以前的文章曾经学过多环境开发,如不嫌弃,可以移步SpringBoot专栏,这里就不赘述了。
瑞吉外卖项目介绍
项目介绍
原话:
本项目(瑞吉外卖)是专门为餐饮企业(餐厅、饭店)定制的一款软件产品,包括系统管理后台和移动端应用两部分其中系统管理后台主要提供给餐饮企业内部员工使用,可以对餐厅的菜品、套餐、订单等进行管理维护。移动端应用主要提供给消费者使用,可以在线浏览菜品、添加购物车、下单等。
本项目共分为3期进行开发:
第一期主要实现基本需求,其中移动端应用通过H5实现,用户可以通过手机浏览器访问。第二期主要针对移动端应用进行改进,使用微信小程序实现,用户使用起来更加方便。第三期主要针对系统进行优化升级,提高系统的访问性能。
理解:
其实没什么好说的,就是在项目开始的时候,一定是先搭架子,把基本的跑通,然后再基础之上做改进,最后进行优化,切不可图快。不要把自己绕进去。
下面是项目图片:
产品原型展示
原话:
产品原型,就是一款产品成型之前的一个简单的框架,就是将页面的排版布局展现出来,使产品的初步构思有一个可视化的展示。通过原型展示,可以更加直观的了解项目的需求和提供的功能。
理解:就是一个基本的架子,可以看到基本的效果,值得注意的是,产品原型可不等于完整的产品(不用说也知道)。
让我们去看看产品原型吧,原型资料在文章最后可以拿到,或者去黑马视频下领取:
可以看到,这里已经有了产品的原型。产品原型一般不是开发工程师去完成的,这里我们了解。
可以看到产品原型分为管理端和用户端,这是正常的软件的开发格式,软件肯定有管理者,有用户;其实管理者也是用户,但是管理者用的肯定跟用户端的不同。
可以看到管理端和用户端都有自己的界面等相关资料。
以上就是该项目的产品原型,非常的nice。
注意:产品原型主要用于展示项目的功能,并不是最终的页面效果。
技术选型
技术选型是一个重要的过程,不同产品所用到的技术是不一样的。有的追求高效率、高并发;而有的要保证安全性。
那么我们这个项目的技术选项是什么呢?
这里面有的技术已经学过,有的技术根本就没见过,怎么办呢?管它呢,这里先了解一下该项目用到的技术,等做到那一步再看看也不迟,但是最基础的你得会。
功能架构
下面是整体功能架构图:
可以分为两大部分,分别是移动端前台和系统管理后台;移动端前台又分为H5、微信小程序;即网页版和微信小程序版。
角色
一般没有后台系统管理员,这个权力太大了。而后台普通员工和C端用户可以对上功能架构图。其实想想也知道,功能是给人用的,不同的功能可能就对应不同的用户类型。
开发环境搭建
数据库环境搭建
这里的数据库用的是官方给的数据库,大概十几张表,关系有点复杂。
所以导入已给的sql语句即可:
第一步:创建数据库
这里直接用工具创建,不用cmd模式了。
第二步:导入sql脚本
右键选择执行SQL文件
找到SQL文件,注意路径不要带有中文,不然可能出错。点击开始即可。
然后刷新表:
我们已经把数据库创建好了。里面已经有了初始数据。
maven项目搭建
在把数据库准备好以后,我们要着手开始我们的项目的搭建。
注意看,我创建了一个SpringBoot类型的项目,而且保存在了SpringBoot project目录中加以区分。
后面的什么技术也不要选,导入项目给的配置就行。
导入数据:
首先把pom.xml文件替换掉
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.itheima</groupId>
<artifactId>reggie_take_out</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.76</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.23</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.4.5</version>
</plugin>
</plugins>
</build>
</project>
检查仓库和jdk及其他环境正不正确:
如上图,在这里我的maven仓库它并没有给我配好,需要手动更改一下,不然程序是运行不了的。
运行程序,检查错误:
更换application.yml:
server:
port: 8080
spring:
application:
#应用的名称,可选
name: reggie_take_out
datasource:
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/reggie?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
username: root
password: 775033
mybatis-plus:
configuration:
#在映射实体或者属性时,将数据库中表名和字段名中的下划线去掉,按照驼峰命名法映射
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
id-type: ASSIGN_ID
上面的application.name是设置当前应用的名字,不设置的话默认用的是你创建项目的名称。
map-underscore-to-camel-case 是设置实体和数据库中属性的关系,如果设置为true,则表示将数据库中表名和字段名中的下划线去掉,按照驼峰命名法映射:
如实体:username
数据库属性:user_name
当设置为true并映射时,会自动把user_name描述为username。
建立三层架构目录:
创建实体类:
package com.example.entity;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 员工实体
*/
@Data
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private String username;
private String name;
private String password;
private String phone;
private String sex;
private String idNumber;//身份证号码
private Integer status;
private LocalDateTime createTime;
private LocalDateTime updateTime;
@TableField(fill = FieldFill.INSERT)
private Long createUser;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updateUser;
}
创建mapper层接口:EmployeeMapper集成BaseMapper使用Mybatisplus
package com.example.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.entity.Employee;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface EmployeeMapper extends BaseMapper<Employee>{
}
@Mapper是告诉sprigng框架此接口的实现类由Mybatis负责创建,并将其实现类对象存储到spring容器中。这里由Mybatisplus创建。
创建service层接口:EmployeeService、Mybatis-plus同样为service层也进行了增强,需要在接口去继承IService接口。
package com.example.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.example.entity.Employee;
public interface EmployeeService extends IService<Employee> {
}
创建Service层接口的实现类:EmployeeServiceImpl、这个类除了实现它的父接口以外,还得去继承一个ServiceImpl的方法,并且传入实体类和mapper层的接口。
package com.example.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.entity.Employee;
import com.example.mapper.EmployeeMapper;
import com.example.service.EmployeeService;
import org.springframework.stereotype.Service;
@Service
public class EmployeeServiceImpl extends ServiceImpl<EmployeeMapper, Employee> implements EmployeeService {
}
至于为什么这样,那是Mybatis-plus的内容,可以回去复习复习。
导入前端静态页面资料:
设置静态资源映射
在完成上面内容之后,我们不着急编写controller,现在还有一个棘手的问题,请看:
当我去访问静态资源的时候,发现了错误,状态显示404,没有找到。当然找不到,为什么呢?
还记得以前我们创建SpringBoot项目时有的static、Template目录吗?
静态资源一般是存放在那里面的,而且SpringBoot默认的静态资源访问路径就是它们,而现在我们并没有这两个目录,怎么办呢?配置静态资源映射。
我们创建一个config目录:
因为资源访问在ssm的时候其实是属于mvc框架管理的,所以创建一个WebMvcConfig类用以实现资源路径,见名知意。并且实现WebMvcConfigurationSupport:
ctrl+h看类关系图
看到该类是servlet.config包下的类,就是servlet的配置文件,我们以前在servlet里设置访问路径时是在web.xml文件中设置。
package com.example.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
/**
* @author 不止于梦想
* @date 2022/11/12 18:54
*/
@Slf4j
@Configuration//表明这是一个配置类
public class WebMvcConfig extends WebMvcConfigurationSupport {
/**
* 设置静态资源映射
* @param registry
*/
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
log.info("资源解析器启动");
registry.addResourceHandler("/backend/**").addResourceLocations("/backend");
registry.addResourceHandler("/front/**").addResourceLocations("/front");
}
}
验证:看到资源资源解析器启动,
postman验证:
还是显示没找到,出错了?没有,看看后台
后台已经收到了请求。说明我们的资源解析器配置成功。
后台登录
需求分析
需求分析,我们先来看看登录界面长什么样吧,拉出来溜溜。由于代码十分多,且有点复杂,我就截出需要看的代码,小伙伴们最好也自己上手代码,不然可能不知道我这些是啥玩意:
登录按钮绑定了一个事件,事件是一个方法handleLogin,在下图中我找到了这个方法,如图:
最值得探究的是loginApi,我们跟进去:
发现这其实是一个函数,并且发送axios请求去寻找后台的/employee/login
路径,当然它现在找不到,因为我们并没有编写controller,也就没有请求路径。还得注意的是,这是一个post请求:
到这就清楚了,原来这是一个点击登录,然后在前台进行数据格式校验,校验通过则登录标签span设为登录中,然后调用loginApi发送axios请求,去/employee/login路径下寻找登录的controller,返回状态进行判断,通过则在前端进行页面跳转到欢迎界面,否则则把span标签设为false,即登录。继续留在登录界面
分析完毕!!
代码开发
在上面我们已经分析了整个过程,现在应该编写相应的controller,提供路径和方法供其访问。
编写一个EmployeeController,专门为Employee服务的控制层
在开始注入service层的服务对象:
新建一个方法Login方法,这里我们前后端整合的时候一般都会统一返回格式,比如状态码、msg信息,对象信息。
package com.example.commons;
/**
* @author 不止于梦想
* @date 2022/11/13 15:52
*/
import lombok.Data;
import java.util.HashMap;
import java.util.Map;
/**
* 通用返回结果,服务端响应的数据最终都会封装成此对象
* @param <T>
*/
@Data
public class R<T> {
private Integer code; //编码:1成功,0和其它数字为失败
private String msg; //错误信息
private T data; //数据
private Map map = new HashMap(); //动态数据
public static <T> R<T> success(T object) {
R<T> r = new R<T>();
r.data = object;
r.code = 1;
return r;
}
public static <T> R<T> error(String msg) {
R r = new R();
r.msg = msg;
r.code = 0;
return r;
}
public R<T> add(String key, Object value) {
this.map.put(key, value);
return this;
}
}
状态码表示成功与否,一目了然,msg用来存储错误信息。data是数据,而且用了泛型,就是你想查询什么数据,就查什么,泛型会给你转换的。
这时候就可以编写实际的方法了,返回值类型也是用到了泛型,类型是Employee。
该方法会保存session信息,以供后面检查登录的过滤器或者拦截器使用,所以参数应该有HttpServletRequest,并且是验证客户是否存在,参数应该有客户对象,使用@RequestBody在参数中会自动把前端传入的参数注入到被注释的形参中并转换为json格式。
这里都不在后端进行页面跳转,而是统一格式后把数据传给前端,由前端拿到数据并进行判断,在加以视图的切换。
@PostMapping("/login")
public R<Employee> login(HttpServletRequest request, @RequestBody Employee employee){
//1、将页面提交的密码password进行md5加密处理
String password = employee.getPassword();
password = DigestUtils.md5DigestAsHex(password.getBytes());
//2、根据页面提交的用户名username查询数据库
LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Employee::getUsername,employee.getUsername());
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);
}
上面的语句中用了都是Mybatis-plus的工具,看起来有些吃力,建议大家把mybatisplus学完之后再来完成这个项目。
功能测试
在功能测试这里,建议大家手动的在地址栏上敲出登录的地址,如果直接在IEDA中进入登录界面,那么就会出现以下问题:
这上面其实不是axios.min.js的错误,这是IDEA的错误,太傻了,浪费我很多时间。这个错误在chore也不完整,我们在其他浏览器打开:
看到没有,直接从IEDA里面进入,会默认把你的端口号都改了。但是你手动的在地址栏上输入登录的地址,然后再输入账号和密码,则不会出错。
因为在页面上已经给出了账号和密码,所以点击就进入了管理界面,说明前后端已经跑通了。
后台退出
需求分析
做好了登录功能,我们来完成以下退出功能,由于都是Employee的用户,所以代码写在一个controller中。
由于我们是先登录,然后才有的退出选项,所以退出功能应该在index.html界面:
可以看到,在一张图片上,就是一个退出的功能,并且这个功能绑定了一个单击事件,我们还是一样,跟进去看看。
无非就是这几个,我们现在关注的是退出Api,即logoutApi。
可以看到,这个方法同样是调用axios方式异步请求,细节如图。
现在可以了解到了,只要我们点击退出那个图片,就会触发一个事件,这个事件绑定的函数就会向/employee/logout这个路径发送post请求。
代码开发
在上面我们已经完成了代码的分析,现在就是编写controller,应为这都employee一类对象,所以直接在EmployeeController里面编写一个退出方法即可。
@PostMapping("/logout")
public R<String> logout(HttpServletRequest request){
//清理Session中保存的当前登录员工的id
request.getSession().removeAttribute("employee");
return R.success("退出成功");
}
代码十分简介,还是需要HttpServletRequest对象,然后把请求对象保存的session移除即可,移除之后调用一个统一返回格式的success方法,
返回一个退出成功的信息。并把code赋值为1,return回前端进行比较,比较成功,则跳转视图到登录页面
功能测试
在上面已经编写好了退出的方法,现在我们只需要去点击退出按钮即可,
管理员旁边的图片就是退出按钮,我在退出的时候在后台打印一句话,如果退出成功则输出。
我们现在完成了项目的第一步,登录和退出功能。