精华内容
下载资源
问答
  • 作者:冷豪链接:cnblogs.com/learnhow/p/5694876.html一、架构要学习如何使用Shiro必须先从它的架构谈起,作为一款安全框架Shiro的设计相当精妙。Shiro的应用不依赖任何容器,它也可以在JavaSE下使用。但是最常用的...

    作者:冷豪

    链接:cnblogs.com/learnhow/p/5694876.html

    e54f0d66114a7a41e1f3c9349bdce373.png

    一、架 构

    要学习如何使用Shiro必须先从它的架构谈起,作为一款安全框架Shiro的设计相当精妙。Shiro的应用不依赖任何容器,它也可以在JavaSE下使用。但是最常用的环境还是JavaEE。下面以用户登录为例:

    cf488567e971b262a25484aa6f55a740.png

    1、使用用户的登录信息创建令牌

    UsernamePasswordToken token = new UsernamePasswordToken(username, password);

    token可以理解为用户令牌,登录的过程被抽象为Shiro验证令牌是否具有合法身份以及相关权限。

    2、执行登陆动作

    SecurityUtils.setSecurityManager(securityManager); // 注入SecurityManager
    Subject subject = SecurityUtils.getSubject(); // 获取Subject单例对象
    subject.login(token); // 登陆

    Shiro的核心部分是SecurityManager,它负责安全认证与授权。Shiro本身已经实现了所有的细节,用户可以完全把它当做一个黑盒来使用。SecurityUtils对象,本质上就是一个工厂类似Spring中的ApplicationContext。

    Subject是初学者比较难于理解的对象,很多人以为它可以等同于User,其实不然。Subject中文翻译:项目,而正确的理解也恰恰如此。它是你目前所设计的需要通过Shiro保护的项目的一个抽象概念。通过令牌(token)与项目(subject)的登陆(login)关系,Shiro保证了项目整体的安全。

    3、判断用户

    Shiro本身无法知道所持有令牌的用户是否合法,因为除了项目的设计人员恐怕谁都无法得知。因此Realm是整个框架中为数不多的必须由设计者自行实现的模块,当然Shiro提供了多种实现的途径,本文只介绍最常见也最重要的一种实现方式——数据库查询。

    4、两条重要的英文

    我在学习Shiro的过程中遇到的第一个障碍就是这两个对象的英文名称:AuthorizationInfo,AuthenticationInfo。不用怀疑自己的眼睛,它们确实长的很像,不但长的像,就连意思都十分近似。

    在解释它们前首先必须要描述一下Shiro对于安全用户的界定:和大多数操作系统一样。用户具有角色和权限两种最基本的属性。例如,我的Windows登陆名称是learnhow,它的角色是administrator,而administrator具有所有系统权限。这样learnhow自然就拥有了所有系统权限。那么其他人需要登录我的电脑怎么办,我可以开放一个guest角色,任何无法提供正确用户名与密码的未知用户都可以通过guest来登录,而系统对于guest角色开放的权限极其有限。

    同理,Shiro对用户的约束也采用了这样的方式。AuthenticationInfo代表了用户的角色信息集合,AuthorizationInfo代表了角色的权限信息集合。如此一来,当设计人员对项目中的某一个url路径设置了只允许某个角色或具有某种权限才可以访问的控制约束的时候,Shiro就可以通过以上两个对象来判断。说到这里,大家可能还比较困惑。先不要着急,继续往后看就自然会明白了。

    二、实现Realm

    如何实现Realm是本文的重头戏,也是比较费事的部分。这里大家会接触到几个新鲜的概念:缓存机制、散列算法、加密算法。由于本文不会专门介绍这些概念,所以这里仅仅抛砖引玉的谈几点,能帮助大家更好的理解Shiro即可。

    1、缓存机制

    Ehcache是很多Java项目中使用的缓存框架,Hibernate就是其中之一。它的本质就是将原本只能存储在内存中的数据通过算法保存到硬盘上,再根据需求依次取出。你可以把Ehcache理解为一个Map对象,通过put保存对象,再通过get取回对象。

    xml version="1.0" encoding="UTF-8"?>

    以上是ehcache.xml文件的基础配置,timeToLiveSeconds为缓存的最大生存时间,timeToIdleSeconds为缓存的最大空闲时间,当eternal为false时ttl和tti才可以生效。更多配置的含义大家可以去网上查询。

    2、散列算法与加密算法

    md5是本文会使用的散列算法,加密算法本文不会涉及。散列和加密本质上都是将一个Object变成一串无意义的字符串,不同点是经过散列的对象无法复原,是一个单向的过程。例如,对密码的加密通常就是使用散列算法,因此用户如果忘记密码只能通过修改而无法获取原始密码。但是对于信息的加密则是正规的加密算法,经过加密的信息是可以通过秘钥解密和还原。

    3、用户注册

    请注意,虽然我们一直在谈论用户登录的安全性问题,但是说到用户登录首先就是用户注册。如何保证用户注册的信息不丢失,不泄密也是项目设计的重点。

    public 

    如果你不清楚什么叫加盐可以忽略散列的过程,只要明白存储在数据库中的密码是根据户注册时填写的密码所产生的一个新字符串就可以了。经过散列后的密码替换用户注册时的密码,然后将User保存进数据库。剩下的工作就丢给UserService来处理。

    那么这样就带来了一个新问题,既然散列算法是无法复原的,当用户登录的时候使用当初注册时的密码,我们又应该如何判断?答案就是需要对用户密码再次以相同的算法散列运算一次,再同数据库中保存的字符串比较。

    4、匹配

    CredentialsMatcher是一个接口,功能就是用来匹配用户登录使用的令牌和数据库中保存的用户信息是否匹配。当然它的功能不仅如此。本文要介绍的是这个接口的一个实现类:HashedCredentialsMatcher

    public 

    可以看到,这个实现里设计人员仅仅是增加了一个不允许连续错误登录的判断。真正匹配的过程还是交给它的直接父类去完成。连续登录错误的判断依靠Ehcache缓存来实现。显然match返回true为匹配成功。

    5、获取用户的角色和权限信息

    说了这么多才到我们的重点Realm,如果你已经理解了Shiro对于用户匹配和注册加密的全过程,真正理解Realm的实现反而比较简单。我们还得回到上文提及的两个非常类似的对象AuthorizationInfo和AuthenticationInfo。因为Realm就是提供这两个对象的地方。

    public 

    根据Shiro的设计思路,用户与角色之前的关系为多对多,角色与权限之间的关系也是多对多。在数据库中需要因此建立5张表,分别是:

    用户表(存储用户名,密码,盐等)

    角色表(角色名称,相关描述等)

    权限表(权限名称,相关描述等)

    用户-角色对应中间表(以用户ID和角色ID作为联合主键)

    角色-权限对应中间表(以角色ID和权限ID作为联合主键)

    具体dao与service的实现本文不提供。总之结论就是,Shiro需要根据用户名和密码首先判断登录的用户是否合法,然后再对合法用户授权。而这个过程就是Realm的实现过程。

    6、会话

    用户的一次登录即为一次会话,Shiro也可以代替Tomcat等容器管理会话。目的是当用户停留在某个页面长时间无动作的时候,再次对任何链接的访问都会被重定向到登录页面要求重新输入用户名和密码而不需要程序员在Servlet中不停的判断Session中是否包含User对象。

    启用Shiro会话管理的另一个用途是可以针对不同的模块采取不同的会话处理。以淘宝为例,用户注册淘宝以后可以选择记住用户名和密码。之后再次访问就无需登陆。但是如果你要访问支付宝或购物车等链接依然需要用户确认身份。当然,Shiro也可以创建使用容器提供的Session最为实现。

    三、与SpringMVC集成

    有了注册模块和Realm模块的支持,下面就是如何与SpringMVC集成开发。有过框架集成经验的同学一定知道,所谓的集成基本都是一堆xml文件的配置,Shiro也不例外。

    1、配置前端过滤器

    先说一个题外话,Filter是过滤器,interceptor是拦截器。前者基于回调函数实现,必须依靠容器支持。因为需要容器装配好整条FilterChain并逐个调用。后者基于代理实现,属于AOP的范畴。

    如果希望在WEB环境中使用Shiro必须首先在web.xml文件中配置

    xml version="1.0" encoding="UTF-8"?>

    熟悉Spring配置的同学可以重点看有绿字注释的部分,这里是使Shiro生效的关键。由于项目通过Spring管理,因此所有的配置原则上都是交给Spring。DelegatingFilterProxy的功能是通知Spring将所有的Filter交给ShiroFilter管理。

    接着在classpath路径下配置spring-shiro-web.xml文件

    <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/beans    
                           http://www.springframework.org/schema/beans/spring-beans-3.1.xsd    
                           http://www.springframework.org/schema/context    
                           http://www.springframework.org/schema/context/spring-context-3.1.xsd    
                           http://www.springframework.org/schema/mvc    
                           http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd"
    >

    需要注意filterChainDefinitions过滤器中对于路径的配置是有顺序的,当找到匹配的条目之后容器不会再继续寻找。因此带有通配符的路径要放在后面。三条配置的含义是:

     /authc/admin需要用户有用admin权限

    /authc/**用户必须登录才能访问

    /**其他所有路径任何人都可以访问

    说了这么多,大家一定关心在Spring中引入Shiro之后到底如何编写登录代码呢。

    @Controller

    登录完成以后,当前用户信息被保存进Session。这个Session是通过Shiro管理的会话对象,要获取依然必须通过Shiro。传统的Session中不存在User对象。

    @Controller

    90e5c53cd4b0eab41a4882e110c3bb86.png

    展开全文
  • 发挥硬件的能力一般是 C 这种面向硬件的语言常干的事儿,C 语言领域经常通过调整内存布局优化内存占用,而 Java 领域则的很少,原因在于 Java 可以智能地优化内存布局,内存布局对 Java 程序员的透明的。...

    Disruptor 是一款高性能的有界内存队列,目前应用非常广泛,Log4j2、SpringMessaging、HBase、Storm 都用到了 Disruptor,那 Disruptor 的性能为什么这么高呢?Disruptor 项目团队曾经写过一篇论文,详细解释了其原因,可以总结为如下:

    1. 内存分配更加合理,使用 RingBuffer 数据结构,数组元素在初始化时一次性全部创建,提升缓存命中率;对象循环利用,避免频繁 GC。
    2. 能够避免伪共享,提升缓存利用率。
    3. 采用无锁算法,避免频繁加锁、解锁的性能消耗。
    4. 支持批量消费,消费者可以无锁方式消费多个消息。

    其中,前三点涉及到的知识比较多,所以今天咱们重点讲解前三点,不过在详细介绍这些知识之前,我们先来聊聊 Disruptor 如何使用,好让你先对 Disruptor 有个感官的认识。

    下面的代码出自官方示例,我略做了一些修改,相较而言,Disruptor 的使用比 Java SDK提供 BlockingQueue 要复杂一些,但是总体思路还是一致的,其大致情况如下:

    在 Disruptor 中,生产者生产的对象(也就是消费者消费的对象)称为 Event,使用Disruptor 必须自定义 Event,例如示例代码的自定义 Event 是 LongEvent;

    构建 Disruptor 对象除了要指定队列大小外,还需要传入一个 EventFactory,示例代码中传入的是LongEvent::new;

    消费 Disruptor 中的 Event 需要通过 handleEventsWith() 方法注册一个事件处理器,发布 Event 则需要通过 publishEvent() 方法。

    // 自定义 Eventclass LongEvent {    private long value;    public void set(long value) {        this.value = value;    }}// 指定 RingBuffer 大小,// 必须是 2 的 N 次方int bufferSize = 1024;// 构建 DisruptorDisruptor disruptor    = new Disruptor<>(    LongEvent::new,    bufferSize,    DaemonThreadFactory.INSTANCE);// 注册事件处理器disruptor.handleEventsWith(    (event, sequence, endOfBatch) ->    System.out.println("E: "+event));// 启动 Disruptordisruptor.start();// 获取 RingBufferRingBuffer ringBuffer    = disruptor.getRingBuffer();// 生产 EventByteBuffer bb = ByteBuffer.allocate(8);for (long l = 0; true; l++){    bb.putlong(0, l);    // 生产者生产消息    ringBuffer.publishEvent(    (event, sequence, buffer) ->    event.set(buffer.getlong(0)), bb);    Thread.sleep(1000);}

    RingBuffer 如何提升性能

    Java SDK 中 ArrayBlockingQueue 使用数组作为底层的数据存储,而 Disruptor 是使用RingBuffer作为数据存储。RingBuffer 本质上也是数组,所以仅仅将数据存储从数组换成RingBuffer 并不能提升性能,但是 Disruptor 在 RingBuffer 的基础上还做了很多优化,其中一项优化就是和内存分配有关的。

    在介绍这项优化之前,你需要先了解一下程序的局部性原理。简单来讲,程序的局部性原理指的是在一段时间内程序的执行会限定在一个局部范围内。这里的“局部性”可以从两个方面来理解,一个是时间局部性,另一个是空间局部性。时间局部性指的是程序中的某条指令一旦被执行,不久之后这条指令很可能再次被执行;如果某条数据被访问,不久之后这条数据很可能再次被访问。而空间局部性是指某块内存一旦被访问,不久之后这块内存附近的内存也很可能被访问。

    CPU 的缓存就利用了程序的局部性原理:CPU 从内存中加载数据 X 时,会将数据 X 缓存在高速缓存 Cache 中,实际上 CPU 缓存 X 的同时,还缓存了 X 周围的数据,因为根据程序具备局部性原理,X 周围的数据也很有可能被访问。从另外一个角度来看,如果程序能够很好地体现出局部性原理,也就能更好地利用 CPU 的缓存,从而提升程序的性能。Disruptor 在设计 RingBuffer 的时候就充分考虑了这个问题,下面我们就对比着ArrayBlockingQueue 来分析一下。

    首先是 ArrayBlockingQueue。生产者线程向 ArrayBlockingQueue 增加一个元素,每次增加元素 E 之前,都需要创建一个对象 E,如下图所示,ArrayBlockingQueue 内部有 6个元素,这 6 个元素都是由生产者线程创建的,由于创建这些元素的时间基本上是离散的,所以这些元素的内存地址大概率也不是连续的。

    4c04e56b1768585222754aaed7db3f29.png

    下面我们再看看 Disruptor 是如何处理的。Disruptor 内部的 RingBuffer 也是用数组实现的,但是这个数组中的所有元素在初始化时是一次性全部创建的,所以这些元素的内存地址大概率是连续的,相关的代码如下所示。

    for (int i=0; i

    Disruptor 内部 RingBuffer 的结构可以简化成下图,那问题来了,数组中所有元素内存地址连续能提升性能吗?能!为什么呢?因为消费者线程在消费的时候,是遵循空间局部性原理的,消费完第 1 个元素,很快就会消费第 2 个元素;当消费第 1 个元素 E1 的时候,CPU 会把内存中 E1 后面的数据也加载进 Cache,如果 E1 和 E2 在内存中的地址是连续的,那么 E2 也就会被加载进 Cache 中,然后当消费第 2 个元素的时候,由于 E2 已经在Cache 中了,所以就不需要从内存中加载了,这样就能大大提升性能。

    1823aad535d860c0042e6aba3975d72c.png

    除此之外,在 Disruptor 中,生产者线程通过 publishEvent() 发布 Event 的时候,并不是创建一个新的 Event,而是通过 event.set() 方法修改 Event, 也就是说 RingBuffer 创建的 Event 是可以循环利用的,这样还能避免频繁创建、删除 Event 导致的频繁 GC 问题。

    如何避免“伪共享”

    高效利用 Cache,能够大大提升性能,所以要努力构建能够高效利用 Cache 的内存结构。而从另外一个角度看,努力避免不能高效利用 Cache 的内存结构也同样重要。

    有一种叫做“伪共享(False sharing)”的内存布局就会使 Cache 失效,那什么是“伪共享”呢?

    伪共享和 CPU 内部的 Cache 有关,Cache 内部是按照缓存行(Cache Line)管理的,缓存行的大小通常是 64 个字节;CPU 从内存中加载数据 X,会同时加载 X 后面(64-size(X))个字节的数据。下面的示例代码出自 Java SDK 的 ArrayBlockingQueue,其内部维护了 4 个成员变量,分别是队列数组 items、出队索引 takeIndex、入队索引putIndex 以及队列中的元素总数 count。

    /** 队列数组 */final Object[] items;/** 出队索引 */int takeIndex;/** 入队索引 */int putIndex;/** 队列中元素总数 */int count;

    当 CPU 从内存中加载 takeIndex 的时候,会同时将 putIndex 以及 count 都加载进Cache。下图是某个时刻 CPU 中 Cache 的状况,为了简化,缓存行中我们仅列出了takeIndex 和 putIndex。

    268b3acd6cb4e34dd9f8d11153c1dc25.png

    假设线程 A 运行在 CPU-1 上,执行入队操作,入队操作会修改 putIndex,而修改putIndex 会导致其所在的所有核上的缓存行均失效;此时假设运行在 CPU-2 上的线程执行出队操作,出队操作需要读取 takeIndex,由于 takeIndex 所在的缓存行已经失效,所以 CPU-2 必须从内存中重新读取。入队操作本不会修改 takeIndex,但是由于 takeIndex和 putIndex 共享的是一个缓存行,就导致出队操作不能很好地利用 Cache,这其实就是伪共享。简单来讲,伪共享指的是由于共享缓存行导致缓存无效的场景

    ArrayBlockingQueue 的入队和出队操作是用锁来保证互斥的,所以入队和出队不会同时发生。如果允许入队和出队同时发生,那就会导致线程 A 和线程 B 争用同一个缓存行,这样也会导致性能问题。所以为了更好地利用缓存,我们必须避免伪共享,那如何避免呢?

    5c705f8734b3c42135050c3dad941e56.png

    方案很简单,每个变量独占一个缓存行、不共享缓存行就可以了,具体技术是缓存行填充。比如想让 takeIndex 独占一个缓存行,可以在 takeIndex 的前后各填充 56 个字节,这样就一定能保证 takeIndex 独占一个缓存行。下面的示例代码出自 Disruptor,Sequence对象中的 value 属性就能避免伪共享,因为这个属性前后都填充了 56 个字节。Disruptor中很多对象,例如 RingBuffer、RingBuffer 内部的数组都用到了这种填充技术来避免伪共享。

    // 前:填充 56 字节class LhsPadding{    long p1, p2, p3, p4, p5, p6, p7;}class Value extends LhsPadding{    volatile long value;}// 后:填充 56 字节class RhsPadding extends Value{    long p9, p10, p11, p12, p13, p14, p15;}class Sequence extends RhsPadding{    // 省略实现}

    Disruptor 中的无锁算法

    ArrayBlockingQueue 是利用管程实现的,中规中矩,生产、消费操作都需要加锁,实现起来简单,但是性能并不十分理想。Disruptor 采用的是无锁算法,很复杂,但是核心无非是生产和消费两个操作。Disruptor 中最复杂的是入队操作,所以我们重点来看看入队操作是如何实现的。

    对于入队操作,最关键的要求是不能覆盖没有消费的元素;对于出队操作,最关键的要求是不能读取没有写入的元素,所以 Disruptor 中也一定会维护类似出队索引和入队索引这样两个关键变量。Disruptor 中的 RingBuffer 维护了入队索引,但是并没有维护出队索引,这是因为在 Disruptor 中多个消费者可以同时消费,每个消费者都会有一个出队索引,所以 RingBuffer 的出队索引是所有消费者里面最小的那一个。

    下面是 Disruptor 生产者入队操作的核心代码,看上去很复杂,其实逻辑很简单:如果没有足够的空余位置,就出让 CPU 使用权,然后重新计算;反之则用 CAS 设置入队索引。

    // 生产者获取 n 个写入位置do {    //cursor 类似于入队索引,指的是上次生产到这里    current = cursor.get();    // 目标是在生产 n 个    next = current + n;    // 减掉一个循环    long wrapPoint = next - bufferSize;    // 获取上一次的最小消费位置    long cachedGatingSequence = gatingSequenceCache.get();    // 没有足够的空余位置    if (wrapPoint>cachedGatingSequence || cachedGatingSequence>current){        // 重新计算所有消费者里面的最小值位置        long gatingSequence = Util.getMinimumSequence(        gatingSequences, current);        // 仍然没有足够的空余位置,出让 CPU 使用权,重新执行下一循环        if (wrapPoint > gatingSequence){            LockSupport.parkNanos(1);            continue;        }        // 从新设置上一次的最小消费位置        gatingSequenceCache.set(gatingSequence);    } else if (cursor.compareAndSet(current, next)){        // 获取写入位置成功,跳出循环        break;    }}while (true);

    总结

    Disruptor 在优化并发性能方面可谓是做到了极致,优化的思路大体是两个方面,一个是利用无锁算法避免锁的争用,另外一个则是将硬件(CPU)的性能发挥到极致。尤其是后者,在 Java 领域基本上属于经典之作了。

    发挥硬件的能力一般是 C 这种面向硬件的语言常干的事儿,C 语言领域经常通过调整内存布局优化内存占用,而 Java 领域则用的很少,原因在于 Java 可以智能地优化内存布局,内存布局对 Java 程序员的透明的。这种智能的优化大部分场景是很友好的,但是如果你想通过填充方式避免伪共享就必须绕过这种优化,关于这方面 Disruptor 提供了经典的实现,你可以参考。

    由于伪共享问题如此重要,所以 Java 也开始重视它了,比如 Java 8 中,提供了避免伪共享的注解:@sun.misc.Contended,通过这个注解就能轻松避免伪共享(需要设置 JVM参数 -XX:-RestrictContended)。不过避免伪共享是以牺牲内存为代价的,所以具体使用的时候还是需要仔细斟酌。

    写在最后

    今天的分享就到这里,其实本文的"高性能队列Disruptor"只是小编收集整理的《Java并发编程学习笔记》中的一篇;完整的学习笔记小编已经打包整理好了,正在学习Java并发编程或者有需要的朋友可以帮忙转发一下(以便让更多人的看到),然后在私信我【并发编程】即可获取免费下载方式

    3610656fd6c24cbb40ed2a6cb2d18f6a.png

    《Java并发编程学习笔记》目录

    一定要先转发+转发+转发,在私信我【编发编程】

    展开全文
  • Bootstrap模版框架怎么用

    千次阅读 2017-08-09 16:35:35
    Bootstrap是现在很流行的一套前端框架,美观大方而且用起来非常方便,可能很多做前端开发的新手朋友还不知道Bootstrap模版框架怎么用,今天小编就来向大家介绍一下Bootstrap的用法。 工具/...

    Bootstrap是现在很流行的一套前端框架,美观大方而且用起来非常方便,可能很多做前端开发的新手朋友还不知道Bootstrap模版框架怎么用,今天小编就来向大家介绍一下Bootstrap的用法。

    Bootstrap模版框架怎么用

    工具/原料

    • Bootstrap相关文件

    方法/步骤

    1. 1

      首先我们当然是需要得到Bootstrap相关文件,因为在网页中应用Bootstrap是需要引入其相关文件的。我们可以到Bootstrap官网下载。

      Bootstrap模版框架怎么用
    2. 2

      如果你的英文水平不是太好的话,没关系,我们可以到国内做的汉化比较好的Bootstrap网站去下载,最新版本都是3,属于扁平化的那种。

      Bootstrap模版框架怎么用
    3. 3

      以上两步点击下载按钮后都会跳转到一个详细下载列表,有三种Bootstrap,这里我们下载第一个就可以了。

      Bootstrap模版框架怎么用
    4. 4

      下载完成后解压,会看到文件有三个子文件夹,分别是css、font、js,里面带min的文件都是压缩后的文件,在网站上线的时候用,其他未压缩的文件我们可以在平时开发的时候用。

      Bootstrap模版框架怎么用
    5. 5

      再之后就是要用这套Bootstrap框架了,首先要做的就是建立一个html文件,你可以用任何文本编辑器,这里推荐Dreamweaver CS6,个人感觉比较好用。

      Bootstrap模版框架怎么用
    6. 6

      接下来就是要引入css文件了,要把文件的路径写正确,如果网页内用到了Bootstrap的js效果,那么必须先引入jQuery文件,因为Bootstrap的js插件都是基于jQuery的。

      Bootstrap模版框架怎么用
    7. 7

      最后就可以在body标签内应用Bootstrap相关的class了,这些都是封装好的,只要嵌套正确就是做出漂亮的网页了。

      Bootstrap模版框架怎么用
      Bootstrap模版框架怎么用
      END

    注意事项

    • Bootstrap标签需要合理嵌套。
    展开全文
  • 怎么用bootstrap框架

    2016-01-23 15:59:47
    怎么把引用bootstrap,将自己做的页面做成响应式。是要用bootstrap里的样式.css文件吗,那自己做的页面的类名是不是得改成bootstrap样式文件里的类名?求大神指教,第一次用bootstrap,不会
  • 有会的SSH +bootStrap的教教我啊有会的SSH +bootStrap的教教我啊
  • Bootstrap框架

    2019-09-28 03:40:15
    1、设置默认格式 3、md,sm, xs 4、空格和没有空格的选择器 二、响应式介绍 - 响应式布局是什么? 同一个网页在不同的终端上呈现不同的布局等- 响应式怎么实现的? 1.... 用框架 ...

     

    1、设置默认格式

    3、md,sm, xs

     

    4、空格和没有空格的选择器

     

    二、响应式介绍

    - 响应式布局是什么?
      同一个网页在不同的终端上呈现不同的布局等
    - 响应式怎么实现的?
      1. CSS3 media query 媒体查询
      2. JS去控制网页的布局和样式等
        - 缺点:工作量大,网页响应慢
        - 优点: 专治疑难杂症
      3. 用框架
        - Bootstrap

    测试用css 媒体查询实现响应式

    方式一、link.css文件

    主文件中导入link.css文件

    方式二、link2.css文件

    在主文件中导入link2.css文件

     

    三、常用插件

    常用插件基本上都是基于jQuery

      先导入插件的CSS文件

      再导入jQuery文件

      最后导入JS,注意jQuery是必须要放在JS上面的

     1、Sweet Alert(弹出框)

      使用步骤:1下载 2解压找到里面的dist(主要是dist)和animate.css  3引入到自己的文件里就行了
    注:如果是html参数就要用animate
       





    
    

    五、需要知道的几个插件网址

          1、SweetAlert (弹出框):https://github.com/t4t5/sweetalert

       2、SweetAlert2 (弹出框):https://github.com/limonte/sweetalert2

       3、Font Awesome(字体图标):http://fontawesome.io

          4、jQuery lazy load(懒加载):https://github.com/tuupola/jquery_lazyload

          5、Toastr(通知栏):http://codeseven.github.io/toastr/

    六、Bootstrap网址:http://v3.bootcss.com/

          有时间看一下这个网址:http://www.jq22.com/daima

    七、自定义Bootstrap组件,

        1、找到自定义那一页

        2、勾选我用到的组件
        3、拉到最后面,点击下载

    八、Bootstrap补充:

       - modal
       和模态框使用的
       $("#myModal").modal("show")
      - collapse :也是在JavaScript组件中去找,点击按钮有信息出来

    - tooltip : 相当于提示信息,就像是一个按钮,指向按钮会有提示信息

    转载于:https://www.cnblogs.com/lujiacheng-Python/p/10013799.html

    展开全文
  • 1.bootStrap是干嘛的?有什么用处? 我们在开发前端页面的时候,如果每一个按钮、样式、处理浏览器兼容性的代码都要...2.bootStrap怎么用? 1.bootstrap官网 学习bootstrap最主要是学会看文档,bootstrap本是一个已...
  • BootStrap 需要更多资料点我 主要内容 BootStrap的安装和使用 ...​ Bootstrap 是最受欢迎的 HTML、CSS 和 JS 框架,用于开发响应式布局、移动设备优先的 WEB 项目。 ​ 2011年,twitter 的"一小撮"工程师为了提
  • 介绍移动端常用开发框架Bootstrap;介绍动态样式语言less、sass、stylus的基本使用。移动端js事件移动端的操作方式和PC端是不同的,移动端主要手指操作,所以有特殊的touch事件,touch事件包括如下几个事件:1、...
  • right叠加,那样整个页面效果不是非常好,那么怎么解决了,首先,如果第一个摸态框有button按钮,那么点击按钮时就是延时器,在body上赋予“modal-body”类,代码如下: function btn_register() { ...
  • 的时候提示我类型错误了,但我不知道怎么改,请大神伸出援手,下面是我的代码 js代码: ``` function dic_table(){ var row=1; //alert("gggg"); $('#dic_table').bootstrapTable('destroy'); $('#dic...
  • 拼图Pintuer-跨屏响应式布局前端开发CSS框架几个推荐理由:国产;跨屏响应式,这是最基本的;使用简单,只需引入jquery.js、pinter.js、pinter.css...目前国产前端框架比较活跃的是layui,layui我也挺强大的,拿他...
  • 今天学习前端Bootstrap,其实很久以前就看过,但没怎么用。总觉得只是定义一个类用人家封装好的东西,自己再在它的基础之上进行样式的修改,没有什么需要去学的。 但等到前段时间要写页面了,既然是自适应,自己当然...
  • Bootstrap的基本使用方法,5分钟帮你搞懂怎么用

    万次阅读 多人点赞 2016-03-28 21:13:04
    作为Web开发的Coder,是不是很对浏览器兼容性,各种移动设备适配都很头大,所以我们有必要学习一下当下主流的一个Html5框架,即Bootstrap
  • chrome来调试页面,发现手机上浏览布局全乱了,我在页面中用到了bootstrap框架,使用时要哪个就去套用class样式,贴上部分代码,html代码:首页第二页第三页//图片轮播图 css代码:body {padding-bottom: 50px;...
  • bootstrap中的表格能够很好的显示想要显示的页面, 然后也能够响应式的方式来处理显示的表格. 工具/原料 bootstrap的基本框架, 这里使用最新版3. 方法/步骤1 首 先, 你...
  • 在异步刷新需要更新某个Bootstrap框架的Select控件,为其添加一个,或是重新选中某个值时,会发现隐藏的select框的值修改了,但是前面显示选中的值还是不变,就需要下面的方法。 先前在网上搜了好久,试了这篇文章...
  • 下了个BeyondAdmin连开发文档都没有,不知道怎么用,而且还是收费的,有没有其他好用的基于bootstrap的UI开发组件?
  • Bootstrap用户手册

    2014-10-08 18:03:10
    这本书教你怎么用Bootstrap框架轻松设计出“杀手级”界面及响应式网站。从怎么用Bootstrap的HTML/CSS工具和现成模板构建页面开始,逐步深入地掌握它内置的交互组件和jQuery插件,常常是一行代码都不用写。 作为源自...
  • 引子 哟大家好啊,我是非凡小王 前段时间我发了个blink,就是说我做了一个网站然后赚到q了,很多人也想知道怎么做 ...这个框架也是很多人的一个框架,是十分好看的 并且支持响应式布局 通俗点来说就是手机...
  • 1. 第二种方式,访问页面的时候通过后台获取当前用户的所有权限,然后判断是否相等然后显示,但是我寻思着,shiro框架干啥?还不如直接获取当前用户的权限,每个节点id与数据库的权限相匹配也同样完成相同效果 1. 第三...
  • 由于项目需要,所以打算好好学习下bootstrap框架,之前了解一点,框架总体不难,但涉及到的东西还是很多,想要熟练掌握它,还是要多练练。一:bootstrap是什么?bs是什么? 即前端页面搭建的标准化框架工具,已经写好...
  • flask之前过,不过前端点框架没用过bootstrap,第一次使用终于通了。 期间好多地方不知道怎么写,使用bootstrap提供点模板还是要修改一些东西才能够。 遇到的问题: 点击提交按钮没有反应 提交后,在flask中...
  • BootStrap基本使用

    2019-12-07 14:07:06
    这几天在学习BootStrap,...对于BootStrap框架我不做介绍,因为我自己也是不太懂,但是我知道怎么用的。以下的代码都是一些小小demo,便于自己以后查找使用吧! 1、基本的框架: <!DOCTYPE html> <h...
  • 最近都是vue及基于vue的UI框架,比如Element,有些年没有用BootStrap了,不知怎么的今晚突然想装个BootStrap到自己的小项目看看,使用bower安装时一直报以下错误: /usr/local/lib/node_modules/bower/lib/node_...
  • ajax能返回值,字符串拼接,就是拼不上。的是bring boot+mybatise框架
  • 就在昨天我要洗洗睡了的时候,我的同学给我发消息,说他做web开发遇到了一个问题,问我学“bootstrap怎么做到两个模块之间很平滑的衔接?”what?平滑衔接是个什么鬼?然后他就给我发了下面的图: 他告诉我在做...

空空如也

空空如也

1 2 3 4 5 ... 8
收藏数 156
精华内容 62
关键字:

bootstrap框架怎么用