管理系统前台样式统一布局
一、顶端标题
1、主标题要求加粗,主标题下的子页面要有副标题使用标签
<section class="content-header">
<h1>
<b>账号管理</b> <small>账号列表</small>
</h1>
</section>
二、内容
1、概述
内容分模块展示,以每个box为一个展示模块,每个box都有头部、内容和底部。
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">模块标题</h3>
</div>
<div class="box-body">
模块内容
</div>
<!-- /.box-body -->
<div class="box-footer">
模块底部
</div>
<!-- /.box-footer-->
</div>
2、搜索框
使用div form-group 排版,以form表单的class="form-horizontal"设置表单元素居中,box内容内嵌查询条件,提交按钮与查询条件都位于中间内容区,底部安置其他额外按钮。
<div class="box box-primary">
<div class="box-header with-border">
<h2 class="box-title">
<b>查询条件</b>
</h2>
</div>
<div class="box-body">
<form class="form-horizontal"
action="#" method="post">
<div class="row">
<div class="col-md-4">
<div class="form-group">
<label for="inputEmail3" class="col-sm-4 control-label">用户名:</label>
<div class="col-sm-8">
<input type="text" class="form-control" name="query"
value="${query[0] }">
</div>
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label for="inputEmail3" class="col-sm-4 control-label">联系人:</label>
<div class="col-sm-8">
<input type="text" class="form-control" name="query"
value="${query[1] }">
</div>
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label for="inputEmail3" class="col-sm-4 control-label">联系电话:</label>
<div class="col-sm-8">
<input type="text" class="form-control" name="query"
value="${query[2] }">
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-4">
<div class="form-group">
<label for="inputEmail3" class="col-sm-4 control-label">权限组:</label>
<div class="col-sm-8">
<select name="query" class="form-control">
<option value="">--选择权限组类型--</option>
<c:forEach items="${pGroups }" var="o">
<c:choose>
<c:when test="${o.id==query[3] }">
<option value="${o.id }" selected>${o.groupName }</option>
</c:when>
<c:otherwise>
<option value="${o.id }">${o.groupName }</option>
</c:otherwise>
</c:choose>
</c:forEach>
</select>
</div>
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<div class="col-sm-offset-4 col-sm-4">
<button type="submit" class="btn btn-primary btn-block">查 询</button>
</div>
</div>
</div>
</div>
</form>
</div>
<div class="box-footer">
<div class="row">
<div class="col-md-2">
<button type="button" class="btn btn-primary" data-toggle="modal"
data-target="#addAdminModal">添加管理员账号</button>
</div>
</div>
</div>
</div>
3、查询结果区
查询内容使用data-table安排布局,表格必须使用元素,选用。
<div class="box box-primary">
<div class="box-header with-border">
<h2 class="box-title">
<b>查询结果</b>
</h2>
</div>
<div class="box-box-body">
<table class="table table-bordered table-striped" id="userList">
<thead style="">
<tr>
<th>序号</th>
<th>用户名</th>
<th>密码</th>
<th>权限组</th>
<th>联系人</th>
<th>手机号</th>
<th>注册时间</th>
<th>登陆日志</th>
<th>拟登陆</th>
</tr>
</thead>
<tbody>
<c:forEach items="${pData.datas}" var="o" varStatus="status">
<tr>
<td>${status.count}</td>
<td>${o.userName }</td>
<td>${o.password }</td>
<td><c:forEach items="${pGroups }" var="p"
varStatus="status">
<c:choose>
<c:when test="${p.id==o.powergroupId }">
${p.groupName }
</c:when>
<c:otherwise></c:otherwise>
</c:choose>
</c:forEach></td>
<td>${o.contacts }</td>
<td>${o.mobilePhone }</td>
<td><fmt:formatDate value="${o.regTime }"
pattern="yyyy-MM-dd HH:mm:ss" /></td>
<td><a class="btn btn-primary"
href="${APP_PATH}/webSystem/loginLogList.action?userId=${o.id}">查看</a></td>
<td><button class="btn btn-primary"
onclick="login(${o.id},${o.userType })">登陆</button></td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
<div class="box-footer">
<form action="${APP_PATH }/webSystem/userList.action" method="post">
<input type="hidden" name="query" value="${query[0] }"> <input
type="hidden" name="query" value="${query[1] }"> <input
type="hidden" name="query" value="${query[2] }"> <input
type="hidden" name="query" value="${query[3] }">
${pagebar}
</form>
</div>
</div>
三、页面底部
<footer class="main-footer">
<div class="pull-right hidden-xs">
<b>版本</b> 1.0
</div>
<strong>主办单位 © <a href="#">*****</a>.技术支持 © <a>*******
</a></strong>
</footer>
四、其他配置
1、分页
(1)、自定义分页类:
import java.io.Serializable;
import java.util.List;
public class PaginationData implements Serializable{
/**
* 总行数
*/
private Integer total = 0;
/**
* 总页数
*/
private Integer totalPages;
/**
* 当前第几页
*/
private Integer currentPage = 1;
/**
* 每页条数
*/
private Integer pageSize = 10;
/**
* 查询记录
*/
private List datas = null;
private String paginationName = "paginator";
public String getPaginationHTML() {
StringBuffer str = new StringBuffer("<div class=\"pagination\" id=\"" + this.paginationName + "\">");
int prev = this.currentPage - 1;
int next = this.currentPage + 1;
str.append("<div class='btn-group'>");
if (this.currentPage > 1) {
str.append("<button class='btn btn-primary' name='firs' onclick='this.form." + this.paginationName
+ "_currentPage.value=1;this.form.submit();'/>首页</a>");
} else {
str.append("<button class='btn btn-primary' name='firs' disabled>首页</button>");
}
if (this.currentPage > 1) {
str.append("<button class='btn btn-primary' name='prev' onclick='this.form." + this.paginationName + "_currentPage.value="
+ prev + ";this.form.submit();'>上页</button>");
} else {
str.append("<button class='btn btn-primary' name='prev' disabled>上页</button>");
}
if (this.currentPage < this.totalPages) {
str.append("<button class='btn btn-primary' name='next' onclick='this.form." + this.paginationName + "_currentPage.value="
+ next + ";this.form.submit();'>下页</button>");
} else {
str.append("<button class='btn btn-primary' name='next' disabled>下页</button>");
}
if ((this.totalPages > 1) && (this.currentPage != this.totalPages)) {
str.append("<button class='btn btn-primary' name='last' onclick='this.form." + this.paginationName + "_currentPage.value="
+ this.totalPages + ";this.form.submit();'>末页</button>");
} else {
str.append("<button class='btn btn-primary' name='last' disabled>末页</button>");
}
str.append("</div>");
str.append("<span class=\"pagination-limits\" style=\"margin-left: 20px;\"><b>每页</b><SELECT style='height:34px;' name=\"pageSize\" id=\""
+ this.paginationName + "_pageSize\" onchange='this.form.submit();this.disabled=true;'");
if (getTotalPages() == 0) {
str.append(" disabled");
}
str.append(">");
if (this.pageSize == 10) {
str.append("<OPTION value=10 selected>10条</OPTION>");
} else {
str.append("<OPTION value=10>10 条</OPTION>");
}
if (this.pageSize == 20) {
str.append("<OPTION value=20 selected>20 条</OPTION>");
} else {
str.append("<OPTION value=20>20 条</OPTION>");
}
if (this.pageSize == 50) {
str.append("<OPTION value=50 selected>50 条</OPTION>");
} else {
str.append("<OPTION value=50>50 条</OPTION>");
}
if (this.pageSize == 72) {
str.append("<OPTION value=72 selected>72 条</OPTION>");
} else {
str.append("<OPTION value=72>72 条</OPTION>");
}
if (this.pageSize == 80) {
str.append("<OPTION value=80 selected>80 条</OPTION>");
} else {
str.append("<OPTION value=80>80 条</OPTION>");
}
if (this.pageSize == 96) {
str.append("<OPTION value=96 selected>96 条</OPTION>");
} else {
str.append("<OPTION value=96>96 条</OPTION>");
}
str.append("</SELECT></span>");
str.append("<span class=\"pagination-skip\" style=\"margin-left: 5px;\"> <b>转到</b>");
str.append("<SELECT style='height:34px;width:60px' name='currentPage' id='" + this.paginationName + "_currentPage' onchange='this.form.submit();this.disabled=true;'");
if (getTotalPages() == 0) {
str.append(" disabled");
}
str.append(">");
for (int i = 1; i < this.getTotalPages() + 1; i++) {
if (i == this.currentPage) {
str.append("<OPTION value=" + i + " selected>第" + i + "页</OPTION>");
} else {
str.append("<OPTION value=" + i + ">第" + i + "页</OPTION>");
}
}
str.append("</SELECT></span>");
str.append("<span class=\"pagination-count\" style=\"margin-left: 20px;\"><b> 总共" + this.getTotalPages() + "页," + getTotal() + "条记录</b></span>");
str.append("<INPUT type=hidden value=" + this.paginationName + " name=\"" + this.paginationName
+ ".paginationName\" id=\"" + this.paginationName + "_paginationName\"> ");
str.append("</div>");
return str.toString();
}
public int getPageSize() {
return this.pageSize;
}
public void setPageSize(Integer pageSize) {
this.pageSize = pageSize;
}
public Integer getTotalPages() {
return totalPages;
}
public Integer getCurrentPage() {
return currentPage;
}
public void setCurrentPage(Integer currentPage) {
this.currentPage = currentPage;
this.updateCurrentPage();
}
public Integer getTotal() {
return total;
}
public void setTotal(Integer total) {
if (this.pageSize != 0) {
this.totalPages = (total / this.pageSize);
if (total % this.pageSize != 0) {
this.totalPages += 1;
}
}
this.total = total;
this.updateCurrentPage();
}
private void updateCurrentPage(){
if(this.currentPage != null && this.totalPages != null && currentPage > this.totalPages) {
this.currentPage = this.totalPages;
}
}
public List getDatas() {
return datas;
}
public void setDatas(List datas) {
this.datas = datas;
}
public String getPaginationName() {
return paginationName;
}
public void setPaginationName(String paginationName) {
this.paginationName = paginationName;
}
public static void main(String[] args){
PaginationData page = new PaginationData();
page.setPageSize(20);//每页大小
page.setTotal(100);//总行数
page.setCurrentPage(13);//第几页
//下面的方法生成分页html
String paginationHTML = page.getPaginationHTML();
System.out.println(paginationHTML);
}
}
(2)、分页的使用
构建查询条件
@Override
public PowerSearch getPowerSearchByQuery(PowerSearch search, String[] query) {
if (query != null) {
for (int i = 0; i < query.length; i++) {
String str = query[i].trim();
if (!str.equals("")) {
if (i == 0) {
search.setPowerName(str);
}else if(i==1) {
search.setSuper_id(Integer.valueOf(str));
}else if(i==2) {
if(str.equals("0")) {
search.setLeft(false);
}else if(str.equals("1")) {
search.setLeft(true);
}
}else if(i==3) {
if(str.equals("0")) {
search.setAdmit(false);
}else if(str.equals("1")) {
search.setAdmit(true);
}
}else if(i==4) {
if(str.equals("0")) {
search.setHave(false);
}else if(str.equals("1")) {
search.setHave(true);
}
}
}
}
}
return search;
}
根据条件查询数据并分页,PowerSearch类里必须要有start、limit,来限定搜索数据的条数
@Override
public PaginationData pagePowerBySearch(PowerSearch powerSearch, PaginationData paginationData) {
// TODO Auto-generated method stub
if (paginationData == null) {
paginationData = new PaginationData();
}
if (paginationData.getCurrentPage() < 1) {
paginationData.setCurrentPage(1);
}
int curPage = paginationData.getCurrentPage();
int limit = paginationData.getPageSize();
int count = searchMapper.countPowerBySearch(powerSearch);
paginationData.setTotal(count);
powerSearch.setStart((curPage - 1) * limit);
powerSearch.setLimit(limit);
paginationData.setDatas(searchMapper.selectPowerBySearch(powerSearch));
return paginationData;
}
2、生成验证码
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Random;
import javax.imageio.ImageIO;
public class ValidateCode {
// 图片的宽度。
private int width = 160;
// 图片的高度。
private int height = 40;
// 验证码字符个数
private int codeCount = 4;
// 验证码干扰线数
private int lineCount = 150;
// 验证码
private String code = null;
// 验证码图片Buffer
private BufferedImage buffImg = null;
//数字
private static char[] numCode = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
//数字+大写字母+小写字母
private static char[] numCharCode = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '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', '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'};
/**
* 默认构造函数,设置默认参数
*/
public ValidateCode() {
this.createCode();
}
/**
* 生成纯数字验证码
* @param length
* @return
*/
public static String getNumCode(int length) {
Random random = new Random();
StringBuffer randomCode = new StringBuffer();
for(int i=0;i<length;i++) {
randomCode.append(String.valueOf(numCode[random.nextInt(numCode.length)]));
}
return randomCode.toString();
}
/**
* 生成数字字母混合验证码
* @param length
* @return
*/
public static String getNumCharCode(int length) {
Random random = new Random();
StringBuffer randomCode = new StringBuffer();
for(int i=0;i<length;i++) {
randomCode.append(String.valueOf(numCharCode[random.nextInt(numCharCode.length)]));
}
return randomCode.toString();
}
/**
* @param width 图片宽
* @param height 图片高
*/
public ValidateCode(int width, int height) {
this.width = width;
this.height = height;
this.createCode();
}
/**
* @param width 图片宽
* @param height 图片高
* @param codeCount 字符个数
* @param lineCount 干扰线条数
*/
public ValidateCode(int width, int height, int codeCount, int lineCount) {
this.width = width;
this.height = height;
this.codeCount = codeCount;
this.lineCount = lineCount;
this.createCode();
}
public void createCode() {
int x = 0, fontHeight = 0, codeY = 0;
int red = 0, green = 0, blue = 0;
x = width / (codeCount + 2);//每个字符的宽度(左右各空出一个字符)
fontHeight = height - 2;//字体的高度
codeY = height - 4;
// 图像buffer
buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g = buffImg.createGraphics();
// 生成随机数
Random random = new Random();
// 将图像填充为白色
g.setColor(Color.WHITE);
g.fillRect(0, 0, width, height);
// 创建字体,可以修改为其它的
Font font = new Font("Fixedsys", Font.PLAIN, fontHeight);
// Font font = new Font("Times New Roman", Font.ROMAN_BASELINE, fontHeight);
g.setFont(font);
for (int i = 0; i < lineCount; i++) {
// 设置随机开始和结束坐标
int xs = random.nextInt(width);//x坐标开始
int ys = random.nextInt(height);//y坐标开始
int xe = xs + random.nextInt(width / 8);//x坐标结束
int ye = ys + random.nextInt(height / 8);//y坐标结束
// 产生随机的颜色值,让输出的每个干扰线的颜色值都将不同。
red = random.nextInt(255);
green = random.nextInt(255);
blue = random.nextInt(255);
g.setColor(new Color(red, green, blue));
g.drawLine(xs, ys, xe, ye);
}
// randomCode记录随机产生的验证码
StringBuffer randomCode = new StringBuffer();
// 随机产生codeCount个字符的验证码。
for (int i = 0; i < codeCount; i++) {
String strRand = String.valueOf(numCode[random.nextInt(numCode.length)]);
// 产生随机的颜色值,让输出的每个字符的颜色值都将不同。
red = random.nextInt(255);
green = random.nextInt(255);
blue = random.nextInt(255);
g.setColor(new Color(red, green, blue));
g.drawString(strRand, (i + 1) * x, codeY);
// 将产生的四个随机数组合在一起。
randomCode.append(strRand);
}
// 将四位数字的验证码保存到Session中。
code = randomCode.toString();
}
public void write(String path) throws IOException {
OutputStream sos = new FileOutputStream(path);
this.write(sos);
}
public void write(OutputStream sos) throws IOException {
ImageIO.write(buffImg, "png", sos);
sos.close();
}
public BufferedImage getBuffImg() {
return buffImg;
}
public String getCode() {
return code;
}
/**
* 测试函数,默认生成到d盘
* @param args
*/
public static void main(String[] args) {
System.out.println(ValidateCode.getNumCharCode(6));
System.out.println(ValidateCode.getNumCode(4));
}
}
3、token一次性令牌
通过session的添加移除控制,每次添加都是一个新的一次性令牌
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.Random;
public class TokenProccessor {
/*
*单例设计模式(保证类的对象在内存中只有一个)
*1、把类的构造函数私有
*2、自己创建一个类的对象
*3、对外提供一个公共的方法,返回类的对象
*/
private TokenProccessor(){}
private static final TokenProccessor instance = new TokenProccessor();
/**
* 返回类的对象
* @return
*/
public static TokenProccessor getInstance(){
return instance;
}
/**
* 生成Token
* Token:Nv6RRuGEVvmGjB+jimI/gw==
* @return
*/
public String makeToken(){ //checkException
// 7346734837483 834u938493493849384 43434384
String token = (System.currentTimeMillis() + new Random().nextInt(999999999)) + "";
//数据指纹 128位长 16个字节 md5
try {
MessageDigest md = MessageDigest.getInstance("md5");
byte md5[] = md.digest(token.getBytes());
//base64编码--任意二进制编码明文字符 adfsdfsdfsf
return Base64.getEncoder().encode(md5).toString();
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
}
4、data-table以及bootstrap-valid
$(function(){
$("#userList").DataTable({
autoWidth: false,//是否自动计算表格各列宽度
searching: true,//是否显示搜索框 -》显示
ordering:true,//是否允许排序-》允许
lengthChange: false,//是否显示每页大小的下拉,已有自定义分页-》false
bPaginate:false,
bInfo:false,
language: { //语言转为中文
zeroRecords: "没有匹配的数据",
infoEmpty: "没有符合条件的记录",
search: "查找",
infoFiltered: "(从 _MAX_条记录中过滤)",
},
"aoColumnDefs": [ { "bSortable": false, "aTargets": [ 7,8] }] , //从0开始指定某几列不使用排序
});
$("#addAdminForm").bootstrapValidator({
excluded:[":disabled"],//关键配置,表示只对于禁用域不进行验证,其他的表单元素都要验证
//反馈显示
feedbackIcons: {
valid: 'glyphicon glyphicon-ok',
invalid: 'glyphicon glyphicon-remove',
validating: 'glyphicon glyphicon-refresh'
},
fields:{
userName:{
message: '用户名验证失败',
validators: {
notEmpty: {
message: '用户名不能为空'
}
}
},
password:{
message: '密码验证失败',
validators: {
notEmpty: {
message: '密码不能为空'
},
stringLength: {
min: 6,
max: 18,
message: '密码必须在6到18位之间'
}
}
},
mobilePhone:{
message: '手机号验证失败',
validators: {
notEmpty: {
message: '手机号不能为空'
},
regexp: {
regexp: /^1[356789][0-9]{9}$/,
message: '不是有效的手机号'
}
}
},
powergroupId:{
message: '权限组选择失败',
validators:{
notEmpty:{
message:'权限组择不能为空'
},
callback: {
message: '必须选择一个权限组',
callback: function(value, validator) {
if (value == 0) {
return false;
} else {
return true;
}
}
}
}
},
}
});
})
5、三级联动
页面:
选择省份
${o.disName }
选择地市
</select> <select class="form-control select2" style="width: 33%;"
id="county" name="countyId">
<option value="0">选择区县</option>
</select>
</div>
</div>
js:
$("#province").change(function(){
if($("#province").val()!='0'){
$.ajax({
url:url+"user/dists.action",
type:"POST",
data:"superId="+$("#province").val(),
success:function(result){
$("#city").empty();
$("#city").append("<option value=''>选择地市</option>");
var citylist=result.extend.dists;
$.each(citylist,function(index,city){
$("#city").append("<option value='"+city.id+"'>"+city.disName+"</option>");
})
},
error:function(){
}
});
}
})
$("#city").change(function(){
$.ajax({
url:url+"user/dists.action",
type:"POST",
data:"superId="+$("#city").val(),
success:function(result){
$("#county").empty();
$("#county").append("<option value=''>选择区县</option>");
var countylist=result.extend.dists;
$.each(countylist,function(index,county){
$("#county").append("<option value='"+county.id+"'>"+county.disName+"</option>");
})
},
error:function(){
}
});
});