SpringBoot+SpringCloud 笔记
SpringBoot总结 使用Typora打开https://pan.baidu.com/s/1tXS45j6ooXpnzhy1Zp78Gw 提取码: c8fi
SpringCloud总结 使用XMind打开https://pan.baidu.com/s/1yDeZ9bhZIuBTQIipyIfzqw 提取码: batn
- SpringBoot默认读取主配置文件
- application.properties
- application.yml
- SpringBoot的四种属性注入
- @Autowired注入
- 构造方法注入
- @Bean方法形参注入
- 直接在@Bean方法上使用@ConfigurationProperties(prefix="前缀名")
- SpringBoot注解
- @RestController 包括@Controller+@ResponseBody
- @EnableAutoConfiguration 开启SpringBoot自动配置
- @ComponentScan 组件扫描 类似于 扫描当前所在包以及子包
- @SpringBootApplication 包括 @EnableAutoConfiguration+@ComponentScan+@SpringBootConfiguration
- @SpringBootConfiguration SpringBoot配置
- @Configuration 标注是一个配置类 相当于xml配置文件
- @PropertiesSource 指定一个资源文件 @PropertySource("classpath:jdbc.properties")
- @Bean 把方法的返回值注入到Spring容器
- @Value 注入指定属性值 需要有setter
- @ConfigurationProperties 指定配置文件 @ConfigurationProperties(prefix = "前缀名")
- @EnableConfigurationProperties 开启配置 @EnableConfigurationProperties(JdbcProperties.class)
- SpringBoot默认读取主配置文件
之前的架构
- Tomcat(前台,后台,用户管理,订单管理,购物车管理...)
- 单点故障(一台服务器挂了,全部挂,全部访问不了)
- 并发数低(不能实现高并发)
- 代码耦合度高,不方便优化(你调用我,我调用你,)
- 不方便扩展(要么都扩展,要么都不扩展)
- 好处:维护简单
- Tomcat(前台,后台,用户管理,订单管理,购物车管理...)
SpringBoot
- 整合springMVC
- 修改端口(server.port=8081)
- 访问静态资源("classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/")
- springboot的拦截器
- 创建类MyInterceptor 实现 HandlerInterceptor接口
- 并且在MyInterceptor类上配置@Component
- 重写方法preHandle(前置方法),postHandle(后置方法),afterCompletion(完成方法)
- preHandle返回false拦截,返回true放行,return false开启拦截,return true关闭拦截
- 创建类WebWvcConfiguration 实现 WebMvcConfigurer接口
- 在WebWvcConfiguration上标注@Configuration
- 在WebWvcConfiguration中写上@Autowired MyInterceptor myInterceptor;
- 在WebWvcConfiguration中重写addInterceptors方法
- registry.addInterceptor(myInterceptor).addPathPatterns("/**").excludePathPatterns("/student/**");
- 表示拦截所有请求,但不拦截/student下的所有请求
/** 表示所有
/* 表示一级
- 整合数据源 DataSource
- 引入依赖spring-boot-starter-jdbc mysql-connector-java
- 添加配置properties
#不用导入驱动,也会自动帮你找到合适的驱动
#spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#jdbc:mysql:///student 相当于 jdbc:mysql://localhost:3306/student
#在后面加 ?serverTimezone=UTC 防止报错 java.sql.SQLException: The server time zone value '�й���
spring.datasource.url=jdbc:mysql:///student?serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123456
- 整合MyBatis
- 引入依赖 mybatis-spring-boot-starter
- 覆盖默认配置
mybatis.type-aliases-package=tpfstudent.pojo
#如果需要配置映射文件,
#mybatis.mapper-locations=classpath:mybatis/mappers/**/*.xml
- 整合通用Mapper
- 引入依赖 mapper-spring-boot-starter
- 继承接口public interface StudentMapper extends Mapper
@Service
public class StudentService
{
@Autowired
private StudentMapper studentMapper; public Student selectStudentById(Integer id){
//this表示全局
return this.studentMapper.selectByPrimaryKey(id);
}
- 整合事务:数据库查询方法上添加注解@Transactional
- 整合springMVC
Thymeleaf
- 默认前缀 "classpath:/templates/";
- 默认后缀 = ".html";
什么是SpringBoot
- 搭建spring应用的工作平台,内置Tomcat,打包成jar,自动配置(根据引入的依赖) 混乱的依赖管理,简化配置
Java配置
- 原生的Java配置
- @Configuration 标注一个类为配置类 相当于xml配置
- @Bean 把方法的返回值注入到spring容器
- @Value 注入参数
- @PropertySource 读取资源文件
- SpringBoot提供Java配置
- @ConfigurationProperties(prefix="jdbc") 声明一个类是一个属性读取类,读取application.properties yml
- @EnableConfigurationProperties (属性读取类.class)
- @Autowired注入
- 构造方法注入
- 通过@Bean方法参数注入
- 直接在@Bean方法上使用@ConfigurationProperties(prefix="前缀名")
- 原生的Java配置
SpringBoot的基本使用,搭建SpringBoot的基本应用
- 引入统一父工程,以及需要的启动器
- 覆盖默认配置
- 添加引导类,@SpringBootApplication(EnableAutoConfiguration @ComponentScan @SpringBootConfiguration)
Eureka服务注册中心,服务提供者,服务消费者
架构的演变 传统架构-->水平拆分-->垂直拆分(最早的分布式)-->soa(dubbo)-->微服务(springCloud)
远程调用技术:rpc http rpc协议:远程过程调用(Remote Procedure Call),自定义数据格式,限定技术,传输速度快,效率高 tcp,dubbo
http协议:统一的数据格式,不限定技术,需要rest接口 tcp协议 springCloud什么是SpringCloud 微服务架构的解决方案,是很多组件的集合 eureka:注册中心,服务的注册与发现
zuul:网关协议,路由请求,过滤器(集成ribbon,集成hystrix)
ribbon:负载均衡组件
hystrix:熔断组件,电路保险丝
feign:远程调用组件(集成ribbon,集成hystrix)Eureka 服务注册中心,服务提供者,服务消费者
服务注册中心: tpf-eureka
- 引入依赖<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> 可以使用spring初始化器进行勾选
- 配置application.properties
#修改端口号为8761
server.port=8761 #将Module的名称作为微服务名称注入eureka容器
spring.application.name=tpf-eureka #配置eureka客户端服务地址
#默认 eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/#失效服务剔除时间,默认为60秒,单位毫秒,生产环境不要修改.
eureka.server.eviction-interval-timer-in-ms=60000
#1,服务下线
#当服务进行正常关闭操作时,它会触发一个服务下线的REST请求给Eureka Server,
#告诉服务注册中心:“我要下线了”。服务中心接受到请求之后,将该服务置为下线状态。
#2,失效剔除
#有些时候,我们的服务提供方并不一定会正常下线,可能因为内存溢出、网络故障等原因导致服务无法正常工作。
#Eureka Server需要将这样的服务剔除出服务列表。
#因此它会开启一个定时任务,每隔60秒对所有失效的服务(超过90秒未响应)进行剔除。 #解决错误EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY'RE NOT. RENEWALS ARE LESSER THAN
#THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE.
#自我保护模式,默认为true,如果设置为false就不会报上面的错
eureka.server.enable-self-preservation=true - 在主配置类的类上加@EnableEurekaServer 启用eureka服务注册中心
服务提供者: tpf-service-provider
- 引入启动器 spring-cloud-starter-netflix-eureka-client 可以使用spring初始化器进行勾选
- 配置application.properties
#修改端口号为8081
server.port=8081 #将服务提供者的Module名作为微服务名称
spring.application.name=tpf-service-provider #配置eureka客户端服务地址
#默认 eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/#默认为true
#服务启动时,检测为true会注册给eureka,为false则不会注册
eureka.client.register-with-eureka=true #服务失效时间,默认90秒过期
eureka.instance.lease-expiration-duration-in-seconds=90
#服务续约(renew)的间隔,默认30秒一次心跳
eureka.instance.lease-renewal-interval-in-seconds=30
#服务提供者启动时,默认30秒向注册中心发一次心跳,证明自己还活着,90秒没有发送心跳,eureka server会认为该服务宕机,会从服务列表移除
#这两个生产环境默认就好,不要改. - 在主配置类的类上加@EnableDiscoveryClient 启动eureka客户端
服务消费者: tpf-service-consumer
- 引入启动器 <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> 可以使用spring初始化器进行勾选
- 配置application.properties
#修改端口号为8082
server.port=8082 #将服务消费者的Module名作为微服务名称
spring.application.name=tpf-service-consumer #配置eureka客户端服务地址
#默认 eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/#服务更新时间间隔
eureka.client.registry-fetch-interval-seconds=30
#默认为true表示需要用来注册,false不需要用来注册
eureka.client.fetch-registry=true
#服务消费者启动时,会检查eureka.client.fetch-registry为true时,则会拉取eureka server服务列表只读备份,进行缓存到本地,默认没30秒更新一次数据
#这两个生产环境默认就好,不要改. - 在主配置类
- 类上加@EnableDiscoveryClient 启动eureka客户端
- 类中写
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
- controller中,这里方法调用需要Student实体类,从provider中copy,只要属性和setter getter toSting
@Autowired
private RestTemplate restTemplate; //包含了所有服务信息
//DiscoveryClient需要导入import org.springframework.cloud.client.discovery.DiscoveryClient;
@Autowired
private DiscoveryClient discoveryClient; @GetMapping("select/{id}")
@ResponseBody
public Student selectStudentById(@PathVariable("id") Integer id)
{
//getInstances("服务名称");
List<ServiceInstance> serviceInstance_list = discoveryClient.getInstances("tpf-service-provider");
//get(0);0表示第一个
ServiceInstance serviceInstance = serviceInstance_list.get(0);
//服务地址
String host=serviceInstance.getHost();
//服务端口号
Integer port=serviceInstance.getPort();
return this.restTemplate.getForObject("http://"+host+":"+port+"/provider/student/select/"+id,Student.class);
}
Ribbon 负载均衡
- 在consumer主配置类的restTemplate方法上加@LoadBalanced开启负载均衡,默认策略:简单轮询
- 在consumer的测试类里编写
@Autowired
private RibbonLoadBalancerClient ribbonLoadBalancerClient; //测试负载均衡,调用50次,看看都是调用哪个服务
@Test
public void test()
{
for (int i = 1; i < 51; i++)
{
ServiceInstance serviceInstance = this.ribbonLoadBalancerClient.choose("tpf-service-provider");
System.out.println("调用"+i+"次---"+serviceInstance.getHost()+":"+serviceInstance.getPort());
//打印信息 5 3 1 7 5 3 1 7... 由此可见负载均衡策略:简单轮询
}
} - 修改负载均衡策略,在provider的application.properties中添加
#服务名.ribbon.类型=具体类名
#例如下面这个,但是这个不可用
#配置负载均衡策略
#tpf-service-provider.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule
运行不同端口SpringBootApplication主配置
- 打开Run Dashboard,
- 运行已有配置类,对着想copy的主配置类,鼠标右键 copy configuration ,
- 全部默认,可以修改名称,左下角Before launch:Activate tool window,点击+,选择build,再点ok即可
Hystrix 熔断器
Hystrix解决雪崩问题的方式有两个
- 线程隔离
- 服务熔断
触发Hystrix服务降级的情况
- 线程池已满
- 请求超时
Hystrix 熔断器的服务降级--->(检查每次请求,是否请求超时或者连接池已满)
- 引入启动器spring-cloud-starter-netflix-hystrix
- 在主配置类上添加@EnableCircuitBreaker 开启熔断器
- 定义全局熔断方法
- 在被熔断的方法中自定义一个方法,返回值类型要被熔断的方法一致,参数列表必须为空
- 在被熔断的方法中,在类上标注 @DefaultProperties(defaultFallback = "自定义的全局方法名") 指定全局默认熔断方法
- 给被熔断方法上添加@HystrixCommand 使用默认熔断方法
- 定义指定熔断方法
- 在被熔断的方法中自定义一个方法,要和被熔断的方法返回值和参数列表一致
- 给被熔断方法上添加@HystrixCommand(fallbackMethod = "自定义的指定方法名") 使用指定熔断方法
- 设置hystrix的超时时间
- 在consumer的application.properties中加
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=6000
- 修改provider的controller中的方法,添加休眠
@GetMapping("select/{id}")
@ResponseBody
public Student selectStudentById(@PathVariable("id") Integer id)
{
try {
Thread.sleep(6000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return this.studentService.selectStudentById(id);
}
- 在consumer的application.properties中加
- 熔断:不再发送请求,
- 熔断的三个状态
- close:闭合状态,所有请求正常方法
- open:打开状态,所有请求都无法访问.如果在一定时间内容,失败的比例不小于50%或者次数不少于20次
- half open:半开状态,打开状态默认5s休眠期,在休眠期所有请求无法正常访问.过了休眠期会进入半开状态,放部分请求通过
- 测试用例:
- 在consumer的controller中方法之前写上 if (id==1){throw new RuntimeException();}
- 如果我们准备两个请求窗口,
- 一个请求http://localhost:8082/consumer/student/select/1 请求失败
- 一个请求 http://localhost:8082/consumer/student/select/2 请求成功
- 当我们疯狂访问id为1的请求时(超过20次),就会触发熔断。断路器会断开,一切请求都会被降级处理。
- 此时你访问id为2的请求,会发现返回的也是失败,而且失败时间很短,只有几毫秒左右
- @SpringCloudApplication 相当于@SpringBootApplication + @EnableDiscoveryClient + @EnableCircuitBreaker
Feign
- 简单使用
- consumer中引入feign ,注意这里是 openfeign 而不是 feign,spring-cloud-starter-openfeign
- 在consumer的主配置类上添加@EnableFeignClients 启用feign组件,注释consumer中主配置类的restTemplate方法
- consumer的controller内容
//启用feign组件
@EnableFeignClients
//相当于@SpringBootApplication + @EnableDiscoveryClient + @EnableCircuitBreaker
@SpringCloudApplication
//开启熔断器
//@EnableCircuitBreaker
//启动eureka客户端,等同于 @EnableEurekaClient
//@EnableDiscoveryClient SpringCloud提供
//@EnableEurekaClient eureka提供
//@EnableDiscoveryClient
//@SpringBootApplication
public class TpfServiceConsumerApplication
{ /*//开启负载均衡,默认策略:简单轮询
@LoadBalanced
//将方法返回结果注入spring容器
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}*/ public static void main(String[] args)
{
SpringApplication.run(TpfServiceConsumerApplication.class, args);
} } - 创建一个接口StudentClient
@FeignClient("tpf-service-provider")
public interface StudentClient
{
@GetMapping("provider/student/select/{id}")
public Student selectStudentById(@PathVariable("id") Integer id);
} feign整合hystrix熔断器
1,在consumer的application.properties添加feign.hystrix.enabled=true 开启feign的熔断功能,默认为false
2,创建一个类StudentClientFallback
//注入容器
@Component
public class StudentClientFallback implements StudentClient
{
@Override
public Student selectStudentById(Integer id)
{
Student student=new Student();
student.setStu_name("StudentClientFallback_selectStudentById---服务器正忙,请稍后再试...");
return student;
}
}
- 在consumer的application.properties添加feign.hystrix.enabled=true 开启feign的熔断功能,默认为false
- 创建一个类StudentClientFallback
//注入容器
@Component
public class StudentClientFallback implements StudentClient
{
@Override
public Student selectStudentById(Integer id)
{
Student student=new Student();
student.setStu_name("StudentClientFallback_selectStudentById---服务器正忙,请稍后再试...");
return student;
}
} - 把StudentClient类上注解@FeignClient("tpf-service-provider")改为@FeignClient(value = "tpf-service-provider",fallback = StudentClientFallback.class)
Feign整合Hystrix熔断器
- 简单使用
Zuul 服务网关
简单使用
- 指定zuul依赖spring-cloud-starter-netflix-zuul
- 配置properties
#服务网关 #修改端口号为8180
server.port=8180
#将服务提供者的Module名作为微服务名称
spring.application.name=tpf-zuul - 在主配置类上添加 @EnableZuulProxy 开启zuul服务网关功能
- 可默认访问 http://localhost:8180/tpf-service-provider/provider/student/select/1
Zuul+Eureka使用
- 引入eureka client依赖 spring-cloud-starter-netflix-eureka-client
- 配置properties
#zuul.routes.路由id... 可以自定义,一般都写服务名
#path 映射路径
#url 映射路径对应的实际url地址
#service-id 服务名称 #配置方式1,
#zuul.routes.tpf-service-provider.path=/tpf-service-provider/**
#zuul.routes.tpf-service-provider.url=http://localhost:8081 #配置方式2,
#zuul.routes.tpf-service-provider.path=/tpf-service-provider/**
#zuul.routes.tpf-service-provider.service-id=tpf-service-provider #配置方式3,
#默认访问 http://localhost:8180/tpf-service-provider/provider/student/select/1
#配置访问 http://localhost:8180/tpf/provider/student/select/1
#zuul.routes.tpf-service-provider=/tpf/** #配置方式4,
#就是不配置,使用默认,也可以访问 http://localhost:8180/tpf-service-provider/provider/student/select/1 #配置前缀
#之前访问 http://localhost:8180/tpf-service-provider/provider/student/select/1
#现在访问 http://localhost:8180/diy-prefix/tpf-service-provider/provider/student/select/1
zuul.prefix=/diy-prefix - 在主配置类上添加 @EnableDiscoveryClient 启动eureka客户端
Zuul 过滤器
- 创建一个类LoginFilter 继承 ZuulFilter
//@Component注入组件,再在主配置类中用@Bean注入LoginFilter到spring容器
@Component
public class LoginFilter extends ZuulFilter
{
//过滤类型:pre route post error
//pre(路由之前),route(路由之时),post(路由之后),error(发生错误时调用)
@Override
public String filterType()
{
//return null;
return "pre";
} //过滤顺序,返回值越小,优先级越高
@Override
public int filterOrder()
{
return 0;
} //是否过滤(是否执行run方法),true过滤,false不过滤
@Override
public boolean shouldFilter()
{
//return false;
return true;
} //编写过滤器的具体逻辑,比如:权限判断,合法校验...
@Override
public Object run() throws ZuulException
{
//初始化context上下文对象 import com.netflix.zuul.context.RequestContext;
RequestContext context=RequestContext.getCurrentContext();
//获取request对象
HttpServletRequest request = context.getRequest();
//获取参数
String token = request.getParameter("token");
//如果为空 import org.apache.commons.lang.StringUtils;
if (StringUtils.isBlank(token)){
//拦截,不转发请求
context.setSendZuulResponse(false); //响应状态码 HttpStatus.SC_UNAUTHORIZED=401,未经授权的意思 import org.apache.http.HttpStatus;
//context.setResponseStatusCode(401);
context.setResponseStatusCode(HttpStatus.SC_UNAUTHORIZED); //设置响应提示
context.setResponseBody("{\"status\":\"401\", \"text\":\"request error...\"}");
} //返回值为null,就代表该过滤器什么都不做
return null;
} } - 在主配置类中添加
//把返回值注入spring容器
@Bean
public LoginFilter loginFilter(){
return new LoginFilter();
}
- 创建一个类LoginFilter 继承 ZuulFilter
- 1
- 1
- 1
- 1
- 1
- 1
SpringBoot+SpringCloud 笔记的更多相关文章
- 【原创】SpringBoot & SpringCloud 快速入门学习笔记(完整示例)
[原创]SpringBoot & SpringCloud 快速入门学习笔记(完整示例) 1月前在系统的学习SpringBoot和SpringCloud,同时整理了快速入门示例,方便能针对每个知 ...
- SpringBoot学习笔记
SpringBoot个人感觉比SpringMVC还要好用的一个框架,很多注解配置可以非常灵活的在代码中运用起来: springBoot学习笔记: .一.aop: 新建一个类HttpAspect,类上添 ...
- spring springMvc spring-boot spring-cloud分别是什么
本文来源于:克己习礼成仁 的<spring springMvc spring-boot spring-cloud分别是什么> 什么是spring 关于spring的定义无论是从官方还是 ...
- Springboot学习笔记(六)-配置化注入
前言 前面写过一个Springboot学习笔记(一)-线程池的简化及使用,发现有个缺陷,打个比方,我这个线程池写在一个公用服务中,各项参数都定死了,现在有两个服务要调用它,一个服务的线程数通常很多,而 ...
- SpringBoot学习笔记(14):使用SpringBootAdmin管理监控你的应用
SpringBoot学习笔记(14):使用SpringBootAdmin管理监控你的应用 Spring Boot Admin是一个管理和监控Spring Boot应用程序的应用程序.本文参考文档: 官 ...
- SpringBoot学习笔记(3):静态资源处理
SpringBoot学习笔记(3):静态资源处理 在web开发中,静态资源的访问是必不可少的,如:Html.图片.js.css 等资源的访问. Spring Boot 对静态资源访问提供了很好的支持, ...
- SpringBoot学习笔记(2):引入Spring Security
SpringBoot学习笔记(2):用Spring Security来保护你的应用 快速开始 本指南将引导您完成使用受Spring Security保护的资源创建简单Web应用程序的过程. 参考资料: ...
- SpringBoot学习笔记(7):Druid使用心得
SpringBoot学习笔记(7):Druid使用心得 快速开始 添加依赖 <dependency> <groupId>com.alibaba</groupId> ...
- SpringBoot学习笔记(4):与前端交互的日期格式
SpringBoot学习笔记(4):与前端交互的日期格式 后端模型Date字段解析String 我们从前端传回来表单的数据,当涉及时间.日期等值时,后端的模型需将其转换为对应的Date类型等. 我们可 ...
随机推荐
- hibernate entitymanager的理解
hibernate EntityManager是围绕提供JPA编程接口的Hibernate Core的一个包装,支持JPA实体实例的生命周期,并允许你用标准的JavaPersistence查询语言编写 ...
- EventChannel 原生向Flutter传递数据
目的:原生页面主动向Flutter页面传递信息 1 flutter步骤 定义EventChannel static const EventChannel eventChannel = EventCha ...
- 说说 Activity、Intent、Service 是什么关系
他们都是 Android 开发中使用频率最高的类.其中 Activity 和 Service 都是 Android 四大组件之一.他俩都是Context 类的子类 ContextWrapper 的子类 ...
- Rate 评分
评分组件 基础用法 评分被分为三个等级,可以利用颜色对分数及情感倾向进行分级(默认情况下不区分颜色).三个等级所对应的颜色用过colors属性设置,而它们对应的两个阈值则通过 low-threshol ...
- centos7 禁止root远程ssh直接登录
修改/etc/ssh/sshd_config文件,将 #PermitRootLogin yes 修改为 PermitRootLogin no 查看 more /etc/ssh/sshd_confi ...
- mysql的逻辑架构
架构图 做Java开发时,项目一般会分为数据访问层.业务逻辑层.控制层等,每层处理不同的任务.类似的,mysql也不是单一的模块,其内部也分为几层.自己不会画,从网上找来了经典的mysql架构图: 分 ...
- maven将自己的springboot项目打包成jar包后,作为工具包引入其他项目,找不到jar中的类
将springboot项目打包成jar包,作为工具包导入项目后,找不到jar中的类. 原因是:springboot项目使用了自动的打包插件. 原先的插件配置: <build> <pl ...
- java: (正则表达式,XML文档,DOM和DOM4J解析方法)
常见的XML解析技术: 1.DOM(基于XML树结构,比较耗资源,适用于多次访问XML): 2.SAX(基于事件,消耗资源小,适用于数量较大的XML): 3.JDOM(比DOM更快,JDOM仅使用具体 ...
- 【Ruby on Rails 学习三】Ruby 基本数据类型(类、类的实例、对象)
数字.文本.范围.符合.True.False.Nil 1为什么是一个类的对象,使用methods方法可以查看一个对象的所有函数(方法) $ irb irb(main)::> => irb( ...
- python+selenium下载文件——Chrome
from selenium import webdriver import time options = webdriver.ChromeOptions() prefs = { 'profile.de ...