Compare commits

...

No commits in common. 'chenweiyou_branch' and 'main' have entirely different histories.

3
.idea/.gitignore vendored

@ -0,0 +1,3 @@
# 默认忽略的文件
/shelf/
/workspace.xml

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<annotationProcessing>
<profile name="Maven default annotation processors profile" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<module name="math-learning" />
</profile>
</annotationProcessing>
</component>
</project>

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
</component>
</project>

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Central Repository" />
<option name="url" value="https://repo.maven.apache.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
</component>
</project>

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_25" default="true" project-jdk-name="25" project-jdk-type="JavaSDK" />
</project>

@ -1,383 +1,367 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.coproject</groupId>
<artifactId>math-learning</artifactId>
<version>0.1.4</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<javafx.version>21.0.3</javafx.version>
<!-- 允许通过 -DskipJlink=true 跳过 jlink避免 javafx:run 时误触发 -->
<skipJlink>false</skipJlink>
</properties>
<dependencies>
<!-- JavaFX UI -->
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>${javafx.version}</version>
<classifier>win</classifier>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>${javafx.version}</version>
<classifier>win</classifier>
</dependency>
<!-- JSON storage -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.17.1</version>
</dependency>
<!-- Mail sending (Jakarta Mail implementation) -->
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>jakarta.mail</artifactId>
<version>2.0.1</version>
</dependency>
<!-- Commons Lang for utilities -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.14.0</version>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
<!-- Enable `mvn javafx:run` for local development -->
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.8</version>
<configuration>
<mainClass>com.coproject.MainApp</mainClass>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jlink-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<image>${project.build.directory}/jlink-image</image>
<jlinkExecutable>${env.JAVA_HOME}/bin/jlink</jlinkExecutable>
<modulePaths>
<modulePath>${env.JAVA_HOME}/jmods</modulePath>
<modulePath>${project.basedir}/lib/javafx-jmods-21.0.8/javafx-jmods-21.0.8</modulePath>
</modulePaths>
<!-- 仅包含 JDK 与 JavaFX 模块,第三方库不参与 jlink -->
<addModules>javafx.base,javafx.graphics,javafx.controls,javafx.fxml</addModules>
<noHeaderFiles>true</noHeaderFiles>
<noManPages>true</noManPages>
<stripDebug>true</stripDebug>
<skip>${skipJlink}</skip>
</configuration>
<executions>
<execution>
<id>make-jlink-image</id>
<phase>package</phase>
<goals>
<goal>jlink</goal>
</goals>
<configuration>
<!-- 在 execution 级别也应用 skip确保 -DskipJlink=true 生效 -->
<skip>${skipJlink}</skip>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<outputDirectory>${project.build.directory}/dist</outputDirectory>
<archive>
<!-- 使用我们在 antrun 中生成的 manifest 文件,显式包含 lib 下所有依赖 -->
<manifestFile>${project.build.directory}/dist/manifest.mf</manifestFile>
</archive>
</configuration>
<executions>
<execution>
<id>force-jar</id>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- 备用方案:生成 jar-with-dependencies胖包 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.6.0</version>
<configuration>
<archive>
<manifest>
<mainClass>com.coproject.MainApp</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<finalName>${project.artifactId}-${project.version}</finalName>
<appendAssemblyId>true</appendAssemblyId>
<outputDirectory>${project.build.directory}/dist</outputDirectory>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- 生成包含所有依赖的可运行 JAR避免安装版缺失类路径导致启动失败 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<skip>true</skip>
<!-- 将产物写入 dist 并与 finalName 保持一致 -->
<outputFile>${project.build.directory}/dist/${project.build.finalName}.jar</outputFile>
<shadedArtifactAttached>false</shadedArtifactAttached>
<createDependencyReducedPom>false</createDependencyReducedPom>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.coproject.MainApp</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.6.1</version>
<executions>
<execution>
<id>copy-runtime-deps</id>
<phase>prepare-package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/dist/lib</outputDirectory>
<includeScope>runtime</includeScope>
<!-- 复制全部运行时依赖,包含 JavaFX win JAR 到 dist/lib -->
</configuration>
</execution>
</executions>
</plugin>
<!-- Prepare external config file: copy and rename smtp.env.example -> data/smtp.env into dist -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>generate-manifest-with-classpath</id>
<phase>prepare-package</phase>
<configuration>
<target>
<!-- 确保 dist 与 dist/lib 目录存在 -->
<mkdir dir="${project.build.directory}/dist"/>
<mkdir dir="${project.build.directory}/dist/lib"/>
<property name="dist.lib" value="${project.build.directory}/dist/lib"/>
<path id="deps.jars">
<fileset dir="${dist.lib}" includes="*.jar"/>
</path>
<pathconvert refid="deps.jars" property="deps.cp" pathsep=" ">
<map from="${project.build.directory}/dist/lib/" to="lib/"/>
<map from="${project.build.directory}/dist/lib\" to="lib/"/>
</pathconvert>
<echo file="${project.build.directory}/dist/manifest.mf">
Manifest-Version: 1.0
Main-Class: com.coproject.MainApp
Class-Path: ${deps.cp}
</echo>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
<execution>
<id>prepare-smtp-env</id>
<phase>package</phase>
<configuration>
<target>
<mkdir dir="${project.build.directory}/dist/data"/>
<copy file="${project.basedir}/smtp.env.example" tofile="${project.build.directory}/dist/data/smtp.env" overwrite="true"/>
<mkdir dir="${project.build.directory}/dist/data/papers"/>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
<execution>
<id>cleanup-dist-jars</id>
<phase>post-package</phase>
<configuration>
<target>
<delete>
<fileset dir="${project.build.directory}/dist" includes="math-learning-*.jar" excludes="${project.build.finalName}.jar"/>
</delete>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.3.1</version>
<executions>
<execution>
<id>copy-javafx-win</id>
<phase>prepare-package</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/dist/lib</outputDirectory>
<resources>
<resource>
<directory>${project.basedir}/lib/javafx-win</directory>
<includes>
<include>javafx-*-win.jar</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
<execution>
<id>copy-app-README</id>
<phase>package</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/dist</outputDirectory>
<resources>
<resource>
<directory>${project.basedir}</directory>
<includes>
<include>README.md</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
<execution>
<id>copy-config-guides</id>
<phase>package</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/dist</outputDirectory>
<resources>
<resource>
<directory>${project.basedir}</directory>
<includes>
<include>configure_smtp_qq.ps1</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.panteleyev</groupId>
<artifactId>jpackage-maven-plugin</artifactId>
<version>1.7.1</version>
<configuration>
<input>${project.build.directory}/dist</input>
<resourceDir>${project.build.directory}/dist</resourceDir>
<destination>${project.build.directory}/jpackage</destination>
<type>msi</type>
<name>数学学习软件</name>
<vendor>Coproject</vendor>
<appVersion>0.1.4</appVersion>
<winConsole>true</winConsole>
<winDirChooser>true</winDirChooser>
<winMenu>true</winMenu>
<winShortcut>true</winShortcut>
<verbose>true</verbose>
<!-- 与 maven-jar-plugin 输出一致:固定为 artifactId.jar -->
<mainJar>${project.artifactId}.jar</mainJar>
<mainClass>com.coproject.MainApp</mainClass>
<!-- 让启动器包含 dist/lib 下所有依赖 -->
<classPath>lib/*</classPath>
<!-- JavaFX 模块所在路径 -->
<modulePath>app/lib</modulePath>
<!-- 类路径由主 JAR 的 MANIFEST.MF 提供antrun 生成 Class-Path -->
<removeDestination>true</removeDestination>
<!-- 显式添加 JavaFX 模块,避免运行期缺失导致退出码 1 -->
<javaOptions>
<javaOption>--module-path</javaOption>
<javaOption>app/lib</javaOption>
<javaOption>--add-modules</javaOption>
<javaOption>javafx.controls,javafx.fxml</javaOption>
</javaOptions>
<!-- 不强制使用 jlink 镜像,默认使用当前 JDK 的 jpackage -->
</configuration>
<executions>
<execution>
<id>make-installer</id>
<phase>package</phase>
<goals>
<goal>jpackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<profiles>
<!-- 使用 -P no-jlink 强制跳过 jlink某些环境下 -DskipJlink=true 未被采纳) -->
<profile>
<id>no-jlink</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<properties>
<skipJlink>true</skipJlink>
</properties>
</profile>
</profiles>
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.coproject</groupId>
<artifactId>math-learning</artifactId>
<version>0.1.2</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<maven.compiler.release>17</maven.compiler.release>
<javafx.version>21.0.3</javafx.version>
<maven.build.timestamp.format>yyyy-MM-dd HH:mm:ss</maven.build.timestamp.format>
</properties>
<dependencies>
<!-- JavaFX UI -->
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>${javafx.version}</version>
<classifier>win</classifier>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>${javafx.version}</version>
<classifier>win</classifier>
</dependency>
<!-- JSON storage -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.17.1</version>
</dependency>
<!-- Mail sending (Jakarta Mail implementation) -->
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>jakarta.mail</artifactId>
<version>2.0.1</version>
</dependency>
<!-- Commons Lang for utilities -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.14.0</version>
</dependency>
</dependencies>
<build>
<finalName>${artifactId}-${version}</finalName>
<plugins>
<!-- 编译器插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
<!-- Enable `mvn javafx:run` for local development -->
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.8</version>
<configuration>
<mainClass>com.coproject.MainApp</mainClass>
</configuration>
</plugin>
<!-- 生成主 JAR -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<outputDirectory>${project.build.directory}/dist</outputDirectory>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>com.coproject.MainApp</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<!-- 复制依赖到 lib 目录 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.6.1</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/dist/lib</outputDirectory>
<includeScope>runtime</includeScope>
</configuration>
</execution>
</executions>
</plugin>
<!-- 复制 JavaFX Windows JAR 和配置文件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.3.1</version>
<executions>
<execution>
<id>copy-javafx-win</id>
<phase>package</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/dist/lib</outputDirectory>
<resources>
<resource>
<directory>${project.basedir}/lib/javafx-win</directory>
<includes>
<include>*.jar</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
<execution>
<id>copy-config-files</id>
<phase>package</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/dist</outputDirectory>
<resources>
<resource>
<directory>${project.basedir}</directory>
<includes>
<include>smtp.env.example</include>
<include>README.md</include>
<include>configure_smtp_qq.ps1</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<!-- 创建数据目录 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>create-data-directories</id>
<phase>package</phase>
<configuration>
<target>
<mkdir dir="${project.build.directory}/dist/data"/>
<mkdir dir="${project.build.directory}/dist/data/papers"/>
<copy file="${project.basedir}/smtp.env.example"
tofile="${project.build.directory}/dist/data/smtp.env"
overwrite="true"/>
<echo file="${project.build.directory}/dist/data/papers/README.txt">试卷存储目录
将生成的试卷PDF文件保存在此目录中。
</echo>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
<!-- 自动生成分发包 -->
<execution>
<id>create-distribution</id>
<phase>package</phase>
<configuration>
<target>
<echo>=== 开始生成分发包 ===</echo>
<!-- 创建分发目录 -->
<mkdir dir="${project.build.directory}/数学学习软件-${project.version}"/>
<!-- 生成正确的启动脚本 -->
<echo file="${project.build.directory}/数学学习软件-${project.version}/run.bat">@echo off
chcp 65001 >nul
title 数学学习软件
echo 启动数学学习软件...
REM 检查JAR文件是否存在
if not exist "math-learning-0.1.2.jar" (
echo 错误: 找不到主程序文件 math-learning-0.1.2.jar
echo 请确保所有文件在同一个目录下
pause
exit /b 1
)
REM 检查lib目录是否存在
if not exist "lib" (
echo 错误: 找不到依赖库目录 lib
echo 请确保lib目录存在且完整
pause
exit /b 1
)
REM 运行程序
echo 正在启动程序...
java --module-path "lib" --add-modules javafx.controls,javafx.fxml -jar "math-learning-0.1.2.jar"
REM 如果程序退出,暂停窗口
echo.
echo 程序已退出。
pause
</echo>
<!-- 生成简化版启动脚本 -->
<echo file="${project.build.directory}/数学学习软件-${project.version}/start.bat">@echo off
chcp 65001 >nul
cd /d %~dp0
java --module-path "lib" --add-modules javafx.controls,javafx.fxml -jar "math-learning-0.1.2.jar"
</echo>
<!-- 生成测试脚本 -->
<echo file="${project.build.directory}/数学学习软件-${project.version}/测试运行.bat">@echo off
echo 正在测试程序是否能正常运行...
cd /d %~dp0
if exist "math-learning-0.1.2.jar" (
echo ✓ 找到主程序文件
) else (
echo ✗ 找不到主程序文件
pause
exit /b 1
)
if exist "lib" (
echo ✓ 找到依赖库目录
) else (
echo ✗ 找不到依赖库目录
pause
exit /b 1
)
echo 正在启动程序...
start start.bat
</echo>
<!-- 复制主程序 JAR -->
<copy todir="${project.build.directory}/数学学习软件-${project.version}">
<fileset dir="${project.build.directory}/dist">
<include name="math-learning-${project.version}.jar"/>
<include name="README.md"/>
<include name="smtp.env.example"/>
<include name="configure_smtp_qq.ps1"/>
</fileset>
</copy>
<!-- 复制依赖库 -->
<copy todir="${project.build.directory}/数学学习软件-${project.version}/lib">
<fileset dir="${project.build.directory}/dist/lib"/>
</copy>
<!-- 复制数据目录 -->
<copy todir="${project.build.directory}/数学学习软件-${project.version}/data">
<fileset dir="${project.build.directory}/dist/data"/>
</copy>
<!-- 生成详细使用说明 -->
<echo file="${project.build.directory}/数学学习软件-${project.version}/使用说明.txt">数学学习软件 v${project.version}
=== 基本信息 ===
版本号: ${project.version}
生成时间: ${maven.build.timestamp}
开发者: Coproject 团队
=== 系统要求 ===
- 操作系统: Windows 7/10/11
- Java版本: Java 17 或更高版本
- 内存: 至少 2GB 可用内存
=== 启动方法 ===
推荐使用以下方式启动:
1. 双击运行 run.bat (推荐,有错误提示)
2. 双击 start.bat (简洁版)
3. 双击 测试运行.bat (先检查环境再启动)
=== 功能特点 ===
✓ 小学数学题目生成
✓ 初中数学题目生成(含平方根号)
✓ 高中数学题目生成(含三角函数)
✓ 选择题答题系统
✓ 邮件发送验证码功能
✓ 试卷PDF导出功能
=== 目录说明 ===
math-learning-0.1.2.jar - 主程序文件
lib/ - 程序依赖库(请勿删除或移动)
data/ - 数据存储目录
├── smtp.env - 邮箱配置文件
└── papers/ - 试卷存储目录
run.bat - Windows启动脚本(详细版)
start.bat - Windows启动脚本(简洁版)
测试运行.bat - 环境测试脚本
README.md - 项目说明文档
=== 配置说明 ===
1. 首次运行会自动创建配置文件
2. 邮箱配置请参考 smtp.env.example
3. 生成的试卷保存在 data/papers/ 目录
=== 常见问题 ===
Q: 启动时提示"缺少JavaFX运行时组件"
A: 请确保使用 .bat 文件启动不要直接双击JAR文件
Q: 邮件发送失败
A: 请检查 data/smtp.env 中的邮箱配置
Q: 程序无法启动
A: 请先运行"测试运行.bat"检查环境
=== 技术支持 ===
如有问题请联系开发团队。
注意:请保持所有文件在同一个目录下,不要单独移动文件!
</echo>
<!-- 创建ZIP压缩包 -->
<zip destfile="${project.build.directory}/数学学习软件-${project.version}.zip"
basedir="${project.build.directory}/数学学习软件-${project.version}"/>
<echo>=== 分发包生成完成 ===</echo>
<echo>分发包位置: ${project.build.directory}/数学学习软件-${project.version}.zip</echo>
<echo>目录位置: ${project.build.directory}/数学学习软件-${project.version}/</echo>
<echo> </echo>
<echo>用户运行说明:</echo>
<echo>- 解压ZIP文件到任意位置</echo>
<echo>- 进入"数学学习软件-0.1.2"文件夹</echo>
<echo>- 双击 run.bat 启动程序</echo>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,29 @@
@echo off
chcp 65001 >nul
title 数学学习软件
echo 启动数学学习软件...
REM 检查JAR文件是否存在
if not exist "math-learning-0.1.2.jar" (
echo 错误: 找不到主程序文件 math-learning-0.1.2.jar
echo 请确保所有文件在同一个目录下
pause
exit /b 1
)
REM 检查lib目录是否存在
if not exist "lib" (
echo 错误: 找不到依赖库目录 lib
echo 请确保lib目录存在且完整
pause
exit /b 1
)
REM 运行程序
echo 正在启动程序...
java --module-path "lib" --add-modules javafx.controls,javafx.fxml -jar "math-learning-0.1.2.jar"
REM 如果程序退出,暂停窗口
echo.
echo 程序已退出。
pause

@ -282,7 +282,7 @@ public class UnifiedQuestionEngine {
static class Elementary extends Base {
public Elementary(Random random, DecimalFormat df) { super(random, df); }
@Override public MathProblem generate() {
int operandCount = random.nextInt(3) + 3; // 3-5
int operandCount = random.nextInt(5) + 1; // 1-5
int[] operands = new int[operandCount];
String[] operators = new String[operandCount - 1];
for (int i = 0; i < operandCount; i++) operands[i] = random.nextInt(100) + 1;
@ -302,54 +302,85 @@ public class UnifiedQuestionEngine {
// ---------- 初中题目生成器 ----------
static class Middle extends Base {
public Middle(Random random, DecimalFormat df) { super(random, df); }
@Override public MathProblem generate() {
// 始终生成 3-5 个操作数;当包含根号时,根号为其中一个或两个项
int operandCount = random.nextInt(3) + 3; // 3-5
boolean includeSqrt = random.nextDouble() < 0.5; // 约半数题含根号
int sqrtCount = includeSqrt ? (1 + random.nextInt(2)) : 0; // 1-2 个根号项
if (sqrtCount > operandCount) sqrtCount = operandCount; // 不超过操作数数量
@Override
public MathProblem generate() {
int operandCount = random.nextInt(5) + 1;
int sqrtCount = 1 + random.nextInt(2); // 1-2个平方/根号项
if (sqrtCount > operandCount) sqrtCount = operandCount;
return buildMathProblem(operandCount, sqrtCount);
}
private MathProblem buildMathProblem(int operandCount, int sqrtCount) {
double[] operands = new double[operandCount];
String[] operators = new String[operandCount - 1];
String[] termTexts = new String[operandCount];
// 随机选择根号项位置
Set<Integer> sqrtPos = new HashSet<>();
while (sqrtPos.size() < sqrtCount) {
sqrtPos.add(random.nextInt(operandCount));
Set<Integer> sqrtPositions = selectSqrtPositions(operandCount, sqrtCount);
buildOperandsAndTerms(operands, termTexts, sqrtPositions);
buildOperators(operators);
String expression = buildExpression(termTexts, operators);
double result = evaluateWithPrecedenceDouble(operands, operators);
return new MathProblem(expression, df.format(result), "初中");
}
private Set<Integer> selectSqrtPositions(int operandCount, int sqrtCount) {
Set<Integer> positions = new HashSet<>();
while (positions.size() < sqrtCount) {
positions.add(random.nextInt(operandCount));
}
return positions;
}
// 构造各项
for (int i = 0; i < operandCount; i++) {
if (sqrtPos.contains(i)) {
// 使用完全平方数,确保计算结果为整数,便于初中题目
int base = random.nextInt(9) + 2; // 2-10确保 √n 的 n ≤ 100
int square = base * base;
operands[i] = Math.sqrt(square); // = base
termTexts[i] = "√" + square;
private void buildOperandsAndTerms(double[] operands, String[] termTexts, Set<Integer> sqrtPositions) {
for (int i = 0; i < operands.length; i++) {
if (sqrtPositions.contains(i)) {
buildPowerOrSqrtTerm(operands, termTexts, i);
} else {
int val = random.nextInt(100) + 1; // 1-100 的常数
operands[i] = val;
termTexts[i] = String.valueOf(val);
buildNormalTerm(operands, termTexts, i);
}
}
}
private void buildPowerOrSqrtTerm(double[] operands, String[] termTexts, int index) {
boolean useSquare = random.nextBoolean();
int base = random.nextInt(9) + 2; // 2-10
// 构造运算符(保持简单四则)
if (useSquare) {
operands[index] = base * base;
termTexts[index] = base + "²";
} else {
int square = base * base;
operands[index] = base;
termTexts[index] = "√" + square;
}
}
private void buildNormalTerm(double[] operands, String[] termTexts, int index) {
int val = random.nextInt(100) + 1;
operands[index] = val;
termTexts[index] = String.valueOf(val);
}
private void buildOperators(String[] operators) {
String[] ops = {"+", "-", "*", "/"};
for (int i = 0; i < operandCount - 1; i++) {
for (int i = 0; i < operators.length; i++) {
operators[i] = ops[random.nextInt(ops.length)];
}
}
// 拼接表达式文本
private String buildExpression(String[] termTexts, String[] operators) {
StringBuilder expr = new StringBuilder();
for (int i = 0; i < operandCount; i++) {
for (int i = 0; i < termTexts.length; i++) {
expr.append(termTexts[i]);
if (i < operandCount - 1) expr.append(" ").append(operators[i]).append(" ");
if (i < operators.length) {
expr.append(" ").append(operators[i]).append(" ");
}
}
double result = evaluateWithPrecedenceDouble(operands, operators);
return new MathProblem(expr.toString(), df.format(result), "初中");
return expr.toString();
}
}
@ -357,8 +388,8 @@ public class UnifiedQuestionEngine {
static class High extends Base {
public High(Random random, DecimalFormat df) { super(random, df); }
@Override public MathProblem generate() {
// 生成包含三角函数与常数混合运算的表达式(3-5个操作数至少包含一个三角函数
int operandCount = random.nextInt(3) + 3; // 3-5
// 生成包含三角函数与常数混合运算的表达式(1-5个操作数至少包含一个三角函数
int operandCount = random.nextInt(5) + 1; // 1-5
int trigIndex = random.nextInt(operandCount);
double[] operands = new double[operandCount];
@ -413,6 +444,9 @@ public class UnifiedQuestionEngine {
// 混合三角表达式(包含常数与一个三角项)选项符号化
private ChoiceQuestion toMixedTrigSumChoice(MathProblem p) {
String expr = p.getExpression();
if (isPureTrigFunction(expr)) {
return createPureTrigChoiceQuestion(expr, p);
}
String[] tokens = expr.split(" ");
// 解析操作数与运算符
@ -522,6 +556,44 @@ public class UnifiedQuestionEngine {
int correctIndex = options.indexOf(correct);
return new ChoiceQuestion(p.getExpression() + " = ?", options, correctIndex);
}
// 判断是否为纯三角函数题目
private boolean isPureTrigFunction(String expr) {
return expr.matches("^(sin|cos|tan)\\d+$");
}
// 创建纯三角函数选择题
// 创建纯三角函数选择题
private ChoiceQuestion createPureTrigChoiceQuestion(String expr, MathProblem p) {
String func = expr.substring(0, 3);
int angle = Integer.parseInt(expr.substring(3));
String trigSym = getSymbolicTrig(func, angle);
// 正确答案
String correct = trigSym;
// 生成干扰项 - 只使用符号形式,避免数值
Set<String> optionsSet = new LinkedHashSet<>();
optionsSet.add(correct);
String[] symPool = {"0", "1/2", "√2/2", "√3/2", "1", "1/√3", "√3"};
for (String sym : symPool) {
if (optionsSet.size() >= 4) break;
if (!sym.equals(trigSym)) {
optionsSet.add(sym);
}
}
// 确保选项数量为4个
while (optionsSet.size() < 4) {
optionsSet.add("1"); // 或其他默认值
}
List<String> options = new ArrayList<>(optionsSet);
Collections.shuffle(options, random);
int correctIndex = options.indexOf(correct);
return new ChoiceQuestion(expr + " = ?", options, correctIndex);
}
// 解析常见符号三角值为数值(仅用于没有根号的情况)
private double parseSymbolicToDouble(String s) {

@ -1,18 +1,141 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="maven-antrun-" default="main">
<target name="main">
<mkdir dir="C:\Users\Chan\Desktop\coproject\target/dist" />
<mkdir dir="C:\Users\Chan\Desktop\coproject\target/dist/lib" />
<property name="dist.lib" value="C:\Users\Chan\Desktop\coproject\target/dist/lib" />
<path id="deps.jars">
<fileset includes="*.jar" dir="${dist.lib}" />
</path>
<pathconvert property="deps.cp" pathsep=" " refid="deps.jars">
<map from="C:\Users\Chan\Desktop\coproject\target/dist/lib/" to="lib/" />
<map from="C:\Users\Chan\Desktop\coproject\target/dist/lib\" to="lib/" />
</pathconvert>
<echo file="C:\Users\Chan\Desktop\coproject\target/dist/manifest.mf">Manifest-Version: 1.0
Main-Class: com.coproject.MainApp
Class-Path: ${deps.cp}</echo>
<echo>=== 开始生成分发包 ===</echo>
<mkdir dir="C:\Users\Lenovo\Desktop\coproject\target/数学学习软件-0.1.2" />
<echo file="C:\Users\Lenovo\Desktop\coproject\target/数学学习软件-0.1.2/run.bat">@echo off
chcp 65001 >nul
title 数学学习软件
echo 启动数学学习软件...
REM 检查JAR文件是否存在
if not exist "math-learning-0.1.2.jar" (
echo 错误: 找不到主程序文件 math-learning-0.1.2.jar
echo 请确保所有文件在同一个目录下
pause
exit /b 1
)
REM 检查lib目录是否存在
if not exist "lib" (
echo 错误: 找不到依赖库目录 lib
echo 请确保lib目录存在且完整
pause
exit /b 1
)
REM 运行程序
echo 正在启动程序...
java --module-path "lib" --add-modules javafx.controls,javafx.fxml -jar "math-learning-0.1.2.jar"
REM 如果程序退出,暂停窗口
echo.
echo 程序已退出。
pause</echo>
<echo file="C:\Users\Lenovo\Desktop\coproject\target/数学学习软件-0.1.2/start.bat">@echo off
chcp 65001 >nul
cd /d %~dp0
java --module-path "lib" --add-modules javafx.controls,javafx.fxml -jar "math-learning-0.1.2.jar"</echo>
<echo file="C:\Users\Lenovo\Desktop\coproject\target/数学学习软件-0.1.2/测试运行.bat">@echo off
echo 正在测试程序是否能正常运行...
cd /d %~dp0
if exist "math-learning-0.1.2.jar" (
echo ✓ 找到主程序文件
) else (
echo ✗ 找不到主程序文件
pause
exit /b 1
)
if exist "lib" (
echo ✓ 找到依赖库目录
) else (
echo ✗ 找不到依赖库目录
pause
exit /b 1
)
echo 正在启动程序...
start start.bat</echo>
<copy todir="C:\Users\Lenovo\Desktop\coproject\target/数学学习软件-0.1.2">
<fileset dir="C:\Users\Lenovo\Desktop\coproject\target/dist">
<include name="math-learning-0.1.2.jar" />
<include name="README.md" />
<include name="smtp.env.example" />
<include name="configure_smtp_qq.ps1" />
</fileset>
</copy>
<copy todir="C:\Users\Lenovo\Desktop\coproject\target/数学学习软件-0.1.2/lib">
<fileset dir="C:\Users\Lenovo\Desktop\coproject\target/dist/lib" />
</copy>
<copy todir="C:\Users\Lenovo\Desktop\coproject\target/数学学习软件-0.1.2/data">
<fileset dir="C:\Users\Lenovo\Desktop\coproject\target/dist/data" />
</copy>
<echo file="C:\Users\Lenovo\Desktop\coproject\target/数学学习软件-0.1.2/使用说明.txt">数学学习软件 v0.1.2
=== 基本信息 ===
版本号: 0.1.2
生成时间: 2025-10-12 07:43:29
开发者: Coproject 团队
=== 系统要求 ===
- 操作系统: Windows 7/10/11
- Java版本: Java 17 或更高版本
- 内存: 至少 2GB 可用内存
=== 启动方法 ===
推荐使用以下方式启动:
1. 双击运行 run.bat (推荐,有错误提示)
2. 双击 start.bat (简洁版)
3. 双击 测试运行.bat (先检查环境再启动)
=== 功能特点 ===
✓ 小学数学题目生成
✓ 初中数学题目生成(含平方根号)
✓ 高中数学题目生成(含三角函数)
✓ 选择题答题系统
✓ 邮件发送验证码功能
✓ 试卷PDF导出功能
=== 目录说明 ===
math-learning-0.1.2.jar - 主程序文件
lib/ - 程序依赖库(请勿删除或移动)
data/ - 数据存储目录
├── smtp.env - 邮箱配置文件
└── papers/ - 试卷存储目录
run.bat - Windows启动脚本(详细版)
start.bat - Windows启动脚本(简洁版)
测试运行.bat - 环境测试脚本
README.md - 项目说明文档
=== 配置说明 ===
1. 首次运行会自动创建配置文件
2. 邮箱配置请参考 smtp.env.example
3. 生成的试卷保存在 data/papers/ 目录
=== 常见问题 ===
Q: 启动时提示"缺少JavaFX运行时组件"
A: 请确保使用 .bat 文件启动不要直接双击JAR文件
Q: 邮件发送失败
A: 请检查 data/smtp.env 中的邮箱配置
Q: 程序无法启动
A: 请先运行"测试运行.bat"检查环境
=== 技术支持 ===
如有问题请联系开发团队。
注意:请保持所有文件在同一个目录下,不要单独移动文件!</echo>
<zip basedir="C:\Users\Lenovo\Desktop\coproject\target/数学学习软件-0.1.2" destfile="C:\Users\Lenovo\Desktop\coproject\target/数学学习软件-0.1.2.zip" />
<echo>=== 分发包生成完成 ===</echo>
<echo>分发包位置: C:\Users\Lenovo\Desktop\coproject\target/数学学习软件-0.1.2.zip</echo>
<echo>目录位置: C:\Users\Lenovo\Desktop\coproject\target/数学学习软件-0.1.2/</echo>
<echo></echo>
<echo>用户运行说明:</echo>
<echo>- 解压ZIP文件到任意位置</echo>
<echo>- 进入"数学学习软件-0.1.2"文件夹</echo>
<echo>- 双击 run.bat 启动程序</echo>
</target>
</project>

Binary file not shown.

@ -0,0 +1,71 @@
# 数学学习软件(当前说明)
本说明已根据最新代码与构建流程全面更新,并清理了过时脚本与旧文档。你可按本文档直接开发、运行与打包应用。
## 概述
- 技术栈Java 17、JavaFX 21、Maven、JacksonJSON 持久化、Jakarta MailSMTP、Commons Lang。
- 功能:注册/登录、验证码发送SMTP 或本地文件回退)、题目生成与作答、评分、试卷导出与打开。
- 数据存储:基于 JSON 文件,无需数据库。
## 当前状态0.1.4
- 邮件配置优先读取 `%APPDATA%\数学学习软件\data\smtp.env`,统一安装版与源码运行行为。
- “打开试卷文件夹”稳定指向 `%APPDATA%\数学学习软件\data\papers`,使用系统默认文件管理器打开。
- 打包使用 Maven 插件化流程,无需仓库内的旧脚本。
## 目录与数据路径
- 应用数据根:`%APPDATA%\数学学习软件\data`
- 用户数据:`%APPDATA%\数学学习软件\data\users.json`
- 验证码文件(未配置 SMTP 时):`%APPDATA%\数学学习软件\data\outbox.txt`
- 试卷目录:`%APPDATA%\数学学习软件\data\papers`
## 开发运行
1. 安装 JDK 17+ 与 Maven 3.8+。
2. 在项目根执行:
- 编译:`mvn -DskipTests package`
- 运行:`mvn javafx:run`
## 安装包打包Windows MSI
执行:
```powershell
mvn -DskipTests -P no-jlink clean package jpackage:jpackage
```
产物位于:`target\jpackage\数学学习软件-<版本>.msi`
## SMTP 配置(可选)
`%APPDATA%\数学学习软件\data\smtp.env` 创建配置文件:
```
SMTP_HOST=smtp.qq.com
SMTP_PORT=465
SMTP_USER=你的QQ邮箱
SMTP_PASS=你的授权码
SMTP_FROM=你的QQ邮箱
SMTP_SSL=true
```
- 使用 587 端口时,将 `SMTP_SSL=false`STARTTLS
- 安装包会附带 `dist/data/smtp.env` 示例(来自 `smtp.env.example`),实际使用以 AppData 路径为准。
- 可选便利脚本:`configure_smtp_qq.ps1` 会设置系统级环境变量(保留)。
## 常见问题排查
- 验证码未收到:检查 AppData 中 `smtp.env` 内容与端口/SSL 设置;允许应用联网。
- 未配置 SMTP验证码写入 `outbox.txt`,在“注册”页点击“打开验证码文件”查看。
- 打开试卷文件夹异常:当前实现使用 `Desktop.open`,目标路径为 `%APPDATA%\数学学习软件\data\papers`;如仍异常,请反馈你系统的 `%APPDATA%` 实际值。
## 维护说明
- 构建:`maven-jar-plugin` 输出主 JAR`maven-dependency-plugin` 复制运行时依赖到 `dist/lib``maven-antrun-plugin` 生成带 Class-Path 的清单与示例数据;`jpackage-maven-plugin` 生成 MSI。
- 清理:仓库中的旧日志、备份与不再使用的脚本/文档已删除,避免混淆与错误依赖。
## 许可证
课堂/课程作业用途,无外部依赖的许可文本。

@ -0,0 +1,36 @@
Param(
[string]$Email = "2482315830@qq.com",
[string]$AuthCode = "", # QQ邮箱授权码非登录密码
[ValidateSet("587","465")][string]$Port = "587" # 587=STARTTLS, 465=SSL
)
Write-Host "配置 QQ 邮箱 SMTP 环境变量..." -ForegroundColor Cyan
$useSsl = $Port -eq "465"
$smtpSslValue = if ($useSsl) { "true" } else { "false" }
# 显式设置变量(进程 + 用户作用域),避免哈希表解析问题
[Environment]::SetEnvironmentVariable("SMTP_HOST", "smtp.qq.com", "Process")
[Environment]::SetEnvironmentVariable("SMTP_PORT", $Port, "Process")
[Environment]::SetEnvironmentVariable("SMTP_USER", $Email, "Process")
[Environment]::SetEnvironmentVariable("SMTP_PASS", $AuthCode, "Process")
[Environment]::SetEnvironmentVariable("SMTP_FROM", $Email, "Process")
[Environment]::SetEnvironmentVariable("SMTP_SSL", $smtpSslValue, "Process")
[Environment]::SetEnvironmentVariable("SMTP_HOST", "smtp.qq.com", "User")
[Environment]::SetEnvironmentVariable("SMTP_PORT", $Port, "User")
[Environment]::SetEnvironmentVariable("SMTP_USER", $Email, "User")
[Environment]::SetEnvironmentVariable("SMTP_PASS", $AuthCode, "User")
[Environment]::SetEnvironmentVariable("SMTP_FROM", $Email, "User")
[Environment]::SetEnvironmentVariable("SMTP_SSL", $smtpSslValue, "User")
Write-Host "已设置如下环境变量:" -ForegroundColor Green
Get-ChildItem Env:SMTP_*
if ($useSsl) {
Write-Host "当前模式:端口 465启用 SSL 直连 (SMTP_SSL=true)" -ForegroundColor Cyan
} else {
Write-Host "当前模式:端口 587启用 STARTTLS (SMTP_SSL=false)" -ForegroundColor Cyan
}
Write-Host "配置完成。若刚设置用户级变量,请重新打开终端或直接在当前终端运行 mvn javafx:run 进行验证。" -ForegroundColor Green

@ -0,0 +1,2 @@
试卷存储目录
将生成的试卷PDF文件保存在此目录中。

@ -0,0 +1,5 @@
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER=your_user
SMTP_PASS=your_password
SMTP_FROM=noreply@example.com

@ -1,3 +0,0 @@
Manifest-Version: 1.0
Main-Class: com.coproject.MainApp
Class-Path: lib/commons-lang3-3.14.0.jar lib/jackson-annotations-2.17.1.jar lib/jackson-core-2.17.1.jar lib/jackson-databind-2.17.1.jar lib/jakarta.activation-2.0.1.jar lib/jakarta.mail-2.0.1.jar lib/javafx-base-21.0.3-win.jar lib/javafx-base-21.0.3.jar lib/javafx-controls-21.0.3-win.jar lib/javafx-controls-21.0.3.jar lib/javafx-fxml-21.0.3-win.jar lib/javafx-graphics-21.0.3-win.jar lib/javafx-graphics-21.0.3.jar

Binary file not shown.

Binary file not shown.

@ -0,0 +1,5 @@
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER=your_user
SMTP_PASS=your_password
SMTP_FROM=noreply@example.com

@ -1,3 +1,3 @@
artifactId=math-learning
groupId=com.coproject
version=0.1.4
version=0.1.2

@ -1,29 +1,29 @@
C:\Users\Chan\Desktop\coproject\src\main\java\com\coproject\SimpleLauncher.java
C:\Users\Chan\Desktop\coproject\src\main\java\com\coproject\controller\ForgotPasswordController.java
C:\Users\Chan\Desktop\coproject\src\main\java\com\coproject\controller\LoginController.java
C:\Users\Chan\Desktop\coproject\src\main\java\com\coproject\service\UserService.java
C:\Users\Chan\Desktop\coproject\src\main\java\module-info.java
C:\Users\Chan\Desktop\coproject\src\main\java\com\coproject\DebugMiddle.java
C:\Users\Chan\Desktop\coproject\src\main\java\com\coproject\SimpleTest.java
C:\Users\Chan\Desktop\coproject\src\main\java\com\coproject\service\UnifiedQuestionEngine.java
C:\Users\Chan\Desktop\coproject\src\main\java\com\coproject\controller\PasswordSetupController.java
C:\Users\Chan\Desktop\coproject\src\main\java\com\coproject\storage\DataPaths.java
C:\Users\Chan\Desktop\coproject\src\main\java\com\coproject\TestApp.java
C:\Users\Chan\Desktop\coproject\src\main\java\com\coproject\DebugHigh.java
C:\Users\Chan\Desktop\coproject\src\main\java\com\coproject\model\User.java
C:\Users\Chan\Desktop\coproject\src\main\java\com\coproject\service\QuestionService.java
C:\Users\Chan\Desktop\coproject\src\main\java\com\coproject\ConsoleTest.java
C:\Users\Chan\Desktop\coproject\src\main\java\com\coproject\controller\QuizController.java
C:\Users\Chan\Desktop\coproject\src\main\java\com\coproject\controller\RegisterController.java
C:\Users\Chan\Desktop\coproject\src\main\java\com\coproject\controller\GradeSelectController.java
C:\Users\Chan\Desktop\coproject\src\main\java\com\coproject\service\MailService.java
C:\Users\Chan\Desktop\coproject\src\main\java\com\coproject\storage\JsonStorage.java
C:\Users\Chan\Desktop\coproject\src\main\java\com\coproject\model\PaperRecord.java
C:\Users\Chan\Desktop\coproject\src\main\java\com\coproject\controller\ScoreController.java
C:\Users\Chan\Desktop\coproject\src\main\java\com\coproject\DirectHighDebug.java
C:\Users\Chan\Desktop\coproject\src\main\java\com\coproject\DirectMiddleDebug.java
C:\Users\Chan\Desktop\coproject\src\main\java\com\coproject\MainApp.java
C:\Users\Chan\Desktop\coproject\src\main\java\com\coproject\model\Question.java
C:\Users\Chan\Desktop\coproject\src\main\java\com\coproject\util\ValidationUtil.java
C:\Users\Chan\Desktop\coproject\src\main\java\com\coproject\controller\ChangePasswordController.java
C:\Users\Chan\Desktop\coproject\src\main\java\com\coproject\controller\DeleteAccountController.java
C:\Users\Lenovo\Desktop\coproject\src\main\java\com\coproject\service\MailService.java
C:\Users\Lenovo\Desktop\coproject\src\main\java\com\coproject\controller\ForgotPasswordController.java
C:\Users\Lenovo\Desktop\coproject\src\main\java\com\coproject\model\User.java
C:\Users\Lenovo\Desktop\coproject\src\main\java\com\coproject\controller\ScoreController.java
C:\Users\Lenovo\Desktop\coproject\src\main\java\com\coproject\ConsoleTest.java
C:\Users\Lenovo\Desktop\coproject\src\main\java\com\coproject\service\UserService.java
C:\Users\Lenovo\Desktop\coproject\src\main\java\com\coproject\controller\RegisterController.java
C:\Users\Lenovo\Desktop\coproject\src\main\java\com\coproject\storage\DataPaths.java
C:\Users\Lenovo\Desktop\coproject\src\main\java\com\coproject\model\Question.java
C:\Users\Lenovo\Desktop\coproject\src\main\java\com\coproject\util\ValidationUtil.java
C:\Users\Lenovo\Desktop\coproject\src\main\java\com\coproject\TestApp.java
C:\Users\Lenovo\Desktop\coproject\src\main\java\com\coproject\model\PaperRecord.java
C:\Users\Lenovo\Desktop\coproject\src\main\java\module-info.java
C:\Users\Lenovo\Desktop\coproject\src\main\java\com\coproject\controller\QuizController.java
C:\Users\Lenovo\Desktop\coproject\src\main\java\com\coproject\DebugMiddle.java
C:\Users\Lenovo\Desktop\coproject\src\main\java\com\coproject\DirectMiddleDebug.java
C:\Users\Lenovo\Desktop\coproject\src\main\java\com\coproject\SimpleLauncher.java
C:\Users\Lenovo\Desktop\coproject\src\main\java\com\coproject\MainApp.java
C:\Users\Lenovo\Desktop\coproject\src\main\java\com\coproject\controller\LoginController.java
C:\Users\Lenovo\Desktop\coproject\src\main\java\com\coproject\DirectHighDebug.java
C:\Users\Lenovo\Desktop\coproject\src\main\java\com\coproject\storage\JsonStorage.java
C:\Users\Lenovo\Desktop\coproject\src\main\java\com\coproject\controller\GradeSelectController.java
C:\Users\Lenovo\Desktop\coproject\src\main\java\com\coproject\service\QuestionService.java
C:\Users\Lenovo\Desktop\coproject\src\main\java\com\coproject\DebugHigh.java
C:\Users\Lenovo\Desktop\coproject\src\main\java\com\coproject\controller\DeleteAccountController.java
C:\Users\Lenovo\Desktop\coproject\src\main\java\com\coproject\service\UnifiedQuestionEngine.java
C:\Users\Lenovo\Desktop\coproject\src\main\java\com\coproject\controller\ChangePasswordController.java
C:\Users\Lenovo\Desktop\coproject\src\main\java\com\coproject\SimpleTest.java
C:\Users\Lenovo\Desktop\coproject\src\main\java\com\coproject\controller\PasswordSetupController.java

@ -0,0 +1,71 @@
# 数学学习软件(当前说明)
本说明已根据最新代码与构建流程全面更新,并清理了过时脚本与旧文档。你可按本文档直接开发、运行与打包应用。
## 概述
- 技术栈Java 17、JavaFX 21、Maven、JacksonJSON 持久化、Jakarta MailSMTP、Commons Lang。
- 功能:注册/登录、验证码发送SMTP 或本地文件回退)、题目生成与作答、评分、试卷导出与打开。
- 数据存储:基于 JSON 文件,无需数据库。
## 当前状态0.1.4
- 邮件配置优先读取 `%APPDATA%\数学学习软件\data\smtp.env`,统一安装版与源码运行行为。
- “打开试卷文件夹”稳定指向 `%APPDATA%\数学学习软件\data\papers`,使用系统默认文件管理器打开。
- 打包使用 Maven 插件化流程,无需仓库内的旧脚本。
## 目录与数据路径
- 应用数据根:`%APPDATA%\数学学习软件\data`
- 用户数据:`%APPDATA%\数学学习软件\data\users.json`
- 验证码文件(未配置 SMTP 时):`%APPDATA%\数学学习软件\data\outbox.txt`
- 试卷目录:`%APPDATA%\数学学习软件\data\papers`
## 开发运行
1. 安装 JDK 17+ 与 Maven 3.8+。
2. 在项目根执行:
- 编译:`mvn -DskipTests package`
- 运行:`mvn javafx:run`
## 安装包打包Windows MSI
执行:
```powershell
mvn -DskipTests -P no-jlink clean package jpackage:jpackage
```
产物位于:`target\jpackage\数学学习软件-<版本>.msi`
## SMTP 配置(可选)
`%APPDATA%\数学学习软件\data\smtp.env` 创建配置文件:
```
SMTP_HOST=smtp.qq.com
SMTP_PORT=465
SMTP_USER=你的QQ邮箱
SMTP_PASS=你的授权码
SMTP_FROM=你的QQ邮箱
SMTP_SSL=true
```
- 使用 587 端口时,将 `SMTP_SSL=false`STARTTLS
- 安装包会附带 `dist/data/smtp.env` 示例(来自 `smtp.env.example`),实际使用以 AppData 路径为准。
- 可选便利脚本:`configure_smtp_qq.ps1` 会设置系统级环境变量(保留)。
## 常见问题排查
- 验证码未收到:检查 AppData 中 `smtp.env` 内容与端口/SSL 设置;允许应用联网。
- 未配置 SMTP验证码写入 `outbox.txt`,在“注册”页点击“打开验证码文件”查看。
- 打开试卷文件夹异常:当前实现使用 `Desktop.open`,目标路径为 `%APPDATA%\数学学习软件\data\papers`;如仍异常,请反馈你系统的 `%APPDATA%` 实际值。
## 维护说明
- 构建:`maven-jar-plugin` 输出主 JAR`maven-dependency-plugin` 复制运行时依赖到 `dist/lib``maven-antrun-plugin` 生成带 Class-Path 的清单与示例数据;`jpackage-maven-plugin` 生成 MSI。
- 清理:仓库中的旧日志、备份与不再使用的脚本/文档已删除,避免混淆与错误依赖。
## 许可证
课堂/课程作业用途,无外部依赖的许可文本。

@ -0,0 +1,36 @@
Param(
[string]$Email = "2482315830@qq.com",
[string]$AuthCode = "", # QQ邮箱授权码非登录密码
[ValidateSet("587","465")][string]$Port = "587" # 587=STARTTLS, 465=SSL
)
Write-Host "配置 QQ 邮箱 SMTP 环境变量..." -ForegroundColor Cyan
$useSsl = $Port -eq "465"
$smtpSslValue = if ($useSsl) { "true" } else { "false" }
# 显式设置变量(进程 + 用户作用域),避免哈希表解析问题
[Environment]::SetEnvironmentVariable("SMTP_HOST", "smtp.qq.com", "Process")
[Environment]::SetEnvironmentVariable("SMTP_PORT", $Port, "Process")
[Environment]::SetEnvironmentVariable("SMTP_USER", $Email, "Process")
[Environment]::SetEnvironmentVariable("SMTP_PASS", $AuthCode, "Process")
[Environment]::SetEnvironmentVariable("SMTP_FROM", $Email, "Process")
[Environment]::SetEnvironmentVariable("SMTP_SSL", $smtpSslValue, "Process")
[Environment]::SetEnvironmentVariable("SMTP_HOST", "smtp.qq.com", "User")
[Environment]::SetEnvironmentVariable("SMTP_PORT", $Port, "User")
[Environment]::SetEnvironmentVariable("SMTP_USER", $Email, "User")
[Environment]::SetEnvironmentVariable("SMTP_PASS", $AuthCode, "User")
[Environment]::SetEnvironmentVariable("SMTP_FROM", $Email, "User")
[Environment]::SetEnvironmentVariable("SMTP_SSL", $smtpSslValue, "User")
Write-Host "已设置如下环境变量:" -ForegroundColor Green
Get-ChildItem Env:SMTP_*
if ($useSsl) {
Write-Host "当前模式:端口 465启用 SSL 直连 (SMTP_SSL=true)" -ForegroundColor Cyan
} else {
Write-Host "当前模式:端口 587启用 STARTTLS (SMTP_SSL=false)" -ForegroundColor Cyan
}
Write-Host "配置完成。若刚设置用户级变量,请重新打开终端或直接在当前终端运行 mvn javafx:run 进行验证。" -ForegroundColor Green

@ -0,0 +1,2 @@
试卷存储目录
将生成的试卷PDF文件保存在此目录中。

@ -0,0 +1,5 @@
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER=your_user
SMTP_PASS=your_password
SMTP_FROM=noreply@example.com

@ -0,0 +1,29 @@
@echo off
chcp 65001 >nul
title 数学学习软件
echo 启动数学学习软件...
REM 检查JAR文件是否存在
if not exist "math-learning-0.1.2.jar" (
echo 错误: 找不到主程序文件 math-learning-0.1.2.jar
echo 请确保所有文件在同一个目录下
pause
exit /b 1
)
REM 检查lib目录是否存在
if not exist "lib" (
echo 错误: 找不到依赖库目录 lib
echo 请确保lib目录存在且完整
pause
exit /b 1
)
REM 运行程序
echo 正在启动程序...
java --module-path "lib" --add-modules javafx.controls,javafx.fxml -jar "math-learning-0.1.2.jar"
REM 如果程序退出,暂停窗口
echo.
echo 程序已退出。
pause

@ -0,0 +1,5 @@
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER=your_user
SMTP_PASS=your_password
SMTP_FROM=noreply@example.com

@ -0,0 +1,4 @@
@echo off
chcp 65001 >nul
cd /d %~dp0
java --module-path "lib" --add-modules javafx.controls,javafx.fxml -jar "math-learning-0.1.2.jar"

@ -0,0 +1,56 @@
数学学习软件 v0.1.2
=== 基本信息 ===
版本号: 0.1.2
生成时间: 2025-10-12 07:43:29
开发者: Coproject 团队
=== 系统要求 ===
- 操作系统: Windows 7/10/11
- Java版本: Java 17 或更高版本
- 内存: 至少 2GB 可用内存
=== 启动方法 ===
推荐使用以下方式启动:
1. 双击运行 run.bat (推荐,有错误提示)
2. 双击 start.bat (简洁版)
3. 双击 测试运行.bat (先检查环境再启动)
=== 功能特点 ===
✓ 小学数学题目生成
✓ 初中数学题目生成(含平方根号)
✓ 高中数学题目生成(含三角函数)
✓ 选择题答题系统
✓ 邮件发送验证码功能
✓ 试卷PDF导出功能
=== 目录说明 ===
math-learning-0.1.2.jar - 主程序文件
lib/ - 程序依赖库(请勿删除或移动)
data/ - 数据存储目录
├── smtp.env - 邮箱配置文件
└── papers/ - 试卷存储目录
run.bat - Windows启动脚本(详细版)
start.bat - Windows启动脚本(简洁版)
测试运行.bat - 环境测试脚本
README.md - 项目说明文档
=== 配置说明 ===
1. 首次运行会自动创建配置文件
2. 邮箱配置请参考 smtp.env.example
3. 生成的试卷保存在 data/papers/ 目录
=== 常见问题 ===
Q: 启动时提示"缺少JavaFX运行时组件"
A: 请确保使用 .bat 文件启动不要直接双击JAR文件
Q: 邮件发送失败
A: 请检查 data/smtp.env 中的邮箱配置
Q: 程序无法启动
A: 请先运行"测试运行.bat"检查环境
=== 技术支持 ===
如有问题请联系开发团队。
注意:请保持所有文件在同一个目录下,不要单独移动文件!

@ -0,0 +1,22 @@
@echo off
echo 正在测试程序是否能正常运行...
cd /d %~dp0
if exist "math-learning-0.1.2.jar" (
echo ✓ 找到主程序文件
) else (
echo ✗ 找不到主程序文件
pause
exit /b 1
)
if exist "lib" (
echo ✓ 找到依赖库目录
) else (
echo ✗ 找不到依赖库目录
pause
exit /b 1
)
echo 正在启动程序...
start start.bat
Loading…
Cancel
Save