作业管理系统

1.系统框架

springboot+springsecurity+mybatis+websocket+thymeleaf+layui

2.功能描述

教师功能:

1.发布作业
(1)教师可以发布多种格式的作业。1纯文本作业,2.纯文件作业,3.混合式作业。

2.修改作业
(1).教师可以修改发布作业(修改发布时间)。

3.批改作业
(1)可以对成绩打分。

(2)对于不合格的作业,老师可以打回让学生从做.

4.作业统计
(1)分数段统计

(2).作业评价关键字统计

5.信箱
(1).消息

学生功能:
1.提交作业
(1).作业格式:1学生提交作业,没有按照指定格式形式提交,系统直接打回

(2).超时不可提交作业.

2.查询批改后的作业
(1).学生查看批改的作业详情。

3.信箱
(1).消息

3.项目运行效果

1.用户登录:(用户可以点击刷新验证码)

2.教师发布作业 :(可以为所带班级布置3种不同类别的作业)

3.教师修改作业(对于粗心超时未提交的学生,老师可以修改作业截止时间,从而学生继续提交作业)

4.教师批改作业(教师可以查看学生提交过来的作业,打分或者不合格直接打回)

5.作业数据统计(系统对学生的分数进行统计,评价作业进行关键字的提取)

6.教师查看自己的信箱中的信息

7.消息实时推送 (在教师发布作业的时,学生就立即收到消息)

8.学生查看信箱

9.学生提交作业

10.学生查看批改作业信息

3.项目配置:

1.工具:
IDEA

2.项目种类:
springboot-maven项目

