SSM概述
SSM框架是spring、spring MVC 、和mybatis框架的整合,是标准的MVC模式。标准的SSM框架有四层,分别是dao层(mapper),service层,controller层和View层。使用spring实现业务对象管理,使用spring MVC负责请求的转发和视图管理,mybatis作为数据对象的持久化引擎。
1)持久层:dao层(mapper)层
作用:主要是做数据持久层的工作,负责与数据库进行联络的一些任务都封装在此。
Dao层首先设计的是接口,然后再Spring的配置文件中定义接口的实现类。
然后可以在模块中进行接口的调用来进行数据业务的处理。(不在关心接口的实现类是哪个类)
数据源的配置以及有关数据库连接的参数都在Spring的配置文件中进行配置。
2)业务层:Service层
作用:Service层主要负责业务模块的逻辑应用设计。
先设计接口然后再设计实类,然后再在Spring的配置文件中配置其实现的关联。(业务逻辑层的实现具体要调用到自己已经定义好的Dao的接口上)这样就可以在应用中调用Service接口来进行业务处理。
建立好Dao之后再建立service层,service层又要在controller层之下,因为既要调用Dao层的接口又要提供接口给controller层。每个模型都有一个service接口,每个接口分别封装各自的业务处理的方法。
3)表现层:Controller层(Handler层)
作用:负责具体的业务模块流程的控制。
配置也同样是在Spring的配置文件里面进行,
调用Service层提供的接口来控制业务流程。
业务流程的不同会有不同的控制器,在具体的开发中可以将我们的流程进行抽象的归纳,设计出可以重复利用的子单元流程模块。
4)View层
作用:主要和控制层紧密结合,主要负责前台jsp页面的表示。
一 配置文件的内容整合
1)web.xml中的配置
<!-- 一、配置一个字符编码过滤器,此类过滤器一般都在其他Filter之前,因为POST请求编码设置需要在请求发起前进行编码设置-->
<!-- 而HiddenHttpMethodFilter的工作机制是先发起请求,这样的话put和delete请依然会存在乱码问题-->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<!-- 针对全部的POST请求的乱码解决方式(GET请求乱码问题在tomcat的配置文件夹下的server.xml文件中配置)-->
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<!-- forceEncoding顺手解决响应乱码问题,但只是设置了 -->
<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>
<!-- 二、支持Rest风格的Filter,可以将post类型的请转化为另外两种PUT和DELETE类型-->
<filter>
<filter-name>hiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>hiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 三、配置上下文参数,在项目启动的时候自动加载Spring的配置文件-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:config/spring.xml</param-value>
</context-param>
<!-- 配置前端控制器 ,SpringMVC的思想是有一个前端控制器能够自动拦截所有请求,-->
<!-- 并智能派发,而这个前端控制器本质就是一个Servlet ,所以需要再次配置-->
<servlet>
<!-- 1配置Servlet类-->
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 2 在类路径下指定springmvc配置文件的位置 如果此处不指定,可以采取另一种路径规则,即-->
<!-- 在/WEB-INF/springDispatcherServlet(前端控制器名)-servlet.xml;-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:config/springmvc.xml</param-value>
</init-param>
<!-- 3 servlet启动加载项,servlet本来是在第一次被访问时创建对象,有了以下的配置就-->
<!-- 会在服务器启动时创建对象,且值越小优先级越高-->
<load-on-startup>1</load-on-startup>
</servlet>
<!-- 4 对所有访问安装一定的匹配规则,访问进行拦截处理-->
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<!-- 注意:/和/*都是拦截所有请求,但是后者拦截范围更大,还会拦截到.jsp的请求,一单拦截浏览器端就不会再显示了-->
<!-- 此外,我们可以以.xxx后缀为依据进行进行更精确的匹配-->
<url-pattern>/</url-pattern>
</servlet-mapping>
需要配置如下内容
*
2)spring.xml配置
<!-- 1:spring负责自动扫描添加组件com.wzh下的全部组件,除了springmvc除了单独负责的@Controller/@ControllerAdvice标注的类-->
<context:component-scan base-package="com.wzh">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<context:exclude-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
</context:component-scan>
<!-- 2 ①加载类路径下的Druid配置文件-->
<context:property-placeholder location="classpath:config/Druid.properties"></context:property-placeholder>
<!-- ②配置druid数据源-->
<bean id="druid" class="com.alibaba.druid.pool.DruidDataSource">
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="driverClassName" value="${jdbc.driverClassName}"></property>
</bean>
<!-- 配置jdbcTemplate(基本不用)-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="druid"></property>
</bean>
<!-- 3 事物控制 配置事物管理器进行事物控制(切面);-->
<bean id="tm" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 控制住数据源-->
<property name="dataSource" ref="druid"></property>
</bean>
<!-- 配置aop切面,在切面内通过事物建议标签指定那些方法需要事物控制-->
<aop:config>
<aop:pointcut id="myPoint" expression="execution(* mvc.*.*(..))" />
<aop:advisor advice-ref="myAdvice" pointcut-ref="myPoint" />
</aop:config>
<tx:advice id="myAdvice" transaction-manager="tm">
<!-- 这里是指定那些方法是事物方法,然后用advisor标签将事物建议加入注册aop切面,只有这样事物方法才会有效;-->
<tx:attributes>
<tx:method name="checkout" propagation="REQUIRED" timeout="-1"/>
<tx:method name="get*" read-only="true"/>
</tx:attributes>
</tx:advice>
<!-- 根据mybatis的全局配置文件得到SqlsessionFactory用来创建Sqlsession-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 指定mybatis配置文件的位置-->
<property name="dataSource" ref="druid"/>
</bean>
<!-- 配置Mapper扫描,最终将全部的dao层接口实现的配置文件的mapper对象加入到ioc容器中 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 指定dao接口所在的包-->
<property name="basePackage" value="daoo"></property>
</bean>
需要如下配置项
- Spring编码过滤器
- 配置处理请求方式的过滤器
- 配置SpringMVC的前端控制器dispatchServlet
3)springmvc.xml配置
<!-- 1:spring负责自动扫描添加组件com.wzh下的全部组件,除了springmvc除了单独负责的@Controller/@ControllerAdvice标注的类-->
<context:component-scan base-package="com.wzh" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
</context:component-scan>
<!-- 2 视图解析器,默认优先级最低 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!-- 2.1 SpringMVC管理国际化资源文件;配置一个资源文件管理器,id必须是messageSource-->
<bean id="mssageSource" class="org.springframework.context.support.ResourceBundleMessageSource"></bean>
<!-- 2.2 单独为某个方法指定跳转路径-->
<mvc:view-controller path="/test/hello1" view-name="a"></mvc:view-controller>
<!-- 背景。前端控制器控制路径url-pattern设置为了 '/' 拦截了除了jsp外的所有请求-->
<!-- 告诉SpringMVC,自己映射的请求就自己处理,不能处理的就交给tomcat,意义是使前端控制器放弃对静态资源尤其是*.html资源的请求;-->
<mvc:default-servlet-handler></mvc:default-servlet-handler>
<!-- 3 开启mvc注解模式,针对所有的方法,上面的是针对静态的请求,这个是针对动态资源的请求,二者要相互结合-->
<mvc:annotation-driven></mvc:annotation-driven>
<!-- 自定义的视图解析器,value越小优先级越高-->
<!-- <bean id="resolver" class="mvc.view.MyViewResolver">-->
<!-- <property name="order" value="1"></property>-->
<!-- </bean>-->
<!-- 4 SpringMVC整合Spring-->
<!-- <import resource="spring.xml"></import>-->
<!-- 文件上传解析器-->
<bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" id="multipartResolver">
<property name="defaultEncoding" value="utf-8"></property>
<property name="maxUploadSize" value="100000000"></property>
</bean>
<!-- 注册自定义拦截器-->
<mvc:interceptors>
<!-- 配置某个拦截器,默认拦截所有请求–>-->
<mvc:interceptor>
<!-- 拦截器的拦截路径-->
<mvc:mapping path="/test3"/>
<bean class="mvc.controller.MyInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<!-- 这个属性是Properties类型的属性,配置那些异常去那些页面-->
<property name="exceptionMappings">
<props>
<prop key="java.lang.NullPointerException">error/error404</prop>
</props>
</property>
<!-- 跳转到指定的错误页面后通过${exception}可以打印错误信息-->
<property name="exceptionAttribute" value="ex"></property>
</bean>
需要如下配置项
- 扫描控制层(controller)组件component-scan
- 配置视图解析器InternalResourceViewResolver
- 开启mvc注解模式annotation-driven,针对所有动态请求进行处理,优先级高于默认的servlet
- 配置默认的servlet处理静态资源default-servlet-handler,告诉SpringMVC,自己映射的请求就自己处理,不能处理的就交给tomcat,意义是使前端控制器放弃对静态资源尤其是*.html资源的请求
- 配置视图控制器view-controller:将访问路径静态文件名绑定
- 配置文件上传解析器
- 配置拦截器interceptor,主要用作异常处理
4)mybatis-config.xml
<configuration>
<!-- 1 properities相当于spring.xml中的context:properity-placeholder 引入外部配置文件-->
<properties resource="jdbc.properties"></properties>
<!-- 2 setting是MyBatis中极为重要的调整设置,会改变MyBatis运行时的行为-->
<settings>
<!-- 这是开始自动驼峰命名的转换,例如,开启后javabean中和数据表字段(数据库中不区分大小写)的img_path自动转化为imgPath(原理是_p转化为P),-->
<!-- 这样在涉及该属性的sql(查询)操作语句中就不用额外起别名了(jdbc的解决方案是通过给这一类的数据起别名,别名与数据库的字段名严格一致)-->
<!-- 总之:数据表字段为img_path我们在javabean大胆的封装为imgPath属性,且查询是不需要器别名就能顺序完成查询与结果的封装-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!-- 开启延时加载开关-->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 开启属性按需加载-->
<setting name="aggressiveLazyLoading" value="true"/>
<!-- 开启全局缓存开关-->
<setting name="cacheEnabled" value="true"/>
</settings>
<!-- <typeAliases>-->
<!--<!– 3 为常用的javabean类型起别名,默认就是全类名最后的类名部分,alias可以指定定义的的别名–>-->
<!-- <typeAlias type="bean.Book" alias="book"></typeAlias>-->
<!--<!– 这是选择指定的包批量起别名,此时的别名都是默认的,我们可以使用注解自定义指定别名–>-->
<!--<!– 注意:myBatis为基本数据类型默认起了别名,规则案例 _int,_float,_char...,也为封装数据类型起了默认别名,名是他们本身;–>-->
<!-- <package name="bean"/>-->
<!--<!– 总结:推荐还是使用全类名–>-->
<!-- </typeAliases>-->
<!-- 4 java的类型与SQL类型的转换每一类型的数据对应着一种类型的数据处理器,MyBtais已经自动帮我们实现了-->
<!-- <typeHandlers></typeHandlers>-->
<!-- 7 强大的插件功能-->
<!-- <plugins>-->
<!-- <plugin interceptor=""></plugin>-->
<!-- </plugins>-->
<!-- 8 environments配置一个具体的环境,需要一个具体的事物管理器transctionManager和数据源dataSource
id是当前环境environment的标识,可以同时配置多个开发环境,default就是默认指定开发环境
数据源我们使用更专业的druib,c3p0等技术,但实际上数据源的获取和事务控制使用spring框架-->
<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/book?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone = GMT"/>-->
<!-- <property name="username" value="root"/>-->
<!-- <property name="password" value="123"/>-->
<property name="driver" value="${driverClass}"/>
<property name="url" value="${url}"/>
<property name="username" value="${user}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
<environment id="testEnv">
<transactionManager type=""></transactionManager>
<dataSource type=""></dataSource>
</environment>
</environments>
<!-- 用来考虑数据库的移植性,name是数据库厂商的标识,value是给该标识起名,这项相当于固定配置-->
<!-- 在sql配置文件中通过在<select>等标签中通过databaseId来精确指定该语句由那个数据库执行-->
<databaseIdProvider type="DB_VENDOR">
<property name="MySQL" value="mysql"/>
<property name="Oracla" value="oracla"/>
<property name="SQL Server" value="sqlserver"/>
</databaseIdProvider>
<!--
10 引入我们自己编写的每一个配置文件(接口实现类)的信息,其中
resource:表示在类路径下找资源;
url:在磁盘或者网络中动态引入路径
class:直接引用接口(sql配置文件的本质就是该接口的实现类)的全类名,这涉及到了另一种用法
分别用class引入XXXDAO接口和XXXDaoAnnotation(在XXXDAO方法声明上通过注解标注sql语句),
但实际开发中完全使用注解是不可取的,推荐做法是配合使用,简单的sql使用注解完成,复杂的sql还
是使用配置文件来完成;总之,注解是取代配置文件方式的存在;
$();读入配置文件的值
我们可以通过package进行批量注册,但是这样的话就要求XXXDAO接口和XXX.xml接口在同一个包(dao)
下才能完成引入工作,但这显然是不完美的,因为我们习惯将sql的xml配置文件集中到config文件夹下;
两全其美的解决方案是:在config下建立一个和XXXDAO所在包同名的包a,将XXX.xml放到a下,但实际
上由于两者有相同的包名最终都会被整合到同一个类路径(.idea)下
-->
<mappers>
<!-- <mapper resource="config/dao/UserDAO.xml"/>-->
<!-- <mapper resource="config/dao/BookDAO.xml"/>-->
<!-- <mapper class="daoo.BookDAO"/>-->
<!-- <mapper class="dao.BookDAOAnnotation"/>-->
<!-- 以仅有的bookDAO.java极其sql配置文件举例,相当于在配置文件中同时bookDAO.class和bookDAO.xml都被放到了类路径的dao包下了-->
<!-- 注意:该包下的所有配置文件,命名格式与他的实现的接口名必须一致才能扫描成功,否则报错-->
<!-- Invalid bound statement (not found): com.xxx.dao.xxxDao.selectByxx-->
<package name="daoo"/>
</mappers>
</configuration>
二 测试
@Service
public class UserService {
@Autowired
UserDAO userDAO;
@Autowired
EmployDAO employDAO;
public User getUser(int id){
//org.apache.ibatis.binding.MapperProxy@5ac7353c,这是获取到的mybatis配置文件
System.out.println(userDAO);
//dao.EmployDAO@1f081380,employDAO是注册的普通的@Repository组件
System.out.println(employDAO);
return userDAO.queryUserById(1);
}
}
@Controller
public class EmployeeController {
@Autowired
UserService userService;
@RequestMapping(value = "/SSMTest")
public String ttt(@RequestParam(value = "id",defaultValue = "1") Integer id){
System.out.println(userService.getUser(id));
return "restStyle/emps";
}
}
三 总结
======================================Spring与SpringMVC整合(SS)=========================================
整合的目的是分工明确,条理清晰
1 SpringMVC负责和网站的转发逻辑和网站的功能有关的:视图解析器,文件上传器,支持ajax...
2 Spring负责配置和业务相关的,如获取数据源,事物控制,组件添加
3 处理一个矛盾关于组件扫描的矛盾,方案:只是让SpringMVC扫描关于@Controller和@ControllerAdvice的组件,而Spring则是扫描SpringMVC扫描剩下的全部组件
注意1:spirng.xml默认作为springmvc.xml的父容器内容,子容器能拿父容器的内容,反正则不行,例如service层无法通过@AutoWired组件装配Controller类的组件
注意2:在测试方法中无法使用@AutoWired自动装配,因为测试方法无法注册到spring容器中,既然无法注册就无法享受到spring的服务
=======================================SS整合Mybatis(SSM)================================================
①mybatis先初始化一个sqlSessionFactory,这是一个数据库会话对象工厂
②每一个线程通过sqlSessionFactory.openSession()获取一个数据库的会话
③sqlSession.getMapper(UserDAO.class);通过sqlSession加载mybatis映射文件得到由myBatis创建的接口的代理类对象userDAO
④通过userDAO调用映射文件配置标签方法,mybatis的映射文件就相当于DAO接口的实现类DAOImpl,映射文件内的每个标签方法相当于是对DAO层接口方法的实现
⑤ssm整合后,1,2,3步相当于ssm框架自动帮我们完成,只需要在Controller类中,通过 @Autowired EmployDAO employDAO;
即可将原先第③部所创建的对象注入到employeeDAO中,然后直接调使用;