這個項目只有後端,沒有前端部分,只適合用來複習SpringBoot後端知識和體系。
B站視頻:https://www.bilibili.com/video/BV1AY4y1v7Xe/
https://pan.baidu.com/s/1efT4eY-dLBtNI-OTSUaWgA 提取碼:yyds
一、項目簡介
1.1 簡介
智慧校園管理系統:主要是以年級、班級爲單位,進行老師和學生信息記錄和統計功能。項目採用前後端分離架構思想,前端採用 HTML+CSS+VUE來實現頁面效果展示,後端採用 SpringBoot+MybatisPlus 框架實現數據存儲等服務。存儲層使用高性能的 MySQL,服務器使用 SpringBoot 內置的Tomcat9.x,項目構建工具使用Maven來管理jar包和項目構建。
1.2 項目模塊
1.3 使用的技術
-
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項目架構
頁面發送請求給控制器,控制器調用業務層處理邏輯,邏輯層向持久層發送請求,持久層與數據庫交互,後將結果返回給業務層,業務層將處理邏輯發送給控制器,控制器再調用視圖展現數據。
-
Swagger
Swagger 是一個規範且完整的框架,用於生成、描述、調用和可視化 RESTful 風格的 Web 服務。 Swagger 的目標是對 REST API 定義一個標準且和語言無關的接口,可以讓人和計算機擁有無須訪問源碼、文檔或網絡流量監測就可以發現和理解服務的能力。當通過 Swagger 進行正確定義,用戶可以理解遠程服務並使用最少實現邏輯與遠程服務進行交互。與爲底層編程所實現的接口類似,Swagger 消除了調用服務時可能會有的猜測。
Swagger 的優勢:支持 API 自動生成同步的在線文檔:使用 Swagger 後可以直接通過代碼生成文檔,不再需要自己手動編寫接口文檔了,對程序員來說非常方便,可以節約寫文檔的時間去學習新技術。提供 Web 頁面在線測試 API:光有文檔還不夠,Swagger 生成的文檔還支持在線測試。參數和格式都定好了,直接在界面上輸入參數對應的值即可在線測試接口。
1.4 軟件環境
二、環境搭建
2.1 使用IDEA的SpringBoot腳手架創建一個Maven項目
設置好包名及存放位置即可,無需添加其他功能,後面會對 pom.xml 大改,其他功能通過 maven 添加即可
2.2 在 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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- 繼承方式使用SpringBoot -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
<relativePath/>
</parent>
<groupId>com.atguigu</groupId>
<artifactId>myzhxy</artifactId>
<version>0.0.1-SNAPSHOT</version>
<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>
<!--spring boot maven插件 , 可以將項目運行依賴的jar包打到我們的項目中-->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2.3 準備項目結構
-
java目錄下
- config : 項目的配置類
- controller: 控制層
- mapper : 持久層接口
- pojo : 實體類
- service: 服務層
- util: 工具類包
- ZhxyApplication : 啓動類
-
resources目錄下
- mapper :持久層映射文件
- public/upload:文件上傳目錄
- static: 靜態資源目錄
- application.yml :SpringBoot核心配置文件
2.4 配置 application.yaml
server:
port: 8080 #指定當前項目啓動的端口號
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.jdbc.Driver
url: jdbc:mysql://localhost:3306/zhxy_db?characterEncoding=utf-8&useSSL=false #&serverTimezone=GMT%2B8
username: root
password: zyj123
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
2.5 準備分頁插件的配置類
源自mybatisplus
package com.atguigu.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.zyj.myzhxy.mapper")
public class MyConfig {
@Bean
public PaginationInterceptor paginationInterceptor(){
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
//paginationInterceptor.setLimit(你的最大單頁限制數量,默認 500 條,小於 0 如 -1 不受限制);
return paginationInterceptor;
}
}
2.6 準備 swagger2 的配置類
若想查看,需訪問 localhost:端口號/swagger-ui.html
只有有 Api 相關的註解纔會生成
@Api 標註在類上,示例:@Api(tags = "年級控制器")
@ApiOperation 標註在方法上,示例:@ApiOperation("(批量)刪除年級信息")
@ApiParam 標註在方法參數上,示例:@ApiParam("要刪除的年級信息的id的JSON集合") @RequestBody List<Integer> ids
package com.atguigu.zhxy.config;
import com.google.common.base.Predicates;
import io.swagger.annotations.ApiOperation;
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.PathSelectors;
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.withClassAnnotation(ApiOperation.class))
//過濾掉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("atguigu", "http://atguigu.com", "[email protected]"))
.build();
}
private ApiInfo adminApiInfo(){
return new ApiInfoBuilder()
.title("後臺管理系統-API文檔")
.description("本文檔描述了後臺管理系統微服務接口定義")
.version("1.0")
.contact(new Contact("atguigu", "http://atguigu.com", "[email protected]"))
.build();
}
}
2.7、準備 util 下的工具類
驗證碼圖片工具類
package com.atguigu.zhxy.util;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Random;
/**
* @project: ssm_sms
* @description: 繪製驗證碼圖片
*/
public class CreateVerifiCodeImage {
private static int WIDTH = 90;
private static int HEIGHT = 35;
private static int FONT_SIZE = 20; //字符大小
private static char[] verifiCode; //驗證碼
private static BufferedImage verifiCodeImage; //驗證碼圖片
/**
* @description: 獲取驗證碼圖片
* @param: no
* @return: java.awt.image.BufferedImage
*/
public static BufferedImage getVerifiCodeImage() {
verifiCodeImage = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_BGR);// create a image
Graphics graphics = verifiCodeImage.getGraphics();
verifiCode = generateCheckCode();
drawBackground(graphics);
drawRands(graphics, verifiCode);
graphics.dispose();
return verifiCodeImage;
}
/**
* @description: 獲取驗證碼
* @param: no
* @return: char[]
*/
public static char[] getVerifiCode() {
return verifiCode;
}
/**
* @description: 隨機生成驗證碼
* @param: no
* @return: char[]
*/
private static char[] generateCheckCode() {
String chars = "0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char[] rands = new char[4];
for (int i = 0; i < 4; i++) {
int rand = (int) (Math.random() * (10 + 26 * 2));
rands[i] = chars.charAt(rand);
}
return rands;
}
/**
* @description: 繪製驗證碼
* @param: g
* @param: rands
* @return: void
*/
private static void drawRands(Graphics g, char[] rands) {
g.setFont(new Font("Console", Font.BOLD, FONT_SIZE));
for (int i = 0; i < rands.length; i++) {
g.setColor(getRandomColor());
g.drawString("" + rands[i], i * FONT_SIZE + 10, 25);
}
}
/**
* @description: 繪製驗證碼圖片背景
* @param: g
* @return: void
*/
private static void drawBackground(Graphics g) {
g.setColor(Color.white);
g.fillRect(0, 0, WIDTH, HEIGHT);
// 繪製驗證碼干擾點
for (int i = 0; i < 200; i++) {
int x = (int) (Math.random() * WIDTH);
int y = (int) (Math.random() * HEIGHT);
g.setColor(getRandomColor());
g.drawOval(x, y, 1, 1);
}
}
/**
* @description: 獲取隨機顏色
* @param: no
* @return: java.awt.Color
*/
private static Color getRandomColor() {
Random ran = new Random();
return new Color(ran.nextInt(220), ran.nextInt(220), ran.nextInt(220));
}
}
token口令生成工具 JwtHelper
package com.atguigu.zhxy.util;
import io.jsonwebtoken.*;
import org.springframework.util.StringUtils;
import java.util.Date;
public class JwtHelper {
// 過期時間1天
private static long tokenExpiration = 24*60*60*1000;
// token信息後綴
private static String tokenSignKey = "123456";
//生成token字符串
public static String createToken(Long userId, Integer userType) {
String token = Jwts.builder()
.setSubject("YYGH-USER")
.setExpiration(new Date(System.currentTimeMillis() + tokenExpiration))
.claim("userId", userId)
// .claim("userName", userName)
.claim("userType", userType)
.signWith(SignatureAlgorithm.HS512, tokenSignKey)
.compressWith(CompressionCodecs.GZIP)
.compact();
return token;
}
//從token字符串獲取userid
public static Long getUserId(String token) {
if(StringUtils.isEmpty(token)) return null;
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
Claims claims = claimsJws.getBody();
Integer userId = (Integer)claims.get("userId");
return userId.longValue();
}
//從token字符串獲取userType
public static Integer getUserType(String token) {
if(StringUtils.isEmpty(token)) return null;
Jws<Claims> claimsJws
= Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
Claims claims = claimsJws.getBody();
return (Integer)(claims.get("userType"));
}
//從token字符串獲取userName
public static String getUserName(String token) {
if(StringUtils.isEmpty(token)) return "";
Jws<Claims> claimsJws
= Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
Claims claims = claimsJws.getBody();
return (String)claims.get("userName");
}
//判斷token是否有效
public static boolean isExpiration(String token){
try {
boolean isExpire = Jwts.parser()
.setSigningKey(tokenSignKey)
.parseClaimsJws(token)
.getBody()
.getExpiration().before(new Date());
//沒有過期,有效,返回false
return isExpire;
}catch(Exception e) {
//過期出現異常,返回true
return true;
}
}
/**
* 刷新Token
* @param token
* @return
*/
public String refreshToken(String token) {
String refreshedToken;
try {
final Claims claims = Jwts.parser()
.setSigningKey(tokenSignKey)
.parseClaimsJws(token)
.getBody();
refreshedToken = JwtHelper.createToken(getUserId(token), getUserType(token));
} catch (Exception e) {
refreshedToken = null;
}
return refreshedToken;
}
// 測試方法
// public static void main(String[] args) {
// String token = JwtHelper.createToken(1L, "lucy");
// System.out.println(token);
// System.out.println(JwtHelper.getUserId(token));
// System.out.println(JwtHelper.getUserName(token));
// }
}
解析request請求中的 token口令的工具AuthContextHolder
對JwtHelper進一步封裝
package com.atguigu.zhxy.util;
import javax.servlet.http.HttpServletRequest;
public class AuthContextHolder {
//從請求頭token獲取userid
public static Long getUserIdToken(HttpServletRequest request) {
//從請求頭token
String token = request.getHeader("token");
//調用工具類
Long userId = JwtHelper.getUserId(token);
return userId;
}
//從請求頭token獲取name
public static String getUserName(HttpServletRequest request) {
//從header獲取token
String token = request.getHeader("token");
//jwt從token獲取username
String userName = JwtHelper.getUserName(token);
return userName;
}
}
MD5加密工具類
明文轉密文,進行加密
登錄輸入的是明文,數據庫存儲的是密文
package com.atguigu.zhxy.util;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public final class MD5 {
public static String encrypt(String strSrc) {
try {
char hexChars[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8',
'9', 'a', 'b', 'c', 'd', 'e', 'f' };
byte[] bytes = strSrc.getBytes();
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(bytes);
bytes = md.digest();
int j = bytes.length;
char[] chars = new char[j * 2];
int k = 0;
for (int i = 0; i < bytes.length; i++) {
byte b = bytes[i];
chars[k++] = hexChars[b >>> 4 & 0xf];
chars[k++] = hexChars[b & 0xf];
}
return new String(chars);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
throw new RuntimeException("MD5加密出錯!!+" + e);
}
}
}
JSON響應結果格式封裝類Result
後端在相應數據時,如果數據沒有同一格式,將會非常混亂。
所以要定義一個公共規範,後端不論返回任何數據都要裝到Result中,再去返回。
package com.atguigu.zhxy.util;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* 全局統一返回結果類
*
*/
@Data
@ApiModel(value = "全局統一返回結果")
public class Result<T> {
@ApiModelProperty(value = "返回碼")
private Integer code;
@ApiModelProperty(value = "返回消息")
private String message;
@ApiModelProperty(value = "返回數據")
private T data;
public Result(){}
// 返回數據
protected static <T> Result<T> build(T data) {
Result<T> result = new Result<T>();
if (data != null)
result.setData(data);
return result;
}
// ResultCodeEnum 響應狀態碼的枚舉
public static <T> Result<T> build(T body, ResultCodeEnum resultCodeEnum) {
Result<T> result = build(body);
result.setCode(resultCodeEnum.getCode());
result.setMessage(resultCodeEnum.getMessage());
return result;
}
public static<T> Result<T> ok(){
return Result.ok(null);
}
/**
* 操作成功
* @param data
* @param <T>
* @return
*/
public static<T> Result<T> ok(T data){
Result<T> result = build(data);
return build(data, ResultCodeEnum.SUCCESS);
}
public static<T> Result<T> fail(){
return Result.fail(null);
}
/**
* 操作失敗
* @param data
* @param <T>
* @return
*/
public static<T> Result<T> fail(T data){
Result<T> result = build(data);
return build(data, ResultCodeEnum.FAIL);
}
public Result<T> message(String msg){
this.setMessage(msg);
return this;
}
public Result<T> code(Integer code){
this.setCode(code);
return this;
}
public boolean isOk() {
if(this.getCode().intValue() == ResultCodeEnum.SUCCESS.getCode().intValue()) {
return true;
}
return false;
}
}
響應結果類型碼枚舉
package com.atguigu.zhxy.util;
import lombok.Getter;
/**
* 統一返回結果狀態信息類
*
*/
@Getter
public enum ResultCodeEnum {
SUCCESS(200,"成功"),
FAIL(201, "失敗"),
SERVICE_ERROR(2012, "服務異常"),
ILLEGAL_REQUEST( 204, "非法請求"),
PAY_RUN(205, "支付中"),
ARGUMENT_VALID_ERROR(206, "參數校驗錯誤"),
LOGIN_ERROR(207, "用戶名或密碼錯誤"),
LOGIN_AUTH(208, "未登陸"),
PERMISSION(209, "沒有權限"),
SECKILL_NO_START(210, "秒殺還沒開始"),
SECKILL_RUN(211, "正在排隊中"),
SECKILL_NO_PAY_ORDER(212, "您有未支付的訂單"),
SECKILL_FINISH(213, "已售罄"),
SECKILL_END(214, "秒殺已結束"),
SECKILL_SUCCESS(215, "搶單成功"),
SECKILL_FAIL(216, "搶單失敗"),
SECKILL_ILLEGAL(217, "請求不合法"),
SECKILL_ORDER_SUCCESS(218, "下單成功"),
COUPON_GET(220, "優惠券已經領取"),
COUPON_LIMIT_GET(221, "優惠券已發放完畢"),
//2022-02-22
LOGIN_CODE(222,"長時間未操作,會話已失效,請刷新頁面後重試!"),
CODE_ERROR(223,"驗證碼錯誤!"),
TOKEN_ERROR(224,"Token無效!")
;
private Integer code;
private String message;
private ResultCodeEnum(Integer code, String message) {
this.code = code;
this.message = message;
}
}
文件上傳工具類
package com.atguigu.zhxy.util;
import org.apache.commons.io.filefilter.SuffixFileFilter;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* @project: zhxy
* @description: 上傳文件的工具類
*/
public class UploadFile {
//存儲文件上傳失敗的錯誤信息
private static Map<String, Object> error_result = new HashMap<>();
//存儲頭像的上傳結果信息
private static Map<String, Object> upload_result = new HashMap<>();
/**
* @description: 效驗所上傳圖片的大小及格式等信息...
* @param: photo
* @param: path
* @return: java.util.Map<java.lang.String, java.lang.Object>
*/
private static Map<String, Object> uploadPhoto(MultipartFile photo, String path) {
//限制頭像大小(20M)
int MAX_SIZE = 20971520;
//獲取圖片的原始名稱
String orginalName = photo.getOriginalFilename();
//如果保存文件的路徑不存在,則創建該目錄
File filePath = new File(path);
if (!filePath.exists()) {
filePath.mkdirs();
}
//限制上傳文件的大小
if (photo.getSize() > MAX_SIZE) {
error_result.put("success", false);
error_result.put("msg", "上傳的圖片大小不能超過20M喲!");
return error_result;
}
// 限制上傳的文件類型
String[] suffixs = new String[]{".png", ".PNG", ".jpg", ".JPG", ".jpeg", ".JPEG", ".gif", ".GIF", ".bmp", ".BMP"};
SuffixFileFilter suffixFileFilter = new SuffixFileFilter(suffixs);
if (!suffixFileFilter.accept(new File(path + orginalName))) {
error_result.put("success", false);
error_result.put("msg", "禁止上傳此類型文件! 請上傳圖片喲!");
return error_result;
}
return null;
}
/**
* @description: (提取公共代碼 : 提高代碼的可重用性)獲取頭像的上傳結果信息
* @param: photo
* @param: dirPaht
* @param: portraitPath
* @return: java.util.Map<java.lang.String, java.lang.Object>
*/
public static Map<String, Object> getUploadResult(MultipartFile photo, String dirPaht, String portraitPath) {
if (!photo.isEmpty() && photo.getSize() > 0) {
//獲取圖片的原始名稱
String orginalName = photo.getOriginalFilename();
//上傳圖片,error_result:存儲頭像上傳失敗的錯誤信息
Map<String, Object> error_result = UploadFile.uploadPhoto(photo, dirPaht);
if (error_result != null) {
return error_result;
}
//使用UUID重命名圖片名稱(uuid__原始圖片名稱)
String newPhotoName = UUID.randomUUID() + "__" + orginalName;
//將上傳的文件保存到目標目錄下
try {
photo.transferTo(new File(dirPaht + newPhotoName));
upload_result.put("success", true);
upload_result.put("portrait_path", portraitPath + newPhotoName);//將存儲頭像的項目路徑返回給頁面
} catch (IOException e) {
e.printStackTrace();
upload_result.put("success", false);
upload_result.put("msg", "上傳文件失敗! 服務器端發生異常!");
return upload_result;
}
} else {
upload_result.put("success", false);
upload_result.put("msg", "頭像上傳失敗! 未找到指定圖片!");
}
return upload_result;
}
}
2.8 創建數據表及數據
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for tb_admin
-- ----------------------------
DROP TABLE IF EXISTS `tb_admin`;
CREATE TABLE `tb_admin` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(15) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`gender` CHAR(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`password` VARCHAR(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`email` VARCHAR(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`telephone` VARCHAR(12) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`address` VARCHAR(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`portrait_path` VARCHAR(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = INNODB AUTO_INCREMENT = 157 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of tb_admin
-- ----------------------------
INSERT INTO `tb_admin` VALUES (101, 'admin', '女', '21232f297a57a5a743894a0e4a801fc3', '[email protected]', '13260161111', '昌平', 'upload/default.jpg');
INSERT INTO `tb_admin` VALUES (102, 'admin1', '男', '21232f297a57a5a743894a0e4a801fc3', '[email protected]', '13260166090', '北京', 'upload/default.jpg');
INSERT INTO `tb_admin` VALUES (103, 'admin2', '男', '21232f297a57a5a743894a0e4a801fc3', '[email protected]', '13260166090', '北京', 'upload/default.jpg');
INSERT INTO `tb_admin` VALUES (104, 'admin3', '男', '21232f297a57a5a743894a0e4a801fc3', '[email protected]', '13666666666', '宏福苑', 'upload/default.jpg');
-- ----------------------------
-- Table structure for tb_clazz
-- ----------------------------
DROP TABLE IF EXISTS `tb_clazz`;
CREATE TABLE `tb_clazz` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(15) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`number` INT(3) NULL DEFAULT NULL,
`introducation` VARCHAR(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`headmaster` VARCHAR(15) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`email` VARCHAR(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`telephone` VARCHAR(12) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`grade_name` VARCHAR(15) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = INNODB AUTO_INCREMENT = 10 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of tb_clazz
-- ----------------------------
INSERT INTO `tb_clazz` VALUES (1, '一年一班', 30, '大聖的一年一班好', '大聖', '[email protected]', '13260166090', '一年級');
INSERT INTO `tb_clazz` VALUES (2, '一年二班', 28, '小張的一年二班好', '小張', '[email protected]', '13260166090', '一年級');
INSERT INTO `tb_clazz` VALUES (3, '二年一班', 35, '小韓的二年一班好', '小韓', '[email protected]', '13260166090', '二年級');
INSERT INTO `tb_clazz` VALUES (4, '二年二班', 30, '小強的二年二班好', '小強', '[email protected]', '13260166090', '二年級');
INSERT INTO `tb_clazz` VALUES (5, '三年一班', 30, '小花的三年一班好', '小花', '[email protected]', '13260166090', '三年級');
INSERT INTO `tb_clazz` VALUES (6, '三年二班', 30, '小趙的三年二班好', '小趙', '[email protected]', '13260166090', '三年級');
INSERT INTO `tb_clazz` VALUES (7, '四年一班', 30, '小趙的三年二班好', '小飛', '[email protected]', '13260166090', '四年級');
-- ----------------------------
-- Table structure for tb_grade
-- ----------------------------
DROP TABLE IF EXISTS `tb_grade`;
CREATE TABLE `tb_grade` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(15) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
`manager` VARCHAR(15) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`email` VARCHAR(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`telephone` VARCHAR(12) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`introducation` VARCHAR(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`, `name`) USING BTREE
) ENGINE = INNODB AUTO_INCREMENT = 12 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of tb_grade
-- ----------------------------
INSERT INTO `tb_grade` VALUES (1, '一年級', '大聖', '[email protected]', '13260166090', '大學一年級');
INSERT INTO `tb_grade` VALUES (2, '二年級', '小魏', '[email protected]', '13260166090', '大學二年級');
INSERT INTO `tb_grade` VALUES (3, '三年級', '小李', '[email protected]', '13666666666', '三年級,這個班級的孩子們很有才藝');
INSERT INTO `tb_grade` VALUES (4, '五年級', '小麗', '[email protected]', '13666666666', '這個年級的同學多才多活力');
INSERT INTO `tb_grade` VALUES (5, '六年級', '小明', '[email protected]', '13666666666', '這個年級的主任是小明');
-- ----------------------------
-- Table structure for tb_student
-- ----------------------------
DROP TABLE IF EXISTS `tb_student`;
CREATE TABLE `tb_student` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`sno` VARCHAR(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`name` VARCHAR(15) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`gender` CHAR(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`password` VARCHAR(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`email` VARCHAR(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`telephone` VARCHAR(12) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`address` VARCHAR(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`introducation` VARCHAR(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`portrait_path` VARCHAR(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`clazz_name` VARCHAR(15) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = INNODB AUTO_INCREMENT = 10 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of tb_student
-- ----------------------------
INSERT INTO `tb_student` VALUES (1, '1001', '張小明', '男', 'e10adc3949ba59abbe56e057f20f883e', '[email protected]', '13260166090', '北京天通苑', '這個學生學習好', 'upload/default.jpg', '一年一班');
INSERT INTO `tb_student` VALUES (2, '1002', '郭建超', '男', 'e10adc3949ba59abbe56e057f20f883e', '[email protected]', '13260166090', '北京昌平', '這個學生會功夫', 'upload/default.jpg', '一年一班');
INSERT INTO `tb_student` VALUES (3, '1003', '史汶鑫', '男', 'e10adc3949ba59abbe56e057f20f883e', '[email protected]', '13260166090', '北京昌平', '這個學生酒量好', 'upload/default.jpg', '二年一班');
INSERT INTO `tb_student` VALUES (4, '1004', '高建軍', '男', 'e10adc3949ba59abbe56e057f20f883e', '[email protected]', '13260166090', '北京昌平', '這個學生會做飯', 'upload/default.jpg', '二年一班');
INSERT INTO `tb_student` VALUES (5, '1005', '鄒偉斌', '男', 'e10adc3949ba59abbe56e057f20f883e', '[email protected]', '13260166090', '北京昌平', '這個學生能喫辣', 'upload/default.jpg', '三年一班');
INSERT INTO `tb_student` VALUES (6, '1006', '劉路', '男', 'e10adc3949ba59abbe56e057f20f883e', '[email protected]', '13260166090', '北京昌平', '這個學生是學霸', 'upload/default.jpg', '三年二班');
INSERT INTO `tb_student` VALUES (7, '1007', '龐家仨', '女', 'e10adc3949ba59abbe56e057f20f883e', '[email protected]', '13260166090', '北京昌平', '這個學生海拔高', 'upload/default.jpg', '三年二班');
INSERT INTO `tb_student` VALUES (8, '1008', '譚帥', '男', 'e10adc3949ba59abbe56e057f20f883e', '[email protected]', '13260166090', '北京昌平', '這個學生想考研', 'upload/default.jpg', '四年一班');
-- ----------------------------
-- Table structure for tb_teacher
-- ----------------------------
DROP TABLE IF EXISTS `tb_teacher`;
CREATE TABLE `tb_teacher` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`tno` VARCHAR(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`name` VARCHAR(15) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`gender` CHAR(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`password` VARCHAR(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`email` VARCHAR(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`telephone` VARCHAR(12) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`address` VARCHAR(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`portrait_path` VARCHAR(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`clazz_name` VARCHAR(15) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = INNODB AUTO_INCREMENT = 9 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of tb_teacher
-- ----------------------------
INSERT INTO `tb_teacher` VALUES (1, '101', '大聖', '女', '123456', '[email protected]', '13260166090', '北京昌平', 'upload/default.jpg', '一年一班');
INSERT INTO `tb_teacher` VALUES (2, '102', '小張', '男', 'e10adc3949ba59abbe56e057f20f883e', '[email protected]', '13260166090', '北京海淀', 'upload/default.jpg', '一年二班');
INSERT INTO `tb_teacher` VALUES (3, '103', '小韓', '男', 'e10adc3949ba59abbe56e057f20f883e', '[email protected]', '13260166090', '北京朝陽', 'upload/default.jpg', '二年一班');
INSERT INTO `tb_teacher` VALUES (4, '104', '小強', '男', 'e10adc3949ba59abbe56e057f20f883e', '[email protected]', '13260166090', '北京通州', 'upload/default.jpg', '二年二班');
INSERT INTO `tb_teacher` VALUES (5, '105', '小花', '男', 'e10adc3949ba59abbe56e057f20f883e', '[email protected]', '13260166090', '北京順義', 'upload/default.jpg', '三年一班');
INSERT INTO `tb_teacher` VALUES (6, '106', '小趙', '男', 'e10adc3949ba59abbe56e057f20f883e', '[email protected]', '13260166090', '北京東城', 'upload/default.jpg', '三年二班');
INSERT INTO `tb_teacher` VALUES (7, '107', '小飛', '男', 'e10adc3949ba59abbe56e057f20f883e', '[email protected]', '13260166090', '北京西城', 'upload/default.jpg', '四年一班');
INSERT INTO `tb_teacher` VALUES (8, '108', '秀秀', '女', 'e10adc3949ba59abbe56e057f20f883e', '[email protected]', '13855555555', '海淀', 'upload/12fe07bf8b6d493b96294f1ef0552339default.jpg', '一年一班');
SET FOREIGN_KEY_CHECKS = 1;
2.9 準備各層基礎代碼
這裏只寫 admin,其他類似
這裏只是演示一個框架,具體實現內容參見後面內容
pojo
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("tb_admin")
public class Admin {
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
private String name;
private Character gender;
private String password;
private String email;
private String telephone;
private String address;
private String portraitPath; // 頭像圖片路徑
}
mapper
@Mapper
public interface AdminMapper extends BaseMapper<Admin> {
}
service
接口
public interface AdminService extends IService<Admin> {
}
接口實現類
@Service("adminServiceImpl")
@Transactional
public class AdminServiceImpl extends ServiceImpl<AdminMapper, Admin> implements AdminService {
}
controller
@RestController
@RequestMapping("/sms/adminController")
public class AdminController {
}
三、登錄功能實現
3.1 登錄的過程
登錄需要實現兩個請求處理
第一次需要處理表單的內容,校驗登錄信息
第二次請求,會發送第一次請求的 token,需要處理這個 token,從而從登錄頁跳轉到首頁
3.2 驗證碼功能實現
在 SystemController 添加相應的方法
@Api(tags = "系統控制器")
@RestController
@RequestMapping("/sms/system")
public class SystemController {
//獲取驗證碼圖片
@GetMapping("/getVerifiCodeImage")
public void getVerifiCodeImage(HttpServletRequest request, HttpServletResponse response){
// 獲取圖片
BufferedImage verifiCodeImage = CreateVerifiCodeImage.getVerifiCodeImage();
// 獲取圖片上的驗證碼
char[] verifiCodeChars = CreateVerifiCodeImage.getVerifiCode();
String verifiCode = new String(verifiCodeChars);
// 將驗證碼文本放入session域,爲下一次驗證做準備
HttpSession session = request.getSession();
session.setAttribute("verifiCode", verifiCode);
try {
// 將驗證碼圖片響應給瀏覽器
ServletOutputStream outputStream = response.getOutputStream();
// 將verifiCodeImage以JPEG的格式寫到outputStream流中
ImageIO.write(verifiCodeImage,"JPEG",outputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
}
3.3 登錄校驗功能實現
在 service 及其實現類添加登錄驗證方法
AdminService
public interface AdminService extends IService<Admin> {
/**
* 登錄校驗,查詢提交的表單是否有此人
* @param loginForm 登錄頁提交的表單
* @return
*/
Admin login(LoginForm loginForm);
}
AdminServiceImpl
@Service("adminServiceImpl")
@Transactional
public class AdminServiceImpl extends ServiceImpl<AdminMapper, Admin> implements AdminService {
/**
* 登錄驗證,查詢提交的表單是否有此人
* @param loginForm 登錄頁提交的表單
* @return
*/
@Override
public Admin login(LoginForm loginForm) {
QueryWrapper<Admin> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("name",loginForm.getUsername())
// 注意將密碼轉爲密文
.eq("password", MD5.encrypt(loginForm.getPassword()));
Admin admin = baseMapper.selectOne(queryWrapper);
return admin;
}
}
StudentService
public interface StudentService extends IService<Student> {
/**
* 登錄校驗,查詢提交的表單是否有此人
* @param loginForm 登錄頁提交的表單
* @return
*/
Student login(LoginForm loginForm);
}
StudentServiceImpl
@Service("stuService")
@Transactional
public class StudentServiceImpl extends ServiceImpl<StudentMapper, Student> implements StudentService {
/**
* 登錄校驗,查詢提交的表單是否有此人
* @param loginForm 登錄頁提交的表單
* @return
*/
@Override
public Student login(LoginForm loginForm) {
QueryWrapper<Student> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("name", loginForm.getUsername())
// 注意將密碼轉爲密文
.eq("password", MD5.encrypt(loginForm.getPassword()));
Student student = baseMapper.selectOne(queryWrapper);
return student;
}
}
TeacherService
public interface TeacherService extends IService<Teacher> {
/**
* 登錄校驗,查詢提交的表單是否有此人
* @param loginForm 登錄頁提交的表單
* @return
*/
Teacher login(LoginForm loginForm);
}
TeacherServiceImpl
@Service("teaService")
@Transactional
public class TeacherServiceImpl extends ServiceImpl<TeacherMapper, Teacher> implements TeacherService {
/**
* 登錄校驗,查詢提交的表單是否有此人
* @param loginForm 登錄頁提交的表單
* @return
*/
@Override
public Teacher login(LoginForm loginForm) {
QueryWrapper<Teacher> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("name", loginForm.getUsername())
// 注意將密碼轉爲密文
.eq("password", MD5.encrypt(loginForm.getPassword()));
Teacher teacher = baseMapper.selectOne(queryWrapper);
return teacher;
}
}
controller 中的方法
@RestController
@RequestMapping("/sms/system")
public class SystemController {
@Autowired
private AdminService adminService;
@Autowired
private StudentService studentService;
@Autowired
private TeacherService teacherService;
/**
* 驗證碼功能的實現
*
* @param request
* @param response
*/
@GetMapping("/getVerifiCodeImage")
public void getVerifiCodeImage(HttpServletRequest request, HttpServletResponse response) {
// 獲取圖片
BufferedImage verifiCodeImage = CreateVerifiCodeImage.getVerifiCodeImage();
// 獲取圖片上的驗證碼
char[] verifiCodeChars = CreateVerifiCodeImage.getVerifiCode();
String verifiCode = new String(verifiCodeChars);
// 將驗證碼文本放入session域,爲下一次驗證做準備
HttpSession session = request.getSession();
session.setAttribute("verifiCode", verifiCode);
try {
// 將驗證碼圖片響應給瀏覽器
ServletOutputStream outputStream = response.getOutputStream();
// 將verifiCodeImage以JPEG的格式寫到outputStream流中
ImageIO.write(verifiCodeImage, "JPEG", outputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 登錄驗證,查詢提交的表單是否有效
* @param loginForm 登錄頁提交的表單
* @param request
* @return
*/
@PostMapping("/login")
public Result login(@RequestBody LoginForm loginForm, HttpServletRequest request) {
// 驗證碼校驗
HttpSession session = request.getSession();
String sessionVerifiCode = (String) session.getAttribute("verifiCode");
String loginVerifiCode = loginForm.getVerifiCode();
if ("".equals(sessionVerifiCode) || null == sessionVerifiCode) {
return Result.fail().message("驗證碼失效,請刷新後重試");
}
if (!sessionVerifiCode.equalsIgnoreCase(loginVerifiCode)) {
return Result.fail().message("驗證碼錯誤");
}
// 從session中移除現有驗證碼記錄
session.removeAttribute("verifiCode");
// 對用戶類型進行校驗
Map<String, Object> map = new LinkedHashMap<>(); // 用於存放響應的數據
switch (loginForm.getUserType()) {
case 1:
try {
Admin admin = adminService.login(loginForm);
if (null != admin) {
// 在數據庫找到該用戶,將用戶類型和用戶id轉換爲密文,以token向客戶端返回信息
map.put("token", JwtHelper.createToken(admin.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 {
Student student = studentService.login(loginForm);
if (null != student) {
// 在數據庫找到該用戶,將用戶類型和用戶id轉換爲密文,以token向客戶端返回信息
map.put("token", JwtHelper.createToken(student.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 {
Teacher teacher = teacherService.login(loginForm);
if (null != teacher) {
// 在數據庫找到該用戶,將用戶類型和用戶id轉換爲密文,以token向客戶端返回信息
map.put("token", JwtHelper.createToken(teacher.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("查無此用戶");
}
}
3.4 登錄校驗後從登錄頁跳轉到首頁
當驗證通過後,前端會產生第二個請求,用以獲取用戶的類型,然後根據用戶的類型來展現不同的頁面,所以後端要有一個根據token解析用戶類型並做出結果響應的控制層
完成 service 方法及其實現類
AdminService
/**
* 根據用戶id查找用戶
* @param userId
* @return
*/
Admin getAdminById(Long userId);
AdminServiceImpl
/**
* 根據用戶id查找用戶
* @param userId
* @return
*/
@Override
public Admin getAdminById(Long userId) {
Admin admin = baseMapper.selectById(userId);
return admin;
}
StudentService
/**
* 根據用戶id查找用戶
* @param userId
* @return
*/
Student getStdentById(Long userId);
StudentServiceImpl
/**
* 根據用戶id查找用戶
* @param userId
* @return
*/
@Override
public Student getStdentById(Long userId) {
Student student = baseMapper.selectById(userId);
return student;
}
TeacherService
/**
* 根據用戶id查找用戶
* @param userId
* @return
*/
Teacher getTeacherById(Long userId);
TeacherServiceImpl
/**
* 根據用戶id查找用戶
* @param userId
* @return
*/
@Override
public Teacher getTeacherById(Long userId) {
Teacher teacher = baseMapper.selectById(userId);
return teacher;
}
完成 controller 方法
@Api(tags = "系統控制器")
@RestController
@RequestMapping("/sms/system")
public class SystemController {
@Autowired
private AdminService adService;
@Autowired
private StudentService studentService;
@Autowired
private TeacherService teacherService;
@ApiOperation("通過token獲取用戶信息")
@GetMapping("/getInfo")
public Result getUserInfoByToken(HttpServletRequest request, @RequestHeader("token")String token){
// 獲取用戶中請求的token
// 檢查token 是否過期 20H
boolean isEx = JwtHelper.isExpiration(token);
if (isEx) {
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 = adService.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",1);
break;
case 3:
Teacher teacher = teacherService.getTeacherById(userId.intValue());
map.put("user",teacher);
map.put("userType",1);
break;
}
return Result.ok(map);
}
}
四 、年級管理功能實現
4.1 查詢年級信息(分頁帶條件)
Controller層代碼
@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);
}
}
Service層代碼
@Service
@Transactional
public class GradeServiceImpl extends ServiceImpl<GradeMapper, Grade> implements GradeService {
@Override
public IPage<Grade> getGradeByOpr(Page<Grade> pageParam, String gradeName) {
// 設置查詢條件
QueryWrapper queryWrapper = new QueryWrapper();
// 判斷gradeName是否非空
if(!StringUtils.isEmpty(gradeName)){
queryWrapper.like("name",gradeName);
}
// 設置排序規則
queryWrapper.orderByDesc("id");
queryWrapper.orderByAsc("name");
// 分頁查詢數據
Page page = baseMapper.selectPage(pageParam, queryWrapper);
return page;
}
}
持久層代碼
// MyBatisPlus 的BaseMapper已經封裝好分頁帶條件查詢方法
<E extends IPage<T>> E selectPage(E page, @Param("ew") Wrapper<T> queryWrapper);
4.2 添加和修改年級信息
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();
}
}
service層代碼
由於 mybatisplus 提供的 IService 有 saveOrUpdate 方法,所以不用寫 service 層的方法
mybatisplus 似乎入侵到了 控制層和服務層???
// MyBatisPlus源碼可見
public boolean saveOrUpdate(T entity) {
if (null == entity) {
return false;
} else {
Class<?> cls = entity.getClass();
TableInfo tableInfo = TableInfoHelper.getTableInfo(cls);
Assert.notNull(tableInfo, "error: can not execute. because can not find cache of TableInfo for entity!", new Object[0]);
String keyProperty = tableInfo.getKeyProperty();
Assert.notEmpty(keyProperty, "error: can not execute. because can not find column for id from entity!", new Object[0]);
Object idVal = ReflectionKit.getMethodValue(cls, entity, tableInfo.getKeyProperty());
return !StringUtils.checkValNull(idVal) && !Objects.isNull(this.getById((Serializable)idVal)) ? this.updateById(entity) : this.save(entity);
}
}
持久層代碼
略
4.3 刪除和批量刪除年級信息
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();
}
}
由於 mybatisplus 提供的 IService 有 removeByIds 方法,所以不用寫 service 層的方法
五 、班級管理功能實現
5.1 回顯搜索條件中的班級選項
Controller層代碼
@Api(tags = "班級控制器")
@RestController
@RequestMapping("/sms/clazzController")
public class ClazzController {
@Autowired
private ClazzService clazzService;
@ApiOperation("獲取所有班級的JSON")
@GetMapping("/getClazzs")
public Result getClazzs(){
List<Clazz> clazzList = clazzService.getClazzs();
return Result.ok(clazzList);
}
}
service層代碼
@Override
public List<Clazz> getClazzs() {
return baseMapper.selectList(null);
}
5.2 查詢班級信息(分頁帶條件)
請求路徑爲:/sms/clazzController/getClazzsByOpr/{pageNo}/{pageSize}?gradeName=xxx&name=xxx
Controller層代碼
@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層代碼
@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 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.orderByDesc("id");
queryWrapper.orderByAsc("name");
}
Page page = baseMapper.selectPage(pageParam, queryWrapper);
return page;
}
}
5.3 添加和修改班級信息
Controller層代碼
@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();
}
}
service層代碼
由於 mybatisplus 提供的 IService 有 saveOrUpdate 方法,所以不用寫 service 層的方法
5.4 刪除和批量刪除班級信息
Controller層代碼
@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();
}
}
由於 mybatisplus 提供的 IService 有 removeByIds 方法,所以不用寫 service 層的方法
六、學生管理功能實現
6.1 回顯搜索條件中的班級選項
Controller層代碼
@Api(tags = "班級控制器")
@RestController
@RequestMapping("/sms/clazzController")
public class ClazzController {
@Autowired
private ClazzService clazzService;
@ApiOperation("獲取所有班級的JSON")
@GetMapping("/getClazzs")
public Result getClazzs(){
List<Clazz> clazzList = clazzService.getClazzs();
return Result.ok(clazzList);
}
}
6.2 查詢學生信息(分頁帶條件)
Controller層代碼
@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層代碼
@Service("stuService")
@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.orderByDesc("id");
queryWrapper.orderByAsc("name");
}
//創建分頁對象
IPage<Student> pages = baseMapper.selectPage(pageParam, queryWrapper);
return pages;
}
6.3 異步圖片上傳處理頭像
@Api(tags = "系統控制器")
@RestController
@RequestMapping("/sms/system")
public class SystemController {
@ApiOperation("頭像上傳統一入口")
@P("/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 ="c:/code/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);
}
}
6.4 添加和修改學生信息
Controller層代碼
@Api(tags = "學生控制器")
@RestController
@RequestMapping("/sms/studentController")
public class StudentController {
@Autowired
private StudentService studentService;
@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();
}
}
6.5 刪除和批量刪除學生信息
Controller層代碼
@Api(tags = "學生控制器")
@RestController
@RequestMapping("/sms/studentController")
public class StudentController {
@Autowired
private StudentService studentService;
@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();
}
}
七、教師管理功能實現
7.1 查詢教師信息(分頁帶條件)
Controller層代碼
@Api(tags = "教師信息管理控制器")
@RestController
@RequestMapping("/sms/teacherController")
public class TeacherController {
@Autowired
private TeacherService teacherService;
@ApiOperation("獲取教師信息,分頁帶條件")
@GetMapping("/getTeachers/{pageNo}/{pageSize}")
public Result getTeachers(
@PathVariable("pageNo") Integer pageNo,
@PathVariable("pageSize") Integer pageSize,
Teacher teacher
){
Page<Teacher> pageParam = new Page<>(pageNo,pageSize);
IPage<Teacher> page = teacherService.getTeachersByOpr(pageParam, teacher);
return Result.ok(page);
}
}
service層代碼
@Override
public IPage<Teacher> getTeachersByOpr(Page<Teacher> pageParam, Teacher teacher) {
QueryWrapper queryWrapper = new QueryWrapper();
if(teacher != null){
//班級名稱條件
String clazzName = teacher.getClazzName();
if (!StringUtils.isEmpty(clazzName)) {
queryWrapper.eq("clazz_name",clazzName);
}
//教師名稱條件
String teacherName = teacher.getName();
if(!StringUtils.isEmpty(teacherName)){
queryWrapper.like("name",teacherName);
}
queryWrapper.orderByDesc("id");
queryWrapper.orderByAsc("name");
}
IPage<Teacher> page = baseMapper.selectPage(pageParam, queryWrapper);
return page;
}
7.2 添加和修改教師信息
Controller層代碼
@ApiOperation("添加和修改教師信息")
@PostMapping("/saveOrUpdateTeacher")
public Result saveOrUpdateTeacher(
@RequestBody Teacher teacher
){
teacherService.saveOrUpdate(teacher);
return Result.ok();
}
7.3 刪除和批量刪除教師信息
Controller層代碼
@ApiOperation("刪除一個或者多個教師信息")
@DeleteMapping("/deleteTeacher")
public Result deleteTeacher(
@RequestBody List<Integer> ids
){
teacherService.removeByIds(ids);
return Result.ok();
}
八 、管理員管理功能實現
8.1 查詢管理員信息(分頁帶條件)
Request URL: /sms/adminController/getAllAdmin/{pageNo}/{pageSize}?adminName=%E4%B8%89
Request Method: GET
Controller層代碼
@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層代碼
@Override
public IPage<Admin> getAdmins(Page<Admin> pageParam,String adminName) {
QueryWrapper queryWrapper = new QueryWrapper();
if(!StringUtils.isEmpty(adminName)){
queryWrapper.like("name",adminName);
}
queryWrapper.orderByDesc("id");
queryWrapper.orderByAsc("name");
Page page = baseMapper.selectPage(pageParam, queryWrapper);
return page;
}
8.2 添加和修改管理員信息
Controller層代碼
@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();
}
8.3 刪除和批量刪除管理員信息
Request URL: /sms/adminController/deleteAdmin
Request Method: DELETE
Controller層代碼
@ApiOperation("刪除Admin信息")
@DeleteMapping("/deleteAdmin")
public Result deleteAdmin(@RequestBody List<Integer> ids){
adService.removeByIds(ids);
return Result.ok();
}
8.4 管理員修改自己的密碼
Request URL: sms/system/updatePwd/{oldPwd}/{newPwd}
Request Method: POST
Controller層代碼
@Api(tags = "系統控制器")
@RestController
@RequestMapping("/sms/system")
public class SystemController {
@ApiOperation("修改密碼")
@PostMapping("/updatePwd/{oldPwd}/{newPwd}")
public Result updatePwd(@RequestHeader("token") String token,
@PathVariable("oldPwd") String oldPwd,
@PathVariable("newPwd") String newPwd){
boolean yOn = JwtHelper.isExpiration(token);
if(yOn){
//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 = adService.getOne(queryWrapper);
if (null!=admin) {
admin.setPassword(newPwd);
adService.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();
}
}