Java生态圈中有很多处理JSON和XML格式化的类库,Jackson是其中比较著名的一个。虽然JDK自带了XML处理类库,但是相对来说比较低级,使用本文介绍的Jackson等高级类库处理起来会方便很多。

引入类库

由于Jackson相关类库按照功能分为几个相对独立的,所以需要同时引入多个类库,为了方便我将版本号单独提取出来设置,相关Gradle配置如下。

ext {
  jacksonVersion = '2.9.5'
}

dependencies {
  compile group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: jacksonVersion
  compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: jacksonVersion
  compile group: 'com.fasterxml.jackson.core', name: 'jackson-annotations', version: jacksonVersion
  // 引入XML功能
  compile group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-xml', version: jacksonVersion
  // 比JDK自带XML实现更高效的类库
  compile group: 'com.fasterxml.woodstox', name: 'woodstox-core', version: '5.1.0'
  // Java 8 新功能
  compile group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310', version: jacksonVersion
  compile group: 'com.fasterxml.jackson.module', name: 'jackson-module-parameter-names', version: jacksonVersion
  compile group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jdk8', version: jacksonVersion

  compileOnly group: 'org.projectlombok', name: 'lombok', version: '1.16.22'
}

Maven配置请去mvnrepository搜索。

Jackson注解

Jackson类库包含了很多注解,可以让我们快速建立Java类与JSON之间的关系。详细文档可以参考Jackson-Annotations。下面介绍一下常用的。

属性命名

@JsonProperty注解指定一个属性用于JSON映射,默认情况下映射的JSON属性与注解的属性名称相同,不过可以使用该注解的value值修改JSON属性名,该注解还有一个index属性指定生成JSON属性的顺序,如果有必要的话。

属性包含

还有一些注解可以管理在映射JSON的时候包含或排除某些属性,下面介绍一下常用的几个。

@JsonIgnore注解用于排除某个属性,这样该属性就不会被Jackson序列化和反序列化。

@JsonIgnoreProperties注解是类注解。在序列化为JSON的时候,@JsonIgnoreProperties({"prop1", "prop2"})会忽略pro1和pro2两个属性。在从JSON反序列化为Java类的时候,@JsonIgnoreProperties(ignoreUnknown=true)会忽略所有没有Getter和Setter的属性。该注解在Java类和JSON不完全匹配的时候很有用。

@JsonIgnoreType也是类注解,会排除所有指定类型的属性。

序列化相关

@JsonPropertyOrder和@JsonProperty的index属性类似,指定属性序列化时的顺序。

@JsonRootName注解用于指定JSON根属性的名称。

处理JSON

简单映射

我们用Lombok设置一个简单的Java类。

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Friend {
  private String nickname;
  private int age;
}

然后就可以处理JSON数据了。首先需要一个ObjectMapper对象,序列化和反序列化都需要它。

    ObjectMapper mapper = new ObjectMapper();
    Friend friend = new Friend("yitian", 25);

    // 写为字符串
    String text = mapper.writeValueAsString(friend);
    // 写为文件
    mapper.writeValue(new File("friend.json"), friend);
    // 写为字节流
    byte[] bytes = mapper.writeValueAsBytes(friend);
    System.out.println(text);
    // 从字符串中读取
    Friend newFriend = mapper.readValue(text, Friend.class);
    // 从字节流中读取
    newFriend = mapper.readValue(bytes, Friend.class);
    // 从文件中读取
    newFriend = mapper.readValue(new File("friend.json"), Friend.class);
    System.out.println(newFriend);

程序结果如下。可以看到生成的JSON属性和Java类中定义的一致。

{"nickname":"yitian","age":25}
Friend(nickname=yitian, age=25)

集合的映射

