二刷苍穹外卖 day01

nginx

nginx反向代理

将前端发送的请求由nginx转发到后端服务器
好处:
提速:nginx本身可缓存数据
负载均衡:配置多台服务器,大量请求来临可均衡分配
保证后端安全:不暴露后端服务真实地址

server{listen 80;server_name localhost;location /api/{proxy_pass http://localhost:8080/admin/; #反向代理}
}

**proxy_pass:**该指令是用来设置代理服务器的地址,可以是主机名称,IP地址加端口号等形式。

如上代码的含义是:监听80端口号, 然后当我们访问 http://localhost:80/api/…/…这样的接口的时候,它会通过 location /api/ {} 这样的反向代理到 http://localhost:8080/admin/上来。

负载均衡

upstream webservers{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;#负载均衡}
}

upstream:如果代理服务器是一组服务器,可以使用upstream指令配置后端服务器
如上代码的含义是:监听80端口号, 然后当我们访问 http://localhost:80/api/…/…这样的接口的时候,它会通过 location /api/ {} 这样的反向代理到 http://webservers/admin,根据webservers名称找到一组服务器,根据设置的负载均衡策略(默认是轮询)转发到具体的服务器。

注:upstream后面的名称可自定义,但要上下保持一致。

负载策略:

轮询:默认

upstream webservers{server 192.168.100.128:8080;server 192.168.100.129:8080;
}

weight:添加权重

upstream webservers{server 192.168.100.128:8080 weight=90;server 192.168.100.129:8080 weight=10;
}

配置前端环境

nginx.conf

  #user nobody;worker_processes 1;#error_log logs/error.log;#error_log logs/error.log notice;#error_log logs/error.log info;#pid logs/nginx.pid;events {worker_connections 1024;}http {include mime.types;default_type application/json;sendfile on;keepalive_timeout 65;upstream webservers{server 127.0.0.1:8080 weight=90 ;#server 127.0.0.1:8088 weight=10 ;}server {listen 80;server_name localhost;# 指定前端项目所在的位置location / {root html/sky;index index.html index.htm;}error_page 500 502 503 504 /50x.html;location = /50x.html {root html;}# location /api {# default_type application/json;# #internal;# keepalive_timeout 30s;# keepalive_requests 1000;# #支持keep-alive# proxy_http_version 1.1;# rewrite /api(/.*) $1 break;# proxy_pass_request_headers on;# #more_clear_input_headers Accept-Encoding;# proxy_next_upstream error timeout;# #proxy_pass http://127.0.0.1:8081;# proxy_pass http://backend;# }# 反向代理,处理管理端发送的请求location /api/ {proxy_pass http://localhost:8080/admin/;#proxy_pass http://webservers/admin/;}# 反向代理,处理用户端发送的请求location /user/ {proxy_pass http://webservers/user/;}# WebSocket# location /ws/ {# proxy_pass http://webservers/ws/;# proxy_http_version 1.1;# proxy_read_timeout 3600s;# proxy_set_header Upgrade $http_upgrade;# proxy_set_header Connection "$connection_upgrade";# }}# upstream backend {# server 127.0.0.1:8080 weight=90 ;# # server 127.0.0.1:8081 max_fails=5 fail_timeout=10s weight=1;# # server 127.0.0.1:8082 max_fails=5 fail_timeout=10s weight=1;# }}

输入nginx -s reload重启服务,访问80端口有效
![[Pasted image 20250610191304.png]]

项目整体架构:

sky-take-out 父工程,通过pom统一管理依赖版本并聚合其他子模块
sky-common 存放常量,工具类,异常类等子模块
sky-pojo 存放实体,VO、DTO等
sky-server 子模块,存放配置文件、Controller、Service、mapper等配置文件

common:

constant 相关常量
context 上下文
enumeration 枚举操作
exception 自定义异常
json 处理json转换 基于jackson将Java对象转为json,或者将json转为Java对象
properties 存放springboot相关配置属性类,如阿里OSS服务,jwt令牌和微信支付接口等配置
result 返回结果封装,分页返回类和标准返回格式

Serializable接口是Java提供的一个标记接口,用于表示一个类的对象是否可被序列化,序列化意味着将对象转换为字节流,还能从字节重构对象,
- 一个类只有实现了 Serializable 接口,它的对象才是可序列化的。因此如果要序列化某些类的对象,这些类就必须实现 Serializable 接口。而实际上,Serializable 的源码是一个空接口,没有什么具体内容,它的目的只是简单的标识一个类的对象可以被序列化。

util 常见工具类

pojo

entity :存放与数据库表对应的实体
DTO :数据传输对象,在后端各层中进行传输
VO :视图,用于为前端展示数据所提供的对象

server

config:配置类
controller
interceptor:拦截器类
mapper:
service:
SkyApplication :启动类

前后端整体实现思路:

![[Pasted image 20250610195506.png]]

controller层:

@PostMapping("/login")  
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);  
}
1.接受登陆请求:

