代理模式我们会先讲一下静态代理,然后讲一下动态代理,为了能从JDK的静态代理和动态代理之中体会他们之间的不同,加深对他们的理解,在这里面引入的业务场景,是你们非常感兴趣的,也就是说我们会引入一个分库的业务场景,那这里面会简单扩展一下,Spring的分库使用方式,并不会重点的来讲Spring的分库,而是重点来讲我们的静态代理和动态代理,毕竟我们还是基于JDK模式的课程,但是我相信你们,如果这章节理解透彻的话,自己也是能实现的,首先我们找到这个包,在结构型里面创建这个包,proxy,代理包,这里面有个实体,Order
public abstract class AbstractRoutingDataSource extends AbstractDataSource implements InitializingBean {private Map<Object, Object> targetDataSources;private Object defaultTargetDataSource;private boolean lenientFallback = true;private DataSourceLookup dataSourceLookup = new JndiDataSourceLookup();private Map<Object, DataSource> resolvedDataSources;private DataSource resolvedDefaultDataSource;我们还会配置默认的目标defaultTargetDataSource,其他的我们先不展开来讲,看源码的时候,再分享一个看源码的技巧,很多类都是分在不同包的,我们看一个大包的时候怎么看呢,;里面有这种package,我们右键点这个展开节点,当然节点也可以收缩回去,把各项属性都打开,还有依赖,上面这里非常清晰,代理和具体被代理的目标对象

首先这两个类实现DAO层,和service层的接口,然后service的实现里边,组合了OrderDao这个接口,向左看,静态代理类里面,组合了OrderService这个接口,也就是这个,两个类实现对应的接口

然后service的实现组合了OrderDao,OrderServiceStaticProxy组合了OrderService,同时又创建了OrderService的一个实现,为了增强目标对象,那这个静态代理类,到此就讲完了,希望你们能吸收好,理解好,后续我们在使用各种框架,代理相关的类库的时候,这样才会融会贯通
package com.learn.design.pattern.structural.proxy;/*** 那如果我们使用Mybatis的话* 这个类一般叫IOrderMapper* 或者OrderMapper* 只不过我们现在来手写* * * @author Leon.Sun**/
public interface IOrderDao {/*** DAO层肯定是和业务无关的* 只是一个insert* 把class改成interface* 接下来我们写一个DAO层的实现* OrderDaoImpl* * * @param order* @return*/int insert(Order order);}
package com.learn.design.pattern.structural.proxy;/*** @author Leon.Sun**/
public interface IOrderService {/*** 这里面有一个方法* saveOrder* 里面传一个实体Order* 保存这个订单* 再写一个DAO层的接口* * 我们要增强这个方法* 所以我们使用同样的方法名* * * * @param order* @return*/int saveOrder(Order order);
}
package com.learn.design.pattern.structural.proxy;/*** 订单* * 我们现在有两个库* 那因为我们有两个库* 所以索引一个是0* 一个是1* 我们使用userId对2进行取模* 用余数对数据库dataSource声明的后缀* 假设在我们生成订单的时候* 是必须要登陆的* 必须获取userId* 那这里面是为了简化* 我们代理模式的讲解* 我们关注点还是要放在代理模式上* 那现在我们创建一个包* 为了区分* staticproxy静态代理包* * * @author Leon.Sun**/
public class Order {/*** 订单就有订单数据* 这个订单属于哪个用户呢* * */private Object orderInfo;/*** 所以我们关联一个userId* 那这里不用纠结* 是使用Integer还是String* 还是long类型* 然后写一下他的get/set方法* 然后这个实体就写完了* 那当然我们在存储订单的时候* 也可以通过service层来接收* user对象和Order对象* 然后再进行处理* 只不过我们这里把两个属性合成一个* Order这个类当中* 也是为了方便* 接下来我们还要写一下他的service层* 我们直接声明一个service的接口* IOrderService* * */private Integer userId;public Object getOrderInfo() {return orderInfo;}public void setOrderInfo(Object orderInfo) {this.orderInfo = orderInfo;}public Integer getUserId() {return userId;}public void setUserId(Integer userId) {this.userId = userId;}
}
package com.learn.design.pattern.structural.proxy;/*** 实现IOrderDao* 然后实现里面的方法* * * @author Leon.Sun**/
public class OrderDaoImpl implements IOrderDao {@Overridepublic int insert(Order order) {/*** 这个很简单* 我们就认为* 和DB的交互就在这里面* 所以呢我们直接输出* Dao层添加Order成功* return 1* 返回生效函数为1行* 代表Order插入数据库成功* 然后我们再写一个类* 当然是Service的实现* * */System.out.println("Dao层添加Order成功");return 1;}
}
package com.learn.design.pattern.structural.proxy;/*** 他来实现IOrderService* 实现IOrderService里的方法* 当然我们现在这个分层比较简单* Service下边是DAO* 那在Service之上是Controller* 那也有业务逻辑复杂的情况下呢* 加一个Manager层* Manager位于DAO层之上* * * @author Leon.Sun**/
public class OrderServiceImpl implements IOrderService {/*** 把DAO层注入进来* 只不过我们这里并没有集成Spring* 所以像@Autowired和@Resource我们并不用加* 然后我们会通过人工注入的方式* 把OrderDao注入进来* 那我们写一个Service的实现* */private IOrderDao iOrderDao;@Overridepublic int saveOrder(Order order) {//Spring会自己注入,我们课程中就直接new了/*** 我们课程中就直接new了* 直接new出来* DAO层的implement* 当然如果这一行使用Spring容器管理的话* 我们就不用显示的来写了* 或者在应用层使用set方法注入进来* 或者通过构造器注入也是OK的* 我们为了简单* 直接在这里new了* 但是我们实际在也业务的时候* 是不应该这么写的* 因为这样DAO层会new很多对象* 那对于DAO层来说* 保持一个单例是OK的* * */iOrderDao = new OrderDaoImpl();/*** 然后我们输出* service层调用DAO添加Order* * */System.out.println("Service层调用Dao层添加Order");/*** DAO层调用insert方法* 把Order传进来* 那这个Service实现就写完了* 那我们再看一下包* 这个包的类是非常的common的* 实体* DAO层* service层* 只不过我们讲设计模式都放在这个包下了* 下面我们就不分包了* 那现在我们要进行分库了* 怎么分库呢* 我们看一下Order* * */return iOrderDao.insert(order);}
}
package com.learn.design.pattern.structural.proxy.staticproxy;import com.learn.design.pattern.structural.proxy.IOrderService;
import com.learn.design.pattern.structural.proxy.Order;
import com.learn.design.pattern.structural.proxy.OrderServiceImpl;
import com.learn.design.pattern.structural.proxy.db.DataSourceContextHolder;/*** 这个类是静态代理类* OrderService的静态代理* 这里面也很简单* 我们首先在这个静态代理类里边* * * @author Leon.Sun**/
public class OrderServiceStaticProxy {/*** 来注入目标对象* 那这里面的IOrderService* 是目标对象* 我们要对saveOrder方法* 进行增强* 那我们来到orderService里边* * */private IOrderService iOrderService;/*** 当然使用不同的方法名也是OK的* 这里面并没有严格的限制* 写一个before和after* 那后面我们讲源码解析的时候* 也会领着大家来看一下* 那就是Spring里面的beforeAdvice* 在AOP包下的* 还有afterAdvice* 只不过我们通过静态代理* 非常简单的一个实现* 所以我们声明两个方法* 一个beforeMethod* 还有一个* afterMethod* 直接输出* 输出什么呢* * * @param order* @return*/public int saveOrder(Order order){/*** 首先调用beforeMethod* * */beforeMethod(order);/*** 先把这个Service new出来* 这里面和DAO层一样* 如果使用Spring容器的话就不需要显示的来new了* 那现在我们获取userId* * service的实现* 如果使用Spring容器的话* 这里面不需要显示的来new他* * */iOrderService = new OrderServiceImpl();/*** 调用saveOrder方法* 然后把Order传进来* Spring的分库实现* 首先我们创建一个包* 这个包叫db* 这里面我们创建一个类* DynamicDataSource* 动态的数据源* * */int result = iOrderService.saveOrder(order);afterMethod();return result;}/*** 执行saveOrder之前要执行的* * 那首先在saveOrder之前* 我们调用一下beforeMethod* 对saveOrder进行一个增强* * * @param order*/private void beforeMethod(Order order){/*** order获取userId* * * */int userId = order.getUserId();/*** 获得DB的路由编号* 用userId对2进行取模* 这样只会得到0或者1* * 在这里取完模之后呢* 我们就要写一段代码* 设置dataSource* 怎么设置呢* * 然后对2取模* 2对2取余余数是0* 所以dbRouter是0* * */int dbRouter = userId % 2;/*** 然后我们输出一下* 静态代理增强了OrderService的实现* 把DB切到DB Router这个上* db0或者db1* * 输出这一行* * */System.out.println("静态代理分配到【db"+dbRouter+"】处理数据");//todo 设置dataSource;/*** 我们直接调用DataSourceContextHolder* 我们自己写的* 然后setDBType* 把什么传进来呢* 把dbRouter* 只不过我们现在这里没有和Spring容器集成* String类型的* String.valueOf* 那这个静态代理类就写完了* 根据userId的不同* 插入到不同的DB当中* 一个是db0* 一个是db1* 那我们现在来到静态代理这个包下* 写一个Test* * 然后把DataSourceContextHolder里面的DBType* 设置为0* 当然这里讲代理模式的时候* 这一行执不执行都没关系* 只不过这里面只是为了扩展* 所以分库的一些知识点* 调一下他的getDBType* 可以看到这里面是0* 那这里面是有问题的* 这里面要存的是db0* 也就是说在写分库的时候* 这里很容易忽略* 里面的dbType和我们配置文件里面的是一样* 这里不要出bug* 而我在这里面就做了一个反面教材* * * */DataSourceContextHolder.setDBType("db"+String.valueOf(dbRouter));System.out.println("静态代理 before code");}/*** 这个是执行saveOrder之后要执行的代码* * */private void afterMethod(){System.out.println("静态代理 after code");}
}
package com.learn.design.pattern.structural.proxy.db;/*** 创建这么一个类* 那么这个类的核心就是ThreadLocal* 那在讲单例的时候* 我们也讲过ThreadLocal* 他是线程和线程之间隔离的* 里面是通过一个ThreadLocalMap* 来进行实现的* 那我们来写一下* * * * @author Leon.Sun**/
public class DataSourceContextHolder {/*** 现在我们来声明一个* 这里面就放String就可以了* 里面要放的值正是DataSource的beanName* 那一会我们会模拟配置一下* 保证你们能理解* 我们声明一些上下文的holder* CONTEXT_HOLDER* 等于什么呢* new ThreadLocal<String>* 也是String泛型的* 那这里面我们再开放两个方法* 静态方法就可以了* * */private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<String>();/*** 里面传一个String的dbType* 很简单* 我们向ThreadLocal里面放这个值* * * @param dbType*/public static void setDBType(String dbType){CONTEXT_HOLDER.set(dbType);}/*** 同时我们再返回一个dbType* 返回值就是String类型* 那这里就不需要入参了* 直接调用ThreadLocal的get方法* 对他进行强转* 因为我们放的就是String类型* 当然这里不强转也是OK的* 如果我们使用Object泛型的话* 那这里就一定要强转* 只不过我们这里使用的是String类型* 不强转也是OK的* 对于dataSource的上下文holder* 我们还可以清除* * * * @return*/public static String getDBType(){return (String)CONTEXT_HOLDER.get();}/*** 这里面也很简单* 调用上下文的remove方法* 那就把ThreadLocal里面包含的* map里面的值* 清除掉了* 也就是说在执行DAO层之前* 如果我们通过setDBType* 设置了这个DB为db0* 或者db1* 那么下面的DAO层就会连接对应的数据库* 那么这个db0和db1呢* 就是Spring容器中* 我们在配置里面* 声明的beanId* 那么接着回来* * * */public static void clearDBType(){CONTEXT_HOLDER.remove();}
}
package com.learn.design.pattern.structural.proxy.db;import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;/*** 用它来继承AbstractRoutingDataSource* 这个类是Spring里面提供的* 然后我们实现一下具体的方法* 注意这个方法是protected* 返回值是一个Object* 那这里面的返回值就代表着* 当前线程是哪个DB* 于是我们要写一个dataSource上下文* 我们再创建一个类* DataSourceContextHolder* * DynamicDataSource这个类里面* 写他的实现* 那这个实现非常的简单* 我们可以直接return* return什么呢* * 这一块可以跳过* 这里都没有关系的* 只不过想扩展来讲解一下* Spring的一个分库* 对分库都是非常感兴趣的* 而我们对原始的实现方案* 来实现分库* 这样我们的基础就会比较牢固* 后续再学习应用层的* 分库工具的时候* 也会得心应手* 那基础还是非常重要的* 正如我们设计模式课程一样* 他就是一个编程的内功* 非常值得温故而知新* 那每当工作一段时间回头看设计模式的时候* 都会有一种新的体会* 一时半会理解不了* 没有关系* 把能理解的理解了* 理解不了的过一阵再回头来看* 那现在的Spring分库就实现了* 那具体这些是如何对应的呢* * * * @author Leon.Sun**/
public class DynamicDataSource extends AbstractRoutingDataSource {@Overrideprotected Object determineCurrentLookupKey() {/*** return DataSourceContextHolder.getDBType* 把这个值返回回去* 那* * */return DataSourceContextHolder.getDBType();}/*** 关于bean的配置* 这个就是在Spring当中DB的配置* 所以这个dataSource我们要声明db0* * */
//    <bean id="db0" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
//        <property name="driverClassName" value="${db.driverClassName}"/>
//        <property name="url" value="${db.url}"/>
//        <property name="username" value="${db.username}"/>
//        <property name="password" value="${db.password}"/>
//        <!-- 连接池启动时的初始值 -->
//        <property name="initialSize" value="${db.initialSize}"/>
//        <!-- 连接池的最大值 -->
//        <property name="maxActive" value="${db.maxActive}"/>
//        <!-- 最大空闲值.当经过一个高峰时间后,连接池可以慢慢将已经用不到的连接慢慢释放一部分,一直减少到maxIdle为止 -->
//        <property name="maxIdle" value="${db.maxIdle}"/>
//        <!-- 最小空闲值.当空闲的连接数少于阀值时,连接池就会预申请去一些连接,以免洪峰来时来不及申请 -->
//        <property name="minIdle" value="${db.minIdle}"/>
//        <!-- 最大建立连接等待时间。如果超过此时间将接到异常。设为-1表示无限制 -->
//        <property name="maxWait" value="${db.maxWait}"/>
//        <!--#给出一条简单的sql语句进行验证 -->
//         <!--<property name="validationQuery" value="select getdate()" />-->
//        <property name="defaultAutoCommit" value="${db.defaultAutoCommit}"/>
//        <!-- 回收被遗弃的(一般是忘了释放的)数据库连接到连接池中 -->
//         <!--<property name="removeAbandoned" value="true" />-->
//        <!-- 数据库连接过多长时间不用将被视为被遗弃而收回连接池中 -->
//         <!--<property name="removeAbandonedTimeout" value="120" />-->
//        <!-- #连接的超时时间,默认为半小时。 -->
//        <property name="minEvictableIdleTimeMillis" value="${db.minEvictableIdleTimeMillis}"/>
//
//        <!--# 失效检查线程运行时间间隔,要小于MySQL默认-->
//        <property name="timeBetweenEvictionRunsMillis" value="40000"/>
//        <!--# 检查连接是否有效-->
//        <property name="testWhileIdle" value="true"/>
//        <!--# 检查连接有效性的SQL语句-->
//        <property name="validationQuery" value="SELECT 1 FROM dual"/>
//    </bean>/*** 然后再copy一份过来* 如果我们要在Spring里面实现分库的话* 刚刚也说了* 要把sqlSessionFactory里面的dataSource* property指定成dataSource的集合* * 这个是db1* 这里面包括url* 包括账号密码* 端口等等* 都可以根据实际的需要来修改了* 首先这个beanId是db0* 这个beanId是db1* 然后下面的dataSource* * */
//    <bean id="db1" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
//        <property name="driverClassName" value="${db.driverClassName}"/>
//        <property name="url" value="${db.url}"/>
//        <property name="username" value="${db.username}"/>
//        <property name="password" value="${db.password}"/>
//        <!-- 连接池启动时的初始值 -->
//        <property name="initialSize" value="${db.initialSize}"/>
//        <!-- 连接池的最大值 -->
//        <property name="maxActive" value="${db.maxActive}"/>
//        <!-- 最大空闲值.当经过一个高峰时间后,连接池可以慢慢将已经用不到的连接慢慢释放一部分,一直减少到maxIdle为止 -->
//        <property name="maxIdle" value="${db.maxIdle}"/>
//        <!-- 最小空闲值.当空闲的连接数少于阀值时,连接池就会预申请去一些连接,以免洪峰来时来不及申请 -->
//        <property name="minIdle" value="${db.minIdle}"/>
//        <!-- 最大建立连接等待时间。如果超过此时间将接到异常。设为-1表示无限制 -->
//        <property name="maxWait" value="${db.maxWait}"/>
//        <!--#给出一条简单的sql语句进行验证 -->
//         <!--<property name="validationQuery" value="select getdate()" />-->
//        <property name="defaultAutoCommit" value="${db.defaultAutoCommit}"/>
//        <!-- 回收被遗弃的(一般是忘了释放的)数据库连接到连接池中 -->
//         <!--<property name="removeAbandoned" value="true" />-->
//        <!-- 数据库连接过多长时间不用将被视为被遗弃而收回连接池中 -->
//         <!--<property name="removeAbandonedTimeout" value="120" />-->
//        <!-- #连接的超时时间,默认为半小时。 -->
//        <property name="minEvictableIdleTimeMillis" value="${db.minEvictableIdleTimeMillis}"/>
//
//        <!--# 失效检查线程运行时间间隔,要小于MySQL默认-->
//        <property name="timeBetweenEvictionRunsMillis" value="40000"/>
//        <!--# 检查连接是否有效-->
//        <property name="testWhileIdle" value="true"/>
//        <!--# 检查连接有效性的SQL语句-->
//        <property name="validationQuery" value="SELECT 1 FROM dual"/>
//    </bean>/*** 这里是一个dataSource* * */
//  <bean id="dataSource" class="com.learn.design.pattern.structural.proxy.db.DynamicDataSource">/*** 声明了targetDataSources* 里面注入了targetDataSources* 复数的一个property* 然后赋值了里面的db0和db1* 注意依赖的是db0* 也就是依赖于上面的beanId为db0和db1* 一般我们把key和ref声明成一样的* 那这个key就是CONTEXT_HOLDER里面放的* dbType* 对于这个动态的dataSource来说* return DataSourceContextHolder.getDBType()* 那就是这里的返回值* 我们要在DataSourceContextHolder里面放的就是db0和db1* 接着往下看* 上边OK了* * */
//      <property name="targetDataSources">
//          <map key-type="java.lang.String">
//              <entry value-ref="db0" key="db0"></entry>
//              <entry value-ref="db1" key="db1"></entry>
//          </map>
//      </property>/*** 然后默认的dataSource* 也就是我们如果不指定的话* 默认就是这个db0这个beanId* * */
//      <property name="defaultTargetDataSource" ref="db0"></property>
//  </bean>/*** 注意看这里面的sqlSessionFactory* 这里面加了分页的插件* 但是我们主要关注的是dataSource* 注入的这个property* 那接下来由于分库的原因* 这个dataSource就不能具体的指定到具体的某一个数据库* 而是要指定到数据库的集合* 并且配置他默认db的beanId* * 下边sqlSessionFactory* 也就是说mybatis的sqlSessionFactory* ref依赖的就是dataSource* dataSource里边有两个DB* 那这些xml配置就放到这里边* 供你们自己尝试使用* 作为一个代理模式的一个扩展* 那这一块也是特意加的* 为了你们的提高* * * */
//  <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
//      <property name="dataSource" ref="dataSource" />
//  </bean>
}
package com.learn.design.pattern.structural.proxy.staticproxy;import com.learn.design.pattern.structural.proxy.Order;/*** * @author Leon.Sun**/
public class Test {public static void main(String[] args) {Order order = new Order();order.setUserId(2);OrderServiceStaticProxy orderServiceStaticProxy = new OrderServiceStaticProxy();orderServiceStaticProxy.saveOrder(order);}
}

代理模式coding-静态代理相关推荐

