完成后端全部内容,等待后续修补
This commit is contained in:
parent
b91c790f8c
commit
0320a79e33
13
README.md
13
README.md
@ -2,6 +2,17 @@
|
||||
采用SpringBoot3 + Vue3编写的前后端分离模版项目,集成多种技术栈,使用JWT校验方案。
|
||||
***
|
||||
### 后端功能与技术点
|
||||
* 用户注册、用户登录、重置密码
|
||||
用户注册、用户登录、重置密码等基础功能以及对应接口
|
||||
* 采用Mybatis-Plus作为持久层框架,使用更便捷
|
||||
* 采用Redis存储注册/重置操作验证码,带过期时间控制
|
||||
* 采用RabbitMQ积压短信发送任务,再由监听器统一处理
|
||||
* 采用SpringSecurity作为权限校验框架,手动整合Jwt校验方案
|
||||
* 采用Redis进行IP地址限流处理,防刷接口
|
||||
* 视图层对象和数据层对象分离,编写工具方法利用反射快速互相转换
|
||||
* 错误和异常页面统一采用JSON格式返回,前端处理响应更统一
|
||||
* 手动处理跨域,采用过滤器实现
|
||||
* 使用Swagger作为接口文档自动生成,已自动配置登录相关接口
|
||||
* 采用过滤器实现对所有请求自动生成雪花ID方便线上定位问题
|
||||
* 项目整体结构清晰,职责明确,注释全面,开箱即用
|
||||
|
||||
### 前端功能与技术点
|
||||
|
@ -88,6 +88,12 @@
|
||||
<artifactId>java-jwt</artifactId>
|
||||
<version>4.3.0</version>
|
||||
</dependency>
|
||||
<!-- Swagger文档生成框架 -->
|
||||
<dependency>
|
||||
<groupId>org.springdoc</groupId>
|
||||
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
|
||||
<version>2.1.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<profiles>
|
||||
|
@ -53,8 +53,8 @@ public class SecurityConfiguration {
|
||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
return http
|
||||
.authorizeHttpRequests(conf -> conf
|
||||
.requestMatchers("/api/auth/**").permitAll()
|
||||
.requestMatchers("/error").permitAll()
|
||||
.requestMatchers("/api/auth/**", "/error").permitAll()
|
||||
.requestMatchers("/swagger-ui/**", "/v3/api-docs/**").permitAll()
|
||||
.anyRequest().hasAnyRole(Const.ROLE_DEFAULT)
|
||||
)
|
||||
.formLogin(conf -> conf
|
||||
|
@ -0,0 +1,113 @@
|
||||
package com.example.config;
|
||||
|
||||
import com.example.entity.RestBean;
|
||||
import com.example.entity.vo.response.AuthorizeVO;
|
||||
import io.swagger.v3.oas.annotations.OpenAPIDefinition;
|
||||
import io.swagger.v3.oas.annotations.enums.SecuritySchemeIn;
|
||||
import io.swagger.v3.oas.annotations.enums.SecuritySchemeType;
|
||||
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||
import io.swagger.v3.oas.annotations.security.SecurityScheme;
|
||||
import io.swagger.v3.oas.models.ExternalDocumentation;
|
||||
import io.swagger.v3.oas.models.OpenAPI;
|
||||
import io.swagger.v3.oas.models.Operation;
|
||||
import io.swagger.v3.oas.models.PathItem;
|
||||
import io.swagger.v3.oas.models.info.Info;
|
||||
import io.swagger.v3.oas.models.info.License;
|
||||
import io.swagger.v3.oas.models.media.Content;
|
||||
import io.swagger.v3.oas.models.media.MediaType;
|
||||
import io.swagger.v3.oas.models.parameters.QueryParameter;
|
||||
import io.swagger.v3.oas.models.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.models.responses.ApiResponses;
|
||||
import org.springdoc.core.customizers.OpenApiCustomizer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Swagger开发文档相关配置
|
||||
*/
|
||||
@Configuration
|
||||
@SecurityScheme(type = SecuritySchemeType.HTTP, scheme = "Bearer",
|
||||
name = "Authorization", in = SecuritySchemeIn.HEADER)
|
||||
@OpenAPIDefinition(security = { @SecurityRequirement(name = "Authorization") })
|
||||
public class SwaggerConfiguration {
|
||||
|
||||
/**
|
||||
* 配置文档介绍以及详细信息
|
||||
* @return OpenAPI
|
||||
*/
|
||||
@Bean
|
||||
public OpenAPI springShopOpenAPI() {
|
||||
return new OpenAPI()
|
||||
.info(new Info().title("示例项目 API 文档")
|
||||
.description("欢迎来到本示例项目API测试文档,在这里可以快速进行接口调试")
|
||||
.version("1.0")
|
||||
.license(new License()
|
||||
.name("项目开源地址")
|
||||
.url("https://github.com/Ketuer/SpringBoot-Vue-Template-Jwt")
|
||||
)
|
||||
)
|
||||
.externalDocs(new ExternalDocumentation()
|
||||
.description("我们的官方网站")
|
||||
.url("https://itbaima.net")
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置自定义的OpenApi相关信息
|
||||
* @return OpenApiCustomizer
|
||||
*/
|
||||
@Bean
|
||||
public OpenApiCustomizer customerGlobalHeaderOpenApiCustomizer() {
|
||||
return api -> this.authorizePathItems().forEach(api.getPaths()::addPathItem);
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录接口和退出登录接口手动添加一下
|
||||
* @return PathItems
|
||||
*/
|
||||
private Map<String, PathItem> authorizePathItems(){
|
||||
Map<String, PathItem> map = new HashMap<>();
|
||||
map.put("/api/auth/login", new PathItem()
|
||||
.post(new Operation()
|
||||
.tags(List.of("登录校验相关"))
|
||||
.summary("登录验证接口")
|
||||
.addParametersItem(new QueryParameter()
|
||||
.name("username")
|
||||
.required(true)
|
||||
)
|
||||
.addParametersItem(new QueryParameter()
|
||||
.name("password")
|
||||
.required(true)
|
||||
)
|
||||
.responses(new ApiResponses()
|
||||
.addApiResponse("200", new ApiResponse()
|
||||
.description("OK")
|
||||
.content(new Content().addMediaType("*/*", new MediaType()
|
||||
.example(RestBean.success(new AuthorizeVO()).asJsonString())
|
||||
))
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
map.put("/api/auth/logout", new PathItem()
|
||||
.get(new Operation()
|
||||
.tags(List.of("登录校验相关"))
|
||||
.summary("退出登录接口")
|
||||
.responses(new ApiResponses()
|
||||
.addApiResponse("200", new ApiResponse()
|
||||
.description("OK")
|
||||
.content(new Content().addMediaType("*/*", new MediaType()
|
||||
.example(RestBean.success())
|
||||
))
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
);
|
||||
return map;
|
||||
}
|
||||
}
|
@ -4,15 +4,14 @@ import com.example.entity.RestBean;
|
||||
import com.example.entity.vo.request.EmailRegisterVO;
|
||||
import com.example.entity.vo.request.EmailResetVO;
|
||||
import com.example.service.AccountService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.Email;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@ -22,6 +21,7 @@ import java.util.function.Supplier;
|
||||
@Validated
|
||||
@RestController
|
||||
@RequestMapping("/api/auth")
|
||||
@Tag(name = "登录校验相关", description = "包括用户登录、注册、验证码请求等操作。")
|
||||
public class AuthorizeController {
|
||||
|
||||
@Resource
|
||||
@ -34,6 +34,7 @@ public class AuthorizeController {
|
||||
* @return 是否请求成功
|
||||
*/
|
||||
@PostMapping("/ask-code")
|
||||
@Operation(summary = "请求邮件验证码")
|
||||
public RestBean<Void> askVerifyCode(@RequestParam @Email String email,
|
||||
HttpServletRequest request){
|
||||
return this.messageHandle(() ->
|
||||
@ -46,7 +47,8 @@ public class AuthorizeController {
|
||||
* @return 是否注册成功
|
||||
*/
|
||||
@PostMapping("/register")
|
||||
public RestBean<Void> register(@Valid EmailRegisterVO vo){
|
||||
@Operation(summary = "用户注册操作")
|
||||
public RestBean<Void> register(@RequestBody @Valid EmailRegisterVO vo){
|
||||
return this.messageHandle(() ->
|
||||
accountService.registerEmailAccount(vo));
|
||||
}
|
||||
@ -57,7 +59,8 @@ public class AuthorizeController {
|
||||
* @return 是否操作成功
|
||||
*/
|
||||
@PostMapping("/reset-password")
|
||||
public RestBean<Void> reset(@Valid EmailResetVO vo){
|
||||
@Operation(summary = "密码重置操作")
|
||||
public RestBean<Void> reset(@RequestBody @Valid EmailResetVO vo){
|
||||
return this.messageHandle(() ->
|
||||
accountService.resetEmailAccountPassword(vo));
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ import org.springframework.web.filter.OncePerRequestFilter;
|
||||
import org.springframework.web.util.ContentCachingResponseWrapper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 请求日志过滤器,用于记录所有用户请求信息
|
||||
@ -28,14 +29,32 @@ public class RequestLogFilter extends OncePerRequestFilter {
|
||||
@Resource
|
||||
SnowflakeIdGenerator generator;
|
||||
|
||||
private final Set<String> ignores = Set.of("/swagger-ui", "/v3/api-docs");
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
|
||||
long startTime = System.currentTimeMillis();
|
||||
this.logRequestStart(request);
|
||||
ContentCachingResponseWrapper wrapper = new ContentCachingResponseWrapper(response);
|
||||
filterChain.doFilter(request, wrapper);
|
||||
this.logRequestEnd(wrapper, startTime);
|
||||
wrapper.copyBodyToResponse();
|
||||
if(this.isIgnoreUrl(request.getServletPath())) {
|
||||
filterChain.doFilter(request, response);
|
||||
} else {
|
||||
long startTime = System.currentTimeMillis();
|
||||
this.logRequestStart(request);
|
||||
ContentCachingResponseWrapper wrapper = new ContentCachingResponseWrapper(response);
|
||||
filterChain.doFilter(request, wrapper);
|
||||
this.logRequestEnd(wrapper, startTime);
|
||||
wrapper.copyBodyToResponse();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判定当前请求url是否不需要日志打印
|
||||
* @param url 路径
|
||||
* @return 是否忽略
|
||||
*/
|
||||
private boolean isIgnoreUrl(String url){
|
||||
for (String ignore : ignores) {
|
||||
if(url.startsWith(ignore)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,4 +1,8 @@
|
||||
# 开发环境配置
|
||||
springdoc:
|
||||
paths-to-match: /api/**
|
||||
swagger-ui:
|
||||
operations-sorter: alpha
|
||||
spring:
|
||||
mail:
|
||||
host: smtp.163.com
|
||||
@ -29,12 +33,9 @@ spring:
|
||||
mail-limit: 60
|
||||
flow:
|
||||
period: 3
|
||||
limit: 10
|
||||
limit: 50
|
||||
block: 30
|
||||
cors:
|
||||
origin: '*'
|
||||
credentials: false
|
||||
methods: '*'
|
||||
mybatis-plus:
|
||||
configuration:
|
||||
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
||||
|
@ -1,4 +1,12 @@
|
||||
#生产环境配置
|
||||
server:
|
||||
port: 80
|
||||
springdoc:
|
||||
api-docs:
|
||||
enabled: false
|
||||
mybatis-plus:
|
||||
configuration:
|
||||
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
||||
spring:
|
||||
mail:
|
||||
host: smtp.163.com
|
||||
|
Loading…
x
Reference in New Issue
Block a user