一、基础
1、基本数据类型
整型
类型 | 存储 | 说明 |
---|---|---|
byte | 1 byte | |
short | 2 byte | |
int | 4 byte | 默认整型 |
long | 8 byte |
浮点型
类型 | 存储 | 说明 |
---|---|---|
float | 4 byte | |
double | 8 byte | 默认浮点型 |
字符型
类型 | 存储 | 说明 |
---|---|---|
char |
布尔型
类型 | 存储 | 说明 |
---|---|---|
boolean |
Java
中没有无符号整型。
Java
中整型和布尔型之间不能互相转换。
1 | // 声明变量 |
2、字符串
Java
中 String
不是基本类型而是一个类。
String
是不可变字符串,每次对字符串的修改都会返回一个新的字符串。
String
的判等只能使用 equals
而不能使用 ==
,equals
判断的是字符串语义上是否相等,==
判断的是内存地址是否相同。
String
常用方法:
1 | int compareTo(String other); // 按字典顺序排序,在 other 前返回小于0;在 other 之后返回大于0;相等返回0; |
因为字符串是不可变的,所以每次拼接字符串都会产生一个新的对象。可以使用 StringBuilder
和 StringBuffer
拼接字符串。StringBuilder
线程不安全性能更好,StringBuffer
线程安全但性能略差。
1 | StringBuilder builder = new StringBuilder(); |
3、控制流程
switch-case
中可以放三种类型:
- 整型(byte、short、int、long)
- 枚举类型
- 字符串
4、数组
数组创建之后不能在修改大小,如果要使用能动态修改大小的数组可以使用 ArrayList
。
1 | // 初始化 |
java.util.Arrays
是数组的伴随类,提供了数组的常见操作,基本都是静态方法:
1 | Arrays.toString(); |
5、枚举
所有的枚举类型都是 Enum
类的子类。
1 | enum Size { |
定义了一个 Size
类,该类有四个实例。
枚举的判等必须使用 ==
而不能使用 equals
。
枚举常用方法
1 | // |
6、面向对象
私有域 + 公开的访问器与修改器方法。
方法重载:多个方法有相同的名字,不同的参数就叫方法重载。
方法覆盖:子类重写父类的方法叫方法覆盖,方法覆盖时子类必须比父类更开放。
方法签名:包括方法名称、参数类型,但不包括返回类型。
默认构造器:如果类没有提供构造器则会自动添加一个默认无参构造器,如果提供了则不会有默认无参构造器。
初始化一个类中的域可以有三个地方:
- 域声明中
- 初始化块(对象初始化块、静态域初始化块)
- 构造器
执行顺序是加载该类是就执行静态初始化块,构造对象时先执行域声明语句,然后执行对象初始化块,最后执行构造器:
1 | public class Employee { |
子类必须在构造器第一行调用父类的构造器,如果没有主动调用就会自动调用父类的默认无参构造器,如果父类没有默认无参构造器则报错。
多态:一个对象变量可能指向多种实际的类型叫多态。(变量可以引用一个类型,也可以引用一个类型的子类)
动态绑定:在运行时自动决定使用哪个对象的方法叫动态绑定。
Java
中的方法调用默认是动态绑定的,使用 static
、final
、private
可以消除动态绑定使用静态绑定。
访问控制符:
public
:所以类都可见protected
:本包及所有子类可见- 默认:本包可见
private
:只有本类可见
超类 Object
常用方法:
1 | // 默认判断两个对象是否具有相同的引用 |
7、抽象类
抽象类不一定有抽象方法,但有抽象方法就一定是抽象类。
抽象类中可以包含具体数据和方法:
1 | abstract class Person { |
8、反射
9、接口
接口中所有方法默认都是 public
的不用显式声明,但是实现接口类中必须显示声明 public
。
接口不能包含实例域,但可以包含常量,所有的常量默认是 public static final
。
1 | public interface Comparable { |
接口中方法可以使用 default
默认实现方法,实现类不必一定实现默认实现方法:
1 | public interface Comparable<T> { |
如果一个类中有很多静态方法,以前的解决办法是实现一个伴随类把这些静态方法都放到伴随类中,比如 Collection/Collections
、Path/Paths
等。现在接口中可以有静态方法,这是一个更好的解决办法:
1 | public interface Path { |
如果实现类的父类和它实现的接口中有方法冲突,则父类方法优先,叫类优先。
在没有 lambda
和内部类之前,回调的实现只能使用接口实现:
1 | // 定义回调中需要使用的接口 |
10、lambda
lambda
不需要指定返回类型。
lambda
可以指定参数类型,如果可以推导出参数类型也可以省略参数类型。
lambda
如果没有参数也不能省略小括号。
lambda
如果只有一个参数才可以省略小括号。
函数式接口:对于只有一个抽象方法(注意是只有一个抽象方法,可以有多个静态方法、多个默认实现方法)的接口叫函数式接口。
1 | // Timer 需要一个接口 ActionListener 参数 |
java.util.function
中定义了很多常用的函数是接口,方便实用。
方法引用:如果已有方法就满足了函数式接口的需求,可以使用方法引用的方式把该方法直接作为 lambda
传递。
1 | public class Test { |
方法引用有三种方式:
对象::实例方法
类::静态方法
类::实例方法
前两个形式中所有参数都作为引用方法的参数。
第三种方法中必须有多个参数,第一个参数作为该实例方法的调用者,其他参数作为实例方法参数。
1 | String::compareToIgnoreCase |
构造器也可以用在方法引用中:
1 | public class Person { |
lambda
中使用的 this
指的是创建该 lambda
表达式的方法中的 this
。
1 | public class Person { |
lambda
会捕获外围变量,注意被捕获的变量不能被修改(无论 lambda
内部修改还是外部修改都不行)。
11、内部类
1 | public class Outer { |
内部类所有的静态域都必须是 final
。
内部类不能有 static
方法。
在虚拟机中并没有内部类,内部类会被编译器编译成用 $
分隔的外部类与内部类:
1 | public class Outer { |
内部类也可以定义在方法中,这时候称为局部内部类,局部内部类不能使用 private
或 public
修饰:
1 | public class Outer { |
和 lambda
一样,内部类中捕获的外部变量必须是不可变的 final
。
如果局部内部类只需要创建一次对象,可以直接 匿名内部类
直接创建对象而不用命名类:
1 | ActionListener listener = new ActionListener() { |
如果内部类不需要使用外部类的变量,可以将内部类设置为 static
以便取消内部类对外部类的引用:
1 | public class Outer { |
12、异常
所有异常都派生自 Throwable
:
Error
:系统内部错误,发生时应该停止程序。Exception
:分为RuntimeException
、IOException
。程序本身错误是RuntimeException
,IO
错误是IOException
。
常见 RuntimeException
:
- 错误类型转换
- 数组越界访问
- 访问 null 指针
常见 IOException
:
- 试图在文件尾部读取数据
- 试图打开一个不存在的文件
- 给定字符串查找类时类不存在
Error
和 RuntimeException
是非受查异常,IOException
是受查异常,只有受查异常才能抛出。
异常的处理有两种方法:抛出异常、捕获异常。
try-catch
中可以 catch
多个异常:
1 | try { |
finally
在不论是否捕获异常都会执行,一般用来释放资源,但如果资源实现了 AutoCloseable
接口,可以使用更好的方法:
1 | // 传统的 finally 中释放资源 |
13、泛型
1 | // 泛型类 |
限定泛型类型:
1 | // 限定列表中,类应该放在第一个,接口应该放在后面 |
类型擦除
:虚拟机中没有泛型,泛型类在编译之后会被去除类型,使用限定类型替换,如果没有限定类型则使用 Object
类型替换:
1 | // 没有限定泛型类型时 |
因为类型擦除,应该将没有方法的接口放到限定列表的后面。
桥方法。
几个注意点:
泛型的类型不能是基本类型,必须使用包装器:
1 | // error |
不能创建泛型类型的数组:
1 | // error |
注意,无论 S
和 T
有什么关系,Pair<S>
和 Pair<T>
都没关系:
1 | class Pair<T> {} |
但是 Pair<SonClass>
一定是 Pair
的子类型:
1 | air<Manager> managerPair = new Pair<>(); |
通配符类型
???
14、集合
for-each
循环可以用在任何实现了 Iterable
接口的类上。
1 | Iterator<String> it = c.iterator(); |
15、并发
16、打包
传统的 Java 会打包成一个 applet
程序,可以通过网络下载在浏览器中运行,后来出现了打包成 jar
包。
applet
程序已经基本废弃不用,如今基本使用 jar
打包代码。
jar
jar
其实就是一个使用 zip
格式压缩的文件,可以包含代码及资源文件。
打包成 jar
包:
1 | # 打包 |
一般 jar
包中有一个描述文档特征的清单文件 META-INF/MANIFEST.MF
,文件分为多个节,开头主节作用于整个 jar
包,下面的命名条目(指定文件、包、URL 都可以作为命名条目)作用于指定条目:
1 | # 主节 |
注意:清单文件最后一行必须以换行符结束。
要想直接启动 jar
包,在打包时必须指定程序入口或者在清单文件中指定主类:
1 | # 打包时指定入口 |
启动 jar
包:
1 | java -jar 包名.jar |
jar
包中的资源如何定位?通过可以访问的 class
文件来定位资源文件,一般可以把资源文件放到类文件文件夹中:
1 | // 通过 ResourceTest 的位置来定位资源 about.gif |
Properties
、Preferences
常用作配置功能,web 开发一般用不到就不详写了。
applet
applet
是包含在 HTML 页面中的 Java 程序,基本不再使用。
Java Web Start
二、JDBC
三、JavaWeb
JSP
与 Servlet
是一致的,JSP
最终会被web 服务器编译为 Servlet
,web 服务器上实际运行的是 Servlet
。第一次访问 JSP
文件时会比较慢,因为要等待 JSP
编译成 Servlet
文件。
一个标准的 Web 应用结构如下:
1 | webapp |
Servlet 3.0
之前 web.xml
是必须的,之后 web.xml
不再是必需文件,因为可以使用注解。
项目中的这个 web.xml
文件是项目级的配置,只会影响该项目,web 服务器还会提供一个服务器级的 web.xml
(Tomcat
配置文件位于 conf/web.xml
)配置文件,作为所有项目共有配置。
web.xml
及注解主要可配置有:
- JSP
- Servlet
- Listener
- Filter
1、JSP
2、Servlet
Servlet
生命周期由 web 服务器(比如 Tomcat)来管理,创建 Servlet
实例有两个时机:
- 第一次请求到该
Servlet
时 - 通过
load-on-startup
配置让启动 web 服务器时就创建该Servlet
实例,load-on-startup
值越小越先创建
已创建的 Servelet
会放到容器中,后续再请求到该 Servlet
时不需要重新创建实例。
Servlet 3.0
增加了很多新特性,比如注解配置、web 模块支持、Servlet 异步处理。
注解配置
1 | package com.ifangcy.servlets; |
web.xml 配置
1 | <servlet> |
3、Filter
Filter
是一种加强版的 Servlet
,用来对请求进行预处理、对响应进行后处理。Filter
一般用来先对请求预处理,然后把请求交给 Servlet
,最后拿到 Servlet
的响应在进行后处理,最后返回响应。
Filter
通常可以用来处理多个 Servlet
中的共有部分,比如记录日志、权限控制等。
Filter
可拦截多个请求或响应,一个请求或响应也可以被多个 Filter
拦截。
注解配置
1 |
|
web.xml 配置
1 | <filter> |
4、Listener
Listener
用来监听 web 容器内部的事件,比如 web 应用被启动、web 应用停止、用户 session 开始、用户 session 结束、用户请求到达等,这些内容本来对开发者是不可见的。
常用的 web 事件监听器接口有如下:
- ServletContextListener:监听 web 容器的启动和关闭
- ServletContextAttributeListener:监听 ServletContext 范围内属性改变
- ServletRequestListener:监听用户请求,可以用来实现系统日志
- ServletRequestAttributeListener:监听 ServletRequest 范围内属性改变
- HttpSessionListener:监听用户 session 开始和结束,可以用来实现监听在线用户数
- HttpSessionAttributeListner:监听 HttpSession 范围内属性改变
Listener
配置无需参数。
注解配置
1 |
|
web.xml 配置
1 | <listener> |
四、Maven
在 Maven
打包时不会把 src/test
目录下的测试代码打包进最终包。
Maven
默认打包成 jar
包,默认打包成的 jar
并不能直接运行,因为打包出的 MATA-INF/MANIFEST.MF
文件中没有指定 Main-Class
,如果想要直接运行该包需要配置在配置中使用 maven-shade-plugin
配置主类:
1 | <plugin> |
1、基础
安装
Maven
安装目录:
1 | |---bin # maven 命令脚本 |
安装之后,把 ${M2_HOME}/conf
下的 settings.xml
配置文件复制一份到用户目录下 ~/.m2/settings.xml
,作为用户级的配置文件。
1 | ~/.m2/---repository # 下载包存放 |
在 settings.xml
添加阿里云镜像:
1 | <mirrors> |
常用命令
1 | mvn dependency:list |
当插件的 groupId
不是 org.apache.maven.plugins
和 org.codehaus.mojo
时,必须在 ~/.m2/settings.xml
中配置上插件的 groupId
才能通过命令行使用插件:
1 | <settings> |
Maven 项目结构
Maven
项目必须遵守固定的结构才能被 Maven
编译打包:
1 | .---src |
- 源码目录:
src/main/java/
- 包输出目录:
target/
- 编译输出目录:
target/classes/
- 默认打包方式:
jar
一般不会手动去创建这样的项目结构,可以使用 Archetype
自动生成项目骨架,即使是 IDEA
也是通过 Archetype
命令生成的:
1 | mvn archetype:generate |
坐标
项目必须定义坐标,引入的第三方包也是通过坐标引入。
项目坐标包括:
groupId
:对应到项目,比如com.ifangcy.mall
artifactId
:对应到项目的模块,比如com.ifangcy.mall.account
version
:项目版本packaging
:项目打包方式,默认(不填时)jar
,可选war
、pom
classifier
:生成打包时的一些附属构件,需要配合插件
打包生成的包名为 artifactId-version[-classifier].packaging
。
引入的第三方包坐标包括:
groupId
:基本坐标,必填artifactId
:基本坐标,必填version
:基本坐标,非必填,如果不填则使用依赖最新发布版本type
:对应packaging
,项目类型,默认jar
,非必填scope
:依赖范围,非必填optional
:是否可选,非必填exclusions
:排除依赖,非必填
依赖
classpath 与依赖范围
classpath
可以看做运行环境,Maven
使用三套环境/classpath
隔离依赖:
- 测试
classpath
- 编译
classpath
- 运行
classpath
依赖通过指定 scope
来决定放到哪个 classpath
环境中:
compile
:编译依赖范围,默认值,三种classpath
环境中都会放入依赖test
:测试依赖范围,只会放入测试classpath
环境中,例如JUnit
provided
:依赖范围,编译、测试classpath
环境中会放入依赖,例如servlet-api
runtime
:运行时依赖范围,测试、运行classpath
环境中会放入依赖,例如JDBC
驱动system
:系统依赖范围,与provided
以来范围一致,区别是system
需要指定systemPath
从本地获取依赖而不是Maven
仓库import
:不影响三种classpath
环境,在使用dependencyManagement
时可能用到
传递依赖
直接依赖如果还有其他依赖,这时候依赖范围怎么处理?
最左边一列为第一直接依赖,第一行为第二直接依赖。
compile | test | provided | runtime | |
---|---|---|---|---|
compile | compile | - | - | runtime |
test | test | - | - | test |
provided | provided | - | provided | provided |
runtime | runtime | - | - | runtime |
如果依赖范围不包括运行 classpath
,则该依赖不会被放到最终的打包中。
依赖调解
对于多个依赖最终依赖了一个包的不同版本时怎么处理?
两个原则:
- 路劲最近优先:
A->B->C(1.0)
与A->C(2.0)
因为第二个路径更近,所以C
导入2.0
版本 - 第一声明优先:同样长度的依赖,在
POM
中先声明的优先
2、仓库
依赖下载到本地的仓库下 ~/.m2/repository/
,路径为 groupId/artifactId/version/artifactId-version.packaging
。
仓库分为本地仓库、远程仓库,私服也是一种远程仓库。
国内一般需要配置远程仓库的镜像,在 ~/.m2/settings.xml
添加镜像:
1 | <mirrors> |
这个镜像对当前用户所有项目都生效。
一般来说,有的项目需要特定的远程仓库,可以在项目 pom.xml
中配置项目范围的远程仓库:
1 | <project> |
这种配置只对当前项目有效。
有的仓库为了安全需要认证才能访问,认证信息的配置必须放到 ~/.m2/settings.xml
中,不能放到项目 pom.xml
中(放在项目中会被提交到版本控制中,不安全):
1 | <servers> |
快照版本
:指的是 version
指定为 1.1-SNAPSHOT
这样形式的包。
1 | <project> |
快照版本在每次打包时 Maven
会自动为项目版本加上时间戳,生成形如 1.1-20201212.221212-12
这样的版本号。
快照版本的依赖每次在编译时都会自动检查是否有最新快照版本可下载,确保使用最新快照版。
3、生命周期与插件
Maven
把构建过程抽象成一整套抽象的生命周期,每个生命周期都可以完成一定的任务,这些任务都交给插件来完成,Maven
已经自带了每个生命周期的默认插件,当然这些插件是可以随时替换的。
对于整个构建过程,Maven
抽象出了三套生命周期:clean
、default
、site
。每套生命周期内部又分为多个阶段,在一套生命周期内部的阶段是有顺序的,后面的阶段依赖前面的阶段,但是三套生命周期是互相独立的,在不同生命周期的阶段是没有依赖关系。
clean
生命周期是负责清理项目,主要阶段:
pre-clean
clean
post-clean
default
生命周期是真正的构建,主要阶段:
validate
initialize
generate-sources
process-sources
generate-resources
process-resources
compile
process-classes
generate-test-sources
process-test-sources
generate-test-resources
process-test-resources
test-compile
process-test-classes
test
prepare-package
package
pre-integration-test
integration-test
post-integration-test
verify
install
deploy
site
生命周期是用于建立和发布站点,主要阶段:
pre-site
site
post-site
site-deploy
执行指定任务的方式就是调用特定的 Maven
生命周期阶段,比如 mvn clean deploy
调用 clean
生命周期的 clean
阶段、default
生命周期的 deploy
阶段。
如上所述,生命周期的阶段的任务由插件来完成,但阶段与插件并不是直接对应的,而是阶段与插件目标直接对应,而且一个阶段可能对应多个目标,多个目标的执行顺序是按照声明顺序执行。
所谓的插件目标就是插件可以完成的工作,通常来说一个插件可以完成多种工作,每种工作都叫做一个目标,如下:
1 | maven-dependency-plugin:analyze |
表示 maven-dependency-plugin
有三个目标:analyze
、tree
、list
。
只有 org.apache.maven.plugins
和 org.codehaus.mojo
两个 groupId
下的插件才支持命令行调用,如果不是这两个 groupId
下的插件想要使用命令,需要修改 ~/.m2/settings.xml
配置:
1 | <settings> |
自定义阶段对应的目标:
1 | <plugin> |
phase
并不是必须的,一般插件会默认指定绑定阶段,所以不显式指定也可以。
每个插件都可以通过 pom.xml
配置参数,有的插件还可以通过命令行配置参数,插件的每个目标也可以单独配置参数:
1 | <plugin> |
依赖的远程仓库和插件的远程仓库是不同的,在 pom.xml
中配置插件的远程仓库,一般不需要自己配置插件仓库:
1 | <pluginRepositories> |
Maven
有一个超级 pom.xml
文件,所有项目的 pom.xml
都继承自该超级 pom.xml
文件,该文件路径 ${M2_HOME}/lib/maven-model-builder-x.x.x.jar/org/apache/maven/model/pom-4.0.0.xml
。这个超级 pom.xml
中指定了每个默认核心插件的版本号,所以即使项目中没有指定核心插件版本也可以,当然其他第三方插件是不行的。
4、聚合与继承
聚合
:指的是把一个项目分成多个模块,把这些模块聚合到一起。
继承
:指的是把多个模块相同的依赖、插件抽取到一起。
聚合模块仅帮助聚合其他模块,本身不包含实质性内容。
聚合模块的 packaging
必须使用 pom
。
有的设计中聚合模块、所有模块的父模块是分开成两个模块的,有的设计中聚合模块、所有模块的父模块作为一个模块,我们采取第二种方式。
子模块会自动继承父模块的 groupId
和 version
。
父模块/聚合模块 pom.xml
1 | <project> |
模块1 pom.xml
:
1 | <project> |
父模块可以被子模块继承的元素有:
groupId
version
description
organization
inceptionYear
url
developers
contributors
distributionManagement
issueManagement
ciManagement
scm
mailingLists
properties
dependencies
dependencyManagement
pluginManagement
repositories
build
reporting
依赖管理
所有模块的依赖都可以放到父模块的 dependencies
中,但是放到 dependencies
中的依赖所有模块都会全部继承,即使该模块不需要这个依赖。问题在于如果即让父模块统一管理依赖,又能让子模块按需导入依赖。
dependencyManagement
就是为了解决这个问题而存在,它 不会给父模块和子模块导入依赖,但子模块却可以继承这些依赖。
父模块:
1 | <dependencyManagement> |
子模块:
1 | <dependencies> |
父模块指定两个依赖 junit
、spring-jcl
,子模块只需要一个 junit
而不需要 spring-jcl
,子模块指定依赖时不需要指定版本,版本由父模块统一管理。
父模块实际不会导入任何依赖,子模块只会导入 junit
一个依赖。
插件管理
插件的管理和依赖一样,使用 pluginManagement
,而且插件的配置参数等也会一并继承。
父模块:
1 | <build> |
子模块:
1 | <build> |
5、使用 Maven 测试代码
Maven
运行测试代码主要通过 maven-surefire-plugin
与 JUnit/TestNG
集成,Maven
本身不提供测试功能,通过执行生命周期的测试阶段来执行 JUnit
或 TestNG
测试用例。
运行 mvn test
时 maven-surefire-plugin
插件自动执行测试源码 src/test/java
路径下所以符合如下命名的测试代码:
**/Test*.java
**/*Test.java
**/*TestCase.java
跳过运行测试代码:
1 | mvn package -DskipTests |
或在 pom.xml
中配置:
1 | <plugin> |
要想不运行测试代码,同时也不编译测试代码:
1 | mvn package -Dmaven.test.skip=true |
或 pom.xml
中配置:
1 | <plugin> |
指定运行特定测试代码,可以使用明确指定、逗号分隔、匹配符等多种方式:
1 | mvn test -Dtest=RandomGeneratorTest |
maven-surefire-plugin
会自动在 target/surefire-reports
下生成错误报告。
如果想生成测试覆盖率报告,可以使用 Cobertura
实现,加入插件 cobertura-maven-plugin
使用命令:
1 | mvn cobertura:cobertura |
6、Maven 构建 war 包
Web 应用目录结构如下:
1 | war |
在 Web 容器中运行时,clases
和 lib
目录会被加入到 classpath
中。
Web 项目的打包必须为 war
,项目目录结构如下:
1 | project |
Web 项目比起普通 jar
项目特殊在多了一个 webapp
目录,对应打包后的 Web 应用。Maven
在打包时会把依赖 jar
文件复制到打包的 war/WEB-INF/lib
中。
一般 Web
项目 pom.xml
中会特别配置 finalName
来指定最终打包名,替代默认的 artifactId-version.packaging
格式的打包名。
1 | <build> |
常见的,Web 项目中 src/main/resources
和 src/main/webapp
中都可能有资源文件,但是打包后这些资源文件在 war
包中的位置是不同的。src/main/resources
下的资源文件打包后位于 war/WEB-INF/classes
目录下(也就是会放到应用的 classpath
中),src/main/webapp
下的资源文件打包后位于 war/
根目录下(这些资源不会被放到 classpath
中,一般称为 web 资源比如 css
、js
、img
等)。
内嵌热部署
Web 开发中,每次修改都需要重新打包,部署到容器中查看效果。
可以使用内嵌容器的方式直接在项目中启动容器查看。
1 | <plugins> |
因为该插件 groupId
是 org.mortbay.jetty
,为了在命令行中使用该插件,需要修改下 ~/.m2/settings.xml
:
1 | <settings> |
在命令中启动容器:
1 | mvn jetty:run # 默认使用 8080 端口 |
自动部署
可以使用 Cargo
将项目部署到本地或远程容器。
Cargo
有两种部署方式:
standalone
:把本地容器内容复制一份到指定目录下,然后把项目部署到该目录下existing
:把项目部署到本地容器目录下,推荐
standalone 模式部署
1 | <plugins> |
同样的,需要修改 ~/.m2/settings.xml
以便使用命令。
使用:
1 | mvn cargo:start |
existing 模式部署
1 | <plugins> |
部署到远程容器
1 | <plugins> |
部署:
1 | mvn cargo:deploy |
7、版本管理
版本约定:
1 | <主版本>.<次要版本>.<增量版本>-<里程碑版本> |
- 主版本:架构重大变化
- 次要版本:较大范围功能增加、变化,bug修复
- 增量版本:bug修复
- 里程碑版本:非稳定版,需要测试
使用 maven-release-plugin
管理版本
8、灵活构建
属性
Maven
中可使用6中属性:
- 内置属性:主要就是两个,
${basedir}
表示项目根目录(也就是pom.xml
所在目录),${version}
项目版本 - POM 属性:
pom.xml
文件中每个元素都可以作为属性使用,比如<project><artifactId>
可以通过${project.artifactId}
使用 - Settings 属性:和 POM 属性类似,
settings.xml
中每个元素也可以作为属性使用,如${settings.localRepository}
- 自定义属性:在
pom.xml
的<properties>
中定义属性 - Java 系统属性:Java 系统属性可以通过属性使用,比如
${user.home}
- 环境变量属性:所有环境变量也可以通过
env.
开头属性使用,比如${env.JAVA_HOME}
常用 POM 属性:
${project.build.sourceDirectory}
${project.build.testSourceDirectory}
${project.build.directory}
${project.outputDirectory}
${project.testOutputDirectory}
${project.groupId}
${project.artifactId}
${project.version}
${project.build.finalName}
环境隔离
资源文件过滤
Maven
对资源文件的处理知识在打包后把资源文件复制到编译输出目录中,这个过程是由插件 maven-resources-plugin
实现的,并不会主动对资源文件中使用到的 Maven
属性进行处理。
要想让资源文件中的 Maven
属性生效,需要修改插件配置开启资源过滤,这个配置在超级 POM
中(${M2_HOME}/lib/maven-model-builder.jar/org/apache/maven/model/pom.xml
):
1 | <resources> |
进行资源过滤之后,资源文件中就可以使用 Maven
属性,
web 资源过滤
对于 web 资源(位于 src/main/webapp
下,一般为 css
、js
、img
等),有时候可能也需要不同环境使用不同资源,可以通过配置 maven-war-plugin
实现过滤:
1 | <plugin> |
Maven
对不同环境使用不同配置通过 profile
实现,一个 profile
就是一个环境。
profile
可以配置的位置有:
pom.xml
:只对当前项目生效,推荐~/.m2/settings.xml
:对所有项目生效${M2_HOME}/conf/settings.xml
:对所有项目生效
1 | <profiles> |
激活 profile
方式有多种:
- 命令行中激活:比如
mvn install -Pdev
激活dev profile
profile
配置中激活:使用activeByDefault
默认激活- 系统属性激活:’’
- 操作系统环境激活:
- 文件是否存在激活:
Maven
的 maven-site-plugin
插件默认会使用两个自定义属性配置读取源码和文档的编码格式及生成站点的编码格式:
1 | <properties> |
Maven
私服??
持续集成??
实现插件??
自定义 archetype
???
五、Mybatis
1、基础
一般的 ORM
框架将 Java 对象和数据库表关联,而 Mybatis
是将 Java 方法和 SQL 语句关联。
Java 方法和 SQL 语句的关联是通过称为 mapper
的 xml
文件和以 Mapper
为后缀的接口文件实现的。
Mybatis
自带基于 HashMap
的高速缓存,第一次执行一条 SQL 时会从数据库中取数据,之后再次执行就会从高速缓存中取数据。