標(biāo)簽(空格分隔): jpa repository 樹(shù)形菜單 adminlte springboot thymeleaf
側(cè)邊欄樹(shù)形結(jié)構(gòu)菜單應(yīng)該是后臺(tái)管理系統(tǒng)的標(biāo)配吧植酥,這里講一下在選用的方案中有thymeleaf,jpa/repository弦牡,adminlte的情況下怎么實(shí)現(xiàn)這個(gè)功能友驮。
實(shí)現(xiàn)
功能雖然簡(jiǎn)單,但是要綜合三種工具來(lái)做驾锰,不太好說(shuō)卸留,所以下面一邊列代碼一遍做點(diǎn)說(shuō)明
layout.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/web/thymeleaf/layout">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>AdminLTE 2 | Dashboard</title>
<!-- Tell the browser to be responsive to screen width -->
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
<!-- Bootstrap 3.3.7 -->
<link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.min.css">
<!-- Font Awesome -->
<link rel="stylesheet" href="bower_components/font-awesome/css/font-awesome.min.css">
<!-- Ionicons -->
<link rel="stylesheet" href="bower_components/Ionicons/css/ionicons.min.css">
<!-- Theme style -->
<link rel="stylesheet" href="dist/css/AdminLTE.min.css">
<!-- AdminLTE Skins. Choose a skin from the css/skins
folder instead of downloading all of them to reduce the load. -->
<link rel="stylesheet" href="dist/css/skins/_all-skins.min.css">
<!-- Morris chart -->
<link rel="stylesheet" href="bower_components/morris.js/morris.css">
<!-- jvectormap -->
<link rel="stylesheet" href="bower_components/jvectormap/jquery-jvectormap.css">
<!-- Date Picker -->
<link rel="stylesheet" href="bower_components/bootstrap-datepicker/dist/css/bootstrap-datepicker.min.css">
<!-- Daterange picker -->
<link rel="stylesheet" href="bower_components/bootstrap-daterangepicker/daterangepicker.css">
<!-- bootstrap wysihtml5 - text editor -->
<link rel="stylesheet" href="plugins/bootstrap-wysihtml5/bootstrap3-wysihtml5.min.css">
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
<!-- Google Font -->
<link rel="stylesheet" >
</head>
<body class="hold-transition skin-blue sidebar-mini">
<div class="wrapper">
<header class="main-header">
<!-- Logo -->
<a href="index2.html" class="logo">
<span class="logo-lg"><b>Ticket</b>Business</span>
</a>
<nav class="navbar navbar-static-top">
<a href="#" class="sidebar-toggle" data-toggle="push-menu" role="button">
<span class="sr-only">Toggle navigation</span>
</a>
</nav>
</header>
<!-- Left side column. contains the logo and sidebar -->
<aside class="main-sidebar">
<!-- sidebar: style can be found in sidebar.less -->
<section class="sidebar">
<!-- sidebar menu: : style can be found in sidebar.less -->
<ul class="sidebar-menu" data-widget="tree">
<li class="header">HEADER</li>
<li class="treeview" th:each="FirstLevelItem : ${FirstLeveles}">
<a href="#">
<i class="fa fa-pie-chart"></i>
<span th:text="${FirstLevelItem.name}">Multilevel</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li><a th:each="SecondLevelItem : ${FirstLevelItem.GetSecondLevelItems()}" th:href="@{${SecondLevelItem.site}}" th:text="${SecondLevelItem.name}"><i class="fa fa-circle-o"></i>Link in level 2</a></li>
</ul>
</li>
</ul>
</section>
<!-- /.sidebar -->
</aside>
<!-- Content Wrapper. Contains page content -->
<div class="content-wrapper" layout:fragment="contentWrapper">
</div>
</div>
<!-- ./wrapper -->
<!-- jQuery 3 -->
<script src="bower_components/jquery/dist/jquery.min.js"></script>
<!-- jQuery UI 1.11.4 -->
<script src="bower_components/jquery-ui/jquery-ui.min.js"></script>
<!-- Resolve conflict in jQuery UI tooltip with Bootstrap tooltip -->
<script>
$.widget.bridge('uibutton', $.ui.button);
</script>
<!-- Bootstrap 3.3.7 -->
<script src="bower_components/bootstrap/dist/js/bootstrap.min.js"></script>
<!-- Morris.js charts -->
<script src="bower_components/raphael/raphael.min.js"></script>
<script src="bower_components/morris.js/morris.min.js"></script>
<!-- Sparkline -->
<script src="bower_components/jquery-sparkline/dist/jquery.sparkline.min.js"></script>
<!-- jvectormap -->
<script src="plugins/jvectormap/jquery-jvectormap-1.2.2.min.js"></script>
<script src="plugins/jvectormap/jquery-jvectormap-world-mill-en.js"></script>
<!-- jQuery Knob Chart -->
<script src="bower_components/jquery-knob/dist/jquery.knob.min.js"></script>
<!-- daterangepicker -->
<script src="bower_components/moment/min/moment.min.js"></script>
<script src="bower_components/bootstrap-daterangepicker/daterangepicker.js"></script>
<!-- datepicker -->
<script src="bower_components/bootstrap-datepicker/dist/js/bootstrap-datepicker.min.js"></script>
<!-- Bootstrap WYSIHTML5 -->
<script src="plugins/bootstrap-wysihtml5/bootstrap3-wysihtml5.all.min.js"></script>
<!-- Slimscroll -->
<script src="bower_components/jquery-slimscroll/jquery.slimscroll.min.js"></script>
<!-- FastClick -->
<script src="bower_components/fastclick/lib/fastclick.js"></script>
<!-- AdminLTE App -->
<script src="dist/js/adminlte.min.js"></script>
<!-- AdminLTE dashboard demo (This is only for demo purposes) -->
<script src="dist/js/pages/dashboard.js"></script>
<!-- AdminLTE for demo purposes -->
<script src="dist/js/demo.js"></script>
</body>
</html>
針對(duì)側(cè)邊欄樹(shù)形樹(shù)形菜單的這個(gè)功能,三個(gè)工具在layout.html中分別有以下的貢獻(xiàn):
- adminlte
class="treeview"
class="treeview-menu"
treeview是li的樣式椭豫,treeview-menu是ul的樣式
- thymeleaf
th:each
th:text
th:each 告訴thymeleaf耻瑟,需要循環(huán)渲染多次當(dāng)前這個(gè)標(biāo)簽(渲染一個(gè)樹(shù)形結(jié)構(gòu)必定是要依賴(lài)循環(huán)操作的);
th:text 告訴thymeleaf當(dāng)前標(biāo)簽的text是什么
- jpa/repository
${FirstLeveles}
${FirstLevelItem.GetSecondLevelItems()}
FirstLeveles對(duì)應(yīng)的是用jpa/repository從數(shù)據(jù)庫(kù)中讀取出來(lái)的第一層的數(shù)據(jù)赏酥;FirstLevelItem.GetSecondLevelItems()對(duì)應(yīng)的是從用jpa/repository從數(shù)據(jù)庫(kù)中讀取出來(lái)的第二層的數(shù)據(jù)喳整。
FirstLevelRepository.java
package springbootexample.repositories;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import springboot.entities.FirstLevel;
@Repository
public interface FirstLevelRepository extends JpaRepository<FirstLevels, Integer> {
}
FirstLevel.java
package springbootexample.entities;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.*;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
/**
* The persistent class for the firstlevel database table.
*
*/
@Entity
@Table(name="firstlevel")
@NamedQuery(name="FirstLevel.findAll", query="SELECT t FROM FirstLevel t")
public class FirstLevel implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Column(name="ID")
private int id;
@Column(name="NAME")
private String name;
public FirstLevel() {
}
public FirstLevel(String name) {
this.name = name;
}
@Transient //告訴hibernage不要固化這個(gè)變量
@JsonSerialize //雖然不固化,但是允許序列化
@JsonDeserialize //雖然不固化裸扶,但是允許反序列化
private List<SecondLevel> secondLevels = new ArrayList<SecondLevel>();
public void addSecondLevel(SecondLevel secondLevel) {
this.secondLevels.add(secondLevel);
}
public List<SecondLevel> GetSecondLevels(){
return this.secondLevels;
}
public int getId() {
return this.id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
SecondLevelRepository.java
package springbootexample.repositories;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import springboot.entities.SecondLevel;
@Repository
public interface SecondLevelRepository extends JpaRepository<SecondLevel, Integer> {
}
SecondLevel.java
package springbootexample.entities;
import java.io.Serializable;
import javax.persistence.*;
/**
* The persistent class for the secondlevel database table.
*
*/
@Entity
@Table(name="secondlevel")
@NamedQuery(name="SecondLevel.findAll", query="SELECT p FROM SecondLevel p")
public class SecondLevel implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Column(name="ID")
private int id;
@Column(name="NAME")
private String name;
@Column(name="SITE")
private String site;
@Column(name="FIRSTLEVEL_ID")
private int firstlevelId;
public SecondLevel() {
}
public int getId() {
return this.id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getSite() {
return this.site;
}
public void setSite(String site) {
this.site = site;
}
public int getFirstLevelId() {
return this.firstlevelId;
}
public void setFirstLevelId(int firstelvelId) {
this.firstelvelId = firstelvelId;
}
}
上面列出來(lái)的是數(shù)據(jù)庫(kù)操作相關(guān)的主要的代碼框都,代碼的重要部分做了一點(diǎn)點(diǎn)的解釋。