当前位置: 首页 > news >正文

使用IDEA+Maven实现MapReduced的WordCount

使用IDEA+Maven实现MapReduce

准备工作

  1. 在桌面创建文件wordfile1.txt
I love Spark
I love Hadoop
  1. 在桌面创建文件wordfile2.txt
Hadoop is good
Spark is fast

上传文件到Hadoop

# 启动Hadoop
cd /usr/local/hadoop
./sbin/start-dfs.sh
# 删除HDFS的hadoop对应的input和output目录,确保后面程序运行不会出现问题(如果有)
cd /usr/local/hadoop
./bin/hdfs dfs -rm -r input
./bin/hdfs dfs -rm -r output
# 新建input目录
./bin/hdfs dfs -mkdir input
# 上传本地文件系统中的文件
./bin/hdfs dfs -put ~/Desktop/wordfile1.txt input
./bin/hdfs dfs -put ~/Desktop/wordfile2.txt input

IDEA创建项目

创建Maven项目

我的项目名是MapReduce,可以自己修改。
IDEA自带Maven,如果需要自己安装Maven可以参考安装Maven
创建项目,选择Maven,模板可以选择第一个maven-archetype-archetype

创建java 文件(WordCount)

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.GenericOptionsParser;import java.io.IOException;
import java.util.Iterator;
import java.util.StringTokenizer;public class WordCount2 {public WordCount2() {}public static void main(String[] args) throws Exception {// 创建一个Configuration对象,用于配置MapReduce作业Configuration conf = new Configuration();// 使用GenericOptionsParser解析命令行参数并判断String[] otherArgs = (new GenericOptionsParser(conf, args)).getRemainingArgs();if(otherArgs.length < 2) {System.err.println("Usage: buycount <in> [<in>...] <out>");System.exit(2);}// 创建一个MapReduce作业实例,并设置作业名称。Job job = Job.getInstance(conf, "buy count");//  指定包含作业类的jar文件job.setJarByClass(WordCount2.class);//  设置Mapper类。job.setMapperClass(WordCount2.TokenizerMapper.class);// 设置Combiner类,Combiner是Map端的一个可选优化步骤,可以减少传输到Reduce端的数据量。job.setCombinerClass(WordCount2.IntSumReducer.class);// 设置Reducer类job.setReducerClass(WordCount2.IntSumReducer.class);// 设置作业输出键和值的类型。job.setOutputKeyClass(Text.class);job.setOutputValueClass(IntWritable.class);// 为作业添加输入路径。FileInputFormat.addInputPath(job, new Path(otherArgs[0]));// 设置作业的输出路径。FileOutputFormat.setOutputPath(job, new Path(otherArgs[1]));// 等待作业完成,并根据作业是否成功来设置退出状态。System.exit(job.waitForCompletion(true)?0:1);}/**定义了一个名为TokenizerMapper的Mapper类,* 它继承自Hadoop的Mapper类,* 并指定了输入键、输入值、输出键和输出值的类型。* 计算每个单词的个数* */public static class TokenizerMapper extends Mapper<Object, Text, Text, IntWritable> {// one用于在map方法中输出计数为1private static final IntWritable one = new IntWritable(1);// word用于存储当前处理的单词。private Text word = new Text();public TokenizerMapper() {}// 接收输入键值对和上下文对象,public void map(Object key, Text value, Mapper<Object, Text, Text, IntWritable>.Context context) throws IOException, InterruptedException {// 使用StringTokenizer分割输入文本行,并为每个单词输出一个键值对(单词,1)。StringTokenizer itr = new StringTokenizer(value.toString());while(itr.hasMoreTokens()) {this.word.set(itr.nextToken());context.write(this.word, one);}}}/** 定义了一个名为IntSumReducer的Reducer类,* 它继承自Hadoop的Reducer类,* 并指定了输入键、输入值、输出键和输出值的类型。* */public static class IntSumReducer extends Reducer<Text, IntWritable, Text, IntWritable> {// 存储单词的总计数private IntWritable result = new IntWritable();public IntSumReducer() {}// reduce方法,它接收输入键、值的集合和上下文对象public void reduce(Text key, Iterable<IntWritable> values, Reducer<Text, IntWritable, Text, IntWritable>.Context context) throws IOException, InterruptedException {// 遍历值的集合,计算单词的总计数。int sum = 0;IntWritable val;for(Iterator i$ = values.iterator(); i$.hasNext(); sum += val.get()) {val = (IntWritable)i$.next();}// 设置结果并输出。this.result.set(sum);context.write(key, this.result);}}
}

添加依赖(pom.xml)

记得修改自己的hadoop的版本和Java_Home的路径
打包时记得修改main方法的位置

  <build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-shade-plugin</artifactId><version>3.6.0</version><executions><execution><phase>package</phase><goals><goal>shade</goal></goals><configuration><transformers><transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"><!-- main()所在的类,注意修改 --><mainClass>WordCount</mainClass></transformer></transformers></configuration></execution></executions></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>7</source><target>7</target></configuration></plugin></plugins></build><!-- 环境配置 --><properties><hadoop.version>3.3.5</hadoop.version><JAVA_HOME>C:\lang\Java\jdk1.8.0_151</JAVA_HOME></properties><dependencies><!-- 打包工具 --><dependency><groupId>jdk.tools</groupId><artifactId>jdk.tools</artifactId><version>1.8</version><scope>system</scope><systemPath>${JAVA_HOME}/lib/tools.jar</systemPath></dependency><!-- Hadoop --><dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-common</artifactId><version>${hadoop.version}</version></dependency><dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-client</artifactId><version>${hadoop.version}</version></dependency><dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-hdfs</artifactId><version>${hadoop.version}</version></dependency><dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-mapreduce-client-core</artifactId><version>${hadoop.version}</version></dependency></dependencies>

设置完成后重新加载Maven
在这里插入图片描述

Maven 打包

IDEA的终端运行以下代码

mvn clean package

打包完成后可以查看target文件夹中是否有MapReduce-2.0-SNAPSHOT.jar
在这里插入图片描述
在这里插入图片描述
打包过程可能存在的报错

  1. No compiler is provided in this environment. Perhaps you are running on a JRE rather than a JDK?
    没有配置Java_Home,在系统环境变量中配置Java_Home

在虚拟机运行jar包

  1. 复制jar包(MapReduce-2.0-SNAPSHOT.jar)到虚拟机的桌面或其他位置
  2. 在终端运行以下代码
cd /usr/local/hadoop
# jar包位置需要根据自己的位置修改
./bin/hadoop jar ~/Desktop/MapReduce-2.0-SNAPSHOT.jar input output

上面命令执行以后,当运行顺利结束时,屏幕上会显示类似如下的信息:

... //这里省略若干屏幕信息
2023-06-17 02:50:31,862 INFO mapred.LocalJobRunner: reduce task executor complete.
2023-06-17 02:50:32,532 INFO mapreduce.Job:  map 100% reduce 100%
2023-06-17 02:50:32,533 INFO mapreduce.Job: Job job_local51129470_0001 completed successfully
2023-06-17 02:50:32,578 INFO mapreduce.Job: Counters: 36    
... //这里省略若干屏幕信息

在这里插入图片描述
词频统计结果已经被写入了HDFS的“/user/hadoop/output”目录中,可以执行如下命令查看词频统计结果:

cd /usr/local/hadoop
./bin/hdfs dfs -cat output/*

如果要再次运行,需要首先删除HDFS中的output目录,否则会报错。
在这里插入图片描述

题目二

题目:
假设你有一个包含用户购买记录的文本文件,每行记录包含用户ID、商品ID和购买数量,格式如“user1,item1,2”。请编写一个MapReduce程序来处理这个文件,统计每个用户购买商品的总数量,并输出每个用户及其购买的总商品数。下面是一个示例
用户购买记录的文本文件

user1,item1,2
user1,item2,3
user2,item1,1
user3,item3,4
user1,item3,1
user2,item2,2

输出

user1 6 user2 3 user3 4

要求:

  • 使用Java或Python等支持MapReduce的编程语言编写。
  • 详细描述Map函数和Reduce函数的实现逻辑。
    给出运行程序所需的输入文件示例和预期输出结果。

实现

  1. 在虚拟机桌面创建文件(buy_count.txt)添加内容并上传文件到Hadoop
# 启动Hadoop
cd /usr/local/hadoop
./sbin/start-dfs.sh
# 删除HDFS的hadoop对应的input和output目录,确保后面程序运行不会出现问题
cd /usr/local/hadoop
./bin/hdfs dfs -rm -r input
./bin/hdfs dfs -rm -r output
# 新建input目录
./bin/hdfs dfs -mkdir input
# 上传本地文件系统中的文件
./bin/hdfs dfs -put ~/Desktop/buy_count.txt input
  1. 创建Java文件(BuyCount)
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.GenericOptionsParser;import java.io.IOException;
import java.util.Iterator;public class BuyCount {public BuyCount() {}public static void main(String[] args) throws Exception {// 创建一个Configuration对象,用于配置MapReduce作业Configuration conf = new Configuration();// 使用GenericOptionsParser解析命令行参数并判断String[] otherArgs = (new GenericOptionsParser(conf, args)).getRemainingArgs();if(otherArgs.length < 2) {System.err.println("Usage: buycount <in> [<in>...] <out>");System.exit(2);}// 创建一个MapReduce作业实例,并设置作业名称。Job job = Job.getInstance(conf, "buy count");//  指定包含作业类的jar文件job.setJarByClass(BuyCount.class);//  设置Mapper类。job.setMapperClass(BuyCount.TokenizerMapper.class);// 设置Combiner类,Combiner是Map端的一个可选优化步骤,可以减少传输到Reduce端的数据量。job.setCombinerClass(BuyCount.IntSumReducer.class);// 设置Reducer类job.setReducerClass(BuyCount.IntSumReducer.class);// 设置作业输出键和值的类型。job.setOutputKeyClass(Text.class);job.setOutputValueClass(IntWritable.class);// 为作业添加输入路径。FileInputFormat.addInputPath(job, new Path(otherArgs[0]));// 设置作业的输出路径。FileOutputFormat.setOutputPath(job, new Path(otherArgs[1]));// 等待作业完成,并根据作业是否成功来设置退出状态。System.exit(job.waitForCompletion(true)?0:1);}/**定义了一个名为TokenizerMapper的Mapper类,* 它继承自Hadoop的Mapper类,* 并指定了输入键、输入值、输出键和输出值的类型。* 计算每个单词的个数* */public static class TokenizerMapper extends Mapper<Object, Text, Text, IntWritable> {// one用于在map方法中输出计数为1private static final IntWritable one = new IntWritable(1);// word用于存储当前处理的单词。private Text word = new Text();public TokenizerMapper() {}// 接收输入键值对和上下文对象,// 会得到每一行public void map(Object key, Text value, Mapper<Object, Text, Text, IntWritable>.Context context) throws IOException, InterruptedException {String[] strs = value.toString().split(",");this.word.set(strs[0]);int num =  Integer.parseInt(strs[2]);context.write(this.word, new IntWritable(num));}}/** 定义了一个名为IntSumReducer的Reducer类,* 它继承自Hadoop的Reducer类,* 并指定了输入键、输入值、输出键和输出值的类型。* */public static class IntSumReducer extends Reducer<Text, IntWritable, Text, IntWritable> {// 存储单词的总计数private IntWritable result = new IntWritable();public IntSumReducer() {}// reduce方法,它接收输入键、值的集合和上下文对象// 将相同的结果进行相加public void reduce(Text key, Iterable<IntWritable> values, Reducer<Text, IntWritable, Text, IntWritable>.Context context) throws IOException, InterruptedException {// 遍历值的集合,计算单词的总计数。int sum = 0;IntWritable val;for(Iterator i$ = values.iterator(); i$.hasNext(); sum += val.get()) {val = (IntWritable)i$.next();}// 设置结果并输出。this.result.set(sum);context.write(key, this.result);}}
}
  1. 修改pom.xml中的mainClass
    在这里插入图片描述
  2. 在虚拟机运行jar包
cd /usr/local/hadoop
# 删除output目录
./bin/hdfs dfs -rm -r output
# jar包位置需要根据自己的位置修改
./bin/hadoop jar ~/Desktop/MapReduce-2.0-SNAPSHOT.jar input output
# 查看统计结果
./bin/hdfs dfs -cat output/*

在这里插入图片描述
我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=156a5nk5kjl84

相关文章:

使用IDEA+Maven实现MapReduced的WordCount

使用IDEAMaven实现MapReduce 准备工作 在桌面创建文件wordfile1.txt I love Spark I love Hadoop在桌面创建文件wordfile2.txt Hadoop is good Spark is fast上传文件到Hadoop # 启动Hadoop cd /usr/local/hadoop ./sbin/start-dfs.sh # 删除HDFS的hadoop对应的input和out…...

go语言示例代码

go语言示例代码&#xff0c; package mainimport "fmt" import "encoding/json"func main() {list : []int{11, 12, 13, 14, 15}for i,x : range list {fmt.Println("i ", i, ",x ", x)}fmt.Println("")for i : range l…...

华为云容器监控平台

首先搜索CCE,点击云容器引擎CCE 有不同的测试&#xff0c;生产&#xff0c;正式环境 工作负载--直接查询服务名看监控 数据库都是走的一个 Redis的查看...

阿里短信发送报错 InvalidTimeStamp.Expired

背景 给客户做的人力资源系统&#xff0c;今天客户用阿里云短信&#xff0c;结果报错&#xff1a; nvalidTimeStamp.Expired Specified time stamp or date value is expired. HTTP Status: 400 RequestID: A 怎么办呢&#xff1f;搜资料&#xff0c; 是客户端时间&#xff…...

Ubuntu问题 -- 设置ubuntu的IP为静态IP (图形化界面设置) 小白友好

目的 为了将ubuntu服务器IP固定, 方便ssh连接人在服务器前使用图形化界面设置 设置 找到自己的网卡名称, 我的是 eno1, 并进入设置界面 查看当前的IP, 网关, 掩码和DNS (注意对应eno1) nmcli dev show掩码可以通过以下命令查看完整的 (注意对应eno1) , 我这里是255.255.255.…...

Sigrity SPEED2000 TDR TDT Simulation模式如何进行时域阻抗仿真分析操作指导-差分信号

Sigrity SPEED2000 TDR TDT Simulation模式如何进行时域阻抗仿真分析操作指导-差分信号 Sigrity SPEED2000 TDR TDT Simulation模式如何进行时域阻抗仿真分析操作指导-单端信号详细介绍了单端信号如何进行TDR仿真分析,下面介绍如何对差分信号进行TDR分析,还是以下图为例进行分…...

Cesium 加载B3DM模型

一、引入Cesium&#xff0c;可以使用该链接下载cesium 链接: https://pan.baidu.com/s/1BRQyaFCkxO2xQQT5RzFUCw?pwdkcv9 提取码: kcv9 在index.html文件中引入cesium <script type"text/javascript" src"/Cesium/Cesium.js"></script> …...

阿里巴巴官方「SpringCloudAlibaba全彩学习手册」限时开源!

最近我在知乎上看过的一个热门回答&#xff1a; 初级 Java 开发面临的最大瓶颈在于&#xff0c;脱离不出自身业务带来的局限。日常工作中大部分时间在增删改查、写写接口、改改 bug&#xff0c;久而久之就会发现&#xff0c;自己的技术水平跟刚工作时相比没什么进步。 所以我们…...

Docker是一个容器化平台注意事项

Docker本身是一个容器化平台&#xff0c;它允许你将应用及其依赖打包到一个可移植的容器中&#xff0c;然后可以在任何安装了Docker的机器上运行这个容器。Docker容器是跨平台的&#xff0c;但有一些限制和注意事项&#xff1a; 跨架构不可行 操作系统兼容性&#xff1a;Docke…...

Redis中的zset用法详解

文章目录 Redis中的zset用法详解一、引言二、zset的基本概念和操作1、zset的添加和删除1.1、添加元素1.2、删除元素 2、zset的查询2.1、获取元素分数2.2、获取元素排名 3、zset的范围查询3.1、按排名查询3.2、按分数查询 三、zset的应用场景1、排行榜1.1、添加玩家得分1.2、获取…...

上位机编程命名规范

1.大小写规范 文件名全部小写是一种广泛使用的命名约定&#xff0c;特别是在跨平台开发和开源项目中。主要原因涉及技术约束、可读性和一致性等方面。以下是原因和优劣势的详细分析&#xff1a; 1. 避免跨平台问题 不同操作系统对文件名的大小写处理方式不同&#xff1a; Li…...

Python 操作mysql - 关系型数据库存储

Python 操作mysql - 关系型数据库存储 文章目录 Python 操作mysql - 关系型数据库存储简单介绍连接数据库创建表插入数据更新数据删除数据查询数据 简单介绍 关系型数据库是一种以“关系”的方式来组织和存储数据的数据库。它使用表&#xff08;也称为“关系”&#xff09;来表…...

React基础知识一

写的东西太多了&#xff0c;照成csdn文档编辑器都开始卡顿了&#xff0c;所以分篇写。 1.安装React 需要安装下面三个包。 react:react核心包 react-dom:渲染需要用到的核心包 babel:将jsx语法转换成React代码的工具。&#xff08;没使用jsx可以不装&#xff09;1.1 在html中…...

游戏行业趋势:“AI、出海、IP”大热下,如何提升竞争力?

游戏&#xff1a;新品供给影响业绩释放节奏&#xff0c;后续游戏新品逐步上线&#xff0c;或驱动板块业绩修复 2024年前三季度A股游戏板块实现营业收入681.8亿元&#xff0c;同比增长5.1%&#xff0c;实现归母净利润73.3亿元&#xff0c;同比下滑30.4%&#xff0c;或主要受 20…...

shell--第一次作业

1.接收用户部署的服务名称 # 脚本入口 read -p "请输入要部署的服务名称&#xff1a;" service_name 2.判断服务是否安装 # 判断服务是否安装 if rpm -q "$service_name" &>/dev/null; then echo "服务 $service_name 已安装。" 已…...

Rust:原子操作 AtomicBool

在 Rust 中&#xff0c;你可以使用 std::sync::atomic 模块来进行原子操作。原子操作在多线程环境中特别有用&#xff0c;因为它们可以确保操作的原子性和可见性&#xff0c;从而避免数据竞争和其他并发问题。 为了读取和设置布尔值&#xff0c;你可以使用 AtomicBool 类型。以…...

深入浅出学算法002-n个1

任务内容 Description 由n个1组成的整数能被K&#xff08;K<10000)整除&#xff0c;n至少为多少&#xff1f; Input 多组测试数据&#xff0c;第一行输入整数T,表示组数 然后是T行&#xff0c;每行输入1个整 数代表K Output 对于每组测试数据输出1行&#xff0c;值为n Sampl…...

GPT1.0 和 GPT2.0 的联系与区别

随着自然语言处理技术的飞速发展&#xff0c;OpenAI 提出的 GPT 系列模型成为了生成式预训练模型的代表。作为 GPT 系列的两代代表&#xff0c;GPT-1 和 GPT-2 虽然在架构上有着继承关系&#xff0c;但在设计理念和性能上有显著的改进。本文将从模型架构、参数规模、训练数据和…...

STM32F103 GPIO和串口实战

本节我们将会对STM32F103的硬件资源GPIO和串口进行介绍。 一、GPIO 1.1 电路原理图 LED电路原理图如下图所示&#xff1a; 其中&#xff1a; LED1连接到PA8引脚&#xff0c;低电平点亮&#xff1b;LED2连接到PD2引脚&#xff0c;低电平点亮&#xff1b; 1.2 GPIO引脚介绍 STM32…...

Go 并发

Go 并发 Go 语言,自2009年发布以来,以其独特的并发模型和简洁的语法在编程界崭露头角。Go 语言的并发机制是其最大的亮点之一,它通过轻量级的线程——goroutine,以及通道(channel)和同步原语,为开发者提供了一种高效、易用的并发编程方式。 Goroutine:Go 语言的并发基…...

vscode(仍待补充)

写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh&#xff1f; debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...

关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案

问题描述&#xff1a;iview使用table 中type: "index",分页之后 &#xff0c;索引还是从1开始&#xff0c;试过绑定后台返回数据的id, 这种方法可行&#xff0c;就是后台返回数据的每个页面id都不完全是按照从1开始的升序&#xff0c;因此百度了下&#xff0c;找到了…...

深入理解JavaScript设计模式之单例模式

目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式&#xff08;Singleton Pattern&#…...

令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍

文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结&#xff1a; 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析&#xff1a; 实际业务去理解体会统一注…...

WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成

厌倦手动写WordPress文章&#xff1f;AI自动生成&#xff0c;效率提升10倍&#xff01; 支持多语言、自动配图、定时发布&#xff0c;让内容创作更轻松&#xff01; AI内容生成 → 不想每天写文章&#xff1f;AI一键生成高质量内容&#xff01;多语言支持 → 跨境电商必备&am…...

自然语言处理——Transformer

自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效&#xff0c;它能挖掘数据中的时序信息以及语义信息&#xff0c;但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN&#xff0c;但是…...

Spring数据访问模块设计

前面我们已经完成了IoC和web模块的设计&#xff0c;聪明的码友立马就知道了&#xff0c;该到数据访问模块了&#xff0c;要不就这俩玩个6啊&#xff0c;查库势在必行&#xff0c;至此&#xff0c;它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据&#xff08;数据库、No…...

佰力博科技与您探讨热释电测量的几种方法

热释电的测量主要涉及热释电系数的测定&#xff0c;这是表征热释电材料性能的重要参数。热释电系数的测量方法主要包括静态法、动态法和积分电荷法。其中&#xff0c;积分电荷法最为常用&#xff0c;其原理是通过测量在电容器上积累的热释电电荷&#xff0c;从而确定热释电系数…...

免费数学几何作图web平台

光锐软件免费数学工具&#xff0c;maths,数学制图&#xff0c;数学作图&#xff0c;几何作图&#xff0c;几何&#xff0c;AR开发,AR教育,增强现实,软件公司,XR,MR,VR,虚拟仿真,虚拟现实,混合现实,教育科技产品,职业模拟培训,高保真VR场景,结构互动课件,元宇宙http://xaglare.c…...

tomcat入门

1 tomcat 是什么 apache开发的web服务器可以为java web程序提供运行环境tomcat是一款高效&#xff0c;稳定&#xff0c;易于使用的web服务器tomcathttp服务器Servlet服务器 2 tomcat 目录介绍 -bin #存放tomcat的脚本 -conf #存放tomcat的配置文件 ---catalina.policy #to…...