除了使用Java类进行映射之外,我们还可以直接使用Map和List等Java集合组织JSON数据,在需要的时候可以使用readTree方法直接读取JSON中的某个属性值。需要注意的是从JSON转换为Map对象的时候,由于Java的类型擦除,所以类型需要我们手动用new TypeReference给出。

    ObjectMapper mapper = new ObjectMapper();

    Map map = new HashMap<>();
    map.put("age", 25);
    map.put("name", "yitian");
    map.put("interests", new String[]{"pc games", "music"});

    String text = mapper.writeValueAsString(map);
    System.out.println(text);

    Map map2 = mapper.readValue(text, new TypeReference>() {
    });
    System.out.println(map2);

    JsonNode root = mapper.readTree(text);
    String name = root.get("name").asText();
    int age = root.get("age").asInt();

    System.out.println("name:" + name + " age:" + age);

程序结果如下。

{"name":"yitian","interests":["pc games","music"],"age":25}
{name=yitian, interests=[pc games, music], age=25}
name:yitian age:25

Jackson配置

Jackson预定义了一些配置,我们通过启用和禁用某些属性可以修改Jackson运行的某些行为。详细文档参考JacksonFeatures。下面我简单翻译一下Jackson README上列出的一些属性。

// 美化输出
mapper.enable(SerializationFeature.INDENT_OUTPUT);
// 允许序列化空的POJO类
// (否则会抛出异常)
mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
// 把java.util.Date, Calendar输出为数字(时间戳)
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

// 在遇到未知属性的时候不抛出异常
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
// 强制JSON 空字符串("")转换为null对象值:
mapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);

// 在JSON中允许C/C++ 样式的注释(非标准,默认禁用)
mapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
// 允许没有引号的字段名(非标准)
mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
// 允许单引号(非标准)
mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
// 强制转义非ASCII字符
mapper.configure(JsonGenerator.Feature.ESCAPE_NON_ASCII, true);
// 将内容包裹为一个JSON属性,属性名由@JsonRootName注解指定
mapper.configure(SerializationFeature.WRAP_ROOT_VALUE, true);

这里有三个方法,configure方法接受配置名和要设置的值,Jackson 2.5版本新加的enable和disable方法则直接启用和禁用相应属性,我推荐使用后面两个方法。

用注解管理映射

前面介绍了一些Jackson注解,下面来应用一下这些注解。首先来看看使用了注解的Java类。

@Data
@NoArgsConstructor
@AllArgsConstructor
@JsonRootName("FriendDetail")
@JsonIgnoreProperties({"uselessProp1", "uselessProp3"})
public class FriendDetail {
  @JsonProperty("NickName")
  private String name;
  @JsonProperty("Age")
  private int age;
  private String uselessProp1;
  @JsonIgnore
  private int uselessProp2;
  private String uselessProp3;
}

然后看看代码。需要注意的是,由于设置了排除的属性,所以生成的JSON和Java类并不是完全对应关系,所以禁用DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES是必要的。

    ObjectMapper mapper = new ObjectMapper();
    //mapper.enable(SerializationFeature.WRAP_ROOT_VALUE);
    mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
    FriendDetail fd = new FriendDetail("yitian", 25, "", 0, "");
    String text = mapper.writeValueAsString(fd);
    System.out.println(text);

    FriendDetail fd2 = mapper.readValue(text, FriendDetail.class);
    System.out.println(fd2);

运行结果如下。可以看到生成JSON的时候忽略了我们制定的值,而且在转换为Java类的时候对应的属性为空。

{"NickName":"yitian","Age":25}
FriendDetail(name=yitian, age=25, uselessProp1=null, uselessProp2=0, uselessProp3=null)

然后取消注释代码中的那行,也就是启用WRAP_ROOT_VALUE功能,再运行一下程序,运行结果如下。可以看到生成的JSON结果发生了变化,而且由于JSON结果变化,所以Java类转换失败(所有字段值全为空)。WRAP_ROOT_VALUE这个功能在有些时候比较有用,因为有些JSON文件需要这种结构。

{"FriendDetail":{"NickName":"yitian","Age":25}}
FriendDetail(name=null, age=0, uselessProp1=null, uselessProp2=0, uselessProp3=null)

Java8日期时间类支持

Java8增加了一套全新的日期时间类,Jackson对此也有支持。这些支持是以Jackson模块形式提供的,所以首先就是注册这些模块。

    ObjectMapper mapper = new ObjectMapper()
        .registerModule(new JavaTimeModule())
        .registerModule(new ParameterNamesModule())
        .registerModule(new Jdk8Module());