  1. 代理模式之---静态代理

    代理模式之-静态代理 代理模式:为一个对象提供一个替身,以控制对这个对象的访问.即通过代理对象访问目标对象,这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能. 被代 ...

  2. 【Java】代理模式(静态代理动态代理)

    CONTENT 代理模式 静态代理 动态代理 JDK 动态代理(基于接口) CGLIB 动态代理(基于类继承) JDK 动态代理 v.s. CGLIB 动态代理 JDK 动态代理为什么必须基于接口 R ...

  3. 23种设计模式7_代理模式之一静态代理

    23种设计模式7_代理模式之一静态代理 1 基本介绍 代理模式:为其他对象提供一种代理以控制对这个对象的访问 代理模式也叫委托模式,它是一项基本设计技巧.许多其他的模式,如状态模式.策略模式.访问者模 ...

  4. Java的代理模式之静态代理和动态代理

    文章目录 静态代理 动态代理 jdk生成代理对象 cglib代理 代理模式简介: 代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目 ...

  5. 【学习笔记】结合代码理解设计模式 —— 代理模式(静态代理、动态代理、延伸)

    文章目录 什么是代理模式 一. 代理模式简介 二. 静态代理模式 三. 动态代理模式 万能模版 前言:笔记基于狂神设计模式视频.<大话设计模式>观后而写 (最近一直在更新之前的刷题博客,今 ...

  6. java代理模式之静态代理

    (一)静态代理 1.静态代码模式的介绍 静态代理在使用时,需要定义接口或者父类,被代理对象(即目标对象)与代理对象一起实现相同的接口或者是继承相同父类. 2.应用实例 具体要求: 1)定义一个接口:I ...

