基于springboot+bootstrap+mysql+redis搭建一套完整的权限架构整合springSecurity

Posted ljljlj1993

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于springboot+bootstrap+mysql+redis搭建一套完整的权限架构整合springSecurity相关的知识,希望对你有一定的参考价值。

1、创建数据库
注意:mysql默认字符集为utf8,默认排序规则为utf8_general_ci。一般我们也会选择字符集为utf-8
MySQL在5.5.3之后增加了这个utf8mb4的编码,utf8mb4完全向下兼容utf8,为了节省空间,一般情况下使用utf8也就够了,我这边没有utf8。所以选择了utf8mb4 。

2、建表
若需要整合我们的springSecurity,一种是直接使用springSecurity自带的权限架构,另外一种是使用我们自己设计的数据架构,本文所阐述的就是使用自己设计的RBAC权限架构,因此我们要事先设计好用户权限架构的PDM如下图所示,并创建我们的数据库:数据库名:hyll_springboot,以及我们的三张表:user、user_role、user_associate_role:




接着打开我们的工程新建如下工程的目录:

接着在我们的sys包底下新建entity和dao这两个包:

同时打开我们的pom.xml引入该工程所需要的所有依赖,接着我们的IDEA会弹出一个框,我们点击import就自动会去maven给我们下载依赖,若你有自己的私有maven则将其指向自己的私有maven,若这边有缺少不懂的直接去我的第一章的github上的源代码中自己去copy下来:

<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
		<mysql.version>5.1.41</mysql.version>
		<guava.version>18.0</guava.version>
		<org.mapstruct.version>1.1.0.Final</org.mapstruct.version>
	</properties>
 
	<dependencies>
 
		<!-- 集成Druid数据库连接池和监控 -->
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid-spring-boot-starter</artifactId>
			<version>1.1.3</version>
		</dependency>
 
		<!-- 引入mybatis的支持 -->
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>1.3.1</version>
		</dependency>
 
		<!-- 引入mapstruct的支持 -->
		<dependency>
			<groupId>org.mapstruct</groupId>
			<artifactId>mapstruct-jdk8</artifactId>
			<version>$org.mapstruct.version</version>
		</dependency>
 
		<dependency>
			<groupId>org.mapstruct</groupId>
			<artifactId>mapstruct-processor</artifactId>
			<version>$org.mapstruct.version</version>
		</dependency>
 
		<!--  Java EE 6 规范 JSR 330 -->
		<dependency>
			<groupId>javax.inject</groupId>
			<artifactId>javax.inject</artifactId>
			<version>1</version>
		</dependency>
 
		<!-- 引入json的依赖 classifier必须要加这个是json的jdk的依赖-->
		<dependency>
			<groupId>net.sf.json-lib</groupId>
			<artifactId>json-lib</artifactId>
			<version>2.4</version>
			<classifier>jdk15</classifier>
		</dependency>
 
 
		<!-- 开启spring-websocket的支持 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-websocket</artifactId>
		</dependency>
 
		<!-- 开启spring-security的支持 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>
		<!-- 开启thymeleaf的spring-security的支持 -->
		<dependency>
			<groupId>org.thymeleaf.extras</groupId>
			<artifactId>thymeleaf-extras-springsecurity4</artifactId>
		</dependency>
 
		<!-- 表示对thymeleaf模板不再是用默认的html5标准来做严格限制 -->
		<dependency>
			<groupId>net.sourceforge.nekohtml</groupId>
			<artifactId>nekohtml</artifactId>
			<version>1.9.22</version>
		</dependency>
 
		<!-- 添加对spring-redis的支持 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-redis</artifactId>
			<version>1.3.8.RELEASE</version>
		</dependency>
 
		<!-- 添加对spring-cache的支持 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-cache</artifactId>
		</dependency>
 
		<dependency>
			<groupId>net.sf.ehcache</groupId>
			<artifactId>ehcache</artifactId>
		</dependency>
 
		<!-- 添加对spring-data-rest的支持 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-rest</artifactId>
		</dependency>
 
		<!-- 添加对spring-jpa的支持 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
 
		<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>$mysql.version</version>
		</dependency>
 
		<dependency>
			<groupId>com.google.guava</groupId>
			<artifactId>guava</artifactId>
			<version>$guava.version</version>
		</dependency>
 
		<!-- 添加对thymeleaf的支持 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
 
		<!-- 添加对websocket的支持 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-websocket</artifactId>
		</dependency>
 
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
 
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>javax.servlet-api</artifactId>
			<version>3.1.0</version>
			<scope>provided</scope>
		</dependency>
 
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-tomcat</artifactId>
			<version>1.3.5.RELEASE</version>
			<scope>provided</scope>
		</dependency>
 
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<optional>true</optional><!-- optional=true,依赖不会传递,该项目依赖devtools;之后依赖myboot项目的项目如果想要使用devtools,需要重新引入 -->
		</dependency>
 
		<dependency>
			<groupId>com.xiaoleilu</groupId>
			<artifactId>hutool-all</artifactId>
			<version>3.0.9</version>
		</dependency>
 
		<dependency>
			<groupId>io.springfox</groupId>
			<artifactId>springfox-swagger2</artifactId>
			<version>2.6.1</version>
		</dependency>
 
		<dependency>
			<groupId>io.springfox</groupId>
			<artifactId>springfox-swagger-ui</artifactId>
			<version>2.6.1</version>
		</dependency>
		<dependency>
			<groupId>com.vaadin.external.google</groupId>
			<artifactId>android-json</artifactId>
			<version>0.0.20131108.vaadin1</version>
		</dependency>
 
	</dependencies>

