学习地址:http://tutorials.jenkov.com/java-json/index.html

github地址:https://github.com/FasterXML/jackson

fasterxml官方地址:http://fasterxml.com/

Jackson ObjectMapper

解析器和生成器

jackson有两个json解析器

  • ObjectMapper将Json解析为Java对象或jackson的tree model
  • JsonParser,一次解析一个token

jackson有两个json生成器

  • ObjectMapper从java对象或tree model生成json
  • JsonGenerator,一次生成一个token

如何映射

jackson通过映射java对象的getter和setter方法实现与json串字段的对应,去掉get set,然后将第一个字母小写,如果要实现别的对应,需要定制序列化与反序列化,或者使用一些jackson注解。

jackson可以读取的内容

jackson读取对象、对象数组可以从

  • json 字符串
  • Reader
  • json file
  • URL,包括HTTP URL
  • InputStream
  • ByteArray
  • 需要使用new TypeReference<List<Car>>(){}的复杂对象的解析
    • 通过json数组读取对象数组
    • 通过json数组读取对象List
    • 通过json字符串读取map

jackson的配置

// 忽略额外的json字段,默认会抛出异常
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); //null值赋值给java原生类型时抛出异常
objectMapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, true);

定制反序列化器

String json = "{ \"brand\" : \"Ford\", \"doors\" : 6 }";

SimpleModule module =
new SimpleModule("CarDeserializer", new Version(3, 1, 8, null, null, null));
module.addDeserializer(Car.class, new CarDeserializer(Car.class)); ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(module); Car car = mapper.readValue(json, Car.class);
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import java.io.IOException; public class CarDeserializer extends StdDeserializer<Car> { public CarDeserializer(Class<?> vc) {
super(vc);
} @Override
public Car deserialize(JsonParser parser, DeserializationContext deserializer) throws IOException {
Car car = new Car();
while(!parser.isClosed()){
JsonToken jsonToken = parser.nextToken(); if(JsonToken.FIELD_NAME.equals(jsonToken)){
String fieldName = parser.getCurrentName();
System.out.println(fieldName); jsonToken = parser.nextToken(); if("brand".equals(fieldName)){
car.setBrand(parser.getValueAsString());
} else if ("doors".equals(fieldName)){
car.setDoors(parser.getValueAsInt());
}
}
}
return car;
}
}

将对象转化为json

  • writeValue()
  • writeValueAsString()
  • writeValueAsBytes()

定制序列化器

CarSerializer carSerializer = new CarSerializer(Car.class);
ObjectMapper objectMapper = new ObjectMapper(); SimpleModule module =
new SimpleModule("CarSerializer", new Version(2, 1, 3, null, null, null));
module.addSerializer(Car.class, carSerializer); objectMapper.registerModule(module); Car car = new Car();
car.setBrand("Mercedes");
car.setDoors(5); String carJson = objectMapper.writeValueAsString(car);
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer; import java.io.IOException; public class CarSerializer extends StdSerializer<Car> { protected CarSerializer(Class<Car> t) {
super(t);
}
public void serialize(Car car, JsonGenerator jsonGenerator,
SerializerProvider serializerProvider)
throws IOException {
jsonGenerator.writeStartObject();
jsonGenerator.writeStringField("producer", car.getBrand());
jsonGenerator.writeNumberField("doorCount", car.getDoors());
jsonGenerator.writeEndObject();
}
}

修改默认的日期序列化格式

SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
objectMapper2.setDateFormat(dateFormat); String output2 = objectMapper2.writeValueAsString(transaction);
System.out.println(output2);

json树模型 JsonNode类

