Spring Boot 和 AdminLTE 的集成

Spring Boot 和 AdminLTE 的集成

AdminLTE 是个开源的管理模板,首页:http://adminlte.io/,GitHub地址:https://github.com/almasaeed2010/AdminLTE,目前有 2w+ star,100 多个 contributor,可以说是非常出名的开源管理模板了。

image

这篇描述将 AdminLTE 和 Spring Boot 整合起来进行后台开发并利用 AdminLTE 的前端组件、模板、布局。

  • 使用的 AdminLTE 版本 v2.4.3 (2018-02-22)
  • 项目地址:https://github.com/yingw/adminlte-boot-template

下面将介绍三种前后端集成的方式

  • static:所有 AdminLTE 的静态资源直接集成到项目
  • webjars:用 Webjars 将前端库集成到后端 maven 的依赖 jar 中
  • bower:用 Bower 将前端依赖定义,在项目编译过程中创建前端资源

1. 初步集成

1.1. 创建 Spring Boot 项目

从 http://start.spring.io/ 或者 IDE 中创建一个 Spring Boot 项目,依赖:Web、Thymeleaf、DevTools

1.2. 下载 AdminLTE

从 AdminLTE 的 GitHub release 页 下载项目(v2.4.3),解压

  • 拷贝 pages 目录、index.html、index2.html、start.html 到 templates 目录
  • 拷贝 dist 下 css、img、js 目录、bower_components、plugins 目录到 static 目录

    注意的是 bower_components 内有上千文件,拷贝、编译都很慢,虽然用后面的 webjars 依赖可以避免,目前还是需要的,在项目代码中没有放,请自行拷贝。

1.3. 修正路径

批量替换 pages 下面页面的一些相对路径,主要是 css、js、img 的引用

  • ../../dist/ 替换为 ../../
  • ../dist/ 替换为 ../
  • "dist/ 替换为 "./
  • 还有一些上级目录的如 index.html 替换

1.4. 动态跳转控制器

创建一个动态跳转控制器 AdminController

/**
 * @author yinguowei@gmail.com 2018/3/27.
 */
@Controller
class AdminController {
    private static Logger logger = LoggerFactory.getLogger(AdminController.class);

    @GetMapping("/")
    public String home() {
        return "redirect:index2.html";
    }

    @GetMapping(value = {"/**/*.html"})
    public String route(HttpServletRequest request) {
        logger.debug("AdminController.route: request.getRequestURI() = {}", request.getRequestURI());
        String path = request.getRequestURI();
        return path;
    }
}

设置些属性 application.properties

spring.thymeleaf.cache=false
spring.thymeleaf.suffix=

设置了这个控制器后所有的 .html 就可以跳转到对应的视图。如果将来不希望通过 .html 后缀访问 url,而是采用类似 restful 的地址,可以去掉 spring.thymeleaf.suffix 定义(默认是 .html),并在解析时候去掉 .html

    @RequestMapping(value = {"/**/*.html"})
    public String route(HttpServletRequest request) {
        logger.debug("DynamicController.route: request.getRequestURI() = {}", request.getRequestURI());
        String path = request.getRequestURI();
        return path.substring(1, path.length() - 5); // remove "/" and ".html"
    }

1.5. 字体和主题

临时去掉 Googleapi 字体

由于 googleapi 的字体可能被墙,建议全部注释

<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600,700,300italic,400italic,600italic">

加上雅黑字体

并在主题内加上 AdminLTE.css 和 AdminLTE.min.css

font-family: 'Microsoft YaHei UI', 'Source Sans Pro', 'Helvetica Neue', Helvetica, Arial, sans-serif;

来使用客户端的微软雅黑字体

主题替换

如果需要主题,定制专门的 skin 和 skin.min.css

替换 <link rel="stylesheet" href="/css/skins/_all-skins.min.css"><link rel="stylesheet" href="dist/css/skins/skin-blue.min.css">

生成 min.css

TBD,有在线工具

1.6. 其他修正

部分页面由于 json/javascript 格式问题和 Thymeleaf 冲突,比如 charts/flot.html 改成:

<script th:inline="none">

1.7. 静态测试

