精华内容
下载资源
问答
  • 2021-02-12 11:51:00

    public String sendPost_body(String arl, String s) {

    // 创建url资源

    OutputStreamWriter out = null;

    URL url;

    BufferedReader in = null;

    StringBuilder result = new StringBuilder();

    try {

    url = new URL(arl);

    // 建立http连接

    HttpURLConnection conn = (HttpURLConnection) url.openConnection();

    // 设置允许输出

    conn.setDoOutput(true);

    conn.setDoInput(true);

    // 设置不用缓存

    conn.setUseCaches(false);

    // 设置传递方式

    conn.setDoOutput(true);

    conn.setDoInput(true);

    conn.setUseCaches(false);

    conn.setInstanceFollowRedirects(true);

    conn.setRequestMethod("POST"); // 设置请求方式

    conn.setRequestProperty("Accept", "application/json"); // 设置接收数据的格式

    conn.setRequestProperty("Content-Type", "application/json"); // 设置发送数据的

    conn.setRequestProperty("user-agent",

    "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");//设置消息头,解决508错误

    // 开始连接请求

    conn.connect();

    out = new OutputStreamWriter(

    conn.getOutputStream(), "UTF-8"); // utf-8编码

    // 写入请求的字符串

    out.append(s);

    out.flush();

    out.close();

    // System.out.println(conn.getResponseCode());

    if(conn.getResponseCode()==200){

    // System.out.println("success");

    in = new BufferedReader(new InputStreamReader(conn.getInputStream(),"utf-8"));

    String line;

    while ((line = in.readLine()) != null) {

    result.append(line);

    }

    }

    } catch (Exception e) {

    //System.out.println("发送 POST 请求出现异常!" + e);

    result = new StringBuilder("{\"resCode\":\"1\",\"errCode\":\"1001\",\"resData\":\"\"}");

    e.printStackTrace();

    //log.error("远程服务未开启", e);

    }

    finally {

    try {

    if (out != null) {

    out.close();

    }

    if (in != null) {

    in.close();

    }

    } catch (IOException ex) {

    ex.printStackTrace();

    }

    }

    return result.toString();

    }

    原文:https://www.cnblogs.com/idefault/p/12101849.html

    更多相关内容
  • java实现带参数发送post请求,以body方式传参的get请求,以pathValue方式传参的get请求
  • package ...import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.OutputStreamWriter;import java.io.PrintWriter;import ja...

    package com.huayu.tizong.matchteam.util;

    import java.io.BufferedReader;

    import java.io.IOException;

    import java.io.InputStreamReader;

    import java.io.OutputStreamWriter;

    import java.io.PrintWriter;

    import java.net.MalformedURLException;

    import java.net.URL;

    import java.net.URLConnection;

    /**

    * 请求接口数据

    *

    * @author Administrator

    *

    */

    public class httpPostUrl {

    /**

    *

    * @param url

    * @param param 参数 k=v

    * @return

    */

    public static String sendPost(String url, String param) {

    PrintWriter out = null;

    BufferedReader in = null;

    String result = "";

    try {

    URL realUrl = new URL(url);

    // 打开和URL之间的连接

    URLConnection conn = realUrl.openConnection();

    // 设置通用的请求属性

    conn.setRequestProperty("accept", "*/*");

    conn.setRequestProperty("connection", "Keep-Alive");

    conn.setRequestProperty("user-agent",

    "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");

    conn.setRequestProperty("Charsert", "UTF-8");

    // 发送POST请求必须设置如下两行

    conn.setDoOutput(true);

    conn.setDoInput(true);

    // 获取URLConnection对象对应的输出流

    out = new PrintWriter(conn.getOutputStream());

    // 发送请求参数

    out.print(param);

    // flush输出流的缓冲

    out.flush();

    // 定义BufferedReader输入流来读取URL的响应

    in = new BufferedReader(

    new InputStreamReader(conn.getInputStream(),"utf-8"));

    String line;

    while ((line = in.readLine()) != null) {

    result += line;

    }

    } catch (Exception e) {

    System.out.println("发送 POST 请求出现异常!" + e);

    e.printStackTrace();

    }

    // 使用finally块来关闭输出流、输入流

    finally {

    try {

    if (out != null) {

    out.close();

    }

    if (in != null) {

    in.close();

    }

    } catch (IOException ex) {

    ex.printStackTrace();

    }

    }

    return result;

    }

    /**

    * 数据流post请求

    *

    * @param urlStr

    * @param xmlInfo

    */

    public static String doPost(String urlStr, String strInfo) {

    String reStr = "";

    try {

    URL url = new URL(urlStr);

    URLConnection con = url.openConnection();

    con.setDoOutput(true);

    con.setRequestProperty("Pragma:", "no-cache");

    con.setRequestProperty("Cache-Control", "no-cache");

    con.setRequestProperty("Content-Type", "text/xml");

    OutputStreamWriter out = new OutputStreamWriter(

    con.getOutputStream());

    out.write(new String(strInfo.getBytes("utf-8")));

    out.flush();

    out.close();

    BufferedReader br = new BufferedReader(new InputStreamReader(

    con.getInputStream(), "utf-8"));

    String line = "";

    for (line = br.readLine(); line != null; line = br.readLine()) {

    reStr += line;

    }

    } catch (MalformedURLException e) {

    e.printStackTrace();

    } catch (IOException e) {

    e.printStackTrace();

    }

    return reStr;

    }

    }

    原文:http://www.cnblogs.com/pqy521/p/6957011.html

    展开全文
  • java远程接口调用

    2021-02-12 16:00:02
    } } 7、调用另一项目中的借口(TestController.java) packagecom.controller;importorg.springframework.stereotype.Controller;importorg.springframework.web.bind.annotation.RequestBody;importorg.spring...

    一、通过地址栏传值

    1、项目结构

    45c0e7566dc4fdb6f5256c72fab4ac9a.png

    2、pom.xml

    4.0.0

    test.com

    test-com

    war

    1.0-SNAPSHOT

    test-com Maven Webapp

    http://maven.apache.org

    junit

    junit

    3.8.1

    test

    org.springframework

    spring-webmvc

    ${spring.version}

    org.springframework

    spring-jdbc

    ${spring.version}

    org.springframework

    spring-context

    ${spring.version}

    org.springframework

    spring-aop

    ${spring.version}

    org.springframework

    spring-core

    ${spring.version}

    org.springframework

    spring-test

    ${spring.version}

    javax.servlet

    jstl

    1.2

    org.springframework

    spring-aspects

    3.0.6.RELEASE

    org.aspectj

    aspectjrt

    1.6.11

    org.aspectj

    aspectjweaver

    1.6.11

    cglib

    cglib

    2.1_3

    javax.servlet

    servlet-api

    2.5

    provided

    net.sf.json-lib

    json-lib

    2.4

    jdk15

    test-com

    UTF-8

    3.1.2.RELEASE

    3、web.xml

    /p>

    "http://java.sun.com/dtd/web-app_2_3.dtd" >

    Archetype Created Web Application

    dispatcher

    org.springframework.web.servlet.DispatcherServlet

    1

    dispatcher

    /

    encodingFilter

    org.springframework.web.filter.CharacterEncodingFilter

    encoding

    UTF-8

    forceEncoding

    true

    encodingFilter

    /*

    4、dispatcher-servlet.xml

    default-lazy-init="true">

    5、TestController.java

    packagecom.controller;importcom.log.Log;importcom.remote.RemoteDemo;importnet.sf.json.JSONObject;importorg.springframework.stereotype.Controller;importorg.springframework.web.bind.annotation.RequestMapping;/*** Created by sunjf on 2016/6/26.*/@Controllerpublic classTestController {

    @Log(desc= "log测试")

    @RequestMapping(value= "test1")publicString test1(){

    String result= RemoteDemo.remoteJsonRequest("http://localhost:8080/test2?username=sun&password=123", 5000, newJSONObject());

    System.out.println(result);return "success";

    }

    }

    6、RemoteDemo.java

    packagecom.remote;importnet.sf.json.JSONObject;importjava.io.BufferedReader;importjava.io.InputStream;importjava.io.InputStreamReader;importjava.io.OutputStreamWriter;importjava.net.HttpURLConnection;importjava.net.URL;/*** Created by Administrator on 2016/6/27.*/

    public classRemoteDemo {public static String remoteJsonRequest(String url, inttimeout, JSONObject object) {

    URL connect;

    StringBuffer data= newStringBuffer();try{

    connect= newURL(url);

    HttpURLConnection connection=(HttpURLConnection) connect.openConnection();

    connection.setRequestMethod("POST");

    connection.setDoOutput(true);

    connection.setReadTimeout(timeout);

    connection.setRequestProperty("Content-Type", "application/json");

    OutputStreamWriter paramout = new OutputStreamWriter(connection.getOutputStream(), "UTF-8");

    paramout.write(object.toString());

    paramout.flush();

    InputStream inputStream =connection.getInputStream();

    InputStreamReader inputStreamReader= new InputStreamReader(inputStream, "UTF-8");

    BufferedReader reader= newBufferedReader(inputStreamReader);

    String line;while ((line = reader.readLine()) != null) {

    data.append(line);

    }

    paramout.close();

    reader.close();

    }catch(Exception e) {

    e.printStackTrace();

    }returndata.toString();

    }

    }

    7、调用另一项目中的借口(TestController.java)

    packagecom.controller;importorg.springframework.stereotype.Controller;importorg.springframework.web.bind.annotation.RequestBody;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.ResponseBody;/*** Created by sunjf on 2016/6/26.*/@Controllerpublic classTestController {

    @RequestMapping(value= "test2")

    @ResponseBodypublicString test2(String username, String password){

    System.out.println(username+ " | " +password);return username + " | " +password;

    }

    }

    8、index.jsp

    Hello World!

    9、success.jsp

    Hello Success!

    二、同过jsonObject传值,通过object接收

    1、TestController.java,请求端发送请求

    packagecom.controller;importcom.log.Log;importcom.remote.RemoteDemo;importnet.sf.json.JSONObject;importorg.springframework.stereotype.Controller;importorg.springframework.web.bind.annotation.RequestMapping;/*** Created by sunjf on 2016/6/26.*/@Controllerpublic classTestController {

    @Log(desc= "log测试")

    @RequestMapping(value= "test1")publicString test1(){

    JSONObject jsonObject= newJSONObject();

    jsonObject.put("username", "sun");

    jsonObject.put("password", "123");

    String result= RemoteDemo.remoteJsonRequest("http://localhost:8080/test2", 5000, jsonObject);

    System.out.println(result);return "success";

    }

    }

    2、TestController.java,被访问端接口

    packagecom.controller;importorg.springframework.stereotype.Controller;importorg.springframework.web.bind.annotation.RequestBody;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RequestMethod;importorg.springframework.web.bind.annotation.ResponseBody;/*** Created by sunjf on 2016/6/26.*/@Controllerpublic classTestController {

    @RequestMapping(value= "test2", method = RequestMethod.POST, produces="application/json")

    @ResponseBodypublicString test2(@RequestBody User user){

    System.out.println(user.toString());returnuser.toString();

    }

    }

    注:注意此时的@RequestBody注解,为此需要在被访问端引入依赖

    org.codehaus.jackson

    jackson-mapper-asl

    1.9.8

    jar

    compile

    3、User.java,接收实体类

    packagecom.controller;/*** Created by Administrator on 2016/6/28.*/

    public classUser {privateString username;privateString password;

    @OverridepublicString toString() {return "User{" +

    "username='" + username + '\'' +

    ", password='" + password + '\'' +

    '}';

    }publicString getUsername() {returnusername;

    }public voidsetUsername(String username) {this.username =username;

    }publicString getPassword() {returnpassword;

    }public voidsetPassword(String password) {this.password =password;

    }

    }

    展开全文
  • JAVA调用远程接口

    千次阅读 2019-12-30 16:11:36
    JAVA调用远程接口 介绍一下JAVA调用远程接口获取数据。一般业务中主要用到的就是get和post的方式。其他的方式,以后用到了,再补充。 啰嗦一下get和post方式不同点.如果只说使用功能,那么下面几句话就够了,如果要...

    JAVA调用远程接口

    介绍一下JAVA调用远程接口获取数据。一般业务中主要用到的就是get和post的方式。其他的方式,以后用到了,再补充。
    啰嗦一下get和post方式不同点.如果只说使用功能,那么下面几句话就够了,如果要深究为什么这样,那么可以参考这篇博客,讲解的清晰易懂:https://www.cnblogs.com/logsharing/p/8448446.html
    Get:将参数放在URL后面,全部信息被暴露不安全,参数编码有限制,URL长度有限制。
    POST:将请求参数通过BODY传送,安全的,且参数编码和长度无限制。

    好了,下面是我用GET和POST调用远程接口的两个例子,注释的很清楚。首先使用CloseHttpClient需要引用jar。

    		<dependency>
    			<groupId>org.apache.httpcomponents</groupId>
    			<artifactId>httpclient</artifactId>
    		</dependency>
    

    Get方式远程请求调用接口

    	@Override
    	public String getSecondPBOC(String applicationNumber) {
    		InputStream is = null;
    		String body = null;
    		StringBuilder res = new StringBuilder();
    		// 实例化CloseableHttpClient
    		CloseableHttpClient client = HttpClients.createDefault();
    		CloseableHttpResponse response = null;
    		try {
    			// 添加URL和请求参数
    			URIBuilder ub = new URIBuilder(secondPBOCURL);
    			ub.setParameter("applicationNumber", applicationNumber);
    			// 使用get方法添加URL
    			HttpGet get = new HttpGet(ub.build());
    			// 设置请求超时时间
    			RequestConfig config = RequestConfig.custom().setConnectTimeout(5000).build();
    			get.setConfig(config);
    			//使用http调用远程,获取相应信息
    			response = client.execute(get);
    			// 获取响应状态码,可根据是否响应正常来判断是否需要进行下一步
    			int statusCode = response.getStatusLine().getStatusCode();
    			// 获取响应实体
    			HttpEntity entity = response.getEntity();
    			// 读取响应内容
    			if (entity != null) {
    				is = entity.getContent();
    				BufferedReader br = new BufferedReader(new InputStreamReader(is, Consts.UTF_8));
    				while ((body = br.readLine()) != null) {
    					res.append(body);
    				}
    			}
    		} catch (Exception e) {
    			log.error(e.getMessage(), e);
    		}
    		return res.toString();
    	}
    

    以下是使用POST方法调用远程接口获取信息的,其中我的请求参数是XML报文的,所以前期先使用dom4j生成了一下请求参数。添加依赖。

    		<dependency>
    			<groupId>dom4j</groupId>
    			<artifactId>dom4j</artifactId>
    		</dependency>
    

    POST方式调用远程接口

    @Override
    	public String getSecondPBOCReport(String applicationNumber, String idNumber, String idType, String chineseName) {
    		//格式化时间,生成渠道代码
    		SimpleDateFormat format=new SimpleDateFormat("YYYYmmDDHHMMSSFFFF");
    		String chnlTxNo=format.format(new Date());
    		//实例化文档
    		Document document = DocumentHelper.createDocument();
    		//添加节点
    		Element service = document.addElement("request");
    		Element head = service.addElement("head");
    		Element body = service.addElement("Proc_Query");
    		//设置节点内容
    		head.addElement("Chnl_Tx_No").setText(chnlTxNo);		
    		head.addElement("Sys_Code").setText(sysCode);
    		head.addElement("Txn_Code").setText(txnCode);
    		body.addElement("User_Name").setText(Base64Util.decodeBase64(userName));
    		body.addElement("User_Password").setText(Base64Util.decodeBase64(userPassword));
    		body.addElement("Application_Number").setText(applicationNumber);
    		body.addElement("Id_Number").setText(idNumber);
    		body.addElement("Id_Type").setText(idType);
    		body.addElement("Chinese_Name").setText(chineseName);
    		body.addElement("Query_reason").setText(queryReason);
    		//生成XML报文
    		log.info("request="+document.asXML());
    		
    		InputStream is = null;
    		String responseBody = null;
    		StringBuilder res = new StringBuilder();
    		//实例化HttpClient
    		CloseableHttpClient client = HttpClients.createDefault();
    		//使用POST方法
    		HttpPost post = new HttpPost(reportURL);
    		//设置httpPost的请求头中的MIME类型为xml
    		post.setHeader("Content-Type", "application/xml");
    		//添加请求body的内容,就是我的请求参数,不再拼接到URL尾部
    		post.setEntity(new StringEntity(document.asXML(),"utf-8"));
    		CloseableHttpResponse response = null;
    		try {
    			//设置信息超时时间
    			RequestConfig config = RequestConfig.custom().setConnectTimeout(5000).build();
    			post.setConfig(config);
    			//调用远程接口,获取返回信息
    			response = client.execute(post);
    			//获取响应实体
    			HttpEntity entity = response.getEntity();
    			//读取响应内容
    			if (entity != null) {
    				is = entity.getContent();
    				BufferedReader br = new BufferedReader(new InputStreamReader(is, Consts.UTF_8));
    				while ((responseBody = br.readLine()) != null) {
    					res.append(responseBody);
    				}
    			}
    		} catch (Exception e) {
    			log.error(e.getMessage(), e);
    		}
    		return res.toString();
    	}
    

    一般调用远程接口这样就可以了。
    可以自己写一个接口来测试调用一下。下面是我用于测试POST方法获取报文的servlet,记下来自己下次测试备用。

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    		// 获取请求参数
    		BufferedReader reader1 = new BufferedReader(new InputStreamReader(request.getInputStream()));
    		String str = "";
    		String reqContent = "";
    		while ((str = reader1.readLine()) != null) {
    			reqContent += str;
    		}
    		// 读取本地文件,返回文件内容
    		File file = new File("D:\\text.html");
    		BufferedReader reader = null;
    		StringBuffer sbf = new StringBuffer();
    		try {
    			InputStreamReader read = new InputStreamReader(new FileInputStream(file), "UTF-8");
    			reader = new BufferedReader(read);
    			String tempStr;
    			while ((tempStr = reader.readLine()) != null) {
    				sbf.append(tempStr);
    			}
    			reader.close();
    		} catch (IOException e) {
    		} finally {
    			if (reader != null) {
    				try {
    					reader.close();
    				} catch (IOException e1) {
    				}
    			}
    		}
    		// 返回post的请求内容
    		response.setCharacterEncoding("UTF-8");
    		response.setHeader("Content-Type", "application/text, charset=UTF-8");
    		PrintWriter out = response.getWriter();
    		out.print(sbf.toString());
    		out.flush();
    		out.close();
    	}
    
    展开全文
  • java使用post调取接口

    千次阅读 2021-05-28 15:06:32
    public static String sendSZPost(String url, String params, ... String response = HttpRequestUtil.sendSZPost(posturl, mydata.toString(), token1); log.info("返回结果: {}", response); return response; }
  • //传文件到远程post接口 public static String sendPostWithFile(File file, String urlStr) throws Exception{ MultipartEntityBuilder builder = MultipartEntityBuilder.create().addPart("file", new FileBody...
  • Java远程调用对方接口

    千次阅读 2020-04-11 14:46:47
    这里猿君主要介绍java调用远程接口的两种方式: 一、调用远程http接口 通过jdk的网络类Java.net.HttpURLConnection调用第三方http接口 /** * @Auther kezf * @Date 2020/4/11 * @param urlStr 目标地...
  • Java调用接口get,post

    2019-09-03 23:20:21
    Get Post 【参考文献】 [1]https://blog.csdn.net/fsy9595887/article/details/84143573
  • packagecom.vcgeek.hephaestus....importjava.io.BufferedReader;importjava.io.IOException;importjava.io.InputStreamReader;importjava.io.PrintWriter;importjava.util.HashMap;importjava.util.List;importj...
  • Java调用远程接口记录

    2020-12-17 19:40:35
    Java调用远程接口记录 因为实际应用中会有很多的情景需要使用他人的接口,所以记录一种自己惯用的接口访问方式。 使用apache的CloseableHttpClient进行一次POST请求的记录 记录代码如下: import ...
  • import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.io.OutputStreamWriter;...public class SoapUtil {/** 远程访问SOAP协议接口** @param url: 服务接口地址"http:...
  • 利用Java的HttpURLConnection进行远程url请求(调用远程接口)测试类:请求类型为json,以post方式请求,利用OutputStream写入数据实体类:public class User implementsSerializable {privateString name;private...
  • 使用java的HttpClient调用远程接口

    千次阅读 2018-04-01 00:45:35
    httpClient比jdk自带的URLConection更加易用和方便,这里介绍一下使用httpClient来调用远程接口。首先导入相关的依赖包:&lt;!-- httpClient --&gt; &lt;dependency&gt; &lt;groupId&...
  • Java调用远程接口(传递json数据或文件和其它参数)调用接口传递json数据调用接口传递文件及其它参数 调用接口传递json数据 package com.my.test; import com.alibaba.fastjson.JSON; import org.apache....
  • java通过url调用远程接口返回json数据,有用户名和密码验证,转自 https://blog.csdn.net/wanglong1990421/article/details/78815856Java请求远程URLJava请求一个URL。获取网站返回的数据。转自...
  • Java访问远程接口

    千次阅读 2019-06-28 23:54:44
    Java 应用程序可以直接通过 HTTP 协议来访问网络资源。虽然在 JDK 的net包中已经提供了访问 HTTP 协议的基本功能,但是对于大部分应用程序来说,JDK 库本身提供的功能还不够丰富和灵活。HttpClient 是 Apache ...
  • java调用远程接口的工具类 import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.HttpURLConnection; import java...
  • 1、使用Post请求时,需要传递两个参数,第一个是请求url,第二个参数是请求参数;返回值是一个string,可以直接接收返回的参数,也可以使用工具转换成map格式; 请求参数示例:String params = "systype=4&aa...
  • 一、Java访问远程url接口并获取结果 1、原生JavaAPI获取 package com.util; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import java.io....
  • import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.util.HashMap; import java.util.List; import java.util.Map; /** *...
  • java后端通过url调用远程接口服务public static String sendRequest(String url, Object object) {PrintWriter out = null;BufferedReader in = null;StringBuilder result = new StringBuilder();try {URL realUrl ...
  • 最原始URLConnection方式如下,除此之外还有更加优化版的http请求方式,如HttpClient、okhttp3请求方式。 HttpClient案例详解:... ... 一、调用端 提供get、post两种方式 package com.exa
  • java httpUrlConnection 调用远程接口报4001.问题的出现:线下开发时候使用httpUrlConnction测试调用远程接口一点问题都没有,但是打包后放到线上去后出现400的错误同样的参数在线下可以调试,放在线上就不行了。...
  • 1.URL调用远程 /* * URL调用远程服务 */ public class MyRemoteClient { public void go(){ try { //lookup 返回与指定 name 关联的远程对象的引用 //bind(String name, Remote obj) 指定 name 绑定到远程...
  • 一.Java访问远程url接口并获取结果 1.原生JavaAPI获取 package com.util; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import java.io....
  • java编写了http Post的请求代码,通过发送请求的 URL,获取远程资源的响应结果,入参为json字符串。使用到httpPost,CloseableHttpClient
  • java实现远程调用

    千次阅读 2021-10-22 21:06:21
    远程调用也就是调用远程接口,我们都知道接口有自己本地的,也有远程别人写好的,而调用远程接口的就需要使用远程调用啦。个人比较喜欢随意,放荡不羁一点,像概念这东西不太不喜欢引经据典,这里我就随便说几句,有...
  • ResponseEntity exchange = restTemplate().exchange('url', HttpMethod.POST, contentDataPushVoHttp, JSONObject.class); 咋样就可以成功访问别人的接口了。当然还有很多种,大家也可以分享!
  • 原创地址 ... import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.util....

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 67,853
精华内容 27,141
关键字:

java调用远程post接口

java 订阅