同时在我们的entity包底下新建我们刚刚的三个实体:

UserRole 的代码部分

package com.example.demo.sys.entity;

/**
 * @author lj
 * @version 1.0
 * @date 2023/1/314:18
 * Description:com.example.demo.sys.entity
 */
public class UserRole 
    private long id;
    private String name;
    private String roleName;

    public long getId() 
        return id;
    

    public void setId(long id) 
        this.id = id;
    

    public String getName() 
        return name;
    

    public void setName(String name) 
        this.name = name;
    

    public String getRoleName() 
        return roleName;
    

    public void setRoleName(String roleName) 
        this.roleName = roleName;
    


User 代码部分

package com.example.demo.sys.entity;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;

/**
 * @author lj
 * @version 1.0
 * @date 2023/1/310:01
 * Description:com.example.demo.sys.entity
 */
public class User implements UserDetails 

    private int id;
    private String login;
    private String password;
    private String userName;
    private String address;
    private String job;
    private long groupId;
    private Date birthDate;
    private String city;
    private String district;
    private String province;
    private String streetAddress;
    private String state;
    private String type;
    private Date lastLoginDate;
    // 用户角色信息
    private List<UserRole> roles;
    // 权限集合数据
    private String roleArray;


    public int getId() 
        return id;
    

    public void setId(int id) 
        this.id = id;
    

    public String getLogin() 
        return login;
    

    public void setLogin(String login) 
        this.login = login;
    

    public void setPassword(String password) 
        this.password = password;
    

    public String getUserName() 
        return userName;
    

    public void setUserName(String userName) 
        this.userName = userName;
    

    public String getAddress() 
        return address;
    

    public void setAddress(String address) 
        this.address = address;
    

    public String getJob() 
        return job;
    

    public void setJob(String job) 
        this.job = job;
    

    public long getGroupId() 
        return groupId;
    

    public void setGroupId(long groupId) 
        this.groupId = groupId;
    

    public Date getBirthDate() 
        return birthDate;
    

    public void setBirthDate(Date birthDate) 
        this.birthDate = birthDate;
    

    public String getCity() 
        return city;
    

    public void setCity(String city) 
        this.city = city;
    

    public String getDistrict() 
        return district;
    

    public void setDistrict(String district) 
        this.district = district;
    

    public String getProvince() 
        return province;
    

    public void setProvince(String province) 
        this.province = province;
    

    public String getStreetAddress() 
        return streetAddress;
    

    public void setStreetAddress(String streetAddress) 
        this.streetAddress = streetAddress;
    

    public String getState() 
        return state;
    

    public void setState(String state) 
        this.state = state;
    

    public String getType() 
        return type;
    

    public void setType(String type) 
        this.type = type;
    

    public Date getLastLoginDate() 
        return lastLoginDate;
    

    public void setLastLoginDate(Date lastLoginDate) 
        this.lastLoginDate = lastLoginDate;
    

    public List<UserRole> getRoles() 
        return roles;
    

    public void setRoles(List<UserRole> roles) 
        this.roles = roles;
    

    public String getRoleArray() 
        return roleArray;
    

    public void setRoleArray(String roleArray) 
        this.roleArray = roleArray;
    

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() 
        List<GrantedAuthority> auths = new ArrayList<GrantedAuthority>();
        if (this.getRoles() != null) 
            List<UserRole> roles = this.getRoles();
            for (UserRole role : roles) 
                if (role.getName() != null) 
                    auths.add(new SimpleGrantedAuthority(role.getName()));
                
            
        
        return auths;
    

    @Override
    public String getPassword() 
        return null;
    

    @Override
    public String getUsername() 
        return null;
    

    @Override
    public boolean isAccountNonExpired() 
        return false;
    

    @Override
    public boolean isAccountNonLocked() 
        return false;
    

    @Override
    public boolean isCredentialsNonExpired() 
        return false;
    

    @Override
    public boolean isEnabled() 
        return false;
    

    /**
     * 功能描述:组装角色数据集合
     *
     * @param roleArray
     */
    public void packagingRoles(String roleArray) 
        List<UserRole> roles = new ArrayList<UserRole>();
        if (roleArray != null) 
            UserRole userRole = null;
            for (String roleId : roleArray.split(",")) 
                if (!roleId.isEmpty()) 
                    userRole = new UserRole();
                    userRole.setId(Long.parseLong(roleId));
                    roles.add(userRole);
                
            
        
        this.setRoles(roles);
    



