小菜家教平台:基于SpringBoot+Vue打造一站式学习管理系统

前言

现在已经学习了很多与Java相关的知识,但是迟迟没有进行一个完整的实践(之前这个项目开发到一半,很多东西没学搁置了,同时原先的项目中也有很多的问题),所以现在准备从零开始做一个基于SpringBoot+Vue的大学生家教平台,打算边写项目的过程中写一个系列博客用于记录,故有了这篇文章。这个项目是从零开始做起,预计周期一个月,希望大家能多多支持,那样我就更多的动力能进行下去,同时大家也可以提出建议,我会积极采纳合理建议的!让我们一起见证一个从零开始的项目开发过程!

项目相关说明

技术栈

后端:SpringBoot、MyBatis-Plus、MySQL、Redis、SpringSecurity、Swagger等

前端:Vue

主要功能

1.用户注册与登录:提供安全的用户注册和登录机制,支持不同角色(家长、学生、教师)的账户管理。 

2.家教信息管理:家长可以发布家教信息,教师可以接家教,管理员能对家教信息进行管理等。

3.家教沟通:在课后教师可以线上布置作业、与家长交流等,同时家长在学生完成作业后可以进行上传、查看完成结果、对教师进行评价等。

4.信息发布与查询:在这个系统中,所有用户可以查看管理员发布的系统公告,同时所有人都能对系统进行反馈保证系统在不断修改的过程中变得更好~

项目开发

DAY 1任务 创建项目并进行一些依赖配置

一、创建SpringBoot项目

首先创建一个普通的SpringBoot项目

添加几个普通的依赖,后面其他依赖可以在pom.xml中进行添加

创建完项目后我们可以写一个简单controller进行测试

如图,我创建了一个简单Hellocontroller输出信息

package com.example.familyeducation.controller;import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class HelloController {@RequestMapping("/hello")public String hello(){return "hello";}
}

接着去application.properties中修改一下端口保证不会冲突

好,现在运行项目,并在浏览器中输入localhost:8889/hello进行访问,输出hello说明SpringBoot项目创建成功,没有什么问题

二、初步配置SpringSecurity

这个SpringSecurity的配置是跟着B站一个播放量最多的视频学的,推荐大家也可以去看看哦~

我们先在pom.xml文件中添加上依赖,同时我们可以去右侧maven中进行检查依赖是否添加成功

添加完依赖启动项目,继续访问localhost:8889/hello,界面跳转至SpringSecurity的默认登录界面

现在我们使用SpringSecurity的账号密码进行登录,后面会进行修改

登录名写test,密码去IDEA的输出框中查找,接着点击Sign in,界面成功跳转到hello中

接着我们继续配置Redis和一些登录相关的东西(fastjson、jwt、序列化器等)

我们先添加一下redis、fastjson、jwt的依赖同时去右侧maven进行检查

同时添加以下代码

