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

news2024/9/30 9:30:38

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://www.coloradmin.cn/o/348763.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

中国国家级地面气象站基本气象要素日值数据集(V3.0)

数据集摘要 数据集包含了中国基本气象站、基准气候站、一般气象站在内的主要2474个站点1951年1月以来本站气压、气温、降水量、蒸发量、相对湿度、风向风速、日照时数和0cm地温要素的日值数据。数据量为21.3GB。 (1)SURF_CLI_CHN_MUL_DAY-TEM-12001-201501.TXT 气温数据TEM, 包…

央行数据-一款查逆回购 LPR 货币供应量 资产负债表 Shibor 数据的专业工具

自己开发的APP, App Store搜索"央行数据" 即可下载欢迎大家下载,给修改意见逆回购、正回购、MLF、票据&#xff0c;俗称央行发钱房贷基准利率多少? M2/M1/M0, 资产负债表,Shibor 了解下这款APP是经济,投资理财,股市,房价分析参考利器适用于关注经济、货币政策的用户…

第五章.与学习相关技巧—权重初始值(随机初始值,Xavier初始值,He初始值)

第五章.与学习相关技巧 5.2 权重初始值 本节将介绍权重初始值的推荐值&#xff0c;并通过实验确认神经网络的学习是否会快速进行。 1.权值衰减 权值衰减就是一种以减少权重参数的值为目的进行学习的方法&#xff0c;通过减少权重参数值来抑制过拟合的情况发生。 2.权重初始值不…

表现良好的最长时段[前缀和思想子数组]

前缀和与最长子数组前言一、表现良好的最长时间段二、前缀和思想&子数组1、前缀和&map2、前缀和&单调栈总结参考文献前言 对于子数组/子串问题&#xff0c;紧密连续前缀和/滑动窗口/单调栈&#xff1b;挖掘内在规律&#xff0c;可以简化代码&#xff0c;降低时空复…

Python多进程同步——文件锁

多个进程共享同一份资源&#xff08;共享内存、文件等&#xff09;时&#xff0c;会涉及到资源竞争问题。为了解决这种问题&#xff0c;一般采取的措施是进程在访问资源前加锁保护&#xff0c;避免多个进程同时读写。本文介绍的Python文件锁可以用来解决多进程的同步问题。 目录…

天荒地老修仙功-第六部第二篇:Spring Cloud Eureka自我保护机制

Eureka Server 在运行期间会去统计心跳失败比例在 15 分钟之内是否低于 85%&#xff0c;如果低于 85%&#xff0c;Eureka Server 会将这些实例保护起来&#xff0c;让这些实例不会过期&#xff0c;但是在保护期内如果服务刚好这个服务提供者非正常下线了&#xff0c;此时服务消…

[SCTF2019]babyre 题解

对未来的真正慷慨&#xff0c;是把一切献给现在。 ——加缪 目录 1.查壳 2.处理花指令&#xff0c;找到main函数 这一操作过程可以参考下面的视频&#xff1a; 3.静态分析第一部分,psword1 4.静态分析第二部分,psword2 5.静态分析第五部分&#xff0c;psword3 6.根据ps…

国产Linux操作系统读写RFID、NFC、IC卡示例源码

Windows系统应该是我们接触最多、最为熟悉的电脑端操作系统。Windows操作系统只能安装在x86指令集的CPU电脑中&#xff0c;x64是x86的升级版&#xff0c;Intel、Amd是x86指令集CPU最大的2个生产商。Windows系统下&#xff0c;外设接口驱动一般都封装成DLL动态库内&#xff0c;通…

基于springboot开发众筹平台前后台管理系统【完整源码+数据库+运行指导】

一、项目简介 本项目是一套基于springboot开发众筹平台前后台管理系统&#xff0c;主要针对计算机相关专业的正在做bishe的学生和需要项目实战练习的Java学习者。 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目可以直接作为bishe使用。 项目都经过严格调试&#…

2023csoj寒假训练10

csoj寒假训练10 A 并查集 两个黑球之间距离不够这个白球通过的话&#xff0c;视为一个集合 考虑怎样维护这样两两之间的关系&#xff0c;我们使用并查集 同时黑球与直线的关系也要做一次维护 最后可以直接判断是否上下两条直线是否在一个集合里面 如果在一个集合里面说明…