  7. 设计模式之代理模式(静态代理、Java动态代理、Cglib动态代理)

    代理模式的定义:由于某些原因需要给某对象提供一个代理以控制对该对象的访问.这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介. 提醒:动态代理中涉及到以前的一些知识 ...

  8. 设计模式之代理模式(静态代理动态代理)

    目录 1.什么是代理模式 2.代理模式的结构 3.代理模式的实现 3.1 静态代理和动态代理概念 3.2 静态代理 3.3 动态搭理 3.3.1 代码实现 3.3.2 Proxy类讲解 4.动态代理V ...

  9. 设计模式之代理模式(上) 静态代理与JDK动态代理

    2019独角兽企业重金招聘Python工程师标准>>> 代理模式 给某一个对象提供一个代理,并由代理对象控制对原对象的引用. 静态代理 静态代理是由我们编写好的类,在程序运行之前就已 ...

  10. 1小时搞懂设计模式之代理模式(静态代理)

    1 什么是代理模式 这个问题让我们用生活的例子来进行解释,在我们买火车票的时候可以通过黄牛帮我们买票 ,或者 我们通过媒婆介绍对象找到我们生活中的另一伴.在或者每个明星需要经纪人帮忙打理他的通告.这些 ...

最新文章

  1. 成功解决Exception “unhandled ModuleNotFoundError“No module named ‘face_recognition.cli‘
  2. python爬虫为什么xpath路径正确却检索不到内容_中国知网爬虫
  3. tftp刷路由器 linux,TP-Link无线路由器HTTP/TFTP后门漏洞
  4. 函数计算如何帮助语雀构建稳定且安全的业务架构?
  5. 用程序算法做人生选择
  6. 有没有哪种贷款不用利息,而且门槛又低?
  7. linux主机添加discuz伪静态规则,Discuz! X2.5论坛win主机与linux主机伪静态设置方法...
  8. 嵌入式环境搭建之NFS
  9. gcc观察运行时链接符号绑定
  10. 基于与非门和多路开关结构的一位全加器实现方法
  11. Linux ftp ldap认证,vsftpd+ldap认证
  12. c++实现多对多生产者消费者和socket连用
  13. html短期总结(至表单)
  14. 孙式无极桩站桩要领--林泰年
  15. 二项分布算法(伯努利实验)
  16. TypeError: this.$refs.resetFields is not a function解决方法
  17. 2020 JAVA eclipse 中文汉化包 安装教程--傻瓜式操作
  18. 如何制作查分系统-Leo老师
  19. 专业程序员开发-老狼孩插件懒人精灵版
  20. 前端 HTML(1)

热门文章

  1. JAVA语法基础 动手动脑及课后作业
  2. Android 滑动效果基础篇(四)—— Gallery + GridView
  3. LINUX Find命令使用
  4. 021:自定义path(或url)转换器
  5. 谈Elasticsearch下分布式存储的数据分布
  6. Grafana Worldmap外网用户request地图监控
  7. Vitamio中文API文档(1)—— MediaStore
  8. zookeeper 的安装配置及简单使用
  9. 测试你的Python 水平----7
  10. 在windows 2008/2012中配置RADIUS 客户端计算机上网WiFi 认证