Thymeleaf 的一大好处就是可以直接打开 html 进行页面测试而不需要启动服务器。编辑各 stylesheet 和 javascript 的应用地址,改为和当前页面相对,如:

<html xmlns:th="http://www.thymeleaf.org">

<link rel="stylesheet" href="../static/bower_components/bootstrap/dist/css/bootstrap.min.css" th:href="{/bower_components/bootstrap/dist/css/bootstrap.min.css}">
<script src="../static/bower_components/jquery/dist/jquery.min.js" th:src="@{/bower_components/jquery/dist/jquery.min.js}"></script>

但注意这一步也可以不用急着改太多页面,而是只改一两个测试下,因为后面要放到 Layout 公共页面统一改。

小结

经过这一系列集成,已经可以跑起来测试 http://localhost:8080,会自动跳转到 index2.html,可能有些路径的修正不完善或有问题,观察控制台 404 异常修正。

2. Thymeleaf Layout

Layout 是让多个页面共用一套页面模板,这样很多重复的代码就不用重复编码了。

引入 pom 依赖

<dependency>
  <groupId>nz.net.ultraq.thymeleaf</groupId>
  <artifactId>thymeleaf-layout-dialect</artifactId>
</dependency>

在 layout 目录创建 layout.html,可以用 index2.html 拷贝过去修改

2.1 layout/layout.html

标题

  <title layout:title-pattern="$LAYOUT_TITLE | $CONTENT_TITLE">AdminLTE 2</title>

修改原来的相对地址,去掉 static,只保留大部分页面都要用的如 bootstrap, jquery, datatable

  <!-- 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">
  <!-- jvectormap -->
  <link rel="stylesheet" href="/bower_components/jvectormap/jquery-jvectormap.css">
  <!-- Theme style -->
  <link rel="stylesheet" href="/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="/css/skins/_all-skins.min.css">

修改菜单可以动态根据传入变量选中

<li class="treeview" th:classappend="${menu=='index' || menu=='index2' ? 'active menu-open' : ''}">
  <ul class="treeview-menu">
    <li th:classappend="${menu=='index' ? 'active' : ''}"><a href="/index.html"><i class="fa fa-circle-o"></i> Dashboard v1</a></li>

修改 img 的相对地址,如

<img class="direct-chat-img" src="../static/img/user1-128x128.jpg" th:src="@{/img/user1-128x128.jpg}" alt="message user image">

js

<!-- jQuery 3 -->
<script src="/bower_components/jquery/dist/jquery.min.js"></script>
<!-- Bootstrap 3.3.7 -->
<script src="/bower_components/bootstrap/dist/js/bootstrap.min.js"></script>
<!-- AdminLTE App -->
<script src="/js/adminlte.min.js"></script>

<!-- Optionally -->
<!-- Slimscroll -->
<script src="/bower_components/jquery-slimscroll/jquery.slimscroll.min.js"></script>
<!-- FastClick -->
<script src="/bower_components/fastclick/lib/fastclick.js"></script>
<!-- AdminLTE for demo purposes -->
<script src="/js/demo.js"></script>

<div layout:fragment="customScript" th:remove="tag">

</div>

如果想单独测试 layout.html,跟下面 index2 一样修改加上静态和动态的地址

声明插入点

<div class="content-wrapper" layout:fragment="content">
...
<div layout:fragment="customScript" th:remove="tag">
</tag>

2.2 index2.html

修改 index2.html、start.html、blank.html 来使用 layout


<html xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
      layout:decorate="~{layout/layout.html}"
      th:with="menu='index2'">

stylesheet 和 javascript

为了本地测试,保留 stylesheet 和 javascript,但是加上 th:remove="all" 在解析时自己删掉

  <!-- Bootstrap 3.3.7 -->
  <link rel="stylesheet" href="../static/bower_components/bootstrap/dist/css/bootstrap.min.css" th:remove="all">
  <!-- Font Awesome -->
  <link rel="stylesheet" href="../static/bower_components/font-awesome/css/font-awesome.min.css" th:remove="all">
  <!-- Ionicons -->
  <link rel="stylesheet" href="../static/bower_components/Ionicons/css/ionicons.min.css" th:remove="all">
  <!-- Theme style -->
  <link rel="stylesheet" href="../static/css/AdminLTE.min.css" th:remove="all">
  <!-- AdminLTE Skins. -->
  <link rel="stylesheet" href="../static/css/skins/_all-skins.min.css" th:remove="all">
  <!-- jvectormap -->
  <link rel="stylesheet" href="../static/bower_components/jvectormap/jquery-jvectormap.css" th:remove="all">
  <!-- 表格 -->
  <link rel="stylesheet" href="../static/bower_components/datatables.net-bs/css/dataTables.bootstrap.min.css" th:remove="all">
  <!-- PACE -->
  <link rel="stylesheet" href="../static/bower_components/PACE/themes/blue/pace-theme-minimal.css" th:remove="all">

