Spring shiro + bootstrap + jquery.validate 實(shí)現(xiàn)登錄、注冊功能
之前的文章中我們已經(jīng)搭建好框架,并且設(shè)計(jì)好了,數(shù)據(jù)庫。
現(xiàn)在我們開始實(shí)現(xiàn)登錄功能,這個(gè)可以說是Web應(yīng)用最最最普遍的功能了。
先來說說我們登錄的邏輯:
輸入用戶名、密碼(validate進(jìn)行前端驗(yàn)證)——ajax調(diào)用后臺(tái)action方法——根據(jù)用戶名調(diào)用業(yè)務(wù)層到數(shù)據(jù)層查詢數(shù)據(jù)庫信息——查詢的密碼跟用戶輸入的密碼比對——shiro登錄身份驗(yàn)證——將用戶信息存入session——響應(yīng)前端——前端跳轉(zhuǎn)
這個(gè)是我要告訴大家的姿勢,還有很多很多的姿勢。下面我們來看具體的代碼。
首先前端驗(yàn)證,這里使用了jquery.validate來進(jìn)行驗(yàn)證,jquery.validate的使用很簡單,這里我們說說存js的方式:
$().ready(function() {
/**登錄驗(yàn)證**/
$("#login_form").validate({
rules: {
loginAccount: "required",
loginPass: {
required: true,
minlength: 5
},
},
messages: {
loginAccount: "請輸入姓名",
loginPass: {
required: "請輸入密碼",
minlength: jQuery.format("密碼不能小于{0}個(gè)字 符")
},
},
submitHandler:function(form){
$.ajax({
dataType : "json",
url : "sysuser/login.action",
type : "post",
data : $("#login_form").serialize(),
success : function(data) {
$.alert(data.message);
if(data.success){
window.location.href = 'page/main.action';
}
},
error : function (e){
var d = e.responseJSON;
if(d){
$.alert(d.message);
}
}
});
return false; //阻止form提交
}
});
/**注冊驗(yàn)證**/
$("#register_form").validate({
rules: {
loginAccount:{
required:true,
remote: {
url: "sysuser/getUserNameCount.action",
type: "post",
dataType: "json",
data: {
loginAccount: function () {
return $("#register_account").val();
}
},
dataFilter: function (data) { //判斷控制器返回的內(nèi)容
data = jQuery.parseJSON(data);
return data.success;
}
}
},
loginPass: {
required: true,
minlength: 5,
maxlength:20
},
rloginPass: {
equalTo: "#register_password"
},
userEmail: {
required: true,
email: true,
remote: {
url: "sysuser/getEMailCount.action",
type: "post",
dataType: "json",
data: {
email: function () {
return $("#register_email").val();
}
},
dataFilter: function (data) { //判斷控制器返回的內(nèi)容
data = jQuery.parseJSON(data);
return data.success;
}
}
}
},
messages: {
loginAccount:{
required: "請輸入姓名",
remote: "用戶名已存在"
},
loginPass: {
required: "請輸入密碼",
minlength: jQuery.format("密碼不能小于{0}個(gè)字 符"),
maxlength: jQuery.format("密碼不能大于{0}個(gè)字 符"),
},
rloginPass: {
required: "請輸入確認(rèn)密碼",
equalTo: "兩次密碼不一樣"
},
userEmail: {
required: "請輸入郵箱",
email: "請輸入有效郵箱",
remote: "郵箱已存在"
}
},
submitHandler:function(form){
$.ajax({
dataType : "json",
url : "sysuser/register.action",
type : "post",
data : $("#register_form").serialize(),
success : function(data) {
$.alert(data.message);
if(data.success){
window.location.href = 'page/main.action';
}
},
error : function (e){
var d = e.responseJSON;
if(d){
$.alert(d.message);
}
}
});
return false; //阻止form提交
}
});
/**隱藏顯示登錄注冊**/
$("#register_btn").click(function() {
$("#register_form").css("display", "block");
$("#login_form").css("display", "none");
});
$("#back_btn").click(function() {
$("#register_form").css("display", "none");
$("#login_form").css("display", "block");
});
});
html頁面:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<c:set var="contextPath" value="${pageContext.request.contextPath}"></c:set>
<!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">
<meta name="description" content="">
<meta name="author" content="">
<title>主頁</title>
<!-- Bootstrap core CSS -->
<link href="${contextPath }/static/bootstrap/css/bootstrap.min.css" rel="external nofollow" rel="stylesheet">
<link href="${contextPath }/static/bootstrap/css/font-awesome.min.css" rel="external nofollow" rel="stylesheet">
<link href="${contextPath }/static/alert/jquery-confirm.min.css" rel="external nofollow" rel="stylesheet">
<style type="text/css">
body {
background: url(${contextPath }/static/img/login/bg.jpg) no-repeat;
background-size: cover;
font-size: 16px;
}
.form {
background: rgba(255, 255, 255, 0.2);
width: 400px;
margin: 100px auto;
}
#login_form {
display: block;
}
#register_form {
display: none;
}
.fa {
display: inline-block;
top: 27px;
left: 6px;
position: relative;
color: #ccc;
}
input[type="text"], input[type="password"] {
padding-left: 26px;
}
.checkbox {
padding-left: 21px;
}
</style>
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="${contextPath }/static/bootstrap/html5shiv/html5shiv.js"></script>
<script src="${contextPath }/static/bootstrap/respond/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="container">
<div class="form row">
<form class="form-horizontal col-sm-offset-3 col-md-offset-3" id="login_form">
<h3 class="form-title">登錄</h3>
<div class="col-sm-9 col-md-9">
<div class="form-group">
<i class="fa fa-user fa-lg"></i> <input
class="form-control required" type="text" placeholder="請輸入賬號(hào)"
name="loginAccount" autofocus="autofocus" maxlength="20" />
</div>
<div class="form-group">
<i class="fa fa-lock fa-lg"></i> <input
class="form-control required" type="password"
placeholder="請輸入密碼" name="loginPass" maxlength="8" />
</div>
<div class="form-group">
<label class="checkbox"> <input type="checkbox"
name="rememberMe" value="1" /> 記住我
</label>
<hr />
<a href="javascript:;" rel="external nofollow" id="register_btn" class="">注冊?</a>
</div>
<div class="form-group">
<input type="submit" class="btn btn-success pull-right" value="登錄 " />
</div>
</div>
</form>
</div>
<div class="form row">
<form class="form-horizontal col-sm-offset-3 col-md-offset-3" id="register_form">
<h3 class="form-title">注冊</h3>
<div class="col-sm-9 col-md-9">
<div class="form-group">
<i class="fa fa-user fa-lg"></i> <input
class="form-control required" type="text" placeholder="請輸入賬號(hào)"
name="loginAccount" autofocus="autofocus" id="register_account" />
</div>
<div class="form-group">
<i class="fa fa-lock fa-lg"></i> <input
class="form-control required" type="password"
placeholder="請輸入密碼" id="register_password" name="loginPass" />
</div>
<div class="form-group">
<i class="fa fa-check fa-lg"></i> <input
class="form-control required" type="password"
placeholder="請輸入確認(rèn)密碼" name="rloginPass" />
</div>
<div class="form-group">
<i class="fa fa-envelope fa-lg"></i> <input
class="form-control eamil" type="text" placeholder="Email"
name="userEmail" id="register_email"/>
</div>
<div class="form-group">
<input type="submit" class="btn btn-success pull-right"
value="注冊" /> <input type="submit"
class="btn btn-info pull-left" id="back_btn" value="返回" />
</div>
</div>
</form>
</div>
</div>
<script type="text/javascript" src="${contextPath }/static/jquery/jquery.min.js"></script>
<script type="text/javascript" src="${contextPath }/static/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="${contextPath }/static/alert/jquery-confirm.min.js" ></script>
<script type="text/javascript" src="${contextPath }/static/jquery/jquery.validate.min.js" ></script>
<script type="text/javascript" src="${contextPath }/static/login/login.js" ></script>
</body>
</html>
在$("#login_form").validate({...})方法中,login_form為你要驗(yàn)證的form的id;rules為要驗(yàn)證的字段;messages為要提示的內(nèi)容,如果不填寫,則會(huì)提示默認(rèn)信息;submitHandler為點(diǎn)擊提交(submit)按鈕后的回調(diào)方法,這里面最后的return false是為了阻止form表單的提交,因?yàn)槲疫@里要用ajax的方式提交;在注冊中的loginAccount字段有一個(gè)屬性remote這個(gè)是為了做ajax驗(yàn)證的,在沒有提交表單之前,我們就驗(yàn)證用戶輸入的用戶名是否在系統(tǒng)中已經(jīng)存在。
我們在編程總,發(fā)現(xiàn)總是會(huì)有那么幾個(gè)方法在相同的代碼層總用到,比如在控制層中獲取用戶session,或者輸出響應(yīng)信息等;在dao層中調(diào)用Hibernate的save方法,update方法,delete方法等。所以我們應(yīng)該在框架搭建的初期去建立一些通用的工具類或者是Base方法,下面我們新建BaseController方法,并且讓后面的控制器都來繼承它。
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.web.bind.annotation.ModelAttribute;
import com.fasterxml.jackson.core.JsonEncoding;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;
import yfkj.gz.task.entity.SysUser;
import yfkj.gz.task.util.Result;
/**
* 父類控制器
* @author 胡漢三
* @date 2017年1月9日 下午5:23:52
*/
@SuppressWarnings("deprecation")
public class BaseController{
public static final String USER_SESSION = "USER_SESSION";
protected static ObjectMapper mapper = new ObjectMapper();
protected static JsonFactory factory = mapper.getJsonFactory();
protected static Result result = new Result();
protected HttpServletRequest request;
protected HttpServletResponse response;
protected HttpSession session;
@ModelAttribute
public void setReqAndRes(HttpServletRequest request, HttpServletResponse response){
this.request = request;
this.response = response;
this.session = request.getSession();
}
/**將json字符串輸出**/
protected void writeJSON(String json) throws IOException {
response.setContentType("text/html;charset=utf-8");
response.getWriter().write(json);
}
/**將對象轉(zhuǎn)成json輸出**/
protected void writeJSON(Object obj) throws IOException {
response.setContentType("text/html;charset=utf-8");
JsonGenerator responseJsonGenerator = factory.createJsonGenerator(response.getOutputStream(), JsonEncoding.UTF8);
responseJsonGenerator.writeObject(obj);
}
/**
* 獲得session用戶對象
* @return
*/
protected SysUser getUser(){
Object userObj = session.getAttribute(USER_SESSION);
if(userObj == null){
return null;
}
return (SysUser)userObj;
}
}
用戶的控制器SysUserController:
package yfkj.gz.task.controller;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import javax.annotation.Resource;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import yfkj.gz.task.entity.SysRole;
import yfkj.gz.task.entity.SysUser;
import yfkj.gz.task.service.ISysRoleService;
import yfkj.gz.task.service.ISysUserService;
import yfkj.gz.task.util.DateUtil;
import yfkj.gz.task.util.StringUtils;
import yfkj.gz.support.BTView;
import yfkj.gz.support.controller.BaseController;
/**
* 用戶控制器
* @author 胡漢三
* @date 2017年1月16日 下午2:31:39
*/
@Controller
@RequestMapping("/sysuser")
public class SysUserController extends BaseController{
@Resource
private ISysUserService userService;
@Resource
private ISysRoleService roleService;
/**
* 分頁查詢用戶
* @param response
* @param user
* @param btView
* @throws IOException
*/
@RequestMapping(value = "/findUser", method = { RequestMethod.POST, RequestMethod.GET })
public void findUser(SysUser user,BTView<SysUser> btView) throws IOException{
List<SysUser> list = userService.findSysUserPage(btView, null);
btView.setRows(list);
super.writeJSON(btView);
}
/**
* 用戶登錄
* @param response
* @param user
* @throws IOException
*/
@RequestMapping(value = "/login", method = { RequestMethod.POST, RequestMethod.GET })
public void login(SysUser user,boolean rememberMe) throws IOException{
//用戶登錄
SysUser userInfo = userService.getByProerties(new String[]{"loginAccount"}, new String[]{user.getLoginAccount()},null);
if(userInfo==null){
result.setMessage("用戶名錯(cuò)誤");
super.writeJSON(result);
return;
}
if(!userInfo.getLoginPass().equals(new Sha256Hash(user.getLoginPass()).toHex())){
result.setMessage("密碼錯(cuò)誤");
super.writeJSON(result);
return;
}
//存入session
Subject subject = SecurityUtils.getSubject();
//記得傳入明文密碼
subject.login(new UsernamePasswordToken(userInfo.getLoginAccount(), user.getLoginPass(), rememberMe));
session.setAttribute(USER_SESSION, userInfo);
result.setMessage("登錄成功");
result.setSuccess(true);
super.writeJSON(result);
}
/**
* 用戶注冊
* @param response
* @param user
* @throws IOException
*/
@RequestMapping(value = "/register", method = { RequestMethod.POST, RequestMethod.GET })
public void register(SysUser user) throws IOException{
Long count = userService.getCountByProerties(new String[]{"loginAccount"}, new String[]{user.getLoginAccount()});
if(count>0){
result.setMessage("賬號(hào)已存在");
super.writeJSON(result);
return;
}
Long countEmail = userService.getCountByProerties(new String[]{"userEmail"}, new String[]{user.getUserEmail()});
if(countEmail>0){
result.setMessage("郵箱已存在");
super.writeJSON(result);
return;
}
try{
//注冊時(shí)間
user.setRegisterTime(DateUtil.getDateTime(new Date()));
//Sha256Hash加密
user.setLoginPass(new Sha256Hash(user.getLoginPass()).toHex());
//默認(rèn)為注冊用戶
SysRole role = roleService.getByProerties(new String[]{"roleKey"},new String[]{"ROLE_USER"},null);
user.getRoles().add(role);
userService.save(user);
//存入session
Subject subject = SecurityUtils.getSubject();
subject.login(new UsernamePasswordToken(user.getLoginAccount(), user.getLoginPass()));
session.setAttribute(USER_SESSION, user);
result.setMessage("注冊成功");
result.setSuccess(true);
}catch(Exception e){
result.setMessage("注冊失敗");
}
super.writeJSON(result);
}
/**
* 判斷用戶賬號(hào)是否已存在
* @param response
* @param user
* @throws IOException
*/
@RequestMapping(value = "/getUserNameCount", method = { RequestMethod.POST, RequestMethod.GET })
public void getUserNameCount(String loginAccount) throws IOException{
result.setSuccess(false);
if(StringUtils.isBlank(loginAccount)){
result.setMessage("賬號(hào)不能為空");
super.writeJSON(result);
return;
}
Long count = userService.getCountByProerties(new String[]{"loginAccount"}, new String[]{loginAccount});
if(count>0){
result.setMessage("賬號(hào)已存在");
}else{
result.setSuccess(true);
result.setMessage("該賬號(hào)可用");
}
super.writeJSON(result);
}
/**
* 判斷用戶郵箱是否已存在
* @param response
* @param email
* @throws IOException
*/
@RequestMapping(value = "/getEMailCount", method = { RequestMethod.POST, RequestMethod.GET })
public void getEMailCount(String email) throws IOException{
result.setSuccess(false);
if(StringUtils.isBlank(email)){
result.setMessage("郵箱不能為空");
super.writeJSON(result);
return;
}
Long count = userService.getCountByProerties(new String[]{"userEmail"}, new String[]{email});
if(count>0){
result.setMessage("郵箱已存在");
}else{
result.setSuccess(true);
result.setMessage("該郵箱可用");
}
super.writeJSON(result);
}
// 登出
@RequestMapping("/logout")
public void logout() throws IOException {
//退出權(quán)限驗(yàn)證
SecurityUtils.getSubject().logout();
//銷毀session
session.invalidate();
response.sendRedirect(request.getContextPath()+"/login.jsp");
}
}
至此,登錄跟注冊就OK啦!