UserAssociateRole 代码部分



package com.example.demo.sys.entity;

/**
 * @author lj
 * @version 1.0
 * @date 2023/1/314:26
 * Description:com.example.demo.sys.entity
 */
public class UserAssociateRole 

    private int userId;
    private long roleId;

    public UserAssociateRole() 
        super();
    

    public int getUserId() 
        return userId;
    

    public void setUserId(int userId) 
        this.userId = userId;
    

    public long getRoleId() 
        return roleId;
    

    public void setRoleId(long roleId) 
        this.roleId = roleId;
    


接着我们在dao包里面创建以下的接口:

package com.example.demo.sys.dao;

import com.example.demo.sys.entity.User;

/**
 * @author lj
 * @version 1.0
 * @date 2023/1/314:54
 * Description:com.example.demo.sys.dao
 */
public interface UserDao 
    /**
     * 功能描述:根据账户获取用户信息
     *
     * @param user
     * @return com.example.demo.sys.entity.User
     * @author: LJ
     * @date: 2023/1/3
     */

    User findByLogin(String user);


接着我们引入我们的mybatis配置以及我们的security和快速切换环境配置,
首先在我们的application.properties底下增加以下配置:

spring.profiles.active=dev

#配置放行的目录和方法
security.ignored=/api/*,/css/*,/js/*,/images/*,/fonts/*,/font-awesome/*
#表示对thymeleaf模板不再是用默认的HTML5标准来做严格限制
spring.thymeleaf.mode = LEGACYHTML5

#配置mybatis的扫描的包的文件的入口
mybatis.config-locations=classpath:mybatis/mybatis-config.xml
mybatis.mapper-locations=classpath:mybatis/mapper/*.xml

同时在我们的resources目录底下创建一个目录mybatis并在该目录底下创建一个文件mybatis-config.xml和mapper目录如下所示:

mybatis-config.xml代码如下所示

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <typeAliases>
        <typeAlias alias="Integer" type="java.lang.Integer" />
        <typeAlias alias="Long" type="java.lang.Long" />
        <typeAlias alias="HashMap" type="java.util.HashMap" />
        <typeAlias alias="LinkedHashMap" type="java.util.LinkedHashMap" />
        <typeAlias alias="ArrayList" type="java.util.ArrayList" />
        <typeAlias alias="LinkedList" type="java.util.LinkedList" />
    </typeAliases>
</configuration>

同时在我们的resource目录底下创建我们的application-dev.properties文件信息如下:

server.port = 8080
#数据库连接配置
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/hyll_springboot?characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=111111

接着我们在resource/mapper目录底下创建一个mybatis_user.xml内容如下:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <typeAliases>
        <typeAlias alias="Integer" type="java.lang.Integer" />
        <typeAlias alias="Long" type="java.lang.Long" />
        <typeAlias alias="HashMap" type="java.util.HashMap" />
        <typeAlias alias="LinkedHashMap" type="java.util.LinkedHashMap" />
        <typeAlias alias="ArrayList" type="java.util.ArrayList" />
        <typeAlias alias="LinkedList" type="java.util.LinkedList" />
    </typeAliases>
</configuration>

同时在我们的resource目录底下创建我们的application-dev.properties文件信息如下

server.port = 8080
#数据库连接配置
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/hyll_springboot?characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=111111

接着我们在resource/mapper目录底下创建一个mybatis_user.xml内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.sys.dao.UserDao">

    <!-- 包含角色信息的map -->
    <resultMap type="com.example.demo.sys.entity.User" id="UserLoginMap">
        <id property="id" column="id"/>
        <result property="login" column="login"/>
        <result property="password" column="password"/>
        <result property="userName" column="user_name"/>
        <result property="address" column="address"/>
        <result property="job" column="job"/>
        <result property="groupId" column="group_id"/>
        <result property="birthDate" column="birth_date"/>
        <result property="city" column="city"/>
        <result property="district" column="district"/>
        <result property="province" column="province"/>
        <result property="streetAddress" column="street_address"/>
        <result property="state" column="state"/>
        <result property="type" column="type"/>
        <result property="lastLoginDate" column="last_login_date"/>
        <collection property="roles"  ofType="com.example.demo.sys.entity.UserRole" javaType="java.util.ArrayList">
            <result column="user_role_id" property="id" jdbcType="VARCHAR" />
            <result column="name" property="name" jdbcType="VARCHAR" />
            <result column="role_name" property="roleName" jdbcType="VARCHAR" />
        </collection>
    </resultMap>

    <!-- 根据账号来获取用户信息 -->
    <select id="findByLogin" parameterType="java.lang.String" resultMap="UserLoginMap">
		select u.*,ur.id as user_role_id,ur.name,ur.role_name from user u inner join user_associate_role uar on u.id = uar.user_id inner join user_role ur on uar.role_id = ur.id where u.login = #login
	</select>

</mapper>

接着开始我们的springsecurity的配置,找到我们的config包在该包底下我们创建一个security和mybatis包如下所示

接着在我们的security增加以下三个类分别是(CustomPasswordEncoder:密码加密类;CustomUserService:登陆逻辑重写类;WebSecurityConfig:security实现配置类):
注意maven的版本,如果版本高的话,就没有Md5PasswordEncoder的依赖

package com.example.demo.common.config.security;

import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.authentication.encoding.Md5PasswordEncoder;

/**
 * 功能描述:spring-security登陆的密码进行MD5加密传到数据库
 *
 * @author: LJ
 * @date: 2023/1/3
 * @return
 */