3.框架:
Layui框架(本项目的页面基本是调用X-admin写好的layui页面,下载地址:http://x.xuebingsi.com/

4.jdk:
1.8

5.数据库:
mysql5.0

6.数据库可视化工具:
navicat

4.项目详细讲解:

1.数据库设计:
总共有九张表,下面为表的相关属性。
semester表(学期表)

属性 类型 长度 是否为主键 是否为外键 备注
id int 2 ID号 1
name char 10 学期名 2019-2020上学年

course表(课程表)

属性 类型 长度 是否为主键 是否为外键 备注
id int 10 流水号 1
courseid char 10 课程号 1
name char 10 课程名 大学英语
score Int 10 学分 3

teacher表(老师表)

属性 类型 长度 是否为主键 是否为外键 备注
id int 10 流水号 1
tcode char 10 教工号 001
name char 10 教师名字 王渊
gender char 10 性别
degree char 10 学历 博士
title char 10 职称 博士导师
introduction char 10 简介 本科毕业于…
photo char 10 照片 001
Unreadinfo Int 10 未读总消息条数 0

class表
班级表,是指开课班级表(老师与开课班级绑定)

属性 类型 长度 是否为主键 是否为外键 备注
id int 10 班级号 1
semester_id int 10 学期id 1
course_id int 10 课程表id 1
int 10 老师id 1

student表(学生表)

属性 类型 长度 是否为主键 是否为外键 备注
id int 10 流水号 1
scode char 10 学号 201701
name char 10 姓名 陈联盛
gender char 10 性别
photo char 10 照片 201701
Unreadinfo Int 10 未读总消息 0

class_student(学生课程表)
学生与开课班级绑定

属性 类型 长度 是否为主键 是否为外键 备注
id int 10 流水号 1
class_id int 10 开课班级 1
Student_id int 10 学生id 1

meaaage消息表
state角色0表示系统,1表示教师,2表示学生(普通消息(0),作业消息(1))

属性 类型 长度 是否为主键 是否为外键 备注
id int 10 流水号 1
Sendid Int 1 发送者id 0
Receid Int 1 接收者id 1
sendState Int 1 发送者角色 1
Recestate Int 1 接收者角色 1
State Int 1 普通消息(0),作业消息(1) 0
Info char 10 当state为1时,state为homework主键 1

homework表(作业表)
标志是否过期(1,未过期,0表示过期)

属性 类型 长度 是否为主键 是否为外键 备注
id int 10 流水号 1
class_id int 10 开课班级id 1
stime char 10 开始时间 2019-10-10
etime char 10 结束时间 2019-12-10
type int 10 作业格式(1,纯文本,2纯文件,3,混 1
Filename 10 文件名 Null
Text text 10 文本作业 。。。。。。。
State Int 10 标志是否过期(1,未过期,0表示过期) 1

homeworkinfo 作业详情表

属性 类型 长度 是否为主键 是否为外键 备注
Id int 10 流水号 1
Homework_id int 10 作业id 1
Student_id int 10 学生id 1
Type Int 10 否是 作业格式 1
filename char 10 作业文件名 Null
text text 10 文本答案 。。。。
Info Var 10 学生作业心得 。。。。
piyu text 10 老师批语 学无止境
filescore int 10 文件题目得分 0
textscore int 10 文本提得分 99
totalscore int 10 总分 99

2.基本的springboot的maven项目的创建.
创建初步的spingboot的项目后,注意修改两个配置文件1.pom.xml,2.application.properties

1.pom.xml

<?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>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>student_work-2</groupId>
    <artifactId>alian</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>alian</name>
    <description>Demo project for Spring Boot</description>
 
    <properties>
        <java.version>1.8</java.version>
        <spring-security.version>5.1.2.RELEASE</spring-security.version>
    </properties>
    <dependencies>
        <!--springboot web启动 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- spingboot测试-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--安全认证-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <!--数据库驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>
        <!--数据库连接池-->
        <!--<dependency>-->
        <!--<groupId>c3p0</groupId>-->
        <!--<artifactId>c3p0</artifactId>-->
        <!--<version>0.9.5.4</version>-->
        <!--</dependency>-->
        <!--数据库框架mybatis-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.0</version>
        </dependency>
        <!-- devtools热部署-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
        <!-- thymeleaf模板引擎-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <!-- websocket消息推送-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>
        <!--日志-->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
        </dependency>
        <!--加密-->
        <!--json解析-->
 
        <!--保证样式版本唯一-->
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>webjars-locator-core</artifactId>
            <version>0.35</version>
        </dependency>
        <!--引入wsockjs-->
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>sockjs-client</artifactId>
            <version>1.1.2</version>
        </dependency>
        <!--引入websocket-->
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>stomp-websocket</artifactId>
            <version>2.3.3-1</version>
        </dependency>
        <!--引入jquery-->
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>jquery</artifactId>
            <version>3.3.1-1</version>
        </dependency>
        <!--引入中文工具类-->
        <dependency>
            <groupId>com.hankcs</groupId>
            <artifactId>hanlp</artifactId>
            <version>portable-1.3.2</version>
        </dependency>
 
    </dependencies>
 
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <!--逆向工具插件引入-->
            <!-- mybatis generator 自动生成代码插件 -->
            <plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <configuration>
                    <configurationFile>${basedir}/src/main/resources/generatorConfig.xml</configurationFile>
                    <overwrite>true</overwrite>
                    <verbose>true</verbose>
                </configuration>
            </plugin>
        </plugins>
        <resources>
            <resource>
                <directory>${project.basedir}/src/main/resources</directory>
                <filtering>true</filtering>
                <excludes>
                    <exclude>static/**
                
            
 
            
                ${project.basedir}/src/main/resources
                false
                
                    static/**
                
            
        
    


步骤请参考文章:springboot整合HanLP详解文本的关键字提取-人名识别-字体转换-分词-文本推荐:地址https://blog.csdn.net/qq_41593124/article/details/99548014。

2.application.properties

#描述数据源
spring.datasource.url=jdbc:mysql://localhost:3306/student_work?useUnicode=true&characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driverClassName=com.mysql.jdbc.Driver
 
#扫描配置 mybatis整合
mybatis.type-aliases-package=alian.mapper
mybatis.mapper-locations=classpath:mapper/*Mapper.xml
 
#配置数据库连接池
#c3p0.jdbcUrl=jdbc:mysql://localhost:3306/ssm_student_work?useUnicode=true&characterEncoding=utf8&autoReconnect=true&failOverReadOnly=false
#c3p0.user=root
#c3p0.password=123456
#c3p0.driverClass=com.mysql.jdbc.Driver
#c3p0.minPoolSize=2
#c3p0.maxPoolSize=10
#c3p0.maxIdleTime=1800000
#c3p0.acquireIncrement=3
#c3p0.maxStatements=1000
#c3p0.initialPoolSize=3
#c3p0.idleConnectionTestPeriod=60
#c3p0.acquireRetryAttempts=30
#c3p0.acquireRetryDelay=1000
#c3p0.breakAfterAcquireFailure=false
#c3p0.testConnectionOnCheckout=false
#配置thymeleaf
#关闭thymeleaf缓存的功能
spring.thymeleaf.cache=false
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.check-template-location=true
spring.thymeleaf.servlet.content-type=text/html
spring.thymeleaf.encoding=UTF-8
 
#设置登录过期时间为30m
server.servlet.session.timeout=30m

3.springboot整合maybatis逆向工程生成domian,mapper 文件
1.在pom.xml配置plus插件。上面pom.xml已经修改,不用从新添加。

 <!--逆向工具插件引入-->
            <!-- mybatis generator 自动生成代码插件 -->
            <plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <configuration>
                    <configurationFile>${basedir}/src/main/resources/generatorConfig.xml</configurationFile>
                    <overwrite>true</overwrite>
                    <verbose>true</verbose>
                </configuration>
            </plugin>

2.在 项目resources文件夹下面创建逆向工程配置文件:generatorConfig.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
    <!-- 数据库驱动:选择你的本地硬盘上面的数据库驱动包-->
    <classPathEntry  location="D:\Java所有JAR\数据库驱动\mysql-connector-java-5.1.39.jar"/>
    <context id="DB2Tables"  targetRuntime="MyBatis3">
        <commentGenerator>
            <property name="suppressDate" value="true"/>
            <!-- 是否去除自动生成的注释 true:是 : false:-->
            <property name="suppressAllComments" value="true"/>
        </commentGenerator>
        <!--数据库链接URL,用户名、密码 -->
        <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://127.0.0.1/student_work" userId="root" password="123456">
        </jdbcConnection>
        <javaTypeResolver>
            <property name="forceBigDecimals" value="false"/>
        </javaTypeResolver>
        <!-- 生成模型的包名和位置-->
        <javaModelGenerator targetPackage="alian.domain" targetProject="src/main/java">
            <property name="enableSubPackages" value="true"/>
            <property name="trimStrings" value="true"/>
        </javaModelGenerator>
        <!-- 生成映射文件的包名和位置-->
        <sqlMapGenerator targetPackage="mapper" targetProject="src/main/resources">
            <property name="enableSubPackages" value="true"/>
        </sqlMapGenerator>
        <!-- 生成DAO的包名和位置-->
        <javaClientGenerator type="XMLMAPPER" targetPackage="alian.mapper" targetProject="src/main/java">
            <property name="enableSubPackages" value="true"/>
        </javaClientGenerator>
        <!-- 要生成的表 tableName是数据库中的表名或视图名 domainObjectName是实体类名-->
        <!-- 要生成的表 tableName是数据库中的表名或视图名 domainObjectName是实体类名-->
        <!--<table tableName="class"  enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>-->
        <!--<table tableName="classstudent"  enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>-->
        <!--<table tableName="course"  enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>-->
        <!--<table tableName="homework"  enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>-->
        <!--<table tableName="homeworkinfo"  enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>-->
        <!--<table tableName="meaagesinfo"  enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>-->
        <!--<table tableName="meaasge"  enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>-->
        <!--<table tableName="semester"  enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>-->
        <!--<table tableName="student"  enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>-->
        <!--<table tableName="teacher"  enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>-->
    </context>
</generatorConfiguration>

注意:三个地方需要注意:,。

1.这个路径是你本地数据库驱动的路径。
2.要生成的表 tableName是数据库中的表名或视图名 domainObjectName是实体类名

<table tableName="class"  enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>

表生成相应的domain,每张表都需要配置,上面是class表,其余的只需修改表名即可。

3.生成的mapper,domain的位置

<!-- 生成模型的包名和位置-->
        <javaModelGenerator targetPackage="alian.domain" targetProject="src/main/java">
            <property name="enableSubPackages" value="true"/>
            <property name="trimStrings" value="true"/>
        </javaModelGenerator>
        <!-- 生成映射文件的包名和位置-->
        <sqlMapGenerator targetPackage="mapper" targetProject="src/main/resources">
            <property name="enableSubPackages" value="true"/>
        </sqlMapGenerator>
        <!-- 生成DAO的包名和位置-->
        <javaClientGenerator type="XMLMAPPER" targetPackage="alian.mapper" targetProject="src/main/java">
            <property name="enableSubPackages" value="true"/>
        </javaClientGenerator>

生成结果如图:
作业管理系统_第1张图片
4.springboot整合springsecurity相关配置
1.添加两个配置config类(MyUserDatalis,SpringSercurityConfig),四个拦截器配置处理器(MyAuthenticationFailHandler,MyAuthenticationSuccessHandler,UserLogoutSuccessHandler,ValidateCodeFilter)。

MyUserDatalis(配置springsecurity登录验证信息,在这一步主要对用户的登录信息进行验证)

package alian.config;
 
import alian.mapper.StudentMapper;
import alian.mapper.TeacherMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
 
@Component
public class MyUserDatalis implements UserDetailsService {
 
    @Autowired
    private StudentMapper studentMapper;
    @Autowired
    private TeacherMapper teacherMapper;
 
    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        String judge1=studentMapper.findpasswordbyid(s);
        String judge2=teacherMapper.findpasswordbyid(s);
        BCryptPasswordEncoder passwordencodeing=new BCryptPasswordEncoder();
        if(judge1==null&&judge2==null)
        {
            return new User(s, "@@@", AuthorityUtils.commaSeparatedStringToAuthorityList("error"));
        }
        if(judge1!=null)
        {
            return new User(s, passwordencodeing.encode(judge1), AuthorityUtils.commaSeparatedStringToAuthorityList("student"));
        }
        if(judge2!=null)
        {
            return new User(s, passwordencodeing.encode(judge2), AuthorityUtils.commaSeparatedStringToAuthorityList("teacher"));
        }
        return null;
    }
}

SpringSercurityConfig(访问路径配置)

package alian.config;
 
import alian.filter.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
 
@EnableWebSecurity
public class SpringSercurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private MyUserDatalis myUserDatalis;
    @Autowired
    private MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;
    @Autowired
    private MyAuthenticationFailHandler myAuthenticationFailHandler;
 
    @Override
    protected void configure(HttpSecurity http) throws Exception {
 
         ValidateCodeFilter validateCodeFilter=new ValidateCodeFilter();
             http.authorizeRequests()
                     .antMatchers("/teacher/**")
                     .hasAuthority ("teacher")
                    .antMatchers("/student/**")
                    .hasAnyAuthority ("student")
                    .and()
                     .addFilterBefore(validateCodeFilter,UsernamePasswordAuthenticationFilter.class)
                     .formLogin()
                    .loginPage("/login")// 登录路径
                     .loginProcessingUrl("/login/form")
                     .successHandler(myAuthenticationSuccessHandler)
                     .failureHandler(myAuthenticationFailHandler)
                    .and()
                     .logout()
                     .logoutUrl("/logout")
//                     .logoutSuccessHandler(userLogoutSuccessHandler)
                     .deleteCookies("JSESSIONID")
//                     .permitAll()
                     .and()
                    .authorizeRequests()
                    .antMatchers("/login","/login/indentycode","/test/**/").permitAll()
                    .antMatchers("/images/**","/css/**","/js/**","/font/**","/my_js/**","/webjars/**","/lib/**","/layui/**").permitAll()
                    .anyRequest()
                     .authenticated()
          .and()
                .csrf().disable();
 
        http.headers().frameOptions().disable();
        http.csrf().disable();
    }
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(myUserDatalis).passwordEncoder(new BCryptPasswordEncoder());
    }
}