其中還使用到啦jquery-confirm.js,這是一個(gè)彈出框的插件:點(diǎn)擊查看
源碼地址:https://git.oschina.net/gzsjd/task
以上所述是小編給大家介紹的Spring shiro + bootstrap + jquery.validate 實(shí)現(xiàn)登錄、注冊功能,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
- Spring MVC+mybatis實(shí)現(xiàn)注冊登錄功能
- IDEA實(shí)現(xiàn) springmvc的簡單注冊登錄功能的示例代碼
- springboot實(shí)現(xiàn)注冊加密與登錄解密功能(demo)
- SpringBoot實(shí)現(xiàn)登錄注冊常見問題解決方案
- Spring boot+mybatis+thymeleaf 實(shí)現(xiàn)登錄注冊增刪改查功能的示例代碼
- springboot+VUE實(shí)現(xiàn)登錄注冊
- SpringBoot+Mybatis實(shí)現(xiàn)登錄注冊的示例代碼
- Spring MVC登錄注冊以及轉(zhuǎn)換json數(shù)據(jù)
- Android使用OKhttp3實(shí)現(xiàn)登錄注冊功能+springboot搭建后端的詳細(xì)過程
- 基于Spring5實(shí)現(xiàn)登錄注冊功能
相關(guān)文章
jquery實(shí)現(xiàn)頂部向右伸縮的導(dǎo)航區(qū)域代碼
這篇文章主要介紹了jquery實(shí)現(xiàn)頂部向右伸縮的導(dǎo)航區(qū)域代碼,涉及jquery鼠標(biāo)click點(diǎn)擊事件及頁面元素動(dòng)態(tài)操作的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-09-09
Jquery高級(jí)應(yīng)用Deferred對象原理及使用實(shí)例
這篇文章主要介紹了Jquery高級(jí)應(yīng)用Deferred對象原理及使用實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-05-05
基于jquery實(shí)現(xiàn)點(diǎn)擊左右按鈕圖片橫向滾動(dòng)
點(diǎn)擊左右按鈕圖片橫向滾動(dòng)jquery,一次滾動(dòng)四個(gè),圖片滾動(dòng)完成,自動(dòng)回到第一個(gè)版面,效果相當(dāng)不錯(cuò),感興趣的前端工程師們可以參考下2013-04-04
Jquery設(shè)置attr的disabled屬性控制某行顯示或者隱藏
這篇文章主要與大家分享Jquery設(shè)置attr的disabled屬性控制某行顯示或者隱藏的具體實(shí)現(xiàn),喜歡的朋友可以參考下2014-09-09
jQuery zTree樹插件動(dòng)態(tài)加載實(shí)例代碼
這篇文章主要介紹了jQuery zTree樹插件動(dòng)態(tài)加載效果的實(shí)例代碼,需要的朋友可以參考下2017-05-05
基于jQuery實(shí)現(xiàn)響應(yīng)式圓形圖片輪播特效
這篇文章主要介紹了基于jQuery實(shí)現(xiàn)響應(yīng)式圓形圖片輪播特效,mislider插件可以將圖片以圓形圖片顯示,然后使圖片無限循環(huán)形成輪播圖或旋轉(zhuǎn)木馬特效,感興趣的小伙伴們可以參考一下2015-11-11
基于jQuery實(shí)現(xiàn)動(dòng)態(tài)搜索顯示功能
這篇文章主要介紹了基于jQuery實(shí)現(xiàn)動(dòng)態(tài)搜索顯示功能的相關(guān)資料,輸入數(shù)值自動(dòng)匹配相關(guān)信息,感興趣的小伙伴們可以參考一下2016-05-05
基于jQuery實(shí)現(xiàn)簡單人工智能聊天室
這篇文章主要為大家詳細(xì)介紹了基于jQuery實(shí)現(xiàn)簡單人工智能聊天室的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-02-02
jQuery獲取checkboxlist的value值的方法
最近著手一個(gè)項(xiàng)目用到了服務(wù)器空間checkboxlist ,使用起來是方便,可以想要從js獲取值就稍微麻煩點(diǎn)了,google后找到了如下方法,感興趣的小伙伴們可以參考一下2015-09-09