导入类库之后,Jackson也可以自动搜索所有模块,不需要我们手动注册。

mapper.findAndRegisterModules();

我们新建一个带有LocalDate字段的Java类。

@Data
@NoArgsConstructor
@AllArgsConstructor
@JsonRootName("Person")
public class Person {
  @JsonProperty("Name")
  private String name;
  @JsonProperty("NickName")
  private String nickname;
  @JsonProperty("Age")
  private int age;
  @JsonProperty("IdentityCode")
  private String identityCode;
  @JsonProperty
  @JsonFormat(pattern = "yyyy-MM-DD")
  private LocalDate birthday;

}

然后来看看代码。

  static void java8DateTime() throws IOException {
    Person p1 = new Person("yitian", "易天", 25, "10000", LocalDate.of(1994, 1, 1));
    ObjectMapper mapper = new ObjectMapper()
        .registerModule(new JavaTimeModule());
    //mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
    String text = mapper.writeValueAsString(p1);
    System.out.println(text);

    Person p2 = mapper.readValue(text, Person.class);
    System.out.println(p2);
  }

运行结果如下。可以看到,生成的JSON日期变成了[1994,1,1]这样的时间戳形式,一般情况下不符合我们的要求。

{"birthday":[1994,1,1],"Name":"yitian","NickName":"易天","Age":25,"IdentityCode":"10000"}
Person(name=yitian, nickname=易天, age=25, identityCode=10000, birthday=1994-01-01)

取消注释那行代码,程序运行结果如下。这样一来就变成了我们一般使用的形式了。如果有格式需要的话,可以使用@JsonFormat(pattern = "yyyy-MM-DD")注解格式化日期显示。

{"birthday":"1994-01-01","Name":"yitian","NickName":"易天","Age":25,"IdentityCode":"10000"}
Person(name=yitian, nickname=易天, age=25, identityCode=10000, birthday=1994-01-01)

处理XML

Jackson是一个处理JSON的类库,不过它也通过jackson-dataformat-xml包提供了处理XML的功能。Jackson建议我们在处理XML的时候使用woodstox-core包,它是一个XML的实现,比JDK自带XML实现更加高效,也更加安全。

这里有个注意事项,如果你正在使用Java 9以上的JDK,可能会出现java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException异常,这是因为Java 9实现了JDK的模块化,将原本和JDK打包在一起的JAXB实现分隔出来。所以这时候需要我们手动添加JAXB的实现。在Gradle中添加下面的代码即可。

compile group: 'javax.xml.bind', name: 'jaxb-api', version: '2.3.0'

注解

Jackson XML除了使用Jackson JSON和JDK JAXB的一些注解之外,自己也定义了一些注解。下面简单介绍一下几个常用注解。

@JacksonXmlProperty注解有三个属性,namespace和localname属性用于指定XML命名空间的名称,isAttribute指定该属性作为XML的属性()还是作为子标签().

@JacksonXmlRootElement注解有两个属性,namespace和localname属性用于指定XML根元素命名空间的名称。

@JacksonXmlText注解将属性直接作为未被标签包裹的普通文本表现。

@JacksonXmlCData将属性包裹在CDATA标签中。

XML映射

新建如下一个Java类。

@Data
@NoArgsConstructor
@AllArgsConstructor
@JsonRootName("Person")
public class Person {
  @JsonProperty("Name")
  private String name;
  @JsonProperty("NickName")
  //@JacksonXmlText
  private String nickname;
  @JsonProperty("Age")
  private int age;
  @JsonProperty("IdentityCode")
  @JacksonXmlCData
  private String identityCode;
  @JsonProperty("Birthday")
  //@JacksonXmlProperty(isAttribute = true)
  @JsonFormat(pattern = "yyyy/MM/DD")
  private LocalDate birthday;

}

下面是代码示例,基本上和JSON的API非常相似,XmlMapper实际上就是ObjectMapper的子类。

    Person p1 = new Person("yitian", "易天", 25, "10000", LocalDate.of(1994, 1, 1));
    XmlMapper mapper = new XmlMapper();
    mapper.findAndRegisterModules();
    mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
    mapper.enable(SerializationFeature.INDENT_OUTPUT);
    String text = mapper.writeValueAsString(p1);
    System.out.println(text);

    Person p2 = mapper.readValue(text, Person.class);
    System.out.println(p2);

