【JavaWeb项目】一个众筹网站的开发(八)后台页面详细设置
一、user.jsp改造
删除引入菜单
抽取导航栏 nav-bar.jsp,删除引入导航栏
删除引入main.jsp的到好烂
数据库里添加url
报错,url不对
没有/
url正确
action="${ctp}/permission/user/login"
<a href="${c_menu.url }">
<%@page import="com.atguigu.scw.manager.constant.Constants"%> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %> <div class="col-sm-3 col-md-2 sidebar"> <div class="tree"> <ul style="padding-left: 0px;" class="list-group"> <li class="list-group-item tree-closed"><a href="${ctp }/main.html"><i class="glyphicon glyphicon-dashboard"></i> 控制面板</a></li> <!-- 遍历菜单 --> <c:forEach items="<%=session.getAttribute(Constants.USER_MENUS) %>" var="p_menu"> <li class="list-group-item tree-closed"><span> <i class="${p_menu.icon }"></i> ${p_menu.name } <span class="badge" style="float: right">${fn:length(p_menu.childs)}</span></span> <ul style="margin-top: 10px; display: none;"> <c:forEach items="${p_menu.childs}" var="c_menu"> <li style="height: 30px;"><a href="${ctp }/${c_menu.url }"><i class="${c_menu.icon }"></i> ${c_menu.name }</a></li> </c:forEach> </ul> </li> </c:forEach> </ul> </div> </div>
在controller里实现分页逻辑
package com.atguigu.scw.manager.controller.permission; //处理所有/permission/user下的请求 @RequestMapping("/permission/user") @Controller public class UserController { private final String MANAGER_MAIN = "manager/main"; @Autowired UserService userService; /** * 用户列表页面显示 * * @Description (TODO这里用一句话描述这个方法的作用) * @return */ @RequestMapping("/list") public String users(@RequestParam(value = "pn", defaultValue = "1") Integer pn, @RequestParam(value = "ps", defaultValue = "10") Integer ps, Model model) { // 有表单提交,防止重复提交,建议额外写一个转发方法重定向到页面 // 没有表单提交就直接转发到目标页面 // 分页获取用户的逻辑 System.out.println("分页获取用户的逻辑"); PageHelper.startPage(pn, ps); // 拿到分页查出的结果 List<TUser> list = userService.getAll(); // 去页面显示的数据 PageInfo<TUser> info = new PageInfo<TUser>(list, 5); model.addAttribute("user_info", info);// 直接转到页面 return "manager/permission/user"; } @RequestMapping("/login") public String login(TUser user, HttpSession session) { // 省略 } // /permission/user/reg @RequestMapping("/reg") public String reg(TUser user, Model model, HttpSession session) { // 省略 } }
Mybatis的插件 PageHelper 分页查询使用方法 https://blog.csdn.net/maoyuanming0806/article/details/77720754
pageHelper.startPage(m,n),只对最近的一次查询有效,之前不是很理解什么是最近的一次查询。
原来mapper代理对象.selectXXX(),这个方法就是查询。
比如说:
pageHelper.startPage(1,30);
List<Item> list = ItemMapper.selectByExample(example);
也就是分页只针对这次获得的list有效。
PageHelper.startPage(pageNum, pageSize);
pageNum :当前页数
pageSize :一页大小
调用该方法后,在此方法后面的第一个mybaits查询语句就会按照这个进行分页
PageInfo pageInfo=new PageInfo(shippingList);
则对第一次查询的集合传入,可以获得更多的页面操作信息,封装在PageInfo 这个类上
PageInfo pageInfo = new PageInfo(list,5);
使用pageInfo包装查询后的结果,封装了详细的查询数据,其中参数5是页码导航连续显示的页数
用到了UserService的getAll方法
在接口中添加方法,在实现类中实现方法
public interface UserService { public boolean register(TUser user); public TUser login(TUser user); public List<TUser> getAll(); }
实现类
package com.atguigu.scw.manager.service.impl; @Service public class UserServiceImpl implements UserService { @Autowired TUserMapper userMapper; public boolean register(TUser user) { // 省略 } public TUser login(TUser user) { // 省略 } public List<TUser> getAll() { return userMapper.selectByExample(null); } }
user.jsp
<tbody> <c:forEach items="${user_info.list}" var="user"> <tr> <!-- varStatus="" 当前遍历的所有信息,索引 --> <!-- 取出用户的实际ID --> <td>${user.id }</td> <td><input type="checkbox"></td> <td>${user.loginacct }</td> <td>${user.username }</td> <td>${user.email }</td> <td> <button type="button" class="btn btn-success btn-xs"><i class=" glyphicon glyphicon-check"></i></button> <button type="button" class="btn btn-primary btn-xs"><i class=" glyphicon glyphicon-pencil"></i></button> <button type="button" class="btn btn-danger btn-xs"><i class=" glyphicon glyphicon-remove"></i></button> </td> </tr> </c:forEach> </tbody>
<tfoot> <tr > <td colspan="6" align="center"> <ul class="pagination"> <li><a href="${ctp}/permission/user/list?pn=1">首页</a></li> <c:if test="${user_info.hasPreviousPage}"> <li><a href="${ctp}/permission/user/list?pn=${user_info.prePage }">上一页</a></li> </c:if> <!-- 遍历连续显示的页面navigatepageNums: int[] --> <c:forEach items="${user_info.navigatepageNums }" var="pn"> <!-- 是当前页 --> <c:if test="${pn == user_info.pageNum }"> <li class="active"><a href="${ctp}/permission/user/list?pn=${pn}">${pn } <span class="sr-only">(current)</span></a></li> </c:if> <!-- 不是当前页 --> <c:if test="${pn != user_info.pageNum }"> <li><a href="${ctp}/permission/user/list?pn=${pn }">${pn }</a></li> </c:if> </c:forEach> <c:if test="${user_info.hasNextPage}"> <li><a href="${ctp}/permission/user/list?pn=${user_info.nextPage }">下一页</a></li> </c:if> <li><a href="${ctp}/permission/user/list?pn=${user_info.pages }">末页</a></li> </ul> </td> </tr> </tfoot>
tbody标签就是显示的用户信息
tfoot标签中就是下面的导航
逻辑就是,点击用户维护按钮,会有请求到/permission/user/list,UserController的usrers处理该请求,使用PageHelpler插件,设置每页显示多少,通过新定义的getAll()方法从数据库获得用户信息,放在PageInfo对象中,在model中添加该对象往前台传数据,命名位user_info,最后转到user.jsp。
user.jsp接收到user_info,遍历该对象的list,显示用户的信息
在页脚,如果没有前一页就是首页,没有后一页就是末页,遍历首页和末页中正在连续显示的页面,这些页面中是当前的页面就高亮显示。
提防小失误
<c:if test=" ${pn == user_info.pageNum}">
上面多了一个空格,就会出错,去掉空格:
<c:if test="${pn == user_info.pageNum}">
PageInfo中的属性
public class PageInfo<T> implements Serializable { private static final long serialVersionUID = 1L; private int pageNum; private int pageSize; private int size; private int startRow; private int endRow; private long total; private int pages; private List<T> list; private int prePage; private int nextPage; private boolean isFirstPage; private boolean isLastPage; private boolean hasPreviousPage; private boolean hasNextPage; private int navigatePages; private int[] navigatepageNums; private int navigateFirstPage; private int navigateLastPage;
在后台打印pageinfo
设置 ps=2
PageInfo{pageNum=2, pageSize=2, size=2, startRow=3, endRow=4, total=9, pages=5,
list=Page{count=true, pageNum=2, pageSize=2, startRow=2, endRow=4, total=9, pages=5, reasonable=false, pageSizeZero=false},
prePage=1, nextPage=3, isFirstPage=false, isLastPage=false, hasPreviousPage=true, hasNextPage=true, navigatePages=5,
navigateFirstPage1, navigateLastPage5, navigatepageNums=[1, 2, 3, 4, 5]}真正存储数据的是Page,它就是个列表,可以存储东西
public class Page<E> extends ArrayList<E> implements Closeable我们在代码中是最初是查询所有数据,分页插件做了些什么呢?这个Page里有所有的数据,比如TUser吗,还是仅仅有当前查询页的数据。
翻看日志
DEBUG (org.apache.ibatis.logging.jdbc.BaseJdbcLogger:debug) - ==> Preparing: select id, loginacct, userpswd, username, email, createtime from t_user LIMIT 2,2我们发现,本来查询所有数据的SQL被修改了,现在只是从第二行开始查询两条数据,也就是当前页的数据,Page并不包含所有数据
pagehelper内部其实也是跟平常的分页一样,内部都是创建了分页page,在你调用的地方传入page,最后在mybatis中的拦截器中取得传入的page并利用反射重新拼接sql再执行
二、页面样式优化
当再次点击 用户维护 的时候
url链接重叠
菜单抽取中设置的url不对
<a href="${c_menu.url }"><i class="${c_menu.icon }"></i> ${c_menu.name }</a>
应改为当前项目下,这样才会最终是绝对路径,否则上面是相对路径,出现url重叠的现象
<a href="${ctp }/${c_menu.url }"><i class="${c_menu.icon }"></i> ${c_menu.name }</a>
来到页面后我们发现菜单是闭合的
我们想要展开,且当前菜单红色显示
查看网页源码
<!-- 遍历菜单 --> <li class="list-group-item tree-closed"> <span><i class="glyphicon glyphicon glyphicon-tasks"></i> 权限管理 <span class="badge" style="float:right">3</span></span> <ul style="margin-top:10px;display:none;"> <li style="height:30px;"> <a href="/manager-web/permission/user/list"><i class="glyphicon glyphicon-user"></i> 用户维护</a> </li> <li style="height:30px;"> <a href="/manager-web/"><i class=""></i> 角色维护</a> </li> <li style="height:30px;"> <a href="/manager-web/"><i class=""></i> 许可维护</a> </li> </ul> </li>
<ul style="margin-top:10px;display:none;">我们发现展示是none
<a href="/manager-web/permission/user/list"><i class="glyphicon glyphicon-user"></i> 用户维护</a> 字在a链接里
因此要展示ul,且在a链接中设置字体颜色,编写js
<script type="text/javascript"> // 省略// 当前页面所在的那个超链接red:color // 它的父list-group-item tree-closed是没有的 // 找到当前页面的a链接 // 使用css为某个元素加样式 list-group-item $("a[href='${ctp }/permission/user/list']").css("color", "red"); $("a[href='${ctp }/permission/user/list']").parent(".list-group-item").removeClass("tree-closed"); $("a[href='${ctp }/permission/user/list']").parent().parent("ul").show(100); </script>
还要设置最上面的导航栏
在nav-bar.jsp中改为
<div><a class="navbar-brand" style="font-size:32px;" href="#">众筹平台 - ${navinfo }</a></div>
在user.jsp中添加这个navinfl变量
<body> <%pageContext.setAttribute("navinfo", "用户维护"); %> ...
同理在需要该变量的各个页面设置即可
抽取页面显示效果
我们想各个页面都是菜单展开,当前菜单红色的设置,因此将共同的显示效果进行抽取
把js抽取抽来存放到common-js.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <script> changePageStyle("${curUrl }"); function changePageStyle(url) { //只有超链接在变化 $("a[href='${ctp }/"+url+"']").css("color", "red"); $("a[href='${ctp }/"+url+"']").parents(".list-group-item").removeClass("tree-closed"); $("a[href='${ctp }/"+url+"']").parent().parent("ul").show(100); } </script>
user.jsp中使用时只需要
设置curUrl并引入该jsp文件
<% pageContext.setAttribute("navinfo", "用户维护"); pageContext.setAttribute("curUrl", "permission/user/list"); %> ... <%@include file="/WEB-INF/includes/common-js.jsp" %>
<%@include file="/WEB-INF/includes/common-js.jsp" %>要插在<script>标签以外
三、带查询条件的分页
是一个form表单
指定action,表单提交的方向
指定提交方式为post
<form class="form-inline" role="form" style="float:left;" action="${ctp }/permission/user/list" method="post"> <div class="form-group has-feedback"> <div class="input-group"> <div class="input-group-addon">查询条件</div> <input class="form-control has-success" type="text" name="sp" placeholder="请输入查询条件"> </div> </div> <button type="submit" class="btn btn-warning"><i class="glyphicon glyphicon-search"></i> 查询</button> </form>
controller
@RequestMapping("/list") public String users(@RequestParam(value = "pn", defaultValue = "1") Integer pn, @RequestParam(value = "ps", defaultValue = "10") Integer ps, Model model, @RequestParam(value = "sp", defaultValue = "") String search) { // 有表单提交,防止重复提交,建议额外写一个转发方法重定向到页面 // 没有表单提交就直接转发到目标页面 // 分页获取用户的逻辑 System.out.println("分页获取用户的逻辑"); PageHelper.startPage(pn, ps); // 拿到分页查出的结果,不带条件的 // List<TUser> list = userService.getAll(); // 带条件的查询,将条件作为用户名或用户昵称的查询条件 // select * from t_user where loginacct like ? or username=? // 第一次创建的条件,默认使用and连接 TUserExample example = new TUserExample(); Criteria criteria1 = example.createCriteria(); Criteria criteria2 = example.createCriteria(); if (!search.trim().equals("")) { criteria1.andLoginacctLike("%" + search + "%"); criteria2.andUsernameLike("%" + search + "%"); } example.or(criteria2); List<TUser> list = userService.getAllByCondition(example); // 去页面显示的数据 PageInfo<TUser> info = new PageInfo<TUser>(list, 5); model.addAttribute("user_info", info); for (TUser tUser : list) { System.out.println(tUser); } // 直接转到页面 return "manager/permission/user"; }
service层定义方法
接口
public interface UserService { public boolean register(TUser user); public TUser login(TUser user); public List<TUser> getAll(); public List<TUser> getAllByCondition(TUserExample example); }
实现类
public List<TUser> getAllByCondition(TUserExample example) { return userMapper.selectByExample(example); }
存在的问题是:查询条件不能回显,且当切换页面的时候,重新回到了不查询的状态,即查询状态无法维持
原因:当换页的时候,每个页的按钮都有转向的url,现在的url没有查询参数,因此切换的时候不会带查询条件
解决:给分页超链接绑上单击事件
// 为所有分页连接绑定单击事件,让其动态带上分页查询参数 $(".pagination").find("a").click(function(){ // 1.获取查询表单的查询参数 //$("input[name='searchParam']").val(); // 不禁用默认行为,而是为超链接多拼装上查询条件 // 为超链接动态拼上查询条件 var href = $(this).attr("href")+"&sp="+$("input[name='sp']").val(); $(this).attr("href", href); });
回显
controller里添加
model.addAttribute("sp", search);
往前端传递search,名字为sp
查询框添加value
<input class="form-control has-success" type="text" name="sp" placeholder="请输入查询条件" value=${sp }>
四、批量删除
首先实现全选全不选
user.jsp
<div class="table-responsive"> <table class="table table-bordered"> <thead> <tr > <th width="30">#</th> <th width="30"><input id="checkall_btn" type="checkbox"></th> <th>账号</th> <th>名称</th> <th>邮箱地址</th> <th width="100">操作</th> </tr> </thead> <tbody> <c:forEach items="${user_info.list}" var="user"> <tr> <!-- varStatus="" 当前遍历的所有信息,索引 --> <!-- 取出用户的实际ID --> <td>${user.id }</td> <td><input type="checkbox" class="single_check"></td> <td>${user.loginacct }</td> <td>${user.username }</td> <td>${user.email }</td> <td> <button type="button" class="btn btn-success btn-xs"><i class=" glyphicon glyphicon-check"></i></button> <button type="button" class="btn btn-primary btn-xs"><i class=" glyphicon glyphicon-pencil"></i></button> <button type="button" class="btn btn-danger btn-xs"><i class=" glyphicon glyphicon-remove"></i></button> </td> </tr> </c:forEach> </tbody>
js实现全选
放在common-js.jsp中
// 做全选全不选功能 // 传入全选按钮对象 function check_reverse(check_all_btn, check_btn) { check_all_btn.click(function(){ // 如果是原生的属性,使用prop获取比较好 var flag = $(this).prop("checked"); check_btn.prop("checked", $(this).prop("checked")) }); check_btn.click(function(){ // 当check_btn点满以后check_all_btn勾上,否则不选中 // 获取被选中的checkbtn个数 var flag = check_btn.filter(":checked").length == check_btn.length; check_all_btn.prop("checked", flag); }); }
删除
在user.jsp中获得id,并拼接成url
button的class设置为deleteAllBtn
js处理该button的点击
... <button type="button" class="btn btn-danger deleteAllBtn" style="float:right;margin-left:10px;"> <i class=" glyphicon glyphicon-remove"> </i> 删除</button> ... check_reverse($("#checkall_btn"), $(".single_check")); $(".deleteAllBtn").click(function () { // 点击删除按钮,先拿到要删除的所有员工的id var delUrl = "${ctp}/permission/user/del?ids=" var ids = ""; $(".single_check:checked").each(function () { // 取出自定义的id属性 ids += $(this).attr("del_id")+","; // 1,2,3, }) //剔除最后一个逗号 1,2,3 delUrl += ids.substring(0, ids.length-1); //让浏览器访问这个删除链接 if(confirm("确认删除【"+ids+"】这些员工吗?")){ location.href = delUrl; } return false; });
转到controller里进行处理
package com.atguigu.scw.manager.controller.permission; //处理所有/permission/user下的请求 @RequestMapping("/permission/user") @Controller public class UserController { private final String MANAGER_MAIN = "manager/main"; @Autowired UserService userService; /** * 用户删除 */ @RequestMapping("/del") public String userDelete(@RequestParam(value = "ids", defaultValue = "") String ids) { if (!ids.trim().equals("")) { userService.deleteBatchOrSingle(ids); } // 删除完成重新查询所有数据 return "redirect:/permission/user/list"; } /** * 用户列表页面显示 * * @Description (TODO这里用一句话描述这个方法的作用) * @return */ @RequestMapping("/list") public String users(@RequestParam(value = "pn", defaultValue = "1") Integer pn, @RequestParam(value = "ps", defaultValue = "10") Integer ps, Model model, @RequestParam(value = "sp", defaultValue = "") String search) { // 省略 } @RequestMapping("/login") public String login(TUser user, HttpSession session) { // 省略 } // /permission/user/reg @RequestMapping("/reg") public String reg(TUser user, Model model, HttpSession session) { // 省略 } }
userService接口增加deleteBatchOrSingle(ids)方法
接口
public interface UserService { public boolean register(TUser user); public TUser login(TUser user); public List<TUser> getAll(); public List<TUser> getAllByCondition(TUserExample example); public void deleteBatchOrSingle(String ids); }
实现类中实现方法
public void deleteBatchOrSingle(String ids) { if (ids.contains(",")) { String[] split = ids.split(","); List<Integer> list = new ArrayList<Integer>(); for (String s : split) { int i = 0; try { i = Integer.parseInt(s); } catch (NumberFormatException e) { } list.add(i); } TUserExample example = new TUserExample(); Criteria criteria = example.createCriteria(); // 删除id所在的集合 criteria.andIdIn(list); userMapper.deleteByExample(example); } else { userMapper.deleteByPrimaryKey(Integer.parseInt(ids)); } }
五、角色分配页面
从用户页面点击分配角色,来到分配角色页面,左侧是未分配角色列表,右侧是已分配角色列表
数据库角色
user.jsp配置下分配权限按钮
<tbody> <c:forEach items="${user_info.list}" var="user"> <tr> <!-- varStatus="" 当前遍历的所有信息,索引 --> <!-- 取出用户的实际ID --> <td>${user.id }</td> <td><input type="checkbox" class="single_check" del_id=${user.id }></td> <td>${user.loginacct }</td> <td>${user.username }</td> <td>${user.email }</td> <td> <button u_id="${user.id }" type="button" class="btn btn-success btn-xs assignBtn"> <i class=" glyphicon glyphicon-check"></i></button> <button type="button" class="btn btn-primary btn-xs"> <i class=" glyphicon glyphicon-pencil"></i></button> <button type="button" class="btn btn-danger btn-xs"> <i class=" glyphicon glyphicon-remove"></i></button> </td> </tr> </c:forEach> </tbody>
js
// 点击权限分配来到权限分配页面 $(".assignBtn").click(function(){ // 必须将用户id带给后台 自定义用attr var id = $(this).attr("u_id"); // 去权限列分配页面 var url = "${ctp}/permission/user/toAssignRole?uid="+id; location.href=url; })
location.href
自定义属性
定义响应/permission/user/toAssignRole的controller
UserController中添加
@Autowired
RoleService roleService;
// 去权限分配页面 @RequestMapping("/toAssignRole") public String toAssignRolePage(@RequestParam(value = "uid") Integer uid, Model model) { System.out.println("要去权限分配页面,用户id:" + uid); // 1.查出所有权限 List<TRole> roles = roleService.getAllRole(); // 2.查出当前用户拥有的权限 // List<TRole> userRole = roleService.getUserRole(uid); Map<Integer, TRole> map = new HashMap<Integer, TRole>(); for (TRole tRole : userRole) { map.put(tRole.getId(), tRole); } // 3.用户未分配权限 List<TRole> unRoles = new ArrayList<TRole>(); for (TRole tRole : roles) { if (!map.containsKey(tRole.getId())) { // 用户已拥有的权限 unRoles.add(tRole); } } model.addAttribute("unroles", unRoles); model.addAttribute("roles", userRole); // 来到权限分配页 return "manager/permission/assignRole"; }
定义RoleService接口
package com.atguigu.scw.manager.service; import java.util.List; import com.atguigu.scw.manager.bean.TRole; public interface RoleService { public List<TRole> getAllRole(); public List<TRole> getUserRole(Integer userId); }
实现方法
package com.atguigu.scw.manager.service.impl; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.atguigu.scw.manager.bean.TRole; import com.atguigu.scw.manager.dao.TRoleMapper; import com.atguigu.scw.manager.service.RoleService; @Service public class RoleServiceImpl implements RoleService { @Autowired TRoleMapper roleMapper; public List<TRole> getAllRole() { return roleMapper.selectByExample(null); } public List<TRole> getUserRole(Integer userId) { // select t.id,t.name from t_role t left join t_user_role u_r ON t.`id`=u_r.`roleid` // left join t_user u on u. `id`=u_r.`userid` // WHERE u.`id`=? return roleMapper.getUserRole(userId); } }
TRoleMapper.xml中增加自己以方法
<select id="getUserRole" resultMap="BaseResultMap"> select t.id,t.name from t_role t left join t_user_role u_r ON t.`id`=u_r.`roleid` left join t_user u on u.`id`=u_r.`userid` where u.`id`=#{uid} </select>
连接查询
select 我们本意要查的字段from这个表
left join 其他表 on a 关联表
跳转到assignRole.jsp
<div class="panel panel-default"> <div class="panel-body"> <form role="form" class="form-inline"> <div class="form-group"> <label for="exampleInputPassword1">未分配角色列表</label><br> <select class="form-control unroles" multiple size="10" style="width:100px;overflow-y:auto;"> <c:forEach items="${unroles }" var="role"> <option value="${role.id }">${role.name }</option> </c:forEach> </select> </div> <div class="form-group"> <ul> <li class="btn btn-default glyphicon glyphicon-chevron-right"></li> <br> <li class="btn btn-default glyphicon glyphicon-chevron-left" style="margin-top:20px;"></li> </ul> </div> <div class="form-group" style="margin-left:40px;"> <label for="exampleInputPassword1">已分配角色列表</label><br> <select class="form-control roles_select" multiple size="10" style="width:100px;overflow-y:auto;"> <c:forEach items="${roles }" var="role"> <option value="${role.id }">${role.name }</option> </c:forEach> </select> </div> </form> </div> </div>
分别对应
js
$(".glyphicon-chevron-right").click(function () { var rids = "" $(".unroles :selected").each(function(){ rids += $(this).val()+","; }); // 去掉最后的, rids = rids.substring(0, rids.length-1); // 选中的添加到权限中 // 发送请求给后台,数据库完成操作 // 必须带上权限id的拼串和userid var uid = "${param.uid }" $.get("${ctp }/permission/user/assignrole?opt=add&uid="+uid+"&rids="+rids,function(){ // 选中并且分配成功的过去 $(".unroles :selected").appendTo(".roles_select"); }) }); $(".glyphicon-chevron-left").click(function () { var uid = "${param.uid }" var rids = "" $(".roles_select :selected").each(function(){ rids += $(this).val()+","; }); // 去掉最后的, rids = rids.substring(0, rids.length-1); // 发送请求移除 $.get("${ctp }/permission/user/assignrole?opt=remove&uid="+uid+"&rids="+rids,function(){ //显示移除的效果 $(".roles_select :selected").appendTo(".unroles"); }); });
EL表达式${param.xxx}可以从url中获取参数放在页面中直接使用
比如:一个网址:127.0.0.1/test/testparam?test1=3&test2=sss
用${param.test1}就可以直接获取到test1的值,也就是3
用${param.test2}就可以直接获取到test2的值,也就是sss
${param.xxx} 就等价于 request.getparam("xxx"),也就是服务器从页面或者客户端获取的内容
定义响应/permission/user/assignrole的controller
控制器处理请求:
查出当前用户为拥有的权限
查出当前用户已拥有的权限
查出的结果放在页面
UserController中添加
@Autowired UserRoleService urService; // 添加角色 如果返回值为空,默认请求地址就会当成页面地址 // public void UserRole(@RequestParam("rids") String rids, @RequestParam("uid") Integer uid) { // 加@ResponseBody注解后,return "成功!"相当于out.write("成功") @ResponseBody @RequestMapping("/assignrole") public String UserRole(@RequestParam("rids") String rids, @RequestParam("uid") Integer uid, @RequestParam("opt") String opt) { if ("add".equals(opt)) { // 为某个用户添加一些角色 urService.addRole(rids, uid); System.out.println("成功"); } else if ("remove".equals(opt)) { // 移除角色 urService.removeRole(rids, uid); System.out.println("删除完成"); } return ""; }
创建接口,实现方法
package com.atguigu.scw.manager.service; public interface UserRoleService { // 给用户添加角色 public void addRole(String ids, Integer userId); // 移除用户的某些角色 public void removeRole(String ids, Integer userId); }
实现方法
package com.atguigu.scw.manager.service.impl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.atguigu.scw.manager.bean.TUserRole; import com.atguigu.scw.manager.bean.TUserRoleExample; import com.atguigu.scw.manager.bean.TUserRoleExample.Criteria; import com.atguigu.scw.manager.dao.TUserRoleMapper; import com.atguigu.scw.manager.service.UserRoleService; @Service public class UserRoleServiceImpl implements UserRoleService { @Autowired TUserRoleMapper userRoleMapper; public void addRole(String ids, Integer userId) { // 没有包含逗号,直接添加 if (ids.contains(",")) { String[] split = ids.split(","); for (String rid : split) { // 创建一个中间表的数据对象 TUserRole role = new TUserRole(); int i = Integer.parseInt(rid); role.setRoleid(i); role.setUserid(userId); userRoleMapper.insertSelective(role); } } else { TUserRole role = new TUserRole(); int i = Integer.parseInt(ids); role.setRoleid(i); role.setUserid(userId); userRoleMapper.insertSelective(role); } } public void removeRole(String ids, Integer userId) { if (ids.contains(",")) { String[] split = ids.split(","); for (String rid : split) { int i = Integer.parseInt(rid); TUserRoleExample example = new TUserRoleExample(); Criteria criteria = example.createCriteria(); criteria.andRoleidEqualTo(i); criteria.andUseridEqualTo(userId); userRoleMapper.deleteByExample(example); } } else { int i = Integer.parseInt(ids); TUserRoleExample example = new TUserRoleExample(); Criteria criteria = example.createCriteria(); criteria.andRoleidEqualTo(i); criteria.andUseridEqualTo(userId); userRoleMapper.deleteByExample(example); } } }
六、角色维护
新建控制器
t_permission
role.jsp设置导航栏、菜单等
先把分页部分做好
tbody
tfoot
<tbody> <c:forEach items="${role_info.list }" var="role"> <tr> <td>${role.id }</td> <td><input type="checkbox"></td> <td>${role.name }</td> <td> <button type="button" rid="${role.id }" class="btn btn-success btn-xs assignPermissionModelBtn"> <i class=" glyphicon glyphicon-check"></i> </button> <button type="button" class="btn btn-primary btn-xs"> <i class=" glyphicon glyphicon-pencil"></i> </button> <button type="button" class="btn btn-danger btn-xs"> <i class=" glyphicon glyphicon-remove"></i> </button> </td> </tr> </c:forEach> </tbody> <tfoot> <tr> <td colspan="6" align="center"> <ul class="pagination"> <!-- 即使点击分页连接也应该带上查询条件的值 --> <!-- 给分页超链接绑定单击事件; --> <li><a href="${ctp}/permission/role/list?pn=1">首页</a></li> <c:if test="${role_info.hasPreviousPage}"> <li><a href="${ctp}/permission/role/list?pn=${role_info.prePage}">上一页</a></li> </c:if> <!-- 遍历连续显示的页面 navigatepageNums : int[]--> <c:forEach items="${role_info.navigatepageNums}" var="pn"> <c:if test="${pn == role_info.pageNum }"> <li class="active"><a href="${ctp}/permission/role/list?pn=${pn}">${pn } <span class="sr-only">(current)</span></a></li> </c:if> <c:if test="${pn != role_info.pageNum }"> <li><a href="${ctp}/permission/role/list?pn=${pn}">${pn }</a></li> </c:if> </c:forEach> <c:if test="${role_info.hasNextPage}"> <li><a href="${ctp}/permission/role/list?pn=${role_info.nextPage}">下一页</a></li> </c:if> <li><a href="${ctp}/permission/role/list?pn=${role_info.pages}">末页</a></li> </ul> </td> </tr> </tfoot>
RoleContrller里写处理逻辑
package com.atguigu.scw.manager.controller.permission; // 处理角色维护模块 @RequestMapping("/permission/role") @Controller public class RoleController { @Autowired RoleService roleService; // 来到角色维护页面 @RequestMapping("/list") public String toRolePage(@RequestParam(value = "pn", defaultValue = "1") Integer pn, @RequestParam(value = "ps", defaultValue = "10") Integer ps, Model model, @RequestParam(value = "sp", defaultValue = "") String search) { PageHelper.startPage(pn, ps); List<TRole> role = roleService.getAllRole(); PageInfo<TRole> info = new PageInfo<TRole>(role, 5); // 连续显示5页 model.addAttribute("role_info", info); return "manager/permission/role"; } }
bootstrap的模态框
在模态框里展示权限树
<!-- 模态框 --> <div class="modal fade" id="permissModel" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">×</span> </button> <h4 class="modal-title" id="myModalLabel">分配权限</h4> </div> <div class="modal-body"> <!-- 展示权限树 --> <div> <ul id="permissionTree" class="ztree"></ul> </div> </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">关闭</button> <button type="button" class="btn btn-primary" id="addPermissionBtn">分配权限</button> </div> </div> </div> </div>
js
ztree的js和cs文件放入cs-file.jsp、js-file.jsp
//保存ztree对象的 var ztreeObject; //用户角色分配权限- //点击按钮-打开模态框-查出所有的权限-在模态框中树形显示-将当前用户拥有的权限选中 /* $("tbody .btn-success").click(function() { window.location.href = "assignPermission.html"; }); */ //点击分配权限按钮, //模态框的按钮 $(".assignPermissionModelBtn").click(function() { var options = { backdrop : 'static', show : true } //"permissionTree"刷出权限树 //js的this会经常飘逸 initPermissionTree($(this).attr("rid")); //getUser(1) //勾选当前角色的权限 //打开模态框 $('#permissModel').modal(options); //将角色id保存到模态框的哪个属性中; }); //treeId:是权限树ul的id //treeNode:当前节点信息 function showIcon(treeId, treeNode) { //console.log(treeId); //treeNode里面有一个tId; //这个tid用来拼串以后就是图标显示位置的元素id和名字显示位置的元素id //tId:"permissionTree_3" //<span id="permissionTree_2_span">用户维护</span> //<span id="permissionTree_2_ico" ></span> //console.log(treeNode); //改图标;找到当前元素图标显示的节点,将这个节点的class设置为当前节点的icon $("#" + treeNode.tId + "_ico").removeClass() .addClass(treeNode.icon); } function initPermissionTree(rid) { var setting = { data : { simpleData : { enable : true, idKey : "id", pIdKey : "pid", }, key : { url : "haha" } }, view : { //自定义显示的效果 addDiyDom : showIcon }, check : { enable : true } }; //从数据库查出的所有权限节点数据 //发送ajax请求获取到所有权限的json数据 $.getJSON("${ctp}/permission/role/json", function(nodes) { //console.log(nodes); //给每一个节点修改或者添加一些属性 $.each(nodes, function() { if (this.pid == 0) { this.open = true; } }) //如果不是用var声明的变量,这个变量就默认变为全局的 //把初始化好的ztree对象传递给外界使用,可以通用操作这个对象,来改变树 //ztree为了不影响下面的操作是异步展示数据的 ztreeObject = $.fn.zTree.init($("#permissionTree"), setting, nodes); checkcurPermisson(rid); }) }
RoleController处理
// 处理角色维护模块 @RequestMapping("/permission/role") @Controller public class RoleController { @Autowired RoleService roleService; @Autowired TPermissionService permissionService; // 返回所有权限的json数据 // 返回所有权限的list @ResponseBody @RequestMapping("/json") public List<TPermission> getAllPermission() { // 返回所有的权限 return permissionService.getPermissions(); } // 来到角色维护页面 @RequestMapping("/list") public String toRolePage(@RequestParam(value = "pn", defaultValue = "1") Integer pn, @RequestParam(value = "ps", defaultValue = "10") Integer ps, Model model, @RequestParam(value = "sp", defaultValue = "") String search) { PageHelper.startPage(pn, ps); List<TRole> role = roleService.getAllRole(); PageInfo<TRole> info = new PageInfo<TRole>(role, 5); // 连续显示5页 model.addAttribute("role_info", info); return "manager/permission/role"; } }
TPermissionService接口添加方法,并实现
package com.atguigu.scw.manager.service.impl; @Service public class TPermissionServiceImpl implements TPermissionService { @Autowired TPermissionMapper mapper; public List<TPermission> getAllMenus() { // 省略 } public List<TPermission> getPermissions() { return mapper.selectByExample(null); } }
七、分配权限
已有的权限应该打勾
控制器里增加
RoleController
// /permission/role/perm/4 @ResponseBody @RequestMapping("/perm/{id}") public List<TPermission> getRolePermission(@PathVariable("id")Integer rid) { List<TPermission> permissions = permissionService.getRolePermission(rid); return permissions; }
接口中增加方法,并实现该方法
package com.atguigu.scw.manager.service;
public interface TPermissionService { // 拿到所有菜单 public List<TPermission> getAllMenus(); public List<TPermission> getPermissions(); public List<TPermission> getRolePermission(Integer rid); }
实现方法
// 查询角色对应的权限 public List<TPermission> getRolePermission(Integer rid) { return mapper.getRolePermission(rid); }
TPermissionMapper中增加查询方法
List<TPermission> getRolePermission(Integer rid);
实现
配置mybatis的mapper文件
TPermissionMapper.xml
<!-- List<TPermission> getRolePermission --> <select id="getRolePermission" resultMap="BaseResultMap"> SELECT p.* FROM t_permission p LEFT JOIN t_role_permission rp ON rp.`permissionid`=p.`id` WHERE rp.`roleid`=#{rid} </select>
js
<script type="text/javascript"> $(function() { $(".list-group-item").click(function() { if ($(this).find("ul")) { $(this).toggleClass("tree-closed"); if ($(this).hasClass("tree-closed")) { $("ul", this).hide("fast"); } else { $("ul", this).show("fast"); } } }); }); //保存ztree对象的 var ztreeObject; //用户角色分配权限- //点击按钮-打开模态框-查出所有的权限-在模态框中树形显示-将当前用户拥有的权限选中 /* $("tbody .btn-success").click(function() { window.location.href = "assignPermission.html"; }); */ //点击分配权限按钮, //模态框的按钮 $("#addPermissionBtn").click(function(){ //1、获取当前我们已经选中的权限 var nodes = ztreeObject.getCheckedNodes(true); //2、将这些权限的id和角色的id发给程序 var permission_ids = ""; $.each(nodes,function(){ permission_ids += this.id+","; }); var rid = $(this).attr("rid"); //3、使用程序保存这个角色对应的权限的值 //写程序;删除对应的东西即可 $.get("${ctp}/permission/role/update?pids="+permission_ids+"&rid="+rid,function(){ alert("权限分配成功"); $('#permissModel').modal("hide"); }) }); $(".assignPermissionModelBtn").click(function() { var options = { backdrop : 'static', show : true } //"permissionTree"刷出权限树 //js的this会经常飘逸 initPermissionTree($(this).attr("rid")); //getUser(1) //勾选当前角色的权限 //打开模态框 $('#permissModel').modal(options); //将角色id保存到模态框的哪个属性中; //打开模态框将角色id传递给model里面的权限分配按钮 $('#addPermissionBtn').attr("rid",$(this).attr("rid")); }); //treeId:是权限树ul的id //treeNode:当前节点信息 function showIcon(treeId, treeNode) { //console.log(treeId); //treeNode里面有一个tId; //这个tid用来拼串以后就是图标显示位置的元素id和名字显示位置的元素id //tId:"permissionTree_3" //<span id="permissionTree_2_span">用户维护</span> //<span id="permissionTree_2_ico" ></span> //console.log(treeNode); //改图标;找到当前元素图标显示的节点,将这个节点的class设置为当前节点的icon $("#" + treeNode.tId + "_ico").removeClass() .addClass(treeNode.icon); } ///传入角色id,将当前角色拥有的权限勾选 function checkcurPermisson(rid) { // /permission/role/perm/4 $.getJSON("${ctp}/permission/role/perm/" + rid, function(data) { //查出的当前角色拥有的权限 //ztree对象的方法;checkNode; //三个参数: //第一个参数就是要勾选的节点 //第二个参数就是勾选与否 //第三个参数是是否和父节点级联互动 //第四个参数是勾选状态变化后,是否调用之前用(callback)规定的回调函数 $.each(data, function() { //console.log(this); //从ztree中获取到要勾选的对象; var node = ztreeObject.getNodeByParam("id", this.id, null); ztreeObject.checkNode(node, true, false); }) }) } function initPermissionTree(rid) { var setting = { data : { simpleData : { enable : true, idKey : "id", pIdKey : "pid", }, key : { url : "haha" } }, view : { //自定义显示的效果 addDiyDom : showIcon }, // 图标前的选中框开启 check : { enable : true } }; //从数据库查出的所有权限节点数据 //发送ajax请求获取到所有权限的json数据 $.getJSON("${ctp}/permission/role/json", function(nodes) { //console.log(nodes); //给每一个节点修改或者添加一些属性 父菜单pid为0 $.each(nodes, function() { if (this.pid == 0) { this.open = true; } }) //如果不是用var声明的变量,这个变量就默认变为全局的 //把初始化好的ztree对象传递给外界使用,可以通用操作这个对象,来改变树 //ztree为了不影响下面的操作是异步展示数据的 ztreeObject = $.fn.zTree.init($("#permissionTree"), setting, nodes); checkcurPermisson(rid); }) } </script>
$.getJSON(url [, data ] [, success ] )方法函数主要用来从服务器加载json编码的数据
相当于
$.ajax({ dataType: "json", url: url, data: data, success: success });
分配权限数据读取
<div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">关闭</button> <button type="button" class="btn btn-primary" id="addPermissionBtn">分配权限</button> </div>
//点击分配权限按钮, //模态框的按钮 $("#addPermissionBtn").click(function(){ //1、获取当前我们已经选中的权限 var nodes = ztreeObject.getCheckedNodes(true); //2、将这些权限的id和角色的id发给程序 var permission_ids = ""; $.each(nodes,function(){ permission_ids += this.id+","; }); var rid = $(this).attr("rid"); //3、使用程序保存这个角色对应的权限的值 }) }); $(".assignPermissionModelBtn").click(function() { var options = { backdrop : 'static', show : true } //"permissionTree"刷出权限树 //js的this会经常飘逸 initPermissionTree($(this).attr("rid")); //getUser(1) //勾选当前角色的权限 //打开模态框 $('#permissModel').modal(options); //将角色id保存到模态框的哪个属性中; //打开模态框将角色id传递给model里面的权限分配按钮 $('#addPermissionBtn').attr("rid",$(this).attr("rid")); });
更新角色权限
RoleController
package com.atguigu.scw.manager.controller.permission; // 处理角色维护模块 @RequestMapping("/permission/role") @Controller public class RoleController { @Autowired RoleService roleService; @Autowired TPermissionService permissionService; /** * 更新角色权限 * 1.先删除当前角色的所有权限 * 2.在新增之前选中的所有权限 */ @ResponseBody // ajax请求 @RequestMapping("/update") public String deleteRolePermission(@RequestParam("pids")String pids, @RequestParam("rid")Integer rid) { boolean flag = permissionService.updatePermission(pids, rid); return "ok"; } // 省略 }
接口增加上面方法,实现该方法
package com.atguigu.scw.manager.service; import java.util.List; import com.atguigu.scw.manager.bean.TPermission; public interface TPermissionService { // 拿到所有菜单 public List<TPermission> getAllMenus(); public List<TPermission> getPermissions(); public List<TPermission> getRolePermission(Integer rid); public boolean updatePermission(String pids, Integer rid); }
实现方法
package com.atguigu.scw.manager.service.impl; @Service public class TPermissionServiceImpl implements TPermissionService { @Autowired TPermissionMapper mapper; @Autowired TRolePermissionMapper rolePermissionMapper; // 省略 public boolean updatePermission(String pids, Integer rid) { // 1.删除当前角色的所有权限 TRolePermissionExample example = new TRolePermissionExample(); Criteria criteria = example.createCriteria(); criteria.andRoleidEqualTo(rid); rolePermissionMapper.deleteByExample(example); // 2.新增 String[] split = pids.split(","); if (split != null && split.length>=1) { for (String pid : split) { int i = Integer.parseInt(pid); TRolePermission permission = new TRolePermission(); // 设置角色id permission.setRoleid(rid); // 设置权限id permission.setPermissionid(i); // 保存角色权限关系 rolePermissionMapper.insertSelective(permission); } return true; } return false; } }
js
$("#addPermissionBtn").click(function(){ //1、获取当前我们已经选中的权限 var nodes = ztreeObject.getCheckedNodes(true); //2、将这些权限的id和角色的id发给程序 var permission_ids = ""; $.each(nodes,function(){ permission_ids += this.id+","; }); var rid = $(this).attr("rid"); //3、使用程序保存这个角色对应的权限的值 //写程序;删除对应的东西即可 $.get("${ctp}/permission/role/update?pids="+permission_ids+"&rid="+rid,function(){ alert("权限分配成功"); $('#permissModel').modal("hide"); }) });
后续完成
几个同类的增删改查:
1.项目分类 每个项目属于一类 类别的增删改查
2.项目标签(目前做独立的)
每个分类下有一些标签,小分类(spu)
和分类没联系
经常使用的技巧:
1)抽取页面
2)利用某个按钮获取某个元素设置自定义属性来给回调函数带值
<button uid="${user.id}"></button>
$("#btn").click(function(){
// 用户id
$(this).attr("uid")
})
3)给某个元素绑定属性值
绑定:jQuery.data(element,[key],[value])
获取: 当前jQuery对象.key
4)写一个功能的流程:
- 从登陆注册写起
- 具体某一个功能,分清楚整个跳转逻辑
- 搭出整个跳转流程
- 分析执行功能要给服务器带什么数据 想尽办法把页面带给服务器的数据组装好
- 服务器 收到数据进行增删改查分析 原则:能用mbg生成的dao自带的CRUD就用自带的,不能就给这个dao新增方法
- 梳理清楚流程,脑海中必须有实现出的最终效果