package com.example.familyeducation.config;import com.example.familyeducation.utils.FastJsonRedisSerializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/*** @author 小菜* @date  2024/11/4* @description Redis序列化配置**/
@Configuration
public class RedisConfig {@Bean@SuppressWarnings(value = { "unchecked", "rawtypes" })//注解:用于告诉编译器在检查代码时忽略特定类型的警告public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory){RedisTemplate<Object, Object> template = new RedisTemplate<>();template.setConnectionFactory(connectionFactory);FastJsonRedisSerializer serializer = new FastJsonRedisSerializer(Object.class);// 使用StringRedisSerializer来序列化和反序列化redis的key值template.setKeySerializer(new StringRedisSerializer());template.setValueSerializer(serializer);// Hash的key也采用StringRedisSerializer的序列化方式template.setHashKeySerializer(new StringRedisSerializer());template.setHashValueSerializer(serializer);template.afterPropertiesSet();return template;}
}
package com.example.familyeducation.utils;import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import com.alibaba.fastjson.parser.ParserConfig;
import org.springframework.util.Assert;
import java.nio.charset.Charset;/*** Redis使用FastJson序列化*/
public class FastJsonRedisSerializer<T> implements RedisSerializer<T>
{public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");private Class<T> clazz;static{ParserConfig.getGlobalInstance().setAutoTypeSupport(true);}public FastJsonRedisSerializer(Class<T> clazz){super();this.clazz = clazz;}@Overridepublic byte[] serialize(T t) throws SerializationException{if (t == null){return new byte[0];}return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);}@Overridepublic T deserialize(byte[] bytes) throws SerializationException{if (bytes == null || bytes.length <= 0){return null;}String str = new String(bytes, DEFAULT_CHARSET);return JSON.parseObject(str, clazz);}protected JavaType getJavaType(Class<?> clazz){return TypeFactory.defaultInstance().constructType(clazz);}
}
package com.example.familyeducation.utils;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;import java.util.*;
import java.util.concurrent.TimeUnit;
/*** @author 小菜* @date  2024/11/4* @description Redis工具类,可以快速进行Redis操作**/@SuppressWarnings(value = { "unchecked", "rawtypes" })
@Component
public class RedisCache
{@Autowiredpublic RedisTemplate redisTemplate;/*** 缓存基本的对象,Integer、String、实体类等** @param key 缓存的键值* @param value 缓存的值*/public <T> void setCacheObject(final String key, final T value){redisTemplate.opsForValue().set(key, value);}/*** 缓存基本的对象,Integer、String、实体类等** @param key 缓存的键值* @param value 缓存的值* @param timeout 时间* @param timeUnit 时间颗粒度*/public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit){redisTemplate.opsForValue().set(key, value, timeout, timeUnit);}/*** 设置有效时间** @param key Redis键* @param timeout 超时时间* @return true=设置成功;false=设置失败*/public boolean expire(final String key, final long timeout){return expire(key, timeout, TimeUnit.SECONDS);}/*** 设置有效时间** @param key Redis键* @param timeout 超时时间* @param unit 时间单位* @return true=设置成功;false=设置失败*/public boolean expire(final String key, final long timeout, final TimeUnit unit){return redisTemplate.expire(key, timeout, unit);}/*** 获得缓存的基本对象。** @param key 缓存键值* @return 缓存键值对应的数据*/public <T> T getCacheObject(final String key){ValueOperations<String, T> operation = redisTemplate.opsForValue();return operation.get(key);}/*** 删除单个对象** @param key*/public boolean deleteObject(final String key){return redisTemplate.delete(key);}/*** 删除集合对象** @param collection 多个对象* @return*/public long deleteObject(final Collection collection){return redisTemplate.delete(collection);}/*** 缓存List数据** @param key 缓存的键值* @param dataList 待缓存的List数据* @return 缓存的对象*/public <T> long setCacheList(final String key, final List<T> dataList){Long count = redisTemplate.opsForList().rightPushAll(key, dataList);return count == null ? 0 : count;}/*** 获得缓存的list对象** @param key 缓存的键值* @return 缓存键值对应的数据*/public <T> List<T> getCacheList(final String key){return redisTemplate.opsForList().range(key, 0, -1);}/*** 缓存Set** @param key 缓存键值* @param dataSet 缓存的数据* @return 缓存数据的对象*/public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet){BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);Iterator<T> it = dataSet.iterator();while (it.hasNext()){setOperation.add(it.next());}return setOperation;}/*** 获得缓存的set** @param key* @return*/public <T> Set<T> getCacheSet(final String key){return redisTemplate.opsForSet().members(key);}/*** 缓存Map** @param key* @param dataMap*/public <T> void setCacheMap(final String key, final Map<String, T> dataMap){if (dataMap != null) {redisTemplate.opsForHash().putAll(key, dataMap);}}/*** 获得缓存的Map** @param key* @return*/public <T> Map<String, T> getCacheMap(final String key){return redisTemplate.opsForHash().entries(key);}/*** 往Hash中存入数据** @param key Redis键* @param hKey Hash键* @param value 值*/public <T> void setCacheMapValue(final String key, final String hKey, final T value){redisTemplate.opsForHash().put(key, hKey, value);}/*** 获取Hash中的数据** @param key Redis键* @param hKey Hash键* @return Hash中的对象*/public <T> T getCacheMapValue(final String key, final String hKey){HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();return opsForHash.get(key, hKey);}/*** 删除Hash中的数据** @param key* @param hkey*/public void delCacheMapValue(final String key, final String hkey){HashOperations hashOperations = redisTemplate.opsForHash();hashOperations.delete(key, hkey);}/*** 获取多个Hash中的数据** @param key Redis键* @param hKeys Hash键集合* @return Hash对象集合*/public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys){return redisTemplate.opsForHash().multiGet(key, hKeys);}/*** 获得缓存的基本对象列表** @param pattern 字符串前缀* @return 对象列表*/public Collection<String> keys(final String pattern){return redisTemplate.keys(pattern);}
}
package com.example.familyeducation.utils;import com.fasterxml.jackson.annotation.JsonInclude;/*** @author 小菜* @date  2024/11/4* @description 结果封装类**/
//注解:减少数据冗余,当你将 ResponseResult 对象序列化为 JSON 时,只有当对象的属性不为 null 时,才会包含在生成的 JSON 中
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ResponseResult<T> {/*** 状态码*/private Integer code;/*** 提示信息,如果有错误时,前端可以获取该字段进行提示*/private String msg;/*** 查询到的结果数据,*/private T data;public ResponseResult(Integer code, String msg) {this.code = code;this.msg = msg;}public ResponseResult(Integer code, T data) {this.code = code;this.data = data;}public Integer getCode() {return code;}public void setCode(Integer code) {this.code = code;}public String getMsg() {return msg;}public void setMsg(String msg) {this.msg = msg;}public T getData() {return data;}public void setData(T data) {this.data = data;}public ResponseResult(Integer code, String msg, T data) {this.code = code;this.msg = msg;this.data = data;}
}
package com.example.familyeducation.utils;import javax.servlet.http.HttpServletResponse;
import java.io.IOException;public class WebUtils
{/*** 将字符串渲染到客户端** @param response 渲染对象* @param string 待渲染的字符串* @return null*/public static String renderString(HttpServletResponse response, String string) {try{response.setStatus(200);response.setContentType("application/json");response.setCharacterEncoding("utf-8");response.getWriter().print(string);}catch (IOException e){e.printStackTrace();}return null;}
}

