今天我们完成框架的thymeleaf模板显示页面功能,页面的用户登陆,密码的AES加密解密,输错3次进行验证码验证功能,东西可能比较多,这个是我这两天在网上结合各种资源整合出来的,基本功能都已经实现,项目代码我会附在文章的最后面。
1.thymeleaf模板显示页面功能
简单说, Thymeleaf 是一个跟 Velocity、FreeMarker 类似的模板引擎,它可以完全替代 JSP 。相较与其他的模板引擎,它有如下三个极吸引人的特点:
a、Thymeleaf 在有网络和无网络的环境下皆可运行,即它可以让美工在浏览器查看页面的静态效果,也可以让程序员在服务器查看带数据的动态页面效果。这是由于它支持 html 原型,然后在 html 标签里增加额外的属性来达到模板+数据的展示方式。浏览器解释 html 时会忽略未定义的标签属性,所以 thymeleaf 的模板可以静态地运行;当有数据返回到页面时,Thymeleaf 标签会动态地替换掉静态内容,使页面动态显示。
b、Thymeleaf 开箱即用的特性。它提供标准和spring标准两种方言,可以直接套用模板实现JSTL、 OGNL表达式效果,避免每天套模板、该jstl、改标签的困扰。同时开发人员也可以扩展和创建自定义的方言。
c、Thymeleaf 提供spring标准方言和一个与 SpringMVC 完美集成的可选模块,可以快速的实现表单绑定、属性编辑器、国际化等功能。
下面在原有的项目框架中整合thymeleaf:
首先在pom.xml中添加thymeleaf的依赖
复制代码
org.thymeleaf
thymeleaf
3.0.9.RELEASE
org.thymeleaf
thymeleaf-spring4
3.0.9.RELEASE
org.springframework.boot
spring-boot-starter-thymeleaf
复制代码
在customer模块的resources下创建static、templates文件夹,如下:
在static下放置一些页面样式的js和css,在templates文件夹下放置html页面,此时在resources下的application.properties配置文件中配置thymeleaf,
复制代码
#thymelea模板配置
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.mode=HTML5
spring.thymeleaf.encoding=UTF-8
#热部署文件,页面不产生缓存,及时更新
spring.thymeleaf.cache=false
spring.resources.chain.strategy.content.enabled=true
spring.resources.chain.strategy.content.paths=/**
复制代码
此时thymeleaf模板就配置完成了。
2.页面的用户登陆,AES加密解密:
关于AES的加密解密,我的实现思路是:首先用户在浏览器中输入网址跳转到登录页面,此时在页面中已经保存了从后台传过来的key,该key值是后台随机生成的,后台session中保存key值,前台页面的隐藏框中也要保存key值,用于前端页面的密码加密以及后端的密码解密,页面刷新或用户名、密码输入错误时,都会重新生成新的key值来替换原有保存的key。
首先在pom.xml中添加依赖:
复制代码
com.alibaba
fastjson
1.2.28
commons-codec
commons-codec
1.10
复制代码
用AES加密解密
a.前端加密用到的js有:aes.js和mode-ecb-min.js,就为了下载这两个js花了我30个积分呢,[/哭],可以在static文件夹下创建一个aes文件夹,用于放置这两个js。js下载地址:https://download.csdn.net/download/weixin_38340967/10677798
在templates下创建login.html,代码如下:
复制代码
welcome
复制代码
这里有一个坑,就是在html页面中引入js的时候路径的问题,可以看到我在页面中是这样写的:,但是你仔细看应该是才对,为什么会少一个static呢,这是因为thymeleaf模板本身引入js时的路径就是默认在static下的,要是加上static反而页面会报js404错误,不信大家可以试试看。
var key = $('#KEY').val();
// alert("key的值是: "+key);
key = CryptoJS.enc.Utf8.parse(key);
// alert("加密后key的值是: "+key);
p = CryptoJS.enc.Utf8.parse($.trim(p));
var encrypted = CryptoJS.AES.encrypt(p, key, {mode:CryptoJS.mode.ECB,padding: CryptoJS.pad.Pkcs7});
param.password = encrypted.toString();
这段代码就是通过AES将用户输入的明文密码和后台传过来的key加密成密文,放到input框中提交到后台。
b.后台生成随机的key值,并将前台传过来的密文解密成明文密码,
这里要在common模块中写几个工具类:EncryptUtil用于密码的加密解密,Helper用于记录一些常量,RandomUtil用于随机生成key值,Result用于向前台返回一个结果对象,样式如下:
工具类代码如下:
EncryptUtil:
复制代码
package com.lj.common.util;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import sun.misc.BASE64Decoder;
import java.security.SecureRandom;
/**
* Created with IntelliJ IDEA.
* User: gaopeng
* Date: 2018/9/17 0017
* Time: 17:30
* Description:
*/
public class EncryptUtil {
private static final String KEY = "abcdefgabcdefg12";
private static final String ALGORITHMSTR = "AES/ECB/PKCS5Padding";
public static String base64Encode(byte[] bytes){
return Base64.encodeBase64String(bytes);
}
public static byte[] base64Decode(String base64Code) throws Exception{
return new BASE64Decoder().decodeBuffer(base64Code);
}
public static byte[] aesEncryptToBytes(String content, String encryptKey) throws Exception {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128);
Cipher cipher = Cipher.getInstance(ALGORITHMSTR);
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(encryptKey.getBytes(), "AES"));
return cipher.doFinal(content.getBytes("utf-8"));
}
public static String aesEncrypt(String content, String encryptKey) throws Exception {
return base64Encode(aesEncryptToBytes(content, encryptKey));
}
public static String aesDecryptByBytes(byte[] encryptBytes, String decryptKey) throws Exception {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG" );
secureRandom.setSeed(decryptKey.getBytes());
kgen.init(128,secureRandom);
Cipher cipher = Cipher.getInstance(ALGORITHMSTR);
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(decryptKey.getBytes(), "AES"));
byte[] decryptBytes = cipher.doFinal(encryptBytes);
return new String(decryptBytes);
}
public static String aesDecrypt(String encryptStr, String decryptKey) throws Exception {
return aesDecryptByBytes(base64Decode(encryptStr), decryptKey);
}
/**
* 测试
*
*/
public static void main(String[] args) throws Exception {
String content = "Test String么么哒"; //0gqIDaFNAAmwvv3tKsFOFf9P9m/6MWlmtB8SspgxqpWKYnELb/lXkyXm7P4sMf3e
System.out.println("加密前:" + content);
System.out.println("加密密钥和解密密钥:" + KEY);
String encrypt = aesEncrypt(content, KEY);
System.out.println(encrypt.length()+":加密后:" + encrypt);
String decrypt = aesDecrypt(encrypt, KEY);
System.out.println("解密后:" + decrypt);
}
}
复制代码
Helper:
复制代码
package com.lj.common.util;
/**
* Created with IntelliJ IDEA.
* User: gaopeng
* Date: 2018/9/17 0017
* Time: 17:08
* Description:
*/
public class Helper {
public static final String SESSION_CHECKCODE = "SESSION_CHECKCODE";
public static final String SESSION_LOGIN_TOKEN = "SESSION_LOGIN_TOKEN";
public static final String SESSION_USER = "SESSION_USER";
public static final String SESSION_LOGIN_FAILURE_COUNT = "SESSION_LOGIN_FAILURE_COUNT";
public static final String logTypeSecurity = "logTypeSecurity";
public static final Integer COUNT = 3;
}
复制代码
RandomUtil:
复制代码
package com.lj.common.util;
import java.util.Random;
/**
* Created with IntelliJ IDEA.
* User: gaopeng
* Date: 2018/9/17 0017
* Time: 17:22
* Description:
*/
public class RandomUtil {
public static final String ALLCHAR = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
public static final String LETTERCHAR = "abcdefghijkllmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
public static final String NUMBERCHAR = "0123456789";
/**
* 返回一个定长的随机字符串(只包含大小写字母、数字)
*
* @param length
* 随机字符串长度
* @return 随机字符串
*/
public static String generateString(int length) {
StringBuffer sb = new StringBuffer();
Random random = new Random();
for (int i = 0; i < length; i++) {
sb.append(ALLCHAR.charAt(random.nextInt(ALLCHAR.length())));
}
return sb.toString();
}
/**
* 返回一个定长的随机纯字母字符串(只包含大小写字母)
*
* @param length
* 随机字符串长度
* @return 随机字符串
*/
public static String generateMixString(int length) {
StringBuffer sb = new StringBuffer();
Random random = new Random();
for (int i = 0; i < length; i++) {
sb.append(LETTERCHAR.charAt(random.nextInt(LETTERCHAR.length())));
}
return sb.toString();
}
/**
* 返回一个定长的随机纯大写字母字符串(只包含大小写字母)
*
* @param length
* 随机字符串长度
* @re