diff --git a/pom.xml b/pom.xml
index 1e1984e..51f74d8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -40,6 +40,26 @@
spring-boot-starter-test
test
+
+
+
+
+ org.xerial
+ sqlite-jdbc
+ 3.50.3.0
+
+
+
+ io.swagger.parser.v3
+ swagger-parser-v3
+ 2.1.34
+
+
+
+ io.swagger.parser.v3
+ swagger-parser-core
+ 2.1.34
+
@@ -48,6 +68,78 @@
org.springframework.boot
spring-boot-maven-plugin
+
+
+ org.openapitools
+ openapi-generator-maven-plugin
+ 7.15.0
+
+
+ bookmark-api
+
+ generate
+
+
+ ${project.basedir}/src/main/resources/config/bookmark/bookmark.yaml
+ spring
+
+ src/gen/java/main
+ false
+ true
+ true
+ true
+ true
+ true
+ true
+ false
+
+
+
+
+ user-np-api
+
+ generate
+
+
+ ${project.basedir}/src/main/resources/config/user_np/user_np.yaml
+ spring
+
+ src/gen/java/main
+ false
+ true
+ true
+ true
+ true
+ true
+ true
+ false
+
+
+
+
+
+
diff --git a/src/main/java/com/zzyxyz/api/bookmarks/BookmarksApplication.java b/src/main/java/com/zzyxyz/api/bookmarks/BookmarksApplication.java
index 2272ef0..842291e 100644
--- a/src/main/java/com/zzyxyz/api/bookmarks/BookmarksApplication.java
+++ b/src/main/java/com/zzyxyz/api/bookmarks/BookmarksApplication.java
@@ -2,12 +2,23 @@ package com.zzyxyz.api.bookmarks;
import org.springframework.boot.SpringApplication;
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
+@RestController
+@ComponentScan(basePackages = {"com.zzyxyz.api.bookmarks", "org.openapitools"})
public class BookmarksApplication {
public static void main(String[] args) {
SpringApplication.run(BookmarksApplication.class, args);
}
+ @GetMapping("/hello")
+ public String hello(@RequestParam(value = "name", defaultValue = "World") String name) {
+ return String.format("Hello %s!", name);
+ }
+
}
diff --git a/src/main/java/com/zzyxyz/api/bookmarks/CorsConfig.java b/src/main/java/com/zzyxyz/api/bookmarks/CorsConfig.java
new file mode 100644
index 0000000..43e226f
--- /dev/null
+++ b/src/main/java/com/zzyxyz/api/bookmarks/CorsConfig.java
@@ -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);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/zzyxyz/api/bookmarks/bookmark/Bookmark.java b/src/main/java/com/zzyxyz/api/bookmarks/bookmark/Bookmark.java
new file mode 100644
index 0000000..670f915
--- /dev/null
+++ b/src/main/java/com/zzyxyz/api/bookmarks/bookmark/Bookmark.java
@@ -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;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/zzyxyz/api/bookmarks/bookmark/BookmarkController.java b/src/main/java/com/zzyxyz/api/bookmarks/bookmark/BookmarkController.java
new file mode 100644
index 0000000..0897064
--- /dev/null
+++ b/src/main/java/com/zzyxyz/api/bookmarks/bookmark/BookmarkController.java
@@ -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 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 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 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 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());
+ }
+}
diff --git a/src/main/java/com/zzyxyz/api/bookmarks/bookmark/BookmarkDAO.java b/src/main/java/com/zzyxyz/api/bookmarks/bookmark/BookmarkDAO.java
new file mode 100644
index 0000000..36d0d99
--- /dev/null
+++ b/src/main/java/com/zzyxyz/api/bookmarks/bookmark/BookmarkDAO.java
@@ -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 findAll() throws SQLException {
+ String sql = "SELECT * FROM bookmarks";
+ List 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;
+ }
+}
diff --git a/src/main/java/com/zzyxyz/api/bookmarks/user_np/UserNP.java b/src/main/java/com/zzyxyz/api/bookmarks/user_np/UserNP.java
new file mode 100644
index 0000000..ed473f9
--- /dev/null
+++ b/src/main/java/com/zzyxyz/api/bookmarks/user_np/UserNP.java
@@ -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
+ }
+}
diff --git a/src/main/java/com/zzyxyz/api/bookmarks/user_np/UserNPController.java b/src/main/java/com/zzyxyz/api/bookmarks/user_np/UserNPController.java
new file mode 100644
index 0000000..57343ba
--- /dev/null
+++ b/src/main/java/com/zzyxyz/api/bookmarks/user_np/UserNPController.java
@@ -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 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 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 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 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