由于我们是要去数据库中进行用户账号密码的匹配登录,所以我们还要添加一下Mybatis-Plus和Mysql驱动器

然后去application.properties中配置一下Mysql的相关信息

都配置完之后我们就可以进行测试了

先添加一下实体类和mapper接口信息,我之前的项目中是直接将用户分成了三个表,又使用视图将三个表连接起来,后面出现了很多问题,后续也会进行全部修改,这里先进行演示

package com.example.familyeducation.entity;import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;import java.io.Serializable;@Data
@TableName(value = "user_view")
public class User implements Serializable {//因为这个类要存数据到Redis中,所以要进行序列化操作,继承Serializableprivate static final long serialVersionUID = 1L;private Integer userId;private String userPhone;private String userPassword;private String userName;private String userPicture;private String userRole;
}
package com.example.familyeducation.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.familyeducation.entity.User;public interface UserMapper extends BaseMapper<User> {
}

编写测试类进行测试,成功得到视图中的所有用户信息,说明我们的Mysql和Mybatis-Plus配置地都没有问题

这里运行过程中出现了一个小问题,好像是MyBatis-Plus和SpringBoot的版本冲突引起的问题,将SpringBoot版本变为2.7.16解决

同时运行还报了一个错,是密码加密存储的问题,我们要添加一个BCryptPasswordEncoder来将密码进行加密存储

package com.example.familyeducation.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Beanpublic PasswordEncoder passwordEncoder(){return new BCryptPasswordEncoder();}}

然后我们编写一个测试类输出加密后的密码并添加到数据库中,不然登录的时候会显示密码不是BCryptPassword报错

