第5章SSM整合开发
SSM编程,即SpringMVC+Spring+MyBatis整合,是当前最为流行的JavaEE开发技术架构。其实SSM整合的实质,仅仅就是将MyBatis整合入Spring。因为SpringMVC原本就是Spring的一部分,不用专门整合。
SSM整合的实现方式可分为两种:基于XML配置方式,基于注解方式。
再次分析SpringMVC流程
执行流程简单分析
(1)浏览器提交请求到中央调度器
(2)中央调度器做了一个简单的判断,直接将请求转给处理器映射器。
(3)处理器映射器会根据请求,找到处理该请求的处理器,并将其和拦截器封装为处理器执行链后返回给中央调度器。
(4)中央调度器根据处理器执行链中的处理器,找到能够执行该处理器的处理器适配器。
(5)处理器适配器调用执行处理器方法。
(6)处理器将处理结果及要跳转的视图封装到一个对象ModelAndView中,并将其返回给处理器适配器。
(7)处理器适配器直接将结果返回给中央调度器。
(8)中央调度器调用视图解析器,将ModelAndView中的视图名称封装为视图对象。(实际上是把逻辑视图转变为物理视图)
(9)视图解析器将封装了的view视图对象返回给中央调度器
(10)中央调度器调用视图对象,让其自己进行render渲染,即进行数据填充,形成响应对象。
(11)中央调度器响应浏览器。
/*.do
表示结尾必须是.do
如:/aa/bb/cc/dd.do
和*.do
不同
1、配置web.xml
(1)指定Spring配置文件的位置
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:resources/spring-*.xml</param-value>
</context-param>
注意,这里指定的Spring的配置文件,是整个SSM项目的总的容器。其中注册了数据源、事务管理、Service、Dao的Bean等。这是与SpringMVC的中央调度器中指定的配置文件SpringMVC.xml是不同的。
SpringMVC.xml中存放的仅仅是用于SpringMVC的“四器”注册,及SpringMVC相关Bean的注册,只是SSM项目中的一部分。
当然,也可以将这两个配置文件合为一个。不过,一般不进行合并。因为为了便于后期的维护,Spring的配置文件还要根据功能与模块,再拆分为多个子配置文件,所以SpringMVC的配置文件就无需再合并进来了。
这里将所有的配置文件均放入到了类路径下的resources目录中。
(2)注册 ServletContext监听器
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
注册 ServletContext 监听器的实现类ContextLoaderListener,用于创建 Spring容器及将创建好的Spring容器对象放入到ServletContext的域属性空间中。保证了整个应用中Spring容器的唯一性。
(3)注册字符集过滤器
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
注册字符集过滤器,用于解决请求参数中携带中文时产生乱码问题。
(4)配置中央调度器
配置中央调度器时需要注意,SpringMVC的配置文件名要与其它Spring配置文件名名称格式相同。这样在上一步中指定所有Spring配置文件时,就将SpringMVC的配置文件也就包含了进来。这样,就使得Spring容器在初始化时,将SpringMVC配置文件中注册的Bean也
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:resources/spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
2、配置式开发
/54-ssm-xml项目名称
定义学生类Student Bean包下
省略get、set、toString 使用Navicat创建学生表
package com.bjpowernode.beans;
public class Student {
private Integer id;
private String name;
private int age;
public Student() {
super();
// TODO Auto-generated constructor stub
}
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
}
定义index页面
起始页面
<html>
<head>
<title>My JSP 'index.jsp' starting page</title>
</head>
<body>
<form action="${pageContext.request.contextPath }/test/register.do" method="POST">
姓名:<input type="text" name="name"/><br>
年龄:<input type="text" name="age"/><br>
<input type="submit" value="注册"/>
</form>
</body>
</html>
定义处理器 handlers包
package com.bjpowernode.handlers;
public class StudentController implements Controller {
private IStudentService service;
public void setService(IStudentService service) {
this.service = service;
}
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
String name = request.getParameter("name");
String ageStr = request.getParameter("age");
Integer age = Integer.valueOf(ageStr);
Student student = new Student(name, age);
service.addStudent(student);
return new ModelAndView("/welcome.jsp");
}
}
定义Dao接口 Dao包
package com.bjpowernode.dao;
import com.bjpowernode.beans.Student;
public interface IStudentDao {
void insertStudent(Student student);
}
定义Dao的Mapper配置文件
在Dao包中定义MyBatis的映射文件IStudentDao.xml。
映射的SQL语句
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bjpowernode.dao.IStudentDao">
<insert id="insertStudent">
insert into student(name,age) values(#{name},#{age})
</insert>
</mapper>
定义mybatis的主配置文件
在类路径下的resources目录中,即src下的reources目录中定义该配置文件。该配置文件中主要用于注册Mapper中所使用的类的别名,及Mapper的位置。
<configuration>
<!-- 为实体类指定别名 -->
<typeAliases>
<package name="com.bjpowernode.beans"/>
</typeAliases>
<!-- 注册映射文件,mapper位置 -->
<mappers>
<package name="com.bjpowernode.dao"/>
</mappers>
</configuration>
定义jdbc.properties
在类路径下的resources目录中
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3366/test
jdbc.user=root
jdbc.password=111
定义Spring的配置文件
Spring的配置文件均定义在类路径下的resources目录中。
(1)spring-db.xml
该配置文件中用于注册数据源相关Bean。
<!-- 注册C3P0数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- 注册属性文件 -->
<context:property-placeholder location="classpath:resources/jdbc.properties"/>
(2)spring-mybatis.xml
该配置文件主要用于注册SqlSessionFactoryBean及Mapper动态代理生成器的Bean。
<!-- 注册SqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="configLocation" value="classpath:resources/mybatis.xml"/>
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 生成Dao的代理对象 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<property name="basePackage" value="com.bjpowernode.dao"/>
</bean>
(3)spring-service.xml
该配置文件中用于进行Service的Bean的注册。注意,这里在为Service注入dao属性时,使用的是Mapper 文件的名字(或者说是Dao接口的简单类名,它们的名字相同),且使用ref属性。
<!-- 注册Service -->
<bean id="studentService" class="com.bjpowernode.service.StudentServiceImpl">
<property name="dao" ref="IStudentDao"/>
</bean>
(4)spring-tx.xml
该配置文件中用于注册事务相关Bean。
<!-- 注册事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 注册事务通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="add*" isolation="DEFAULT" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!-- AOP配置 -->
<aop:config>
<aop:pointcut expression="execution(* *..service.*.*(..))" id="studentPointcut"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="studentPointcut"/>
</aop:config>
AspectJ 的切入点表达式
AspectJ 除了提供了六种通知外,还定义了专门的表达式用于指定切入点。表达式的原
型是:
只有加粗的部分是不可省略的
execution ( [modifiers-pattern] 访问权限类型
ret-type-pattern 返回值类型
[declaring-type-pattern] 全限定性类名
name-pattern(param-pattern) 方法名(参数名)
[throws-pattern] 抛出异常类型
)
切入点表达式要匹配的对象就是目标方法的方法名。所以,execution 表达式中明显就
是方法的签名。注意,表达式中加[ ]的部分表示可省略部分,各部分间用空格分开。在其中
可以使用以下符号:
示例1:
execution(* .service..*(…))
1
解析:从后往前括号里的”点点“表示任意多个参数,第四个星号挨着括号所以表示方法名,方法名之前的第三个星号则表示所有子类或接口,第二个星表示包,第一个星表示返回值类型
表示前面只能有一级包下的service子包下所有类(接口)中所有方法为切入点
示例2:
execution(* …service..doSome())
1
指定所有包下的 serivce 子包下所有类中的 doSome()方法为切入点
定义SpringMVC配置文件
该配置文件主要用于注册 SpringMVC的处理器。当然,还有可能需要配置的处理器映射器、处理器适配器、视图解析器等SpringMVC相关Bean的注册。
<!-- 注册处理器 -->
<bean id="/test/register.do" class="com.bjpowernode.handlers.StudentController">
<property name="service" ref="studentService"/>
</bean>
欢迎页面
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'index.jsp' starting page</title>
</head>
5.3 全注解开发
5.3.1将SpringMVC改为注解
项目:ssm-annotation-1。该项目在ssm-xml项目基础上进行修改。
(1)修改spring-mvc.xml
<!-- 注册处理器 -->
<!-- 省略这里
// <bean id="/test/register.do" class="com.bjpowernode.handlers.StudentController">
// <property name="service" ref="studentService"/>
</bean>
--> 省略这里
<!-- 注册组件扫描器 -->
<context:component-scan base-package="com.bjpowernode.handlers"/>
注意,将处理器的注册方式,由原来的注册方式,改为组件扫描器后,会产生一个问题:在配置文件中无法完成将Service注入给处理器。所以,需要在处理器中以注解的方式完成Service的注入。
(2)修改处理器类
@Controller
@RequestMapping("/test")
public class StudentController {
@Autowired
@Qualifier("studentService")
// @Resource(name="studnetService")
private IStudentService service;
public void setService(IStudentService service) {
this.service = service;
}
@RequestMapping("/register.do")
public String doRegister(String name, int age) {
Student student = new Student(name, age);
service.addStudent(student);
return "/welcome.jsp";
}
}
5.3.2 将Spring改为注解
将Spring改为注解,又分为两步:将Service改为注解,完成Dao的注入;将事务以注解方式织入到Service层。
(1)将Service改为注解,完成Dao的注入
A、修改spring-service.xml
<!-- 注册Service -->
<!-- 省略
// <bean id="studentService" class="com.bjpowernode.service.StudentServiceImpl">
// <property name="dao" ref="IStudentDao"/>
</bean>
--> 省略
<!-- 注册组件扫描器,注意,不能与SpringMVC的组件扫描器进行合并 -->
<context:component-scan base-package="com.bjpowernode.service"/>
B、修改Service实现类
对于Service中Dao的注入可以采用ByType方式进行注入,也可以使用ByName方式。
但若采用ByName方式,则需要注意,注入的Name为Dao接口的简单类名。
ByType方式自动注入:
@Service("studentService")
public class StudentServiceImpl implements IStudentService {
@Autowired//ByType方式自动注入
private IStudentDao dao;
public void setDao(IStudentDao dao) {
this.dao = dao;
}
@Transactional
public void addStudent(Student student) {
dao.insertStudent(student);
}
}
ByName方式:
@Autowired
@Autowired
@Qualifier("IStudentDao")//ByName方式自动注入
private IStudentService service;
//因为是注入的,会调用set方法,所有要写上这个set
public void setService(IStudentService service) {
this.service = service;
}
@Resource(name=“IStudentDao”)也可以哦
(2)将事务以注解方式织入到Service层
A、修改spring-tx.xml
省略了事务通知advice和AOP配置execution
<!-- Spring默认发生运行时异常回滚,发生受查异常时提交,对于受查异常,可以手动设置回滚 -->
<!-- 注册事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 注册事务注解驱动 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
B、修改Service实现类
@Transactional,默认
@Service("studentService")//必须和StudentController中注解写的一样
public class StudentServiceImpl implements IStudentService {
@Resource(name="IStudentDao")
private IStudentDao dao;
public void setDao(IStudentDao dao) {
this.dao = dao;
}
@Transactional
public void addStudent(Student student) {
dao.insertStudent(student);
}
}
一般情况下,考虑到性能问题,对于MyBatis是不建议使用注解式开发的。所以这里省略。