js,页面自定义的 js 可以放到 customScript fragment 里面去

<!-- jQuery 3 -->
<script src="../static/bower_components/jquery/dist/jquery.min.js" th:remove="all"></script>
<!-- Bootstrap 3.3.7 -->
<script src="../static/bower_components/bootstrap/dist/js/bootstrap.min.js" th:remove="all"></script>
<!-- FastClick -->
<script src="../static/bower_components/fastclick/lib/fastclick.js" th:remove="all"></script>
<!-- AdminLTE App -->
<script src="../static/js/adminlte.min.js" th:remove="all"></script>

<div layout:fragment="customScript">

  <!-- Sparkline -->
  <script src="../static/bower_components/jquery-sparkline/dist/jquery.sparkline.min.js" th:src="@{/bower_components/jquery-sparkline/dist/jquery.sparkline.min.js}"></script>
  <!-- jvectormap  -->
  <script src="../static/plugins/jvectormap/jquery-jvectormap-1.2.2.min.js" th:src="@{/plugins/jvectormap/jquery-jvectormap-1.2.2.min.js}"></script>
  <script src="../static/plugins/jvectormap/jquery-jvectormap-world-mill-en.js" th:src="@{/plugins/jvectormap/jquery-jvectormap-world-mill-en.js}"></script>
  <!-- SlimScroll -->
  <script src="../static/bower_components/jquery-slimscroll/jquery.slimscroll.min.js" th:src="@{/bower_components/jquery-slimscroll/jquery.slimscroll.min.js}"></script>
  <!-- ChartJS -->
  <script src="../static/bower_components/chart.js/Chart.js" th:src="@{/bower_components/chart.js/Chart.js}"></script>
  <!-- AdminLTE dashboard demo (This is only for demo purposes) -->
  <script src="../static/js/pages/dashboard2.js" th:src="@{/js/pages/dashboard2.js}"></script>
  <!-- AdminLTE for demo purposes -->
  <script src="../static/js/demo.js" th:src="@{/js/demo.js}"></script>

</div>

删掉不用的节点

删掉:navbar-custom-menumain-sidebar(也可以保留菜单测试)、main-footercontrol-sidebarcontrol-sidebar-bg

内容声明

在 content-wrapper 上声明

<div class="content-wrapper" layout:fragment="content">

2.3 login layout

还有些 404、500 页面使用的是和 layout 完全不同的布局,也可以提炼一个 layout-login,然后 login.html、logout.html、404、500 等都使用这个布局,这里就不重复了。

总结

通过使用 layout,可以将大部分页面共用代码提取出来,通过 fragment 插入页面的定制内容。但是这里大部分页面将来都不会是项目内必须使用的,就不全部改了。

3. Webjars

上面介绍的基本就是静态集成的全部内容,不过前面提到,要把 bower_componenets 这个几千个文件夹的第三方 js、css 依赖库放到项目管理中,总是不太方便的,对于后端开发来说,最好前端的组件也是几个依赖来管理就最简单了,webjars 就是以这个目标设计的工具。

3.1 Webjars 依赖

根据项目使用的库的版本,到 webjars 官网去搜索对应的定义即可,再把 maven 定义拷进来。

例如:

<!--bootstrap-->
<dependency>
	<groupId>org.webjars.bower</groupId>
	<artifactId>bootstrap</artifactId>
	<version>3.3.7</version>
</dependency>

所有的声明

<!-- Webjars begin -->
<!--bootstrap-->
<dependency>
	<groupId>org.webjars.bower</groupId>
	<artifactId>bootstrap</artifactId>
	<version>3.3.7</version>
