【2023】java常用HTTP客户端对比以及使用(HttpClient/OkHttp/WebClient)

💻目录

  • 1、介绍
  • 2、使用
    • 2.1、添加配置
      • 2.1.1、依赖
      • 2.1.2、工具类
      • 2.1.3、实体
      • 2.1.4、Controller接口
    • 2.2、Apache HttpClient使用
    • 2.3 、OkHttp使用
    • 2.4、WebClient使用

1、介绍

现在java使用的http客户端主要包括以下几种
java使用http通讯
而这些中使用得最频繁的主要是:

  1. Apache HttpClient:这是一个功能强大且广泛使用的第三方库,用于进行HTTP通讯。它提供了更高级的API和更丰富的功能,比如支持连接池、认证、重定向、Cookie管理等。Apache HttpClient可以作为独立的库使用,也可以作为Apache HttpComponents项目的一部分。

  2. OkHttp:这是另一个流行的第三方库,用于进行HTTP通讯。OkHttp提供了简洁的API和高性能的特性,支持同步和异步请求,以及连接池、缓存、拦截器等功能。OkHttp也是Square公司的一个开源项目。

  3. Spring WebClient:这是Spring框架中的一个模块,是RestTemplate的升级版,用于进行非阻塞的HTTP通讯。它基于Reactive Streams编程模型,适用于构建响应式的应用程序。Spring WebClient提供了简单的API来发送HTTP请求和处理响应,可以与Spring WebFlux等模块一起使用。

2、使用

下面展示了Apache HttpClient和OkHttp以及Spring WebClient的常用使用方式,包括get和post

2.1、添加配置

2.1.1、依赖

        <!-- https://mvnrepository.com/artifact/org.apache.httpcomponents.client5/httpclient5 --><dependency><groupId>org.apache.httpcomponents.client5</groupId><artifactId>httpclient5</artifactId></dependency><!--okhttp--><dependency><groupId>com.squareup.okhttp3</groupId><artifactId>okhttp</artifactId></dependency><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.22</version></dependency><!--webClient--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency>

2.1.2、工具类

  • Result:统一返回类
@Data
public class Result<T> {//状态码private Integer code;//信息private String message;//数据private T data;private Result(){}//设置数据,返回对象的方法public static <T> Result<T> build(T data, ResultCodeEnum resultCodeEnum) {//创建Result对象,设置值,返回对象Result<T> result = new Result<>();//判断返回结果中是否需要数据if (data != null) {//设置数据到result对象result.setData(data);}//设置其他值result.setCode(resultCodeEnum.getCode());result.setMessage(resultCodeEnum.getMessage());//返回设置值之后的对象return result;}//成功的方法public static <T> Result<T> ok(T data) {return build(data, ResultCodeEnum.SUCCESS);}//成功的方法public static <T> Result<T> ok() {return build(null, ResultCodeEnum.SUCCESS);}//失败的方法public static <T> Result<T> fail(T data) {return build(data, ResultCodeEnum.FAIL);}
}
  • ResultCodeEnum:返回结果
@Getter
public enum  ResultCodeEnum {SUCCESS(200,"成功"),FAIL(201, "失败"),;private Integer code;private String message;ResultCodeEnum(Integer code, String message) {this.code = code;this.message = message;}
}

2.1.3、实体

  • User
@Data
public class User {private String name;private Integer age;private Integer post;
}
  • ProductInfo:返回数据
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class ProductInfo implements Serializable {private Long id;/**销量*/private Integer sale;/**价格*/private Integer price;/**名称*/private String name;/**类型*/private Integer type;/**端口*/private Integer port;
}

2.1.4、Controller接口

