前言

你好,我是A哥(YourBatman)。

如何给Module模块单独增加依赖?

如何知道哪些Module模块用了Spring框架,哪些是web工程?

IDEA如何打Jar包?打War包?

熟练的正确使用IntelliJ IDEA,是一个“高手”该有的样子,因为那是你的门面上篇文章 重点介绍了IDEA里最为重要的两个概念:Project项目和Module模块。相信你看完后再也不会把IDEA的Project比作Eclipse的Workspace,并且对IDEA有了一份更深的了解。

本文继续理解IDEA对项目、模块的管理。管理项目是一个IDE的基本功能,但往往最基础的是最重要的更是最容易被忽略的。因此本文是你更好去理解IDEA管理maven结构、gradle结构、Spring Boot项目结构的基础,万丈高楼平地起,它就是这个地基。上层结构再怎么繁繁多变,殊途同归最终都由Project Structure来体现,从而给开发者以几近相同的编码体验。

本文提纲

版本约定

  • IntelliJ IDEA:2020.3.1

正文

Project Structure是一个你开发过程中偶尔/经常会打开,但却很少用心留意的窗口。不同于一般设置窗口,它和项目的紧密度非常的高且有一定理解难度,若设置不当项目可能无法运行甚至无法编码(比如编译报错、jar包找不着等),为此我做件一般人都不愿意做的事,对它进行详解,相信做难事必有所得。

本文基于上文已搭建好的hello项目案例,继续研究其项目结构Project Structure的管理。从结构查看,到修改定制,那么问题来了,如何打开一个Project项目的结构页呢?

如何打开Project Structure?

看似一个简单的操作,里面其实蕴藏着你对IDEA Project和Module的理解,否则势必不知从哪下手。据了解,也许你是多年的程序员,也未必知道从哪下手。

按照一般思维,会鼠标选中hello,然后右键:



但对不起,右键菜单里并无Project Structure选项。Project Structure顾名思义,是针对Project维度的结构视窗,而你鼠标选中的hello只是个module,所以自然弹出的是对此module的操作菜单喽,而非Project的。也许你可能会讲:我点击了Open Module Settings也打开了Project Structure视窗呀,是的效果上你可能是打开了但道理并非如此,而仅仅是因为把它俩放在了一起(同一视窗)而已。

说明:理解IDEA的Project和Module两大概念,是对IDEA进行一切操作的基础。前文已非常详细(可能是全网最全)的介绍了它俩,可花几分钟前往学习。点这里电梯直达

三种打开方式

要打开一个Project的结构展示窗口,至少有如下三种办法,本文都例举给你。

  1. 顶部菜单File -> Project Structure

  1. 点击右上角的快捷按钮

  1. 快捷键方式(推荐)

这是我本人最喜欢的方式,至于快捷键是哪个就看你是如何设定的喽,我的快捷键是ctrl + shift + alt + s。

啰嗦一句:建议你操作IDEA多用快捷键,那会大大提高编码的效率,并且看起来像高手。基本上记住50个左右快捷键就够用了,长期以往成了肌肉记忆后这就是你的核心竞争力之一了


打开hello项目的结构页如下图所示:

解释:为何不需要鼠标选中项目?

对于这个动作,敏感的你是否有发现:打开项目结构并不需要鼠标选中任何东西(快捷键随意使用),也就是说鼠标失焦状态都没问题,何解呢?

回答这个问题并不难,前提是你已经对IDEA的Project概念烂熟于胸。一个Project对应一个视窗,它们是严格1:1的关系。换句话讲,当前视窗就代表着Project,因此操作本视窗顶部菜单栏就肯定是作用在该Project上,又何须专门选中什么呢?再者,Project只是个逻辑概念,你想选都没得选中的,所以把视窗当作它就好。有没有觉得,这和Java中的this关键字调用特别像?

最后,这个问题的答案是:只要鼠标还在IDEA视窗内(该视窗是活跃窗口),那么对Project就永远就是“选中”状态。

Project Structure项目结构剖析