</dependency>
<!--font-awesome-->
<dependency>
	<groupId>org.webjars.bower</groupId>
	<artifactId>font-awesome</artifactId>
	<version>4.7.0</version>
</dependency>
<!--ionicons-->
<dependency>
	<groupId>org.webjars.bower</groupId>
	<artifactId>ionicons</artifactId>
	<version>2.0.1</version>
</dependency>
<!--morrisjs-->
<dependency>
	<groupId>org.webjars.bower</groupId>
	<artifactId>morrisjs</artifactId>
	<version>0.5.1</version>
</dependency>
<dependency>
	<groupId>org.webjars.bower</groupId>
	<artifactId>raphael</artifactId>
	<version>2.2.7</version>
</dependency>
<!--sparkline-->
<dependency>
	<groupId>org.webjars.bower</groupId>
	<artifactId>jquery-sparkline</artifactId>
	<version>2.1.3</version>
</dependency>
<!--jvectormap-->
<dependency>
	<groupId>org.webjars</groupId>
	<artifactId>jvectormap</artifactId>
	<version>2.0.4</version>
</dependency>
<dependency>
	<groupId>org.webjars.bower</groupId>
	<artifactId>bower-jvectormap</artifactId>
	<version>1.2.2</version>
</dependency>
<!--datepicker-->
<dependency>
	<groupId>org.webjars.bower</groupId>
	<artifactId>bootstrap-datepicker</artifactId>
	<version>1.7.1</version>
</dependency>
<!--daterangepicker-->
<dependency>
	<groupId>org.webjars.bower</groupId>
	<artifactId>bootstrap-daterangepicker</artifactId>
	<version>2.1.27</version>
</dependency>
<!--moment-->
<dependency>
	<groupId>org.webjars.bower</groupId>
	<artifactId>moment</artifactId>
	<version>2.20.1</version>
</dependency>
<!--knob-->
<dependency>
	<groupId>org.webjars.bower</groupId>
	<artifactId>jquery-knob</artifactId>
	<version>1.2.13</version>
</dependency>
<!--chartjs-->
<dependency>
	<groupId>org.webjars.bower</groupId>
	<artifactId>chartjs</artifactId>
	<version>1.0.2</version>
</dependency>
<!--icheck-->
<dependency>
	<groupId>org.webjars.bower</groupId>
	<artifactId>iCheck</artifactId>
	<version>1.0.2</version>
</dependency>
<!--Flot.js-->
<dependency>
	<groupId>org.webjars.bower</groupId>
	<artifactId>flot</artifactId>
	<version>0.8.3</version>
</dependency>
<!--color picker-->
<dependency>
	<groupId>org.webjars.bower</groupId>
	<artifactId>bootstrap-colorpicker</artifactId>
	<version>2.5.1</version>
</dependency>
<!--select2-->
<dependency>
	<groupId>org.webjars.bower</groupId>
	<artifactId>select2</artifactId>
	<version>4.0.5</version>
</dependency>
<!--ckeditor-->
<dependency>
	<groupId>org.webjars.npm</groupId>
	<artifactId>ckeditor</artifactId>
	<version>4.8.0</version>