String carJson =
"{ \"brand\" : \"Mercedes\", \"doors\" : 5 }";
ObjectMapper objectMapper = new ObjectMapper();
try {
JsonNode jsonNode = objectMapper.readTree(carJson);
} catch (IOException e) {
e.printStackTrace();
}
String carJson =
"{ \"brand\" : \"Mercedes\", \"doors\" : 5," +
" \"owners\" : [\"John\", \"Jack\", \"Jill\"]," +
" \"nestedObject\" : { \"field\" : \"value\" } }";
ObjectMapper objectMapper = new ObjectMapper();
try {
JsonNode jsonNode = objectMapper.readValue(carJson, JsonNode.class); JsonNode brandNode = jsonNode.get("brand");
String brand = brandNode.asText();
System.out.println("brand = " + brand); JsonNode doorsNode = jsonNode.get("doors");
int doors = doorsNode.asInt();
System.out.println("doors = " + doors); JsonNode array = jsonNode.get("owners");
JsonNode jsonNode = array.get(0);
String john = jsonNode.asText();
System.out.println("john = " + john); JsonNode child = jsonNode.get("nestedObject");
JsonNode childField = child.get("field");
String field = childField.asText();
System.out.println("field = " + field);
} catch (IOException e) {
e.printStackTrace();
}

java对象与JsonNode的转换

ObjectMapper objectMapper = new ObjectMapper();

Car car = new Car();
car.brand = "Cadillac";
car.doors = 4; JsonNode carJsonNode = objectMapper.valueToTree(car);
ObjectMapper objectMapper = new ObjectMapper();
String carJson = "{ \"brand\" : \"Mercedes\", \"doors\" : 5 }";
JsonNode carJsonNode = objectMapper.readTree(carJson);
Car car = objectMapper.treeToValue(carJsonNode);

ObjectMapper读取其他的数据格式

  • CBOR
  • MessagePack
  • YAML
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import java.io.IOException; public class YamlJacksonExample {
public static void main(String[] args) {
ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory());
Employee employee = new Employee("John Doe", "john@doe.com");
String yamlString = null;
try {
yamlString = objectMapper.writeValueAsString(employee);
} catch (JsonProcessingException e) {
e.printStackTrace();
// normally, rethrow exception here - or don't catch it at all.
}
try {
Employee employee2 = objectMapper.readValue(yamlString, Employee.class);
System.out.println("Done");
} catch (IOException e) {
e.printStackTrace();
}
}
}

Jackson JsonNode

JsonNode是不可变的,子类ObjectNode是可变的

将json读取为JsonNode,写为json

JsonNode jsonNode = objectMapper.readTree(json);
String json = objectMapper.writeValueAsString(jsonNode);

获取字段

sonNode jsonNode = ... //parse above JSON into a JsonNode

JsonNode field1 = jsonNode.get("field1");
JsonNode field2 = jsonNode.get("field2"); JsonNode nameNode = jsonNode.at("/identification/name"); //开头必须有/

转化字段的值(注意如果该字段会导致空指针异常)

String f2Str = jsonNode.get("f2").asText();
double f2Dbl = jsonNode.get("f2").asDouble();
int f2Int = jsonNode.get("f2").asInt();
long f2Lng = jsonNode.get("f2").asLong();

提供默认值

ObjectMapper objectMapper = new ObjectMapper();
String json = "{ \"f1\":\"Hello\", \"f2\":null }";
JsonNode jsonNode = objectMapper.readTree(json);
String f2Value = jsonNode.get("f2").asText("Default");

判断是否是有效的JsonNode

JsonNode fieldNode = parentNode.get("fieldName");
if(fieldNode == null || fieldNode.isNull()) {
// the field is either not present in parentNode, or explicitly set to null .
}

递归遍历整个JsonNode

public static void traverse(JsonNode root){

    if(root.isObject()){
Iterator<String> fieldNames = root.fieldNames(); while(fieldNames.hasNext()) {
String fieldName = fieldNames.next();
JsonNode fieldValue = root.get(fieldName);
traverse(fieldValue);
}
} else if(root.isArray()){
ArrayNode arrayNode = (ArrayNode) root;
for(int i = 0; i < arrayNode.size(); i++) {
JsonNode arrayElement = arrayNode.get(i);
traverse(arrayElement);
}
} else {
// JsonNode root represents a single value field - do something with it.
}
}

创建ObjectNode,设置值,删除值

//创建
ObjectMapper objectMapper = new ObjectMapper();
ObjectNode parentNode = objectMapper.createObjectNode(); JsonNode childNode = readJsonIntoJsonNode(); parentNode.set("child1", childNode); //直接赋值原生类型
objectNode.put("field1", "value1");
objectNode.put("field2", 123);
objectNode.put("field3", 999.999); //删除值
objectNode.remove("fieldName");

遍历JsonNode的字段