项目结构视窗已打开,那接下来重点来喽。可以看到它左边的“菜单栏”,共分为三个part:

  • Project Settings:项目设置(最重要),本文详解
  • Platform Settings:平台设置,也叫全局设置。用于管理SDK们(如JDK、Kotlin的SDK等)、全局库。
    • 一般来讲,全局的JDK都会配置在此处,比如我因为经常要做多版本尝试,就管理了多个JDK版本

  • Problems:问题。一般项目出现了问题都会在此体现(如依赖不一致问题等等),总之问题数量一致让它是0是最优的

其中Project Settings里面的每个标签页是最常用,最关心的。下面就对它的每个tab页作出解释和使用说明。

Project页情况

此视窗可以看到Project本身的基础信息。如:名称、SDK版本、语言等级等等,比较简单。

对于此页面的元素,多啰嗦几句:

  1. 为何是SDK版本而不是JDK版本?答:因为IntelliJ IDEA是JVM平台IDEA,不仅仅支持Java还有其它语言如Kotlin,所以写成SDK更抽象
  2. 为何指定了SDK还要指定语言等级?答:因为SDK版本并不直接决定语言等级。如你用的JDK 11,但依旧可以把语言等级调为8来进行编译/运行
    1. 这是集成开发环境的优势所在,轻松对多环境进行定制化支持
  3. SDK和语言等级Project都可指定,作为全局默认
    1. 这些配置Module默认集成,但可自行修改自己的。比如module 1使用Java 5编译,module 2使用Java 11编译,这是允许的

Module页情况

Module页可谓是重点中的重点,甚至是最重要。毕竟Module作为实际存在形式,所有的源代码、配置、依赖等都在这里,因此大有可学呀。

值得注意:Tests测试包里面的是可以访问Sources源码的,但反过来不行。

每个模块都能独立管理着自己的依赖,这种关系在模块自己的.iml文件中记录着。

知识点:

  1. Project创建时默认会创建一个同名的Module模块
  2. Module默认沿用Project的SDK、语言等级等设置,当然也可自己指定
  3. 每个Module可自行管理依赖,可以是二方库、三方库......
  4. 本模块的依赖情况默认存储在项目的{moduleName}.iml文件里

新增依赖

既然Module可以自行管理依赖,那么如何给该模块新增依赖呢?

举个例子,现在需要向hello模块增加一个commons-io jar包依赖,可以点击Dependencies标签页左下角的+号,选择Library:

然后选择,如果没有就选择New Libarary...创建一个呗(有就直接用就成):

下面分别演示选择Java和选择From Maven两种不同库的方式:

新建Java依赖库

New Library新建菜单选项中选择Java选项:

这种方式简单的讲:从你本机里选择一个jar(或者一个目录里面包含jar、文档)就成。优点是非常轻便,不依赖网络,缺点是这些jar必须是你本机已实际存在的。

新建Maven依赖库

New Library新建菜单选项中选择From Maven选项:

输入GAV(或者关键字查找)就能定位到jar,此种方式使用起来其实非常方便,毕竟maven非常好用嘛。缺点自然就是一般情况下需要都需要依赖于网络喽,除非你本地仓库已存在对应的jar。


通过这两种方式各执行一次添加新的依赖完成后,再看hello模块的依赖情况,效果如图:

既然依赖变化了,自然而然的也会体现在hello.iml文件里喽,来看看:

依赖添加进来,源代码里就可以正常使用啦:

依赖作用范围

在New Library创建依赖的时候,不管用哪种方式选中后,它都会弹出这个窗口让你选择此依赖的作用范围

  • Module Library:模块级别,只能本模块使用,别的模块看都看不见
  • Project Library(默认选中):项目级别,该项目下所有的模块均能看见和选中使用
  • Global Library:全局级别,任何项目均可看见和使用

在本例中commons-io是模块级别,commons-lang3是项目级别。因此hello-client模块添加依赖时也是能够看到commons-lang3这个依赖的(但看不见commons-io):

Libraries页情况

当某Library是所有/大部分模块都需要的依赖时,就可以上升为Project级别的依赖,抽取到Libraries标签页来统一管理。如图,因为上面步骤创建的commons-lang3是项目级别的,所以也会出现在这里。

至于如何创建/添加Project级别的依赖,这里就不用再赘述了吧,上面【新增依赖】章节已讲得很明白。唯一区别在该页面选好后不用再选择Library的作用范围了(因为就是Project级别的嘛),取而代之的是让你选择作用的模块:

