Shiro和Spring MVC、Mybatis整合教程

栏目: Java · 发布时间: 6年前

内容简介:Apache Shiro 是Java的在开始之前,首先了解一下Shiro的四大功能,俗话说“知己知彼百战不殆”。认证就是用户访问系统的时候,系统要验证用户身份的合法性,比如我们通常所说的“登录”就是认证的一种方式,只有登录成功了之后我们才能访问相应的资源。在Shiro中,我们可以将用户理解为
Shiro和Spring MVC、Mybatis整合教程

Apache Shiro 是 Java安全框架 ,提供了认证(Authentication)、授权(Authorization)、会话(Session)管理、加密(Cryptography)等功能,且Shiro与Spring Security等安全框架相比具有简单性、灵活性、支持细粒度鉴权、支持一级缓存等, 还有Shiro不跟任何容器(Tomcat等)和框架(Sping等)捆绑,可以独立运行,这也造就了Shiro不仅仅是可以用在Java EE上还可以用在Java SE上

Shiro四大功能

在开始之前,首先了解一下Shiro的四大功能,俗话说“知己知彼百战不殆”。

Shiro和Spring MVC、Mybatis整合教程

认证

认证就是用户访问系统的时候,系统要验证用户身份的合法性,比如我们通常所说的“登录”就是认证的一种方式,只有登录成功了之后我们才能访问相应的资源。在Shiro中,我们可以将用户理解为 Subject 主体,在用户身份认证的时候,用户需要提供能证明他身份的信息,如用户名、密码等,用户所提供的这些用户名、密码则对应Shiro中的Principal、 Credentials,即在Subject进行身份认证的时候,需要提供相应的Principal、 Credentials,对应的代码如下:

UsernamePasswordToken token = new UsernamePasswordToken(username, password);
Subject subject = SecurityUtils.getSubject();
subject.login(token); //提交认证
复制代码

我们知道Http协议是 无状态 的,所以用户认证成功后怎么才能保持认证成功的状态呢?如果是我们开发的话一般都是登录成功后将Session储存在服务器,然后再将Session返回给用户,之后的请求用户都将这个Session带上,然后服务器根据用户请求携带的Session和服务器储存的Session进行比较来判断用户是否已认证。但是使用Shiro后, Shiro已经帮我们做好这个了(下面介绍的会话管理),是不是feel爽~

授权

授权可以理解为访问控制,在用户认证(登录)成功之后,系统对用户访问资源的权限进行控制,即确定什么用户能访问什么资源,如普通用户不能访问后台,但是管理员可以。在这里我们还需要认识几个概念,资源(Resource)、角色(Role)、权限(Permission),上面提到的Subject主体可以有多个角色,每个角色又对应多个资源的多个权限,这种 基于资源的访问控制 可以实现细粒度的权限。对主体设置角色、权限的代码如下:

SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
//  添加用户的角色
authorizationInfo.addRoles(roleIdList);
//  添加用户的权限
authorizationInfo.addStringPermissions(resourceIdList);
复制代码

如果要实现这样的授权功能,我们必定需要设计一个用户组、权限,给每个方法或者URL加上判断,是否当前登录的用户满足条件。但是使用Shiro后, Shiro也帮我们帮这些都做好了

会话管理

会话管理的会话即Session,所谓会话,即用户访问应用时保持的连接关系,在多次交互中应用能够识别出当前访问的用户是谁,且可以在多次交互中保存一些数据。如访问一些网站时登录成功后,网站可以记住用户,且在退出之前都可以识别当前用户是谁。在Shiro中,与用户有关的一切信息都可以通过Shiro的接口获得,和用户的会话Session也都由Shiro管理。如实现“记住我”或者“下次自动登录”的功能,如果要自己去开发的话,估计又得话不少时间。但是使用Shiro后, Shiro也帮我们帮这些都做好了

加密

用户密码明文保存是不是安全,应不应该MD5加密,是不是应该加盐,又要写密码加密的代码。 这些Shiro已经帮你做好了

Shiro三大核心概念

从整体概念上理解,Shiro的体系架构有三个主要的概念,Subject(主体),Security Manager (安全管理器)和 Realms (域)。

Shiro和Spring MVC、Mybatis整合教程

Subject主体