Iterator<Map.Entry<String, JsonNode>> fields = jsonNode.fields();

while(fields.hasNext()) {
Map.Entry<String, JsonNode> field = fields.next();
String fieldName = field.getKey();
JsonNode fieldValue = field.getValue(); System.out.println(fieldName + " = " + fieldValue.asText());
}

遍历字段名

Iterator<String> fieldNames = jsonNode.fieldNames();

while(fieldNames.hasNext()) {
String fieldName = fieldNames.next(); JsonNode field = jsonNode.get(fieldName);
}

Jackson JsonParser

JsonParser相对于ObjectMapper是low-level的Json解析器,因此也更快,但也更笨重。通过解析器解析就是将json分解为一个一个的token,然后迭代

创建解析器,解析(也可以直接从objectMapper创建)

String carJson =
"{ \"brand\" : \"Mercedes\", \"doors\" : 5 }"; JsonFactory factory = new JsonFactory();
JsonParser parser = factory.createParser(carJson); Car car = new Car();
while(!parser.isClosed()){
JsonToken jsonToken = parser.nextToken(); if(JsonToken.FIELD_NAME.equals(jsonToken)){
String fieldName = parser.getCurrentName();
System.out.println(fieldName); jsonToken = parser.nextToken(); if("brand".equals(fieldName)){
car.brand = parser.getValueAsString();
} else if ("doors".equals(fieldName)){
car.doors = parser.getValueAsInt();
}
}
} System.out.println("car.brand = " + car.brand);
System.out.println("car.doors = " + car.doors);

token的类型有以下几种,可以通过这些常量找出当前token的类型

START_OBJECT
END_OBJECT
START_ARRAY
END_ARRAY
FIELD_NAME
VALUE_EMBEDDED_OBJECT
VALUE_FALSE
VALUE_TRUE
VALUE_NULL
VALUE_STRING
VALUE_NUMBER_INT
VALUE_NUMBER_FLOAT

Jackson JsonGenerator

创建Json生成器、生成json

JsonFactory factory = new JsonFactory();

JsonGenerator generator = factory.createGenerator(
new File("data/output.json"), JsonEncoding.UTF8); generator.writeStartObject(); //写入{
generator.writeStringField("brand", "Mercedes");
generator.writeNumberField("doors", 5);
generator.writeEndObject(); //写入} generator.close();

Jackson Annotations

  • Read + Write Annotations

    • @JsonIgnore 忽略该属性的序列化和反序列化
    • @JsonIgnoreProperties 忽略一组属性的序列化和反序列化,放在类上,@JsonIgnoreProperties({"firstName", "lastName"})
    • @JsonIgnoreType 忽略该类型的属性(所有出现的地方)
    • @JsonAutoDetect 包含非public的字段,放在类上,@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY )
  • Read Annotations
    • @JsonSetter 放在setter方法上,修改读取的json字段名,@JsonSetter("id")
    • @JsonAnySetter 对于未识别的Json字段将调用该注解放的set方法上
    • @JsonCreator @JsonAnySetter不可以用的时候用,用该注解标注的构造器创建,也需要标注哪些参数需要构造
    • @JacksonInject 通过注入的方式赋值该字段的值
    • @JsonDeserialize 指定定制的反序列化器
  • Write Annotations
    • @JsonInclude 放在类上,指定非空才序列化@JsonInclude(JsonInclude.Include.NON_EMPTY),

      @JsonInclude(Include.NON_NULL)指定非null才序列化
    • @JsonGetter 修改序列化的字段名
    • @JsonAnyGetter 将该注解标注的方法返回的值其中的kv单独拿出来序列化
    • @JsonPropertyOrder 放在类上,指定字段序列化的顺序
    • @JsonRawValue 该注解标注的字段会去掉字符串的引号进行序列化
    • @JsonValue 序列化时不序列化对象,而是调用该注解标注的方法
    • @JsonSerialize 指定序列化器

总结:

  • Java对象到Json字符串:objectMapper.writeValueAsString(user)

    • 可以定制序列化器
  • Json到Java对象
    • 简单类型:objectMapper.readValue(jsonString, User.class);
    • 复杂类型:objectMapper.readValue(jsonString, new TypeReference<List<User>>(){});
    • 可以定制反序列化器,Custom Deserializer
  • 核心模块(三个)

