作业管理系统
简介:
技术:
jsp + springboot + layui + mybatis + docker + restful api
功能:
老师:登录,注册,添加学生、作业(面向自己的学生),查看自己的学生、自己布置的作业以及学生作业的完成情况,删除学生、作业,更改作业信息,退出登录
学生:登录,注册查看作业、提交作业(可重复提交),退出登录
一、数据库设计
数据库一共有五张表,设计均满足第三范式要求:
- student(sid)
- teacher(tid)
- homework(hid)
- student_homework(sid, hid)
- teach(sid, tid)
以下是数据库关系模式图

二、用例设计
用例图

三、流程图设计
1. 学生流程

2. 教师流程

四、详细设计
1. 结构总览

项目总共两大模块: core 和 web
core:
主要包含model和util,model存放的是实体类,util存放工具类,这里存放了一个SpringContextUtil,用来获取Context创建bean
web:
java目录下主要包含一些源代码,config、controller、dao、service,分别存放配置类、路由映射、mybatis访问接口、服务.
resources下包含springboot的配置文件,mybatis-generator的配置文件,mybatis的mapper文件
web-app下包含jsp页面和web.xml
2. 登录模块
- 采用了前端cookie保持登录状态,当再次打开登录页面时,会进行登录状态的判断,若已登录且未退出,则会自动进行登录,登录成功与登出成功的时候则会改变cookie中的登录状态。
- 添加了拦截器设置,用来检验登录状态,未登录时不能访问只有登录后才能访问的页面,通过WebConfig配置学生和老师相关操作的拦截器。
- 记住密码功能,使用cookie记住最近一次登录成功的用户名+密码,不小心退出后可以直接登录。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| <% request.setCharacterEncoding("utf-8"); Cookie[] cookies = request.getCookies(); boolean studentLogged = false; boolean teacherLogged = false; String username = ""; String password = ""; if(cookies != null){ for (Cookie c : cookies) { if ("loginStatus".equals(c.getName())) { String loginStatus = c.getValue(); if ("student_true".equals(loginStatus)) { response.sendRedirect("/student/studentHome"); } else if ("teacher_true".equals(loginStatus)) { response.sendRedirect("/teacher/teacherHome"); } break; } } for (Cookie c : cookies) { if ("loginStatus".equals(c.getName())) { String loginStatus = c.getValue(); if ("student_false".equals(loginStatus)) { studentLogged = true; } else if ("teacher_false".equals(loginStatus)) { teacherLogged = true; } break; } } if(teacherLogged || studentLogged){ for(Cookie c : cookies){ if("username".equals(c.getName())){ username = URLDecoder.decode(c.getValue(), "utf-8"); } if("password".equals(c.getName())){ password = URLDecoder.decode(c.getValue(), "utf-8"); } } } } %>
|
1 2 3 4 5 6 7
| <% if(!username.equals("") && !password.equals("") && studentLogged){ %> <script> document.getElementById("s_username").value = <%=username%>; document.getElementById("s_password").value = <%=password%>; </script> <%}%>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
@Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { Cookie[] cookies = request.getCookies(); String loginStatus = ""; for (Cookie c : cookies) { if ("loginStatus".equals(c.getName())) { loginStatus = c.getValue(); if ("student_true".equals(loginStatus)) { return true; } break; } } response.sendRedirect("/login"); return false; }
|
3. service设计
- 抽象出StudentService和TeacherService两个接口,在impl包下进行实现,好处是有新的实现时上层不用做修改。
- 使用@Transactional注解TeacherServiceImpl中的addHomework, removeStudent, deleteHomework三个方法,因为方法当中的多个sql必须绑定执行才符合逻辑,也可以使用之前学到的AOP代理实现,就是稍微麻烦点。
4. Restful api设计
url |
method |
description |
/ |
get |
跳转至登录界面 |
/login |
get |
跳转至登录界面 |
/logout |
get |
退出登录 |
/studentLogin |
post |
学生登录 |
/teacherLogin |
post |
教师登录 |
/studentRegister |
get |
跳转至学生注册界面 |
/studentRegister |
post |
学生注册 |
/teacherRegister |
get |
跳转至教师注册界面 |
/teacherRegister |
post |
教师注册 |
/register-success |
get |
注册成功界面 |
/studentHome |
get |
学生主页(自己的作业列表) |
/homework |
get |
查看作业 |
/homework |
post |
提交/更新作业 |
/new-homework |
get |
跳转至添加作业界面 |
/new-homework |
post |
添加作业 |
/homework |
post |
修改作业 |
/homework |
get |
跳转至修改作业界面 |
/homework |
delete |
删除作业 |
/new-student |
get |
跳转至给自己班级添加学生的界面 |
/new-student |
post |
添加1个或多个学生到自己班级 |
/student |
delete |
将学生移除班级 |
/teacherHome |
get |
教师主页(该教师班级学生列表) |
/teacherHomework |
get |
作业列表(仅含该教师布置) |
/studentHomework |
get |
某一作业的所有学生的完成情况 |
5. 其他设计
- js表单验证,登录、注册、提交作业以及布置作业时的验证。
- 表单提交错误相关提示,密码错误、用户表不存在等提示信息。
- dao层与mapper是通过myabtis-generator插件生成的。
- 重复提交时会自动显示之前提交内容,教师修改作业也是一样的
这里举两个例子:
密码必须6-12位,不含空格

