SpringBoot+Shiro+Thymeleaf项目整合与配置&SpringBoot文件上传&Thymeleaf页面Shiro标签&分页配置

SpringBoot+Shiro+Thymeleaf框架的整合与配置

前言

  • 本次记录的是本人学习开发期间使用SpringBoot+Shiro+Thymeleaf框架的整合与配置过程。其目的主要为:一来是为以后的项目开发提供参考;二来记录自己的学习过程;三来希望本帖能起到沟通交流的作用,为自己的学习增加更多知识点。每个项目都会有独特与独到之处,因此希望本项目整合的分享不要影响到读者的创造力,仅供交流
  • 本项目所涉及到的技术有SSM框架、Maven构建工具、SpringBoot框架、Shiro安全性框架、Thymeleaf静态模板页、layui前端框架、Ajax、MySQL数据库、MD5加密、Json、EhCache等。
  • 其中连接池使用的是 Druid ,Json数据使用fastjson,这两个都是阿里的产品,项目依赖包为本地仓库。
    关键词:SpringBoot; SSM; Shiro; Maven;

Maven项目搭建

  1. Maven环境变量配置
  2. 本地仓库配置

项目分包

在这里插入图片描述
分包说明:
由于很多都是熟悉的分包规则,这里只描述有特点的几个包。

  1. java包:
    (1). shiro:存放的是Shiro的配置类(ShiroFilterFactoryBean等)、继承AuthorizingRealm的用户认证与授权类 、继承于FormAuthenticationFilter的用户自定义拦截器类。
    (2). utils:文件上传相关的配置等工具类。
  2. resource包:
    (1). static:存放CSS、JS、Images等静态资源文件
    (2). templates:.html视图文件
    (3). **.mapper:对应源码包名下Mybatis的xml映射文件,这里需要注意的是,在IDEA中创建这个包时不能通过直接复制源码内的包名创建这个包。由于源码包的特殊性,在resource文件夹中通过直接复制源码包内的包名将只会创建一个文件夹,因此在编译后mapper的.xml文件不会与对应的接口类在同一个包下。所以,在resource文件夹下创建包应该一个一个层叠创建。
    (4). application.yml:配置数据库连接、分页、Thymeleaf等配置,在本文后面一节中会提到。
    (5).shiro-ehcache.xml:配置shiro缓存,同样在接下来会提到。

pom.xml文件配置SpringBoot+Thymeleaf整合

相关整合xml配置(含注释)如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.gec</groupId>
    <artifactId>oa_sys</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <!--父工程坐标-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.3.RELEASE</version>
        <relativePath/> 
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>

        <!--SpringMVC-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--Junit-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- java ee -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>

        <!--Thymeleaf-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

        <!-- mybatis -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>

        <!-- mysql -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <!--connect pool-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.10</version>
        </dependency>

        <!-- file Upload -->
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.3.1</version>
        </dependency>

        <!--Json-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.31</version>
        </dependency>
        <dependency>
            <groupId>commons-beanutils</groupId>
            <artifactId>commons-beanutils</artifactId>
            <version>1.9.3</version>
        </dependency>

        <!-- 上传文件到FTP -->
        <dependency>
            <groupId>commons-net</groupId>
            <artifactId>commons-net</artifactId>
            <version>3.3</version>
        </dependency>

        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.2</version>
        </dependency>

        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

        <!--Shiro-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.0-RC2</version>
        </dependency>
        <!--EhCache-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-ehcache</artifactId>
            <version>1.3.2</version>
        </dependency>

        <!--thymeleaf+shiro页面标签库-->
        <dependency>
            <groupId>com.github.theborakompanioni</groupId>
            <artifactId>thymeleaf-extras-shiro</artifactId>
            <version>2.0.0</version>
        </dependency>

        <!--Page Helper-->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.2.3</version>
            <exclusions>
                <exclusion>
                    <groupId>org.mybatis.spring.boot</groupId>
                    <artifactId>mybatis-spring-boot-starter</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
<!--Maven启动配置-->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

项目配置

注意由于application.yml中涉及到多方的配置,在这里分开解说。

MySQL数据库连接配置

在resource包下的application.yml文件中配置
application.yml:

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: 'jdbc:mysql://localhost:3306/oa_sys?useUnicode=true&characterEncoding=UTF-8'
    username: ----add your MySQL username----
    password: ----add your MySQL password----

在数据库连接Url后加上:useUnicode=true&characterEncoding=UTF-8使用UTF-8进行统一编码,防止乱码。