Spring容器演示——采用Spring配置文件管理Bean

一、创建Maven项目 创建Maven项目 - SpringDemo&#xff0c;设置项目位置以及组ID 修改项目的Maven配置 二、添加Spring依赖 在Maven仓库里查找Spring框架&#xff08;https://mvnrepository.com&#xff09; 查看Spring Core 选择版本 - 5.3.25 添加到pom.xml文件的元…

盘点程序员都不一定知道的小众网站!建议收藏,java编程必备!

俗话说的好&#xff0c;有一个趁手的工具解决了80%的疑虑。作为智慧物种的新新人类&#xff0c;手上掌握一两个不为人知的好用网站已经是件稀疏平常的事情。 今天我们就一起来看看&#xff0c;有哪些小众网站是程序员必备的&#xff01; 业内人士都知道&#xff0c;一直劈里啪…

windows下面安装Python和pip终极教程

Python的语言风格很nice&#xff0c;但是这门语言对于windows并不算很友好&#xff0c;因为如果是初学者在windows环境下安装&#xff0c;简直是折磨人&#xff0c;会遇到各种蛋疼的情况。本文希望提供傻瓜式的教程&#xff0c;能够令读者成功安装Python和pip。 第一步&#xf…

什么是push通知栏消息?

我是3y&#xff0c;一年CRUD经验用十年的markdown程序员&#x1f468;&#x1f3fb;‍&#x1f4bb;常年被誉为职业八股文选手 今天继续更新Austin&#xff0c;给Austin新增一个发送渠道&#xff08;PUSH通知栏推送&#xff09; Push通知栏消息是非常常见的&#xff0c;几乎每…

【elementUI】自定义封装el-upload上传内容

文章目录为实现如图所示功能&#xff0c;点击第一步弹出模态框&#xff0c;第二部将所有文件导入&#xff0c;第三步点击确定的时候上传到后台接口&#xff0c;封装一个组件 1.搭建template <div style"display: inline-block; margin-left: 10px;"><el-bu…

leaflet 设置多个marker,导出为一个geojson文件(066)

第066个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+leaflet中使用L.marker设置多个markers, 通过数据重组,导出为geojson文件。 这里面 ayer instanceof L.Marker 是一个很重要的判断条件,可以灵活地去运用。 直接复制下面的 vue+openlayers源代码,操作2分钟即可…

Ubuntu20.04LTS设置DNS解析(解决系统重启DNS不生效的问题)

文章目录背景介绍解决方案背景介绍 近期买了一台戴尔的工作站&#xff0c;搭建的是Ubuntu20.04系统&#xff0c;使用时发现Ubuntu20.04系统上网经常卡顿&#xff08;上网方式是有线网&#xff0c;使用的千兆网口和千兆网线&#xff09;。 使用网速测试工具speedtest-cli进行了…

redis五大数据结构

目录1.1 Redis数据结构-动态字符串1.2 Redis数据结构-intset1.3 Redis数据结构-Dict1.4 Redis数据结构-ZipList1.5 Redis数据结构-ZipList的连锁更新问题1.6 Redis数据结构-QuickList1.7 Redis数据结构-SkipList1.8 Redis数据结构-RedisObject2.0 Redis数据结构-String2.1 Redi…

前端性能优化的整理笔记

&#x1f6b4; 前言大厂面试题分享 面试题库后端面试题库 &#xff08;面试必备&#xff09; 推荐&#xff1a;★★★★★地址&#xff1a;前端面试题库&#x1f3c4;利用碎片化的时间&#xff0c;系统的整理&#xff0c;性能优化的知识点。&#x1f3af; 前端性能优化&#xf…

初识网络原理,关于网络编程的基础

一.网络的重要性对于程序员而言&#xff0c;几乎所程序都依赖于网络&#xff0c;对于公司来说&#xff0c;几乎所有产品也是依赖于网络&#xff0c;这些产品不仅包括面向用户的产品&#xff0c;公司内部的一些服务也是基于公司内网来进行相互调用的。二.组网方式①基于网线直连…