“Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。”
一、Maven基础
Maven是一个项目管理工具。依赖管理既Maven对项目中的JAR包的管理过程,传统工程我们将JAR包放在项目中,而Maven工程将JAR包放在仓库中,项目中只引用JAR包的坐标。
Maven放置JAR包的地方称为仓库,仓库又分为本地仓库、远程仓库既私服和中央仓库;当启动一个Maven项目是,Maven工程会通过pom文件中的JAR包坐标到本地仓库查询JAR包,如果本地仓库没有对应的JAR包会自动到中央仓库或者远程仓库中下载JAR包
Maven常用的命令有:
- clean:清除项目
- compile:编译代码
- test:测试代码
- package:打包代码
- install:在本地仓库中安装JAR包
- deploy:上传到私服
Maven的生命周期
- 清理生命周期
- 默认生命周期
- 站点生命周期
二、 Maven 构建项目
搭建Maven项目
在数据中创建item表,SQL如下;
代码语言:javascript复制SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for item
-- ----------------------------
DROP TABLE IF EXISTS `item`;
CREATE TABLE `item` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`name` varchar(20) DEFAULT NULL,
`price` float(10,0) DEFAULT NULL,
`pic` varchar(40) DEFAULT NULL,
`create_time` datetime DEFAULT NULL,
`detail` varchar(200) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=70 DEFAULT CHARSET=utf8;
SET FOREIGN_KEY_CHECKS = 1;
使用IDEA创建一个maven项目maven-high-level,点击File-Add Framework Support添加Web Framework。
Maven的JAR包冲突解决方案
在pom文件中添加5.x版本的spring-context,spring-context本身包含了许多jar包
再增加一个spring-beans依赖,版本为4.x
代码语言:javascript复制<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.16</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>
</dependencies>
查看pom.xml文件中maven依赖关系图
根据Maven依赖图可以看出spring-beans和spring-context都包含了spring-core,但是由于版本不同也导致了spring-core有两个版本,这就是Maven的JAR包冲突,但是从左侧可以确定Maven选择了5.x版本的spring-core。JAR冲突时Maven时如何选择的?
第一声明优先原则
在pom文件中颠倒两个版本依赖的顺序,改为4.x版本的spring-beans在第一位,5.x版本的spring-context在第二位
根据左侧Maven的JAR包列表可以确定Maven选择了4.x版本的spring-core。
这就是第一声明优先原则:哪个JAR包坐标在靠上的位置上,这个JAR包就是先声明的,先声明的JAR包就会优先进入项目中
路径近者优先原则
首先来明确两个概念
- 直接依赖:项目中直接引入的JAR包
- 传递依赖:项目中没有直接导入JAR包,可以通过项目直接依赖的JAR包传递到项目中去,spring-core就是传递依赖
直接在项目中加入spring-core的依赖,版本为4.2.8.RELEASE,不同于spring-context和spring-bean包含的spring-core的版本
可以看出Maven选择的是直接引入的spring-core的版本,既没有选择spring-context也没有选择spring-bean
直接导入spring-core,所依赖的版本就变成了直接导入的版本,没有直接导入的话就是用间接传递依赖的版本,间接传递依赖的版本又依赖于第一声明优先原则
路径近者优先原则:直接依赖路径比传递依赖路径近,最终进入项目的JAR包会是直接依赖的JAR包
exclusion标签排除JAR包
首先删除直接引入的spring-core 4.2.8.RELEASE,保持4.2.4.RELSEAS版本在第一位,5.3.16版本在第二位的情况下又想使用5.3.16版本的spring-core,这种情况下就可以使用exclusions标签,将4.x版本的spring-core排除掉
exclusion标签中不用写版本号默认使用上层的版本号。此时,Spring-core就变成5.3.16版本的了
推荐使用第三种方式
完成Maven项目搭建
pom文件中添加Maven依赖
代码语言:javascript复制<!-- 统一管理jar包版本 -->
<properties>
<spring.version>5.3.16</spring.version>
<slf4j.version>1.7.36</slf4j.version>
<logback.version>1.2.11</logback.version>
<shiro.version>1.8.0</shiro.version>
<mysql.version>8.0.16</mysql.version>
<mybatis.version>3.5.7</mybatis.version>
<spring.security.version>5.6.1</spring.security.version>
<project.build.sourceEncoding>
UTF-8
</project.build.sourceEncoding>
</properties>
<!-- 锁定jar包版本 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<!-- 项目依赖jar包 -->
<dependencies>
<!-- spring -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.8</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- log start -->
<!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- log end -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.7</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.3.0</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.14</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.18</version>
<scope>provided</scope>
</dependency>
</dependencies>
Maven工程是可以分父子依赖关系的,凡是依赖别的项目后,拿到的都是别的项目的依赖包,属于传递依赖,为了放置直接依赖的JAR包覆盖传递依赖的JAR包,通常会使用dependencyManagement标签把JAR包锁住,这样的话直接依赖就无法覆盖间接依赖引入的JAR包
创建Mapper层、Service层和Controller层
根据item表的字段来创建Item实体类,新建entity包增加Item实体类
代码语言:javascript复制@Data
public class Item {
private Integer id;
private String name;
private Double price;
private String pic;
private Date createTime;
private String detail;
}
创建ItemMapper接口,新增mapper文件夹以及ItemMapper接口
代码语言:javascript复制public interface ItemMapper {
}
在resources目录下创建MyBatis全局配置文件
代码语言:javascript复制<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<!--开启驼峰命名-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
</configuration>
在resources目录下常见mappers文件夹,在mappers中创建MyBatis SQL Mapper XML文件
代码语言:javascript复制<?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.lilith.mapper.ItemMapper">
</mapper>
在resources目录下创建数据库连接配置文件db.properties
代码语言:javascript复制jdbc_driver=com.mysql.cj.jdbc.Driver
jdbc_url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&serverTimezone=Asia/Shanghai
jdbc_username=root
jdbc_password=root
在resources目录下创建logback.xml配置文件,用于打印执行的SQL
代码语言:javascript复制<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>[%thread] %d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="debug">
<appender-ref ref="console"/>
</root>
</configuration>
在WEB-INF下创建Spring MVC配置文件dispatcherServlet-servlet.xml
代码语言:javascript复制<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-4.3.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.lilith" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!--配置试图解析器,自动拼接页面地址,自动在jsp页面前增加/WEB-INF/pages/-->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!-- 默认前端控制器是拦截所有资源(除过jsp),js文件就404了;要js文件的请求是交给tomcat处理的 -->
<!-- 告诉SpringMVC,自己映射的请求就自己处理,不能处理的请求直接交给tomcat -->
<!-- 静态资源能访问,动态映射的请求就不行 -->
<mvc:default-servlet-handler/>
<!-- springmvc可以保证动态请求和静态请求都能访问 -->
<mvc:annotation-driven></mvc:annotation-driven>
</beans>
在resources目录下创建Spring配置文件application.xml
代码语言:javascript复制<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-4.3.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.alibaba.com/schema/stat http://www.alibaba.com/schema/stat.xsd http://www.springframework.org/schema/tool http://www.springframework.org/schema/tool/spring-tool.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd">
<!--扫描除了控制器之前的其他包-->
<context:component-scan base-package="com.lilith">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!--引用外部配置文件-->
<context:property-placeholder location="classpath:db.properties"></context:property-placeholder>
<!--数据库连接池配置-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc_driver}"/>
<property name="url" value="${jdbc_url}" />
<property name="username" value="${jdbc_username}"/>
<property name="password" value="${jdbc_password}"/>
<!--<property name="initialSize" value="${jdbc_initialSize}"/>-->
<!--<property name="maxActive" value="${jdbc_maxActive}"/>-->
</bean>
<bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="configLocation" value="classpath:mybatis-config.xml"></property>
<property name="dataSource" ref="dataSource"></property>
<property name="mapperLocations" value="classpath:/mappers/*.xml"></property>
</bean>
<!--mapper层接口加入到Spring容器-->
<bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--指定接口所在的包-->
<property name="basePackage" value="com.lilith.mapper"></property>
</bean>
</beans>
配置web.xml
代码语言:javascript复制<?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_4_0.xsd"
version="4.0">
<!--Spring-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:application.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--DispatchServlet-->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<!--"/" 代表拦截所有请求,/*拦截所有请求包括jsp页面这些请求-->
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--解决POST请求中文乱码问题-->
<filter>
<filter-name>characterFilter</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>
</filter>
<filter-mapping>
<filter-name>characterFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--Rest支持-->
<filter>
<filter-name>hiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>hiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
在ItemMapper中新增insert和selectById两个方法
代码语言:javascript复制public interface ItemMapper {
void insert(Item item);
Item selectById(Integer id);
}
在ItemMapper XML文件中增加对应的SQL语句,在mapper标签下新增以下内容
代码语言:javascript复制<sql id="itemColumsWithoutId">
name,price,pic,create_time,detail
</sql>
<sql id="itemColums">
id,name,price,pic,create_time,detail
</sql>
<insert id="insert" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
INSERT item
(<include refid="itemColumsWithoutId" />)
VALUES (#{name},#{price},#{pic},#{createTime},#{detail})
</insert>
<select id="selectById" resultType="com.lilith.entity.Item">
SELECT
<include refid="itemColums"></include>
FROM item
WHERE id=#{id}
</select>
增加ItemMapperTest测试类,对方法进行测试
代码语言:javascript复制@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:application.xml")
public class ItemMapperTest {
@Autowired
private ItemMapper itemMapper;
@Test
public void insert() {
for (int i = 10; i < 20; i ) {
Item item = new Item();
item.setName("Mark " i);
item.setPrice(12.0);
item.setDetail("IRON MAN ARMY");
item.setCreateTime(new Date());
itemMapper.insert(item);
}
}
@Test
public void selectById() {
Item item = itemMapper.selectById(18);
System.out.println("查询到的数据为:" item);
}
}
测试insert方法
测试selectById方法
新增ItemService接口及实现类
代码语言:javascript复制public interface ItemService {
void save(Item item);
Item findById(Integer id);
}
代码语言:javascript复制@Service
public class ItemServiceImpl implements ItemService {
@Autowired
private ItemMapper itemMapper;
@Override
public void save(Item item) {
itemMapper.insert(item);
}
@Override
public Item findById(Integer id) {
return itemMapper.selectById(id);
}
}
service层配置切面和事务通知,在application.xml中增加配置
代码语言:javascript复制<!--配置事务通知-->
<tx:advice id="advice" transaction-manager="dataSourceTransactionManager">
<tx:attributes>
<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.lilith.service.impl.*.*(..))"/>
<aop:advisor advice-ref="advice" pointcut-ref="pointcut" />
</aop:config>
生成ItemServiceTest测试类
代码语言:javascript复制@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:application.xml")
public class ItemServiceTest {
@Autowired
private ItemService itemService;
@Test
public void save() {
Item item = new Item();
item.setName("电脑");
item.setPrice(9999.0);
item.setCreateTime(new Date());
itemService.save(item);
}
@Test
public void findById() {
Item item = itemService.findById(20);
System.out.println("itemService查询到的数据为:" item);
}
}
测试save方法
测试findById方法
编写ItemController
代码语言:javascript复制@Controller
@RequestMapping("/item")
public class ItemController {
@Autowired
private ItemService itemService;
@GetMapping("/{id}")
public String getItem(@PathVariable("id") Integer id, Model model){
Item item = itemService.findById(id);
model.addAttribute("item",item);
return "item";
}
}
在WEB-INF下创建pages文件夹,新增item.jsp页面
代码语言:javascript复制<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<!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>
<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>
在Project Structure的Artifacts目录下将右侧的jar包全部导入左侧的新建的lib目录下
配置Tomcat并启动,浏览器输入地址 http://localhost:8080/item/20
成功查询到数据并显示在页面上