springboot+springsecurity+mybatis+websocket+thymeleaf+layui
教师功能:
1.发布作业
(1)教师可以发布多种格式的作业。1纯文本作业,2.纯文件作业,3.混合式作业。
2.修改作业
(1).教师可以修改发布作业(修改发布时间)。
3.批改作业
(1)可以对成绩打分。
(2)对于不合格的作业,老师可以打回让学生从做.
4.作业统计
(1)分数段统计
(2).作业评价关键字统计
5.信箱
(1).消息
学生功能:
1.提交作业
(1).作业格式:1学生提交作业,没有按照指定格式形式提交,系统直接打回
(2).超时不可提交作业.
2.查询批改后的作业
(1).学生查看批改的作业详情。
3.信箱
(1).消息
1.用户登录:(用户可以点击刷新验证码)
2.教师发布作业 :(可以为所带班级布置3种不同类别的作业)
3.教师修改作业(对于粗心超时未提交的学生,老师可以修改作业截止时间,从而学生继续提交作业)
4.教师批改作业(教师可以查看学生提交过来的作业,打分或者不合格直接打回)
5.作业数据统计(系统对学生的分数进行统计,评价作业进行关键字的提取)
6.教师查看自己的信箱中的信息
7.消息实时推送 (在教师发布作业的时,学生就立即收到消息)
8.学生查看信箱
9.学生提交作业
10.学生查看批改作业信息
1.工具:
IDEA
2.项目种类:
springboot-maven项目
3.框架:
Layui框架(本项目的页面基本是调用X-admin写好的layui页面,下载地址:http://x.xuebingsi.com/
4.jdk:
1.8
5.数据库:
mysql5.0
6.数据库可视化工具:
navicat
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>
生成结果如图:
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);// 向老师发送消息
}
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;
}
}
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"></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"></i>弹出最大化</a></dd>
<dd>
<a onclick="xadmin.open('弹出自动宽高','http://www.baidu.com')">
<i class="layui-icon"></i>弹出自动宽高</a></dd>
<dd>
<a onclick="xadmin.open('弹出指定宽高','http://www.baidu.com',500,300)">
<i class="layui-icon"></i>弹出指定宽高</a></dd>
<dd>
<a onclick="xadmin.add_tab('在tab打开','member-list.html')">
<i class="layui-icon"></i>在tab打开</a></dd>
<dd>
<a onclick="xadmin.add_tab('在tab打开刷新','member-del.html',true)">
<i class="layui-icon"></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;"></i>消息</a>
<dl class="layui-nav-child" id="messageBox">
<!--<!– 二级菜单 –>-->
<!--<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="作业管理"></i>
<cite>作业管理</cite>
<i class="layui-icon "></i></a>
<ul class="sub-menu">
<li>
<a onclick="xadmin.add_tab('发布作业','publishomework')">
<i class="layui-icon"></i>
<cite>发布作业</cite></a>
</li>
<li>
<a onclick="xadmin.add_tab('修改作业','edithomeworkwork')">
<i class="layui-icon"></i>
<cite>修改作业</cite></a>
</li>
<li>
<a onclick="xadmin.add_tab('批改作业','checkhomeworkwork',true)">
<i class="layui-icon"></i>
<cite>批改作业</cite></a>
</li>
<li>
<a onclick="xadmin.add_tab('测试','test',true)">
<i class="layui-icon"></i>
<cite>测试</cite></a>
</li>
</ul>
</li>
<li>
<a href="javascript:;">
<i class="layui-icon left-nav-li" lay-tips="教师通知管理模块"></i>
<cite>教师通知管理模块</cite>
<i class="layui-icon "></i></a>
<ul class="sub-menu">
<li>
<a onclick="xadmin.add_tab('发布通知','order-list.html')">
<i class="layui-icon"></i>
<cite>发布通知</cite></a>
</li>
<li>
<a onclick="xadmin.add_tab('查看通知','order-list1.html')">
<i class="layui-icon"></i>
<cite>查看通知</cite></a>
</li>
</ul>
</li>
<li>
<a href="javascript:;">
<i class="layui-icon left-nav-li" lay-tips="学生通知管理模块"></i>
<cite>学生通知管理模块</cite>
<i class="layui-icon "></i></a>
<ul class="sub-menu">
<li>
<a onclick="xadmin.add_tab('查看消息','studentReceiveMessages')">
<i class="layui-icon"></i>
<cite>查看消息</cite></a>
</li>
<li>
<a onclick="xadmin.add_tab('查看作业','StudentReceiveHomeworks')">
<i class="layui-icon"></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"></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>
其他页面基本相似
对这个项目的总结:熟悉了springboot的基本项目该怎样去做,对Layui进一步了解(本来是准备用vue做的,还不太熟悉,所以采用了Layui),对websocket消息推送进一步了解,对springsecurity的配置能有了宏观的掌握。
展望:希望自己这个小白能在编程之路上越走越远。