- 1.getStudentList
- 2.studentDelete
- 3.getStudentListExcl
- 4.studentEditSave
- 5.getStudentIntroduceData
- 6.saveStudentIntroduce
- 7.importFeeData
- 8.uploadPhoto
- 9.getStudentIntroducePdf
- 10.getFileByteData
- 11.getStudentInfo
- 12.examine/achievementPass
- 13.getHomeworkOptionItemListByStudentIdAndCourseId
该系统能够建立符合标准的基础数据库,实现数据的统一规范,管理,实现数据变化的一致性控制,并具有三个端口,分别通过不同账号登入。
通过用户名admin密码登入界面,能够增删改查全体学生及教师的各种信息。
通过学号密码登入界面,展示并管理该学号对应学生的各种信息。
学生端添加不需审核信息时示例序列图:
学生端添加需审核信息时示例序列图s:
通过工号密码登入界面,展示并管理该工号对应教师的各种信息。
- IntelliJ IDEA
- Windows 11 X64环境
- JavaFX,JavaFX是java实现图形界面的一种方式,包括可以直接调用Java API的能力。因为 JavaFX Script是静态类型,它同样具有结构化代码、重用性和封装性,如包、类、继承和单独编译和发布单元,这些特性使得使用JavaFX技术创建和管理大型程序变为可能。JavaFX可以实现逻辑和样式的分离,可以使用xml和css来编写样式。
- Java Spring Boot,Spring Boot是由Pivotal团队提供的一套开源框架,可以简化spring应用的创建及部署。它提供了丰富的Spring模块化支持,可以帮助开发者更轻松快捷地构建出企业级应用。Spring Boot通过自动配置功能,降低了复杂性,同时支持基于JVM的多种开源框架,可以缩短开发时间,使开发更加简单和高效。
- 此页面统一管理学生的所有信息,用户通过此界面可以查看系统中已有的学生的信息,可选择相应的学生进行编辑、删除、查询以及新增学生信息。
- 添加学生时需保证身份证号合法,同时,需保证生日与身份证号对应,若不合法或不对应会有弹出错误提示框。
- 对学生的查询可以通过姓名和学号两种方式查询。
- 此页面统一管理教师的所有信息,用户通过此界面可以查看系统中已有的教师的信息,可选择相应的教师进行编辑、删除、查询以及新增教师信息。
- 添加教师时需保证身份证号合法,同时,需保证生日与身份证号对应,若不合法或不对应会有弹出错误提示框。
- 对教师的查询可以通过教师姓名和工号两种方式查询。
- 此页面统一管理学生教师的以往入学信息,用户通过此界面可以查看对应学生教师的教育经历,可对查看的学生教师的教育经历进行编辑和删除。如果查看的学生教师信息缺失,可对其进行添加。
- 教育经历包括学校名称,级别,入学时间,毕业时间,担任职务、证明人等信息。
- 此页面统一管理学生教师的家庭成员信息,用户通过此界面可以查看对应学生教师的家庭信息,可对查看的学生教师的家庭信息进行编辑和删除。如果查看的学生教师信息缺失,可对其进行添加。
- 家庭成员信息包括成员名字、成员与用户关系、生日、性别等信息。
- 此页面统一管理学生教师的员社会关系信息,用户通过此界面可以查看对应学生教师的社会关系,可对查看的学生教师的社会关系信息进行编辑和删除。如果查看的学生社会关系信息缺失,可对其进行添加。
- 社会关系信息包括成员名字、成员与用户关系、生日、性别等信息。
- 管理员端可在此页面添加、删除、修改学生的考勤信息。
- 教师端和学生端对考勤信息只读。
- 考勤信息包括学生个人基本信息,课程基本信息,考勤结果,日期等信息。
- 管理员端可在此页面添加、删除、修改学生的作业信息。
- 教师端和学生端对作业信息只读。
- 作业信息包括学生个人基本信息,课程基本信息,作业名称,得分等信息。
- 管理员端可在此页面添加、删除、修改学生的成绩信息。
- 可使用下拉框选的形式查询课程
- 教师端和学生端对作业信息只读。
- 作业信息包括学生个人基本信息,课程基本信息,学分,成绩等信息。
- 学生端可查看自己当前平均绩点
- 管理员端可在此页面添加、删除、修改学生的课程信息。
- 教师端和学生端对课程信息只读。
- 课程信息包括课程的名称、课序号、学年、学时、学分、上课教师、教师工号、上课时间、地点等信息。
- 可根据课程名或课序号进行查询
- 学生端可查看个人课表
- 课表以课程表的形式呈现学生所选的课程,包括课程名、上课教师以及上课地点,方便学生查看课程安排。
- 管理员和学生可在此页面添加、删除、修改学生的文艺演出信息。
- 管理员可通过时间对学生文艺演出信息查询。
- 文艺演出信息包括学生学号、姓名、汇演类型、日期、地点、节目等信息,在详情页可进行编辑修改。
- 管理员和学生可在此页面添加、删除、修改学生的体育活动的信息。
- 管理员可通过名称和日期对学生体育活动信息进行查询。
- 体育活动信息主要包括学生学号、姓名、活动名称、日期、地点等信息,其中可在详情页查看体育活动的详细介绍,并进行编辑修改。
- 管理员和学生可在此页面添加、删除、修改学生的外出旅游管理的信息。
- 管理员可通过日期和地点对学生外出旅游信息进行查询。
- 外出旅游信息主要包括学生学号、姓名、旅行主题、日期、地点等信息,其中可在详情页查看外出旅游的详细介绍,并进行编辑修改。
- 管理员和学生可在此页面添加、删除、修改学生的聚会信息。
- 管理员可通过组织者和地点对学生聚会信息进行查询。
- 聚会信息主要包括学生学号、姓名、聚会主题、日期、地点、组织者等信息,其中可在详情页查看聚会的详细介绍,并进行编辑修改。
-
管理员和学生可在此页面添加、删除、修改学生的社会实践的信息。
-
学生修改或新增信息后会显示待审核状态,管理员可以从后台进行审核。
-
管理员可通过学号和姓名对学生社会实践信息进行查询。
-
社会实践信息主要包括学生学号、姓名、立项属性、团队名称、主题、摘要、学生自评、过程阐述等信息,其中可在详情页查看社会实践的详细介绍。
-
管理员和学生可在此页面添加、删除、修改学生的学科竞赛的信息。
-
学生修改或新增信息后会显示待审核状态,管理员可以从后台进行审核。
-
管理员可通过学号和姓名对学生学科竞赛信息进行查询。
-
学科竞赛信息主要包括学生学号、姓名、竞赛名称、竞赛级别、团队名称、团队成员、指导教师、获奖情况、排名等信息,其中可在详情页查看学科竞赛的详细介绍。
-
管理员和学生可在此页面添加、删除、修改学生的培训讲座的信息。
-
学生修改或新增信息后会显示待审核状态,管理员可以从后台进行审核。
-
管理员可通过学号和姓名对学生学科培训讲座进行查询。
-
培训讲座信息主要包括学生学号、姓名、主题、主讲人、时间、地点、素拓分、收获与感悟等信息,其中可在详情页查看培训讲座的详细介绍。
-
管理员和学生可在此页面添加、删除、修改学生的校外实习的信息。
-
学生修改或新增信息后会显示待审核状态,管理员可以从后台进行审核。
-
管理员可通过学号和姓名对学生学科校外实习进行查询。
-
校外实习信息主要包括学生学号、姓名、实习单位、实习时长、实习岗位、实习证明等信息,其中可在详情页查看校外实习的详细介绍。
-
管理员和学生可在此页面添加、删除、修改学生的科研成果的信息。
-
学生修改或新增信息后会显示待审核状态,管理员可以从后台进行审核。
-
管理员可通过学号和姓名对学生学科科研成果进行查询。
-
科研成果信息主要包括学生学号、姓名、主题、主讲人、时间、地点、素拓分、收获与感悟等信息,其中可在详情页查看科研成果的详细介绍。
-
管理员和学生可在此页面添加、删除、修改学生的创新项目的信息。
-
学生修改或新增信息后会显示待审核状态,管理员可以从后台进行审核。
-
管理员可通过学号和姓名对学生创新项目信息进行查询。
-
创新项目信息主要包括学生学号、姓名、项目名称、团队名称、团队成员、指导教师、是否投稿/参赛、阐述及成果等信息,其中可在详情页查看创新项目的详细介绍。
- 管理员、学生和教师可在此页面添加、删除、修改奖励的信息。
- 管理员添加后,审核状态自动修改为已通过。
- 学生及教师添加后,审核状态为待审核,等待管理员进行审核。
- 若学生及教师编辑审核已通过的信息,审核状态会自动修改为待审核。
- 管理员可通过学号/工号及姓名对奖励信息进行查询。
- 奖励信息主要包括名称,级别,种类,时间等内容,其中可在详情页查看奖励信息的具体内容,并进行编辑修改,管理员可审核。
- 管理员可在此页面添加、删除、修改学生的处分信息。
- 学生端只读,不可修改。
- 管理员可通过学号及姓名对处分信息进行查询。
- 处分信息主要包括名称,处分内容时间等,其中管理员可在详情页对处分信息进行编辑修改。
-
管理员可在此页面添加、删除、修改学生的请假信息。
-
管理员添加后,审核状态自动修改为已通过。
-
学生添加后,审核状态为待审核,等待管理员进行审核。
-
若学生编辑审核已通过的信息,审核状态会自动修改为待审核。
-
管理员可通过学号及姓名对请假信息进行查询。
-
请假信息包括学号姓名,外出地点,开始时间,结束时间等内容,其中可在详情页查看请假信息的具体内容,并进行编辑修改,管理员可审核。
- 管理员可在此页面添加、删除、修改学生的消费信息。
- 消费信息包括消费金额,日期等内容,可在详情页进行编辑修改。
- 学生端能够计算平均消费。
- 教师和学生端可查看个人画像,画像内容包含该用户基本信息,教育经历,家庭成员,消费信息等内容。
- 个人简历在个人画像界面,使用者可以在HTML转换器中修改美化个人简历,可以通过PDF查看预览简介,并实现导出为pdf文档。
- 初始时通过代码获取学生和教师的基本信息、教育经历、所获荣誉、竞赛经历、科研成果、创新项目并合理且美观地呈现在编辑器内。
在原有功能的基础上设置弹窗,使用户更好地与页面进行交互,功能更加人性化。弹窗处于信息层级的顶端,可以给用户强的提醒。弹窗要求用户必须作出回馈后,才能继续其他操作,强制性让用户根本无法忽略弹窗的存在。同时弹窗相对于其他引导形式尺寸更大,能够承载更多的活动信息,有效的增强氛围。
弹窗设计中有很多细节:
1.在打开弹窗后主页面无法关闭,无法退出登录,必须先关闭弹窗才能关闭主页面和退出登录。
- 主页面关闭权限设置:
stage.setOnCloseRequest(event ->{ MainFrameController mainFrameController=(MainFrameController)ControllerStageManager.controller.get("mainFrameController"); mainFrameController.getLogoutButton().setDisable(false); MainApplication.setCanClose(true); });
MainApplication.setCanClose(false);
MainApplication.setCanClose(true);
- 退出登录权限设置:
MainFrameController mainFrameController=(MainFrameController)ControllerStageManager.controller.get("mainFrameController"); mainFrameController.getLogoutButton().setDisable(true);2.在添加时若输入不合法信息,在错误提示弹窗弹出并关闭后,添加及编辑的弹窗不会自动关闭,会保留所填写的内容,为用户提供便利。
3.添加及编辑的弹窗始终位于顶层。
stage.setAlwaysOnTop(true);
在学生端添加了查看个人课表的功能
public class CourseScheduleController {
@FXML
private GridPane scheduleGridPane;
@FXML
private ScrollPane scrollPane;
@FXML
public void initialize() {
//将scrollPane的高度和tabPane的高度绑定
MainFrameController mainFrameController=(MainFrameController)ControllerStageManager.controller.get("MainFrameController");
scrollPane.prefHeightProperty().bind(mainFrameController.getContentTabPane().heightProperty());
ControllerStageManager.controller.remove("MainFrameController");
DataRequest req=new DataRequest();
DataResponse res;
req.put("userId", AppStore.getJwt().getId());
req.put("numName","");
res = HttpRequestUtil.request("/api/course/getByStudentIdAndNumName",req); //从后台获取所有考勤信息列表集合
ArrayList<Map> courseList=(ArrayList<Map>)res.getData();
for (int i=0;i<courseList.size();i++){
Label courseName=new Label(CommonMethod.getString(courseList.get(i),"courseName"));
Label teacherName=new Label(CommonMethod.getString(courseList.get(i),"teacherName"));
Label place=new Label(CommonMethod.getString(courseList.get(i),"place"));
String time=CommonMethod.getString(courseList.get(i),"time");
for(int j=0;j<time.length();j+=7){
char cDay=time.charAt(j+2);
char cLesson=time.charAt(j+4);
Integer day=null,lesson=null;
switch (cDay){
case '一':
day=1;
break;
case '二':
day=2;
break;
case '三':
day=3;
break;
case '四':
day=4;
break;
case '五':
day=5;
break;
case '六':
day=6;
break;
case '日':
day=7;
break;
}
switch (cLesson){
case '一':
lesson=1;
break;
case '二':
lesson=2;
break;
case '三':
lesson=3;
break;
case '四':
lesson=4;
break;
case '五':
lesson=5;
break;
}
if(day!=null&lesson!=null){
courseName.setStyle("-fx-font-size:15px");
VBox SBox=new VBox(courseName,teacherName,place);
SBox.setAlignment(Pos.CENTER);
switch (day){
case 1:
SBox.setStyle("-fx-background-color:#ffcccc;-fx-background-radius:8px");
break;
case 2:
SBox.setStyle("-fx-background-color:#ffe6cc;-fx-background-radius:8px");
break;
case 3:
SBox.setStyle("-fx-background-color:#ffffcc;-fx-background-radius:8px");
break;
case 4:
SBox.setStyle("-fx-background-color:#e6ffcc;-fx-background-radius:8px");
break;
case 5:
SBox.setStyle("-fx-background-color:#ccffcc;-fx-background-radius:8px");
break;
case 6:
SBox.setStyle("-fx-background-color:#ccffe6;-fx-background-radius:8px");
break;
case 7:
SBox.setStyle("-fx-background-color:#ccffff;-fx-background-radius:8px");
break;
}
VBox FBox=(VBox) (scheduleGridPane.getChildren().get(lesson*8+day));
FBox.setMargin(SBox,new Insets(1.5,1.5,1.5,1.5));
FBox.setVgrow(SBox, Priority.ALWAYS);
FBox.getChildren().add(SBox);
}
}
}
}
}
体现山东大学独有的风格与特色,与山大百年红色基因相结合,展现出浓重的历史厚重感。
在目录设计方面,队伍突破了原有菜单在面板上方的设计,而采用在屏幕左侧的树状菜单。
树状目录使得检索效率更高,结构更加清晰简洁明了。
- 代码示例如下:
//设置一个虚拟根节点
TreeItem<String> root=new TreeItem<>();
TreeItem<String> rootItem;
TreeItem<String> item;
TreeItem<String> item1;
rootItem=new TreeItem<>("账号管理");
item= new TreeItem<> ("修改密码");
rootItem.getChildren().add(item);
item= new TreeItem<> ("课程资料");
rootItem.getChildren().add(item);
item= new TreeItem<> ("项目文档");
rootItem.getChildren().add(item);
item= new TreeItem<> ("项目视频");
rootItem.getChildren().add(item);
root.getChildren().add(rootItem);
if(role.equals("ROLE_STUDENT") || role.equals("ROLE_TEACHER")) {
item= new TreeItem<> ("个人画像");
rootItem.getChildren().add(item);
}
if(role.equals("ROLE_ADMIN")) {
rootItem= new TreeItem<>("人员管理");
item=new TreeItem<>("学生管理");
rootItem.getChildren().add(item);
item=new TreeItem<>("教师管理");
rootItem.getChildren().add(item);
root.getChildren().add(rootItem);
rootItem=new TreeItem<>("教务管理");
item=new TreeItem<>("学习信息管理");
item1=new TreeItem<>("课程管理");
item.getChildren().add(item1);
item1=new TreeItem<>("考勤管理");
item.getChildren().add(item1);
item1=new TreeItem<>("作业管理");
item.getChildren().add(item1);
item1=new TreeItem<>("成绩管理");
item.getChildren().add(item1);
rootItem.getChildren().add(item);
root.getChildren().add(rootItem);
}
在项目中加入以下代码,引入Lombok
依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
<scope>provided</scope>
</dependency>
我们在实体类加入了@Setter
与@Getter
注解后,这时 Lombok
会代替我们在编译的时候,去 class
文件增加 get
与 set
方法,减少了代码的重复,在新增属性时,可减少大量的代码维护工作,同时增强代码的可读性。
项目中采用了一对一,一对多,多对多的对应关系设计数据库。
在创建一对多映射时,要在多的一方添加外键。但是在建立多对多关系的映射时,我们借助一张中间表,并在中间表里添加外键。
其中学生和课程,老师和课程部分均使用中间表达到多对多的对应关系。
具体数据库结构如下图所示:
在作业、成绩、考勤页面的查询功能采用下拉框选的形式
<FlowPane fx:id="chooseFlowPane" alignment="CENTER_RIGHT" prefHeight="40.0" prefWidth="800.0" BorderPane.alignment="CENTER">
<children>
<Label text="年级" textFill="WHITE">
<FlowPane.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</FlowPane.margin>
</Label>
<ComboBox fx:id="gradeComboBox" style="-fx-background-color: white;">
<FlowPane.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</FlowPane.margin>
</ComboBox>
<Label text="班级" textFill="WHITE">
<FlowPane.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</FlowPane.margin>
</Label>
<Button fx:id="resetButton" mnemonicParsing="false" onAction="#onResetButtonClick" style="-fx-background-color: white;" text="重置" textFill="#920e14" />
<Button fx:id="queryButton" mnemonicParsing="false" onAction="#onQueryButtonClick" style="-fx-background-color: white;" text="查询" textFill="#920e14">
<FlowPane.margin>
<Insets left="5.0" right="5.0" />
</FlowPane.margin>
</Button>
</children>
</FlowPane>
@FXML
protected void onQueryButtonClick(){
if(AppStore.getJwt().getRoles().equals("ROLE_TEACHER")&&!courseComboBox.isDisable()){
DataResponse res;
DataRequest req =new DataRequest();
req.put("userId",AppStore.getJwt().getId());
res = HttpRequestUtil.request("/api/score/getScoreListByTeacherId",req); //从后台获取所有学生信息列表集合
if(res != null && res.getCode()== 0) {
scoreList = (ArrayList<Map>)res.getData();
}
setTableViewData();
return;
}
Integer studentId = 0;
Integer courseId = 0;
Integer gradeId=0;
Integer clazzId = 0;
OptionItem op;
op = gradeComboBox.getSelectionModel().getSelectedItem();
if(op != null) {
gradeId=op.getId();
}
op = clazzComboBox.getSelectionModel().getSelectedItem();
if(op != null) {
clazzId=op.getId();
}
op = studentComboBox.getSelectionModel().getSelectedItem();
if(op != null) {
studentId = op.getId();
}
op = courseComboBox.getSelectionModel().getSelectedItem();
if(op != null) {
courseId = op.getId();
}
DataResponse res;
DataRequest req =new DataRequest();
req.put("gradeId",gradeId);
req.put("clazzId",clazzId);
if(AppStore.getJwt().getRoles().equals("ROLE_STUDENT")){
req.put("userId",AppStore.getJwt().getId());
}
else {
req.put("studentId",studentId);
}
req.put("courseId",courseId);
res = HttpRequestUtil.request("/api/score/getScoreList",req); //从后台获取所有学生信息列表集合
if(res != null && res.getCode()== 0) {
scoreList = (ArrayList<Map>)res.getData();
}
setTableViewData();
}
- 添加学生和教师时,对身份证号是否合法进行判断。
- 对于身份证号于生日是否一致进行判断!
- 在添加成绩等数据时,对输入是否为数字进行判断。
具体实现方法在工具类中添加以下代码并引用:
//后端
package org.fatmansoft.teach.util;
public class FormatJudge {
public static boolean IdCard(String str) {
if(str.length()!=18){
return false;
}
//创建数组arr[]存放17位系数
int arr[] = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
//创建数组arrCheck[]存放校验码,元素对应余数为数组下标,88为大写'X'字符的ASCII码
int arrCheck[] = {1, 0, 88, 9, 8, 7, 6, 5, 4, 3, 2};
//计算身份证前17位与17位系数乘积的总和
int sum = 0;
for (int i = 0; i < arr.length; i++) {
char c = str.charAt(i);
int a = c - 48;
sum += a * arr[i];
}
//身份证为X结尾
if (str.charAt(17) == 88) {
//总和sum对11取余后通过数组arrCheck[]校验
if (arrCheck[sum % 11] == 88)
return true;
else
return false;
}
//身份证为阿拉伯数字结尾
else {
//将身份证最后一位数字字符转换为int型
char c = str.charAt(17);
//总和sum对11取余后通过数组arrCheck[]校验
if (arrCheck[sum % 11] == c - 48)
return true;
else
return false;
}
}
public static boolean birthday(String birthday,String card){
//2000-10-10
String day = card.substring(6,14);
String day0 = birthday.substring(0,4)+birthday.substring(5,7)+birthday.substring(8,10);
if(day.equals(day0)){
return true;
}else{
return false;
}
}
public static boolean isInteger(String str) {
if (null == str || "".equals(str)) {
return false;
}
Pattern pattern = Pattern.compile("^-?\\d+(\\.\\d+)?$");
return pattern.matcher(str).matches();
}
//前端CommonMethod类
public static boolean isDouble(String str) {
if (null == str || "".equals(str)) {
return false;
}
Pattern pattern = Pattern.compile("[+-]?[0-9]+\\.([0-9]+)");
return pattern.matcher(str).matches();
}
包图
实体类图
获取学生信息列表
学生管理 点击查询按钮请求
前台请求参数 numName
学号或名称的查询串
返回前端 存储学生信息的 MapList
框架会自动将Map
转换程用于前后台传输数据的Json对象,Map
的嵌套结构和Json
的嵌套结构类似
删除学生信息
Student
页面的列表里点击删除按钮则可以删除已经存在的学生信息, 前端会将该记录的id
回传到后端,方法从参数获取id,查出相关记录,调用delete
方法删除
这里注意删除顺序,应为user关联person,Student关联Person 所以要先删除Student,User,再删除Person
以Excl形式导出学生基本信息列表
前端学生信息提交服务
前端把所有数据打包成一个Json
对象作为参数传回后端,后端直接可以获得对应的Map
对象form
, 再从form
里取出所有属性,复制到实体对象里,保存到数据库里即可。
如果是添加一条记录, id
为空,这是先 new Person
, User
,Student
计算新的id
,复制相关属性,保存,如果是编辑原来的信息,studentId
不为空,则查询出实体对象,复制相关属性,保存后修改数据库信息,永久修改
新建修改学生的主键 student_id
返回前端
获取学生个人画像的数据
@param dataRequest
从前端获取 studentId
查询学生信息的主键 student_id
根据studentId
从数据库中查出相关数据,存在Map
对象里,并返回前端
@return
操作正常
保存学生在前端对个人简历的修改内容
学生在HTML
转换器中可对自己的个人简历进行修改美化,以html代码的形式传给后端,存储在数据库中。
导入消费信息
@param barr
文件二进制数据
@param uploader
上传者
@param studentIdStr student
主键
@param fileName
前端上传的文件名
@return
上传图片
查看生成的个人简历pdf
生成获取个人简历的PDF数据流服务
@param dataRequest studentId
学生主键
@return
返回PDF文件二进制数据
显示上传的个人照片
前端点击学生列表时前端获取学生详细信息请求服务
@param dataRequest
从前端获取 studentId 查询学生信息的主键 student_id
@return
根据studentId从数据库中查出数据,存在Map对象里,并返回前端
管理员审核通过
@param dataRequest
从前端获取 achievementId 查询成就信息的主键 achievement_id
修改实体类属性status
为已通过对应的1
@return
操作正常
根据所选学生和课程获取作业选项列表,用于显示下拉列表的内容
所需参数 studentId courseId
实现思路 根据studentId和courseId查找scoreId,再根据scoreId查找对应的作业记录
返回前端 用相应的方法将获取的List打包成List发送给前端,方便其使用
创建添加,读取查询,更新修改,删除:[以成就类为例]:
设置各种所需属性 确定主键 表的关联以及一对多多对多等对应关系。
@Getter
@Setter
@Entity
@Table( name = "achievement",
uniqueConstraints = {
})
public class Achievement {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer achievementId;
@ManyToOne
@JoinColumn(name = "student_id")
private Student student;
@ManyToOne
@JoinColumn(name = "teacher_id")
private Teacher teacher;
private String name;
//奖项名称
private String level;
//等级 国家级 省级 市级 校级 院级
private String type;
private String content;
//内容
private String time;
private Integer status=0;
// 2为未通过 1为已通过审核 0为待审核
}
将封装Map的方法封装至Service
类中。
@Service
public class AchievementService {
@Autowired
private AchievementRepository achievementRepository;
/**
* getMapFromAchievement 将学生成就属性数据转换复制MAp集合里
*/
public Map getMapFromAchievement(Achievement achievement) {
Map m = new HashMap();
Student s;
Teacher t;
if (achievement == null)
return m;
m.put("achievementId",achievement.getAchievementId());
m.put("achievementName", achievement.getName());
m.put("achievementLevel", achievement.getLevel());
m.put("time", achievement.getTime());
m.put("type", achievement.getType());
m.put("content", achievement.getContent());
m.put("status", achievement.getStatus());
Integer status = achievement.getStatus();
m.put("statusName", ComDataUtil.getInstance().getStatusByValue(status));//性别类型的值转换成数据类型名
s = achievement.getStudent();
t = achievement.getTeacher();
if (s == null && t ==null)
return m;
if (s != null) {
m.put("personId", s.getPerson().getPersonId());
m.put("num", s.getPerson().getNum());
m.put("name", s.getPerson().getName());
m.put("dept", s.getPerson().getDept());
m.put("card", s.getPerson().getCard());
String gender = s.getPerson().getGender();
m.put("gender", s.getPerson().getGender());
m.put("genderName", ComDataUtil.getInstance().getDictionaryLabelByValue("XBM", gender)); //性别类型的值转换成数据类型名
m.put("birthday", s.getPerson().getBirthday()); //时间格式转换字符串
m.put("email", s.getPerson().getEmail());
m.put("phone", s.getPerson().getPhone());
m.put("address", s.getPerson().getAddress());
m.put("introduce", s.getPerson().getIntroduce());
}else{
m.put("personId", t.getPerson().getPersonId());
m.put("num", t.getPerson().getNum());
m.put("name", t.getPerson().getName());
m.put("dept", t.getPerson().getDept());
m.put("card", t.getPerson().getCard());
String gender = t.getPerson().getGender();
m.put("gender", t.getPerson().getGender());
m.put("genderName", ComDataUtil.getInstance().getDictionaryLabelByValue("XBM", gender)); //性别类型的值转换成数据类型名
m.put("birthday", t.getPerson().getBirthday()); //时间格式转换字符串
m.put("email", t.getPerson().getEmail());
m.put("phone", t.getPerson().getPhone());
m.put("address", t.getPerson().getAddress());
m.put("introduce", t.getPerson().getIntroduce());
}
return m;
}
/**
* getAchievementMapList 根据输入参数查询得到学生成就数据的 Map List集合 参数为空 查出说有学生, 参数不为空,查出人员编号或人员名称 包含输入字符串的学生
*/
public List getAchievementMapList(String numName) {
List dataList = new ArrayList();
List<Achievement> sList = achievementRepository.findAchievementListByStudentNumName(numName); //数据库查询操作
if (sList == null || sList.size() == 0)
return dataList;
for (int i = 0; i < sList.size(); i++) {
dataList.add(getMapFromAchievement(sList.get(i)));
}
List<Achievement> tList = achievementRepository.findAchievementListByTeacherNumName(numName); //数据库查询操作
if (tList == null || tList.size() == 0)
return dataList;
for (int i = 0; i < tList.size(); i++) {
dataList.add(getMapFromAchievement(tList.get(i)));
}
return dataList;
}
public List getPassedAchievementMapList(String numName) {
List dataList = new ArrayList();
List<Achievement> sList = achievementRepository.findPassedAchievementListByStudentNumName(numName); //数据库查询操作
if (sList == null || sList.size() == 0)
return dataList;
for (int i = 0; i < sList.size(); i++) {
dataList.add(getMapFromAchievement(sList.get(i)));
}
List<Achievement> tList = achievementRepository.findPassedAchievementListByTeacherNumName(numName); //数据库查询操作
if (tList == null || tList.size() == 0)
return dataList;
for (int i = 0; i < tList.size(); i++) {
dataList.add(getMapFromAchievement(tList.get(i)));
}
return dataList;
}
public List getAchievementMapListByStudentId(Integer studentId) {
List dataList = new ArrayList();
List<Achievement> sList = achievementRepository.findAchievementByStudentId(studentId); //数据库查询操作
if (sList == null || sList.size() == 0)
return dataList;
for (int i = 0; i < sList.size(); i++) {
dataList.add(getMapFromAchievement(sList.get(i)));
}
return dataList;
}
public List getAchievementMapListByTeacherId(Integer teacherId) {
List dataList = new ArrayList();
List<Achievement> sList = achievementRepository.findAchievementByTeacherId(teacherId); //数据库查询操作
if (sList == null || sList.size() == 0)
return dataList;
for (int i = 0; i < sList.size(); i++) {
dataList.add(getMapFromAchievement(sList.get(i)));
}
return dataList;
}
}
设置sql
查询语句 根据主键id查找 根据学生/教师id查找 根据学/工号姓名查找等。
@Repository
public interface AchievementRepository extends JpaRepository<Achievement,Integer> {
@Query(value = "select max(achievementId) from Achievement")
Integer getMaxId();
@Query(value= "from Achievement where student.studentId= ?1")
List<Achievement> findAchievementByStudentId(Integer studentId);
@Query(value = "from Achievement where ?1='' or teacher.person.num like %?1% or teacher.person.name like %?1% ")
List<Achievement> findAchievementListByTeacherNumName(String numName);
@Query(value = "from Achievement where ?1='' or student.person.num like %?1% or student.person.name like %?1% ")
List<Achievement> findAchievementListByStudentNumName(String numName);
@Query(value= "from Achievement where teacher.teacherId= ?1")
List<Achievement> findAchievementByTeacherId(Integer teacherId);
@Query(value = "from Achievement where status=1 and ?1='' or teacher.person.num like %?1% or teacher.person.name like %?1% ")
List<Achievement> findPassedAchievementListByTeacherNumName(String numName);
@Query(value = "from Achievement where status=1 and ?1='' or student.person.num like %?1% or student.person.name like %?1% ")
List<Achievement> findPassedAchievementListByStudentNumName(String numName);
}
@PostMapping("/achievementDelete")
public DataResponse achievementDelete(@Valid @RequestBody DataRequest dataRequest) {
Integer achievementId = dataRequest.getInteger("achievementId"); //获取achievement_id值
Achievement a= null;
Optional<Achievement> op;
if(achievementId != null) {
op= achievementRepository.findById(achievementId); //查询获得实体对象
if(op.isPresent()) {
a = op.get();
}
}
if(a != null) {
achievementRepository.delete(a);//删除该条成就
}
return CommonMethod.getReturnMessageOK(); //通知前端操作正常
}
由于添加编辑分为学生端、教师端、管理端三方,为方便管理成员权限,将方法微调后对应三个不同角色在前端调用。此处以学生端代码为例:
@PostMapping("/achievementStudentEditSave")
@PreAuthorize("hasRole('ROLE_STUDENT')")
public DataResponse achievementStudentEditSave(@Valid @RequestBody DataRequest dataRequest) {
Integer achievementId = dataRequest.getInteger("achievementId"); //获取achievement_id值
Map form = dataRequest.getMap("form"); //参数获取Map对象
String achievementName = CommonMethod.getString(form,"achievementName"); //Map 获取属性的值
String level = CommonMethod.getString(form,"level"); //Map 获取属性的值
String type = CommonMethod.getString(form,"type"); //Map 获取属性的值
String content = CommonMethod.getString(form,"content"); //Map 获取属性的值
String time = CommonMethod.getString(form,"time"); //Map 获取属性的值
String num = CommonMethod.getString(form,"num");
String name = CommonMethod.getString(form,"name");
Integer userId = CommonMethod.getUserId();
Optional<User> uOp = userRepository.findByUserId(userId); // 查询获得 user对象
if(!uOp.isPresent())
return CommonMethod.getReturnMessageError("用户不存在!");
User u = uOp.get();
Optional<Student> sOp= studentRepository.findByPersonPersonId(u.getUserId()); // 查询获得 Student对象
if(!sOp.isPresent())
return CommonMethod.getReturnMessageError("学生不存在!");
Student s= sOp.get();
Achievement a = null;
Optional<Achievement> op;
if(achievementId != null) {
op= achievementRepository.findById(achievementId); //查询对应数据库中主键为id的值的实体对象
if(op.isPresent()) {
a = op.get();
}
}
if(a == null){
achievementId = getNewAchievementId(); //获取Achievement新的主键
a = new Achievement();
a.setAchievementId(achievementId);
}
a.setName(achievementName);
a.setLevel(level);
a.setContent(content);
a.setType(type);
a.setTime(time);
a.setStudent(s);
a.setStatus(0);
achievementRepository.saveAndFlush(a);//插入新的Achievement记录
return CommonMethod.getReturnData(a.getAchievementId()); // 将achievementId返回前端
}
学生端和教师端会先获取用户的id
并查询当前用户的相关信息,显示在界面中,而管理员可以查看所有用户的相关信息。
@PostMapping("/getAchievementList")
@PreAuthorize("hasRole('ADMIN')")
public DataResponse getAchievementList(@Valid @RequestBody DataRequest dataRequest) {
String numName= dataRequest.getString("numName");
List dataList = achievementService.getAchievementMapList(numName);
System.out.println(dataList);
return CommonMethod.getReturnData(dataList); //按照测试框架规范会送Map的list
}
@PostMapping("/getStudentAchievement")
@PreAuthorize("hasRole('ROLE_STUDENT')")
public DataResponse getStudentAchievement(@Valid @RequestBody DataRequest dataRequest) {
Integer userId = CommonMethod.getUserId();
Optional<User> uOp = userRepository.findByUserId(userId); // 查询获得 user对象
if(!uOp.isPresent())
return CommonMethod.getReturnMessageError("用户不存在!");
User u = uOp.get();
Optional<Student> sOp= studentRepository.findByPersonPersonId(u.getUserId()); // 查询获得 Student对象
if(!sOp.isPresent())
return CommonMethod.getReturnMessageError("学生不存在!");
Student s= sOp.get();
Integer studentId = s.getStudentId();
List dataList = achievementService.getAchievementMapListByStudentId(studentId);
return CommonMethod.getReturnData(dataList); //按照测试框架规范会送Map的list
}
@PostMapping("/getTeacherAchievement")
@PreAuthorize("hasRole('ROLE_TEACHER')")
public DataResponse getTeacherAchievement(@Valid @RequestBody DataRequest dataRequest) {
Integer userId = CommonMethod.getUserId();
Optional<User> uOp = userRepository.findByUserId(userId); // 查询获得 user对象
if(!uOp.isPresent())
return CommonMethod.getReturnMessageError("用户不存在!");
User u = uOp.get();
Optional<Teacher> sOp= teacherRepository.findByPersonPersonId(u.getUserId()); // 查询获得 Student对象
if(!sOp.isPresent())
return CommonMethod.getReturnMessageError("教师不存在!");
Teacher s= sOp.get();
Integer teacherId = s.getTeacherId();
List dataList = achievementService.getAchievementMapListByTeacherId(teacherId);
return CommonMethod.getReturnData(dataList); //按照测试框架规范会送Map的list
}
@PostMapping("/getHomeworkOptionItemListByStudentIdAndCourseId")
public OptionItemList getHomeworkOptionItemListByStudentIdAndCourseId(@Valid @RequestBody DataRequest dataRequest) {
Integer studentId=dataRequest.getInteger("studentId");
Integer courseId=dataRequest.getInteger("courseId");
List<Homework> hList=new ArrayList<>();
List<OptionItem> itemList = new ArrayList();
if(studentId==null){
List<Score> scoreList=scoreRepository.findByCourseCourseId(courseId);
if(!scoreList.isEmpty()){
Integer scoreId=scoreList.get(0).getScoreId();
hList = homeworkRepository.findHomeworkListByScoreScoreId(scoreId);
}
}
else {
Optional<Score> opScore=scoreRepository.findByStudentStudentIdAndCourseCourseId(studentId,courseId);
if(opScore.isPresent()){
Score score= opScore.get();
hList=homeworkRepository.findHomeworkListByScoreScoreId(score.getScoreId());
}
}
for (Homework h : hList) {
itemList.add(new OptionItem(h.getId(), h.getName(), h.getName()));
}
return new OptionItemList(0, itemList);
}
作业、成绩、考勤等管理的查询功能采用下拉框选的形式,使用特殊的查询方法。
@PostMapping("/examine/achievementPass")
@PreAuthorize("hasRole('ADMIN')")
public DataResponse achievementPass(@Valid @RequestBody DataRequest dataRequest) {
Integer achievementId = dataRequest.getInteger("achievementId"); //获取achievement_id值
Achievement a= null;
Optional<Achievement> op;
if(achievementId != null) {
op= achievementRepository.findById(achievementId); //查询获得实体对象
if(op.isPresent()) {
a = op.get();
}
if(a!=null){
a.setStatus(1);
achievementRepository.save(a);
}
}
return CommonMethod.getReturnMessageOK(); //通知前端操作正常
}
if(AppStore.getJwt().getRoles().equals("ROLE_STUDENT")) {
double sum1=0,sum2=0,result;
for(int i=0;i<scoreList.size();i++){
Integer mark=CommonMethod.getInteger(scoreList.get(i),"mark");
Integer credit=CommonMethod.getInteger(scoreList.get(i),"credit");
if(mark!=null){
sum1+=mark*credit;
sum2+=credit;
}
}
if(sum1==0&&sum2==0){
result=0;
}
else {
result=sum1/(double)sum2;
}
Label label=new Label("平均绩点:"+String.format("%.2f", result));
label.setPadding(new Insets(0,0,0,5));
label.setTextFill(WHITE);
functionFlowPane.getChildren().add(label);
}
平均绩点的计算在前端实现
负责处理弹窗界面逻辑和保存功能逻辑。
初始化,处理弹窗界面逻辑
@FXML
public void initialize() {
AchievementController achievementController= (AchievementController) ControllerStageManager.controller.get("AchievementController");
Map achievementData=achievementController.achievementData;
if(AppStore.getJwt().getRoles().equals("ROLE_STUDENT")){
passButton.setVisible(false);
failButton.setVisible(false);
} else if(AppStore.getJwt().getRoles().equals("ROLE_TEACHER")) {
passButton.setVisible(false);
failButton.setVisible(false);
}
achievementId= CommonMethod.getInteger(achievementData,"achievementId");
studentId=CommonMethod.getInteger(achievementData,"studentId");
if((AppStore.getJwt().getRoles().equals("ROLE_STUDENT"))||(AppStore.getJwt().getRoles().equals("ROLE_TEACHER"))) {
Label label;
label = new Label("奖励名称");
achievementNameField.setText(CommonMethod.getString(achievementData, "achievementName"));
gridPane.addRow(0, label, achievementNameField);
label = new Label("级别");
levelField.setText(CommonMethod.getString(achievementData, "level"));
gridPane.addRow(1, label, levelField);
label = new Label("种类");
typeField.setText(CommonMethod.getString(achievementData, "type"));
gridPane.addRow(2, label, typeField);
label = new Label("时间");
datePicker.getEditor().setText(CommonMethod.getString(achievementData, "time"));
gridPane.addRow(3, label, datePicker);
datePicker.setConverter(new LocalDateStringConverter("yyyy-MM-dd"));
label = new Label("奖励内容");
contentArea.setText(CommonMethod.getString(achievementData, "content"));
gridPane.addRow(4, label, contentArea);
gridPane.setVgap(4);
gridPane.setHgap(4);
}else {
Label label;
label = new Label("学号");
numField.setText(CommonMethod.getString(achievementData, "num"));
gridPane.addRow(0, label, numField);
label = new Label("奖励名称");
achievementNameField.setText(CommonMethod.getString(achievementData, "achievementName"));
gridPane.addRow(1, label, achievementNameField);
label = new Label("级别");
levelField.setText(CommonMethod.getString(achievementData, "level"));
gridPane.addRow(2, label, levelField);
label = new Label("种类");
typeField.setText(CommonMethod.getString(achievementData, "type"));
gridPane.addRow(3, label, typeField);
label = new Label("时间");
datePicker.getEditor().setText(CommonMethod.getString(achievementData, "time"));
gridPane.addRow(4, label, datePicker);
datePicker.setConverter(new LocalDateStringConverter("yyyy-MM-dd"));
label = new Label("奖励内容");
contentArea.setText(CommonMethod.getString(achievementData, "content"));
gridPane.addRow(5, label, contentArea);
gridPane.setVgap(5);
gridPane.setHgap(5);
}
}
负责保存按钮的逻辑 完成弹窗中的保存功能。
@FXML
protected void onSaveButtonClick() {
MainApplication.setCanClose(false);
if(!((AppStore.getJwt().getRoles().equals("ROLE_STUDENT"))||(AppStore.getJwt().getRoles().equals("ROLE_TEACHER")))) {
if (numField.getText().equals("")) {
MessageDialog.showDialog("学号/工号为空,不能修改");
return;
}
}
Map form = new HashMap();
form.put("num",numField.getText());
form.put("achievementName",achievementNameField.getText());
form.put("level",levelField.getText());
form.put("type",typeField.getText());
form.put("time",datePicker.getEditor().getText());
form.put("content",contentArea.getText());
DataRequest req = new DataRequest();
req.put("achievementId", achievementId);
req.put("form", form);
DataResponse res;
if(AppStore.getJwt().getRoles().equals("ROLE_STUDENT")){
res = HttpRequestUtil.request("/api/achievement/achievementStudentEditSave",req);
} else if(AppStore.getJwt().getRoles().equals("ROLE_TEACHER")) {
res = HttpRequestUtil.request("/api/achievement/achievementTeacherEditSave",req);
}else{
res = HttpRequestUtil.request("/api/achievement/achievementEditSave",req);
}
if(res.getCode() == 0) {
studentId = CommonMethod.getIntegerFromObject(res.getData());
MessageDialog.showDialog("提交成功!");
AchievementController achievementController= (AchievementController) ControllerStageManager.controller.get("AchievementController");
achievementController.onQueryButtonClick();
Stage stage= ControllerStageManager.stage.get("editStage");
stage.close();
ControllerStageManager.stage.remove("editStage");
MainFrameController mainFrameController=(MainFrameController)ControllerStageManager.controller.get("mainFrameController");
mainFrameController.getLogoutButton().setDisable(false);
MainApplication.setCanClose(true);
}else if(res.getCode() == 1){
MessageDialog.showDialog("该用户不存在,请输入正确的学号/工号!");
} else {
MessageDialog.showDialog(res.getMsg());
}
}
弹窗中管理员的审核通过功能(不通过审核功能同理)
@FXML
protected void onPassButtonClick(){
MainApplication.setCanClose(true);
DataRequest req = new DataRequest();
req.put("achievementId", achievementId);
DataResponse res = HttpRequestUtil.request("/api/achievement/examine/achievementPass",req);
if(res.getCode() == 0) {
studentId = CommonMethod.getIntegerFromObject(res.getData());
MessageDialog.showDialog("操作成功");
AchievementController achievementController= (AchievementController) ControllerStageManager.controller.get("AchievementController");
achievementController.onQueryButtonClick();
}else {
MessageDialog.showDialog(res.getMsg());
}
}
负责弹窗界面的绘制
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<VBox fx:id="vBox" xmlns="http://javafx.com/javafx/11.0.14-internal" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.teach.javafxclient.controller.studentInfo.AchievementEditController">
<GridPane fx:id="gridPane">
<VBox.margin>
<Insets bottom="5.0" left="20.0" right="20.0" top="20.0" />
</VBox.margin>
<columnConstraints>
<ColumnConstraints halignment="RIGHT" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" />
</rowConstraints></GridPane>
<FlowPane alignment="CENTER" columnHalignment="CENTER" prefHeight="36.0">
<Button onAction="#onSaveButtonClick" prefHeight="23.0" prefWidth="46.0" text="保存" />
<Button fx:id="passButton" mnemonicParsing="false" onAction="#onPassButtonClick" text="通过">
<FlowPane.margin>
<Insets left="5.0" right="5.0" />
</FlowPane.margin></Button>
<Button fx:id="failButton" mnemonicParsing="false" onAction="#onFailButtonClick" text="不通过" />
</FlowPane>
</VBox>
public Map getIntroduceDataMap(Integer personId){
Optional<Student> op = studentRepository.findByPersonPersonId(personId);
Person p = op.get().getPerson();
String name = "";
if(op.isPresent()) {
name = p.getName();
}
Map data = new HashMap();
String html = "";
if(html.length()> 0) {
data.put("html", html);
return data;
}
data.put("myName", name+"个人简历");
List attachList = new ArrayList();
Map o = new HashMap();
o.put("title","基本信息");
o.put("content",getStudentBasicInfo(op.get()));
attachList.add(o);
Map e = new HashMap();
e.put("title","教育经历");
e.put("content",getStudentEducation(op.get().getStudentId()));
attachList.add(e);
Map m = new HashMap();
m.put("title","所获荣誉");
m.put("content",getStudentAchievement(op.get().getStudentId()));
attachList.add(m);
Map c = new HashMap();
c.put("title","竞赛经历");
c.put("content",getStudentCompetition(op.get().getStudentId()));
attachList.add(c);
Map n = new HashMap();
n.put("title","创新项目");
n.put("content",getStudentProject(op.get().getStudentId()));
attachList.add(n);
Map s = new HashMap();
s.put("title","科研成果");
s.put("content",getStudentScientific(op.get().getStudentId()));
attachList.add(s);
data.put("attachList",attachList);
return data;
}
public String getStudentEducation(Integer studentId){
List<EducationExperience> pList = educationExperienceRepository.findEducationExperienceListByStudentId(studentId);
if(pList==null||pList.size()==0)
return "<ul>无教育经历</ul>" ;
String result="", schoolName="", level="", startTime="",endTime="";
result +="<ul>";
for(int i=0;i<pList.size();i++){
schoolName = pList.get(i).getName();
level = pList.get(i).getLevel();
startTime = pList.get(i).getStartTime();
if(pList.get(i).getEndTime().length()==0){endTime = "今";}
else{endTime = pList.get(i).getEndTime();}
result += "<p>" + (i+1) + ". <b>学校名称</b>:" + schoolName +"</p>";
result += "<p><b>时间</b>: 自" + startTime + "\t" + "至 "+ endTime + "</p>";
result += "<p><b>级别</b>: " + level +"</p>";
}
result +="</ul>";
return result;
}
public String drawIntroduceHtml(Map introduce){
String introHtml = "";
String myName = CommonMethod.getString(introduce,"myName");
introHtml += "<h1 style=\"text-align: center;\">" + myName + "</h1>";
List<Map> attachList = (List)introduce.get("attachList");
for(Map i : attachList){
String title = CommonMethod.getString(i,"title");
String content = CommonMethod.getString(i,"content");
introHtml += "<h3>" + title + "</h3>";
introHtml += content;
}
return introHtml;
}
-
不同用户的登录问题:根据用户的类别(管理员、学生、教师)实现用户操作权限的区分并显示不同的操作界面。
-
数据库的连接问题:数据库连接为系统中的关键技术。
-
数据的一致性和安全问题:本系统必须保证数据的一致性和安全,才能实现有效的管理。不能让没有权限的用户对数据进行操作并且定期对数据库进行备份。
-
界面开发:系统界面的设计很重要,要使界面具有亲和力。
-
多表之间的条件查询:本系统涉及到很多查询,对一些复杂的查询必须经过严谨的分析后再写出查询的数据库语句并且要优化查询方法。
-
完成本系统所必须的工作条件及解决的办法:
-
学习并掌握网站开发工具javafx、springboot、DB Browser数据库管理系统。
-
进行需求性分析,包括功能需求并设计流程图,性能需求以及需要注意的其他各项要求。
-
进行数据库的结构分析,包括逻辑结构分析和物理结构分析
-
进行界面的设计,把各个功能模块排列组合,其中包括对首页、用户登录界面、后台登陆界面、后台主界面、后台各功能模块的设计。
-
安装部署。检查安装环境。
-
-
研究困难及解决方法:
-
界面方面:系统有“学生端”、“教师端”、“管理员端”三个界面。每个界面对应系统不同的运行状态(具体由登录系统人员的身份而定)。
-
安全性方面:设立用户名和密码验证方式,同时设置验证码等方式,防止非法用户登录和越权操作。
-
数据可视化:对数据进行可视化分析与统计,实现多种图形界面的展示。
-
其他:对数据库的严密设计,保证数据的完整性;使用其他辅助工具对系统的界面进行美化和布局,以达到更好的效果。
-
- 使用git、gitee等工具进行多人协作开发,使用github desktop图形化界面工具进行git操作。减小了项目开发的难度,提高了进行代码交流与合并的效率,加快了项目的开发进度。