maven
Maven介绍与作用
直接复制jar包到lib目录内的问题
问题1:到处项目复制jar包,导致磁盘jar包冗余
问题2:jar包之间可能存在冲突
问题3:项目复制给其他人员,必须还要复制这些jar包,导致jar冗余
问题4:如果需要的ar包本地没有,需要自己去网络查找下载比较麻烦
maven介绍
maven是apache基金会开发的开源的构建jar的工具或服务器。可以非常方便的获取jar包,构建项目使用。并且还可以管理项目打包,测试,传输。
maven的作用
-
jar包的构建
以后所有的jar包都找maven获取
-
项目管理工具(项目生命周期管理)
maven可以对项目生成、编译、测试、打包、安装、上传等管理项目
生成:使用maven创建生成项目
编译:将编写java源代码编译成class文件
测试:编译并运行所有junit单元测试
打包:将项目进行打包
安装:将打包的项目安装到本地的maven里面给内自己项目使用
上传:将打包的项目上传到远程maven里面给所有人使用
-
创建聚合项目
就是jar包有继承关系,可以让jar包在多个项目内进行jar包重用
Maven的仓库
Maven仓库介绍
maven仓库里面拥有所有的jar包,以后项目使用jar包就从maven仓库获取
Maven仓库类型
官方中央仓库地址:https://repo1.maven.org/maven2/
官方允许浏览器和maven服务器访问
缺点: 中央仓库是国外服务器, 下载较慢
第三方阿里云仓库:http://maven.aliyun.com/nexus/content/groups/public/
注意,阿里云不对浏览器访问开放,只对maven服务器访问开放
优点: 一般都是国内的服务器, 下载速度快
注意: 第三方与中央仓库都有共同的缺点, 只能下载不能上传
私服
介绍: 就是自己公司搭建的服务器
优点: 不仅可以下载还可以上传
经验: 一般大公司都使用自己私服 , 团队内可以下载, 又可以将好用的jar上传到服务器中共享给团队其他成员使用
本地仓库的说明
Maven的坐标
为什么学习坐标?
因为仓库里面的jar包有很多,需要通过坐标获取里面的jar包
坐标介绍
坐标就是去仓库里面的不同目录获取对应的jar包给项目去构建使用
坐标由3部分组成
groupId,对应仓库里面第一层目录
artifactId,对应仓库里面第二层目录
version,对应仓库里面第三层目录
引用junit的jar包坐标例子
引用仓库里面的junit的jar包,在配置文件pom.xml中做如下配置:
<dependency> <!--依赖,就是导入jar包的含义 -->
<groupId>junit</groupId> <!--组织名 -->
<artifactId>junit</artifactId> <!--项目名.模块名 -->
<version>4.12</version> <!--版本号 -->
<scope>test</scope> <!--依赖访问,后面讲解 -->
</dependency>
本地仓库的jar包位置
注意:
一般情况下: 坐标中groupId对应仓库中jar包位置的第一层目录
特殊情况下: 如果groupId配置的目录名字中有"."点, 就代表多层目录, 比如: groupId的信息为javax.servlet, 多一个一个点就会多一层目录
其他artifactId与version: 无论配置什么信息, 每个标签都只对应一层目录
Maven的安装与配置
实现步骤
-
下载maven
官网地址:http://maven.apache.org/download.cgi
maven是apache开源项目,专门为java提供的项目构建工具
-
解压完成安装
-
介绍maven服务器的目录结构
-
配置maven全局配置文件settings.xml
-
绑定本地仓库
<localRepository>C:\xxx\repository</localRepository>
-
绑定远程仓库,阿里云
<mirror> <id>nexus</id> <mirrorOf>*</mirrorOf> <url>http://maven.aliyun.com/nexus/content/groups/public/</url> </mirror>
将上面信息配置到如下位置
-
配置全局的jdk编译语言级别版本(如果不配这个,默认编译级别是1.5,太低,idea运行的会有警告)
<profile> <id>development</id> <activation> <jdk>1.8</jdk> <activeByDefault>true</activeByDefault> </activation> <properties> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion> </properties> </profile>
将上面内容添加到如下配置文件位置
-
-
设置环境变量,到处都可以使用maven的命令
-
测试是否安装配置成功,如下信息代表配置成功
IDEA绑定本地Maven服务器
当前项目绑定Maven实现步骤
运行参数绑定
-
设置运行参数
-DarchetypeCatalog=internal ,用于设置任何配置信息都从本地缓存中拿。有一些模板信息maven默认从远程仓库下载获取,如果设置了这个参数第一次从远程拿,以后从本地拿(这就要求第一次用maven必须联网,1~5M不等)
-DarchetypeCatalog=internal
配置效果如下
配置自动刷新maven
新项目绑定Maven实现步骤
- 绑定本地maven软件
注意,旧的项目或工作空间需要每个单独设置绑定maven
Maven骨架web工程1-创建项目
Maven骨架创建maven项目
创建module
根据骨架创建模块
骨架:是maven官方apache提供的创建项目模板
设置坐标信息
下一步
设置磁盘目录名
成功信息
创建项目初始化结构
maven项目目录结构规范
maven工程以后是由maven管理的,对项目目录结构maven是由规范要求的适合进行管理
分析
划分3个部分为了对jar包设置使用的范围
完善目录结构
注意:上面手动创建后需要在maven窗口进行刷新,让对应的目录变色,只有变色才说明目录结构正确
maven窗口刷新
Maven骨架web工程2-pom.xml
介绍pom.xml文件
每个项目都有maven的核心配置文件,主要用于配置项目依赖的jar包坐标与使用的插件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!--1.当前项目配置的坐标【必须有】-->
<groupId>xxx</groupId>
<artifactId>xxxxxxx</artifactId>
<version>1.0-SNAPSHOT</version>
<!--2.配置打包方式【必须有】
包含3种方式:
方式1:<packaging>war</packaging>, 将当前项目打成war包,适合web项目
方式2:<packaging>jar</packaging>, 将当前项目打成jar包,适合直接双击运行的类库项目
方式3:<packaging>pom</packaging>, 如果当前项目是聚合父项目就设置为pom
如果没有设置,默认是jar
-->
<packaging>war</packaging>
<!--3.配置当前项目一些不重要的属性,可有可无
<name>是配置maven窗口显示的模块名,可以去掉,maven窗口的名字就为artifactId的名字
<url>没有具体含义,只是用来看的
-->
<name>xxxxxxx Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.xxx.com</url>
<!--4.设置全局属性-->
<properties>
<!--设置maven控制台消息的码表-->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!--设置jdk编译语言级别,骨架工程默认设置为1.7,这里修改为1.8
如果不设置默认采用全局settings.xml的设置-->
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<!--5.设置jar包的依赖【必须有】-->
<dependencies>
<!--引用junit的依赖-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<!--6.配置构建使用的组件-->
<build>
<!--finalName没有任何含义,只是用来显示-->
<finalName>xxxxxxx</finalName>
<!--pluginManagement配置插件的,插件用于执行maven的项目管理工具命令,比如打包,测试,编译。。。
注意:这里配置的插件是高版本的插件,可以删除,删除后有默认低版本的插件
-->
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
总结:骨架方式生成的pom.xml文件生成了很多没有用的信息
Maven骨架web工程3-开发Servlet
创建Servlet
中main/java鼠标右键创建servlet
注意,勾上如图
代码效果
发现上面servlet的类报错,是由于没有引用servlet的jar包
pom.xml导入Servlet的jar包引用依赖
<!--引用servlet的依赖-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
截图
导入后观察Servlet已经不报错了
DemoServlet的代码
@javax.servlet.annotation.WebServlet(name = "DemoServlet", urlPatterns = "/DemoServlet")
public class DemoServlet extends javax.servlet.http.HttpServlet {
protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
doGet(request, response);
}
protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
response.getWriter().print("hello maven javaweb archetype");
}
}
部署项目运行
maven工程需要手动部署项目到tomcat上
点击OK
启动项目
注意运行部署的位置
查看部署位置
Maven自定义web工程
实现步骤
-
创建maven项目,不用向导骨架
设置坐标+删除父项目关系修改模块名
生成的默认目录结构
-
完成项目目录结构
完成webapp目录(整个过程项目名字可以忽略)
将web目录拖拽到main目录里面,并修改名字为webapp更新当前项目的webapp目录位置,因为如下报错
修改正确
maven自定义工程的插件优化
实现步骤
-
安装插件,安装完成之后重启idea
鼠标右键有如下菜单说明插件安装完成
-
新建项目
-
使用插件优化项目目录结构
直接点击OK
项目管理1—clean命令
生命周期命令介绍
clean命令介绍
因为有的时候编译器的编译结果没有更新获取出错, 一般解决办法先清除原来的编译结果,再重新编译
使用命令方式
- 方式一:传统方式使用dos命令
- 方式二:使用idea开发工具内置集成的maven工具操作(推荐方式)
项目管理2—其他命令
complie命令
作用
用于对main目录下的java代码编译
test命令
作用
先编译再运行test目录下的所有单元测试代码
使用要求
测试类类名必须以Test为结尾,否则只会编译不会运行
中文乱码问题
使用test命令运行测试类输出中文默认会乱码,不建议使用test命令运行测试类,而是直接在测试类里面点击运行不会乱码
解决测试中文乱码
a.设置当前项目maven码表为utf8
b.所有生命周期的命令都是使用插件完成的,要求插件必须使用最新版本
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>xxx</groupId>
<artifactId>xxxxxxxx</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<!--解决测试中文乱码第一步:设置码表UTF-8-->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<!--解决测试中文乱码第二步:设置使用高版本的插件-->
<build>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
package命令
作用
将当前项目进行打包的
intall命令
作用
将当前项目安装到本地仓库,给自己其他项目引用构建使用
依赖管理1-依赖插件
maven的插件介绍
maven通过插件来扩展maven工具的功能,maven的项目管理工具的命令就是使用了插件。maven有很多插件,其中最知名有2个,一个是jdk编译语言级别插件和一个tomcat7运行插件
实现步骤
-
jdk插件用于设置编译级别
-
tomcat7插件,非常建议使用这个,因为部署项目速度快
配置插件代码
<build> <plugins> <!-- jdk版本编译语言级别插件,因为一般都采用全局settings.xml配置了,如果当前项目不使用全局就可以使用这个插件 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.2</version> <configuration> <source>1.8</source> <target>1.8</target> <encoding>UTF-8</encoding> <showWarnings>true</showWarnings> </configuration> </plugin> <!--tomcat7的插件,官方只提供了tomcat7,没有提供tomcat8 对比:tomcat7插件比tomcat正式服务器启动部署速度快,有如下2个快: A.支持webapp目录下资源修改的热部署,即修改后立即生效,不需要重新部署 B.其他位置修改需要重启,注意重启速度快,因为服务器直接运行当前项目模块位置的代码 --> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> <configuration> <port>8080</port><!--设置插件使用端口--> <path>/</path> <!--设置项目资源部署目录的名字--> <uriEncoding>UTF-8</uriEncoding> <!--设置get提交中文码表为utf-8,目的解决tomcat7的get方式提交中文乱码--> <server>tomcat7</server> <!--插件服务器的名字--> </configuration> </plugin> </plugins> </build>
使用插件运行
运行效果
对与webapp目录下的资源修改,支持热部署(修改完立刻可以看到效果,不用重新部署)
对于main目录下java和resources任何的修改,不支持热部署,需要重新部署。
运行资源页面注意
tomcat7插件服务器运行资源位置
依赖管理2-依赖范围
依赖jar包
mvn坐标网站: http://mvnrepository.com/ ,可以在这里参照jar包的坐标依赖写法
点击“MyBatis”连接
点击版本3.5.4
<!--引用junit依赖-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
<!--
scope标签:用于设置当前jar的依赖范围,就是设置jar包在哪里使用
-->
</dependency>
<!--引用servlet的依赖-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
依赖范围
介绍
<scope>依赖范围</scope>
用于设置当前jar包在哪个范围使用,一共有3个范围:主体(编译位置),测试(测试位置),运行(运行时位置)
有三种不同的依赖范围
依赖范围 | 含义 |
---|---|
编译位置 | 设置jar包在main/java编译代码的时候使用 |
测试位置 | 设置jar包在test/java测试目录编译和运行代码时候使用 |
运行时位置 | 设置jar包在服务器上运行时的使用 |
常用依赖范围
什么是依赖范围:就是使用上面一种或多种类路径
通过标签<scope>
标签 来指定当前jar包依赖范围
常用的依赖范围有以下四种,其中默认是:compile
依赖范围见下表
scope标签配置依赖范围的关键字有如下:
依赖范围 | 编译位置 main | 测试位置 test | 运行时位置 target |
---|---|---|---|
compile | Y | Y | Y |
provided | Y | Y | - |
runtime | - | Y | Y |
test | - | Y | - |
示例:test依赖范围
介绍
设置jar包只能在test/java目录下编译与运行的时候使用
测试
演示:在main/java目录下使用junit会报错
设置junit的jar包尾test范围
<!--引用junit的依赖-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version><!--推荐使用4.12,所以讲4.11修改为4.12-->
<scope>test</scope> <!--配置jar包的依赖范围-->
</dependency>
test应用场景
专门用于junit的jar包设置依赖范围
示例:provided依赖范围
介绍
设置jar包在编译位置和测试位置可以使用
provided应用场景
专用用于设置servlet的jar包不能在运行时使用,否则与tomcat7插件运行servlet产生冲突
测试
需求:演示一个冲突,servlet的jar包不能在运行时使用,否则产生冲突
冲突描述:servlet的jar包在tomcat服务器上已经存在,如果将本地的servlet的jar包给运行时使用,会与服务器上的servlet的jar包产生冲突
tomcat服务器上已有的servlet的jar包
解决冲突
将servlet的jar包依赖范围设置为provided
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
示例:runtime依赖范围
介绍
设置jar包在测试位置和运行时位置可以使用
runtime应用场景
专用用于mysql数据库驱动包使用的依赖范围
分析:
mysql驱动包:都是jdbc接口的实现类
编译时写代码:都使用JDBC接口类,所以编译时不需要mysql驱动包
测试
pom.xml中没有引用依赖mysql驱动包
//加载驱动类
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306", "root", "root");
System.out.println(connection);
在main/java目录下编写jdbc操作不会报错,说明不需要mysql驱动包
运行代码会报错,因为运行时没有导入mysql驱动包依赖
解决方案
在pom.xml中导入mysql驱动包依赖使用范围为runtime
<!--导入mysql驱动包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
<scope>runtime</scope>
</dependency>
删除maven项目再打开
删除项目
右键项目,点击Delete,项目删除了
恢复项目
New => Module from Existing Sources => 点击pom.xml => OK
接下来,一直下一步(Next)
如果导入的是非自己创建的项目需要做这一步
清除下载失败标记文件
当maven的pom.xml配置的坐标会到本地仓库查找jar包给项目使用,如果本地没有jar包则会去远程仓库下载,有的时候由于各种网络问题导致下载jar包失败,就会生成失败文件xxxxjar.lastUpdate, 一旦这个文件产生,maven服务器就不会再次下载,导致项目永远报错,这就要到本地仓库删除xxx.lastUpdate文件即可。
解决方案
进入本地仓库
搜索*.lastUpdate
JDK动态代理优化SqlSession资源开启与关闭
优化需求
对于每个业务层方法都需要如下操作
1. 初始化SqlSession资源
2.释放SqlSession资源
可以将这些代码抽取出来,使用动态代理增强每个dao数据库的方法,实现统一初始化与释放资源
创建Dao工厂类实现动态代理增强每个dao的方法
DaoFactory代码
public class DaoFactory {
//目标:增强Dao的每个方法,在运行方法前初始化sqlSession,运行方法后释放SqlSession
//根据Dao接口类进行增强返回增强代理类
public static <T> T getBean(Class daoInterfaceClass){
//增强方式:jdk动态代理
//语法:Proxy.newProxyInstance(目标对象类加载器,对象属实接口类数组,事件处理程序)
// 参数1:目标对象类加载器,需要被增强对象的类加载,这里就是dao接口类加载器
// 参数2:对象属实接口类数组
// 参数3:事件处理程序,调用代理对象方法时触发的代码,在事件处理程序中增强目标方法
return (T)Proxy.newProxyInstance(
daoInterfaceClass.getClassLoader(),//参数1
new Class[]{daoInterfaceClass},//参数2
/*new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return null;
}
}*/
(proxy,method,args)->{ //参数3
//proxy:增强后的代理对象
//method: daoInterfaceClass类里面的方法对象
//args:daoInterfaceClass类里面的方法的参数数组
//目标:正确每一个dao的方法
//1.增强1:初始化sqlSession资源
SqlSession sqlSession = MybatisUtils.getSession();
Object dao = sqlSession.getMapper(daoInterfaceClass);
//2.执行dao方法
Object result = method.invoke(dao, args);
//3.增强2:释放sqlSession资源
MybatisUtils.closeSession(sqlSession);
//4.返回dao方法执行的结果
return result;
}
);
}
}
优化ContactService代码
/**
* 业务层
*/
public class ContactService {
//获取dao的代理对象
private IContactDao contactDao = DaoFactory.getBean(IContactDao.class);
/**
* 查询所有的联系人
*/
public String findContacts() {
//创建Jedis对象
Jedis jedis = JedisUtils.getJedis();
//从Jedis中得到所有的联系人的字符串
String contacts = jedis.get("contacts");
//判断字符串是否为空
if (contacts == null) {
//如果为空,表示redis中没有数据,从mysql中去查询
List<Contact> list = contactDao.findAll();
//判断,如果list大于0,将list转成json对象
if (list.size() > 0) {
ObjectMapper mapper = new ObjectMapper();
try {
contacts = mapper.writeValueAsString(list);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
//存到redis数据库中
jedis.set("contacts", contacts);
}
}
else {
//不为空,从redis中得到数据
System.out.println("从Redis中得到数据");
}
//关闭
jedis.close();
//返回json对象,执行到这里contacts一定有字符串值
return contacts;
}
//添加联系人
public boolean addContactByRedis(Contact contact){
//1.调用dao方法添加联系人
int count = contactDao.insert(contact);
//2.删除redis中缓存的联系人数据
//获取连接
Jedis jedis = JedisUtils.getJedis();
//删除
jedis.del("contacts");
//关闭连接
jedis.close();
return count>0;
}
}