转载

基于springboot+mybatisplus构建系统管理平台(二) 原 荐

上一篇主要说到了spring security和mybatis-plus的使用,当然都是使用过程中的一些描述,可能在理解上与实际有一些出入,毕竟是学习的过程,循序渐渐才更有价值。

其实后台的服务基本在之前的基础上已经有了,现在的关键就是前段的界面与后台的集成,当然现在很多应用前后端都已经分离,当我们作为两个服务去部署时,其实又会有很多新问题需要处理,同时会有更多的知识需要去了解,当然毕竟在目前阶段这不属于核心的东西,所有此次依旧将前端代码与后台带打包在一起使用。

一直说到使用vue,其实很早就接触过,但确实也没怎么去使用,一是因为目前工作环境影响;其次前端框架太多,在选择上没有做过过多的评估与对比,所以一直不知道选用什么样的框架与当前工作内容更贴切 。当然由于现在不是vue的教学,我们需要的是一个成型的界面,可供操作,所以vue只是其中的一个技术点,在项目中会结合thymeleaf与ivew来使用。

项目结构大致如下:

基于springboot+mybatisplus构建系统管理平台(二) 原 荐

其中pages存放的是页面相关内容,static则是一些js、css等,由于我们引入了安全框架,同时由于权限配置关系,导致所有的脚步样式图片等资源都会被拦截,因此我们有必要忽略这些镜头资源,在WebSecurityConfigurerAdapter的子类中配置即可:

@Override
public void configure(WebSecurity web) throws Exception {
    web.ignoring().antMatchers("/static/**").antMatchers("/favicon.ico")
            .mvcMatchers("/webjars/**")
            .mvcMatchers("/js/**")
            .mvcMatchers("/css/**");
}

为什么把pages分了这么多,主要是将一个完整的html页面进行了分割,比如头部分,会引入css以及一些其他相关配置,页面也会有相应的布局,比如分为上下左中几个部分,其实只是做了一下分离,这个完全是因人而异。

可以看下common:

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
    <body>
        <th:block th:fragment="common-css">
            <link rel="stylesheet" th:href="@{/webjars/iview/dist/styles/iview.css}">
            <link rel="stylesheet" th:href="@{/static/css/main.css}">
        </th:block>

        <th:block th:fragment="common-js">
            <!-- import vue-->
            <script type="text/javascript" th:src="@{/webjars/vue/dist/vue.min.js}"></script>
            <!-- import axios -->
            <script type="text/javascript" th:src="@{/webjars/axios/dist/axios.min.js}"></script>
            <!-- import iView -->
            <script type="text/javascript" th:src="@{/webjars/iview/dist/iview.min.js}"></script>
            <!-- i18n -->
            <script type="text/javascript" th:src="@{/webjars/iview/dist/locale/zh-CN.js}"></script>
        </th:block>
    </body>
</html>

因为是通过webjars引入的前端依赖库,所有都是通过maven来管理的:

<dependency>
    <groupId>org.webjars</groupId>
    <artifactId>webjars-locator</artifactId>
    <version>0.32-1</version>
</dependency>
<dependency>
    <groupId>org.webjars.npm</groupId>
    <artifactId>vue</artifactId>
    <version>2.6.10</version>
</dependency>
<dependency>
    <groupId>org.webjars.npm</groupId>
    <artifactId>iview</artifactId>
    <version>3.4.0</version>
</dependency>
<dependency>
    <groupId>org.webjars.bower</groupId>
    <artifactId>axios</artifactId>
    <version>0.17.1</version>
</dependency>
<dependency>
    <groupId>org.webjars.bower</groupId>
    <artifactId>jquery</artifactId>
    <version>3.4.1</version>
</dependency>

这里没有使用vue的一些脚手架,主要也是用最基本的功能区完成一些效果,主要是为了使用与理解。这里要提到webjars-locator这样一个jar,帮助我们处理了所有版本问题,所以在引入的时候不会有相关的版本信息在路径中。

其次核心的框子都在layout.html中,主要帮我们完成了布局,菜单数据加载,以及以下菜单路由相关的工作:

<head>
    <title th:text="管理系统"></title>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="Shortcut Icon" href="favicon.ico">
    <!-- import css -->
    <div th:replace="common/commons::common-css"></div>
    <!-- import js -->
    <div th:replace="common/commons::common-js"></div>
    <script type="text/javascript" th:inline="javascript">
        iview.lang('zh-CN');
        /*<![CDATA[*/
            window['contextPath'] = /*[[@{/}]]*/
        /*]]>*/
    </script>
</head>