主体是当前正在操作的用户的特定数据集合。主体可以是一个人,也可以代表第三方服务,守护进程,定时任务或类似的东西,也就是几乎所有与该应用进行交互的事物。所有Subject都绑定到 SecurityManager ,与Subject的所有交互都会委托给 SecurityManager,可以把 Subject 认为是一个门面,SecurityManager 才是实际的执行者。

Security Manager安全管理器

安全管理器,即所有与安全有关的操作都会与 SecurityManager 交互,且它 管理着所有Subject 可以看出它是Shiro的核心,它负责与后边介绍的其他组件进行交互,如果学习过 SpringMVC,你可以把它看成DispatcherServlet前端控制器, 一般来说,一个应用只会存在一个SecurityManager实例

Realms域

域,Shiro从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法,也需要从Realm得到用户相应的角色 / 权限进行验证用户是否能进行操作,即Realms作为Shiro与应用程序安全数据之间的“桥梁”。从这个意义上讲,Realm实质上是一个安全相关的 DAO ,它封装了数据源的连接细节,并在需要时将相关数据提供给Shiro。其中Realm有2个方法, doGetAuthenticationInfo 用来认证, doGetAuthorizationInfo 用来授权。

Spring、Spring MVC、Mybatis、Shiro集成

项目目录

Shiro和Spring MVC、Mybatis整合教程

添加依赖包

pox.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>shiro</groupId>
  <artifactId>shiro</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>

  <name>shiro Maven Webapp</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>

    <!--Sping核心依赖-->
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>5.1.3.RELEASE</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.springframework/spring-web -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>5.1.3.RELEASE</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>5.1.3.RELEASE</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.1.3.RELEASE</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.1.3.RELEASE</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.springframework/spring-context-support -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context-support</artifactId>
      <version>5.1.3.RELEASE</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>5.1.3.RELEASE</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>5.1.3.RELEASE</version>
      <scope>test</scope>
    </dependency>

    <!--Mybatis依赖-->
    <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.4.6</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>1.3.2</version>
    </dependency>

    <!--MySQL连接驱动-->
    <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.13</version>
    </dependency>


    <!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-core -->
    <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-core</artifactId>
      <version>1.4.0</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-web -->
    <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-web</artifactId>
      <version>1.4.0</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring -->
    <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-spring</artifactId>
      <version>1.4.0</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>4.0.1</version>
      <scope>provided</scope>
    </dependency>


  </dependencies>

  <build>
    <finalName>shiro</finalName>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-war-plugin</artifactId>
          <version>3.2.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>

复制代码

创建数据库和实体类

为了减少篇幅,只做简单介绍,详情可以查看源码,数据库文件在本项目根目录。

Shiro和Spring MVC、Mybatis整合教程
  • resource表:资源表,有 idname 两个字段,分别对应资源id和权限。
  • role表:角色表,有 idname 两个字段,分别对应角色id和角色名。
  • role_resource表:角色资源权限表,有 idroleidresid 三个字段,分别对应自增id、角色id和资源id。
  • user表:用户表,有 idusernamepassword 三个字段,分别对应自增id、用户名和密码。
  • user_role表:有 iduidrid 三个字段,分别对应自增id、用户id、和角色id。

Dao层

AccountDao.java:

public interface AccountDao {
    User findUserByUsername(String username);
    List<Role> findRoleByUserId(int id);
    List<Resource> findResourceByUserId(int id);
}
复制代码

service层

AccountService.java:

public interface AccountService {
    User findUserByUsername(String username);
    List<Role> findRoleByUserId(int id);
    List<Resource> findResourceByUserId(int id);
    boolean login(User user);
}
复制代码

AccountServiceImpl.java:

package com.shiro.service.impl;

import com.shiro.dao.AccountDao;
import com.shiro.entity.Role;
import com.shiro.entity.User;
import com.shiro.service.AccountService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;

/**
 * @program: shiro
 * @description:
 * @author: Xue 8
 * @create: 2019-02-01 15:37
 **/
@Service
public class AccountServiceImpl implements AccountService {
    @Resource
    AccountDao accountDao;

    /**
     * @description: 根据用户名查找用户信息
     * @param: [username]
     * @return: com.shiro.entity.User
     * @author: Xue 8
     * @date: 2019/2/1
     */
    @Override
    public User findUserByUsername(String username) {
        return accountDao.findUserByUsername(username);
    }

    @Override
    public List<Role> findRoleByUserId(int id) {
        return accountDao.findRoleByUserId(id);
    }

    @Override
    public List<com.shiro.entity.Resource> findResourceByUserId(int id) {
        return accountDao.findResourceByUserId(id);
    }

