苍穹外卖-Day1 | 环境搭建、nginx、git、令牌、登录加密、接口文档、Swagger
目录
nginx:
nginx反向代理和负载均衡概念
nginx反向代理和负载均衡如何配置?
后端环境:maven管理
sky-common
sky-pojo
sky-server:
后端环境搭建--Git进行版本控制
后端数据库--Mysql
前后端联调
前后端运行:
前后端联调如何完成--断点调试跟踪代码
断点调试小tips:
.yml文件简介:
YAML 的常见应用场景
令牌生成
完善登录功能
TODO使用小tips
导入接口文档
Swagger技术
介绍
使用方式
在线接口测试:
Swagger常用注解
nginx:
nginx学习,看这一篇就够了:下载、安装。使用:正向代理、反向代理、负载均衡。常用命令和配置文件,很全-CSDN博客
前端分为web端、小程序端
web端在nginx下面的html文件夹下面,nginx必须放在没有中文目录的环境运行
运行方法:双击nginx.exe,用浏览器打开访问localhost,访问端口号默认80
nginx反向代理和负载均衡概念
验证方法:在前端页面点击登录(打开F12开发者模式)可以看到前端请求地址
nginx反向代理:将前端发送的动态请求转发到后端服务器
nginx反向代理好处:
- 缓存提高访问速度,
- 进行负载均衡(把大量请求按照指定方式均衡的分配给集群中的每台服务器),
- 保证后端服务安全
nginx反向代理和负载均衡如何配置?
反向代理主要依靠proxy_pass来配置
负载均衡的底层也是基于反向代理实现的,多配置了一些服务器server,转发可能需要给多个后台服务器
在这个项目中,负载均衡的配置文件在
后端环境:maven管理
sky-common
- constant:常量类
- context:上下文相关
- enumaration:枚举类
- exception:自定义异常类
- json:处理json转换
- properties:Springboot中的配置属性类,把配置文件中的一些配置对象封装
- result:后端返回结果
- utils:工具类
sky-pojo
前三项都属于POJO(Plain Old Java Object ,简单老式java对象),一种遵循简单设计原则的普通 Java 类,主要用于封装数据。
POJO 的核心特点:
- 无继承要求:不需要继承特定的类(如
Serializable
等,不过实际中为了序列化可能会实现) - 无接口强制:不需要实现特定的接口
- 字段私有化:成员变量通常用
private
修饰 - 提供访问方法:通过
public
的getter
和setter
方法操作字段 - 无业务逻辑:主要用于数据存储,不包含复杂的业务处理方法
- 可包含构造方法:通常会有默认构造方法和带参数的构造方法
sky-server:
配置文件、配置类、拦截器、controller、service、mapper、启动类等
后端环境搭建--Git进行版本控制
在IDEA中VCS(version control system版本控制系统)新建git仓库,上方就会出现Git相关操作按钮。
先对号commit到本地仓库,再箭头push到远程仓库
后端数据库--Mysql
前段时间做数据库作业好像破坏了什么Mysql配置,启动方式:
管理员身份运行cmd,net start mysql,再使用Navicat
前后端联调
前后端运行:
前端双击nginx
后端代码编译:点击compile(父工程sky-take-out整体编译)
sky-server中运行application,运行项目
尝试在登录页面前端登录,报错,原因没有修改数据库连接账号密码
修改之后成功登录:
前后端联调如何完成--断点调试跟踪代码
右上角绿框可以快速运行查看启动类,旁边的小虫子是debug断点调试,
在EmployeeController类里面有login方法,打一个断点
重新登陆
@PostMapping(\"/login\") public Result login(@RequestBody EmployeeLoginDTO employeeLoginDTO) { log.info(\"员工登录:{}\", employeeLoginDTO);
员工登录DTO中封装前端试图登录的账号密码
断点调试可以方便看到前端提供过来的数据
- Mapper中的sql语句,如果是简单的查询可以写注解,复杂/mybatis中动态标签通过xml配置
- 后面的异常处理,由全局捕获业务异常的GlobalExceptionHandeler捕获,类型是BaseException(父类),其他类型的异常继承它
断点调试小tips:
stepover单步调试(F8),resume program左侧--运行至下一个断点
ctrl + alt + b可以跳转到光标的函数位置
.yml文件简介:
.yml
是一种文件格式的扩展名,对应的文件类型是 YAML 文件(YAML 全称是 \"YAML Ain\'t Markup Language\",即 “YAML 不是标记语言”)。它是一种数据序列化格式,主要用于存储和传输结构化数据,语法简洁、易读
简洁直观:
采用缩进(通常是空格,而非 Tab)来表示数据的层级关系,避免了 XML 或 JSON 中的大量标签(如 )或括号(如
{}
[]
),可读性极强。
例如,一个简单的用户信息 YAML 配置:
user: name: Alice age: 25 hobbies: - reading - hiking contact: email: alice@example.com phone: 123456789
YAML 的常见应用场景
- 配置文件:很多框架(如 Spring Boot、Docker、Kubernetes、Ansible 等)默认使用 YAML 作为配置文件格式,例如 Spring Boot 的
application.yml
用于配置数据库连接、端口号等。 - 数据存储:可用于存储简单的结构化数据(如测试数据、配置参数)。
- API 交互:部分 API 会使用 YAML 格式传输数据(虽然 JSON 更常见)。
如图上中的两个是springboot的配置文件
令牌生成
JwtProperties是一个配置属性类,在common-properties中,如下所示
package com.sky.properties;import lombok.Data;import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.stereotype.Component;@Component// 封装了SpringBoot里面的一些配置项@ConfigurationProperties(prefix = \"sky.jwt\")@Datapublic class JwtProperties { /** * 管理端员工生成jwt令牌相关配置 */ private String adminSecretKey; private long adminTtl; private String adminTokenName; /** * 用户端微信用户生成jwt令牌相关配置 */ private String userSecretKey; private long userTtl; private String userTokenName;}
其中
@ConfigurationProperties(prefix = \"sky.jwt\")
是 Spring Boot 中的一个注解,用于将配置文件(如 application.yml
或 application.properties
)中指定前缀的配置项,自动绑定到当前类的属性上。
-
@ConfigurationProperties
:
这是 Spring Boot 提供的核心注解,作用是 “配置属性绑定”。它会自动读取配置文件中的内容,并将符合规则的配置值赋值给类中的成员变量。 -
prefix = \"sky.jwt\"
:
prefix
表示 “配置前缀”,指定了要读取的配置项的共同前缀。
这意味着:Spring 会去配置文件中寻找所有以sky.jwt
开头的配置项,然后与当前类的属性进行匹配绑定。
所以在aplication.yml中找到下面这一段,会被绑定到JwtProperties类的属性上
sky: jwt: # 设置jwt签名加密时使用的秘钥 admin-secret-key: itcast # 设置jwt过期时间 admin-ttl: 7200000 # 设置前端传递过来的令牌名称 admin-token-name: token
可以看到和上面一一对应
生成jwt令牌在EmployeeController
package com.sky.controller.admin;import com.sky.constant.JwtClaimsConstant;import com.sky.dto.EmployeeLoginDTO;import com.sky.entity.Employee;import com.sky.properties.JwtProperties;import com.sky.result.Result;import com.sky.service.EmployeeService;import com.sky.utils.JwtUtil;import com.sky.vo.EmployeeLoginVO;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import java.util.HashMap;import java.util.Map;/** * 员工管理 */@RestController@RequestMapping(\"/admin/employee\")@Slf4jpublic class EmployeeController { @Autowired private EmployeeService employeeService; @Autowired private JwtProperties jwtProperties; /** * 登录 * * @param employeeLoginDTO * @return */ @PostMapping(\"/login\") public Result login(@RequestBody EmployeeLoginDTO employeeLoginDTO) { log.info(\"员工登录:{}\", employeeLoginDTO); Employee employee = employeeService.login(employeeLoginDTO); //登录成功后,生成jwt令牌 Map claims = new HashMap(); claims.put(JwtClaimsConstant.EMP_ID, employee.getId()); // jwt令牌 String token = JwtUtil.createJWT( jwtProperties.getAdminSecretKey(), jwtProperties.getAdminTtl(), claims); // 需要传递给前端的信息,用VO进行封装 EmployeeLoginVO employeeLoginVO = EmployeeLoginVO.builder() .id(employee.getId()) .userName(employee.getUsername()) .name(employee.getName()) .token(token) .build(); return Result.success(employeeLoginVO); } /** * 退出 * * @return */ @PostMapping(\"/logout\") public Result logout() { return Result.success(); }}
其中EmployeeLoginVO如下所示
package com.sky.vo;import io.swagger.annotations.ApiModel;import io.swagger.annotations.ApiModelProperty;import lombok.AllArgsConstructor;import lombok.Builder;import lombok.Data;import lombok.NoArgsConstructor;import java.io.Serializable;@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;}
完善登录功能
问题:密码在数据库明文存储,安全性低
TODO使用小tips
导入接口文档
教程使用Yapi,这个网站现在无法使用
尝试使用ApiPost失败,于是尝试apifox,导入类型选择Yapi,可以成功导入
Swagger技术
介绍
可以帮助后端生成接口文档,并进行在线调试
使用方式
Bean注解:使用Spring框架创建并管理对象
在server的config类下面
package com.sky.config;import com.sky.interceptor.JwtTokenAdminInterceptor;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.InterceptorRegistry;import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;import springfox.documentation.builders.ApiInfoBuilder;import springfox.documentation.builders.PathSelectors;import springfox.documentation.builders.RequestHandlerSelectors;import springfox.documentation.service.ApiInfo;import springfox.documentation.spi.DocumentationType;import springfox.documentation.spring.web.plugins.Docket;/** * 配置类,注册web层相关组件 */@Configuration@Slf4jpublic class WebMvcConfiguration extends WebMvcConfigurationSupport { @Autowired private JwtTokenAdminInterceptor jwtTokenAdminInterceptor; /** * 注册自定义拦截器 * * @param registry */ protected void addInterceptors(InterceptorRegistry registry) { log.info(\"开始注册自定义拦截器...\"); registry.addInterceptor(jwtTokenAdminInterceptor) .addPathPatterns(\"/admin/**\") .excludePathPatterns(\"/admin/employee/login\"); } /** * 通过knife4j生成接口文档 * @return */ @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; } /** * 设置静态资源映射 * @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/\"); }}
由于上面配置的静态资源映射,将后端接口文档映射到localhost:8080/doc.html
- 如果不设置静态资源映射,SpringMVC会以为在请求某一个controller,是动态请求
- 如果扫描包的名字写错了,就无法正确扫描生成动态接口文档
访问即可查看该接口文档
knife4j为此动态生成接口文档
目前已经有的两个接口是解析下面的类生成的
/** * 员工管理 */@RestController@RequestMapping(\"/admin/employee\")@Slf4jpublic class EmployeeController { @Autowired private EmployeeService employeeService; @Autowired private JwtProperties jwtProperties; /** * 登录 * * @param employeeLoginDTO * @return */ @PostMapping(\"/login\") public Result login(@RequestBody EmployeeLoginDTO employeeLoginDTO) { log.info(\"员工登录:{}\", employeeLoginDTO); Employee employee = employeeService.login(employeeLoginDTO); //登录成功后,生成jwt令牌 Map 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\") public Result logout() { return Result.success(); }}
在线接口测试:
Swagger常用注解
在EmployeeController里面加入相关注解之后