# 几个常见问题
# 1. maven-archetype-webapp 骨架的 Servlet 版本问题
通过 maven-archetype-webapp 骨架去创建 java web 项目时,自动生成的 web.xml 配置文件所使用的 Servlet 的版本比较低(2.3),而在低版本的 Servlet 中 EL 表达式默认是关闭的。
通常,我们使用的 Servlet 至少会是 3.1 。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
...
</web-app>
# 2. .lastUpdated 文件问题
.lastUpdated 文件是 Maven 在下载依赖包时的中间文件。例如:
slf4j-api-1.7.5.pom.lastUpdated
surefire-junit4-2.12.4.jar.lastUpdated
在下载成功完成后,.lastUpdated 文件会被移除,成功下载的包文件将会出现。
当你发现你的本地仓库中的某个包的目录下存在 .lastUpdated 文件,那么这意味着发生了以下 2 种情况之一:
Maven 正在下载这个包。通常不会是这个情况,因为配置国内的中央仓库镜像后,下载包的速度较快,再加上各个包实际并不大,这种情况的 .lastUpdated 文件只存在极短的一瞬间,不会让你『长期看到』它。
上一次 maven 下载这个包时失败,而遗留下来的,通常你可能『长期看到』一个 .lastUpdated 文件就是因为这个原因。
如果是第二种情况,则会给你带来麻烦:因为 maven 不支持断点续传,而 .lastUpdated 文件既不可用,又会导致 maven 不会重新下载。
因此,理论上,你要清除掉你本地仓库中的 .lastUpdated 文件,以免它干扰你的 maven 的正常使用。
cleanLastUpdated.bat
@echo off rem 这里写你的仓库路径 set REPOSITORY_PATH=C:\Users\xxx\.m2\repository rem 正在搜索... for /f "delims=" %%i in ('dir /b /s "%REPOSITORY_PATH%\*lastUpdated*"') do ( echo %%i del /s /q "%%i" ) rem 搜索完毕 pause
# 3. IDEA Maven 默认使用 JDK 1.5 编译问题
IDEA 在『调用』maven 时,IDEA 默认都会采用 JDK 1.5 编译,不管你安装的 JDK 版本是 JDK 7 还是 JDK 8 或者更高。这样一来非常不方便,尤其是时不时使用 JDK 7/8 的新特性时。如果使用新特性,编译器直接报错。
对于此类问题,解决办法不止一种。Maven 官方推荐做法是固定 JDK 的编译版本。
需要在 pom.xml 文件中加入:
<properties>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
# 4. tomcat7-maven-plugin 版本『低』的问题
相较于当前最新版的 tomcat 10 而言,tomcat7-maven-plugin 确实看起来很显老旧。但是,这个问题并不是问题,至少不是大问题。
tomcat7-maven-plugin 仅用于我们(程序员)开发环境中,最终项目交付以后的运行环境,是 tomcat7 还是更高版本的 tomcat,甚至是其它的 Servlet 容器,这就是另一个问题了,这和 tomcat7-maven-plugin 的版本无关。
tomcat7 支持 Servlet 3.0,tomcat8 支持 Servlet 3.1,实际上 Servlet 3.0 和 3.1 的区别并不大,甚至说,从 Servlet 3.0 开始,tomcat 的新特性在绝大多数的项目中都用不少,所以,tomcat8-maven-plugin 的高级也没高到哪里去。
这里涉及到一个小知识,从 3.1 开始,Servlet 开始内置了文件上传功能。但是,经测试实际上,3.0 就已经有了这个功能。另外,Servlet 内置的上传功能,在上传文件名是中文的文件是有中文乱码问题,不是很好解决。所以,实际上上传文件的方案,还是 commons-fileupload 更常见,Servlet 3.0 开始出现的内置的上传方案并没有那么美好。
tomcat7-maven-plugin 是 tomcat-maven-plugin 的子项目,tomcat-maven-plugin 的最高版本是 2.2 ,版本新特性就是支持 tomcat7 。也就是说 tomcat8-maven-plugin 并非官方项目,这也是为什么,中央仓库没中 tomcat8-maven-plugin 的原因。
如果对 tomcat7 的版本仍疑虑,也不一定非要使用非官方的 tomcat8-maven-plugin。可以使用其它的 Servlet 容器的 maven 插件,例如 jetty 。
# 5. mirrorOf 是 central 还是 * 的问题
在配置阿里对官方中央仓库的镜像服务器时,我们使用到了 <mirror> 元素。
故名思意,<mirror> 用于配置网络仓库的『镜像』。当你准备去默认的中央仓库下载包和插件时,Maven 会『拦截』你的下载请求,转而去你所配置的『镜像网址』下载,从而也能实现从指定的国内的网址下载。
而 <mirror> 元素的子元素 <mirrorOf> 的值常见两种:central 和通配符 * 。
central 和 * 的区别在于:
如果是 central,那么 maven 只会将你的从『中央仓库』下载请求(无论是 jar 包,还是插件包),转向你所配置的镜像地址。
如果是 * ,那么 maven 会将你的『所有』下载请求转向你所配置的镜像地址。
如果你要下载一个不在中央仓库的包(或插件),例如 tomcat8-maven-plugin ,
如果你配置的值是 central,那么 maven 会去你所配置的『别的』仓库下载,因为中央仓库没有这个包;
如果你配置的值是 *,那么无论这个包在不在中央仓库,maven 只会去中央仓库下载。有,则有;没有,则没有。
# 6. 高版本的 lombok 和 tomcat 7 插件冲突问题
在开发期间,当我们使用 tomcat7-maven-plugin 来作为运行环境运行我们项目使,如果我们项目中使用了 1.16.20 及以上版本的 lombok 包,项目启动时会报错:
for annotations org.apache.tomcat.util.bcel.classfile.ClassFormatException: Invalid byte tag in constant pool: 19
原因在于,从 1.16.20 开始 lombok 包中有了一个叫 module-info.class 的文件,而低版本的 tomcat 不能识别这个文件,从而导致运行时出错。
其实这个问题对于我们而言不是问题,因为项目部署时,肯定不会部署到 tomcat 7 上,至少是 tomcat 8.5 。
对于这个问题,解决办法有 2 个:
使用 tomcat8-maven-plugin 。
将 lombok 的
<scope>
设置为provided
,这样,maven 在打包时就不会将 lombok 包含在 jar/war 包内。我们对 lombok 的使用也就是在编译时使用,运行时不需要它。使用低版本的 lombok,例如,
1.14.x
的最高版本1.14.8
。
# 7. hibernate-validator 高版本问题
hibernate-validator 的高版本(邮箱注解)依赖于高版本的 el-api,tomcat 8 的 el-api 是 3.0,满足需要。但是 tomcat 7 的 el-api 只有 2.2,不满足其要求。
解决办法有 2 种:
低版本如 5.4.3.Final 在 tomcat7-maven-plugin 上可用。
使用 tomcat8-maven-plugin 。