MyAuthenticationFailHandler(失败登录过滤器)

package alian.filter;
 
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;
 
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
 
@Component
public class MyAuthenticationFailHandler implements AuthenticationFailureHandler {
    @Autowired
    private ObjectMapper objectMapper;
 
    @Override
    public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
        Map<String, Object> map = new HashMap<>();
        map.put("code","0");
        map.put("msg","用户名或者密码错误");
        httpServletResponse.setContentType("application/json;charset=UTF-8");
        httpServletResponse.getWriter().write(objectMapper.writeValueAsString(map));
    }
}

MyAuthenticationSuccessHandler(成功登录过滤器)

package alian.filter;
 
import alian.domain.Student;
import alian.domain.Teacher;
import alian.mapper.StudentMapper;
import alian.mapper.TeacherMapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import netscape.security.Principal;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.support.SimpleTriggerContext;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
 
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Authenticator;
import java.util.*;
 
@Component
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
 
    @Autowired
    private ObjectMapper objectMapper;
 
    @Autowired StudentMapper studentMapper;
 
    @Autowired TeacherMapper teacherMapper;
 
    @Override
    public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
        Map<String, Object> map = new HashMap<>();
        Collection<? extends GrantedAuthority> authorities= authentication.getAuthorities();
        Iterator <SimpleGrantedAuthority>  temp= (Iterator<SimpleGrantedAuthority>) authorities.iterator();
        String role=null;
        while(temp.hasNext())
        {
            SimpleGrantedAuthority a=temp.next();
            role=a.toString();
            map.put("msg",role);
        }
        map.put("code","0");
        String name=authentication.getName();
        if(role.equals("student"))
        {
            Student student=studentMapper.findinfoByname(name);
            httpServletRequest.getSession().setAttribute("user", student);
        }
        else{
            Teacher teacher=teacherMapper.findinfoByname(name);
            httpServletRequest.getSession().setAttribute("user", teacher);
        }
        httpServletResponse.setContentType("application/json;charset=UTF-8");
        httpServletResponse.getWriter().write(objectMapper.writeValueAsString(map));
    }
}

UserLogoutSuccessHandler(用户退出过滤器)

package alian.filter;
 
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.stereotype.Component;
 
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
 
/**
 * 用户登出处理类
 */
 
@Component("UserLogoutSuccessHandler")
 
public class UserLogoutSuccessHandler implements LogoutSuccessHandler{
 
    @Override
    public void onLogoutSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
 
        httpServletResponse.setContentType("application/json;charset=utf-8");
        PrintWriter out = httpServletResponse.getWriter();
        out.flush();
        out.close();
 
 
 
//        HttpServletRequest request = (HttpServletRequest) req;
//        HttpServletResponse response = (HttpServletResponse) res;
//        // 1 匹配到/logout请求
//        if (requiresLogout(request, response)) {
//            Authentication auth = SecurityContextHolder.getContext().getAuthentication();
//            // 2 清空Cookie、remember-me、session和SecurityContext
//            this.handler.logout(request, response, auth);
//            // 3 重定向到注册界面
//            logoutSuccessHandler.onLogoutSuccess(request, response, auth);
//
//            return;
//        }
 
 
    }
}

ValidateCodeFilter(验证码过滤器)

package alian.filter;
 
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
import org.springframework.web.filter.OncePerRequestFilter;
import org.thymeleaf.util.StringUtils;
 
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
 