databind依赖于streaming和annotations,使用这一个就可以了

地址:https://github.com/FasterXML/jackson-databind,doc见wiki

  • 介绍

其他格式的也支持,只要实现了解析器和生成器

mvn仓库

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.4</version>
</dependency>

如果使用java8的LocalDateTime需要引入jackson-datatype-jsr310(依赖于databind)的maven,且需要使用objectMapper.findAndRegisterModules()代码注册模块。

  • 简单使用

//Java对象转为JSON字符串
user = new User();
objectMapper = new ObjectMapper();
objectMapper.findAndRegisterModules(); //使用java8的localDateTime时使用,但是日期还是有问题,需要在日期的属性上加@JsonFormat(paattern = "yyyy-MM-dd HH:mm:ss")
String jsonString = objectMapper.writeValueAsString(user); //返回json字符串 //JSON字符串转为Java对象
objectMapper = new ObjectMapper();
objectMapper.findAndRegisterModules();
objectMapper.readValue(jsonString, User.class); //简单类型, 有对应的实体类, 如果有泛型会出问题,反序列化的时候会把泛型丢掉, 使用new TypeReference<复杂类型>(){}
objectMapper.readValue(jsonString, new TypeReference<List<User>>(){}); //复杂类型 //修改属性名
@JsonProperty("changedName") //在属性上加 //忽略属性
@JsonIgnore //在属性上加
@JsonIgnoreProperties({"name1", "name2"}) //在类上加
  • 复杂类型使用

    /**
* 复杂类型转换1
*/
@Test
public void test() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper(); User2 user2 = new User2();
user2.setId(1001);
user2.setName("zhangsan");
ArrayList<Account> accList = new ArrayList<>();
Account acc1 = new Account(100, "100");
Account acc2 = new Account(200, "200");
accList.add(acc1);
accList.add(acc2);
HashMap<String, Account> accMap = new HashMap<>();
accMap.put("zhang10", acc1);
accMap.put("zhang20", acc2);
user2.setAccList(accList);
user2.setAccMap(accMap);
String s = mapper.writeValueAsString(user2);
System.out.println(s);
User2 user21 = mapper.readValue(s, User2.class);
System.out.println(user21); } /**
* 复杂类型转换2
* List, Map转换, 简单类型可以直接使用,复杂类型使用TypeReference
*/
@Test
public void test02() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
ArrayList<User> list = new ArrayList<>();
User u1 = new User(1001, "zhang1001");
User u2 = new User(1002, "zhang1002");
list.add(u1);
list.add(u2);
String s = mapper.writeValueAsString(list);
System.out.println(s);
List list1 = mapper.readValue(s, List.class);
System.out.println(list1);
//
System.out.println("----------------------");
HashMap<String, User> map = new HashMap<>();
map.put("10", u1);
map.put("20", u2);
String s1 = mapper.writeValueAsString(map);
System.out.println(s1);
Map map1 = mapper.readValue(s1, Map.class); //返回值没有泛型信息
System.out.println(map1);
System.out.println("--------");
Object o = map1.get("10"); //强转报错
// User o = (User) map1.get("10"); //强转报错
Map<String, User> map2 = mapper.readValue(s1, new TypeReference<Map<String, User>>() {
});
System.out.println(map2);
User user = map2.get("10");
System.out.println(user); }
  • Tree Model

将Json转化为树结构

    /**
* 使用 tree 模型, 类似于JSONObject
*/
@Test
public void test03() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
User user = new User(1001, null);
String s = mapper.writeValueAsString(user);
JsonNode node = mapper.readTree(s);
System.out.println(node.toString());
System.out.println("------------");
JsonNode jsonNode = node.get("id");
int id = node.get("id").asInt();
String name = node.get("name").asText();
String name1 = node.get("name").asText("123");
System.out.println(name);
System.out.println(name1);
System.out.println(id);
}
  • Streaming parser, generator

