1. spring的注入方式
a . bean配置
设值注入
- setXxx()方法,
构造注入
标签
p命名空间
- xmlns:p=”http://www.springframework.org/schema/p" 并在
标签中 P:name=””
- xmlns:p=”http://www.springframework.org/schema/p" 并在
自动装配 (只适用于引用类型)autowire=”byName | byType | constructor | no” (不建议多次使用)
- 在< bean id=”” autowire=”byName” /> ,当id的类中有和IOC容器中bean的id相同时,自动装配
byName : bean的id值=类的属性名
byType : 其他bean的类型(class)是否与该类的ref属性类型一致(当前IOC容器中只能有一个bean满足条件)
constructor : 其他bean的类型(class)是否与该类的构造方法参数的类型一致,本质是byType - 在头文件的beans标签中添加统一自动装配:default-autowire=”byName”
- 自动装配虽然可以减少代码量,但是会降低程度的可读性,使用时需要谨慎
- 在< bean id=”” autowire=”byName” /> ,当id的类中有和IOC容器中bean的id相同时,自动装配
b . 注解方式
@Component细化:
- @Repository Dao层
- @Service service层
- @Controller controller层
配置包扫描器:
xmlns:context="http://www.springframework.org/schema/context" http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd <context:component-scan base-package="com.test.pojo" />
在声明前加上 @Value(“”)
2. 使用注解实现声明式事务
1.需要的包:
- spring-tx.jar
- ojdbc.jar 驱动
- commons-dbcp.jar 连接池使用到的数据源
- commons-pool.jar 连接池
- spring-jdbc.jar
- aopalliance.jar aop相关
2.增加事务tx的命名空间
3.增加对事务的支持(核心):
<tx:annotation-driven transaction-manager="txManager" />
配置事务管理器:
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
配置数据库相关:
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
<property name="driverClassName" value="oracle.jdbc.OracleDriver" />
<property name="url" value="" />
<property name="username" value="system" />
<property name="password" value="123456" />
<property name="maxIdle" value="10" />
<property name="maxWaitMillis" value="1000" />
</bean>
4.将需要成为事务的方法 前增加注解:
@Transactional(readOnly=false,propagation=Propagation.REQUIRED,rollBackFor=...)
3. AOP
需要的jar:
- aopliance.jar
- aspectjweaver.jar
通知类型:org.springframework.aop.
前置通知:MethodBeforeAdvice 接口方法 before()
后置通知:AfterReturningAdvice 接口方法 afterReturning()
异常通知:ThrowsAdvice 接口方法 无
环绕通知:MethodInterceptor 接口方法 invoke()
<!-- 配置前置通知 切面 --> <bean id="logBefore" class="com.test.aop.LogBefore"> </bean> <!-- 关联切入点和切面 --> <aop:config > <!-- 配置切入点 --> <aop:pointcut id="pointcut" expression="execution(public void com.test.service.demoService.DemoServiceImpl.addUser())" /> <!-- 连接线 --> <aop:advisor advice-ref="logBefore" pointcut-ref="pointcut" /> </aop:config>
异常通知必须实现方法:
public void afterThrowing(Throwable ex)
or
public void afterThrowing(Method method, Object[] args, Object target, Throwable ex)
环绕通知:
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
Object result = null;
try {
System.out.println("环绕-前置通知");
//在此之前的为前置通知
result = mi.proceed(); //控制目标方法是否执行
//在此之后的为后置通知
System.out.println("环绕-后置通知:目标对象:" + mi.getThis() + ",调用的方法:" + mi.getMethod().getName() +
",参数个数:" + mi.getArguments().length + ",返回值:" + result);
}catch (Exception e){
//异常通知
System.out.println("环绕-异常通知");
}
return result;
}
注解实现AOP
前置: @Before
后置: @AfterReturning
异常: @AfterThrowing
环绕: @Around
最终: @After
注解形式AOP,需设置扫描器,扫描器会将指定的包中的 @Component @Service @Repository @Controller修饰的类产生的对象增加到IOC容器
通过注解形式实现的AOP,若要获取目标对象的一些参数,则需要使用一个对象:JoinPoint
@Component(“logAnnotation”)
@Aspect //表示此类是一个AOP通知
public class LogAnnotation {// 前置通知 @Before("execution(public void addUser())") // 属性定义触发时机(切点) public void myBefore(JoinPoint jp){ System.out.println("《注解》-前置通知:目标对象:" + jp.getTarget() + ",方法名:" + jp.getSignature().getName() + ",参数个数:" +jp.getArgs().length ); } // 后置通知 @AfterReturning(pointcut = "execution(public void deleteUser())", returning = "returningValue") // 属性定义触发时机(切点) public void myAfter(JoinPoint jp, Object returningValue){ //需要声明该方法有返回值, returningValue 是返回值 System.out.println("《注解》-后置通知:目标对象:" + jp.getTarget() + ",方法名:" + jp.getSignature().getName() + ",参数列表:" + Arrays.toString(jp.getArgs()) + ",返回值:" + returningValue ); } // 异常通知:如果只捕获特定类型的异常,则可以通过第二个参数实现:e @AfterThrowing(pointcut = "execution(public void addUser())", throwing = "e") public void myException(JoinPoint jp, NullPointerException e){ System.out.println("《注解》-异常通知: " + e.getMessage()); } // 环绕通知 @Around("execution(public void addUser())") public void myAround(ProceedingJoinPoint pjp){ //前置通知 System.out.println("《注解-环绕》-前置通知"); try{ pjp.proceed(); // 执行方法,抛出的是Throwable System.out.println("《注解-环绕》-后置通知"); }catch (Throwable e){ // 异常通知 System.out.println("《注解-环绕》-异常通知"); }finally { // 最终通知 System.out.println("《注解-环绕》-最终通知"); } } //单独的最终通知 @After("execution(public void addUser())") public void myAfter(){ System.out.println("《注解-环绕》-【单独的最终通知】"); }
}
开启注解对AOP的支持
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
通过Scheme配置AOP
xmlns:aop="http://www.springframework.org/schema/aop"
类似于实现接口的方式
编写一个普通的类
// Schema实现的AOP不需要实现接口,只需要在xml里配置 public class LogSchema { // 前置通知 public void before(JoinPoint jp){ System.out.println("【Schema】前置通知"); } //后置通知 public void afterReturning(JoinPoint jp, Object returnValue){ System.out.println("【Schema】后置通知:目标对象:" + jp.getThis() + ",方法名:" + jp.getSignature().getName() + ",参数个数:" + jp.getArgs().length + ", 返回值:" + returnValue); } // 环绕通知 public Object around(ProceedingJoinPoint pjp){ System.out.println("【Schema】环绕-前置通知"); Object result = null; try { //在此之前的为前置通知 result = pjp.proceed(); //控制目标方法是否执行 //在此之后的为后置通知 System.out.println("【Schema】环绕-后置通知:目标对象:" + pjp.getThis() + ",调用的方法:" + pjp.getSignature().getName() + ",参数个数:" + pjp.getArgs().length + ",返回值:" + result); }catch (Throwable e){ //异常通知 System.out.println("【Schema】环绕-异常通知"); } return result; } }
将该类通过配置,转为一个通知
如果要获取目标对象的信息:
注解、schema:JoinPoint
接口:Method method, Object[] args, Object target
<!-- 通过Schema实现AOP --> <bean id="logSchema" class="com.test.aop.LogSchema"> </bean> <!-- 关联切入点和切面 --> <aop:config > <!-- 配置切入点 --> <aop:pointcut id="pcSchema" expression="execution(public void com.test.service.demoService.DemoServiceImpl.addUser())" /> <!-- 连接线 Schema方式不需要这个 <aop:advisor advice-ref="logSchema" pointcut-ref="pcSchema" /> --> <aop:aspect ref="logSchema"> <!-- pointcut-ref:连接线 returnValue: 返回值 --> <aop:before method="before" pointcut-ref="pcSchema"/> <aop:after-returning method="afterReturning" pointcut-ref="pcSchema" returning="returnValue"/> <aop:around method="around" pointcut-ref="pcSchema" /> </aop:aspect> </aop:config>
Spring 开发Web项目
Java项目中从main开始启动,可以初始化IOC容器,在Web项目中从服务器启动时,需通过监听器初始化IOC容器
需要用到 spring-web.jar ,并在web.xml中进行配置
<!-- 配置spring-web.jar 提供的监听器,可以在服务器启动时初始化IOC容器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<!--
1. 必须告诉监听器此容器的位置:context-param
2. 默认约定的位置:WEB-INF/applicationContext.xml
-->
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
配置时必须告诉监听器此容器的位置,或者用默认的名称放在默认约定的位置:
WEB-INF/applicationContext.xml
拆分Spring配置文件
Web项目拆分配置:
- 三层结构
- UI(html/css/jsp/servlet)
- Service
- Dao
- 公共 数据库
- 功能结构
- 学生管理系统的功能结构:学生相关配置、班级相关配置…
Web项目合并配置:
1.在web.xml的context-param的classpath:中配置
<param-value>
classpath:applicationContext.xml,
classpath:applicationContext-1.xml,
classpath:applicationContext-2.xml
</param-value>
或
(推荐)
<param-value>
classpath:applicationContext.xml,
classpath:applicationContext-*.xml
</param-value>
2.在主配置文件applicationContext.xml中引入其他文件
<import resource="applicationContext-*.xml" />
...
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!-- 配置spring-web.jar 提供的监听器,可以在服务器启动时初始化IOC容器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<!--
1. 必须告诉监听器此容器的位置:context-param
2. 或者放在默认约定的位置:WEB-INF/applicationContext.xml
-->
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
</web-app>
springIOC容器与Servlet容器搭建通道,传递数据 (servlet与service)
在Servlet的init初始化方法中,获取SpringIOC容器中的bean对象
ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext("");
xxxService = (xxxxService) context.getBean("");
SpringMVC
Mybatis
MyBatis 可以简化JDBC操作,实现数据持久化
- ORM: Object Relational Mapping
- ORM概念:MyBatis是ORM的一个实现 / Hibernate
- ORM可以使得开发人员,像操作对象一样操作数据库表
开发Mybatis步骤:
配置Mybatis
- jar包: mybatis.jar ojdbc6.jar
- config.xml : 配置数据库信息 和 需要加载的映射文件
- 表 - 类
- 映射文件xxxMapper.xml : 增删改查标签 < select>
- 测试类:sqlSession.selectOne(“需要查询的SQL的namespace.id”,”SQL的参数值”);
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">
<!--
default和id值保持一致,通过default找到id
-->
<configuration>
<environments default="development"> <!-- 默认环境,即环境的id -->
<environment id="development">
<!-- 配置事务的提交方式:
1.用JDBC方式进行事务处理(commit rollback close)
2.MANAGER:将事务交由其他组件去托管(spring, jobss),默认会关闭连接
<property name="closeConnection" value="false" /> // 设置为不关闭
-->
<transactionManager type="JDBC"/>
<!-- 连接方式 UNPOOLED: 传统的连接方式(每次访问数据库都需要打开和关闭等操作)
POOLED: 使用数据库连接池
JNDI: 从tomcat获取一个内置的数据库连接池
-->
<dataSource type="POOLED">
<property name="driver" value="oracle.jdbc.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:@localhost:1521:ORCL"/>
<property name="username" value="system"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
<mappers>
<!-- 在配置文件中加载映射文件 -->
<mapper resource="personMapper.xml"/>
</mappers>
</configuration>
xxxMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--
namespace 映射文件路径
id 区分查询语句
resultType 返回值
parameterType 传入参数的类型,这里是id的类型int
-->
<mapper namespace="com.pojo.personMapper">
<select id="queryPersonById" resultType="com.pojo.Person" parameterType="int">
select * from person where id = #{id}
</select>
</mapper>
Mybatis的CRUD:
// 加载Mybatis文件,访问数据库
Reader reader = Resources.getResourceAsReader("config.xml");
// 当config.xml里的default不是所需的时,可以在build里强行切换数据库环境
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader, "development");
// SqlSessionFactory -- Connection
SqlSession sqlSession = sessionFactory.openSession();
// 通过配置文件personMapper.xml里的namespace和id获得sql语句
String statement = "com.pojo.personMapper.addPerson";
Person person = new Person(8, "cui8", 27);
// insert 插入一个person
int count = sqlSession.insert(statement, person);
//需要 commit
sqlSession.commit();
System.out.println("增加" + count + "个成功");
sqlSession.close();
Mybatis 约定:
输入参数parameterType 和 输出参数resultType,在形式上都只能有一个
如果输入参数是简单类型(8个基本+String),是可以使用任何占位符#{xxx}的;
如果是对象类型,则必须是对象的属性:#{属性名}
如果使用的事务方式为 jdbc,则需要手动提交:sqlSession.commit()
Mybatis动态代理方式的CRUD
原则:约定优于配置
硬编码方式:abc.java
Configguration conf = new Configuration();
con.setName(“myProject”);
配置方式:abc.xml
< name>myProject< /name>
约定:默认值就是myProject
具体实现步骤:
- jar包,config.xml ,mapper.xml…
(不同处)约定的目标:省略掉Statement,即根据约定直接定位出SQL语句
1.建立一个接口PersonMapper
- 约定:
- 方法名和mapper.xml 文件中标签的id值一样
- 方法的输入参数类型和parameterType一样
- 方法的返回值和resultType一样
- 如: Person queryPersonById(int id);
要实现接口中的方法 和 Mapper.xml中的SQL标签一 一对应,还需要:
- namespace的值,就是接口的全类名(接口–mapper.xml一 一对应)
匹配的过程:(约定过程)
根据接口名 找到mapper.xml文件 (根据的是namespace=接口全类名)
根据接口的方法名 找到mapper.xml文件中的SQL标签(方法名=SQL标签id值)
根据以上两点可以保证:当调用接口中的方法时,程序能自动定位到某一个Mapper.xml文件中的SQL标签
习惯:SQL映射文件 和 接口放在同一位置(注意修改config.xml中加载mapper.xml文件的路径)
以上,可以通过接口的方法————> 映射到SQL语句
// 通过约定接口的方式
PersonMapper personMapper = sqlSession.getMapper(PersonMapper.class);
personMapper.updatePerson(person); // 根据接口的方法 ---> 自动查找到SQL语句
优化:
- 可以将数据库信息放入db.properties,再通过 ${key} 动态引入
<configuration>
<properties resource="db.properties" />
Mybatis 全局参数
//开启缓存 <settings> <setting name="cacheEnabled" value="true" /> <setting name="" value="" /> ... </settings>
设置类的别名(忽略大小写)
a. 设置单个别名
在config.xml中,< typeAliases> < typeAlias type=”org…Person” alias=”Person” />…
b. 批量设置别名,别名就是不带包名的类名
// 包名
< typeAliases> < package name=”org.test” />…
Mybatis 还内置了一些常见类的别名:_integer/_byte/_long/int/boolean…
类型处理器 (类型转换器)(将Java类型转换为JDBC类型,如int转换为oracle的number类型)
a. Mybatis 自带一些常见的类型处理器
如:BooleanTypeHandler:Boolean/boolean–>任何兼容的布尔值
IntegerTypeHandler:Integer/int–>任何兼容的数字和整形
…b. 自定义Mybatis 类型处理器
Java类型 –> 数据库(JDBC类型)
示例:实体类Student: boolean stuSex true:男 false: 女 表student:number stuSex 1:男 0:女
自定义类型转换器(boolean – number) 步骤:
a. 创建类型转换器,要实现 TypeHandler接口 或继承BaseTypeHandler(更简单)
b. 在config.xml 中配置转换器
<!-- 类型处理器,将java的boolean类型 转换为 jdbc的number类型 -->
<typeHandlers>
<typeHandler handler="com.mybatis.MyTypeHandler" javaType="Boolean" jdbcType="INTEGER" />
</typeHandlers>
c. 更改映射文件
<!-- 验证类型转换器
1. 如果类的属性 和 表的字段类型 能够合理识别(String - varchar2),则可以使用resultType,否则使用resultMap(boolean-number)
2. 如果类的属性名 和 表的字段名 能够合理识别(String - varchar2),则可以使用resultType,否则使用resultMap(boolean-number)
-->
<select id="queryPersonByIdWithConverter" resultMap="resultPerson" parameterType="int">select * from person where id = #{id}</select>
<!-- 建立Person属性和表的字段的对应关系 主键id,非主键result , 再设置需要转换的类型-->
<resultMap id="resultPerson" type="person">
<id property="id" column="id" />
<result property="sex" column="sex" javaType="boolean" jdbcType="INTEGER" />
</resultMap>
类型转换的增加
// 更改SQL语句中需要转换的字段
#{sex,javaType=boolean,jdbcType=INTEGER}
注意:
1. 映射文件路径
<!-- 在配置文件中加载映射文件 IDEA里无法加载src下的xml文件 因此改用url class package等方式(接口与映射文件名称相同),
或将xml文件放到resources目录-->
<!-- 通过包名设置路径 -->
<package name="com.mybatis.myInter" />
2. 映射文件和config.xml的jdbcType的类型
integer 必须写成大写形式:INTEGER
5. 取值符号
- 简单类型
#{任意值} // 自动给String类型加上单引号’’ (自动类型转换)
${value} // 原样输出,但适合于动态排序(动态字段),其中的标识符只能是value - 对象类型
#{属性名}
${属性名}
SSM整合
SSM需要的jar
- mybatis.jar
- spring-tx.jar
- spring-jdbc.jar
- spring-context.support.jar
- spring-core.jar
- spring-beans.jar
- spring-aop.jar
- spring-web.jar
- spring-expression.ar
- spring-context.jar
- commons-logging.jar
- commons-dbcp.jar
- ojdbc.jar
- mybaits.jar
- log4.jar
- commons-pool.jar
Mybatis需要的:类-表
Mybaits配置文件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> <!-- 加载数据库配置文件 --> <properties resource="db.properties"/> <!-- 批量设置别名 --> <typeAliases> <package name="bean" /> </typeAliases> <!-- 配置数据库环境 --> <environments default="development"> <environment id="development"> <transactionManager type="JDBC" /> <dataSource type="POOLED"> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource> </environment> </environments> <!-- 加载映射文件 --> <mappers> <package name="dao" /> </mappers> </configuration>
通过mapper.xml将类、表建立映射关系
之前MyBatis使用config.xml –> SqlSessionFactory,现在整合时,需要通过Spring管理SqlSessionFactory,因此 产生SqlSessionFactory不再放入config.xml,而是放入spring配置文件
使用spring整合Mybatis
目标: 通过spring产生mybatis最终操作需要的动态mapper对象
spring产生动态mapper对象有3种方法:DAO层实现类 继承 SqlSessionDaoSupport类:提供了一个属性 SqlSession ,产生mapper
扫描包方式
继续整合SpringMVC:将springmvc加入项目即可:需要spring-webmvc.jar
- 给项目加入springmvc支持:web.xml–> dispatcherServlet
- 编写springmvc配置文件:applicationContext-controller.xml:视图解析器、注解驱动(基础配置、标配)