public class ValidateCodeFilter extends OncePerRequestFilter {
 
 
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
 
 
        /*
         *
         * 拦截表单登录url 进行验证码的提前验证
         *
         * */
        if(StringUtils.equals("/login/form", request.getRequestURI())&& StringUtils.equalsIgnoreCase("post", request.getMethod()))
        {
                String validatecode=request.getParameter("validatecode");
                String code= (String) request.getSession().getAttribute("code");
                Map<String, Object> map = new HashMap<>();
                map.put("code","0");
               ObjectMapper objectMapper=new ObjectMapper();
 
                if(StringUtils.isEmpty(validatecode))
                {
                    map.put("msg","验证码不能为空");
                    response.setContentType("application/json;charset=UTF-8");
                    response.getWriter().write(objectMapper.writeValueAsString(map));
                    return;
                }
                if(StringUtils.isEmpty(validatecode))
                {
                    map.put("msg","验证码已过期");
                    response.setContentType("application/json;charset=UTF-8");
                    response.getWriter().write(objectMapper.writeValueAsString(map));
                    return;
                }
 
                if(code.toUpperCase().equals(validatecode.toUpperCase()))
                {
                    filterChain.doFilter(request, response);
                }
                else{
                    map.put("msg","验证码输入不正确");
                    response.setContentType("application/json;charset=UTF-8");
                    response.getWriter().write(objectMapper.writeValueAsString(map));
                    return;
                }
        }
        else {
            filterChain.doFilter(request, response);
        }
    }
}

springsecurity引入的好处:实现单点登录,对密码的加密处理,对资源的分权限访问。

5.springboot整合websocket (实现消息推送)
1.引入websocket相关的jar包(上面pom.xml文件引入即可),这里用到了webjar资源管理,可以引入库中的js和css样式。

 <!--保证样式版本唯一-->
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>webjars-locator-core</artifactId>
            <version>0.35</version>
        </dependency>
        <!--引入wsockjs-->
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>sockjs-client</artifactId>
            <version>1.1.2</version>
        </dependency>
        <!--引入websocket-->
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>stomp-websocket</artifactId>
            <version>2.3.3-1</version>
        </dependency>
        <!--引入jquery-->
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>jquery</artifactId>
            <version>3.3.1-1</version>
        </dependency>

2.添加java配置类:(WebSocketSecurityConfig)

package alian.config;
 
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.messaging.MessageSecurityMetadataSourceRegistry;
import org.springframework.security.config.annotation.web.socket.AbstractSecurityWebSocketMessageBrokerConfigurer;
 
//@Configuration
public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
 
    @Override
    protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
        messages.nullDestMatcher().authenticated()  //任何没有目的地的消息(即消息类型为MESSAGE或SUBSCRIBE以外的任何消息)将要求用户进行身份验证
                .simpSubscribeDestMatchers("/user/queue/errors").permitAll() //任何人都可以订阅/ user / queue / error
                .simpDestMatchers("/app/**").hasRole("USER")  //任何目的地以“/ app /”开头的消息都要求用户具有角色ROLE_USER
                .anyMessage().denyAll(); //拒绝任何其他消息。这是一个好主意,以确保您不会错过任何消息。
    }
    // @formatter:on
 
    @Override
    protected boolean sameOriginDisabled() {
        return true;
    }
}

参考文章,springboot整合springsecurity+websocket+thymeleaf https://blog.csdn.net/qq_41593124/article/details/99309260

3.添加js配置类:mywebscoket.js文件

