JAVA学习笔记Day25——动态接口的实现

动态接口的实现有很多好处,今天以HTTP协议解析json字符串为例。

基本知识

1、JAVA中我们有时候想要传递一个方法,在C/C++中有方法指针,而在JAVA中,我们可以使用的唯一方法就是接口。所以我们一个接口来传递其中的方法。
2、我们今天是想要从网上获取一个json字符串,然后再用Gson方式去解析得到想要的对象。选择使用动态接口的方式去解决是为了节省代码,不必要在不同的地址去获取json串时还需要去写HTTP协议那一套的连接下载。

2、下载具体步骤

1、首先我们需要建立json串对应的相关对象。在这里,我们需要为每个对象添加注解,因为在fastJson、Gson中不加注解容易混淆。
2、我们是解析这个地址的相关信息。http://www.tngou.net/api/top/list

// TnGou类
package net.xiaohong.proxy;

import com.google.gson.annotations.SerializedName;

import java.util.List;

public class TnGou {
    @SerializedName("status")
    private boolean status;
    @SerializedName("total")
    private int total;
    @SerializedName("tngou")
    private List<News> data;
// 为了节省空间,大家需要自行解决getter、setter,嘿嘿
  }
// News类
package net.xiaohong.proxy;

import com.google.gson.annotations.SerializedName;

import java.util.Calendar;

/**
 * Created HTTP_Work.
 * By XIAOHONG .
 * On 2016/8/18.
 */
public class News {
    @SerializedName("count")
    private int count;
    @SerializedName("description")
    private String description;
    @SerializedName("fCount")
    private int fCount;
    @SerializedName("fromName")
    private String fromName;
    @SerializedName("fromURL")
    private String fromURL;
    @SerializedName("id")
    private int id;
    @SerializedName("img")
    private String img;
    @SerializedName("keyWords")
    private String keyWords;
    @SerializedName("rCount")
    private int rCount;
    // 毫秒值,做转换
      @SerializedName("time")
    @JsonAdapter(CalendarAdapter.class)
    private Calendar time;
    @SerializedName("title")
    private String title;
    @SerializedName("topClass")
    private int topClass;
    // 为了节省空间,大家需要自行解决getter、setter,嘿嘿
}

类型适配器,在gson解析中如果拿不到想要的类型,可以对其进行类型适配,比如时间

// 时间类型比配。会返回一个时间类
package com.xiaohong.proxy;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;

import java.io.IOException;
import java.util.Calendar;

public class CalendarAdapter extends TypeAdapter<Calendar> {
// 写Calendar ->json
    @Override
    public void write(JsonWriter jsonWriter, Calendar calendar) throws IOException {
        if (calendar == null) {
            jsonWriter.nullValue();
        } else {
            jsonWriter.value(calendar.getTimeInMillis());
        }
    }

// 读,将json->Calendar 
    @Override
    public Calendar read(JsonReader jsonReader) throws IOException {
        if (jsonReader.hasNext()) {
            long l = jsonReader.nextLong();
            Calendar calendar = Calendar.getInstance();
            calendar.setTimeInMillis(l);
            return calendar;
        }
        return null;
    }
}

要实现动态接口,需要把自己想要的方法定义在接口中。

package net.xiaohong.proxy;
public interface HttpInter {
    @GET("http://www.tngou.net/api/top/list?page=%d&rows=%d&id=%d")
    TnGou getList(int page, int rows, int id);
}

在这里,我使用到了注解,通过注解来获取想要的方式(GET、POST)

package net.xiaohong.proxy;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface GET {
    String value();
}

往下需要一个工具类去实现动态接口的方式,我们需要将HttpInter 作为参数,通过这个接口拿到这里面的方法,进而,我们再去执行相关的下载操作。

// 动态接口实现类
package net.xiaohong.proxy;

import com.google.gson.Gson;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.HttpURLConnection;
import java.net.URL;

public class Utils {
    public static<T> T getInstance(Class<T> type) {
        Object o = Proxy.newProxyInstance(type.getClassLoader(),
                new Class[]{type},
                new MyHandler());

        return (T) o;
    }


    private static class MyHandler implements InvocationHandler {

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 拿到方法的注解类型,因为在这里我默认就让他使用GET了
            GET get = method.getAnnotation(GET.class);
            // 
             if (get != null) {
            String url = String.format(get.value(), args);
            Class<?> type = method.getReturnType();
            HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
            connection.setRequestMethod("GET");
            int code = connection.getResponseCode();
            if (code == 200) {
                int length;
                byte[] buffer = new byte[102400];
                InputStream is = connection.getInputStream();
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                while ((length = is.read(buffer)) != -1) {
                    baos.write(buffer, 0, length);
                }
                Gson gson = new Gson();
                return gson.fromJson(baos.toString("UTF-8"), type);
            }
            }

            return null;
    }
}
}
// 测试类
package net.xiaohong.proxy;

import java.util.List;

public class HttpTest {
    public static void main(String[] args) {
        HttpInter instance = Utils.getInstance(HttpInter.class);
        TnGou list = instance.getList(1, 5, 0);
//        News show = instance.getShow(2);
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        List<News> data = list.getData();
        for (News news : data) {
            System.out.print(format.format(news.getTime().getTime()) + ": ");
            System.out.println(news.getTitle());
        }
    }
}

运行结果:
这里写图片描述

到这里整个项目就实现了。这样使用动态接口的好处:我们可以在对不同的地址获取不同的json进行解析成对象。集体方法:

1、我们需要在HttpInter接口中添加我们想要的方法:比如我们想要获取这样的数据:
@GET("http://www.tngou.net/api/top/show?id=%d")
News getShow(long id);
}

此时我们需要在News类中添加一个属性:
@SerializedName("message")
private String message;

测试类中:
News show = instance.getShow(2);
System.out.println(show.getMessage());

运行结果:
这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值