    public boolean login(User user){
//        获取当前用户对象subject
        Subject subject = SecurityUtils.getSubject();
        System.out.println("subject:" + subject.toString());
//        创建用户名/密码身份证验证Token
        UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword());
        System.out.println("token" + token);
        try {
            subject.login(token);
            System.out.println("登录成功");
            return true;
        } catch (Exception e) {
            System.out.println("登录失败" + e);
            return false;
        }
    }
}

复制代码

MyRealm.java

package com.shiro.service.impl;

import com.shiro.entity.Role;
import com.shiro.entity.User;
import com.shiro.service.AccountService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
 * @program: shiro
 * @description:
 * @author: Xue 8
 * @create: 2019-02-01 15:16
 **/

public class MyRealm extends AuthorizingRealm {
    @Resource
    AccountService accountService;

    /**
      * 身份认证的方法 认证成功获取身份验证信息
     * 这里最主要的是user.login(token);这里有一个参数token,这个token就是用户输入的用户密码,
     * 我们平时可能会用一个对象user来封装用户名和密码,shiro用的是token,这个是控制层的代码,还没到shiro,
     * 当调用user.login(token)后,就交给shiro去处理了,接下shiro应该是去token中取出用户名,然后根据用户去查数据库,
     * 把数据库中的密码查出来。这部分代码一般都是要求我们自定义实现,自定义一个realm,重写doGetAuthenticationInfo方法
    **/
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//        获取用户输入的用户名和密码
//        实际上这个token是从UserResource面currentUser.login(token)传过来的
//        两个token的引用都是一样的
        String username = (String) authenticationToken.getPrincipal();
//        密码要用字符数组来接受 因为UsernamePasswordToken(username, password) 储存密码的时候是将字符串类型转成字符数组的 查看源码可以看出
        String password = new String((char[]) authenticationToken.getCredentials());
//        调用service 根据用户名查询用户信息
        User user = accountService.findUserByUsername(username);
//        String password = user.getPassword();
//        判断用户是否存在 不存在则抛出异常
        if (user != null) {
//            判断用户密码是否匹配 匹配则不匹配则抛出异常
            if (user.getPassword().equals(password)) {
//                登录成功 把用户信息储存在Session中
                Session session = SecurityUtils.getSubject().getSession();
                session.setAttribute("userSession", user);
                session.setAttribute("userSessionId", user.getId());
//                认证成功 返回一个AuthenticationInfo的实现
                return new SimpleAuthenticationInfo(username, password, getName());
            } else {
                System.out.println("密码不正确");
                throw new IncorrectCredentialsException();
            }
        } else {
            System.out.println("账号不存在");
            throw new UnknownAccountException();
        }
    }

    /**
      * 授权的方法
     * 1、subject.hasRole(“admin”) 或 subject.isPermitted(“admin”):自己去调用这个是否有什么角色或者是否有什么权限的时候;
     *
     * 2、@RequiresRoles("admin") :在方法上加注解的时候;
     *
     * 3、[@shiro.hasPermission name = "admin"][/@shiro.hasPermission]:在页面上加shiro标签的时候,即进这个页面的时候扫描到有这个标签的时候。
     * 4、xml配置权限的时候也会走
    **/
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("授权");
//        从principalCollection获取用户信息
//        如果doGetAuthenticationInfo(user,password,getName()); 传入的是user类型的数据 那这里getPrimaryPrincipal获取到的也是user类型的数据
        String username = (String) principalCollection.getPrimaryPrincipal();
        User user = accountService.findUserByUsername(username);
//        获取该用户的所有角色
        List<Role> roleList = accountService.findRoleByUserId(user.getId());
//        将角色的id放到一个String列表中 因为authorizationInfo.addRoles()方法只支持角色的String列表或者单个角色String
        List<String> roleIdList = new ArrayList<String>();
        for (Role role:roleList) {
            roleIdList.add(role.getName());
        }
//        获取该用户的所有权限
        List<com.shiro.entity.Resource> resourceList = accountService.findResourceByUserId(user.getId());
        List<String> resourceIdList = new ArrayList<String>();
//        将权限id放到一个String列表中 因为authorizationInfo.addRoles()方法只支持角色的String列表或者单个角色String
        for (com.shiro.entity.Resource resource:resourceList) {
            resourceIdList.add(resource.getName());
        }
        System.out.println("授权11");
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
//        添加用户的角色
        authorizationInfo.addRoles(roleIdList);