var stompClient = null;// 创建全局变量
var receviemessages=null;
var isMessageing=false;
function receiveMessage() {
    if (isMessageing)
    {
        return receviemessages;
    }
}
function connect(distinctPath,sendPath) {// 连接方法(连接成功后会自动接收服务器传来的消息)
    var socket = new SockJS(distinctPath);
    stompClient = Stomp.over(socket);
    console.log("连接服务器成功");
    stompClient.connect({}, function(frame) {
        // setConnected(true);
        stompClient.subscribe(sendPath, function(greeting) {
            // isMessageing=true;
            // receviemessages=JSON.parse(greeting.body);
            // console.log("接收服务器传来的信息");
            // // console.log(JSON.parse(greeting.body));
            // console.log(greeting)
            // console.log(greeting.body)
            var info=greeting.body;
                layui.use(['layer','jquery'],function () {
                    var $=layui.$;
                    /*
                    *
                    * 将消息插入固定下拉列表位置
                    *
                    * */
                    var node = $('
+ info + '\')">' + info + '
'
); $('#messageBox').append(node); // 1:1班:王渊老师:发布:60作业 }); }); }); } // 断开连接方法 function disconnect() { if (stompClient !== null) { stompClient.disconnect(); console.log("关闭服务器连接成功"); } } // 发送消息 meaaages智能为json数据 function sendMessage(receviePath,messages) { stompClient.send(receviePath, {}, messages ); } function teacherconnect(id) { connect("/chat","/topic/teacherinfo/"+id+"/"); } function studentconnect(id) { connect("/chat","/topic/studentinfo/"+id+"/"); }

4.调用的html页面(这里分两种权限连接,地址都是一样的,通过与服务器建立连接,达到即时通讯的目的)

<script>
        window.onload=function () {
            /*
            *
            * 进行用户角色的判断
            *
            * */
            // 注意:导航 依赖 element 模块,否则无法进行功能性操作
            layui.use('element', function(){
                var element = layui.element;
            });
            var state='[[${session.user.photo}]]'; // --获取session中的值
            var id='[[${session.user.id}]]';
            if (state.length>3)// 学生连接
            {
                studentconnect(id);
            }
            else {// 教师连接
                teacherconnect(id);
            }
        }
    </script>

5.Controller服务器端消息发送(这里用学生向老师发送info举例,SimpMessagingTemplate可以点对点发送消息,前台通过字符串的拼接可以实现向不同用户发送消息)

  @Autowired
    SimpMessagingTemplate simpMessagingTemplate;
    public void sendMessagesToTeacher(int teacherid,int student,int sendstate,int receivestate,int state,String info) throws Exception {
 
             simpMessagingTemplate.convertAndSend("/topic/teacherinfo/"+teacherid+"/",info);// 向老师发送消息
 
    }

5.项目整体结构图

作业管理系统_第2张图片

6.Controller源码解析

LoginController用于管理用户的登录

package alian.controller;
 
import alian.utils.VerifyCodeUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
 
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.IOException;
 
/*
 * 登录控制器
 *
 */
@Controller
@RequestMapping(path = "/login")
public class LoginController {
    @GetMapping()
    public String login()
    {
        return "login";
    }
    @RequestMapping(value ="indentycode")
    public void indentycode(HttpServletRequest request, HttpServletResponse response) throws IOException {
        VerifyCodeUtil.setHeight(37);
        VerifyCodeUtil.setWidth(83);
        VerifyCodeUtil.setSize(10);
        VerifyCodeUtil.setDsize(10);
        String indentycode=VerifyCodeUtil.generateVerifyCode();
        request.getSession().setAttribute("code", indentycode);
        BufferedImage image = VerifyCodeUtil.getBufferedImage(indentycode);
        ImageIO.write(image, "jpg", response.getOutputStream());
    }
    /*测试*/
 
    @Autowired
    SimpMessagingTemplate simpMessagingTemplate;
    @MessageMapping("/hello")
    public @ResponseBody void greeting(String name)throws Exception{
        simpMessagingTemplate.convertAndSend("/topic/greetings",name);
    }
    @RequestMapping("/text")
    public String test()
    {
        return "text";
    }
 
 
}

StudentController(配置学生相关操作)

package alian.controller;
 
import alian.domain.Homework;
import alian.domain.Meaasge;
import alian.domain.Student;
import alian.domain.UserInfo;
import alian.service.StudentService;
import org.apache.commons.compress.utils.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
 
@Controller
@RequestMapping("/student")
public class StudentController {
 
    @GetMapping()
    public String Student()
    {
        return "index";
    }
 
    @Autowired
    private StudentService studentService;
 
    /*
    *
    * 查询用户收到的信息
    *
    * */
    @RequestMapping("/findallStudentMessages")
    public @ResponseBody Map findallStudentMessages(HttpServletRequest request)
    {
        Student user= (Student) request.getSession().getAttribute("user");
        List<Meaasge> messages= studentService.findallStudentMessages(user.getId());
        Map map=new LinkedHashMap();
        map.put("code", 0);
        map.put("msg", "查询成功");
        map.put("count", 20);
        map.put("data", messages);
        return map;
    }
 
    /*
    *
    * 查询学生所在班级发布作业
    *
    * */
    @RequestMapping("/findallStudentHomeworks")
    public @ResponseBody Map findallStudentHomeworks(HttpServletRequest request)
    {
        Student user= (Student) request.getSession().getAttribute("user");
        List<Homework> messages= studentService.findallStudentHomeworks(user.getId());
        Map map=new LinkedHashMap();
        map.put("code", 0);
        map.put("msg", "查询成功");
        map.put("count", 20);
        map.put("data", messages);
        return map;
    }
 
    @RequestMapping("/readinfo")
    public @ResponseBody Map readinfo(int messageid,HttpServletRequest request)
    {
        Student user= (Student) request.getSession().getAttribute("user");
        Map map=new HashMap();
        if(studentService.readMeeages(messageid))
        {
            studentService.readinfo(user.getId());
            map.put("msg", "读取成功");
        }
        else {
            map.put("msg", "请不要重复点击读取");
        }
        return map;
    }
 
    @RequestMapping("/readmanyinfo")
    public @ResponseBody Map readmanyinfo(@RequestParam(value = "messageid[]",required = true) int messageid[], HttpServletRequest request)
    {
        Student user= (Student) request.getSession().getAttribute("user");
        Map map=new HashMap();
        String ids="";
        for(int i=0;i<messageid.length;i++)
        {
            if(i==0){
                ids=""+messageid[i];
            }
            else
                ids=ids+","+messageid[i];
        }
        UserInfo userInfo = new UserInfo();
        userInfo.setId(user.getId());
        userInfo.setNums(messageid.length);
        if(studentService.receivemanyinfo(userInfo))
        {
            if(studentService.readmanyinfo(ids))
            {
                map.put("msg", "读取成功");
            }
        }
        else{
            map.put("msg", "读取成功");
        }
        return map;
    }
    /*
    *
    * 学生下载走也
    *
    * */
    @RequestMapping("/downHomework")
    public  void downHomework(String filename, HttpServletResponse response)
    {
        File a=new File("D:/"+filename);
        FileInputStream read=null;
        OutputStream outputStream=null;
        try {
            read=new FileInputStream(a);
            outputStream=response.getOutputStream();
            response.setCharacterEncoding("utf-8");
            response.setContentType("application/x-download");
            response.addHeader("Content-Disposition", "attachment;filename=test.txt");
            IOUtils.copy(read, outputStream);
            outputStream.flush();
        }catch (IOException e) {
            e.printStackTrace();
        }
    }
}

TeacherController(配置教师相关操作)


package alian.controller;
 
import alian.config.WebSocketServer;
import alian.domain.*;
import alian.service.StudentService;
import alian.service.TeacherService;
import alian.utils.SaveFileUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
 
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.security.PublicKey;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
 
@Controller
@RequestMapping("/teacher")
public class TeacherController {
    @GetMapping()
    public  String teacher()
    {
        return "index";
    }
 
    @Autowired
    private TeacherService teacherService;
 
 
    @Autowired
    private StudentService studentService;
    /*
     *
     * 查询教师所带的班级接口
     *
     * */
    @RequestMapping(value ="class")
    public @ResponseBody
    Map classbyteacher_id(HttpServletRequest request)
    {
        Teacher user= (Teacher) request.getSession().getAttribute("user");
 
        List<Integer> lists = teacherService.coursebycourse_id(user.getId());
        Map map=new LinkedHashMap();
        map.put("lists", lists);
        return map;
    }
    /**
     *
     * 作业的发布
     *
     */
    @RequestMapping(value = "publishHomework")
    public @ResponseBody Map publishHomework(String classid, int type ,String time, String text,MultipartFile file, HttpServletRequest request)
    {
        Map map=new LinkedHashMap();
        map.put("code", 0);
        /*
         *
         * 将文件按照班级号+发布时间名命名
         * 存入upload文件夹
         *
         * 班级号 时间戳 文件名
         *
         * */
        String stime=time.substring(0,19);
        String etime=time.substring(22, 41);
        Homework homework=new Homework();
        homework.setClassId(Integer.parseInt(classid));
        DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:MM:SS");
        Date date1=null,date2=null;
        Teacher user= (Teacher) request.getSession().getAttribute("user");
 
        try {
            date1 = format.parse(stime);
            date2=format.parse(etime);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        List<Integer> students=teacherService.findStudentsbyClassId(Integer.parseInt( classid));
        homework.setStime(date1);
        homework.setEtime(date2);
        homework.setState(1);
        homework.setType(type);
        homework.setText(text);
        /*消息类型
        *
        * 消息类型:几班:xxlao老师:发布:xx作业
        * */
        String info=null;
        if(type==0)
        {
            /*解析text*/
            homework.setText(text);
            int homeworkid=teacherService.uploadHomework(homework);
            info=1+":"+classid+"班:"+user.getName()+"老师:"+"发布:"+homeworkid+"作业";
                map.put("msg","作业发布成功");
                /*
                *
                * 作业成功发布的同时向学生推送
                *
                * */
                /*
                *
                *
                * 发送者 接受者 发送者类型 接受者类型 消息类型
                * (state角色0表示系统,1表示教师,2表示学生)(普通消息(0),作业消息(1))
                *
                *
                * */
                try {
                    sendMessagesToStudents(user.getId(),students,1,2,1,info);
                } catch (Exception e) {
                    e.printStackTrace();
                }
        }
        else
        {
            if(type==1) text=null;
            homework.setText(text);
            // 文件后缀名
            String lastfilename=file.getOriginalFilename();
            lastfilename =lastfilename.substring(lastfilename.lastIndexOf('.'), lastfilename.length());
            /*文件名*/
            String filename=classid+new Date().getTime()+lastfilename ;
            filename=filename.replace(":", "");
            homework.setFilename(filename);
 
            int homeworkid=teacherService.uploadHomework(homework);
            info=classid+"班:"+user.getName()+"老师:"+"发布:"+homeworkid+"作业";
                String path="D:\\upload";
                if(SaveFileUtil.savefile(path,filename,file))
                {
                    map.put("msg", "作业发布成功");
                    try {
                        //老师id先写死
                        sendMessagesToStudents(1,students,1,2,1,info);
 
                        } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                else  map.put("msg", "作业发布失败,文件上传失败");
 
            }
        return map;
    }
    /*跟新消息队列*/
    /*
     *
     *
     * 发送者 接受者 发送者类型 接受者类型 消息类型
     * (state角色0表示系统,1表示教师,2表示学生)(普通消息(0),作业消息(1))
     *
     *
     * */
    public void  updateMessages(int teacherid,Integer studentsid,int sendstate,int receivestate,int state,String info)
    {
    Meaasge message=new Meaasge();
    message.setSendid(teacherid);
    message.setReceid(studentsid);
    message.setSendstate(sendstate);
    message.setRecestate(receivestate);
    message.setState(state);
    message.setInfo(info);
    teacherService.insertMessage(message);
    }
    /*
    *
    * 向学生列表发送信息
    * 同时跟新消息队列
    *
    * */
    @Autowired
    SimpMessagingTemplate simpMessagingTemplate;
    public void sendMessagesToStudents(int teacherid,List<Integer> students,int sendstate,int receivestate,int state,String info) throws Exception {
        for(Integer student: students)
        {
            simpMessagingTemplate.convertAndSend("/topic/studentinfo/"+student+"/",info);// 向学生发送消息
            updateMessages(teacherid,student,sendstate,receivestate,state,info);//跟新消息队列
            studentService.receiveInfo(student);// 学生更新未读消息
        }
    }
 
    /*教师查询发布的作业*/
 
    @RequestMapping("/findallHomeworksbyteacherid")
    public @ResponseBody Map findallHomeworksbyteacherid(HttpServletRequest request)
    {
        Teacher user= (Teacher) request.getSession().getAttribute("user");
        List<Homework> messages= teacherService.findallHomeworksbyteacherid(user.getId());
        Map map=new LinkedHashMap();
        map.put("code", 0);
        map.put("msg", "查询成功");
        map.put("count", messages.size());
        map.put("data", messages);
        return map;
    }
 
    @RequestMapping("/checkhomeworkwork")
    public @ResponseBody Map checkhomeworkwork(HttpServletRequest request)
    {
        Teacher user= (Teacher) request.getSession().getAttribute("user");
        List<Homeworkinfo> messages= teacherService.checkhomeworkwork(user.getId());
        Map map=new LinkedHashMap();
        map.put("code", 0);
        map.put("msg", "查询成功");
        map.put("count", messages.size());
        map.put("data", messages);
        return map;
    }
 
    /*
    *
    * 修改作业
    *
    *
    * */
    @RequestMapping(value = "changePublishHomework")
    public @ResponseBody Map changePublishHomework(String id ,String time, String text,MultipartFile file, HttpServletRequest request)
    {
        Map map=new LinkedHashMap();
        map.put("code", 0);
        /*
         *
         * 将文件按照班级号+发布时间名命名
         * 存入upload文件夹
         *
         * 班级号 时间戳 文件名
         *
         * */
        Homework homework=new Homework();
        homework.setId(Integer.parseInt(id));
        DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:MM:SS");
        Date date1=null;
        Teacher user= (Teacher) request.getSession().getAttribute("user");
        try {
            date1 = format.parse(time);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        homework.setEtime(date1);
        List<Integer> students=teacherService.findStudentsbyHomeworkid(Integer.parseInt(id));
        String lastfilename=file.getOriginalFilename();
        lastfilename =lastfilename.substring(lastfilename.lastIndexOf('.'), lastfilename.length());
        /*文件名*/
        String filename=id+new Date().getTime()+lastfilename ;
        filename=filename.replace(":", "");
        homework.setFilename(filename);
        /*消息类型
         *
         * 消息类型:几班:xxlao老师:发布:xx作业
         * */
        String info=null;
        /*解析text*/
        homework.setText(text);
        boolean homeworkid=teacherService.changePublishHomework(homework);
        info=0+":"+id+"班:"+user.getName()+"老师:"+"修改:"+id+"作业";
        map.put("msg","作业发布成功");
        String path="D:\\upload";
        if(SaveFileUtil.savefile(path,filename,file))
        {
            map.put("msg", "作业修改成功");
            try {
                //老师id先写死
                sendMessagesToStudents(1,students,1,2,1,info);
 
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        else  map.put("msg", "作业修改失败,文件上传失败");
        return map;
    }
}

7.Html源码解析 :

login.html

<!doctype html>
<html  class="x-admin-sm" xmlns:th="http://www.thymeleaf.org">
<head>
	<meta charset="UTF-8">
	<title>作业管理系统登录</title>
	<meta name="renderer" content="webkit|ie-comp|ie-stand">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width,user-scalable=yes, minimum-scale=0.4, initial-scale=0.8,target-densitydpi=low-dpi" />
    <meta http-equiv="Cache-Control" content="no-siteapp" />
    <link rel="stylesheet" href="./css/font.css">
    <link rel="stylesheet" href="./css/xadmin.css">
    <link rel="stylesheet" href="./lib/layui/css/layui.css">
    <script type="text/javascript" src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
    <script src="./lib/layui/layui.js" charset="utf-8"></script>
    <!--[if lt IE 9]>
      <script src="https://cdn.staticfile.org/html5shiv/r29/html5.min.js"></script>
      <script src="https://cdn.staticfile.org/respond.js/1.4.2/respond.min.js"></script>
    <![endif]-->
 
    <style type="text/css">
        body{color:#FFF;background:#E2E2E2 url(/images/bg.jpg) repeat-y center 0; text-align:center}
        #box{
            margin-top: 15%;
            margin-left: 35%;
            width:420PX;
            height:420PX;
            background-color:#E3D8D9;
            background: rgba(224,204,204,0.3);
        }
    </style>
</head>
<div id="box">
    <form class="layui-form"  style="opacity:1;" id="form">
        <br/><br/><br/><br/><br/><br/>
        <div class="layui-form-item">
            <label class="layui-form-label"><i class="layui-icon layui-icon-username" style="font-size: 15px;color:black;">用户名</i>  </label>
            <div class="layui-input-block">
                <input type="text" name="username" required   placeholder="请输入标题" autocomplete="off" class="layui-input">
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label"><i class="layui-icon layui-icon-password" style="font-size: 15px;color:black;">密码</i></label>
            <div class="layui-input-inline">
                <input type="password" name="password" required  placeholder="请输入密码" autocomplete="off" class="layui-input">
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label"><i class="layui-icon layui-icon-vercode" style="font-size: 15px;color:black;">验证码</i></label>
            <div class="layui-input-inline">
                <input type="text" name="validatecode" required  placeholder="请输入密码" autocomplete="off" class="layui-input">
            </div>
            <img id="suiji" src="/login/indentycode" alt="验证码" />
        </div>
        <div class="layui-form-item">
            <div class="layui-input-block">
                <button class="layui-btn"  lay-submit lay-filter="formDemo" >登录</button>
                <button type="reset" class="layui-btn layui-btn-primary">注册</button>
            </div>
        </div>
    </form>
    <!--调入自定义登录脚本-->
    <script th:src="@{/my_js/login.js}" type="text/javascript"></script>
</div>
</body>
</html>

关于其中x-admin.js和x-admin.css的下载,是调用layui集成好的开源框架,地址:http://x.xuebingsi.com/

直接免费下载。

index.html主页

<!doctype html>
<html class="x-admin-sm" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>作业管理主页</title>
        <meta name="renderer" content="webkit|ie-comp|ie-stand">
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
        <!--<meta name="viewport" content="width=device-width,user-scalable=yes, minimum-scale=0.4, initial-scale=0.8,target-densitydpi=low-dpi" />-->
        <meta http-equiv="Cache-Control" content="no-siteapp" />
        <link rel="stylesheet" href="/css/font.css" th:href="@{/css/font.css}">
        <link rel="stylesheet" href="/css/xadmin.css" th:href="@{/css/xadmin.css}">
        <link rel="stylesheet" href="/lib/layui/css/layui.css" th:href="@{/lib/layui/css/layui.css}">
        <!-- <link rel="stylesheet" href="./css/theme5.css"> -->
 
        <!--IE8/9支持媒体查询,从而兼容栅格 -->
        <!--[if lt IE 9]>
          <script src="https://cdn.staticfile.org/html5shiv/r29/html5.min.js"></script>
          <script src="https://cdn.staticfile.org/respond.js/1.4.2/respond.min.js"></script>
        <![endif]-->
        <script>
            // 是否开启刷新记忆tab功能
            // var is_remember = false;
        </script>
    </head>
    <body class="index">
        <!-- 顶部开始 -->
        <div class="container">
            <div class="logo">
                <a href="./index.html">作业管理系统</a></div>
            <div class="left_open">
                <a><i title="展开左侧栏" class="layui-icon">&#xe668;</i> </a>
 
            </div>
            <ul class="layui-nav left fast-add" lay-filter="">
                <li class="layui-nav-item">
                    <a href="javascript:;">+新增</a>
                    <dl class="layui-nav-child">
                        <!-- 二级菜单 -->
                        <dd>
                            <a onclick="xadmin.open('最大化','http://www.baidu.com','','',true)">
                                <i class="layui-icon">&#xe65b;</i>弹出最大化</a></dd>
                        <dd>
                            <a onclick="xadmin.open('弹出自动宽高','http://www.baidu.com')">
                                <i class="layui-icon">&#xe65a;</i>弹出自动宽高</a></dd>
                        <dd>
                            <a onclick="xadmin.open('弹出指定宽高','http://www.baidu.com',500,300)">
                                <i class="layui-icon">&#xe602;</i>弹出指定宽高</a></dd>
                        <dd>
                            <a onclick="xadmin.add_tab('在tab打开','member-list.html')">
                                <i class="layui-icon">&#xe642;</i>在tab打开</a></dd>
                        <dd>
                            <a onclick="xadmin.add_tab('在tab打开刷新','member-del.html',true)">
                                <i class="layui-icon">&#xe638;</i>在tab打开刷新</a></dd>
                    </dl>
                </li>
            </ul>
            <ul class="layui-nav right" lay-filter="">
                <li class="layui-nav-item">
                    <a href="javascript:;" id="judge"><i class="layui-icon"  style="font-size:20px;">&#xe611;</i>消息</a>
                    <dl class="layui-nav-child" id="messageBox">
                        <!--&lt;!&ndash; 二级菜单 &ndash;&gt;-->
                        <!--<dd>-->
                            <!--<a onclick="xadmin.open('个人信息','http://www.baidu.com')">个人信息</a></dd>-->
                        <!--<dd>-->
                            <!--<a onclick="xadmin.open('切换帐号','http://www.baidu.com')">切换帐号</a></dd>-->
                        <!--<dd>-->
                            <!--<a href="./login.html">退出</a></dd>-->
                    </dl>
                </li>
                <li class="layui-nav-item">
                    <a href="javascript:;" th:text="${session.user.name}"></a>
                    <dl class="layui-nav-child">
                        <!-- 二级菜单 -->
                        <dd>
                            <a onclick="xadmin.open('个人信息','http://www.baidu.com')">个人信息</a></dd>
                        <dd>
                            <a onclick="xadmin.open('切换帐号','http://www.baidu.com')">切换帐号</a></dd>
                        <dd>
                            <a href="./login.html">退出</a></dd>
                    </dl>
                </li>
                <li class="layui-nav-item to-index">
                    <a href="javascript:void(0);">回到主页</a></li>
            </ul>
        </div>
        <!-- 顶部结束 -->
        <!-- 中部开始 -->
        <!-- 左侧菜单开始 -->
        <div class="left-nav">
            <div id="side-nav">
                <ul id="nav">
                    <li>
                        <a href="javascript:;">
                            <i class="layui-icon left-nav-li" lay-tips="作业管理">&#xe705;</i>
                            <cite>作业管理</cite>
                            &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;
                            <i class="layui-icon ">&#xe603;</i></a>
                        <ul class="sub-menu">
                            <li>
                                <a onclick="xadmin.add_tab('发布作业','publishomework')">
                                    <i class="layui-icon">&#xe602;</i>
                                    <cite>发布作业</cite></a>
                            </li>
                            <li>
                                <a onclick="xadmin.add_tab('修改作业','edithomeworkwork')">
                                    <i class="layui-icon">&#xe602;</i>
                                    <cite>修改作业</cite></a>
                            </li>
                            <li>
                                <a onclick="xadmin.add_tab('批改作业','checkhomeworkwork',true)">
                                    <i class="layui-icon">&#xe602;</i>
                                    <cite>批改作业</cite></a>
                            </li>
                            <li>
                                <a onclick="xadmin.add_tab('测试','test',true)">
                                    <i class="layui-icon">&#xe602;</i>
                                    <cite>测试</cite></a>
                            </li>
                        </ul>
                    </li>
                    <li>
                        <a href="javascript:;">
                            <i class="layui-icon left-nav-li" lay-tips="教师通知管理模块">&#xe609;</i>
                            <cite>教师通知管理模块</cite>
                            &nbsp;&nbsp; &nbsp;&nbsp;
                            <i class="layui-icon ">&#xe603;</i></a>
                            <ul class="sub-menu">
                            <li>
                                <a onclick="xadmin.add_tab('发布通知','order-list.html')">
                                    <i class="layui-icon">&#xe602;</i>
                                    <cite>发布通知</cite></a>
                            </li>
                            <li>
                                <a onclick="xadmin.add_tab('查看通知','order-list1.html')">
                                    <i class="layui-icon">&#xe602;</i>
                                    <cite>查看通知</cite></a>
                            </li>
                        </ul>
                    </li>
                    <li>
                        <a href="javascript:;">
                            <i class="layui-icon left-nav-li" lay-tips="学生通知管理模块">&#xe613;</i>
                            <cite>学生通知管理模块</cite>
                            &nbsp;&nbsp; &nbsp;&nbsp;
                            <i class="layui-icon ">&#xe603;</i></a>
                        <ul class="sub-menu">
                            <li>
                                <a onclick="xadmin.add_tab('查看消息','studentReceiveMessages')">
                                    <i class="layui-icon">&#xe602;</i>
                                    <cite>查看消息</cite></a>
                            </li>
                            <li>
                                <a onclick="xadmin.add_tab('查看作业','StudentReceiveHomeworks')">
                                    <i class="layui-icon">&#xe602;</i>
                                    <cite>查看作业</cite></a>
                            </li>
                        </ul>
                    </li>
 
                </ul>
            </div>
        </div>
        <!-- <div class="x-slide_left"></div> -->
        <!-- 左侧菜单结束 -->
        <!-- 右侧主体开始 -->
        <div class="page-content">
            <div class="layui-tab tab" lay-filter="xbs_tab" lay-allowclose="false">
                <ul class="layui-tab-title">
                    <li class="home">
                        <i class="layui-icon">&#xe68e;</i>我的桌面</li></ul>
                <div class="layui-unselect layui-form-select layui-form-selected" id="tab_right">
                    <dl>
                        <dd data-type="this">关闭当前</dd>
                        <dd data-type="other">关闭其它</dd>
                        <dd data-type="all">关闭全部</dd></dl>
                </div>
                <div class="layui-tab-content">
                    <div class="layui-tab-item layui-show">
                        <iframe src='/welcome' frameborder="0" scrolling="yes" class="x-iframe"></iframe>
                        <!--<iframe th:src='@{/welcome.html}' frameborder="0" scrolling="yes" class="x-iframe"></iframe>-->
                    </div>
                </div>
                <div id="tab_show"></div>
            </div>
        </div>
        <div class="page-content-bg"></div>
        <style id="theme_style"></style>
    <script src="/my_js/mywebscoket.js"></script>
    <script src="/lib/layui/layui.js" charset="utf-8" th:src="@{/lib/layui/layui.js}"></script>
    <script type="text/javascript" src="/js/xadmin.js" th:src="@{/js/xadmin.js}"></script>
    <!--<script th:src="@{/webjars/jquery/jquery.min.js}"  type="text/javascript"></script>-->
    <script th:src="@{/webjars/sockjs-client/sockjs.min.js}"  type="text/javascript"></script>
    <!--<script th:src="@{/webjars/jquery/jquery.min.js}"  type="text/javascript"></script>-->
    <script th:src="@{/webjars/stomp-websocket/stomp.min.js}"  type="text/javascript"></script>
    <script>
        window.onload=function () {
            /*
            *
            * 进行用户角色的判断
            *
            * */
            // 注意:导航 依赖 element 模块,否则无法进行功能性操作
            layui.use('element', function(){
                var element = layui.element;
            });
            var state='[[${session.user.photo}]]'; // --获取session中的值
            var id='[[${session.user.id}]]';
            if (state.length>3)// 学生连接
            {
                studentconnect(id);
            }
            else {// 教师连接
                teacherconnect(id);
            }
        }
 
        /*
          *
          *
          * 自定义定时器 为存在消息的图标添加样式
          *
          *
          * */
        layui.use(['layer','jquery'],function(){
            var $ = layui.$;
            function check(){
                if ($("#messageBox").children().length>0)
                {
                    // 有新消息
                    var info=''+$("#messageBox").children().length+'新消息';
                    $("#judge").html(info);
                }
                else{
                    // 无新消息
                    var info='消息';
                    $("#judge").html(info);
                    // console.log("replypoint无消息");
                }
            }
            window.setInterval(check, 1000);
 
        });
    </script>
    </body>
</html>

其他页面基本相似

8.项目总结与展望

对这个项目的总结:熟悉了springboot的基本项目该怎样去做,对Layui进一步了解(本来是准备用vue做的,还不太熟悉,所以采用了Layui),对websocket消息推送进一步了解,对springsecurity的配置能有了宏观的掌握。

展望:希望自己这个小白能在编程之路上越走越远。

你可能感兴趣的:(java,spring)