当然喽,你也可以一个都不选(点击cancle),那么该jar只是被创建了,而不作用于任何module模块。

说明:对于一个多模块的Project来讲,建议项目使用的所有Jar都放在这里统一管理,模块要使用时直接按需choose就成,而不需要自己再单独add,方便统一管理

Facets页情况

Facets可理解为用于配置Project项目的框架区,它能看到项目的每个Module模块使用的框架、语言等情况,并且还可以对它们进行配置。

比如Spring框架,如果某个模块使用了它就可以来这里统一配置。优点是你会发现借助IDEA强大的功能它都给你想好了哪些地方可配置,你可以更改,让你实现配置界面化。除了Spring,其它框架如Hibernate也是如此~

目前支持的Facets(语言/框架)类型有:

模块对应的Facets IDEA会自动Detection探测,若没有你也可以手动添加。

为了更形象的描述此tab页的作用,这里搬一个我自己生产项目来看看实际效果:

说明:不同的Facet对应的最右端窗口内容配置项是不一样的。

通过此视窗,可以看到你当前Project项目,哪些模块使用了Spring框架,哪些是web项目,一目了然。它有个非常大的作用就是站在Project的视角对每个模块进行整体把控,比如若你发现有个模块不需要是web项目(并不需要对外提供服务接口),那铁定就是多引包了或者职责不清晰导致的,就可立马针对性解决,消除隐患。

在实际工作中我自己比较频繁的使用这个功能,用于对模块性质的定位,比如如果是普通模块,绝对不允许是web工程,如果不需要依赖Spring绝对不允许成为Spring工程。因为严格控制Jar包依赖、工程性质是应对大型项目的有效手段。

当然喽,Facets还有个作用是让IDEA编译器认识你的模块,比如如果你是个web模块,若没有在Facets里体现出来,那IDEA就不认识你,就无法给你提供web的一些便捷操作了。

Artifacts页情况

IDEA如何打Jar包?如何打War包? 来,上菜~

在Maven大行其道的今天,虽然用IDEA打包很少使用了,但是有些时候它对你本地调试还是蛮有用的,并且对理解maven的打包依旧有效,来,了解一下。

Artifacts这个概念不是特别好理解,artifact是maven里的一个概念,被IDEA借鉴过来。表示某个模块要何种打包形式,如jar、war exploded、war、ear等等。Artifact是一个项目资源的组合体,整合编译后的 java 文件,资源文件等。有不同的整合方式,比如jar、war、war exploded等等,对于一个module而言,有了Artifact就可以部署了,类似于maven的package打包。

说明:war 和 war exploded区别就是后者不压缩,开发时选后者便于实时看到修改文件后的效果

来个栗子,这里演示下将hello模块打包成一个Jar:

配置好后,只需顶部菜单栏Build -> Build Artifacts,就可以打出这个Jar包:

执行完此命令后,在Output Directory里就能看到hello.jar这个打包好的文件啦。然后java -jar .\hello.jar就能运行喽(因为咱们打的是可执行Jar包)。关于使用IDEA打包还包括打可执行jar包、Fatjar、包外引用jar包等等,这里就不展开了,后面会放在单独文章里把各种方式汇总在一起聊聊。

总的来说,无论配置Facets还是Artifacts,都是Intellij IDEA要求我们来做的(虽然有些可自动识别),目的是以便其能识别这些文件并整合各插件实现功能(如自动化配置、自动打包),一切为了编码体验和编码效率。

模块如何依赖其它Module

一个中大型项目一般有多个模块,它们各司其职。模块与模块之间一般都存在依赖关系,比如常见的xxx-core模块一般会被其它几乎所有模块所依赖。模块依赖外部库Library知道怎么搞了,那么如何增加本项目的模块依赖呢?

其实道理和步骤基本一样,比如hello-core模块里有个Person类:

hello-service模块也需要用到Person类及其功能,那么就需要把hello-core模块依赖进来,操作步骤如下:

添加Dependency依赖时,请选择Module Dependency...选项:

选择本项目中需要依赖进来的模块:

选中hello-core模块把它依赖到hello-service里来:

点击ok,搞定了。对应的,此依赖关系也会体现在hello-service.iml这个配置文件上:

如此,我们就可以在hello-service模块里正常使用Person类啦:

public static void main(String[] args) {
System.out.println(new Person());
}

完美。

总结

本文对IntelliJ IDEA的项目结构Project Structure的每个tab页进行了全面分析,据我短浅的目光所及,可能是全网独一份写这个内容的。很多同学觉得IntelliJ IDEA不需要专门的学习分析,会用它导入maven项目,跑跑main函数启动下Spring Boot就成啦,我却不以为然。

衡量一个新手和一个高手的差异不是顺风顺水时,而是遇到问题时谁能够快速解决,谁又只能望洋兴叹,相信薪资的差异也体现在此。我见过的“高手”对自己最常用的工具用得都是很666的,这不正是技术范该有的样子麽?说到底,我们不可能认为用一指禅敲代码的人会是大牛嘛~

好啦,关于IDEA的话题暂且先聊到这。其实我想到的主题还有好几个,如:

  • IDEA如何主动去识别导入不能被自动识别的Maven项目?原理是什么呢?
  • IDEA如何打可执行Jar包?又如何打FatJar?如何打 包外Jar包(散包) 呢?
  • IDEA如何巧用其最新的Http Client脚本能力,结合对Controller的嗅探快速完成本地测试?
  • ......

有你pick的吗?欢迎留言告诉我,需求多就尽快上号,不然这个专题就暂时告一段落啦,把时间继续花在其它专题上啦。

本文思考题

本文所属专栏:IDEA,后台回复专栏名即可获取全部内容。本文已被https://www.yourbatman.cn收录。

看完了不一定懂,看懂了不一定会。来,文末3个思考题帮你复盘:

  1. Module模块如何单独设置JDK版本?
  2. IDEA如何打jar包?
  3. 开个脑洞:Maven用pom管理项目结构,IDEA是如何识别它的呢?

推荐阅读

System.out.println("点个赞吧!");
print_r('关注【BAT的乌托邦】!');
var_dump('私聊A哥:fsx1056342982');
console.log("点个赞吧!");
NSLog(@"关注【BAT的乌托邦】!");
print("私聊A哥:fsx1056342982");
echo("点个赞吧!");
cout << "关注【BAT的乌托邦】!" << endl;
printf("私聊A哥:fsx1056342982");
Console.WriteLine("点个赞吧!");
fmt.Println("关注【BAT的乌托邦】!");
Response.Write("私聊A哥:fsx1056342982");
alert("点个赞吧!");

A哥(YourBatman):Spring Framework开源贡献者,Java架构师,领域专家。文章不标题党,不哗众取宠,每篇文章都成系列去系统的攻破一个知识点,每个系列可能是全网最佳/唯一。注重基本功修养,底层基础决定上层建筑。现有IDEA系列、Spring N多系列、Bean Validation系列、日期时间系列......关注免费获取