</dependency>
<!--PACE (update from original plugins-->
<dependency>
	<groupId>org.webjars.bower</groupId>
	<artifactId>pace</artifactId>
	<version>1.0.2</version>
</dependency>

<!--datatables-->
<dependency>
	<groupId>org.webjars.bower</groupId>
	<artifactId>datatables.net</artifactId>
	<version>1.10.16</version>
</dependency>
<dependency>
	<groupId>org.webjars.bower</groupId>
	<artifactId>datatables.net-bs</artifactId>
	<version>2.1.1</version>
</dependency>
<!--fastclick-->
<dependency>
	<groupId>org.webjars.bower</groupId>
	<artifactId>fastclick</artifactId>
	<version>1.0.6</version>
</dependency>
<!--jquery-->
<dependency>
	<groupId>org.webjars.bower</groupId>
	<artifactId>jquery</artifactId>
	<version>3.3.1</version>
</dependency>
<!--jquery-ui-->
<dependency>
	<groupId>org.webjars</groupId>
	<artifactId>jquery-ui</artifactId>
	<version>1.11.4</version>
</dependency>
<!--metisMenu-->
<dependency>
	<groupId>org.webjars</groupId>
	<artifactId>metisMenu</artifactId>
	<version>2.7.0</version>
</dependency>
<!--slimScroll-->
<dependency>
	<groupId>org.webjars</groupId>
	<artifactId>jQuery-slimScroll</artifactId>
	<version>1.3.8</version>
</dependency>
<!--pace (updated from Plugins)-->
<dependency>
	<groupId>org.webjars</groupId>
	<artifactId>pace</artifactId>
	<version>1.0.2</version>
</dependency>
<!-- sweetalert -->
<dependency>
	<groupId>org.webjars.npm</groupId>
	<artifactId>sweetalert</artifactId>
	<version>2.1.0</version>
</dependency>

<!-- Webjars end -->

3.2 修正路径

替换 bower_components 为 /webjars,可以直接从 /webjars 开始应用这些依赖,如:

<link rel="stylesheet" href="/webjars/bootstrap/3.3.7/dist/css/bootstrap.min.css">

注意个别有大小写问题:Ionicons,等等

有些 plugins 目录的依赖也可以通过 webjars 改掉,可能是作者稍微做了修改,如 pace

注意将来要是用上 Spring Security,记得把 webjars 上下文的资源设置为可以访问

..., "/webjars/**").permitAll();

3.3 Webjars Locator

还有个 Webjars 的 Locator 可以用来自动检索版本,写引用 url 的时候就可以连版本号也省略了。

但是会没有代码提示功能,而且只在版本需要经常升级不想动代码的时候才有用,意义不大。

<!--webjars-locator-->
<dependency>
	<groupId>org.webjars</groupId>
	<artifactId>webjars-locator</artifactId>
	<version>0.30</version>
</dependency>

3.4 使用 webjars 的限制

使用 webjars,也有缺点,就是在静态测试的时候,没法直接引用 jar 内的样式和脚本,所以用 webjars 的时候就不能做静态测试了;好处是不用在代码库中存着那上千个依赖。各有取舍吧。

4. Bower

最后一种方式,还可以使用 Bower 来在编译时生成依赖文件。需要用到 frontend-maven-plugin,安装 node 和 bower

4.1 node 配置

package.json

{
  "name": "BootifulAdminLTE",
  "version": "1.0.0",
  "description": "Bootiful-AdminLTE application",
  "dependencies": {
    "bower": "~1.8.4"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/yingw/bootiful-adminlte.git"
  },
  "author": "yinguowei",
  "license": "MIT"
}
  • 也可以根目录执行 npm init,创建 package.json,加上 bower:npm install bower --save
  • 建议加上 description、repository,否则会有一些告警

4.2 Bower 配置

AdminLTE 本身就用了 bower 来管理依赖,拷贝项目中的 bower.json 到根目录,创建 .bowerrc

bower.json

{
  "name": "admin-lte",
  "homepage": "https://adminlte.io",
  "authors": [
    "Abdullah Almsaeed <abdullah@almsaeedstudio.com>"
  ],
  "description": "Admin dashboard and control panel template",
  "main": [
    "index2.html",
    "dist/css/AdminLTE.css",
    "dist/js/adminlte.js",
    "build/less/AdminLTE.less"
  ],
  "keywords": [
    "css",
    "js",
    "html",
    "template",
    "admin",
    "bootstrap",
    "theme",
    "backend",
    "responsive"
  ],
  "license": "MIT",
  "ignore": [
    "/.*",
    "node_modules",
    "bower_components",
    "composer.json",
    "documentation"
  ],
  "dependencies": {
    "bootstrap-slider": "*",
    "chart.js": "1.0.*",
    "ckeditor": "^4.7.0",
    "bootstrap-colorpicker": "^2.5.1",
    "bootstrap": "^3.3.7",
    "jquery": "^3.2.1",
    "datatables.net": "^1.10.15",
    "datatables.net-bs": "^2.1.1",
    "bootstrap-datepicker": "^1.7.0",
    "bootstrap-daterangepicker": "^2.1.25",
    "moment": "^2.18.1",
    "fastclick": "^1.0.6",
    "Flot": "flot#^0.8.3",
    "fullcalendar": "^3.4.0",
    "inputmask": "jquery.inputmask#^3.3.7",
    "ion.rangeSlider": "ionrangeslider#^2.2.0",
    "jvectormap": "^2.0.4",
    "jquery-knob": "^1.2.13",
    "morris.js": "^0.5.1",
    "PACE": "pace#^1.0.2",
    "select2": "^4.0.3",
    "jquery-slimscroll": "slimscroll#^1.3.8",
    "bootstrap-timepicker": "^0.5.2",
    "jquery-sparkline": "^2.1.3",
    "font-awesome": "^4.7.0",
    "Ionicons": "ionicons#^2.0.1",
    "jquery-ui": "1.11.4"
  },
  "resolutions": {
    "jquery": "^3.2.1"
  }
}