流处理

   /**
* Streaming parser, generator
* 将json写入流
*/
@Test
public void test04() throws IOException {
ObjectMapper mapper = new ObjectMapper();
File jsonfile = new File("test.json");
JsonGenerator g = mapper.createGenerator(jsonfile, JsonEncoding.UTF8);
g.writeStartObject();
g.writeStringField("message", "hello world");
g.writeEndObject();
g.close();
boolean newFile = jsonfile.createNewFile(); //写入文件 //从流写回
JsonParser p = mapper.createParser(jsonfile);
JsonToken t = p.nextToken();
t = p.nextToken();
if ((t != JsonToken.FIELD_NAME) || (!"message".equals(p.getCurrentName()))) {
System.out.println("handle error");
} t = p.nextToken();
if (t != JsonToken.VALUE_STRING) {
System.out.println("handle error..");
} String text = p.getText();
System.out.println("my message: " + text);
}
  • 配置(特性、注解)

所有配置:https://github.com/FasterXML/jackson-databind/wiki/JacksonFeatures

特性配置(higher-level data-binding configuration)

//序列化
// SerializationFeature for changing how JSON is written // to enable standard indentation ("pretty-printing"):
mapper.enable(SerializationFeature.INDENT_OUTPUT); //开启序列化标准缩进
// to allow serialization of "empty" POJOs (no properties to serialize)
// (without this setting, an exception is thrown in those cases)
mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); //关闭空bean序列化异常, 允许空bean的序列化
// to write java.util.Date, Calendar as number (timestamp):
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); //关闭date序列化为时间戳 //反序列化
// DeserializationFeature for changing how JSON is read as POJOs: // to prevent exception when encountering unknown property:
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); //关闭反序列化未知属性的异常
// to allow coercion of JSON empty String ("") to null Object value:
mapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT); //开启空字符串反序列化为null

特性配置(low-level JSON parsing, generation details)

//解析json特性
// JsonParser.Feature for configuring parsing settings: // to allow C/C++ style comments in JSON (non-standard, disabled by default)
// (note: with Jackson 2.5, there is also `mapper.enable(feature)` / `mapper.disable(feature)`)
mapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true); //允许注释的存在
// to allow (non-standard) unquoted field names in JSON:
mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true); //允许字段名未使用双引号
// to allow use of apostrophes (single quotes), non standard
mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true); //允许字段名使用单引号 //生成json特性
// JsonGenerator.Feature for configuring low-level JSON generation: // to force escaping of non-ASCII characters:
mapper.configure(JsonGenerator.Feature.ESCAPE_NON_ASCII, true); //强制生成非ascii码字符

注解

public class MyBean {
private String _name; // without annotation, we'd get "theName", but we want "name":
@JsonProperty("name")
public String getTheName() { return _name; } // note: it is enough to add annotation on just getter OR setter;
// so we can omit it here
public void setTheName(String n) { _name = n; }
}
// means that if we see "foo" or "bar" in JSON, they will be quietly skipped
// regardless of whether POJO has such properties
@JsonIgnoreProperties({ "foo", "bar" })
public class MyBean
{
// will not be written as JSON; nor assigned from JSON:
@JsonIgnore
public String internal; // no annotation, public field is read/written normally
public String external; @JsonIgnore
public void setCode(int c) { _code = c; } // note: will also be ignored because setter has annotation!
public int getCode() { return _code; }
} public class ReadButDontWriteProps {
private String _name;
@JsonProperty public void setName(String n) { _name = n; }
@JsonIgnore public String getName() { return _name; }
}

使用定制构造器

public class CtorBean
{
public final String name;
public final int age; @JsonCreator // constructor can be public, private, whatever
private CtorBean(@JsonProperty("name") String name,
@JsonProperty("age") int age)
{
this.name = name;
this.age = age;
}
} public class FactoryBean
{
// fields etc omitted for brevity
@JsonCreator
public static FactoryBean create(@JsonProperty("name") String name) {
// construct and return an instance
}
}
  • POJO到POJO的转换

直接转换,只要to-JSON,from-JSON正常就可以使用

  • 使用建造者模式 + Jackson

在反序列化时指定建造者进行反序列化

