1.初识Spring
2.Spring Dramework
2.1学习路线
-
Aop:面向切面编程
-
Aspects:AOP思想实现
-
Core Container:核心容器
-
Data Access:数据访问
-
Date Integration:数据集成
-
Web:web开发
-
Text:单元测试和集成测试
2.2核心概念
-
IoC(Inversion of Control)控制反转
-
使用对象时,由主动new产生对象转换为由外部提供对象,此过程中对象创建控制权由程序转移到外部,此思想称为控制反转
-
-
Spring技术对IoC思想进行了实现
-
Spring提供了一个容器,称为IoC容器,用来充当IoC思想中的外部
-
IoC容器负责对象的创建,初始化等一系列工作,被创建或被管理的对象在IoC容器中统称为 Bean
-
-
DI(Dependence Injection)依赖注入
-
在容器中建立bean与bean之间的依赖关系的整个过程,称为依赖注入
-
-
目标:充分解耦
-
使用IoC容器管理bean (IoC)
-
在IoC容器内将有依赖关系的bean进行关系绑定 (DI)
-
-
最终效果
-
使用对象时不仅可以直接从IoC容器中获取,并且获取到的bean已经绑定了所有的依赖关系
-
2.3IoC入门案例思路分析
-
管理什么? (Service 和Dao)
-
如何将被管理的对象告知IoC容器?(配置)
-
被管理的对象交给IoC容器,如何获取到IoC容器? (接口)
-
IoC容器得到后,如何从容器中获取bean?(接口方法)
-
使用Spring导入那些坐标? (pom.xml)
IOC入门案例
1.导入spring坐标
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.10.RELEASE</version> </dependency>
2.定义Spring管理的类(接口)
public interface BookDao { public void save(); } public class BookDaoImpl implements BookDao { public void save() { System.out.println("book dao save ..."); } }
3.创建Spring配置文件,配置对应类作为Spring管理的bean
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 1.导入spring的坐标spring-context,对应版本是5.2.10.RELEASE--> <!-- 2.配置bean bean标签表示配置bean id属性表示bean起名字 class属性表示给bean定义类型 --> <bean id="bookDao" class="com.wen.dao.impl.BookDaoImpl"></bean> <bean id="bookService" class="com.wen.service.impl.BookServiceImpl"></bean> </beans>
4.初始化IOC容器(Spring核心容器/Spring容器),通过容器获取bean
public static void main(String[] args) { //3.获取IoC容器 ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); //4.获取bean(根据bean配置id获取) // BookDao bookDao = (BookDao) ctx.getBean("bookDao"); // bookDao.save(); BookService bookService = (BookService) ctx.getBean("bookService"); bookService.save(); }
2.4 DI入门案例思路分析
-
基于IoC管理bean
-
Service中使用new形式创建的Dao对象是否保留?(否)
-
Service中需要的Dao对象如何进入到Service中?(提供方法)
-
Service与Dao间的关系如何描述?(配置)
DI入门案例(XML版)
1.删除使用的new的形式创建的对象
public class BookServiceImpl implements BookService{ private BookDao bookDao = new BookDaoImpl(); public void save(){ bookDao.save(); } }
2.提供依赖对象对应的setter方法
public class BookServiceImpl implements BookService { //5.删除业务层中使用new的方式创建的dao对象 private BookDao bookDao; public void save() { System.out.println("book service save ..."); bookDao.save(); } //6.提供对应的set方法 public void setBookDao(BookDao bookDao) { this.bookDao = bookDao; } }
3.配置service与dao之间的关系
<bean id="bookDao" class="com.wen.dao.impl.BookDaoImpl"/> <bean id="bookService" class="com.wen.service.impl.BookServiceImpl"> <!-- 7.配置service与dao的关系 property标签表示配置当前的bean name的属性表示配置哪一个具体的属性(方法) ref表示这个属性(方法)参考哪一个bean --> <property name="bookDao" ref="bookDao"/> </bean>
3.1bean作用范围说明
-
为什么bean默认为单例?
-
适合给容器进行管理的bean
-
表现层对象
-
业务层对象
-
数据层对象
-
工具对象
-
-
不适合交给容器的进行管理的bean
-
封装实体的域对象
-
3.2bean实例化
-
bean本质上就是对象,创建bean使用构造方法完成
实例化bean的三种构造方法
1.提供可访问 的构造方法
public class BookDaoImpl implements BookDao { // public BookDaoImpl() { // System.out.println("book dao constructor is running ...."); // } public void save() { System.out.println("book dao save ..."); } }
-
配置
<bean id="bookDao" class="com.wen.dao.impl.BookDaoImpl"/>
-
无参构造方法如果不存在,,将抛出异常BeanCreationException
2.静态工厂
public class OrderDaoFactory{ public static OrderDao getOrderDao(){ return new OrderDaoImpl(); } }
-
配置
<bean id = "orderDao" factory-method = "getOrderDao" class="com.wen.factory.OrderDaoFactory" />
3.实例工厂
-
FactoryBean
public class UserDaoFactoryBean implement FactoryBean<UserDao>{ public UserDao getObject() throws Exception{ return new UserDaoImpl(); } public Class<?> getObjectType(){ return UserDao.class; } }
-
配置
<!-- 方式四:使用FactoryBean实例化bean--> <bean id="userDao" class="com.wen.factory.UserDaoFactoryBean"/>
3.3bean生命周期
-
生命周期:从创建到消亡的完整过程
-
bean生命周期:bean从创建到消亡的整体过程
-
bean生命周期控制:在bean创建后到销毁前做一些事情
-
初始化容器
-
创建对象(内存分配)
-
执行构造方法
-
执行属性注入(set操作)
-
执行bean初始化方法
-
-
使用bean
-
执行业务操作
-
-
关闭销毁bean
-
执行bean销毁方法
-
3.4bean生命周期控制
-
提供生命周期控制方法
public class BookDaoImpl implements BookDao { public void save() { System.out.println("book dao save ..."); } //表示bean初始化对应的操作 public void init(){ System.out.println("init..."); } //表示bean销毁前对应的操作 public void destroy(){ System.out.println("destory..."); } }
-
配置生命周期控制方法
<bean id="bookDao" class="com.wen.dao.impl.BookDaoImpl" init-method="init" destroy-method="destroy"/>
-
接口控制InitializingBean, DisposableBean接口
public class BookServiceImpl implements BookService, InitializingBean, DisposableBean { private BookDao bookDao; public void setBookDao(BookDao bookDao) { System.out.println("set ....."); this.bookDao = bookDao; } public void save() { System.out.println("book service save ..."); bookDao.save(); } public void destroy() throws Exception { System.out.println("service destroy"); } public void afterPropertiesSet() throws Exception { System.out.println("service init"); } }g
关闭容器
-
close()
-
registerShutdownHook()
-
4.1依赖注入
-
思考:向一个类中传递数据的方式有几种?
-
普通方法(set方法)
-
构造方法
-
-
思考:依赖注入描述了在容器中建立bean与bean之间依赖关系的过程,如果bean运行需要的是数字或是字符串呢?
-
引用类型
-
简单类型(基本数据类型与String)
-
-
依赖注入方式
-
setter注入
-
简单类型
-
引用类型
-
-
构造器注入
-
简单类型
-
引用类型
-
-
setter注入---简单类型
-
在bean中定义引用类型属性并提供可访问的set方法
private String databaseName; public void setDatabaseName(String databaseName) { this.databaseName = databaseName; }
-
配置中使用property标签value属性注入简单类型数据
<bean id="bookDao" class="com.wen.dao.impl.BookDaoImpl"> <property name="databaseName" value="mysql"/> </bean>
构造器注入---引用类型(了解)
-
在bean中定义引用类型属性并提供可访问的构造方法
public class BookServiceImpl implements BookService{ private BookDao bookDao; private UserDao userDao; public BookServiceImpl(BookDao bookDao, UserDao userDao) { this.bookDao = bookDao; this.userDao = userDao; } }
-
配置中使用constructor-arg标签ref属性注入引用类型对象
<bean id="userDao" class="com.wen.dao.impl.UserDaoImpl"/> <bean id="bookService" class="com.wen.service.impl.BookServiceImpl"> <constructor-arg name="bookDao" ref="bookDao"/> <constructor-arg name="userDao" ref="userDao"/>
构造器注入--简单类型(了解)
-
在bean中定义引用类型属性并提供可访问的set方法
public class BookDaoImpl implements BookDao { private String databaseName; private int connectionNum; public BookDaoImpl(String databaseName, int connectionNum) { this.databaseName = databaseName; this.connectionNum = connectionNum; } public void save() { System.out.println("book dao save ..."+databaseName+","+connectionNum); } }
-
配置中使用constructor-arg标签value属性注入简单类型数据
<!-- <bean id="bookDao" class="com.wen.dao.impl.BookDaoImpl">--> <!-- <constructor-arg name="connectionNum" value="100"/>--> <!-- <constructor-arg name="databaseName" value="mysql"/>--> <!-- </bean>-->
4.2依赖自动装配
-
Ioc容器根据bean所依赖的资源在容器中自动查找并注入到bean的过程叫自动装配
-
自动装配方式
-
按类型
-
按名称
-
按构造方法
-
配置中使用bean标签autowire属性设置自动装配的类型
<bean id="userDao" class="com.wen.dao.impl.BookDaoImpl"/> <bean id="bookService" class="com.wen.service.impl.BookServiceImpl" autowire="byType"/>
4.3集合注入
<property name="array"> <array> <value>100</value> <value>200</value> <value>300</value> </array> </property> <property name="list"> <list> <value>pp</value> <value>kk</value> <value>jj</value> </list> </property> <property name="set"> <set> <value>100</value> <value>200</value> <value>300</value> <value>300</value> </set> </property> <property name="map"> <map> <entry key="country" value="china"/> <entry key="province" value="shanxi"/> <entry key="city" value="xin"/> </map> </property> <property name="properties"> <props> <prop key="country">china</prop> <prop key="province">shanxi</prop> <prop key="city">xin</prop> </props> </property>
5.1第三方资源配置管理
导入druid坐标
<dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.16</version> </dependency>
配置数据源对象作为spring管理的bean
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc//:mysql://localhost:3306/spring_db"/> <property name="username" value="root"/> <property name="password" value="root"/> </bean>
5.2加载properties配置信息
开启context命名空间
<?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:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
使用context命名空间,加载指定properties文件
2.使用context空间加载properties文件 --> <context:property-placeholder location="jdbc.properties"/>
<!-- 3.使用属性站位符${}读取properties中的属性--> <bean 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}"/> </bean> <bean id="bookDao" class="com.wen.dao.impl.BookDaoImpl"> <property name="name" value="${}"/> </bean>
6.1容器
创建
-
ClassPathXmlApplicationContext
-
FileSystemXmlApplicationContext
BeanFactory是Ioc容器的顶层接口,初始化BeanFactory对象时,加载的bean延迟加载 (lazy-init="true")
ApplicationContext接口是Spring容器的核心接口,初始化bean立即加载
ApplicationContext接口提供基础的bean操作相关方法,通过其他接口扩展其功能
3.注解
1.1注解开发定义bean
-
使用@Component定义bean
@Component("bookDao") public class BookDaoImpl implements BookDao{} @Component public class BookServiceImpl implements BookService{}
-
核心配置文件中通过组件扫描加载bean
<context:component-scan base-package="com.wen"/>
1.2纯注解开发
-
java类代替Spring核心配置文件
//声明当前类为Spring配置类 @Configuration //设置bean扫描路径,多个路径书写为字符串数组格式 @ComponentScan({"com.wen.service", "com.wen.dao"}) public class SpringConfig { }
-
@Configuration注解用于设定当前类为配置
-
@Configuration注解用于设定扫描路径,此注解只能添加一次,多个数据请用数组格式
@ComponentScan({"com.wen.service", "com.wen.dao"})
-
读取Spring核心配置文件初始化容器对象切换为读取Java配置类初始化容器对象
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); //AnnotationConfigApplicationContext加载Spring配置类初始化Spring容器 ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
1.3bean作用范围
-
使用@Scope定义bean作用范围
@Repository //@Scope设置bean的作用范围 @Scope("singleton") public class BookDaoImpl implements BookDao { }
-
使用@PostConstruct.@PreDestory定义bean生命周期
@Repository //@Scope设置bean的作用范围 @Scope("singleton") public class BookDaoImpl implements BookDao { public void save() { System.out.println("book dao save ..."); } //@PostConstruct设置bean的初始化方法 @PostConstruct public void init() { System.out.println("init ..."); } //@PreDestroy设置bean的销毁方法 @PreDestroy public void destroy() { System.out.println("destroy ..."); } }
2.1依赖注入
-
使用@Qualifier注解开启指定名称装配bean
@Service public class BookServiceImpl implements BookService { //@Autowired:注入引用类型,自动装配模式,默认按类型装配 @Autowired //@Qualifier:自动装配bean时按bean名称装配 @Qualifier("bookDao") private BookDao bookDao; public void save() { System.out.println("book service save ..."); bookDao.save(); } }
注意: @Qualifiler注解无法单独使用,必须配合@Autowired注解使用
-
使用@Value实现简单类型注入
//@Value:注入简单类型(无需提供set方法) @Value("${name}") private String name;
-
加载properties文件
-
使用@PropertySource注解加载properties文件
@Configuration @ComponentScan("com.wen") //@PropertySource加载properties配置文件 @PropertySource({"jdbc.properties"}) public class SpringConfig { }
-
注意:路径仅仅支持单一文件配置,多文件请使用数组格式配置,不允许使用通配符*
-
2.2第三方bean管理,第三方依赖注入
-
使用@Bean配置第三方bean
-
使用Import注解手动加入配置类到核心配置,此注解只能添加一次,多个请使用数组格式
@Configuration @ComponentScan("com.wen") //@Import:导入配置信息 @Import({JdbcConfig.class}) public class SpringConfig { } public class JdbcConfig { //1.定义一个方法获得要管理的对象 @Value("com.mysql.jdbc.Driver") private String driver; @Value("jdbc:mysql://localhost:3306/spring_db") private String url; @Value("root") private String userName; @Value("root") private String password; //2.添加@Bean,表示当前方法的返回值是一个bean //@Bean修饰的方法,形参根据类型自动装配 @Bean public DataSource dataSource(){ DruidDataSource ds = new DruidDataSource(); ds.setDriverClassName(driver); ds.setUrl(url); ds.setUsername(userName); ds.setPassword(password); return ds; } }
-
引用类型依赖注入
@Bean public DataSource dataSource(BookDao bookDao){ System.out.println(bookDao); DruidDataSource ds = new DruidDataSource(); ds.setDriverClassName(driver); ds.setUrl(url); ds.setUsername(userName); ds.setPassword(password); return ds; }
-
引用类型注入只需要为bean定义方法设置形参即可,容器会根据类型自动装配
3.1Xml配置与注解配置比较
4.Spring整合Mybits
1.mybits
public static void main(String[] args) throws IOException { // 1. 创建SqlSessionFactoryBuilder对象 SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder(); // 2. 加载SqlMapConfig.xml配置文件 InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml.bak"); // 3. 创建SqlSessionFactory对象 SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream); // 4. 获取SqlSession SqlSession sqlSession = sqlSessionFactory.openSession(); // 5. 执行SqlSession对象执行查询,获取结果User AccountDao accountDao = sqlSession.getMapper(AccountDao.class); Account ac = accountDao.findById(2); System.out.println(ac); // 6. 释放资源 sqlSession.close(); }
2.Spring整合Mybatis
public class MybatisConfig { //定义bean,SqlSessionFactoryBean,用于产生SqlSessionFactory对象 @Bean public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource){ SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean(); ssfb.setTypeAliasesPackage("com.itheima.domain"); ssfb.setDataSource(dataSource); return ssfb; } //定义bean,返回MapperScannerConfigurer对象 @Bean public MapperScannerConfigurer mapperScannerConfigurer(){ MapperScannerConfigurer msc = new MapperScannerConfigurer(); msc.setBasePackage("com.itheima.dao"); return msc; } }
3.Spring整合JUnit
//设置类运行器 @RunWith(SpringJUnit4ClassRunner.class) //设置Spring环境对应的配置类 @ContextConfiguration(classes = SpringConfig.class) public class AccountServiceTest { //支持自动装配注入bean @Autowired private AccountService accountService; @Test public void testFindById(){ System.out.println(accountService.findById(1)); } @Test public void testFindAll(){ System.out.println(accountService.findAll()); } }
5.Aop
1.1Aop简介
-
AOP面向切面编程,一种编程范式,指导开发着如何组织程序结构
-
OOP面向对象编程
-
-
作用:在不动原始设计的基础上为其进行功能增强
-
spring理念:无侵入式
-
1.2AOP核心概念
-
连接点:程序执行过程中的任意位置,粒度为执行方法.抛出异常.设置变量
-
在SpringAOP中.理解为方法的执行
-
-
切入点:匹配连接点的式子
-
在spring中,一个切入点可以只描述一个具体方法,也可以匹配多个方法
-
一个具体方法com.itheima.dao包下的BookDao接口中的无参无返回值的save方法
-
匹配多个方法:所有的save方法,所有的get开头的方法,有所有以Dao结尾的接口中的任意方法,所有带有一个参数的方法
-
-
通知:在切入点处执行的操作,也就是共性功能
-
在SpringAOP中,功能最终以方法的形式呈现
-
-
通知类:定义通知的类
-
切面:描述通知与切入点的对应关系
2.1AOP的入门案例
-
导包
-
制作连接点方法(原始操作,Dao接口与实现类)
-
制作公共功能(通知类与通知)
-
第一切入点
-
绑定切入点和通知关系(切面)
2.2AOP入门案例(注解版)
-
导包
-
定义Dao接口和实现类
@Repository public class BookDaoImpl implements BookDao { public void save() { System.out.println(System.currentTimeMillis()); System.out.println("book dao save ..."); } public void update(){ System.out.println("book dao update ..."); } }
-
定义通知类,制作通知
public class MyAdvice{ public void before(){ System.out.println(System.currentTimeMillis()); } }
-
定义切入点
//通知类必须配置成Spring管理的bean @Component //设置当前类为切面类类 @Aspect public class MyAdvice { //设置切入点,要求配置在方法上方 @Pointcut("execution(void com.itheima.dao.BookDao.update())") private void pt(){} }
-
绑定切入点与通知关系,并指定通知添加到原始连接点的具体执行位置
//设置切入点,要求配置在方法上方 @Pointcut("execution(void com.itheima.dao.BookDao.update())") private void pt(){} //设置在切入点pt()的前面运行当前操作(前置通知) // @Before("pt()") public void method(){ System.out.println(System.currentTimeMillis()); }
-
开启Spring对Aop注解驱动支持
@Configuration @ComponentScan("com.itheima") //开启注解开发AOP功能 @EnableAspectJAutoProxy public class SpringConfig { }
3.1AOP工作流程
-
Spring容器启动
-
读取所有切面配置中的切入点
-
初始化bean,判定bean对应的类中的方法是否匹配到任意切点
-
匹配失败,创建对象
-
匹配成功,创建原始对象(目标对象)的代理对象
-
-
获取bean执行方法
-
获取bean,调用方法并执行,完成操作
-
获取bean是代理时,根据代理对象的运行模式运行原始方法与增强的内容,完成操作3
-
3.2核心概念
-
目标对象:原始功能去掉共性功能对应的类产生的对象,这种对象是无法直接完成最终工作的
-
代理(Proxy):目标对象无法直接完成工作,需要对其进行功能回填,通过原始对象的代理对象实现
3.3SpringAOP本质
本质:代理模式
4.1AOP切入点表达式
-
切入点:要进行增强的方法
-
切入点表达式:要进行增强的方法的描述方式
-
切入点表达式标准格式:动作关键字(访问修饰符 返回值 包名.类/接口名.方法名(参数) 异常名
execution(public void com.itheima.dao.BookDao.update(int))
-
可以使用通配符描述切入点,快速描述
-
*:
execution(public * com.itheima.*.BookDao.find*(int))
-
..
execution(public .. com.itheima.dao.BookDao.update(..))
-
-
书写技巧
4.2AOP通知类型
-
AOP通知描述了抽取的公共功能,根据共性功能抽取的位置不同,最终运行的代码时要将其加入到合理的位置
-
AOP通知共分为5中类型
-
前置通知
-
//@Before:前置通知,在原始方法运行之前执行 @Before("pt()") public void before() { System.out.println("before advice ...");
-
-
后置通知
-
//@After:后置通知,在原始方法运行之后执行 @After("pt2()") public void after() { System.out.println("after advice ..."); }
-
-
环绕通知 ProceedingJoinPoint
-
//@Around:环绕通知,在原始方法运行的前后执行 // @Around("pt()") public Object around(ProceedingJoinPoint pjp) throws Throwable { System.out.println("around before advice ..."); //表示对原始操作的调用 Object ret = pjp.proceed(); System.out.println("around after advice ..."); return ret; }
-
-
返回后通知(了解)
-
抛出异常后通知(了解)
-
4.3案例:测量业务层接口万次执行效率
@Component @Aspect public class ProjectAdvice { //匹配业务层的所有方法 @Pointcut("execution(* com.itheima.service.*Service.*(..))") private void servicePt(){} //设置环绕通知,在原始操作的运行前后记录执行时间 @Around("ProjectAdvice.servicePt()") public void runSpeed(ProceedingJoinPoint pjp) throws Throwable { //获取执行的签名对象 Signature signature = pjp.getSignature(); String className = signature.getDeclaringTypeName(); String methodName = signature.getName(); long start = System.currentTimeMillis(); for (int i = 0; i < 10000; i++) { pjp.proceed(); } long end = System.currentTimeMillis(); System.out.println("万次执行:"+ className+"."+methodName+"---->" +(end-start) + "ms"); } }
4.4 AOP通知获取数据
获取参数
-
获取切入点方法的参数
-
JoinPoint:适用于前置,后置,返回后,抛出异常后通知
-
ProceedJointPoint:适用于环绕通知
-
//JoinPoint:用于描述切入点的对象,必须配置成通知方法中的第一个参数,可用于获取原始方法调用的参数 // @Before("pt()") public void before(JoinPoint jp) { Object[] args = jp.getArgs(); System.out.println(Arrays.toString(args)); System.out.println("before advice ..." ); } // @After("pt()") public void after(JoinPoint jp) { Object[] args = jp.getArgs(); System.out.println(Arrays.toString(args)); System.out.println("after advice ..."); }
获取返回值
-
获取切入点方法返回值
-
返回后通知
-
环绕通知
-
@Around("pt()") public Object around(ProceedingJoinPoint pjp) { Object[] args = pjp.getArgs(); return ret; }
获取异常
-
获取切入点方法运行异常信息
-
抛出异常后通知
-
环绕通知
-
4.5案例:百度网盘密码数据兼容处理
@Component @Aspect public class DataAdvice { @Pointcut("execution(boolean com.itheima.service.*Service.*(*,*))") private void servicePt(){} @Around("DataAdvice.servicePt()") public Object trimStr(ProceedingJoinPoint pjp) throws Throwable { Object[] args = pjp.getArgs(); for (int i = 0; i < args.length; i++) { //判断参数是不是字符串 if(args[i].getClass().equals(String.class)){ args[i] = args[i].toString().trim(); } } Object ret = pjp.proceed(args); return ret; }
4.6 AOP总结
6. Spring事务简介
1. Spring事务简介
事务作用:在数据层保障一系列的数据库操作同成功同失败
Spring事务作用:在数据层或 业务层保障一系列的数据库操作同成功同失败
1.业务层接口上添加Spring事务管理
public interface AccountService { @Transactional public void transfer (String out,String in,Double money); }
注意事项: Spring注解式事务通常添加在业务接口中而不会添加到业务层实现类中,降低耦合 注解式事务可以添加到业务方法上表示当前方法开启事务,也可以添加到接口上表示当前接口所有方法开启事务
2.设置事务管理器
@Bean public PlatfromTransactionManager transactionManager(DataSource dataSource){ DataSourceTransactionManager ptm = new DataSourceTransactionManager(); ptm.setDataSource(dataSource); return ptm; }
注意事项:
事务管理器要根据实现技术进行选则
Mybatis框架使用的是JDBC事务
3.开启注解式事务驱动
@Configuration @ComponentScan("com.itheima") @PropertySource("classpath:jdbc.properties") @Import({JdbcConfig.class,MybatisConfig.class}) @EnableTransactionManagement public class SpringConfig{ }
2 Spring事务角色
事务角色
-
事务管理员:发起事务方,在Spring中通常指代业务层开启事物的方法
-
事务协调员:假如事务方,在Spring中通常指代数据层方法,也可以是业务层方法
3 事务相关配置
1.事务相关配置
2.事务传播行为
public interface LogService { //propagation设置事务属性:传播行为设置为当前操作需要新事务 @Transactional(propagation = Propagation.REQUIRES_NEW) void log(String out, String in, Double money); } @Service public class LogServiceImpl implements LogService { @Autowired private LogDao logDao; public void log(String out,String in,Double money ) { logDao.log("转账操作由"+out+"到"+in+",金额:"+money); } }
7.SpringMVC简介
1.1 SpringMVC概述
-
SpringMVC技术与Servlet技术功能等同,均属于web层技术开发
-
SpringMVC是一种基于Java实现MVC模型的轻量级Web框架
-
优点
-
使用简单,开发便捷(相比于Servlet)
-
灵活性强
-
1.2 SpringMVC入门案例
-
导包
-
创建SpringMVC控制器类(等同于Servlet功能)
//定义表现层控制器bean @Controller public class UserController { //设置映射路径为/save,即外部访问路径 @RequestMapping("/save") //设置当前操作返回结果为指定json数据(本质上是一个字符串信息) @ResponseBody public String save(){ System.out.println("user save ..."); return "{'info':'springmvc'}"; }
-
初始化SpringMVC环境(同Spring环境),设定SPringMVC加载对应的bean
//springmvc配置类,本质上还是一个spring配置类 @Configuration @ComponentScan("com.itheima.controller") public class SpringMvcConfig { }
-
初始化Servlet容器,加载SpringMVC环境,并设置SpringMVC技术处理的请求
//web容器配置类 public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer { //加载springmvc配置类,产生springmvc容器(本质还是spring容器) protected WebApplicationContext createServletApplicationContext() { //初始化WebApplicationContext对象 AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext(); //加载指定配置类 ctx.register(SpringMvcConfig.class); return ctx; } //设置由springmvc控制器处理的请求映射路径 protected String[] getServletMappings() { return new String[]{"/"}; } //加载spring配置类 protected WebApplicationContext createRootApplicationContext() { return null; } }
1.3入门案例工作流程分析
-
启动服务器初始化过程
-
服务器启动,执行ServletContainersInitConfig类,初始化web容器
-
执行createServletApplicationContext方法,创建了WebApplicationContext对象
-
加载SpringMvcConfig
-
执行@ComponentScan加载对应的bean
-
加载UserController,每个@RequestMapping的名称对应一个具体的方法
-
执行getServletMappings方法,定义所有的请求都通过SpringMVC
-
-
单词请求过程
-
发送请求localhost/save
-
web容器发现所有请求都经过SpringMVC,将请求交给SpringMVC处理
-
解析请求路径/save
-
由/save匹配执行对应的方法save()
-
执行save()
-
检测到有@ResponseBody直接将save()方法的返回值作为响应求体返回给请求方
-
1.4 Controller加载控制
@Configuration //@ComponentScan({"com.itheima.service","com.itheima.dao"}) //设置spring配置类加载bean时的过滤规则,当前要求排除掉表现层对应的bean //excludeFilters属性:设置扫描加载bean时,排除的过滤规则 //type属性:设置排除规则,当前使用按照bean定义时的注解类型进行排除 //classes属性:设置排除的具体注解类,当前设置排除@Controller定义的bean @ComponentScan(value="com.itheima", excludeFilters = @ComponentScan.Filter( type = FilterType.ANNOTATION, classes = Controller.class ) ) public class SpringConfig { }
-
属性
-
excludeFilters:排除扫描路径中加载的bean,需要指定类别(type)与具体项(classse)
-
includeFilters:加载指定的bean,需要指定类别(type)与具体项(classes)
-
bean加载格式
//web配置类简化开发,仅设置配置类类名即可 public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer { protected Class<?>[] getRootConfigClasses() { return new Class[]{SpringConfig.class}; } protected Class<?>[] getServletConfigClasses() { return new Class[]{SpringMvcConfig.class}; } protected String[] getServletMappings() { return new String[]{"/"}; } }
2.1请求映射路径
@RequestMapping
-
作用:访问当前控制器方法请求访问路径,如果设置在类上统一设置当前控制器方法请求访问路径前缀
-
属性
-
value(默认):请求访问路径,或访问路径前缀
-
@Controller public class BookController { //请求路径映射 @RequestMapping("/book/save") @ResponseBody public String save(){ System.out.println("book save ..."); return "{'module':'book save'}"; } }
2.2请求方式
-
Get请求
-
Post请求
-
为web容器添加过滤器并指定字符集,Spring——web包中提供了专用的字符过滤器
//乱码处理 @Override protected Filter[] getServletFilters() { CharacterEncodingFilter filter = new CharacterEncodingFilter(); filter.setEncoding("UTF-8"); return new Filter[]{filter}; }
2.3请求参数
-
@RequestParam
//普通参数:请求参数名与形参名不同时,使用@RequestParam注解关联请求参数名称与形参名称之间的关系 @RequestMapping("/commonParamDifferentName") @ResponseBody public String commonParamDifferentName(@RequestParam("name") String userName , int age){ System.out.println("普通参数传递 userName ==> "+userName); System.out.println("普通参数传递 age ==> "+age); return "{'module':'common param different name'}"; }
-
POJO参数:请求参数名与形参对象属性名相同,定义POJO类型形参即可接收参数
//POJO参数:请求参数与形参对象中的属性对应即可完成参数传递 @RequestMapping("/pojoParam") @ResponseBody public String pojoParam(User user){ System.out.println("pojo参数传递 user ==> "+user); return "{'module':'pojo param'}"; }
-
嵌套POJO参数:请求参数名与形参对象属性名相同,按照对象层次结构关系即可接收嵌套POJO属性参数
-
数组参数:请求参数名与形参对象属性名相同且请求参数为多个,定义数组类型形参即可接收参数
//数组参数:同名请求参数可以直接映射到对应名称的形参数组对象中 @RequestMapping("/arrayParam") @ResponseBody public String arrayParam(String[] likes){ System.out.println("数组参数传递 likes ==> "+ Arrays.toString(likes)); return "{'module':'array param'}"; }
-
集合保存普通参数:请求参数参数名形参集合对象名相同请求参数为多个,@RequestParam绑定参数关系
//集合参数:同名请求参数可以使用@RequestParam注解映射到对应名称的集合对象中作为数据 @RequestMapping("/listParam") @ResponseBody public String listParam(@RequestParam List<String> likes){ System.out.println("集合参数传递 likes ==> "+ likes); return "{'module':'list param'}"; }
2.4请求参数(传递json数据)
-
@EnableWebMvc
@Configuration @ComponentScan("com.itheima.controller") //开启json数据类型自动转换 @EnableWebMvc public class SpringMvcConfig { }
-
@RequestBody
@RequestMapping("/listParam") @ResponseBody public String listParam(@RequestBody List<String> likes){ System.out.println("集合参数传递 likes ==> "+ likes); return "{'module':'list param'}"; }
2.5日期类型参数传递
-
@DataTimeFormat
-
属性:pattern:日期时间格式字符串
//日期参数 //使用@DateTimeFormat注解设置日期类型数据格式,默认格式yyyy/MM/dd @RequestMapping("/dataParam") @ResponseBody public String dataParam(Date date, @DateTimeFormat(pattern="yyyy-MM-dd") Date date1, @DateTimeFormat(pattern="yyyy/MM/dd HH:mm:ss") Date date2){ System.out.println("参数传递 date ==> "+date); System.out.println("参数传递 date1(yyyy-MM-dd) ==> "+date1); System.out.println("参数传递 date2(yyyy/MM/dd HH:mm:ss) ==> "+date2); return "{'module':'data param'}"; }
-
-
Converter接口
-
@EnableWebMvc功能之一:根据类型匹配对应的类型转换器
public interface Converter<S,T>{ @Nullable T converter(S var1); }
-
请求参数年龄数据(String-->Integer)
-
日期格式转换(String--->Date)
-
3.1响应
-
响应文本数据(了解)
-
响应json数据
3.2REST风格
REST:风格简介
-
按照REST风格访问资源时使用行为动作区分对资源进行了何种操作
-
http://localhost/users 查询全部用户信息 GET(查询)
-
http://localhost/users/1 查询指定用户信息 GET(查询)
-
http://localhost/users 添加用户信息 POST(新增/保存)
-
http://localhost/users 修改用户信息 PUT(修改/更新)
-
http://localhost/users/1 删除用户信息 DELETE(删除)
-
-
根据REST风格对资源访问称为RESTful
3.3RESTful入门案例
-
设定http请求动作(动词)
//设置当前请求方法为POST,表示REST风格中的添加操作 @RequestMapping(value = "/users",method = RequestMethod.POST) @ResponseBody public String save(){ System.out.println("user save..."); return "{'module':'user save'}"; } //设置当前请求方法为PUT,表示REST风格中的修改操作 @RequestMapping(value = "/users",method = RequestMethod.PUT) @ResponseBody public String update(@RequestBody User user){ System.out.println("user update..."+user); return "{'module':'user update'}"; }
-
设定请求参数(路径变量)
//设置当前请求方法为DELETE,表示REST风格中的删除操作 //@PathVariable注解用于设置路径变量(路径参数),要求路径上设置对应的占位符,并且占位符名称与方法形参名称相同 @RequestMapping(value = "/users/{id}",method = RequestMethod.DELETE) @ResponseBody public String delete(@PathVariable Integer id){ System.out.println("user delete..." + id); return "{'module':'user delete'}"; }
-
@RequestMapping
-
作用:设置当前控制器方法请求访问路径
-
属性:
-
value:请求访问路径
-
method:http请求动作,标准动作(GET/POST/PUT/DELETE)
-
-
-
@PathVarIable
-
类型:形参注解
-
位置:SpringMVC控制器方法形参定义前面
-
作用:绑定路径参数与处理器方法形参间的关系,要求路径参数名与形参名一一对应
-
//设置当前请求方法为DELETE,表示REST风格中的删除操作 //@PathVariable注解用于设置路径变量(路径参数),要求路径上设置对应的占位符,并且占位符名称与方法形参名称相同 @RequestMapping(value = "/users/{id}",method = RequestMethod.DELETE) @ResponseBody public String delete(@PathVariable Integer id){ System.out.println("user delete..." + id); return "{'module':'user delete'}"; }
-
-
3.4RESTful快速开发
-
@RestController
-
作用:设置当前控制器类为RESTful风格,等同于@Controller与@ResponseBody两个注解的结合
-
@RequestMapping("/books") public class BookController2 {
-
3.5基于RESTful页面数据交互
-
制作SpringMVC控制器,并通过POSTMan测试接口功能
@RestController @RequestMapping("/books") public class BookController { @PostMapping public String save(@RequestBody Book book){ System.out.println("book save ==> "+ book); return "{'module':'book save success'}"; } @GetMapping public List<Book> getAll(){ System.out.println("book getAll is running ..."); List<Book> bookList = new ArrayList<Book>(); Book book1 = new Book(); book1.setType("计算机"); book1.setName("SpringMVC入门教程"); book1.setDescription("小试牛刀"); bookList.add(book1); return bookList; } }
-
设置对静态资源的访问放行
@Configuration public class SpringMvcSupport extends WebMvcConfigurationSupport { //设置静态资源访问过滤,当前类需要设置为配置类,并被扫描加载 @Override protected void addResourceHandlers(ResourceHandlerRegistry registry) { //当访问/pages/????时候,从/pages目录下查找内容 registry.addResourceHandler("/pages/**").addResourceLocations("/pages/"); registry.addResourceHandler("/js/**").addResourceLocations("/js/"); registry.addResourceHandler("/css/**").addResourceLocations("/css/"); registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/"); } }
-
前端页面通过异步提交访问后台控制器
//添加 saveBook () { axios.post("/books",this.formData).then((res)=>{ }); }, //主页列表查询 getAll() { axios.get("/books").then((res)=>{ this.dataList = res.data; }); },
8. SSM框架整合
8.1SSM整合流程
-
创建工程
-
SSM整合
-
Spring
-
SpringConfig
-
-
Mybatis
-
MybatisConfig
-
JdbcConfig
-
jdbc.properties
-
-
SpringMVC
-
ServletConfig
-
SpringMvcConfig
-
-
-
功能模块
-
标与实体类
-
dao(接口+自动代理)
-
service(接口+实现类)
-
业务层接口测试(整合 JUnit)
-
-
controller
-
表现层接口测试(PostMan)
-
-
-
Spring整合Mybatis
-
配置
-
SpringConfig
-
JDBCConfig,jdbc.properties
-
MyBatisConfig
-
-
模型
-
Book
-
-
数据层标准开发
-
BookDao
-
-
业务层标准开发
-
BookService
-
BookServiceImpl
-
-
测试接口
-
BookServiceTest
-
-
事务处理
-
-
Spring整合SpringMVC
-
web配置类
-
SpringMVC配置类
-
基于Restful的Controller开发
-
8.2表现层数据封装
-
前端接收数据格式-----创建结果模型类,封装数据到data属性中
-
前端接收数据格式-----封装操作结果到code属性中
-
前端接收数据格式-----封装特殊消息到message(msg)属性中
-
设置统一数据返回结果类
public class Result { //描述统一格式中的数据 private Object data; //描述统一格式中的编码,用于区分操作,可以简化配置0或1表示成功失败 private Integer code; //描述统一格式中的消息,可选属性 private String msg;
-
设置统一的数据返回结果编码
//状态码 public class Code { public static final Integer SAVE_OK = 20011; public static final Integer DELETE_OK = 20021; public static final Integer UPDATE_OK = 20031; public static final Integer GET_OK = 20041; public static final Integer SAVE_ERR = 20010; public static final Integer DELETE_ERR = 20020; public static final Integer UPDATE_ERR = 20030; public static final Integer GET_ERR = 20040; }
-
-
根据情况设定合理的Result
//统一每一个控制器方法返回值 @RestController @RequestMapping("/books") public class BookController { @Autowired private BookService bookService; @GetMapping("/{id}") public Result getById(@PathVariable Integer id) { Book book = bookService.getById(id); Integer code = book != null ? Code.GET_OK : Code.GET_ERR; String msg = book != null ? "" : "数据查询失败,请重试!"; return new Result(code,book,msg); }
8.3异常处理器
1.
-
异常处理器
-
集中的,统一的,处理项目中出现的异常
//@RestControllerAdvice用于标识当前类为REST风格对应的异常处理器 @RestControllerAdvice public class ProjectExceptionAdvice { //@ExceptionHandler用于设置当前处理器类对应的异常类型 @ExceptionHandler(SystemException.class) public Result doSystemException(SystemException ex){ return new Result(666,null); } }
-
-
ExceptionHandler
-
作用:设置指定异常的处理方案,功能等同于控制器方法,出现异常后终止原始控制器执行,并转入当前方法执行
-
此类方法可以根据处理的异常不同,制作多个方法分别处理对应的异常
-
2.
-
项目异常分类
-
业务异常
-
规范用户行为产生的异常
-
不规范的用户行为操作产生的异常
-
-
系统异常
-
项目运行过程中可预计且无法避免的异常
-
-
其他异常
-
编程人员位未预期刀的异常
-
-
-
项目异常处理方案
-
业务异常
-
发送对应的消息传递给用户,体醒规范操作
-
-
系统异常
-
发送固定消息传递给用户,安抚用户
-
提醒维护人员维护
-
日志
-
-
其他异常
-
发送固定消息传递给用户,安抚用户
-
提醒维护人员维护
-
日志
-
-
-
自定义项目系统级异常
-
自定义项目业务级异常
-
自定义异常编码
-
出发自定义异常
-
拦截并处理
//@RestControllerAdvice用于标识当前类为REST风格对应的异常处理器 @RestControllerAdvice public class ProjectExceptionAdvice { //@ExceptionHandler用于设置当前处理器类对应的异常类型 @ExceptionHandler(SystemException.class) public Result doSystemException(SystemException ex){ //记录日志 //发送消息给运维 //发送邮件给开发人员,ex对象发送给开发人员 return new Result(ex.getCode(),null,ex.getMessage()); } @ExceptionHandler(BusinessException.class) public Result doBusinessException(BusinessException ex){ return new Result(ex.getCode(),null,ex.getMessage()); } //除了自定义的异常处理器,保留对Exception类型的异常处理,用于处理非预期的异常 @ExceptionHandler(Exception.class) public Result doOtherException(Exception ex){ //记录日志 //发送消息给运维 //发送邮件给开发人员,ex对象发送给开发人员 return new Result(Code.SYSTEM_UNKNOW_ERR,null,"系统繁忙,请稍后再试!"); } }
-
异常处理器效果对比
-
自定义项目系统级异常
axios.get("/books").then((res)=>{}); axios.post("/books",this.formData).then((res)=>{}); axios.delete("/books/"+row.id).then((res)=>{}); axios.put("/books",this.formData).then((res)=>{}); axios.get("/books"+row.id).then((res)=>{});
8.4 拦截器
拦截器概念
-
拦截器是一种动态拦截方法调用的机制,在SpringMVC中动态拦截控制器方法的执行
-
作用:
-
在指定的方法调用前后执行预先设定的代码
-
组织原始方法的执行
-
拦截器和过滤器的区别
-
归属不同:Filter属于Servlet技术,Interceptor属于SpringMVC技术
-
拦截内容不同:Filter对所有访问进行增强,Intercepor仅针对SpringMVC的访问进行增强
制作拦截器功能类 配置拦截器的执行位置
-
声明拦截器的bean,并实现HandlerInterceptor接口(注意:扫描加载bean)
@Component //定义拦截器类,实现HandlerInterceptor接口 //注意当前类必须受Spring容器控制 public class ProjectInterceptor implements HandlerInterceptor { @Override //原始方法调用前执行的内容 //返回值类型可以拦截控制的执行,true放行,false终止 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String contentType = request.getHeader("Content-Type"); HandlerMethod hm = (HandlerMethod)handler; System.out.println("preHandle..."+contentType); return true; } @Override //原始方法调用后执行的内容 public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle..."); } @Override //原始方法调用完成后执行的内容 public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion..."); } }
-
定义配置类,继承WebMvcConfigurationSupport,实现addInterceptor方法(注意:扫描加载配置)
@Configuration public class SpringMvcSupport extends WebMvcConfigurationSupport { @Override protected void addInterceptors(InterceptorRegistry registry) { ... } }
-
添加拦截器并设定拦截的访问路径,路径可以通过可变参数设置多个
@Configuration public class SpringMvcSupport extends WebMvcConfigurationSupport { @Override protected void addInterceptors(InterceptorRegistry registry) { //配置拦截器 registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*"); } }
-
使用标准接口WebMvc'Configurer简化开发(注意:侵入式较强)
@Configuration @ComponentScan("com.itheim.controller") @EnableWebMvc public class SpringMvcConfig implements WebMvcConfigurer{ @Autowired private ProjectInterceptor projectInterceptor; public void addInterceptors(InterceptorRegistry){ registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*"); } }
多个拦截器执行顺序
-
类似先进后出
9.Maven
9.1分模块开发与设计
-
分模块开发意义
-
将原始模块按照功能拆成若干个子模块,方便模块间的相互调用,接口共享
-
-
新建新模块,放进去,在添加对应依赖,
-
依赖具有传递性
-
直接依赖
-
间接依赖
-
-
依赖冲突
-
特殊优先:当同级配置了相同的资源的不同版本,后配置的覆盖先配置的
-
声明优先:当资源在相同层级被依赖时,配置顺序考前
-
路径优先:当依赖中出现相同的
-
9.2继承与聚合
聚合
-
作用:使用聚合工程可以将多个工程编组,通过对聚合工程进行构建,实现对所包含的模块进行同步构建
-
当工程中某个模块发生更新时,必须保障工程中与已更新模块关联的模块同步更新,此时可以使用聚合工程来解决批量模块同步构建的问题
-
-
创建Maven模块,设置打包类型
<packaging>pom<packaging>
-
设置当前聚合工程所包含的子模块名称
<modules> <module>../maven_02_ssm</module> </modules>
继承
-
创建Maven模块,设置打包类型为pom
-
在父工程的pom文件中配置依赖关系(子工程将沿用父工程中的依赖关系)
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.10.RELEASE</version> </dependency> </dependencies>
-
配置子工程中可选的依赖关系
<!--定义依赖管理--> <dependencyManagement> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> </dependencies> </dependencyManagement>
-
在子过程中配置当前工程所继承的父工程
定义该工程的父工程 <parent> <groupId>com.itheima</groupId> <artifactId>maven_parent</artifactId> <version>1.0-SNAPSHOT</version> 填写父工程的文件 <relativePath>../maven_parent/pom.xml</relativePath> </parent>
-
在子工程中配置使用父工程中可选依赖的坐标
<dependencies> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> </dependency> </dependencies>
属性
-
定义属性
<!--定义属性--> <properties> <spring.version>5.2.10.RELEASE</spring.version> <junit.version>4.12</junit.version> <mybatis-spring.version>1.3.0</mybatis-spring.version> <!--<jdbc.url>jdbc:mysql://127.0.0.1:3306/ssm_db</jdbc.url>--> </properties>
-
引用属性
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> 撒旦 阿斯顿萨达会尽量快点撒发给发爱上覅偶尔ncy>
版本管理
9.3多环境配置与应用
9.4私服
-
启动服务器 nexus.exe /run nexus
-
访问服务器(默认端口:8081)
10.SpringBoot
1.创建一个Spring
2.执行启动指令
java -jar springboot.jar
3.SpringBoot配置文件
4.整合JUnit
@SpringBootTest
@SpringBootTest(classes = Springboot07JunitApplication.class) class Spirngboot07JunitApplicationTest{}
5.SpringBoot整合MyBatis(主要)
-
设置数据源
spring: datasource: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/ssm_db username: root pasword: root
-
定义数据层接口与映射配置
@Mapper public interface UserDao{ @Select("select * from user") public List<User> getAll(); }
-
测试类注入dao接口,测试功能
6.基于SpringBoot的SSM整合案例
-
pom.xml
配置起步依赖,必要的资源坐标(druid)
-
application.yml
设置数据源.端口等
-
配置类
全部删除
-
dao
设置@Mapper
-
测试类
-
页面
放置在resource目录下的static目录中
11.MybatisPlus完成标准Dao开发
1.1MybatisPlus简介
入门案例
-
手动添加依赖
-
设置Jdbc参数(application.yml)
-
制作实体类与表结构(类名与表名对应,属性与字段名对应)
-
定义数据接口,继承BaseMapper<User>
@Mapper public interface UserDao extends BaseMapper<User>{ }
-
测试类中注入Dao接口,测试功能
@SpringBootTest class Mybatispuls01QuickstartApplicationTest{ @Autowired private UserDao userdao; @Test public void testGetAll(){ List<User> userList = userDao.selectList(null); userList.forEach(System.out::println); } }
MybatisPlus特性
-
无侵入:只做增强不做改变,不会对现有的工程产生影响
-
强大的 CRUD 操作:内置通用 Mapper,少量配置即可实现单表CRUD操作
-
支持 Lambda :编写查询条件无需担心字段写错
-
支持主键自动生成
-
内置分页插件
-
...........
lombok依赖包 @Data
1.2MP分页查询功能
-
设置分页拦截器作为Spring管理的bean
@Configuration public class MpConfig { @Bean public MybatisPlusInterceptor mpInterceptor(){ //1.定义Mp拦截器 MybatisPlusInterceptor mpInterceptor = new MybatisPlusInterceptor(); //2.添加具体的拦截器 mpInterceptor.addInnerInterceptor(new PaginationInnerInterceptor()); return mpInterceptor; } }
-
执行分页查询
void textGetByPage(){ IPage page = new Page(1,2); userDao.selectPage(page,null); System.out.println("当前页码值:"+page.getCurrent()); System.out.println("每页显示数:"+page.getSize()); System.out.println("一共多少页:"+page.getPages()); System.out.println("一共多少条数据:"+page.getTotal()); System.out.println("数据:"+page.getRecords()); }
-
开启日志
-
mybatis-plus: configuration: log-impl:org.apache.ibatis.logging.stdout.StdOutImpl
1.3条件查询
//方式一:按条件查询 QueryWrapper qw = new QueryWrapper(); qw.lt("age",18); List<User> userList = userDao.selectList(qw); System.out.println(userList); //方式二:lambda格式按条件查询 QueryWrapper<User> qw = new QueryWrapper<User>(); qw.lambda().lt(User::getAge, 10); List<User> userList = userDao.selectList(qw); System.out.println(userList); //方式三:lambda格式按条件查询 LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>(); lqw.lt(User::getAge, 10); List<User> userList = userDao.selectList(lqw); System.out.println(userList);
1.4 条件查询-null值处理
//null判定 LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>(); lqw.lt(User::getAge, uq.getAge2()); if( null != uq.getAge()) { lqw.gt(User::getAge, uq.getAge()); } List<User> userList = userDao.selectList(lqw); System.out.println(userList); LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>(); //先判定第一个参数是否为true,如果为true连接当前条件 // lqw.lt(null != uq.getAge2(),User::getAge, uq.getAge2()); // lqw.gt(null != uq.getAge(),User::getAge, uq.getAge()); lqw.lt(null != uq.getAge2(),User::getAge, uq.getAge2()) .gt(null != uq.getAge(),User::getAge, uq.getAge()); List<User> userList = userDao.selectList(lqw); System.out.println(userList);
1.4查询投影
//查询投影 // LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>(); // lqw.select(User::getId,User::getName,User::getAge); // QueryWrapper<User> lqw = new QueryWrapper<User>(); // lqw.select("id","name","age","tel"); // List<User> userList = userDao.selectList(lqw); // System.out.println(userList); // QueryWrapper<User> lqw = new QueryWrapper<User>(); // lqw.select("count(*) as count, tel"); // lqw.groupBy("tel"); // List<Map<String, Object>> userList = userDao.selectMaps(lqw); // System.out.println(userList);
查询条件
//条件查询 LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>(); //等同于= lqw.eq(User::getName,"Jerry").eq(User::getPassword,"jerry"); User loginUser = userDao.selectOne(lqw); System.out.println(loginUser); LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>(); //范围查询 lt le gt ge eq between lqw.between(User::getAge,10,30); List<User> userList = userDao.selectList(lqw); System.out.println(userList); LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>(); //模糊匹配 like lqw.likeLeft(User::getName,"J"); List<User> userList = userDao.selectList(lqw); System.out.println(userList);
1.5字段映射与表名映射
@TableField
-
作用: 设置当前属性对应的数据库表中的字段关系
-
value #select:设置属性是否参与查询,此属性与value()映射不冲突
public class User{ @TableField(value = "pwd",select = false) private String password; }
-
exist: 设置属性在数据库表字段中是否存在,默认为true.此属性无法发与value合并使用
public class User{ @TableField(exist=false) private Interage online; }
-
@TableName
-
作用:设置当前类对应与数据库表关系
@TableName("tbl_user") public class User{ private Long id; }
1.6 id生产策略控制
@Table
-
作用:设置当前类中主键属性的生成策略
public class User{ @Table(type = IdType.AUTO) private Long Id; }
1.7 多数据操作
-
按照主键删除多条记录
List<Long> ids = Arrays.asList(new Long[]{2,3}); userDao.deleteBatchIds(ids);
-
根据主键查询多条记录
List<Long> ids = Arrays.asList(new Long[]{2,3}); List<User> userList = userDao.selectBatchIds(ids);
-
逻辑删除
-
实体类中添加对应字段,并设定当前字段为逻辑删除标记字段
public class User{ private Long id; @TableLogic private Interger deleted; }
-
(通用的)配置逻辑删除字面值
mybatis-plus: global-config: db-config: logic-delete-field:delete logic-not-delete-value:0 logic-delete-value:1
1.8乐观锁
-
数据库里加入字段
-
在实体类中加入对应字段,并设定当前字段为逻辑删除字段
public class User{ private Long id; @Version private Integer version; }
-
配置乐观锁拦截器实现锁机制对应的动态SQL语句拼装
@Congfiguration public class MpConfig{ @Bean public MybatisPlusTnterceptor mpInterceptor(){ MybatisPlusTnterceptor mpInterceptor = new MybatisPlusTnterceptor(); mpIntercepor.addInnerInterceptor(new OptimisticLockerInterceptor()); return mpInterceptor; } }
-
使用乐观锁机制在修改前必须先获取到对应数据的Version方可正常进行
@Test void testUpdate(){ //先查询数据,获取到version数据 User user = userDao.selectById(1L); //执行数据修改操作 user.setName("Tom and Jerry"); userDao.updateById(user); }
2.1快速开发
代码生成器
public class CodeGenerator { public static void main(String[] args) { AutoGenerator autoGenerator = new AutoGenerator(); DataSourceConfig dataSource = new DataSourceConfig(); dataSource.setDriverName("com.mysql.cj.jdbc.Driver"); dataSource.setUrl("jdbc:mysql://localhost:3306/jdbc?serverTimezone=UTC"); dataSource.setUsername("root"); dataSource.setPassword("root"); autoGenerator.setDataSource(dataSource); //设置全局配置 GlobalConfig globalConfig = new GlobalConfig(); globalConfig.setOutputDir(System.getProperty("test.SSM")+"/mybatisplus_04/src/main/java"); //设置代码生成位置 globalConfig.setOpen(false); //设置生成完毕后是否打开生成代码所在的目录 globalConfig.setAuthor("黑马程序员"); //设置作者 globalConfig.setFileOverride(true); //设置是否覆盖原始生成的文件 globalConfig.setMapperName("%sDao"); //设置数据层接口名,%s为占位符,指代模块名称 globalConfig.setIdType(IdType.ASSIGN_ID); //设置Id生成策略 autoGenerator.setGlobalConfig(globalConfig); //设置包名相关配置 PackageConfig packageInfo = new PackageConfig(); packageInfo.setParent("com.aaa"); //设置生成的包名,与代码所在位置不冲突,二者叠加组成完整路径 packageInfo.setEntity("domain"); //设置实体类包名 packageInfo.setMapper("dao"); //设置数据层包名 autoGenerator.setPackageInfo(packageInfo); //策略设置 StrategyConfig strategyConfig = new StrategyConfig(); strategyConfig.setInclude("tbl_user"); //设置当前参与生成的表名,参数为可变参数 strategyConfig.setTablePrefix("tbl_"); //设置数据库表的前缀名称,模块名 = 数据库表名 - 前缀名 例如: User = tbl_user - tbl_ strategyConfig.setRestControllerStyle(true); //设置是否启用Rest风格 strategyConfig.setVersionFieldName("version"); //设置乐观锁字段名 strategyConfig.setLogicDeleteFieldName("deleted"); //设置逻辑删除字段名 strategyConfig.setEntityLombokModel(true); //设置是否启用lombok autoGenerator.setStrategy(strategyConfig); //2.执行生成操作 autoGenerator.execute(); } }