玩转IDEA项目结构Project Structure,打Jar包、模块/依赖管理全搞定的更多相关文章

  1. 02_MyBatis项目结构,所需jar包,ehcache.xml配置,log4j.properties,sqlMapConfig.xml配置,SqlMapGenerator.xml配置

     项目结构(所需jar包,配置文件) sqlMapConfig.xml的配置内容如下: <?xmlversion="1.0"encoding="UTF-8&qu ...

  2. java项目(java project)如何导入jar包的解决方案列表

    右键项目-properties-java build path(左侧菜单)-选择libraries 有两种方式,导入jar包实际上就是建立一种链接,并不是copy式的导入 一.导入外部包,add ex ...

  3. eclipse项目(java project)如何导入jar包的解决方案列表?

    右键项目-properties-java build path(左侧菜单)-选择libraries 有两种方式,导入jar包实际上就是建立一种链接,并不是copy式的导入 一.导入外部包,add ex ...

  4. spring boot:在项目中引入第三方外部jar包集成为本地jar包(spring boot 2.3.2)

    一,为什么要集成外部jar包? 不是所有的第三方库都会上传到mvnrepository, 这时我们如果想集成它的第三方库,则需要直接在项目中集成它们的jar包, 在操作上还是很简单的, 这里用luos ...

  5. eclipse java项目中明明引入了jar包 为什么项目启动的时候不能找到jar包 项目中已经 引入了 com.branchitech.app 包 ,但时tomcat启动的时候还是报错? java.lang.ClassNotFoundException: com.branchitech.app.startup.AppStartupContextListener java.lang.ClassN

    eclipse java项目中明明引入了jar包 为什么项目启动的时候不能找到jar包 项目中已经 引入了 com.branchitech.app 包 ,但时tomcat启动的时候还是报错?java. ...

  6. Intellij IDEA 中如何查看maven项目中所有jar包的依赖关系图(转载)

    Intellij IDEA 中如何查看maven项目中所有jar包的依赖关系图 2017年04月05日 10:53:13 李学凯 阅读数:104997更多 所属专栏: Intellij Idea   ...

  7. Intellij IDEA 中如何查看maven项目中所有jar包的依赖关系图

    Maven 组件界面介绍 如上图标注 1 所示,为常用的 Maven 工具栏,其中最常用的有: 第一个按钮:Reimport All Maven Projects 表示根据 pom.xml 重新载入项 ...

  8. eclipse maven项目如何将所有的jar包复制到lib目录下?

      1.情景展示 我们知道,maven项目的jar包并不存在于项目当中,项目所需的jar包都保存在本地仓库中,如果本地仓库没有,会从配置的中央仓库下载,如果中央仓库也没有就会报错: 如上图所示,我想将 ...

  9. 使用maven-shade-plugin打包spring项目为可执行的jar包

    使用maven-shade-plugin打包spring项目为可执行的jar包,打包后的jar包里面包含依赖的jar包. POM文件: <plugin> <groupId>or ...

随机推荐

  1. Java内存模型精讲

    1.JAVA 的并发模型 共享内存模型 在共享内存的并发模型里面,线程之间共享程序的公共状态,线程之间通过读写内存中公共状态来进行隐式通信 该内存指的是主内存,实际上是物理内存的一小部分 2.JAVA ...

  2. Python学习-小黑屋游戏

    给大家分享一下有趣的游戏,在大一上学期学习的内容里,小黑屋比较好玩. 1.导入函数库 先导入random.time两个函数库的使用来达到随机生成人物.生成人物加载时间的目的. import rando ...

  3. Head First 设计模式 —— 04. 工厂 (Factory) 模式

    思考题 如何将实例化具体类的代码从应用中抽离,或者封装起来,使它们不会干扰应用的其他部分? P111 将实例化具体类的代码放入一个对象中管理,通过不同入参决定实例化具体的类 简单工厂 不是23种GOF ...

  4. 原生redis命令

    一. redis-cli 连接 redis 进入redis安装目录 cd /usr/local/bin 进入redis客户端 ./redis-cli -p 6379 -h 用于指定 ip -p 用于指 ...

  5. 第9章 集合处理(数组、Map、Set)

    目录 1. 数组 1.1 创建数组 1.2 在数组两端添加删除元素 1.3 在数组任意位置添加.删除元素 delete删除数组元素无效 使用splice方法增.删.改元素 1.4 数组的常用操作 数组 ...

  6. chatsRoom Design Report

    基于TCP实现聊天室 主要使用四个类 ChatClient类     使用BufferedReader 得到输入流,使用OutputStream得到输出流     实现读取服务器广播的消息和发送消息到 ...

  7. three.js canvas内场景生成图片 canvas生成图片

    第一种最简单的方法: 1 threeBox.render();//重点 解决拿到图片后为黑色 2 3 let src=threeBox.renderer.domElement.toDataURL(); ...

  8. go判断字符串是否是IP地址

    前言 现在有这样的需求 正文 使用net包 net包的方法可以判断是否是 ip,需要注意的是 ip 分为 ipv4 和 ipv6 此方法将 v4 和 v6 一起判断出来 address := net. ...

  9. sublime python 去掉单行超出字数的白色框框 (E501)

    方法一 E501错误:行过长 (大于79个字符),在配置文件里设置 忽略E501错误即可 首选项-->Package Settings-->Anaconda-->Settings - ...

  10. Laya 断点调试

    Laya 打断点调试并查看堆栈的方法 发现直接加断点不行没办法调试,直接使用这中方法好像可以,选择F5调试 var camera =this.GameScene.getChildByName(&quo ...