- Java工程师的进阶之路
- 资料地址
一、项目展示
1、登录及角色控制
2、业务模块展示
二、智慧校园系统简介
2.1、项目简介
智慧校园管理系统:主要是以年级、班级为单位,进行老师和学生信息记录和统计功能。项目采用前后端分离架构思想,前端采用HTML+CSS+VUE来实现页面效果展示,后端采用SpringBoot+MybatisPlus框架实现数据存储等服务。存储层使用高性能的MySQL,服务器使用SpringBoot内置的Tomcat9.x,项目构建工具使用Maven来管理jar包和项目构建。
2.2、项目模块
2.3、技术栈
VUE
是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。 前后端分离是目前一种非常流行的开发模式,它使项目的分工更加明确:后端:负责处理、存储数据. 前端:负责显示数据 前端和后端开发人员通过 接口 进行数据的交换。
Spring
Spring就像是整个项目中装配bean的大工厂,在配置文件中可以指定使用特定的参数去调用实体类的构造方法来实例化对象。也可以称之为项目中的粘合剂。
Spring的核心思想是IoC(控制反转),即不再需要程序员去显式地new
一个对象,而是让Spring框架帮你来完成这一切。
SpringMVC
SpringMVC在项目中拦截用户请求,它的核心Servlet即DispatcherServlet承担中介或是前台这样的职责,将用户请求通过HandlerMapping去匹配Controller,Controller就是具体对应请求所执行的操作。SpringMVC相当于SSH框架中struts。
mybatis-plus
mybatis是对jdbc的封装,它让数据库底层操作变的透明。mybatis的操作都是围绕一个sqlSessionFactory实例展开的。mybatis通过配置文件关联到各实体类的Mapper文件,Mapper文件中配置了每个类对数据库所需进行的sql语句映射。在每次与数据库交互时,通过sqlSessionFactory拿到一个sqlSession,再执行sql命令。MyBatis-plus
就是在MyBatis的基础上,为Mapper接口,Service层提供一些比较全面的CURD的业务逻辑功能,使程序员可以减少在Mapper和Service层的代码编写
MVC项目架构
页面发送请求给控制器,控制器调用业务层处理逻辑,逻辑层向持久层发送请求,持久层与数据库交互,后将结果返回给业务层,业务层将处理逻辑发送给控制器,控制器再调用视图展现数据。
2.4、环境准备
三、项目搭建
3.1、搭建工程
1、新建工程 - zhxy
- 包名:com.laptoy.zhxy
- Group:com.laptoy
2、安装插件
MybatisX、Lombok
3、开启注解功能
4、指定Maven配置
5、指定字符编码
6、POM
<?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 https://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.2.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.laptoy</groupId>
<artifactId>zhxy</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>zhxy</name>
<description>zhxy</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--单元测试启动器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- thymeleaf支持-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.1</version>
</dependency>
<!-- 简化POJO实体类开发 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.31</version>
</dependency>
<!--swagger-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.7.0</version>
</dependency>
<!--swagger ui-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.7.0</version>
</dependency>
<!--swagger2 增强版接口文档-->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>2.0.4</version>
</dependency>
<!--开发者工具-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.29</version>
</dependency>
<!-- JWT生成Token-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.7.0</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3.2、项目结构
1、目录结构
java目录:
- config : 项目的配置类
- controller: 控制层
- mapper : 持久层接口
- pojo : 实体类
- service: 服务层
- util: 工具类包
- ZhxyApplication : 启动类
resources目录:创建多级目录以 /
连接而不是 .
- mapper :持久层映射文件
- public/upload:文件上传目录
- static: 静态资源目录
- application.yml :SpringBoot核心配置文件
效果展示:
2、新建数据库 - 执行资料的SQL文件(资料在最上面)
3、application.yml
server:
port: 9001
spring:
# 解决SpringBoot2.6.0与swagger冲突问题【原因是在springboot2.6.0中将SpringMVC 默认路径匹配策略从AntPathMatcher 更改为PathPatternParser,导致出错,解决办法是切换回原先的AntPathMatcher】
mvc:
pathmatch:
matching-strategy: ant_path_matcher
datasource:
# 配置数据源类型
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/zhxy_db?characterEncoding=utf-8&serverTimezone=GMT%2B8&userSSL=false
username: root
password: root
# Mybatis-plus内置连接池
hikari:
connection-test-query: SELECT 1
connection-timeout: 60000
idle-timeout: 500000
max-lifetime: 540000
maximum-pool-size: 12
minimum-idle: 10
pool-name: GuliHikariPool
thymeleaf:
# 模板的模式,支持 HTML, XML TEXT JAVASCRIPT
mode: HTML5
# 编码 可不用配置
encoding: UTF-8
# 开发配置为false,避免修改模板还要重启服务器
cache: false
# 配置模板路径,默认是templates,可以不用配置
prefix: classpath:/static/
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
servlet:
# 设置文件上传上限
multipart:
max-file-size: 10MB
max-request-size: 100MB
mybatis-plus:
configuration:
#添加日志支持
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
mapper-locations: classpath*:/mapper/**/*.xml
4、前端页面放入static目录(资料在最上面)
5、测试
运行主启动类访问 localhost:9001
3.3、配置类
1、分页插件的配置类
package com.laptoy.zhxy.config;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@MapperScan("com.laptoy.zhxy.mapper")
public class MpConfig {
/**
* 分页插件
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
// paginationInterceptor.setLimit(你的最大单页限制数量,默认 500 条,小于 0 如 -1 不受限制);
return paginationInterceptor;
}
}
2、Swagger2的配置类
package com.laptoy.zhxy.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.service.Parameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.ArrayList;
import java.util.List;
/**
* Swagger2配置信息
*/
@Configuration
@EnableSwagger2
public class Swagger2Config {
@Bean
public Docket webApiConfig() {
//添加head参数start
List<Parameter> pars = new ArrayList<>();
ParameterBuilder tokenPar = new ParameterBuilder();
tokenPar.name("userId")
.description("用户ID")
.defaultValue("1")
.modelRef(new ModelRef("string"))
.parameterType("header")
.required(false)
.build();
pars.add(tokenPar.build());
ParameterBuilder tmpPar = new ParameterBuilder();
tmpPar.name("userTempId")
.description("临时用户ID")
.defaultValue("1")
.modelRef(new ModelRef("string"))
.parameterType("header")
.required(false)
.build();
pars.add(tmpPar.build());
//添加head参数end
return new Docket(DocumentationType.SWAGGER_2)
.groupName("webApi")
.apiInfo(webApiInfo())
.select()
//可以测试请求头中:输入token
.apis(RequestHandlerSelectors.basePackage("com.laptoy.zhxy.controller"))
//过滤掉admin路径下的所有页面
//.paths(Predicates.and(PathSelectors.regex("/sms/.*")))
//过滤掉所有error或error.*页面
//.paths(Predicates.not(PathSelectors.regex("/error.*")))
.build()
.globalOperationParameters(pars);
}
private ApiInfo webApiInfo() {
return new ApiInfoBuilder()
.title("网站-API文档")
.description("本文档描述了网站微服务接口定义")
.version("1.0")
.contact(new Contact("Laptoy", "https://blog.csdn.net/apple_53947466", "laptoy458@163.com"))
.build();
}
private ApiInfo adminApiInfo() {
return new ApiInfoBuilder()
.title("后台管理系统-API文档")
.description("本文档描述了后台管理系统微服务接口定义")
.version("1.0")
.contact(new Contact("Laptoy", "https://blog.csdn.net/apple_53947466", "laptoy458@163.com"))
.build();
}
}
3.4、工具类
从资源直接粘贴到 util包
1、验证码图片工具类 - CreateVerifiCodeImage
2、token口令生成工具 - JwtHelper
3、解析request请求中的 token口令的工具 - AuthContextHolder
4、MD5加密工具类 - MD5
5、响应结果类型码枚举 - ResultCodeEnum
6、JSON响应结果格式封装类 - Result
7、文件上传工具类 - UploadFile
3.5、业务层
使用MybatisX插件进行逆向生成
1、选中所有表
2、配置实体类
3、配置
4、每个impl添加 - @Transactional
开启事务
5、最终效果
6、额外 - 实体类 LoginForm 封装登录表单信息
@Data
public class LoginForm {
private String username;
private String password;
private String verifiCode;
private Integer userType;
}
7、控制层 - 按照前端接口 /sms/xxxController
进行编写
@RestController
@RequestMapping("/sms/adminController")
public class AdminController {
}
@RestController
@RequestMapping("/sms/clazzController")
public class ClazzController {
}
@RestController
@RequestMapping("/sms/gradeController")
public class GradeController {
}
@RestController
@RequestMapping("/sms/teacherController")
public class TeacherController {
}
@RestController
@RequestMapping("/sms/studentController")
public class StudentController {
}
8、系统控制层(如验证码)
@RestController
@RequestMapping("/sms/system")
public class SystemController {
}
四、登录功能后台实现
4.1、获取验证码
刷新页面 - 验证码API - /sms/system/getVerifiCodeImage
获取验证码图片及向session中存储验证码功能实现
1、控制层 - SystemController
@Api(tags = "系统控制器")
@RestController
@RequestMapping("/sms/system")
public class SystemController {
/**
* 获取验证码及展示验证码
*/
@ApiOperation("获取验证码图片")
@GetMapping("/getVerifiCodeImage")
public void getVerifiCodeImage(HttpServletRequest request, HttpServletResponse response) {
// 获取图片及图片上的验证码
BufferedImage verifiCodeImage = CreateVerifiCodeImage.getVerifiCodeImage();
String verifiCode = String.valueOf(CreateVerifiCodeImage.getVerifiCode());
// 将验证码放入session,为验证做准备
HttpSession session = request.getSession();
session.setAttribute("verifiCode", verifiCode);
// 将验证码图片响应给浏览器
try {
ImageIO.write(verifiCodeImage, "JPEG", response.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
}
2、效果
4.2、登录校验功能
点击登录按钮 - 登录API - /sms/system/login
代码实现
@Api(tags = "系统控制器")
@RestController
@RequestMapping("/sms/system")
public class SystemController {
@Autowired
private AdminService adminService;
@Autowired
private StudentService studentService;
@Autowired
private TeacherService teacherService;
/**
* 登录验证
*/
@ApiOperation("登录请求验证")
@PostMapping("/login")
public Result login(@RequestBody LoginForm loginForm, HttpServletRequest request) {
// 获取用户提交的验证码和session域中的验证码
HttpSession session = request.getSession();
String systemVerifiCode = (String) session.getAttribute("verifiCode");
String loginVerifiCode = loginForm.getVerifiCode();
// session过期,验证码超时
if ("".equals(systemVerifiCode)) {
return Result.fail().message("验证码失效,请刷新后重试");
}
// 验证码错误
if (!loginVerifiCode.equalsIgnoreCase(systemVerifiCode)) {
return Result.fail().message("验证码有误,请刷新后重新输入");
}
// 验证码使用完毕,移除当前请求域中的验证码
session.removeAttribute("verifiCode");
// 准备一个Map集合,用户存放响应的信息
Map<String, Object> map = new HashMap<>();
// 根据用户身份,验证登录的用户信息
switch (loginForm.getUserType()) {
case 1: // 管理员身份
try {
// 调用服务层登录方法,根据用户提交的LoginInfo信息,查询对应的Admin对象,找不到返回Null
Admin login = adminService.login(loginForm);
if (null != login) {
// 登录成功,将用户id和用户类型转换为token口令,作为信息响应给前端
map.put("token", JwtHelper.createToken(login.getId().longValue(), 1));
} else {
throw new RuntimeException("用户名或者密码有误!");
}
return Result.ok(map);
} catch (RuntimeException e) {
e.printStackTrace();
// 捕获异常,向用户响应错误信息
return Result.fail().message(e.getMessage());
}
case 2: // 学生身份
try {
// 调用服务层登录方法,根据用户提交的LoginInfo信息,查询对应的Student对象,找不到返回Null
Student login = studentService.login(loginForm);
if (null != login) {
// 登录成功,将用户id和用户类型转换为token口令,作为信息响应给前端
map.put("token", JwtHelper.createToken(login.getId().longValue(), 2));
} else {
throw new RuntimeException("用户名或者密码有误!");
}
return Result.ok(map);
} catch (RuntimeException e) {
e.printStackTrace();
// 捕获异常,向用户响应错误信息
return Result.fail().message(e.getMessage());
}
case 3: // 教师身份
try {
// 调用服务层登录方法,根据用户提交的LoginInfo信息,查询对应的Student对象,找不到返回Null
Teacher login = teacherService.login(loginForm);
if (null != login) {
// 登录成功,将用户id和用户类型转换为token口令,作为信息响应给前端
map.put("token", JwtHelper.createToken(login.getId().longValue(), 3));
} else {
throw new RuntimeException("用户名或者密码有误!");
}
return Result.ok(map);
} catch (RuntimeException e) {
e.printStackTrace();
// 捕获异常,向用户响应错误信息
return Result.fail().message(e.getMessage());
}
}
// 查无此用户,响应失败
return Result.fail().message("查无此用户");
}
}
AdminService中的login方法
@Service
@Transactional
public class AdminServiceImpl extends ServiceImpl<AdminMapper, Admin>
implements AdminService {
/**
* 超级管理员登录
*/
@Override
public Admin login(LoginForm loginForm) {
QueryWrapper<Admin> wrapper = new QueryWrapper<>();
wrapper.eq("name", loginForm.getUsername());
// 转换为密文进行查询
wrapper.eq("password", MD5.encrypt(loginForm.getPassword()));
Admin admin = baseMapper.selectOne(wrapper);
return admin;
}
}
StudentService中的login方法
@Service
@Transactional
public class StudentServiceImpl extends ServiceImpl<StudentMapper, Student>
implements StudentService {
/**
* 学生登录方法
*/
@Override
public Student login(LoginForm loginForm) {
QueryWrapper<Student> wrapper = new QueryWrapper<>();
wrapper.eq("name", loginForm.getUsername());
wrapper.eq("password", MD5.encrypt(loginForm.getPassword()));
return baseMapper.selectOne(wrapper);
}
}
TeacherService中的login方法
@Service
@Transactional
public class TeacherServiceImpl extends ServiceImpl<TeacherMapper, Teacher>
implements TeacherService {
/**
* Teacher登录方法
*/
@Override
public Teacher login(LoginForm loginForm) {
QueryWrapper<Teacher> wrapper = new QueryWrapper<>();
wrapper.eq("name", loginForm.getUsername());
wrapper.eq("password", MD5.encrypt(loginForm.getPassword()));
return baseMapper.selectOne(wrapper);
}
}
2、登录测试
4.3、跳转至首页功能实现
当验证通过后,前端会产生第二个请求,用以获取用户的类型,然后根据用户的类型来展现不同的页面,所以后端要有一个根据token解析用户类型并做出结果响应的控制层
获取信息API - /sms/system/getInfo
代码实现
@Api(tags = "系统控制器")
@RestController
@RequestMapping("/sms/system")
public class SystemController {
@Autowired
private AdminService adminService;
@Autowired
private StudentService studentService;
@Autowired
private TeacherService teacherService;
/**
* 跳转至首页
*/
@ApiOperation("通过token获取用户信息")
@GetMapping("/getInfo")
public Result getUserInfoByToken(HttpServletRequest request, @RequestHeader("token") String token) {
// 检查token 是否过期
if (JwtHelper.isExpiration(token)) {
return Result.build(null, ResultCodeEnum.TOKEN_ERROR);
}
// 解析token,获取用户id和用户类型
Long userId =JwtHelper.getUserId(token);
Integer userType =JwtHelper.getUserType(token);
// 准备一个Map集合用于存响应的数据
Map<String,Object> map=new HashMap<>();
switch (userType){
case 1:
Admin admin = adminService.getAdminById(userId.intValue());
map.put("user",admin);
map.put("userType",1);
break;
case 2:
Student student = studentService.getStudentById(userId.intValue());
map.put("user",student);
map.put("userType",2);
break;
case 3:
Teacher teacher = teacherService.getTeacherById(userId.intValue());
map.put("user",teacher);
map.put("userType",3);
break;
}
return Result.ok(map);
}
}
AdminService中的getAdminById方法
@Override
public Admin getAdminById(int intValue) {
QueryWrapper<Admin> wrapper = new QueryWrapper<>();
wrapper.eq("id",intValue);
Admin admin = baseMapper.selectOne(wrapper);
return admin;
}
StudentService中的getAdminById方法
@Override
public Student getStudentById(int intValue) {
QueryWrapper<Student> wrapper = new QueryWrapper<>();
wrapper.eq("id",intValue);
Student student = baseMapper.selectOne(wrapper);
return student;
}
TeacherService中的getAdminById方法
@Override
public Teacher getTeacherById(int intValue) {
QueryWrapper<Teacher> wrapper = new QueryWrapper<>();
wrapper.eq("id",intValue);
Teacher teacher = baseMapper.selectOne(wrapper);
return teacher;
}
效果
4.4、API文档展示
五、年级管理功能实现
5.1、查询年级信息【分页带条件】
点击年级管理模块API - /sms/gradeController/getGrades/1/3
GradeController 控制层代码
@Api(tags = "年级控制器")
@RestController
@RequestMapping("/sms/gradeController")
public class GradeController {
@Autowired
private GradeService gradeService;
/**
* 分页展示数据
*/
@ApiOperation("查询年级信息,分页带条件")
@GetMapping("/getGrades/{pageNo}/{pageSize}")
public Result getGradeByOpr(
@ApiParam("分页查询页码数") @PathVariable(value = "pageNo") Integer pageNo, // 页码数
@ApiParam("分页查询页大小") @PathVariable(value = "pageSize") Integer pageSize, // 页大小
@ApiParam("分页查询模糊匹配班级名") String gradeName) {
// 设置分页信息
Page<Grade> page = new Page<>(pageNo, pageSize);
// 调用服务层方法,传入分页信息,和查询的条件
IPage<Grade> pageRs = gradeService.getGradeByOpr(page, gradeName);
return Result.ok(pageRs);
}
}
GradeServiceImpl 业务层代码
@Service
@Transactional
public class GradeServiceImpl extends ServiceImpl<GradeMapper, Grade> implements GradeService {
@Override
public IPage<Grade> getGradeByOpr(Page<Grade> page, String gradeName) {
QueryWrapper<Grade> wrapper = new QueryWrapper<>();
if (!StringUtils.isEmpty(gradeName)) {
wrapper.like("name", gradeName);
}
wrapper.orderByAsc("id");
Page<Grade> gradePage = baseMapper.selectPage(page, wrapper);
return gradePage;
}
}
5.2、添加和修改年级信息
点击添加年级按钮输入数据执行添加API - /sms/gradeController/saveOrUpdateGrade
Controller层代码
@Api(tags = "年级控制器")
@RestController
@RequestMapping("/sms/gradeController")
public class GradeController {
@Autowired
private GradeService gradeService;
/**
* 保存或更新信息
*/
@ApiOperation("添加或者修改年级信息")
@PostMapping("/saveOrUpdateGrade")
public Result saveOrUpdateGrade(@ApiParam("JSON的grade对象转换后台数据模型") @RequestBody Grade grade) {
// 调用服务层方法,实现添加或者修改年级信息
gradeService.saveOrUpdate(grade);
return Result.ok();
}
}
5.3、删除和批量删除年级信息
点击删除按钮API - sms/gradeController/deleteGrade
(这张截图后面补截的)
Controller层代码
@Api(tags = "年级控制器")
@RestController
@RequestMapping("/sms/gradeController")
public class GradeController {
@Autowired
private GradeService gradeService;
/**
* 删除或批量删除
*/
@ApiOperation("删除一个或者多个grade信息")
@DeleteMapping("/deleteGrade")
public Result deleteGradeById(@ApiParam("JSON的年级id集合,映射为后台List<Integer>") @RequestBody List<Integer> ids) {
gradeService.removeByIds(ids);
return Result.ok();
}
}
5.4、API文档展示
六、班级管理功能实现
6.1、回显搜索条件中的年级选项
点击班级管理模块 - 年级名称API - /sms/gradeController/getGrades
控制层
@Api(tags = "年级控制器")
@RestController
@RequestMapping("/sms/gradeController")
public class GradeController {
@Autowired
private GradeService gradeService;
/**
* 回显搜索条件中的年级选项
*/
@ApiOperation("获取所有Grade信息")
@GetMapping("/getGrades")
public Result getGrades(){
List<Grade> grades = gradeService.getGrades();
return Result.ok(grades);
}
}
业务层
@Service
@Transactional
public class GradeServiceImpl extends ServiceImpl<GradeMapper, Grade> implements GradeService {
@Override
public List<Grade> getGrades() {
return baseMapper.selectList(null);
}
}
6.2、查询班级信息【分页带条件】
点击年级管理模块API - /sms/clazzController/getClazzsByOpr/1/3
控制层
@Api(tags = "班级控制器")
@RestController
@RequestMapping("/sms/clazzController")
public class ClazzController {
@Autowired
private ClazzService clazzService;
@ApiOperation("查询班级信息,分页带条件")
@GetMapping("/getClazzsByOpr/{pageNo}/{pageSize}")
public Result getClazzsByOpr(@ApiParam("页码数") @PathVariable("pageNo") Integer pageNo,
@ApiParam("页大小") @PathVariable("pageSize") Integer pageSize,
@ApiParam("查询条件") Clazz clazz) {
//设置分页信息
Page<Clazz> page = new Page<>(pageNo, pageSize);
IPage<Clazz> iPage = clazzService.getClazzsByOpr(page, clazz);
return Result.ok(iPage);
}
}
业务层
@Service
@Transactional
public class ClazzServiceImpl extends ServiceImpl<ClazzMapper, Clazz> implements ClazzService {
/**
* 分页查询所有班级信息【带条件】
*
* @param clazz
* @return
*/
@Override
public IPage<Clazz> getClazzsByOpr(Page<Clazz> pageParam, Clazz clazz) {
QueryWrapper<Clazz> queryWrapper = new QueryWrapper<>();
if (clazz != null) {
//年级名称条件
String gradeName = clazz.getGradeName();
if (!StringUtils.isEmpty(gradeName)) {
queryWrapper.eq("grade_name", gradeName);
}
//班级名称条件
String clazzName = clazz.getName();
if (!StringUtils.isEmpty(clazzName)) {
queryWrapper.like("name", clazzName);
}
queryWrapper.orderByAsc("id");
}
Page<Clazz> clazzPage = baseMapper.selectPage(pageParam, queryWrapper);
return clazzPage;
}
}
6.3、添加和修改学生信息
添加功能API - sms/clazzController/saveOrUpdateClazz
控制层
@Api(tags = "班级控制器")
@RestController
@RequestMapping("/sms/clazzController")
public class ClazzController {
@Autowired
private ClazzService clazzService;
@ApiOperation("保存或者修改班级信息")
@PostMapping("/saveOrUpdateClazz")
public Result saveOrUpdateClazz(@ApiParam("JSON转换后端Clazz数据模型") @RequestBody Clazz clazz) {
clazzService.saveOrUpdate(clazz);
return Result.ok();
}
}
6.4、删除和批量删除班级信息
删除功能API - sms/clazzController/deleteClazz
控制层
@Api(tags = "班级控制器")
@RestController
@RequestMapping("/sms/clazzController")
public class ClazzController {
@Autowired
private ClazzService clazzService;
@ApiOperation("删除一个或者多个班级信息")
@DeleteMapping("/deleteClazz")
public Result deleteClazzByIds(@ApiParam("多个班级id的JSON") @RequestBody List<Integer> ids) {
clazzService.removeByIds(ids);
return Result.ok();
}
}
6.5、API文档展示
七、学生管理功能实现
7.1、回显搜索条件的班级选项
点击教师管理API - sms/clazzController/getClazzs
控制层
@Api(tags = "班级控制器")
@RestController
@RequestMapping("/sms/clazzController")
public class ClazzController {
@Autowired
private ClazzService clazzService;
@ApiOperation("获取所有Clazz信息")
@GetMapping("/getClazzs")
public Result getClazzs() {
List<Clazz> list = clazzService.getClazzs();
return Result.ok(list);
}
}
业务层
@Service
@Transactional
public class ClazzServiceImpl extends ServiceImpl<ClazzMapper, Clazz> implements ClazzService {
@Override
public List<Clazz> getClazzs() {
return baseMapper.selectList(null);
}
}
7.2、查询学生信息【分页带条件】
控制层
@Api(tags = "学生控制器")
@RestController
@RequestMapping("/sms/studentController")
public class StudentController {
@Autowired
private StudentService studentService;
@ApiOperation("查询学生信息,分页带条件")
@GetMapping("/getStudentByOpr/{pageNo}/{pageSize}")
public Result getStudentsByOpr(@ApiParam("页码数") @PathVariable("pageNo") Integer pageNo,
@ApiParam("页大小") @PathVariable("pageSize") Integer pageSize,
@ApiParam("查询条件转换后端数据模型") Student student) {
// 准备分页信息封装的page对象
Page<Student> page = new Page<>(pageNo, pageSize);
// 获取分页的学生信息
IPage<Student> iPage = studentService.getStudentByOpr(page, student);
// 返回学生信息
return Result.ok(iPage);
}
}
业务层
@Service
@Transactional
public class StudentServiceImpl extends ServiceImpl<StudentMapper, Student> implements StudentService {
/**
* 按条件查询学生信息【带分页】
*/
public IPage<Student> getStudentByOpr(Page<Student> pageParam, Student student) {
QueryWrapper<Student> queryWrapper = null;
if (student != null) {
queryWrapper = new QueryWrapper<>();
if (student.getClazzName() != null) {
queryWrapper.eq("clazz_name", student.getClazzName());
}
if (student.getName() != null) {
queryWrapper.like("name", student.getName());
}
queryWrapper.orderByAsc("id");
}
//创建分页对象
IPage<Student> pages = baseMapper.selectPage(pageParam, queryWrapper);
return pages;
}
}
7.3、异步图片上传处理头像
Controller层代码
@Api(tags = "系统控制器")
@RestController
@RequestMapping("/sms/system")
public class SystemController {
@ApiOperation("头像上传统一入口")
@PostMapping("/headerImgUpload")
public Result headerImgUpload(@ApiParam("文件二进制数据") @RequestPart("multipartFile") MultipartFile multipartFile) {
//使用UUID随机生成文件名
String uuid = UUID.randomUUID().toString().replace("-", "").toLowerCase();
//生成新的文件名字
String filename = uuid.concat(multipartFile.getOriginalFilename());
//生成文件的保存路径(实际生产环境这里会使用真正的文件存储服务器)
String portraitPath = "D:/MyCode/IdeaCode/zhxy/target/classes/public/upload/".concat(filename);
//保存文件
try {
multipartFile.transferTo(new File(portraitPath));
} catch (IOException e) {
e.printStackTrace();
}
String headerImg = "upload/" + filename;
return Result.ok(headerImg);
}
}
7.4、添加和修改和删除学生信息
@Api(tags = "学生控制器")
@RestController
@RequestMapping("/sms/studentController")
public class StudentController {
@ApiOperation("增加学生信息")
@PostMapping("/addOrUpdateStudent")
public Result addOrUpdateStudent(@RequestBody Student student) {
//对学生的密码进行加密
if (!Strings.isEmpty(student.getPassword())) {
student.setPassword(MD5.encrypt(student.getPassword()));
}
//保存学生信息进入数据库
studentService.saveOrUpdate(student);
return Result.ok();
}
@ApiOperation("删除一个或者多个学生信息")
@DeleteMapping("/delStudentById")
public Result delStudentById(@ApiParam("多个学生id的JSON") @RequestBody List<Integer> ids) {
studentService.removeByIds(ids);
return Result.ok();
}
}
八、教师管理功能实现
8.1、查询教师信息【分页带条件】
点击教师管理API - sms/teacherController/getTeachers/1/3
控制层
@Api(tags = "教师控制器")
@RestController
@RequestMapping("/sms/teacherController")
public class TeacherController {
@Autowired
private TeacherService teacherService;
@ApiOperation("获取教师信息,分页带条件")
@GetMapping("/getTeachers/{pageNo}/{pageSize}")
public Result getTeachers(@PathVariable Integer pageNo, @PathVariable Integer pageSize, Teacher teacher) {
Page<Teacher> pageParam = new Page<>(pageNo, pageSize);
IPage<Teacher> page = teacherService.getTeachersByOpr(pageParam, teacher);
return Result.ok(page);
}
}
业务层
@Service
@Transactional
public class TeacherServiceImpl extends ServiceImpl<TeacherMapper, Teacher> implements TeacherService {
@Override
public IPage<Teacher> getTeachersByOpr(Page<Teacher> pageParam, Teacher teacher) {
QueryWrapper<Teacher> wrapper = new QueryWrapper<>();
if (teacher != null) {
//班级名称条件
String clazzName = teacher.getClazzName();
if (!StringUtils.isEmpty(clazzName)) {
wrapper.eq("clazz_name", clazzName);
}
//教师名称条件
String teacherName = teacher.getName();
if (!StringUtils.isEmpty(teacherName)) {
wrapper.like("name", teacherName);
}
wrapper.orderByAsc("id");
}
Page<Teacher> page = baseMapper.selectPage(pageParam, wrapper);
return page;
}
}
8.2、添加和修改和删除教师信息
@ApiOperation("添加和修改教师信息")
@PostMapping("/saveOrUpdateTeacher")
public Result saveOrUpdateTeacher(@RequestBody Teacher teacher) {
teacherService.saveOrUpdate(teacher);
return Result.ok();
}
@ApiOperation("删除一个或者多个教师信息")
@DeleteMapping("/deleteTeacher")
public Result deleteTeacher(@RequestBody List<Integer> ids) {
teacherService.removeByIds(ids);
return Result.ok();
}
九、管理员管理功能实现
9.1、查询管理员信息【分页带条件】
控制层
@Api(tags = "系统管理员控制器")
@RestController
@RequestMapping("/sms/adminController")
public class AdminController {
@Autowired
private AdminService adService;
@ApiOperation("分页获取所有Admin信息【带条件】")
@GetMapping("/getAllAdmin/{pageNo}/{pageSize}")
public Result getAllAdmin(@PathVariable Integer pageNo,
@PathVariable Integer pageSize,
String adminName){
Page<Admin> pageParam = new Page<>(pageNo,pageSize);
IPage<Admin> page = adService.getAdmins(pageParam, adminName);
return Result.ok(page);
}
}
业务层
@Service
@Transactional
public class AdminServiceImpl extends ServiceImpl<AdminMapper, Admin> implements AdminService {
@Override
public IPage<Admin> getAdmins(Page<Admin> pageParam, String adminName) {
QueryWrapper<Admin> queryWrapper = new QueryWrapper<>();
if (!StringUtils.isEmpty(adminName)) {
queryWrapper.like("name", adminName);
}
queryWrapper.orderByAsc("id");
Page page = baseMapper.selectPage(pageParam, queryWrapper);
return page;
}
}
9.2、添加和修改和删除管理员信息
@ApiOperation("添加或修改Admin信息")
@PostMapping("/saveOrUpdateAdmin")
public Result saveOrUpdateAdmin(@RequestBody Admin admin){
if (!Strings.isEmpty(admin.getPassword())) {
admin.setPassword(MD5.encrypt(admin.getPassword()));
}
adService.saveOrUpdate(admin);
return Result.ok();
}
@ApiOperation("删除Admin信息")
@DeleteMapping("/deleteAdmin")
public Result deleteAdmin(@RequestBody List<Integer> ids){
adService.removeByIds(ids);
return Result.ok();
}
9.3、管理员修改自己的密码
@Api(tags = "系统控制器")
@RestController
@RequestMapping("/sms/system")
public class SystemController {
@Autowired
private AdminService adminService;
@Autowired
private StudentService studentService;
@Autowired
private TeacherService teacherService;
@ApiOperation("修改密码")
@PostMapping("/updatePwd/{oldPwd}/{newPwd}")
public Result updatePwd(@RequestHeader("token") String token,
@PathVariable("oldPwd") String oldPwd,
@PathVariable("newPwd") String newPwd) {
if (JwtHelper.isExpiration(token)) {
// token过期
return Result.fail().message("token失效");
}
// 通过token获取当前登录的用户id
Long userId = JwtHelper.getUserId(token);
// 通过token获取当前登录的用户类型
Integer userType = JwtHelper.getUserType(token);
// 将明文密码转换为暗文
oldPwd = MD5.encrypt(oldPwd);
newPwd = MD5.encrypt(newPwd);
if (userType == 1) {
QueryWrapper<Admin> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("id", userId.intValue()).eq("password", oldPwd);
Admin admin = adminService.getOne(queryWrapper);
if (null != admin) {
admin.setPassword(newPwd);
adminService.saveOrUpdate(admin);
} else {
return Result.fail().message("原密码输入有误!");
}
} else if (userType == 2) {
QueryWrapper<Student> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("id", userId.intValue()).eq("password", oldPwd);
Student student = studentService.getOne(queryWrapper);
if (null != student) {
student.setPassword(newPwd);
studentService.saveOrUpdate(student);
} else {
return Result.fail().message("原密码输入有误!");
}
} else if (userType == 3) {
QueryWrapper<Teacher> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("id", userId.intValue()).eq("password", oldPwd);
Teacher teacher = teacherService.getOne(queryWrapper);
if (null != teacher) {
teacher.setPassword(newPwd);
teacherService.saveOrUpdate(teacher);
} else {
return Result.fail().message("原密码输入有误!");
}
}
return Result.ok();
}
}
十、毕业设计相关指导
10.1、开题报告
1、课题的名称
- 智慧校园管理系统
- 智能校园管理系统
- 智慧校园云台系统
2、设计课题的目标和意义
- 对使用者的意义 提高使用者工作效率,远程办公
- 对企业或者学校的意义 精简学校的管理人员,节约成本,提高效率
- 对社会的意义 为教育行业提供一个优秀的管理解决方案
- 技术层次的意义 更新项目的使用技术,功能拓展和性能提升更加方便容易
3、预期目标及成果形式
4、 成果的展现形式
项目成果展示+毕业论文
5、开发工具和技术栈
-
操作系统的选择:开发者使用Windows10 /11 ,项目运行环境为Linux.服务容器使用Tomcat
-
开发使用的工具
- 前端开发工具为HbuilderX,配合NodeJS运行时
- 后端开发工具为Idea,使用maven作为项目构建工具
-
数据库管理系统:mysql8作为数据库服务,同时配合Navicat/Sqlyog可视化数据库前端工具
-
相关框架
- VUE 独立开发前端代码
- SpringBoot快速搭建后端服务
- MyBatisPlus快速实现数据操作,同时优化业务层代码
- swagger2快速生成接口文档,同时可以帮助接口测试
- fastjson快速实现前后端数据转换
- commons-fileupload快速实现文件上传
6、项目的架构模式和开发模式
- 架构模式: MVC三层技术模型
- 开发模式:前后端分离的开发模式
7、进度和计划
- 需求分析 在导师的指导下,同时阅读相关文献,了解学校的实际的管理工作内容,同时接受一些新的管理理念,完成需求调研
- 数据库设计 在明确需求的情况下,对数据库进行设计
- 资料收集 根据要应用的技术,大量阅读资料,收集相关文献,问后续的编码做准备
- 接口设计 根据具体的业务项,开始逐一设计接口
- 模块实现 具体功能的实现
- 测试程序,整理资料,撰写文档
8、参考的相关资料
中国知网: 搜索关键字 校园管理 VUE SpringBoot MyBatisPlus swagger2
10.2、毕设编写
目录
1 论文名称
2 摘要
3 绪论
4 相关技术介绍
5 系统需求分析
6 系统概要设计
7 系统各功能模块的详细设计
8 系统实现中关键的问题和解决方案
9 系统测试及实现效果
10 总结与展望
11 参考文献
12 致谢
1、论文名称
- 名称不要太短
- 工程类项目且有成果展示可以叫 ***设计与实现
- 如果在理论上有一些建树,可以叫***理论研究
如:智慧校园云端管理系统的设计和实现
2、 摘要
- 项目的背景介绍:可以参考开题报告中,课题的目标和意义
- 毕业设计过程
- 管理类知识和理论的学习,引入了互联网的管理思维
- 结合实际校园工作内容,设计了那些业务
- 具体功能模块有那些,实现了那些业务
- 本项目的开发和测试中遇见的难点,遇见的问题,以及解决方案
- cookie session问题,登录的失效问题,用户权限问题,数据安全问题… …
- 成果说明:目前项目取得那些成果,完成了那些功能的开发,实际使用的体验感等
- 关键词:校园管理 SpringBoot+VUE SpringBoot+MyBatisPlus Swagger2 前后端分离
3、绪论(第一章)
- 论文设计的背景和意义 (管理相关的,互联网技术对于管理方式的革命性影响)
- 国内外现状和社会现状 (互联网技术在管理方面的应用已经渗入到各行各业,带来了效率的提高,教育行业也应该使用)
- 论文的主要内容介绍
本文主要进行了互联网时代校园管理的设计和实现. 由于… 因此… 本文在深入分析Vue+SpringBoot+MyBatisPlus的技术前提下,提出了一套校园管理的软件系统并详细阐述了技术选型和实现过程. 需求如何分析的,数据库如何设计的,技术如何选型的,项目如何搭建的. 过程是如何开发的
-
论文的组织结构
- 第一章 绪论
- 第二章 技术选型 +配合内容介绍
- 第三章 系统需求分析
- 第四章 … …
4、核心组件技术介绍(第二章)
- VUE技术介绍 历史 背景 特点 优点 原理
- SSM技术介绍与分析
- SpringBoot技术介绍
- MyBatisPlus技术介绍
- Swagger2技术介绍
- MVC架构
- 前后端分离开发和部署模式
5、系统需求分析(第三章)
-
功能需求分析
- 数据库的设计
- 登录的控制
- 年级模块
- 班级模块
- 教师模块
- 学生模块
- 管理员模块
- 个人信息管理模块
- 权限的控制
-
非功能需求
- 可靠性
- 可扩展性
- 易用性
- 其他约束
6、软件安装和项目环境搭建(第四章)
- 系统环境的准备
- 软件的安装
- 项目的搭建
- 运行检测
7、系统各功能模块的实现(第五章)
例如:验证码功能的实现
1、效果截图
业务分析 当加载登录页时,前端项目自动向后端请求一个验证码图片并展示在页面上,后端生成验证码后响应给前端,并将 验证码图片上的文本存储在session中,可以采用时序图,流程图等
2、接口介绍
- 请求方式 GET
- 请求的URI /sms/system/getVerifiCodeImage
- 请求的数据: none
- 响应的数据: image/jpeg
3、核心代码实现
8、系统实现中关键的问题和解决方案(第六章)
- 问题1 前后端分离开发,接口文档和接口测试问题:解决方案是: swagger2
- 问题2 cookie和Session控制登录校验的有效期问题:解决方案是:token
- 问题3 管理员,教师,学生三个身份登录后权限不同:解决方案是:根据用户类型查询不同的表格,根据不同的类型展示不同的页面
- 问题4 数据安全问题:解决方案是:MD5加密,密码的校验在密文状态下
- …
9、系统测试及实现效果(第七章)
每个业务如何使用swagger2测试,在这里进行介绍
删除学生信息测试
- 请求的URI
- 请求的方式
- 请求要提交的数据
- 响应的数据
swagger2测试的结果效果截图
10、总结与展望(第八章)
- 夸夸自己和导师 业务完整实现,技术选型新,开发过程流畅. 系统的可靠性,扩展性,易用性
- 展望未来 目前项目的设计还缺少具体的针对性,针对某个学校的业务工作流程继续细化,继续添加功能 打卡,考勤统计,成绩统计分析… …
11、参考文献
12、致谢
10.3、答辩PPT编写
主要包含的内容
首页 课题+答辩人+指导教师
第二页 后面的内容
第三页 目的和意义
第四页 系统的需求
第五页 项目的架构和技术栈
第六页 系统测试及实现效果
第七页 总结和展望文章来源:https://www.toymoban.com/news/detail-404060.html
第八页 致谢文章来源地址https://www.toymoban.com/news/detail-404060.html
到了这里,关于Java毕设项目:智慧校园管理系统的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!