@RestController
@RequestMapping("/productInfo/index")
public class ProductInfoController {@Resourceprivate ProductInfoService productInfoService;//    获取当前服务的端口@Value("${server.port}")private Integer port;@GetMapping("/get")public Result<?> get(Integer type){List<ProductInfo> productInfoList = getProductInfoList(type);System.out.println(productInfoList);return Result.ok(productInfoList);}@PostMapping("/post")public Result<?> post(@RequestBody User user){Integer post = user.getPost();List<ProductInfo> productInfoList = getProductInfoList(post);System.out.println(productInfoList);return Result.ok(productInfoList);}public List<ProductInfo> getProductInfoList(Integer type) {ProductInfo productInfo3 = new ProductInfo(3l,800,20,"哈密瓜1",1,port);ProductInfo productInfo1 = new ProductInfo(1l,50,8,"苹果1",1,port);ProductInfo productInfo2 = new ProductInfo(2l,200,13,"牛肉1",2,port);ProductInfo productInfo4 = new ProductInfo(4l,50,9,"青菜1",2,port);/*        实际项目中,会从数据库查出数据 */List<ProductInfo> productInfoList = Arrays.asList(productInfo1,productInfo2,productInfo3,productInfo4);//        根据传入的类型返回指定类型List<ProductInfo> result = productInfoList.stream().filter(productInfo -> productInfo.getType() == type).collect(Collectors.toList());return result;}
}

