QiYu Admin-架构搭建(SpringBoot实战)

简述

自从上周写了第一篇博客,我就开始不停的忙活起来我的项目了,真佩服现在的我还有那么大的精神,半夜4点突然醒了,然后就睡不着了,想着想着就打开了我的电脑,开始编写我那没有回报的后台管理系统的项目,我现在称之为QiYu Admin。只因为我的女儿叫做七语。
这个星期只要是下班时间我就疯狂的想我的博客,但是总得出点东西才能写啊,一周过去了,基本上时间都在框架和前端页面的封装上了,到现在还算出了一点点东西了,那就先出一篇吧,动漫在慢也会每周更新一集啊,先看下集成哪些东西吧:

  • shiro集成(认证)
  • Thymeleaf3.0集成和Shiro标签
  • 异常页面自定义
  • 一些前端框架的封装(layer、sweetalert、bootstrap-table等)
  • 用户分页列表
  • 用户修改页面

成果

一、首页
这里写图片描述
二、用户管理
这里写图片描述
表格用的BootStrap-table,分页自动影藏和展现,当超过设定每页的条数时自动回出来分页。
三、选中一个用户点击修改(Layer弹出和用户信息页面)
这里写图片描述
四、微妙微笑的弹出提示框
不能多选
不能多选
不能选择一个
这里写图片描述
更多弹出框将在后续出来。
五、异常页面
这里写图片描述

具体实现

接下来就是对上述的成果进行详细的说明喽。

Shiro的配置和Thymeleaf标签

package com.qiyu.admin.auth.shiro;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * Shiro 配置 Apache Shiro 核心通过 Filter 来实现,就好像SpringMvc 通过DispachServlet 来主控制一样。
 * 既然是使用 Filter 一般也就能猜到,是通过URL规则来进行过滤和权限校验,所以我们需要定义一系列关于URL的规则和访问权限。
 */
@Configuration
public class ShiroConf {
    /**
     * ShiroFilterFactoryBean 处理拦截资源文件问题。
     * 注意:单独一个ShiroFilterFactoryBean配置是或报错的,以为在
     * 初始化ShiroFilterFactoryBean的时候需要注入:SecurityManager
     * Filter Chain定义说明 1、一个URL可以配置多个Filter,使用逗号分隔 2、当设置多个过滤器时,全部验证通过,才视为通过
     * 3、部分过滤器可指定参数,如permsroles
     */
    @Bean
    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        // 必须设置 SecurityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        // 拦截器.
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
        // 配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了
        filterChainDefinitionMap.put("/logout", "logout");
        filterChainDefinitionMap.put("/assets/**", "anon");
        // 配置记住我或认证通过可以访问的地址
        // filterChainDefinitionMap.put("/index", "user");
        // filterChainDefinitionMap.put("/", "user");
        // <!-- 过滤链定义,从上向下顺序执行,一般将 /**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了;
        // <!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
        filterChainDefinitionMap.put("/**", "authc");
        shiroFilterFactoryBean.setLoginUrl("/login");
        // 登录成功后要跳转的链接
        shiroFilterFactoryBean.setSuccessUrl("/index");
        // 未授权界面;
        shiroFilterFactoryBean.setUnauthorizedUrl("/403");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }
    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        // 设置realm.
        securityManager.setRealm(customRealm());
        // 注入记住我管理器;
        securityManager.setRememberMeManager(rememberMeManager());
        return securityManager;
    }
    /**
     * 身份认证realm; (这个需要自己写,账号密码校验;权限等)
     * @return
     */
    @Bean
    public AuthCustomRealm customRealm() {
        AuthCustomRealm customRealm = new AuthCustomRealm();
        customRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        return customRealm;
    }
    /**
     * 凭证匹配器 (由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了
     * 所以我们需要修改下doGetAuthenticationInfo中的代码; )
     * @return
     */
    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName("md5");// 散列算法:这里使用MD5算法;
        hashedCredentialsMatcher.setHashIterations(3);// 散列的次数,比如散列两次,相当于md5(md5(""));
        hashedCredentialsMatcher.setStoredCredentialsHexEncoded(true);
        return hashedCredentialsMatcher;
    }
    /**
     * 开启shiro aop注解支持. 使用代理方式;所以需要开启代码支持;
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }
    /**
     * cookie对象;
     * @return
     */
    @Bean
    public SimpleCookie rememberMeCookie() {
        // 这个参数是cookie的名称,对应前端的checkbox 的name = rememberMe
        SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
        // <!-- 记住我cookie生效时间30天 ,单位秒;-->
        simpleCookie.setMaxAge(259200);
        return simpleCookie;
    }
    /**
     * cookie管理对象;
     * @return
     */
    @Bean
    public CookieRememberMeManager rememberMeManager() {
        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
        cookieRememberMeManager.setCookie(rememberMeCookie());
        return cookieRememberMeManager;
    }
    /**
     * ShiroDialect,为了在thymeleaf里使用shiro的标签的bean
     * @return
     */
    @Bean
    public ShiroDialect shiroDialect() {
        return new ShiroDialect();
    }
}

备注:至于源码很多都不是我自己原创出来的,都是通过网上的一些网友和朋友借鉴而来。其中比较有名是我的一个朋友林祥纤开设了专栏,《从零开始学spring boot》。

异常页面配置

其实也就是实现了ErrorController类(这些都可以在《从零开始学spring boot》里面找到),这里就不做赘述。

Layer封装

其实没啥技术含量就是把layer.open给封装了一下,方便以后类似的功能调用。

 var layerOpen=function(title,width,height,content){
        return layer.open({
            type:2,
            skin:"qiyu-custom-layer",
            title: title,
            area: [width,height],
            fix: false, //不固定
            shadeClose: true,
            shade: 0.8,
            scrollbar: false,
            content: content
        });
    }

sweetalert封装(同上)

  var bootstrapSweetAlert=function (sa_title,sa_message,sa_type) {
        swal({
            title: sa_title,
            text: sa_message,
            type: sa_type
            });
    }

Bootstrap-table封装(同上)

var initBootStrapTable=function(table,ajaxUrl,columns) {
        table.bootstrapTable({
            method: 'get',
            url: ajaxUrl,
            cache: false,
            dataType: "json",
            striped: false,  //使表格带有条纹
            sortable: true,
            pagination: true,   //在表格底部显示分页工具栏
            pageSize: 8,
            pageNumber: 1,
            pageList: [5, 8, 10],
            idField: "id",  //标识哪个字段为id主键
            showToggle: false,   //名片格式
            cardView: false,//设置为True时显示名片(card)布局
            singleSelect: false,//复选框只能选择一条记录
            search: false,//是否显示右上角的搜索框
            clickToSelect: true,//点击行即可选中单选/复选框
            sidePagination: "server",//表格分页的位置
            queryParamsType: "", //参数格式,发送标准的RESTFul类型的参数请求
            strictSearch: true,
            showColumns: false,     //是否显示所有的列
            showRefresh: false,     //是否显示刷新按钮
            minimumCountColumns: 2,    //最少允许的列数
            responseHandler: function (res) {
                return {
                    "rows": res.dataList,
                    "total": res.total
                };
            },
            silent: true,  //刷新事件必须设置
            formatNoMatches: function () {  //没有匹配的结果
                return '无符合条件的记录';
            },
            rowStyle: function (row, index) {
                return {classes: "cursorHand"}
            },
            columns: columns
        });
    }

结语

其实都是站在巨人的肩膀上来做的,所以我把自己定位为我不是一个程序员、我不是一个架构师、我不是一个设计师。

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页