Jackson 快速入门-程序员宅基地

技术标签: Spring-WEB  Java类库  

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<T>给出。

ObjectMapper mapper = new ObjectMapper();

Map<String, Object> 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<String, Object> map2 = mapper.readValue(text, new TypeReference<Map<String, Object>>() {
    
});
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);
// 不返回 null 值字段
OBJECT_MAPPER.setDefaultPropertyInclusion(JsonInclude.Include.NON_NULL);

这里有三个方法,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)

返回JSON日期少一天问题

// 设置为中国时区. "GMT+08:00"
TimeZone china = TimeZone.getTimeZone("GMT+:08:00");
mapper.setTimeZone(china);

// 设置中国重庆时区
mapper.setTimeZone(TimeZone.getTimeZone("Asia/Chongqing"));

 

处理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);

运行结果如下。

<Person>
  <Name>yitian</Name>
  <NickName>易天</NickName>
  <Age>25</Age>
  <IdentityCode><![CDATA[10000]]></IdentityCode>
  <Birthday>1994/01/01</Birthday>
</Person>

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

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

<Person birthday="1994/01/01">
  <Name>yitian</Name>易天
  <Age>25</Age>
  <IdentityCode><![CDATA[10000]]></IdentityCode>
</Person>

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

由于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,感兴趣的同学可以看看。

 

实际应用示例

public class JacksonUtil {
    
    private static final transient ObjectMapper OBJECT_MAPPER = new ObjectMapper();
    static {
    
        OBJECT_MAPPER.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        OBJECT_MAPPER.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
    }

    public static <T> T parseObject(String json, Class<T> clazz) {
    
        try {
    
            return OBJECT_MAPPER.readValue(json, clazz);
        } catch (Exception e) {
    
            throw new RuntimeException("JacksonUtil parseObject json:["+json+"] error", e);
        }
    }

    public static String toJsonString(Object obj) {
    
        try {
    
            return OBJECT_MAPPER.writeValueAsString(obj);
        } catch (Exception e) {
    
            throw new RuntimeException("JacksonUtil toJsonString obj:["+obj+"] error", e);
        }
    }
}

 

参考文档

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/u010979642/article/details/103670478

智能推荐