public class CustomPasswordEncoder implements PasswordEncoder 
    @Override
    public String encode(CharSequence rawPassword) 
        Md5PasswordEncoder encoder = new Md5PasswordEncoder();
        return encoder.encodePassword(rawPassword.toString(), "hyll");

    

    @Override
    public boolean matches(CharSequence rawPassword, String encodedPassword) 
        Md5PasswordEncoder encoder = new Md5PasswordEncoder();
        return encoder.isPasswordValid(encodedPassword, rawPassword.toString(), "hyll");
    


注意,你得密码是经过md5加密得,所以比如我得密码是1,那么加密后得a2098ac42fe033111a1f678b8d621899,这个填入到数据库中对应user表得密码中,你可以根据自己的密码进行加密,加密后的结果放到数据库中

  public static void main(String[] args) 
        Md5PasswordEncoder encoder = new Md5PasswordEncoder();

        System.out.println(encoder.encodePassword("1", "hyll"));
        System.out.println( encoder.isPasswordValid("a2098ac42fe033111a1f678b8d621899","1", "hyll"));

    

package com.example.demo.common.config.security;

import com.example.demo.sys.dao.UserDao;
import com.example.demo.sys.entity.User;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

import javax.annotation.Resource;

/**
 * @author lj
 * @version 1.0
 * @date 2023/1/510:51
 * Description:com.example.demo.common.config.security
 */
public class CustomUserService implements UserDetailsService 

    @Resource
    private UserDao userDao;

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException 
        User user = userDao.findByLogin(s);
        if (user == null) 
            throw new UsernameNotFoundException("用户名不存在");
        
// 自定义错误的文章说明的地址:http://blog.csdn.net/z69183787/article/details/21190639?locationNum=1&fps=1
        if (user.getState().equalsIgnoreCase("0")) 
            throw new LockedException("用户账号被冻结,无法登陆请联系管理员!");
        
        return user;
    


package com.example.demo.common.config.security;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
 * @author lj
 * @version 1.0
 * @date 2023/1/513:34
 * 实现Security的配置
 */
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
//当我们想要开启spring方法级安全时,只需要在任何 @Configuration实例上使用 @EnableGlobalMethodSecurity 注解就能达到此目的
public class WebSecurityConfig extends WebSecurityConfigurerAdapter 
    @Bean
    UserDetailsService customUserService() 
        return new CustomUserService();
    

    @Bean
    PasswordEncoder passwordEncoder() 
        return new CustomPasswordEncoder();
    


    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception 
        auth.userDetailsService(customUserService()).passwordEncoder(passwordEncoder());
    

    @Override
    protected AuthenticationManager authenticationManager() throws Exception 
        return super.authenticationManager();
    

    /**
     * 功能描述: csrf().disable()为了关闭跨域访问的限制,若不关闭则websocket无法与后台进行连接
     *
     * @param http
     * @return void
     * @author: LJ
     * @date: 2023/1/5
     */

    @Override
    protected void configure(HttpSecurity http) throws Exception 

        http.headers().frameOptions().disable();
        http.csrf().disable().authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .loginPage("/login")
                .defaultSuccessUrl("/main")
                .failureUrl("/login?error=true")
                .permitAll()
                .and()
                .logout()
                .logoutSuccessUrl("/login")
                .permitAll();
    


