4.后台登录功能开发
一、需求分析
(一)页面原型展示
- 找到项目资源 - 产品原型 > 瑞吉外卖后台(管理端)- 登录.html
- 点开登录.html页面
- 登录页面有两个文本框需要用户输入用户名和密码,客户端要进行非空校验,单击【登录】按钮之后,表单数据以JSON格式通过AJAX请求方式发送到后台,后台控制器要编写相应的处理函数,对提交的数据进行业务处理,然后将处理结果返回给前端。
- 不妨看一看login.html页面代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>瑞吉外卖管理端</title>
<link rel="shortcut icon" href="../../favicon.ico">
<!-- 引入样式 -->
<link rel="stylesheet" href="../../plugins/element-ui/index.css" />
<link rel="stylesheet" href="../../styles/common.css">
<link rel="stylesheet" href="../../styles/login.css">
<link rel="stylesheet" href="../../styles/icon/iconfont.css" />
<style>
.body{
min-width: 1366px;
}
</style>
</head>
<body>
<div class="login" id="login-app">
<div class="login-box">
<img src="../../images/login/login-l.png" alt="">
<div class="login-form">
<el-form ref="loginForm" :model="loginForm" :rules="loginRules" >
<div class="login-form-title">
<img src="../../images/login/logo.png" style="width:139px;height:42px;" alt="" />
</div>
<el-form-item prop="username">
<el-input v-model="loginForm.username" type="text" auto-complete="off" placeholder="账号" maxlength="20"
prefix-icon="iconfont icon-user" />
</el-form-item>
<el-form-item prop="password">
<el-input v-model="loginForm.password" type="password" placeholder="密码" prefix-icon="iconfont icon-lock" maxlength="20"
@keyup.enter.native="handleLogin" />
</el-form-item>
<el-form-item style="width:100%;">
<el-button :loading="loading" class="login-btn" size="medium" type="primary" style="width:100%;"
@click.native.prevent="handleLogin">
<span v-if="!loading">登录</span>
<span v-else>登录中...</span>
</el-button>
</el-form-item>
</el-form>
</div>
</div>
</div>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="../../plugins/vue/vue.js"></script>
<!-- 引入组件库 -->
<script src="../../plugins/element-ui/index.js"></script>
<!-- 引入axios -->
<script src="../../plugins/axios/axios.min.js"></script>
<script src="../../js/request.js"></script>
<script src="../../js/validate.js"></script>
<script src="../../api/login.js"></script>
<script>
new Vue({
el: '#login-app',
data() {
return {
loginForm:{
username: 'admin',
password: '123456'
},
loading: false
}
},
computed: {
loginRules() {
const validateUsername = (rule, value, callback) => {
if (value.length < 1 ) {
callback(new Error('请输入用户名'))
} else {
callback()
}
}
const validatePassword = (rule, value, callback) => {
if (value.length < 6) {
callback(new Error('密码必须在6位以上'))
} else {
callback()
}
}
return {
'username': [{ 'validator': validateUsername, 'trigger': 'blur' }],
'password': [{ 'validator': validatePassword, 'trigger': 'blur' }]
}
}
},
created() {
},
methods: {
async handleLogin() {
this.$refs.loginForm.validate(async (valid) => {
if (valid) {
this.loading = true
let res = await loginApi(this.loginForm)
if (String(res.code) === '1') {
localStorage.setItem('userInfo',JSON.stringify(res.data))
window.location.href= '/backend/index.html'
} else {
this.$message.error(res.msg)
this.loading = false
}
}
})
}
}
})
</script>
</body>
</html>
- Vue对象通过el属性绑定了id属性为login-app的div元素
- Vue对象通过data()方法绑定JSON数据loginForm,通过computed绑定校验规则loginRules
- Vue对象通过methods绑定对登录表单数据进行处理的异步方法handleLogin
- 在前端处理函数里,有后端处理函数返回的结果,保存在res变量里,里面有三个数据:res.code、res.data、res.msg,这就要求后端处理函数返回JSON数据必须要包含这三项内容。
(二)登录页面展示
- 页面位置:项目/resources/backend/page/login/login.html
- 为什么Vue对象里要绑定这个用户登录数据呢?
- 因为员工表employee里有一条数据:admin与123456(MD5加密之后就成了e10adc3949ba59abbe56e057f20f883e)
- 单击【登录】按钮,首先进行校验,如果校验通过,按钮标题就会变成登录中……,如果校验失败,按钮标题就依然是登录
(三)查看登录请求信息
- 按F12键进入浏览器的调试模式
- 说明单击登录按钮通过客户端校验之后,请求的URL:http://localhost:8080/employee/login
- 后面我们会在雇员控制器里编写相应的处理函数login()
@RestController // 交给Spring容器管理
@RequestMapping("/employee")
public class EmployeeController {
@PostMapping("/login")
public R<Employee> login(HttpRequest request, @RequestBody Employee employee) {
return null;
}
}
(四)数据模型-雇员表
- 查看雇员表结构
二、代码开发
- 开发流程图
(一)创建雇员实体类
- ORM(Object Relation Mapping)对象关系映射
- 雇员实体类(Employee)—— 雇员表(employee)
- 实体属性名采用驼峰命名法,关系字段名采用xml命名规范
- 如果关系字段名由多个单词用下划线连接,那么实体属性名与关系字段名就不一致,需要进行一个转换,但是这个转换工作不需要手工去操作,直接在应用属性文件(application.yml)里进行设置。
- 创建
entity
子包
- 在net.hw.entity包里创建雇员实体类 - Employee
package net.hw.entity;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 功能:雇员实体类
* 作者:xizaizhao
* 日期:2022年11月03日
*/
@Data // Lombok注解,注在类上,提供类的get、set、equals、hashCode、canEqual、toString方法
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private String username;
private String name;
private String password;
private String phone;
private String sex;
private String idNumber; // 对应字段 - id_number
private Integer status;
private LocalDateTime createTime; // 对应字段 - create_time
private LocalDateTime updateTime; // 对应字段 - update_time
@TableField(fill = FieldFill.INSERT) // mybatis-plus注解,填充策略
private Long createUser; // 对应字段 - create_user
@TableField(fill = FieldFill.INSERT_UPDATE) // mybatis-plus注解,填充策略
private Long updateUser; // 对应字段 - update_user
}
-
参看博文《lombok的@Data注解(https://blog.csdn.net/qq_39900031/article/details/126376871)》
-
参看博文《mybatis-plus常用注解(https://blog.csdn.net/m0_61682705/article/details/125348601)》
(二)创建雇员映射器接口
-
创建mapper子包
-
在net.hw.mapper包里创建雇员映射器接口 - EmployeeMapper
-
采用了mybatis-plus插件,就不用再去创建对应的映射器配置文件(EmployeeMapper.xml)
package net.hw.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import net.hw.entity.Employee;
import org.apache.ibatis.annotations.Mapper;
/**
* 功能:雇员映射器接口
* 作者:xizaizhao
* 日期:2022年11月03日
*/
@Mapper // 交给Spring容器来管理
public interface EmployeeMapper extends BaseMapper<Employee> {
}
- 继承了BaseMapper接口,无需编写任何代码,直接就实现了对Employee进行增删改查的功能。
(三)创建雇员服务
# 1、创建雇员服务接口
- 创建service子包
- 在net.hw.service包里创建雇员服务接口 - EmployeeService
- 采用mybatis-plus插件,代码及其简单,只需要继承IService接口
package net.hw.service;
import com.baomidou.mybatisplus.extension.service.IService;
import net.hw.entity.Employee;
/**
* 功能:雇员服务接口
* 作者:xizaizhao
* 日期:2022年11月03日
*/
public interface EmployeeService extends IService<Employee> {
}
#2、创建雇员服务接口实现类
- 在net.hw.service包里创建impl子包
- 在net.hw.service.impl子包里创建雇员服务接口实现类 - EmployeeServiceImpl
package net.hw.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import net.hw.entity.Employee;
import net.hw.mapper.EmployeeMapper;
import net.hw.service.EmployeeService;
import org.springframework.stereotype.Service;
/**
* 功能:雇员服务接口实现类
* 作者:xizaizhao
* 日期:2022年11月03日
*/
@Service // 交给Spring容器管理
public class EmployeeServiceImpl extends ServiceImpl<EmployeeMapper, Employee>
implements EmployeeService {
}
- 注意:必须先继承ServiceImpl<EmployeeMapper,
Employee>类,后实现EmployeeService接口,顺序绝对不能交换(打个不恰当的比方,继承类是与父亲的关系,实现接口是与叔叔的关系,在Java里,一个类只能继承一个父类,但是可以实现多个接口,现实生活中也是如此,一个人只能有一个父亲,但是可以有多个叔叔,父亲肯定比叔叔亲,因此排名必定在前)。
(四)创建返回结果类
- 服务器端所有处理方法返回结果都封装到这个通用类里
- 创建common子包
- 在net.hw.common包里创建返回结果类 - R
package net.hw.common;
import lombok.Data;
import java.util.HashMap;
import java.util.Map;
/**
* 功能:返回结果类
* 作者:赵茜
* 日期:2022年11月03日
*/
@Data // Lombok注解,精简代码
public class R<T> {
private Integer code; // 编码:1成功,0和其它数字为失败
private String msg; // 错误信息
private T data; // 数据
private Map map = new HashMap(); // 动态数据
public static <T> R<T> success(T object) {
R<T> r = new R<T>();
r.data = object;
r.code = 1;
return r;
}
public static <T> R<T> error(String msg) {
R r = new R();
r.msg = msg;
r.code = 0;
return r;
}
public R<T> add(String key, Object value) {
this.map.put(key, value);
return this;
}
}
(五)创建雇员控制器
-
创建controller子包
-
在net.hw.controller包里创建雇员控制器类 - EmployeeController
-
基本框架代码,登录方法代码尚未编写
package net.hw.controller;
import lombok.extern.slf4j.Slf4j;
import net.hw.common.R;
import net.hw.entity.Employee;
import net.hw.service.EmployeeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
/**
* 功能:雇员控制器类
* 作者:xizaizhao
* 日期:2022年11月03日
*/
@Slf4j // 日志注解
@RestController // 交给Spring容器管理
@RequestMapping("/employee")
public class EmployeeController {
@Autowired
private EmployeeService employeeService;
@PostMapping("/login")
public R<Employee> login(HttpServletRequest request, @RequestBody Employee employee) {
return null;
}
}
- 登录方法处理逻辑
1、将页面提交的密码password进行md5加密处理
2、根据页面提交的用户名username查询数据库
3、如果没有查询到则返回登录失败结果
4、密码比对,如果不一致则返回登录失败结果
5、查看员工状态,如果为已禁用状态,则返回员工已禁用结果
6、登录成功,将员工id存入Session并返回登录成功结果
- 登录方法流程图
- 将页面提交的密码password进行md5加密处理
- 根据页面提交的用户名username查询数据库
- 一般情况下,按用户名查询,返回的是一个记录集,但是雇员表对用户名字段做了唯一约束
- 因此,按用户名查询雇员表,只有两种情况:要么没找到,要么找到一条
- 如果没有查询到则返回登录失败结果
- 密码比对,如果不一致则返回登录失败结果
- 查看员工状态,如果为已禁用状态,则返回员工已禁用结果
- 登录成功,将员工id存入Session并返回登录成功结果
三功能测试
(一)修改超时配置
- 在resources/backend/js/request.js文件里设置超时为1000000毫秒,便于后面做断点调试
(二)设置断点
- 在EmployeeController里设置断点
(三)采用调试模式启动应用
- 点击工具栏上的调试按钮
- 查看控制台信息
- 查看调试器信息,目前啥也没有
测试登录 - [成功]
- 浏览器访问http://localhost:8080/backend/page/login/login.html
- 按F12键,打开开发者工具
- 利用目前正确的用户登录信息(admin:123456)来登录,单击【登录】按钮
- 刚才设置了超时1000000毫秒,还是出现系统接口请求超时的错误信息,这是浏览器缓存未清除所导致的,我们得先清除浏览器缓存数据。
- 重启应用,再刷新登录页面,就没有超时警告信息了
- 查看断点调试信息
- 单击【Step Over】按钮3次,判断用户名是否错误
- 单击【Step Over】按钮,判断密码是否错误
- 单击【Step Over】按钮,判断雇员状态是否已禁用
- 单击【Step Over】按钮3次,返回登录成功结果
- 此时,查看登录页面,登录成功,会本地存储用户信息
四、哈希加密
(一)加密基础
Python里面实现MD5、SHA256、SHA512、SHA1和SHA224加密
- 雇员表密码字段采用了md5加密 [密码明文:123456,密文:e10adc3949ba59abbe56e057f20f883e]
- 采用md5加密,得到的加密字符串都是定长的,32位
1、采用md5加密算法
- 编写程序 - 哈希加密md5.py
# 哈希加密是单向加密
# 导入加密模块
import hashlib
# 采用md5加密算法
obj = hashlib.md5()
# 输入待加密字符串 - 明文 [plaintext]
plaintext = input('输入待加密字符串:')
# 转换成二进制数据
obj.update(plaintext.encode('utf-8'))
# 获得密文 [cryptotext]
cryptotext = obj.hexdigest()
# 打印密文及密文长度
print('加密之后的字符串:{}'.format(cryptotext))
print('md5加密字符长度:{}'.format(len(cryptotext)))
- 运行程序,查看结果
- 无论明文多长,采用md5加密之后的密文都是32位定长字符串;明文细微变化,密文天壤之别
采用sha256加密算法
- 编写程序 - 哈希加密sha256.py
# 哈希加密是单向加密
# 导入加密模块
import hashlib
# 采用sha256加密算法
obj = hashlib.sha256()
# 输入待加密字符串 - 明文 [plaintext]
plaintext = input('输入待加密字符串:')
# 转换成二进制数据
obj.update(plaintext.encode('utf-8'))
# 获得密文 [cryptotext]
cryptotext = obj.hexdigest()
# 打印密文及密文长度
print('加密之后的字符串:{}'.format(cryptotext))
print('sha256加密字符长度:{}'.format(len(cryptotext)))
- 运行程序,查看结果
- 无论明文多长,采用sha256加密之后的密文都是64位定长字符串;明文细微变化,密文天壤之别
采用sha512加密算法
- 编写程序 - 哈希加密sha512.py
# 哈希加密是单向加密
# 导入加密模块
import hashlib
# 采用sha512加密算法
obj = hashlib.sha512()
# 输入待加密字符串 - 明文 [plaintext]
plaintext = input('输入待加密字符串:')
# 转换成二进制数据
obj.update(plaintext.encode('utf-8'))
# 获得密文 [cryptotext]
cryptotext = obj.hexdigest()
# 打印密文及密文长度
print('加密之后的字符串:{}'.format(cryptotext))
print('sha512加密字符长度:{}'.format(len(cryptotext)))
- 运行程序,查看结果
- 无论明文多长,采用sha512加密之后的密文都是128位定长字符串;明文细微变化,密文天壤之别
4、采用sha1加密算法
- 编写程序 - 哈希加密sha1.py
# 哈希加密是单向加密
# 导入加密模块
import hashlib
# 采用sha1加密算法
obj = hashlib.sha1()
# 输入待加密字符串 - 明文 [plaintext]
plaintext = input('输入待加密字符串:')
# 转换成二进制数据
obj.update(plaintext.encode('utf-8'))
# 获得密文 [cryptotext]
cryptotext = obj.hexdigest()
# 打印密文及密文长度
print('加密之后的字符串:{}'.format(cryptotext))
print('sha1加密字符长度:{}'.format(len(cryptotext)))
- 运行程序,查看结果
- 无论明文多长,采用sha1加密之后的密文都是40位定长字符串;明文细微变化,密文天壤之别
采用sha224加密算法
- 编写程序 - 哈希加密sha224.py
# 哈希加密是单向加密
# 导入加密模块
import hashlib
# 采用sha224加密算法
obj = hashlib.sha224()
# 输入待加密字符串 - 明文 [plaintext]
plaintext = input('输入待加密字符串:')
# 转换成二进制数据
obj.update(plaintext.encode('utf-8'))
# 获得密文 [cryptotext]
cryptotext = obj.hexdigest()
# 打印密文及密文长度
print('加密之后的字符串:{}'.format(cryptotext))
print('sha224加密字符长度:{}'.format(len(cryptotext)))
- 运行程序,查看结果
- 无论明文多长,采用sha224加密之后的密文都是56位定长字符串;明文细微变化,密文天壤之别
(三)Java里实现MD5、SHA256、SHA512、SHA1和SHA224加密
1、采用md5加密算法
(1)采用DigestUtils类
- 在net.hw.common包里创建Encrypt类
package net.hw.common;
import org.springframework.util.DigestUtils;
import java.util.Scanner;
/**
* 功能:MD5加密
* 作者:xizaizhao
* 日期:2022年12月01日
*/
public class Encrypt {
public static void main(String[] args) {
// 声明变量
String plainText, cryptoText;
Scanner sc = new Scanner(System.in);
// 输入待加密字符串
System.out.print("输入待加密字符串:");
plainText = sc.nextLine();
// 采用MD5加密算法进行加密
cryptoText = DigestUtils.md5DigestAsHex(plainText.getBytes());
// 输出MD5加密字符串
System.out.println("加密之后的字符串:" + cryptoText);
System.out.println("md5加密字符串长度:" + cryptoText.length());
}
}
-
运行程序,查看结果
-
有点遗憾,DigestUtils类没有提供SHA系列的加密算法
-
无论明文多长,采用md5加密之后的密文都是32位定长字符串;明文细微变化,密文天壤之别
(2)采用MessageDigest类
- 在net.hw.common包里创建EncryptMD5类
package net.hw.common;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Scanner;
/**
* 功能:MD5加密
* 作者:xizaizhao
* 日期:2022年12月01日
*/
public class EncryptMD5 {
public static void main(String[] args) {
// 声明变量
String plainText, cryptoText;
Scanner sc = new Scanner(System.in);
// 输入待加密字符串
System.out.print("输入待加密字符串:");
plainText = sc.nextLine();
// 采用SHA256加密算法进行加密
cryptoText = sha256DigestAsHex(plainText);
// 输出SHA256加密字符串
System.out.println("加密之后的字符串:" + cryptoText);
System.out.println("md5加密字符串长度:" + cryptoText.length());
}
/**
* md5加密
*
* @param text 待加密的字符串
* @return 加密后的字符串
*/
public static String sha256DigestAsHex(String text) {
MessageDigest md;
String encodedText = "";
try {
md = MessageDigest.getInstance("MD5");
md.update(text.getBytes(StandardCharsets.UTF_8));
encodedText = byte2Hex(md.digest());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return encodedText;
}
/**
* md5 加密 将byte转为16进制
*
* @param bytes 字节数组
* @return 加密后的字符串
*/
private static String byte2Hex(byte[] bytes) {
StringBuilder builder = new StringBuilder();
String temp;
for (byte aByte : bytes) {
temp = Integer.toHexString(aByte & 0xFF);
if (temp.length() == 1) {
// 得到一位的进行补0操作
builder.append("0");
}
builder.append(temp);
}
return builder.toString();
}
}
-
运行程序,查看结果
-
无论明文多长,采用md5加密之后的密文都是32位定长字符串;明文细微变化,密文天壤之别
2、采用sha256加密算法
- 在net.hw.common包里创建EncryptSHA256类
package net.hw.common;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Scanner;
/**
* 功能:SHA256加密
* 作者:xizaizhao
* 日期:2022年12月01日
*/
public class EncryptSHA256 {
public static void main(String[] args) {
// 声明变量
String plainText, cryptoText;
Scanner sc = new Scanner(System.in);
// 输入待加密字符串
System.out.print("输入待加密字符串:");
plainText = sc.nextLine();
// 采用SHA256加密算法进行加密
cryptoText = sha256DigestAsHex(plainText);
// 输出SHA256加密字符串
System.out.println("加密之后的字符串:" + cryptoText);
System.out.println("sha256加密字符串长度:" + cryptoText.length());
}
/**
* sha256加密
*
* @param text 要加密的字符串
* @return 加密后的字符串
*/
public static String sha256DigestAsHex(String text) {
MessageDigest md;
String encodedText = "";
try {
md = MessageDigest.getInstance("SHA-256");
md.update(text.getBytes(StandardCharsets.UTF_8));
encodedText = byte2Hex(md.digest());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return encodedText;
}
/**
* sha256加密 将byte转为16进制
*
* @param bytes 字节码
* @return 加密后的字符串
*/
private static String byte2Hex(byte[] bytes) {
StringBuilder builder = new StringBuilder();
String temp;
for (byte aByte : bytes) {
temp = Integer.toHexString(aByte & 0xFF);
if (temp.length() == 1) {
// 得到一位的进行补0操作
builder.append("0");
}
builder.append(temp);
}
return builder.toString();
}
}
-
运行程序,查看结果
-
无论明文多长,采用sha256加密之后的密文都是64位定长字符串;明文细微变化,密文天壤之别
3、采用sha512加密算法
- 在net.hw.common包里创建EncryptSHA512类
package net.hw.common;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Scanner;
/**
* 功能:SHA512加密
* 作者:xizaizhao
* 日期:2022年12月01日
*/
public class EncryptSHA512 {
public static void main(String[] args) {
// 声明变量
String plainText, cryptoText;
Scanner sc = new Scanner(System.in);
// 输入待加密字符串
System.out.print("输入待加密字符串:");
plainText = sc.nextLine();
// 采用SHA512加密算法进行加密
cryptoText = sha512DigestAsHex(plainText);
// 输出SHA512加密字符串
System.out.println("加密之后的字符串:" + cryptoText);
System.out.println("sha512加密字符串长度:" + cryptoText.length());
}
/**
* sha512加密
*
* @param text 待加密的字符串
* @return 加密后的字符串
*/
public static String sha512DigestAsHex(String text) {
MessageDigest md;
String encodedText = "";
try {
md = MessageDigest.getInstance("SHA-512");
md.update(text.getBytes(StandardCharsets.UTF_8));
encodedText = byte2Hex(md.digest());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return encodedText;
}
/**
* sha512加密 将byte转为16进制
*
* @param bytes 字节数组
* @return 加密后的字符串
*/
private static String byte2Hex(byte[] bytes) {
StringBuilder builder = new StringBuilder();
String temp;
for (byte aByte : bytes) {
temp = Integer.toHexString(aByte & 0xFF);
if (temp.length() == 1) {
// 得到一位的进行补0操作
builder.append("0");
}
builder.append(temp);
}
return builder.toString();
}
}
-
运行程序,查看结果
-
无论明文多长,采用sha512加密之后的密文都是128位定长字符串;明文细微变化,密文天壤之别
4、采用sha1加密算法
- 在net.hw.common包里创建EncryptSHA1类
package net.hw.common;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Scanner;
/**
* 功能:SHA1加密
* 作者:xizaizhao
* 日期:2022年12月01日
*/
public class EncryptSHA1 {
public static void main(String[] args) {
// 声明变量
String plainText, cryptoText;
Scanner sc = new Scanner(System.in);
// 输入待加密字符串
System.out.print("输入待加密字符串:");
plainText = sc.nextLine();
// 采用SHA256加密算法进行加密
cryptoText = sha256DigestAsHex(plainText);
// 输出SHA256加密字符串
System.out.println("加密之后的字符串:" + cryptoText);
System.out.println("sha1加密字符串长度:" + cryptoText.length());
}
/**
* sha1加密
*
* @param text 待加密的字符串
* @return 加密后的字符串
*/
public static String sha256DigestAsHex(String text) {
MessageDigest md;
String encodedText = "";
try {
md = MessageDigest.getInstance("SHA-1");
md.update(text.getBytes(StandardCharsets.UTF_8));
encodedText = byte2Hex(md.digest());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return encodedText;
}
/**
* sha1 加密 将byte转为16进制
*
* @param bytes 字节数组
* @return 加密后的字符串
*/
private static String byte2Hex(byte[] bytes) {
StringBuilder builder = new StringBuilder();
String temp;
for (byte aByte : bytes) {
temp = Integer.toHexString(aByte & 0xFF);
if (temp.length() == 1) {
// 得到一位的进行补0操作
builder.append("0");
}
builder.append(temp);
}
return builder.toString();
}
}
-
运行程序,查看结果
-
无论明文多长,采用sha1加密之后的密文都是40位定长字符串;明文细微变化,密文天壤之别
5、采用sha224加密算法
- 在net.hw.common包里创建EncryptSHA224类
package net.hw.common;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Scanner;
/**
* 功能:SHA224加密
* 作者:xizaizhao
* 日期:2022年12月01日
*/
public class EncryptSHA224 {
public static void main(String[] args) {
// 声明变量
String plainText, cryptoText;
Scanner sc = new Scanner(System.in);
// 输入待加密字符串
System.out.print("输入待加密字符串:");
plainText = sc.nextLine();
// 采用SHA224加密算法进行加密
cryptoText = sha224DigestAsHex(plainText);
// 输出SHA224加密字符串
System.out.println("加密之后的字符串:" + cryptoText);
System.out.println("sha224加密字符串长度:" + cryptoText.length());
}
/**
* sha224加密
*
* @param text 待加密的字符串
* @return 加密后的字符串
*/
public static String sha224DigestAsHex(String text) {
MessageDigest md;
String encodedText = "";
try {
md = MessageDigest.getInstance("SHA-224");
md.update(text.getBytes(StandardCharsets.UTF_8));
encodedText = byte2Hex(md.digest());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return encodedText;
}
/**
* sha224加密 将byte转为16进制
*
* @param bytes 字节数组
* @return 加密后的字符串
*/
private static String byte2Hex(byte[] bytes) {
StringBuilder builder = new StringBuilder();
String temp;
for (byte aByte : bytes) {
temp = Integer.toHexString(aByte & 0xFF);
if (temp.length() == 1) {
// 得到一位的进行补0操作
builder.append("0");
}
builder.append(temp);
}
return builder.toString();
}
}
-
运行程序,查看结果
-
无论明文多长,采用sha224加密之后的密文都是56位定长字符串;明文细微变化,密文天壤之别