Maven创建项目完整指南:从环境配置到依赖管理
发布时间:2026/10/6 9:05:46 作者:尧图编辑部 阅读量:1,286

每次有人问我如何用Maven创建项目我第一反应不是甩给他一条命令而是先问一句你手边的JDK是什么版本、IDEA是什么版本、本机装没装过Maven因为创建项目这件事表面上是敲几下键盘背后牵扯的其实是环境、配置、仓库、镜像这一整套东西。真正在项目开发里让人卡住半天的往往不是创建本身而是创建之后依赖拉不下来、包冲突、构建失败这些破事。Maven是Java生态里最主流的项目管理和构建工具核心就解决三件事依赖管理jar包不用手动下载、复制、构建标准化编译、测试、打包、安装一套命令走完、项目信息管理坐标、版本、模块关系。它的适用面极广从单机学习demo到企业级多模块微服务工程基本都基于Maven搭骨架。这篇文章就从一个新手视角把创建Maven项目的完整链路讲透下载安装、环境变量、配置文件、IDEA实操、pom核心概念、命令行构建、常见问题排查照着做就能一次性跑通。1. 为什么用Maven创建项目从一个依赖报错说起1.1 没有Maven的时候项目有多难搞在没有Maven的年代Java项目里的第三方库全靠手动管理。你要去官网下载jar包复制到项目下的lib目录然后在IDEA里逐个Add to Library。这个过程听着简单实际体验堪称噩梦。先说重复劳动。每个项目都要重复下载一遍jar包不同项目之间互相拷贝。更要命的是版本冲突项目A里用了fastjson 1.2.58项目B里用了1.2.83两个项目各自维护一团jar一旦系统里存在多个版本ClassLoader加载哪个完全看运气报错的时候你根本不知道是哪一层引入的。还有传递依赖的问题你明明只引入了HttpClient结果它还悄悄带了netty、logging、apache commons这些间接依赖你根本不知道哪些jar是被谁依赖进来的。我见过最典型的案例是新同事入职第一天把同事的项目压缩包拷过来跑起来直接报NoClassDefFoundError。查了半天发现他本地lib目录里少了一个xml解析的jar。这种问题在没有依赖管理工具的时代排查成本极高。1.2 Maven解决的三个核心问题Maven用一套模型把上述问题全部收敛了。它把项目里的jar包管理抽象成坐标加仓库的机制每个依赖都有唯一的坐标groupId、artifactId、versionMaven根据坐标去中央仓库下载下载后统一存到本地仓库默认在用户目录的.m2/repository所有项目共享这份本地缓存。这样全机器只有一个仓库不用重复复制。第二是构建的标准化。Maven定义了完整的生命周期clean、compile、test、package、install、deploy每个阶段对应固定的插件和执行顺序。你不需要关心javac怎么调用、class文件输出到哪、jar包怎么打一条mvn package就把整个构建流程跑完。这和工厂流水线一个道理输入是源码输出是产物中间的工序全部标准化。第三是项目结构的约定优于配置。Maven强制了标准目录结构src/main/java放业务源码src/main/resources放配置文件src/test/java放测试代码。新员工接手任何Maven项目都能快速定位不用再靠猜。1.3 Maven与JDK版本对应关系这里必须先说清楚一件事Maven本身是Java写的运行它需要本机装好JDK。但Maven的版本和JDK版本之间存在兼容关系很多人在创建项目前就卡在这一步。Maven版本最低JDK版本建议搭配JDKMaven 3.3.xJDK 1.7JDK 8Maven 3.6.xJDK 1.8JDK 8 / JDK 11Maven 3.8.xJDK 1.8JDK 8 / JDK 11 / JDK 17Maven 3.9.xJDK 8JDK 11 / JDK 17 / JDK 21个人建议如果你是新项目直接用JDK 17配Maven 3.9.x如果是维护老项目比如很多公司还在用JDK 8就老老实实用Maven 3.6.3或3.8.8。JDK版本高于Maven最高支持版本时构建可能报UnsupportedClassVersionError或者莫名其妙的不兼容错误这不是你的代码问题是工具链版本没对齐。1.4 先搞清楚Maven在整条构建链路里的角色工程化的Java开发链路大概是源代码 → Maven管理依赖和构建 → 产出可执行的jar/war包 → 部署到服务器或容器里。Maven处在源代码和运行产物之间它既不写业务逻辑也不管运行时的表现只负责把源码变成产物这个过程。理解这一点很重要因为后面学习过程中你会接触大量概念坐标、仓库、生命周期、插件。别急着背你只需要记住Maven负责全流程的调度这个主线其他的都是围绕主线展开的工具细节。2. 安装与初始化先把环境配到一次成功2.1 下载Maven版本选型与压缩包获取第一步永远是从Apache Maven官网下载正确的发行版。打开官网后你会看到当前版本和历史版本入口页面会列出完整的版本列表。这里我的建议很明确不要下载最新的Source包下载Binary zip archivebin.zipWindows用户选apache-maven-x.x.x-bin.zipmacOS/Linux用户同样下载zip或者tar.gz都行。为什么我只推荐二进制发行版因为源码包需要你自己编译初学者折腾这个纯属浪费时间。下载完之后解压到你想要的位置。Windows我习惯放D:\Java\apache-maven-3.9.9macOS我习惯放/opt/maven下重点不是放哪而是后续环境变量要能准确指到它。一个很常见的疑问是要不要用Homebrew装Mac版Maven或者用包管理器装Linux版。可以但我不推荐新手这么做。因为包管理器装的Maven版本往往不是你想要的而且配置文件的路径经常和官方文档不一致出了事你都不知道去哪找settings.xml。手动解压安装虽然多一步但路径、版本、配置全部可控。2.2 环境变量配置Windows、macOS与LinuxMaven安装完必须配置环境变量否则命令行里输入mvn会提示找不到命令。Windows的实操步骤右键此电脑 → 属性 → 高级系统设置 → 环境变量。在系统变量里新建MAVEN_HOME值填你的Maven解压路径比如D:\Java\apache-maven-3.9.9。在系统变量的Path里追加%MAVEN_HOME%\bin。打开一个新的命令行窗口输入mvn -v验证。macOS/Linux则编辑profile文件在~/.zshrcmacOS默认终端或~/.bashrcUbuntu等Linux发行版末尾追加两行export MAVEN_HOME/opt/apache-maven-3.9.9 export PATH$MAVEN_HOME/bin:$PATH然后执行source ~/.zshrc使配置生效。这里有个细节容易踩坑Windows上配完环境变量后如果你用的是已经打开的命令行窗口需要关掉重开否则不会加载新的环境变量。另外如果你的Path里既有Maven又有多版本Java命令要确认mvn -v输出里的Java version和你的JAVA_HOME一致。如果Maven运行的是错误的JDK版本你后面创建的项目会连带出错。2.3 验证安装mvn -v输出怎么看配置完成后命令行输入mvn -v正常情况下会输出类似结果Apache Maven 3.9.9 (8e8019d9a3f5e09e05b3e8afe5e94d1a7e9d3d4f) Maven home: D:\Java\apache-maven-3.9.9 Java version: 17.0.11, vendor: Oracle Corporation, runtime: D:\Java\jdk-17.0.11 Default locale: zh_CN, platform encoding: UTF-8重点看三行Maven home是否指向你解压的路径Java version的JDK版本是否符合项目要求platform encoding如果是GBK而你的代码是UTF-8后续编译会报乱码问题。遇到编码问题通常需要在mvn命令或pom里强制指定file.encoding后面排查章节会细说。2.4 本地仓库为什么默认位置不推荐怎么改Maven下载的依赖全部存放在本地仓库。默认情况下本地仓库在C:\Users\你的用户名.m2\repositoryWindows或~/.m2/repositoryLinux/macOS。这个默认位置有个大问题C盘空间不足是Windows用户的常态而一个大型项目动辄拉取几百MB甚至几个GB的依赖全堆C盘很容易出事。更现实的场景是你有多块硬盘或者开发环境迁移过默认仓库路径跟实际不匹配。所以我拿到任何一台新机器第一步就是改localRepository。改法很简单找到Maven安装目录下conf/settings.xml搜到localRepository标签默认是被注释掉的取消注释并改成你想要的位置。比如localRepositoryD:/Java/maven-repo/localRepository注意Windows路径在XML里用正斜杠或者双反斜杠不要用单反斜杠。改完后IDEA里也要同步指定这个路径否则IDEA和命令行会各用各的仓库导致IDEA里好好的项目命令行一构建就重新下载一堆东西。3. 配置文件里要做的两件大事阿里云镜像与本地仓库3.1 settings.xml结构速览Maven的全局配置文件是conf/settings.xml每个开发者都可以在~/.m2/settings.xml放一份用户级配置用户级配置会覆盖全局配置。对绝大多数人来说需要动的地方就三个节点localRepository本地仓库位置前面已讲过。mirror镜像配置用来解决下载慢的问题。profile可以包含一堆默认属性最常配的是JDK编译版本和代理仓库。打开settings.xml你会发现它默认把很多配置都注释了你不需要去理解所有节点的含义知道这三个就够上路了。3.2 配置阿里云仓库镜像为什么默认下载那么慢Maven默认去中央仓库repo.maven.apache.org拉取依赖这个仓库架设在国外国内访问经常是龟速尤其是高峰期拉一个大项目的依赖可能十几分钟卡在下载进度条上。这不是你的网络问题是物理距离导致的时延和丢包。解决办法是配置国内镜像。国内最常用的是阿里云公共仓库配置方式是在settings.xml的mirrors节点里加一个mirrormirror idaliyunmaven/id mirrorOf*/mirrorOf name阿里云公共仓库/name urlhttps://maven.aliyun.com/repository/public/url /mirrormirrorOf写*表示所有中央仓库的请求都走阿里云镜像。这个配置把下载速度从可能失败变成几秒完成可以说是我配Maven时优先级最高的事情。新手如果还没配镜像就急着创建项目大概率要等很久。阿里云公共仓库兼容了central和jcenter的绝大多数构件普通项目用它完全够。如果你们公司有私服Nexus那就把mirrorOf改成centralURL指向你们内网Nexus地址拉包更快也更安全。3.3 多镜像配置与第一个匹配生效机制很多人在网上搜到多个镜像配置然后一股脑全粘进mirrors节点结果发现有的生效有的不生效因为Maven对mirror的匹配规则是按照顺序使用第一个匹配成功的mirror。比如你同时配了阿里云和腾讯云两个mirror且mirrorOf都是*那么排在第一个的永远生效第二个等于白配。正确思路是mirrorOf的值要精确控制匹配范围。如果你只想让中央仓库走阿里云其他不走就写mirrorOf为central。如果你还想给某个私服留位置可以配置多个mirror但mirrorOf不要冲突。一个常见的多镜像配置长这样mirrors mirror idaliyun/id mirrorOfcentral/mirrorOf urlhttps://maven.aliyun.com/repository/public/url /mirror mirror idnexus/id mirrorOfinternal-repo/mirrorOf urlhttp://nexus.company.com/repository/maven-public//url /mirror /mirrors这种情况下中央仓库的依赖走阿里云内部仓库的依赖走公司Nexus互不干扰。注意内部仓库的URL要换成你们公司真实的私服地址这里只是示例。3.4 两个本地仓库怎么合并这个问题的标准答案其实很反直觉不要真的把两个仓库目录去合并文件而是选择一个做主仓库让新项目统一指向它然后让旧仓库里的jar包自然地被新仓库复用。我之前在团队里遇到过一台机器上有两个仓库一个在C盘用户目录老项目在用一个在D盘自定义路径新项目配置的。新人开发时IDEA里两个项目分属两个仓库同一套依赖各自拉一遍浪费磁盘也容易混乱。我的处理方式是在settings.xml里把localRepository统一指向空间大的那个通常是D盘那个然后手动删除老的仓库目录。删除前建议先把老仓库里独有的jar确认一遍如果没有用到特殊版本直接删没有任何影响。为什么不建议物理合并因为Maven仓库的结构是groupId/artifactId/version这样的层级目录两个仓库合并时如果存在同名但不同版本的jar你需要逐个比较版本号而且仓库里还有一堆maven-metadata-local.xml之类的元数据文件合并这些文件极易出错。让新项目统一指向旧仓库等于变相完成了合并Maven发现旧仓库里有对应依赖就不会再去远程下载。4. 在IDEA中创建Maven项目从零到能跑4.1 配置IDEA里的Maven三件套IDEA安装后默认使用的是自带的Maven但这个默认配置有两个问题Maven版本可能与命令行不一致而且本地仓库路径一定是C盘的默认位置。所以每次拿到新电脑我第一步都是修改IDEA的Maven配置。打开IDEAFile → Settings → Build, Execution, Deployment → Build Tools → Maven。这里有三项值得改Maven home path选成你自己安装的Maven目录而不是IDEA自带的。User settings file选成你自己修改过的settings.xml勾选Override。Local repository会自动读取settings.xml里的localRepository你也可以在这里手动指定注意要和settings里的配置一致。设置完成后IDEA的Maven行为和命令行就完全统一了。这里的区别很大如果你不OverrideIDEA用的是它内置的Maven和配置你在命令行配好的阿里云镜像、自定义仓库路径全部无法生效依赖下载依然龟速。4.2 创建普通Java工程坐标三要素的填写确认Maven配置无误后开始创建项目。操作路径是File → New → Project左侧选择Maven右侧选择SDKJDK版本然后填写项目坐标。GroupId通常写公司的域名反写比如com.exampleArtifactId写项目模块名比如user-serviceVersion默认1.0-SNAPSHOT新手不用改。这三者合起来就是Maven坐标唯一标识一个项目后续引依赖、发布到仓库全靠它。这里有个细节很多教程会让你勾选Create from archetype但普通Java项目我不建议勾选archetype保持默认的快速启动模板就行。因为archetype的本质是用预定义的骨架生成项目结构选错了骨架反而生成一堆多余文件。IDEA默认的quickstart模板已经包含了src/main/java、src/main/resources、src/test/java这几个核心目录够用了。创建完成后项目目录结构大概是project-name ├── pom.xml ├── src │ ├── main │ │ ├── java │ │ └── resources │ └── test │ └── java4.3 创建Web工程2024版本的推荐做法老版本的IDEA教程都喜欢教你勾选org.apache.maven.archetypes:maven-archetype-webapp然后自动生成web项目。但IDEA 2024版本更推荐的做法是不用archetype先创建普通Java项目再手动添加Web支持目录。具体操作先按4.2的方式创建普通Maven项目然后在main目录下新建webapp目录并在webapp下建WEB-INF目录在WEB-INF里放web.xml文件。如果你的项目用的是Tomcat 10Jakarta Servlet规范web.xml可以只写一个空壳如果你用Servlet 4及以下web.xml需要声明标准的servlet版本头。还有一点值得单独说现代Java Web项目很多不用WAR包放外部Tomcat了而是打成JAR包内嵌Tomcat直接跑。比如Spring Boot项目本质就是一个JAR包根本不关心webapp目录。所以如果你用的是Spring Boot直接创建普通Jar类型项目即可Web目录结构由框架自己管理。4.4 IDEA 2024版本对Maven项目的默认处理IDEA从2022.2之后对Maven项目的支持非常自动pom文件一改动右下角会弹出Maven projects need to be reloaded的提示点一下就会重新加载依赖。2024版本进一步优化了新建流程New Project界面能直接看到Generating的进度条不会像老版本那样长时间无响应。顺便提一个高频场景有时候你拿到的不是标准Maven项目而是一堆纯源码没有pom。这时候别急你可以在IDEA里新建一个Maven项目然后把现有源码的src目录直接拷进新项目的src里再把依赖全部写到pom。这种做法本质上是借壳上市比你自己徒手建目录、配库、配打包快得多我处理老项目时经常用。5. pom.xml才是创建项目的真正核心5.1 坐标三要素的命名规范pom.xml是Maven项目的灵魂创建项目只是画了个壳真正的骨架和血肉都在pom里。先看最基础的坐标三要素groupIdcom.example/groupId artifactIduser-service/artifactId version1.0.0/version packagingjar/packaginggroupId用域名倒写保证全局唯一artifactId用中划线分隔的模块名version一般格式是主版本.次版本.修订版本加上SNAPSHOT后缀代表快照版本开发阶段互相联调用SNAPSHOT正式发布则去掉。packaging可选jar、war、pom纯工具模块用jarWeb项目用war或jar内嵌容器父POM聚合模块用pom。5.2 引入第一个依赖版本号的两种写法最简单的依赖写法是dependency groupIdcn.hutool/groupId artifactIdhutool-all/artifactId version5.8.25/version /dependency依赖是Maven的核心价值在pom里声明坐标Maven自动从仓库下载。但你会发现企业项目里的pom往往不直接写version而是用properties统一管理properties hutool.version5.8.25/hutool.version /properties然后在依赖里引用dependency groupIdcn.hutool/groupId artifactIdhutool-all/artifactId version${hutool.version}/version /dependency这种做法叫版本集中管理。当项目有几十个依赖时你不可能去每个dependency里找版本号统一收敛到properties里升级版本只改一处。如果项目整合了Spring Boot更推荐用spring-boot-starter-parent作为父工程父工程里已经定义好了一整套兼容版本子模块依赖Spring相关组件时可以不写版本号Maven会自动从父POM继承。5.3 依赖scope什么时候影响打包新手最容易忽略的是dependency里的scope标签。scope决定依赖的作用域常见有四种scope编译类路径运行时打包产物典型场景compile默认有有包含几乎所有业务库provided有有容器提供不包含Tomcat等Servlet APIruntime无有包含各种数据库驱动test有仅测试无不包含JUnit等测试库如果你的依赖scope写错了会出现本地跑得好好的打包部署后找不到类的诡异问题。最常见的是Servlet API、JSP API必须用provided因为运行时Tomcat自己提供这些实现如果你打成WAR里还带一份反而可能导致类冲突。反过来数据库驱动要用runtime或者compile否则打包出去没有驱动连不上数据库。5.4 Maven侧边栏的正确用法IDEA右侧的Maven工具窗口View → Tool Buttons → Maven是日常开发用得最多的面板。它默认展示项目所有模块每个模块下面有Lifecycle和Plugins两个列表。Lifecycle里的双击操作clean清空target、compile编译、test跑测试、package打包、install安装到本地仓库、deploy发布到远程仓库。开发过程中最常用的就是clean和install的连招清理旧产物并重装。Plugins列表里则罗列了打包插件、编译插件等一般不用手动点跟着Lifecycle跑就行。右上角的M标志Toggle Maven Projects相当于手动刷新按钮当你改了pom没弹提示或者依赖状态不对时点一下它触发重新加载。还有一个蓝色圆圈的刷新按钮作用是刷新项目依赖。这两个按钮的差别M按钮是重新加载Maven模型刷新按钮是重新下载解析依赖。改pom后不确定就两个都点一遍问题基本能解决。5.5 依赖红线和冲突的现场处理IDEA pom文件里依赖的下方时不时有红色的波浪线把鼠标悬停上去通常提示Cannot resolve symbol或者Packages not found。这个报错本质是Maven解析不到对应坐标。处理步骤按顺序来先看坐标本身是否拼错很多人把fastjson写成fatjson一查一个准。确认网络和镜像配置没问题刚配完镜像时可能因为缓存了失败的记录需要强制更新一次。在Maven侧边栏点击刷新按钮让IDEA重新解析。如果还红在命令行执行mvn dependency:resolve -U-U参数会强制检查远程仓库的最新版本绕过本地失败缓存。如果依赖能解析出来但运行时报NoSuchMethodError那就不是依赖解析问题而是版本冲突。比如项目里引入了A库1.0和B库2.0两个库同时依赖了C库的不同版本Maven默认路径是最近优先往往不是你期望的那个版本。排查冲突用mvn dependency:tree它能输出完整的依赖树你看哪个库同时引了多个版本的同一个jar然后用exclusion在pom里排除掉多余的那个或者用dependencyManagement强行指定版本。6. 从命令行到CI构建项目的常用组合拳6.1 生命周期与核心命令Maven的构建生命周期是一串有序阶段validate → compile → test → package → install → deploy。执行后面某个阶段时前面的阶段会自动执行比如mvn package等价于先validate再compile再test再package。日常开发最常用的几个命令mvn clean # 清理target目录删除上次构建产物 mvn compile # 编译主代码到target/classes mvn test # 运行测试代码 mvn package # 打jar/war包到target目录 mvn install # 打包并安装到本地仓库其他项目可以直接引用 mvn deploy # 打包并发布到远程仓库如Nexus私服注意clean和install的搭配。很多人习惯mvn clean install因为install前先把上次的构建残留清干净避免旧class污染新的产物。这个习惯十分推荐尤其是你改了代码但jar包表现无变化时先clean再install基本能解决。6.2 跳过测试的两种方式及区别构建时想跳过测试有两种命令mvn package -DskipTests mvn package -Dmaven.test.skiptrue区别在于-DskipTests只是不执行测试代码但仍然会编译测试类-Dmaven.test.skiptrue连测试代码都直接不编译比skipTests更彻底。日常开发偶尔跳过测试没问题但在CI环境里我不建议盲目跳过测试回归是保证质量的第一道防线。6.3 VSCode与IDEA之外的Maven使用场景除了IDEAVSCode也可以配置Maven。VSCode里需要安装Extension Pack for Java插件然后在设置项里指定maven.executable.path。创建项目时VSCode的Maven插件会在侧边栏提供Maven面板和mvn命令快捷入口只是IDEA的图形化处理更顺手。如果你用VSCode做Java开发建议把它当成轻量IDEA理解Maven的核心操作逻辑完全一致。前端玩家经常提到的uniapp创建项目支持TypeScript这条工具链跟Maven没有直接关系uniapp走的是npm、yarn这些前端包管理器。但你要做完整的全栈应用后端接口往往是Maven工程前端uniapp通过HTTP调后端接口。所以Maven不是全栈项目里必须懂的部分但是后端Java项目的事实标准懂它可以让你端到端构建更顺畅。6.4 常见报错速查与排查思路做Maven构建必然会遇到各种妖魔鬼怪的报错。我把最常见的几类整理成一张速查表现象原因解决方式mvn不是内部或外部命令环境变量没配好或窗口没重开检查MAVEN_HOME和Path重开命令行下载速度极慢或卡住中央仓库远或镜像没配在settings.xml配阿里云镜像依赖一直红线依赖下载失败网络缓存了失败记录命令行执行mvn -U强制更新或检查坐标编译乱码平台编码不是UTF-8pom里添加project.build.sourceEncodingUTF-8/...打出的jar运行报错no main manifest attribute缺少主类配置pom配置maven-jar-plugin的mainClass执行mvn命令时JDK版本不对JAVA_HOME指向了错误的JDK修改系统环境变量JAVA_HOME并重启终端Spring项目打包后启动报ClassNotFound依赖scope写错运行时被排除了检查provided、runtime的使用举一个乱码问题的例子你mvn install时看到满屏的[ERROR] malformed input around column XX多半是源码文件是GBK编码而Maven默认用了平台编码读取。在pom.xml里加上properties project.build.sourceEncodingUTF-8/project.build.sourceEncoding /properties就能解决绝大多数乱码问题。别小看这一行配置它能避免你在Windows机器上开发、Linux服务器上部署时因为文件编码不同导致的诡异行为。6.5 值得长期养成的构建习惯最后分享几个用Maven多年的好习惯。第一个是先配镜像再建项目新环境的第一件事永远是检查settings.xml有没有配好国内镜像没有就自动跳过整个依赖下载过程。第二个是依赖出问题先看依赖树盲目去pom里乱试版本只会让问题更复杂mvn dependency:tree输出的树状结构能清晰地告诉你每个jar是谁带进来的这是排查冲突的唯一正道。还有一个实际体验尽量保持命令行的Maven和IDEA的Maven用同一个配置同一套版本。我见过太多人IDEA里构建正常一到命令行mvn install就各种报错最后发现是IDEA的Maven路径和命令行不一致。统一之后这类问题直接消失了。这是创建Maven项目这件事里最少有人讲但最该讲的一个坑。