接着我们在mybatis包底下新增MyBatisConfig 配置类如下所示 MapperScan扫描的是我们的dao接口的存放路径,因此此处大家一定要注意自己的dao包的路径是否正确,否则会导致调用dao方法出错】

package com.example.demo.common.config.mybatis;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;

/**
 * @author lj
 * @version 1.0
 * @date 2023/1/2520:15
 * Description:com.example.demo.common.config.mybatis
 */
@Configuration
@MapperScan("com.example.demo.*.dao")
public class MyBatisConfig 


接着在我们的config目录底下创建我们的WebMvcConfig配置文件如下所示:

package com.example.demo.common.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

/**
 * @author lj
 * @version 1.0
 * @date 2023/1/2520:21
 * Description:com.example.demo.common.config
 */
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter 

    /**
     * 重写方法描述:实现在url中输入相应的地址的时候直接跳转到某个地址
     *
     * @param registry
     */
    @Override
    public void addViewControllers(ViewControllerRegistry registry) 
        registry.addViewController("/login").setViewName("login");
        registry.addViewController("/main").setViewName("main");
        registry.addViewController("/error").setViewName("error");
    


到此处我们的整个基础工程已经构建完成,我们可以直接将该工程运行起来,访问http://127.0.0.1:8080/login,由于还没有引入bootstrap因此整个页面显得不叫的丑,后续将bootstrap引入那么你们就会发现我们的页面越来越漂亮,运行效果如下图所示:

基于springboot+bootstrap+mysql+redis搭建一套完整的权限架构引入bootstrap前端框架

https://blog.csdn.net/linzhefeng89/article/details/78752658

 

基于springboot+bootstrap+mysql+redis搭建一套完整的权限架构【六】【引入bootstrap前端框架】

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/linzhefeng89/article/details/78752658

       bootstrap是目前最受欢迎的前端框架,bootstrap是基于HTML、CSS、JAVASCRIPT的,她界面美光、代码简介、开发灵活,因此深受开发者的喜爱,本文中用的bootstrap框架的版本是3.0以上的版本,若大家对bootstrap框架有兴趣可以直接到她的官方网站直接查阅相应的文档信息,官网地址:http://getbootstrap.com/

       由于bootstrap实际上我们在谷歌的时候会发现已经有大量的大神已经基于bootstrap给我们搭建好了各种各样的DEMO,因此我们完全没有必要自己去闭门造车,我们直接拿着前人写好的DEMO我们自己修改下就可以变成我们自己的东西,由于深入bootstrap的话那就是要一个专题来讲解了,此处主要讲解的是如何基于bootstrap来搭建一套完整的权限架构因此就不再此处深入的去讲解该框架,只要大家跑过一遍代码可以懂得如何使用就好了,若像更深入的去学习,那么大家去网上搜索下资料,上面有大量的资料供大家学习。

       首先基于我们的第五章的工程我们将我们事先已经封装好的bootstrap脚本引入到我们现有的工程,大家若需要该快的代码,请大家直接在文章的末尾去github上自己去拿此块封装的代码,目录如下:

