fix: 修复网关启动找不到服务的问题,修复jwt问题,修复自动导入失败问题。
This commit is contained in:
9
.claude/settings.local.json
Normal file
9
.claude/settings.local.json
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"permissions": {
|
||||||
|
"allow": [
|
||||||
|
"Bash(mvn clean compile:*)",
|
||||||
|
"Bash(mvn spring-javaformat:apply)",
|
||||||
|
"Bash(cat:*)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
2
.idea/CoolRequestCommonStatePersistent.xml
generated
2
.idea/CoolRequestCommonStatePersistent.xml
generated
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="CoolRequestCommonStatePersistent">
|
<component name="CoolRequestCommonStatePersistent">
|
||||||
<option name="searchCache" value="AIOJAdminA" />
|
<option name="searchCache" value="G" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
13
.idea/dataSources.xml
generated
Normal file
13
.idea/dataSources.xml
generated
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
||||||
|
<data-source source="LOCAL" name="jdbc:mysql://10.0.0.10/aioj_dev [DEBUG]" group="UserServiceApplication" uuid="07fb0260-0355-4ed0-9bd2-c20d69288289">
|
||||||
|
<driver-ref>mysql.8</driver-ref>
|
||||||
|
<synchronize>true</synchronize>
|
||||||
|
<imported>true</imported>
|
||||||
|
<jdbc-driver>com.mysql.cj.jdbc.Driver</jdbc-driver>
|
||||||
|
<jdbc-url>jdbc:mysql://10.0.0.10/aioj_dev</jdbc-url>
|
||||||
|
<working-dir>$ProjectFileDir$</working-dir>
|
||||||
|
</data-source>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
6
.idea/db-forest-config.xml
generated
Normal file
6
.idea/db-forest-config.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="db-tree-configuration">
|
||||||
|
<option name="data" value="1:0:UserServiceApplication ---------------------------------------- 2:1:07fb0260-0355-4ed0-9bd2-c20d69288289 " />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
251
CLAUDE.md
251
CLAUDE.md
@@ -2,195 +2,122 @@
|
|||||||
|
|
||||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
## Project Overview
|
## Codebase Overview
|
||||||
|
|
||||||
This is a microservices-based Online Judge (OJ) system with AI integration called AIOJ (AI Online Judge). It's built with Spring Boot 3.5.7 and Spring Cloud 2025.0.0, following a modular Maven multi-module architecture.
|
This is a microservices architecture for an Online Judge (OJ) system, built on **Spring Boot 3.5.7**. The project uses Maven as the build tool and follows a modular monorepo structure, with clearly separated core modules and service modules.
|
||||||
|
|
||||||
## Common Development Commands
|
### Core Modules
|
||||||
|
|
||||||
### Building the Project
|
The `aioj-backend-common` directory contains shared components and utilities used across all service modules:
|
||||||
```bash
|
|
||||||
# Build entire project
|
|
||||||
mvn clean install
|
|
||||||
|
|
||||||
# Build with specific environment profile
|
1. **aioj-backend-common-bom**
|
||||||
mvn clean install -P dev # Development (default)
|
Bill of materials for centralized dependency management. This ensures consistent versions of all external libraries across all modules.
|
||||||
mvn clean install -P test # Testing
|
|
||||||
mvn clean install -P prod # Production
|
|
||||||
|
|
||||||
# Format code according to Spring standards
|
2. **aioj-backend-common-core**
|
||||||
mvn spring-javaformat:apply
|
Core utilities and Spring framework extensions:
|
||||||
|
- `BannerApplicationRunner`: Custom application banner display during startup
|
||||||
|
- `SpringContextHolder`: Spring context accessor for non-Spring-managed classes
|
||||||
|
- `JavaTimeModule`: Jackson module for Java 8+ time API support
|
||||||
|
- Common constants and enumerations
|
||||||
|
- Application-level configurations and auto-configuration classes
|
||||||
|
|
||||||
# Build Docker images using Jib
|
3. **aioj-backend-common-feign**
|
||||||
mvn clean package jib:build
|
Feign client configurations for seamless inter-service communication:
|
||||||
|
- Auto-configuration for Feign clients with default settings
|
||||||
|
- `@EnableAIOJFeignClients` annotation for enabling Feign clients with predefined base packages
|
||||||
|
- Feign interceptors and error handling mechanisms
|
||||||
|
|
||||||
# Or use Maven wrapper
|
4. **aioj-backend-common-log**
|
||||||
./mvnw clean install
|
Aspect-oriented programming (AOP) based logging framework:
|
||||||
```
|
- `SysLogAspect`: Aspect for logging system operations (controller methods, service calls)
|
||||||
|
- `SysLogEvent` and `SysLogListener`: Event-driven logging mechanism
|
||||||
|
- `SysLogUtils`: Utility class for creating and managing log entries
|
||||||
|
- Configuration properties for logging behavior
|
||||||
|
|
||||||
### Running Services
|
5. **aioj-backend-common-mybatis**
|
||||||
Each service runs on different ports:
|
MyBatis ORM framework extensions:
|
||||||
- Gateway: 8085
|
- Auto-fill functionality for `createTime` and `updateTime` fields
|
||||||
- Other services: configured via Nacos
|
- Pagination interceptor implementation
|
||||||
|
- MyBatis configuration auto-configuration classes
|
||||||
|
|
||||||
Run individual services from their respective directories:
|
6. **aioj-backend-common-starter**
|
||||||
```bash
|
Auto-configuration starters for easily enabling common features in service modules.
|
||||||
cd aioj-backend-gateway
|
|
||||||
mvn spring-boot:run
|
|
||||||
|
|
||||||
# Or with specific profile
|
|
||||||
mvn spring-boot:run -Dspring.profiles.active=dev
|
|
||||||
```
|
|
||||||
|
|
||||||
### Database Setup
|
### Service Modules
|
||||||
1. Create databases using the provided script:
|
|
||||||
```bash
|
|
||||||
mysql -u root -p < db/create_db.sql
|
|
||||||
```
|
|
||||||
This creates three databases: `aioj_dev`, `aioj_test`, and `aioj_prod`
|
|
||||||
|
|
||||||
## Architecture Overview
|
The service modules represent the individual microservices that make up the system:
|
||||||
|
|
||||||
### Microservices Architecture
|
1. **aioj-backend-auth**
|
||||||
The system consists of seven main services:
|
Authentication and authorization service:
|
||||||
|
- JWT-based authentication with `JwtAuthenticationFilter`
|
||||||
|
- Security configuration with Spring Security
|
||||||
|
- User login, token generation, and validation
|
||||||
|
- Permission verification and access control
|
||||||
|
|
||||||
1. **aioj-backend-gateway** (Port 8085)
|
2. **aioj-backend-gateway**
|
||||||
- API Gateway using Spring Cloud Gateway
|
API gateway for request routing and filtering:
|
||||||
- Routes requests to appropriate services
|
- Request routing to appropriate service modules
|
||||||
- Built with WebFlux for reactive programming
|
- Authentication token validation before forwarding requests
|
||||||
|
- Rate limiting and request filtering mechanisms
|
||||||
|
|
||||||
2. **aioj-backend-auth**
|
3. **aioj-backend-judge-service**
|
||||||
- OAuth2 authentication and authorization service
|
Code judge service (under development):
|
||||||
- Manages user credentials and tokens
|
- Will handle code submission, compilation, and execution
|
||||||
|
- Support for multiple programming languages
|
||||||
|
- Test case validation and result return
|
||||||
|
|
||||||
3. **aioj-backend-user-service**
|
4. **aioj-backend-user-service**
|
||||||
- User management and profiles
|
User management service:
|
||||||
- Handles registration, login, profile updates
|
- User registration, profile management, and information retrieval
|
||||||
- Integrates with Redis for session management
|
- User role and permission assignment
|
||||||
|
- Integration with the auth service for authentication
|
||||||
|
|
||||||
4. **aioj-backend-question-service**
|
5. **aioj-backend-question-service**
|
||||||
- Problem/question management
|
Question bank service (under development):
|
||||||
- Handles problem storage and retrieval
|
- Will manage programming problems, test cases, and problem categories
|
||||||
|
- Support for problem difficulty levels and tags
|
||||||
5. **aioj-backend-judge-service**
|
- Integration with the judge service for problem submission
|
||||||
- Core OJ functionality for code execution
|
|
||||||
- Supports multiple programming languages
|
|
||||||
|
|
||||||
6. **aioj-backend-ai-service**
|
6. **aioj-backend-ai-service**
|
||||||
- AI integration for enhanced features
|
AI-related functionality service (under development):
|
||||||
- Code analysis and automated feedback
|
- Will provide AI-assisted features like problem recommendation, code analysis, etc.
|
||||||
|
|
||||||
7. **aioj-backend-upms** (User Permission Management System)
|
7. **aioj-backend-upms**
|
||||||
- Role-based access control
|
User, permission, and menu management service:
|
||||||
- Permission management
|
- Low-level user and permission management
|
||||||
|
- Menu and resource access control
|
||||||
|
- Integration with other services for authorization
|
||||||
|
|
||||||
### Common Modules
|
## Commonly Used Commands
|
||||||
- **aioj-backend-common**: Shared utilities with sub-modules:
|
|
||||||
- `core`: Core utilities and configurations
|
|
||||||
- `log`: Custom logging implementation
|
|
||||||
- `starter`: Auto-configuration starters
|
|
||||||
- `mybatis`: Database access layer
|
|
||||||
- `feign`: HTTP client for service communication
|
|
||||||
- `bom`: Bill of Materials for dependency management
|
|
||||||
|
|
||||||
## Technology Stack
|
### Build
|
||||||
|
- **Build the entire project**: `mvn clean compile`
|
||||||
### Core Technologies
|
- **Build with tests**: `mvn clean install`
|
||||||
- **Java 17**
|
- **Build a single module**: `mvn clean compile -pl aioj-backend-auth`
|
||||||
- **Spring Boot 3.5.7**
|
|
||||||
- **Spring Cloud 2025.0.0**
|
|
||||||
- **Spring Cloud Alibaba 2025.0.0.0**
|
|
||||||
- **Maven** for build management
|
|
||||||
|
|
||||||
### Database & Persistence
|
|
||||||
- **MySQL 9.4.0** as primary database
|
|
||||||
- **MyBatis-Plus 3.5.14** for ORM
|
|
||||||
- **Redis** for caching and session management
|
|
||||||
|
|
||||||
### Cloud & Infrastructure
|
|
||||||
- **Nacos** for service discovery and configuration (server: 10.0.0.10:8848)
|
|
||||||
- **Spring Cloud Gateway** for API routing
|
|
||||||
- **Docker** with Jib plugin for containerization
|
|
||||||
- **Sentinel** for circuit breaking
|
|
||||||
|
|
||||||
### Security
|
|
||||||
- **Spring Security 6.5.6** with OAuth2
|
|
||||||
- JWT token-based authentication
|
|
||||||
- Role-based access control
|
|
||||||
|
|
||||||
### API Documentation
|
|
||||||
- **Knife4j** (OpenAPI 3) integrated across services
|
|
||||||
|
|
||||||
## Configuration Management
|
|
||||||
|
|
||||||
### Environment-Specific Configuration
|
|
||||||
Three environments are supported:
|
|
||||||
- `dev` (development, default)
|
|
||||||
- `test` (testing)
|
|
||||||
- `prod` (production)
|
|
||||||
|
|
||||||
Configuration files:
|
|
||||||
- `bootstrap.yml` - Nacos service discovery configuration
|
|
||||||
- `application.yml` - Main application configuration
|
|
||||||
- `application-{env}.yml` - Environment-specific settings
|
|
||||||
|
|
||||||
### Nacos Integration
|
|
||||||
All services use Nacos for:
|
|
||||||
- Service discovery
|
|
||||||
- Configuration management
|
|
||||||
- Centralized properties management
|
|
||||||
|
|
||||||
Default Nacos configuration:
|
|
||||||
```yaml
|
|
||||||
spring:
|
|
||||||
cloud:
|
|
||||||
nacos:
|
|
||||||
discovery:
|
|
||||||
server-addr: 10.0.0.10:8848
|
|
||||||
username: nacos
|
|
||||||
password: nacos
|
|
||||||
```
|
|
||||||
|
|
||||||
## Database Schema
|
|
||||||
|
|
||||||
### Environment Databases
|
|
||||||
- Development: `aioj_dev`
|
|
||||||
- Testing: `aioj_test`
|
|
||||||
- Production: `aioj_prod`
|
|
||||||
|
|
||||||
All databases use UTF-8 character set with `utf8mb4_general_ci` collation.
|
|
||||||
|
|
||||||
## Development Guidelines
|
|
||||||
|
|
||||||
### Code Formatting
|
### Code Formatting
|
||||||
- Uses Spring JavaFormat plugin for consistent code style
|
- **Format code**: `mvn spring-javaformat:apply`
|
||||||
- IDE plugin available: https://repo1.maven.org/maven2/io/spring/javaformat/spring-javaformat-intellij-idea-plugin
|
- **Check code format**: `mvn spring-javaformat:check`
|
||||||
- Run `mvn spring-javaformat:apply` before commits
|
|
||||||
|
|
||||||
### Docker Integration
|
### Testing
|
||||||
- Jib plugin configured for container builds
|
- **Run all tests**: `mvn test`
|
||||||
- Target registry: `10.0.0.3/aioj/{service-name}:{version}`
|
- **Run tests for a single module**: `mvn test -pl aioj-backend-user-service`
|
||||||
- JVM memory configured: -Xms512m -Xmx512m
|
|
||||||
|
|
||||||
### Service Communication
|
### Running Services
|
||||||
- Uses OpenFeign for inter-service communication
|
- **Run a service locally**: Use Spring Boot's `Application` class directly in IDE or use `mvn spring-boot:run -pl <module-name>`
|
||||||
- Load balancing with Spring Cloud LoadBalancer
|
- **Example**: `mvn spring-boot:run -pl aioj-backend-auth`
|
||||||
- Circuit breaking with Sentinel
|
|
||||||
|
|
||||||
### Logging
|
## Architecture Highlights
|
||||||
- Custom logging implementation in `aioj-backend-common-log`
|
|
||||||
- Integrates with Spring Security for context logging
|
|
||||||
- Uses Hutool utilities for enhanced logging
|
|
||||||
|
|
||||||
## Testing
|
- **Authentication**: JWT-based authentication implemented in `aioj-backend-auth` with `JwtAuthenticationFilter`
|
||||||
- Spring Boot Test framework included
|
- **Logging**: Aspect-oriented logging with `SysLogAspect` in `aioj-backend-common-log`
|
||||||
- Spring Security Test for authentication testing
|
- **Database**: MyBatis with auto-fill for create/update times implemented in `common-mybatis`
|
||||||
- Test structure is evolving - check individual modules for test coverage
|
- **Inter-service communication**: Feign clients with auto-configuration from `common-feign`
|
||||||
|
- **Banner**: Custom application banner system in `common-core`
|
||||||
|
|
||||||
## Important Notes
|
## Key Entry Points
|
||||||
|
|
||||||
1. **Service Dependencies**: Services depend on Nacos for discovery - ensure Nacos is running before starting services
|
- **Gateway Application**: `aioj-backend-gateway/src/main/java/cn/meowrain/aioj/backend/gateway/AIOJGatewayApplication.java`
|
||||||
2. **Database Setup**: Run the database creation script before first run
|
- **Auth Application**: `aioj-backend-auth/src/main/java/cn/meowrain/aioj/backend/auth/AIOJAuthApplication.java`
|
||||||
3. **Port Configuration**: Gateway runs on 8085, other services are dynamically registered
|
- **User Service Application**: `aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/UserServiceApplication.java`
|
||||||
4. **Environment Profiles**: Default is `dev` - use appropriate profiles for different environments
|
|
||||||
5. **Configuration Management**: Most configuration is externalized to Nacos - check Nacos for service-specific settings
|
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
package cn.meowrain.aioj.backend.auth.config;
|
package cn.meowrain.aioj.backend.auth.config;
|
||||||
|
|
||||||
|
import cn.meowrain.aioj.backend.auth.filter.JwtAuthenticationFilter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
@@ -10,11 +12,15 @@ import org.springframework.security.config.http.SessionCreationPolicy;
|
|||||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
import org.springframework.security.web.SecurityFilterChain;
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
|
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
|
@RequiredArgsConstructor
|
||||||
public class SecurityConfiguration {
|
public class SecurityConfiguration {
|
||||||
|
|
||||||
|
private final JwtAuthenticationFilter jwtAuthenticationFilter;
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||||
http.csrf(csrf -> csrf.disable())
|
http.csrf(csrf -> csrf.disable())
|
||||||
@@ -24,7 +30,8 @@ public class SecurityConfiguration {
|
|||||||
"/v3/api-docs/**", "/favicon.ico")
|
"/v3/api-docs/**", "/favicon.ico")
|
||||||
.permitAll()
|
.permitAll()
|
||||||
.anyRequest()
|
.anyRequest()
|
||||||
.authenticated());
|
.authenticated())
|
||||||
|
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
|
||||||
return http.build();
|
return http.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,106 @@
|
|||||||
package cn.meowrain.aioj.backend.auth.filter;
|
package cn.meowrain.aioj.backend.auth.filter;
|
||||||
|
|
||||||
|
import cn.meowrain.aioj.backend.auth.service.AuthService;
|
||||||
|
import cn.meowrain.aioj.backend.auth.utils.JwtUtil;
|
||||||
|
import io.jsonwebtoken.Claims;
|
||||||
|
import jakarta.servlet.FilterChain;
|
||||||
|
import jakarta.servlet.ServletException;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JWT拦截器
|
* JWT认证过滤器
|
||||||
|
* 拦截所有请求,验证JWT Token
|
||||||
*/
|
*/
|
||||||
@Component
|
@Component
|
||||||
public class JwtAuthenticationFilter {
|
@RequiredArgsConstructor
|
||||||
|
@Slf4j
|
||||||
|
public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
||||||
|
|
||||||
|
private final JwtUtil jwtUtil;
|
||||||
|
private final AuthService authService;
|
||||||
|
|
||||||
|
private static final String TOKEN_PREFIX = "Bearer ";
|
||||||
|
private static final String HEADER_NAME = "Authorization";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
||||||
|
throws ServletException, IOException {
|
||||||
|
|
||||||
|
try {
|
||||||
|
String token = extractTokenFromRequest(request);
|
||||||
|
|
||||||
|
if (StringUtils.hasText(token) && jwtUtil.isTokenValid(token)) {
|
||||||
|
Claims claims = jwtUtil.parseClaims(token);
|
||||||
|
Authentication authentication = createAuthentication(claims);
|
||||||
|
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||||
|
|
||||||
|
log.debug("JWT Authentication successful for user: {}", claims.getSubject());
|
||||||
|
} else {
|
||||||
|
log.debug("No valid JWT token found in request");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("JWT Authentication failed", e);
|
||||||
|
SecurityContextHolder.clearContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
filterChain.doFilter(request, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从请求中提取JWT Token
|
||||||
|
*/
|
||||||
|
private String extractTokenFromRequest(HttpServletRequest request) {
|
||||||
|
String bearerToken = request.getHeader(HEADER_NAME);
|
||||||
|
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(TOKEN_PREFIX)) {
|
||||||
|
return bearerToken.substring(TOKEN_PREFIX.length());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据JWT Claims创建Authentication对象
|
||||||
|
*/
|
||||||
|
private Authentication createAuthentication(Claims claims) {
|
||||||
|
String userId = claims.getSubject();
|
||||||
|
String userName = claims.get("userName", String.class);
|
||||||
|
String role = claims.get("role", String.class);
|
||||||
|
|
||||||
|
// 创建权限列表
|
||||||
|
List<SimpleGrantedAuthority> authorities = Collections.singletonList(
|
||||||
|
new SimpleGrantedAuthority("ROLE_" + (role != null ? role : "USER"))
|
||||||
|
);
|
||||||
|
|
||||||
|
// 创建认证对象
|
||||||
|
UsernamePasswordAuthenticationToken authentication =
|
||||||
|
new UsernamePasswordAuthenticationToken(userId, null, authorities);
|
||||||
|
|
||||||
|
return authentication;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
|
||||||
|
String path = request.getRequestURI();
|
||||||
|
// 跳过不需要JWT验证的路径
|
||||||
|
return path.startsWith("/v1/auth/") ||
|
||||||
|
path.startsWith("/doc.html") ||
|
||||||
|
path.startsWith("/swagger-ui/") ||
|
||||||
|
path.startsWith("/swagger-resources/") ||
|
||||||
|
path.startsWith("/webjars/") ||
|
||||||
|
path.startsWith("/v3/api-docs/") ||
|
||||||
|
path.equals("/favicon.ico");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>cn.meowrain</groupId>
|
<groupId>cn.meowrain</groupId>
|
||||||
@@ -63,5 +63,9 @@
|
|||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-validation</artifactId>
|
<artifactId>spring-boot-starter-validation</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-autoconfigure</artifactId>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
@@ -14,43 +14,47 @@ import java.time.format.DateTimeFormatter;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class BannerApplicationRunner implements ApplicationRunner {
|
public class BannerApplicationRunner implements ApplicationRunner {
|
||||||
private final Environment env;
|
|
||||||
@Value("${spring.application.name:unknown}")
|
|
||||||
private String appName;
|
|
||||||
|
|
||||||
@Override
|
private final Environment env;
|
||||||
public void run(ApplicationArguments args) throws Exception {
|
|
||||||
// Active profiles
|
|
||||||
String profiles = String.join(",", env.getActiveProfiles());
|
|
||||||
if (profiles.isEmpty()) {
|
|
||||||
profiles = "default";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Port
|
@Value("${spring.application.name:unknown}")
|
||||||
String port = env.getProperty("server.port", "unknown");
|
private String appName;
|
||||||
|
|
||||||
// JVM info
|
@Override
|
||||||
String jvm = System.getProperty("java.version") + " (" + System.getProperty("java.vendor") + ")";
|
public void run(ApplicationArguments args) throws Exception {
|
||||||
|
// Active profiles
|
||||||
|
String profiles = String.join(",", env.getActiveProfiles());
|
||||||
|
if (profiles.isEmpty()) {
|
||||||
|
profiles = "default";
|
||||||
|
}
|
||||||
|
|
||||||
// PID
|
// Port
|
||||||
String pid = ManagementFactory.getRuntimeMXBean().getPid() + "";
|
String port = env.getProperty("server.port", "unknown");
|
||||||
|
|
||||||
// Time
|
// JVM info
|
||||||
String time = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
|
String jvm = System.getProperty("java.version") + " (" + System.getProperty("java.vendor") + ")";
|
||||||
|
|
||||||
// Git commit id (如果没有 git.properties,不会报错)
|
// PID
|
||||||
String gitCommit = env.getProperty("git.commit.id.abbrev", "N/A");
|
String pid = ManagementFactory.getRuntimeMXBean().getPid() + "";
|
||||||
|
|
||||||
printBanner(appName, profiles, port, jvm, pid, time, gitCommit);
|
// Time
|
||||||
}
|
String time = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
|
||||||
private void printBanner(String appName, String profiles, String port, String jvm, String pid, String time,
|
|
||||||
String gitCommit) {
|
// Git commit id (如果没有 git.properties,不会报错)
|
||||||
|
String gitCommit = env.getProperty("git.commit.id.abbrev", "N/A");
|
||||||
|
|
||||||
|
printBanner(appName, profiles, port, jvm, pid, time, gitCommit);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void printBanner(String appName, String profiles, String port, String jvm, String pid, String time,
|
||||||
|
String gitCommit) {
|
||||||
|
|
||||||
|
String banner = "\n" + "------------------------------------------------------------\n"
|
||||||
|
+ " ✨AI Online Judge✨ - " + appName + "\n" + " Environment : " + profiles + "\n" + " Port : "
|
||||||
|
+ port + "\n" + " Git Commit : " + gitCommit + "\n" + " JVM : " + jvm + "\n"
|
||||||
|
+ " PID : " + pid + "\n" + " Started At : " + time + "\n"
|
||||||
|
+ "------------------------------------------------------------\n";
|
||||||
|
System.out.println(banner);
|
||||||
|
}
|
||||||
|
|
||||||
String banner = "\n" + "------------------------------------------------------------\n"
|
|
||||||
+ " ✨AI Online Judge✨ - " + appName + "\n" + " Environment : " + profiles + "\n" + " Port : "
|
|
||||||
+ port + "\n" + " Git Commit : " + gitCommit + "\n" + " JVM : " + jvm + "\n"
|
|
||||||
+ " PID : " + pid + "\n" + " Started At : " + time + "\n"
|
|
||||||
+ "------------------------------------------------------------\n";
|
|
||||||
System.out.println(banner);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,10 @@ import org.springframework.core.env.Environment;
|
|||||||
|
|
||||||
@AutoConfiguration
|
@AutoConfiguration
|
||||||
public class AIOJBannerAutoConfiguration {
|
public class AIOJBannerAutoConfiguration {
|
||||||
@Bean
|
|
||||||
public BannerApplicationRunner bannerApplicationRunner(Environment env) {
|
@Bean
|
||||||
return new BannerApplicationRunner(env);
|
public BannerApplicationRunner bannerApplicationRunner(Environment env) {
|
||||||
}
|
return new BannerApplicationRunner(env);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,18 +4,20 @@ package cn.meowrain.aioj.backend.framework.core.constants;
|
|||||||
* 全局服务名称
|
* 全局服务名称
|
||||||
*/
|
*/
|
||||||
public class ServiceNameConstants {
|
public class ServiceNameConstants {
|
||||||
/**
|
|
||||||
* 用户服务 SERVICE NAME
|
|
||||||
*/
|
|
||||||
public static final String USER_SERVICE = "user-service";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 认证服务 SERVICE NAME
|
* 用户服务 SERVICE NAME
|
||||||
*/
|
*/
|
||||||
public static final String AUTH_SERVICE = "auth-service";
|
public static final String USER_SERVICE = "user-service";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 认证服务 SERVICE NAME
|
||||||
|
*/
|
||||||
|
public static final String AUTH_SERVICE = "auth-service";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UPMS模块
|
||||||
|
*/
|
||||||
|
public static final String UPMS_SERVICE = "upms-service";
|
||||||
|
|
||||||
/**
|
|
||||||
* UPMS模块
|
|
||||||
*/
|
|
||||||
public static final String UPMS_SERVICE = "upms-service";
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import cn.meowrain.aioj.backend.framework.core.web.Result;
|
|||||||
import cn.meowrain.aioj.backend.framework.core.web.Results;
|
import cn.meowrain.aioj.backend.framework.core.web.Results;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.core.Ordered;
|
||||||
|
import org.springframework.core.annotation.Order;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
import org.springframework.validation.BindingResult;
|
import org.springframework.validation.BindingResult;
|
||||||
import org.springframework.validation.FieldError;
|
import org.springframework.validation.FieldError;
|
||||||
@@ -12,6 +14,8 @@ import org.springframework.web.bind.MethodArgumentNotValidException;
|
|||||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -19,12 +23,18 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@RestControllerAdvice
|
@RestControllerAdvice
|
||||||
|
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||||
public class GlobalExceptionHandler {
|
public class GlobalExceptionHandler {
|
||||||
|
// 加这个构造器,启动看日志
|
||||||
|
public GlobalExceptionHandler() {
|
||||||
|
System.out.println("===== 自定义异常处理器已加载 =====");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 捕获所有参数错误,然后统一捕获并且抛出
|
* 捕获所有参数错误,然后统一捕获并且抛出
|
||||||
|
*
|
||||||
* @param request {@link HttpServletRequest}
|
* @param request {@link HttpServletRequest}
|
||||||
* @param ex {@link org.springframework.validation.method.MethodValidationException}
|
* @param ex {@link org.springframework.validation.method.MethodValidationException}
|
||||||
* @return {@link Result<Void>}
|
* @return {@link Result<Void>}
|
||||||
*/
|
*/
|
||||||
@ExceptionHandler(value = MethodArgumentNotValidException.class)
|
@ExceptionHandler(value = MethodArgumentNotValidException.class)
|
||||||
@@ -32,9 +42,9 @@ public class GlobalExceptionHandler {
|
|||||||
BindingResult bindingResult = ex.getBindingResult();
|
BindingResult bindingResult = ex.getBindingResult();
|
||||||
// 收集所有错误字段
|
// 收集所有错误字段
|
||||||
List<String> errorMessages = bindingResult.getFieldErrors()
|
List<String> errorMessages = bindingResult.getFieldErrors()
|
||||||
.stream()
|
.stream()
|
||||||
.map(FieldError::getDefaultMessage)
|
.map(FieldError::getDefaultMessage)
|
||||||
.toList();
|
.toList();
|
||||||
String exceptionMessage = String.join(",", errorMessages);
|
String exceptionMessage = String.join(",", errorMessages);
|
||||||
log.error("[{}] {} [ex] {}", request.getMethod(), getUrl(request), exceptionMessage);
|
log.error("[{}] {} [ex] {}", request.getMethod(), getUrl(request), exceptionMessage);
|
||||||
return Results.paramsValidFailure();
|
return Results.paramsValidFailure();
|
||||||
@@ -42,8 +52,9 @@ public class GlobalExceptionHandler {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 抽象异常捕获其
|
* 抽象异常捕获其
|
||||||
|
*
|
||||||
* @param request {@link HttpServletRequest}
|
* @param request {@link HttpServletRequest}
|
||||||
* @param ex {@link AbstractException}
|
* @param ex {@link AbstractException}
|
||||||
* @return {@link Result<Void>}
|
* @return {@link Result<Void>}
|
||||||
*/
|
*/
|
||||||
@ExceptionHandler(value = { AbstractException.class })
|
@ExceptionHandler(value = { AbstractException.class })
|
||||||
@@ -74,6 +85,7 @@ public class GlobalExceptionHandler {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取请求URL
|
* 获取请求URL
|
||||||
|
*
|
||||||
* @param request {@link HttpServletRequest}
|
* @param request {@link HttpServletRequest}
|
||||||
* @return String
|
* @return String
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import java.io.Serial;
|
|||||||
import java.time.*;
|
import java.time.*;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
|
|
||||||
|
|
||||||
public class JavaTimeModule extends SimpleModule {
|
public class JavaTimeModule extends SimpleModule {
|
||||||
|
|
||||||
@Serial
|
@Serial
|
||||||
@@ -19,7 +18,7 @@ public class JavaTimeModule extends SimpleModule {
|
|||||||
/**
|
/**
|
||||||
* JavaTimeModule构造函数,用于初始化时间序列化和反序列化规则
|
* JavaTimeModule构造函数,用于初始化时间序列化和反序列化规则
|
||||||
*/
|
*/
|
||||||
public JavaTimeModule() {
|
public JavaTimeModule() {
|
||||||
super(PackageVersion.VERSION);
|
super(PackageVersion.VERSION);
|
||||||
|
|
||||||
// ======================= 时间序列化规则 ===============================
|
// ======================= 时间序列化规则 ===============================
|
||||||
|
|||||||
@@ -13,65 +13,69 @@ import org.springframework.stereotype.Service;
|
|||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
public class SpringContextHolder implements ApplicationContextAware, EnvironmentAware, DisposableBean {
|
public class SpringContextHolder implements ApplicationContextAware, EnvironmentAware, DisposableBean {
|
||||||
private static ApplicationContext applicationContext = null;
|
|
||||||
|
|
||||||
private static Environment environment = null;
|
private static ApplicationContext applicationContext = null;
|
||||||
/**
|
|
||||||
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
|
|
||||||
*/
|
|
||||||
public static <T> T getBean(String name) {
|
|
||||||
return (T) applicationContext.getBean(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
private static Environment environment = null;
|
||||||
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
|
|
||||||
*/
|
|
||||||
public static <T> T getBean(Class<T> requiredType) {
|
|
||||||
return applicationContext.getBean(requiredType);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
@SneakyThrows
|
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
|
||||||
public void destroy() throws Exception {
|
*/
|
||||||
clearHolder();
|
public static <T> T getBean(String name) {
|
||||||
}
|
return (T) applicationContext.getBean(name);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
|
||||||
SpringContextHolder.applicationContext = applicationContext;
|
*/
|
||||||
}
|
public static <T> T getBean(Class<T> requiredType) {
|
||||||
|
return applicationContext.getBean(requiredType);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setEnvironment(Environment environment) {
|
@SneakyThrows
|
||||||
SpringContextHolder.environment = environment;
|
public void destroy() throws Exception {
|
||||||
}
|
clearHolder();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* 清除SpringContextHolder中的ApplicationContext为Null.
|
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||||
*/
|
SpringContextHolder.applicationContext = applicationContext;
|
||||||
public static void clearHolder() {
|
}
|
||||||
if (log.isDebugEnabled()) {
|
|
||||||
log.debug("清除SpringContextHolder中的ApplicationContext:" + applicationContext);
|
@Override
|
||||||
}
|
public void setEnvironment(Environment environment) {
|
||||||
applicationContext = null;
|
SpringContextHolder.environment = environment;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* 发布事件
|
/**
|
||||||
* @param event
|
* 清除SpringContextHolder中的ApplicationContext为Null.
|
||||||
*/
|
*/
|
||||||
public static void publishEvent(ApplicationEvent event) {
|
public static void clearHolder() {
|
||||||
if (applicationContext == null) {
|
if (log.isDebugEnabled()) {
|
||||||
return;
|
log.debug("清除SpringContextHolder中的ApplicationContext:" + applicationContext);
|
||||||
}
|
}
|
||||||
applicationContext.publishEvent(event);
|
applicationContext = null;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* 是否是微服务
|
/**
|
||||||
* @return boolean
|
* 发布事件
|
||||||
*/
|
* @param event
|
||||||
public static boolean isMicro() {
|
*/
|
||||||
return environment.getProperty("spring.cloud.nacos.discovery.enabled", Boolean.class, true);
|
public static void publishEvent(ApplicationEvent event) {
|
||||||
}
|
if (applicationContext == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
applicationContext.publishEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否是微服务
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public static boolean isMicro() {
|
||||||
|
return environment.getProperty("spring.cloud.nacos.discovery.enabled", Boolean.class, true);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,4 +4,5 @@ import org.springframework.boot.autoconfigure.AutoConfiguration;
|
|||||||
|
|
||||||
@AutoConfiguration
|
@AutoConfiguration
|
||||||
public class FeignAutoConfiguration {
|
public class FeignAutoConfiguration {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,5 +9,7 @@ import java.lang.annotation.*;
|
|||||||
@Documented
|
@Documented
|
||||||
@EnableFeignClients
|
@EnableFeignClients
|
||||||
public @interface EnableAIOJFeignClients {
|
public @interface EnableAIOJFeignClients {
|
||||||
String[] basePackages() default {};
|
|
||||||
|
String[] basePackages() default {};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import org.springframework.expression.EvaluationContext;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class SysLogAspect {
|
public class SysLogAspect {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 环绕通知方法,用于处理系统日志记录
|
* 环绕通知方法,用于处理系统日志记录
|
||||||
* @param point 连接点对象
|
* @param point 连接点对象
|
||||||
@@ -29,7 +30,7 @@ public class SysLogAspect {
|
|||||||
*/
|
*/
|
||||||
@Around("@annotation(sysLog)")
|
@Around("@annotation(sysLog)")
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public Object around(ProceedingJoinPoint point,SysLog sysLog) {
|
public Object around(ProceedingJoinPoint point, SysLog sysLog) {
|
||||||
String strClassName = point.getTarget().getClass().getName();
|
String strClassName = point.getTarget().getClass().getName();
|
||||||
String strMethodName = point.getSignature().getName();
|
String strMethodName = point.getSignature().getName();
|
||||||
log.debug("[类名]:{},[方法]:{}", strClassName, strMethodName);
|
log.debug("[类名]:{},[方法]:{}", strClassName, strMethodName);
|
||||||
@@ -76,4 +77,5 @@ public class SysLogAspect {
|
|||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,11 +24,10 @@ public class AIOJLogPropertiesConfiguration {
|
|||||||
*/
|
*/
|
||||||
private Integer maxLength = 20000;
|
private Integer maxLength = 20000;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 放行字段,password,mobile,idcard,phone
|
* 放行字段,password,mobile,idcard,phone
|
||||||
*/
|
*/
|
||||||
@Value("${log.exclude-fields:password,mobile,idcard,phone}")
|
@Value("${log.exclude-fields:password,mobile,idcard,phone}")
|
||||||
private List<String> excludeFields;
|
private List<String> excludeFields;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package cn.meowrain.aioj.backend.framework.log.event;
|
package cn.meowrain.aioj.backend.framework.log.event;
|
||||||
|
|
||||||
|
|
||||||
import cn.meowrain.aioj.backend.upms.api.entity.SysLog;
|
import cn.meowrain.aioj.backend.upms.api.entity.SysLog;
|
||||||
import org.springframework.context.ApplicationEvent;
|
import org.springframework.context.ApplicationEvent;
|
||||||
|
|
||||||
|
|||||||
@@ -38,38 +38,40 @@ public class SysLogListener implements InitializingBean {
|
|||||||
SysLog sysLog = new SysLog();
|
SysLog sysLog = new SysLog();
|
||||||
BeanUtils.copyProperties(source, sysLog);
|
BeanUtils.copyProperties(source, sysLog);
|
||||||
|
|
||||||
// json 格式刷参数放在异步中处理,提升性能
|
// json 格式刷参数放在异步中处理,提升性能
|
||||||
if (Objects.nonNull(source.getBody())) {
|
if (Objects.nonNull(source.getBody())) {
|
||||||
String params = objectMapper.writeValueAsString(source.getBody());
|
String params = objectMapper.writeValueAsString(source.getBody());
|
||||||
sysLog.setParams(StrUtil.subPre(params, logProperties.getMaxLength()));
|
sysLog.setParams(StrUtil.subPre(params, logProperties.getMaxLength()));
|
||||||
}
|
}
|
||||||
|
|
||||||
remoteLogService.saveLog(sysLog);
|
remoteLogService.saveLog(sysLog);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 在 Bean 初始化后执行,用于初始化 ObjectMapper
|
* 在 Bean 初始化后执行,用于初始化 ObjectMapper
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void afterPropertiesSet() throws Exception {
|
public void afterPropertiesSet() throws Exception {
|
||||||
//给 ObjectMapper 添加 MixIn(用于过滤字段)
|
// 给 ObjectMapper 添加 MixIn(用于过滤字段)
|
||||||
objectMapper.addMixIn(Object.class, PropertyFilterMixIn.class);
|
objectMapper.addMixIn(Object.class, PropertyFilterMixIn.class);
|
||||||
String[] ignorableFieldNames = logProperties.getExcludeFields().toArray(new String[0]);
|
String[] ignorableFieldNames = logProperties.getExcludeFields().toArray(new String[0]);
|
||||||
|
|
||||||
|
FilterProvider filters = new SimpleFilterProvider().addFilter("filter properties by name",
|
||||||
|
SimpleBeanPropertyFilter.serializeAllExcept(ignorableFieldNames));
|
||||||
|
objectMapper.setFilterProvider(filters);
|
||||||
|
objectMapper.registerModule(new JavaTimeModule());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 属性过滤混合类:用于通过名称过滤属性
|
||||||
|
*
|
||||||
|
* @author lengleng
|
||||||
|
* @date 2025/05/31
|
||||||
|
*/
|
||||||
|
@JsonFilter("filter properties by name")
|
||||||
|
class PropertyFilterMixIn {
|
||||||
|
|
||||||
FilterProvider filters = new SimpleFilterProvider().addFilter("filter properties by name",
|
|
||||||
SimpleBeanPropertyFilter.serializeAllExcept(ignorableFieldNames));
|
|
||||||
objectMapper.setFilterProvider(filters);
|
|
||||||
objectMapper.registerModule(new JavaTimeModule());
|
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* 属性过滤混合类:用于通过名称过滤属性
|
|
||||||
*
|
|
||||||
* @author lengleng
|
|
||||||
* @date 2025/05/31
|
|
||||||
*/
|
|
||||||
@JsonFilter("filter properties by name")
|
|
||||||
class PropertyFilterMixIn {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,14 +29,13 @@ import java.util.Objects;
|
|||||||
|
|
||||||
public final class SysLogUtils {
|
public final class SysLogUtils {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取系统日志事件源
|
* 获取系统日志事件源
|
||||||
* @return 系统日志事件源对象
|
* @return 系统日志事件源对象
|
||||||
*/
|
*/
|
||||||
public static SysLogEventSource getSysLog() {
|
public static SysLogEventSource getSysLog() {
|
||||||
HttpServletRequest request = ((ServletRequestAttributes) Objects
|
HttpServletRequest request = ((ServletRequestAttributes) Objects
|
||||||
.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
|
.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
|
||||||
SysLogEventSource sysLog = new SysLogEventSource();
|
SysLogEventSource sysLog = new SysLogEventSource();
|
||||||
sysLog.setLogType(LogTypeEnum.NORMAL.getType());
|
sysLog.setLogType(LogTypeEnum.NORMAL.getType());
|
||||||
sysLog.setRequestUri(URLUtil.getPath(request.getRequestURI()));
|
sysLog.setRequestUri(URLUtil.getPath(request.getRequestURI()));
|
||||||
@@ -47,7 +46,8 @@ public final class SysLogUtils {
|
|||||||
sysLog.setServiceId(SpringUtil.getProperty("spring.application.name"));
|
sysLog.setServiceId(SpringUtil.getProperty("spring.application.name"));
|
||||||
|
|
||||||
// get 参数脱敏
|
// get 参数脱敏
|
||||||
AIOJLogPropertiesConfiguration logProperties = SpringContextHolder.getBean(AIOJLogPropertiesConfiguration.class);
|
AIOJLogPropertiesConfiguration logProperties = SpringContextHolder
|
||||||
|
.getBean(AIOJLogPropertiesConfiguration.class);
|
||||||
Map<String, String[]> paramsMap = MapUtil.removeAny(new HashMap<>(request.getParameterMap()),
|
Map<String, String[]> paramsMap = MapUtil.removeAny(new HashMap<>(request.getParameterMap()),
|
||||||
ArrayUtil.toArray(logProperties.getExcludeFields(), String.class));
|
ArrayUtil.toArray(logProperties.getExcludeFields(), String.class));
|
||||||
sysLog.setParams(HttpUtil.toParams(paramsMap));
|
sysLog.setParams(HttpUtil.toParams(paramsMap));
|
||||||
@@ -74,7 +74,7 @@ public final class SysLogUtils {
|
|||||||
* @param <T> 返回泛型
|
* @param <T> 返回泛型
|
||||||
* @return 参数值
|
* @return 参数值
|
||||||
*/
|
*/
|
||||||
public static <T> T getValue(EvaluationContext context, String key, Class<T> clazz) {
|
public static <T> T getValue(EvaluationContext context, String key, Class<T> clazz) {
|
||||||
SpelExpressionParser spelExpressionParser = new SpelExpressionParser();
|
SpelExpressionParser spelExpressionParser = new SpelExpressionParser();
|
||||||
Expression expression = spelExpressionParser.parseExpression(key);
|
Expression expression = spelExpressionParser.parseExpression(key);
|
||||||
return expression.getValue(context, clazz);
|
return expression.getValue(context, clazz);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>cn.meowrain</groupId>
|
<groupId>cn.meowrain</groupId>
|
||||||
@@ -50,17 +50,14 @@
|
|||||||
<groupId>com.alibaba.csp</groupId>
|
<groupId>com.alibaba.csp</groupId>
|
||||||
<artifactId>sentinel-datasource-extension</artifactId>
|
<artifactId>sentinel-datasource-extension</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- https://mvnrepository.com/artifact/com.github.xiaoymin/knife4j-openapi3-jakarta-spring-boot-starter -->
|
<!--
|
||||||
|
https://mvnrepository.com/artifact/com.github.xiaoymin/knife4j-openapi3-jakarta-spring-boot-starter -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.xiaoymin</groupId>
|
<groupId>com.github.xiaoymin</groupId>
|
||||||
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
|
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
|
||||||
|
<version>4.5.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.cloud</groupId>
|
|
||||||
<artifactId>spring-cloud-starter-bootstrap</artifactId>
|
|
||||||
<version>4.3.0</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cn.meowrain</groupId>
|
<groupId>cn.meowrain</groupId>
|
||||||
<artifactId>aioj-backend-common-core</artifactId>
|
<artifactId>aioj-backend-common-core</artifactId>
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import org.springframework.http.HttpStatus;
|
|||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||||
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
|
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.util.AntPathMatcher;
|
import org.springframework.util.AntPathMatcher;
|
||||||
import org.springframework.web.reactive.function.client.WebClient;
|
import org.springframework.web.reactive.function.client.WebClient;
|
||||||
@@ -27,7 +26,6 @@ import org.springframework.web.server.ServerWebExchange;
|
|||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@@ -44,15 +42,6 @@ public class AuthGlobalFilter implements GlobalFilter, Ordered {
|
|||||||
|
|
||||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
|
||||||
/**
|
|
||||||
* 不需要认证的路径
|
|
||||||
*/
|
|
||||||
private static final String[] DEFAULT_WHITE_LIST = {
|
|
||||||
"/api/v1/auth/login",
|
|
||||||
"/api/v1/auth/register",
|
|
||||||
"/api/v1/auth/refresh",
|
|
||||||
"/api/v1/user/info"
|
|
||||||
};
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
|
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
|
||||||
@@ -60,6 +49,7 @@ public class AuthGlobalFilter implements GlobalFilter, Ordered {
|
|||||||
String path = request.getURI().getPath();
|
String path = request.getURI().getPath();
|
||||||
|
|
||||||
log.info("Auth filter processing request: {}", path);
|
log.info("Auth filter processing request: {}", path);
|
||||||
|
log.info("Loaded white list from config: {}", gatewayPropertiesConfiguration.getWhiteList());
|
||||||
|
|
||||||
// 检查是否在白名单中
|
// 检查是否在白名单中
|
||||||
if (isWhiteListPath(path)) {
|
if (isWhiteListPath(path)) {
|
||||||
@@ -97,13 +87,6 @@ public class AuthGlobalFilter implements GlobalFilter, Ordered {
|
|||||||
* 检查路径是否在白名单中
|
* 检查路径是否在白名单中
|
||||||
*/
|
*/
|
||||||
private boolean isWhiteListPath(String path) {
|
private boolean isWhiteListPath(String path) {
|
||||||
// 先检查默认白名单
|
|
||||||
for (String whitePath : DEFAULT_WHITE_LIST) {
|
|
||||||
if (antPathMatcher.match(whitePath, path)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查配置文件中的白名单
|
// 检查配置文件中的白名单
|
||||||
if (gatewayPropertiesConfiguration.getWhiteList() != null && !gatewayPropertiesConfiguration.getWhiteList().isEmpty()) {
|
if (gatewayPropertiesConfiguration.getWhiteList() != null && !gatewayPropertiesConfiguration.getWhiteList().isEmpty()) {
|
||||||
for (String whitePath : gatewayPropertiesConfiguration.getWhiteList()) {
|
for (String whitePath : gatewayPropertiesConfiguration.getWhiteList()) {
|
||||||
@@ -122,7 +105,7 @@ public class AuthGlobalFilter implements GlobalFilter, Ordered {
|
|||||||
private Mono<Boolean> validateToken(String token) {
|
private Mono<Boolean> validateToken(String token) {
|
||||||
return webClientBuilder.build()
|
return webClientBuilder.build()
|
||||||
.post()
|
.post()
|
||||||
.uri("lb://auth-service/api/v1/auth/validate")
|
.uri("lb://auth-service/v1/auth/validate")
|
||||||
.header(HttpHeaders.AUTHORIZATION, "Bearer " + token)
|
.header(HttpHeaders.AUTHORIZATION, "Bearer " + token)
|
||||||
.contentType(MediaType.APPLICATION_JSON)
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
.retrieve()
|
.retrieve()
|
||||||
|
|||||||
@@ -8,11 +8,59 @@ spring:
|
|||||||
nacos:
|
nacos:
|
||||||
discovery:
|
discovery:
|
||||||
enabled: true
|
enabled: true
|
||||||
register-enabled: true
|
register-enabled: false
|
||||||
server-addr: 10.0.0.10:8848
|
server-addr: 10.0.0.10:8848
|
||||||
username: nacos
|
username: nacos
|
||||||
password: nacos
|
password: nacos
|
||||||
|
config:
|
||||||
|
enabled: false
|
||||||
|
import-check:
|
||||||
|
enabled: false
|
||||||
|
gateway:
|
||||||
|
# Gateway 发现定位器配置
|
||||||
|
server:
|
||||||
|
webflux:
|
||||||
|
discovery:
|
||||||
|
locator:
|
||||||
|
enabled: true
|
||||||
|
lower-case-service-id: true
|
||||||
|
loadbalancer:
|
||||||
|
nacos:
|
||||||
|
enabled: true
|
||||||
|
retry:
|
||||||
|
enabled: true
|
||||||
|
max-retries-on-same-service-instance: 1
|
||||||
|
max-retries-on-next-service-instance: 2
|
||||||
|
cache:
|
||||||
|
enabled: true
|
||||||
|
ttl: 35s
|
||||||
|
health-check:
|
||||||
|
initial-delay: 0ms
|
||||||
|
interval: 30s
|
||||||
|
|
||||||
|
|
||||||
|
aioj-backend-gateway:
|
||||||
|
# 白名单配置
|
||||||
|
white-list:
|
||||||
|
- /api/v1/auth/login
|
||||||
|
- /api/v1/auth/register
|
||||||
|
- /api/v1/auth/refresh
|
||||||
|
- /api/v1/user/register
|
||||||
|
- /api/v1/user/info
|
||||||
|
- /api/v1/question/list
|
||||||
|
- /api/v1/question/detail/**
|
||||||
|
- /actuator/health
|
||||||
|
- /swagger-ui/**
|
||||||
|
|
||||||
logging:
|
logging:
|
||||||
level:
|
level:
|
||||||
root: INFO
|
root: INFO
|
||||||
|
# Nacos 相关日志
|
||||||
|
com.alibaba.nacos: INFO
|
||||||
|
com.alibaba.cloud.nacos: DEBUG
|
||||||
|
# LoadBalancer 日志
|
||||||
|
org.springframework.cloud.loadbalancer: DEBUG
|
||||||
|
# Gateway 日志
|
||||||
|
org.springframework.cloud.gateway: DEBUG
|
||||||
|
# 自定义过滤器日志
|
||||||
|
cn.meowrain.aioj.backend.gateway: DEBUG
|
||||||
|
|||||||
@@ -1,29 +1,50 @@
|
|||||||
server:
|
server:
|
||||||
port: 8085
|
port: 8085
|
||||||
|
error:
|
||||||
|
include-stacktrace: never
|
||||||
|
|
||||||
spring:
|
spring:
|
||||||
|
profiles:
|
||||||
|
active: @env@
|
||||||
cloud:
|
cloud:
|
||||||
gateway:
|
gateway:
|
||||||
server:
|
server:
|
||||||
webflux:
|
webflux:
|
||||||
routes:
|
routes:
|
||||||
- id: auth-service
|
- id: auth-service
|
||||||
uri: lb://auth-service/api
|
uri: lb://auth-service
|
||||||
predicates:
|
predicates:
|
||||||
- Path=/api/v1/auth/**
|
- Path=/api/v1/auth/**
|
||||||
|
filters:
|
||||||
|
- name: Retry
|
||||||
|
args:
|
||||||
|
retries: 3
|
||||||
|
statuses: BAD_GATEWAY,SERVICE_UNAVAILABLE
|
||||||
|
backoff:
|
||||||
|
firstBackoff: 50ms
|
||||||
|
maxBackoff: 500ms
|
||||||
- id: user-service
|
- id: user-service
|
||||||
uri: lb://user-service/api
|
uri: lb://user-service
|
||||||
predicates:
|
predicates:
|
||||||
- Path=/api/v1/user/**
|
- Path=/api/v1/user/**
|
||||||
|
filters:
|
||||||
|
- name: Retry
|
||||||
|
args:
|
||||||
|
retries: 3
|
||||||
|
statuses: BAD_GATEWAY,SERVICE_UNAVAILABLE
|
||||||
|
backoff:
|
||||||
|
firstBackoff: 50ms
|
||||||
|
maxBackoff: 500ms
|
||||||
|
# 设置应用启动后的就绪探针
|
||||||
|
lifecycle:
|
||||||
|
timeout-per-shutdown-phase: 30s
|
||||||
|
|
||||||
aioj-backend-gateway:
|
aioj-backend-gateway:
|
||||||
# 白名单配置
|
# 白名单配置
|
||||||
white-list:
|
white-list:
|
||||||
- /api/v1/auth/login
|
- /api/v1/auth/login
|
||||||
- /api/v1/auth/register
|
- /api/v1/user/register
|
||||||
- /api/v1/auth/refresh
|
- /api/v1/auth/refresh
|
||||||
- /api/v1/user/info
|
|
||||||
- /api/v1/question/list
|
|
||||||
- /api/v1/question/detail/**
|
|
||||||
- /actuator/health
|
- /actuator/health
|
||||||
- /swagger-ui/**
|
- /swagger-ui/**
|
||||||
- /v3/api-docs/**
|
- /v3/api-docs/**
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
spring:
|
|
||||||
application:
|
|
||||||
name: aioj-gateway
|
|
||||||
cloud:
|
|
||||||
nacos:
|
|
||||||
discovery:
|
|
||||||
server-addr: 10.0.0.10:8848
|
|
||||||
username: nacos
|
|
||||||
password: nacos
|
|
||||||
config:
|
|
||||||
server-addr: 10.0.0.10:8848
|
|
||||||
username: nacos
|
|
||||||
password: nacos
|
|
||||||
file-extension: yaml
|
|
||||||
group: DEFAULT_GROUP
|
|
||||||
@@ -19,7 +19,6 @@
|
|||||||
|
|
||||||
package cn.meowrain.aioj.backend.upms.api.entity;
|
package cn.meowrain.aioj.backend.upms.api.entity;
|
||||||
|
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.annotation.*;
|
import com.baomidou.mybatisplus.annotation.*;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import jakarta.validation.constraints.NotBlank;
|
import jakarta.validation.constraints.NotBlank;
|
||||||
@@ -41,14 +40,14 @@ import java.time.LocalDateTime;
|
|||||||
@Schema(description = "日志")
|
@Schema(description = "日志")
|
||||||
public class SysLog implements Serializable {
|
public class SysLog implements Serializable {
|
||||||
|
|
||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 编号
|
* 编号
|
||||||
*/
|
*/
|
||||||
@TableId(type = IdType.ASSIGN_ID)
|
@TableId(type = IdType.ASSIGN_ID)
|
||||||
// @ExcelProperty("日志编号")
|
// @ExcelProperty("日志编号")
|
||||||
@Schema(description = "日志编号")
|
@Schema(description = "日志编号")
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
@@ -56,7 +55,7 @@ public class SysLog implements Serializable {
|
|||||||
* 日志类型
|
* 日志类型
|
||||||
*/
|
*/
|
||||||
@NotBlank(message = "日志类型不能为空")
|
@NotBlank(message = "日志类型不能为空")
|
||||||
// @ExcelProperty("日志类型(0-正常 9-错误)")
|
// @ExcelProperty("日志类型(0-正常 9-错误)")
|
||||||
@Schema(description = "日志类型")
|
@Schema(description = "日志类型")
|
||||||
private String logType;
|
private String logType;
|
||||||
|
|
||||||
@@ -64,14 +63,14 @@ public class SysLog implements Serializable {
|
|||||||
* 日志标题
|
* 日志标题
|
||||||
*/
|
*/
|
||||||
@NotBlank(message = "日志标题不能为空")
|
@NotBlank(message = "日志标题不能为空")
|
||||||
// @ExcelProperty("日志标题")
|
// @ExcelProperty("日志标题")
|
||||||
@Schema(description = "日志标题")
|
@Schema(description = "日志标题")
|
||||||
private String title;
|
private String title;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建者
|
* 创建者
|
||||||
*/
|
*/
|
||||||
// @ExcelProperty("创建人")
|
// @ExcelProperty("创建人")
|
||||||
@TableField(fill = FieldFill.INSERT)
|
@TableField(fill = FieldFill.INSERT)
|
||||||
@Schema(description = "创建人")
|
@Schema(description = "创建人")
|
||||||
private String createBy;
|
private String createBy;
|
||||||
@@ -79,7 +78,7 @@ public class SysLog implements Serializable {
|
|||||||
/**
|
/**
|
||||||
* 创建时间
|
* 创建时间
|
||||||
*/
|
*/
|
||||||
// @ExcelProperty("创建时间")
|
// @ExcelProperty("创建时间")
|
||||||
@TableField(fill = FieldFill.INSERT)
|
@TableField(fill = FieldFill.INSERT)
|
||||||
@Schema(description = "创建时间")
|
@Schema(description = "创建时间")
|
||||||
private LocalDateTime createTime;
|
private LocalDateTime createTime;
|
||||||
@@ -87,7 +86,7 @@ public class SysLog implements Serializable {
|
|||||||
/**
|
/**
|
||||||
* 更新时间
|
* 更新时间
|
||||||
*/
|
*/
|
||||||
// @ExcelIgnore
|
// @ExcelIgnore
|
||||||
@TableField(fill = FieldFill.UPDATE)
|
@TableField(fill = FieldFill.UPDATE)
|
||||||
@Schema(description = "更新时间")
|
@Schema(description = "更新时间")
|
||||||
private LocalDateTime updateTime;
|
private LocalDateTime updateTime;
|
||||||
@@ -95,7 +94,7 @@ public class SysLog implements Serializable {
|
|||||||
/**
|
/**
|
||||||
* 操作IP地址
|
* 操作IP地址
|
||||||
*/
|
*/
|
||||||
// @ExcelProperty("操作ip地址")
|
// @ExcelProperty("操作ip地址")
|
||||||
@Schema(description = "操作ip地址")
|
@Schema(description = "操作ip地址")
|
||||||
private String remoteAddr;
|
private String remoteAddr;
|
||||||
|
|
||||||
@@ -108,42 +107,42 @@ public class SysLog implements Serializable {
|
|||||||
/**
|
/**
|
||||||
* 请求URI
|
* 请求URI
|
||||||
*/
|
*/
|
||||||
// @ExcelProperty("浏览器")
|
// @ExcelProperty("浏览器")
|
||||||
@Schema(description = "请求uri")
|
@Schema(description = "请求uri")
|
||||||
private String requestUri;
|
private String requestUri;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 操作方式
|
* 操作方式
|
||||||
*/
|
*/
|
||||||
// @ExcelProperty("操作方式")
|
// @ExcelProperty("操作方式")
|
||||||
@Schema(description = "操作方式")
|
@Schema(description = "操作方式")
|
||||||
private String method;
|
private String method;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 操作提交的数据
|
* 操作提交的数据
|
||||||
*/
|
*/
|
||||||
// @ExcelProperty("提交数据")
|
// @ExcelProperty("提交数据")
|
||||||
@Schema(description = "提交数据")
|
@Schema(description = "提交数据")
|
||||||
private String params;
|
private String params;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 执行时间
|
* 执行时间
|
||||||
*/
|
*/
|
||||||
// @ExcelProperty("执行时间")
|
// @ExcelProperty("执行时间")
|
||||||
@Schema(description = "方法执行时间")
|
@Schema(description = "方法执行时间")
|
||||||
private Long time;
|
private Long time;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 异常信息
|
* 异常信息
|
||||||
*/
|
*/
|
||||||
// @ExcelProperty("异常信息")
|
// @ExcelProperty("异常信息")
|
||||||
@Schema(description = "异常信息")
|
@Schema(description = "异常信息")
|
||||||
private String exception;
|
private String exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 服务ID
|
* 服务ID
|
||||||
*/
|
*/
|
||||||
// @ExcelProperty("应用标识")
|
// @ExcelProperty("应用标识")
|
||||||
@Schema(description = "应用标识")
|
@Schema(description = "应用标识")
|
||||||
private String serviceId;
|
private String serviceId;
|
||||||
|
|
||||||
@@ -151,7 +150,7 @@ public class SysLog implements Serializable {
|
|||||||
* 删除标记
|
* 删除标记
|
||||||
*/
|
*/
|
||||||
@TableLogic
|
@TableLogic
|
||||||
// @ExcelIgnore
|
// @ExcelIgnore
|
||||||
@TableField(fill = FieldFill.INSERT)
|
@TableField(fill = FieldFill.INSERT)
|
||||||
@Schema(description = "删除标记,1:已删除,0:正常")
|
@Schema(description = "删除标记,1:已删除,0:正常")
|
||||||
private String delFlag;
|
private String delFlag;
|
||||||
|
|||||||
@@ -10,12 +10,14 @@ import org.springframework.web.bind.annotation.RequestBody;
|
|||||||
|
|
||||||
@FeignClient(contextId = "remoteLogService", value = ServiceNameConstants.UPMS_SERVICE)
|
@FeignClient(contextId = "remoteLogService", value = ServiceNameConstants.UPMS_SERVICE)
|
||||||
public interface RemoteLogService {
|
public interface RemoteLogService {
|
||||||
/**
|
|
||||||
* 保存日志 (异步多线程调用,无token)
|
/**
|
||||||
* @param sysLog 日志实体
|
* 保存日志 (异步多线程调用,无token)
|
||||||
* @return succes、false
|
* @param sysLog 日志实体
|
||||||
*/
|
* @return succes、false
|
||||||
@NoToken
|
*/
|
||||||
@PostMapping("/log/save")
|
@NoToken
|
||||||
Result<Boolean> saveLog(@RequestBody SysLog sysLog);
|
@PostMapping("/log/save")
|
||||||
|
Result<Boolean> saveLog(@RequestBody SysLog sysLog);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>cn.meowrain</groupId>
|
<groupId>cn.meowrain</groupId>
|
||||||
@@ -20,7 +20,12 @@
|
|||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cn.meowrain</groupId>
|
<groupId>cn.meowrain</groupId>
|
||||||
<artifactId>aioj-backend-common-starter</artifactId>
|
<artifactId>aioj-backend-common-core</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.meowrain</groupId>
|
||||||
|
<artifactId>aioj-backend-common-log</artifactId>
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -60,21 +65,15 @@
|
|||||||
<artifactId>spring-boot-starter-test</artifactId>
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<!-- <dependency>-->
|
||||||
<groupId>org.springframework.boot</groupId>
|
<!-- <groupId>org.springframework.boot</groupId>-->
|
||||||
<artifactId>spring-boot-devtools</artifactId>
|
<!-- <artifactId>spring-boot-devtools</artifactId>-->
|
||||||
<scope>runtime</scope>
|
<!-- <scope>runtime</scope>-->
|
||||||
<optional>true</optional>
|
<!-- <optional>true</optional>-->
|
||||||
</dependency>
|
<!-- </dependency>-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.alibaba.cloud</groupId>
|
<groupId>com.alibaba.cloud</groupId>
|
||||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>cn.meowrain</groupId>
|
|
||||||
<artifactId>aioj-backend-common-core</artifactId>
|
|
||||||
<version>1.0-SNAPSHOT</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
@@ -5,7 +5,8 @@ import org.springframework.context.annotation.ComponentScans;
|
|||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@ComponentScans({ @ComponentScan("cn.meowrain.aioj.backend.framework.core.banner") })
|
// @ComponentScans({
|
||||||
|
// @ComponentScan("cn.meowrain.aioj.backend.framework.core.banner") })
|
||||||
public class FrameworkConfiguration {
|
public class FrameworkConfiguration {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ server:
|
|||||||
port: 10010
|
port: 10010
|
||||||
servlet:
|
servlet:
|
||||||
context-path: /api
|
context-path: /api
|
||||||
|
error:
|
||||||
|
include-stacktrace: never
|
||||||
springdoc:
|
springdoc:
|
||||||
api-docs:
|
api-docs:
|
||||||
enabled: true
|
enabled: true
|
||||||
|
|||||||
243
docs/auth-api.md
Normal file
243
docs/auth-api.md
Normal file
@@ -0,0 +1,243 @@
|
|||||||
|
# AIOJ 认证服务 API 文档
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
AIOJ认证服务提供JWT(JSON Web Token)为基础的用户认证和授权功能。该服务负责用户登录、令牌生成、令牌刷新和令牌验证。
|
||||||
|
|
||||||
|
**基础信息:**
|
||||||
|
- 服务名称: auth-service
|
||||||
|
- 基础路径: `/api`
|
||||||
|
- API版本: v1
|
||||||
|
- 认证方式: JWT Bearer Token
|
||||||
|
- 数据格式: JSON
|
||||||
|
|
||||||
|
## JWT认证机制
|
||||||
|
|
||||||
|
### 访问令牌 (Access Token)
|
||||||
|
- 有效期: 15分钟
|
||||||
|
- 用途: 访问受保护的API接口
|
||||||
|
- 格式: Bearer Token
|
||||||
|
|
||||||
|
### 刷新令牌 (Refresh Token)
|
||||||
|
- 有效期: 7天
|
||||||
|
- 用途: 获取新的Access Token
|
||||||
|
- 存储位置: Redis
|
||||||
|
|
||||||
|
### 请求头格式
|
||||||
|
```
|
||||||
|
Authorization: Bearer {access_token}
|
||||||
|
```
|
||||||
|
|
||||||
|
## API接口
|
||||||
|
|
||||||
|
### 1. 用户登录
|
||||||
|
用户通过用户名和密码进行登录认证。
|
||||||
|
|
||||||
|
**接口信息:**
|
||||||
|
- URL: `POST /api/v1/auth/login`
|
||||||
|
- 描述: 用户登录获取访问令牌
|
||||||
|
- 认证要求: 无需认证
|
||||||
|
|
||||||
|
**请求参数:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"userAccount": "string", // 用户账号
|
||||||
|
"userPassword": "string" // 用户密码
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**请求示例:**
|
||||||
|
```bash
|
||||||
|
curl -X POST http://localhost:10011/api/v1/auth/login \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{
|
||||||
|
"userAccount": "admin",
|
||||||
|
"userPassword": "password123"
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
**响应示例:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"message": "操作成功",
|
||||||
|
"data": {
|
||||||
|
"id": 1,
|
||||||
|
"userAccount": "admin",
|
||||||
|
"unionId": null,
|
||||||
|
"accessToken": "eyJhbGciOiJIUzI1NiJ9...",
|
||||||
|
"refreshToken": "eyJhbGciOiJIUzI1NiJ9...",
|
||||||
|
"expire": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 令牌刷新
|
||||||
|
使用刷新令牌获取新的访问令牌。
|
||||||
|
|
||||||
|
**接口信息:**
|
||||||
|
- URL: `POST /api/v1/auth/refresh`
|
||||||
|
- 描述: 刷新访问令牌
|
||||||
|
- 认证要求: 无需认证
|
||||||
|
|
||||||
|
**请求参数:**
|
||||||
|
```
|
||||||
|
refreshToken=string // 刷新令牌
|
||||||
|
```
|
||||||
|
|
||||||
|
**请求示例:**
|
||||||
|
```bash
|
||||||
|
curl -X POST "http://localhost:10011/api/v1/auth/refresh?refreshToken=eyJhbGciOiJIUzI1NiJ9..."
|
||||||
|
```
|
||||||
|
|
||||||
|
**响应示例:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"message": "操作成功",
|
||||||
|
"data": {
|
||||||
|
"id": null,
|
||||||
|
"userAccount": null,
|
||||||
|
"unionId": null,
|
||||||
|
"accessToken": "eyJhbGciOiJIUzI1NiJ9...",
|
||||||
|
"refreshToken": "eyJhbGciOiJIUzI1NiJ9...",
|
||||||
|
"expire": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 获取访问令牌
|
||||||
|
简化版的登录接口,仅返回访问令牌。
|
||||||
|
|
||||||
|
**接口信息:**
|
||||||
|
- URL: `POST /api/v1/auth/auth`
|
||||||
|
- 描述: 获取访问令牌(简化版登录)
|
||||||
|
- 认证要求: 无需认证
|
||||||
|
|
||||||
|
**请求参数:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"userAccount": "string", // 用户账号
|
||||||
|
"userPassword": "string" // 用户密码
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**请求示例:**
|
||||||
|
```bash
|
||||||
|
curl -X POST http://localhost:10011/api/v1/auth/auth \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{
|
||||||
|
"userAccount": "admin",
|
||||||
|
"userPassword": "password123"
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
**响应示例:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"message": "操作成功",
|
||||||
|
"data": "eyJhbGciOiJIUzI1NiJ9..."
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 令牌验证
|
||||||
|
验证访问令牌的有效性。
|
||||||
|
|
||||||
|
**接口信息:**
|
||||||
|
- URL: `POST /api/v1/auth/validate`
|
||||||
|
- 描述: 验证访问令牌
|
||||||
|
- 认证要求: 可选的Authorization头
|
||||||
|
|
||||||
|
**请求头:**
|
||||||
|
```
|
||||||
|
Authorization: Bearer {access_token} // 可选
|
||||||
|
```
|
||||||
|
|
||||||
|
**请求示例:**
|
||||||
|
```bash
|
||||||
|
curl -X POST http://localhost:10011/api/v1/auth/validate \
|
||||||
|
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9..."
|
||||||
|
```
|
||||||
|
|
||||||
|
**响应示例:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"message": "操作成功",
|
||||||
|
"data": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 状态码说明
|
||||||
|
|
||||||
|
| 状态码 | 说明 | 描述 |
|
||||||
|
|--------|------|------|
|
||||||
|
| 200 | OK | 请求成功 |
|
||||||
|
| 400 | Bad Request | 请求参数错误 |
|
||||||
|
| 401 | Unauthorized | 未授权访问或令牌无效 |
|
||||||
|
| 403 | Forbidden | 禁止访问 |
|
||||||
|
| 500 | Internal Server Error | 服务器内部错误 |
|
||||||
|
|
||||||
|
## 错误响应格式
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": false,
|
||||||
|
"message": "错误描述",
|
||||||
|
"data": null
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 常见错误码
|
||||||
|
|
||||||
|
| 错误信息 | 可能原因 | 解决方案 |
|
||||||
|
|----------|----------|----------|
|
||||||
|
| "用户不存在或密码错误" | 用户账号或密码不正确 | 检查用户名和密码 |
|
||||||
|
| "Refresh Token 已过期" | 刷新令牌已过期 | 重新登录获取新令牌 |
|
||||||
|
| "Refresh Token 已失效" | 刷新令牌在Redis中不存在或已失效 | 重新登录获取新令牌 |
|
||||||
|
| "系统错误" | 服务间调用失败或系统异常 | 检查服务状态和网络连接 |
|
||||||
|
|
||||||
|
## 配置信息
|
||||||
|
|
||||||
|
### JWT配置
|
||||||
|
```yaml
|
||||||
|
jwt:
|
||||||
|
secret: "12345678901234567890123456789012" # 32字节密钥
|
||||||
|
access-expire: 900000 # 15分钟(毫秒)
|
||||||
|
refresh-expire: 604800000 # 7天(毫秒)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 服务配置
|
||||||
|
```yaml
|
||||||
|
spring:
|
||||||
|
application:
|
||||||
|
name: auth-service
|
||||||
|
server:
|
||||||
|
port: 10011
|
||||||
|
servlet:
|
||||||
|
context-path: /api
|
||||||
|
```
|
||||||
|
|
||||||
|
## 安全注意事项
|
||||||
|
|
||||||
|
1. **令牌存储**: Access Token应存储在内存或HttpOnly Cookie中
|
||||||
|
2. **HTTPS传输**: 生产环境必须使用HTTPS协议
|
||||||
|
3. **密钥管理**: JWT密钥应定期轮换,使用强密钥
|
||||||
|
4. **令牌过期**: 合理设置令牌过期时间,平衡安全性和用户体验
|
||||||
|
5. **错误处理**: 不要在错误信息中泄露敏感信息
|
||||||
|
|
||||||
|
## 使用流程
|
||||||
|
|
||||||
|
1. **用户登录**: 调用`/login`接口获取Access Token和Refresh Token
|
||||||
|
2. **API访问**: 在请求头中携带Access Token访问受保护接口
|
||||||
|
3. **令牌刷新**: Access Token过期时使用Refresh Token获取新的Access Token
|
||||||
|
4. **令牌验证**: 可使用`/validate`接口验证Token有效性
|
||||||
|
|
||||||
|
## 联系信息
|
||||||
|
|
||||||
|
如有问题或建议,请联系开发团队。
|
||||||
|
|
||||||
|
---
|
||||||
|
*文档版本: v1.0*
|
||||||
|
*更新时间: 2025-12-14*
|
||||||
32
pom.xml
32
pom.xml
@@ -1,13 +1,13 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-parent</artifactId>
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
<version>3.5.7</version>
|
<version>3.5.7</version>
|
||||||
<relativePath/>
|
<relativePath />
|
||||||
</parent>
|
</parent>
|
||||||
<groupId>cn.meowrain</groupId>
|
<groupId>cn.meowrain</groupId>
|
||||||
<artifactId>ai-oj</artifactId>
|
<artifactId>ai-oj</artifactId>
|
||||||
@@ -66,7 +66,8 @@
|
|||||||
<type>pom</type>
|
<type>pom</type>
|
||||||
<scope>import</scope>
|
<scope>import</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!--Spring Boot依赖-->
|
<!--Spring
|
||||||
|
Boot依赖-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-dependencies</artifactId>
|
<artifactId>spring-boot-dependencies</artifactId>
|
||||||
@@ -75,7 +76,8 @@
|
|||||||
<scope>import</scope>
|
<scope>import</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- Spring Cloud依赖-->
|
<!-- Spring Cloud依赖-->
|
||||||
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-dependencies -->
|
<!--
|
||||||
|
https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-dependencies -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.cloud</groupId>
|
<groupId>org.springframework.cloud</groupId>
|
||||||
<artifactId>spring-cloud-dependencies</artifactId>
|
<artifactId>spring-cloud-dependencies</artifactId>
|
||||||
@@ -96,10 +98,6 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<resource>
|
<resource>
|
||||||
<directory>src/main/resources</directory>
|
<directory>src/main/resources</directory>
|
||||||
<includes>
|
|
||||||
<include>application*.yml</include>
|
|
||||||
<include>application*.properties</include>
|
|
||||||
</includes>
|
|
||||||
<filtering>true</filtering>
|
<filtering>true</filtering>
|
||||||
</resource>
|
</resource>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -120,7 +118,8 @@
|
|||||||
<version>${spring-boot.version}</version>
|
<version>${spring-boot.version}</version>
|
||||||
</plugin>
|
</plugin>
|
||||||
<!--
|
<!--
|
||||||
代码格式插件,默认使用spring 规则,可运行命令进行项目格式化:./mvnw spring-javaformat:apply 或 mvn spring-javaformat:apply,可在IDEA中安装插件以下插件进行自动格式化:
|
代码格式插件,默认使用spring 规则,可运行命令进行项目格式化:./mvnw spring-javaformat:apply 或 mvn
|
||||||
|
spring-javaformat:apply,可在IDEA中安装插件以下插件进行自动格式化:
|
||||||
https://repo1.maven.org/maven2/io/spring/javaformat/spring-javaformat-intellij-idea-plugin
|
https://repo1.maven.org/maven2/io/spring/javaformat/spring-javaformat-intellij-idea-plugin
|
||||||
-->
|
-->
|
||||||
<plugin>
|
<plugin>
|
||||||
@@ -135,7 +134,8 @@
|
|||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
|
||||||
<!--打包jar 与git commit 关联插件-->
|
<!--打包jar
|
||||||
|
与git commit 关联插件-->
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>io.github.git-commit-id</groupId>
|
<groupId>io.github.git-commit-id</groupId>
|
||||||
<artifactId>git-commit-id-maven-plugin</artifactId>
|
<artifactId>git-commit-id-maven-plugin</artifactId>
|
||||||
@@ -168,13 +168,14 @@
|
|||||||
<allowInsecureRegistries>true</allowInsecureRegistries>
|
<allowInsecureRegistries>true</allowInsecureRegistries>
|
||||||
<from>
|
<from>
|
||||||
<!--使用openjdk官方镜像,tag是8-jdk-stretch,表示镜像的操作系统是debian9,装好了jdk8-->
|
<!--使用openjdk官方镜像,tag是8-jdk-stretch,表示镜像的操作系统是debian9,装好了jdk8-->
|
||||||
<image>registry.cn-shanghai.aliyuncs.com/all_lib/eclipse-temurin:17.0.10_7-jdk-jammy</image>
|
<image>
|
||||||
|
registry.cn-shanghai.aliyuncs.com/all_lib/eclipse-temurin:17.0.10_7-jdk-jammy</image>
|
||||||
</from>
|
</from>
|
||||||
<to>
|
<to>
|
||||||
<!-- 前缀名/命名空间/项目名:项目版本-->
|
<!-- 前缀名/命名空间/项目名:项目版本-->
|
||||||
<image>10.0.0.3/aioj/${project.artifactId}:${project.version}</image>
|
<image>10.0.0.3/aioj/${project.artifactId}:${project.version}</image>
|
||||||
<tags>
|
<tags>
|
||||||
<!--版本号-->
|
<!--版本号-->
|
||||||
<tag>${project.version}</tag>
|
<tag>${project.version}</tag>
|
||||||
</tags>
|
</tags>
|
||||||
<auth>
|
<auth>
|
||||||
@@ -183,7 +184,8 @@
|
|||||||
</auth>
|
</auth>
|
||||||
</to>
|
</to>
|
||||||
<outputPaths>
|
<outputPaths>
|
||||||
<tar>${project.build.directory}/${project.artifactId}-${project.version}.tar</tar>
|
<tar>
|
||||||
|
${project.build.directory}/${project.artifactId}-${project.version}.tar</tar>
|
||||||
</outputPaths>
|
</outputPaths>
|
||||||
<!--容器相关的属性-->
|
<!--容器相关的属性-->
|
||||||
<container>
|
<container>
|
||||||
|
|||||||
Reference in New Issue
Block a user