Shiro配置

  1. Shiro代码配置:
    由于在SpringBoot中使用注解代码进行配置,因此在配置类上需要加上@Configuration注解,以“告诉”Spring容器这是一个配置类。同时与Xml文件配置类似的地方是,每一项配置都以Bean为基础单位,不同的是在xml文件中一项配置是一个Bean节点,而配置类中则是@Bean注解方法。

下面开始使用代码配置Shiro(含注释):


@Configuration
public class ShiroConfig {

    @Bean
    public AuthorizationAttributeSourceAdvisor advisor(){
        AuthorizationAttributeSourceAdvisor advisor=new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager());
        return advisor;
    }

    @Bean
    public ShiroFilterFactoryBean shiroFilter(){
        ShiroFilterFactoryBean shiroFilter=new ShiroFilterFactoryBean();
        shiroFilter.setSecurityManager(securityManager());
        //设置登录Url
        shiroFilter.setLoginUrl("/login");
        //设置登录成功后的Url
        shiroFilter.setSuccessUrl("/oa_sys/index");
        //未授权跳转Url
        shiroFilter.setUnauthorizedUrl("/oa_sys/userList");
        //shiro过滤器
        Map<String,String> filterChain=new LinkedHashMap<>();
        filterChain.put("/layui/**","anon");
        filterChain.put("/css/**","anon");
        filterChain.put("/images/**","anon");
        filterChain.put("/jquery-3.3.1/**","anon");
        filterChain.put("/js/**","anon");
        filterChain.put("/layui_menu/**","anon");
        filterChain.put("/zTree/**","anon");
        filterChain.put("/font-awesome-4.7.0","anon");
        filterChain.put("/ckfinder/**","anon");
        filterChain.put("/cron/**","anon");
        filterChain.put("/templates/**","anon");
        //rememberMe
        filterChain.put("/", "user");
        filterChain.put("/loginPage","anon");
        filterChain.put("/login","anon");
        filterChain.put("/logout","logout");
        filterChain.put("/**","authc");
        shiroFilter.setFilterChainDefinitionMap(filterChain);
        return shiroFilter;
    }

    //配置SecurityManager
    @Bean
    public DefaultWebSecurityManager securityManager(){
        DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();
        securityManager.setRealm(myShiroRealm());
        securityManager.setCacheManager(ehCacheManager());
        securityManager.setRememberMeManager(cookieRememberMeManager());
        return securityManager;
    }
    
    @Bean
    public Realm myShiroRealm() {
        //自定义Realm,认证及授权规则
        CustomShiroRealm myShiroRealm = new CustomShiroRealm();
        myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        return myShiroRealm;
    }

    //加密方式,Md5,加密2@Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher  hashedCredentialsMatcher = new HashedCredentialsMatcher ();
        hashedCredentialsMatcher.setHashAlgorithmName("md5");
        hashedCredentialsMatcher.setHashIterations(2);
        return hashedCredentialsMatcher;
    }

    //使用EhCache缓存
    @Bean
    public EhCacheManager ehCacheManager() {
        EhCacheManager cacheManager=new EhCacheManager();
        //缓存配置文件所在位置
        cacheManager.setCacheManagerConfigFile("classpath:shiro-ehcache.xml");
        return cacheManager;
    }

    //配置RememberMe
    @Bean
    public CookieRememberMeManager cookieRememberMeManager() {
        CookieRememberMeManager cookieRememberMeManager=new CookieRememberMeManager();
        cookieRememberMeManager.setCipherKey(Base64.decode("6ZmI6I2j5Y+R5aSn5ZOlAA=="));
        cookieRememberMeManager.setCookie(simpleCookie());
        return cookieRememberMeManager;
    }

    //配置Cookie的属性
    @Bean
    public SimpleCookie simpleCookie() {
        SimpleCookie simpleCookie =new SimpleCookie();
        simpleCookie.setName("rememberMe");
        simpleCookie.setMaxAge(2592000);
        return simpleCookie;
    }

    //Thymeleaf+Shiro视图页面标签的方言配置
    @Bean
    public ShiroDialect getShiroDialect(){
        return new ShiroDialect();
    }

}

自定义认证管理器:

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String userName = (String) token.getPrincipal();
        if (userName == null) {
            //没有返回登录用户名对应的SimpleAuthenticationInfo对象时,就会在LoginController中抛出UnknownAccountException异常
            throw new UnknownAccountException("用户不存在");
        }
        User u= service.selectUserByName(userName);
        String db_password=u.getPassword();//数据库查出来的密文
        String db_salt=u.getSalt();//盐
        SimpleAuthenticationInfo info =new SimpleAuthenticationInfo(u,db_password, ByteSource.Util.bytes(db_salt),"CustomRealm");
        return info;
    }