可以在最后再加入些从 plugins 切换来的依赖

    "jquery-validation": "^1.17.0",
    "datatables-plugins": "^1.10.15",
    "iCheck": "^1.0.2",
    "html5shiv": "^3.7.3",
    "respond": "Respond#^1.4.2",
    "datatables-i18n": "^1.0.4",
    "zTree": "^3.5.33",
    "switchery": "^0.8.2"

有版本冲突的话可以在最后的 resolutions 里面添加定义

  "resolutions": {
    "fastclick": "^1.0.6",
    "jquery": "^3.2.1"
  }

.bowerrc

{
  "directory" : "src/main/resources/static/bower_components",
  "allow_root": true
}

指定输出目录(默认根目录),并允许 root 执行(在 Linux 下打包用)

4.3 frontend-maven-plugin

使用 frontend-maven-plugin 来安装 Node 和 Bower。

在 pom 里面定义

    <properties>
        <frontend-maven-plugin.version>1.6</frontend-maven-plugin.version>
        <node.version>v8.10.0</node.version>
        <npm.version>5.6.0</npm.version>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>com.github.eirslett</groupId>
                <artifactId>frontend-maven-plugin</artifactId>
                <version>${frontend-maven-plugin.version}</version>
                <executions>
                    <execution>
                        <id>install node and npm</id>
                        <goals>
                            <goal>install-node-and-npm</goal>
                        </goals>
                        <configuration>
                            <nodeVersion>${node.version}</nodeVersion>
                            <npmVersion>${npm.version}</npmVersion>
                            <!-- if you don't need to download from these 3rd party registry, comments these -->
                            <nodeDownloadRoot>https://npm.taobao.org/mirrors/node/</nodeDownloadRoot>
                            <npmDownloadRoot>https://registry.npm.taobao.org/npm/-/</npmDownloadRoot>
                        </configuration>
                    </execution>
                    <execution>
                        <id>npm install</id>
                        <goals>
                            <goal>npm</goal>
                        </goals>
                        <configuration>
                            <npmInheritsProxyConfigFromMaven>false</npmInheritsProxyConfigFromMaven>
                        </configuration>
                    </execution>
                    <execution>
                        <id>bower install</id>
                        <goals>
                            <goal>bower</goal>
                        </goals>
                        <configuration>
                            <bowerInheritsProxyConfigFromMaven>false</bowerInheritsProxyConfigFromMaven>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
  • install-node-and-npm: 安装 node 和 npm,并使用的淘宝镜像
  • npm: 执行 npm install,禁用 maven 的代理
  • bower: 执行 bower install,禁用 maven 的代理

这样就会在 static 目录创建出 bower_components 并下载好所有依赖,第一次比较慢,之后就快了。

运行 mvn spring-boot:run 就可以编译执行

使用本项目

clone 后,由于 master 分支是基于静态依赖,但是没有提交 bower_components 目录。可以:

  1. 第一种方式自己下载 AdminLTE 后解压该目录到 static 目录
  2. 第二种方式直接用 webjars 分支
  3. 第三种方式先切换到 bower 分支,编译完成就自动下载在 static 目录了,再切换回 static 目录或者直接使用 bower 分支

个人建议用 webjars 分支,如果对 node、bower 很熟悉也不在乎超多文件打包就使用 bower 分支。

详细的命令查看项目首页 README:https://github.com/yingw/bootiful-adminlte.git

上篇Service 层缓存
下篇构建喊图片的“ASCII牛(COWSAY)”docker 镜像