Spring:实现模块间,类之间的解耦合(重点技术:IOC控制反转和AOP面向切面编程)
官网:Spring.io
一、IOC(技术核心-DI:依赖注入)
概念:把对象的创建,赋值,管理工作都交给代码之外的容器实现
控制:创建对象,对象赋值,对象之间的关系控制
反转:把管理对象的权限交付给代码之外的容器(容器是一个服务器软件或者一个框架)
正转:开发人员new对象,主动控制对象
二、简单Spring的创建
首先,创建一个新的空工程,创建一个在本项目中的Maven模块,在模块的建立过程中把代码的包名设置好(com.node),进入界面后,在main的包下Alt+Insert建立一个resources(mark as resources root);当中自动生成的java文件可以随意删除;在pom.xml中修改JDK为1.8,依赖中添加spring依赖(如下图);在包中创建包名service创建一个接口,并后缀Impl实现该接口;在resources中建立spring config(其中代码如下图)---把完成的spring config复制倒target.classes的目录下(具体原因参见下图);最后在test包中创建实例进行检测。
pom.xml文件中
<!--spring依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
spring config文件(本次命名为beans.xml)
<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">
<!--
告诉spring创建对象
声明bean 告诉spring要船舰某个类的对象
id:对象的自定义名称,唯一值,spring通过这个找到对象
class:类的全限定名称(不能是接口,因为反射机制创建对象,必须使用类)
spring 完成 SomeService sonmeService = new SomServiceImpl();
spring是把创建好的对象放入map中,spring框架有一个map存放对象
springMap.put(id,对象);
eg:springMap.put("someservice",new SomServiceImpl());
一个bean创建一个对象
-->
<bean id="someservice" class="com.node.service.impl.SomeServiceImpl"/>
</beans>
<!--
spring的配置文件
1.beans:根标签,spring把Java对象称为bean。
2.spring-beans.xsd是约束文件,和mybatis dtd相似。更强的约束文件
-->
spring对象的数量和名称查询
String config="beans.xml";
ApplicationContext ac = new ClassPathXmlApplicationContext(config);
//使用spring提供的方法,获取容器中定义的对象数量
int nums = ac.getBeanDefinitionCount();
System.out.println(nums);
//容器每个定义对象的名称
String names[]=ac.getBeanDefinitionNames();
for (String name:names){
System.out.println(name);
}
三、DI(依赖注入)
1.set注入:
简单类型:Java的基本数据类型和String类型
1)简单类型注入
<bean id="xx" class="xx">
<property name="属性名" value="此属性的值"/>
</bean>
2)引用类型注入
<bean id="xx" class="xx">
<property name="属性名" ref="bean的id"/>
</bean>
2.构造注入(spring调用类的有参构造)
<constructor-arg>标签:一个代表一个构造方法的参数 <constructor-arg>标签属性: name:构造方法的形参名 index:构造方法的参数位置从0开始 value:构造方法形参的数据类型为 简单类型 ref:数据类型为 引用类型
<bean id="myStudent" class="com.node.k03.Student">
<constructor-arg name="name" value="张三"/>
<constructor-arg name="age" value="20"/>
<constructor-arg name="school" ref="mySchool"/>
</bean>
<!--index的使用-->
<bean id="myStudent2" class="com.node.k03.Student">
<constructor-arg index="0" value="李四"/>
<constructor-arg index="1" value="30"/>
<constructor-arg index="2" ref="mySchool"/>
</bean>
<!-- 声明school对象 -->
<bean id="mySchool" class="com.node.k03.School">
<property name="name" value="华师"/>
<property name="address" value="广州"/>
</bean>
<!--创建File,使用构造注入-->
<bean id="myfile" class="java.io.File">
<constructor-arg name="parent" value="H:\学习作业\JAVA\SpringBaseStudy\ch02-di-xml"/>
<constructor-arg name="child" value="readme.txt"/>
</bean>
3、ByName和ByType
引用类型的自动注入:spring框架根据某些规则给引用类型赋值。不用给引用类型赋值了 使用规则 byName,byType 1.byName(按名称注入):Java类中引用类型的属性名和sprig容器中(配置文件)<bean>的id名称一样 且数据类型是一致的,这样的容器中的bean,spring能够赋值给引用类型 2.byType(按类型注入):Java类中引用类型的数据类型和spring容器中(配置文件)<bean>的class属性时同源关系的, 这样的bean能够赋值给引用类型 同源:1.Java类中引用类型的数据类型和class的值是一样的。 2.Java类中引用类型的数据类型和class的值是父子类关系。 3.Java类中引用类型的数据类型和class的值是接口和实现类关系的。
1.byName
<!--byName-->
<!--byName方法只与set方法有关,set方法后的名称与bean的id需要设置成一致-->
<bean id="myStudent" class="com.node.k04.Student" autowire="byName">
<property name="name" value="李四"/>
<property name="age" value="22"/>
<!-- 引用类型 -->
<!--<property name="school" ref="mySchool"/>-->
</bean>
<!-- 声明school对象 -->
<!--sch和Student类中声明的学校对象的名字一致-->
<bean id="sch" class="com.node.k04.School">
<property name="name" value="华师"/>
<property name="address" value="广州"/>
</bean>
2.byType
<!--byType-->
<bean id="myStudent" class="com.node.k05.Student" autowire="byType">
<property name="name" value="李四"/>
<property name="age" value="22"/>
<!-- 引用类型 -->
<!--<property name="school" ref="mySchool"/>-->
</bean>
<!-- 声明school对象 -->
<!--<bean id="mysch" class="com.node.k05.School">
<property name="name" value="华师"/>
<property name="address" value="广州"/>
</bean>-->
<!-- 声明school子类对象 -->
<bean id="primarysch" class="com.node.k05.PrimarySchool">
<property name="name" value="华师"/>
<property name="address" value="广州"/>
</bean>
3.spring配置文件的整合
1)student配置文件
<!-- student 模块 所有bean的声明-->
<!--byType-->
<bean id="myStudent" class="com.node.k06.Student" autowire="byType">
<property name="name" value="李四"/>
<property name="age" value="30"/>
<!-- 引用类型 -->
<!--<property name="school" ref="mySchool"/>-->
</bean>
2)school配置文件
<!-- school 模块 所有bean的声明-->
<!--byType-->
<!-- 声明school对象 -->
<bean id="sch" class="com.node.k06.School">
<property name="name" value="华师大"/>
<property name="address" value="广州天河"/>
</bean>
3)总配置文件
<!--
包含关系的配置文件:
spring-total表示主配置文件:包含其他配置文件,主文件一般不定义对象
语法:<import resource="其他配置文件的路径"/>
关键字:"classpath" 表示类路径(class文件所在的目录),
在spring的配置文件中指定其他问价的位置
需要使用classpath,告诉spring到哪去加载读取文件。
-->
<!--加载是文件列表-->
<!--<import resource="classpath:k06/spring-school.xml"/>
<import resource="classpath:k06/spring-student.xml"/>-->
<!--
在包含关系的文件中,可以使用通配符 *表示任意字符
注意主文件不要加入范围 避免自我匹配 (所以spring-s*.xml)
-->
<import resource="classpath:k06/spring-s*.xml"/>
四、注解(anno)
配置文件applicationContext.xml的使用
<!-- 声明组件扫描器(component-scan),组件就是java对象
base-package:指定注解在你的项目中的包名。
component-scan工作方式:spring会扫描遍历base-package指定的包,
把包中和子包中的所有类,找到类中的注解,按照注解的功能创建对象,或给属性赋值
-->
<context:component-scan base-package="com.Gcompany.node.k01"/>
<!-- 指定多个包的三种方式 -->
<!-- 第一种:使用多次组件扫描器,指定不同的包-->
<context:component-scan base-package="com.Gcompany.node.k01"/>
<context:component-scan base-package="com.Gcompany.node.k02"/>
<!-- 第二种:使用分隔符(;或,)分隔多个包名-->
<context:component-scan base-package="com.Gcompany.node.k01;com.Gcompany.node.k02"/>
<!-- 第三种:指定父包-->
<context:component-scan base-package="com.Gcompany.node"/>
**<context:component-scan base-package="包全名"/>
1.@Component
/**
* @Component 创建对象的,等同于<bean>的功能
*
* 属性:value 就是对象的名称,也就是bean的id值,
* value的值是唯一的,创建的对象在整个spring容器中就一个
* 位置:类的上面
*
* @Component(value="myStudent")
* =<bean id="myStudent" class="com.Gcompany.node.k01.Student"/>
*
*
* spring中和@Component功能一致,创建对象的注解滑油:
* 1.@Repository(用在持久层类上面):放在dao实现类上面,表示创建dao对象,dao对象是能访问数
据库的。
* 2.@Service(用在业务层类上面):放在service的实现类上面,创建service对象,
* service是做业务处理
* 3.@Controller(用在控制器类上面):创建控制器对象
* 控制器对象,能够接受用户提交的参数,显示请求的处理结果
*
* 以上三个注解的使用语法和@Component一样的。都能创造对象,但是这三个注解有额外功能。
*
* @Repository,@Service,@Controller是给项目的对象分层的。
*
*/
2.@value
/**
* @value 简单类型的属性赋值
* 属性:value是String类型的,表示简单类型的属性值
* 位置:1.在属性定义的上面,无需set方法,推荐使用
* 2.在set方法上面
*/
3.@Autowired
引用类型也需要使用@Component创建实例对象且可选择@value赋值
/**
* 引用类型
* @Autowired:spring框架提供的注解,实现引用类型的赋值
* spring中通过注解给引用类型赋值,使用的是自动注入原理,支持byName、byType
*
* @Autowired:默认使用byType
* 位置:1)属性定义的上方,无需set方法 推荐使用
* 2)set方法上
*
* 使用byName方式:1.在属性上方加入@Autowired
* 2.在属性上加入@Qualifier(value="bean的id"):表示使用指定名称的bean完成赋值
*
* 两个注解没有先后顺序问题
*/
4.@Resource
/**
* 引用类型
* @Resource:来自JDK中的注解,spring框架提供了对这个注解的功能支持,可以使用它给的引用类型赋值
* 使用的也是自动注入原理,支持byName,byType。默认是byName
*位置:1.属性定义的上面,无需set
* 2.set方法上面
*
* @Resource只使用byName方式,需要增加一个属性
* name的值为bean的id
*/
eg: @Resource(name = "mySchool")//仅使用byName
//默认是byName:先使用byName自动注入,如果赋值失败,再使用byType
五、aspectj(面向切面的框架)AOP框架
主配置文件的建立
<!-- 把对象交给spring容器,由spring容器统一创建,管理对象-->
<!-- 声明目标对象-->
<bean id="myService" class="com.GCompany.node.k03.SomeServiceImpl"/>
<!-- 声明切面对象-->
<bean id="myAspect" class="com.GCompany.node.k03.MyAspect"/>
<!--声明自动代理生成器,使用aspectj框架内部的功能,
创建代理对象是在内存中实现,修改目标对下那个的内存中的结构。创建为代理对象
所以目标对象就是被修改后的代理对象
<aop:aspectj-autoproxy />:会把spring容器内中的有所目标对象,一次性都生成代理对象
-->
<!--
<aop:aspectj-autoproxy proxy-target-class="true"/>告诉spring框架使用gclib代理
-->
<!-- <aop:aspectj-autoproxy />-->
<aop:aspectj-autoproxy proxy-target-class="true"/>
使用AOP框架aspectJ时需要在需要创造ASpect的类上加上注解@Aspect
1.@Before(前置通知)
/**
* 定义方法:方法实现功能。
* 方法定义要求:
* 1.公共方法public
* 2.方法没有返回值
* 3.方法名称自定义
* 4.方法可以存在参数
* 若存在参数,参数不是自定义的,有几个参数类型可以使用。
*/
/**
* @Before: 前置通知注解
* 属性:value 是切入点表达式,表示切面的功能执行的位置
* 位置:切面方法的上面
* 特点:
* 1.目标方法前执行
* 2.不影响不改变目标方法的执行和结果
*/
// @Before(value = "execution(public void com.GCompany.node.k01.SomeServiceImpl.doSome(String, Integer))")
// public void myBefore(){
// //切面功能
// System.out.println("切面功能:在目标方法执行之前输出时间"+new Date());
// }
// @Before(value = "execution(void *..SomeServiceImpl.do*(..))")
// public void myBefore(){
// //切面功能
// System.out.println("1切面功能:在目标方法执行之前输出时间"+new Date());
// }
/**
* 指定通知方法中的参数:JoinPoint
* JoinPoint:业务方法(要加入切面功能的业务方法)
* 作用: 可以在通知方法中获取方法执行时的信息,例如方法名称,方法实参
* 如果你的切面功能中需要用到方法的信息,就加入joinpoint,
* 这个joinpoint参数的值由框架赋予,必须第一个位置的参数
*/
@Before(value = "execution(public void *..SomeServiceImpl.do*(..))")
public void myBefore(JoinPoint jp){
//使用PJ获取方法的完整定义
System.out.println("方法的签名="+jp.getSignature());
System.out.println("方法的名称="+jp.getSignature().getName());
//获取方法的实参
Object[] args = jp.getArgs();
for (Object obj : args) {
System.out.println("参数="+obj);
}
//切面功能
System.out.println("1切面功能:在目标方法执行之前输出时间"+new Date());
}
2.@AfterReturning(后置通知)
/**
* 后置定义方法:方法实现功能。
* 方法定义要求:
* 1.公共方法public
* 2.方法没有返回值
* 3.方法名称自定义
* 4.方法有参数
* 参数推荐Object,参数名自定义
*/
@Before(value = "execution(public void *..SomeServiceImpl.do*(..))")
public void myBefore(JoinPoint jp){
//使用PJ获取方法的完整定义
System.out.println("方法的签名="+jp.getSignature());
System.out.println("方法的名称="+jp.getSignature().getName());
//获取方法的实参
Object[] args = jp.getArgs();
for (Object obj : args) {
System.out.println("参数="+obj);
}
//切面功能
System.out.println("1切面功能:在目标方法执行之前输出时间"+new Date());
}
/**
* @AfterReturning:后置通知
* 属性:1.value :切入点表达式
* 2.returning:自定义的变量,表示目标方法的返回值
* 自定义变量名必须和通知方法的形参名一样。
* 位置,方法定义的上面
* 特点:
* 1.在目标方法之后执行的
* 2.能够获取到目标方法的返回值,根据返回值做不同的处理功能
* Object res = doOther
* 3.可以修改返回值
*
*
* 后置通知的执行顺序
* Object res = doOther();
* myAfterReturning(res);
*
*/
@AfterReturning(value = "execution(* com.GCompany.node.k02.SomeServiceImpl.doOther(..))",
returning ="res" )
public void myAfterReturning(JoinPoint jp,Object res){
// res :是目标方法的返回值,根据返回值做切面处理
System.out.println(jp.getSignature());
System.out.println("后置通知:在目标方法之后执行的,获取的返回值是:"+res);
//修改目标方法的返回值 不影响String类型最后的调用结果
if(res!=null){
res="hello";
}
}
//修改目标方法的引用类型的返回值 影响最后的调用结果
@AfterReturning(value = "execution(* com.GCompany.node.k02.SomeServiceImpl.doOther1(..))",
returning ="res" )
public void myAfterReturning1(Object res){
// res :是目标方法的返回值,根据返回值做切面处理
System.out.println("后置通知:在目标方法之后执行的,获取的返回值是:"+res);
//改变返回对象的值 引用类型
Student stu= (Student) res;
stu.setName("张三");
stu.setAge(18);
}
3.@Around(环绕通知)
/**
* 环绕通知定义方法:方法实现功能。
* 方法定义要求:
* 1.公共方法public
* 2.方法有返回值 推荐使用Object
* 3.方法名称自定义
* 4.方法有参数 固定的参数 ProceedingJoinPoint
*
*
* 环绕通知==JDK的动态代理,InvocationHandler接口
*
* 参数:ProceedingJoinPoint 就等同于Method
* 作用:执行目标方法的
* 返回值:就是目标方法的执行结果,可被修改
*/
/**
* @Around:环绕通知
* 属性:value(切入点表达式)
*
* 特点:
* 1.功能最强的通知
* 2.在目标方法前后都能增强
* 3.控制目标方法是否被调用执行
* 4.可修改原来的目标方法的执行结果,影响最后的调用结果
*
*/
@Around(value = "execution(* *..SomeServiceImpl.doFirst(..))")
public Object myAround(ProceedingJoinPoint pjp) throws Throwable {
String name="";
//获取第一个参数的值
Object[] args = pjp.getArgs();
if(args!=null && args.length>1){
Object arg = args[0];
name = (String)arg;
}
//实现环绕通知的功能
Object result = null;
System.out.println("环绕通知前:"+new Date());
//1.目标方法调用
if("zhangsan".equals(name)){
//符合条件
result = pjp.proceed();//method.invoke(); Object result = doFirst();
System.out.println("目标方法调用后返回值:"+result);
}
System.out.println("环绕通知后:提交事务");
//2.在目标方法的前后键入功能
//修改目标方法的执行结果
if(result!=null){
result="Hello AspectJ";
}
//返回目标方法的执行结果
return result;
}
**使用pjp.proceed();实现事务方法的调用:原理为:method.invoke();
(可在无接口类中使用)
4.@Pointcut
@Before(value = "pct()")
public void myBefore(){
System.out.println("事务处理前输出时间:"+new Date());
}
@Pointcut(value = "execution(* com.GCompany.node.k05.SomeServiceImpl.doSome(..))")
private void pct(){}
==================================分隔线==================================
一、spring和mybatis整合
/*mybatis复习:
①Maven配置文件导入mybatis、junit、mysql驱动依赖且在build中配置resources,防止资源导出失败
<!--导入依赖-->
<dependencies>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.27</version>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<!--junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<!--在build中配置resources,来防止我们资源导出失败的问题-->
<build>
<resources>
<resource>
<directory>src/main/resoures</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
②在resources文件中创建核心配置文件(数据库连接及Mapper配置文件的注册)-mybatis主配置文件
<!--核心配置文件-->
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF8&serverTimezone=GMT%2B8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!--每一个Mapper.xml都需要在Mybatis核心配置文件中注册!!!-->
<mappers>
<mapper resource="com/GHcode/dao/UserMapper.xml"/>
</mappers>
</configuration>
③创建工具类MybatisUtils获取SqlsessionFactory对象进一步获取SqlSession对象
private static SqlSessionFactory sqlSessionFactory;
static {
try {
//获取SqlSessionFactory对象
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
//既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。
// SqlSession 提供了在数据库执行 SQL 命令所需的所有方法
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
④创建domain实体类(实体类的属性必须与数据库的表数据对应)
⑤创建对象的Mapper接口添加数据库的操作功能
⑥配置Mapper.xml文件(注意namespace的包名)
<!--namespace绑定一个指点的Dao/Mapper接口-->
<mapper namespace="com.GHcode.dao.UserMapper">
<!--查询语句-->
<select id="getUserList" resultType="com.GHcode.pojo.User">
select * from mybatis.user;
</select>
<!--模糊查询-->
<select id="getUserLike" resultType="com.GHcode.pojo.User">
select * from mybatis.user where name like "%"#{value}"%"
</select>
<!--通过ID查对象-->
<select id="getUserById" parameterType="int" resultType="com.GHcode.pojo.User">
select * from mybatis.user where id = #{param};
</select>
<!--通过其他非主键信息查对象-->
<select id="getUserByOther" parameterType="map" resultType="com.GHcode.pojo.User">
select * from mybatis.user where name=#{name} and pwd=#{pwd};
</select>
<!--增加对象-->
<insert id="addUser" parameterType="com.GHcode.pojo.User">
insert into mybatis.user(id, name, pwd) values (#{id},#{name},#{pwd});
</insert>
<insert id="addUser2" parameterType="map">
insert into mybatis.user(id, name, pwd) values (#{userid},#{username},#{userpwd});
</insert>
<!--更新对象-->
<update id="updateUser" parameterType="com.GHcode.pojo.User">
update mybatis.user set name=#{name},pwd=#{pwd} where id=#{id};
</update>
<!--删除对象-->
<delete id="deleteUser" parameterType="int">
delete from mybatis.user where id=#{id};
</delete>
</mapper>
*/
**
二、整合mybatis的spring
1、Maven主配置文件添加依赖和build
<dependencies>
<!--spring依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<!--做spring事务-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<!--mybatis和spring集成的依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.1</version>
</dependency>
<!--mysql驱动配置-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.27</version>
</dependency>
<!--mybatis配置-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<!--junit测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!--国内阿里公司连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.12</version>
</dependency>
</dependencies>
<build>
<!--目的是把src/main/resoures/java目录中的文件包含到输出结果中,输出到classes目录中-->
<resources>
<resource>
<directory>src/main/java</directory>
<includes><!--包括目录下的.properties.xml文件都会扫描到-->
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resoures</directory>
<includes><!--包括目录下的.properties.xml文件都会扫描到-->
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
<!--指定jdk版本-->
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
2、创建实体类
3、创建对象Mapper接口和Mapper配置文件
public interface StudentMapper {
int insertStudent(Student student);
List<Student> selectStudentAll();
}
<mapper namespace="com.GHcode.mapper.StudentMapper">
<select id="selectStudentAll" resultType="com.GHcode.domain.Student">
select * from springdb.student order by id desc
</select>
<insert id="insertStudent">
insert into student values(#{id},#{name},#{email},#{age})
</insert>
</mapper>
4、创建Service接口及对应的实现类
/*Service接口*/
package com.GHcode.service;
import com.GHcode.domain.Student;
import java.util.List;
public interface StudentService {
int addStudent(Student student);
List<Student> queryStudents();
}
/*Service接口实现类Impl*/
package com.GHcode.service.impl;
import com.GHcode.domain.Student;
import com.GHcode.mapper.StudentMapper;
import com.GHcode.service.StudentService;
import java.util.List;
public class StudentServiceImpl implements StudentService {
//引用类型Dao
private StudentMapper studentMapper;
//使用set注入 赋值
public void setStudentMapper(StudentMapper studentMapper) {
this.studentMapper = studentMapper;
}
@Override
public int addStudent(Student student) {
return studentMapper.insertStudent(student);
}
@Override
public List<Student> queryStudents() {
return studentMapper.selectStudentAll();
}
}
5、mybatis配置文件
<?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:控制mybatis全局行为-->
<settings>
<!--设置mybatis输出日志-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<!--设置别名-->
<typeAliases>
<!--name:实体类所在的包名-->
<package name="com.GHcode.domain"/>
</typeAliases>
<!--sql mapper(sql映射文件)的位置-->
<mappers>
<!--
name:是包名,包中所有mapper.xml一次都能加载
-->
<package name="com.GHcode.mapper"/>
</mappers>
</configuration>
*6、主配置文件applicationContext.xml(重要的是 数据源DataResoures、SqlSessionFactory类、Mapper对象、Service对象)
<?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">
<!--声明数据源DataSource,作用是连接数据库-->
<bean id="myDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<!--使用set注入,给DruidDataSource提供连接数据库的信息-->
<property name="url" value="jdbc:mysql://localhost:3306/springdb?useSSL=false&useUnicode=true&characterEncoding=UTF8&serverTimezone=GMT%2B8"/><!--GMT%2B8-->
<property name="username" value="root"/>
<property name="password" value="123456"/>
<property name="maxActive" value="20"/>
</bean>
<!--声明的是mybatis中所提供的sqlsessionfactoryBean类,这个类用来创建sqlsessionfactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--set注入,把数据库连接池付给了dataSource属性-->
<property name="dataSource" ref="myDataSource"/>
<!--myBatis主配置文件的位置
configLocation属性是Resource类型 读取配置文件
它的赋值使用value,指定文件的路径,classpath表示文件的位置
-->
<!--在spring配置文件中,指定其他文件路径,要使用classpath-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<!--创建Dao/Mapper对象,使用SqlSession的getMapper(StudentMapper.class)-->
<!--
MapperScannerConfigurer:在内部调用getMapper()方法生成每个dao/mapper接口代理对象。
-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--指定SqlSessionFactory对象的id-->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<!--指定Dao/Mapper包名 包名为接口所在的包名
MapperScannerConfigurer会扫描这个包中的所有接口,把每个接口都执行一次getMapper;
得到每个接口的Dao/Mapper对象
创建的对象放到spring容器中
-->
<property name="basePackage" value="com.GHcode.mapper"/><!--多个包用逗号分隔-->
</bean>
<!--声明service-->
<bean id="studentService" class="com.GHcode.service.impl.StudentServiceImpl">
<property name="studentMapper" ref="studentMapper"/>
</bean>
</beans>
处理事务
1、声明事务处理器实现类
2、说明需要事务的类型
1)事务的隔离级别
DEFAULT:采用 DB 默认的事务隔离级别。MySql 的默认为 REPEATABLE_READ;
Oracle默认为 READ_COMMITTED。
➢ READ_UNCOMMITTED:读未提交。未解决任何并发问题。
➢ READ_COMMITTED:读已提交。解决脏读,存在不可重复读与幻读。
➢ REPEATABLE_READ:可重复读。解决脏读、不可重复读,存在幻读
➢ SERIALIZABLE:串行化。不存在并发问题。
2)事务的超时时间:表示一个方法最长的执行时间,如果方法执行时超过了时间,事务就回滚。单位是秒, 整数值, 默认是 -1.
3)事物的传播行为
PROPAGATION_REQUIRED
PROPAGATION_REQUIRES_NEW
PROPAGATION_SUPPORTS
以上三个需要掌握的
PROPAGATION_MANDATORY
PROPAGATION_NESTED
PROPAGATION_NEVER
PROPAGATION_NOT_SUPPORTED
三、spring-trans-anno(注解)
@Transactional
public class BuyGoodsServiceImpl implements BuyGoodsService {
private SaleDao saleDao;
private GoodsDao goodsDao;
/**
* rollbackFor:表示发生的指定异常一定回滚
*
*/
/*@Transactional(
propagation = Propagation.REQUIRED,
isolation = Isolation.DEFAULT,
readOnly = false,
rollbackFor = {
NullPointerException.class,NotEnoughException.class
}
)*/
//直接写Transactional的默认值就是以上的
//使用的是事务控制的默认值,默认的传播行为是REQUIRED,默认的隔离级别是DEFAULT
//默认抛出运行时异常,回滚事务
@Transactional
@Override
public void buy(int goodsId, int nums) {
System.out.println("===========buy方法的开始=============");
//记录销售信息
Sale sale = new Sale();
sale.setGid(goodsId);
sale.setNums(nums);
saleDao.insertSale(sale);
//更新库存
Goods goods = goodsDao.selectGoods(goodsId);
if(goods==null){
//商品不存在
throw new NullPointerException("编号是:"+goodsId+"商品不存在");
}else if(goods.getAmount()<nums){
//商品不足
throw new NotEnoughException("编号是:"+goodsId+"商品库存不足");
}
//修改库存了
Goods buyGoods = new Goods();
buyGoods.setId(goodsId);
buyGoods.setAmount(nums);
goodsDao.updateGoods(buyGoods);
System.out.println("===========buy方法的完成=============");
}
public void setSaleDao(SaleDao saleDao) {
this.saleDao = saleDao;
}
public void setGoodsDao(GoodsDao goodsDao) {
this.goodsDao = goodsDao;
}
}
四、spring-trans-aspectj(aop切面)
1、applicationContext配置文件(补充)
<!--1. 声明式事务处理:和源代码完全分离-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="myDataSource"/>
</bean>
<!--2. 声明业务方法它的事务属性(隔离级别、传播行为、超时时间)-->
<!--
id:表示自定义名称,表示tx:advice 和 <\tx:aadvice>之间的配置内容
transaction-manager:事务管理器对象的id
-->
<tx:advice id="myAdvice" transaction-manager="transactionManager">
<!-- tx:attributes:配置事务的属性 -->
<tx:attributes>
<!--tx:method:给具体的方法配置事务属性 method可以有多个,分别给不同的方法设置事务属性
name:方法名称,1)完整的方法名称,不带有包和类
2)方法可以使用通配符,*表示任意字符
propagation:传播行为
isolation:隔离级别
rollback-for:指定的异常类,全限定类型;发生异常一定回滚
-->
<tx:method name="buy" propagation="REQUIRED" isolation="DEFAULT"
rollback-for="com.GHcode.excep.NotEnoughException,
java.lang.NullPointerException"/>
<!--使用通配符,指定很多的方法-->
<tx:method name="add*" propagation="REQUIRES_NEW"/>
<tx:method name="notify*" propagation="REQUIRES_NEW"/>
<tx:method name="remove*" propagation="REQUIRED"/>
<!--查询方法-->
<tx:method name="*" propagation="SUPPORTS" read-only="true"/>
</tx:attributes>
</tx:advice>
<!--配置aop-->
<aop:config>
<!--切入点表达式:指定哪个包中类,要使用事务
id:切入点表达式的名称,唯一值
expression:切入点表达式,指定哪些类要使用事务,aspectj会创建代理对象
若包中有许多包名都为service则需要指定所需的包
com.GHcode.service
com.crm.service
com.service
-->
<aop:pointcut id="servicept" expression="execution(* *..service.*.*(..))"/>
<!--配置增强器:关联advice和pointcut
advice-ref:通知,上面tx:advice那里的配置
pointcut-ref:切入点表达式的id
-->
<aop:advisor advice-ref="myAdvice" pointcut-ref="servicept"/>
</aop:config>
五、在web中使用spring,完成注册
1、创建maven,web项目
2、加入依赖(主要是servlet、jsp、监听器对象依赖)
<dependencies>
<!--servlet依赖-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!--jsp依赖-->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2.1-b03</version>
<scope>provided</scope>
</dependency>
<!--监听器对象依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<!--spring依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<!--做spring事务-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<!--mybatis和spring集成的依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.1</version>
</dependency>
<!--mysql驱动配置-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.27</version>
</dependency>
<!--mybatis配置-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<!--junit测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!--国内阿里公司连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.12</version>
</dependency>
</dependencies>
<build>
<!--目的是把src/main/resoures/java目录中的文件包含到输出结果中,输出到classes目录中-->
<resources>
<resource>
<directory>src/main/java</directory>
<includes><!--包括目录下的.properties.xml文件都会扫描到-->
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resoures</directory>
<includes><!--包括目录下的.properties.xml文件都会扫描到-->
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
<!--指定jdk版本-->
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
3、mybatis-config、spring(applicationContext)配置文件
mybatis-config.xml
<?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:控制mybatis全局行为-->
<settings>
<!--设置mybatis输出日志-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<!--设置别名-->
<typeAliases>
<!--name:实体类所在的包名-->
<package name="com.GHcode.domain"/>
</typeAliases>
<!--sql mapper(sql映射文件)的位置-->
<mappers>
<!--
name:是包名,包中所有mapper.xml一次都能加载
-->
<package name="com.GHcode.mapper"/>
</mappers>
</configuration>
spring.xml
<!--
把数据库的配置信息,写在一个独立的文件中,编译修改数据库的配置内容
spring直到jdbc.properties文件的位置
<context:property-placeholder location="classpath:jdbc.properties"/>
-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--声明数据源DataSource,作用是连接数据库-->
<bean id="myDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<!--使用set注入,给DruidDataSource提供连接数据库的信息-->
<!--
使用属性配置文件中的数据,语法${key}
-->
<!-- <property name="url" value="jdbc:mysql://localhost:3306/springdb?useSSL=false&useUnicode=true&characterEncoding=UTF8&serverTimezone=GMT%2B8"/><!–GMT%2B8–>
<property name="username" value="root"/>
<property name="password" value="123456"/>
<property name="maxActive" value="20"/>-->
<property name="url" value="${jdbc.url}"/><!--GMT%2B8-->
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.pwd}"/>
<property name="maxActive" value="${jdbc.max}"/>
</bean>
<!-- 声明的是mybatis中所提供的sqlsessionfactoryBean类,这个类用来创建sqlsessionfactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--set注入,把数据库连接池付给了dataSource属性-->
<property name="dataSource" ref="myDataSource"/>
<!--myBatis主配置文件的位置
configLocation属性是Resource类型 读取配置文件
它的赋值使用value,指定文件的路径,classpath表示文件的位置
-->
<!--在spring配置文件中,指定其他文件路径,要使用classpath-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<!--创建Dao/Mapper对象,使用SqlSession的getMapper(StudentMapper.class)-->
<!--
MapperScannerConfigurer:在内部调用getMapper()方法生成每个dao/mapper接口代理对象。
-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--指定SqlSessionFactory对象的id-->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<!--指定Dao/Mapper包名 包名为接口所在的包名
MapperScannerConfigurer会扫描这个包中的所有接口,把每个接口都执行一次getMapper;
得到每个接口的Dao/Mapper对象
创建的对象放到spring容器中
-->
<property name="basePackage" value="com.GHcode.mapper"/><!--多个包用逗号分隔-->
</bean>
<!--声明service-->
<bean id="studentService" class="com.GHcode.service.impl.StudentServiceImpl">
<property name="studentMapper" ref="studentMapper"/>
</bean>
jdbc.properties
jdbc.url=jdbc:mysql://localhost:3306/springdb?serverTimezone=GMT%2B8
jdbc.username=root
jdbc.pwd=123456
jdbc.max=20
只剩下时区就对了
4、创建一个jsp发起请求,有参数id,name,email,age.
5、创建Servlet,接受请求参数,调用Service,调用dao完成注册
public class RegisterServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
String strId = request.getParameter("id");
String strName = request.getParameter("name");
String strEmail = request.getParameter("email");
String strage = request.getParameter("age");
//创建spring的容器对象
String config = "spring.xml";
//ApplicationContext ac = new ClassPathXmlApplicationContext(config);
WebApplicationContext ctx = null;
//获取ServletContext中的容器对象,创建好的容器对象,拿来就用
/*String key = WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE;
Object attr = getServletContext().getAttribute(key);
if (attr!=null){
ctx= (WebApplicationContext) attr;
}
*/
//使用框架中的方法,获取容器对象
ServletContext sc = getServletContext();
ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(sc);
System.out.println("容器对象的信息======"+ctx);
//获取service
StudentService service = (StudentService) ctx.getBean("studentService");
Student student = new Student();
student.setId(Integer.parseInt(strId));
student.setName(strName);
student.setEmail(strEmail);
student.setAge(Integer.parseInt(strage));
service.addStudent(student);
//给出一个页面
request.getRequestDispatcher("/result.jsp").forward(request,response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
6、创建jsp作为显示结果页面
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<p>注册学生</p>
<form action="reg" method="post">
<table>
<tr>
<td>id</td>
<td><input type="text" name="id"></td>
</tr>
<tr>
<td>姓名</td>
<td><input type="text" name="name"></td>
</tr>
<tr>
<td>email</td>
<td><input type="text" name="email"></td>
</tr>
<tr>
<td>年龄</td>
<td><input type="text" name="age"></td>
</tr>
<tr>
<td></td>
<td><input type="submit" value="注册学生"></td>
</tr>
</table>
</form>
</body>
</html>
result.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
result.jsp 注册成功
</body>
</html>
7、配置Tomcat(详细CSDN)
--------------------------------------------------------------------------暂停更新