运行结果如下。


 yitian
 易天
 25
 
 1994/01/01


Person(name=yitian, nickname=易天, age=25, identityCode=10000, birthday=1994-01-01)

如果取消那两行注释,那么运行结果如下。可以看到Jackson XML注解对生成的XML的控制效果。


 yitian易天
 25
 


Person(name=yitian, nickname=null, age=25, identityCode=10000, birthday=1994-01-01)

Spring Boot集成

自动配置

Spring Boot对Jackson的支持非常完善,只要我们引入相应类库,Spring Boot就可以自动配置开箱即用的Bean。Spring自动配置的ObjectMapper(或者XmlMapper)作了如下配置,基本上可以适应大部分情况。

  • 禁用了MapperFeature.DEFAULT_VIEW_INCLUSION
  • 禁用了DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
  • 禁用了SerializationFeature.WRITE_DATES_AS_TIMESTAMPS

如果需要修改自动配置的ObjectMapper属性也非常简单,Spring Boot提供了一组环境变量,直接在application.properties文件中修改即可。

|Jackson枚举|Spring环境变量|
|—?|—?|
com.fasterxml.jackson.databind.DeserializationFeature|spring.jackson.deserialization.=true|false
com.fasterxml.jackson.core.JsonGenerator.Feature|spring.jackson.generator.=true|false
com.fasterxml.jackson.databind.MapperFeature|spring.jackson.mapper.=true|false
com.fasterxml.jackson.core.JsonParser.Feature|spring.jackson.parser.=true|false
com.fasterxml.jackson.databind.SerializationFeature|spring.jackson.serialization.=true|false
com.fasterxml.jackson.annotation.JsonInclude.Include|spring.jackson.default-property-inclusion=always|non_null|non_absent|non_default|non_empty

由于Spring会同时配置相应的HttpMessageConverters,所以我们其实要做的很简单,用Jackson注解标注好要映射的Java类,然后直接让控制器返回对象即可!下面是一个Java类。

@JsonRootName("person")
public class Person {
  @JsonProperty
  private String name;
  @JsonProperty
  private int id;
  @JsonFormat(pattern = "yyyy-MM-DD")
  private LocalDate birthday;

  public Person(String name, int id, LocalDate birthday) {
    this.name = name;
    this.id = id;
    this.birthday = birthday;
  }
}

然后是控制器代码。在整个过程中我们只需要引入Jackson类库,然后编写业务代码就好了。关于如何配置Jackson类库,我们完全不需要管,这就是Spring Boot的方便之处。

@Controller
public class MainController {
  private Person person = new Person("yitian", 10000, LocalDate.of(1994, 1, 1));

  @RequestMapping("/")
  public String index() {
    return "index";
  }


  @RequestMapping(value = "/json", produces = "application/json")
  @ResponseBody
  public Person json() {
    return person;
  }
}

进入localhost:8080/xml就可以看到对应结果了。

手动配置

Spring Boot自动配置非常方便,但不是万能的。在必要的时候,我们需要手动配置Bean来替代自动配置的Bean。

@Configuration
public class JacksonConfig {
  @Bean
  @Primary
  @Qualifier("xml")
  public XmlMapper xmlMapper(Jackson2ObjectMapperBuilder builder) {
    XmlMapper mapper = builder.createXmlMapper(true)
        .build();
    mapper.enable(SerializationFeature.INDENT_OUTPUT);
    mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
    return mapper;
  }

  @Bean
  @Qualifier("json")
  public ObjectMapper jsonMapper(Jackson2ObjectMapperBuilder builder) {
    ObjectMapper mapper = builder.createXmlMapper(false)
        .build();
    mapper.enable(SerializationFeature.INDENT_OUTPUT);
    mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
    return mapper;
  }
}

然后在需要的地方进行依赖注入。需要注意为了区分ObjectMapper和XmlMapper,需要使用@Qualifier注解进行标记。