//        添加用户的权限
        authorizationInfo.addStringPermissions(resourceIdList);
        return authorizationInfo;
    }
}

复制代码

controller层

AccountController.java

package com.shiro.controller;

import com.shiro.entity.User;
import com.shiro.service.AccountService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

/**
 * @program: shiro
 * @description:
 * @author: Xue 8
 * @create: 2019-02-01 13:14
 **/
@Controller
public class AccountController {
    @Resource
    AccountService accountService;
    @Resource
    HttpServletRequest servletRequest;

    @RequestMapping(value = "/home")
    public String  home(){
        return "home";
    }

    @RequestMapping(value = "/login", method = RequestMethod.GET)
    public String  getLogin(){
        return "login";
    }

    @RequestMapping(value = "/login", method = RequestMethod.POST)
    public String doLogin(@RequestParam(value = "username") String username,
                        @RequestParam(value = "password") String password){
        User user = new User();
        user.setUsername(username);
        user.setPassword(password);
        if (accountService.login(user)) {
            return "/home";
        }
        return "/login";
    }
}

复制代码

GET 方法访问 /login 的时候,会出现登录页面,输入账号密码点击登录数据将以 POST 方式提交给 /login ,如果账号密码匹配返回 /home 的页面,否则返回 /login 的页面。 /home 页面只有在登录且有权限的情况下才可以访问, 未登录情况下 访问会转跳 /login 页面,这个在Shiro的配置文件里面配置。

配置文件

applicationContext.xml:配置Spring

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">

    <!--开启扫描注册-->
    <context:component-scan base-package="com.shiro"></context:component-scan>

    <!--读取properties配置-->
    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location" value="classpath:jdbcConfig.properties"></property>
    </bean>

    <!--配置数据源-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${driverClassName}"></property>
        <property name="username" value="${username}"></property>
        <property name="password" value="${password}"></property>
        <property name="url" value="${url}"></property>
    </bean>

    <!--配置session工厂-->
    <bean id="sessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"></property>
        <property name="configLocation" value="classpath:mybatis-config.xml"></property>
        <property name="mapperLocations" value="classpath:mapping/*.xml"></property>
    </bean>

    <!--配置扫描mapping-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.shiro.dao"></property>
        <property name="sqlSessionFactoryBeanName" value="sessionFactoryBean"></property>
    </bean>
</beans>
复制代码

spring-shiro.xml:配置Shiro

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="myRealm"></property>
    </bean>

    <bean id="myRealm" class="com.shiro.service.impl.MyRealm">
        <!--关闭权限缓存 不然doGetAuthorizationInfo授权方法不执行-->
        <property name="authorizationCachingEnabled" value="false"/>
    </bean>

    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager"></property>
        <property name="successUrl" value="/success"></property>
        <!--登录页面-->
        <property name="loginUrl" value="/login"></property> 
        <property name="filterChainDefinitions">
            <value>
                <!--配置`/home`只有拥有`admin`角色的用户才可以访问-->
                /home = authc,roles[admin]
            </value>
        </property>
    </bean>

</beans>
复制代码

这里需要注意的是 在配置Realm的时候,如果没用上缓存功能的话,需要将缓存关掉,不然进不到doGetAuthorizationInfo授权方法。

测试

打开 http://localhost:8080/login 登录页面,填写正确用户名和密码登录

Shiro和Spring MVC、Mybatis整合教程

登录成功 转跳成功页面

Shiro和Spring MVC、Mybatis整合教程
清除浏览器cookie之后(未登录状态),打开 http://localhost:8080/home 页面,自动转跳到了 /login 登录页面(即没有权限访问),登录账户,再次打开 http://localhost:8080/home

页面即可正常访问。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

复杂网络理论及其应用

复杂网络理论及其应用

汪小帆、李翔、陈关荣 / 清华大学出版社 / 2006 / 45.00元

国内首部复杂网络专著 【图书目录】 第1章 引论 1.1 引言 1.2 复杂网络研究简史 1.3 基本概念 1.4 本书内容简介 参考文献 第2章 网络拓扑基本模型及其性质 2.1 引言 2.2 规则网络 2.3 随机图 2.4 小世界网络模型 2.5 无标度网络模型 ......一起来看看 《复杂网络理论及其应用》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

在线进制转换器
在线进制转换器

各进制数互转换器

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具