springboot+springsecurity+mybatis+websocket+thymeleaf+layui整合作业管理系统-详细解析

1.项目存在意义

对spring系列的框架进行整合,熟悉项目开发的流程和基本的章法,加强对基本框架的掌握。

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.学生查看批改作业信息

4.项目战前配置准备:

1.工具:

IDEA(没有工具的小伙伴们,可以在微信公众号软件安装管家下载哦)

2.项目种类:

springboot-maven项目

3.框架:

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

)

4.jdk:

1.8

5.数据库:

mysql5.0

6.数据库可视化工具:

navicat(网上有大把的免费资源)

5.项目详细讲解:

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

teacher_id

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

pom.xml如图(带有详细注解)



    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        2.1.6.RELEASE
         
    
    student_work-2
    alian
    0.0.1-SNAPSHOT
    alian
    Demo project for Spring Boot

    
        1.8
        5.1.2.RELEASE
    
    
        
        
            org.springframework.boot
            spring-boot-starter-web
        
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
        
        
        
            org.springframework.boot
            spring-boot-starter-security
        
        
        
            mysql
            mysql-connector-java
            5.1.6
        
        
        
        
        
        
        
        
        
            org.mybatis.spring.boot
            mybatis-spring-boot-starter
            2.1.0
        
        
        
            org.springframework.boot
            spring-boot-devtools
        
        
        
            org.springframework.boot
            spring-boot-starter-thymeleaf
        
        
        
            org.springframework.boot
            spring-boot-starter-websocket
        
        
        
            org.slf4j
            slf4j-api
        
        
        

        
        
            org.webjars
            webjars-locator-core
            0.35
        
        
        
            org.webjars
            sockjs-client
            1.1.2
        
        
        
            org.webjars
            stomp-websocket
            2.3.3-1
        
        
        
            org.webjars
            jquery
            3.3.1-1
        
        
        
            com.hankcs
            hanlp
            portable-1.3.2
        

    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
            
            
            
                org.mybatis.generator
                mybatis-generator-maven-plugin
                
                    ${basedir}/src/main/resources/generatorConfig.xml
                    true
                    true
                
            
        
        
            
                ${project.basedir}/src/main/resources
                true
                
                    static/**
                
            

            
                ${project.basedir}/src/main/resources
                false
                
                    static/**
                
            
        
    

当存在部分坐标引入的失败的时候,不必慌张,是由于您选择的maven中心库的原因,小编这里是选择阿里的maven库。

具体修改步骤请参考小编上篇文章: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已经修改,不用从新添加。

 
            
            
                org.mybatis.generator
                mybatis-generator-maven-plugin
                
                    ${basedir}/src/main/resources/generatorConfig.xml
                    true
                    true
                
            

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

内容如下:




    
    
    
        
            
            
            
        
        
        
        
        
            
        
        
        
            
            
        
        
        
            
        
        
        
            
        
        
        
        
        
        
        
        
        
        
        
        
        
    

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

1.这个路径是你本地数据库驱动的路径。

2.

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

3.生成的mapper,domain的位置,这里小编生成在alian这个包下面。


        
            
            
        
        
        
            
        
        
        
            
        

生成结果如图:

springboot+springsecurity+mybatis+websocket+thymeleaf+layui整合作业管理系统-详细解析_第1张图片

4.springboot整合springsecurity相关配置

*(为什么要引入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 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 map = new HashMap<>();
        Collection authorities= authentication.getAuthorities();
        Iterator   temp= (Iterator) 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;

/**
 * Created by linziyu on 2019/2/12.
 *
 * 用户登出处理类
 */

@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 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样式。

 
        
            org.webjars
            webjars-locator-core
            0.35
        
        
        
            org.webjars
            sockjs-client
            1.1.2
        
        
        
            org.webjars
            stomp-websocket
            2.3.3-1
        
        
        
            org.webjars
            jquery
            3.3.1-1
        

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 + '
'); $('#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页面(这里分两种权限连接,地址都是一样的,通过与服务器建立连接,达到即时通讯的目的)

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);// 向老师发送消息

    }

6.项目整体结构图

springboot+springsecurity+mybatis+websocket+thymeleaf+layui整合作业管理系统-详细解析_第2张图片

7.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 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 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

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 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 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 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 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 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 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;
    }
}

8.Html源码解析 :

login.html




	
	作业管理系统登录
	
    
    
    
    
    
    
    
    
    

    







验证码

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

直接免费下载。

index.html主页



    
        
        作业管理主页
        
        
        
        
        
        
        
        

        
        
        
    
    
        
        
        
        
        
        
        
        
        
        
  • 我的桌面
关闭当前
关闭其它
关闭全部

其他页面基本相似,小编就不一一列出了。

9.项目总结与展望

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

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

10.希望能得到指导和点评。

最喜欢的一句话:最高贵的一件事不是超过别人,而是超过过去的自己。

 

 

你可能感兴趣的:(项目Demo,springboot,springsecurity,mybatis,websocket,layui)