介绍
界面采用了Semantic ui框,用thymeleaf模板引擎进行渲染。
用户注册时,所要填写的内容主要有用户名,昵称,密码、邮箱,以及验证码。如下图所示。填写完整后,按照实现制定的规则对表单进行校验,如果交过通过,则向后端发送注册信息。完成注册工作。
代码如下,这里就只展示注册信息填写部分的代码了。完整代码到 github。上看。
<div class="ui five column centered stackable grid">
<div class="ui column m-margin-top-large " style="min-width: 480px">
<div class="ui container m-margin">
<h2 class="ui center aligned header m-text m-teal">用户注册</h2>
</div>
<div class="ui container m-shadow-small">
<form class="ui form" method="post" action="#">
<div class="ui segment">
<div class="field">
<div class="ui left icon input">
<i class="user icon"></i>
<input type="text" name="username" class="tooltip" placeholder="用户名"
data-content="由6-16个字母或数字组成,必须以字母开头">
</div>
</div>
<div class="field">
<div class="ui left icon input">
<i class="tag icon"></i>
<input type="text" name="nickname" class="tooltip" placeholder="昵称" data-content="不能为空">
</div>
</div>
<div class="field">
<div class="ui left icon input">
<i class="lock icon"></i>
<input type="password" name="password" class="tooltip" placeholder="密码"
data-content="长度必须为8-16个字符">
</div>
</div>
<div class="field">
<div class="ui left icon input">
<i class="lock icon"></i>
<input type="password" name="repeatpassword" class="tooltip" placeholder="确认密码">
</div>
</div>
<div class="field">
<div class="ui left icon input">
<i class="envelope icon"></i>
<input type="email" name="email" class="tooltip" placeholder="邮箱">
</div>
</div>
<div class="field container">
<div class="ui two column grid">
<div class="ui column">
<div class="ui left icon input">
<i class="check icon"></i>
<input type="text" name="checkcode" class="tooltip" placeholder="验证码"
data-content="请填写验证码">
</div>
</div>
<div class="ui column">
<a href="javascript:void(0)" id="checkCode"><img src="static/img/checkcode.png"
th:src="@{/user/checkCode}"
class="rounded checkcode tooltip"
data-content="点击刷新验证码" alt=""></a>
</div>
</div>
</div>
<button id="register-btn" class="ui fluid large teal button" type="button">注 册</button>
</div>
</form>
</div>
<div class="ui container m-margin-top-small">
<div class="ui bottom attached warning message container center aligned">
<i class="icon help"></i>
已经有账号了? <a href="#" th:href="@{/login}">这里登录</a>。
</div>
</div>
</div>
</div>
表单校验
Semantic UI提供了表单校验的API,可以通过调用.form()
方法,传入指定参数来完成表单校验。用法如下。
先用选择器获取表单对象,调用.form()
方法。如果要将提示信息几种到一起显示的话,需要在表单中添加一个带有.error.message
的元素,例如
<form class="ui form">
。。。。。。。。。
<div class"ui error message">
</div>
</form>
键inline
表示显示错误提示的方式,默认是false,将会显示在同一行。
fields
的值对应了要进行校验的对象,具体解释看代码中的注释
$('.ui.form').form({
inline: true,// 默认为false
fields: {
name: { //name值可以任意,不重复就行
identifier: xxx, //identifier 需要填写校验字段的name
rules: [// rules指定校验的规则,值为一个数组,数组中每个元素为json格式,可以传入多个
{
type: 'typename', // 这里需要填写校验的类型。 可以选择semantic ui提供的,也可以用自己自定义,如何自定义在下面代码会演示
prompt: '提示信息' // 当校验失败是,可以给出相应的提示信息。
}
]
}
}
})
inline
值为false时的效果
表单校验的使用
-
regExp
:进行正则表达式校验,需要传入一个值,即正则表达式。 -
mathch[identifier]
:对比两个输入是否一样。identifier为对比对象的name。 -
empty
:判断输入是否为空。 -
email
:判断输入的email格式是否合法。
$('.ui.form').form({
// inline: true,
fields: {
password: {
identifier: 'password',
rules: [
{
type: 'regExp', //
value: /^\w{8,16}$/i,
prompt: '密码不合法,请重新输入'
}
]
},
repeatpassword: {
identifier: 'repeatpassword',
rules: [
{
type: 'match[password]',
prompt: '密码不匹配'
}
]
},
nickname: {
identifier: 'nickname',
rules: [
{
type: 'empty',
prompt: '昵称不能为空'
}
]
},
username: {
identifier: 'username',
rules: [
{
type: 'regExp',
value: /^[a-zA-Z]\w{5,15}$/i,
prompt: '用户名不合法'
},
{
type: 'checkUsername',
prompt: '用户名已经被注册 <a href=[[@{/login}]]>点击登录?</a> '
}
]
},
email: {
identifier: 'email',
rules: [
{
type: 'email',
prompt: '请输入合法的邮箱'
},
{
type: 'checkEmail',
prompt: '邮箱已经注册, <a href=[[@{/login}]]>点击登录?</a> '
}
]
},
checkcode: {
identifier: 'checkcode',
rules: [
{
type: 'empty',
prompt: '请填写验证码'
},
{
type: 'checkCode',
prompt: '验证码填写错误'
}
]
}
}
})
除了使用semantic UI官方提供的验证方法外,我们也可以自己定义,向上面代码中 checkUsername
和checkCode
就是使用自定的规则。
自定义规则方式如下:
以$.fn.form.settings.rules.
开头,最后接一个方法名,然后定义一个匿名函数。在函数题中,编写判断逻辑。返回true
表示验证通过,返回false
则为验证失败。
在对邮箱进行校验时,要判断邮箱是否已经被注册了,所以在用ajax发送post请求时,要把异步给关闭了才行。
$.fn.form.settings.rules.checkEmail = function () {
var email = $('[name="email"]').val();
// console.log(email);
var flag = false;
$.post({
url: '[[@{/user/findEmail}]]', // 获取验证信息的url,可以自行更换
async: false,
data: {
'email': email
},
success: function (data) {
// console.log(data);
flag = data.flag;
}
})
return flag;
}
$.fn.form.settings.rules.checkUsername = function () {
var username = $('[name="username"]').val();
// console.log(username);
var flag = false;
$.post({
url: '[[@{/user/findUsername}]]',
async: false,
data: {
'userName': username
},
success: function (data) {
flag = data.flag;
}
})
return flag;
}
验证码的获取
验证是通过后端返回的一个图片信息。验证码图片是通过一个图片生成器的工具类生成验证码信息,然后返回给前端,验证码的值用session保存。
生成验证码的工具类是从网上找的,代码如下
package cn.jxj4869.blog.utils;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import javax.imageio.ImageIO;
public class CheckCodeGenerator {
private static int width = 90;// 定义图片的width
private static int height = 20;// 定义图片的height
private static int codeCount = 4;// 定义图片上显示验证码的个数
private static int xx = 15;
private static int fontHeight = 18;
private static int codeY = 16;
private static char[] codeSequence = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R',
'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
/**
* 生成一个map集合
* code为生成的验证码
* codePic为生成的验证码BufferedImage对象
* @return
*/
public static Map<String,Object> generateCodeAndPic() {
// 定义图像buffer
BufferedImage buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// Graphics2D gd = buffImg.createGraphics();
// Graphics2D gd = (Graphics2D) buffImg.getGraphics();
Graphics gd = buffImg.getGraphics();
// 创建一个随机数生成器类
Random random = new Random();
// 将图像填充为白色
gd.setColor(Color.WHITE);
gd.fillRect(0, 0, width, height);
// 创建字体,字体的大小应该根据图片的高度来定。
Font font = new Font("Fixedsys", Font.BOLD, fontHeight);
// 设置字体。
gd.setFont(font);
// 画边框。
gd.setColor(Color.BLACK);
gd.drawRect(0, 0, width - 1, height - 1);
// 随机产生40条干扰线,使图象中的认证码不易被其它程序探测到。
gd.setColor(Color.BLACK);
for (int i = 0; i < 30; i++) {
int x = random.nextInt(width);
int y = random.nextInt(height);
int xl = random.nextInt(12);
int yl = random.nextInt(12);
gd.drawLine(x, y, x + xl, y + yl);
}
// randomCode用于保存随机产生的验证码,以便用户登录后进行验证。
StringBuffer randomCode = new StringBuffer();
int red = 0, green = 0, blue = 0;
// 随机产生codeCount数字的验证码。
for (int i = 0; i < codeCount; i++) {
// 得到随机产生的验证码数字。
String code = String.valueOf(codeSequence[random.nextInt(36)]);
// 产生随机的颜色分量来构造颜色值,这样输出的每位数字的颜色值都将不同。
red = random.nextInt(255);
green = random.nextInt(255);
blue = random.nextInt(255);
// 用随机产生的颜色将验证码绘制到图像中。
gd.setColor(new Color(red, green, blue));
gd.drawString(code, (i + 1) * xx, codeY);
// 将产生的四个随机数组合在一起。
randomCode.append(code);
}
Map<String,Object> map =new HashMap<String,Object>();
//存放验证码
map.put("code", randomCode);
//存放生成的验证码BufferedImage对象
map.put("codePic", buffImg);
return map;
}
public static void main(String[] args) throws Exception {
//创建文件输出流对象
OutputStream out = new FileOutputStream(System.getProperty("user")+System.currentTimeMillis()+".jpg");
Map<String,Object> map = CheckCodeGenerator.generateCodeAndPic();
ImageIO.write((RenderedImage) map.get("codePic"), "jpeg", out);
System.out.println("验证码的值为:"+map.get("code"));
}
}
controller类
package cn.jxj4869.blog.controller;
import cn.jxj4869.blog.utils.CheckCodeGenerator;
import javax.imageio.ImageIO;
。。。。。。。。。。。。
/**
* @author jxj4869
* @since 2020-05-06
*/
@Controller
@RequestMapping("/user")
public class UserController {
@GetMapping("/checkCode")
public void checkCode(HttpServletResponse response, HttpSession session) throws IOException {
Map<String, Object> map = CheckCodeGenerator.generateCodeAndPic();
session.setAttribute("checkCode", map.get("code").toString());
ImageIO.write((RenderedImage) map.get("codePic"), "PNG", response.getOutputStream());
}
}
用户登录部分
<div class="ui five column centered stackable grid">
<div class="ui column m-margin-top-large " style="min-width: 480px">
<div class="ui error message" th:if="${msg!=null}" th:text="${msg}"></div>
<div class="ui container m-margin">
<h2 class="ui center aligned header m-text m-teal">用户登录</h2>
</div>
<div class="ui container m-shadow-small">
<form class="ui large form" method="post" action="#">
<div class="ui segment">
<div class="field">
<div class="ui left icon input">
<i class="user icon"></i>
<input type="text" name="username" placeholder="用户名">
</div>
</div>
<div class="field">
<div class="ui left icon input">
<i class="lock icon"></i>
<input type="password" name="password" placeholder="密码">
</div>
</div>
<div class="field container">
<div class="ui two column grid">
<div class="ui column">
<div class="ui left icon input">
<i class="check icon"></i>
<input type="text" name="checkcode" placeholder="验证码">
</div>
</div>
<div class="ui column">
<a href="javascript:void(0)" id="checkCode"><img src="static/img/checkcode.png"
th:src="@{/user/checkCode}"
class="rounded checkcode tooltip"
data-content="点击刷新验证码" alt=""></a>
</div>
</div>
</div>
<button id="login-btn" class="ui fluid large teal button" type="button">登 录</button>
</div>
</form>
</div>
<div class="ui container">
<div class="ui bottom attached warning message container center aligned">
<i class="icon help"></i>
新用户? <a href="#" th:href="@{/register}">这里注册</a>。
</div>
</div>
</div>
</div>
表单校验部分
$.fn.form.settings.rules.checkCode = function () {
var checkcode = $('[name="checkcode"]').val();
var flag = false;
$.post({
url: '[[@{/user/checkCode}]]',
async: false,
data: {
'checkCode': checkcode
},
success: function (data) {
flag = data.flag;
}
})
return flag;
}
$('.ui.form').form({
inline:true,
keyboardShortcuts:false,
fields:{
username:{
identifier:'username',
on:`blur`,
rules:[
{
type:'empty',
prompt:'请输入用户名'
}
]
},
password:{
identifier: 'password',
rules:[
{
type:'empty',
prompt:'请输入密码'
}
]
},
checkcode:{
identifier: 'checkcode',
rules:[
{
type:'checkCode',
prompt:'验证码填写错误'
}
]
},
}
})
完整源码
源码已上传到 github。