目录项目来源:B站黑马程序员《苍穹外卖》
本帖仅为学习日志
一、软件开发
(一)软件开发流程
- 需求分析:制作需求规格说明书、产品原型;
- 设计:UI设计(用户界面设计)、数据库设计、接口设计;
- 编码:项目代码、单元测试;
- 测试:测试用例、测试报告;
- 上线运维:软件环境安装、配置。
(二)角色分工
- 项目经理:对整个项目负责,任务分配、把控进度。
- 产品经理:进行需求调研,输出需求调研文档、产品原型等。
- UI设计师:根据产品原型输出界面效果图。
- 架构师:项目整体架构设计、技术选型等。
- 开发工程师:代码实现。
- 测试工程师:编写测试用例、输出测试报告。
- 运维工程师:软件环境搭建、项目上线。
(三)软件环境
- 开发环境(development):开发人员在开发阶段使用的环境,一般外部用户无法访问。
- 测试环境(testing):专门给测试人员使用的环境,用于测试项目,一般外部用户无法访问。
- 生产环境(production):即线上环境,正式提供对外服务的环境。
二、苍穹外卖项目介绍
(一)项目介绍
定位:专门为餐饮企业(餐厅、饭店)定制的一款软件产品。
功能架构:体现项目中的业务功能模块。
- 管理端:员工管理、分类管理、菜品管理、套餐管理、订单管理、工作台、数据统计、来单提醒。
- 客户端:微信登录、商品浏览、购物车、用户下单、微信支付、历史订单、地址管理、用户催单。
(二)产品原型
用于展示项目的业务功能,一般由产品经理进行设计。
(三)技术选型
展示项目中使用的技术框架和中间件等。
- 用户层:node.js、VUE.js、ElementUI、微信小程序、apache echarts
- 网关层:Nginx
- 应用层:Spring Boot、Spring MVC、Spring Task、httpclient、Spring Cache、JWT、阿里云OSS、Swagger、POI、WebSOcket
- 数据层:MySQL、Redis、mybatis、pagehelper、spring data redis
- 工具:Git、maven、Junit、postman
三、开发环境搭建
整体结构:
前端 | 管理端(Web) | 用户端(小程序) |
后端 | 后端服务(Java) |
(一)前端环境搭建
前端工程基于nginx运行
(二)后端环境搭建
表2 项目结构
序号 | 名称 | 说明 |
---|---|---|
1 | sky-take-out | maven父工程,统一管理依赖版本,聚合其他子模块 |
2 | sky-common | 子模块,存放公共类,例如:工具类、常量类、异常类等 |
3 | sky-pojo | 子模块,存放实体类、VO、DTO、等 |
4 | sky-server | 子模块,后端服务,存放配置文件、Controller、Service、Mapper等 |
表3
名称 | 说明 |
---|---|
Entity | 实体,通常和数据库中的表对应 |
DTO | 数据传输对象,通常用于程序中各层之间传递数据 |
VO | 视图对象,为前端展示数据提供的对象 |
POJO | 普通Java对象,只有属性和对应的getter和setter |
1.使用Git进行项目代码的版本控制:
- 创建Git本地仓库
在IDEA中点击VCS -> Create Git Repository -> 选择推送目录 -> 点击对号,快速提交 -> 选择提交文件 -> 编写Amend -> 点击Commit,提交到本地 - 创建Git远程仓库
登录Gitee网站 -> 新建仓库 - 将本地文件推送到Git远程仓库
复制仓库地址 -> 点击push按钮
2.数据库环境搭建
通过数据库建表语句创建数据库表结构:
表4
序号 | 表名 | 中文名 |
---|---|---|
1 | employee | 员工表 |
2 | category | 分类表 |
3 | dish | 菜品表 |
4 | dish_flavor | 菜品口味表 |
5 | setmeal | 套餐表 |
6 | setmeal_dish | 套餐菜品关系表 |
7 | user | 用户表 |
8 | address_book | 地址表 |
9 | shopping_cart | 购物车表 |
10 | orders | 订单表 |
11 | orders_detail | 订单明细表 |
3.前后端联调
浏览器 -> Controller(1,接收并封装参数;2,调用Service方法查询数据库;3,封装结果并响应) -> Service(1,调用Mapper查询数据库;2,密码比对;3,返回结果) -> Mapper(select * from employee where username = ?) -> 数据库
打开sky-server,resources中的application-dev.yml文件,更改对应数据库的用户名及密码
前端发出的请求,是如何请求到后端服务的?
nginx反向代理,将前端发送的动态请求由nginx转发到后端服务器
nginx反向代理的好处:
- 提高访问速度
- 进行负载均衡(负载均衡:把大量的请求按照我们指定的方式均衡的分配给集群中的每台服务器)
- 保障后端服务安全
nginx反向代理的配置方式:
在nginx.conf文件中:
点击查看代码
server{
listen 80;
server_name localhost;
location/api/{
proxy_pass http://localhost:8080/admin/;#反向代理
}
}
nginx负载均衡的配置方式:
点击查看代码
upstream webserves{
server 192.168.100.128:8080;
server 192.168.100.129:8080;
}
server{
listen 80;
server_name localhost;
location/api/{
proxy_pass http://webservers/admin/;#负载均衡
}
}
表5 nginx负载均衡策略
名称 | 说明 |
---|---|
轮询 | 默认方式 |
weight | 权重方式,默认为1,权重越高,被分配的客户端请求就越多 |
ip_hash | 根据ip分配方式,这样每个访客可以固定访问一个后端服务 |
least_conn | 依据最少连接方式,把请求优先分配给连接数少的后台服务 |
url_hash | 依据url分配方式,这样相同的url会被分配到同一个后端服务 |
fair | 依据响应时间方式,响应时间短的服务将会被优先分配 |
(三)完善登录功能
问题:员工表中的密码是明文存储,安全性低
1,将密码加密后存储,提高安全性
2,使用MD5加密方式对明文密码加密
注:加密不可逆
步骤:
- 修改数据库中明文密码,改为MD5加密后的密文
注:123456这个经md5算法加密之后32位:e10adc3949ba59abbe56e057f20f883e
- 修改Java代码,前端提交的密码进行MD5加密后再跟数据库中密码比对
在EmployeeServiceImpl.java文件中
点击查看代码
// 对前端传过来的明文密码进行MD5加密处理
password = DigestUtils.md5DigestAsHex(password.getBytes());
四、导入接口文档
(一)前后端分离开发流程
(二)操作步骤
将课程资料中提供的项目接口导入YAPI。
五、Swagger
(一)介绍
使用Swagger只需要按照它的规范去定义接口及接口相关的信息,就可以做到生成接口文档,以及在线接口调试页面。
Knife4j是为Java MVC框架集成Swagger生成Api文档的增强解决方案。
(二)使用方法:
- 导入knife4j的maven坐标;
在pom.xml文件中配置:
点击查看代码
<dependency
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>3.0.2</version>
</dependency>
- 在配置类中加入knife4j相关配置;
点击查看代码
//WebMvcConfiguration.java
@Bean
public Docket docket() {
log.info("准备生成接口文档……");
ApiInfo apiInfo = new ApiInfoBuilder()
.title("苍穹外卖项目接口文档")
.version("2.0")
.description("苍穹外卖项目接口文档")
.build();
Docket docket = new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo)
.select()
.apis(RequestHandlerSelectors.basePackage("com.sky.controller"))
.paths(PathSelectors.any())
.build();
return docket;
}
- 设置静态资源映射,否则接口文档页面无法反问。
点击查看代码
//WebMvcConfiguration.java
/**
* 设置静态资源映射
* @param registry
*/
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
log.info("开始设置静态资源映射……");
registry.addResourceHandler("/doc.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
苍穹外卖项目接口文档:http://localhost:8080/doc.html
- Yapi是设计阶段使用的工具,管理和维护接口;
- Swagger在开发阶段使用的框架,帮助后端开发人员做后端的接口测试。
(三)常用注解
通过注解可以控制生成的接口文档,使用接口文档拥有更好的可读性。
表6 常用注解
注解 | 说明 |
---|---|
@Api | 用在类上,例如Controller,表示对类的说明 |
@ApiModel | 用在类上,例如entity、DTO、VO |
@ApiModelProperty | 用在属性上,描述属性信息 |
@ApiOperation | 用在方法上,例如Controller的方法,说明方法的用途、作用 |
点击查看代码
//EmployeeController.java
/**
* 员工管理
*/
@RestController
@RequestMapping("/admin/employee")
@Slf4j
@Api(tags = "员工相关接口")
public class EmployeeController {
@Autowired
private EmployeeService employeeService;
@Autowired
private JwtProperties jwtProperties;
/**
* 登录
*
* @param employeeLoginDTO
* @return
*/
@PostMapping("/login")
@ApiOperation(value = "员工登录")
public Result<EmployeeLoginVO> login(@RequestBody EmployeeLoginDTO employeeLoginDTO) {
log.info("员工登录:{}", employeeLoginDTO);
Employee employee = employeeService.login(employeeLoginDTO);
//登录成功后,生成jwt令牌
Map<String, Object> claims = new HashMap<>();
claims.put(JwtClaimsConstant.EMP_ID, employee.getId());
String token = JwtUtil.createJWT(
jwtProperties.getAdminSecretKey(),
jwtProperties.getAdminTtl(),
claims);
EmployeeLoginVO employeeLoginVO = EmployeeLoginVO.builder()
.id(employee.getId())
.userName(employee.getUsername())
.name(employee.getName())
.token(token)
.build();
return Result.success(employeeLoginVO);
}
/**
* 退出
*
* @return
*/
@PostMapping("/logout")
@ApiOperation("员工退出")
public Result<String> logout() {
return Result.success();
}
}
点击查看代码
//EmployeeLoginDTO.java
@Data
@ApiModel(description = "员工登录时传递的数据模型")
public class EmployeeLoginDTO implements Serializable {
@ApiModelProperty("用户名")
private String username;
@ApiModelProperty("密码")
private String password;
}
点击查看代码
//EmployeeLoginVO.java
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@ApiModel(description = "员工登录返回的数据格式")
public class EmployeeLoginVO implements Serializable {
@ApiModelProperty("主键值")
private Long id;
@ApiModelProperty("用户名")
private String userName;
@ApiModelProperty("姓名")
private String name;
@ApiModelProperty("jwt令牌")
private String token;
}