当前位置:

首页 > 编程开发 > Java服务RestTemplate与HttpClient如何使用

Java服务RestTemplate与HttpClient如何使用

概述常见的远程调用方式有以下2种:RPC:RemoteProduceCall远程过程调用,类似的还有RMI(remotemethodinvoke)。自定义数据格式,基于原生TCP通信,速度快,效率高。早期的webservice,现在热门的dubbo,都是RPC的典型代表。Http:http其实是一种网络传输协议,基于TCP,规定了数据传输的格式。现在客户端浏览器与服务端通信基本都是采用Http协议,也可以用来进行远程服务调用。缺点是消息封装臃肿,优势是对服务的提供和调用方没有任何技术限定,自由灵活,更符合

本文目录

    概述

    常见的远程调用方式有以下2种:

    • RPC: Remote Produce Call远程过程调用,类似的还有RMI(remote method invoke)。自定义数据格式,基于原生TCP通信,速度快,效率高。早期的webservice,现在热门的dubbo,都是RPC的典型代表。

    • Http: http其实是一种网络传输协议,基于TCP,规定了数据传输的格式。 现在客户端浏览器与服务端通信基本都是采用Http协议,也可以用来进行远程服务调用。缺点是消息封装臃肿,优势是对服务的提供和调用方没有任何技术限定,自由灵活,更符合微服务理念。现在热门的Rest风格,就可以通过http协议来实现。

    如果项目全部采用 Java技术栈,那么使用Dubbo作为微服务架构是一个不错的选择。

    如果项目的技术栈多样化,主要采用了Spring和SpringBoot框架,那么SpringCloud搭建微服务是不二之选,使用Http方式来实现服务间调用。

    java开发中,使用http连接,访问第三方网络接口,通常使用的连接工具为RestTemplate、HttpClient和OKHttp。

    RestTemplate

    概述及依赖

    HttpClient和OKHttp两种连接工具,使用起来比较复杂,如果使用spring框架,可以使用restTemplate来进行http连接请求。

    restTemplate默认的连接方式是java中的HttpConnection,可以使用ClientHttpRequestFactory指定不同的HTTP连接方式。

    依赖

    
        org.springframework
        spring-web
        5.2.2.RELEASE
    
    
        org.apache.httpcomponents
        httpclient
        4.5.7
    

    配置类

    基础配置

    @Configuration
    public class RestTemplateConfig {
       @Bean
       public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
           return new RestTemplate(factory);
       }
       @Bean
       public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
           SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
           factory.setReadTimeout(150 * 1000); // ms
           factory.setConnectTimeout(150 * 1000); // ms
           return factory;
       }
    }

    进阶配置

    import org.apache.http.client.HttpClient;
    import org.apache.http.conn.HttpClientConnectionManager;
    import org.apache.http.impl.client.HttpClientBuilder;
    import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.http.client.ClientHttpRequestFactory;
    import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
    import org.springframework.web.client.RestTemplate;
    @Configuration
    public class RestTemplateConfig {
        /**
         * http连接管理器
         */
        @Bean
        public HttpClientConnectionManager poolingHttpClientConnectionManager() {
            /*// 注册http和https请求
            Registry registry = RegistryBuilder.create()
                    .register("http", PlainConnectionSocketFactory.getSocketFactory())
                    .register("https", SSLConnectionSocketFactory.getSocketFactory())
                    .build();
            PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(registry);*/
            PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager();
            // 最大连接数
            poolingHttpClientConnectionManager.setMaxTotal(500);
            // 同路由并发数(每个主机的并发)
            poolingHttpClientConnectionManager.setDefaultMaxPerRoute(100);
            return poolingHttpClientConnectionManager;
        }
        /**
         * HttpClient
         * @param poolingHttpClientConnectionManager
         */
        @Bean
        public HttpClient httpClient(HttpClientConnectionManager poolingHttpClientConnectionManager) {
            HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
            // 设置http连接管理器
            httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager);
            /*// 设置重试次数,默认是3次,没有开启
            httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(3, true));*/
            // 设置默认请求头
            /*List
     headers = new ArrayList<>();         headers.add(new BasicHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.16 Safari/537.36"));         headers.add(new BasicHeader("Accept-Encoding", "gzip,deflate"));         headers.add(new BasicHeader("Accept-Language", "zh-CN"));         headers.add(new BasicHeader("Connection", "Keep-Alive"));         headers.add(new BasicHeader("Content-type", "application/json;charset=UTF-8"));         httpClientBuilder.setDefaultHeaders(headers);*/         return httpClientBuilder.build();     }     /**      * 请求连接池配置      * @param httpClient      */     @Bean     public ClientHttpRequestFactory clientHttpRequestFactory(HttpClient httpClient) {         HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory();         // httpClient创建器         clientHttpRequestFactory.setHttpClient(httpClient);         // 连接超时时间/毫秒(连接上服务器(握手成功)的时间,超出抛出connect timeout)         clientHttpRequestFactory.setConnectTimeout(5 * 1000);         // 数据读取超时时间(socketTimeout)/毫秒(服务器返回数据(response)的时间,超过抛出read timeout)         clientHttpRequestFactory.setReadTimeout(10 * 1000);         // 从连接池获取请求连接的超时时间,不宜过长,必须设置/毫秒(超时间未拿到可用连接,会抛出org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool)         clientHttpRequestFactory.setConnectionRequestTimeout(10 * 1000);         return clientHttpRequestFactory;     }     /**      * rest模板      */     @Bean     public RestTemplate restTemplate(ClientHttpRequestFactory clientHttpRequestFactory) {         // 配置请求工厂         return new RestTemplate(clientHttpRequestFactory);     } }

    使用

    实体类

    @Data
    @Builder
    @NoArgsConstrutor
    @AllArgsConstrutor
    public class BaseResponse implements Serializable {
        private static final long serialVersionUID  = 1L;
        private String responseCode;
        private String responseMessage;
        private List responseData;
    }
    @Data
    @Builder
    @NoArgsConstrutor
    @AllArgsConstrutor
    public class TempUser implements Serializable {
        private static final long serialVersionUID  = 1L;
        private String userName;   
        private Integer age;
    }

    GET请求

    普通访问

    BaseResponse result = restTemplate.getForObject(
        "http://localhost:8080/cs-admin/rest/getUser?userName=张三&age=18", BaseResponse.class);

    返回HTTP状态

    ResponseEntity responseEntity = restTemplate.getForEntity(
        "http://localhost:8080/cs-admin/rest/getUser?userName=张三&age=18", TempUser.class);
    // 获取状态对象
    HttpStatus httpStatus = responseEntity.getStatusCode();
    // 获取状态码
    int statusCodeValue = responseEntity.getStatusCodeValue();
    // 获取headers
    HttpHeaders httpHeaders = responseEntity.getHeaders();
    // 获取body
    BaseResponse result = responseEntity.getBody();

    映射请求参数

    Map paramMap = new HashMap<>();
    paramMap.put("userName", "张三");
    paramMap.put("age", 18);
    BaseResponse result = restTemplate.getForObject(
        "http://localhost:8080/cs-admin/rest/getUser?userName={userName}&age={age}", 
        BaseResponse.class, paramMap);

    POST请求

    普通访问接口

    TempUser param = new TempUser();
    param.setUserName("张三");
    param.setAge(18);
    BaseResponse result = restTemplate.postForObject("http://localhost:8080/cs-admin/rest/getPostUser", 
                                                 param, BaseResponse.class);

    带HEAD访问接口

    // 请求头信息
    HttpHeaders headers = new HttpHeaders();
    //headers.setContentType(MediaType.valueOf("application/json;charset=UTF-8"));
    headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
    //headers.add("headParam1", "headParamValue");
    // 请求体内容
    TempUser param = new TempUser();
    param.setUserName("张三");
    param.setAge(18);
    // 组装请求信息
    HttpEntity httpEntity=new HttpEntity<>(param, headers);
    BaseResponse result = restTemplate.postForObject("http://localhost:8080/cs-admin/rest/getPostUser", 
                                                 httpEntity, BaseResponse.class);

    无请求体的访问:仅method为post,传参方式仍然为get的param方式

    Map paramMap = new HashMap<>();
    paramMap.put("userName", "张三");
    paramMap.put("age", 18);
    BaseResponse result = restTemplate.postForObject(
        "http://localhost:8080/cs-admin/rest/getPostUserNoBody?userName={userName}&age={age}", 
        null, BaseResponse.class, paramMap);
    System.out.println(result);

    上传文件

    后台接口代码:

    @RequestMapping("uploadFile")
    public TempUser uploadFile(HttpServletRequest request, TempUser form) {
        MultipartHttpServletRequest multipartHttpServletRequest = (MultipartHttpServletRequest) request;
        //获取文件信息
        MultipartFile multipartFile = multipartHttpServletRequest.getFile("file");
        TempUser tempUser = new TempUser();
        if (multipartFile != null) {
            tempUser.setUserName(form.getUserName() + " " + multipartFile.getOriginalFilename());
        }
        if(form!=null){
            tempUser.setAge(form.getAge());
        }
        return tempUser;
    }

    访问方式:

    // 文件
    FileSystemResource file=new FileSystemResource("D:\\Elasticsearch权威指南(中文版).pdf");
    // 设置请求内容
    MultiValueMap param=new LinkedMultiValueMap<>();
    param.add("file", file);
    // 其他参数
    param.add("userName", "张三");
    param.add("age", 18);
    // 组装请求信息
    HttpEntity> httpEntity=new HttpEntity<>(param);
    // 发送请求
    TempUser result = restTemplate.postForObject("http://localhost:8080/cs-admin/rest/uploadFile", 
                                                 httpEntity, TempUser.class);

    HttpClient

    概述

    HttpClient 通过连接池创建连接:

    • 管理连接的基本单位是Route(路由),每个路由上都会维护一定数量的HTTP连接

    • 每次调用后必须执行 releaseConnection

    • 路由可以理解为客户端机器到目标机器的一条线路

    • 如果不给 httpclient配置指定的连接管理器,httpclient会自动使用PoolingHttpClientConnectionManager作为连接管理器。

    • PoolingHttpClientConnectionManager默认的maxConnPerRoute和maxConnTotal分别是是2和20。也就是对于每个服务器最多只会维护2个连接,看起来有点少。所以,在日常使用时我们尽量使用自己配置的连接管理器比较好。

    连接池:

    • 连接池技术作为创建和管理连接的缓冲池技术。

    • 连接池管理的对象是长连接

    • 有长连接的优势

    **长连接:**是指客户端与服务器端一旦建立连接以后,可以进行多次数据传输而不需重新建立连接,

    优势:

    • 省去了每次数据传输连接建立的时间开销

    • 资源的访问控制

    **短连接:**每次数据传输都需要客户端和服务器端建立一次连接

    使用

    使用HttpClient发送请求、接收响应很简单,一般需要如下几步即可:

    • 创建HttpClient对象

    • 创建请求方法的实例,并指定请求URL。如果需要发送GET请求,创建HttpGet对象;如果需要发送POST请求,创建HttpPost对象。

    • 如果需要发送请求参数,可调用HttpGet、HttpPost共同的setParams(HetpParams params)方法来添加请求参数;对于HttpPost对象而言,也可调用setEntity(HttpEntity entity)方法来设置请求参数,参数则必须用NameValuePair[]数组存储

    • 调用HttpClient对象的execute(HttpUriRequest request)发送请求,该方法返回一个HttpResponse

    • 调用HttpResponse的getAllHeaders()、getHeaders(String name)等方法可获取服务器的响应头;调用HttpResponse的getEntity()方法可获取HttpEntity对象,该对象包装了服务器的响应内容。程序可通过该对象获取服务器的响应内容

    • 释放连接。无论执行方法是否成功,都必须释放连接

    依赖:

    
        org.apache.httpcomponents
        httpclient
        4.5.2
    
        
        org.apache.httpcomponents
        httpclient-cache
        4.5.2
    
        
        org.apache.httpcomponents
        httpmime
        4.5.2
    

    java工具类

    import com.alibaba.fastjson.JSON;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.commons.lang3.StringUtils;
    import org.apache.http.Consts;
    import org.apache.http.HttpResponse;
    import org.apache.http.NameValuePair;
    import org.apache.http.client.HttpClient;
    import org.apache.http.client.config.RequestConfig;
    import org.apache.http.client.entity.UrlEncodedFormEntity;
    import org.apache.http.client.methods.HttpGet;
    import org.apache.http.client.methods.HttpPost;
    import org.apache.http.entity.StringEntity;
    import org.apache.http.impl.client.HttpClients;
    import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
    import org.apache.http.message.BasicNameValuePair;
    import org.apache.http.util.EntityUtils;
    import org.slf4j.Logger;
    import java.net.URI;
    import java.nio.charset.StandardCharsets;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;
    /**
     * HttpClient 工具类
     */
    @Slf4j
    public class HttpClientUtil {
        public static final String APPLICATION_JSON_VALUE = "application/json";
        private static final Logger logger = log;
        private static final Integer CONN_TIME_OUT = 3000;// 超时时间豪秒
        private static final Integer SOCKET_TIME_OUT = 10000;
        /** 每个路由的最大请求数,默认2 */
        private static final Integer DEFAULT_MAX_PER_ROUTE = 40;
        /** 最大连接数,默认20 */
        private static final Integer MAX_TOTAL = 400;
        private static HttpClient httpClient;
        static {
            // 请求配置
            RequestConfig requestConfig = RequestConfig.custom()
                    .setConnectTimeout(CONN_TIME_OUT)
                    .setConnectionRequestTimeout(CONN_TIME_OUT)
                    .setSocketTimeout(SOCKET_TIME_OUT)
                    .build();
            // 管理 http连接池
            PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
            cm.setDefaultMaxPerRoute(DEFAULT_MAX_PER_ROUTE);
            cm.setMaxTotal(MAX_TOTAL);
            httpClient = HttpClients.custom()
                .setConnectionManager(cm)
                .setDefaultRequestConfig(requestConfig)
                .build();
        }
        /**
         * Get请求
         */
        public static String requestGet(String url, Map paramsMap) throws Exception {
            logger.info("GET request  url:{} params:{}", url, paramsMap);
            Long start = System.currentTimeMillis();
            List params = initParams(paramsMap);
            // Get请求
            HttpGet httpGet = new HttpGet(url);
            try {
                // 设置参数
                String str = EntityUtils.toString(new UrlEncodedFormEntity(params, StandardCharsets.UTF_8));
                String uriStr = StringUtils.isEmpty(str) ? 
                    httpGet.getURI().toString() : httpGet.getURI().toString() + "?" + str;
                httpGet.setURI(new URI(uriStr));
                // 发送请求
                HttpResponse response = httpClient.execute(httpGet);
                logger.info("GET request  url:{} response:{} time:{}",
                        url, response, System.currentTimeMillis() - start);
                // 获取返回数据
                return getSuccessRetFromResp(response, url, JSON.toJSONString(paramsMap));
            } finally {
                // 必须释放连接,不然连接用完后会阻塞
                httpGet.releaseConnection();
            }
        }
        /**
         * Post请求,Map格式数据
         */
        public static String requestPost(String url, Map paramsMap) throws Exception {
            logger.info("POST request  url:{} params:{}", url, paramsMap);
            Long start = System.currentTimeMillis();
            List params = initParams(paramsMap);
            HttpPost httpPost = new HttpPost(url);
            try {
                httpPost.setEntity(new UrlEncodedFormEntity(params, Consts.UTF_8));
                HttpResponse response = httpClient.execute(httpPost);
                logger.info("POST request  url:{} response:{}  time:{}",
                        url, response, System.currentTimeMillis() - start);
                String retStr = getSuccessRetFromResp(response, url, JSON.toJSONString(paramsMap));
                return retStr;
            } finally {
                httpPost.releaseConnection();
            }
        }
        /**
         * Post请求,json格式数据
         *
         */
        public static String requestPostJsonStr(String url, String json) throws Exception {
            logger.info("POST request  url:{} params:{}", url, json);
            long start = System.currentTimeMillis();
            HttpPost httpPost = new HttpPost(url);
            try {
                StringEntity entity = new StringEntity(json, Consts.UTF_8);
                entity.setContentType(APPLICATION_JSON_VALUE);
                httpPost.setEntity(entity);
                HttpResponse response = httpClient.execute(httpPost);
                logger.info("POST request  url:{} response:{}  time:{}", 
                            url, response, System.currentTimeMillis() - start);
                return getSuccessRetFromResp(response, url, json);
            } finally {
                // 资源释放
                httpPost.releaseConnection();
            }
        }
        /**
         * post Object格式数据
         */
        public static String requestPostJson(String url, Object obj) throws Exception {
            String params = JSON.toJSONString(obj);
            return requestPostJsonStr(url, params);
        }
        private static String getSuccessRetFromResp(HttpResponse response, String url, String params) throws Exception {
            String retStr = "";
            // 检验状态码,如果成功接收数据
            int code = response.getStatusLine().getStatusCode();
            if (code == 200) {
                retStr = EntityUtils.toString(response.getEntity(), Consts.UTF_8);
            } else {
                throw new RuntimeException(String.format("Http request error:%s, url:%s, params:%s", response, url, params));
            }
            logger.info("Http request retStr:{}. url:{}", retStr, url);
            return retStr;
        }
        private static List initParams(Map paramsMap) {
            List params = new ArrayList();
            if (paramsMap == null)
                return params;
            for (Map.Entry entry : paramsMap.entrySet()) {
                params.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
            }
            return params;
        }
    }
    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发 Java httpclient
    相关文章 更多
    Java单元测试入门:使用JUnit 5编写第一个测试用例
    Java单元测试入门:使用JUnit 5编写第一个测试用例

    面向初学者的JUnit 5实用入门指南。从测试概念、Maven依赖配置,到手把手编写首个单元测试用例及断言验证,助你掌握Java单元测试的核心流程。

    Java变量未初始化报错解析:局部变量与成员变量默认值差异
    Java变量未初始化报错解析:局部变量与成员变量默认值差异

    深入解析Java中局部变量未初始化编译报错与成员变量自动赋予默认值的机制差异,涵盖JVM内存分配、编译期确定性赋值检查与实际排查修复方案。

    Java获取当前时间并格式化输出:DateTimeFormatter与SimpleDateFormat
    Java获取当前时间并格式化输出:DateTimeFormatter与SimpleDateFormat

    详细讲解在Java中获取当前系统时间并进行格式化输出的两种核心方案:基于Java 8全新日期时间API的DateTimeFormatter与传统遗留的SimpleDateFormat,包含完整代码示例、线程安全机制对比及生产选型建议。

    Java中final与static final常量的定义及初始化规则
    Java中final与static final常量的定义及初始化规则

    深入解析Java中final变量与static final常量的定义、内存语义、初始化时机及合法赋值路径,涵盖编译期常量优化与实战避坑指南。

    Java抽象方法与接口方法的区别及选型建议
    Java抽象方法与接口方法的区别及选型建议

    深入对比Java中抽象类抽象方法与接口方法的语法演进、设计意图及运行期差异,并提供清晰的架构选型决策流程与实战范例。

    Java实现HTTP请求与JSON解析的完整代码示例
    Java实现HTTP请求与JSON解析的完整代码示例

    本文提供Java标准库HttpClient发起HTTP GET/POST请求并结合Jackson进行JSON数据反序列化与序列化的完整代码示例与工程实践指南。

    Java递归出现StackOverflowError的原因分析及栈空间优化方案
    Java递归出现StackOverflowError的原因分析及栈空间优化方案

    详细分析Java递归调用出现StackOverflowError的原因,结合代码说明线程栈、栈帧和递归深度之间的关系,并介绍终止条件排查、迭代改写、减少栈帧开销以及通过-Xss调整JVM栈空间的方法。

    Java空指针异常(NPE)的代码排查与修复实例
    Java空指针异常(NPE)的代码排查与修复实例

    针对Java中常见的NullPointerException(NPE),本文从堆栈日志定位、典型代码触发场景、具体修复代码对比到防御体系进行系统讲解,提供实用且易上手的排查与修复方案。

    selenium上传文件教程本地文件路径设置方法
    selenium上传文件教程本地文件路径设置方法

    深入解析Selenium处理文件上传的技术细节,涵盖标准HTML控件的路径直接注入法与非标准控件的系统级模拟方案,提供Windows与Linux环境下的路径设置最佳实践及常见异常排查。

    大数据开发语言选型:Java对比Scala与Python的优缺点及适用场景
    大数据开发语言选型:Java对比Scala与Python的优缺点及适用场景

    针对大数据工程场景,系统对比Java、Scala与Python在执行性能、生态结合、开发效率和维护成本上的核心差异,给出清晰的架构选型依据与落地方案。

    查看更多
    精品专题 更多
    装机必备
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows
    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程
    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    Mac软件 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    Aperty macOS版
    Aperty macOS版
    macOS

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    WINDOWS 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    PixTV 网页版
    PixTV 网页版
    Windows

    PixTV 是一款在浏览器中使用的 AI 视觉内容创作平台,提供图片、视频、音频、文字生成、AI 分镜、局部重绘、提示词反推和无限画布等工具,适合短剧、漫剧、广告及社交媒体内容制作。