<body>
    <div id="app" class="layout layout-full">
        <layout class="menu-container">
            <header v-cloak>
                <i-menu mode="horizontal" theme="dark" active-name="1">
                    <div class="layout-logo"><span class="log-text">管理系统</span></div>
                    <div class="layout-nav">
                        <menu-item name="1">
                            <icon type="ios-notifications-outline"></icon>
                            消息
                        </menu-item>
                        <menu-item name="2">
                            <icon type="md-volume-down" />
                            提醒
                        </menu-item>
                        <menu-item name="3">
                            <icon type="ios-mail-outline"></icon>
                            邮件
                        </menu-item>
                    </div>
                    <divider type="vertical" />
                </i-menu>
                <i-menu mode="horizontal" theme="dark" class="layout-header-rignt">
                    <div class="">
                        <menu-item>
                            <span>管理员</span>
                        </menu-item>
                        <menu-item>
                            <icon type="md-exit" style="font-size: 18px"></icon>
                            <a th:href="@{/logout}"></a>
                        </menu-item>
                    </div>
                </i-menu>
            </header>
            <layout>
                <sider hide-trigger :style="{background: '#fff'}" class="layout-menu">
                    <!--@on-select="goPage"-->
                    <i-menu ref="side_menu" :open-names="openNames" :active-name="activeName"  theme="light" width="auto" accordion  class="app-left">
                        <submenu v-for="menu in menus" :name="menu.id" v-cloak>
                            <template slot="title">
                                <icon :type="menu.style"></icon>
                                {{menu.name}}
                            </template>
                            <!--@click.native="goPage"-->
                            <menu-item v-for="m in menu.children" :name="m.id" :to="m.path">{{m.name}}</menu-item>
                        </submenu>
                    </i-menu>
                </sider>
                <layout :style="{padding: '0 24px 24px'}">
                    <breadcrumb :style="{margin: '24px 0','padding-left': '200px',position: 'absolute',top: '60px'}" v-cloak>
                        <breadcrumb-item v-for="menu in menuNav">{{menu}}</breadcrumb-item>
                    </breadcrumb>
                    <content class="app-main">
                        <div th:replace="::app-content"></div>
                    </content>
                </layout>
            </layout>
        </layout>
    </div>
<script th:inline="javascript">
    var vm = new Vue({
        el:'#app',
        data(){
            return {
                menus:[],
                openNames:[],
                activeName:'',
                menuNav:['主页']
            };
        },
        created:function () {
            var that = this;
            /*<![CDATA[*/
                var _menuNav = /*[[${menuNav}]]*/
                    _openNames = /*[[${openNames}]]*/
                    _activeName = /*[[${activeName}]]*/
                _menuNav && (this.menuNav = _menuNav);
                _openNames && (this.openNames = _openNames);
                _activeName && (this.activeName = _activeName);
            /*]]>*/
            axios.get(contextPath+'system/menu/tree')
                .then(function (res) {
                    that.menus = res.data;
                    //自动构建的菜单需要加上处理
                    that.$nextTick(() => {
                        that.$refs.side_menu.updateOpened()
                        that.$refs.side_menu.updateActiveName()
                    })
                });
        },
        methods:{
            goPage:function (name) {
                // window.location.hash = name;
                // name && (window.location.href = name);
            }
        }
    });

</script>
</body>

可以看下,最先引入了我们在common中的css与js,之后用到了iview,其实就是在 布局 中拷贝了一个,进行了简单的修改,然后有几点需要说明的:

1、记得一定需要使用new Vue({el:''}),对页面元素处理,这样相关的组件才能进行渲染,因为页面中使用了iview的自定义组件,但又是基于vue的,所以这个必须要加上。

2、页面中一些动态的数据,比如菜单数据、样式相关的配置属性、导航属性等,要优先定义,在之后的页面操作中,进行修改这些属性即可实现动态效果,这个看vue的教程即可。

3、web项目上下文路径会随部署而变化,在thymeleaf中,我们可以通过这样获取,前提是script标签需要th:inline="javascript"声明:

window['contextPath'] = [[@{/}]]

4、围绕vue的生命周期,有很多钩子函数可以在其创建过程中完成我们自定义的修改

5、菜单的路由主要根据iview的提供的属性进行了处理,其中:to会将该元素渲染成a标签,最后其实是全局刷新,其实每个模块就是一个新地址,

<menu-item v-for="m in menu.children" :name="m.id" :to="m.path">{{m.name}}</menu-item>

这个不同于之前的做法,将整个项目作为一个页面,将子页面全部嵌入到注页面中,这次主要是通过layout.html作为一个模板,所有的子页面内容都是加载到

<content class="app-main">
    <div th:replace="::app-content"></div>
</content>

中,同时页面会重新定位,而我们真正的页面则是这样的:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
      layout:decorator="layout/layout">

    <div th:fragment="app-content">
        index
    </div>

</html>

其实前端的构建大致也就是这样,当然会有很多细节,在真正去构建的时候都会遇到各种问题,当然,遇到问题解决问题,这样的方式能够更快的了解并使用新的技术。

目前只是完成了一个用户查询的界面:

<div th:fragment="app-content">
    <div id="user">
        <i-table border
                 :columns="columns"
                 :data="users">
        </i-table>
    </div>
    <script th:src="@{/webjars/jquery/dist/jquery.min.js}"></script>
    <script>
        new Vue({
            el: '#user',
            data() {
                return {
                    users: [],
                    columns: [
                        {
                            title: '登录名',
                            key: 'username'
                        },
                        {
                            title: '用户名',
                            key: 'userCaption'
                        },
                        {
                            title: '年龄',
                            key: 'age'
                        },
                        {
                            title: '电话',
                            key: 'telephone'
                        },
                        {
                            title: '邮箱',
                            key: 'email'
                        }
                    ]
                }
            },
            created(){
                this.getUsers();
            },
            methods: {
                getUsers:function () {
                    var that = this;
                    //异步加载无数据!!
                    // axios.get(contextPath+'system/user')
                    //     .then(function (res) {
                    //         that.users = res.data;
                    //     })
                    $.ajax({
                        url:contextPath+'system/user',
                        async:false,
                        success:function(res){
                            that.users = res;
                        }
                    })
                }
            }
        });
    </script>
</div>

界面大致这样:

基于springboot+mybatisplus构建系统管理平台(二) 原 荐

基于springboot+mybatisplus构建系统管理平台(二) 原 荐 当然这样有个问题一直不知道什么原因,因为请求时使用的是axios,其中users数据一直无法和页面实现双向绑定。

代码: https://github.com/suspring/springboot-mybatisplus-security-ms.git

下一次看下消息队列把...

原文  https://my.oschina.net/suspring/blog/3048966
正文到此结束
Loading...