這一節講用戶管理界面設計。先想想用戶管理都要做什么,新增、修改、刪除、查詢用戶基本信息,密碼重置、加鎖、解鎖用戶,查詢用戶登錄記錄,姑且這么多,如果還有額外的要求,后期都可以加進去。
1、新建公共引用taglib.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
頁面開發中肯定要用到各種表達式語言,所以就用公共的jsp引進來,包括JSTL里面的C標簽,ftm函數標簽,還有Spring的form標簽,后續還會用到自定義標簽。
2、各頁面的編寫
這里面一共包括四個頁面:
1、index.jsp,管理頁面
2、add.jsp,新增頁面
3、update.jsp,修改頁面
4、login.jsp,用戶的登錄信息
都不是很復雜,下面主要講特殊一點的知識點。
3、自定義函數式標簽
開發中有些頁面的引用可能用在好多地方,這時候就需要自定義一些函數式標簽,常用的功能提前寫好,用到的時候以標簽的形式展示。比如用戶管理界面用戶狀態字段,數據庫存儲的是1正常,2鎖定,頁面展示的時候就需要顯示為漢字,更好看一些的話,正常是綠色,鎖定是紅色,加一些樣式,這時候標簽的好處就能體現出來了。
webtag.tld
在/webapp/WEB-INF/下面新建標簽配置文件webtag.tld
<?xml version="1.0" encoding="UTF-8" ?>
<taglib xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
version="2.0">
<tlib-version>1.0</tlib-version>
<short-name>critc</short-name>
<uri>http://www.critc.com/jsp/jstl/tags</uri>
<function>
<description>系統管理-用戶管理獲取用戶狀態</description>
<name>getUserStatus</name>
<function-class>com.critc.plat.util.web.WebTag</function-class>
<function-signature>java.lang.String getUserStatus(java.lang.Integer)</function-signature>
</function>
</taglib>
這里面首先定義標簽的版本號<tlib-version>
,縮寫名<short-name>
,及URI<uri>
,這樣在jsp頁面里面就可以引用該標簽了。
這里面定義了一個function
,里面四個配置項,<description>
標簽的描述,<name>
函數名,<function-class>
函數對應的類,需要寫全路徑,<function-signature>
函數簽名,需要寫清楚調用的是類里面的哪個方法,返回值是什么,這里面返回值和參數都需要時包裝類型,不能是原生類型。
WebTag.java
public class WebTag {
/**
* 獲取用戶狀態,系統管理-用戶管理用到
*
* @param user_status
* @return
*/
public static String getUserStatus(Integer user_status) {
if (user_status == 1)
return "<span class=\"label label-success arrowed\">正常</span>";
else if (user_status == 2)
return "<span class=\"label label-warning arrowed\">已鎖定</span>";
else
return "";
}
}
taglib.jsp增加引用
<%@ taglib prefix="critc" uri="http://www.critc.com/jsp/jstl/tags"%>
index.jsp中的具體使用
${critc:getUserStatus(sysUser.status)}
很簡單吧,而且可以重復使用。
4、SiteMesh中自定義Tag
實際開發中頁面會有自定義的JS和CSS,這些JS和CSS需要按照格式要求放到指定位置,比如CSS放到header中,JS放到公共引用js的后面,這時候就需要自定義Tag了。
SiteMesh3.xml
<!-- 自定義標簽 -->
<content-processor>
<tag-rule-bundle class="com.critc.plat.core.tagrules.ScriptTagRuleBundle" />
<tag-rule-bundle class="com.critc.plat.core.tagrules.CssTagRuleBundle" />
</content-processor>
增加這樣兩句話,自定義位置包括javascript和css
ScriptTagRuleBundle.java和CssTagRuleBundle.java
public class ScriptTagRuleBundle implements TagRuleBundle {
@Override
public void install(State defaultState, ContentProperty contentProperty, SiteMeshContext siteMeshContext) {
defaultState.addRule("critc-script",
new ExportTagToContentRule(siteMeshContext, contentProperty.getChild("critc-script"), false));
}
@Override
public void cleanUp(State defaultState, ContentProperty contentProperty, SiteMeshContext siteMeshContext) {
}
}
這一段的代碼非常簡單,實現TagRuleBundle
接口,增加一個Tag 規則即可,這里定義為critc-script
decorator.jsp
<%@include file="../common/scripts.jspf" %>
<sitemesh:write property='critc-script'/>
這里就和定位body和header一樣,<sitemesh:write property='critc-script'/>
這句話就可以頁面定義的javascript放到最后。
index.jsp
<critc-script>
<script type="text/javascript">
///省略
</script>
</critc-script>
這里就和普通javascript
定義一樣,只不過在最外層包了一下<critc-script>
,原理一看就明白了。
5、自定義操作成功界面和失敗界面
每個按鈕操作成功后,比如新增、修改,需要告訴用戶操作成功了,然后跳轉回原先界面。一版這種場景有以下幾種方式:
1、alert以下或頁面上方、下方彈出一個tip,提示操作成功了,然后列表頁面刷新一下,常用于頁面無刷新的架構,比如easyUI、ext等
2、跳轉至成功頁面,提示操作成功,3秒后返回列表頁面,常用于互聯網界面。
這里選擇第二種方式。
SysUserController.java
@RequestMapping("/add")
public String add(HttpServletRequest request, HttpServletResponse response, SysUser sysUser) {
sysUser.setStatus(1);
int flag = sysUserService.add(sysUser);
if (flag == 0)
return "forward:/error.htm?msg=" + StringUtil.encodeUrl("用戶信息新增失敗");
else if (flag == 2)
return "forward:/error.htm?msg=" + StringUtil.encodeUrl("用戶賬號已存在");
else
return "forward:/success.htm?msg=" + StringUtil.encodeUrl("用戶信息新增成功");
}
操作成功或失敗,跳往對應界面,同時把操作結果,以msg的形式帶過去了。
更好的方式是以代碼或數字碼的方式傳過去,在SccessController或ErrorController再解析這些代碼具體對應的中文是什么。
SuccessController.java
@Controller
@RequestMapping("/")
public class SuccessController {
/**
* 成功處理操作
* @param request
* @param response
* @return
*/
@RequestMapping("/success")
public ModelAndView success(HttpServletRequest request, HttpServletResponse response) {
ModelAndView mv = new ModelAndView();
mv.setViewName("/plat/common/success");
mv.addObject("msg", StringUtil.decodeUrl(request.getParameter("msg")));
mv.addObject("backUrl", StringUtil.decodeUrl(request.getParameter("backUrl")));
return mv;
}
}
這一塊代碼很簡單啊,就是獲取msg
和backUrl
,并跳轉success.jsp
界面
success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ include file="../common/taglib.jsp" %>
<head>
<title>${webTitle }-操作成功</title>
</head>
<body>
<div class="breadcrumbs breadcrumbs-fixed" id="breadcrumbs">
<ul class="breadcrumb">
<li><i class="ace-icon fa fa-home home-icon"></i> <a href="${dynamicServer}/index.htm">首頁</a></li>
<li class="active">操作結果</li>
</ul>
</div>
<div class="page-content">
<div class="alert alert-success" style="text-align: center;">
<h4>
<i class="fa fa-check-circle"></i> ${msg }
</h4>
<a href="${backUrl}">如果你的瀏覽器沒有自動跳轉,請點擊此鏈接</a>
<script type="text/javascript">
setTimeout(function() {
location.href = "${backUrl}";
}, 2000);
</script>
</div>
</div>
</body>
</html>
具體效果
6、彈出框提示
在刪除用戶、鎖定等操作時,一定要提示用戶,這種情況下就需要提示框了。
bootbox.confirm("你確定要刪除該用戶嗎?", function (result) {
if (result) {
window.location = "delete.htm?id=" + id + "&backUrl=${backUrl}";
}
})
這里整合了bootbox,只需要一句話即可,還是很方便的。
7、SysUserSearchVO.java的作用域
寫java代碼的時候定義SysUserSearchVO這個類,用于獲取查詢條件,具體怎么用的呢,很多人會有疑問。
index請求方法
/**
* 進入用戶管理界面
*
* @return
*/
@RequestMapping("/index")
public ModelAndView index(HttpServletRequest request, HttpServletResponse response, SysUserSearchVO sysUserSearchVO) {
ModelAndView mv = new ModelAndView();
int recordCount = sysUserService.count(sysUserSearchVO);// 獲取查詢總數
String url = createUrl(sysUserSearchVO);
PageNavigate pageNavigate = new PageNavigate(url, sysUserSearchVO.getPageIndex(), recordCount);//定義分頁對象
List<SysUser> list = sysUserService.list(sysUserSearchVO);
mv.addObject("pageNavigate", pageNavigate);// 設置分頁的變量
mv.addObject("list", list);// 把獲取的記錄放到mv里面
mv.addObject("listRole", sysRoleService.list());// 角色列表
mv.setViewName("/plat/sys/user/index");// 跳轉至指定頁面
BackUrlUtil.createBackUrl(mv, request, url);// 設置返回url
return mv;
}
這里面SysUserSearchVO作為一個參數,由SpringMVC自動進行參數的包裝,就是說進入這個方法,SysUserSearchVO的各個參數都已經賦值了。
頁面傳值
// 查詢方法
var searchUser = function () {
var url = "index.htm?";
if ($("#txtUsername").val() != '')
url += "username=" + $("#txtUsername").val();
if ($("#txtRealname").val() != '')
url += "&realname=" + $("#txtRealname").val();
if ($("#cmbStatus").val() != '')
url += "&status=" + $("#cmbStatus").val();
if ($("#cmbRoleId").val() != '')
url += "&role_id=" + $("#cmbRoleId").val();
window.location = encodeURI(url);
}
頁面的傳值是通過拼請求的url,來實現的。包括分頁的鏈接也都是這種寫法。原理就是不管是查詢還是分頁,把所有參數都寫到url的參數里面,這樣不管怎么跳轉,參數是不會變的。一定要牢記,頁面查詢一定不要用用form的post方法,這樣分頁就無法post了。
8、表單校驗
這里表單校驗用的是jquery-validator,用起來還是比較簡單的。
引用jquery-validator
頁面校驗對應js
$("#userForm").validate({
errorElement: "label",
errorClass: "valiError",
errorPlacement: function (error, element) {
error.appendTo($("#" + element.attr('id') + "Tip"));
},
rules: {
username: {
required: true,
minlength: 4,
maxlength: 20,
remote: {
url: "checkUserExist.htm", //后臺處理程序
type: "post", //數據發送方式
//dataType: "json", //接受數據格式
data: { //要傳遞的數據
username: function () {
return $("#username").val();
}
}
}
},
realname: {
required: true,
maxlength: 20
},
mobile: {
required: true,
maxlength: 11
},
roleId: {
required: true
}
},
messages: {
username: {
remote: "賬號已存在!"
}
},
submitHandler: function (form) {
form.submit();
}
});
這里面在rules定義校驗規則,比如長度、是否為空、email、數字、ajax異步校驗等等。
提示信息
jquery-validator校驗表單如果出錯,默認是在該表單后面顯示錯誤信息,但是ACE里面需要設置一個默認的div,來定位錯誤信息的輸出。
生效代碼是這一段
errorElement: "label",
errorClass: "valiError",
errorPlacement: function (error, element) {
error.appendTo($("#" + element.attr('id') + "Tip"));
},
錯誤信息的標簽用label
,樣式class是valiError
,錯誤的位置是當前表單的id+Tip
,比如當前表單的id是username
,則錯誤提示的顯示位置為usernameTip
,所以在每個表單后面加了一句話<label id="usernameTip"></label>
jquery-validator功能非常豐富,還可以ajax異步校驗、自定義校驗方法等等,可以參見網上的教程
http://www.cnblogs.com/linjiqin/p/3431835.html
9、查看登錄歷史
用戶列表里面有一個鏈接,登錄歷史,點擊該鏈接,彈出框,顯示用戶的登錄歷史。
這里需要利用ajax的post的方法,請求整個頁面,加載進來放到bootstrap的model里面。
先看看具體代碼實現:
viewLoginHis
var viewLoginHis = function (id, title) {
$.post('searchUserLogin.htm', {
userId: id
}, function (html) {
$("#dialog-viewLogin").html(html);
var dialog = $("#dialog-viewLogin").removeClass('hide').dialog({
title: "【" + title + "】登錄歷史",
title_html: false,
width: 1000,
minHeight: 500,
position: {my: "center", at: "center", of: window},
modal: true,
buttons: [
{
text: "返回",
"class": "btn btn-minier btn-center",
click: function () {
$(this).dialog("close");
}
}
]
});
});
}
這是點擊鏈接的js代碼,post請求url
searchUserLogin java方法
/**
* 用戶登錄信息
*
* @param request
* @param response
*/
@RequestMapping("/searchUserLogin")
public ModelAndView searchUserLogin(HttpServletRequest request, HttpServletResponse response, SysUserloginSearchVO sysUserloginSearchVO) {
ModelAndView mv = new ModelAndView();
int recordCount = sysUserLoginService.count(sysUserloginSearchVO);// 獲取查詢總數
String url = createUserLoginUrl(sysUserloginSearchVO);
PageNavigate pageNavigate = new PageNavigate(url, sysUserloginSearchVO.getPageIndex(), recordCount);//
List<SysUserLogin> list = sysUserLoginService.list(sysUserloginSearchVO);
mv.addObject("pageNavigate", pageNavigate);// 設置分頁的變量
mv.addObject("list", list);// 把獲取的記錄放到mv里面
mv.setViewName("/plat/sys/user/login");// 跳轉至指定頁面
return mv;
}
這一塊和普通的請求controller代碼沒什么兩樣。
login.jsp
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8" %>
<%@ include file="../../common/taglib.jsp" %>
<c:if test="${empty list}">
<div class="row">
<div class="col-xs-12">暫無數據</div>
</div>
</c:if>
<c:if test="${!empty list && list.size() > 0}">
<div class="row">
<div class="col-xs-12">
<table id="simple-table" class="table table-striped table-bordered table-hover">
<thead>
<tr>
<th width=40>#</th>
<th width=140>登錄時間</th>
<th width="120">登錄IP</th>
<th>終端</th>
<th>瀏覽器類型</th>
<th>瀏覽器版本</th>
</tr>
</thead>
<tbody>
<c:forEach items="${list }" var="sysUserLogin" varStatus="st">
<tr>
<td>${st.index+1 }</td>
<td><fmt:formatDate value="${sysUserLogin.loginDate }" pattern="yyyy-MM-dd HH:mm"/></td>
<td>${sysUserLogin.loginIp }</td>
<td>${sysUserLogin.terminal }</td>
<td>${sysUserLogin.explorerType }</td>
<td>${sysUserLogin.explorerVersion}</td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
</div>
<div class="row">
<div class="col-xs-12" id="pageNavForward">${ pageNavigate.pageModel}</div>
</div>
</c:if>
<script type="text/javascript">
$(function() {
$("#pageNavForward").on('click', 'a', function(e) {
var $link = $(this);
var $container = $link.closest('.ui-dialog-content');
$container.load( $link.attr('href'));
return false;
});
$("#forward_div").css("max-height", $(window).height() - 300);
})
</script>
SiteMesh3.xml增加過濾項
searchUserLogin.htm
這個請求是不需要被裝飾的,所以需要過濾掉
<mapping path="/sys/user/searchUserLogin.htm" exclue="true" />
查看登錄歷史效果
效果.png
最終整體效果圖如下:
注意:
這一塊和java開發還不一樣,需要掌握的技能點比較多,主要是ACE框架的使用,div、css、html等相關代碼的編寫都需要了解,不能把自己僅僅定位于寫java代碼,要全面發展,前端的技能也都要掌握,這樣才能游刃有余!