diff --git a/.cursorrules b/.cursorrules new file mode 100644 index 0000000..06a625d --- /dev/null +++ b/.cursorrules @@ -0,0 +1,62 @@ +# 项目规则文档 + +## 1. 日志查看规则 +- 不允许使用 `tail -f` 命令查看日志文件 +- 应该使用 `tail` 命令查看日志内容 +- 查看日志直接查看项目本身的日志,而非tomcat的日志 + +## 2. 项目结构规则 +- 后端项目目录:`backend/` +- 前端项目目录:`frontend/` +- 数据库脚本目录:`database/` +- 文档目录:`doc/` + +## 3. 构建和部署规则 +- 使用 Maven 构建后端项目:`mvn clean package -DskipTests` +- Tomcat 运行在 Docker 容器中: + - 端口映射:18080 + - 数据目录:`$DOCKER_DATA_DIR/tomcat` + - 日志目录:`$DOCKER_DATA_DIR/tomcat/logs` + - WAR包目录:`$DOCKER_DATA_DIR/tomcat/webapps` +- 应用上下文路径:`/llm-survey-api` +- 复制文件时,使用 `command cp` 命令 + +## 4. 数据库规则 +- 数据库名称:`llm_survey` +- 数据库用户:`dev` +- 数据库地址:`127.0.0.1:3306` +- 使用 `init_database.sh` 脚本初始化数据库 + +## 5. 代码规范 +- Java源代码使用UTF-8编码 +- 使用Lombok简化代码 +- DAO层继承BaseDao接口 +- Service层继承BaseService接口 +- 控制器使用RestController注解 + +## 6. Spring配置规则 +- 共享的bean定义放在 `applicationContext.xml` +- MVC相关配置放在 `spring-mvc.xml` +- MyBatis相关配置放在 `spring-mybatis.xml` +- 避免重复的bean定义 + +## 7. 错误处理规则 +- 使用统一的错误处理格式(ErrorInfo) +- 所有异常由GlobalExceptionHandler处理 +- 业务异常使用IllegalArgumentException + +## 8. API规范 +- RESTful API设计 +- 统一的响应格式 +- 支持跨域访问 +- API文档位于 `doc/api.md` + +## 9. 安全规则 +- 不在代码中硬编码敏感信息 +- 配置信息放在properties文件中 +- 使用prepared statement防止SQL注入 + +## 10. 版本控制 +- 使用Git进行版本控制 +- 遵循语义化版本规范 +- 重要配置文件加入版本控制 \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..af3535d --- /dev/null +++ b/.gitignore @@ -0,0 +1,36 @@ +# Maven +target/ +*.war +*.jar +*.ear +.classpath +.project +.settings/ + +# Node.js +node_modules/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* +dist/ +.cache/ + +# IDE - VSCode +.vscode/ +*.code-workspace +.history/ + +# IDE - IntelliJ IDEA +.idea/ +*.iml +*.iws +*.ipr + +# Logs +logs/ +*.log + +# OS +.DS_Store +Thumbs.db \ No newline at end of file diff --git a/backend/pom.xml b/backend/pom.xml index f7deefc..1405523 100644 --- a/backend/pom.xml +++ b/backend/pom.xml @@ -14,16 +14,18 @@ ${java.version} ${java.version} UTF-8 - 5.3.31 + 6.1.4 3.5.15 - 2.1.2 + 3.0.3 8.3.0 5.1.0 2.16.1 1.18.30 2.0.11 1.4.14 - 4.0.1 + 6.0.0 + 5.3.3 + 1.9.21 @@ -82,6 +84,13 @@ ${jackson.version} + + + com.github.pagehelper + pagehelper + ${pagehelper.version} + + org.projectlombok @@ -104,11 +113,18 @@ - javax.servlet - javax.servlet-api + jakarta.servlet + jakarta.servlet-api ${servlet-api.version} provided + + + + org.aspectj + aspectjweaver + ${aspectj.version} + @@ -122,6 +138,9 @@ ${java.version} ${project.build.sourceEncoding} + + -parameters + org.projectlombok diff --git a/backend/src/main/java/com/fasterxml/jackson/databind/JsonTypeHandler.java b/backend/src/main/java/com/fasterxml/jackson/databind/JsonTypeHandler.java new file mode 100644 index 0000000..b7ceb08 --- /dev/null +++ b/backend/src/main/java/com/fasterxml/jackson/databind/JsonTypeHandler.java @@ -0,0 +1,51 @@ +package com.fasterxml.jackson.databind; + +import java.sql.CallableStatement; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import org.apache.ibatis.type.BaseTypeHandler; +import org.apache.ibatis.type.JdbcType; + +/** + * 自定义的 JSON 类型处理器 + */ +public class JsonTypeHandler extends BaseTypeHandler { + private static final ObjectMapper MAPPER = new ObjectMapper(); + + @Override + public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) + throws SQLException { + try { + ps.setString(i, MAPPER.writeValueAsString(parameter)); + } catch (Exception e) { + throw new SQLException("Error converting JSON to String", e); + } + } + + @Override + public Object getNullableResult(ResultSet rs, String columnName) throws SQLException { + return parse(rs.getString(columnName)); + } + + @Override + public Object getNullableResult(ResultSet rs, int columnIndex) throws SQLException { + return parse(rs.getString(columnIndex)); + } + + @Override + public Object getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { + return parse(cs.getString(columnIndex)); + } + + private Object parse(String json) throws SQLException { + try { + if (json == null || json.isEmpty()) { + return null; + } + return MAPPER.readValue(json, Object.class); + } catch (Exception e) { + throw new SQLException("Error converting String to JSON", e); + } + } +} \ No newline at end of file diff --git a/backend/src/main/java/ltd/qubit/survey/common/mybatis/JsonTypeHandler.java b/backend/src/main/java/ltd/qubit/survey/common/mybatis/JsonTypeHandler.java new file mode 100644 index 0000000..7325edf --- /dev/null +++ b/backend/src/main/java/ltd/qubit/survey/common/mybatis/JsonTypeHandler.java @@ -0,0 +1,52 @@ +package ltd.qubit.survey.common.mybatis; + +import java.sql.CallableStatement; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import org.apache.ibatis.type.BaseTypeHandler; +import org.apache.ibatis.type.JdbcType; +import com.fasterxml.jackson.databind.ObjectMapper; + +/** + * 自定义的 JSON 类型处理器 + */ +public class JsonTypeHandler extends BaseTypeHandler { + private static final ObjectMapper MAPPER = new ObjectMapper(); + + @Override + public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) + throws SQLException { + try { + ps.setString(i, MAPPER.writeValueAsString(parameter)); + } catch (Exception e) { + throw new SQLException("Error converting JSON to String", e); + } + } + + @Override + public Object getNullableResult(ResultSet rs, String columnName) throws SQLException { + return parse(rs.getString(columnName)); + } + + @Override + public Object getNullableResult(ResultSet rs, int columnIndex) throws SQLException { + return parse(rs.getString(columnIndex)); + } + + @Override + public Object getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { + return parse(cs.getString(columnIndex)); + } + + private Object parse(String json) throws SQLException { + try { + if (json == null || json.isEmpty()) { + return null; + } + return MAPPER.readValue(json, Object.class); + } catch (Exception e) { + throw new SQLException("Error converting String to JSON", e); + } + } +} \ No newline at end of file diff --git a/backend/src/main/java/ltd/qubit/survey/mapper/SurveyResponseMapper.xml b/backend/src/main/java/ltd/qubit/survey/mapper/SurveyResponseMapper.xml new file mode 100644 index 0000000..aecc2ca --- /dev/null +++ b/backend/src/main/java/ltd/qubit/survey/mapper/SurveyResponseMapper.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties index df235fd..82da790 100644 --- a/backend/src/main/resources/application.properties +++ b/backend/src/main/resources/application.properties @@ -1,6 +1,6 @@ # 数据库配置 jdbc.driver=com.mysql.cj.jdbc.Driver -jdbc.url=jdbc:mysql://127.0.0.1:3306/llm_survey?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai +jdbc.url=jdbc:mysql://host.docker.internal:3306/llm_survey?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai jdbc.username=dev jdbc.password= diff --git a/backend/src/main/resources/logback.xml b/backend/src/main/resources/logback.xml new file mode 100644 index 0000000..e318e4b --- /dev/null +++ b/backend/src/main/resources/logback.xml @@ -0,0 +1,54 @@ + + + + + + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + UTF-8 + + + + + + ${LOG_HOME}/app.log + + + ${LOG_HOME}/app.%d{yyyy-MM-dd}.log + + 30 + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + UTF-8 + + + + + + + 0 + + 512 + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/backend/src/main/resources/mybatis/mapper/OptionMapper.xml b/backend/src/main/resources/mybatis/mapper/OptionMapper.xml index 51ae85e..a0533ce 100644 --- a/backend/src/main/resources/mybatis/mapper/OptionMapper.xml +++ b/backend/src/main/resources/mybatis/mapper/OptionMapper.xml @@ -2,7 +2,7 @@ - + @@ -52,21 +52,21 @@ - SELECT FROM options WHERE id = #{id} - SELECT FROM options ORDER BY question_id, option_code - SELECT FROM options WHERE question_id = #{questionId} @@ -74,7 +74,7 @@ - SELECT FROM options WHERE question_id = #{questionId} diff --git a/backend/src/main/resources/mybatis/mapper/SurveyResponseMapper.xml b/backend/src/main/resources/mybatis/mapper/SurveyResponseMapper.xml index c7b0430..c7347fe 100644 --- a/backend/src/main/resources/mybatis/mapper/SurveyResponseMapper.xml +++ b/backend/src/main/resources/mybatis/mapper/SurveyResponseMapper.xml @@ -6,7 +6,7 @@ - + @@ -19,7 +19,7 @@ INSERT INTO survey_responses (user_id, question_id, selected_options, text_answer) - VALUES (#{userId}, #{questionId}, #{selectedOptions,typeHandler=org.apache.ibatis.type.JsonTypeHandler}, #{textAnswer}) + VALUES (#{userId}, #{questionId}, #{selectedOptions,typeHandler=com.fasterxml.jackson.databind.JsonTypeHandler}, #{textAnswer}) @@ -28,7 +28,7 @@ VALUES (#{item.userId}, #{item.questionId}, - #{item.selectedOptions,typeHandler=org.apache.ibatis.type.JsonTypeHandler}, + #{item.selectedOptions,typeHandler=com.fasterxml.jackson.databind.JsonTypeHandler}, #{item.textAnswer}) @@ -38,7 +38,7 @@ UPDATE survey_responses SET user_id = #{userId}, question_id = #{questionId}, - selected_options = #{selectedOptions,typeHandler=org.apache.ibatis.type.JsonTypeHandler}, + selected_options = #{selectedOptions,typeHandler=com.fasterxml.jackson.databind.JsonTypeHandler}, text_answer = #{textAnswer} WHERE id = #{id} diff --git a/backend/src/main/resources/mybatis/mybatis-config.xml b/backend/src/main/resources/mybatis/mybatis-config.xml index 59d59f2..431d9e2 100644 --- a/backend/src/main/resources/mybatis/mybatis-config.xml +++ b/backend/src/main/resources/mybatis/mybatis-config.xml @@ -12,6 +12,12 @@ + + + + + + + + + - - - - - + \ No newline at end of file diff --git a/backend/src/main/resources/spring/applicationContext.xml b/backend/src/main/resources/spring/applicationContext.xml index 96c3210..14c8c55 100644 --- a/backend/src/main/resources/spring/applicationContext.xml +++ b/backend/src/main/resources/spring/applicationContext.xml @@ -3,16 +3,32 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" + xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx - http://www.springframework.org/schema/tx/spring-tx.xsd"> + http://www.springframework.org/schema/tx/spring-tx.xsd + http://www.springframework.org/schema/aop + http://www.springframework.org/schema/aop/spring-aop.xsd"> + + + + + + + + + + NON_NULL + + + @@ -21,4 +37,21 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/backend/src/main/resources/spring/spring-mvc.xml b/backend/src/main/resources/spring/spring-mvc.xml index efabb13..b90005a 100644 --- a/backend/src/main/resources/spring/spring-mvc.xml +++ b/backend/src/main/resources/spring/spring-mvc.xml @@ -20,27 +20,39 @@ - - - - - - - - + + + + application/json;charset=UTF-8 + + + + + + + + text/plain;charset=UTF-8 + text/html;charset=UTF-8 + + + + + + + \ No newline at end of file diff --git a/backend/src/main/resources/spring/spring-mybatis.xml b/backend/src/main/resources/spring/spring-mybatis.xml index 8c7889f..b3d611a 100644 --- a/backend/src/main/resources/spring/spring-mybatis.xml +++ b/backend/src/main/resources/spring/spring-mybatis.xml @@ -1,8 +1,11 @@ + http://www.springframework.org/schema/beans/spring-beans.xsd + http://www.springframework.org/schema/tx + http://www.springframework.org/schema/tx/spring-tx.xsd"> @@ -16,13 +19,35 @@ + + + + + + - + + + + + + + + + helperDialect=mysql + reasonable=true + supportMethodsArguments=true + params=count=countSql + + + + + diff --git a/backend/src/main/webapp/WEB-INF/web.xml b/backend/src/main/webapp/WEB-INF/web.xml index 6662b81..92144a5 100644 --- a/backend/src/main/webapp/WEB-INF/web.xml +++ b/backend/src/main/webapp/WEB-INF/web.xml @@ -1,9 +1,9 @@ - + xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee + https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd" + version="6.0"> LLM Survey API diff --git a/backend/target/classes/application.properties b/backend/target/classes/application.properties index df235fd..82da790 100644 --- a/backend/target/classes/application.properties +++ b/backend/target/classes/application.properties @@ -1,6 +1,6 @@ # 数据库配置 jdbc.driver=com.mysql.cj.jdbc.Driver -jdbc.url=jdbc:mysql://127.0.0.1:3306/llm_survey?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai +jdbc.url=jdbc:mysql://host.docker.internal:3306/llm_survey?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai jdbc.username=dev jdbc.password= diff --git a/backend/target/classes/ltd/qubit/survey/controller/GlobalExceptionHandler.class b/backend/target/classes/ltd/qubit/survey/controller/GlobalExceptionHandler.class index d2cda04..50970f9 100644 Binary files a/backend/target/classes/ltd/qubit/survey/controller/GlobalExceptionHandler.class and b/backend/target/classes/ltd/qubit/survey/controller/GlobalExceptionHandler.class differ diff --git a/backend/target/classes/ltd/qubit/survey/controller/QuestionController.class b/backend/target/classes/ltd/qubit/survey/controller/QuestionController.class index 05639d8..616664e 100644 Binary files a/backend/target/classes/ltd/qubit/survey/controller/QuestionController.class and b/backend/target/classes/ltd/qubit/survey/controller/QuestionController.class differ diff --git a/backend/target/classes/ltd/qubit/survey/controller/SurveyController.class b/backend/target/classes/ltd/qubit/survey/controller/SurveyController.class index 573e741..8db65d4 100644 Binary files a/backend/target/classes/ltd/qubit/survey/controller/SurveyController.class and b/backend/target/classes/ltd/qubit/survey/controller/SurveyController.class differ diff --git a/backend/target/classes/ltd/qubit/survey/controller/UserController.class b/backend/target/classes/ltd/qubit/survey/controller/UserController.class index 7014764..2a8479b 100644 Binary files a/backend/target/classes/ltd/qubit/survey/controller/UserController.class and b/backend/target/classes/ltd/qubit/survey/controller/UserController.class differ diff --git a/backend/target/classes/ltd/qubit/survey/dao/BaseDao.class b/backend/target/classes/ltd/qubit/survey/dao/BaseDao.class index 402bc79..dddfd3f 100644 Binary files a/backend/target/classes/ltd/qubit/survey/dao/BaseDao.class and b/backend/target/classes/ltd/qubit/survey/dao/BaseDao.class differ diff --git a/backend/target/classes/ltd/qubit/survey/dao/OptionDao.class b/backend/target/classes/ltd/qubit/survey/dao/OptionDao.class index 0966365..acd91bf 100644 Binary files a/backend/target/classes/ltd/qubit/survey/dao/OptionDao.class and b/backend/target/classes/ltd/qubit/survey/dao/OptionDao.class differ diff --git a/backend/target/classes/ltd/qubit/survey/dao/QuestionDao.class b/backend/target/classes/ltd/qubit/survey/dao/QuestionDao.class index e4bf898..9da36f7 100644 Binary files a/backend/target/classes/ltd/qubit/survey/dao/QuestionDao.class and b/backend/target/classes/ltd/qubit/survey/dao/QuestionDao.class differ diff --git a/backend/target/classes/ltd/qubit/survey/dao/SurveyResponseDao.class b/backend/target/classes/ltd/qubit/survey/dao/SurveyResponseDao.class index 08e54fb..2748c90 100644 Binary files a/backend/target/classes/ltd/qubit/survey/dao/SurveyResponseDao.class and b/backend/target/classes/ltd/qubit/survey/dao/SurveyResponseDao.class differ diff --git a/backend/target/classes/ltd/qubit/survey/dao/UserDao.class b/backend/target/classes/ltd/qubit/survey/dao/UserDao.class index 9e1eb3a..60e72fc 100644 Binary files a/backend/target/classes/ltd/qubit/survey/dao/UserDao.class and b/backend/target/classes/ltd/qubit/survey/dao/UserDao.class differ diff --git a/backend/target/classes/ltd/qubit/survey/model/ErrorInfo.class b/backend/target/classes/ltd/qubit/survey/model/ErrorInfo.class index 2cd8f64..fb52328 100644 Binary files a/backend/target/classes/ltd/qubit/survey/model/ErrorInfo.class and b/backend/target/classes/ltd/qubit/survey/model/ErrorInfo.class differ diff --git a/backend/target/classes/ltd/qubit/survey/model/Option.class b/backend/target/classes/ltd/qubit/survey/model/Option.class index 3fef50a..72db590 100644 Binary files a/backend/target/classes/ltd/qubit/survey/model/Option.class and b/backend/target/classes/ltd/qubit/survey/model/Option.class differ diff --git a/backend/target/classes/ltd/qubit/survey/model/PositionType.class b/backend/target/classes/ltd/qubit/survey/model/PositionType.class index 1c29a1b..9bd1a87 100644 Binary files a/backend/target/classes/ltd/qubit/survey/model/PositionType.class and b/backend/target/classes/ltd/qubit/survey/model/PositionType.class differ diff --git a/backend/target/classes/ltd/qubit/survey/model/Question.class b/backend/target/classes/ltd/qubit/survey/model/Question.class index 737203d..6fbbc0a 100644 Binary files a/backend/target/classes/ltd/qubit/survey/model/Question.class and b/backend/target/classes/ltd/qubit/survey/model/Question.class differ diff --git a/backend/target/classes/ltd/qubit/survey/model/QuestionType.class b/backend/target/classes/ltd/qubit/survey/model/QuestionType.class index b0999d6..1816eeb 100644 Binary files a/backend/target/classes/ltd/qubit/survey/model/QuestionType.class and b/backend/target/classes/ltd/qubit/survey/model/QuestionType.class differ diff --git a/backend/target/classes/ltd/qubit/survey/model/SurveyResponse.class b/backend/target/classes/ltd/qubit/survey/model/SurveyResponse.class index 9f86ea3..90bb504 100644 Binary files a/backend/target/classes/ltd/qubit/survey/model/SurveyResponse.class and b/backend/target/classes/ltd/qubit/survey/model/SurveyResponse.class differ diff --git a/backend/target/classes/ltd/qubit/survey/model/User.class b/backend/target/classes/ltd/qubit/survey/model/User.class index 12b3ac7..ebdbbac 100644 Binary files a/backend/target/classes/ltd/qubit/survey/model/User.class and b/backend/target/classes/ltd/qubit/survey/model/User.class differ diff --git a/backend/target/classes/ltd/qubit/survey/model/WorkArea.class b/backend/target/classes/ltd/qubit/survey/model/WorkArea.class index 7f0372a..b7511bb 100644 Binary files a/backend/target/classes/ltd/qubit/survey/model/WorkArea.class and b/backend/target/classes/ltd/qubit/survey/model/WorkArea.class differ diff --git a/backend/target/classes/ltd/qubit/survey/service/BaseService.class b/backend/target/classes/ltd/qubit/survey/service/BaseService.class index 4aadaea..9dc92b0 100644 Binary files a/backend/target/classes/ltd/qubit/survey/service/BaseService.class and b/backend/target/classes/ltd/qubit/survey/service/BaseService.class differ diff --git a/backend/target/classes/ltd/qubit/survey/service/OptionService.class b/backend/target/classes/ltd/qubit/survey/service/OptionService.class index 1b60a4a..0d9db2a 100644 Binary files a/backend/target/classes/ltd/qubit/survey/service/OptionService.class and b/backend/target/classes/ltd/qubit/survey/service/OptionService.class differ diff --git a/backend/target/classes/ltd/qubit/survey/service/QuestionService.class b/backend/target/classes/ltd/qubit/survey/service/QuestionService.class index 1dacf19..b8db983 100644 Binary files a/backend/target/classes/ltd/qubit/survey/service/QuestionService.class and b/backend/target/classes/ltd/qubit/survey/service/QuestionService.class differ diff --git a/backend/target/classes/ltd/qubit/survey/service/SurveyResponseService.class b/backend/target/classes/ltd/qubit/survey/service/SurveyResponseService.class index 8ad32a0..81a06d0 100644 Binary files a/backend/target/classes/ltd/qubit/survey/service/SurveyResponseService.class and b/backend/target/classes/ltd/qubit/survey/service/SurveyResponseService.class differ diff --git a/backend/target/classes/ltd/qubit/survey/service/UserService.class b/backend/target/classes/ltd/qubit/survey/service/UserService.class index 0fc7a63..e3a712f 100644 Binary files a/backend/target/classes/ltd/qubit/survey/service/UserService.class and b/backend/target/classes/ltd/qubit/survey/service/UserService.class differ diff --git a/backend/target/classes/ltd/qubit/survey/service/impl/OptionServiceImpl.class b/backend/target/classes/ltd/qubit/survey/service/impl/OptionServiceImpl.class index 4fad750..f2fdc26 100644 Binary files a/backend/target/classes/ltd/qubit/survey/service/impl/OptionServiceImpl.class and b/backend/target/classes/ltd/qubit/survey/service/impl/OptionServiceImpl.class differ diff --git a/backend/target/classes/ltd/qubit/survey/service/impl/QuestionServiceImpl$1.class b/backend/target/classes/ltd/qubit/survey/service/impl/QuestionServiceImpl$1.class index db24b89..6aac21f 100644 Binary files a/backend/target/classes/ltd/qubit/survey/service/impl/QuestionServiceImpl$1.class and b/backend/target/classes/ltd/qubit/survey/service/impl/QuestionServiceImpl$1.class differ diff --git a/backend/target/classes/ltd/qubit/survey/service/impl/QuestionServiceImpl.class b/backend/target/classes/ltd/qubit/survey/service/impl/QuestionServiceImpl.class index 7ff97b9..aace1bb 100644 Binary files a/backend/target/classes/ltd/qubit/survey/service/impl/QuestionServiceImpl.class and b/backend/target/classes/ltd/qubit/survey/service/impl/QuestionServiceImpl.class differ diff --git a/backend/target/classes/ltd/qubit/survey/service/impl/SurveyResponseServiceImpl.class b/backend/target/classes/ltd/qubit/survey/service/impl/SurveyResponseServiceImpl.class index 3db90e7..b1a938b 100644 Binary files a/backend/target/classes/ltd/qubit/survey/service/impl/SurveyResponseServiceImpl.class and b/backend/target/classes/ltd/qubit/survey/service/impl/SurveyResponseServiceImpl.class differ diff --git a/backend/target/classes/ltd/qubit/survey/service/impl/UserServiceImpl.class b/backend/target/classes/ltd/qubit/survey/service/impl/UserServiceImpl.class index 6824f96..7f7487e 100644 Binary files a/backend/target/classes/ltd/qubit/survey/service/impl/UserServiceImpl.class and b/backend/target/classes/ltd/qubit/survey/service/impl/UserServiceImpl.class differ diff --git a/backend/target/classes/mybatis/mapper/OptionMapper.xml b/backend/target/classes/mybatis/mapper/OptionMapper.xml index 51ae85e..a0533ce 100644 --- a/backend/target/classes/mybatis/mapper/OptionMapper.xml +++ b/backend/target/classes/mybatis/mapper/OptionMapper.xml @@ -2,7 +2,7 @@ - + @@ -52,21 +52,21 @@ - SELECT FROM options WHERE id = #{id} - SELECT FROM options ORDER BY question_id, option_code - SELECT FROM options WHERE question_id = #{questionId} @@ -74,7 +74,7 @@ - SELECT FROM options WHERE question_id = #{questionId} diff --git a/backend/target/classes/mybatis/mapper/SurveyResponseMapper.xml b/backend/target/classes/mybatis/mapper/SurveyResponseMapper.xml index c7b0430..c7347fe 100644 --- a/backend/target/classes/mybatis/mapper/SurveyResponseMapper.xml +++ b/backend/target/classes/mybatis/mapper/SurveyResponseMapper.xml @@ -6,7 +6,7 @@ - + @@ -19,7 +19,7 @@ INSERT INTO survey_responses (user_id, question_id, selected_options, text_answer) - VALUES (#{userId}, #{questionId}, #{selectedOptions,typeHandler=org.apache.ibatis.type.JsonTypeHandler}, #{textAnswer}) + VALUES (#{userId}, #{questionId}, #{selectedOptions,typeHandler=com.fasterxml.jackson.databind.JsonTypeHandler}, #{textAnswer}) @@ -28,7 +28,7 @@ VALUES (#{item.userId}, #{item.questionId}, - #{item.selectedOptions,typeHandler=org.apache.ibatis.type.JsonTypeHandler}, + #{item.selectedOptions,typeHandler=com.fasterxml.jackson.databind.JsonTypeHandler}, #{item.textAnswer}) @@ -38,7 +38,7 @@ UPDATE survey_responses SET user_id = #{userId}, question_id = #{questionId}, - selected_options = #{selectedOptions,typeHandler=org.apache.ibatis.type.JsonTypeHandler}, + selected_options = #{selectedOptions,typeHandler=com.fasterxml.jackson.databind.JsonTypeHandler}, text_answer = #{textAnswer} WHERE id = #{id} diff --git a/backend/target/classes/mybatis/mybatis-config.xml b/backend/target/classes/mybatis/mybatis-config.xml index 59d59f2..431d9e2 100644 --- a/backend/target/classes/mybatis/mybatis-config.xml +++ b/backend/target/classes/mybatis/mybatis-config.xml @@ -12,6 +12,12 @@ + + + + + + + + + - - - - - + \ No newline at end of file diff --git a/backend/target/classes/spring/applicationContext.xml b/backend/target/classes/spring/applicationContext.xml index 96c3210..14c8c55 100644 --- a/backend/target/classes/spring/applicationContext.xml +++ b/backend/target/classes/spring/applicationContext.xml @@ -3,16 +3,32 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" + xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx - http://www.springframework.org/schema/tx/spring-tx.xsd"> + http://www.springframework.org/schema/tx/spring-tx.xsd + http://www.springframework.org/schema/aop + http://www.springframework.org/schema/aop/spring-aop.xsd"> + + + + + + + + + + NON_NULL + + + @@ -21,4 +37,21 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/backend/target/classes/spring/spring-mvc.xml b/backend/target/classes/spring/spring-mvc.xml index efabb13..b90005a 100644 --- a/backend/target/classes/spring/spring-mvc.xml +++ b/backend/target/classes/spring/spring-mvc.xml @@ -20,27 +20,39 @@ - - - - - - - - + + + + application/json;charset=UTF-8 + + + + + + + + text/plain;charset=UTF-8 + text/html;charset=UTF-8 + + + + + + + \ No newline at end of file diff --git a/backend/target/classes/spring/spring-mybatis.xml b/backend/target/classes/spring/spring-mybatis.xml index 8c7889f..b3d611a 100644 --- a/backend/target/classes/spring/spring-mybatis.xml +++ b/backend/target/classes/spring/spring-mybatis.xml @@ -1,8 +1,11 @@ + http://www.springframework.org/schema/beans/spring-beans.xsd + http://www.springframework.org/schema/tx + http://www.springframework.org/schema/tx/spring-tx.xsd"> @@ -16,13 +19,35 @@ + + + + + + - + + + + + + + + + helperDialect=mysql + reasonable=true + supportMethodsArguments=true + params=count=countSql + + + + + diff --git a/backend/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst b/backend/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst index df03b31..03e3ecf 100644 --- a/backend/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst +++ b/backend/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst @@ -12,6 +12,7 @@ ltd/qubit/survey/service/impl/QuestionServiceImpl.class ltd/qubit/survey/model/SurveyResponse.class ltd/qubit/survey/model/User.class ltd/qubit/survey/service/QuestionService.class +ltd/qubit/survey/common/mybatis/JsonTypeHandler.class ltd/qubit/survey/service/impl/QuestionServiceImpl$1.class ltd/qubit/survey/service/UserService.class ltd/qubit/survey/dao/BaseDao.class @@ -25,3 +26,4 @@ ltd/qubit/survey/service/SurveyResponseService.class ltd/qubit/survey/model/Option.class ltd/qubit/survey/model/QuestionType.class ltd/qubit/survey/service/BaseService.class +com/fasterxml/jackson/databind/JsonTypeHandler.class diff --git a/backend/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/backend/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst index 4678e84..325ebd6 100644 --- a/backend/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst +++ b/backend/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst @@ -1,6 +1,7 @@ /Volumes/working/qubit/project/llm-survey/backend/src/main/java/ltd/qubit/survey/dao/QuestionDao.java /Volumes/working/qubit/project/llm-survey/backend/src/main/java/ltd/qubit/survey/service/UserService.java /Volumes/working/qubit/project/llm-survey/backend/src/main/java/ltd/qubit/survey/service/OptionService.java +/Volumes/working/qubit/project/llm-survey/backend/src/main/java/ltd/qubit/survey/common/mybatis/JsonTypeHandler.java /Volumes/working/qubit/project/llm-survey/backend/src/main/java/ltd/qubit/survey/model/Question.java /Volumes/working/qubit/project/llm-survey/backend/src/main/java/ltd/qubit/survey/service/QuestionService.java /Volumes/working/qubit/project/llm-survey/backend/src/main/java/ltd/qubit/survey/service/BaseService.java @@ -8,6 +9,7 @@ /Volumes/working/qubit/project/llm-survey/backend/src/main/java/ltd/qubit/survey/service/impl/OptionServiceImpl.java /Volumes/working/qubit/project/llm-survey/backend/src/main/java/ltd/qubit/survey/service/impl/QuestionServiceImpl.java /Volumes/working/qubit/project/llm-survey/backend/src/main/java/ltd/qubit/survey/service/SurveyResponseService.java +/Volumes/working/qubit/project/llm-survey/backend/src/main/java/com/fasterxml/jackson/databind/JsonTypeHandler.java /Volumes/working/qubit/project/llm-survey/backend/src/main/java/ltd/qubit/survey/model/Option.java /Volumes/working/qubit/project/llm-survey/backend/src/main/java/ltd/qubit/survey/controller/GlobalExceptionHandler.java /Volumes/working/qubit/project/llm-survey/backend/src/main/java/ltd/qubit/survey/model/QuestionType.java diff --git a/doc/deployment.md b/doc/deployment.md new file mode 100644 index 0000000..dd6415d --- /dev/null +++ b/doc/deployment.md @@ -0,0 +1,74 @@ +# 部署文档 + +## 1. 开发环境配置 + +### 1.1 环境变量 +- `DOCKER_DATA_DIR`: Docker数据目录,默认为 `/Volumes/working/docker` + +### 1.2 开发环境组件 +- Tomcat: 运行在Docker容器中 + - 数据目录: `$DOCKER_DATA_DIR/tomcat` + - 日志目录: `$DOCKER_DATA_DIR/tomcat/logs` + - 应用目录: `$DOCKER_DATA_DIR/tomcat/webapps` + +## 2. 项目构建 + +### 2.1 编译打包 +```bash +# 进入后端项目目录 +cd backend + +# 清理并打包项目(跳过测试) +mvn clean package -DskipTests + +# 打包结果 +# - WAR包位置:backend/target/llm-survey-api.war +``` + +### 2.2 数据库初始化 +```bash +# 进入数据库脚本目录 +cd database + +# 添加执行权限 +chmod +x init_database.sh + +# 执行初始化脚本 +./init_database.sh + +# 初始化内容 +# - 创建数据库:llm_survey +# - 创建表:users, questions, options, survey_responses +# - 插入基础数据:工作领域和岗位性质相关的问题和选项 +``` + +## 3. 开发环境部署 + +### 3.1 部署WAR包 +```bash +# 复制WAR包到Tomcat的webapps目录 +cp backend/target/llm-survey-api.war $DOCKER_DATA_DIR/tomcat/webapps/ + +# 部署后的访问地址 +# - 上下文路径:/llm-survey-api +# - API基础路径:/llm-survey-api/api +``` + +### 3.2 查看部署结果 +```bash +# 查看Tomcat日志 +tail -f $DOCKER_DATA_DIR/tomcat/logs/catalina.out + +# 检查应用是否成功部署 +ls -l $DOCKER_DATA_DIR/tomcat/webapps/llm-survey-api/ +``` + +### 3.3 验证部署 +- 访问测试接口:`http://localhost:8080/llm-survey-api/user/check/13800000000` +- 预期返回:`false`(表示手机号未注册) + +## 4. 注意事项 +1. 确保MySQL服务已启动且能够通过localhost:3306访问 +2. 确保Tomcat容器已启动且8080端口可访问 +3. 部署前确保数据库已正确初始化 +4. 如需重新部署,可直接覆盖webapps目录下的WAR包,Tomcat会自动重新部署 \ No newline at end of file diff --git a/pom.xml b/pom.xml deleted file mode 100644 index f7deefc..0000000 --- a/pom.xml +++ /dev/null @@ -1,161 +0,0 @@ - - - 4.0.0 - - ltd.qubit - llm-survey-api - 1.0-SNAPSHOT - war - - - 17 - ${java.version} - ${java.version} - UTF-8 - 5.3.31 - 3.5.15 - 2.1.2 - 8.3.0 - 5.1.0 - 2.16.1 - 1.18.30 - 2.0.11 - 1.4.14 - 4.0.1 - - - - - - org.springframework - spring-webmvc - ${spring.version} - - - org.springframework - spring-jdbc - ${spring.version} - - - org.springframework - spring-context-support - ${spring.version} - - - org.springframework - spring-tx - ${spring.version} - - - - - org.mybatis - mybatis - ${mybatis.version} - - - org.mybatis - mybatis-spring - ${mybatis-spring.version} - - - - - com.mysql - mysql-connector-j - ${mysql-connector.version} - - - - - com.zaxxer - HikariCP - ${hikaricp.version} - - - - - com.fasterxml.jackson.core - jackson-databind - ${jackson.version} - - - - - org.projectlombok - lombok - ${lombok.version} - provided - - - - - org.slf4j - slf4j-api - ${slf4j.version} - - - ch.qos.logback - logback-classic - ${logback.version} - - - - - javax.servlet - javax.servlet-api - ${servlet-api.version} - provided - - - - - llm-survey-api - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.11.0 - - ${java.version} - ${project.build.sourceEncoding} - - - org.projectlombok - lombok - ${lombok.version} - - - - - - - - org.apache.maven.plugins - maven-war-plugin - 3.4.0 - - false - - - - - - - - src/main/resources - true - - - src/main/java - - **/*.xml - - true - - - - \ No newline at end of file diff --git a/src/main/java/ltd/qubit/survey/controller/GlobalExceptionHandler.java b/src/main/java/ltd/qubit/survey/controller/GlobalExceptionHandler.java deleted file mode 100644 index ef094e3..0000000 --- a/src/main/java/ltd/qubit/survey/controller/GlobalExceptionHandler.java +++ /dev/null @@ -1,78 +0,0 @@ -package ltd.qubit.survey.controller; - -import lombok.extern.slf4j.Slf4j; -import ltd.qubit.survey.model.ErrorInfo; -import org.springframework.dao.DataAccessException; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.validation.BindException; -import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.bind.annotation.RestControllerAdvice; - -/** - * 全局异常处理器 - */ -@Slf4j -@RestControllerAdvice -public class GlobalExceptionHandler { - - /** - * 处理参数校验异常 - */ - @ExceptionHandler(BindException.class) - public ResponseEntity handleBindException(BindException e) { - String message = e.getBindingResult().getFieldErrors().stream() - .map(error -> error.getField() + ": " + error.getDefaultMessage()) - .reduce((a, b) -> a + "; " + b) - .orElse("参数错误"); - - ErrorInfo error = ErrorInfo.of( - "INVALID_ARGUMENT", - "参数校验失败", - message, - e.getObjectName()); - - return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST); - } - - /** - * 处理业务异常 - */ - @ExceptionHandler(IllegalArgumentException.class) - public ResponseEntity handleIllegalArgumentException(IllegalArgumentException e) { - log.warn("业务异常", e); - ErrorInfo error = ErrorInfo.of( - "BAD_REQUEST", - e.getMessage(), - e.getClass().getName()); - return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST); - } - - /** - * 处理数据访问异常 - */ - @ExceptionHandler(DataAccessException.class) - public ResponseEntity handleDataAccessException(DataAccessException e) { - log.error("数据访问异常", e); - ErrorInfo error = ErrorInfo.of( - "DATABASE_ERROR", - "数据库访问错误", - e.getMessage(), - e.getClass().getName()); - return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR); - } - - /** - * 处理其他未知异常 - */ - @ExceptionHandler(Exception.class) - public ResponseEntity handleUnknownException(Exception e) { - log.error("系统异常", e); - ErrorInfo error = ErrorInfo.of( - "SYSTEM_ERROR", - "系统错误", - e.getMessage(), - e.getClass().getName()); - return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR); - } -} \ No newline at end of file diff --git a/src/main/java/ltd/qubit/survey/controller/QuestionController.java b/src/main/java/ltd/qubit/survey/controller/QuestionController.java deleted file mode 100644 index 674bb2b..0000000 --- a/src/main/java/ltd/qubit/survey/controller/QuestionController.java +++ /dev/null @@ -1,62 +0,0 @@ -package ltd.qubit.survey.controller; - -import java.util.List; -import lombok.RequiredArgsConstructor; -import ltd.qubit.survey.model.Question; -import ltd.qubit.survey.model.Option; -import ltd.qubit.survey.service.QuestionService; -import ltd.qubit.survey.service.OptionService; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -/** - * 问题控制器 - */ -@RestController -@RequestMapping("/api/questions") -@RequiredArgsConstructor -public class QuestionController { - private final QuestionService questionService; - private final OptionService optionService; - - /** - * 获取用户的问题列表 - * - * @param userId 用户ID - * @return 问题列表 - */ - @GetMapping("/user/{userId}") - public List getUserQuestions(@PathVariable Long userId) { - return questionService.getUserQuestions(userId); - } - - /** - * 获取问题的选项列表 - * - * @param questionId 问题ID - * @return 选项列表 - */ - @GetMapping("/{questionId}/options") - public List