package com.example.familyeducation.config;import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.crypto.password.PasswordEncoder;/*** @ClassDescription:* @Author:小菜* @Create:2024/11/4 19:20**/
@SpringBootTest
public class PasswordEncoderTest {@Autowiredprivate PasswordEncoder passwordEncoder;@Testpublic void testPassword(){String rawPassword = "123456"; // 用户输入的明文密码String encodedPassword = passwordEncoder.encode(rawPassword);System.out.println(encodedPassword);}}
package com.example.familyeducation.service.impl;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.example.familyeducation.entity.LoginUser;
import com.example.familyeducation.entity.User;
import com.example.familyeducation.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;import java.util.Objects;/*** @ClassDescription:* @Author:小菜* @Create:2024/11/4 19:06**///这里继承的是security中的一个默认接口,重写其中的查询用户方法
@Service
public class UserDetailsServiceImpl implements UserDetailsService {@Autowiredprivate UserMapper userMapper;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {//根据用户名查询用户信息LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();wrapper.eq(User::getUserName,username);User user = userMapper.selectOne(wrapper);//如果查询不到数据就通过抛出异常来给出提示if(Objects.isNull(user)){throw new RuntimeException("用户名或密码错误");}//TODO 根据用户查询权限信息 添加到LoginUser中//封装成UserDetails对象返回return new LoginUser(user);}
}

最后我们重启项目,输入我们数据库中视图的对应数据

成功登录!

总结

到此为止,今天的项目大概就进行到这里,我们已经创建了一个最基本的SpringBoot项目并配置了一些组件,但是原先的数据库中有很大问题,需要返工。。。

那今天就这样,先去改改数据库,我们下篇再见!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/58260.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于Matlab的语音识别

一、引言 语音识别技术是让计算机识别一些语音信号&#xff0c;并把语音信号转换成相应的文本或者命令的一种高科技技术。语音识别技术所涉及的领域非常广泛&#xff0c;包括信号处理、模式识别、人工智能等技术。近年来已经从实验室开始走向市场&#xff0c;渗透到家电、通信…

如何在 IntelliJ IDEA 中调整 `Ctrl+/` 快捷键生成注释的位置

前言 在使用 IntelliJ IDEA 编写代码时&#xff0c;注释是代码可读性和维护性的重要组成部分。IDEA 提供了快捷键 Ctrl/ 用于快速生成单行注释。然而&#xff0c;默认情况下&#xff0c;使用此快捷键生成的注释会出现在行首&#xff0c;导致注释与代码之间存在较大的空格&…

源鲁杯 2024 web(部分)

[Round 1] Disal F12查看: f1ag_is_here.php 又F12可以发现图片提到了robots 访问robots.txt 得到flag.php<?php show_source(__FILE__); include("flag_is_so_beautiful.php"); $a$_POST[a]; $keypreg_match(/[a-zA-Z]{6}/,$a); $b$_REQUEST[b];if($a>99999…

使用 ADB 在某个特定时间点点击 Android 设备上的某个按钮

前提条件 安装 ADB&#xff1a;确保你已经在计算机上安装了 Android SDK&#xff08;或单独的 ADB&#xff09;。并将其添加到系统环境变量中&#xff0c;以便你可以在命令行中运行 adb。 USB调试&#xff1a;确保 Android 设备已启用 USB 调试模式。这可以在设备的“设置” -…

数据库的使用02:SQLServer的连接字符串、备份、还原、SQL监视相关设置

目录 一、连接字符串 【本地连接字符串】 【远程连接字符串】 二、备份 三、还原 &#xff08;1&#xff09;还原数据库-bak、btn文件 &#xff08;2&#xff09;附加数据库mdf文件 四、SQL监视器的使用 一、连接字符串 【本地连接字符串】 server DESKTOP-FTH2P3S; Da…

Oracle视频基础1.3.6练习

1.3.6 以下是您的需求清单&#xff08;不含解决方案&#xff09;&#xff1a; 检查数据库启动情况等待会话结束&#xff0c;进行正常关机等待事务全部提交后再关机查看 alert 日志文件查看后台跟踪文件查看用户跟踪文件 检查数据库启动情况 ps -ef | grep oracle ipcs clear…

【大数据学习 | HBASE】hbase的原理与组成结构

1. hbase的简述 hbase作为google的大数据三篇比较重要的论文之一&#xff0c;它的起源叫做bigtable&#xff0c;意思非常简单就是大表的意思&#xff0c;是一个分布式存储很多数据的大型表格系统&#xff0c;它是对于hdfs中的数据不能直观查询和随机读写的病痛的一个补充和完善…

苍穹外卖Bug集合

初始化后端项目运行出现以下问题 以上报错是因为maven和jdk版本不符合&#xff0c;需要将jdk改成17&#xff0c;mavne改成3.9.9

【C++篇】在秩序与混沌的交响乐中: STL之map容器的哲学探寻

文章目录 C map 容器详解&#xff1a;高效存储与快速查找前言第一章&#xff1a;C map 的概念1.1 map 的定义1.2 map 的特点 第二章&#xff1a;map 的构造方法2.1 常见构造函数2.1.1 示例&#xff1a;不同构造方法 2.2 相关文档 第三章&#xff1a;map 的常用操作3.1 插入操作…

太空旅游:科技能否让星辰大海变为现实?

内容概要 在这个快速变化的时代&#xff0c;太空旅游成为了一个让人热血沸腾的话题。想象一下&#xff0c;坐在一颗漂浮的太空舱里&#xff0c;手中端着饮料&#xff0c;眺望着无尽的星辰大海&#xff0c;简直就像科幻电影中的情节一样。不过&#xff0c;这不仅仅是一个空洞的…

程序中怎样用最简单方法实现写excel文档

很多开发语言都能找到excel文档读写的库&#xff0c;但是在资源极其受限的环境下开发&#xff0c;引入这些库会带来兼容性问题。因为一个小功能引入一堆库&#xff0c;我始终觉得划不来。看到有项目引用的jar包有一百多个&#xff0c;看着头麻&#xff0c;根本搞不清谁依赖谁。…

【春秋云镜】CVE-2023-23752

目录 CVE-2023-23752漏洞细节漏洞利用示例修复建议 春秋云镜&#xff1a;解法一&#xff1a;解法二&#xff1a; CVE-2023-23752 是一个影响 Joomla CMS 的未授权路径遍历漏洞。该漏洞出现在 Joomla 4.0.0 至 4.2.7 版本中&#xff0c;允许未经认证的远程攻击者通过特定 API 端…

解决虚拟机启动报:此主机支持AMD-V,但AMD-V处于禁用状态

首先要知道你自己使用的主板型号&#xff0c;如果是京东购买的&#xff0c;可以直接上京东去问客服。如果没有订单号&#xff0c;如果能提供正确的主板型号&#xff0c;他们应该也是会帮忙解答的。 您好&#xff0c;AMD 平台与 Intel 平台以及部分新老主板开启虚拟化的步骤和细…

【EI会议推荐】抢先掌握学术前沿!快来参加EI学术会议投稿,展示你的研究成果,开启科研新高度!

【EI会议推荐】抢先掌握学术前沿&#xff01;快来参加EI学术会议投稿&#xff0c;展示你的研究成果&#xff0c;开启科研新高度&#xff01; 【EI会议推荐】抢先掌握学术前沿&#xff01;快来参加EI学术会议投稿&#xff0c;展示你的研究成果&#xff0c;开启科研新高度&#…

2.若依vue表格数据根据不同状态显示不同颜色style

例如国标显示蓝色&#xff0c;超标是红色 使用是蓝色&#xff0c;未使用是绿色 <el-table-column label"外卖配送是否完成评价" align"center" prop"isOverFlag"> <template slot-scope"scope"> …

Java基础-内部类与异常处理

(创作不易&#xff0c;感谢有你&#xff0c;你的支持&#xff0c;就是我前行的最大动力&#xff0c;如果看完对你有帮助&#xff0c;请留下您的足迹&#xff09; 目录 一、Java 内部类 什么是内部类&#xff1f; 使用内部类的优点 访问局部变量的限制 内部类和继承 内部…

Java 基于SpringBoot+Vue 的公交智能化系统,附源码、文档

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

Spring Boot开发入门教程

简介 Spring Boot是一个开源的Java基础框架&#xff0c;用于创建独立、生产级的基于Spring框架的应用程序。通过Spring Boot&#xff0c;你可以轻松地创建独立的、生产级的Spring应用程序。 环境准备 Java开发环境&#xff1a;确保你的机器上安装了Java 8或更高版本。Maven…

科技资讯|谷歌Play应用商店有望支持 XR 头显,AR / VR设备有望得到发展

据 Android Authority 报道&#xff0c;谷歌似乎正在为其 Play 商店增加对 XR 头显的支持。该媒体在 Play 商店的代码中发现了相关的线索&#xff0c;包括一个代表头显的小图标以及对“XR 头显”的提及。 谷歌也可能改变了此前拒绝将 Play 商店引入 Meta Quest 头显的决定。今…