当前位置: 首页 > 编程日记 > 正文

【Spring Security】五、自定义过滤器

在之前的几篇security教程中,资源和所对应的权限都是在xml中进行配置的,也就在http标签中配置intercept-url,试想要是配置的对象不多,那还好,但是平常实际开发中都往往是非常多的资源和权限对应,而且写在配置文件里面写改起来还得该源码配置文件,这显然是不好的。因此接下来,将用数据库管理资源和权限的对应关系。数据库还是接着之前的,用mysql数据库,因此也不用另外引入额外的jar包。

一、数据库表的设计

数据库要提供给security的数据无非就是,资源(说的通俗点就是范围资源地址)和对应的权限,这里就有两张表,但是因为他们俩是多对多的关系,因此还要设计一张让这两张表关联起来的表,除此之外,还有一张用户表,有因为用户和角色也是多对多的关系,还要额外加一张用户和角色关联的表。这样总共下来就是五张表。下面就是对应的模型图:

建表和添加数据的sql语句:
DROP TABLE IF EXISTS `resc`;
CREATE TABLE `resc` (`id` int(20) NOT NULL DEFAULT '0',`name` varchar(50) DEFAULT NULL,`res_type` varchar(50) DEFAULT NULL,`res_string` varchar(200) DEFAULT NULL,`descn` varchar(200) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;-- ----------------------------
-- Records of resc
-- ----------------------------
INSERT INTO `resc` VALUES (1, '', 'URL', '/page/admin.jsp', '管理员页面');
INSERT INTO `resc` VALUES (2, '', 'URL', '/page/user.jsp', '用户页面');
INSERT INTO `resc` VALUES (3, null, 'URL', '/page/test.jsp', '测试页面');-- ----------------------------
-- Table structure for resc_role
-- ----------------------------
DROP TABLE IF EXISTS `resc_role`;
CREATE TABLE `resc_role` (`resc_id` int(20) NOT NULL DEFAULT '0',`role_id` int(20) NOT NULL DEFAULT '0',PRIMARY KEY (`resc_id`,`role_id`),KEY `fk_resc_role_role` (`role_id`),CONSTRAINT `fk_resc_role_role` FOREIGN KEY (`role_id`) REFERENCES `role` (`id`),CONSTRAINT `fk_resc_role_resc` FOREIGN KEY (`resc_id`) REFERENCES `resc` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;-- ----------------------------
-- Records of resc_role
-- ----------------------------
INSERT INTO `resc_role` VALUES (1, 1);
INSERT INTO `resc_role` VALUES (2, 1);
INSERT INTO `resc_role` VALUES (2, 2);
INSERT INTO `resc_role` VALUES (3, 3);-- ----------------------------
-- Table structure for role
-- ----------------------------
DROP TABLE IF EXISTS `role`;
CREATE TABLE `role` (`id` int(20) NOT NULL DEFAULT '0',`name` varchar(50) DEFAULT NULL,`descn` varchar(200) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;-- ----------------------------
-- Records of role
-- ----------------------------
INSERT INTO `role` VALUES (1, 'ROLE_ADMIN', '管理员角色');
INSERT INTO `role` VALUES (2, 'ROLE_USER', '用户角色');
INSERT INTO `role` VALUES (3, 'ROLE_TEST', '测试角色');-- ----------------------------
-- Table structure for t_c3p0
-- ----------------------------
DROP TABLE IF EXISTS `t_c3p0`;
CREATE TABLE `t_c3p0` (`a` char(1) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;-- ----------------------------
-- Records of t_c3p0
-- ------------------------------ ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (`id` int(20) NOT NULL DEFAULT '0',`username` varchar(50) DEFAULT NULL,`password` varchar(50) DEFAULT NULL,`status` int(11) DEFAULT NULL,`descn` varchar(200) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES (1, 'admin', '123', 1, '管理员');
INSERT INTO `user` VALUES (2, 'user', '123', 1, '用户');
INSERT INTO `user` VALUES (3, 'test', '123', 1, '测试');-- ----------------------------
-- Table structure for user_role
-- ----------------------------
DROP TABLE IF EXISTS `user_role`;
CREATE TABLE `user_role` (`user_id` int(20) NOT NULL DEFAULT '0',`role_id` int(20) NOT NULL DEFAULT '0',PRIMARY KEY (`user_id`,`role_id`),KEY `fk_user_role_role` (`role_id`),CONSTRAINT `fk_user_role_role` FOREIGN KEY (`role_id`) REFERENCES `role` (`id`),CONSTRAINT `fk_user_role_user` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;-- ----------------------------
-- Records of user_role
-- ----------------------------
INSERT INTO `user_role` VALUES (1, 1);
INSERT INTO `user_role` VALUES (1, 2);
INSERT INTO `user_role` VALUES (2, 2);
INSERT INTO `user_role` VALUES (3, 3);

user表中包含用户登陆信息,role角色表中包含授权信息,resc资源表中包含需要保护的资源。

二、实现从数据库中读取资源信息

Spring Security需要的数据无非就是pattern和access类似键值对的数据,就像配置文件中写的那样:

<intercept-url pattern="/login.jsp" access="IS_AUTHENTICATED_ANONYMOUSLY" />1
<intercept-url pattern="/admin.jsp" access="ROLE_ADMIN" />
<intercept-url pattern="/**" access="ROLE_USER" />

其实当项目启动时,Spring Security所做的就是在系统初始化时,将以上XML中的信息转换为特定的数据格式,而框架中其他组件可以利用这些特定格式的数据,用于控制之后的验证操作。现在我们将这些信息存储在数据库中,因此就要想办法从数据库中查询这些数据,所以根据security数据的需要,只需要如下sql语句就可以:

select re.res_string,r.name from role r,resc re,resc_role rr where r.id=rr.role_id and re.id=rr.resc_id

在数据中执行这条语句做测试,得到如下结果:


这样的格式正是security所需要的数据。

三 构建一个数据库的操作的类

虽然上述的数据符合security的需要,但是security将这种数据类型进行了封装,把它封装成Map<RequestMatcher, Collection<ConfigAttribute>>这样的类型,其中RequestMatcher接口就是我们数据库中的res_string,其实现类为AntPathRequestMatcher,构建一个这样的对象只要在new的时候传入res_string就可以了,Collection<ConfigAttribute>这里对象构建起来就也是类似的,构建一个ConfigAttribute对象只需要在其实现类SecurityConfig创建的时候传入角色的名字就可以。代码如下:
package com.sunny.auth;import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;import javax.sql.DataSource;import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.jdbc.object.MappingSqlQuery;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.util.AntPathRequestMatcher;
import org.springframework.security.web.util.RequestMatcher;public class JdbcRequestMapBulider extends JdbcDaoSupport{//查询资源和权限关系的sql语句private String resourceQuery = "";//查询资源@SuppressWarnings("unchecked")public List<Resource> findResources() {ResourceMapping resourceMapping = new ResourceMapping(getDataSource(), resourceQuery);return resourceMapping.execute();}//拼接RequestMappublic LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> buildRequestMap() {LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> requestMap = new LinkedHashMap<>();List<Resource> resourceList = this.findResources();for (Resource resource : resourceList) {RequestMatcher requestMatcher = this.getRequestMatcher(resource.getUrl());List<ConfigAttribute> list = new ArrayList<ConfigAttribute>();list.add(new SecurityConfig(resource.getRole()));requestMap.put(requestMatcher, list);}return requestMap;}//通过一个字符串地址构建一个AntPathRequestMatcher对象protected RequestMatcher getRequestMatcher(String url) {return new AntPathRequestMatcher(url);}public String getResourceQuery() {return resourceQuery;}public void setResourceQuery(String resourceQuery) {this.resourceQuery = resourceQuery;}/*** 内部类,用于封装访问地址和权限* @ClassName: Resource * @Description: TODO(这里用一句话描述这个类的作用) * @author Sunny* @date 2018年7月4日 下午2:42:59 **/private class Resource {private String url;//资源访问的地址private String role;//所需要的权限public Resource(String url, String role) {this.url = url;this.role = role;}public String getUrl() {return url;}public String getRole() {return role;}}@SuppressWarnings("rawtypes")private class ResourceMapping extends MappingSqlQuery {protected ResourceMapping(DataSource dataSource, String resourceQuery) {super(dataSource, resourceQuery);compile();}//对结果集进行封装处理protected Object mapRow(ResultSet rs, int rownum) throws SQLException {String url = rs.getString(1);String role = rs.getString(2);Resource resource = new Resource(url, role);return resource;}}
}

说明:

  • resourceQuery是查询数据的sql语句,该属性在配置bean的时候传入即可。
  • 内部创建了一个resource来封装数据。
  • getRequestMatcher方法就是用来创建RequestMatcher对象的
  • buildRequestMap方法用来最后拼接成LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>>security使用。

四、替换原有功能的切入点

在将这部之前,先得了解大概下security的运行过程,security实现控制的功能其实就是通过一系列的拦截器来实现的,当用户登陆的时候,会被AuthenticationProcessingFilter拦截,调用AuthenticationManager的实现类,同时AuthenticationManager会调用ProviderManager来获取用户验证信息,其中不同的Provider调用的服务不同,因为这些信息可以是在数据库上,可以是在LDAP(轻量目录访问协议)服务器上,可以是xml配置文件上等,这个例子中是数据库;如果验证通过后会将用户的权限信息放到spring的全局缓存SecurityContextHolder中,以备后面访问资源时使用。当访问资源,访问url时,会通过AbstractSecurityInterceptor拦截器拦截,其中会调用FilterInvocationSecurityMetadataSource的方法来获取被拦截url所需的全部权限,其中FilterInvocationSecurityMetadataSource的常用的实现类为DefaultFilterInvocationSecurityMetadataSource,这个类中有个很关键的东西就是requestMap,也就是我们上面所得到的数据,在调用授权管理器AccessDecisionManager,这个授权管理器会通过spring的全局缓存SecurityContextHolder获取用户的权限信息,还会获取被拦截的url和被拦截url所需的全部权限,然后根据所配的策略,如果权限足够,则返回,权限不够则报错并调用权限不足页面。

根据源码debug跟踪得出,其实资源权限关系就放在DefaultFilterInvocationSecurityMetadataSourcerequestMap,中的,这个requestMap就是我们JdbcRequestMapBulider.buildRequestMap()方法所需要的数据类型,因此就想到了我们自定义一个类继承FilterInvocationSecurityMetadataSource接口,将数据查出的数据放到requestMap中去。制定类MyFilterInvocationSecurityMetadataSource继承FilterInvocationSecurityMetadataSourceInitializingBean接口。

package com.sunny.auth;import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;import javax.servlet.http.HttpServletRequest;import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.RequestMatcher;public class MyFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource, InitializingBean{private final static List<ConfigAttribute> NULL_CONFIG_ATTRIBUTE = null;// 资源权限集合private Map<RequestMatcher, Collection<ConfigAttribute>> requestMap;//查找数据库权限和资源关系private JdbcRequestMapBulider builder;/** 更具访问资源的地址查找所需要的权限*/@Overridepublic Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {final HttpServletRequest request = ((FilterInvocation) object).getRequest();Collection<ConfigAttribute> attrs = NULL_CONFIG_ATTRIBUTE;for (Map.Entry<RequestMatcher, Collection<ConfigAttribute>> entry : requestMap.entrySet()) {if (entry.getKey().matches(request)) {attrs = entry.getValue();break;}}return attrs;}/** 获取所有的权限*/@Overridepublic Collection<ConfigAttribute> getAllConfigAttributes() {Set<ConfigAttribute> allAttributes = new HashSet<ConfigAttribute>();for (Map.Entry<RequestMatcher, Collection<ConfigAttribute>> entry : requestMap.entrySet()) {allAttributes.addAll(entry.getValue());}System.out.println("拥有权限:"+allAttributes.toString());return allAttributes;}@Overridepublic boolean supports(Class<?> clazz) {return FilterInvocation.class.isAssignableFrom(clazz);}//绑定requestMapprotected Map<RequestMatcher, Collection<ConfigAttribute>> bindRequestMap() {return builder.buildRequestMap();}@Overridepublic void afterPropertiesSet() throws Exception {this.requestMap = this.bindRequestMap();}public void refreshResuorceMap() {this.requestMap = this.bindRequestMap();}/******************* GET & SET *******************************/public JdbcRequestMapBulider getBuilder() {return builder;}public void setBuilder(JdbcRequestMapBulider builder) {this.builder = builder;}
}

说明:

  • requestMap这个属性就是用来存放资源权限的集合
  • builderJdbcRequestMapBulider类型,用来查找数据库权限和资源关系
  • 其他的代码中都有详细的注释

五、配置文件

spring-dataSource.xml保持不变

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.1.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx-3.0.xsdhttp://www.springframework.org/schema/securityhttp://www.springframework.org/schema/security/spring-security.xsd"><!-- 数据源 --><beans:bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"><!-- 此为c3p0在spring中直接配置datasource c3p0是一个开源的JDBC连接池 --><beans:property name="driverClass" value="com.mysql.jdbc.Driver" /><beans:property name="jdbcUrl" value="jdbc:mysql://localhost:3306/springsecurity?useUnicode=true&amp;characterEncoding=UTF-8" /><beans:property name="user" value="root" /><beans:property name="password" value="" /><beans:property name="maxPoolSize" value="50"></beans:property><beans:property name="minPoolSize" value="10"></beans:property><beans:property name="initialPoolSize" value="10"></beans:property><beans:property name="maxIdleTime" value="25000"></beans:property><beans:property name="acquireIncrement" value="1"></beans:property><beans:property name="acquireRetryAttempts" value="30"></beans:property><beans:property name="acquireRetryDelay" value="1000"></beans:property><beans:property name="testConnectionOnCheckin" value="true"></beans:property><beans:property name="idleConnectionTestPeriod" value="18000"></beans:property><beans:property name="checkoutTimeout" value="5000"></beans:property><beans:property name="automaticTestTable" value="t_c3p0"></beans:property></beans:bean>
</beans:beans>

spring-context.xml修改如下

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.1.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx-3.0.xsdhttp://www.springframework.org/schema/securityhttp://www.springframework.org/schema/security/spring-security.xsd"><!-- 不需要访问权限 --><http pattern="/page/login.jsp" security="none"></http><http auto-config="false"><form-login login-page="/page/login.jsp" default-target-url="/page/admin.jsp" authentication-failure-url="/page/login.jsp?error=true" /><logout invalidate-session="true" logout-success-url="/page/login.jsp" logout-url="/j_spring_security_logout" /><!-- 通过配置custom-filter来增加过滤器,before="FILTER_SECURITY_INTERCEPTOR"表示在SpringSecurity默认的过滤器之前执行。 --><custom-filter ref="filterSecurityInterceptor" before="FILTER_SECURITY_INTERCEPTOR" /></http><!-- 认证过滤器 --><beans:bean id="filterSecurityInterceptor" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor"><!-- 用户拥有的权限 --><beans:property name="accessDecisionManager" ref="accessDecisionManager" /><!-- 用户是否拥有所请求资源的权限 --><beans:property name="authenticationManager" ref="authenticationManager" /><!-- 资源与权限对应关系 --><beans:property name="securityMetadataSource" ref="securityMetadataSource" /></beans:bean><!-- 授权管理器 --><beans:bean id="accessDecisionManager" class="com.sunny.auth.MyAccessDecisionManager"></beans:bean><!--自定义的切入点--><beans:bean id="securityMetadataSource" class="com.sunny.auth.MyFilterInvocationSecurityMetadataSource"><beans:property name="builder" ref="builder"></beans:property></beans:bean><beans:bean id="builder" class="com.sunny.auth.JdbcRequestMapBulider"> <beans:property name="dataSource" ref="dataSource" /> <beans:property name="resourceQuery"value="select re.res_string,r.name from role r,resc re,resc_role rr where r.id=rr.role_id and re.id=rr.resc_id" /> </beans:bean><!--认证管理--><authentication-manager alias="authenticationManager"><authentication-provider><jdbc-user-service data-source-ref="dataSource" id="usersService"users-by-username-query="select username,password,status as enabled from user where username = ?"authorities-by-username-query="select user.username,role.name from user,role,user_role where user.id=user_role.user_id and user_role.role_id=role.id and user.username=?" /></authentication-provider></authentication-manager></beans:beans>

1.http中的custom-filter是特别要注意的,就是通过这个标签来增加过滤器的,其中before="FILTER_SECURITY_INTERCEPTOR"表示在SpringSecurity默认的过滤器之前执行。

2.在配置builder时候,resourceQuery就是要查询的sql语句,dataSource为数据源。
3.在配置认证过滤器的时候,accessDecisionManagerauthenticationManagersecurityMetadataSource这三个属性是必填项,若缺失会报错。其中authenticationManager就是authentication-manager标签,securityMetadataSource是自定义的MyFilterInvocationSecurityMetadataSourceauthenticationManager这里还没有定义,因此再创建一个类叫MyAccessDecisionManager,代码如下:
package com.sunny.auth;import java.util.Collection;
import java.util.Iterator;import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;public class MyAccessDecisionManager implements AccessDecisionManager{/* * 该方法决定该权限是否有权限访问该资源,其实object就是一个资源的地址,authentication是当前用户的* 对应权限,如果没登陆就为游客,登陆了就是该用户对应的权限*/@Overridepublic void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)throws AccessDeniedException, InsufficientAuthenticationException {if(configAttributes == null) {  return;}  //所请求的资源拥有的权限(一个资源对多个权限)  Iterator<ConfigAttribute> iterator = configAttributes.iterator();  while(iterator.hasNext()) {  ConfigAttribute configAttribute = iterator.next();  //访问所请求资源所需要的权限  String needPermission = configAttribute.getAttribute();  System.out.println("访问"+object.toString()+"需要的权限是:" + needPermission);  //用户所拥有的权限authentication  Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();for(GrantedAuthority ga : authorities) {  if(needPermission.equals(ga.getAuthority())) {  return;}  }}//没有权限  throw new AccessDeniedException("没有权限访问! ");  }@Overridepublic boolean supports(ConfigAttribute attribute) {return true;}@Overridepublic boolean supports(Class<?> clazz) {return true;}
}

pom.xml中增加

            <!-- j2ee --><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.1.0</version></dependency>        

web.xml默认页面仍然是

五 结果

admin能访问的页面有admin.jsp、user.jsp;

user能访问的有user.jsp;

test能访问的有test.jsp。

如果权限不足,会提示“没有权限访问!”

相关文章:

一星期没完成Ansible任务

这个星期&#xff0c;前4天&#xff0c;我在看Nginx&#xff0c;没有深入Ansible。 这几天我有思考做Ansible的哪个方面&#xff0c;现在我用Ansible可以用&#xff0c;但是没有生产环境&#xff0c;我对基础部分热情不是特别大&#xff0c;应该是基础部分大家在弄&#xff0c;…

Python 批量处理 Excel 数据后,导入 SQL Server

作者 | 老表来源 | 简说Python1、前言2、开始动手动脑2.1 拆解明确需求2.2 安装第三方包2.3 读取excel数据2.4 特殊数据数据处理2.5 其他需求2.6 完整调用代码1、前言今天教大家一个需求&#xff1a;有很多Excel&#xff0c;需要批量处理&#xff0c;然后存入不同的数据表中。2…

最经典的计算机网络新书推荐--计算机网络(第5版)Tanenbaum著中文版上市

作者&#xff1a;Tanenbaum是全球最著名的计算机科学家。linux之父Linus当年就是参考Tanenbaum写的MINIX&#xff01; Tanenbaum《计算机网络(第5版) 》《现代操作系统(第3版) 》《操作系统设计与实现(第3版) 》《分布式系统原理与范型(第2版) 》《计算机组成结构化方法&#x…

elasticsearch简单操作(二)

让我们建立一个员工目录&#xff0c;假设我们刚好在Megacorp工作&#xff0c;这时人力资源部门出于某种目的需要让我们创建一个员工目录&#xff0c;这个目录用于促进人文关怀和用于实时协同工作&#xff0c;所以它有以下不同的需求&#xff1a;1、数据能够包含多个值的标签、数…

苹果放大招?「廉价版」5G iPhone 将揭晓,M2芯片来袭?

整理 | 张洁来源 | CSDN3 月 2 日&#xff0c;苹果公司正式宣布将于北京时间 3 月 9 日凌晨 2 点举办 2022 年的首场活动&#xff0c;主题为“peek performance&#xff08;高能传送&#xff09;”。与去年一样&#xff0c;苹果 2022 年的第一场活动将继续以线上的方式进行。活…

PHP 预编译加速: eAccelerator的安装和性能比较

eAccelerator已经是很常用的PHP平台预编译加速的手段了。今天在自己机器上尝试安装了一下&#xff0c;备忘如下&#xff1a; 获得源代码&#xff1a;http://bart.eaccelerator.net/source/编译&#xff1a;需要有autoconf支持&#xff0c;解包后在源程序目录下&#xff1a;/usr…

合并区间(LintCode)

合并区间 给出若干闭合区间&#xff0c;合并所有重叠的部分。 样例 给出的区间列表 > 合并后的区间列表&#xff1a; [ [[1, 3], [1, 6],[2, 6], > [8, 10],[8, 10], [15, 18][15, 18] ] ]挑战 O(…

Kylin集群部署和cube使用

Kylin集群部署和cube使用 安装集群环境节点 Kylin节点模式 Ip 内存 磁盘Node1 All 192.167.71.11 2G 80GNode2 query 192.168.71.12 1.5G 80GNode3 query 192.168.71.13 1.5G 80GKylin工作原理如下&#xff1a; 集群时间同步Ntp服务自行设置安装kylin之前所需要的环境Hadoop-2.…

就是个控制结构,Scala 能有什么新花样呢?

作者 | luanhz来源 | 小数志导读编程语言中最为基础的一个概念是控制结构&#xff0c;几乎任何代码都无时无刻不涉及到&#xff0c;其实也就无外乎3种&#xff1a;顺序、分支和循环。本文就来介绍Scala中控制结构&#xff0c;主要是分支和循环。Scala中的控制结构实质上与其他编…

快速开发一个PHP扩展

快速开发一个PHP扩展 作者&#xff1a;heiyeluren时间&#xff1a;2008-12-5博客&#xff1a;http://blog.csdn.net/heiyeshuwu 本文通过非常快速的方式讲解了如何制作一个PHP 5.2 环境的扩展&#xff08;PHP Extension&#xff09;&#xff0c;希望能够在图文的方式下让想快速…

oracle11g的安装

目录层次&#xff1a;linux->oracle软件->dbca数据库安装过程&#xff1a;虚拟机->linux->VMtools->拷贝数据库软件->创建一个目录mkdir->创建组.用户->修改根目录->设置参数->解压 >安装->oracle完成参考&#xff1a;安装oracle软件linu…

python 100例(10)

2019独角兽企业重金招聘Python工程师标准>>> 题目&#xff1a;古典问题&#xff1a;有一对兔子&#xff0c;从出生后第3个月起每个月都生一对兔子&#xff0c;小兔子长到第三个月后每个月又生一对兔子&#xff0c;假如兔子都不死&#xff0c;问每个月的兔子总数为多…

cocos2dx-3.9 集成admob

Part 1: 安装GoogleMobileAds framework &#xff08;即admob&#xff09; 1. 安装Cocoapods&#xff0c;否则解决依赖关系和配置真的会把人不累死也得烦死 sudo gem install cocoapods 国内用户安装过程中可能遇到SSL连接出错的问题&#xff0c;请参考 Cocoapod安装过程中的幺…

用C语言扩展PHP功能

用C语言扩展PHP功能建议读者群&#xff1a;熟悉c,linux,php PHP经过最近几年的发展已经非常的流行&#xff0c;而且PHP也提供了各种各样非常丰富的函数。但有时候我们还是需要来扩展PHP。比如&#xff1a;我们自己开发了一个数据库系统&#xff0c;而且有自己的库函数来操作数…

手把手快速实现 Resnet 残差模型实战

作者 | 李秋键 出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09; 引言&#xff1a;随着深度学习的发展&#xff0c;网络模型的深度也随之越来越深&#xff0c;但随着网络模型深度的加深&#xff0c;往往会曾在这随着模型深度的加大&#xff0c;模型准确率反而下降的问…

JHipster开发环境安装

这里采用官方推荐的Yarn安装方法&#xff0c;默认操作系统为CentOS 7.4。 1 安装JDK 推荐版本&#xff1a;OpenJDK 1.8.0-64bit。 完整安装说明&#xff0c;请参考这里 2 安装Nodejs 推荐版本&#xff1a; v8.11.3 完整安装说明&#xff0c;请参考这里 3 安装Yarn 推荐版本&…

用C语言写PHP扩展

用C语言写PHP扩展 1&#xff1a;预定义 在home目录&#xff0c;也可以其他任意目录&#xff0c;写一个文件&#xff0c;例如caleng_module.def 内容是你希望定义的函数名以及参数&#xff1a; int a(int x,int y)string b(string str,int n) 2&#xff1a;到php源码目录的ext目…

Pandas 数据挖掘与分析时的常用方法

今天我们来讲一下用Pandas模块对数据集进行分析的时候&#xff0c;一些经常会用到的配置&#xff0c;通过这些配置的帮助&#xff0c;我们可以更加有效地来分析和挖掘出有价值的数据。数据集的准备这次我们需要用到的数据集是广为人所知的泰坦尼克号的乘客数据&#xff0c;我们…

MySQL基本概念

1. 分清几个概念&#xff1a;数据库&#xff0c;数据库对象和数据&#xff1b; 数据库分为&#xff1a;系统数据库和用户数据库&#xff1b; 系统数据库 是安装完MySQL服务器后自带的数据库&#xff0c;会记录一些必要的信息&#xff0c;用户不能直接修改这些系统数据库。转载…

SpringMvc+ajax实现文件跨域上传

最近开始学习SpringMVC框架&#xff0c;在学习数据绑定的时候&#xff0c;发现可以使用RequestParam注解绑定请求数据&#xff0c;实现了文件上传。但是如果一个项目是前后端分离的&#xff0c;前端系统向后端服务上传文件该怎么解决了&#xff1f; 首先考虑前端用哪一种方式进…

使用Nmap获取目标服务器开放的服务以及操作系统信息

http://nmap.org/download.html 1.下载安装rpm -vhU http://nmap.org/dist/nmap-5.61TEST5-1.i386.rpmrpm -vhU http://nmap.org/dist/zenmap-5.61TEST5-1.noarch.rpmrpm -vhU http://nmap.org/dist/ncat-5.61TEST5-1.i386.rpmrpm -vhU http://nmap.org/dist/nping-0.5.61TEST5…

Pandas 数据类型概述与转换实战

作者 | 周萝卜 来源 | 萝卜大杂烩 在进行数据分析时&#xff0c;确保使用正确的数据类型是很重要的&#xff0c;否则我们可能会得到意想不到的结果或甚至是错误结果。对于 pandas 来说&#xff0c;它会在许多情况下自动推断出数据类型 尽管 pandas 已经自我推断的很好了&#x…

7.10 数据注解特性--NotMapped

NotMapped特性可以应用到领域类的属性中&#xff0c;Code-First默认的约定&#xff0c;是为所有带有get,和set属性选择器的属性创建数据列。。 NotManpped特性打破了这个约定&#xff0c;你可以使用NotMapped特性到某个属性上面&#xff0c;然后Code-First就不会为这个属性就不…

Condition

2019独角兽企业重金招聘Python工程师标准>>> 1、Condition的简介 线程通信中的互斥除了用synchronized、Object类的wait()和notify()/notifyAll()方式实现外&#xff0c;方法JDK1.5中提供的Condition配套Lock可以实现相同的功能。Condition中的await()和signal()/si…

使用who.is查域名DNS信息以及用sameip.org查其他网站

www.who.is网站可以查域名信息&#xff0c;非常好用&#xff1a;例如查 hack-test.com然后我们可以找找同个IP上的其他站点&#xff08;旁站&#xff1a;sameip.org&#xff09;参考&#xff1a; 黑客是怎么攻击一个网站的&#xff1f;

基于 OpenCV 的人脸追踪

作者 | 努比 来源 | 小白学视觉 在Raspberry上启动项目很简单&#xff0c;所以让我们开始吧。 01. 产品清单 Raspberry Pi 4 Model B — 4GB 适用于Raspberry Pi的Pan-Tilt HAT Pi Camera v2 8MP 微型SD卡 迷你HDMI电缆 Raspberry Pi摄像头电缆—尺寸&#xff1a;457mm x …

-bash: /bin/rm: Argument list too long的解决办法

-bash: /bin/rm: Argument list too long的解决办法 当目录下文件太多时&#xff0c;用rm删除文件会报错&#xff1a; -bash: /bin/rm: Argument list too long 提示文件数目太多。 解决的办法是使用如下命令&#xff1a; ls | xargs -n 10 rm -fr ls 输出所有的文件名(用…

React使用ES6语法重构组件代码

首次使用react&#xff0c;要注意react不同版本库&#xff0c;是ES5还是ES6的写法&#xff0c;如何做到统一。下面对于ES6语法重构组件的代码如下&#xff1a;&#xff08;1&#xff09;原始代码&#xff1a; <script type"text/babel">var destinationdocumen…

PHP哈希表碰撞攻击原理

哈希表碰撞攻击&#xff08;Hashtable collisions as DOS attack&#xff09;的话题不断被提起&#xff0c;各种语言纷纷中招。本文结合PHP内核源码&#xff0c;聊一聊这种攻击的原理及实现。 哈希表碰撞攻击的基本原理 哈希表是一种查找效率极高的数据结构&#xff0c;很多语言…

Java8(jdk1.8)中文档注释处理工具javadoc的环境参量配置及使用方法

Java8(jdk1.8)中文档注释处理工具javadoc的环境参量配置及使用方法Java语言提供了一种功能强大的注释形式&#xff1a;文档注释。如果编写Java源代码时添加了合适的文档注释&#xff0c;然后通过JDK提供的javadoc工具可以直接将源代码里的文档注释提取成一份系统的API文档。jav…