初衷:
一直不太理解整個(gè)前后端的鑒權(quán),跨域等問(wèn)題,抽空兩個(gè)晚上整理出萬(wàn)字文章,也是對(duì)于自己的一個(gè)交代,現(xiàn)在共享出來(lái),希望大家也能受益,將使用過(guò)程在這里一一詳述,還是多說(shuō)一句,本來(lái)是不做限制的,但是為了讓更多的朋友看見(jiàn),有違初心,在這里向大家道歉,希望理解,設(shè)置為粉絲可見(jiàn)!我不會(huì)打擾大家的生活,如果大家需要任何幫助,私信我,我一定全力以赴,我們一起努力,一起為了夢(mèng)想加油?。?!
注意:如果代碼有報(bào)錯(cuò)或者疑問(wèn),請(qǐng)看源碼
源碼地址(免費(fèi))
1.創(chuàng)建后端項(xiàng)目
項(xiàng)目初始化
為了方便快捷開發(fā),我們直接使用Spring Initializr快速創(chuàng)建項(xiàng)目,注意一下,Java版本,軟件包名稱啥的,咋們一次性寫好,雖然后面可以改正,但是沒(méi)必要吃回頭草,咋們盡量做到一鏡到底!
解釋:Spring Initializr是一個(gè)用于創(chuàng)建Spring Boot項(xiàng)目的在線工具。在創(chuàng)建項(xiàng)目時(shí),您可以選擇所需的依賴項(xiàng)和配置選項(xiàng)。
如果您想在Spring Initializr中添加Web依賴項(xiàng),可以在"Dependencies"選項(xiàng)卡下找到"Web"子選項(xiàng)卡。在該子選項(xiàng)卡下,您可以勾選所需的Web依賴項(xiàng),例如Spring Web、Spring MVC等。
勾選所需的Web依賴項(xiàng)后,Spring Initializr會(huì)自動(dòng)為您生成一個(gè)包含這些依賴項(xiàng)的Maven POM文件。您可以使用該文件來(lái)構(gòu)建您的Spring Boot項(xiàng)目。
注意哈,有的同學(xué)這里可能是默認(rèn)的服務(wù)器URL,這樣有一個(gè)問(wèn)題,國(guó)外的服務(wù)器地址,有時(shí)候加載難免超時(shí),速度不夠,給力,大家可以換成國(guó)內(nèi)的阿里地址
接下來(lái),我們把相關(guān)的包直接引入,在這里的操作,相當(dāng)于在pom文件中添加依賴
我們主要添加如下幾個(gè):
Developer Tools -> Lombok
Lombok是一個(gè)Java編程框架,它可以簡(jiǎn)化Java代碼的編寫,提高開發(fā)效率。它的主要作用是減少Java代碼中的樣板代碼(boilerplate code),即重復(fù)性、冗長(zhǎng)的代碼,使開發(fā)人員能夠更加專注于業(yè)務(wù)邏輯的實(shí)現(xiàn)。
Lombok提供了一些注解和庫(kù),可以幫助開發(fā)人員快速地生成getter、setter、構(gòu)造函數(shù)、equals、hashCode等常用方法,從而減少代碼量。此外,Lombok還提供了一些工具類,如@Data、@ToString、@AllArgsConstructor等,可以幫助開發(fā)人員更好地管理Java對(duì)象的屬性和狀態(tài)。
使用Lombok需要在項(xiàng)目中引入相應(yīng)的依賴包,然后在Java代碼中使用相應(yīng)的注解或庫(kù)即可。Lombok的使用可以提高代碼的可讀性和可維護(hù)性,減少開發(fā)人員的學(xué)習(xí)成本和工作量。
下面是一個(gè)使用Lombok的例子:
import lombok.Data; // 自動(dòng)生成getter/setter方法 import lombok.NoArgsConstructor; // 自動(dòng)生成無(wú)參構(gòu)造方法 @Data public class User { private int id; private String name; public User(int id, String name) { this.id = id; this.name = name; } }
在這個(gè)例子中,我們使用了Lombok的@Data注解來(lái)自動(dòng)生成getter和setter方法,以及@NoArgsConstructor注解來(lái)自動(dòng)生成無(wú)參構(gòu)造方法。這樣,我們就可以省去手動(dòng)編寫getter和setter方法以及構(gòu)造方法的過(guò)程,從而減少了代碼量和開發(fā)時(shí)間。
Web ->Spring Web
其實(shí)就是pom里面那些web依賴庫(kù)
sql -> sql driver,mybatis
這里就是默認(rèn)添加一下MySQL驅(qū)動(dòng)和mybatis依賴,用作數(shù)據(jù)查詢
這樣,一個(gè)簡(jiǎn)單的項(xiàng)目我們就完美構(gòu)建出來(lái)了,接下來(lái),配置文件分為三種,做一個(gè)介紹:
Spring Boot的配置文件有三種格式:properties、yml和yaml,它們的區(qū)別如下:
- 語(yǔ)法不同:properties文件使用鍵值對(duì)的方式來(lái)配置,每個(gè)屬性以“=”結(jié)尾;yml文件使用縮進(jìn)來(lái)表示層級(jí)關(guān)系,屬性之間用冒號(hào)分隔;yaml文件也是使用縮進(jìn)來(lái)表示層級(jí)關(guān)系,但不同之處在于屬性值可以包含引號(hào)和換行符。
- 讀寫方式不同:properties文件可以直接讀取,也可以使用Java代碼來(lái)讀??;yml文件需要使用特定的庫(kù)(如YAML庫(kù))來(lái)解析;yaml文件也需要使用特定的庫(kù)(如PyYAML庫(kù))來(lái)解析。
- 功能特性不同:在Spring Boot中,properties文件已經(jīng)被標(biāo)記為過(guò)時(shí),建議使用yml或yaml文件來(lái)進(jìn)行配置;yml文件支持更多的數(shù)據(jù)類型,比如數(shù)組、映射等;yaml文件還支持注釋,可以在注釋中說(shuō)明配置的意義。
總之,選擇哪種配置文件格式取決于個(gè)人喜好和項(xiàng)目需求。如果只是簡(jiǎn)單的配置,可以使用properties文件;如果需要更復(fù)雜的配置結(jié)構(gòu),可以使用yml或yaml文件。
然后大家看一下自動(dòng)導(dǎo)入的依賴(大概瞅一眼)
<?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>
<groupId>com.xiaohui</groupId>
<artifactId>xiaohui-student-system</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>xiaohui-student-system</name>
<description>xiaohui-student-system</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.6.13</spring-boot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<configuration>
<mainClass>com.xiaohui.system.XiaohuiStudentSystemApplication</mainClass>
<skip>true</skip>
</configuration>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Springboot配置文件修改
在這里,不修改也能用,但是為了后期愉快的開發(fā),比如MySQL日志輸出啥的,我們配置一下,避免出問(wèn)題
server:
port: 8080 #端口
spring:
datasource:
#數(shù)據(jù)庫(kù)配置
url: jdbc:mysql://localhost:3306/students?allowMultiQueries=true&useSSL=false&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true
username: root #用戶名
password: root #密碼
driver-class-name: com.mysql.cj.jdbc.Driver #驅(qū)動(dòng)
type: com.zaxxer.hikari.HikariDataSource
hikari:
minimum-idle: 0
maximum-pool-size: 20
idle-timeout: 10000
auto-commit: true
connection-test-query: select 1
# 顯示SQL語(yǔ)句
mybatis:
mapper-locations: classpath:mappers/*xml #注意,創(chuàng)建mapper.xml的時(shí)候,需要遵循這個(gè)規(guī)則,再resource下面建立mappers
type-aliases-package: com.xiaohui.system.entity #注意自己的實(shí)體類位置
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #sql日志輸出
運(yùn)行項(xiàng)目
可見(jiàn)項(xiàng)目成功運(yùn)行了
2.創(chuàng)建前端項(xiàng)目
項(xiàng)目初始化
在這里,node的安裝教程我就不再分享,網(wǎng)絡(luò)上有許多小伙伴的文章很棒噠,找一個(gè)安裝就可以,這里就直接演示如何創(chuàng)建vue項(xiàng)目
- 打開后端項(xiàng)目所在目錄
- 使用cmd窗口打開
3.執(zhí)行命令進(jìn)行創(chuàng)建項(xiàng)目
vue create xiaohui-student-system-ui
這里大家就先選vue2的版本,vue3的版本自己可以嘗試,由于自身能力欠缺,考慮到需要兼容elemui組件,暫不使用
完成后大家使用vscode或者webstorm打開,我這里使用webstorm進(jìn)行展示
配置文件修改
這里,項(xiàng)目其實(shí)可以直接啟動(dòng)的,但是我們先不啟動(dòng),先把語(yǔ)法嚴(yán)格檢查關(guān)掉,不然一個(gè)逗號(hào)就可能報(bào)錯(cuò)
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
lintOnSave:false, //關(guān)閉eslint檢查
devServer: {
client: {
overlay: {
warnings: false, //不顯示警告
errors: false //不顯示錯(cuò)誤
}
}
}
})
運(yùn)行項(xiàng)目
1.第一種:終端命令運(yùn)行
2.第二種:配置webstorm啟動(dòng)器
這樣,我們前后端項(xiàng)目都就創(chuàng)建好了,接下來(lái)我們就仔細(xì)編寫一下后端的數(shù)據(jù)查詢代碼
3.創(chuàng)建數(shù)據(jù)表
大家可以自行創(chuàng)建,這里作為演示,就先創(chuàng)建一個(gè)用戶信息表,大家理解!
CREATE TABLE `user_table` (
`user_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用戶ID',
`user_name` varchar(255) DEFAULT NULL COMMENT '用戶姓名',
`user_pwd` varchar(255) DEFAULT NULL COMMENT '用戶密碼',
`user_status` varchar(255) DEFAULT NULL COMMENT '用戶狀態(tài)',
`user_role` varchar(255) DEFAULT NULL COMMENT '用戶權(quán)限',
`create_time` datetime DEFAULT NULL COMMENT '創(chuàng)建時(shí)間',
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
4.業(yè)務(wù)層次劃分
在這里,再多說(shuō)幾句
在 MyBatis 中,通常會(huì)將實(shí)體類、DAO 接口和對(duì)應(yīng)的值對(duì)象(VO)分開定義,以實(shí)現(xiàn)更好的代碼復(fù)用和可維護(hù)性。下面分別介紹它們的用途和區(qū)別:
- 實(shí)體類(Entity)
實(shí)體類用于表示數(shù)據(jù)庫(kù)中的表與字段的映射關(guān)系,通常包含屬性和 getter/setter 方法。它的主要作用是作為數(shù)據(jù)傳輸?shù)膶?duì)象,將數(shù)據(jù)庫(kù)中的數(shù)據(jù)映射到 Java 對(duì)象中。
實(shí)體類的屬性通常是直接從數(shù)據(jù)庫(kù)表中獲取的,因此它的屬性名和類型應(yīng)該與數(shù)據(jù)庫(kù)表中的列名和數(shù)據(jù)類型一一對(duì)應(yīng)。同時(shí),實(shí)體類也可以添加一些額外的屬性和方法,例如計(jì)算屬性、校驗(yàn)屬性等。
- DAO 接口(Dao)
DAO 接口用于定義對(duì)數(shù)據(jù)庫(kù)的操作方法,包括增刪改查等基本操作,通常需要傳入實(shí)體類作為參數(shù),并返回對(duì)應(yīng)的結(jié)果對(duì)象。它的主要作用是提供一個(gè)標(biāo)準(zhǔn)的接口,供業(yè)務(wù)層調(diào)用。
DAO 接口中的每個(gè)方法都對(duì)應(yīng)著一個(gè)具體的 SQL 語(yǔ)句,MyBatis 會(huì)根據(jù)該方法的名稱和參數(shù)自動(dòng)生成對(duì)應(yīng)的 SQL 語(yǔ)句。因此,使用 DAO 接口可以避免手寫 SQL 語(yǔ)句的繁瑣和錯(cuò)誤。
- VO(Value Object)
VO 用于封裝一些常量或輔助數(shù)據(jù),通常包含一些靜態(tài)方法和屬性。VO 可以被多個(gè) DAO 接口共享,以避免重復(fù)的代碼。它的主要作用是提供一些公共的數(shù)據(jù)結(jié)構(gòu)和方法,方便業(yè)務(wù)層進(jìn)行數(shù)據(jù)處理。
VO 通常包含以下內(nèi)容:
- 常量:用于存儲(chǔ)一些固定不變的數(shù)據(jù),例如日期、時(shí)間、枚舉值等。
- 靜態(tài)方法:用于執(zhí)行一些簡(jiǎn)單的計(jì)算或校驗(yàn)邏輯,例如字符串長(zhǎng)度、數(shù)字比較等。
- 實(shí)例方法:用于返回一些查詢結(jié)果或緩存數(shù)據(jù),例如將查詢結(jié)果封裝成一個(gè)對(duì)象返回給客戶端。
總之,實(shí)體類用于映射數(shù)據(jù)庫(kù)表,DAO 接口用于定義對(duì)數(shù)據(jù)庫(kù)的操作方法,VO 則用于提供一些公共的數(shù)據(jù)結(jié)構(gòu)和方法。它們?nèi)咧g相互獨(dú)立,但又密切相關(guān),共同構(gòu)成了 MyBatis 的基本架構(gòu)。
對(duì)于每個(gè)層做一個(gè)贅述
- DAO(Data Access Object):數(shù)據(jù)訪問(wèn)對(duì)象,用于與數(shù)據(jù)庫(kù)進(jìn)行交互操作,提供對(duì)數(shù)據(jù)的增刪改查等操作。
- Entity:實(shí)體類,用于描述數(shù)據(jù)表中的每一行記錄,包含屬性和getter/setter方法。
- Mapper.xml:MyBatis中的映射文件,用于將SQL語(yǔ)句映射到Java接口中的方法上,實(shí)現(xiàn)對(duì)數(shù)據(jù)庫(kù)的操作。
- Mapper:Mapper接口,定義了與數(shù)據(jù)庫(kù)進(jìn)行交互的方法,通過(guò)注解或XML配置文件來(lái)實(shí)現(xiàn)。
- Service:服務(wù)層,用于處理業(yè)務(wù)邏輯,包括對(duì)DAO的操作、事務(wù)管理等。
- ServiceImpl:服務(wù)實(shí)現(xiàn)類,實(shí)現(xiàn)了Service接口中的方法,通常會(huì)使用@Autowired注解來(lái)自動(dòng)注入DAO對(duì)象。
- Controller:控制器,用于接收前端請(qǐng)求并將其轉(zhuǎn)發(fā)給Service層進(jìn)行處理,同時(shí)返回結(jié)果給前端。
它們之間的關(guān)系如下:
- DAO與Entity和Mapper的關(guān)系:DAO通過(guò)Entity和Mapper來(lái)訪問(wèn)數(shù)據(jù)庫(kù),實(shí)現(xiàn)數(shù)據(jù)的增刪改查等操作。
- Service與ServiceImpl和Mapper的關(guān)系:Service層通過(guò)ServiceImpl來(lái)實(shí)現(xiàn)具體的方法,調(diào)用Mapper進(jìn)行數(shù)據(jù)庫(kù)操作。
- Controller與Service和ServiceImpl的關(guān)系:Controller層通過(guò)Service層來(lái)處理業(yè)務(wù)邏輯和事務(wù)控制,調(diào)用ServiceImpl中的相關(guān)方法來(lái)實(shí)現(xiàn)具體的業(yè)務(wù)邏輯。
創(chuàng)建entity層的實(shí)體類
package com.xiaohui.system.entity;
import lombok.Data;
/**
* @Description 用戶信息實(shí)體類
* @Author IT小輝同學(xué)
* @Date 2023/05/17
*/
@Data
public class User {
/**
* 用戶id
*/
private Long userId;
/**
* 用戶名
*/
private String userName;
/**
* 用戶密碼
*/
private String userPwd;
/**
* 用戶狀態(tài)
*/
private String userStatus;
/**
* 用戶角色
*/
private String userRole;
/**
* 創(chuàng)建時(shí)間
*/
private Date createTime;
}
創(chuàng)建mapper.xml映射
在這個(gè)里面,我們寫了一條查詢sql
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xiaohui.system.mapper.UserMapper">
<resultMap id="UserResultVO" type="com.xiaohui.system.entity.User">
<result property="userId" column="user_id"/>
<result property="userName" column="user_name"/>
<result property="userPwd" column="user_pwd"/>
<result property="userStatus" column="user_status"/>
<result property="userRole" column="user_role"/>
</resultMap>
<!--獲取所有用戶信息-->
<select id="selectAllUserInfo" resultMap="UserResultVO" parameterType="com.xiaohui.system.entity.User">
SELECT *
FROM user_table
</select>
</mapper>
創(chuàng)建mapper接口
注意啊,不要少了注釋,這個(gè)很重要
package com.xiaohui.system.mapper;
import com.xiaohui.system.entity.User;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* @Description 用戶映射器
* @Author IT小輝同學(xué)
* @Date 2023/05/17
*/
@Mapper
public interface UserMapper {
/**
* @Param user 用戶
* @Return {@link List }<{@link User }>
* @Description 獲取所有用戶信息
* @Author IT小輝同學(xué)
* @Date 2023/05/17
*/
List<User> selectAllUserInfo(User user);
}
創(chuàng)建service服務(wù)層
package com.xiaohui.system.service;
import com.xiaohui.system.entity.User;
import java.util.List;
public interface UserService {
/**
* @param user 用戶
* @return {@link List }<{@link User }>
* @Description 獲取所有用戶信息
* @Author IT小輝同學(xué)
* @Date 2023/05/17
*/
List<User> selectAllUserInfo(User user);
}
創(chuàng)建serviceImpl服務(wù)實(shí)現(xiàn)類
package com.xiaohui.system.service.Impl;
import com.xiaohui.system.entity.User;
import com.xiaohui.system.mapper.UserMapper;
import com.xiaohui.system.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @Description 用戶服務(wù)實(shí)現(xiàn)類
* @Author IT小輝同學(xué)
* @Date 2023/05/17
*/
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
/**
* @param user 用戶
* @return {@link List }<{@link User }>
* @Description 獲取所有用戶信息
* @Author IT小輝同學(xué)
* @Date 2023/05/17
*/
@Override
public List<User> selectAllUserInfo(User user) {
return userMapper.selectAllUserInfo(user);
}
}
創(chuàng)建Controller控制器
在這里,我們對(duì)應(yīng)返回體需要處理一下,這里搬過(guò)來(lái)若依的一套封裝,很好用,大家放到Utils里面就行
package com.xiaohui.system.Utils;
/**
* @Description 返回狀態(tài)碼
* @Author IT小輝同學(xué)
* @Date 2023/05/17
*/
public class HttpStatus {
/**
* 操作成功
*/
public static final int SUCCESS = 200;
/**
* 對(duì)象創(chuàng)建成功
*/
public static final int CREATED = 201;
/**
* 請(qǐng)求已經(jīng)被接受
*/
public static final int ACCEPTED = 202;
/**
* 操作已經(jīng)執(zhí)行成功,但是沒(méi)有返回?cái)?shù)據(jù)
*/
public static final int NO_CONTENT = 204;
/**
* 資源已被移除
*/
public static final int MOVED_PERM = 301;
/**
* 重定向
*/
public static final int SEE_OTHER = 303;
/**
* 資源沒(méi)有被修改
*/
public static final int NOT_MODIFIED = 304;
/**
* 參數(shù)列表錯(cuò)誤(缺少,格式不匹配)
*/
public static final int BAD_REQUEST = 400;
/**
* 未授權(quán)
*/
public static final int UNAUTHORIZED = 401;
/**
* 訪問(wèn)受限,授權(quán)過(guò)期
*/
public static final int FORBIDDEN = 403;
/**
* 資源,服務(wù)未找到
*/
public static final int NOT_FOUND = 404;
/**
* 不允許的http方法
*/
public static final int BAD_METHOD = 405;
/**
* 資源沖突,或者資源被鎖
*/
public static final int CONFLICT = 409;
/**
* 不支持的數(shù)據(jù),媒體類型
*/
public static final int UNSUPPORTED_TYPE = 415;
/**
* 系統(tǒng)內(nèi)部錯(cuò)誤
*/
public static final int ERROR = 500;
/**
* 接口未實(shí)現(xiàn)
*/
public static final int NOT_IMPLEMENTED = 501;
/**
* 系統(tǒng)警告消息
*/
public static final int WARN = 601;
}
package com.xiaohui.system.Utils;
import java.util.HashMap;
/**
* @Description 請(qǐng)求返回體
* @Author IT小輝同學(xué)
* @Date 2023/05/17
*/
public class AjaxResult extends HashMap<String, Object>
{
private static final long serialVersionUID = 1L;
/** 狀態(tài)碼 */
public static final String CODE_TAG = "code";
/** 返回內(nèi)容 */
public static final String MSG_TAG = "msg";
/** 數(shù)據(jù)對(duì)象 */
public static final String DATA_TAG = "data";
/**
* 初始化一個(gè)新創(chuàng)建的 AjaxResult 對(duì)象,使其表示一個(gè)空消息。
*/
public AjaxResult()
{
}
/**
* 初始化一個(gè)新創(chuàng)建的 AjaxResult 對(duì)象
*
* @param code 狀態(tài)碼
* @param msg 返回內(nèi)容
*/
public AjaxResult(int code, String msg)
{
super.put(CODE_TAG, code);
super.put(MSG_TAG, msg);
}
/**
* 初始化一個(gè)新創(chuàng)建的 AjaxResult 對(duì)象
*
* @param code 狀態(tài)碼
* @param msg 返回內(nèi)容
* @param data 數(shù)據(jù)對(duì)象
*/
public AjaxResult(int code, String msg, Object data)
{
super.put(CODE_TAG, code);
super.put(MSG_TAG, msg);
if (StringUtils.isNotNull(data))
{
super.put(DATA_TAG, data);
}
}
/**
* 返回成功消息
*
* @return 成功消息
*/
public static AjaxResult success()
{
return AjaxResult.success("操作成功");
}
/**
* 返回成功數(shù)據(jù)
*
* @return 成功消息
*/
public static AjaxResult success(Object data)
{
return AjaxResult.success("操作成功", data);
}
/**
* 返回成功消息
*
* @param msg 返回內(nèi)容
* @return 成功消息
*/
public static AjaxResult success(String msg)
{
return AjaxResult.success(msg, null);
}
/**
* 返回成功消息
*
* @param msg 返回內(nèi)容
* @param data 數(shù)據(jù)對(duì)象
* @return 成功消息
*/
public static AjaxResult success(String msg, Object data)
{
return new AjaxResult(HttpStatus.SUCCESS, msg, data);
}
/**
* 返回警告消息
*
* @param msg 返回內(nèi)容
* @return 警告消息
*/
public static AjaxResult warn(String msg)
{
return AjaxResult.warn(msg, null);
}
/**
* 返回警告消息
*
* @param msg 返回內(nèi)容
* @param data 數(shù)據(jù)對(duì)象
* @return 警告消息
*/
public static AjaxResult warn(String msg, Object data)
{
return new AjaxResult(HttpStatus.WARN, msg, data);
}
/**
* 返回錯(cuò)誤消息
*
* @return 錯(cuò)誤消息
*/
public static AjaxResult error()
{
return AjaxResult.error("操作失敗");
}
/**
* 返回錯(cuò)誤消息
*
* @param msg 返回內(nèi)容
* @return 錯(cuò)誤消息
*/
public static AjaxResult error(String msg)
{
return AjaxResult.error(msg, null);
}
/**
* 返回錯(cuò)誤消息
*
* @param msg 返回內(nèi)容
* @param data 數(shù)據(jù)對(duì)象
* @return 錯(cuò)誤消息
*/
public static AjaxResult error(String msg, Object data)
{
return new AjaxResult(HttpStatus.ERROR, msg, data);
}
/**
* 返回錯(cuò)誤消息
*
* @param code 狀態(tài)碼
* @param msg 返回內(nèi)容
* @return 錯(cuò)誤消息
*/
public static AjaxResult error(int code, String msg)
{
return new AjaxResult(code, msg, null);
}
/**
* 方便鏈?zhǔn)秸{(diào)用
*
* @param key 鍵
* @param value 值
* @return 數(shù)據(jù)對(duì)象
*/
@Override
public AjaxResult put(String key, Object value)
{
super.put(key, value);
return this;
}
}
package com.xiaohui.system.controller;
import com.xiaohui.system.Utils.AjaxResult;
import com.xiaohui.system.entity.User;
import com.xiaohui.system.service.Impl.UserServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
/**
* @Description 用戶控制器
* @Author IT小輝同學(xué)
* @Date 2023/05/17
*/
@CrossOrigin
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserServiceImpl userService;
/**
* @param user 用戶
* @return {@link AjaxResult }
* @Description 獲取所有用戶信息
* @Author IT小輝同學(xué)
* @Date 2023/05/17
*/
@GetMapping("/list")
private AjaxResult selectAllUserInfo() {
User user=new User();
return AjaxResult.success(userService.selectAllUserInfo(user));
}
}
做一個(gè)小小的拓展,加深大家的印象,關(guān)于各種請(qǐng)求和接參形式再啰嗦幾句,一定要把知識(shí)盲區(qū)補(bǔ)上,不能留下漏洞,不然后面真實(shí)開發(fā)遇到問(wèn)題很麻煩!??!
Spring Boot 是一個(gè)基于 Spring 框架的開發(fā)框架,它提供了非常方便和高效的方式來(lái)創(chuàng)建和部署獨(dú)立運(yùn)行的、生產(chǎn)級(jí)別的 Web 應(yīng)用程序。在 Spring Boot 的 Controller 層中,我們可以使用如下注解來(lái)定義請(qǐng)求方法、請(qǐng)求參數(shù)等:
- @RequestMapping
@RequestMapping
注解用于映射 HTTP 請(qǐng)求 URL 到相應(yīng)的處理方法,可以定義 class 級(jí)別或 method 級(jí)別的映射。@RestController @RequestMapping("/api/user") public class UserController { // ... }
- @PostMapping, @GetMapping, @PutMapping, @DeleteMapping
這些是相應(yīng)注解的縮寫形式,用于簡(jiǎn)化
@RequestMapping
的使用方式,并且能夠根據(jù)不同的請(qǐng)求方法來(lái)限定映射范圍。@RestController @RequestMapping("/api/user") public class UserController { @PostMapping("/") public User createUser(@RequestBody User user) { // 處理新增用戶請(qǐng)求 return userService.createUser(user); } @GetMapping("/{userId}") public User getUserById(@PathVariable Long userId) { // 查詢指定 ID 的用戶 return userService.getUserById(userId); } @PutMapping("/{userId}") public User updateUser(@PathVariable Long userId, @RequestBody User newUser) { // 更新指定 ID 的用戶信息 return userService.updateUser(userId, newUser); } @DeleteMapping("/{userId}") public void deleteUser(@PathVariable Long userId) { // 刪除指定 ID 的用戶 userService.deleteUser(userId); } }
- @RequestBody
@RequestBody
注解主要用于處理請(qǐng)求體中傳遞的數(shù)據(jù),將請(qǐng)求體中的 JSON 或 XML 數(shù)據(jù)綁定到 Java 對(duì)象上。@RestController @RequestMapping("/api/user") public class UserController { @PostMapping("/") public User createUser(@RequestBody User user) { // 處理新增用戶請(qǐng)求 return userService.createUser(user); } }
- @PathVariable
@PathVariable
注解主要用于獲取 URL 中的參數(shù)值,例如:@RestController @RequestMapping("/api/user") public class UserController { @GetMapping("/{userId}") public User getUserById(@PathVariable Long userId) { // 查詢指定 ID 的用戶 return userService.getUserById(userId); } }
- @RequestParam
@RequestParam
注解主要用于獲取 URL 中的查詢參數(shù)值,例如:@RestController @RequestMapping("/api/user") public class UserController { @GetMapping("/") public List<User> listUsers( @RequestParam(value = "name", required = false) String name, @RequestParam(value = "age", required = false) Integer age) { // 查詢滿足條件的用戶列表 return userService.listUsers(name, age); } }
- @RequestHeader
@RequestHeader
注解主要用于獲取 HTTP 請(qǐng)求頭參數(shù)。例如:@RestController @RequestMapping("/api/user") public class UserController { @GetMapping("/") public List<User> listUsers( @RequestHeader(value = "User-Agent", required = false) String userAgent) { // 查詢滿足條件的用戶列表 logger.info("User-Agent: {}", userAgent); return userService.listUsers(); } }
以上是 Controller 層中常用的注解和演示代碼,這些注解都提供了非常便利的方式來(lái)接收和處理 HTTP 請(qǐng)求,并且能夠很好地與 Spring Boot 的其他功能(例如異常處理、數(shù)據(jù)校驗(yàn)等)融合使用。
這樣,我們就徹底完成了一整套的流程,先啟動(dòng)試試,看能不能跑起來(lái)
5.ApiPost測(cè)試
這里給大家一點(diǎn)小建議,接口寫好之后不要直接去套前端,有的朋友喜歡全棧開發(fā),就直接上手套,最好使用api工具進(jìn)行測(cè)試,有時(shí)候跨域亂七八糟的問(wèn)題會(huì)導(dǎo)致失敗,而我們卻不知道,這是一個(gè)小建議!在controller層中,我們就已經(jīng)使用@CrossOrigin注釋解決了跨域問(wèn)題,所以前端不需要處理?。?!
6.編寫后端登錄邏輯
后端代碼
mapper.xml
<!-- 根據(jù)用戶名和密碼進(jìn)行登錄校驗(yàn)-->
<select id="userLoginJuage" resultMap="UserResultVO" parameterType="com.xiaohui.system.entity.User" >
select *
from user_table
where user_name = #{userName}
and user_pwd = #{userPwd}
</select>
mapper
/**
* @param user 用戶
* @return {@link User }
* @Description 用戶登錄鑒權(quán)
* @Author IT小輝同學(xué)
* @Date 2023/05/17
*/
User userLoginJuage(User user);
service
/**
* @param user 用戶
* @return {@link User }
* @Description 用戶登錄鑒權(quán)
* @Author IT小輝同學(xué)
* @Date 2023/05/17
*/
User userLoginJuage(User user);
serviceImpl
/**
* @param user 用戶
* @return {@link User }
* @Description 用戶登錄鑒權(quán)
* @Author IT小輝同學(xué)
* @Date 2023/05/17
*/
@Override
public User userLoginJuage(User user) {
return userMapper.userLoginJuage(user);
}
controller
/**
* @param user 用戶
* @return {@link AjaxResult }
* @Description 用戶登錄鑒權(quán)
* @Author IT小輝同學(xué)
* @Date 2023/05/17
*/
@GetMapping("/login")
private AjaxResult userLoginJuage(@RequestBody User user) {
//獲取登錄信息
User userLoginInfo = userService.userLoginJuage(user);
//判斷用戶是否存在
if (userLoginInfo != null) {
return AjaxResult.success("登錄成功", userLoginInfo);
}
return AjaxResult.error("用戶不存在");
}
接口測(cè)試
成功示例
失敗示例
7.編寫前端登錄邏輯
前端代碼
前端我會(huì)使用到vue里面的一些組件,在這里給大家提前給出,就是簡(jiǎn)單下載配置,不費(fèi)事
安裝element-ui
npm install element-ui
安裝router
您可以使用以下命令安裝 Vue Router:
npm install vue-router -S
其中,-S
或 --save
表示將 Vue Router 作為項(xiàng)目的依賴保存在項(xiàng)目中。
安裝axios
您可以使用以下命令安裝 Axios:
npm install axios -S
其中,-S
或 --save
表示將 Axios 作為項(xiàng)目的依賴保存在項(xiàng)目中。
上面這些安裝好了,咋們就開始干活,首先在src下面新建一個(gè)文件夾,名為router,里面新建一個(gè)index.js,內(nèi)容如下
import VueRouter from "vue-router";
import loginPage from "@/view/login/loginPage.vue"
import helloWorld from "@/components/HelloWorld.vue";
export default new VueRouter({
mode: 'history',
routes: [
{
path: '/',
redirect: '/login' // 將默認(rèn)路由重定向到登錄頁(yè)
},
{
name: 'login',
path: '/login',
component: loginPage
},
{
name: 'helloWorld',
path: '/helloWorld',
component: helloWorld
},
]
})
以上代碼是一個(gè)基本的 Vue Router 配置文件,通過(guò)導(dǎo)出實(shí)例化出來(lái)的
VueRouter
對(duì)象,在應(yīng)用中啟用路由功能。以下是對(duì)每個(gè)部分的解釋:
import VueRouter from "vue-router";
:導(dǎo)入 Vue Router 模塊。import loginPage from "@/view/login/loginPage.vue"
:導(dǎo)入登錄頁(yè)組件,使用了 vue-cli 的 alias配置,這種寫法是為了方便通用路徑導(dǎo)入。(如果沒(méi)有使用別名配置,可以寫成import loginPage from "../view/login/loginPage.vue"
)export default new VueRouter({ ... })
:使用 ES6 的模塊化語(yǔ)法,導(dǎo)出實(shí)例化后的 VueRouter 對(duì)象。mode:'history'
:設(shè)置路由模式為 HTML5 history 模式,URL 中不再包含 # 號(hào)。routes:[ { ... }]
:定義路由信息,數(shù)組中每一項(xiàng)表示一個(gè)路由,包括 name、path 和 component 屬性。例如以上代碼中定義了一個(gè)路由對(duì)象,當(dāng) URL 訪問(wèn) /login 路徑時(shí),會(huì)渲染 Login 頁(yè)面組件。name:'loginPage'
:給路由規(guī)則起一個(gè)名稱,方便在程序中進(jìn)行編程式跳轉(zhuǎn)。path:'/login'
:對(duì)應(yīng)的訪問(wèn)路徑。component:loginPage
:訪問(wèn)該路由時(shí)要加載的組件。這是一個(gè)最簡(jiǎn)單的路由示例,當(dāng)然您可以根據(jù)項(xiàng)目需求配置更多路由規(guī)則。
然后我們?cè)趕rc下面的main.js文件一次性引入如下組件
import Vue from 'vue';
import App from './App.vue';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import VueRouter from 'vue-router';
import router from './router'
Vue.use(ElementUI);
Vue.use(VueRouter);
new Vue({
render: h => h(App),
router: router
}).$mount('#app')
以上代碼是一個(gè) Vue 應(yīng)用的入口文件
main.js
,其中做了以下事情:
import Vue from 'vue';
:導(dǎo)入 Vue 模塊。import App from './App.vue';
:導(dǎo)入根組件 App.vue。import ElementUI from 'element-ui';
:按需導(dǎo)入 Element UI 庫(kù)。import 'element-ui/lib/theme-chalk/index.css';
:引入 Element UI 的默認(rèn)樣式文件。import VueRouter from 'vue-router';
:導(dǎo)入 Vue Router 模塊。import router from './router'
:導(dǎo)入路由配置對(duì)象。Vue.use(ElementUI);
:全局注冊(cè) Element UI 組件。Vue.use(VueRouter);
:全局注冊(cè)路由功能。new Vue({ ... }).$mount('#app')
:創(chuàng)建一個(gè) Vue 實(shí)例并掛載到 DOM 元素上。創(chuàng)建的 Vue 實(shí)例掛載的選項(xiàng)包括以下內(nèi)容:
render: h => h(App),
:使用根組件 App.vue 渲染 Vue 應(yīng)用。router: router
:?jiǎn)⒂脤?dǎo)入的 Vue Router 配置。這里可以看到內(nèi)部啟用了傳統(tǒng)的 JavaScript 對(duì)象命名簡(jiǎn)寫方式,即router
等效于router: router
。.$mount('#app')
:將實(shí)例掛載到指定的 DOM 元素上,這里指的是 id 為 app 的 div 容器,與 HTML 頁(yè)面中定義的<div id="app"></div>
對(duì)應(yīng)。通過(guò)以上配置,我們完成了對(duì) Vue、Element UI 和 Vue Router 庫(kù)的引入,并配置了 Vue 應(yīng)用的基本結(jié)構(gòu)。
下面,需要改動(dòng)的代碼比較多,大家先就不要急著運(yùn)行代碼,跟著我稍微整理一下代碼,代碼目錄結(jié)構(gòu)如下
首先,我們需要把登錄界面的代碼完善
<template>
<div class="container">
<form class="form" @submit.prevent="login">
<div class="form-group">
<span class="label"> 賬號(hào)</span>
<el-input placeholder="請(qǐng)輸入賬號(hào)" v-model="form.userName" class="input"></el-input>
</div>
<div class="form-group">
<span class="label">密碼</span>
<el-input placeholder="請(qǐng)輸入密碼" v-model="form.userPwd" class="input" show-password></el-input>
</div>
<el-button type="primary" @click="toLogin" class="loginBt" plain>登錄</el-button>
<el-button type="danger" @click="toRestData" class="loginBt">重置</el-button>
</form>
</div>
</template>
<script>
import {userLogin} from "@/api/login/userLogin";
export default {
data() {
return {
form: {
userName: '',
userPwd: ''
},
queryParams: {
pageNum: 1,
pageSize: 10,
userName: "",
userPwd: ""
},
}
},
methods: {
toLogin() {
userLogin(this.form).then(response => {
console.log(response)
if (response.code !== 200) {
this.form = ""
this.$message.error(response.msg);
} else {
this.$message({message:response.msg , type: 'success'});
this.$router.push({path: "/helloWorld"});
}
}
);
},
toRestData() {
this.form = ""
}
}
}
</script>
<style>
.container {
background: url("@/assets/images/background.jpg") no-repeat center center fixed;
-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
background-size: cover;
display: flex;
flex-direction: column;
flex-direction: column;
justify-content: center;
align-items: center;
background-color: #f2f2f2;
padding-top: 0px;
top: 0;
position: fixed;
height: 100vh;
width: 100%;
}
.form {
/*background-color: #fff;*/
padding: 60px;
border-radius: 10px;
background-color: rgb(222 241 255 / 50%);
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
max-width: 400px;
width: 50%;
height: 28%;
margin-left: 50%;
}
.form label,
.form input[type="text"],
.form input[type="password"],
.form button[type="submit"] {
display: block;
width: 100%;
height: 45px;
box-shadow: none;
margin-bottom: 0px;
}
.form button[type="submit"] {
/*background-color: #0070f3;*/
color: #fff;
padding: 10px;
border: none;
border-radius: 5px;
cursor: pointer;
}
.form-group {
display: flex;
align-items: center; /* 讓內(nèi)容在行中垂直居中 */
margin: 20px;
}
.label {
font-size: large;
margin-right: 10px;
}
.input {
flex: 1; /* 設(shè)置flex-grow為1,讓輸入框占據(jù)多余空間 */
padding: 5px;
border-radius: 5px;
align-items: center;
}
.loginBt {
width: 80px;
height: 40px;
margin-left: 30%;
}
</style>
這里的代碼不算復(fù)雜,就是做了一個(gè)和后端的互動(dòng),看密碼是否正確,然后就只判斷,正確就跳轉(zhuǎn)歡迎頁(yè)
登錄頁(yè)api接口
import { get, post, put, del } from '@/utils/request'
//用戶登錄鑒權(quán)
export function userLogin(data) {
return post('user/login', data)
}
然后大家就會(huì)看到,這里使用了一個(gè)封裝的request工具類,這里給出
import axios from 'axios'
const service = axios.create({
baseURL: "http://localhost:8080",
timeout: 5000 // 請(qǐng)求超時(shí)時(shí)間
})
// request攔截器
service.interceptors.request.use(
config => {
// 在請(qǐng)求發(fā)送之前可以做一些處理,如請(qǐng)求頭攜帶token等
const token = window.localStorage.getItem('Authorization')
if (token) {
// 將 Authorization 請(qǐng)求頭信息組裝為 'Bearer token' 的格式
config.headers.common['Authorization'] = `Bearer ${token}`
}
return config
},
error => {
console.log(error) // for debug
Promise.reject(error)
}
)
// response攔截器
service.interceptors.response.use(
response => {
const res = response.data
return res
},
error => {
console.log('err' + error) // for debug
return Promise.reject(error)
}
)
export function get(url, params) {
return service({
url: url,
method: 'get',
params
})
}
export function post(url, data) {
return service({
url: url,
method: 'post',
data
})
}
export function put(url, data) {
return service({
url: url,
method: 'put',
data
})
}
export function del(url) {
return service({
url: url,
method: 'delete'
})
}
這段代碼是一個(gè)基于
axios
庫(kù)封裝的網(wǎng)絡(luò)請(qǐng)求工具,可以實(shí)現(xiàn)發(fā)送 GET、POST、PUT、DELETE 等常見(jiàn) HTTP 請(qǐng)求,并帶有請(qǐng)求攔截器、響應(yīng)攔截器等功能。詳細(xì)解讀如下:
首先,通過(guò)
axios.create()
創(chuàng)建了一個(gè)名為service
的 Axios 實(shí)例,并配置了一些默認(rèn)選項(xiàng),如請(qǐng)求的 baseURL 和 timeout 等。接下來(lái)定義了兩個(gè)攔截器:
-在請(qǐng)求發(fā)起之前會(huì)進(jìn)行請(qǐng)求攔截,可以進(jìn)行一些處理,如添加請(qǐng)求頭等。如果需要進(jìn)行錯(cuò)誤處理,也可以在該處拋出異常中止請(qǐng)求。
-在獲得響應(yīng)之后會(huì)進(jìn)行響應(yīng)攔截,用于統(tǒng)一處理返回?cái)?shù)據(jù)。在該攔截器中將響應(yīng)數(shù)據(jù)解構(gòu)到 res 對(duì)象中,并將其返回給請(qǐng)求處。
- 最后通過(guò)導(dǎo)出四個(gè)函數(shù):get、post、put 和 del,分別對(duì)應(yīng) GET、POST、PUT、DELETE 四種請(qǐng)求方法。這些函數(shù)通過(guò)調(diào)用
service()
方法發(fā)起請(qǐng)求,函數(shù)的參數(shù)即為 Axios 請(qǐng)求配置中的url
、method
和data/params
等選項(xiàng)。總的來(lái)說(shuō),這是一個(gè)可復(fù)用的網(wǎng)絡(luò)請(qǐng)求工具,可在 Vue、React 或 Node.js 等項(xiàng)目中使用。
歡迎首頁(yè)代碼HelloWorld.vue
<template>
<div id="home"></div>
</template>
<script>
export default {
name: 'homePage'
}
</script>
<style scoped>
#home {
width: 100%;
min-height: 100vh;
background: url("~@/assets/images/index.png") center center no-repeat;
background-size: 100% 100%;
}
</style>
主入口App.vue
<template>
<div id="home"></div>
</template>
<script>
export default {
name: 'homePage'
}
</script>
<style scoped>
#home {
width: 100%;
min-height: 100vh;
background: url("~@/assets/images/index.png") center center no-repeat;
background-size: 100% 100%;
}
</style>
運(yùn)行代碼
輸入賬戶和密碼正確后將會(huì)跳轉(zhuǎn)到helloworld
在這里,我們?cè)侔裩ttp狀態(tài)碼給大家列出來(lái),大家注意,遇到問(wèn)題及時(shí)速查
HTTP 狀態(tài)碼用于指示客戶端向服務(wù)器提交的 HTTP 請(qǐng)求是否成功。常見(jiàn)的狀態(tài)碼包括以下 5 類:
1xx:信息性狀態(tài)碼,表示服務(wù)器已接受請(qǐng)求,正在等待更多數(shù)據(jù)。
2xx:成功狀態(tài)碼,表示服務(wù)器已成功處理請(qǐng)求并發(fā)送響應(yīng)。
3xx:重定向狀態(tài)碼,表示需要客戶端進(jìn)一步操作才能完成請(qǐng)求。
4xx:客戶端錯(cuò)誤狀態(tài)碼,表示請(qǐng)求有錯(cuò)誤或者不可用。
5xx:服務(wù)器錯(cuò)誤狀態(tài)碼,表示服務(wù)器處理請(qǐng)求時(shí)發(fā)生錯(cuò)誤。
以下是經(jīng)常遇到的幾種 HTTP 狀態(tài)碼及其解決方法:
200 OK:請(qǐng)求成功,服務(wù)器正常返回?cái)?shù)據(jù)。
201 Created:請(qǐng)求成功,并創(chuàng)建了新資源。
204 No Content:請(qǐng)求成功,但無(wú)響應(yīng)內(nèi)容。
400 Bad Request:客戶端發(fā)送的請(qǐng)求有異常,如參數(shù)格式錯(cuò)誤、無(wú)權(quán)限訪問(wèn)等。解決方法:檢查請(qǐng)求參數(shù)是否正確。
401 Unauthorized:未授權(quán)或登錄失效。解決方法:用戶重新登錄或確認(rèn) token 是否過(guò)期。
403 Forbidden:禁止訪問(wèn)。解決方法:檢查用戶的權(quán)限是否滿足訪問(wèn) API 的要求。
404 Not Found:資源未找到。解決方法:檢查請(qǐng)求路徑是否正確。
405 Method Not Allowed:請(qǐng)求方式不支持。解決方法:檢查請(qǐng)求方式是否與 API 兼容。
500 Internal Server Error:服務(wù)器內(nèi)部出錯(cuò)。解決方法:查看服務(wù)器日志或聯(lián)系管理員。
503 Service Unavailable:服務(wù)不可用。解決方法:檢查服務(wù)是否正常啟動(dòng),或者與虛擬化環(huán)境相關(guān)的負(fù)載是否太高。
對(duì)于其他的 HTTP 狀態(tài)碼,也需要根據(jù)具體情況進(jìn)行相應(yīng)的處理和解決,以保證應(yīng)用程序的正常運(yùn)行。
8.最復(fù)雜的token校驗(yàn)
解決思路
實(shí)現(xiàn) SpringBoot+Vue+Jwt 的 token 認(rèn)證需要以下幾個(gè)步驟:
首先需要在后端(Spring Boot)中編寫接口,用于用戶登錄、注冊(cè)等操作。在處理用戶登錄時(shí),服務(wù)器需要驗(yàn)證請(qǐng)求體中傳遞的用戶賬號(hào)密碼信息,并根據(jù)其是否匹配從數(shù)據(jù)庫(kù)中獲取該用戶信息。此外,在明確用戶有效身份,且通過(guò)驗(yàn)證后,需要生成 JWT,并將其返回給前端。
在前端(Vue)中使用 axios(或其他 Http 請(qǐng)求庫(kù))對(duì)后端服務(wù)器進(jìn)行 HTTP 調(diào)用,并將用戶賬號(hào)和密碼以 POST 方法發(fā)送到服務(wù)器上。
服務(wù)器端成功驗(yàn)證用戶身份后,將會(huì)頒發(fā)一個(gè)由 Jwt 簽名的 Token,并將 Token 掛載在響應(yīng) Body 中。前端在接收到響應(yīng)后,可以將 Token 存儲(chǔ)在 localStorage 中。
在后續(xù)的 Http 請(qǐng)求中,前端將攜帶 JWT 發(fā)送至服務(wù)端,后端接收 JWT 后驗(yàn)證簽名和有效期,并根據(jù) JWT 中所攜帶的用戶信息判斷用戶是否有權(quán)限進(jìn)行請(qǐng)求操作。如果校驗(yàn)失敗,則返回 401 狀態(tài)碼,否則正常響應(yīng)請(qǐng)求。
鑒于存在 CSRF 攻擊的可能,進(jìn)一步加強(qiáng)機(jī)制 withCredentials 設(shè)置為 true,使得 Vue 對(duì) fetch/webSocket 均攜帶 cookie/session,以便于 SpringBoot 進(jìn)行身份認(rèn)證(只設(shè)置頭 Authorization 不足以防止 csrf 攻擊)
在 Spring Boot 中可以使用 Jwt 和 Spring Security 集成,實(shí)現(xiàn)統(tǒng)一認(rèn)證和鑒權(quán),同時(shí)可以配置登錄攔截器只放行匿名訪問(wèn)(如注冊(cè)、登錄)API,并對(duì)其他 API 進(jìn)行身份認(rèn)證和訪問(wèn)控制。而在 Vue 中可以使用 axios 攔截器,在請(qǐng)求發(fā)送之前對(duì) token 進(jìn)行添加等處理。如果要進(jìn)一步優(yōu)化,可以結(jié)合 Vuex 和 localStorage 等方式來(lái)管理 JWT,以增加安全性和代碼的可讀性。
后端代碼
引入jwt依賴
Java-JWT 是一個(gè)在 Java 平臺(tái)上生成和驗(yàn)證 JSON Web Token(JWT)的庫(kù),符合 RFC 7519 標(biāo)準(zhǔn)。JWT 是一種用于跨域認(rèn)證的安全協(xié)議,能夠?qū)π畔⑦M(jìn)行編碼、加密和驗(yàn)證簽名等操作。使用 JWT 能夠避免傳統(tǒng)的 cookie 機(jī)制存在的跨域訪問(wèn)問(wèn)題,同時(shí)也能夠保護(hù)敏感數(shù)據(jù)的安全性。
Java-JWT 幾乎支持所有主流算法的加密和解密,并通過(guò)底層的 Java Cryptography API 對(duì)密鑰進(jìn)行管理,同時(shí)提供了易于使用的構(gòu)建器模式,可以輕松地創(chuàng)建和解析 JWT。
下面是一些 Java-JWT 中常用的類和方法:
- JWT
這是核心類,提供了創(chuàng)建和解析 JWT 的主要功能,包括設(shè)置 Header 和 Payload 等基本信息。
- JwtBuilder
JwtBuilder 類可以幫助我們構(gòu)建一個(gè)標(biāo)準(zhǔn)的 JSON Web Token,其中包含 Claim 的各項(xiàng)內(nèi)容,例如過(guò)期時(shí)間、簽發(fā)者、主題 ID 等等。一般情況下,我們將 Combine 這些不同的 Claims 填充到一個(gè) Builder 對(duì)象中,最后調(diào)用 build() 方法獲得一個(gè) Json Web Token。
- Jwts
Jwts 類提供了針對(duì) JSON Web Tokens 格式和實(shí)現(xiàn)的默認(rèn)規(guī)則,包括 SignatureAlgorithm 枚舉類中提供的算法以及 DefaultJwtParser 的解析規(guī)則(例如,RSA、HMAC、SHA-256 等)。
- Claims
Claims 類表示 JWT 中包含的聲明,可以通過(guò)字符串形式的 key-value 對(duì)來(lái)體現(xiàn)。它們可以是 JSON 格式的 Key,也可以是自定義格式。
- JwtParser
JwtParser 類提供了解析一個(gè)給定 JWT 的方法,并獲取其內(nèi)部所包含的一些 Claims,例如過(guò)期時(shí)間和簽發(fā)者等。
- SignatureAlgorithm
SignatureAlgorithm 枚舉列出了所有支持進(jìn)行 JSON Web Token 簽名/驗(yàn)證的標(biāo)準(zhǔn)算法,包括 HMAC 和 RSA 簽名等常見(jiàn)的加密方式。
因此,Java-JWT 是一款使用簡(jiǎn)單而強(qiáng)大的 Java 庫(kù),適用于跨越認(rèn)證領(lǐng)域。它可以幫助開發(fā)者輕松生成和驗(yàn)證 JSON Web Token,并可通過(guò)多種算法和編碼保護(hù)數(shù)據(jù)的安全性和完整性。
<!-- java-jwt依賴-->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.10.3</version>
</dependency>
<!-- 阿里巴巴fastjson依賴-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
再pom.xml中加入此依賴,記得刷新Maven
生成token的工具類
package com.xiaohui.system.Utils;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.xiaohui.system.entity.User;
import java.util.Date;
/**
* @Description JWT工具類
* @Author IT小輝同學(xué)
* @Date 2023/05/18
*/
public class MyTokenUtil {
private static final long EXPIRE_TIME = 10 * 60 * 60 * 1000;
/**
* 密鑰鹽
*/
private static final String TOKEN_SECRET = "mytoken";
/**
* @param user
* @return {@link String }
* @Description 簽名生成
* @Author IT小輝同學(xué)
* @Date 2023/05/18
*/
public static String sign(User user) {
String token = null;
try {
Date expiresAt = new Date(System.currentTimeMillis() + EXPIRE_TIME);
token = JWT.create().withIssuer("auth0").withClaim("userName", user.getUserName()).withExpiresAt(expiresAt)
// 使用了HMAC256加密算法。
.sign(Algorithm.HMAC256(TOKEN_SECRET));
} catch (Exception e) {
e.printStackTrace();
}
return token;
}
/**
* @param token
* @return boolean
* @Description 簽名驗(yàn)證
* @Author IT小輝同學(xué)
* @Date 2023/05/18
*/
public static boolean verify(String token) {
try {
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(TOKEN_SECRET)).withIssuer("auth0").build();
DecodedJWT jwt = verifier.verify(token);
return true;
} catch (Exception e) {
return false;
}
}
}
這段代碼是一個(gè) JWT 工具類,實(shí)現(xiàn)了生成 JWT 和驗(yàn)證 JWT 的功能。下面是逐行解讀:
import com.auth0.jwt.JWT;
引入 JWT 類,可以通過(guò)該類創(chuàng)建一個(gè) JWT 實(shí)例。
import com.auth0.jwt.JWTVerifier;
引入 JWTVerifier 類,用于驗(yàn)證 JWT 是否合法。
import com.auth0.jwt.algorithms.Algorithm;
引入 Algorithm 類,用于指定生成或驗(yàn)證 JWT 時(shí)使用的算法。
import com.auth0.jwt.interfaces.DecodedJWT;
引入 DecodedJWT 類,可用于獲取 JWT 中包含的聲明和 payload。
import com.xiaohui.system.entity.User;
引入 User 類,通常情況下,我們會(huì)將一些敏感信息打包成 User 對(duì)象放入 JWT 中,以保證數(shù)據(jù)的安全性。
private static final long EXPIRE_TIME = 10 * 60 * 60 * 1000;
指定 JWT 的過(guò)期時(shí)間,單位為毫秒。
private static final String TOKEN_SECRET = "mytoken";
指定用于生成 JWT 簽名的秘鑰鹽,建議將其存儲(chǔ)在服務(wù)器中。
public static String sign(User user) {...}
生成 JWT 簽名的方法。首先設(shè)置 JWT 過(guò)期時(shí)間、聲明和 payload 等必要信息,并使用算法 HMAC256 對(duì)其進(jìn)行簽名并返回 token 字符串。
public static boolean verify(String token) {...}
驗(yàn)證 JWT 簽名是否合法的方法。通過(guò)傳入 token 字符串,調(diào)用 JWT 相關(guān)類(如 JWTrequire 和 Algorithm)及其方法,返回一個(gè)Boolean值,表示該 token 是否合法。
DecodedJWT jwt = verifier.verify(token);
如果傳入的 token 字符串合法,則將其解碼成 DecodedJWT 對(duì)象,并從該對(duì)象中獲取 JWT 中包含的聲明和 payload。
token認(rèn)證
package com.xiaohui.system.config;
import com.alibaba.fastjson.JSONObject;
import com.xiaohui.system.Utils.MyTokenUtil;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @Description token認(rèn)證攔截器
* @Author IT小輝同學(xué)
* @Date 2023/05/18
*/
@Component
public class MyTokenInterceptor implements HandlerInterceptor {
/**
* @param request 請(qǐng)求
* @param response 響應(yīng)
* @param handler 處理程序
* @return boolean
* @Description HandlerInterceptor 中的方法,重寫它來(lái)自定義攔截邏輯
* @Author IT小輝同學(xué)
* @Date 2023/05/18
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
/*
*針對(duì)跨域請(qǐng)求種類 OPTIONS,設(shè)置成 "SC_OK" 以允許請(qǐng)求方法
* 下一步操作應(yīng)當(dāng)檢查token是否存在。
*/
if (request.getMethod().equals("OPTIONS")) {
response.setStatus(HttpServletResponse.SC_OK);
return true;
}
response.setCharacterEncoding("utf-8");
//從請(qǐng)求頭中獲取到前端 Vue 發(fā)起的 token
String token = request.getHeader("Authorization");
if (token != null) {
boolean result = MyTokenUtil.verify(token);
if (result) {
System.out.println("通過(guò)攔截器");
return true;
}
}
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset=utf-8");
try {
//使用 fastjson 創(chuàng)建 JSON 對(duì)象
JSONObject json = new JSONObject();
json.put("msg", "令牌為空");
json.put("code", "401");
//返回易于 Vue 接受的信息,并說(shuō)明發(fā)生的錯(cuò)誤(如果有)
response.getWriter().append(json.toJSONString());
System.out.println("認(rèn)證失敗,未通過(guò)攔截器!!!");
} catch (Exception e) {
e.printStackTrace();
response.sendError(500);
return false;
}
return false;
}
}
這段代碼是一個(gè)攔截器,用于過(guò)濾請(qǐng)求并處理 JWT 鑒權(quán)問(wèn)題。下面是逐行解讀:
import com.alibaba.fastjson.JSONObject;
引入 fastjson 庫(kù)中的 JSONObject 類,用于構(gòu)造返回結(jié)果。
import com.xiaohui.system.Utils.MyTokenUtil;
引入自定義的 JWT 工具類。
import org.springframework.stereotype.Component;
將該類聲明為 Spring 組件,以便在代碼其他位置使用。
import org.springframework.web.servlet.HandlerInterceptor;
實(shí)現(xiàn) HandlerInterceptor 接口,成為 Spring MVC 的攔截器。
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { ... }
HandlerInterceptor 中的方法,重寫它來(lái)自定義攔截邏輯。
if (request.getMethod().equals("OPTIONS")) {...}
針對(duì)跨域請(qǐng)求種類 OPTIONS,設(shè)置成 “SC_OK” 以允許請(qǐng)求方法。下一步操作應(yīng)當(dāng)檢查token是否存在。
String token = request.getHeader("token");
從請(qǐng)求頭中獲取到前端 Vue 發(fā)起的 token。
boolean result = MyTokenUtil.verify(token);
使用前面定義的 JWT 工具類進(jìn)行鑒權(quán),得到驗(yàn)證結(jié)果。
JSONObject json = new JSONObject();
使用 fastjson 創(chuàng)建 JSON 對(duì)象。
response.getWriter().append(json.toJSONString());
返回易于 Vue 接受的信息,并說(shuō)明發(fā)生的錯(cuò)誤(如果有)。
response.setContentType("application/json; charset=utf-8");
指定返回的內(nèi)容類型,并設(shè)置編碼格式為 utf-8。
最終說(shuō)明,該方法用于 JWT 的校驗(yàn)操作,通過(guò)此攔截器在request將token提取出來(lái),然后使用JWT工具類進(jìn)行校驗(yàn)。如果校驗(yàn)失敗,則響應(yīng)401的狀態(tài),然后自定義錯(cuò)誤信息返回給前端Vue。
token認(rèn)證過(guò)濾器
package com.xiaohui.system.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ConcurrentTaskExecutor;
import org.springframework.web.servlet.config.annotation.AsyncSupportConfigurer;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
/**
* @Description 跨域
* @Author IT小輝同學(xué)
* @Date 2023/05/18
*/
@Configuration
public class CrosConfig implements WebMvcConfigurer {
private ExecutorService executorService = null;
/**
* @param registry 注冊(cè)表
* @Description 通過(guò) registry 來(lái)設(shè)置允許跨域的路由、
* 請(qǐng)求方式、允許順序等消息頭,并在 Spring 容器中創(chuàng)建注冊(cè)器
* @Author IT小輝同學(xué)
* @Date 2023/05/18
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
//設(shè)置允許跨域的路由
registry.addMapping("/**")
.allowedOriginPatterns("*")
.allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")
.allowCredentials(true)
.maxAge(3600)
.allowedHeaders("*");
}
private MyTokenInterceptor tokenInterceptor;
//構(gòu)造方法
public CrosConfig(MyTokenInterceptor tokenInterceptor) {
this.tokenInterceptor = tokenInterceptor;
}
/**
* @param configurer 配置
* @Description 配置異步支持
* @Author IT小輝同學(xué)
* @Date 2023/05/18
*/
@Override
public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
executorService = new ThreadPoolExecutor(2,
2,
100,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(2),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
configurer.setTaskExecutor(new ConcurrentTaskExecutor(executorService));
configurer.setDefaultTimeout(30000);
}
/**
* @param registry 注冊(cè)表
* @Description 添加攔截器
* @Author IT小輝同學(xué)
* @Date 2023/05/18
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
List<String> excludePath = new ArrayList<>();
//排除攔截,除了注冊(cè)登錄(此時(shí)還沒(méi)token),其他都攔截
excludePath.add("/user/register");
excludePath.add("/user/login");
registry.addInterceptor(tokenInterceptor)
.addPathPatterns("/**")
.excludePathPatterns(excludePath);
WebMvcConfigurer.super.addInterceptors(registry);
}
}
這段代碼是一個(gè) Spring MVC 的配置類,主要用于設(shè)置異步支持、跨域訪問(wèn)和攔截器的操作。下面是逐行解讀:
import org.springframework.context.annotation.Configuration;
將該類聲明為 Spring 配置類。
import org.springframework.scheduling.concurrent.ConcurrentTaskExecutor;
引入對(duì)線程池的支持。
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
WebMvcConfigurer 是 Spring MVC 的自定義配置接口,需要實(shí)現(xiàn)該接口才能自定義 Spring MVC 相關(guān)組件。
@Configuration public class CrosConfig implements WebMvcConfigurer { ... }
聲明一個(gè) CrosConfig 類,使用 WebMvcConfigurer 接口提供的方法來(lái)自定義 Spring MVC 相關(guān)組件。
private ExecutorService executorService = null;
使用線程池來(lái)處理異步支持所需的線程。
@Override public void addCorsMappings(CorsRegistry registry) { ... }
通過(guò) registry 來(lái)設(shè)置允許跨域的路由、請(qǐng)求方式、允許順序等消息頭,并在 Spring 容器中創(chuàng)建注冊(cè)器。
private MyTokenInterceptor tokenInterceptor;
注入 MyTokenInterceptor 實(shí)例。
public CrosConfig(MyTokenInterceptor tokenInterceptor) { this.tokenInterceptor = tokenInterceptor; }
構(gòu)造函數(shù),參數(shù)為 MyTokenInterceptor 對(duì)象,以供引入。
@Override public void configureAsyncSupport(AsyncSupportConfigurer configurer) { ... }
異步支持配置,使用線程池來(lái)創(chuàng)建定制異步任務(wù)。
registry.addInterceptor(tokenInterceptor) .addPathPatterns("/**") .excludePathPatterns(excludePath);
添加攔截器,除注冊(cè)和登錄外,其他請(qǐng)求都需要驗(yàn)證 Token 來(lái)實(shí)現(xiàn)安全過(guò)濾。
最終說(shuō)明,該代碼主要用于配置 Spring MVC 的一些屬性,包括跨域訪問(wèn)、攔截器、線程池等。具體來(lái)說(shuō):允許所有的路由進(jìn)行跨域訪問(wèn);使用線程池來(lái)支持異步請(qǐng)求;攔截所有除了注冊(cè)和登錄以外的 HTTP 請(qǐng)求,并通過(guò) tokenInterceptor 對(duì)其進(jìn)行進(jìn)一步處理。
做到這里,我們把原來(lái)寫的controller修改一下
package com.xiaohui.system.controller;
import com.xiaohui.system.Utils.AjaxResult;
import com.xiaohui.system.Utils.MyTokenUtil;
import com.xiaohui.system.entity.User;
import com.xiaohui.system.service.Impl.UserServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
/**
* @Description 用戶控制器
* @Author IT小輝同學(xué)
* @Date 2023/05/17
*/
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserServiceImpl userService;
/**
* @param user 用戶
* @return {@link AjaxResult }
* @Description 獲取所有用戶信息
* @Author IT小輝同學(xué)
* @Date 2023/05/17
*/
@GetMapping("/list")
private AjaxResult selectAllUserInfo() {
User user = new User();
return AjaxResult.success(userService.selectAllUserInfo(user));
}
/**
* @param user 用戶
* @return {@link AjaxResult }
* @Description 用戶登錄鑒權(quán)
* @Author IT小輝同學(xué)
* @Date 2023/05/17
*/
@PostMapping("/login")
private AjaxResult userLoginJuage(@RequestBody User user) {
//獲取登錄信息
User userLoginInfo = userService.userLoginJuage(user);
boolean flag = false;
//判斷用戶是否存在
if (userLoginInfo != null) {
//構(gòu)造token
String token = MyTokenUtil.sign(user);
HashMap tokenMap=new HashMap();
tokenMap.put("token",token);
return AjaxResult.success("登錄成功", tokenMap);
}
return AjaxResult.error("用戶不存在或者密碼錯(cuò)誤");
}
}
前端代碼
重寫router/index.js 路由守衛(wèi)
import Vue from 'vue'
import VueRouter from "vue-router";
import loginPage from "@/view/login/loginPage.vue"
import helloWorld from "@/components/HelloWorld.vue";
Vue.use(VueRouter)
const router = new VueRouter({
mode: 'history',
routes: [
{
path: '/',
redirect: '/login' // 將默認(rèn)路由重定向到登錄頁(yè)
},
{
name: 'login',
path: '/login',
component: loginPage
},
{
name: 'helloWorld',
path: '/helloWorld',
component: helloWorld
},
]
})
//全局前置守衛(wèi)
router.beforeEach((to, from, next) => {
// to and from are both route objects. must call `next`.
if (to.path === '/register' || to.path === '/login' || to.path === '/') {
next();//直接放行
} else {
const token = window.localStorage.getItem('Authorization');
if (token === null || token === '') {
next('/login')
} else {
next()
}
}
})
export default router
配置Vuex
老規(guī)矩,先安裝
npm install vuex
編寫/router/store.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const actions = {
// 定義異步操作等不改變 state 的邏輯 ...
}
const mutations = {
// 修改 token,將 token 放入 localStorage 中
changeLogin(state, user) {
state.Authorization = user.Authorization
window.localStorage.setItem('Authorization', user.Authorization)
},
// 注銷
logout(state) {
state.Authorization = null
window.localStorage.removeItem('Authorization')
}
}
const state = {
// 存儲(chǔ) token
Authorization: window.localStorage.getItem('Authorization') ? window.localStorage.getItem('Authorization') : '',
}
// 向外暴露
const store = new Vuex.Store({
actions,
mutations,
state,
})
export default store
最后,對(duì)于登錄界面的登錄邏輯重寫一下
toLogin() {
userLogin(this.form).then(response => {
console.log(response)
if (response.code !== 200) {
this.form = ""
this.$message.error(response.msg);
} else {
//獲取服務(wù)器響應(yīng)的token值。保存LocalStorage
window.localStorage.setItem("Authorization",response.data.token);
this.$message({message:response.msg , type: 'success'});
this.$router.push({path: "/helloWorld"});
}
}
);
},
9.驗(yàn)證token鑒權(quán)
有token
沒(méi)有token
10.已經(jīng)寫了兩個(gè)晚上了,最后,再給大家補(bǔ)充一個(gè)密碼加密
加密算法我們使用MD5加密
MD5(Message Digest Algorithm 5)是一種常見(jiàn)的哈希函數(shù),用于將任意長(zhǎng)度的消息數(shù)據(jù)計(jì)算得出一個(gè)128位的哈希值。這個(gè)哈希值通常表示為32位的16進(jìn)制數(shù)字,經(jīng)常被用于對(duì)密碼、消息等敏感信息進(jìn)行加密存儲(chǔ)或傳輸。
先引入依賴
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.23</version>
</dependency>
MD5工具類
package com.xiaohui.system.Utils;
import org.springframework.stereotype.Component;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import static com.alibaba.druid.util.Utils.md5;
@Component
public class MD5Utils {
/**
* 使用md5的算法進(jìn)行加密
*/
public static String toMD5(String plainText) {
byte[] secretBytes = null;
try {
secretBytes = MessageDigest.getInstance("md5").digest(
plainText.getBytes());
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("沒(méi)有md5這個(gè)算法!");
}
String md5code = new BigInteger(1, secretBytes).toString(16);// 16進(jìn)制數(shù)字
// 如果生成數(shù)字未滿32位,需要前面補(bǔ)0
for (int i = 0; i < 32 - md5code.length(); i++) {
md5code = "0" + md5code;
}
return md5code;
}
/**
* 可逆的的加密解密方法;兩次是解密,一次是加密
*
* @param inStr
* @return
*/
public static String convertMD5(String inStr) {
char[] a = inStr.toCharArray();
for (int i = 0; i < a.length; i++) {
a[i] = (char) (a[i] ^ 't');
}
String s = new String(a);
return s;
}
/*
public static void main(String[] args) {
String s = md5("1234");
System.out.println("MD5后:"+s);
System.out.println("MD5后:"+s);
System.out.println("MD5后再加密:"+convertMD5(s));
System.out.println("MD5加密后解密:"+convertMD5(convertMD5(s)));
String s2 = convertMD5("12345");
System.out.println("可逆的加密解密方法之加密:"+s2);
System.out.println("可逆的加密解密方法之解密:"+convertMD5(s2));
}
*/
}
新增用戶的時(shí)候,調(diào)用toMD5進(jìn)行密碼加密存儲(chǔ),對(duì)比的時(shí)候?qū)⑤斎氲拿艽aconvertMD5進(jìn)行加密與數(shù)據(jù)庫(kù)進(jìn)行對(duì)比即可
沒(méi)想到,用了兩天時(shí)間終于寫完了,可以說(shuō)是集眾家之長(zhǎng),匯集了眾多大佬的資源,得以完成!很感謝自己,也感謝大家,我們一起努力,相信夢(mèng)想不被辜負(fù),付出終將溫柔回報(bào)!如有不足,大家見(jiàn)諒,私信討論,我們一起進(jìn)步!?。?/strong>
代碼在個(gè)人資源,可以主頁(yè)免費(fèi)下載!文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-450827.html
128位的哈希值。這個(gè)哈希值通常表示為32位的16進(jìn)制數(shù)字,經(jīng)常被用于對(duì)密碼、消息等敏感信息進(jìn)行加密存儲(chǔ)或傳輸。
先引入依賴
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.23</version>
</dependency>
MD5工具類
package com.xiaohui.system.Utils;
import org.springframework.stereotype.Component;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import static com.alibaba.druid.util.Utils.md5;
@Component
public class MD5Utils {
/**
* 使用md5的算法進(jìn)行加密
*/
public static String toMD5(String plainText) {
byte[] secretBytes = null;
try {
secretBytes = MessageDigest.getInstance("md5").digest(
plainText.getBytes());
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("沒(méi)有md5這個(gè)算法!");
}
String md5code = new BigInteger(1, secretBytes).toString(16);// 16進(jìn)制數(shù)字
// 如果生成數(shù)字未滿32位,需要前面補(bǔ)0
for (int i = 0; i < 32 - md5code.length(); i++) {
md5code = "0" + md5code;
}
return md5code;
}
/**
* 可逆的的加密解密方法;兩次是解密,一次是加密
*
* @param inStr
* @return
*/
public static String convertMD5(String inStr) {
char[] a = inStr.toCharArray();
for (int i = 0; i < a.length; i++) {
a[i] = (char) (a[i] ^ 't');
}
String s = new String(a);
return s;
}
/*
public static void main(String[] args) {
String s = md5("1234");
System.out.println("MD5后:"+s);
System.out.println("MD5后:"+s);
System.out.println("MD5后再加密:"+convertMD5(s));
System.out.println("MD5加密后解密:"+convertMD5(convertMD5(s)));
String s2 = convertMD5("12345");
System.out.println("可逆的加密解密方法之加密:"+s2);
System.out.println("可逆的加密解密方法之解密:"+convertMD5(s2));
}
*/
}
新增用戶的時(shí)候,調(diào)用toMD5進(jìn)行密碼加密存儲(chǔ),對(duì)比的時(shí)候?qū)⑤斎氲拿艽aconvertMD5進(jìn)行加密與數(shù)據(jù)庫(kù)進(jìn)行對(duì)比即可
沒(méi)想到,用了兩天時(shí)間終于寫完了,可以說(shuō)是集眾家之長(zhǎng),匯集了眾多大佬的資源,得以完成!很感謝自己,也感謝大家,我們一起努力,愿夢(mèng)想不被辜負(fù),付出終將溫柔回報(bào)!如有不足,大家見(jiàn)諒,私信討論,我們一起進(jìn)步?。?!文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-450827.html
代碼在個(gè)人資源,可以主頁(yè)免費(fèi)下載!
到了這里,關(guān)于鑒權(quán)管理系統(tǒng)(JWT技術(shù)架構(gòu))——SpringBoot2+Vue2(一定驚喜滿滿,萬(wàn)字長(zhǎng)文)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!