项目采用前后端分离的方式开发,包括前端界面(Web端管理程序、小程序客户端界面)前端vue技术开发使用nginx部署启动,后端springboot技术开发IDEA进行启动。
前端项目使用nginx启动,只需要将打包后的vue项目放到nginx安装目录下的html文件夹下。然后对nginx.conf文件进行配置即可启动前端vue,浏览器使用localhost:80
即可访问相关界面。
思考:本项目采用前后端分离的方式开发,前端的浏览器发送的请求是如何请求到后端服务的?
前端请求地址:http://localhost/api/employee/login
后端接口地址:http://localhost:8080/admin/employee/login
前端请求:打开浏览器的调试,Network下的Headers即可看到前端请求的url:http://localhost/api/employee/login
。
后端配置文件:application.yml
server:
port: 8080
#当前环境为dev开发环境,因此application-dev.yml配置文件也生效
spring:
profiles:
active: dev
main:
allow-circular-references: true
datasource:
druid:
driver-class-name: ${sky.datasource.driver-class-name}
url: jdbc:mysql://${sky.datasource.host}:${sky.datasource.port}/${sky.datasource.database}?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
username: ${sky.datasource.username}
password: ${sky.datasource.password}
mybatis:
#mapper配置文件
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.sky.entity
configuration:
#开启驼峰命名
map-underscore-to-camel-case: true
logging:
level:
com:
sky:
mapper: debug
service: info
controller: info
sky:
jwt:
# 设置jwt签名加密时使用的秘钥
admin-secret-key: itcast
# 设置jwt过期时间
admin-ttl: 7200000
# 设置前端传递过来的令牌名称
admin-token-name: token
配置文件:application-dev.yml
sky:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
host: localhost
port: 3306
database: sky_take_out
username: root
password: 12345678
后端接收请求:当后端接收登录请求时,后端接口地址:http://localhost:8080/admin/employee/login
/**
* 员工管理EmployeeController
*/
@RestController
@RequestMapping("/admin/employee")
@Slf4j
public class EmployeeController {
@Autowired
private EmployeeService employeeService;
@Autowired
private JwtProperties jwtProperties;
// 登录请求
@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);
}
}
解答:采用Nginx做反向代理,将前端发送的动态请求由Nginx转发到后端服务器。
Nginx反向代理的好处:提升访问速度、进行负载均衡、保障后端服务安全。
#将匹配到的/api/的前端请求转发到http://localhost:8080/admin/请求地址,后面动态的请求
server {
listen 80; #监听的端口
server_name localhost; #监听的域名
# 反向代理,处理管理端发送的请求
location /api/ {
#反向代理关键proxy_pass指令
proxy_pass http://localhost:8080/admin/; #指令将请求转发到代理的后端服务器
}
}
配置说明:当nginx接收到前端请求含有/api/
时,nginx将请求转发到http://localhost:8080/admin/
的后端服务器请求路径下响应,动态请求路径拼接在http://localhost:8080/admin/
后即可,如下图。
负载均衡的前提是反向代理,将接收到的请求均衡的分配到各应用服务器上
upstream webservers{
server 127.0.0.1:8080 weight=90 ;
server 127.0.0.1:8088 weight=10 ;
}
#将匹配到的/api/的前端请求转发到http://localhost:8080/admin/请求地址,后面动态的请求
server {
listen 80; #监听的端口
server_name localhost; #监听的域名
# 反向代理,处理管理端发送的请求
location /api/ {
#负载均衡
#proxy_pass http://webservers/admin/; #指令将请求转发到的后端服务器
}
}
nginx负载均衡策略:
为了保护用户的隐私和数据安全,密码一般不使用明文存储,此处使用md5加密算法进行加密。
/**
* 员工登录
*
* @param employeeLoginDTO
* @return
*/
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);
}
//密码比对
//对用户登录的密码做md5加密处理后和数据库加密后的密码对比
password = DigestUtils.md5DigestAsHex(password.getBytes());
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;
}
作为前后端分离的项目,接口的设计非常重要,下面是前后端分离开发流程:
对于json格式的接口,使用http://yapi.lootom-ai.com/login
导入接口文件。
Swagger是一款可以根据resutful风格生成的生成的接口开发文档,并且支持做测试的一款中间软件。
Knife4j是一个集Swagger2 和 OpenAPI3为一体的增强解决方案。教程:knife4j使用教程
<!--1、引入Knife4j的官方start包,该指南选择Spring Boot版本<3.0,开发者需要注意-->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi2-spring-boot-starter</artifactId>
<version>4.4.0</version>
</dependency>
/**
* 配置类,注册web层相关组件
*/
@Configuration
@Slf4j
public class WebMvcConfiguration extends WebMvcConfigurationSupport {
/**
* 2、通过knife4j生成接口文档
* @return
*/
@Bean
public 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、设置静态资源映射
* @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/");
}
}
所有配置结束后,重启SpringBoot服务,打开浏览器:http://localhost:8080/doc.html
即可查看相关的接口文档。
思考:通过 Swagger 就可以生成接口文档,那么我们就不需要 Yapi了?
1、Yapi是设计阶段使用的工具,管理和维护接口;
2、Swagger 在开发阶段使用的框架,帮助后端开发人员做后端的接口测试;
注解 | 说明 |
---|---|
@Api | 用在类,例如Controller,表示类的说明 |
@ApiModel | 用在类,例如entity,DTO,VO |
@ApiModelProperty | 用在属性,描述属性信息 |
@ApiOperation | 用在方法上,例如Controller的方法,例如方法的用途、作用 |
标注后,重启服务,打开浏览器:http://localhost:8080/doc.html
即可查看。