方法接收了一个EmplyeeLoginDTO类型的参数,这个DTO包括前端传来的用户名和密码,用于员工登陆,@RequestBody注解表示请求体以JSON格式传递

2.调用Service层进行验证

调用emplyeeService的login()方法,将登陆信息传递给服务层,服务层若验证成功会返回对应的Employee实体对象

3.生成JWT Token

使用JwtUtil.createJWT()方法根据员工id生成JWT令牌
令牌包括用户标识emplyee.getId()
过期时间以及签名算法

4.构建返回值对象给EmployeeLoginVO

创建EmployeeLoginVO对象,封装登录成功后需要返回给前端的信息
包括员工ID,用户名、姓名,token(用于后续请求的身份凭证)

service层:

public Employee login(EmployeeLoginDTO employeeLoginDTO) {  String username = employeeLoginDTO.getUsername();  String password = employeeLoginDTO.getPassword();  //1、根据用户名查询数据库中的数据  Employee employee = employeeMapper.getByUsername(username);  //2、处理各种异常情况(用户名不存在、密码不对、账号被锁定)  if (employee == null) {  //账号不存在  throw new AccountNotFoundException(MessageConstant.ACCOUNT_NOT_FOUND);  }  //密码比对  // TODO 后期需要进行md5加密,然后再进行比对  if (!password.equals(employee.getPassword())) {  //密码错误  throw new PasswordErrorException(MessageConstant.PASSWORD_ERROR);  }  if (employee.getStatus() == StatusConstant.DISABLE) {  //账号被锁定  throw new AccountLockedException(MessageConstant.ACCOUNT_LOCKED);  }  //3、返回实体对象  return employee;  
}

1.获取用户名与密码

从传入的DTO中提取用户名和密码

2.查询数据库中的员工信息

emplyeeMapper.getByUsername(Username),通过MyBatis框架调用数据库接口

3.异常处理逻辑

异常类型:AccountNofFoundException(用户名不存在)

4.密码比对并检查账号状态

5.返回员工实体

所有校验通过后,返回查询到的员工对象,该对象将用于生成JWT Token,并构建成功响应

Mapper层

@Select("select * from employee where username = #{username}")  
Employee getByUsername(String username);

这部分代码定义了一个名为getByUsername的方法,该方法接收一个String类型的参数username@Select注解表示这是一个用于执行 SQL 查询的语句,其注解内的 SQL 语句select * from employee where username = #{username} 意思是从名为employee的表中查询所有列,条件是username字段的值等于传入的username参数值。方法返回类型为Employee,即查询结果会封装成Employee对象返回,整体功能是根据给定的用户名从employee表中获取对应的员工信息。

完善登录功能:

Employee employee = employeeMapper.getByUsername(username);  
log.info("password={}",password);

