Android/Java中使用Protobuf的Any类型实现泛型解析
上一篇博客中只講解到了簡(jiǎn)單的使用protobuf,還不會(huì)的可以先去看一下【Android項(xiàng)目使用Protobuf教程(結(jié)合Retrofit+RxJava及HttpURLConnection使用)】,有位小伙伴問我如何使用泛型呢?
比如每次網(wǎng)絡(luò)請(qǐng)求都會(huì)有一些公共字段和可變參數(shù),如下:
請(qǐng)尊重原創(chuàng),轉(zhuǎn)載需要注明出處,大力哥的博客:https://blog.csdn.net/qq137722697
{
code:0
msg:"登錄成功"
data:{
? ? ? ? ResultResponse
? ? }
}
1
2
3
4
5
6
7
即code和msg是公共字段,每次都會(huì)返回;data為具體的業(yè)務(wù)請(qǐng)求所返回的響應(yīng)結(jié)果。如果按照之前的介紹,可能每一個(gè)接口都需要對(duì)應(yīng)一個(gè)帶有code、msg的proto文件,對(duì)應(yīng)的每個(gè)Response都帶有code和msg,能不能實(shí)現(xiàn)泛型呢?答案是肯定的
proto文件的定義
LoginRequest.proto
syntax = "proto3";
//需要導(dǎo)入any.proto文件才可實(shí)現(xiàn)泛型
import "google/protobuf/any.proto";
//生成的java類所在的包名
package com.zhys.protobufdemo.protobean;
//登錄請(qǐng)求結(jié)構(gòu)體
message LoginRequest {
? ? string username = 1;
? ? string pwd = 2;
}
//網(wǎng)絡(luò)請(qǐng)求的響應(yīng)體
message HttpResultResponse {
? ? int32 code = 1;
? ? string msg = 2;
? ? google.protobuf.Any data = 3;
}
//登陸結(jié)果(也可以單獨(dú)定義一個(gè)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”;)聲明可變參數(shù)data即可;此時(shí)通過Clean Project即可生成對(duì)應(yīng)的java類(此處叫LoginRequestOuterClass),拷出備用
服務(wù)端處理【可選,Android開發(fā)可忽略此步驟】
//次注解需要tomcat7及以上不能才可以運(yùn)行
@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("請(qǐng)求登陸了");
? ? ? ? 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("用戶名或密碼錯(cuò)誤");
? ? ? ? ? ? System.out.println("用戶名或密碼錯(cuò)誤");
? ? ? ? }
? ? ? ? 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
此處跟上一篇的教程區(qū)別也不大,setData的時(shí)候需要傳入泛型類,只需要通過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) {
? ? ? ? ? ? ? ? ? ? //解析結(jié)果
? ? ? ? ? ? ? ? ? ? final LoginRequestOuterClass.HttpResultResponse loginResponse = LoginRequestOuterClass.HttpResultResponse.parseFrom(conn.getInputStream());
? ? ? ? ? ? ? ? ? ? if (loginResponse.getCode()==0) {//登陸成功之后才會(huì)有登陸結(jié)果
? ? ? ? ? ? ? ? ? ? ? ? LoginRequestOuterClass.LoginResult loginResult = loginResponse.getData().unpack(LoginRequestOuterClass.LoginResult.class);
? ? ? ? ? ? ? ? ? ? ? ? ELog.e("登陸結(jié)果: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)即可拿到對(duì)應(yīng)的泛型類,此處需要注意的是protobuf解析不像Gson解析那么強(qiáng)大,缺少參數(shù)會(huì)拋出以下異常
?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();
? ? //開始請(qǐng)求
? ? 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) {//登陸成功之后才會(huì)有登陸結(jié)果
? ? ? ? ? ? ? ? ? ? LoginRequestOuterClass.LoginResult loginResult = value.getData().unpack(LoginRequestOuterClass.LoginResult.class);
? ? ? ? ? ? ? ? ? ? ELog.e("登陸結(jié)果: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)即可拿到對(duì)應(yīng)的泛型類【Any與Retrofit應(yīng)該還有更好的方式處理,知道的朋友可以留言告訴我一下】
最后來看看demo的效果:
————————————————
原文鏈接:https://blog.csdn.net/qq137722697/article/details/81779938
總結(jié)
以上是生活随笔為你收集整理的Android/Java中使用Protobuf的Any类型实现泛型解析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 规则引擎:大厂营销系统资格设计全解
- 下一篇: Android 应用中十大常见 UX 错