2.2、Apache HttpClient使用

  • get使用
    默认只能同步异步需要加额外的依赖,get请求不能携带参数,只能通过拼接路径
        <!--异步请求--><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpasyncclient</artifactId></dependency>
    public static void get(CloseableHttpClient httpClient,String url){
//            连接对象try {
//        HttpGet不能携带参数,如果需要参数只能通过拼接HttpGet httpGet = new HttpGet(url+"?type=1");String execute = httpClient.execute(httpGet, response -> {JSONObject entries = new JSONObject(EntityUtils.toString(response.getEntity()));Result result = JSONUtil.toBean(entries, Result.class);if (result.getCode() == 200) {String data = result.getData().toString();System.out.println(data);return data;} else {System.err.println(result.getMessage());return result.getMessage();}});System.out.println("get成功结果:"+execute);} catch (Exception e) {e.printStackTrace();}}
  • post
    post请求,通过setEntity()给HttpPost对象添加请求对象
    public static void post(CloseableHttpClient httpClient,String url){HttpPost httpPost = new HttpPost(url);User user = new User();user.setPost(1);
//        添加参数对象httpPost.setEntity(new StringEntity(JSONUtil.toJsonStr(user)));// 设置请求头httpPost.setHeader(HttpHeaders.CONTENT_TYPE, "application/json");try {String execute = httpClient.execute(httpPost, response -> {JSONObject entries = new JSONObject(EntityUtils.toString(response.getEntity()));Result result = JSONUtil.toBean(entries, Result.class);if (result.getCode() == 200) {String data = result.getData().toString();log.info(data);return data;} else {log.error(result.getMessage());return result.getMessage();}});log.info("HttpClient的post成功结果:"+execute);} catch (IOException e) {e.printStackTrace();}}
  • 全部代码

执行步骤

  1. 创建CloseableHttpClient对象
  2. 创建get获取post请求对象
  3. 通过execute()方法发送请求
  4. 通过response.getEntity()获取响应回来的数据
@Slf4j
public class HttpClientUtil {private static String postUrl = "http://localhost:8202/productInfo/index/post";private static String getUrl = "http://localhost:8202/productInfo/index/get";public static void main(String[] args) {try {
//            创建客户端对象CloseableHttpClient client = HttpClients.createDefault();get(client,getUrl);post(client,postUrl);client.close();} catch (IOException e) {e.printStackTrace();}}public static void get(CloseableHttpClient httpClient,String url){
//            连接对象try {
//        HttpGet不能携带参数,如果需要参数只能通过拼接HttpGet httpGet = new HttpGet(url+"?type=1");String execute = httpClient.execute(httpGet, response -> {JSONObject entries = new JSONObject(EntityUtils.toString(response.getEntity()));Result result = JSONUtil.toBean(entries, Result.class);if (result.getCode() == 200) {String data = result.getData().toString();log.info(data);return data;} else {log.info(result.getMessage());return result.getMessage();}});log.info("HttpClient的get成功结果:"+execute);} catch (Exception e) {e.printStackTrace();}}public static void post(CloseableHttpClient httpClient,String url){HttpPost httpPost = new HttpPost(url);User user = new User();user.setPost(1);
//        添加参数对象httpPost.setEntity(new StringEntity(JSONUtil.toJsonStr(user)));// 设置请求头httpPost.setHeader(HttpHeaders.CONTENT_TYPE, "application/json");try {String execute = httpClient.execute(httpPost, response -> {JSONObject entries = new JSONObject(EntityUtils.toString(response.getEntity()));Result result = JSONUtil.toBean(entries, Result.class);if (result.getCode() == 200) {String data = result.getData().toString();log.info(data);return data;} else {log.error(result.getMessage());return result.getMessage();}});log.info("HttpClient的post成功结果:"+execute);} catch (IOException e) {e.printStackTrace();}}
}

2.3 、OkHttp使用

执行步骤

  1. 创建OkHttpClient对象,用于配置和管理HTTP请求的行为
  2. 创建Request对象,用于描述要发送的HTTP请求。Request对象包含了URL、请求方法、请求头、请求体等信息。
  3. 创建Call对象,使用OkHttpClient的newCall()方法,传入Request对象,创建一个Call对象,Call对象表示一次HTTP请求的调用,可以用于执行同步或异步的请求。
  4. 执行请求,同步通过Call对象的execute()方法来;异步通过Call对象的enqueue()方法来执行请求,并通过回调函数处理响应
  5. 解析响应,通过response.body()得到响应的内容在通过json解析。
@Slf4j
public class OkHttpUtil {private static String postUrl = "http://localhost:8202/productInfo/index/post";private static String getUrl = "http://localhost:8202/productInfo/index/get";public static void main(String[] args) {OkHttpClient client = new OkHttpClient().newBuilder().connectTimeout(30, TimeUnit.SECONDS) //连接超时时间.writeTimeout(30,TimeUnit.SECONDS)  //请求超时时间.readTimeout(30,TimeUnit.SECONDS)  //响应超时时间.build();
//        get(client);
//        asyncGet(client);
//        post(client);asyncPost(client);}/*** 同步get* @param client        * @return void*/public static void get(OkHttpClient client){
//        创建get请求对象Request request = new Request.Builder().url(getUrl+"?type=1").get().header("Content-Type", "application/json") // 设置Content-Type请求头.build();try {
//            返回响应对象Response response = client.newCall(request).execute();
//              验证响应是否成功if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
//              解码对象Result result = JSONUtil.toBean(response.body().string(), Result.class);Object data = result.getData();System.out.println(data);} catch (IOException e) {e.printStackTrace();}}/*** 异步get* @param client* @return void*/public static void asyncGet(OkHttpClient client){//        创建get请求对象Request request = new Request.Builder().url(getUrl+"?type=1").get()   //不指定请求方式默认是get.build();
//           异步发送请求,没有返回结果client.newCall(request).enqueue(new Callback() {//               处理失败请求@Overridepublic void onFailure(Call call, IOException e) {log.debug("Unexpected code " + e.getMessage());e.printStackTrace();}//            处理成功请求@Overridepublic void onResponse(Call call, Response response) throws IOException {
//              验证响应是否成功if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
//              解码对象Result result = JSONUtil.toBean(response.body().string(), Result.class);Object data = result.getData();System.out.println(data);}});}/*** 同步post* @param client* @return void*/public static void post(OkHttpClient client){User user = new User();user.setPost(1);String str = JSONUtil.toJsonStr(user);Request request = new Request.Builder().url(postUrl).post(RequestBody.create(MediaType.parse(ContentType.JSON.getValue()), str)).build();Call call = client.newCall(request);try {Response response = call.execute();//              验证响应是否成功if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
//              解码对象Result result = JSONUtil.toBean(response.body().string(), Result.class);Object data = result.getData();log.info("post请求成功,返回结果:{}",data);} catch (IOException e) {e.printStackTrace();}}/*** 异步post请求* @param client        * @return void*/public static void asyncPost(OkHttpClient client){User user = new User();user.setPost(1);
//          把对象转为json字符串String str = JSONUtil.toJsonStr(user);Request request = new Request.Builder().url(postUrl).post(RequestBody.create(MediaType.parse(ContentType.JSON.getValue()), str)).build();Call call = client.newCall(request);
//       异步请求没返回call.enqueue(new Callback() {
//            请求异常@Overridepublic void onFailure(Call call, IOException e) {log.debug("Unexpected code " + e.getMessage());e.printStackTrace();}
//            请求成功@Overridepublic void onResponse(Call call, Response response) throws IOException {//              验证响应是否成功if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
//              解码对象Result result = JSONUtil.toBean(response.body().string(), Result.class);Object data = result.getData();log.info("异步post请求成功,返回结果:{}",data);}});}
}

2.4、WebClient使用

执行步骤:

  1. 创建WebClient对象,推荐使用WebClient.builder()的方式创建,因为可以自定义配置客户端的参数,直接new是只能使用默认的配置。

  2. 构建请求,直接通过webClient对象,如get()、post()等,构建一个请求(如果没有指定请求方式),默认是get请求。

  3. 处理响应:使用响应对象(如Mono、Flux等)来处理响应数据。你可以通过操作符(如map()、flatMap()等)对响应进行转换、过滤、合并等操作。

  4. 订阅响应:使用subscribe()方法来订阅响应流,启动请求并处理响应数据。你可以通过回调函数或操作符链来处理响应数据。

@Component
@Slf4j
public class WebClientUtil {private static String postUrl = "http://localhost:8202/productInfo/index/post";private static String getUrl = "http://localhost:8202/productInfo/index/get";/*** 同步执行get请求* @param webClient* @return void*/public void get(WebClient webClient){Mono<Result> mono = webClient.get().uri(getUrl + "?type=2").retrieve().bodyToMono(Result.class);//        获取返回结果 block()会进行堵塞,等待返回结果Result result = mono.block();if (result.getCode()==200){log.info("get请求返回结果{}",result.getData());}}/*** 异步get* @return void*/public void asyncGet(){HttpClient client = HttpClient.create().option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000)  //设置连接超时.doOnConnected(conn -> conn.addHandler(new ReadTimeoutHandler(10, TimeUnit.SECONDS)) //写入超时.addHandler(new WriteTimeoutHandler(10))); //读取超时//        也可以以这种方式创建WebClient可以添加请求头和url以及一些参数;WebClient webClient = WebClient.builder().clientConnector(new ReactorClientHttpConnector(client)).baseUrl(getUrl).defaultHeader(HttpHeaders.USER_AGENT, "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko)")
//                .defaultCookie()  //添加请求Cookie.build();//        获取返回结果Mono<Result> mono = webClient.get().uri( "?type=2")// 请求路径,会拼接上面的.accept(MediaType.APPLICATION_JSON)//                .retrieve() //获取响应体
//                .bodyToMono(Result.class);  //指定获取的类型,直接获取结果。//                或者通过该方式手动处理结果.exchangeToMono(response->{if (response.statusCode().equals(HttpStatus.OK)) {
//                        成功返回return response.bodyToMono(Result.class);}else {
//                        失败返回return response.createException().flatMap(Mono::error);}});//        异步获取返回结果mono.subscribe(result -> {if (result.getCode() == 200) {log.info("get请求返回结果{}", result.getData());}});System.out.println("执行完成");}/*** 同步post* @return void*/public void post(){// 创建 WebClient 对象WebClient webClient = WebClient.builder().baseUrl(getUrl).build();User user = new User();user.setPost(2);Mono<Result> mono = webClient.post().uri(postUrl).contentType(MediaType.APPLICATION_JSON).header("token","12321412").body(BodyInserters.fromValue(user)).retrieve().bodyToMono(Result.class);Result result = mono.block();if (result.getCode()==200){log.info("post请求返回结果{}",result.getData());}}/*** WebClient异步请求* @return void*/public void asyncPost(){// 创建 WebClient 对象WebClient webClient = WebClient.builder().baseUrl(getUrl).build();User user = new User();user.setPost(2);Mono<Result> mono = webClient.post().uri(postUrl).contentType(MediaType.APPLICATION_JSON)  //指定类型.header("token","12321412")  //添加请求头.body(BodyInserters.fromValue(user)) //添加请求对象.retrieve().bodyToMono(Result.class);
//          异步请求mono.subscribe(result -> {if (result.getCode()==200){log.info("post异步请求返回结果{}",result.getData());}});}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/609620.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Deno 1.22 发布

目录 更新默认的类型检查模式 移除Deno.emit()Deno.formatDiagnostics()和Deno.applySourceMap() API 默认启用Deno命名空间 --no-config标识 Navigator.userAgent 更新 Deno.resolveDns() API 引入新的Response.json()静态方法 在 LSP 默认启用 Linting 对测试运行程…

资源调度(2)-----pod的亲和性和反亲和性

集群调度: schedule的调度算法。 预算策略&#xff1a;过滤出合适的节点 优先策略&#xff1a; 选择部署的节点 nodeName:硬匹配&#xff0c;不走调度策略。node01. nodeSelector&#xff1a;根据节点的标签选择&#xff0c;会走调度算法。 只要是走调度算法&#xff0c;在不满…

[VSCode] VSCode 常用快捷键

文章目录 VSCode 源代码编辑器VSCode 常用快捷键分类汇总01 编辑02 导航03 调试04 其他05 重构06 测试07 扩展08 选择09 搜索10 书签11 多光标12 代码片段13 其他 VSCode 源代码编辑器 官网&#xff1a;https://code.visualstudio.com/ 下载地址&#xff1a;https://code.visua…

【排序算法】二、希尔排序(C/C++)

「前言」文章内容是排序算法之希尔排序的讲解。&#xff08;所有文章已经分类好&#xff0c;放心食用&#xff09; 「归属专栏」排序算法 「主页链接」个人主页 「笔者」枫叶先生(fy) 目录 希尔排序1.1 原理1.2 代码实现&#xff08;C/C&#xff09;1.3 特性总结 希尔排序 1.1…

数据结构-测试1

一、判断题 1.队列中允许插入的一端叫队头&#xff0c;允许删除的一端叫队尾&#xff08;F&#xff09; 队列中允许删除的一端叫队头&#xff08;front&#xff09;,允许插入的一端叫队尾&#xff08;rear&#xff09; 2. 完全二叉树中&#xff0c;若一个结点没有左孩子&#…

Developer Tools for Game Creator 1

插件包含: 持久世界时间管理系统 单击以生成对象或预设 游戏内调试控制台 游戏内事件控制台 控制台管理控制 命令模板脚本 游戏内屏幕截图 低分辨率和高分辨率图像 缩略图生成 移动支持 使用Game Creator Action或拖放来激活和控制组件,无需编码。 通过此资产,您可以获得: …

初识 Elasticsearch 应用知识,一文读懂 Elasticsearch 知识文集(1)

文章目录 &#x1f3c6; 初识 Elasticsearch 应用知识&#x1f50e; 初识 Elasticsearch 应用知识(1)&#x1f341;&#x1f341; 01、什么是 Elasticsearch&#xff1f;&#x1f341;&#x1f341; 02、能列出 10 个使用 Elasticsearch 作为其搜索引擎或数据库的公司吗&#x…

2023 年度合辑 | 出海大年的全球化产品洞察和服务动向

2023 年度合辑 年度关键词 出海&全球化 出海 & 全球化通信服务全面升维 出海大年&#xff0c;融云全球互联网通信云作为“全球化最佳基础设施”之一&#xff0c;发挥技术沉淀和实践积累带来的核心优势&#xff0c;结合市场变化对出海 & 全球化通信服务进行了全方位…

李沐之神经网络基础

目录 1.模型构造 1.1层和块 1.2自定义块 1.3顺序块 1.4在前向传播函数中执行代码 2.参数管理 2.1参数访问 2.2参数初始化 3.自定义层 3.1不带参数的层 3.2带参数的层 4.读写文件 4.1加载和保存张量 4.2加载和保存模型参数 1.模型构造 1.1层和块 import torch fr…

c JPEG编码,但有错误

#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdlib.h> #include <unistd.h> #include <sys/ioctl.h> #include <linux/videodev2.h> //v4l2 头文件 #include <strin…

MySQL之数据的导入、导出远程备份

目录 一. navicat的导入、导出 1.1 导入 1.2 导出 二. mysqldump命令导入、导出 2.1 导出 2.2 导入 三. LOAD DATA INFILE 命令导入、导出 3.1 设置 3.2 导出 3.3 导入 3.4 查看secure_file_priv设置 四. 远程备份 4.1 导出 4.2 导入 五. 思维导图 一. navicat的导入、导…

podman configure insecure certificate registry【podman 设置非安全镜像仓库】

预备条件 docker registry仓库私搭并配置证书centos 7.9 部署 harbor 镜像仓库实践harbor 部署入门指南Podman 部署私有镜像仓库 设置 $ vim /etc/hosts 192.168.23.47 registry.ghostwritten.com$ vim /etc/containers/registries.conf ... [[registry]] location "r…

7.2 1D PARALLEL CONVOLUTION—A BASIC ALGORITHM

正如我们在第7.1节中提到的&#xff0c;所有输出&#xff08;P&#xff09;元素的计算可以在卷积中并行完成。这使得卷积成为并行计算的理想问题。根据我们在矩阵-矩阵乘法方面的经验&#xff0c;我们可以快速编写一个简单的并行卷积内核。为了简单起见&#xff0c;我们将从1D卷…

【liunx】线程池+单例模式+STL,智能指针和线程安全+其他常见的各种锁+读者写者问题

线程池单例模式STL,智能指针和线程安全其他常见的各种锁读者写者问题 1.线程池2.线程安全的单例模式3.STL,智能指针和线程安全4.其他常见的各种锁4.读者写者问题 喜欢的点赞&#xff0c;收藏&#xff0c;关注一下把&#xff01; 1.线程池 目前我们学了挂起等待锁、条件变量、信…

【排序算法】一、排序概念和直接插入排序(C/C++)

「前言」文章内容是排序算法之直接插入排序的讲解。&#xff08;所有文章已经分类好&#xff0c;放心食用&#xff09; 「归属专栏」排序算法 「主页链接」个人主页 「笔者」枫叶先生(fy) 目录 一、排序概念的介绍二、直接插入排序2.1 原理2.2 代码实现&#xff08;C/C&#xf…

Linux的网络设置

一.查看网络配置 1.查看网络接口信息 - ifconfig ① 直接使用 ifconfig 命令 默认显示活动的网卡 解析&#xff1a; ② ifconfig 具体网卡名称 只显示具体的网卡的信息 ③ ifconfig -a 显示所有的网卡 ④ ifconfig 网卡名称 down 关闭网卡 ifdown 关闭网卡 …

2024年01月微软更新Bug 已解决 !Explorer.EXE 提示:Windows无法访问指定设备、路径或文件。你可能没有适当的权限访问该项目。

前倾概要 近期大量出现如上图问题&#xff0c;杀毒&#xff0c;系统急救箱都没反应&#xff0c;罪魁祸首就是微软更新&#xff01; 点击什么都是&#xff1a;Windows无法访问指定设备、路径或文件。你可能没有适当的权限访问该项目。 但软件使用正常&#xff0c;还能通过建立…

【产品应用】一体化伺服电机在管道检测机器人中的应用

一体化伺服电机在管道检测机器人的应用正日益受到关注。管道检测机器人是一种能够在管道内部进行检测和维护的智能化设备&#xff0c;它可以检测管道的内部结构、泄漏、腐蚀等问题&#xff0c;以确保管道的安全和稳定运行。而一体化伺服电机作为机器人的动力源&#xff0c;对于…

20230403读书笔记|《苏轼词集》——试问岭南应不好,此心安处是吾乡

20230403读书笔记|《苏轼词集》——试问岭南应不好&#xff0c;此心安处是吾乡 导读卷一卷二卷三 在书架里加了好几本苏轼词集&#xff0c;很多词是重复的&#xff0c;但这并不影响多读几本&#xff0c;苏轼的词豪迈大气&#xff0c;豁达爽朗&#xff0c;蛮值得一读的。有不少都…

中小型家具制造业使用制造管理MES系统应该注意什么?

随着人们生活水平变高&#xff0c;人们对家具的要求也在提高。为了应对越来越高的要求&#xff0c;企业开始寻找更有效的方法&#xff0c;其中就包括mes系统&#xff0c;那么中小型家具企业在使用mes的过程中应该注意什么呢&#xff1f; 第一&#xff0c;要考虑选择什么样的mes…