文章目录
- Spring Basic
- SpringMVC Basic
- SSM × Annotation & XML
- (Basic)SSM × Annotation & XML × Module
Spring Basic
helloSpring × XML
前言
- 一个简单的,使用XML配置的Spring起手示例
- 展示IOC的控制反转
- 关键点
- 初识 Spring IOC。
- IOC是什么?DI又是什么?
关系
基础类
POM.xml
配置MAVEN
<!--
关键点:
1. spring-context
2. 插件版本
-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
UserDao.java
数据库访问层
//关键点:
//1. 路径:cn.ningbaiyu.Dao.IMPL.UserDao.java
//2. 普通的接口实现类。
public interface IUserDao{
void save(){}
}
public class userDao implement IUserDao{
@Override/*这是重写接口的方法*/
public void save(){
sout.save;
}
}
ApplicationContext.xml
配置Spring属性
<!--
关键点:
1. XML约束
2. bean
3. id
4. class
-->
<?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">
<bean id="userDao" class="cn.ningbaiyu.Dao.Impl.UserDao"/>
</beans>
Test.java
一个执行类
//关键点:
//1. ClassPathXMLApplicationContext,类路径xml应用程序上下文。
//2. Object getBean(String ApplicationContext.xml.bean.id)。
//3. 必须完成1、2。Spring IOC才能创建对象。
public class Test{
@Test
public void test(){
ClassPathXmlApplicationContext ac =new ClassPathXmlApplicationContext("ApplicationContext.xml");
IUserDao userDao = (IUserDao)ac.getBean("userDao")
userDao.save();
}
}
执行结果
save
helloAOP × XML
前言
- 一个简单的,使用XML配置的AOP起手示例
- AOP基于日志业务的扩展示例
- 关键点:
- 这个示例是基于SpringAOP实现的。
- SpringAOP底层是JDK动态代理+Cglib动态代理组成的。这里理应有JDK动态代理和Cglib动态代理的示例。但是由于时间关系,就不赘述了。
- JDK动态代理,代理对象通过getClass()方法能看出,前缀包含$Proxy
- Cglib动态代理,代理对象通过getClass()方法能看出,后缀包含Cglib
关系
extend helloSpring × xml
POM.xml
super.get(POM.xml)
<!--
关键点:
1. super.get(POM.xml).dependencies.spring-context包含了AOP模块
2. AOP模块依赖aspectjweaver模块,所以必须导入。
-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.7</version>
</dependency>
AopLog.java
一个简单的类
//路径:cn.ningbaiyu.AOP.AopLog
public class AopLog {
/*对应,执行前打印日志*/
public void before() {
System.out.println("before=====>");
}
/*
*//*对应,执行后打印日志*//*
public void after() {
System.out.println("after=====>");
}
*//*对应,执行后最终状态打印日志*//*
public void afterReturning() {
System.out.println("afterReturning=====>");
}
*//*对应,执行后异常状态打印日志*//*
public void afterThrowing() {
System.out.println("afterThrowing=====>");
}
*//*环绕通知,将所有通知写进同一个方法*//*
*//*这里边有个重要的东西,ProceedingJoinPoint*//*
*//*它的实例,proceed方法是通过反射的方式调用执行对象的。*//*
public Object around(ProceedingJoinPoint joinPoint) {
try {
System.out.println("aroundBefore=====>");
*//*在有返回值的情况下,需要实例化返回值*//*
Object proceed = joinPoint.proceed();
System.out.println("aroundAfter=====>");
*//*判断是否为空,然后返回*//*
if (proceed!=null) {
return proceed;
}
} catch (Throwable throwable) {
System.out.println("afterThrowing=====>");
throwable.printStackTrace();
} finally {
System.out.println("afterReturning=====>");
}
return null;
}*/
}
UserDao.java
super.get(UserDao.java)
applicationContext.xml
super.get(applicationContext.xml)
<bean id="aopLog" class="cn.ningbaiyu.AOP.AopLog"/>
<aop-config>
<aop-aspect ref="aopLog">
<aop-pointcut id="pc" expression="execution(* cn.ningbaiyu.Dao.Impl.UserDao.*(..))/>"/>
<aop-before method="before" pointcut-ref="pc"/>
</aop-aspect>
</aop-config>
Test.java
一个执行类
super.get(UserDao.java)
执行结果
before=====>
save
Spring × AOP × XML
前言
- 普通的,使用XML配置的,包含AOP模块的Spring示例
- IOC的自动封装
- 新增IUserService接口和UserService实现类
关系
extend helloAOP.xml
POM.xml
super.get(POM.xml)
AopLog.java
super.get(AopLog.java)
UserDao.java
super.get(User.java)
UserService.java
//接口
public interface IUserService {
void save();
}
//实现类
public class UserService implements IUserService {
/**
* 关键词:
* IOC控制反转
* 通过Setter方法赋值
*/
//创建一个没有实例化的userDao私有成员对象
//注意这个对象没有数据的,设计交给Spring实例化,赋值的
private IUserDao userDao ;
//通过Xml配置的Spring,实例化对象后,是通过Setter方法赋值的
public void setUserDao(IUserDao userDao) {
this.userDao = userDao;
}
@Override/*这是重写接口的方法*/
public void save() {
//增加不同的地方,让测试更好识别。
System.out.println("i am UserService");
//调用私有成员的方法
userDao.save();
}
}
ApplicationContext.xml
<!--
关键词:
1、指向绑定
2、类路径
3、name="成员属性"
-->
<!--创建bean标签,id是userService-->
<!--绑定类路径为cn.ningbaiyu.Service.Impl.UserService的UserService类-->
<bean id="userService" class="cn.ningbaiyu.Service.Impl.UserService">
<!--创建property 属性标签。绑定UserService类的userDao成员属性-->
<!--指向id为userDao的bean标签-->
<!--获取它的属性为UserService类的userDao成员属性赋值-->
<property name="userDao" ref="userDao"/>
</bean>
Test.java
super.get(Test.java)
@Test
public void test2(){
ClassPathXmlApplicationContext ac =new ClassPathXmlApplicationContext("ApplicationContext.xml");
IUserService userService = (IUserService) ac.getBean("userService");
userService.save();
}
执行结果
i am UserService
before=====>
save
Spring × AOP × JDBC × XML
前言
- 使用XMl配置,使用AOP,使用JDBC的Spring示例
- 更复杂的IOC自动封装例子。
- 新增Pojo.User
关系
extend Spring × AOP × XML
POM.xml
super.get(POM.xml)
<!--
关键点
在没有使用MyBatis框架之前,
链接数据库必须导入这三个包。
1.Mysql数据库驱动包
2.Spring JDBC
3.druid数据库连接池
-->
<!--数据库驱动包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.40</version>
</dependency>
<!--Spring的Jdbc支持包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!--连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
AopLog.java
super.get(AopLog.java)
User.java
public class User {
/*
关键点
1. 这个类是设计来封装数据库的表数据。所以要完全吻合表数据的所有数据名称。
*/
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
parameter.getter
parameter.setter
class.Constructor()
class.Constructor(all parameter)
}
UserDao.java
super.get(UserDao.java)
//接口新增方法
List<User> findAll();
/*
关键点
1. 使用Spring框架,类的所有私有成员都需要提供getter和setter方法才能被Spring IOC创建。
*/
//创建JdbcTemplate私有成员
//交给Spring,通过Setter方法赋值
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Override/*这是重写接口的方法*/
public List<User> findAll() {
//通过JdbcTemplate.query获取所有用户的数据
List<User> userList =
jdbcTemplate.query("SELECT * FROM `user`", new BeanPropertyRowMapper<>(User.class));
//返回用户数据集合
return userList;
}
UserService.java
super.get(UserService.java)
//接口新增方法
void findAll();
@Override/*这是重写接口的方法*/
public void select() {
List<User> userList = userDao.findAll();
for (User user : userList) {
System.out.println("user = " + user);
}
}
ApplicationContext.xml
super.get(ApplicationContext.xml)
<bean id="dataresource" class="com.alibaba.Druid.pool.dataResource">
<properties name="url" value="jdbc:mysql://localhost:3306/spring_02?characterEncoding=UTF8"/>
<properties name="driverClassName" value="com.mysql.jdbc.Driver"/>
<properties name="username" value="root"/>
<properties name="password" value="root"/>
</bean>
<bean id="JdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataResource"/>
</bean>
@Override
<bean id="userDao" class="cn.ningbaiyu.Dao.Impl.UserDao">
<property name="jdbcTemplate" ref="JdbcTemplate"/>
</bean>
Test.java
super.get(Test.java)
@Test
public void test3(){
ApplicationContext ac =new ClassPathXmlApplicationContext("ApplicationContext.xml");
IUserService userService = (IUserService) ac.getBean("userService");
userService.select();
}
执行结果
before=====>
user = User{id=41, username='老王', birthday=2018-02-27 17:47:08.0, sex='男', address='北京'}
user = User{id=42, username='小二王', birthday=2018-03-02 15:09:37.0, sex='女', address='北京金燕龙'}
Spring × AOP × JDBC × Transaction × XML
前言
- SpringIOC,SpringAOP,SpringJDBC,SpringTransaction,通过配置XML的方式实现。
- 关键点
- SpringTX实质上属于AOP的环绕通知。当AOP存在SpringTX和另一个环绕通知的时候,另一个环绕通知会失效。
- 事实性步骤
- 创建bean标签,id为transactionManager指向jdbc.datasource.DataSourceTransactionManager。注入用Druid创建的数据源。
- 这意味着,事务管理器是用jdbc的数据源事务管理器,那么我也可以用其他来源的数据事务管理器。
- 创建bean标签,意味着将jdbc的数据源事务管理器交给SpringIOC容器管理。
- 创建tx:advice(通知)标签,transaction-manager(事务管理器)注入transactionManager,在子标签tx:attributes(属性),配置transactionManager的属性。
- 这样就很明了,拿到JDBC的数据源事务管理器,通过tx:Advice配置这个数据源事务管理器的属性。
- 属性是什么?指向绑定的方法,配置只读,传递等等的属性。这个暂时还未深入去理解。
- 创建aop:config(配置)标签,创建aop:point子标签,创建aop:advisor(顾问)子标签。在aop:point切入点配置被切入代码。在aop:advisor配置插入的事务管理以及应用在哪个切点
- 从这里出发,纵览全局。证明了SpringTX实质上属于AOP的环绕通知这个观点。插入的事务是环绕着被切入代码运行的。
- 创建bean标签,id为transactionManager指向jdbc.datasource.DataSourceTransactionManager。注入用Druid创建的数据源。
关系
extend Spring × AOP × JDBC × XML
2019年7月16日-新改革
从这天开始,不再写具体继承,只写改变的状态以及更新的点。
以前写具体继承的示例有:
1.Spring入门除了本示例以外的所有示例
2.SpringMVC所有示例
改变的状态,比如完全重写:@Override。
更新的点,直接标继承的文件,然后写更新的点。
POM.xml
<!--引入事务管理包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
ApplicationContext.xml
<!--创建事务管理器对象-->
<!--需要注意的是,这个所谓的事务管理器是属于JDBC的。-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--而且它需要链接数据源--><!--数据源也就是德鲁伊的数据源-->
<property name="dataSource" ref="dataResource"/>
</bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--attributes 属性-->
<tx:attributes>
<!--通配find开头的所有方法--><!--只读--><!--传播(propagation):支持(SUPPORTS)-->
<!--需要注意的是,扫描和执行是由上至下执行的。-->
<tx:method name="find*" read-only="true" propagation="SUPPORTS"/>
<tx:method name="query*" read-only="true" propagation="SUPPORTS"/>
<tx:method name="select*" read-only="true" propagation="SUPPORTS"/>
<tx:method name="search*" read-only="true" propagation="SUPPORTS"/>
<!--所以最底层的方法,是最后被扫描到和被执行到的。-->
<!--除了上面的方法 ,其他的所有方法都是读写事务,传播行为(必须有事务环境)-->
<tx:method name="*" read-only="false" propagation="REQUIRED"/>
<!--适配所有方法--><!--REQUIRED需要的-->
</tx:attributes>
</tx:advice>
<!--这个aop:config标签是直接新建的,并不是在之前的aop:config中建立其中的子标签-->
<aop:config>
<!--配置切入点信息--><!--切入Service文件夹中,后缀为Service的所有类的所有方法-->
<aop:pointcut id="txPC" expression="execution(* cn.ningbaiyu.Service.Impl.*Service.*(..))"/>
<!--配置切入后,需要运行的东西-->
<!--这里是注入了txAdvice,切入点为txPC-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPC"/>
<!--总的来说,在Service文件夹中,后缀为Service的所有类的所有方法运行的时候-->
<!--它的全生命周期txAdvice都有参与-->
</aop:config>
<!--这套写法有别于之前创建的aop:config-->
<!--这套写法是应用于别人写的插入代码,之前创建的aop:config是应用于自己写的插入代码-->
<!--之前创建的aop:config中,是建立一个aop:aspect(切面)子标签-->
<!--再在子标签中配置切入点,切入代码在所切入的运行代码的哪个生命周期运行-->
UserDao.java
/*新增`增加方法*/
/*接口*/
IUserDao.java{
boolean AddUser(User user)
}
/*实现类*/
@Override
public boolean AddUser(User user) {
int update = jdbcTemplate.update("INSERT into `user` " +
"values (null,?,?,?,?)", user.getUsername(), user.getBirthday(), user.getSex(), user.getAddress());
return update != 0;
}
UserService.java
/*新增`增加方法*/
/*接口*/
IUserService.java{
boolean AddUser(User user);
}
/*实现类*/
@Override
public boolean AddUser(User user) {
userDao.AddUser(user);
int i = 10 / 0;//制造运行时异常,测试事务是否回滚
userDao.AddUser(user);
//这里一共插入两条数据。如果正常回滚的话,异常之前的插入数据将会被回滚。
//也就是这里的第一条插入数据,遇到异常时候,在事务管理下将会失效。
return false;//不要在乎这个返回值。
}
Test.java
@Test
/*测试事务回滚*/
public void test4(){
//常规创建IOC容器
ApplicationContext ac =new ClassPathXmlApplicationContext("ApplicationContext.xml");
//从ApplicationContext.xml取得“userService“标签
//得到标签中所指向的类路径,创建类。
IUserService userService = (IUserService) ac.getBean("userService");
//通过打印getClass()方法,查看该对象是否被事务管理器代理
System.out.println("userService = " + userService.getClass());
//创建参数对象
User user =new User();
user.setSex("男");
user.setAddress("北极");
user.setUsername("南锣");
user.setBirthday(new Date());
//注入参数,执行方法
userService.AddUser(user);
}
执行结果
//这是打印getClass方法
//通过其后缀可以看出,“userService”对象已经被Cglib动态代理
//如果前缀是$porxy,则是被JDK动态代理
userService = class cn.ningbaiyu.Service.Impl.UserService$$EnhancerBySpringCGLIB$$3816a0bd
//AOP插入的日志信息
before=====>
//打印的异常
java.lang.ArithmeticException: / by zero
//由于Mysql没有打印信息,但是实际上由于事务回滚,MySQL并没有被插入信息。
//所以这次事务管理是成功的。
Spring × AOP × JDBC × Transaction × Annotation
前言
-
基于Spring × AOP × JDBC × Transaction × XML示例实现全注解。
-
关键注解:
- 声明需要Spring IOC容器注入数据的属性
-
@Autowired
-
声明其他类
- @Component;让Spring IOC容器识别这是需要其管理的类,并纳入IOC容器中。
- pojo.javabeen类
- Aspect类
- 需要引入的类
- @Component;让Spring IOC容器识别这是需要其管理的类,并纳入IOC容器中。
-
声明数据库访问层的类
- @Repository;
- 类似@Component,主要是给Spring IOC容器识别的。
- 让Spring IOC容器识别这是数据访问层的类,并纳入IOC容器中。
- @Repository;
-
声明业务层的类
- @Service;
- 类似@Component,主要是给Spring IOC容器识别的。
- 让Spring IOC容器识别这是业务层的类,并纳入IOC容器中。
- @Service;
-
声明配置类
- @Configuration;
- 类似@Component,主要是给Spring IOC容器识别的。
- 声明这是配置类
- @ComponentScan(包的类路径);
- 启用包扫描,扫描哪些类有注解。
- @Import(引入类.class);
- 引入其他类。
- 这里目的是引入写满Bean标签的类。
- @EnableAspectJAutoProxy();
- 启用AOP扫描,扫描哪些类被声明为Aspect(切面)。
- proxy Target Class 意思是代理目标类,true=使用JDK动态代理,false=Cglib动态代理);
- @EnableTransactionManagement;
- 启用事务管理器扫描,扫描哪些类被声明为事务切入点
- @Configuration;
-
声明需要被事务管理的类或方法
- @Transactional;
- 我想到了为什么!这个注解是标识类或方法为切入点,从而进行事务插入。我自己生造了一个术语,事务切入点。
- 等同于
<aop:pointcut>!!
- @Transactional;
-
声明切面(Aspect)类
-
@Aspect;声明这是切面类。
-
@Pointcut(“切入点(切入点全路径)”);声明这是一个id为方法名的切入点。
-
@Before(“切入点的名称()”);声明这是切入点代码执行前插入的方法。
-
-
导入外部配置文件,注入配置文件的数据。
- @PropertySource(配置文件的全路径);导入配置文件。
- @Value("${配置文件中的key}");获取配置文件中的key,注入所注解的属性,配合@PropertySource使用
-
关键代码
- JdbcConfig.java
- SpringConfig.java
- logAspsect.java
关系
@Override Spring × AOP × JDBC × Transaction × XML
POM.xml
<dependencies>
<!--Spring核心依赖-->
<!--包含IOC,AOP-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!--Spring整合junit-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!--AOP第三方依赖-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
</dependency>
<!--Spring数据库连接池,整合transactionManager-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!--德鲁伊数据库连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<!--数据库驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.5</version>
</dependency>
<!--测试类-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
User.java
@Component
//JAVABean类
//@Component;让Spring IOC容器识别这是需要其管理的类,并纳入IOC容器中。
public class User {
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
//getter&setter&@Override ToString
}
UserDao.java
//接口
public interface IUserDao {
public boolean add(User user);
public List<User> findAllUser();
}
@Repository
//@Repository;类似@Component,主要是给Spring IOC容器识别的。
//让Spring IOC容器识别这是数据访问层的类,并纳入IOC容器中。
public class UserDaoIMPL implements IUserDao {
@Autowired
//自动注入jdbcTemplate
private JdbcTemplate jdbcTemplate;
@Override
//这是重写接口的方法
public boolean add(User user) {
int update = jdbcTemplate.update(
"INSERT INTO `USER` VALUES (NULL,?,?,?,?)",
user.getUsername(),
user.getBirthday(),
user.getSex(),
user.getAddress());
return update > 0;
}
@Override
//这是重写接口的方法
public List<User> findAllUser() {
List<User> userList = jdbcTemplate.query("SELECT * FROM `USER`", new BeanPropertyRowMapper<>(User.class));
return userList;
}
}
UserService.java
//接口
public interface IUserService {
public void add(User user);
public List<User> findAllUser();
}
//实现类
@Service
//@Service;类似@Component,主要是给Spring IOC容器识别的。
//让Spring IOC容器识别这是业务层的类,并纳入IOC容器中。
@Transactional
public class UserServiceIMPL implements IUserService {
@Autowired
private IUserDao userDao;
@Override
public void add(User user) {
userDao.add(user);
int i = 10 / 0;//制造运行时异常,测试事务是否回滚
x //这里一共插入两条数据。如果正常回滚的话,异常之前的插入数据将会被回滚。
//也就是这里的第一条插入数据,遇到异常时候,在事务管理下将会失效。
userDao.add(user);
}
@Override
public List<User> findAllUser() {
List<User> userList = userDao.findAllUser();
return userList;
}
}
SpringConfig.java
@Configuration
//@Configuration;声明这是配置类
@Import(JdbcConfig.class)
//@Import(引入类.class);引入其他类。这里的目的是引入写满Bean标签的类。
@ComponentScan("cn.ningbaiyu")
//@ComponentScan(包的类路径);启用包扫描,扫描哪些类有注解。
@EnableAspectJAutoProxy(proxyTargetClass = true)
//@EnableAspectJAutoProxy((proxy Target Class代理目标类),true意味着使用JDK动态代理,false意味着使用Cglib动态代理);
//启用AOP扫描,扫描哪些类被声明为Aspect
@EnableTransactionManagement
//@EnableTransactionManagement;启用事务管理器扫描,扫描哪些类被声明为事务切入点
public class SpringConfig {
}
JdbcConfig.java
@PropertySource("jdbc.properties")
//@PropertySource(配置文件的全路径);导入配置文件。
@Component
//@Component;让Spring IOC容器识别这是需要其管理的类,并纳入IOC容器中。
public class JdbcConfig {
@Value("${jdbc.url}")
//@Value("${配置文件中的key}");获取配置文件中的key,注入所注解的属性
private String url;
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean
//@Bean;XML文件中的bean标签,这意味着,Spring IOC容器将以此新建对象。
private DataSource createDataSource(){
//实例化德鲁伊数据源对象
DruidDataSource dataSource =new DruidDataSource();
//注入各种属性
dataSource.setUrl(url);
dataSource.setDriverClassName(driver);
dataSource.setUsername(username);
dataSource.setPassword(password);
//返回数据对象
return dataSource;
}
@Bean
private JdbcTemplate createJdbcTemplate(DataSource dataSource){
//实例化JDBC连接池对象,注入德鲁伊数据源对象,并且返回
return new JdbcTemplate(dataSource);
}
@Bean
private DataSourceTransactionManager createDBTransactionManager(DataSource dataSource){
//JDBC数据源事务管理对象
DataSourceTransactionManager dbTransactionManager = new DataSourceTransactionManager();
//注入德鲁伊数据源
dbTransactionManager.setDataSource(dataSource);
//返回JDBC数据源事务管理对象
return dbTransactionManager;
//这段代码加上@trasational所注解的类或方法,相当于
//<aop:config>
//<aop:advisor advice-ref="dbTransactionManager"
// pointcut-ref="@trasational所注解的类或方法"/>
//</aop:config>
}
}
LogAspect.java
@Aspect
// @Aspect;声明这是切面类。
@Component
//@Component;让Spring IOC容器识别这是需要其管理的类,并纳入IOC容器中。
public class logAspect {
@Pointcut("execution(* cn.ningbaiyu.Service.IMPL.*ServiceIMPL.*(..))")
//execution,执行
//@Pointcut("切入点(切入点全路径)");声明这是一个id为方法名的切入点。
public void pc(){}
@Before("pc()")
//@Before("切入点的名称()");声明这是插入的方法。
public void testBefore(){
System.out.println("before====>");
}
@After("pc()")
public void testAfter(){
System.out.println("after====>");
}
// @AfterReturning("pc()")
// public void AfterReturning(){
// System.out.println("AfterReturning====>");
// }
@AfterThrowing("pc()")
public void testAfterThrowing(){
System.out.println("AfterThrowing====>");
}
//相当于
//<bean id="logAspect" class="cn.ningbaiyu.config">
//<aop:aspect ref="logAspect">
// <aop:pointcut id="pc()" expression="execution(* cn.ningbaiyu.Service.IMPL.*ServiceIMPL.*(..)))">
// <aop:before method="testBefore" pointcut-ref="pc()">
// <aop:After method="testBefore" pointcut-ref="pc()">
// <aop:AfterThrowing method="testAfterThrowing" pointcut-ref="pc()">
//</aop:aspect>
}
Test.java
@RunWith(SpringJUnit4ClassRunner.class)
//@RunWith(Spring和Junit整合的类);Spring与Junit整合,指向整合类
@ContextConfiguration(classes = SpringConfig.class)
//@ContextConfiguration(配置文件或配置类);Spring与Junit整合,指向配置文件或配置类。
public class Test {
@Autowired
private IUserService userService;
@org.junit.Test
public void findAllUser(){
System.out.println("userService.getClass() = " + userService.getClass());
List<User> userList = userService.findAllUser();
for (User user1 : userList) {
System.out.println("user = " + user1);
}
}
@org.junit.Test
public void add(){
System.out.println("userService.getClass() = " + userService.getClass());
User user = new User();
user.setSex("女");
user.setAddress("北京");
user.setUsername("aa");
user.setBirthday(new Date());
userService.add(user);
}
}
#MyBatis Basic
SpringMVC Basic
helloSpringMVC
前言
- 一个简单的SpringMVC起手示例
- 转发JSP(动态资源)
- 关键点:
- DispatcherServlet
- 开启MVC注解驱动:创建处理器映射器 和 处理器适配器
POM.xml
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
WEB.xml
<!--关键点:创建对象,配置属性以及映射-->
<!-- 配置SpringMVC核心前端控制器 -->
<servlet>
<servlet-name>dispatcherServlet</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>
<!-- 启动优先级,1最高,5最低 -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<!-- 映射 -->
<servlet-name>dispatcherServlet</servlet-name>
<!-- 配置dispatcherServlet拦截地址 -->
<url-pattern>*.do</url-pattern>
</servlet-mapping>
HelloController.java
package cn.ningbaiyu.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
//@Controller等同于@Component。
//声明类而已,方便IOC容器识别。
//这个类中的所有方法,加上@RequestMapping后,都成为了Servlet!
public class HelloController {
@RequestMapping("/hello.do")
public String hello(){
System.out.println("正在处理请求和响应...");
return "success";
}
}
springMVC.xml
<!--classFile_03\SpringMVC_01_01\src\main\resources\springMVC.xml-->
<?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"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 1.IOC组件扫描。由于该标签的存在,必须导入spring-context依赖 -->
<!--这里作用是扫描@Controller标识的类-->
<context:component-scan base-package="cn.ningbaiyu.controller"/>
<!-- 2.配置视图解析器: 给响应页面加上前缀和后缀,最终完成跳转 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 2.1 页面的前缀 -->
<property name="prefix" value="/pages/"/>
<!-- 2.2 页面的后缀 -->
<property name="suffix" value=".jsp"/>
</bean>
<!-- ※ 3.开启MVC注解驱动:创建处理器映射器 和 处理器适配器-->
<mvc:annotation-driven/>
</beans>
success.jsp
success!
执行结果
success.jsp.show success!
HelloController.java.sout.正在处理请求和响应...
springMVC × DispatcherServlet
前言
- 测试dispatcherServlet配置通配地址
- 关键点:
- dispatcherServlet
- WEB.xml.servlet-mapping.url-pattern
关系
extend helloSpringMVC
arr={POM.xml,WEB.xml,HelloController.java,springMVC.xml,success.jsp}
super.get(arr)
客户端
http://localhost:8080/hello.do
WEB.xml
super.get(WEB.xml)
<!--老师的说法是这样的-->
<!--
关键点
/ : 通配所有路径,不包含jsp资源,页面访问jsp,可以找到页面。
据此,我的理解:这么配可以直接找到html和jsp
/* : 通配所有路径,包含jsp资源。页面访问jsp会找不到该页面的。
据此。我理解是这样的,jsp本质上是一个Servlet,这样配置的话,会将jsp当做servlet处理,访问jsp的名称,就意味着访问一个Servlet。就SpringMVC,就这个示例而言,这么访问会直接走HelloController,所以无法访问jsp。
<!--这样的知识,没有丝毫逻辑性可言,只能死记-->
-->
@Override(method)
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<!-- 这里是修改的地方 -->
<url-pattern>/</url-pattern>
</servlet-mapping>
springMVC × HTML
前言
-
通过springMVC访问HTML的三种写法(springMVC访问静态资源的三种解决方案)。所以需要注意的是,本示例是同一案例的三种解决方案,解决方案都可以单独使用。
-
关键点
- tomcat.conf.web.xml.DefultServlet
- mvc:default-servlet-handler(***)
- mvc:resources
-
新增successHTML.html
关系
extend springMVC × dispatcherServlet
arr={POM.xml,WEB.xml,HelloController.java,springMVC.xml,success.jsp}
super.get(arr)
客户端
//关键点:
//这里请求successHTML.html的方法有别于父类的请求jsp的方法。
//1. 父类请求jsp的方法,是走Servlet(HelloController)进行判断,再转发至jsp的
//2. 这里请求successHTML.html是直接走项目地址的,直接访问successHTML.html的
http://localhost:8080/pages/successHTML.html
successHTML.html
i am html5!!!
WEB.xml
第二种解决方案
<!--
关键点:
这么写的本质是,覆盖tomcat/conf/web.xml中的DefultServlet的配置。
-->
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.html</url-pattern>
<url-pattern>*.css</url-pattern>
<url-pattern>*.js</url-pattern>
</servlet-mapping>
SpringMVC.xml
第二种解决方案
<!--
关键点
mapping: 拦截的URI路径
location: 页面所在物理路径(写目录即可)
但老师不推荐这种写法。所以,不用记。
-->
<mvc:resources mapping="/pages/**" location="pages/"/>
<mvc:resources mapping="/index.html" location="/index.html"/>
SpringMVC.xml
第三种解决方案(***)
<!--
关键点:
default-servlet-handler充当了Tomcat的DefaultServlet的功能
????我还是没搞懂。
它是属于Spring的吧,模拟Tomcat的DefaultServlet的功能,其余没任何关系。单独操作静态资源。
-->
<mvc:default-servlet-handler/>
springMVC × Model&ModelMap
前言
- SpringMVC收到的请求数据储存在request请求域(SpringMVC走请求域)的方法
- 关键点:
- Model
- ModelMap
- BindingAwareModelMap
- 走请求域,就意味着动态,动态就意味着JSP。它们的关系是,SpringMVC(model/modelMap)->请求域->jsp
关系
extend springMVC × HTML(solution = 3)
arr={
POM.xml,
WEB.xml,
HelloController.java,
springMVC.xml,
successHTML.html,
success.jsp
};
super.get(arr);
JSP index.jsp = new JSP;//新增一个index.jsp
@Override(class)
HelloController.java;
客户端
http://localhost:3306/textModel
http://localhost:3306/textModelMap
index.jsp
//关键词:
//${}是el表达式,整条句子的意思是获取request域中的名为cn的键的值。
cn:${requestScope.cn}<br/>
//实际显示"cn","china"
us:${requestScope.us}<br/>
//实际显示"us","American"
HelloController.java
@RequestMapping("/testModel")
public String goTestModel(Model model){
model.addAttribute("cn","china");
return "index";
}
//响应的URI
@RequestMapping("/testModelMap")
public String goTestModelMap(Model model){
//为什么Model得走方法的形参?
//我感觉SpringMVC扫描该方法的参数,知道这个方法要用Model。然后…注入Model的实现类,做到走请求域的需求。
model.addAttribute("us","American");
//转发至index.jsp
return "index";
}
springMVC × ReturnValue
前言
- 展示springMVC重定向或跳转的五种解决方案
- 测试springMVC的Servlet的返回值。(示例中的HelloController的返回值)
- 关键词
- Servlet
- 返回值
- forward,转发
- redirect,重定向
- mv,ModelAndView,整合了Model和View
- 然后呢?测试返回值有什么用途?是可以做重定向或跳转页面。所以?所以本示例是展示springMVC重定向或跳转的五种解决方案。
关系
extend springMVC × Model&ModelMap
arr={
POM.xml,
WEB.xml,
HelloController.java,
springMVC.xml,
successHTML.html,
index.jsp,
success.jsp
};
super.get(arr);
@Override(class)
HelloController.java;
客户端
value={
returnString,
returnForward,
returnRedirect,
returnVoid,
void,
mv
}
http://localhost:8080/value
HelloController.java
//关键词:
//forward,redirect的格式,就是一个键值对。
//key是forward或redirect,jsp的项目路径是value。
//当然,这些返回字符都是字符串。
//返回普通字符(jsp的名称)进行转发
@RequestMapping("/returnString")
public String goNormalReturn(){
System.out.println("returnString");
return "success";
}
//返回返回字符(forward)进行转发
//"forward:"+"JSP的项目路径"
@RequestMapping("/returnForward")
public String goForwardReturn(){
System.out.println("forward");
return "forward:/pages/success.jsp";
}
//返回重定向字符进行重定向
//"redirect:"+"JSP的项目路径"
@RequestMapping("/returnRedirect")
public String goRedirect(){
System.out.println("redirect");
return "redirect:/pages/success.jsp";
}
//无返回,自行使用request或response进行转发或重定向
//这和Servlet有没区别
//request.getRequestDispatcher("jsp的项目路径").forward(本方法的request,本方法的response);
@RequestMapping("/returnVoid")
public void goVoid(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//转发
//request.getRequestDispatcher("/pages/success.jsp").forward(request,response);
//重定向
System.out.println("void");
response.sendRedirect("/pages/success.jsp");
}
//返回ModelAndView,进行转发
//ModelAndView顾名思义,Model和View的混合体。
//mv.addObject(key,value);
//mv.setViewName("jsp的名称");
@RequestMapping("/mv")
public ModelAndView goMV(){
ModelAndView mv =new ModelAndView();
mv.addObject("cn","china");
mv.setViewName("index");
System.out.println("ModelAndView");
return mv;
}
springMVC × ResponseBody × RequestBody
前言
- 展示基于SpringMVC&HTML的前后端交互
- 关键词
- Json
- ResponseBody
- RequestBody
- Ajax
- 基于ResponseBody和RequestBody的Json对象自动封装。关于Ajax有个很重要的点,详见requestAjax.html。
- 用Pojo.Account类封装html通过Ajax发送的Json数据。据此,Account也可称为Json对象。需要注意的是,Pojo.Account的属性必须吻合Json数据的字段,才能自动封装从前端请求的Json数据进去。
- 还有一个很重要的点,那就是这个示例是基于SpringMVC和HTML的。之前几个点是基于SpringMVC和JSP的。往结构方面说,那就意味着,这个示例是面向静态资源,之前的是面向动态资源的
关系
extend springMVC × ReturnValuez
arr={
POM.xml,
WEB.xml,
HelloController.java,
springMVC.xml,
successHTML.html,
index.jsp,
success.jsp
};
HTML requestAjax.html =new HTML;
super.get(arr);
@Override(class)
HelloController.java;
客户端
http://localhost:8080/pages/requestAjax.html
POM.xml
<!--额, 这是应用于哪里的?
还是@RequestMapping和@ResponseMapping封装和拆箱所需的依赖?-->
<!--为Servlet开启json支持-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<!--核心包-->
<artifactId>jackson-core</artifactId>
<version>2.9.5</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<!--注解-->
<artifactId>jackson-annotations</artifactId>
<version>2.9.5</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<!--数据绑定-->
<artifactId>jackson-databind</artifactId>
<version>2.9.5</version>
</dependency>
requestAjax.html
<script src="/js/jquery-3.3.1.min.js"></script>
<script>
$(function(){
$("#ajaxPost").click(function(){
$.ajax({
// 请求类型,这里必须为post
type : "post",
// 请求地址
// 在SpringMVC示例中,必须带“/”,不然报错
url : "/responseBodyJson",
// 发送给后台的ajax数据
// 花括号外必须要单引号。这是标准Json格式。
data:'{"id":100,"name":"jack","money":9.9}',
// 后台返回的数据格式
dataType:"json",
// 请求格式与编码
// 这就是第4点提到的,很重要的点。这句请求格式与编码必须写,
// 不然@RequestBody获取的数据是UTF8码,未转成汉字的。
contentType:"application/json;charset=utf-8",
success : function(jsn){
alert("jsn="+jsn+"; jsn.id="+jsn.id+"; jsn.name="+jsn.name+"; jsn.money="+jsn.money);
}
});
});
});
</script>
<h2>RequestBody获取请求JSON格式数据 & ResponseBody自动把对象转json并响应</h2>
<button id="ajaxPost">测试ajax请求json与响应json</button>
HelloController.java
@RequestMapping("/responseBodyJson")
@ResponseBody
//自动拆箱Json对象,分解成Json数据,响应前端
//放到返回值或者方法头上
public Account responseBodyJson
(
@RequestBody//将Json数据,自动封装成所注解的类
Account account//使其成为Json对象
){
System.out.println("前端的数据"+account);
account.setId(666);
account.setName("xiaoAI");
account.setMoney(999d);
return account;
}
Account.java
Json对象
public class Account {
private Integer id ;
private String name;
private Double money;
……
//普通的JavaBean对象
}
##springMVC × ExceptionHandler
前言
- 展示SpringMVC统一异常管理器。
- 本示例并不是唯一解决方案,但是老师最推荐的解决方案。由于时间关系,不一一列举了。
- 关键点:
- @ControllerAdvice;注解在类名上
- @ExceptionHandler;注解在方法上,参数是具体异常.class
- SpringMVC统一异常管理器是Spring组件,由IOC容器管理。所以必须要被bean标签配置,或者被包扫描的范围内。
- 以上两点是最重要的。
关系
extend springMVC × ResponseBody × RequestBody
arr={
POM.xml,
WEB.xml,
HelloController.java,
springMVC.xml,
successHTML.html,
requestAjax.html,
index.jsp,
success.jsp
};
JSP error.jsp =new JSP;
JSP error2.jsp =new JSP;
super.get(arr);
@Override(class)
HelloController.java;
客户端
http://localhost:3306/goError
SpringMVC.xml
<!--与MyExceptionHandler.java有莫大关系-->
<context:component-san base-package="cn.ningbaiyu.Controller"/>
HelloController.java
//路径:Controller\helloController.java
@RequestMapping("/goError")
public String goError(){
//会出现ArithmeticException异常
int i = 10 / 0;
//然后不会跳转success.jsp
return "success";
}
MyExceptionHandler.java
//路径:Controller\exception\MyExceptionHandler.java
//需要注意的是,只要是属于Spring IOC容器的注解。
//1. 都要处于被包扫描范围内
//2. 或者在XML配置文件中被bean标签配置。
@ControllerAdvice
public class MyExceptionHandler {
//这个是SpringMVC统一异常处理器
//只要发生异常,都会被这个处理抓获
//需要声明哪种异常
@ExceptionHandler(NullPointerException.class)
//需要注入超级父类作为形参
public String handlerError(Exception e){
//需要交给某个页面显示
return "error";
////当然,除此之外还可以做其他操作。
}
@ExceptionHandler(ArithmeticException.class)
public String handlerError2(Exception e){
return "error2";
}
@ExceptionHandler(Exception.class)
public String handlerError3(Exception e){
return "error";
}
/*
error.jsp{
error!!!
}
error2.jsp{
error2!!!
}
*/
}
springMVC × Restful × HiddenHttpMethodFilter
前言
- 基于Restful的简写方案。
- 关键词
- Restful是简写一种风格。具体实现跟黑马旅游网的BaseServlet很像。就是前端提交隐藏组件,后端识别组件中的属性,如果该属性等同于后端模块的方法名,那就执行该方法。
- HiddenHttpMethodFilter是过滤器,配置在WEB.xml
- post,增加/查询
- put,修改
- delect,DELETE
- get,查询
关系
extend springMVC × ResponseBody × RequestBody
arr={
POM.xml,
WEB.xml,
HelloController.java,
springMVC.xml,
successHTML.html,
requestAjax.html,
index.jsp,
success.jsp
};
HTML restful.html =new HTML
super.get(arr);
@Override(class)
HelloController.java;
客户端
<!--表单提交组件已经内嵌链接-->
@restful.html
WEB.xml
<!--隐藏的HTTP方法过滤器-->
<!--有个很关键的点,这是过滤器-->
<filter>
<filter-name>hiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>hiddenHttpMethodFilter</filter-name>
<!--拦截所有连接,包括JSP-->
<url-pattern>/*</url-pattern>
</filter-mapping>
restful.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>restful风格</title>
</head>
<body>
<!--
在使用RESTful之前(传统方式的URL)
增加: http://localhost:8080/user?method=add
修改: http://localhost:8080/user?method=update
删除: http://localhost:8080/user?method=delete
查询: http://localhost:8080/user?method=find
使用RESTFul之后 (GET、POST、PUT、DELETE)
增加: http://localhost:8080/user POST
修改: http://localhost:8080/user PUT
删除: http://localhost:8080/user DELETE
查询: http://localhost:8080/user GET / POST
-->
<!--毫无疑问,这是一组表单标签-->
<!--提交的地址,提交的方式-->
<form action="/user" method="post">
<!--这是最关键的点-->
<!--内嵌一个隐藏标签,参数值name是_method,参数值value是post-->
<!--HiddenHttpMethodFilter-->
<!--我想“_method”应该是固定写法,“method”就意味着通过hiddenHttpMethod指定运行的Controller-->
<!--至于“_”是没有逻辑而言的。-->
<input type="hidden" name="_method" value="post">
<input type="submit" value="增加">
</form>
<form action="/user" method="post">
<input type="hidden" name="_method" value="put">
<input type="submit" value="修改">
</form>
<!--这是传参的格式-->
<!--当然了还可以这样传,/user?id=10-->
<form action="/user/10" method="post">
<input type="hidden" name="_method" value="delete">
<input type="submit" value="删除">
</form>
<form action="/user/666/eric" method="post">
<input type="hidden" name="_method" value="get">
<input type="submit" value="查询">
</form>
</body>
</html>
HelloController.java
//这是基于HiddenHttpMethodFiller的指定访问域名
//meth=RequestMethod.POST其实意思就是前端提交表单中的,隐藏标签的,
//value属性是”post“
@RequestMapping(method = RequestMethod.POST)
public String add(){
System.out.println("增加");
return "success";
}
@RequestMapping(method = RequestMethod.PUT)
@ResponseBody
//由于前端并不识别PUT,所以只能用ResponseBody返回PUT。我忘了具体原因。
//这么说,就只能死记硬背了?
public String update(){
System.out.println("修改");
return "success";
}
@RequestMapping(value ="/{id}",method = RequestMethod.DELETE)
@ResponseBody
public String delete(@PathVariable("id") Integer id){
System.out.println("删除");
System.out.println("id = " + id);
return "success";
}
//value="/{id}/{name}",那时候我没有听课,我就觉得这是声明给Spring知道,
//我要前端传过来的哪几个属性,以及我这边要用什么参数来接。
@RequestMapping(value="/{id}/{name}",method = RequestMethod.GET)
//@PathVariable("name") String name
//PathVariable翻译过来是路径变量,括号中的参数,是上方@RequestMapping的Value的
//参数。这两者是对应的。注解的String name,就真正意味着用这个参数封装。
public String find(@PathVariable("name") String name,@PathVariable("id") Integer id){
//如果前端的请求路径是“/url?id=10”,这就意味着得用@RequestParam("id")的方式
//来注解方法的参数
System.out.println("查询");
System.out.println("id + \"\" +name = " + id + "," +name);
return "success";
}
SSM × Annotation & XML
前言
- 三大框架整合示例
- 半注解半XML的整合方案
Spring
Mybatis
SpringMVC
(Basic)SSM × Annotation & XML × Module
前言
- SaaSExport,三大框架整合示例
- 使用半注解半XML的整合方案
- 基于Maven实现模块化。
- 各个模块的关键点在各自的前言中。
parentProject
POM.xml
<!--这是父POM项目-->
<!--导入全部子项目所需要的依赖-->
Spring
Mybatis
SpringMVC
前言
- 关键点
- 三大基本组件
- 类型转换
- 异常处理
- 编码过滤器
- 三大基本组件
1256

被折叠的 条评论
为什么被折叠?