自定义授权管理器:

    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        //认证时SimpleAuthenticationInfo中的第一个参数就是principals.getPrimaryPrincipal();获取的对象
        User user=(User) principals.getPrimaryPrincipal();
        Integer roleId = user.getRoleId();
        List<SysMenu> sysMenus = menuService.selectMenuByRoleId(roleId);

        HashSet<String> permission = new HashSet<>();

        for (SysMenu menu : sysMenus) {
            if(!StringUtils.isEmpty(menu.getPermission())){
                permission.add(menu.getPermission());
                System.out.println("add permission-->"+menu.getPermission());
            }
        }

        SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
        info.setStringPermissions(permission);
        return info;
    }
  1. EhCache缓存配置:

shiro-ehcache.xml:

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
	<!--diskStore:缓存数据持久化的目录 地址  -->
	<diskStore path="d:\develop" />
	<defaultCache 
		maxElementsInMemory="1000" 
		maxElementsOnDisk="10000000"
		eternal="false" 
		overflowToDisk="false" 
		diskPersistent="false"
		timeToIdleSeconds="120"
		timeToLiveSeconds="120" 
		diskExpiryThreadIntervalSeconds="120"
		memoryStoreEvictionPolicy="LRU">
	</defaultCache>
</ehcache>

Json配置

这项配置保证了前后端Json数据正常进行解析

    @Bean
    public HttpMessageConverters fastJsonConfigure(){
        // 1.创建一个converter对象
        FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
        // 2.创建配置对象
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        // 3.添加配置
        fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);
        // 4.将配置添加到转换器对象中
        fastConverter.setFastJsonConfig(fastJsonConfig);
        // 5. 解决中文乱码问题
        List<MediaType> mediaTypes = new ArrayList<>();
        mediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
        fastConverter.setSupportedMediaTypes(mediaTypes);
        // 6.将转换器对象转化为HttpMessageConverter对象
        return new HttpMessageConverters((HttpMessageConverter) fastConverter);
    }

分页配置

application.yml:

pagehelper:
  helper-dialect: mysql
  reasonable: true

文件上传配置

上传文件的大小限制:

servlet:
    multipart:
      max-file-size: 10MB
      max-request-size: 10MB

这项配置的作用是将服务器上某一位置作为映射路径,一提供文件上传空间。

@Configuration
public class FileUploadPathConfigure implements WebMvcConfigurer{
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        //addResourceHandler,文件上传映射地址   th:src="@{/upload/}+${item.pic}"
        registry.addResourceHandler("/upload/**").addResourceLocations("file:d:/Apache-Tomcat/Note/");
    }
}

yml文件

为了方便观看,将yml文件整理如下:

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: 'jdbc:mysql://localhost:3306/oa_sys?useUnicode=true&characterEncoding=UTF-8'
    username: ----add your MySQL username----
    password: ----add your MySQL password----
  servlet:
    multipart:
      max-file-size: 10MB
      max-request-size: 10MB
  thymeleaf:
    suffix: .html
  aop:
    auto: true
    proxy-target-class: true
pagehelper:
  helper-dialect: mysql
  reasonable: true

Thymeleaf页面Shiro标签整理

下面收集了一些标签的用法:

guest标签:用户没有身份验证时显示相应信息,即游客访问信息。

<shiro:guest></shiro:guest>

user标签:用户已经身份验证/记住我登录后显示相应的信息。

<shiro:user></shiro:user>

authenticated标签:用户已经身份验证通过,即Subject.login登录成功,不是记住我登录的。

<shiro:authenticated></shiro:authenticated>

notAuthenticated标签:用户已经身份验证通过,即没有调用Subject.login进行登录,包括记住我自动登录的也属于未进行身份验证。

<shiro:notAuthenticated></shiro:notAuthenticated>

principal标签:相当于((User)Subject.getPrincipals()).getUsername()。

<shiro: principal/><shiro:principal property="username"/>

lacksPermission标签:如果当前Subject没有权限将显示body体内容。

<shiro:lacksPermission name="org:create"></shiro:lacksPermission>

hasRole标签:如果当前Subject有角色将显示body体内容。

<shiro:hasRole name="admin"></shiro:hasRole>

hasAnyRoles标签:如果当前Subject有任意一个角色(或的关系)将显示body体内容。

<shiro:hasAnyRoles name="admin,user"></shiro:hasAnyRoles>

lacksRole标签:如果当前Subject没有角色将显示body体内容。

<shiro:lacksRole name="abc"></shiro:lacksRole>

hasPermission标签:如果当前Subject有权限将显示body体内容。

<shiro:hasPermission name="user:create"></shiro:hasPermission>

用法示例

加入shiro:标签库:

<html xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">

如果有user:add权限则< div>之间的内容会显示:

<div shiro:hasPermission="user:add"></div>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值