搜索词>>GSON 耗时0.0030
  • Gson 序列化NULL值

    前言在Gson中实现的默认行为是忽略空对象字段前言在Gson中实现的默认行为是忽略空对象字段。例如,如果在Employee对象中,我们不指定电子邮件(即电子邮件是null),那么电子邮件将不是序列化JSON输出的一部分。Gson忽略空字段,因为此行为允许更紧凑的JSON输出格式。​1.如何在序列化期间允许空值 要配置GSON实例来输出null,我们必须使用serializeNulls()的GsonBuilder对象。Gson gson = new GsonBuilder() .serializeNulls() .create();2.演示 让我们看一下Gson的行为,同时启用或禁用空字段序列化。这是员工类,有四个字段。我们将电子邮件字段设置为'null'。$title(Employee.java) public class Employee { private Integer id; private String firstName; private String lastName; private String email; }2.1。不要序列化空字段 JSON输出中没有空值的默认Gson序列化。$title(Main.java) Employee employeeObj = new Employee(1, "Lokesh", "Gupta", null); Gson gson = new GsonBuilder() .setPrettyPrinting() .create(); System.out.println(gson.toJson(employeeObj)); 运行输出结果为:{ "id": 1, "firstName": "Lokesh", "lastName": "Gupta" }2.2。序列化空字段 自定义Gson序列化,JSON输出中包含空值。$title(Main.java) Employee employeeObj = new Employee(1, "Lokesh", "Gupta", null); Gson gson = new GsonBuilder() .setPrettyPrinting() .serializeNulls() .create(); System.out.println(gson.toJson(employeeObj)); 执行输出结果:{ "id": 1, "firstName": "Lokesh", "lastName": "Gupta", "emailId": null } 显然,null字段在JSON输出中被序列化。
  • Gson @SerializedName注解使用说明

    前言在这个Gson @SerializedName示例中,学习在序列化和反序列化过程中更改json和java对象之间的字段名称前言在这个Gson @SerializedName示例中,学习在序列化和反序列化过程中更改json和java对象之间的字段名称。​1. @SerializedName 默认情况下,我们假设Java模型类和JSON将完全相同的字段名称。但有时情况并非如此,某些名称也有所不同。现在我们必须将someNamejson someOtherName中的映射映射到Java类中。这是@SerializedName注释有用的地方。@SerializedName注释指示应将带注释的成员序列化为JSON,并将提供的名称值作为其字段名称。此批注将覆盖FieldNamingPolicy可能已使用GsonBuilder该类的任何内容,包括默认字段命名策略。请注意,您在此批注中指定的值必须是有效的JSON字段名称。1.1。注释属性 它接受两个属性:value - 序列化或反序列化时字段的所需名称。alternate - 反序列化时字段的替代名称。除了'value'属性之外,它还提供了更多可能的名称。如果有多个字段与一个属性匹配,Gson将使用最后处理的字段。请记住,alternate具有多个名称的选项仅限于反序列化。在序列化中,它不会产生任何影响。2.在序列化期间更改字段名称 让我们举一个Employee只有4个字段的类的例子。我们想创建JSON,其中"email"写为字段名称"emailId"。$title(Employee.java) public class Employee { private Integer id; private String firstName; private String lastName; @SerializedName(value = "emailId", alternate = "emailAddress") private String email; } 让我们序列化一个员工记录并查看JSON输出。$title(Main.java) Employee emp = new Employee(1001, "Lokesh", "Gupta", "howtodoinjava@gmail.com"); Gson gson = new GsonBuilder().setPrettyPrinting().create(); System.out.println(gson.toJson(emp)); 执行输出:{ "id": 1001, "firstName": "Lokesh", "lastName": "Gupta", "emailId": "howtodoinjava@gmail.com" }3.在反序列化期间更改字段名称 在将JSON反序列化到Java类期间映射不同字段名称的Java程序。{ "id": 1001, "firstName": "Lokesh", "lastName": "Gupta", "email": "howtodoinjava@gmail.com", "emailAddress": "admin@gmail.com" }$title(Main.java) String json = "{'id': 1001," + "'firstName': 'Lokesh'," + "'lastName': 'Gupta'," + "'email': 'howtodoinjava@gmail.com'," + "'emailAddress': 'admin@gmail.com'}"; Gson gson = new GsonBuilder().setPrettyPrinting().create(); Employee emp = gson.fromJson(json, Employee.class); System.out.println(emp); 执行输出:Employee [id=1001, firstName=Lokesh, lastName=Gupta, email=admin@gmail.com] 注意程序输出。我们有两个匹配的电子邮件领域即email和emailAddress。最后一次出现是for "emailAddress",所以它的值被填充到Employee对象中。GSON 图像 小部件
  • GSON 序列化与反序列化使用说明

    前言学习使用Google GSON库将Java对象序列化为JSON表示形式,并将JSON字符串反序列化为等效的Java对象前言学习使用Google GSON库将Java对象序列化为JSON表示形式,并将JSON字符串反序列化为等效的Java对象。GSON提供简单的toJson()和fromJson()方法将Java对象转换为JSON,反之亦然。​GSON使用GsonBuilder创建Gson具有自定义配置的对象,例如漂亮的打印。//Gson gson = new Gson(); Gson gson = new GsonBuilder().setPrettyPrinting().create(); Employee emp = new Employee(1001, "Lokesh", "Gupta", "howtodoinjava@gmail.com"); String jsonString = gson.toJson(emp); Employee empObject = gson.fromJson(jsonString, Employee.class);1.依赖性Maven依赖。访问maven存储库以获取最新版本。$title(pom.xml) <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.8.5</version> </dependency>Gradle依赖。<dependency> dependencies { implementation 'com.google.code.gson:gson:2.8.5' }2.序列化 - 使用Gson编写JSONGson上下文中的序列化意味着将Java对象转换为其JSON表示。为了进行序列化,我们需要一个处理转换的Gson对象。接下来,我们需要调用函数toJson()并传递该Employee对象。Employee emp = new Employee(1001, "Lokesh", "Gupta", "howtodoinjava@gmail.com"); Gson gson = new Gson(); String jsonString = gson.toJson(emp); System.out.println(jsonString);程序输出:{ "id":1001, "firstName":"Lokesh", "lastName":"Gupta", "email":"howtodoinjava@gmail.com" }2.反序列化 - 使用Gson读取JSONGson上下文中的反序列化意味着将JSON字符串转换为等效的Java对象。为了进行反序列化,我们需要一个Gson对象并从json()调用函数并在解析完成后传递两个参数,即JSON字符串和期望的java类型。String jsonString = "{'id':1001, 'firstName':'Lokesh', 'lastName':'Gupta', 'email':'howtodoinjava@gmail.com'}"; Gson gson = new Gson(); Employee empObject = gson.fromJson(jsonString, Employee.class); System.out.println(empObject);程序输出:Employee [id=1001, firstName=Lokesh, lastName=Gupta, email=howtodoinjava@gmail.com]代码段 小部件
  • Gson JsonReader使用讲解

           学习使用Gson JsonReader类,这是一个基于拉的流式JSON解析器,它有助于将JSON作为标记流来读取​GSON1. JsonReader是什么JsonReader是流式JSON解析器和拉解析器的示例       学习使用Gson JsonReader类,这是一个基于拉的流式JSON解析器,它有助于将JSON作为标记流来读取​GSON1. JsonReader是什么JsonReader是流式JSON解析器和拉解析器的示例。推送解析器解析JSON令牌并将它们推送到事件处理程序中。它有助于将JSON(RFC 7159)编码值作为标记流读取。它读取文字值(字符串,数字,布尔值和空值)以及对象和数组的开始和结束分隔符。标记以深度优先顺序遍历,与它们在JSON文档中出现的顺序相同。2. Tokens在流模式下,每个JSON数据都被视为单个令牌。当我们用JsonReader它来处理它时,每个令牌将按顺序处理。例如,$title(Json Tokens) { "name":"Lokesh" } 在使用JsonReader进行解析时,上面的JSON将生成4个token:Token 1 = {Token 2 = nameToken 3 = LokeshToken 4 = }3.如何创建GSON JsonReader 我们可以JsonReader使用它接受java.io.Reader类型输入流的简单构造函数创建一个实例。$title(Create JsonReader) String json = "{}"; JsonReader jsonReader = new JsonReader( new StringReader(json) ); 我们可以根据JSON流的来源使用以下读者之一:BufferedReaderLineNumberReaderCharArrayReaderInputStreamReaderFileReaderFilterReaderPushbackReaderPipedReaderStringReader4.读取JSON Stream 在创建JsonReader包装有效的JSON源之后,我们可以开始迭代流令牌并查看令牌值。以下是在令牌上使用表单中的JsonReader读取简单JSON的示例。$title(JsonReader Example) import java.io.IOException; import java.io.StringReader; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonToken; public class Main { public static void main(String[] args) throws Exception { String json = "{'id': 1001,'firstName': 'Lokesh','lastName': 'Gupta','email': null}"; JsonReader jsonReader = new JsonReader(new StringReader(json)); jsonReader.setLenient(true); try { while (jsonReader.hasNext()) { JsonToken nextToken = jsonReader.peek(); if (JsonToken.BEGIN_OBJECT.equals(nextToken)) { jsonReader.beginObject(); } else if (JsonToken.NAME.equals(nextToken)) { String name = jsonReader.nextName(); System.out.println("Token KEY >>>> " + name); } else if (JsonToken.STRING.equals(nextToken)) { String value = jsonReader.nextString(); System.out.println("Token Value >>>> " + value); } else if (JsonToken.NUMBER.equals(nextToken)) { long value = jsonReader.nextLong(); System.out.println("Token Value >>>> " + value); } else if (JsonToken.NULL.equals(nextToken)) { jsonReader.nextNull(); System.out.println("Token Value >>>> null"); } else if (JsonToken.END_OBJECT.equals(nextToken)) { jsonReader.endObject(); } } } catch (IOException e) { e.printStackTrace(); } finally { jsonReader.close(); } } } 执行输出:Token KEY >>>> id Token Value >>>> 1001 Token KEY >>>> firstName Token Value >>>> Lokesh Token KEY >>>> lastName Token Value >>>> Gupta Token KEY >>>> email Token Value >>>> null 在上面的例子中:令牌的键是JsonToken.NAME类型。使用nextName()方法获取密钥名称。如果hasNext()方法JsonReader有更多的标记,则返回true 的hasNext()方法。的PEEK()方法返回下一个令牌JSON,但不移动在它。对peek()随后的多次调用将返回相同的JSON令牌。可以使用JsonToken类的常量检查返回标记的类型。Array的开启和关闭括号'[',并']'与检查beginArray()和endArray()方法。Object的开始和结束括号'{','}'并使用beginObject()和endObject()方法进行检查。确定令牌的类型后,获得令牌的使用方法的类似的值nextLong(),nextString(),nextInt()等。空文字可以使用任何消耗nextNull()或skipValue()。所有next....()方法都返回当前标记的值,并将内部指针移动到下一个标记。遇到未知名称时,严格的解析器应该失败并出现异常。宽松解析器应该调用skipValue()以递归方式跳过值的嵌套标记,否则可能会发生冲突。
  • GSON 将JSON数组解析为Java数组或集合(List)

    前言值得一提的是JSON只有数组数据类型前言值得一提的是JSON只有数组数据类型。Java同时具有 - 数组和列表。学习使用Google GSON库将包含json数组的JSON反序列化或解析为java 数组或java列表对象。​GSON1.将JSON数组解析为根对象$title(user.json) [ { "name": "Alex", "id": 1 }, { "name": "Brian", "id": 2 }, { "name": "Charles", "id": 3 } ]$title(user.java) public class User { private long id; private String name; public long getId() { return id; } public void setId(long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "User [id=" + id + ", name=" + name + "]"; } }1.1。对象数组用于将json数组反序列化为root的 Java程序- 对象的Java数组。String userJson = "[{'name': 'Alex','id': 1}, " + "{'name': 'Brian','id':2}, " + "{'name': 'Charles','id': 3}]"; Gson gson = new Gson(); User[] userArray = gson.fromJson(userJson, User[].class); for(User user : userArray) { System.out.println(user); }输出:User [id=1, name=Alex] User [id=2, name=Brian] User [id=3, name=Charles]1.2。对象列表用于将json数组反序列化为root的 Java程序- 到Java对象列表。import java.lang.reflect.Type; import java.util.ArrayList; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; String userJson = "[{'name': 'Alex','id': 1}, " + "{'name': 'Brian','id':2}, " + "{'name': 'Charles','id': 3}]"; Gson gson = new Gson(); Type userListType = new TypeToken<ArrayList<User>>(){}.getType(); ArrayList<User> userArray = gson.fromJson(userJson, userListType); for(User user : userArray) { System.out.println(user); }输出:User [id=1, name=Alex] User [id=2, name=Brian] User [id=3, name=Charles]2.将JSON数组解析为成员如果JSON数组是非根对象,它们会毫无困难地将JSON数组解析为成员。我们可以fromJson()以通常的方式使用该方法,它将正确地将json数组解析为所需的java数组或列表。$title(department.json) { "id" : 1, "name" : "HR", "users" : [ { "name": "Alex", "id": 1 }, { "name": "Brian", "id": 2 }, { "name": "Charles", "id": 3 } ]2.1。成员数组将json数组反序列化为成员对象的 Java程序- 作为成员字段的Java对象数组。$title(Department.java) public class Department { private long id; private String name; private User[] users; //Getters and Setters @Override public String toString() { return "Department [id=" + id + ", name=" + name + ", users=" + Arrays.toString(users) + "]"; } }demoString departmentJson = "{'id' : 1, " + "'name': 'HR'," + "'users' : [" + "{'name': 'Alex','id': 1}, " + "{'name': 'Brian','id':2}, " + "{'name': 'Charles','id': 3}]}"; Gson gson = new Gson(); Department department = gson.fromJson(departmentJson, Department.class); System.out.println(department);输出:Department [id=1, name=HR, users=[User [id=1, name=Alex], User [id=2, name=Brian], User [id=3, name=Charles]]]2.2。会员名单Java程序将json数组反序列化为成员对象 - 将Java对象列为成员字段。public class Department { private long id; private String name; private List<User> users; //Getters and Setters @Override public String toString() { return "Department [id=" + id + ", name=" + name + ", users=" + users + "]"; } }String departmentJson = "{'id' : 1, " + "'name': 'HR'," + "'users' : [" + "{'name': 'Alex','id': 1}, " + "{'name': 'Brian','id':2}, " + "{'name': 'Charles','id': 3}]}"; Gson gson = new Gson(); Department department = gson.fromJson(departmentJson, Department.class); System.out.println(department);输出:Department [id=1, name=HR, users=[User [id=1, name=Alex], User [id=2, name=Brian], User [id=3, name=Charles]]]​​​​​​​
  • retrofit2使用详解之入门

    前言       在本教程中,我们将了解Retrofit 的基础知识以和创建一个android HTTP client请求REST API前言       在本教程中,我们将了解Retrofit 的基础知识以和创建一个android HTTP client请求REST API。 1. Retrofit是什么?Retrofit是一个类型安全的REST客户端,适用于android和Java开发应用。Retrofit可将HTTP 网络接口转换为Java接口。Retrofit android 版使用非常简单。它本质上允许我们将API调用视为简单的Java方法调用,因此我们只定义要访问的URL和请求/响应参数的类型作为Java类。整个网络调用+ JSON / XML解析完全由Retrofit处理(例如Gson用于JSON解析)。它允许向远程Web服务器发出同步或异步HTTP请求。2. Retrofit 安装 我们的项目中要使用Retrofit 2,我们将在构建文件中包含以下依赖项。在本教程中,我们将以JSON格式发送和接收数据,因此我们也添加了converter-gson依赖项。maven 方式:$title(pom.xml) <dependency> <groupId>com.squareup.retrofit2</groupId> <artifactId>retrofit</artifactId> <version>2.6.1</version> </dependency> <dependency> <groupId>com.squareup.retrofit2</groupId> <artifactId>converter-gson</artifactId> <version>2.6.1</version> </dependency> gradle 方式:$title(build.gradle) dependencies { compile 'com.squareup.retrofit2:retrofit:2.6.1' compile 'com.squareup.retrofit2:converter-gson:2.6.1' } 在Android应用程序中,我们必须启用Internet权限,因为Retrofit会对Internet上某个服务器上运行的API执行HTTP请求。$title(AndroidManifest.xml) <uses-permission android:name="android.permission.INTERNET"></uses-permission>3. REST API建模3.1. REST API 接口 使用Retrofit的下一步是对REST API建模,我们将会在应用程序中使用它。下面举例说明有一个这样的API可以免费使用HTTP GET https://reqres.in/api/users/2 Response: { "data": { "id": 2, "email": "janet.weaver@reqres.in", "first_name": "Janet", "last_name": "Weaver", "avatar": "https://s3.amazonaws.com/uifaces /faces/twitter/josephstein/128.jpg" } }3.2. 业务数据模型假设我们只需要消费id,姓名和电子邮件字段,而不想使用头像字段。字段数量不匹配,Gson转换器并不会报错,他会解析我们模型中指定的字段。(国内的fastjson也一样效果)$title(UserApiResponse.java) public class UserApiResponse { private User data; //Setters and getters public String toString() { return "UserApiResponse [data=" + data + "]"; } }$title(User.java) public class User { private long id; private String first_name; private String last_name; private String email; //Setters and getters @Override public String toString() { return "User [id=" + id + ", " + "first_name=" + first_name + ", " + "last_name=" + last_name + ", " + "email=" + email + "]"; } }3.3. 业务接口 现在,我们可以使用Retrofit注解来创建具有所需映射信息和请求/响应类的服务接口。$title(UserService.java) import retrofit2.Call; import retrofit2.http.GET; import retrofit2.http.Path; public interface UserService { @GET("/api/users/{id}") public Call<UserApiResponse> getUser(@Path("id") long id); }我们可以使用适当的改造注释为每个HTTP方法:@GET,@POST,@PUT,@DELETE,@PATCH或@HEAD。在方法注释中,我们应该指定REST资源的相对端点URL。在这种情况下,它是 - "/api/users/{id}"。在方法声明中,我们必须将服务器所期望的数据返回到一个类型化的Retrofit Call< >类中。在方法参数中,我们可以传递路径和查询参数,并在PUT / POST请求中请求正文。4. Retrofit 2 实际使用 现在是时候使用create Retrofit REST客户端并进行实际的API调用。在这个例子中,我们使用流畅的API与Retrofit.Builder和OkHttpClient来创建Retrofit实例。我们提供API和转换器类型的基本URL。$title(UserServiceClient.java) import okhttp3.OkHttpClient; import retrofit2.Call; import retrofit2.Response; import retrofit2.Retrofit; import retrofit2.converter.gson.GsonConverterFactory; $title(UserServiceClient.java) public class UserServiceClient { public static void main(String[] args) { OkHttpClient.Builder httpClient = new OkHttpClient.Builder(); Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://reqres.in/") .addConverterFactory(GsonConverterFactory.create()) .client(httpClient.build()) .build(); UserService service = retrofit.create(UserService.class); // Calling '/api/users/2' Call<UserApiResponse> callSync = service.getUser(2); try { Response<UserApiResponse> response = callSync.execute(); UserApiResponse apiResponse = response.body(); System.out.println(apiResponse); } catch (Exception ex) { ex.printStackTrace(); } } } 运行上面的程序,观察控制台中打印的输出。$title(out) UserApiResponse [data=User [ id=2, first_name=Janet, last_name=Weaver, email=janet.weaver@reqres.in]] 在上面的例子中,我们已经进行了同步请求。我们将在接下来的教程中会讲解异步请求。总结在本教程中,我们了解了Retrofit 2并为REST客户端构建了一个使用JSON有效负载的hello world应用程序。我们还了解了Retrofit库的基础知识。
  • Java通过sourceafis比对指纹图片的相似度判断指纹

    Java通过sourceafis比对指纹图片的相似度判断指纹,sourceafis,Java指纹图片<h2>什么是SourceAFIS?</h2> <p>SourceAFIS是一种指纹识别引擎,可以获取一对人类的指纹图像并返回其相似性分数。 它可以进行1:1的比较以及高效的1:N搜索。 这是SourceAFIS算法的Java实现</p> <h2>1.maven环境依赖引入</h2> <pre> <code class="language-xml"> <!-- https://mvnrepository.com/artifact/com.machinezoo.sourceafis/sourceafis --> <dependency> <groupId>com.machinezoo.sourceafis</groupId> <artifactId>sourceafis</artifactId> <version>2.0.11</version> </dependency></code></pre> 不用maven的可以通过上方注释的地址去下载,注意依赖gson.jar <h2>2.Java通过sourceafis比对指纹图片</h2> <pre> <code class="language-java">package com.example.fingerprint; import java.nio.file.Files; import java.nio.file.Paths; import com.machinezoo.sourceafis.FingerprintMatcher; import com.machinezoo.sourceafis.FingerprintTemplate; /** * 通过三方库实现指纹识别对比 * * @author xq * */ public class Test { public static void main(String[] args) { try { //首先是读取两张对比的指纹图片,图片必须是白色背景,指纹为黑色 byte[] probeImage = Files.readAllBytes(Paths.get("d://fp//da1.png")); byte[] candidateImage = Files.readAllBytes(Paths.get("d://fp//da2.png")); FingerprintTemplate probe = new FingerprintTemplate(probeImage); // 由于直接从二进制中生成指纹模板非常消耗性能,推荐第一次使用后序列话成JSON,内部提供方法。再通过json生成模板 // String jsonTemplete=probe.json(); // probe=new FingerprintTemplate(jsonTemplete); FingerprintTemplate candidate = new FingerprintTemplate(candidateImage); FingerprintMatcher matcher = new FingerprintMatcher(probe); double score = matcher.match(candidate); System.out.println("匹配得分:" + score); boolean match = score >= 40; System.out.println("是否匹配:" + match); } catch (Exception e) { e.printStackTrace(); } } } </code></pre> <h2>3.1:N操作</h2> 假设我们要比较一下刚刚从指纹读取器读取的探针指纹与已经存储在数据库中的多个候选指纹。 数据库通常是磁盘,但是指纹数据库必须是内存,因为探针指纹必须与每个候选指纹进行比较。<br /> 以1:N匹配,返回匹配得分已经不够了。 我们需要识别指纹匹配的用户,也许是通过描述用户的类来识别。 <pre> <code class="language-java">public class UserDetails { int id; String name; FingerprintTemplate template; }</code></pre> 我们现在可以定义一种方法,它可以获取探针指纹和候选指纹列表,并返回最佳匹配,如果不匹配则返回null。 <pre> <code class="language-java">UserDetails find(FingerprintTemplate probe, Iterable<UserDetails> candidates) { FingerprintMatcher matcher = new FingerprintMatcher(probe); UserDetails bestCandidate = null; double bestScore = 0; for (UserDetails candidate : candidates) { double score = matcher.match(candidate.template); if (score > bestScore) { bestScore = score; bestCandidate = candidate; } } double threshold = 40; return bestScore >= threshold ? bestCandidate : null; }</code></pre> 构造FingerprintMatcher只需要一次,因为这是一个昂贵的操作。 FingerprintMatcher构建内存数据结构,加快匹配。 个人电话匹配方法相对较快。<br /> <br /> 您可能会想知道为什么SourceAFIS不会在API中提供这样的搜索方法。 除了更容易将模板与应用程序定义的用户身份相关联,保持应用程序侧的搜索循环允许应用程序自定义循环。 此类定制的示例包括:<br /> <br /> 并行策略,<br /> 人口过滤,例如只搜索男性,<br /> 手指位置过滤,例如将右拇指仅匹配到右拇指,<br /> 多指搜索,例如要求左索引和右食指匹配,以及<br /> 多视图搜索,为每个用户保留同一个手指的多个模板,以提高识别率。 <h2>4.除了匹配器比较耗资源通过二进制流创建指纹模板其实也很消耗资源,如何缓存?</h2> 每次应用程序重新启动时,从原始指纹图像重新创建数据库中的所有指纹模板是不合理的。 因此,SourceAFIS提供了缓存指纹模板的方法。 <pre> <code class="language-java">byte[] image = Files.readAllBytes(Paths.get("fingerprint.jpeg")); FingerprintTemplate template = new FingerprintTemplate(image); String json = template.json();</code></pre> 模板的JSON表示可以存储在数据库中,以加快应用程序的重新启动。 当应用程序启动时,它反序列化JSON模板,而不是从指纹图像中重新创建它们。 <pre> <code class="language-java">FingerprintTemplate template = new FingerprintTemplate(json);</code></pre> JSON模板不能代替指纹图像。 它们被绑定到特定的SourceAFIS版本。 为了允许SourceAFIS升级,应用程序应始终存储原始指纹图像,并将JSON模板视为临时缓存。 <h2> </h2>
  • Java EE 8最受关注的新特性或者说最重要的新特性

    备受期待的Java Enterprise Edition 8发布了两个令人兴奋的新API(JSON-Binding 1.0和Java EE Security 1.0)并改进了当前的API(JAX-RS 2.1,Bean Validation 2.0,JSF 2.3,CDI 2.0,JSON-P 1.1,JPA 2.2和Servlet 4.0)。这是Oracle企业Java平台近四年来的第一个版本,它包含数百个新功能,更新的功能和错误修复。那么最好的新功能是什么?<h2>前言</h2> <blockquote> <p>    备受期待的Java Enterprise Edition 8发布了两个令人兴奋的新API(JSON-Binding 1.0和Java EE Security 1.0)并改进了当前的API(JAX-RS 2.1,Bean Validation 2.0,JSF 2.3,CDI 2.0,JSON-P 1.1,JPA 2.2和Servlet 4.0)。这是Oracle企业Java平台近四年来的第一个版本,它包含数百个新功能,更新的功能和错误修复。那么最好的新功能是什么?</p> </blockquote> <h2 style="margin-left:0px; margin-right:0px; text-align:start">前5个新功能</h2> <ul> <li><strong>新的安全API:注释驱动的身份验证机制</strong></li> </ul> 全新的安全API包含三项出色的新功能:身份库抽象,新的安全上下文以及新的注释驱动的身份验证机制,这些机制会使web.xml文件声明过时。最后一个是我今天要讨论的内容。 <ul> <li><strong>JAX-RS 2.1:新的被动式客户</strong></li> </ul> 端JAX-RS 2.1中的新型被动式客户端,采用反应式编程风格并允许组合端点结果。 <ul> <li><strong>新的JSON绑定API</strong></li> </ul> 新的JSON绑定API,为JSON序列化和反序列化提供本机Java EE解决方案。 <ul> <li><strong>CDI 2.0:在Java SE中使用CDI 2.0中</strong></li> </ul> 有趣的新功能允许在Java SE应用程序中引导CDI。 <ul> <li><strong>Servlet 4.0:服务器推送Servlet 4.0中</strong></li> </ul> 的服务器推送功能将servlet规范与HTTP / 2对齐。<br />   <h2 style="margin-left:0px; margin-right:0px; text-align:start">1.新的安全API</h2> 有可能添加到Java EE 8中的最重要的新功能是新的安全API。这个新API的主要动机是简化,标准化和现代化跨容器和实现处理安全问题的方式。 <p style="text-align:start"><span style="color:#333333"><span style="font-family:Tahoma,Arial,Verdana,sans-serif"><span style="background-color:#ffffff">Web认证<strong>的配置</strong>已经实现了现代化,这要归功于三个使web.xml文件声明成为冗余的新注释。稍后再说。</span></span></span></p> <p style="text-align:start"><span style="color:#333333"><span style="font-family:Tahoma,Arial,Verdana,sans-serif"><span style="background-color:#ffffff"><strong>新的安全上下文</strong> API标准化了servlet和EJB容器执行身份验证的方式</span></span></span></p> <p style="text-align:start"><span style="color:#333333"><span style="font-family:Tahoma,Arial,Verdana,sans-serif"><span style="background-color:#ffffff"><strong>新的Identity</strong>存储抽象简化了身份存储的使用。</span></span></span></p> <p style="text-align:start"><span style="color:#333333"><span style="font-family:Tahoma,Arial,Verdana,sans-serif"><span style="background-color:#ffffff">所以我们来看看这些新增的第一个。</span></span></span></p> <h3 style="margin-left:0px; margin-right:0px; text-align:start">注释驱动的认证机制</h3> <p style="text-align:start"><span style="color:#333333"><span style="font-family:Tahoma,Arial,Verdana,sans-serif"><span style="background-color:#ffffff">此功能全部是关于配置网络安全。web.xml文件中的哪个传统所需的XML声明。</span></span></span><br />  </p> <p style="text-align:start"><span style="color:#333333"><span style="font-family:Tahoma,Arial,Verdana,sans-serif"><span style="background-color:#ffffff">由于<em>HttpAuthenticationMechanism</em>接口代表了HTTP身份验证,并且随附了三个内置的启用CDI的实现,这些实现代表了网络安全可以配置的三种方式之一,这已不再是必需的。</span></span></span></p> <p style="text-align:start"><span style="color:#333333"><span style="font-family:Tahoma,Arial,Verdana,sans-serif"><span style="background-color:#ffffff">他们触发使用这些注释之一。</span></span></span></p> <pre> <code class="language-java">@BasicAuthenticationMechanismDefinition @FormAuthenticationMechanismDefinition @CustomFormAuthenticationMechanismDefinition</code></pre> <p style="text-align:start"><span style="color:#333333"><span style="font-family:Tahoma,Arial,Verdana,sans-serif"><span style="background-color:#ffffff">它们替换了servlet容器中已有的传统HTTP基本认证,基于表单和自定义表单的认证功能已经在servlet容器中了。</span></span></span></p> <p style="text-align:start"><span style="color:#333333"><span style="font-family:Tahoma,Arial,Verdana,sans-serif"><span style="background-color:#ffffff">例如,要启用基本身份验证,所需做的一切就是将@<em>BasicAuthenticationMechanismDefinition</em>注释添加到您的servlet,就像下面这样。</span></span></span></p> <pre> <code class="language-java">@BasicAuthenticationMechanismDefinition(realmName="${'user-realm'}") @WebServlet("/user") @DeclareRoles({ "admin", "user", "demo" }) @ServletSecurity(@HttpConstraint(rolesAllowed = "user")) public class UserServlet extends HttpServlet { //其他代码 }</code></pre> <p style="text-align:start">现在,您可以舍弃XML配置,并使用其中一个新注释来启用网络安全。<br /> <br />  </p> <h2 style="margin-left:0px; margin-right:0px; text-align:start">2. JAX-RS 2.1:新的反应客户端</h2> <p style="text-align:start"><span style="color:#333333"><span style="font-family:Tahoma,Arial,Verdana,sans-serif"><span style="background-color:#ffffff">我们来看看JAX-RS 2.1中新的被动客户端以及它如何采用反应式编程风格。</span></span></span></p> <p style="text-align:start"><span style="color:#333333"><span style="font-family:Tahoma,Arial,Verdana,sans-serif"><span style="background-color:#ffffff">被动方法的核心是<strong>数据流</strong>的概念,其中执行模型通过流传播更改。一个典型的例子是JAX-RS方法调用。当调用返回时,将对方法调用的结果执行下一个操作(可能是继续,完成或错误)。</span></span></span></p> <p style="text-align:start"><span style="color:#333333"><span style="font-family:Tahoma,Arial,Verdana,sans-serif"><span style="background-color:#ffffff">您可以将其视为<strong>异步流程</strong>的流程,下一个流程将根据前一个流程的结果进行操作,然后将流程结果传递给链中的下一个流程。数据流是<strong>可组合的,</strong>因此您可以将许多流合并并转换为一个结果。</span></span></span></p> <p style="text-align:start"><span style="color:#333333"><span style="font-family:Tahoma,Arial,Verdana,sans-serif"><span style="background-color:#ffffff">通过<em>调用</em>用于构造客户端实例的<em>Invocation.Builder</em>实例上的<em>rx()</em>方法来启用反应性功能。它的返回类型是<strong>具有参数化</strong><strong><em>响应</em></strong><strong>类型</strong>的<strong><em>CompletionStage</em></strong>。该<em>CompletionStage</em>接口是用Java 8中引入,并提出了一些有趣的可能性。</span></span></span></p> <p style="text-align:start"><span style="color:#333333"><span style="font-family:Tahoma,Arial,Verdana,sans-serif"><span style="background-color:#ffffff">例如,在这个代码片段中,两个调用是对不同的端点进行的,然后将结果合并:</span></span></span></p> <pre> <code class="language-java">CompletionStage<Response> cs1 = ClientBuilder.newClient() .target(".../books/history") .request() .rx() .get(); CompletionStage<Response> cs2 = ClientBuilder.newClient() .target(".../books/geology") .request() .rx() .get(); cs1.thenCombine(cs2, (r1, r2) -> r1.readEntity(String.class) + r2.readEntity(String.class)) .thenAccept(System.out::println);</code></pre> <h2 style="margin-left:0px; margin-right:0px; text-align:start">3.新的JSON绑定API</h2> <p style="text-align:start"><span style="color:#333333"><span style="font-family:Tahoma,Arial,Verdana,sans-serif"><span style="background-color:#ffffff">现在我们来看看下一个伟大的功能。新的JSON绑定API,此API为<strong>JSON序列化和反序列化</strong>提供<strong>了原生Java EE解决方案</strong>。</span></span></span></p> <p style="text-align:start"><span style="color:#333333"><span style="font-family:Tahoma,Arial,Verdana,sans-serif"><span style="background-color:#ffffff">以前,如果您想要将JSON序列化和反序列化,则必须依赖Jackson或GSON等第三方API。不再。使用新的JSON绑定API,您可以使用本地可用的所有功能。</span></span></span></p> <p style="text-align:start"><span style="color:#333333"><span style="font-family:Tahoma,Arial,Verdana,sans-serif"><span style="background-color:#ffffff">从Java对象生成JSON文档并不那么简单。只需调用<em>toJson()</em>方法并将它传递给想要序列化的实例即可。</span></span></span></p> <pre> <code class="language-java">String bookJson = JsonbBuilder.create().toJson(book); </code></pre> <h3 style="margin-left:0px; margin-right:0px; text-align:start">行为定制</h3> <p style="text-align:start"><span style="color:#333333"><span style="font-family:Tahoma,Arial,Verdana,sans-serif"><span style="background-color:#ffffff">可以通过注释字段,JavaBean方法和类来自定义默认的序列化和反序列化行为。</span></span></span></p> <p style="text-align:start"><span style="color:#333333"><span style="font-family:Tahoma,Arial,Verdana,sans-serif"><span style="background-color:#ffffff">例如,您可以使用<em>@JsonbNillable</em>来自定义空处理和<em>@JsonbPropertyOrder</em>注释来自定义您在类级别指定的属性顺序。你可以指定与数字格式<em>@JsonbNumberFormat()</em>注解,并与更改字段的名称<em>@JsonbProperty()</em>注释。</span></span></span></p> <pre> <code class="language-java">@JsonbNillable @JsonbPropertyOrder(PropertyOrderStrategy.REVERSE) public class Booklet { @JsonbProperty("cost") @JsonbNumberFormat("#0.00") private Float price; }</code></pre> 或者,您可以选择使用运行时配置构建器<em>JsonbConfig</em>处理自定义: <pre> <code class="language-java">JsonbConfig jsonbConfig = new JsonbConfig() .withPropertyNamingStrategy(PropertyNamingStrategy.LOWER_CASE_WITH_DASHES) .withNullValues(true) .withFormatting(true); Jsonb jsonb = JsonbBuilder.create(jsonbConfig);</code></pre> 无论哪种方式,JSON绑定API都为Java对象的序列化和反序列化提供了广泛的功能。 <h2 style="margin-left:0px; margin-right:0px; text-align:start">4. CDI 2.0:在Java SE中使用</h2> <p style="text-align:start"><span style="color:#333333"><span style="font-family:Tahoma,Arial,Verdana,sans-serif"><span style="background-color:#ffffff">现在让我们继续看下一个API。CDI 2.0 API。该版本拥有许多新功能,其中一个更有趣的功能是<strong>在Java SE应用程序中引导CDI</strong>的功能。</span></span></span></p> <p style="text-align:start"><span style="color:#333333"><span style="font-family:Tahoma,Arial,Verdana,sans-serif"><span style="background-color:#ffffff">要在Java SE中使用CDI,必须明确引导CDI容器。这是通过调用<strong><em>SeContainerInitializer</em></strong><strong>抽象类</strong>的<strong>静态方法  </strong><strong><em>newInstance()</em></strong><strong>来实现的</strong>。它返回一个<em>SeContainer</em>实例,该实例是CDI运行时的句柄,您可以使用该句柄执行CDI解析,如此代码片段中所示。它可以访问作为CDI核心入口点的BeanManager。</span></span></span><br />  </p> <pre> <code class="language-java">SeContainer seContainer = SeContainerInitializer.newInstance().initialize(); Greeting greeting = seContainer.select(Greeting.class).get(); greeting.printMessage("Hello World"); seContainer.close();</code></pre> 使用<em>select()</em>方法检索CDI bean,方法是传递要检索和使用的bean的类名称。 <h3 style="margin-left:0px; margin-right:0px; text-align:start">配置选项</h3> <p style="text-align:start"><span style="color:#333333"><span style="font-family:Tahoma,Arial,Verdana,sans-serif"><span style="background-color:#ffffff">可以通过添加拦截器,扩展,替代方法,属性和装饰器来<strong>进一步配置</strong><em>SeContext</em>。</span></span></span></p> <pre> <code class="language-java">.enableInterceptors() .addExtensions() .selectAlternatives() .setProperties() .enableDecorators()</code></pre> 通过在<em>SeContainer</em>上调用<em>close()</em>方法手动关闭容器,或者在使用<em>Try  </em><em>-with-resources</em>结构时自动关闭容器,因为<em>SeContainer</em>  扩展了<em>AutoCloseable</em>  接口。 <h2 style="margin-left:0px; margin-right:0px; text-align:start">5. Servlet 4.0:服务器推送</h2> <p style="text-align:start"><span style="color:#333333"><span style="font-family:Tahoma,Arial,Verdana,sans-serif"><span style="background-color:#ffffff">最后但并非最不重要的一点是,Servlet 4.0中的服务器推送功能使servlet规范与HTTP / 2保持一致。</span></span></span></p> <p style="text-align:start"><span style="color:#333333"><span style="font-family:Tahoma,Arial,Verdana,sans-serif"><span style="background-color:#ffffff">要理解此功能,您首先需要知道服务器推送的内容。</span></span></span></p> <h3 style="margin-left:0px; margin-right:0px; text-align:start">什么是服务器推送?</h3> <p style="text-align:start"><span style="color:#333333"><span style="font-family:Tahoma,Arial,Verdana,sans-serif"><span style="background-color:#ffffff">服务器推送是HTTP / 2协议中的许多新功能之一,旨在通过将这些资源推送到浏览器的缓存中来预测客户端资源需求,以便当客户端发送网页请求并接收到响应时从服务器,它需要的资源已经在缓存中。这是一项提高网页加载速度的性能增强功能。</span></span></span></p> <h3 style="margin-left:0px; margin-right:0px; text-align:start">它如何在Servlet 4.0中公开?</h3> <p style="text-align:start"><span style="color:#333333"><span style="font-family:Tahoma,Arial,Verdana,sans-serif"><span style="background-color:#ffffff">在Servlet 4.0中,<strong>Server Push功能通过</strong>从<em>HttpServletRequest</em>实例获得<strong>的</strong><strong><em>PushBuilder</em></strong><strong>实例</strong><strong>公开</strong>。</span></span></span></p> <p style="text-align:start"><span style="color:#333333"><span style="font-family:Tahoma,Arial,Verdana,sans-serif"><span style="background-color:#ffffff">看看这段代码片段。您可以看到,通过<em>path()</em>方法在<em>PushBuilder</em>实例上设置了<em>header.png</em>的<em>路径</em>,并通过调用<em>push()</em>将其推送到客户端。当方法返回时,路径和条件头部将被清除,以便构建器重用。该<em>menu.css</em>文件推,然后<em>ajax.js</em> javascript文件推送到客户端。</span></span></span></p> <pre> <code class="language-java">protected void doGet(HttpServletRequest request, HttpServletResponse response) { PushBuilder pushBuilder = request.newPushBuilder(); pushBuilder.path("images/header.png").push(); pushBuilder.path("css/menu.css").push(); pushBuilder.path("js/ajax.js").push(); // Return JSP that requires these resources }</code></pre> 在Servlet <em>doGet()</em>方法完成执行时,资源将到达浏览器。从JSP生成的需要这些资源的HTML不需要从服务器请求它们,因为它们已经是浏览器缓存。<br />