文章目录
解释
上半部分在javaweb-maven-1-43
https://blog.csdn.net/lidashent/article/details/108302467
项目地址:https://github.com/Jonekaka/javaweb-maven-2-59
maven基础回顾
应用案例-传统web工程查询数据库
解决环境问题
在sql中新建一个数据库,然后导入sql文件夹即可,表以及数据自动生成
工程名:maven_day02_1
创建数据库
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for `items`
-- ----------------------------
DROP TABLE IF EXISTS `items`;
CREATE TABLE `items` (
`id` int(10) NOT NULL auto_increment,
`name` varchar(20) default NULL,
`price` float(10,0) default NULL,
`pic` varchar(40) default NULL,
`createtime` datetime default NULL,
`detail` varchar(200) default NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;
添加数据条目
INSERT INTO `items` VALUES ('1', 'learnEEE', '1000', null, '2018-03-13 09:29:30', '带我走上人生巅峰');
INSERT INTO `items` VALUES ('2', 'learnBBB310', null, null, '2018-03-28 10:05:52', '插入测试');
INSERT INTO `items` VALUES ('3', 'learnBBB307', '199', null, '2018-03-07 10:08:04', '插入测试');
INSERT INTO `items` VALUES ('7', '插入测试', null, null, null, null);
INSERT INTO `items` VALUES ('8', '插入测试', null, null, null, null);
为web.xml补充头部声明
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
解决jar包冲突
maven会自动把主要的包下其他的所有包也导入进来
很简便,但是也存在隐患
点开依赖关系图
举个例子
beans与context都会导入依赖的core包,那么假如版本不同,比如分别导入4和5版本,那么究竟依赖谁的包,5不依赖4,就会报错、高版本依赖低版本的包大概率会出问题
4版本的包
解决方法:
第一优先声明原则,第一个声明的会被当成主要的
使用的是4的包
第二种,路径近者优先,直接依赖与传递依赖,就是如果在坐标中声明了core,会调用直接声明的,而不是默认导入的,直接声明的优先级高,默认导入的路径为2,还需要从大声明中寻找小分类、
使用4.2.8的
第三种:内部排除法,就是在声明中明确表示不使用某个jar包,自然不会导入,就使用其他的了。这种最常用,直接排除掉了,不容易混乱。
排除的时候可以不写版本号,因为版本大声明里已经做过了
排除,4.2的,使用5的
maven工程要导入jar包的坐标,就必须要考虑解决jar包冲突。
解决jar包冲突的方式一:
第一声明优先原则:哪个jar包的坐标在靠上的位置,这个jar包就是先声明的。
先声明的jar包坐标下的依赖包,可以优先进入项目中。
maven导入jar包中的一些概念:
直接依赖:项目中直接导入的jar包,就是该项目的直接依赖包。
传递依赖:项目中没有直接导入的jar包,可以通过项目直接依赖jar包传递到项目中去。
解决jar包冲突的方式二:
路径近者优先原则。直接依赖路径比传递依赖路径近,那么最终项目进入的jar包会是路径近的直接依赖包。
解决jar包冲突的方式三【推荐使用】:
直接排除法。
当我们要排除某个jar包下依赖包,在配置exclusions标签的时候,内部可以不写版本号。
因为此时依赖包使用的版本和默认和本jar包一样。
对pom.xml内引用坐标讲解
未来放三大框架的时候也能够用
maven工程是可以分父子依赖关系的。
凡是依赖别的项目后,拿到的别的项目的依赖包,都属于传递依赖。
比如:当前A项目,被B项目依赖。那么我们A项目中所有jar包都会传递到B项目中。
B项目开发者,如果再在B项目中导入一套ssm框架的jar包,对于B项目是直接依赖。
那么直接依赖的jar包就会把我们A项目传递过去的jar包覆盖掉。
为了防止以上情况的出现。我们可以把A项目中主要jar包的坐标锁住,那么其他依赖该项目的项目中,
即便是有同名jar包直接依赖,也无法覆盖。
意思就是假如B项目想要调用A项目,一旦A项目锁定了A的jar包,只能调用A的jar包,而不能用B自带的jar包,不会形成覆盖,导致A调用出问题
锁定jar包只能锁定,并不能代替导入作用,因此
如果对于新导入的jar包,应该导入后再将坐标复制到包管理中,才能完成导入,并锁定,只导入和只锁定都是错误的
那么版本锁定的版本信息来自于这里
<key-value形式,key可以随便写,但是需要知道意思
未来如果有新的版本出现需要适应特性,可以统一管理,不必一个个改
xml文件里面能写什么,取决于上面的约束,
<properties>
<spring.version>5.0.2.RELEASE</spring.version>
<slf4j.version>1.6.6</slf4j.version>
<log4j.version>1.2.12</log4j.version>
<shiro.version>1.2.3</shiro.version>
<mysql.version>5.1.6</mysql.version>
<mybatis.version>3.4.5</mybatis.version>
<spring.security.version>5.0.1.RELEASE</spring.security.version>
</properties>
dao层代码
需求,从数据库中查询到任意一个数据就行
使用mybatis创建接口后可以不用写实现类,而是让mybatis生成代理对象
因此在资源文件夹下创建对应的文件夹与配置文件
com/xxx/dao
输入后/自动会变成点,会自动生成分级目录,确保和代码文件路径相匹配,切记
itemsdao.xml
数据库的列名字已经对应,如果不对应写resultmap,
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.learnCCC.dao.ItemsDao">
<select id="findById" parameterType="int" resultType="items">
select * from items where id = #{id}
</select>
</mapper>
这个文件应该交给主配置文件管理,但是如今已经和spring融合了,因此主配置文件的功能交给spring容器管理即可
<!--dao层配置文件开始-->
<!--配置连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<!--配置驱动,通过反射的方式创建-->
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///maven"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<!--框架提供一个操作数据库的对象,sqlsession不能共享,安全-->
<!--配置生产SqlSession对象的工厂-->
<!--之前写的是接口,但是接口并不能被实例化,此刻选择实现类,配置属性-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--先把连接池放进来,没有连接池无法操作数据库,放进来对象,引用-->
<property name="dataSource" ref="dataSource"/>
<!--扫描pojo包,给包下所有pojo对象起别名,方便引用包下的对象-->
<property name="typeAliasesPackage" value="com.learnCCC.domain"/>
</bean>
<!--sqlsession的gemapper方法,可以给接口生成代理对象。使用spring容器创建的对象,扔到容器中,因此这个逻辑就简单了,
扫描接口,生成代理对象,放到容器中
这里不写id了,因为一步完成了,不被别人调用了-->
<!--扫描接口包路径,生成包下所有接口的代理对象,并且放入spring容器中-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--让他生成哪些接口的代理对象?-->
<property name="basePackage" value="com.learnCCC.dao"/>
</bean>
<!--dao层配置文件结束-->
测试是否成功
//获取spring容器
/*新建一个容器,创建一个实现类,配置文件,路径需在clssspath下,因为这是路径加载需要的,也是配置的原因*/
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
//dao测试
//从容器中拿到所需的dao的代理对象,返回得到接口
// ItemsDao itemsDao = ac.getBean(ItemsDao.class);
//调用方法
// Items items = itemsDao.findById(1);
// System.out.println(items.getName());/*数据库已经对应*/
service层代码
接口实现类
自己写的类尽量用注解
框架尽量用配置文件
实现类服务层
@Service
public class ItemsServiceImpl implements ItemsService {
@Autowired//自动注入
private ItemsDao itemsDao;
public Items findById(Integer id) {
return itemsDao.findById(id);
}
}
配置文件
service不仅是业务,也有事务管理
spring事务管理内部使用的aop编程模式
配置文件
<!--service层配置文件开始-->
<!--组件扫描配置-->
<context:component-scan base-package="com.learnCCC.service"/>
<!--内部使用aop变成模式,事务-->
<!--aop面向切面编程,切面就是切入点和通知的组合,所谓通知就是增强类-->
<!--只是这里的增强类是别人已经写好的-->
<!--配置事务管理器-->
<!--要控制事务需要用到connection,再用到连接池-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--事务管理器创建完成,一般管理配置完成,通知类自动配置,但这里的通知类不是自己写的,还需要进行个性化配置-->
<!--配置事务的通知-->
<!--不配置id可以默认,但是默认的比较长-->
<tx:advice id="advice">
<tx:attributes>
<!--这里对操作进行约定,凡是方法名字,对于以save,find开头的方法进行约束,对于查询方法让他只读-->
<tx:method name="save*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="delete*" propagation="REQUIRED"/>
<tx:method name="find*" read-only="true"/>
<!--全局扫描-->
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!--配置切面-->
<aop:config>
<!--配置切面表达式,这个类下任意的方法,任意的返回值-->
<aop:pointcut id="pointcut" expression="execution(* com.learnCCC.service.impl.*.*(..))"/>
<!--切入点有了,通知类也有了,整合,已经使用了spring的面向切面编程思想配置好事务-->
<aop:advisor advice-ref="advice" pointcut-ref="pointcut"/>
</aop:config>
<!--service层配置文件结束-->
测试服务可用
@Test
public void findById(){
//获取spring容器
/*新建一个容器,创建一个实现类,配置文件,路径需在clssspath下,因为这是路径加载需要的,也是配置的原因*/
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
//service测试
ItemsService itemsService = ac.getBean(ItemsService.class);
//调用方法
Items items = itemsService.findById(1);
System.out.println(items.getName());
}
web层代码编写
先加上注解,然后写配置文件,反正都是必须的。
@Controller
/*全局路径*/
@RequestMapping("/items")
public class ItemsController {
/*将来会用到service,因此把service再注入进来*/
@Autowired
private ItemsService itemsService;
/*方法路径*/
@RequestMapping("/findDetail")
public String findDetail(Model model){
Items items = itemsService.findById(1);
model.addAttribute("item", items);
return "itemDetail";
}
}
对springmvc进行配置,他自己有独立的配置文件
<!--组件扫描-->
<!--让注解启用-->
<context:component-scan base-package="com.learnCCC.controller"/>
<!--处理器映射器,处理器适配器-->
<!--框架提供的简便配置,开启-->
<mvc:annotation-driven/>
<!--视图解析器-->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--配置前缀后缀,前缀路径,后缀名字-->
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!--释放静态资源-->
<!--拦截器不能拦截所有资源,需要让jsp可以自由访问。以后但凡碰到静态资源,都会交给默认的servlet处理,
就是之前写的httpservlet处理,而不是现在写的disaptherservlet,后者会吞资源-->
<mvc:default-servlet-handler/>
配置jsp页面文件
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<form>
<table width="100%" border=1>
<tr>
<td>商品名称</td>
<%--jstl表达式,获得对象数据--%>
<td> ${item.name } </td>
</tr>
<tr>
<td>商品价格</td>
<td> ${item.price } </td>
</tr>
<tr>
<td>生成日期</td>
<td> <fmt:formatDate value="${item.createtime}" pattern="yyyy-MM-dd HH:mm:ss"/> </td>
</tr>
<tr>
<td>商品简介</td>
<td>${item.detail} </td>
</tr>
</table>
</form>
</body>
</html>
web.xml配置
最终的目的是,服务器一启动,配置文件等等自动加载到servlet容器中
搜素信息时可以使用通配符,比较方便
<!--编码过滤器-->
<!--统一编码信息-->
<filter>
<filter-name>encoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--配置spring核心监听器-->
<!--加载spring的配置文件-->
<listener>
<!--默认情况下只能监听web-inf下的applicationContext信息,因此需要修改默认路径,
现在名字能对上,但是路径不对,其实都一样,改-->
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--重新指定spring配置文件的路径-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!--springmvc的核心servlet-->
<!--拦截器-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<!--也需要修改默认路径,加载配置文件-->
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!--设置高优先级,首先加载-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
maven拆分与聚合的思想
所谓的jar包就是别人已经写好的代码,编译成了class文件,复用而已
因此将jar包类比自己写的代码,能否让自己写的代码分成一个个模块,可以在不同的项目总混合复用,不用重复写?
未来开发新的项目的时候,不用复制粘贴,就像maven的jar包坐标一样,导入之前写的代码坐标就可以
重用,可维护(只需要更新一个独立模块)
这是拆分的思想
聚合的思想就是开发新项目合并之前的模块
将web工程拆分与聚合
创建父工程
父工程可以只有pom.xml
新建一个父工程,两个都可以选
创建时,模板是否使用都行,解释如上
可以简单至此
创建子模块
父工程唯有moudle可选
这里演示,创建三个,方法具备通用性
dao,service,controller
dao模块
不需要与用户交互,即使只有一个java文件也可以
每一个子模块自带pom.xml独立
那么子工程的坐标?
上面是父工程的坐标,用parent圈起来,版本号与父工程项目名共用,子模块有自己的项目名,三者成为坐标
同时父工程拥有子模块的坐标
service同理
但是controller不同,他还需要界面,因此需要借助模板创建
pom.xml不需要过多信息,保留基础即可
相比之前多了一个web.xml
工程和模块的关系,依赖和继承
工程和模块的区别:
工程不等于完整的项目,模块也不等于完整的项目,一个完整的项目看的是代码,代码完整,就可以说这是一个完整的项目 和此项目是工程和模块没有关系。
工程和模块大小无关系,一个模块可以很大,一个工程可以很小。
工程天生只能使用自己内部资源,工程天生是独立的。后天可以和其他工程或模块建立关联关系。
假如A模块要用到B工程的C资源,那么直接将B工程安装到仓库,然后引入C的坐标就行
父子工程不用建立关系,子模块一旦创建,子模块天生继承父工程,可以使用父工程所有资源。
这种次级的父子关系称为继承
子模块之间天生是没有任何关系的。但是可以与其他模块建立后天关系,像引入jar包一样引入坐标就行
这种平级的模块到模块称为依赖
<dependencies>
<dependency>
<groupId>com.learnCCC</groupId>
<artifactId>maven_day02_dao</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
传递依赖下来的包能否使用
如何理解呢?
明确两个概念,
直接依赖:继承也算,就是直接可以获得,比如父工程引用子模块,子模块引用子模块
间接依赖:本身没有,别的给的,比如子模块使用父工程的jar包
不写坐标范围都是compile
以这个父工程的jar包为例子,作用域为test,那么子模块也引用了这个包,子模块对于父工程属于直接依赖,包对于子模块属于间接依赖,compile连线test得到空,就是父工程导入的这个包用不了。
一般也没人看这个表,发现不能导入会直接手动导入。
完善模块代码
将之前的工程代码复制粘贴到对应模块即可
需要注意的是这里的dao与service分开了,因此配置文件里的配置信息应该分别导入到两个模块文件中
模块之间是有依赖的,service引入了dao的坐标,controller引入service坐标就相当于引入了dao与service
配置文件的引入同样也只需要引入坐标即可
<import resource="classpath:spring/applicationContext-dao.xml"/>
<import resource="classpath:spring/applicationContext-service.xml"/>
需要注意的是约束也需要一起导入
maven父子工程的三种启动方式
maven拆分与聚合的方式
第一种:直接启动父工程即可
第二种:启动内部的集成
比如案例工程中的web模块,理论上已经整合了所有必须的模块
但是会报错,这是因为不能找到自定义的service坐标,本地,中央仓库都没有,需要自己安装
因此安装父工程,他会安装所有的jar包
然后再访问web模块就行了,run
第三种:使用本地的tomcat
私服远程仓库
卸载私服
先停掉私服服务
进入管理员的cmd,进入相应的bin目录下,nexus.bat uninstall
安装:nexus.bat install
对于私服是有图像化界面的,可以从配置文件中看到端口
# Jetty section
application-port=8081 # nexus 的访问端口配置
application-host=0.0.0.0 # nexus 主机监听配置(不用修改)
nexus-webapp=${bundleBasedir}/nexus # nexus 工程目录
nexus-webapp-context-path=/nexus # nexus 的 web 访问路径
# Nexus section
nexus-work=${bundleBasedir}/../sonatype-work/nexus # nexus 仓库目录
runtime=${bundleBasedir}/nexus/WEB-INF # nexus 运行程序目录
安装成功以后,访问浏览器可以看到
打开可以看到图形化界面,密码admin,admin123
查看仓库问价
其实只是图像化界面的伪装而已,还是从本地读取的。
查看仓库的文件类型
之前的打包类型,测试版的意思
release发行版
proxy第三方
- hosted,宿主仓库,部署自己的 jar 到这个类型的仓库,包括 releases 和 snapshot 两部
分,Releases 公司内部发布版本仓库、 Snapshots 公司内部测试版本仓库 - proxy,代理仓库,用于代理远程的公共仓库,如 maven 中央仓库,用户连接私服,私
服自动去中央仓库下载 jar 包或者插件。 - group,仓库组,用来合并多个 hosted/proxy 仓库,通常我们配置自己的 maven 连接仓
库组。 - virtual(虚拟):兼容 Maven1 版本的 jar 或者插件,太老了,不用了
nexus 仓库默认在 sonatype-work 目录中
正式库-测试库-第三方-中央-apach,仓库组最常用
私服的应用
将代码上传到私服
打开本地安装的maven
找到server标签
修改私服信息
<server>
<id>releases</id>
<username>admin</username>
<password>admin123</password>
</server>
<server>
<id>snapshots</id>
<username>admin</username>
<password>admin123</password>
</server>
那么该如何上传文件呢?
在需要上传的模块中,修改pom.xml
添加和setting对应的信息
id不要错
<distributionManagement>
<repository>
<id>releases</id>
<url>http://localhost:8081/nexus/content/repositories/releases/</url>
</repository>
<snapshotRepository>
<id>snapshots</id>
<url>http://localhost:8081/nexus/content/repositories/snapshots/</url>
</snapshotRepository>
</distributionManagement>
执行命令,这个是默认生命周期中的最后一个,私服与本地仓库都会安装
私服中出现信息
从私服下载文件
主要解决本地执行项目时不能自动下载本地仓库不存在的jar包问题
给settings.xml配置
找到,然后配置仓库地址
激活
<!-- 下载jar包配置 -->
<profile>
<!--profile的id -->
<id>dev</id>
<repositories>
<repository> <!--仓库id,repositories可以配置多个仓库,保证id不重复 -->
<id>nexus</id> <!--仓库地址,即nexus仓库组的地址 -->
<url>http://localhost:8081/nexus/content/groups/public/</url> <!--是否下载releases构件 -->
<releases>
<enabled>true</enabled>
</releases> <!--是否下载snapshots构件 -->
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories> <!-- 插件仓库,maven的运行依赖插件,也需要从私服下载插件 -->
<pluginRepository> <!-- 插件仓库的id不允许重复,如果重复后边配置会覆盖前边 -->
<id>public</id>
<name>Public Repositories</name>
<url>http://localhost:8081/nexus/content/groups/public/</url>
</pluginRepository>
</pluginRepositories>
</profile>
```python
<activeProfiles>
<activeProfile>dev</activeProfile>
</activeProfiles>
然后启动项目,会自动下载本地不存在的jar包
安装jar包到私服,本地
复制粘贴没有用的,除非安装的方式
有方式,要么本目录,要么补充文件所在路径
–安装第三方jar包到本地仓库
信息有提供,groupid,artifactid,版本号已经提供
----进入jar包所在目录运行
mvn install:install-file -DgroupId=com.alibaba -DartifactId=fastjson -Dversion=1.1.37 -Dfile=fastjson-1.1.37.jar -Dpackaging=jar
----打开cmd直接运行
mvn install:install-file -DgroupId=com.alibaba -DartifactId=fastjson -Dversion=1.1.37 -Dpackaging=jar -Dfile=C:\my_java\授课资料\资料:maven【高级】\安装第三方jar包\fastjson-1.1.37.jar
然后进入本地仓库可以看到已经安装的包,直接复制粘贴没有这些信息的,自然不能引入
将包安装到私服
找到maven的settings.xml文件,配置上传到第三方库的配置信息
–安装第三方jar包到私服
--在settings配置文件中添加登录私服第三方登录信息
<server>
<id>thirdparty</id>
<username>admin</username>
<password>admin123</password>
</server>
配置的仓库id要和具体的文件目录名,以及命令名相同,三者协同
----进入jar包所在目录运行
mvn deploy:deploy-file -DgroupId=com.alibaba -DartifactId=fastjson -Dversion=1.1.37 -Dpackaging=jar -Dfile=fastjson-1.1.37.jar -Durl=http://localhost:8081/nexus/content/repositories/thirdparty/ -DrepositoryId=thirdparty
----打开cmd直接运行
mvn deploy:deploy-file -DgroupId=com.alibaba -DartifactId=fastjson -Dversion=1.1.37 -Dpackaging=jar -Dfile=C:\my_java\fastjson-1.1.37.jar -Durl=http://localhost:8081/nexus/content/repositories/thirdparty/ -DrepositoryId=thirdparty
可以看到仓库已经添加成功