SpringMVC(7)
SSM整合
流程:
思路:XML+注解的方式
(1)先搭建整合的环境
(2)将Spring配置搭建完成(业务层Service)
(3)搭建SpringMVC配置,并使用Spring整合SpringMVC(表现层Web Conreoller)
(4)搭建MyBatis配置,并使用Spring整合MyBatis(持久层Dao)
具体代码:
1. 创建数据库:
create database ssm;
use ssm;
create table account(
id int primary key auto_increment,
name varchar(20),
money double
);
2. 创建JavaBean实体类:
src/main/java/com/Lemon/domain/Account.java
public class Account implements Serializable {
private Integer id;
private String name;
private Double money;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", name='" + name + '\'' +
", money=" + money +
'}';
}
}
3. Service业务层的Spring框架:
(1)Service接口:
src/main/java/com/Lemon/service/AccountService.java
public interface AccountService {
// 查询所有账户
public List<Account> findAll();
// 保存账户信息
public void saveAccount(Account account);
}
(2)Service接口实现类:
src/main/java/com/Lemon/service/Impl/AccountServiceImpl.java
使用@Service
注解
@Service("accountService")
public class AccountServiceImpl implements AccountService {
@Override
public List<Account> findAll() {
System.out.println("业务层:查询所有账户。。。");
}
@Override
public void saveAccount(Account account) {
System.out.println("业务层:保存账户。。。");
}
}
(3)Spring配置文件:
src/main/resources/applicationContext.xml
:
<!-- 开启注解扫描 -->
<context:component-scan base-package="com.Lemon">
<!-- 配置哪些注解不扫描 -->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
注意:这里希望只处理service
和dao
,而controller
不需要Spring框架去处理注解扫描
(4)测试Spring:
com/Lemon/test/TestSpring.java
public class TestSpring {
@Test
public void run1(){
// 加载Spring配置文件
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
// 根据注解的id,获得对象
AccountService as = (AccountService) ac.getBean("accountService");
// 加载方法
as.findAll();
}
}
效果:通过注解@Service("accountService")
调用AccountServiceImpl
类的findAll
方法,控制台打印业务层:查询所有账户。。。
4. 配置SpringMVC
(1)配置SpringMVC的前端控制器和过滤器:
webapp/WEB-INF/web.xml
<web-app>
<display-name>Archetype Created Web Application</display-name>
<!-- 解决中文乱码的过滤器 -->
<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>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 配置前端控制器 -->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 加载springmvc.xml文件 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!-- 启动服务器,创建该servlet -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
(2)SpringMVC配置文件:
src/main/resources/springmvc.xml
<!-- 开启注解扫描 -->
<context:component-scan base-package="com.Lemon">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!-- 配置视图解析器 -->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!-- 过滤静态资源 -->
<mvc:resources location="/css/" mapping="/css/**" />
<mvc:resources location="/images/" mapping="/images/**" />
<mvc:resources location="/js/" mapping="/js/**" />
<!-- 开启SpringMVC注解的支持 -->
<mvc:annotation-driven/>
注意:SpringMVC的注解扫描,只扫描controller
注解
(3)SpringMVC的controller方法和页面:
src/main/java/com/Lemon/controller/AccountController.java
@Controller
@RequestMapping("/account")
public class AccountController {
@RequestMapping("/findAll")
public String findAll(Model model){
System.out.println("表现层:查询所有账户。。。");
return "list";
}
}
src/main/webapp/index.jsp
<a href="account/findAll">测试查询</a>
src/main/webapp/WEB-INF/pages/list.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h3>查询所有的账户</h3>
</body>
</html>
(4)测试SpringMVC:
开启Tomcat服务器,首页点击测试查询
的超链接,可以跳转到list.jsp
显示查询所有的账户
,控制台打印表现层:查询所有账户。。。
5. Spring整合SpringMVC
目的:在Controller
中能够调用Service
对象中的方法
思路:
- Controller --> Service --> Dao --> 数据库,可以在容器中调用service对象
- 但是现在在服务器启动时,只有
springmvc.xml
被应用了,controller
可以被注入到容器中 - 而Spring配置文件
applicationContext.xml
没有被注入到容器中,扫描不到service
和dao
注解 - 所以需要先将
service
和dao
注入到容器中,才能在controller
方法中调用service
的方法
解决办法:
- 在
web.xml
文件中配置ContextLoaderListener
监听器,该监听器会在服务器启动时加载Spring配置文件
注意:
ContextLoaderListener
监听器默认只加载WEB-INF
目录下的applicationContext.xml
配置文件,所以需要加上参数context-param来设置配置文件的路径,指向classpath:applicationContext.xml
具体代码:
(1)在web.xml
中配置监听器:
<!-- 设置配置文件的路径 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!-- 配置Spring的监听器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
(2)在AccountController
中注入AccountService
对象(依赖注入),并调用AccountService
方法:
@Controller
@RequestMapping("/account")
public class AccountController {
// 依赖注入
@Autowired
private AccountService accountService;
@RequestMapping("/findAll")
public String findAll(Model model){
System.out.println("表现层:查询所有账户。。。");
// 调用service的方法
List<Account> list = accountService.findAll();
model.addAttribute("list", list);
return "list";
}
}
注意:这里使用Model
将得到的结果存储在request域对象
中
(3)测试:
开启Tomcat服务器,首页点击测试查询
的超链接,可以跳转到list.jsp
显示查询所有的账户
,控制台打印表现层:查询所有账户。。。
和业务层:查询所有账户。。。
6. 配置MyBatis
(1)MyBatis的配置文件:(不需要,只是在测试时使用,后续在Spring配置文件中配置并注入容器了)
src/main/resources/SqlMapConfig.xml
<!-- 配置环境 -->
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///ssm?useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!-- 引入映射配置文件,可以直接引入接口 -->
<mappers>
<!-- 直接引入dao中所有的接口 -->
<package name="com.Lemon.dao"/>
</mappers>
(2)创建AccountDao
接口,并使用注解编写Sql语句:不需要自己写接口实现类,因为MyBatis会自动生成实现类
src/main/java/com/Lemon/dao/AccountDao.java
public interface AccountDao {
// TODO 配置MyBatis框架,使用注解的方式
// 查询所有账户
@Select("select * from account")
public List<Account> findAll();
// 保存账户信息
@Insert("insert into account (name,money) values (#{name},#{money})")
public void saveAccount(Account account);
}
(3)测试:需要在数据表中添加数据
src/main/java/com/Lemon/test/TestMyBatis.java
public class TestMyBatis {
// 测试查询
@Test
public void run1() throws Exception {
// 加载MyBatis配置文件
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
// 创建SqlSessionFactory对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
// 创建SqlSession对象
SqlSession session = factory.openSession();
// 获取到代理对象
AccountDao dao = session.getMapper(AccountDao.class);
// 调用dao方法
List<Account> list = dao.findAll();
for (Account account : list) {
System.out.println(account);
}
// 关闭资源
session.close();
in.close();
}
// 测试保存
@Test
public void run2() throws Exception {
Account account = new Account();
account.setName("熊大");
account.setMoney(400d);
// 加载MyBatis配置文件
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
// 创建SqlSessionFactory对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
// 创建SqlSession对象
SqlSession session = factory.openSession();
// 获取到代理对象
AccountDao dao = session.getMapper(AccountDao.class);
// 调用dao方法
dao.saveAccount(account);
// 提交事务
session.commit();
// 关闭资源
session.close();
in.close();
}
}
7. Spring整合MyBatis
目的:service要能调用dao对象,必须将dao也要放入到容器中
思路:把SqlMapConfig.xml
配置文件配置到applicationContext.xml
中
解决办法:在Spring配置文件applicationContext.xml中配置(和SqlMapConfig.xml思路是一样的)
- 连接池
- SqlSessionFactory工厂:工厂可以创建Session,Session可以拿到代理对象,代理对象就可以存入到IOC容器中
- AccountDao所在的包:指定Dao接口所在路径
具体代码:
(1)在applicationContext.xml
中配置:
<!-- Spring整合MyBatis框架 -->
<!-- 配置连接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql:///ssm?useUnicode=true&characterEncoding=UTF-8"/>
<property name="user" value="root"/>
<property name="password" value="root"/>
</bean>
<!-- 配置SqlSessionFactory工厂 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置AccountDao所在的包 -->
<bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.Lemon.dao"/>
</bean>
(2)AccountServiceImpl
注入AccountDao
对象,并调用方法:
@Service("accountService")
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
@Override
public List<Account> findAll() {
System.out.println("业务层:查询所有账户。。。");
return accountDao.findAll();
}
@Override
public void saveAccount(Account account) {
System.out.println("业务层:保存账户。。。");
accountDao.saveAccount(account);
}
}
注意:在AccountDao
接口上加上@Repository
注解
(3)在applicationContext.xml
中配置Spring框架声明式事务管理,用于保存数据:
<!--配置事务管理器-->
<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="find*" read-only="true"/>
<tx:method name="*" isolation="DEFAULT"/>
</tx:attributes>
</tx:advice>
<!--配置AOP增强-->
<aop:config>
<!-- 切入点表达式:Impl下的以ServiceImpl结尾的类中的所有的方法 -->
<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.Lemon.service.Impl.*ServiceImpl.*(..))"/>
</aop:config>
(4)一些补充:
list.jsp
:遍历结果并打印
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h3>查询所有的账户</h3>
<c:forEach items="${list}" var="account">
${account.name}
</c:forEach>
</body>
</html>
index.jsp
:表单
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<a href="account/findAll">测试查询</a>
<h3>测试保存</h3>
<form action="account/save" method="post">
姓名:<input type="text" name="name"/><br/>
金额:<input type="text" name="money"/><br/>
<input type="submit" value="保存"/><br/>
</form>
</body>
</html>
(5)测试页面保存:AccountController
类中加入save
方法
@RequestMapping("/save")
public void save(Account account, HttpServletRequest request, HttpServletResponse response) throws Exception {
accountService.saveAccount(account);
// 重定向
response.sendRedirect(request.getContextPath()+"/account/findAll");
// return;
}
8. 整体测试
(1)查询:
- 启动服务器,页面点击
测试查询
的超链接 - 页面显示数据库中的数据
- 控制台打印
表现层:查询所有账户。。。
和业务层:查询所有账户。。。
(2)保存:
- 启动服务器,在页面表单输入姓名和金额并保存
- 页面显示数据库中的数据和刚输入的数据
- 控制台打印
业务层:保存账户。。。
,表现层:查询所有账户。。。
和业务层:查询所有账户。。。
9. 总结
(1)启动服务器,点击超链接,请求到Controller
Controller类中注入了Service,可以调用service方法
findAll方法执行后可以存储结果,并跳转到list.jsp页面
(2)Service类中注入了Dao,可以调用Dao方法
Dao方法会使用sql语句真正查询数据库,并将结果返回
(3)controller中接收到返回值后,可以用Model保存结果
在list页面中可以遍历得到结果,输出到页面上