Compare commits
7 Commits
6839ee7de3
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| bfe6b1bc5e | |||
| 5fec4cb020 | |||
| abe20c99fe | |||
| dae4696224 | |||
| 3f0014c9b4 | |||
| e56fc03099 | |||
| e754fef4da |
195
AGENTS.md
Normal file
195
AGENTS.md
Normal file
@@ -0,0 +1,195 @@
|
||||
# AGENTS.md
|
||||
|
||||
This file provides guidance to Codex (Codex.ai/code) when working with code in this repository.
|
||||
|
||||
## Project Overview
|
||||
|
||||
This is a Spring Boot 2.7.2 application serving as a multi-tenant system with AI integration capabilities. The application focuses on host/streamer data management with AI chat functionality, built on a layered architecture pattern.
|
||||
|
||||
**Key Technologies:**
|
||||
- Spring Boot 2.7.2 with Java 17
|
||||
- MyBatis-Plus 3.5.2 for data access
|
||||
- SA-Token 1.44.0 for authentication
|
||||
- Redis for distributed caching and session management
|
||||
- RabbitMQ for message-driven architecture
|
||||
- Knife4j 4.4.0 for API documentation
|
||||
- MySQL database
|
||||
|
||||
## Build and Run Commands
|
||||
|
||||
### Development
|
||||
```bash
|
||||
# Run the application (dev profile is default)
|
||||
mvn spring-boot:run
|
||||
|
||||
# Build the project
|
||||
mvn clean package
|
||||
|
||||
# Run tests
|
||||
mvn test
|
||||
|
||||
# Skip tests during build
|
||||
mvn clean package -DskipTests
|
||||
```
|
||||
|
||||
### Database Setup
|
||||
```bash
|
||||
# Initialize database using the SQL script
|
||||
mysql -u root -p < sql/create_table.sql
|
||||
```
|
||||
|
||||
**Important:** Update database credentials in `src/main/resources/application.yml` before running.
|
||||
|
||||
### Access Points
|
||||
- Application: http://localhost:8101/api
|
||||
- API Documentation: http://localhost:8101/api/doc.html
|
||||
|
||||
## Architecture
|
||||
|
||||
### Layered Structure
|
||||
The codebase follows a standard layered architecture:
|
||||
|
||||
**Controller Layer** (`controller/`) → **Service Layer** (`service/`) → **Mapper Layer** (`mapper/`) → **Database**
|
||||
|
||||
### Key Packages
|
||||
- `annotation/` - Custom annotations like `@AuthCheck` for role-based access control
|
||||
- `aop/` - Aspect-oriented programming for cross-cutting concerns (logging, auth)
|
||||
- `config/` - Spring configuration classes for SA-Token, MyBatis-Plus, Redis, RabbitMQ, CORS
|
||||
- `model/entity/` - Database entities mapped with MyBatis-Plus
|
||||
- `model/dto/` - Data Transfer Objects for API requests
|
||||
- `model/vo/` - View Objects for API responses
|
||||
- `model/enums/` - Enumerations including `LoginSceneEnum` for multi-scenario authentication
|
||||
- `exception/` - Custom exception handling with `GlobalExceptionHandler`
|
||||
- `utils/` - Utility classes for common operations
|
||||
|
||||
### Authentication System (SA-Token)
|
||||
|
||||
The application uses SA-Token with **multiple login scenarios**:
|
||||
|
||||
1. **HOST** - Host/streamer login (`/user/doLogin`)
|
||||
2. **BIG_BROTHER** - Admin tenant login (`/user/bigbrother-doLogin`)
|
||||
3. **AI_CHAT** - AI chat login (`/user/aiChat-doLogin`)
|
||||
4. **WEB_AI** - Web AI login (`/user/webAi-doLogin`)
|
||||
|
||||
Each scenario uses a different SA-Token login mode (defined in `LoginSceneEnum`) and has its own role validation logic in `SystemUsersService`.
|
||||
|
||||
**Token Configuration:**
|
||||
- Token name: `vvtoken`
|
||||
- Timeout: 172800 seconds (2 days)
|
||||
- Non-concurrent login (new login kicks out old session)
|
||||
- Token style: random-128
|
||||
|
||||
**Public Endpoints** (no authentication required):
|
||||
- All Swagger/Knife4j documentation endpoints
|
||||
- Login endpoints for all scenarios
|
||||
- `/tenant/get-id-by-name`
|
||||
- `/error`
|
||||
|
||||
See `SaTokenConfigure.java:35` for the complete list of excluded paths.
|
||||
|
||||
### Database Layer (MyBatis-Plus)
|
||||
|
||||
**Configuration Notes:**
|
||||
- Camel case to underscore mapping is **disabled** (`map-underscore-to-camel-case: false`)
|
||||
- Field names in entities must match database column names exactly
|
||||
- Logical deletion is enabled globally via `isDelete` field
|
||||
- Pagination is configured via `PaginationInnerInterceptor`
|
||||
|
||||
**Custom Mappers:**
|
||||
- Complex queries use XML mappers in `src/main/resources/mapper/`
|
||||
- Simple CRUD operations use MyBatis-Plus built-in methods
|
||||
|
||||
### Message Queue (RabbitMQ)
|
||||
|
||||
The application uses **HeadersExchange** pattern for message routing. Configuration is in `RabbitMQConfig.java`.
|
||||
|
||||
**Key Queues:**
|
||||
- Multiple business-specific queues with persistent messages
|
||||
- Manual acknowledgment mode
|
||||
- JSON message serialization with Jackson
|
||||
|
||||
### Redis Integration
|
||||
|
||||
Redis is used for:
|
||||
- Distributed session storage (Spring Session)
|
||||
- SA-Token session management
|
||||
- Custom caching needs
|
||||
|
||||
**Configuration:** See `RedisConfig.java` for JSON serialization setup with Jackson.
|
||||
|
||||
### Multi-Tenant Architecture
|
||||
|
||||
The system supports multi-tenancy with:
|
||||
- `SystemTenant` entity for tenant management
|
||||
- `SystemUsers` entity with tenant associations
|
||||
- Tenant-specific authentication flows (BIG_BROTHER scenario)
|
||||
- Tenant ID retrieval endpoint: `/tenant/get-id-by-name`
|
||||
|
||||
## Development Guidelines
|
||||
|
||||
### Adding New Endpoints
|
||||
|
||||
1. Create/update DTO in `model/dto/` for request validation
|
||||
2. Create/update VO in `model/vo/` for response formatting
|
||||
3. Add service method in appropriate service interface and implementation
|
||||
4. Add controller endpoint with proper `@AuthCheck` annotation if authentication is required
|
||||
5. If endpoint should be public, add path to `SaTokenConfigure.getExcludePaths()`
|
||||
|
||||
### Working with Authentication
|
||||
|
||||
**Role-based Access Control:**
|
||||
```java
|
||||
@AuthCheck(mustRole = UserRoleEnum.ADMIN)
|
||||
public BaseResponse<String> adminOnlyEndpoint() {
|
||||
// Implementation
|
||||
}
|
||||
```
|
||||
|
||||
**Multi-scenario Login:**
|
||||
- Use `LoginSceneEnum` to determine the login scenario
|
||||
- Each scenario has its own SA-Token mode and role validation
|
||||
- Logout endpoints are scenario-specific (e.g., `/user/aiChat-logout`)
|
||||
|
||||
### Database Entities
|
||||
|
||||
**Important:** When creating or modifying entities:
|
||||
- Use `@TableName` to specify exact table name
|
||||
- Use `@TableField` for fields that don't follow naming conventions
|
||||
- Include `isDelete` field for logical deletion support
|
||||
- Add `createTime` and `updateTime` with appropriate defaults
|
||||
|
||||
### Code Generation
|
||||
|
||||
The project includes FreeMarker-based code generation utilities in the `generate/` package for scaffolding new modules.
|
||||
|
||||
## Configuration Files
|
||||
|
||||
- `application.yml` - Main configuration with SA-Token, database, and server settings
|
||||
- `application-dev.yml` - Development environment overrides
|
||||
- `application-prod.yml` - Production environment overrides
|
||||
|
||||
**Active Profile:** Defaults to `dev` (see `application.yml:9`)
|
||||
|
||||
## Important Notes
|
||||
|
||||
- **Redis:** Currently disabled in `MainApplication.java`. To enable, remove `RedisAutoConfiguration` from the `exclude` list and uncomment session store-type in `application.yml:17`
|
||||
- **MyBatis Logging:** Disabled by default in static block of `MainApplication.java:24-27`
|
||||
- **Context Path:** All endpoints are prefixed with `/api` (see `application.yml:42`)
|
||||
- **File Upload Limit:** 10MB (see `application.yml:37`)
|
||||
- **CORS:** Configured to allow all origins in `SaTokenConfigure.corsHandle()`
|
||||
|
||||
## Testing
|
||||
|
||||
Tests are located in `src/test/java/`. The project uses Spring Boot Test framework.
|
||||
|
||||
Run specific test class:
|
||||
```bash
|
||||
mvn test -Dtest=ClassName
|
||||
```
|
||||
|
||||
## Common Issues
|
||||
|
||||
1. **Authentication Errors:** Verify the correct login endpoint is being used for the scenario (HOST, BIG_BROTHER, AI_CHAT, WEB_AI)
|
||||
2. **Database Connection:** Ensure MySQL is running and credentials in `application.yml` are correct
|
||||
3. **Redis Connection:** If Redis features are needed, enable Redis in `MainApplication.java` and configure connection in `application.yml`
|
||||
4. **Field Mapping Issues:** Remember that camel-to-underscore mapping is disabled; field names must match exactly
|
||||
BIN
src/.DS_Store
vendored
Normal file
BIN
src/.DS_Store
vendored
Normal file
Binary file not shown.
BIN
src/main/java/com/yupi/springbootinit/.DS_Store
vendored
Normal file
BIN
src/main/java/com/yupi/springbootinit/.DS_Store
vendored
Normal file
Binary file not shown.
@@ -1,5 +1,6 @@
|
||||
package com.yupi.springbootinit.aop;
|
||||
|
||||
import com.yupi.springbootinit.utils.NetUtils;
|
||||
import java.util.UUID;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -41,9 +42,10 @@ public class LogInterceptor {
|
||||
// 获取请求参数
|
||||
Object[] args = point.getArgs();
|
||||
String reqParam = "[" + StringUtils.join(args, ", ") + "]";
|
||||
String clientIp = NetUtils.getIpAddress(httpServletRequest);
|
||||
// 输出请求日志
|
||||
log.info("request start,id: {}, path: {}, ip: {}, params: {}", requestId, url,
|
||||
httpServletRequest.getRemoteHost(), reqParam);
|
||||
clientIp, reqParam);
|
||||
// 执行原方法
|
||||
Object result = point.proceed();
|
||||
// 输出响应日志
|
||||
@@ -53,4 +55,3 @@ public class LogInterceptor {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,12 +4,14 @@ import com.yupi.springbootinit.common.BaseResponse;
|
||||
import com.yupi.springbootinit.common.ResultUtils;
|
||||
import com.yupi.springbootinit.model.entity.AiComment;
|
||||
import com.yupi.springbootinit.model.entity.AiTemplate;
|
||||
import com.yupi.springbootinit.model.entity.ServerCustomServiceInfo;
|
||||
import com.yupi.springbootinit.model.vo.common.AccountCrawlCount;
|
||||
import com.yupi.springbootinit.model.vo.country.CountryInfoVO;
|
||||
import com.yupi.springbootinit.service.AiCommentService;
|
||||
import com.yupi.springbootinit.service.AiTemplateService;
|
||||
import com.yupi.springbootinit.service.CommonService;
|
||||
import com.yupi.springbootinit.service.CountryInfoService;
|
||||
import com.yupi.springbootinit.service.ServerCustomServiceInfoService;
|
||||
import com.yupi.springbootinit.service.SystemNoticeService;
|
||||
import com.yupi.springbootinit.model.entity.SystemNotice;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -44,6 +46,9 @@ public class CommonController {
|
||||
@Resource
|
||||
private SystemNoticeService systemNoticeService;
|
||||
|
||||
@Resource
|
||||
private ServerCustomServiceInfoService serverCustomServiceInfoService;
|
||||
|
||||
@PostMapping("country_info")
|
||||
public BaseResponse<List<CountryInfoVO>> countryInfo() {
|
||||
|
||||
@@ -85,5 +90,11 @@ public class CommonController {
|
||||
return ResultUtils.success(systemNoticeService.getActiveNoticeList());
|
||||
}
|
||||
|
||||
@GetMapping("custom_service_info")
|
||||
public BaseResponse<List<ServerCustomServiceInfo>> listCustomServiceInfo() {
|
||||
return ResultUtils.success(serverCustomServiceInfoService.listNotDeleted());
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
@@ -91,8 +92,8 @@ public class FeatureAuthController {
|
||||
|
||||
// 5. 校验租户是否过期(根据功能代码选择不同的过期时间字段)
|
||||
String featureCode = request.getFeatureCode();
|
||||
Date expireTime = getFeatureExpireTime(tenant, featureCode);
|
||||
if (expireTime != null && expireTime.before(new Date())) {
|
||||
LocalDateTime expireTime = getFeatureExpireTime(tenant, featureCode);
|
||||
if (expireTime != null && expireTime.isBefore(LocalDateTime.now())) {
|
||||
throw new BusinessException(ErrorCode.PACKAGE_EXPIRED, "该功能套餐已过期");
|
||||
}
|
||||
|
||||
@@ -119,7 +120,7 @@ public class FeatureAuthController {
|
||||
/**
|
||||
* 根据功能代码获取对应的过期时间
|
||||
*/
|
||||
private Date getFeatureExpireTime(SystemTenant tenant, String featureCode) {
|
||||
private LocalDateTime getFeatureExpireTime(SystemTenant tenant, String featureCode) {
|
||||
if (featureCode == null) {
|
||||
return tenant.getExpireTime();
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.yupi.springbootinit.controller;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.yupi.springbootinit.common.BaseResponse;
|
||||
import com.yupi.springbootinit.common.ResultUtils;
|
||||
import com.yupi.springbootinit.model.dto.host.HostAiOperationUpdateRequest;
|
||||
import com.yupi.springbootinit.model.dto.host.HostInfoDTO;
|
||||
import com.yupi.springbootinit.model.dto.host.ServerLiveHostDetailDTO;
|
||||
import com.yupi.springbootinit.model.entity.NewHosts;
|
||||
@@ -58,6 +59,14 @@ public class HostInfoController {
|
||||
|
||||
}
|
||||
|
||||
@PostMapping("/update_ai_operation")
|
||||
public BaseResponse<Boolean> updateAiOperation(@RequestBody HostAiOperationUpdateRequest request) {
|
||||
String hostsId = request == null ? null : request.getHostsId();
|
||||
Long tenantId = request == null ? null : request.getTenantId();
|
||||
log.info("更新主播AI操作状态,hostsId: {}, tenantId: {}", hostsId, tenantId);
|
||||
return ResultUtils.success(hostInfoService.updateAiOperation(request));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据主播ID和租户ID查询直播明细
|
||||
* @param detailDTO 查询条件(包含hostsId和tenantId)
|
||||
|
||||
@@ -1,17 +1,11 @@
|
||||
package com.yupi.springbootinit.controller;
|
||||
|
||||
import cn.dev33.satoken.stp.SaTokenInfo;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.yupi.springbootinit.common.BaseResponse;
|
||||
import com.yupi.springbootinit.common.ErrorCode;
|
||||
import com.yupi.springbootinit.common.ResultUtils;
|
||||
import com.yupi.springbootinit.exception.BusinessException;
|
||||
import com.yupi.springbootinit.model.dto.user.SystemUsersDTO;
|
||||
import com.yupi.springbootinit.model.entity.SystemUsers;
|
||||
import com.yupi.springbootinit.model.enums.CommonStatusEnum;
|
||||
import com.yupi.springbootinit.model.enums.LoginSceneEnum;
|
||||
import com.yupi.springbootinit.model.vo.user.SystemUsersVO;
|
||||
import com.yupi.springbootinit.service.SystemLoginLogService;
|
||||
import com.yupi.springbootinit.service.SystemUsersService;
|
||||
import com.yupi.springbootinit.service.impl.LoginService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -34,10 +28,23 @@ public class UserController {
|
||||
@Resource
|
||||
private LoginService loginService;
|
||||
|
||||
@Resource
|
||||
private SystemLoginLogService systemLoginLogService;
|
||||
|
||||
@Resource
|
||||
private SystemUsersService systemUsersService;
|
||||
|
||||
// 用户登陆接口
|
||||
@PostMapping("doLogin")
|
||||
public BaseResponse<SystemUsersVO> doLogin(@RequestBody SystemUsersDTO usersDTO) {
|
||||
return ResultUtils.success(loginService.login(LoginSceneEnum.HOST, usersDTO));
|
||||
try {
|
||||
SystemUsersVO usersVO = loginService.login(LoginSceneEnum.HOST, usersDTO);
|
||||
systemLoginLogService.recordDoLoginLog(usersDTO, usersVO, true);
|
||||
return ResultUtils.success(usersVO);
|
||||
} catch (RuntimeException exception) {
|
||||
recordFailedDoLoginLog(usersDTO, exception);
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -68,9 +75,25 @@ public class UserController {
|
||||
return ResultUtils.success(loginService.logout());
|
||||
}
|
||||
|
||||
@GetMapping("/current")
|
||||
public BaseResponse<SystemUsersVO> getCurrentUser() {
|
||||
return ResultUtils.success(systemUsersService.getCurrentUserInfo());
|
||||
}
|
||||
|
||||
@PostMapping("/bigbrother-logout")
|
||||
public BaseResponse<Boolean> bigBrotherLogout(@RequestBody SystemUsersDTO usersDTO){
|
||||
return ResultUtils.success(loginService.bigBrotherLogout(usersDTO));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private void recordFailedDoLoginLog(SystemUsersDTO usersDTO, RuntimeException exception) {
|
||||
try {
|
||||
systemLoginLogService.recordDoLoginLog(usersDTO, null, false);
|
||||
} catch (RuntimeException logException) {
|
||||
logException.addSuppressed(exception);
|
||||
throw logException;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.yupi.springbootinit.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.yupi.springbootinit.model.entity.ServerCustomServiceInfo;
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2026/3/3 21:32
|
||||
*/
|
||||
|
||||
public interface ServerCustomServiceInfoMapper extends BaseMapper<ServerCustomServiceInfo> {
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.yupi.springbootinit.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.yupi.springbootinit.model.entity.SystemLoginLog;
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2026/3/10 11:32
|
||||
*/
|
||||
|
||||
public interface SystemLoginLogMapper extends BaseMapper<SystemLoginLog> {
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.yupi.springbootinit.model.dto.host;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 主播 AI 操作状态更新请求
|
||||
*/
|
||||
@Data
|
||||
@ApiModel("主播 AI 操作状态更新请求")
|
||||
public class HostAiOperationUpdateRequest implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty(value = "主播ID", required = true, example = "host123")
|
||||
private String hostsId;
|
||||
|
||||
@ApiModelProperty(value = "租户ID", required = true, example = "1001")
|
||||
private Long tenantId;
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
package com.yupi.springbootinit.model.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import java.util.Date;
|
||||
import lombok.Data;
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2026/3/3 21:32
|
||||
*/
|
||||
|
||||
/**
|
||||
* 客服信息表
|
||||
*/
|
||||
@ApiModel(description="客服信息表")
|
||||
@Data
|
||||
@TableName(value = "server_custom_service_info")
|
||||
public class ServerCustomServiceInfo {
|
||||
/**
|
||||
* 主键id
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
@ApiModelProperty(value="主键id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 姓名
|
||||
*/
|
||||
@TableField(value = "`name`")
|
||||
@ApiModelProperty(value="姓名")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 头像
|
||||
*/
|
||||
@TableField(value = "avater")
|
||||
@ApiModelProperty(value="头像")
|
||||
private String avater;
|
||||
|
||||
/**
|
||||
* 简介
|
||||
*/
|
||||
@TableField(value = "description")
|
||||
@ApiModelProperty(value="简介")
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 微信
|
||||
*/
|
||||
@TableField(value = "`concat`")
|
||||
@ApiModelProperty(value="微信")
|
||||
private String concat;
|
||||
|
||||
/**
|
||||
* 手机号
|
||||
*/
|
||||
@TableField(value = "phone")
|
||||
@ApiModelProperty(value="手机号")
|
||||
private String phone;
|
||||
|
||||
/**
|
||||
* 创建人
|
||||
*/
|
||||
@TableField(value = "creator")
|
||||
@ApiModelProperty(value="创建人")
|
||||
private String creator;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField(value = "create_time")
|
||||
@ApiModelProperty(value="创建时间")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 更新人
|
||||
*/
|
||||
@TableField(value = "updater")
|
||||
@ApiModelProperty(value="更新人")
|
||||
private Long updater;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@TableField(value = "update_time")
|
||||
@ApiModelProperty(value="更新时间")
|
||||
private Date updateTime;
|
||||
|
||||
/**
|
||||
* 是否删除
|
||||
*/
|
||||
@TableField(value = "deleted")
|
||||
@ApiModelProperty(value="是否删除")
|
||||
private Boolean deleted;
|
||||
|
||||
/**
|
||||
* 租户Id
|
||||
*/
|
||||
@TableField(value = "tenant_id")
|
||||
@ApiModelProperty(value="租户Id")
|
||||
private Long tenantId;
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
package com.yupi.springbootinit.model.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
|
||||
import java.util.Date;
|
||||
import lombok.Data;
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2026/3/10 11:32
|
||||
*/
|
||||
|
||||
/**
|
||||
* 系统访问记录
|
||||
*/
|
||||
@ApiModel(description="系统访问记录")
|
||||
@Data
|
||||
@TableName(value = "system_login_log")
|
||||
public class SystemLoginLog {
|
||||
/**
|
||||
* 访问ID
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
@ApiModelProperty(value="访问ID")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 日志类型
|
||||
*/
|
||||
@TableField(value = "log_type")
|
||||
@ApiModelProperty(value="日志类型")
|
||||
private Long logType;
|
||||
|
||||
/**
|
||||
* 链路追踪编号
|
||||
*/
|
||||
@TableField(value = "trace_id")
|
||||
@ApiModelProperty(value="链路追踪编号")
|
||||
private String traceId;
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
*/
|
||||
@TableField(value = "user_id")
|
||||
@ApiModelProperty(value="用户编号")
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 用户类型
|
||||
*/
|
||||
@TableField(value = "user_type")
|
||||
@ApiModelProperty(value="用户类型")
|
||||
private Byte userType;
|
||||
|
||||
/**
|
||||
* 用户账号
|
||||
*/
|
||||
@TableField(value = "username")
|
||||
@ApiModelProperty(value="用户账号")
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 登陆结果
|
||||
*/
|
||||
@TableField(value = "`result`")
|
||||
@ApiModelProperty(value="登陆结果")
|
||||
private Byte result;
|
||||
|
||||
/**
|
||||
* 用户 IP
|
||||
*/
|
||||
@TableField(value = "user_ip")
|
||||
@ApiModelProperty(value="用户 IP")
|
||||
private String userIp;
|
||||
|
||||
/**
|
||||
* 浏览器 UA
|
||||
*/
|
||||
@TableField(value = "user_agent")
|
||||
@ApiModelProperty(value="浏览器 UA")
|
||||
private String userAgent;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
@TableField(value = "creator")
|
||||
@ApiModelProperty(value="创建者")
|
||||
private String creator;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField(value = "create_time")
|
||||
@ApiModelProperty(value="创建时间")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
@TableField(value = "updater")
|
||||
@ApiModelProperty(value="更新者")
|
||||
private String updater;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@TableField(value = "update_time")
|
||||
@ApiModelProperty(value="更新时间")
|
||||
private Date updateTime;
|
||||
|
||||
/**
|
||||
* 是否删除
|
||||
*/
|
||||
@TableField(value = "deleted")
|
||||
@ApiModelProperty(value="是否删除")
|
||||
private Boolean deleted;
|
||||
|
||||
/**
|
||||
* 租户编号
|
||||
*/
|
||||
@TableField(value = "tenant_id")
|
||||
@ApiModelProperty(value="租户编号")
|
||||
private Long tenantId;
|
||||
}
|
||||
@@ -84,28 +84,28 @@ public class SystemTenant {
|
||||
*/
|
||||
@TableField(value = "expire_time")
|
||||
@ApiModelProperty(value="过期时间")
|
||||
private Date expireTime;
|
||||
private LocalDateTime expireTime;
|
||||
|
||||
/**
|
||||
* 爬主播过期时间
|
||||
*/
|
||||
@TableField(value = "crawl_expire_time")
|
||||
@ApiModelProperty(value="爬主播过期时间")
|
||||
private Date crawlExpireTime;
|
||||
private LocalDateTime crawlExpireTime;
|
||||
|
||||
/**
|
||||
* ai过期时间
|
||||
*/
|
||||
@TableField(value = "expire_time")
|
||||
@ApiModelProperty(value="ai过期时间")
|
||||
private Date aiExpireTime;
|
||||
@TableField(value = "ai_expire_time")
|
||||
private LocalDateTime aiExpireTime;
|
||||
|
||||
/**
|
||||
* 大哥过期时间
|
||||
*/
|
||||
@TableField(value = "expire_time")
|
||||
@ApiModelProperty(value="大哥过期时间")
|
||||
private Date brotherExpireTime;
|
||||
@TableField(value = "brother_expire_time")
|
||||
private LocalDateTime brotherExpireTime;
|
||||
|
||||
|
||||
/**
|
||||
@@ -125,9 +125,9 @@ public class SystemTenant {
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField(value = "create_time")
|
||||
@ApiModelProperty(value="创建时间")
|
||||
private Date createTime;
|
||||
@TableField(value = "create_time")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
@@ -141,7 +141,7 @@ public class SystemTenant {
|
||||
*/
|
||||
@TableField(value = "update_time")
|
||||
@ApiModelProperty(value="更新时间")
|
||||
private Date updateTime;
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/**
|
||||
* 是否删除
|
||||
|
||||
@@ -11,5 +11,5 @@ import java.util.Date;
|
||||
*/
|
||||
@Data
|
||||
public class SystemTenantVO {
|
||||
private Date expiredTime;
|
||||
private LocalDateTime expiredTime;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Date;
|
||||
|
||||
/*
|
||||
@@ -32,13 +33,13 @@ public class SystemUsersVO {
|
||||
|
||||
private String tokenValue;
|
||||
|
||||
private Date expireTime;
|
||||
private LocalDateTime expireTime;
|
||||
|
||||
private Date brotherExpireTime;
|
||||
private LocalDateTime brotherExpireTime;
|
||||
|
||||
private Date aiExpireTime;
|
||||
private LocalDateTime aiExpireTime;
|
||||
|
||||
private Date crawlExpireTime;
|
||||
private LocalDateTime crawlExpireTime;
|
||||
|
||||
private Byte aiReplay;
|
||||
|
||||
@@ -50,5 +51,15 @@ public class SystemUsersVO {
|
||||
|
||||
private Byte webAi;
|
||||
|
||||
private Boolean aiReplayEnabled;
|
||||
|
||||
private Boolean crawlEnabled;
|
||||
|
||||
private Boolean bigBrotherEnabled;
|
||||
|
||||
private Boolean aiChatEnabled;
|
||||
|
||||
private Boolean webAiEnabled;
|
||||
|
||||
private Integer points;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,14 +3,10 @@ package com.yupi.springbootinit.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.yupi.springbootinit.model.dto.host.HistoryDataDTO;
|
||||
import com.yupi.springbootinit.model.dto.host.HostAiOperationUpdateRequest;
|
||||
import com.yupi.springbootinit.model.dto.host.HostInfoDTO;
|
||||
import com.yupi.springbootinit.model.entity.NewHosts;
|
||||
import com.yupi.springbootinit.model.vo.hosts.NewHostsVO;
|
||||
import com.yupi.springbootinit.model.vo.hosts.SevenDaysData;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
@@ -21,4 +17,6 @@ public interface HostInfoService extends IService<NewHosts> {
|
||||
|
||||
Page<NewHostsVO> getConditionHosts(HostInfoDTO hostInfoDTO);
|
||||
|
||||
boolean updateAiOperation(HostAiOperationUpdateRequest request);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.yupi.springbootinit.service;
|
||||
|
||||
import com.yupi.springbootinit.model.entity.ServerCustomServiceInfo;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import java.util.List;
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2026/3/3 21:32
|
||||
*/
|
||||
|
||||
public interface ServerCustomServiceInfoService extends IService<ServerCustomServiceInfo>{
|
||||
|
||||
/**
|
||||
* 查询所有未删除的客服信息
|
||||
*
|
||||
* @return 未删除的客服信息列表
|
||||
*/
|
||||
List<ServerCustomServiceInfo> listNotDeleted();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.yupi.springbootinit.service;
|
||||
|
||||
import com.yupi.springbootinit.model.entity.SystemLoginLog;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.yupi.springbootinit.model.dto.user.SystemUsersDTO;
|
||||
import com.yupi.springbootinit.model.vo.user.SystemUsersVO;
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2026/3/10 11:32
|
||||
*/
|
||||
|
||||
public interface SystemLoginLogService extends IService<SystemLoginLog>{
|
||||
|
||||
/**
|
||||
* 记录主播端 doLogin 登录日志
|
||||
*
|
||||
* @param usersDTO 登录请求参数
|
||||
* @param usersVO 登录成功后的用户信息,失败时为 null
|
||||
* @param success 是否登录成功
|
||||
*/
|
||||
void recordDoLoginLog(SystemUsersDTO usersDTO, SystemUsersVO usersVO, boolean success);
|
||||
}
|
||||
@@ -7,6 +7,7 @@ package com.yupi.springbootinit.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.yupi.springbootinit.model.entity.SystemUsers;
|
||||
import com.yupi.springbootinit.model.vo.user.SystemUsersVO;
|
||||
|
||||
public interface SystemUsersService extends IService<SystemUsers> {
|
||||
|
||||
@@ -26,4 +27,6 @@ public interface SystemUsersService extends IService<SystemUsers> {
|
||||
boolean checkAiCHatLoginRole(Long userId);
|
||||
|
||||
boolean checkWebAILoginRole(Long userId);
|
||||
|
||||
SystemUsersVO getCurrentUserInfo();
|
||||
}
|
||||
|
||||
@@ -1,27 +1,34 @@
|
||||
package com.yupi.springbootinit.service.impl;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.yupi.springbootinit.common.ErrorCode;
|
||||
import com.yupi.springbootinit.exception.BusinessException;
|
||||
import com.yupi.springbootinit.mapper.NewHostsMapper;
|
||||
import com.yupi.springbootinit.model.dto.host.HostAiOperationUpdateRequest;
|
||||
import com.yupi.springbootinit.model.dto.host.HostInfoDTO;
|
||||
import com.yupi.springbootinit.model.entity.NewHosts;
|
||||
import com.yupi.springbootinit.model.vo.hosts.NewHostsVO;
|
||||
import com.yupi.springbootinit.service.HostInfoService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2025/6/10 19:04
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public class HostInfoServiceImpl extends ServiceImpl<NewHostsMapper, NewHosts> implements HostInfoService {
|
||||
|
||||
private static final byte AI_OPERATION_ENABLED = 1;
|
||||
private static final byte NOT_DELETED = 0;
|
||||
|
||||
@Resource
|
||||
private NewHostsMapper newHostsMapper;
|
||||
|
||||
@@ -31,5 +38,34 @@ public class HostInfoServiceImpl extends ServiceImpl<NewHostsMapper, NewHosts> i
|
||||
return newHostsMapper.selectPageByCondition(page, hostInfoDTO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateAiOperation(HostAiOperationUpdateRequest request) {
|
||||
validateAiOperationUpdateRequest(request);
|
||||
List<NewHosts> matchedHosts = lambdaQuery()
|
||||
.eq(NewHosts::getHostsId, request.getHostsId())
|
||||
.eq(NewHosts::getTenantId, request.getTenantId())
|
||||
.eq(NewHosts::getDeleted, NOT_DELETED)
|
||||
.list();
|
||||
if (matchedHosts.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
boolean allAiOperationEnabled = matchedHosts.stream()
|
||||
.allMatch(host -> Objects.equals(host.getAiOperation(), AI_OPERATION_ENABLED));
|
||||
if (allAiOperationEnabled) {
|
||||
return true;
|
||||
}
|
||||
return lambdaUpdate()
|
||||
.eq(NewHosts::getHostsId, request.getHostsId())
|
||||
.eq(NewHosts::getTenantId, request.getTenantId())
|
||||
.eq(NewHosts::getDeleted, NOT_DELETED)
|
||||
.set(NewHosts::getAiOperation, AI_OPERATION_ENABLED)
|
||||
.update();
|
||||
}
|
||||
|
||||
private void validateAiOperationUpdateRequest(HostAiOperationUpdateRequest request) {
|
||||
if (request == null || StrUtil.isBlank(request.getHostsId()) || request.getTenantId() == null) {
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR, "hostsId和tenantId不能为空");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -102,27 +102,38 @@ public class LoginService {
|
||||
StpUtil.login(user.getId(), scene.getSaMode());
|
||||
switch (scene) {
|
||||
case AI_CHAT:
|
||||
StpUtil.renewTimeout(DateUtils.dateBetween(systemTenant.getAiExpireTime(),DateUtil.date()));
|
||||
StpUtil.renewTimeout(DateUtils.dateBetween(systemTenant.getAiExpireTime(), DateUtil.date().toLocalDateTime()));
|
||||
BeanUtil.copyProperties(user, vo);
|
||||
vo.setTokenName(StpUtil.getTokenName());
|
||||
vo.setTokenValue(StpUtil.getTokenValue());
|
||||
vo.setAiExpireTime(systemTenant.getAiExpireTime());
|
||||
fillFeatureInfo(vo, user, systemTenant);
|
||||
return vo;
|
||||
case HOST:
|
||||
BeanUtil.copyProperties(user, vo);
|
||||
vo.setTokenName(StpUtil.getTokenName());
|
||||
vo.setTokenValue(StpUtil.getTokenValue());
|
||||
vo.setExpireTime(systemTenant.getExpireTime());
|
||||
vo.setBrotherExpireTime(systemTenant.getBrotherExpireTime());
|
||||
vo.setAiExpireTime(systemTenant.getAiExpireTime());
|
||||
vo.setCrawl(user.getCrawl());
|
||||
vo.setAiChat(user.getAiChat());
|
||||
vo.setBigBrother(user.getBigBrother());
|
||||
fillFeatureInfo(vo, user, systemTenant);
|
||||
return vo;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void fillFeatureInfo(SystemUsersVO vo, SystemUsers user, SystemTenant tenant) {
|
||||
vo.setExpireTime(tenant.getExpireTime());
|
||||
vo.setCrawlExpireTime(tenant.getCrawlExpireTime());
|
||||
vo.setBrotherExpireTime(tenant.getBrotherExpireTime());
|
||||
vo.setAiExpireTime(tenant.getAiExpireTime());
|
||||
vo.setAiReplayEnabled(isEnabled(user.getAiReplay()));
|
||||
vo.setCrawlEnabled(isEnabled(user.getCrawl()));
|
||||
vo.setBigBrotherEnabled(isEnabled(user.getBigBrother()));
|
||||
vo.setAiChatEnabled(isEnabled(user.getAiChat()));
|
||||
vo.setWebAiEnabled(isEnabled(user.getWebAi()));
|
||||
}
|
||||
|
||||
private boolean isEnabled(Byte value) {
|
||||
return value != null && value == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验用户登录信息
|
||||
*
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.yupi.springbootinit.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.yupi.springbootinit.model.entity.ServerCustomServiceInfo;
|
||||
import com.yupi.springbootinit.mapper.ServerCustomServiceInfoMapper;
|
||||
import com.yupi.springbootinit.service.ServerCustomServiceInfoService;
|
||||
|
||||
import java.util.List;
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2026/3/3 21:32
|
||||
*/
|
||||
|
||||
@Service
|
||||
public class ServerCustomServiceInfoServiceImpl extends ServiceImpl<ServerCustomServiceInfoMapper, ServerCustomServiceInfo> implements ServerCustomServiceInfoService{
|
||||
|
||||
@Override
|
||||
public List<ServerCustomServiceInfo> listNotDeleted() {
|
||||
QueryWrapper<ServerCustomServiceInfo> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("deleted", false);
|
||||
return this.list(queryWrapper);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package com.yupi.springbootinit.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.yupi.springbootinit.mapper.SystemLoginLogMapper;
|
||||
import com.yupi.springbootinit.model.dto.user.SystemUsersDTO;
|
||||
import com.yupi.springbootinit.model.entity.SystemLoginLog;
|
||||
import com.yupi.springbootinit.model.vo.user.SystemUsersVO;
|
||||
import com.yupi.springbootinit.service.SystemLoginLogService;
|
||||
import com.yupi.springbootinit.utils.NetUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2026/3/10 11:32
|
||||
*/
|
||||
|
||||
@Service
|
||||
public class SystemLoginLogServiceImpl extends ServiceImpl<SystemLoginLogMapper, SystemLoginLog> implements SystemLoginLogService{
|
||||
|
||||
private static final Long HOST_LOGIN_LOG_TYPE = 1L;
|
||||
private static final Byte LOGIN_SUCCESS = 1;
|
||||
private static final Byte LOGIN_FAILURE = 0;
|
||||
private static final String USER_AGENT_HEADER = "User-Agent";
|
||||
private static final String TRACE_ID_HEADER = "X-Trace-Id";
|
||||
private static final String SYSTEM_OPERATOR = "system";
|
||||
|
||||
@Override
|
||||
public void recordDoLoginLog(SystemUsersDTO usersDTO, SystemUsersVO usersVO, boolean success) {
|
||||
HttpServletRequest request = getCurrentRequest();
|
||||
Date now = new Date();
|
||||
SystemLoginLog loginLog = new SystemLoginLog();
|
||||
loginLog.setLogType(HOST_LOGIN_LOG_TYPE);
|
||||
loginLog.setTraceId(resolveTraceId(request));
|
||||
loginLog.setUserId(usersVO == null ? null : usersVO.getId());
|
||||
loginLog.setUsername(resolveUsername(usersDTO, usersVO));
|
||||
loginLog.setResult(success ? LOGIN_SUCCESS : LOGIN_FAILURE);
|
||||
loginLog.setUserIp(NetUtils.getIpAddress(request));
|
||||
loginLog.setUserAgent(request.getHeader(USER_AGENT_HEADER));
|
||||
loginLog.setCreator(SYSTEM_OPERATOR);
|
||||
loginLog.setCreateTime(now);
|
||||
loginLog.setUpdater(SYSTEM_OPERATOR);
|
||||
loginLog.setUpdateTime(now);
|
||||
loginLog.setDeleted(Boolean.FALSE);
|
||||
loginLog.setTenantId(resolveTenantId(usersDTO, usersVO));
|
||||
boolean saved = save(loginLog);
|
||||
if (!saved) {
|
||||
throw new IllegalStateException("保存 doLogin 登录日志失败");
|
||||
}
|
||||
}
|
||||
|
||||
private HttpServletRequest getCurrentRequest() {
|
||||
ServletRequestAttributes attributes =
|
||||
(ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
|
||||
return attributes.getRequest();
|
||||
}
|
||||
|
||||
private String resolveTraceId(HttpServletRequest request) {
|
||||
String traceId = request.getHeader(TRACE_ID_HEADER);
|
||||
if (traceId == null || traceId.isBlank()) {
|
||||
return UUID.randomUUID().toString();
|
||||
}
|
||||
return traceId;
|
||||
}
|
||||
|
||||
private String resolveUsername(SystemUsersDTO usersDTO, SystemUsersVO usersVO) {
|
||||
if (usersVO != null && usersVO.getUsername() != null) {
|
||||
return usersVO.getUsername();
|
||||
}
|
||||
return usersDTO.getUsername();
|
||||
}
|
||||
|
||||
private Long resolveTenantId(SystemUsersDTO usersDTO, SystemUsersVO usersVO) {
|
||||
if (usersVO != null && usersVO.getTenantId() != null) {
|
||||
return usersVO.getTenantId();
|
||||
}
|
||||
return usersDTO.getTenantId();
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,23 @@
|
||||
package com.yupi.springbootinit.service.impl;
|
||||
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.date.DateUnit;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.yupi.springbootinit.common.ErrorCode;
|
||||
import com.yupi.springbootinit.exception.BusinessException;
|
||||
import com.yupi.springbootinit.mapper.SystemTenantMapper;
|
||||
import com.yupi.springbootinit.model.entity.SystemTenant;
|
||||
import com.yupi.springbootinit.model.entity.SystemUsers;
|
||||
import com.yupi.springbootinit.service.SystemTenantService;
|
||||
import com.yupi.springbootinit.mapper.SystemUsersMapper;
|
||||
import com.yupi.springbootinit.model.vo.user.SystemUsersVO;
|
||||
import com.yupi.springbootinit.service.SystemUsersService;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import com.yupi.springbootinit.mapper.SystemUsersMapper;
|
||||
import com.yupi.springbootinit.service.SystemUsersService;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
/*
|
||||
* @author: ziin
|
||||
@@ -50,14 +51,14 @@ public class SystemUsersServiceImpl extends ServiceImpl<SystemUsersMapper,System
|
||||
@Override
|
||||
public boolean isExpired(Long tendId) {
|
||||
SystemTenant systemTenant = systemTenantMapper.selectById(tendId);
|
||||
long between = DateUtil.between(systemTenant.getExpireTime(), DateUtil.date(), DateUnit.DAY);
|
||||
long between = DateUtil.between(DateUtil.date(systemTenant.getExpireTime()), DateUtil.date(), DateUnit.DAY);
|
||||
return between < 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getTenantExpiredTime(Long tenantId) {
|
||||
SystemTenant systemTenant = systemTenantMapper.selectById(tenantId);
|
||||
long between = DateUtil.between(systemTenant.getExpireTime(), DateUtil.date(), DateUnit.SECOND);
|
||||
long between = DateUtil.between(DateUtil.date(systemTenant.getExpireTime()), DateUtil.date(), DateUnit.SECOND);
|
||||
if (between > 0 ) {
|
||||
return between;
|
||||
}
|
||||
@@ -90,5 +91,43 @@ public class SystemUsersServiceImpl extends ServiceImpl<SystemUsersMapper,System
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public SystemUsersVO getCurrentUserInfo() {
|
||||
Long userId = StpUtil.getLoginIdAsLong();
|
||||
SystemUsers user = baseMapper.selectById(userId);
|
||||
if (user == null || Boolean.TRUE.equals(user.getDeleted())) {
|
||||
throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "用户不存在");
|
||||
}
|
||||
SystemTenant tenant = systemTenantMapper.selectById(user.getTenantId());
|
||||
if (tenant == null || Boolean.TRUE.equals(tenant.getDeleted())) {
|
||||
throw new BusinessException(ErrorCode.TENANT_NAME_NOT_EXISTS);
|
||||
}
|
||||
return buildSystemUsersVO(user, tenant);
|
||||
}
|
||||
|
||||
private SystemUsersVO buildSystemUsersVO(SystemUsers user, SystemTenant tenant) {
|
||||
SystemUsersVO userVO = new SystemUsersVO();
|
||||
BeanUtil.copyProperties(user, userVO);
|
||||
userVO.setTokenName(StpUtil.getTokenName());
|
||||
userVO.setTokenValue(StpUtil.getTokenValue());
|
||||
userVO.setExpireTime(tenant.getExpireTime());
|
||||
userVO.setCrawlExpireTime(tenant.getCrawlExpireTime());
|
||||
userVO.setBrotherExpireTime(tenant.getBrotherExpireTime());
|
||||
userVO.setAiExpireTime(tenant.getAiExpireTime());
|
||||
fillFeatureEnabled(userVO, user);
|
||||
return userVO;
|
||||
}
|
||||
|
||||
private void fillFeatureEnabled(SystemUsersVO userVO, SystemUsers user) {
|
||||
userVO.setAiReplayEnabled(isEnabled(user.getAiReplay()));
|
||||
userVO.setCrawlEnabled(isEnabled(user.getCrawl()));
|
||||
userVO.setBigBrotherEnabled(isEnabled(user.getBigBrother()));
|
||||
userVO.setAiChatEnabled(isEnabled(user.getAiChat()));
|
||||
userVO.setWebAiEnabled(isEnabled(user.getWebAi()));
|
||||
}
|
||||
|
||||
private boolean isEnabled(Byte value) {
|
||||
return value != null && value == 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.yupi.springbootinit.utils;
|
||||
import cn.hutool.core.date.DateUnit;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Date;
|
||||
|
||||
/*
|
||||
@@ -11,7 +12,8 @@ import java.util.Date;
|
||||
*/
|
||||
public class DateUtils {
|
||||
|
||||
public static Long dateBetween(Date date1, Date date2) {
|
||||
return DateUtil.between(date1, date2, DateUnit.SECOND);
|
||||
public static Long dateBetween(LocalDateTime date1, LocalDateTime date2) {
|
||||
|
||||
return DateUtil.between(DateUtil.date(date1), DateUtil.date(date2), DateUnit.SECOND);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package com.yupi.springbootinit.utils;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/**
|
||||
* 网络工具类
|
||||
@@ -11,6 +13,23 @@ import javax.servlet.http.HttpServletRequest;
|
||||
*/
|
||||
public class NetUtils {
|
||||
|
||||
private static final String UNKNOWN = "unknown";
|
||||
|
||||
private static final String LOCALHOST_IPV4 = "127.0.0.1";
|
||||
|
||||
private static final String LOCALHOST_IPV6 = "0:0:0:0:0:0:0:1";
|
||||
|
||||
private static final String LOCALHOST_IPV6_SHORT = "::1";
|
||||
|
||||
private static final String[] IP_HEADER_CANDIDATES = {
|
||||
"x-forwarded-for",
|
||||
"X-Forwarded-For",
|
||||
"X-Real-IP",
|
||||
"Proxy-Client-IP",
|
||||
"WL-Proxy-Client-IP",
|
||||
"HTTP_X_FORWARDED_FOR"
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取客户端 IP 地址
|
||||
*
|
||||
@@ -18,38 +37,57 @@ public class NetUtils {
|
||||
* @return
|
||||
*/
|
||||
public static String getIpAddress(HttpServletRequest request) {
|
||||
String ip = request.getHeader("x-forwarded-for");
|
||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
|
||||
ip = request.getHeader("Proxy-Client-IP");
|
||||
String headerIp = getIpFromHeaders(request);
|
||||
if (StringUtils.isNotBlank(headerIp)) {
|
||||
return headerIp;
|
||||
}
|
||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
|
||||
ip = request.getHeader("WL-Proxy-Client-IP");
|
||||
}
|
||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
|
||||
ip = request.getRemoteAddr();
|
||||
if (ip.equals("127.0.0.1")) {
|
||||
// 根据网卡取本机配置的 IP
|
||||
InetAddress inet = null;
|
||||
try {
|
||||
inet = InetAddress.getLocalHost();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (inet != null) {
|
||||
ip = inet.getHostAddress();
|
||||
}
|
||||
return normalizeLocalIp(request.getRemoteAddr());
|
||||
}
|
||||
|
||||
private static String getIpFromHeaders(HttpServletRequest request) {
|
||||
for (String headerName : IP_HEADER_CANDIDATES) {
|
||||
String headerValue = request.getHeader(headerName);
|
||||
String ip = extractFirstValidIp(headerValue);
|
||||
if (StringUtils.isNotBlank(ip)) {
|
||||
return ip;
|
||||
}
|
||||
}
|
||||
// 多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
|
||||
if (ip != null && ip.length() > 15) {
|
||||
if (ip.indexOf(",") > 0) {
|
||||
ip = ip.substring(0, ip.indexOf(","));
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String extractFirstValidIp(String ipValue) {
|
||||
if (StringUtils.isBlank(ipValue)) {
|
||||
return null;
|
||||
}
|
||||
String[] ipList = ipValue.split(",");
|
||||
for (String ip : ipList) {
|
||||
String trimmedIp = StringUtils.trim(ip);
|
||||
if (StringUtils.isNotBlank(trimmedIp) && !UNKNOWN.equalsIgnoreCase(trimmedIp)) {
|
||||
return trimmedIp;
|
||||
}
|
||||
}
|
||||
if (ip == null) {
|
||||
return "127.0.0.1";
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String normalizeLocalIp(String remoteAddr) {
|
||||
if (StringUtils.isBlank(remoteAddr)) {
|
||||
return LOCALHOST_IPV4;
|
||||
}
|
||||
return ip;
|
||||
if (!isLocalhost(remoteAddr)) {
|
||||
return remoteAddr;
|
||||
}
|
||||
try {
|
||||
InetAddress inetAddress = InetAddress.getLocalHost();
|
||||
return inetAddress.getHostAddress();
|
||||
} catch (UnknownHostException e) {
|
||||
return remoteAddr;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isLocalhost(String ip) {
|
||||
return LOCALHOST_IPV4.equals(ip)
|
||||
|| LOCALHOST_IPV6.equals(ip)
|
||||
|| LOCALHOST_IPV6_SHORT.equals(ip);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
25
src/main/resources/mapper/ServerCustomServiceInfoMapper.xml
Normal file
25
src/main/resources/mapper/ServerCustomServiceInfoMapper.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.yupi.springbootinit.mapper.ServerCustomServiceInfoMapper">
|
||||
<resultMap id="BaseResultMap" type="com.yupi.springbootinit.model.entity.ServerCustomServiceInfo">
|
||||
<!--@mbg.generated-->
|
||||
<!--@Table server_custom_service_info-->
|
||||
<id column="id" jdbcType="BIGINT" property="id" />
|
||||
<result column="name" jdbcType="VARCHAR" property="name" />
|
||||
<result column="avater" jdbcType="VARCHAR" property="avater" />
|
||||
<result column="description" jdbcType="VARCHAR" property="description" />
|
||||
<result column="concat" jdbcType="VARCHAR" property="concat" />
|
||||
<result column="phone" jdbcType="VARCHAR" property="phone" />
|
||||
<result column="creator" jdbcType="VARCHAR" property="creator" />
|
||||
<result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
|
||||
<result column="updater" jdbcType="BIGINT" property="updater" />
|
||||
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
|
||||
<result column="deleted" jdbcType="BIT" property="deleted" />
|
||||
<result column="tenant_id" jdbcType="BIGINT" property="tenantId" />
|
||||
</resultMap>
|
||||
<sql id="Base_Column_List">
|
||||
<!--@mbg.generated-->
|
||||
id, `name`, avater, description, `concat`, phone, creator, create_time, updater,
|
||||
update_time, deleted, tenant_id
|
||||
</sql>
|
||||
</mapper>
|
||||
28
src/main/resources/mapper/SystemLoginLogMapper.xml
Normal file
28
src/main/resources/mapper/SystemLoginLogMapper.xml
Normal file
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.yupi.springbootinit.mapper.SystemLoginLogMapper">
|
||||
<resultMap id="BaseResultMap" type="com.yupi.springbootinit.model.entity.SystemLoginLog">
|
||||
<!--@mbg.generated-->
|
||||
<!--@Table system_login_log-->
|
||||
<id column="id" jdbcType="BIGINT" property="id" />
|
||||
<result column="log_type" jdbcType="BIGINT" property="logType" />
|
||||
<result column="trace_id" jdbcType="VARCHAR" property="traceId" />
|
||||
<result column="user_id" jdbcType="BIGINT" property="userId" />
|
||||
<result column="user_type" jdbcType="TINYINT" property="userType" />
|
||||
<result column="username" jdbcType="VARCHAR" property="username" />
|
||||
<result column="result" jdbcType="TINYINT" property="result" />
|
||||
<result column="user_ip" jdbcType="VARCHAR" property="userIp" />
|
||||
<result column="user_agent" jdbcType="VARCHAR" property="userAgent" />
|
||||
<result column="creator" jdbcType="VARCHAR" property="creator" />
|
||||
<result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
|
||||
<result column="updater" jdbcType="VARCHAR" property="updater" />
|
||||
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
|
||||
<result column="deleted" jdbcType="BIT" property="deleted" />
|
||||
<result column="tenant_id" jdbcType="BIGINT" property="tenantId" />
|
||||
</resultMap>
|
||||
<sql id="Base_Column_List">
|
||||
<!--@mbg.generated-->
|
||||
id, log_type, trace_id, user_id, user_type, username, `result`, user_ip, user_agent,
|
||||
creator, create_time, updater, update_time, deleted, tenant_id
|
||||
</sql>
|
||||
</mapper>
|
||||
Binary file not shown.
Reference in New Issue
Block a user