最近工作上做了較多登陸模塊的東西,一個較完善的登陸模塊會涉及到不少知識點,如SSO、用戶權限管理,Redis,今天給大家詳細介紹用戶權限管理這一功能模塊中的動態菜單處理。
先展示需求的效果圖:
一、實現過程簡介:
用戶進行登陸操作,請求進入後臺時,數據庫根據用戶的職能去查詢該用戶可操作的菜單項目,數據庫中存放單條菜單項,通過parent_id是否爲0和child_id來實現父子層級關係,如 parent_id = 1 的菜單項(人員管理、角色管理、菜單管理)均爲 menu_id = 1菜單項(權限管理)的子菜單,順序由他們的 child_id 大小排序。簡單的菜單設計顯示爲如下效果:
由於菜單存在級聯關係,在返回值上我選用了HashMap。
二、代碼實現部分:
Ajax請求菜單(個人認爲前端解析難度大於後臺獲取)
(1)index.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<script type="text/javascript" src="js/jquery-3.1.1.min.js"></script>
</head>
<body>
<h2>Hello World!</h2>
<hr>
<input type="button" value="點擊獲取菜單" id="getmenu">
<div id="menuDiv" style="height:500px;font-size: 10px;">
</div>
<script>
$('#getmenu').click(function(){
$.ajax({
url:'Getmenu',
type:'get',
dataType:'text',
success:function (data) {
$('#menuDiv').empty(); //清空div內容
var data=eval("("+data+")");
var parent_arr = Object.getOwnPropertyNames(data); //獲取data屬性集合,即parent_menu
for(var i = 0;i<parent_arr.length;i++){ //遍歷parent_menu
var obj2=eval("("+parent_arr[i]+")");
$('#menuDiv').append("<hr><input type='checkbox' >"+obj2.menu_name+"<hr>");
for(var j = 0;j<data[parent_arr[i]].length;j++){ //獲取parent_menu下的child_menu
$('#menuDiv').append("<input type='checkbox' style='margin-left:20px;'>"+data[parent_arr[i]][j].menu_name+"<br>");
}
}
}
});
});
</script>
</body>
</html>
(1)Getmenu.java(接收請求並構造動態菜單):
@WebServlet(urlPatterns="/Getmenu")
public class Getmenu extends HttpServlet {
MenuDao menuDao = new MenuDao();
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// response.setContentType("text/xml;charset=UTF-8");
response.setCharacterEncoding("utf-8");
response.setContentType("text/plain;charset=utf-8");
PrintWriter out = response.getWriter();
List<Menu> parentMenu = menuDao.getParentMenu(); //獲取數據庫所有父菜單
List<Menu> childMenu = menuDao.getChildMenu(); //獲取數據庫所有子菜單
Map<Menu,List<Menu>> menuList = new HashMap<Menu,List<Menu>>(); //創建結果菜單menuList
List<Menu> TempChildMenu = null; //創建臨時子菜單
for(Menu parent_menu:parentMenu){ //裝載並遍歷父菜單
TempChildMenu = new ArrayList<Menu>();
for(Menu child_menu:childMenu){ //遍歷父菜單,遍歷過程通過判斷,再遍歷篩選子菜單
if(parent_menu.getMenu_id() == child_menu.getParent_id()){
TempChildMenu.add(child_menu); //裝載子菜單
}
}
menuList.put(parent_menu,TempChildMenu); //裝載父菜單
}
Gson gson = new Gson();
out.write(gson.toJson(menuList));
out.close();
System.out.println(menuList);
}
}
(2)MenuDao.java(數據庫查詢菜單實現類):
public class MenuDao extends BaseDao {
public List<Menu> getParentMenu(){
List<Menu> menus = new ArrayList<Menu>();
Menu menu = null;
try{
String sql = "select * from menu_table where parent_id = 0";
Object[] params = {};
ResultSet rs = this.executeSQL(sql,params);
while(rs.next()){
menu = new Menu();
menu.setMenu_id(rs.getInt(1));
menu.setMenu_name(rs.getString(2));
menu.setParent_id(rs.getInt(3));
menu.setChild_id(rs.getInt(4));
menus.add(menu);
}
}catch (SQLException e){
e.printStackTrace();
}
return menus;
}
public List<Menu> getChildMenu(){
List<Menu> menus = new ArrayList<Menu>();
Menu menu = null;
try{
String sql = "select * from menu_table where parent_id > 0";
Object[] params = {};
ResultSet rs = this.executeSQL(sql,params);
while(rs.next()){
menu = new Menu();
menu.setMenu_id(rs.getInt(1));
menu.setMenu_name(rs.getString(2));
menu.setParent_id(rs.getInt(3));
menu.setChild_id(rs.getInt(4));
menus.add(menu);
}
}catch (SQLException e){
e.printStackTrace();
}
return menus;
}
}
(3)BaseDao.java(數據庫鏈接基Dao):
public class BaseDao {
protected Connection conn;
protected PreparedStatement ps;
protected Statement stmt;
protected ResultSet rs;
//獲取數據庫連接
public boolean getConnection(){
//讀取配置信息
PropertiesUtils.loadFile("config.properties");
String url = PropertiesUtils.getPropertyValue("url");
String username = PropertiesUtils.getPropertyValue("username");
String password = PropertiesUtils.getPropertyValue("password");
String driver = PropertiesUtils.getPropertyValue("driver");
//加載jdbc驅動
try{
Class.forName(driver);
//與數據庫建立連接
conn = DriverManager.getConnection(url,username,password);
}catch(ClassNotFoundException e){
e.printStackTrace();
return false;
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
return true;
}
//增刪改
public int executeUpdate(String sql,Object[] params){
int updateRows = 0;
getConnection();
try{
ps = conn.prepareStatement(sql);
for(int i= 0;i<params.length;i++){
ps.setObject(i+1, params[i]);
}
updateRows = ps.executeUpdate();
}catch(SQLException e){
e.printStackTrace();
}
return updateRows;
}
//查詢
public ResultSet executeSQL(String sql,Object[] params){
getConnection();
try{
ps = conn.prepareStatement(sql);
for(int i=0;i<params.length;i++){
ps.setObject(i+1, params[i]);
}
rs = ps.executeQuery();
}catch(SQLException e){
e.printStackTrace();
}
return rs;
}
//關閉資源
public boolean close(){
if(rs!=null){
try{
rs.close();
}catch(SQLException E){
E.printStackTrace();
return false;
}
}
if(ps !=null){
try{
ps.close();
}catch(SQLException E){
E.printStackTrace();
return false;
}
}
if(stmt!=null){
try{
stmt.close();
}catch(SQLException E){
E.printStackTrace();
return false;
}
}
if(conn!=null){
try{
conn.close();
}catch(SQLException E){
E.printStackTrace();
return false;
}
}
return true;
}
}
(4)config.properties(數據庫連接配置文件):
##jdbc config
driver = com.mysql.jdbc.Driver
url = jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=utf8
username = root
password = 123456
(5)PropertiesUtils.java(數據庫連接通過配置文件實現的工具類):
public class PropertiesUtils {
static Properties prop = new Properties();
/**
* @param fileName 需要加載的properties文件,文件需要放在src根目錄下
* 是否加載成功
*/
public static boolean loadFile(String fileName){
try {
prop.load(PropertiesUtils.class.getClassLoader().getResourceAsStream(fileName));
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 根據KEY取回相應的value
*/
public static String getPropertyValue(String key){
return prop.getProperty(key);
}
}
(6)pom.xml
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.32</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.3.1</version>
</dependency>
三、效果演示
四、注意
在加載動態菜單時值得注意的是,ajax的解析類型與後臺java的響應類型,個人在success回調函數解析返回data的時候花了較多時間調試,如json對象與object對象取值問題。若需更多的擴展功能,通常的做法建議是前端創建menu.js作爲解析生成菜單的專有方法,實現可動畫菜單的菜單與操作事件。該類方法在前端框架中並不少見,在此就不一一列舉了。