密码错误:

五、界面展示
1.登录注册
1.1学生登录(登陆成功会用cookie记住账户密码)

1.2 教师登录(这里使用cookie记住了账户密码)

1.3 学生注册

1.4 教师注册

1.3 注册成功:

2.学生部分
2.1 学生主页

2.2 提交作业(可重复提交,之前有提交内容时会自动显示)

3. 教师部分
3.1 主页(自己教的学生)
可以对自己教的学生进行添加和移除

3.2 从不属于自己学生的列表添加自己的学生

3.3 自己发布的作业列表,可以添加新作业、查看、删除某一作业

3.4 修改作业内容(自动显示之前的内容)

3.5 发布新的作业
3.6 查看某一作业自己所有学生的完成情况
六、Docker部署(多模块Maven项目)
1. docker 部署springboot镜像
1.1环境准备(以下操作在springboot的web模块进行)
1 2 3 4 5 6 7 8 9
| <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>1.4.2.RELEASE</version> <configuration> <executable>true</executable> </configuration> </plugin>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| <plugin> <dependencies> <dependency> <groupId>javax.activation</groupId> <artifactId>activation</artifactId> <version>1.1</version> </dependency> </dependencies> <groupId>com.spotify</groupId> <artifactId>dockerfile-maven-plugin</artifactId> <version>1.4.13</version> <executions> <execution> <id>default</id> <goals> <goal>build</goal> <goal>push</goal> </goals> </execution> </executions> <configuration> <repository>${docker.image.prefix}/${project.artifactId}</repository> <tag>${project.version}</tag> <buildArgs> <JAR_FILE>${project.build.finalName}.jar</JAR_FILE> </buildArgs> </configuration> </plugin>
|
1.2 Dockerfile编写
1 2 3 4 5 6 7 8 9 10 11 12
| FROM openjdk:8-jre
ENTRYPOINT ["java", "-jar", "/usr/share/myservice/app.jar"]
VOLUME /usr/share/myservice
RUN mkdir -p /usr/share/myservice
WORKDIR /usr/share/myservice
ARG JAR_FILE ADD ${JAR_FILE} /usr/share/myservice/app.jar
|
1.3开始制作
1 2 3 4 5 6 7 8
| mvn clean install package -Dmaven.test.skip
mvn package dockerfile:build -Dmaven.test.skip
docker images
|
1.4 运行测试
1 2
| docker run --name service -p 8088:8083 springboot/web:1.0-SNAPSHOT
|
截图(Docker Desktop)

2. docker-compose 部署springboot+mysql
上面的是没有整合mysql的,依赖本地mysql,现在给springboot项目整合docker的mysql
2.1相关配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| version: '3.8'
services:
webapp: build: context: ./web dockerfile: Dockerfile restart: always ports: - 8088:8083 volumes: - /vol/development depends_on: - mysql links: - mysql:mysql
mysql: container_name: mysql-container build: context: ./mysql dockerfile: Dockerfile restart: always ports: - 33068:3306 environment: MYSQL_DATABASE: class MYSQL_ROOT_HOST: '%' MYSQL_ROOT_PASSWORD: 123456 command: [ 'mysqld', '--innodb-buffer-pool-size=20M', '--character-set-server=utf8', '--collation-server=utf8_general_ci', '--default-time-zone=+8:00', '--lower-case-table-names=1', '--default-authentication-plugin=mysql_native_password' ]
|
2.2 mysql目录下有两个文件:calss.sql和Dockerfile
1 2 3 4
| FROM mysql:8.0.20
ADD ./class.sql /docker-entrypoint-initdb.d/class.sql
|
2.3 web目录下的 Dockerfile(和之前差不多)
1 2 3 4 5 6 7 8 9 10
| FROM openjdk:8-jre
ENTRYPOINT ["java", "-jar", "/usr/share/myservice/app.jar"]
VOLUME /usr/share/myservice RUN mkdir -p /usr/share/myservice WORKDIR /usr/share/myservice
ADD /target/web.jar /usr/share/myservice/app.jar
|
2.4 运行docker-compose命令
然后就可以成功制作并启动了(DockerDesktop):

注:以上两种方式运行时都要将springboot中mysql配置中url中的ip换成自己电脑的ipv4地址。
七、总结
- 使用layui如果想通过ajax提交form一定要在ajax提交后写上:return false;否则表单会提交两遍!
- springboot对jsp的支持较差,要添加的东西比较多,我在我的pom.xml中注释了出来,遇到问题的童鞋也可以参考一下。
- mybatis-generator插件真的好用,使用也比较简单,感兴趣的小伙伴可以学一下!
关于mybatis,配置mapper和dao层时要求:
在mapper文件中namespace等于对应接口的全限定名;
接口中的方法名和mapper文件中的statement(,…标签)的id属性值一致;
接口中的方法输入值参数和mapper文件中statement的parameterType指定的类型一致。
接口中的方法的返回值类型和mapper文件中statement的resultType指定的类型一致。
docker访问外部时一定要注意将localhost之类的换成本地的ipv4地址!这里需要将springboot配置中的localhost更换成你的ipv4地址。