无名对象_class student{public:student(char* pname = "no nam-程序员宅基地

文章浏览阅读168次。代码:#include &lt;iostream&gt;#include &lt;cstring&gt; using namespace std;class Student{public:Student(char* pName="no name",int ssId=0){ strncpy(name,pName,40); name[39]='\0'; id = ssId; cout &lt;&..._class student{public:student(char* pname = "no name"){strcpy(name, p

【Android自定义View】仿Photoshop取色器ColorPicker(二)_android 仿ps吸管效果-程序员宅基地

文章浏览阅读2.3k次。ColorPicker一款仿Photoshop取色器的Android版取色器。github地址:ColorPicker前言上一篇已经简单介绍了ColorPicker的项目结构以及两种颜色空间,接下来我们详细解析一下ColorPicker的核心自定义控件ColorPickerView。ColorPickerView在阅读代码之前,我们先看一下ColorPicker的布局以及一些标注的数值在代码里的变量_android 仿ps吸管效果

计算机系统结构复习(一):Introduction概述_data-level parallelism-程序员宅基地

文章浏览阅读1.2k次,点赞2次,收藏4次。计算机系统结构复习(一):Introduction概述体系结构发展新趋势定量分析/量化研究方法计算机种类摩尔定律什么是计算机系统结构两个概念计算机系统结构与计算机组成、实现的关系体系结构发展新趋势1.新的模型:Data-level parallelism (DLP):数据级并行Thread-level parallelism (TLP):线程级并行Request-level parallelism (RLP):满足用户需求的并行2.开源架构 RISC-V3.Domain-Specific A_data-level parallelism

surface pro 4 wifi掉线问题-程序员宅基地

文章浏览阅读897次。更新你的无线网卡驱动到最新版本15.68.9032.47,重启。或者运行regedit修改注册表 HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\mrvlpcie8897,找到值 “TXAMSDU”把它从1改为0。转载于:https://www.cnblogs.com/misstaste/p/5898571.html..._surface pro 4 无线网卡

不断更新中:中文垃圾邮件过滤规则集Chinese_rules.cf_spamassassin 中文规则-程序员宅基地

文章浏览阅读4.2k次。Chinese_rules.cf的使用方法:下载Chinese_rules.cf,把该规则放在SpamAssassin存放规则的目录(一般在/usr/share/spamassassin或/usr/local/etc/mail/spamassassin)。通过wget下载的命令如下:wget -N -P /usr/share/spamassassin www.service-labs.com/dow_spamassassin 中文规则

mysql基础知识:sql通用语法,及分类(mysql学习纪念)-程序员宅基地

文章浏览阅读349次,点赞10次,收藏11次。2.SQL语句可以使用空格/缩进来增强语句的可读性。1.SQL语句可以单行或多行书写,以分号结尾。3.MySQL数据库的SQL语句不区分大小写。

随便推点

Git的相关操作,创建、更新、提交等,代码托管在码云上_使用git提交代码,git commit -m ' ' 提交、同步代码之后,在码云上备注是乱码。怎-程序员宅基地

文章浏览阅读5.9k次。Git的相关操作,创建、更新、提交等,代码托管在码云上一、环境配置:(1)下载安装Git Bash,具体步骤就不赘述了;(2)双击运行“Git Bash”,配置用户名及邮箱:$ git config --global user.name "xxxxxxx"$ git config --global user.email "[email protected]"_使用git提交代码,git commit -m ' ' 提交、同步代码之后,在码云上备注是乱码。怎

Java多线程之线程池深入分析(下)_线程之 1.7 doacquiresharedinterruptibly解析-程序员宅基地

文章浏览阅读1.4k次。一、数据结构与线程构造方法由于已经看到了ThreadPoolExecutor的源码,因此很容易就看到了ThreadPoolExecutor线程池的数据结构。图1描述了这种数据结构。图1 ThreadPoolExecutor 数据结构其实,即使没有上述图形描述ThreadPoolExecutor的数据结构,我们根据线程池的要求也很能够猜测出其数据结构出来。_线程之 1.7 doacquiresharedinterruptibly解析

JS快速获取图片宽高的方法_图片 src和onload 哪个快-程序员宅基地

文章浏览阅读4.8w次,点赞3次,收藏21次。快速获取图片的宽高其实是为了预先做好排版样式布局做准备,通过快速获取图片宽高的方法比onload方法要节省很多时间,甚至一分钟以上都有可能,并且这种方法适用主流浏览器包括IE低版本浏览器。我们一步一步进入这个过程。一、简陋的获取图片方式1234567891011_图片 src和onload 哪个快

严重: 在路径为/book的上下文中,Servlet[jsp]的Servlet.service()引发了具有根本原因的异常java.lang.ClassNotFoundException: org.a_严重: 在路径为/bookmanage的上下文中,servlet[jsp]的servlet.serv-程序员宅基地

文章浏览阅读6.3k次。严重: 在路径为/book的上下文中,Servlet[jsp]的Servlet.service()引发了具有根本原因的异常java.lang.ClassNotFoundException:这种报错,除了其他人的:还有一种可能:名字不一样,哪怕是空格哪怕是一个空格!..._严重: 在路径为/bookmanage的上下文中,servlet[jsp]的servlet.service()引发了具

ios砸壳_ios砸壳需要 闪退怎么砸-程序员宅基地

文章浏览阅读6.2k次。frida-ios-dump源码地址:​​​​​​GitHub - AloneMonkey/frida-ios-dump: pull decrypted ipa from jailbreak devicefrida-ios-dump是基于frida开发的一键砸壳工具,需要配置frida环境手机配置1)越狱状态2)安装openssh3)安装fridaMac配置1)安装frida,命令行:sudo pip install frida-tools (没有安装pip的话需要先安装pip)_ios砸壳需要 闪退怎么砸

IOS-----越狱开发_depends libundirect.depends firmware-程序员宅基地

文章浏览阅读2.6k次,点赞3次,收藏2次。1.制作系统应用程序。 ios的程序分为mobile和root权限模式,我们一般用xcode开发的app取得的是mobile权限,但是ios越狱后安装的app如:Cydia、91助手、PP助手等均为系统级应用程序。系统级app的好处是:用不无法手动删除、取得完全的root权限、可设置开机启动项等等功能。通过xcode打包的ipa是无法安装成为系统app的,所以我们需要另外一种打包方式:_depends libundirect.depends firmware

推荐文章

热门文章

相关标签