技术分享图片

       到此我们的bootstraop框架引入完成,那么基于bootstrap框架我们现在开始开发属于我们的第一个bootstrap页面登陆页,打开我们的templates文件在底下找到我们login.html页面,进行重新的编辑该页面代码如下:

 

  1.  
    <!DOCTYPE html>
  2.  
    <html xmlns:th="http://www.thymeleaf.org">
  3.  
    <head>
  4.  
    <meta content="text/html;charset=UTF-8"/>
  5.  
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
  6.  
    <title>登录页面</title>
  7.  
    <link rel="stylesheet" th:href="@{/css/bootstrap.min.css}"/>
  8.  
    <style type="text/css">
  9.  
    body {
  10.  
    padding-top: 50px;
  11.  
    }
  12.  
    .starter-template {
  13.  
    padding: 40px 15px;
  14.  
    text-align: center;
  15.  
    }
  16.  
    </style>
  17.  
    </head>
  18.  
    <body>
  19.  
    <!--/
  20.  
    <nav class="navbar navbar-inverse navbar-fixed-top">
  21.  
    <div class="container">
  22.  
    <div class="navbar-header">
  23.  
    <a class="navbar-brand" href="#">Spring Security演示</a>
  24.  
    </div>
  25.  
    <div id="navbar" class="collapse navbar-collapse">
  26.  
    <ul class="nav navbar-nav">
  27.  
    <li><a th:href="@{/}"> 首页 </a></li>
  28.  
     
  29.  
    </ul>
  30.  
    </div>.nav-collapse
  31.  
    </div>
  32.  
    </nav>
  33.  
    -->
  34.  
    <div class="container">
  35.  
     
  36.  
    <div class="starter-template">
  37.  
    <p th:if="${param.logout}" class="bg-warning">已成功注销</p><!-- 1 -->
  38.  
    <p th:if="${param.error}" th:text="${session.SPRING_SECURITY_LAST_EXCEPTION.message}==‘Bad credentials‘?‘账号/密码错误!‘:${session.SPRING_SECURITY_LAST_EXCEPTION.message}" class="bg-danger">
  39.  
     
  40.  
    </p> <!-- 2 -->
  41.  
    <h2>使用账号密码登录</h2>
  42.  
    <form name="form" th:action="@{/login}" action="/login" method="POST"> <!-- 3 -->
  43.  
    <div class="form-group">
  44.  
    <label for="username">账号</label>
  45.  
    <input type="text" class="form-control" name="username" id="username" value="" placeholder="账号" />
  46.  
    </div>
  47.  
    <div class="form-group">
  48.  
    <label for="password">密码</label>
  49.  
    <input type="password" class="form-control" name="password" id="password" placeholder="密码" />
  50.  
    </div>
  51.  
    <input type="submit" id="login" value="Login" class="btn btn-primary" />
  52.  
    </form>
  53.  
    </div>
  54.  
     
  55.  
    </div>
  56.  
     
  57.  
    </body>
  58.  
    </html>
      重新加载并运行我们的程序我们会看到我们全新的页面效果如下所示:

 

技术分享图片
       到此我们的登陆的首页已经完成了,接着我们再开发我们登陆成功以后的主页main.html,在我们编写我们的主页的时候,我们需要重新设计下我们的数据库,因此我们现有的表结构无法支撑起来我们的整个业务系统,因此我们重新设计了我们的数据库如下图:

技术分享图片

接着我们直接生成我们的数据库执行脚本,并在我们的数据库中执行,同时使用我们上一章开发的工具我们来快速生成我们的代码,并根据我们的权限架构来修改我们的代码,以下是经过修改以后的代码的结构:

技术分享图片

在我们的工程中有一些我们经常用到的CSS或者js 我们并不想每个页面都进行一次引用,因此我们新建一个全局的引用到我们的工程(在templates底下新建一个文件夹include同时创建includebase.html文件)中如下:

 

  1.  
    <html xmlns:th="http://www.thymeleaf.org">
  2.  
    <link th:href="@{/css/bootstrap.min.css}" rel="stylesheet"/>
  3.  
    <link th:href="@{/css/bootstrap-table.css}" rel="stylesheet"/>
  4.  
    <link th:href="@{/font-awesome/css/font-awesome.min.css}" rel="stylesheet"/>
  5.  
    <link th:href="@{/css/bootstrap-datetimepicker.css}" rel="stylesheet"/>
  6.  
    <link th:href="@{/css/bootstrapValidator.min.css}" rel="stylesheet"/>
  7.  
    <link th:href="@{/css/fileinput.css}" rel="stylesheet"/>
  8.  
    <link th:href="@{/css/fileinput-rtl.css}" rel="stylesheet"/>
  9.  
    <link th:href="@{/css/theme.css}" rel="stylesheet"/>
  10.  
    <link th:href="@{/css/zTreeStyle/metro.css}" rel="stylesheet"/>
  11.  
     
  12.  
     
  13.  
    <script th:src="@{/js/sockjs.min.js}"></script>
  14.  
    <script th:src="@{/js/stomp.min.js}"></script>
  15.  
    <script th:src="@{/js/jquery.js}"></script>
  16.  
    <script th:src="@{/js/distpicker/distpicker.data.js}"></script>
  17.  
    <script th:src="@{/js/distpicker/distpicker.js}"></script>
  18.  
    <script th:src="@{/js/websocket/socketUtil.js}"></script>
  19.  
    <script th:src="@{/js/bootstrap.min.js}"></script>
  20.  
    <script th:src="@{/js/bootstrap/nav/nav.js}"></script>
  21.  
    <script th:src="@{/js/bootstrap/tab/bootstrap-tab.js}"></script>
  22.  
    <script th:src="@{/js/bootstrap/tree/tree.js}"></script>
  23.  
    <script th:src="@{/js/bootstrap/alert/alert.js}"></script>
  24.  
    <script th:src="@{/js/bootstrap/table/bootstrap-table.js}"></script>
  25.  
    <script th:src="@{/js/bootstrap/date/bootstrap-datetimepicker.js}"></script>
  26.  
    <script th:src="@{/js/bootstrap/validator/bootstrapValidator.min.js}"></script>
  27.  
    <script th:src="@{/js/bootstrap/upload/fileinput.min.js}"></script>
  28.  
    <script th:src="@{/js/bootstrap/upload/plugins/sortable.js}"></script>
  29.  
    <script th:src="@{/js/bootstrap/upload/locales/zh.js}"></script>
  30.  
    <script th:src="@{/js/bootstrap/upload/theme.js}"></script>
  31.  
    <script th:src="@{/js/bootstrap/ztree/jquery.ztree.all-3.5.min.js}"></script>
  32.  
    <script th:src="@{/js/bootstrap/checkbox/checkbox.js}"></script>
  33.  
    <script th:src="@{/js/ajaxutil/ajaxUtil.js}"></script>
  34.  
    <script th:src="@{/js/dict/dictUtil.js}"></script>
  35.  
    <script th:src="@{/js/bootstrap/date/date.prototype.format.js}"></script>
  36.  
    <script th:src="@{/js/bootstrap/util/number.pick.util.js}"></script>
  37.  
     
  38.  
    </html>

