学习视频:孙哥说SpringMVC:结合Thymeleaf,重塑你的MVC世界!|前所未有的Web开发探索之旅
dispatcher.xml
<context:component-scan base-package="com.baizhi"/>
<mvc:annotation-driven/>
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"/>
<property name="suffix" value=".jsp"/>
bean>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/myschool?useSSL=false&allowPublicKeyRetrieval=true"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
bean>
<bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="typeAliasesPackage" value="com.baizhi.entity"/>
<property name="mapperLocations">
<list>
<value>classpath:com.baizhi.mapper/*Mapper.xmlvalue>
list>
property>
bean>
<bean id="scanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactoryBean"/>
<property name="basePackage" value="com.baizhi.dao"/>
bean>
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
bean>
<tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>
DAO
// **POJO**
public class User implements Serializable {
private Integer id;
private String name;
private String password;
// **建表**
create table t_user(
id integer primary key auto_increment;
name varchar(12),
password varchar(12)
);
// **DAO**
public interface UserDAO {
void save(User user);
}
// **Mapper**
<mapper namespace="com.baizhi.dao.UserDAO">
<insert id="save">
insert into admin(name,password) values(#{name},#{password})
</insert>
</mapper>
Service
public interface UserService {
void register(User user);
}
Service
@Transactional
public class UserServiceImpl implements UserService {
@Autowired
private UserDAO userDAO;
@Override
public void register(User user) {
userDAO.save(user);
}
}
Controller
@Controller
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/register")
public String register(User user) {
userService.register(user);
return "regOk";
}
}
现有SSM开发中存在的问题
MVC层的对象(Controller,mvc:annotation-driven/,视图解析器)与非MVC层的(连接池 DAO Service 事务),都配置在dispatcher.xml中,最终交给DispatcherServlet创建的工厂来进行实例化,存在着耦合问题,后续一旦替换MVC的实现,代码会受到影响,不利于项目的维护
如何解决
将非MVC的配置放在applicationContext.xml(引入ContextLoaderListener工厂读取配置)
子工厂(DispatcherServlet)读取dispatcher.xml
完成与SpringMVC相关对象的创建:视图解析器、自定义类型转换器、拦截器等
父工厂(ContextLoaderListener)读取applicationContext.xml
完成与非SpringMVC相关对象的创建:连接池、DAO、Service、事务、Redis、ES、MQ等
编码
子工厂(子容器)
# dispatcher.xml
# SpringMVC相关的配置
<context:component-scan base-package="com.baizhi"/>
<mvc:annotation-driven/>
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"/>
<property name="suffix" value=".jsp"/>
bean>
# web.xml子容器的配置
<servlet>
<servlet-name>dispatcherServletservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:dispatcher.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>dispatcherServletservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
父工厂(父容器)
# applicationContext.xml
# Spring相关配置
<context:component-scan base-package="com.baizhi"/>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/myschool?useSSL=false&allowPublicKeyRetrieval=true"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
bean>
<bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="typeAliasesPackage" value="com.baizhi.entity"/>
<property name="mapperLocations">
<list>
<value>classpath:com.baizhi.mapper/*Mapper.xmlvalue>
list>
property>
bean>
<bean id="scanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactoryBean"/>
<property name="basePackage" value="com.baizhi.dao"/>
bean>
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
bean>
<tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>
# web.xml父容器的配置
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListenerlistener-class>
listener>
<context-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:applicationContext.xmlparam-value>
context-param>
问题
按照现有父子工厂(容器)的开发方式,Service层没有添加事务。
问题成因
获取的是子容器的UserService,而子容器中没有事务配置,所以获取不到事务。
解决方案
之所以在子容器没有实现事务,是因为包扫描的全部的包,将service的包也交给子容器管理。
子容器:只扫描控制器及与MVC相关的内容
<context:component-scan base-package="com.baizhi.controller"/>
父容器:不扫描控制器与MVC相关的内容
<context:component-scan base-package="com.baizhi">
<context:exclude-filter type="aspectj" expression="com.baizhi.controller"/>
context:component-scan>
注意:在SpingBoot中不会出现父子容器的问题。
web.xml
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListenerlistener-class>
listener>
<context-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:applicationContext.xmlparam-value>
context-param>
<servlet>
<servlet-name>dispatcherServletservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:dispatcher.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>dispatcherServletservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
<filter>
<filter-name>encodingFilterfilter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
<init-param>
<param-name>encodingparam-name>
<param-value>UTF-8param-value>
init-param>
filter>
<filter-mapping>
<filter-name>encodingFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
dispatcher.xml
<context:component-scan base-package="com.baizhi.controller"/>
<mvc:annotation-driven/>
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"/>
<property name="suffix" value=".jsp"/>
bean>
applicationContex.xml
<context:component-scan base-package="com.baizhi">
<context:exclude-filter type="aspectj" expression="com.baizhi.controller"/>
context:component-scan>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/myschool?useSSL=false&allowPublicKeyRetrieval=true"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
bean>
<bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="typeAliasesPackage" value="com.baizhi.entity"/>
<property name="mapperLocations">
<list>
<value>classpath:com.baizhi.mapper/*Mapper.xmlvalue>
list>
property>
bean>
<bean id="scanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactoryBean"/>
<property name="basePackage" value="com.baizhi.dao"/>
bean>
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
bean>
<tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>
DAO
// **POJO**
public class User implements Serializable {
private Integer id;
private String name;
private String password;
// **建表**
create table t_user(
id integer primary key auto_increment;
name varchar(12),
password varchar(12)
);
// **DAO**
public interface UserDAO {
void save(User user);
}
// **Mapper**
<mapper namespace="com.baizhi.dao.UserDAO">
<insert id="save">
insert into admin(name,password) values(#{name},#{password})
</insert>
</mapper>
Service
public interface UserService {
void register(User user);
}
Service
@Transactional
public class UserServiceImpl implements UserService {
@Autowired
private UserDAO userDAO;
@Override
public void register(User user) {
userDAO.save(user);
}
}
Controller
@Controller
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/register")
public String register(User user) {
userService.register(user);
return "regOk";
}
}
下一章:Spring MVC学习随笔-控制器(Controller)开发详解:控制器跳转与作用域(一)