使用MD5加密的方式对明文密码进行加密得到:
e10adc3949ba59abbe56e057f20f883e
将sql里的admin密码从123456改为以上

     password = DigestUtils.md5DigestAsHex(password.getBytes());if (!password.equals(employee.getPassword())) {//密码错误throw new PasswordErrorException(MessageConstant.PASSWORD_ERROR);}

修改代码后登陆成功

Swagger

用于生成、描述、调用和可视化RESful风格的Web服务,作用:
使得前后端分离开发更加方便
接口文档自动生成,减轻后端开发人员编写借口的负担
可进行功能测试
knife4j是为Java MVC框架集成Swagger生成Api文档的增强解决方案,前身是swagger-bootstrap-ui,取名kni4j是希望它能像一把匕首一样小巧,轻量,并且功能强悍!

目前,一般都使用knife4j框架。

步骤

1.导入pom坐标

<dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-spring-boot-starter</artifactId>
</dependency>

2.在配置类中加入knife4j相关配置

WebMvcConfiguration.java

/*** 通过knife4j生成接口文档* @return
*/@Beanpublic Docket docket() {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;}

3.设置静态资源映射

WebMvcConfiguration.java

/*** 设置静态资源映射* @param registry
*/
protected void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/doc.html").addResourceLocations("classpath:/META-INF/resources/");registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}

4.访问

在http://localhost:8080/doc.html页面进行访问

常见注解

@Api 类上,例如Controller,说明类
@ApiModel 用于类,例如entity,DTO,VO
@ApiModelProperty 用于属性,描述属性信息
@ApiOperation 用于方法上,说明方法用途、作用

使用上述注解,生成可读性更好的接口文档

@ApiModel(description = "员工登录时传递的数据模型")
public class EmployeeLoginDTO implements Serializable @ApiModel(description = "员工登录返回的数据格式")
public class EmployeeLoginVO implements Serializable@ApiOperation(value = "员工登录")public Result<EmployeeLoginVO> login(@RequestBody EmployeeLoginDTO employeeLoginDTO) 

总结

1. Nginx 反向代理的作用是什么?如何配置?

作用

  • 转发前端请求到后端服务器,隐藏真实地址,保障安全;
  • 缓存数据提速,支持负载均衡分配多台服务器请求。
    配置示例
server {listen 80;server_name localhost;location /api/ {proxy_pass http://localhost:8080/admin/;  # 反向代理到后端地址}
}
2. Nginx 负载均衡的策略有哪些?如何配置权重?

常见策略

  • 轮询(默认):请求依次分配到各服务器;
  • weight 权重:按权重比例分配,适用于性能不同的服务器。
    权重配置示例
upstream webservers {server 192.168.100.128:8080 weight=90;  # 权重90%server 192.168.100.129:8080 weight=10;  # 权重10%
}
3. 苍穹外卖项目的整体架构如何设计?各模块的作用是什么?

架构设计

  • sky-take-out:父工程,管理依赖版本并聚合子模块;
  • sky-common:存放常量、工具类、异常类等公共资源;
  • sky-pojo:定义实体类(Entity)、数据传输对象(DTO)、视图对象(VO);
  • sky-server:核心模块,包含配置、Controller、Service、Mapper 等业务逻辑。
4. 登录功能的后端实现流程是什么?如何保证密码安全?

流程

  1. Controller 层:接收前端登录请求,解析用户名和密码;
  2. Service 层:根据用户名查询数据库,验证密码和账号状态(是否锁定);
  3. 生成 JWT 令牌:登录成功后,基于员工 ID 生成令牌并返回给前端。
    密码安全
    使用 MD5 加密算法对明文密码加密
password = DigestUtils.md5DigestAsHex(password.getBytes());  // 加密后比对
5. 什么是 Knife4j?如何配置接口文档?

Knife4j
是 Swagger 的增强解决方案,用于自动生成、可视化 RESTful 接口文档,简化前后端协作。
配置步骤

  1. 导入依赖:
<dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-spring-boot-starter</artifactId>
</dependency>
  1. 配置 Docket Bean(如 WebMvcConfiguration):
@Bean
public Docket docket() {return new Docket(DocumentationType.SWAGGER_2).apiInfo(new ApiInfoBuilder().title("接口文档").build()).select().apis(RequestHandlerSelectors.basePackage("com.sky.controller")).build();
}
  1. 访问地址:http://localhost:8080/doc.html
6. JWT 令牌在登录功能中的作用是什么?如何生成?

作用

  • 作为用户身份凭证,避免每次请求都查询数据库;
  • 实现无状态认证,减轻服务器负担。
// 基于员工ID生成JWT令牌
Map<String, Object> claims = new HashMap<>();
claims.put("empId", employee.getId());
String token = JwtUtil.createJWT(secretKey,          // 签名密钥ttlMillis,          // 过期时间claims              // 载荷数据
);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/bicheng/84488.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

5.2 HarmonyOS NEXT应用性能诊断与优化:工具链、启动速度与功耗管理实战

HarmonyOS NEXT应用性能诊断与优化&#xff1a;工具链、启动速度与功耗管理实战 在HarmonyOS NEXT的全场景生态中&#xff0c;应用性能直接影响用户体验。通过专业的性能分析工具链、针对性的启动速度优化&#xff0c;以及精细化的功耗管理&#xff0c;开发者能够构建"秒…

模型训练-关于token【低概率token, 高熵token】

Qwen团队新发现&#xff1a;大模型推理能力的提高仅由少数高熵 Token 贡献 不要让低概率token主导了LLM的强化学习过程 一 低概率词元问题 论文&#xff1a;Do Not Let Low-Probability Tokens Over-Dominate in RL for LLMs 在RL训练过程中&#xff0c;低概率词元&#xff08…

XCTF-web-easyupload

试了试php&#xff0c;php7&#xff0c;pht&#xff0c;phtml等&#xff0c;都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接&#xff0c;得到flag

gRPC、WebSocket 与 HTTP 的核心区别对比

gRPC、WebSocket 与 HTTP 的核心区别对比&#xff0c;涵盖通信模式、协议特性及适用场景&#xff1a; &#x1f504; ‌一、通信模式‌ ‌HTTP‌ ‌单向请求-响应‌&#xff1a;客户端发起请求&#xff0c;服务器返回响应后连接立即关闭13。‌无状态协议‌&#xff1a;每次请求…

Android第十三次面试总结(四大 组件基础)

Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成&#xff0c;用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机&#xff1a; ​onCreate()​​ ​调用时机​&#xff1a;Activity 首次创建时调用。​…

讲讲JVM的垃圾回收机制

垃圾回收就是对内存堆中已经死亡或者长时间没有使用的对象进行清楚或回收。 JVM 在做 GC 之前&#xff0c;会先搞清楚什么是垃圾&#xff0c;什么不是垃圾&#xff0c;通常会通过可达性分析算法来判断对象是否存活。 在确定了那些垃圾可以被回收后&#xff0c;垃圾回收器&…

QT软件外包开发费用

国内QT软件外包开发费用是一个非常复杂的问题&#xff0c;没有一个固定的价格&#xff0c;它受到多种因素的影响。以下将详细阐述影响QT软件外包开发费用的主要因素&#xff0c;并提供大致的价格区间供参考&#xff08;请注意&#xff0c;这些价格仅为估算&#xff0c;实际报价…

iOS 16 SwiftUI 优雅跳转实践:用枚举路由和 NavigationStack 实现多页面导航

引言&#xff1a;跳转的混乱与优雅的必要性 SwiftUI 给我们带来了声明式界面的全新开发体验&#xff0c;但当涉及到页面跳转时&#xff0c;许多开发者仍然面临一些“旧痛”。最初的 NavigationLink(destination:isActive:) 或 sheet(isPresented:) 等方式虽然能用&#xff0c;…

TikTok矩阵养号实战:住宅IP纯净度与设备指纹联动方案

在TikTok矩阵运营中&#xff0c;住宅IP纯净度和设备指纹管理是规避风控的核心。以下方案整合多平台风控逻辑与实战数据&#xff0c;覆盖环境隔离、行为模拟到风险防控全流程。 &#x1f527; 一、住宅IP纯净度维持策略 IP筛选与验证 静态住宅IP优选&#xff1a;核心账号绑定目标…

Elasticsearch增删改查语句

创建索引库&#xff1a;不带映射的 PUT /索引名称 {"settings": {"number_of_shards": 3, // 主分片数"number_of_replicas": 1 // 每个主分片的副本数} } 创建带映射的索引库&#xff1a; PUT /products {"settings": {"…

树莓派4B, ubuntu20.04, 安装Ros Noetic[踩坑记录]

一、安装过程 1. 硬件要求 树莓派4B (建议4GB或8GB内存版本) 至少16GB的microSD卡 2. 下载并安装Ubuntu 20.04 Ubuntu 20.04 LTS (Focal Fossa) for Raspberry Pi 使用Raspberry Pi Imager或BalenaEtcher将镜像写入microSD卡 3. 安装ROS Noetic ​# 设置sources.list s…

视觉slam--框架

视觉里程计的框架 传感器 VO--front end VO的缺点 后端--back end 后端对什么数据进行优化 利用什么数据进行优化的 后端是怎么进行优化的 回环检测 建图 建图是指构建地图的过程。 构建的地图是点云地图还是什么信息的地图&#xff1f; 建图并没有一个固定的形式和算法…

每日算法 -【Swift 算法】删除链表的倒数第 N 个结点

🧩 Swift | 删除链表的倒数第 N 个结点(含详细注释) 在刷算法题时,我们经常会遇到关于链表的题目,而「删除链表的倒数第 N 个节点」是其中一个非常经典的题。今天我们就用 Swift 来实现它,并梳理清楚整个思路。 🧠 一、题目描述 给你一个链表,删除链表的倒数第 n 个…

Truffle 和 Ganache 使用指南

Truffle 和 Ganache 使用指南 Truffle 命令详解 Truffle 是一个流行的以太坊开发框架,提供了许多有用的命令来简化智能合约的开发、测试和部署。 常用 Truffle 命令 初始化项目 truffle init 创建一个新的 Truffle 项目结构。 编译合约 truffle compile 编译项目中的 Solid…

docker进阶之架构

一、OCI 名为OCI&#xff0c;全称 Open Container Initiative/开放容器倡议,其目的主要是为了制定容器技术的通用技术标准。目前主要有两种标准&#xff1a; 1、容器运行时标准 &#xff08;runtime spec&#xff09; 2、容器镜像标准&#xff08;image spec&#xff09; …

企业产品网络安全日志6月10日-WAF资费消耗排查

发生了什么事&#xff1f; 上个的费用账单出来了&#xff0c;WAF费用有点飙升。比平时多了50%到100%。 周五的时候就已经知道这个事情了&#xff0c;但当时考虑肯定是拦截了一些恶意请求&#xff0c;所以。 反正也是上个月的事情了&#xff0c;所以周一过来复盘一下 数了下&a…

vue3+el-table 利用插槽自定义数据样式

<el-table-column label"匹配度" prop"baseMatchingLevel"><template #default"scope"><div :style"{ color: scope.row.baseMatchingLevel > 0.8 ? #00B578 : #FA5151 }">{{ scope.row.baseMatchingLevel }}&l…

[密码学实战]C语言使用SDF库构建国密算法RESTful服务(五)

[密码学实战]C语言使用SDF库构建国密算法RESTful服务(五) 引言 在现代信息安全领域,国密算法(SM系列算法)作为中国自主研发的密码算法标准,在金融、政务等领域得到广泛应用。本文将详细介绍如何使用C语言结合SDF(Security Device Function)库,构建一个提供国密算法服…

ubuntu 22.04搭建SOC开发环境

目录 AArch64位编译器命名规则 安装交叉工具链编译 安装aarch64-none-elf工具链 安装aarch64-none-linux-gnu工具链 启动板载系统 板卡启动方式 硬件连接 准备阶段 硬件连接 udev规则配置 启动流程 开发板外观图 硬件准备清单 硬件连接 SSH登录系统 设置Windows为…

push [特殊字符] present

push &#x1f19a; present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中&#xff0c;push 和 present 是两种不同的视图控制器切换方式&#xff0c;它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…