通过以上的代码的快速生成、修改以及配置我们这才可以正式开发我们的登陆成功以后的首页,首页代码如下:

 

 

  1.  
    <html xmlns:th="http://www.thymeleaf.org"
  2.  
    xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
  3.  
    <head th:include="include/includebase"></head>
  4.  
    <link th:href="@{css/sb-admin.css}" rel="stylesheet"/>
  5.  
    <script th:inline="javascript">
  6.  
    $(function () {
  7.  
    // 页面加载完成以后开启websocket的连接
  8.  
    var options = new Array();
  9.  
    options.sockurl = ‘/ricky-websocket‘;
  10.  
    options.stompClienturl = ‘/ricky/topic/greetings‘;
  11.  
    options.login = [[${#authentication.name}]];
  12.  
    options.success = function(greeting){
  13.  
    var r = eval("("+JSON.parse(greeting.body).content+")")
  14.  
    alert(r);
  15.  
    // $("#greetings").append("<tr><td>" + JSON.parse(greeting.body).content + "</td></tr>");
  16.  
    }
  17.  
    $.fn.socketConnect(options);
  18.  
    // 初始化nav
  19.  
    $.fn.bootstrapNav({index:‘main‘,navTitle:‘XXXX管理系统‘});
  20.  
    // 初始化标签页
  21.  
    $("#tabContainer").tabs({
  22.  
    data: [{
  23.  
    id: ‘99999999‘,
  24.  
    text: ‘首页‘,
  25.  
    url: "home",
  26.  
    closeable: false
  27.  
    }],
  28.  
    showIndex: 0,
  29.  
    loadAll: false
  30.  
    })
  31.  
    //
  32.  
    $.fn.bootstrapTree({url:"/user/mainTree",treeId:‘menu_tree‘,tabId:"tabContainer"});
  33.  
    $.fn.dictUtil("/dict/loadDict");
  34.  
    });
  35.  
    </script>
  36.  
    <body >
  37.  
    <div id="wrapper">
  38.  
     
  39.  
    <!-- Navigation -->
  40.  
    <nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
  41.  
    <!-- Brand and toggle get grouped for better mobile display -->
  42.  
    <div class="navbar-header" id="navbar_header">
  43.  
     
  44.  
    </div>
  45.  
    <!-- Top Menu Items -->
  46.  
    <ul class="nav navbar-right top-nav">
  47.  
    <li class="dropdown">
  48.  
    <a href="#" class="dropdown-toggle" data-toggle="dropdown"><i class="fa fa-envelope"></i> <b class="caret"></b></a>
  49.  
    <ul class="dropdown-menu message-dropdown">
  50.  
    <li class="message-preview">
  51.  
    <a href="#">
  52.  
    <div class="media">
  53.  
    <span class="pull-left">
  54.  
    <img class="media-object" src="http://placehold.it/50x50" alt="" />
  55.  
    </span>
  56.  
    <div class="media-body">
  57.  
    <h5 class="media-heading"><strong>John Smith</strong>
  58.  
    </h5>
  59.  
    <p class="small text-muted"><i class="fa fa-clock-o"></i> Yesterday at 4:32 PM</p>
  60.  
    <p>Lorem ipsum dolor sit amet, consectetur...</p>
  61.  
    </div>
  62.  
    </div>
  63.  
    </a>
  64.  
    </li>
  65.  
    <li class="message-preview">
  66.  
    <a href="#">
  67.  
    <div class="media">
  68.  
    <span class="pull-left">
  69.  
    <img class="media-object" src="http://placehold.it/50x50" alt="" />
  70.  
    </span>
  71.  
    <div class="media-body">
  72.  
    <h5 class="media-heading"><strong>John Smith</strong>
  73.  
    </h5>
  74.  
    <p class="small text-muted"><i class="fa fa-clock-o"></i> Yesterday at 4:32 PM</p>
  75.  
    <p>Lorem ipsum dolor sit amet, consectetur...</p>
  76.  
    </div>
  77.  
    </div>
  78.  
    </a>
  79.  
    </li>
  80.  
    <li class="message-preview">
  81.  
    <a href="#">
  82.  
    <div class="media">
  83.  
    <span class="pull-left">
  84.  
    <img class="media-object" src="http://placehold.it/50x50" alt="" />
  85.  
    </span>
  86.  
    <div class="media-body">
  87.  
    <h5 class="media-heading"><strong>John Smith</strong>
  88.  
    </h5>
  89.  
    <p class="small text-muted"><i class="fa fa-clock-o"></i> Yesterday at 4:32 PM</p>
  90.  
    <p>Lorem ipsum dolor sit amet, consectetur...</p>
  91.  
    </div>
  92.  
    </div>
  93.  
    </a>
  94.  
    </li>
  95.  
    <li class="message-footer">
  96.  
    <a href="#">Read All New Messages</a>
  97.  
    </li>
  98.  
    </ul>
  99.  
    </li>
  100.  
    <li class="dropdown">
  101.  
    <a href="#" class="dropdown-toggle" data-toggle="dropdown"><i class="fa fa-user"></i> <font th:text="${#authentication.name}"></font> <b class="caret"></b></a>
  102.  
    <ul class="dropdown-menu">
  103.  
    <li>
  104.  
    <a href="#" ><i class="fa fa-fw fa-gear"></i> 修改密码 </a>
  105.  
    </li>
  106.  
    <li class="divider"></li>
  107.  
    <li>
  108.  
    <a href="/logout" ><i class="fa fa-fw fa-power-off"></i>退 出</a>
  109.  
    </li>
  110.  
    </ul>
  111.  
    </li>
  112.  
    </ul>
  113.  
    <!-- Sidebar Menu Items - These collapse to the responsive navigation menu on small screens -->
  114.  
    <div class="collapse navbar-collapse navbar-ex1-collapse">
  115.  
    <ul class="nav navbar-nav side-nav" id="menu_tree">
  116.  
     
  117.  
    </ul>
  118.  
    </div>
  119.  
    <!-- /.navbar-collapse -->
  120.  
    </nav>
  121.  
    <div id="page-wrapper" style="border-radius:5px 5px 0 0;">
  122.  
    <div id="tabContainer"></div>
  123.  
    </div>
  124.  
    </div>
  125.  
    <!--
  126.  
    <div th:text="${#authentication.name}">
  127.  
    The value of the "name" property of the authentication object should appear here.
  128.  
    </div>
  129.  
    这是一个登陆成功以后的首页
  130.  
    <div class="row">
  131.  
    <div class="col-md-12">
  132.  
    <table id="conversation" class="table table-striped">
  133.  
    <thead>
  134.  
    <tr>
  135.  
    <th>Greetings</th>
  136.  
    </tr>
  137.  
    </thead>
  138.  
    <tbody id="greetings">
  139.  
    </tbody>
  140.  
    </table>
  141.  
    </div>
  142.  
    </div>
  143.  
    -->
  144.  
    </body>
  145.  
    </html>

那么到此处我们已经完成了整个系统的基础架构的百分80的开发工作了,那么剩下的就是开发我们相应的功能模块。

 

本章代码的GitHub地址:https://github.com/185594-5-27/csdndemo/tree/master-base-tree

 

上一篇文章地址:基于springboot+bootstrap+mysql+redis搭建一套完整的权限架构【五】【编写基础代码快速生成工具】

 

 

下一篇文章地址:基于springboot+bootstrap+mysql+redis搭建一套完整的权限架构【七】【菜单维护模块】

 

以上是关于基于springboot+bootstrap+mysql+redis搭建一套完整的权限架构整合springSecurity的主要内容,如果未能解决你的问题,请参考以下文章

基于 Springboot + Vue + Bootstrap 的电影票订票购票系统,可用于毕业设计课程设计练手学习

基于 Springboot + Vue + Bootstrap 的电影票订票购票系统,可用于毕业设计课程设计练手学习

基于springboot+bootstrap+mysql+redis搭建一套完整的权限架构整合springSecurity

bootstrap+springboot实现shiro权限控制的坑

基于springboot+bootstrap+thymeleaf的物联网一站式宠物管理平台(领养救助商城)设计 毕业论文+用户手册+源码清单+项目源码及数据库文件

基于Springboot实现销售团队管理系统