Android/Java中使用Protobuf的Any类型实现泛型解析
上一篇博客中只講解到了簡單的使用protobuf,還不會的可以先去看一下【Android項目使用Protobuf教程(結合Retrofit+RxJava及HttpURLConnection使用)】,有位小伙伴問我如何使用泛型呢?
比如每次網絡請求都會有一些公共字段和可變參數,如下:
請尊重原創,轉載需要注明出處,大力哥的博客:https://blog.csdn.net/qq137722697
{
code:0
msg:"登錄成功"
data:{
? ? ? ? ResultResponse
? ? }
}
1
2
3
4
5
6
7
即code和msg是公共字段,每次都會返回;data為具體的業務請求所返回的響應結果。如果按照之前的介紹,可能每一個接口都需要對應一個帶有code、msg的proto文件,對應的每個Response都帶有code和msg,能不能實現泛型呢?答案是肯定的
proto文件的定義
LoginRequest.proto
syntax = "proto3";
//需要導入any.proto文件才可實現泛型
import "google/protobuf/any.proto";
//生成的java類所在的包名
package com.zhys.protobufdemo.protobean;
//登錄請求結構體
message LoginRequest {
? ? string username = 1;
? ? string pwd = 2;
}
//網絡請求的響應體
message HttpResultResponse {
? ? int32 code = 1;
? ? string msg = 2;
? ? google.protobuf.Any data = 3;
}
//登陸結果(也可以單獨定義一個proto文件)
message LoginResult {
? ? string username = 1;
? ? string phone = 2;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
此處的定義也沒有什么特別注意的地方,只需要使用google.protobuf.Any(需要import “google/protobuf/any.proto”;)聲明可變參數data即可;此時通過Clean Project即可生成對應的java類(此處叫LoginRequestOuterClass),拷出備用
服務端處理【可選,Android開發可忽略此步驟】
//次注解需要tomcat7及以上不能才可以運行
@WebServlet("/login.action")
public class LoginServlet extends HttpServlet {
? ? @Override
? ? protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
? ? ? ? doPost(request, response);
? ? }
? ? @Override
? ? protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
? ? ? ? System.out.println("請求登陸了");
? ? ? ? request.setCharacterEncoding("utf-8");
? ? ? ? response.setCharacterEncoding("utf-8");
? ? ? ? LoginRequestOuterClass.LoginRequest loginRequest = LoginRequestOuterClass.LoginRequest.parseFrom(request.getInputStream());
? ? ? ? System.out.println("登陸信息:username = " + loginRequest.getUsername() + "\tpwd = " + loginRequest.getPwd());
? ? ? ? LoginRequestOuterClass.HttpResultResponse.Builder builder = LoginRequestOuterClass.HttpResultResponse.newBuilder();
? ? ? ? if ("admin".equals(loginRequest.getUsername()) && "132".equals(loginRequest.getPwd())) {
? ? ? ? ? ? builder.setCode(0);
? ? ? ? ? ? builder.setMsg("登陸成功");
? ? ? ? ? ? LoginRequestOuterClass.LoginResult loginResult = LoginRequestOuterClass.LoginResult.newBuilder().setPhone("15519099928").setUsername("大力哥的博客").build();
? ? ? ? ? ? builder.setData(Any.pack(loginResult));//使用Any.pack()方法將泛型類
? ? ? ? ? ? System.out.println("登陸成功");
? ? ? ? } else {
? ? ? ? ? ? builder.setCode(1001);
? ? ? ? ? ? builder.setMsg("用戶名或密碼錯誤");
? ? ? ? ? ? System.out.println("用戶名或密碼錯誤");
? ? ? ? }
? ? ? ? builder.build().writeTo(response.getOutputStream());
? ? }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
此處跟上一篇的教程區別也不大,setData的時候需要傳入泛型類,只需要通過Any.pack(泛型類)即可
APP端處理
HttpURLConnection處理
/**
?* 開始登錄(基于HttpURLConnection)
?*
?* @param data
?*/
public void login(final byte[] data) {
? ? new Thread() {
? ? ? ? @Override
? ? ? ? public void run() {
? ? ? ? ? ? OutputStream os = null;
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? URL url = new URL("http://192.168.0.227:8080/protobuf/login.action");
? ? ? ? ? ? ? ? HttpURLConnection conn = (HttpURLConnection) url.openConnection();
? ? ? ? ? ? ? ? conn.setRequestMethod("POST");
? ? ? ? ? ? ? ? os = conn.getOutputStream();
? ? ? ? ? ? ? ? os.write(data);
? ? ? ? ? ? ? ? if (conn.getResponseCode() == 200) {
? ? ? ? ? ? ? ? ? ? //解析結果
? ? ? ? ? ? ? ? ? ? final LoginRequestOuterClass.HttpResultResponse loginResponse = LoginRequestOuterClass.HttpResultResponse.parseFrom(conn.getInputStream());
? ? ? ? ? ? ? ? ? ? if (loginResponse.getCode()==0) {//登陸成功之后才會有登陸結果
? ? ? ? ? ? ? ? ? ? ? ? LoginRequestOuterClass.LoginResult loginResult = loginResponse.getData().unpack(LoginRequestOuterClass.LoginResult.class);
? ? ? ? ? ? ? ? ? ? ? ? ELog.e("登陸結果:code = " + loginResponse.getCode() + "\tmsg = " + loginResponse.getMsg()+"\tusername = "+loginResult.getUsername()+"\tphone = "+loginResult.getPhone());
? ? ? ? ? ? ? ? ? ? }else {
? ? ? ? ? ? ? ? ? ? ? ? ELog.e("登陸失敗信息:code = " + loginResponse.getCode() + "\tmsg = " + loginResponse.getMsg());
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? runOnUiThread(new Runnable() {
? ? ? ? ? ? ? ? ? ? ? ? @Override
? ? ? ? ? ? ? ? ? ? ? ? public void run() {
? ? ? ? ? ? ? ? ? ? ? ? ? ? Toast.makeText(MainActivity.this, loginResponse.getMsg(), Toast.LENGTH_SHORT).show();
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? });
? ? ? ? ? ? ? ? }
? ? ? ? ? ? } catch (MalformedURLException e) {
? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? } finally {
? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? if (os != null) {
? ? ? ? ? ? ? ? ? ? ? ? os.close();
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? runOnUiThread(new Runnable() {
? ? ? ? ? ? ? ? @Override
? ? ? ? ? ? ? ? public void run() {
? ? ? ? ? ? ? ? ? ? progressDialog.dismiss();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? });
? ? ? ? }
? ? }.start();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
只需要使用getData().unpack(泛型類.java)即可拿到對應的泛型類,此處需要注意的是protobuf解析不像Gson解析那么強大,缺少參數會拋出以下異常
?com.google.protobuf.InvalidProtocolBufferException: Type of the Any message does not match the given class.
?at com.google.protobuf.Any.unpack(Any.java:208)
1
2
Retrofit+RxJava處理
/**
?* 登錄
?*
?* @param view
?*/
public void onLogin(View view) {
? ? progressDialog.show();
? ? String username = etUsername.getText().toString().trim();
? ? String pwd = etPwd.getText().toString().trim();
? ? //開始請求
? ? HttpSend.getInstance().login(username,pwd, new ResultCallbackListener<LoginRequestOuterClass.HttpResultResponse>() {
? ? ? ? @Override
? ? ? ? public void onSubscribe(Disposable d) {
? ? ? ? ? ? ELog.e("-----------");
? ? ? ? }
? ? ? ? @Override
? ? ? ? public void onNext(LoginRequestOuterClass.HttpResultResponse value) {
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? if (value.getCode()==0) {//登陸成功之后才會有登陸結果
? ? ? ? ? ? ? ? ? ? LoginRequestOuterClass.LoginResult loginResult = value.getData().unpack(LoginRequestOuterClass.LoginResult.class);
? ? ? ? ? ? ? ? ? ? ELog.e("登陸結果:code = " + value.getCode() + "\tmsg = " + value.getMsg()+"\tusername = "+loginResult.getUsername()+"\tphone = "+loginResult.getPhone());
? ? ? ? ? ? ? ? }else {
? ? ? ? ? ? ? ? ? ? ELog.e("登陸失敗信息:code = " + value.getCode() + "\tmsg = " + value.getMsg());
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? Toast.makeText(MainActivity.this, value.getMsg(), Toast.LENGTH_SHORT).show();
? ? ? ? ? ? } catch (InvalidProtocolBufferException e) {
? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? @Override
? ? ? ? public void onError(Throwable e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? ELog.e("e"+e.getMessage());
? ? ? ? }
? ? ? ? @Override
? ? ? ? public void onComplete() {
? ? ? ? ? ? progressDialog.dismiss();
? ? ? ? ? ? ELog.e("=================");
? ? ? ? }
? ? });
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
處理方式跟HttpURLConnection的方式一樣,使用getData().unpack(泛型類.java)即可拿到對應的泛型類【Any與Retrofit應該還有更好的方式處理,知道的朋友可以留言告訴我一下】
最后來看看demo的效果:
————————————————
原文鏈接:https://blog.csdn.net/qq137722697/article/details/81779938
總結
以上是生活随笔為你收集整理的Android/Java中使用Protobuf的Any类型实现泛型解析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 规则引擎:大厂营销系统资格设计全解
- 下一篇: golang常用库:字段参数验证库-va