init backend
This commit is contained in:
92
pom.xml
92
pom.xml
@ -40,6 +40,26 @@
|
|||||||
<artifactId>spring-boot-starter-test</artifactId>
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- https://github.com/xerial/sqlite-jdbc -->
|
||||||
|
<!-- https://mvnrepository.com/artifact/org.xerial/sqlite-jdbc -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.xerial</groupId>
|
||||||
|
<artifactId>sqlite-jdbc</artifactId>
|
||||||
|
<version>3.50.3.0</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- https://mvnrepository.com/artifact/io.swagger.parser.v3/swagger-parser-v3 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.swagger.parser.v3</groupId>
|
||||||
|
<artifactId>swagger-parser-v3</artifactId>
|
||||||
|
<version>2.1.34</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- https://mvnrepository.com/artifact/io.swagger.parser.v3/swagger-parser-core -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.swagger.parser.v3</groupId>
|
||||||
|
<artifactId>swagger-parser-core</artifactId>
|
||||||
|
<version>2.1.34</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
@ -48,6 +68,78 @@
|
|||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<!-- https://openapi-generator.tech/docs/plugins/ -->
|
||||||
|
<groupId>org.openapitools</groupId>
|
||||||
|
<artifactId>openapi-generator-maven-plugin</artifactId>
|
||||||
|
<version>7.15.0</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>bookmark-api</id>
|
||||||
|
<goals>
|
||||||
|
<goal>generate</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<inputSpec>${project.basedir}/src/main/resources/config/bookmark/bookmark.yaml</inputSpec>
|
||||||
|
<generatorName>spring</generatorName>
|
||||||
|
<configOptions>
|
||||||
|
<sourceFolder>src/gen/java/main</sourceFolder>
|
||||||
|
<delegatePattern>false</delegatePattern>
|
||||||
|
<useTags>true</useTags>
|
||||||
|
<interfaceOnly>true</interfaceOnly>
|
||||||
|
<skipDefaultInterface>true</skipDefaultInterface>
|
||||||
|
<useJakartaEe>true</useJakartaEe>
|
||||||
|
<useBeanValidation>true</useBeanValidation>
|
||||||
|
<withJakartaValidation>true</withJakartaValidation>
|
||||||
|
<openApiNullable>false</openApiNullable>
|
||||||
|
</configOptions>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<id>user-np-api</id>
|
||||||
|
<goals>
|
||||||
|
<goal>generate</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<inputSpec>${project.basedir}/src/main/resources/config/user_np/user_np.yaml</inputSpec>
|
||||||
|
<generatorName>spring</generatorName>
|
||||||
|
<configOptions>
|
||||||
|
<sourceFolder>src/gen/java/main</sourceFolder>
|
||||||
|
<delegatePattern>false</delegatePattern>
|
||||||
|
<useTags>true</useTags>
|
||||||
|
<interfaceOnly>true</interfaceOnly>
|
||||||
|
<skipDefaultInterface>true</skipDefaultInterface>
|
||||||
|
<useJakartaEe>true</useJakartaEe>
|
||||||
|
<useBeanValidation>true</useBeanValidation>
|
||||||
|
<withJakartaValidation>true</withJakartaValidation>
|
||||||
|
<openApiNullable>false</openApiNullable>
|
||||||
|
</configOptions>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
<!-- <execution>
|
||||||
|
<id>vfs-client</id>
|
||||||
|
<goals>
|
||||||
|
<goal>generate</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<inputSpec>${project.basedir}/src/main/resources/config/vfs/vfs.yaml</inputSpec>
|
||||||
|
<generatorName>java</generatorName>
|
||||||
|
<configOptions>
|
||||||
|
<library>webclient</library>
|
||||||
|
<dateLibrary>java</dateLibrary>
|
||||||
|
<useBeanValidation>true</useBeanValidation>
|
||||||
|
<withJakartaValidation>true</withJakartaValidation>
|
||||||
|
<openApiNullable>false</openApiNullable>
|
||||||
|
<groupId>com.zzyxyz.api</groupId>
|
||||||
|
<artifactId>vfs-client</artifactId>
|
||||||
|
<artifactVersion>1.0.0</artifactVersion>
|
||||||
|
<modelPackage>com.zzyxyz.api.vfs.model</modelPackage>
|
||||||
|
<apiPackage>com.zzyxyz.api.vfs.api</apiPackage>
|
||||||
|
</configOptions>
|
||||||
|
</configuration>
|
||||||
|
</execution> -->
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
|
|||||||
@ -2,12 +2,23 @@ package com.zzyxyz.api.bookmarks;
|
|||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.context.annotation.ComponentScan;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
|
@RestController
|
||||||
|
@ComponentScan(basePackages = {"com.zzyxyz.api.bookmarks", "org.openapitools"})
|
||||||
public class BookmarksApplication {
|
public class BookmarksApplication {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
SpringApplication.run(BookmarksApplication.class, args);
|
SpringApplication.run(BookmarksApplication.class, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/hello")
|
||||||
|
public String hello(@RequestParam(value = "name", defaultValue = "World") String name) {
|
||||||
|
return String.format("Hello %s!", name);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
43
src/main/java/com/zzyxyz/api/bookmarks/CorsConfig.java
Normal file
43
src/main/java/com/zzyxyz/api/bookmarks/CorsConfig.java
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package com.zzyxyz.api.bookmarks;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.web.cors.CorsConfiguration;
|
||||||
|
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||||
|
import org.springframework.web.filter.CorsFilter;
|
||||||
|
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||||
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class CorsConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public WebMvcConfigurer corsConfigurer() {
|
||||||
|
return new WebMvcConfigurer() {
|
||||||
|
@Override
|
||||||
|
public void addCorsMappings(@NotNull CorsRegistry registry) {
|
||||||
|
registry.addMapping("/**")
|
||||||
|
.allowedOriginPatterns("*") // 使用allowedOriginPatterns而不是allowedOrigins
|
||||||
|
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
|
||||||
|
.allowedHeaders("*")
|
||||||
|
.allowCredentials(false); // 设置为false避免冲突
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public CorsFilter corsFilter() {
|
||||||
|
CorsConfiguration config = new CorsConfiguration();
|
||||||
|
config.addAllowedOriginPattern("*"); // 使用addAllowedOriginPattern而不是addAllowedOrigin
|
||||||
|
config.setAllowCredentials(false); // 设置为false避免冲突
|
||||||
|
config.addAllowedMethod("*");
|
||||||
|
config.addAllowedHeader("*");
|
||||||
|
|
||||||
|
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||||
|
source.registerCorsConfiguration("/**", config);
|
||||||
|
|
||||||
|
return new CorsFilter(source);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,92 @@
|
|||||||
|
package com.zzyxyz.api.bookmarks.bookmark;
|
||||||
|
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
|
|
||||||
|
public class Bookmark {
|
||||||
|
private Long id;
|
||||||
|
private Long externalId;
|
||||||
|
private String name;
|
||||||
|
private String link;
|
||||||
|
private String detail;
|
||||||
|
private String description;
|
||||||
|
private OffsetDateTime createdAt;
|
||||||
|
private OffsetDateTime updatedAt;
|
||||||
|
|
||||||
|
// Constructors
|
||||||
|
public Bookmark() {}
|
||||||
|
|
||||||
|
public Bookmark(Long externalId, String name, String link, String detail, String description) {
|
||||||
|
this.externalId = externalId;
|
||||||
|
this.name = name;
|
||||||
|
this.link = link;
|
||||||
|
this.detail = detail;
|
||||||
|
this.description = description;
|
||||||
|
this.createdAt = OffsetDateTime.now();
|
||||||
|
this.updatedAt = OffsetDateTime.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getters and Setters
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getExternalId() {
|
||||||
|
return externalId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExternalId(Long externalId) {
|
||||||
|
this.externalId = externalId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLink() {
|
||||||
|
return link;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLink(String link) {
|
||||||
|
this.link = link;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDetail() {
|
||||||
|
return detail;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDetail(String detail) {
|
||||||
|
this.detail = detail;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescription(String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OffsetDateTime getCreatedAt() {
|
||||||
|
return createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreatedAt(OffsetDateTime createdAt) {
|
||||||
|
this.createdAt = createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OffsetDateTime getUpdatedAt() {
|
||||||
|
return updatedAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUpdatedAt(OffsetDateTime updatedAt) {
|
||||||
|
this.updatedAt = updatedAt;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,124 @@
|
|||||||
|
package com.zzyxyz.api.bookmarks.bookmark;
|
||||||
|
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
|
import org.openapitools.api.DataApi;
|
||||||
|
import org.openapitools.model.BookmarkRequest;
|
||||||
|
import org.openapitools.model.BookmarkResponse;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
@CrossOrigin(origins = "*")
|
||||||
|
public class BookmarkController implements DataApi {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private BookmarkDAO bookmarkDAO;
|
||||||
|
|
||||||
|
// 初始化数据库表
|
||||||
|
public BookmarkController() {
|
||||||
|
try {
|
||||||
|
bookmarkDAO = new BookmarkDAO();
|
||||||
|
bookmarkDAO.createTableIfNotExists();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResponseEntity<BookmarkResponse> createBookmark(Long id, BookmarkRequest bookmarkRequest) {
|
||||||
|
try {
|
||||||
|
// 检查是否已存在相同externalId的书签
|
||||||
|
Bookmark existingBookmark = bookmarkDAO.findByExternalId(id);
|
||||||
|
if (existingBookmark != null) {
|
||||||
|
return ResponseEntity.status(409).body(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
Bookmark bookmark = new Bookmark(
|
||||||
|
id,
|
||||||
|
bookmarkRequest.getName(),
|
||||||
|
bookmarkRequest.getLink(),
|
||||||
|
bookmarkRequest.getDetail(),
|
||||||
|
bookmarkRequest.getDescription()
|
||||||
|
);
|
||||||
|
|
||||||
|
Bookmark savedBookmark = bookmarkDAO.insert(bookmark);
|
||||||
|
BookmarkResponse response = convertToResponse(savedBookmark);
|
||||||
|
return ResponseEntity.status(201).body(response);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return ResponseEntity.status(500).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResponseEntity<Void> deleteBookmark(Long id) {
|
||||||
|
try {
|
||||||
|
Bookmark bookmark = bookmarkDAO.findById(id);
|
||||||
|
if (bookmark == null) {
|
||||||
|
return ResponseEntity.notFound().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
bookmarkDAO.delete(id);
|
||||||
|
return ResponseEntity.noContent().build();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return ResponseEntity.status(500).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResponseEntity<BookmarkResponse> getBookmark(Long id) {
|
||||||
|
try {
|
||||||
|
Bookmark bookmark = bookmarkDAO.findById(id);
|
||||||
|
if (bookmark == null) {
|
||||||
|
return ResponseEntity.notFound().build();
|
||||||
|
}
|
||||||
|
BookmarkResponse response = convertToResponse(bookmark);
|
||||||
|
return ResponseEntity.ok(response);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return ResponseEntity.status(500).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResponseEntity<BookmarkResponse> updateBookmark(Long id, BookmarkRequest bookmarkRequest) {
|
||||||
|
try {
|
||||||
|
Bookmark existingBookmark = bookmarkDAO.findById(id);
|
||||||
|
if (existingBookmark == null) {
|
||||||
|
return ResponseEntity.notFound().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
existingBookmark.setName(bookmarkRequest.getName());
|
||||||
|
existingBookmark.setLink(bookmarkRequest.getLink());
|
||||||
|
existingBookmark.setDetail(bookmarkRequest.getDetail());
|
||||||
|
existingBookmark.setDescription(bookmarkRequest.getDescription());
|
||||||
|
existingBookmark.setUpdatedAt(OffsetDateTime.now());
|
||||||
|
|
||||||
|
boolean updated = bookmarkDAO.update(existingBookmark);
|
||||||
|
if (updated) {
|
||||||
|
BookmarkResponse response = convertToResponse(existingBookmark);
|
||||||
|
return ResponseEntity.ok(response);
|
||||||
|
} else {
|
||||||
|
return ResponseEntity.status(500).build();
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return ResponseEntity.status(500).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private BookmarkResponse convertToResponse(Bookmark bookmark) {
|
||||||
|
return new BookmarkResponse()
|
||||||
|
.id(bookmark.getId())
|
||||||
|
.name(bookmark.getName())
|
||||||
|
.link(bookmark.getLink())
|
||||||
|
.detail(bookmark.getDetail())
|
||||||
|
.description(bookmark.getDescription())
|
||||||
|
.createdAt(bookmark.getCreatedAt())
|
||||||
|
.updatedAt(bookmark.getUpdatedAt());
|
||||||
|
}
|
||||||
|
}
|
||||||
170
src/main/java/com/zzyxyz/api/bookmarks/bookmark/BookmarkDAO.java
Normal file
170
src/main/java/com/zzyxyz/api/bookmarks/bookmark/BookmarkDAO.java
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
package com.zzyxyz.api.bookmarks.bookmark;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.sql.*;
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class BookmarkDAO {
|
||||||
|
private static final String DB_URL = "jdbc:sqlite:bookmarks.db";
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
Class.forName("org.sqlite.JDBC");
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void createTableIfNotExists() throws SQLException {
|
||||||
|
String sql = """
|
||||||
|
CREATE TABLE IF NOT EXISTS bookmarks (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
external_id INTEGER UNIQUE NOT NULL,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
link TEXT,
|
||||||
|
detail TEXT,
|
||||||
|
description TEXT,
|
||||||
|
created_at TEXT NOT NULL,
|
||||||
|
updated_at TEXT NOT NULL
|
||||||
|
)
|
||||||
|
""";
|
||||||
|
|
||||||
|
try (Connection connection = DriverManager.getConnection(DB_URL);
|
||||||
|
Statement statement = connection.createStatement()) {
|
||||||
|
statement.executeUpdate(sql);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Bookmark insert(Bookmark bookmark) throws SQLException {
|
||||||
|
String sql = """
|
||||||
|
INSERT INTO bookmarks (
|
||||||
|
external_id, name, link, detail, description, created_at, updated_at
|
||||||
|
) VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||||
|
""";
|
||||||
|
|
||||||
|
try (Connection connection = DriverManager.getConnection(DB_URL);
|
||||||
|
PreparedStatement statement = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
|
||||||
|
|
||||||
|
statement.setLong(1, bookmark.getExternalId());
|
||||||
|
statement.setString(2, bookmark.getName());
|
||||||
|
statement.setString(3, bookmark.getLink());
|
||||||
|
statement.setString(4, bookmark.getDetail());
|
||||||
|
statement.setString(5, bookmark.getDescription());
|
||||||
|
statement.setString(6, bookmark.getCreatedAt().toString());
|
||||||
|
statement.setString(7, bookmark.getUpdatedAt().toString());
|
||||||
|
|
||||||
|
int affectedRows = statement.executeUpdate();
|
||||||
|
|
||||||
|
if (affectedRows == 0) {
|
||||||
|
throw new SQLException("Creating bookmark failed, no rows affected.");
|
||||||
|
}
|
||||||
|
|
||||||
|
try (ResultSet generatedKeys = statement.getGeneratedKeys()) {
|
||||||
|
if (generatedKeys.next()) {
|
||||||
|
bookmark.setId(generatedKeys.getLong(1));
|
||||||
|
} else {
|
||||||
|
throw new SQLException("Creating bookmark failed, no ID obtained.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bookmark;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Bookmark findById(Long id) throws SQLException {
|
||||||
|
String sql = "SELECT * FROM bookmarks WHERE id = ?";
|
||||||
|
|
||||||
|
try (Connection connection = DriverManager.getConnection(DB_URL);
|
||||||
|
PreparedStatement statement = connection.prepareStatement(sql)) {
|
||||||
|
|
||||||
|
statement.setLong(1, id);
|
||||||
|
ResultSet rs = statement.executeQuery();
|
||||||
|
|
||||||
|
if (rs.next()) {
|
||||||
|
return mapResultSetToBookmark(rs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Bookmark findByExternalId(Long externalId) throws SQLException {
|
||||||
|
String sql = "SELECT * FROM bookmarks WHERE external_id = ?";
|
||||||
|
|
||||||
|
try (Connection connection = DriverManager.getConnection(DB_URL);
|
||||||
|
PreparedStatement statement = connection.prepareStatement(sql)) {
|
||||||
|
|
||||||
|
statement.setLong(1, externalId);
|
||||||
|
ResultSet rs = statement.executeQuery();
|
||||||
|
|
||||||
|
if (rs.next()) {
|
||||||
|
return mapResultSetToBookmark(rs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Bookmark> findAll() throws SQLException {
|
||||||
|
String sql = "SELECT * FROM bookmarks";
|
||||||
|
List<Bookmark> bookmarks = new ArrayList<>();
|
||||||
|
|
||||||
|
try (Connection connection = DriverManager.getConnection(DB_URL);
|
||||||
|
Statement statement = connection.createStatement();
|
||||||
|
ResultSet rs = statement.executeQuery(sql)) {
|
||||||
|
|
||||||
|
while (rs.next()) {
|
||||||
|
bookmarks.add(mapResultSetToBookmark(rs));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bookmarks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean update(Bookmark bookmark) throws SQLException {
|
||||||
|
String sql = """
|
||||||
|
UPDATE bookmarks SET
|
||||||
|
name = ?, link = ?, detail = ?, description = ?, updated_at = ?
|
||||||
|
WHERE id = ?
|
||||||
|
""";
|
||||||
|
|
||||||
|
try (Connection connection = DriverManager.getConnection(DB_URL);
|
||||||
|
PreparedStatement statement = connection.prepareStatement(sql)) {
|
||||||
|
|
||||||
|
statement.setString(1, bookmark.getName());
|
||||||
|
statement.setString(2, bookmark.getLink());
|
||||||
|
statement.setString(3, bookmark.getDetail());
|
||||||
|
statement.setString(4, bookmark.getDescription());
|
||||||
|
statement.setString(5, OffsetDateTime.now().toString());
|
||||||
|
statement.setLong(6, bookmark.getId());
|
||||||
|
|
||||||
|
int affectedRows = statement.executeUpdate();
|
||||||
|
return affectedRows > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean delete(Long id) throws SQLException {
|
||||||
|
String sql = "DELETE FROM bookmarks WHERE id = ?";
|
||||||
|
|
||||||
|
try (Connection connection = DriverManager.getConnection(DB_URL);
|
||||||
|
PreparedStatement statement = connection.prepareStatement(sql)) {
|
||||||
|
|
||||||
|
statement.setLong(1, id);
|
||||||
|
int affectedRows = statement.executeUpdate();
|
||||||
|
return affectedRows > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Bookmark mapResultSetToBookmark(ResultSet rs) throws SQLException {
|
||||||
|
Bookmark bookmark = new Bookmark();
|
||||||
|
bookmark.setId(rs.getLong("id"));
|
||||||
|
bookmark.setExternalId(rs.getLong("external_id"));
|
||||||
|
bookmark.setName(rs.getString("name"));
|
||||||
|
bookmark.setLink(rs.getString("link"));
|
||||||
|
bookmark.setDetail(rs.getString("detail"));
|
||||||
|
bookmark.setDescription(rs.getString("description"));
|
||||||
|
bookmark.setCreatedAt(OffsetDateTime.parse(rs.getString("created_at")));
|
||||||
|
bookmark.setUpdatedAt(OffsetDateTime.parse(rs.getString("updated_at")));
|
||||||
|
return bookmark;
|
||||||
|
}
|
||||||
|
}
|
||||||
96
src/main/java/com/zzyxyz/api/bookmarks/user_np/UserNP.java
Normal file
96
src/main/java/com/zzyxyz/api/bookmarks/user_np/UserNP.java
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
package com.zzyxyz.api.bookmarks.user_np;
|
||||||
|
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
|
|
||||||
|
public class UserNP {
|
||||||
|
private Long id;
|
||||||
|
private String username;
|
||||||
|
private String password;
|
||||||
|
private String email;
|
||||||
|
private String token;
|
||||||
|
private OffsetDateTime createdAt;
|
||||||
|
private OffsetDateTime updatedAt;
|
||||||
|
|
||||||
|
// Constructors
|
||||||
|
public UserNP() {
|
||||||
|
this.createdAt = OffsetDateTime.now();
|
||||||
|
this.updatedAt = OffsetDateTime.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserNP(String username, String password, String email) {
|
||||||
|
this.username = username;
|
||||||
|
this.password = password;
|
||||||
|
this.email = email;
|
||||||
|
this.createdAt = OffsetDateTime.now();
|
||||||
|
this.updatedAt = OffsetDateTime.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getters and Setters
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(String password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEmail() {
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEmail(String email) {
|
||||||
|
this.email = email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getToken() {
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setToken(String token) {
|
||||||
|
this.token = token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OffsetDateTime getCreatedAt() {
|
||||||
|
return createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreatedAt(OffsetDateTime createdAt) {
|
||||||
|
this.createdAt = createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OffsetDateTime getUpdatedAt() {
|
||||||
|
return updatedAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUpdatedAt(OffsetDateTime updatedAt) {
|
||||||
|
this.updatedAt = updatedAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hash password method (placeholder)
|
||||||
|
public void hashPassword(String rawPassword) {
|
||||||
|
// In a real implementation, you would use a proper password hashing library like BCrypt
|
||||||
|
this.password = rawPassword; // This is just a placeholder
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check password method (placeholder)
|
||||||
|
public boolean checkPassword(String rawPassword) {
|
||||||
|
// In a real implementation, you would use a proper password hashing library like BCrypt
|
||||||
|
return this.password.equals(rawPassword); // This is just a placeholder
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,142 @@
|
|||||||
|
package com.zzyxyz.api.bookmarks.user_np;
|
||||||
|
|
||||||
|
import org.openapitools.api.AuthApi;
|
||||||
|
import org.openapitools.api.DefaultApi;
|
||||||
|
import org.openapitools.model.*;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||||
|
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
@CrossOrigin(origins = "*")
|
||||||
|
public class UserNPController implements DefaultApi, AuthApi {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UserNPDAO userDAO;
|
||||||
|
|
||||||
|
// 初始化数据库表
|
||||||
|
public UserNPController() {
|
||||||
|
try {
|
||||||
|
userDAO = new UserNPDAO();
|
||||||
|
userDAO.createTableIfNotExists();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResponseEntity<Void> deleteUser(String username) {
|
||||||
|
try {
|
||||||
|
UserNP user = userDAO.findByUsername(username);
|
||||||
|
if (user == null) {
|
||||||
|
// 如果用户不存在,按照API规范返回200状态
|
||||||
|
return ResponseEntity.ok().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
userDAO.delete(user.getId());
|
||||||
|
return ResponseEntity.ok().build();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return ResponseEntity.status(500).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResponseEntity<Void> updatePassword(String username, ChangePasswordRequest changePasswordRequest) {
|
||||||
|
try {
|
||||||
|
UserNP user = userDAO.findByUsername(username);
|
||||||
|
if (user == null) {
|
||||||
|
return ResponseEntity.status(401).build(); // 认证失败
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证旧密码
|
||||||
|
if (!user.checkPassword(changePasswordRequest.getOldPassword())) {
|
||||||
|
return ResponseEntity.status(401).build(); // 认证失败
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新密码
|
||||||
|
user.hashPassword(changePasswordRequest.getNewPassword());
|
||||||
|
user.setUpdatedAt(OffsetDateTime.now());
|
||||||
|
userDAO.update(user);
|
||||||
|
|
||||||
|
return ResponseEntity.ok().build();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return ResponseEntity.status(500).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResponseEntity<LoginResponse> userLogin(String username, LoginRequest loginRequest) {
|
||||||
|
try {
|
||||||
|
UserNP user = userDAO.findByUsername(username);
|
||||||
|
if (user == null) {
|
||||||
|
return ResponseEntity.status(401).build(); // 认证失败
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证密码
|
||||||
|
if (!user.checkPassword(loginRequest.getPassword())) {
|
||||||
|
return ResponseEntity.status(401).build(); // 认证失败
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成token
|
||||||
|
String token = UUID.randomUUID().toString();
|
||||||
|
user.setToken(token);
|
||||||
|
user.setUpdatedAt(OffsetDateTime.now());
|
||||||
|
userDAO.update(user);
|
||||||
|
|
||||||
|
LoginResponse response = new LoginResponse();
|
||||||
|
response.setToken(token);
|
||||||
|
response.setUserId(user.getId());
|
||||||
|
|
||||||
|
return ResponseEntity.ok(response);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return ResponseEntity.status(500).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResponseEntity<Void> userRegister(String username, RegisterRequest registerRequest) {
|
||||||
|
try {
|
||||||
|
// 检查用户名是否已存在
|
||||||
|
UserNP existingUser = userDAO.findByUsername(username);
|
||||||
|
if (existingUser != null) {
|
||||||
|
return ResponseEntity.status(409).build(); // 用户名已存在
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建新用户
|
||||||
|
UserNP user = new UserNP(username, "", registerRequest.getEmail());
|
||||||
|
user.hashPassword(registerRequest.getPassword());
|
||||||
|
|
||||||
|
// 保存到数据库
|
||||||
|
UserNP savedUser = userDAO.insert(user);
|
||||||
|
|
||||||
|
if (savedUser.getId() != null) {
|
||||||
|
return ResponseEntity.status(201).build();
|
||||||
|
} else {
|
||||||
|
return ResponseEntity.status(500).build();
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return ResponseEntity.status(500).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResponseEntity<Object> getUserInfo(String username) {
|
||||||
|
// 未实现
|
||||||
|
return ResponseEntity.status(500).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResponseEntity<Void> saveUserInfo(String username, Object body) {
|
||||||
|
// 未实现
|
||||||
|
return ResponseEntity.status(500).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
166
src/main/java/com/zzyxyz/api/bookmarks/user_np/UserNPDAO.java
Normal file
166
src/main/java/com/zzyxyz/api/bookmarks/user_np/UserNPDAO.java
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
package com.zzyxyz.api.bookmarks.user_np;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import java.sql.*;
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class UserNPDAO {
|
||||||
|
private static final String DB_URL = "jdbc:sqlite:users.db";
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
Class.forName("org.sqlite.JDBC");
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void createTableIfNotExists() throws SQLException {
|
||||||
|
String sql = """
|
||||||
|
CREATE TABLE IF NOT EXISTS users (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
username TEXT NOT NULL UNIQUE,
|
||||||
|
password TEXT NOT NULL,
|
||||||
|
email TEXT,
|
||||||
|
token TEXT,
|
||||||
|
created_at TEXT NOT NULL,
|
||||||
|
updated_at TEXT NOT NULL
|
||||||
|
)
|
||||||
|
""";
|
||||||
|
|
||||||
|
try (Connection connection = DriverManager.getConnection(DB_URL);
|
||||||
|
Statement statement = connection.createStatement()) {
|
||||||
|
statement.executeUpdate(sql);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserNP insert(UserNP user) throws SQLException {
|
||||||
|
String sql = """
|
||||||
|
INSERT INTO users (
|
||||||
|
username, password, email, token, created_at, updated_at
|
||||||
|
) VALUES (?, ?, ?, ?, ?, ?)
|
||||||
|
""";
|
||||||
|
|
||||||
|
try (Connection connection = DriverManager.getConnection(DB_URL);
|
||||||
|
PreparedStatement statement = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
|
||||||
|
|
||||||
|
statement.setString(1, user.getUsername());
|
||||||
|
statement.setString(2, user.getPassword());
|
||||||
|
statement.setString(3, user.getEmail());
|
||||||
|
statement.setString(4, user.getToken());
|
||||||
|
statement.setString(5, user.getCreatedAt().toString());
|
||||||
|
statement.setString(6, user.getUpdatedAt().toString());
|
||||||
|
|
||||||
|
int affectedRows = statement.executeUpdate();
|
||||||
|
|
||||||
|
if (affectedRows == 0) {
|
||||||
|
throw new SQLException("Creating user failed, no rows affected.");
|
||||||
|
}
|
||||||
|
|
||||||
|
try (ResultSet generatedKeys = statement.getGeneratedKeys()) {
|
||||||
|
if (generatedKeys.next()) {
|
||||||
|
user.setId(generatedKeys.getLong(1));
|
||||||
|
} else {
|
||||||
|
throw new SQLException("Creating user failed, no ID obtained.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserNP findById(Long id) throws SQLException {
|
||||||
|
String sql = "SELECT * FROM users WHERE id = ?";
|
||||||
|
|
||||||
|
try (Connection connection = DriverManager.getConnection(DB_URL);
|
||||||
|
PreparedStatement statement = connection.prepareStatement(sql)) {
|
||||||
|
|
||||||
|
statement.setLong(1, id);
|
||||||
|
ResultSet rs = statement.executeQuery();
|
||||||
|
|
||||||
|
if (rs.next()) {
|
||||||
|
return mapResultSetToUser(rs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserNP findByUsername(String username) throws SQLException {
|
||||||
|
String sql = "SELECT * FROM users WHERE username = ?";
|
||||||
|
|
||||||
|
try (Connection connection = DriverManager.getConnection(DB_URL);
|
||||||
|
PreparedStatement statement = connection.prepareStatement(sql)) {
|
||||||
|
|
||||||
|
statement.setString(1, username);
|
||||||
|
ResultSet rs = statement.executeQuery();
|
||||||
|
|
||||||
|
if (rs.next()) {
|
||||||
|
return mapResultSetToUser(rs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<UserNP> findAll() throws SQLException {
|
||||||
|
String sql = "SELECT * FROM users";
|
||||||
|
List<UserNP> users = new ArrayList<>();
|
||||||
|
|
||||||
|
try (Connection connection = DriverManager.getConnection(DB_URL);
|
||||||
|
Statement statement = connection.createStatement();
|
||||||
|
ResultSet rs = statement.executeQuery(sql)) {
|
||||||
|
|
||||||
|
while (rs.next()) {
|
||||||
|
users.add(mapResultSetToUser(rs));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return users;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean update(UserNP user) throws SQLException {
|
||||||
|
String sql = """
|
||||||
|
UPDATE users SET
|
||||||
|
username = ?, password = ?, email = ?, token = ?, updated_at = ?
|
||||||
|
WHERE id = ?
|
||||||
|
""";
|
||||||
|
|
||||||
|
try (Connection connection = DriverManager.getConnection(DB_URL);
|
||||||
|
PreparedStatement statement = connection.prepareStatement(sql)) {
|
||||||
|
|
||||||
|
statement.setString(1, user.getUsername());
|
||||||
|
statement.setString(2, user.getPassword());
|
||||||
|
statement.setString(3, user.getEmail());
|
||||||
|
statement.setString(4, user.getToken());
|
||||||
|
statement.setString(5, OffsetDateTime.now().toString());
|
||||||
|
statement.setLong(6, user.getId());
|
||||||
|
|
||||||
|
int affectedRows = statement.executeUpdate();
|
||||||
|
return affectedRows > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean delete(Long id) throws SQLException {
|
||||||
|
String sql = "DELETE FROM users WHERE id = ?";
|
||||||
|
|
||||||
|
try (Connection connection = DriverManager.getConnection(DB_URL);
|
||||||
|
PreparedStatement statement = connection.prepareStatement(sql)) {
|
||||||
|
|
||||||
|
statement.setLong(1, id);
|
||||||
|
int affectedRows = statement.executeUpdate();
|
||||||
|
return affectedRows > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private UserNP mapResultSetToUser(ResultSet rs) throws SQLException {
|
||||||
|
UserNP user = new UserNP();
|
||||||
|
user.setId(rs.getLong("id"));
|
||||||
|
user.setUsername(rs.getString("username"));
|
||||||
|
user.setPassword(rs.getString("password"));
|
||||||
|
user.setEmail(rs.getString("email"));
|
||||||
|
user.setToken(rs.getString("token"));
|
||||||
|
user.setCreatedAt(OffsetDateTime.parse(rs.getString("created_at")));
|
||||||
|
user.setUpdatedAt(OffsetDateTime.parse(rs.getString("updated_at")));
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1 +1,3 @@
|
|||||||
spring.application.name=bookmarks
|
spring.application.name=bookmarks
|
||||||
|
server.port=8081
|
||||||
|
server.servlet.context-path=/api
|
||||||
|
|||||||
238
src/main/resources/config/bookmark/bookmark.yaml
Normal file
238
src/main/resources/config/bookmark/bookmark.yaml
Normal file
@ -0,0 +1,238 @@
|
|||||||
|
openapi: '3.0.3'
|
||||||
|
info:
|
||||||
|
title: zzyxyz_bookmark_api
|
||||||
|
description: bookmark API服务
|
||||||
|
version: '1.0'
|
||||||
|
servers:
|
||||||
|
- url: http://localhost:8081/api
|
||||||
|
description: 开发环境
|
||||||
|
- url: https://api.zzyxyz.com/api
|
||||||
|
description: 生产环境
|
||||||
|
tags:
|
||||||
|
- name: data
|
||||||
|
description: 书签相关操作
|
||||||
|
security:
|
||||||
|
- ApiKeyAuth: []
|
||||||
|
|
||||||
|
paths:
|
||||||
|
/bookmarks/v1/data/{id}:
|
||||||
|
parameters:
|
||||||
|
- name: id
|
||||||
|
in: path
|
||||||
|
example: 1
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
|
||||||
|
post:
|
||||||
|
summary: 创建书签
|
||||||
|
description: 在文件夹下创建一个书签
|
||||||
|
operationId: createBookmark
|
||||||
|
tags: [data]
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/BookmarkRequest'
|
||||||
|
responses:
|
||||||
|
'201':
|
||||||
|
description: 创建成功的书签
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/BookmarkResponse'
|
||||||
|
'400':
|
||||||
|
description: 请求参数错误
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Error'
|
||||||
|
'401':
|
||||||
|
$ref: '#/components/responses/Unauthorized'
|
||||||
|
'403':
|
||||||
|
$ref: '#/components/responses/Forbidden'
|
||||||
|
'500':
|
||||||
|
$ref: '#/components/responses/ServerInternalError'
|
||||||
|
|
||||||
|
get:
|
||||||
|
summary: 获取书签详情
|
||||||
|
description: 通过id获取书签内容
|
||||||
|
operationId: getBookmark
|
||||||
|
tags: [data]
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: 书签详情
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/BookmarkResponse'
|
||||||
|
'404':
|
||||||
|
description: 书签不存在
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Error'
|
||||||
|
'401':
|
||||||
|
$ref: '#/components/responses/Unauthorized'
|
||||||
|
'403':
|
||||||
|
$ref: '#/components/responses/Forbidden'
|
||||||
|
'500':
|
||||||
|
$ref: '#/components/responses/ServerInternalError'
|
||||||
|
|
||||||
|
put:
|
||||||
|
summary: 更新书签
|
||||||
|
description: 更新指定id的书签
|
||||||
|
operationId: updateBookmark
|
||||||
|
tags: [data]
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/BookmarkRequest'
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: 更新后的书签
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/BookmarkResponse'
|
||||||
|
'400':
|
||||||
|
description: 请求参数错误
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Error'
|
||||||
|
'404':
|
||||||
|
description: 书签不存在
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Error'
|
||||||
|
'401':
|
||||||
|
$ref: '#/components/responses/Unauthorized'
|
||||||
|
'403':
|
||||||
|
$ref: '#/components/responses/Forbidden'
|
||||||
|
'500':
|
||||||
|
$ref: '#/components/responses/ServerInternalError'
|
||||||
|
|
||||||
|
delete:
|
||||||
|
summary: 删除书签
|
||||||
|
description: 删除指定id的书签
|
||||||
|
operationId: deleteBookmark
|
||||||
|
tags: [data]
|
||||||
|
responses:
|
||||||
|
'204':
|
||||||
|
description: 删除成功
|
||||||
|
'404':
|
||||||
|
description: 书签不存在
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Error'
|
||||||
|
'401':
|
||||||
|
$ref: '#/components/responses/Unauthorized'
|
||||||
|
'403':
|
||||||
|
$ref: '#/components/responses/Forbidden'
|
||||||
|
'500':
|
||||||
|
$ref: '#/components/responses/ServerInternalError'
|
||||||
|
|
||||||
|
components:
|
||||||
|
securitySchemes:
|
||||||
|
ApiKeyAuth:
|
||||||
|
type: apiKey
|
||||||
|
in: header
|
||||||
|
name: X-BookMark-Token
|
||||||
|
responses:
|
||||||
|
ServerInternalError:
|
||||||
|
description: 服务器内部错误
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Error'
|
||||||
|
Unauthorized:
|
||||||
|
description: 未授权
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Error'
|
||||||
|
Forbidden:
|
||||||
|
description: 无权限
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Error'
|
||||||
|
schemas:
|
||||||
|
BookmarkRequest:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
minLength: 1
|
||||||
|
maxLength: 255
|
||||||
|
description: 书签名称
|
||||||
|
example: 测试名称
|
||||||
|
link:
|
||||||
|
type: string
|
||||||
|
description: 书签链接
|
||||||
|
example: /swagger/index.html
|
||||||
|
detail:
|
||||||
|
type: string
|
||||||
|
description: 书签详情链接
|
||||||
|
description:
|
||||||
|
type: string
|
||||||
|
description: 书签描述
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
|
||||||
|
BookmarkResponse:
|
||||||
|
type: object
|
||||||
|
description: 书签相应结构体
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
description: 书签ID
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
description: 书签名称
|
||||||
|
link:
|
||||||
|
type: string
|
||||||
|
description: 书签链接
|
||||||
|
detail:
|
||||||
|
type: string
|
||||||
|
description: 书签详情链接
|
||||||
|
description:
|
||||||
|
type: string
|
||||||
|
description: 书签描述
|
||||||
|
created_at:
|
||||||
|
type: string
|
||||||
|
format: date-time
|
||||||
|
description: 创建时间
|
||||||
|
updated_at:
|
||||||
|
type: string
|
||||||
|
format: date-time
|
||||||
|
description: 更新时间
|
||||||
|
required:
|
||||||
|
- id
|
||||||
|
- name
|
||||||
|
- created_at
|
||||||
|
- updated_at
|
||||||
|
|
||||||
|
Error:
|
||||||
|
type: object
|
||||||
|
description: 错误信息
|
||||||
|
properties:
|
||||||
|
errtype:
|
||||||
|
type: string
|
||||||
|
example: "ParameterError"
|
||||||
|
description: 错误类型
|
||||||
|
message:
|
||||||
|
example: "传递的第一个参数错误"
|
||||||
|
type: string
|
||||||
|
description: 错误信息
|
||||||
|
required:
|
||||||
|
- errtype
|
||||||
|
- message
|
||||||
6
src/main/resources/config/bookmark/client.yaml
Normal file
6
src/main/resources/config/bookmark/client.yaml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# yaml-language-server: ...
|
||||||
|
package: client
|
||||||
|
generate:
|
||||||
|
client: true
|
||||||
|
models: true
|
||||||
|
output: ./gen/bookmarks_client/client.go
|
||||||
7
src/main/resources/config/bookmark/server.yaml
Normal file
7
src/main/resources/config/bookmark/server.yaml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# yaml-language-server: ...
|
||||||
|
package: server
|
||||||
|
generate:
|
||||||
|
gin-server: true
|
||||||
|
models: true
|
||||||
|
strict-server: true
|
||||||
|
output: ./gen/bookmarks_server/server.go
|
||||||
7
src/main/resources/config/user_np/server.yaml
Normal file
7
src/main/resources/config/user_np/server.yaml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# yaml-language-server: ...
|
||||||
|
package: server
|
||||||
|
generate:
|
||||||
|
gin-server: true
|
||||||
|
models: true
|
||||||
|
strict-server: true
|
||||||
|
output: ./gen/user_np_server/server.go
|
||||||
210
src/main/resources/config/user_np/user_np.yaml
Normal file
210
src/main/resources/config/user_np/user_np.yaml
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
openapi: '3.0.3'
|
||||||
|
info:
|
||||||
|
title: zzyxyz_user_np_api
|
||||||
|
description: 用户节点权限相关操作(user_name and password)
|
||||||
|
version: '1.0'
|
||||||
|
servers:
|
||||||
|
- url: http://localhost:8081/api
|
||||||
|
description: 开发环境
|
||||||
|
- url: https://api.zzyxyz.com/api
|
||||||
|
description: 生产环境
|
||||||
|
security:
|
||||||
|
- ApiKeyAuth: []
|
||||||
|
|
||||||
|
paths:
|
||||||
|
/auth/user/{username}/login:
|
||||||
|
parameters:
|
||||||
|
- name: username
|
||||||
|
in: path
|
||||||
|
example: user_name
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
post:
|
||||||
|
summary: 用户登录
|
||||||
|
description: 使用用户名和密码进行登录
|
||||||
|
operationId: UserLogin
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/LoginRequest'
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: 登录成功
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/LoginResponse'
|
||||||
|
'400':
|
||||||
|
description: 请求参数错误
|
||||||
|
'401':
|
||||||
|
description: 认证失败
|
||||||
|
|
||||||
|
/auth/user/{username}:
|
||||||
|
parameters:
|
||||||
|
- name: username
|
||||||
|
in: path
|
||||||
|
example: user_name
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
|
||||||
|
post:
|
||||||
|
summary: 用户注册
|
||||||
|
description: 创建新用户账户
|
||||||
|
operationId: UserRegister
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/RegisterRequest'
|
||||||
|
responses:
|
||||||
|
'201':
|
||||||
|
description: 注册成功
|
||||||
|
'400':
|
||||||
|
description: 请求参数错误
|
||||||
|
'409':
|
||||||
|
description: 用户名已存在
|
||||||
|
|
||||||
|
patch:
|
||||||
|
summary: 修改密码
|
||||||
|
description: 修改已登录用户的密码
|
||||||
|
operationId: updatePassword
|
||||||
|
security:
|
||||||
|
- ApiKeyAuth: []
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/ChangePasswordRequest'
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: 密码修改成功
|
||||||
|
'400':
|
||||||
|
description: 请求参数错误
|
||||||
|
'401':
|
||||||
|
description: 认证失败
|
||||||
|
|
||||||
|
delete:
|
||||||
|
summary: 删除用户
|
||||||
|
description: 删除用户
|
||||||
|
operationId: deleteUser
|
||||||
|
security:
|
||||||
|
- ApiKeyAuth: []
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: 用户注销成功
|
||||||
|
'401':
|
||||||
|
description: 认证失败
|
||||||
|
|
||||||
|
/auth/user/{username}/info:
|
||||||
|
parameters:
|
||||||
|
- name: username
|
||||||
|
in: path
|
||||||
|
example: user_name
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
get:
|
||||||
|
summary: 获取用户信息
|
||||||
|
description: 获取用户信息 json object
|
||||||
|
operationId: getUserInfo
|
||||||
|
tags: [auth]
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: 用户信息
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
'500':
|
||||||
|
$ref: '#/components/responses/ServerInternalError'
|
||||||
|
put:
|
||||||
|
summary: 保存用户信息
|
||||||
|
description: 保存用户信息 json object
|
||||||
|
operationId: saveUserInfo
|
||||||
|
tags: [auth]
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: 保存成功
|
||||||
|
'500':
|
||||||
|
$ref: '#/components/responses/ServerInternalError'
|
||||||
|
|
||||||
|
components:
|
||||||
|
responses:
|
||||||
|
ServerInternalError:
|
||||||
|
description: 服务器内部错误
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Error'
|
||||||
|
schemas:
|
||||||
|
LoginRequest:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- password
|
||||||
|
properties:
|
||||||
|
password:
|
||||||
|
type: string
|
||||||
|
|
||||||
|
LoginResponse:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
token:
|
||||||
|
type: string
|
||||||
|
user_id:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
|
||||||
|
RegisterRequest:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- password
|
||||||
|
properties:
|
||||||
|
password:
|
||||||
|
type: string
|
||||||
|
email:
|
||||||
|
type: string
|
||||||
|
|
||||||
|
ChangePasswordRequest:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- old_password
|
||||||
|
- new_password
|
||||||
|
properties:
|
||||||
|
old_password:
|
||||||
|
type: string
|
||||||
|
new_password:
|
||||||
|
type: string
|
||||||
|
|
||||||
|
Error:
|
||||||
|
type: object
|
||||||
|
description: 错误信息
|
||||||
|
properties:
|
||||||
|
errtype:
|
||||||
|
type: string
|
||||||
|
example: "ParameterError"
|
||||||
|
description: 错误类型
|
||||||
|
message:
|
||||||
|
example: "传递的第一个参数错误"
|
||||||
|
type: string
|
||||||
|
description: 错误信息
|
||||||
|
required:
|
||||||
|
- errtype
|
||||||
|
- message
|
||||||
|
|
||||||
|
securitySchemes:
|
||||||
|
ApiKeyAuth:
|
||||||
|
type: apiKey
|
||||||
|
in: header
|
||||||
|
name: Authorization
|
||||||
6
src/main/resources/config/vfs/client.yaml
Normal file
6
src/main/resources/config/vfs/client.yaml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# yaml-language-server: ...
|
||||||
|
package: client
|
||||||
|
generate:
|
||||||
|
client: true
|
||||||
|
models: true
|
||||||
|
output: ./gen/vfs_client/client.go
|
||||||
7
src/main/resources/config/vfs/server.yaml
Normal file
7
src/main/resources/config/vfs/server.yaml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# yaml-language-server: ...
|
||||||
|
package: server
|
||||||
|
generate:
|
||||||
|
gin-server: true
|
||||||
|
models: true
|
||||||
|
strict-server: true
|
||||||
|
output: ./gen/vfs_server/server.go
|
||||||
375
src/main/resources/config/vfs/vfs.yaml
Normal file
375
src/main/resources/config/vfs/vfs.yaml
Normal file
@ -0,0 +1,375 @@
|
|||||||
|
openapi: '3.0.3'
|
||||||
|
info:
|
||||||
|
title: zzyxyz_vfs_api
|
||||||
|
description: 虚拟文件系统API服务
|
||||||
|
version: '1.0'
|
||||||
|
servers:
|
||||||
|
- url: http://localhost:8080/api
|
||||||
|
description: 开发环境
|
||||||
|
- url: https://api.zzyxyz.com/api
|
||||||
|
description: 生产环境
|
||||||
|
tags:
|
||||||
|
- name: vfs
|
||||||
|
description: 虚拟文件系统相关操作
|
||||||
|
- name: user
|
||||||
|
description: 用户相关操作
|
||||||
|
security:
|
||||||
|
- ApiKeyAuth: []
|
||||||
|
|
||||||
|
paths:
|
||||||
|
/vfs/v1/users/{username}:
|
||||||
|
parameters:
|
||||||
|
- name: username
|
||||||
|
in: path
|
||||||
|
example: user
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
|
||||||
|
post:
|
||||||
|
summary: 创建用户
|
||||||
|
description: 创建一个用户
|
||||||
|
operationId: createUser
|
||||||
|
tags: [user]
|
||||||
|
responses:
|
||||||
|
'201':
|
||||||
|
description: 创建成功
|
||||||
|
headers:
|
||||||
|
X-VFS-Token:
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
description: 认证令牌
|
||||||
|
'400':
|
||||||
|
$ref: '#/components/responses/ParameterError'
|
||||||
|
'401':
|
||||||
|
$ref: '#/components/responses/UnauthorizedError'
|
||||||
|
'403':
|
||||||
|
$ref: '#/components/responses/ForbiddenError'
|
||||||
|
'500':
|
||||||
|
$ref: '#/components/responses/ServerInternalError'
|
||||||
|
|
||||||
|
delete:
|
||||||
|
summary: 删除用户
|
||||||
|
description: 删除一个用户
|
||||||
|
operationId: deleteUser
|
||||||
|
tags: [user]
|
||||||
|
responses:
|
||||||
|
'204':
|
||||||
|
description: 删除成功
|
||||||
|
'404':
|
||||||
|
description: 用户不存在
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Error'
|
||||||
|
'400':
|
||||||
|
$ref: '#/components/responses/ParameterError'
|
||||||
|
'401':
|
||||||
|
$ref: '#/components/responses/UnauthorizedError'
|
||||||
|
'403':
|
||||||
|
$ref: '#/components/responses/ForbiddenError'
|
||||||
|
'500':
|
||||||
|
$ref: '#/components/responses/ServerInternalError'
|
||||||
|
|
||||||
|
/vfs/v1/files:
|
||||||
|
parameters:
|
||||||
|
- name: path
|
||||||
|
in: query
|
||||||
|
required: true
|
||||||
|
description: |
|
||||||
|
文件系统路径,例如:
|
||||||
|
- "/documents/readme.txt" (文件路径)
|
||||||
|
- "/services/sql.bk.api" (服务文件)
|
||||||
|
- "/folder/" (目录路径,以/结尾)
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
example: "/documents/readme.txt"
|
||||||
|
|
||||||
|
get:
|
||||||
|
summary: 读取文件或列出目录
|
||||||
|
description: 获取指定路径的文件内容或目录列表
|
||||||
|
operationId: getVFSNode
|
||||||
|
tags: [vfs]
|
||||||
|
parameters:
|
||||||
|
- name: op
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
description: 操作类型, list表示列出目录内容, 不指定则读取文件内容
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
enum: [list]
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: 文件内容或目录列表
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
description: 目录条目列表
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/VFSDirectoryEntry'
|
||||||
|
text/plain:
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
'400':
|
||||||
|
$ref: '#/components/responses/ParameterError'
|
||||||
|
'401':
|
||||||
|
$ref: '#/components/responses/UnauthorizedError'
|
||||||
|
'403':
|
||||||
|
$ref: '#/components/responses/ForbiddenError'
|
||||||
|
'404':
|
||||||
|
$ref: '#/components/responses/PathNotFoundError'
|
||||||
|
'500':
|
||||||
|
$ref: '#/components/responses/ServerInternalError'
|
||||||
|
|
||||||
|
post:
|
||||||
|
summary: 创建文件或目录
|
||||||
|
description: 创建文件或目录
|
||||||
|
operationId: createVFSNode
|
||||||
|
tags: [vfs]
|
||||||
|
requestBody:
|
||||||
|
required: false
|
||||||
|
content:
|
||||||
|
text/plain:
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
description: 文件内容, 或者服务内容
|
||||||
|
responses:
|
||||||
|
'201':
|
||||||
|
description: 创建成功
|
||||||
|
content:
|
||||||
|
text/plain:
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/VFSNodeResponse'
|
||||||
|
'400':
|
||||||
|
$ref: '#/components/responses/ParameterError'
|
||||||
|
'401':
|
||||||
|
$ref: '#/components/responses/UnauthorizedError'
|
||||||
|
'403':
|
||||||
|
$ref: '#/components/responses/ForbiddenError'
|
||||||
|
'404':
|
||||||
|
$ref: '#/components/responses/PathNotFoundError'
|
||||||
|
'500':
|
||||||
|
$ref: '#/components/responses/ServerInternalError'
|
||||||
|
|
||||||
|
patch:
|
||||||
|
summary: 修改文件或修改目录
|
||||||
|
description: 修改/移动/重命名/复制 已存在的 文件/目录
|
||||||
|
operationId: updateVFSNode
|
||||||
|
tags: [vfs]
|
||||||
|
parameters:
|
||||||
|
- name: op
|
||||||
|
in: query
|
||||||
|
description: |
|
||||||
|
更新操作模式:
|
||||||
|
- move: 移动文件或目录到新位置
|
||||||
|
- rename: 重命名文件或目录
|
||||||
|
- change: 修改文件内容或目录属性
|
||||||
|
- copy: 复制文件或目录到新位置
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
enum: [move, rename, change, copy]
|
||||||
|
example: "rename"
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
description: 目的文件夹路径 / 文件名路径
|
||||||
|
example: "/home/"
|
||||||
|
text/plain:
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: 操作成功
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/VFSNodeResponse'
|
||||||
|
'400':
|
||||||
|
$ref: '#/components/responses/ParameterError'
|
||||||
|
'401':
|
||||||
|
$ref: '#/components/responses/UnauthorizedError'
|
||||||
|
'403':
|
||||||
|
$ref: '#/components/responses/ForbiddenError'
|
||||||
|
'404':
|
||||||
|
$ref: '#/components/responses/PathNotFoundError'
|
||||||
|
'500':
|
||||||
|
$ref: '#/components/responses/ServerInternalError'
|
||||||
|
|
||||||
|
delete:
|
||||||
|
summary: 删除文件或目录
|
||||||
|
description: 删除指定路径的文件或目录
|
||||||
|
operationId: deleteVFSNode
|
||||||
|
tags: [vfs]
|
||||||
|
parameters:
|
||||||
|
- name: op
|
||||||
|
in: query
|
||||||
|
description: |
|
||||||
|
删除操作模式:
|
||||||
|
- recursive: 递归删除目录及其所有内容
|
||||||
|
- force: 强制删除,忽略只读等保护属性
|
||||||
|
不指定时执行普通删除操作
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
enum: [recursive, force]
|
||||||
|
example: "recursive"
|
||||||
|
responses:
|
||||||
|
'204':
|
||||||
|
description: 删除成功
|
||||||
|
'400':
|
||||||
|
$ref: '#/components/responses/ParameterError'
|
||||||
|
'401':
|
||||||
|
$ref: '#/components/responses/UnauthorizedError'
|
||||||
|
'403':
|
||||||
|
$ref: '#/components/responses/ForbiddenError'
|
||||||
|
'404':
|
||||||
|
$ref: '#/components/responses/PathNotFoundError'
|
||||||
|
'500':
|
||||||
|
$ref: '#/components/responses/ServerInternalError'
|
||||||
|
|
||||||
|
components:
|
||||||
|
securitySchemes:
|
||||||
|
ApiKeyAuth:
|
||||||
|
type: apiKey
|
||||||
|
in: header
|
||||||
|
name: X-VFS-Token
|
||||||
|
|
||||||
|
responses:
|
||||||
|
ServerInternalError:
|
||||||
|
description: 服务器内部错误
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Error'
|
||||||
|
example:
|
||||||
|
errtype: "InternalServerError"
|
||||||
|
message: "服务器内部错误"
|
||||||
|
|
||||||
|
UnauthorizedError:
|
||||||
|
description: 未授权
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Error'
|
||||||
|
example:
|
||||||
|
errtype: "Unauthorized"
|
||||||
|
message: "访问被拒绝,缺少有效的认证令牌"
|
||||||
|
|
||||||
|
ForbiddenError:
|
||||||
|
description: 禁止
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Error'
|
||||||
|
example:
|
||||||
|
errtype: "Forbidden"
|
||||||
|
message: "访问被拒绝,您没有权限访问此资源"
|
||||||
|
|
||||||
|
PathNotFoundError:
|
||||||
|
description: 路径不存在
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Error'
|
||||||
|
example:
|
||||||
|
errtype: "PathNotFound"
|
||||||
|
message: "指定的路径不存在"
|
||||||
|
|
||||||
|
ParameterError:
|
||||||
|
description: 请求参数错误
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Error'
|
||||||
|
example:
|
||||||
|
errtype: "ParameterError"
|
||||||
|
message: "请求参数无效或缺失"
|
||||||
|
|
||||||
|
schemas:
|
||||||
|
VFSNodeType:
|
||||||
|
type: string
|
||||||
|
description: 节点类型
|
||||||
|
enum: [file, directory, service]
|
||||||
|
|
||||||
|
VFSNodeResponse:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
description: 节点名称
|
||||||
|
type:
|
||||||
|
$ref: '#/components/schemas/VFSNodeType'
|
||||||
|
created_at:
|
||||||
|
type: string
|
||||||
|
format: date-time
|
||||||
|
description: 创建时间
|
||||||
|
updated_at:
|
||||||
|
type: string
|
||||||
|
format: date-time
|
||||||
|
description: 更新时间
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
- type
|
||||||
|
- created_at
|
||||||
|
- updated_at
|
||||||
|
|
||||||
|
VFSDirectoryEntry:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
description: 条目名称
|
||||||
|
type:
|
||||||
|
$ref: '#/components/schemas/VFSNodeType'
|
||||||
|
permissions:
|
||||||
|
type: string
|
||||||
|
description: 权限信息,如 "rwo" (读 写 拥有)
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
- type
|
||||||
|
|
||||||
|
Error:
|
||||||
|
type: object
|
||||||
|
description: 错误信息
|
||||||
|
properties:
|
||||||
|
errtype:
|
||||||
|
type: string
|
||||||
|
description: |
|
||||||
|
错误类型,可能的值包括:
|
||||||
|
- "InternalServerError": 服务器内部错误
|
||||||
|
- "Unauthorized": 客户端需要提供正确格式权限
|
||||||
|
- "Forbidden": 无权限访问
|
||||||
|
- "PathNotFound": 路径不存在
|
||||||
|
- "ParameterError": 请求参数错误
|
||||||
|
- "ConflictError": 资源冲突
|
||||||
|
- "DatabaseError": 数据库操作错误
|
||||||
|
- "NotFoundError": 资源未找到
|
||||||
|
- "AccessDenied": 访问被拒绝
|
||||||
|
- "ServiceProxyError": 代理服务错误
|
||||||
|
example: "InternalServerError"
|
||||||
|
enum:
|
||||||
|
- "InternalServerError"
|
||||||
|
- "Unauthorized"
|
||||||
|
- "Forbidden"
|
||||||
|
- "PathNotFound"
|
||||||
|
- "ParameterError"
|
||||||
|
- "ConflictError"
|
||||||
|
- "DatabaseError"
|
||||||
|
- "NotFoundError"
|
||||||
|
- "AccessDenied"
|
||||||
|
- "ServiceProxyError"
|
||||||
|
message:
|
||||||
|
type: string
|
||||||
|
description: 详细的错误信息
|
||||||
|
example: "传递的第一个参数错误"
|
||||||
|
required:
|
||||||
|
- errtype
|
||||||
|
- message
|
||||||
Reference in New Issue
Block a user