@Controller
public class MainController {
  private ObjectMapper jsonMapper;
  private XmlMapper xmlMapper;
  private Person person = new Person("yitian", 10000, LocalDate.of(1994, 1, 1));

  public MainController(@Autowired @Qualifier("json") ObjectMapper jsonMapper, @Autowired @Qualifier("xml") XmlMapper xmlMapper) {
    this.jsonMapper = jsonMapper;
    this.xmlMapper = xmlMapper;
  }

以上就是Jackson类库的一些介绍,希望对大家有所帮助。项目代码在我的Github,感兴趣的同学可以看看。

到此这篇关于Java中Jackson快速入门的文章就介绍到这了,更多相关Jackson快速入门内容请搜索乐虎体育以前的文章或继续浏览下面的相关文章希望大家以后多多支持乐虎体育!

标签:

Java中Jackson快速入门的更多相关文章

  1. java集合(List Set Map的使用

    ListList的元素以线性方式存储,可以存放重复对象,List主要有以下两个实现类:ArrayList : 长度可变的数组,可以对元素进行随机的访问,向ArrayList中插入与删除元素的速度慢。LinkedList: 采用链表数据结构,插入和删除速度快,但访问速度慢。SetSet中的......

  2. Java序列化

    1.什么是序列化Java序列化是指把Java对象转换为字节序列的过程,而Java反序列化是指把字节序列恢复为Java对象的过程:序列化:对象序列化的最主要的用处就是在传递和保存对象的时候,保证对象的完整性和可传递性。序列化是把对象转换成有序字节流,以便在网络上传输或者保存在本地文件中。核心作用是对象......

  3. synchronized详解

    synchronized是Java多线程中元老级的锁,也是面试的高频考点,让我们来详细了解synchronized吧。在Java中,synchronized锁可能是我们最早接触的锁了,在 JDK1.5之前synchronized是一个重量级锁,相对于juc包中的Lock,synchronized显得......

  4. Java多线程总结(二)

    四.Java多线程的阻塞状态与线程控制上文已经提到Java阻塞的几种具体类型。下面分别看下引起Java线程阻塞的主要方法。1.join()join —— 让一个线程等待另一个线程完成才继续执行。如A线程线程执行体中调用B线程的join()方法,则A线程被阻塞,知道B线程执行完为止,A才能得以继续执行......

  5. Java集合框架分析(List)——LinkedList类详解

    LinkedList类中的方法与实现原理目录一.数据结构二.类标题三.字段四.构造函数五.方法分析5.1 共有方法 public boolean add(Object o)public boolean addAll(Collection c)public boolean contains(Objec......

  6. Java中EasyPoi导出复杂合并单元格的方法

    前言:上星期做了一个Excel的单元格合并,用的是EasyPoi,我之前合并单元格都是原生的,第一次使用EasyPoi合并也不太熟悉,看着网上自己套用,使用后发现比原生的方便些,贡献一下,也给其他用到合并而且用的是EasyPoi的小伙伴节省下时间。导出模板:坐标:版本号,自己来定,可以去官网查看:E......

  7. Java 执行过程中的内存模型

    一、前言本文的主要工作:尝试以时间顺序追踪一遍 Java 执行的整个过程,以及展示 JVM 中内存模型的相应变化。本文的主要目的:希望能够通过 Java 执行过程的冰山一角,增进对编程语言工作原理的理解。以下面这段代码为例,追踪它的执行过程:public class Car {private int......

  8. Java中多线程启动,为什么调用的是start方法,而不是run方法?

    前言大年初二,大家新年快乐,我又开始码字了。写这篇文章,源于在家和基友交流的时候,基友问到了,我猛然发现还真是这么回事,多线程启动调用的都是start,那么为什么没人掉用run呢?于是打开我的idea,翻一波代码,带大家一探究竟。继承thread类实现多线程我们知道java有三种方式实现多线程,这里......

  9. springboot整合websocket最基础入门使用教程详解

    项目最终的文件结构1 添加maven依赖<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artif......

  10. Java中的深浅拷贝问题,你清楚吗?

    一、前言拷贝这个词想必大家都很熟悉,在工作中经常需要拷贝一份文件作为副本。拷贝的好处也很明显,相较于新建来说,可以节省很大的工作量。在Java中,同样存在拷贝这个概念,拷贝的意义也是可以节省创建对象的开销。Object类中有一个方法clone(),具体方法如下:protected native Ob......

随机推荐

  1. JVM系列(四):java方法的查找过程实现

    经过前面几章的简单介绍,我们已经大致了解了jvm的启动框架和执行流程了。不过,这些都是些无关痛痒的问题,几行文字描述一下即可。所以,今天我们从另一个角度来讲解jvm的一些东西,以便可以更多一点认知。即如题:jvm是如何找到对应的java方法,然后执行的呢?(但是执行太复杂,太重要,我们就不说了。我们......

  2. Linux下Too many open files问题排查与解决

    作者:Grey原文地址:Github语雀博客园Too many open files是Linux系统中常见的错误,从字面意思上看就是说程序打开的文件数过多,不过这里的files不单是文件的意思,也包括打开的通讯链接(比如socket),正在监听的端口等等,所以有时候也可以叫做句柄(handle),这......

  3. asp.net core集成CKEditor实现图片上传功能的示例代码

    背景本文为大家分享了asp.net core 如何集成CKEditor ,并实现图片上传功能的具体方法,供大家参考,具体内容如下。准备工作1.visual studio 2019 开发环境2.net core 2.0 及以上版本实现方法1、新建asp.net core web项目2、下载CKEdit......

  4. C# WinForm状态栏实时显示当前时间(窗体状态栏StatusStrip示例)

    本文主要介绍了C# WinForm状态栏实时显示当前时间(窗体状态栏StatusStrip示例),分享给大家,具体如下:实现效果:通过StatusStrip显示窗体状态栏,同时将状态栏分成三部分:居左边显示相关文字信息及时间信息,中间操作系统登录名,居右边显示本地IP。步骤:1.创建窗体及添加Sta......

  5. C# 获取当前总毫秒数的实例讲解

    在.Net下DateTime.Ticks获得的是个long型的时间整数,具体表示是至0001 年 1 月 1 日午夜 12:00:00 以来所经过时间以100纳秒的数字。转换为秒为Ticks/10000000,转换为毫秒Ticks/10000。如果要获取从1970年1月1日至当前时间所经过的毫秒数,......

  6. JavaScript实现浏览器网页自动滚动并点击的示例代码

    1. 打开浏览器控制台窗口JavaScript通常是作为开发Web页面的脚本语言,本文介绍的JavaScript代码均运行在指定网站的控制台窗口。一般浏览器的开发者窗口都可以通过在当前网页界面按F12快捷键调出,然后在上面的标签栏找到Console点击就是控制台窗口,在这里可以直接执行JavaScr......

  7. 原生javascript开发计算器实例

    计算器的主要作用是进行数字运算,开发一个计算器功能的web实例,有助于更好的掌握js基础的数字运算能力。本实例旨在帮助js计算能力有待提高的读者,通过自己一步一步开发完成计算器功能,熟悉js数字处理方法。计算器的主要作用是进行数字运算,开发一个计算器功能的web实例,有助于更好的掌握js基础的数字运......

  8. 使用Python+Appuim 清理微信的方法

    使用 Appium安装一下 Python 用到的模块pip install Appium-Python-Client获取好友列表在 Pycharm 中配置一下启动环境desired_capabilities = {'platformName': 'Android', # 操作系统'deviceNam......

  9. Python利用socket模块开发简单的端口扫描工具的实现

    一、socket1.简介Socket又称"套接字",应用程序通常通过"套接字"向网络发出请求或者应答网络请求,使主机间或者一台计算机上的进程间可以通讯。socket的工作流程socket 采用C/S 模式,分为服务端和客户端服务端数据处理流程创建socket ......

  10. python实现简单的井字棋游戏(gui界面)

    项目输出项目先决条件要使用python构建井字游戏,我们需要tkinter模块和python的基本概念Tkinter模块是用于渲染图形的标准图形用户界面。Tkinter.messagebox用于显示消息框要安装tkinter模块,我们在命令提示符下使用了pip install命令:pip insta......