> 技术文档 > 苍穹外卖-Day1 | 环境搭建、nginx、git、令牌、登录加密、接口文档、Swagger

苍穹外卖-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反向代理好处:

  1. 缓存提高访问速度,
  2. 进行负载均衡(把大量请求按照指定方式均衡的分配给集群中的每台服务器),
  3. 保证后端服务安全

nginx反向代理和负载均衡如何配置?

反向代理主要依靠proxy_pass来配置

负载均衡的底层也是基于反向代理实现的,多配置了一些服务器server,转发可能需要给多个后台服务器

在这个项目中,负载均衡的配置文件在

后端环境:maven管理

sky-common

  1. constant:常量类
  2. context:上下文相关
  3. enumaration:枚举类
  4. exception:自定义异常类
  5. json:处理json转换
  6. properties:Springboot中的配置属性类,把配置文件中的一些配置对象封装
  7. result:后端返回结果
  8. utils:工具类

sky-pojo

前三项都属于POJO(Plain Old Java Object ,简单老式java对象),一种遵循简单设计原则的普通 Java 类,主要用于封装数据。

POJO 的核心特点:

  1. 无继承要求:不需要继承特定的类(如 Serializable 等,不过实际中为了序列化可能会实现)
  2. 无接口强制:不需要实现特定的接口
  3. 字段私有化:成员变量通常用 private 修饰
  4. 提供访问方法:通过 public 的 getter 和 setter 方法操作字段
  5. 无业务逻辑:主要用于数据存储,不包含复杂的业务处理方法
  6. 可包含构造方法:通常会有默认构造方法和带参数的构造方法

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中封装前端试图登录的账号密码

断点调试可以方便看到前端提供过来的数据

  1. Mapper中的sql语句,如果是简单的查询可以写注解,复杂/mybatis中动态标签通过xml配置
  2. 后面的异常处理,由全局捕获业务异常的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 更常见)。
格式 特点 适用场景 YAML 缩进表示层级,简洁易读,支持注释 配置文件(如 Spring Boot 配置)、人工编辑的结构化数据 JSON 用括号表示层级,语法严格(无注释),机器友好 API 数据传输、前端与后端交互 XML 标签嵌套,语法繁琐,支持复杂结构和命名空间 传统配置文件(如早期 Java 框架)、文档标记

如图上中的两个是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)中指定前缀的配置项,自动绑定到当前类的属性上

  1. @ConfigurationProperties
    这是 Spring Boot 提供的核心注解,作用是 “配置属性绑定”。它会自动读取配置文件中的内容,并将符合规则的配置值赋值给类中的成员变量。

  2. 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里面加入相关注解之后