Jackson学习笔记(详细)的更多相关文章

  1. java多线程学习笔记——详细

    一.线程类  1.新建状态(New):新创建了一个线程对象.        2.就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法.该状态的线程位于可运行线程池中, ...

  2. JackSon学习笔记(一)

    概述 Jackson框架是基于Java平台的一套数据处理工具,被称为“最好的Java Json解析器”. Jackson框架包含了3个核心库:streaming,databind,annotation ...

  3. Jackson学习笔记(三)<转>

    概述 使用jackson annotations简化和增强的json解析与生成. Jackson-2.x通用annotations列表:https://github.com/FasterXML/jac ...

  4. Jackson学习笔记-对象序列化

    一.用ObjectMapper.readValue(jsonString, Student.class) , ObjectMapper.writeValueAsString(student) impo ...

  5. jackson 学习笔记

    Jackson以优异的解析性能赢得了好评,今天就看看Jackson的一些简单的用法. Jackson使用之前先要下载,这里一共有三个jar包,想要获得完美的Jackson体验,这三个jar包都不可或缺 ...

  6. java学习笔记(详细)

    java平台 1.J2SE java开发平台标准版 2.J2EE java开发平台企业版 java程序需要在虚拟机上才可以运行,换言之只要有虚拟机的系统都可以运行java程序.不同系统上要安装对应的虚 ...

  7. 关于高淇JAVA中SORM总结学习笔记详细个人解释

    代码来源于高淇JAVA教学视频 谢谢高淇老师的教学. 因为自己在学习的过程中发现了很多困难点,总结下希望对自己接下来学框架提升.给像我一样得初学者方便. SORM框架是一个简单的ORM,关系对象映射, ...

  8. Jackson学习笔记

    老版本的Jackson使用的包名为org.codehaus.jackson,而新版本使用的是com.fasterxml.jackson. Jackson主要包含了3个模块: jackson-core ...

  9. Linux线程互斥学习笔记--详细分析

    一.互斥锁 为啥要有互斥? 多个进程/线程执行的先后顺序不确定,何时切出CPU也不确定. 多个进程/线程访问变量的动作往往不是原子的. 1. 操作步骤 (1)创建锁 // 创建互斥锁mutex pth ...

随机推荐

  1. gin框架中使用jwt

    生成解析token 如今有很多将身份验证内置到API中的方法 -JSON Web令牌只是其中之一.JSON Web令牌(JWT)作为令牌系统而不是在每次请求时都发送用户名和密码,因此比其他方法(如基本 ...

  2. 返回值Student处理过程

  3. Nginx全面介绍 什么是Nginx?

    目录 一:Nginx全面讲解 1.简介: 2.nginx的用武之地 3.关于代理(解析含义作用) 二:正向代理 三:反向代理 四:项目应用场景 五:正向代理与反向代理区别 1.正向代理 2.反向代理 ...

  4. python内置re模块全面实战

    目录 一:取消转义 二:python内置模块之re模块 三:常用方法 findall search match 简便 四:常用方法 finditer 匹配文件多情况 五:切割 替换 内置模块 六:分组 ...

  5. kubernetes之Pod水平自动伸缩(HPA)

    https://k8smeetup.github.io/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/ Horizon ...

  6. Vue.js的组件(slot/动态组件等)、单文件组件、递归组件使用

    一.组件 1> 组件命名方式有两种(注意:在DOM模板中只有kebab-case命名方法才生效): html中引用组件: <!-- 在DOM模板中,只有 kebab-case命名才生效 - ...

  7. 异步回调实现- Guava Retryer

    为什么要使用重试利器Retryer 在实际开发中我们经常会遇到需要轮询查询一个接果,实现轮询的方式有很多种,我们经常要写许多代码,有时还会怕写出的代码有bug,如果已经有轮子了,我们就没必要重复造轮子 ...

  8. 控制器view生命周期

    控制器View的生命周期方法:只要是控制器的生命周期方法,都是以view开头. 控制器View加载完成时调用- (void)viewDidLoad { [super viewDidLoad];} 控制 ...

  9. PHP中的单引号跟双引号的区别

    不同点: 单引号只能解析转义字符"'"和"\",其他的原样输出.

  10. 3.6 万颗星!开源 Web 服务器后起之秀,自带免费 HTTPS 开箱即用

    众所周知,Web 服务器是 Web 开发中不可或缺的基础服务,在开发中经常会用到.耳熟能详的开源 Web 服务器有久负盛名的 Apache.性能强劲的 Nginx.而我们今天要介绍的开源项目是采用 G ...