|
1.准备jar包
2.添加springMVC的核心Servlet并设置其初始化加载的配置文件,web.xml内容,内容如下:
<!-- 设置字符编码 -->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>GBK</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 配置spring核心控制器 -->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring-mvc.xml,classpath:applicationContext-beans.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
3.在WEB-INF目录中添加spring-mvc.xml,内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd">
<!-- 注解探测器 -->
<context:component-scan base-package="com.springmvcmybatis" />
<mvc:annotation-driven />
<!-- annotation默认的方法映射适配器 -->
<!--
<bean id="handlerMapping"
class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
<bean id="handlerAdapter"
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />
-->
<!-- 页面View层基本信息设定 -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
</beans>
4.在src目录下添加applicationContext-beans.xml,内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.1.xsd ">
<!-- 配置DataSource数据源 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:@localhost:1521:oralsb" />
<property name="username" value="scott" />
<property name="password" value="tiger" />
</bean>
<!-- 配置SqlSessionFactoryBean -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:sqlMapConfig.xml" />
<!-- mapper配置路径 -->
<property name="mapperLocations">
<list>
<value>classpath:com/springmvcmybatis/mapper/*-mapper.xml</value>
</list>
</property>
</bean>
<!-- 单独配置一个Mapper; 这种模式就是得给每个mapper接口配置一个bean -->
<!--
<bean id="accountMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="com.springmvcmybatis.mapper.AccountMapper" />
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
-->
<!-- 自动装配:通过扫描的模式,扫描目录在com/springmvcmybatis/mapper目录下,所有的mapper都继承 SqlMapper接口的接口 -->
<!-- MapperScannerConfigurer将会创建MapperFactoryBean,之后自动装配 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.springmvcmybatis.mapper" />
<property name="markerInterface" value="com.springmvcmybatis.mapper.SqlMapper" />
</bean>
</beans>
上面的配置,最先配置的是DataSource,这里采用的是jdbc的DataSource;然后是SqlSessionFactoryBean,这个配置比较关键。SqlSessionFactoryBean需要注入DataSource数据源,其次还要设置configLocation也就是mybatis的xml配置文件路径,完成一些关于mybatis的配置,如settings、mappers、plugin等;
如果使用MapperScannerConfigurer模式,需要设置扫描根路径也就是你的mybatis的mapper接口所在包路径;凡是markerInterface这个接口的子接口都参与到这个扫描,也就是说所有的mapper接口继承这个SqlMapper。
如果你不使用自己的transaction事务,就使用MapperScannerConfigurer来完成SqlSession的打开、关闭和事务的回滚操作。在此期间,出现数据库操作的如何异常都会被转换成DataAccessException,这个异常是一个抽象的类,继承RuntimeException。
5.SqlMapper内容如下:
package com.springmvcmybatis.mapper;
public interface SqlMapper {
}
6.实体类
package com.springmvcmybatis.model;
public class Account {
private int accountId;
private String username;
private String password;
// getter、setter
@Override
public String toString() {
return this.accountId + "#" + this.username + "#" + this.password;
}
}
7.在src目录中添加sqlMapConfig.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>
<!-- 别名 -->
<typeAliases>
<typeAlias type="com.springmvcmybatis.model.Account" alias="Account" />
</typeAliases>
</configuration>
在这个文件放置一些全局性的配置,如handler、objectFactory、plugin以及mappers的映射路径(在applicationContext-beans.xml中的SqlSessionFactoryBean有配置mapper的location,这里就不需要配置)等。
8. AccountMapper接口,内容如下:
package com.springmvcmybatis.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Select;
import com.springmvcmybatis.model.Account;
public interface AccountMapper extends SqlMapper {
public List<Account> getAllAccount();
public Account getAccountById(int id);
public Account getAccountByNames(String name);
// 这里如果数据库字段名和实体类属性名不对应,需要转换
@Select("select account_id accountId, username, password from account where username = #{name}")
public Account getAccountByName(String name);
public void addAccount(Account account);
public void updateAccount(Account account);
public void deleteAccount(int id);
}
这个接口我们不需要实现,由mybatis帮助我们实现,我们通过mapper文件配置sql语句即可完成接口的实现。然后这个接口需要继承SqlMapper接口,不然在其他地方就不能从spring容器中拿到这个mapper接口,也就是说当我们注入这个接口的时候将会失败。当然,你不继承这个接口也可以。那就是你需要给每个mapper配置一个bean。配置方法如下:
<bean id="accountMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="com.springmvcmybatis.mapper.AccountMapper" />
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
这里的MapperFactoryBean可以帮助我们完成Session的打开、关闭等操作。
9.在com.springmvcmybatis.mapper也就是在AccountMapper接口的同一个包下,添加account-mapper.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和定义的Mapper接口对应,并实现其中的方法 -->
<mapper namespace="com.springmvcmybatis.mapper.AccountMapper">
<resultMap id="accountResultMap" type="Account">
<id property="accountId" column="account_id" />
<result property="username" column="username" />
<result property="password" column="password" />
</resultMap>
<!-- id和mapper接口中的方法名对应 -->
<select id="getAllAccount" resultType="list" resultMap="accountResultMap">
SELECT * FROM ACCOUNT
</select>
<select id="getAccountById" parameterType="int" resultMap="accountResultMap">
SELECT * FROM ACCOUNT WHERE ACCOUNT_ID = #{id}
</select>
<select id="getAccountByNames" parameterType="string" resultMap="accountResultMap">
SELECT * FROM ACCOUNT WHERE USERNAME = #{name}
</select>
<!-- 自动生成id策略(oralce不支持、mysql和sqlserver支持) -->
<!--
<insert id="addAccount" useGeneratedKeys="true" keyProperty="account_id" parameterType="Account">
INSERT INTO ACCOUNT (ACCOUNT_ID, USERNAME, PASSWORD) VALUES (#{accountId}, #{username}, #{password})
</insert>
-->
<!-- 根据selectKey语句生成主键 -->
<insert id="addAccount" parameterType="Account">
<selectKey keyProperty="accountId" order="BEFORE" resultType="int">
SELECT ACCOUNT_SEQ.NEXTVAL FROM DUAL
</selectKey>
INSERT INTO ACCOUNT (ACCOUNT_ID, USERNAME, PASSWORD) VALUES (#{accountId}, #{username}, #{password})
</insert>
<update id="updateAccount" parameterType="Account">
UPDATE ACCOUNT SET USERNAME = #{username}, PASSWORD = #{password} WHERE ACCOUNT_ID = #{accountId}
</update>
<delete id="deleteAccount" parameterType="int">
DELETE FROM ACCOUNT WHERE ACCOUNT_ID = #{id}
</delete>
</mapper>
注意:上面的namespace和定义接口类路径必须一致,这里所有的sql语句,如select、insert、delete、update的id和方法名称也必须一致。
10.为了测试发布,这里使用junit和spring官方提供的org.springframework.test-3.1.4.RELEASE.jar,完成spring框架整合的测试,代码如下:
package com.springmvcmybatis.test;
import javax.annotation.Resource;
import org.junit.Test;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
import com.springmvcmybatis.mapper.AccountMapper;
import com.springmvcmybatis.model.Account;
@ContextConfiguration("classpath:applicationContext-beans.xml")
public class AccountMapperTest extends AbstractJUnit4SpringContextTests {
private AccountMapper accountMapper;
public AccountMapper getAccountMapper() {
return accountMapper;
}
@Resource(name = "accountMapper")
public void setAccountMapper(AccountMapper accountMapper) {
this.accountMapper = accountMapper;
}
@Test
public void testGetAccountById() {
System.out.println(accountMapper.getAccountById(4));
}
@Test
public void testGetAccountByName() {
System.out.println(accountMapper.getAccountByName("Jack"));
}
@Test
public void testGetAccountByNames() {
System.out.println(accountMapper.getAccountByNames("Jack"));
}
@Test
public void testAddAccount() {
Account account = new Account();
account.setUsername("Jack");
account.setPassword("abc");
accountMapper.addAccount(account);
}
@Test
public void testUpdateAccount() {
Account account = accountMapper.getAccountByNames("Jack");
System.out.println(account);
account.setUsername("Tom");
account.setPassword("123");
accountMapper.updateAccount(account);
System.out.println(accountMapper.getAccountById(account.getAccountId()));
}
@Test
public void testDeleteAccount() {
Account account = accountMapper.getAccountByNames("Tom");
accountMapper.deleteAccount(account.getAccountId());
System.out.println(accountMapper.getAccountByNames("Tom"));
}
@Test
public void testGetAllAccount() {
System.out.println(accountMapper.getAllAccount());
}
}
运行后,没有发现问题,就可以继续后续的编码工作了。
11.定义AccountDao接口
package com.springmvcmybatis.dao;
import java.util.List;
import org.springframework.dao.DataAccessException;
import com.springmvcmybatis.model.Account;
public interface AccountDao {
public boolean addAccount(Account account) throws DataAccessException;
public Account getAccountById(int id) throws DataAccessException;
public List<Account> getAllAccount() throws DataAccessException;
}
接口实现
package com.springmvcmybatis.dao.impl;
import java.util.List;
import javax.annotation.Resource;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Component;
import com.springmvcmybatis.dao.AccountDao;
import com.springmvcmybatis.mapper.AccountMapper;
import com.springmvcmybatis.model.Account;
@Component("accountDao")
public class AccountDaoImpl implements AccountDao {
private AccountMapper accountMapper;
public AccountMapper getAccountMapper() {
return accountMapper;
}
@Resource(name = "accountMapper")
public void setAccountMapper(AccountMapper accountMapper) {
this.accountMapper = accountMapper;
}
public boolean addAccount(Account account) throws DataAccessException {
boolean flag = false;
try {
accountMapper.addAccount(account);
flag = true;
} catch (DataAccessException e) {
flag = false;
throw e;
}
return flag;
}
public Account getAccountById(int id) throws DataAccessException {
Account account = null;
try {
account = (Account) accountMapper.getAccountById(id);
} catch (DataAccessException e) {
throw e;
}
return account;
}
public List<Account> getAllAccount() throws DataAccessException {
return accountMapper.getAllAccount();
}
}
12.服务层AccountService接口
package com.springmvcmybatis.service;
import java.util.List;
import org.springframework.dao.DataAccessException;
import com.springmvcmybatis.model.Account;
public interface AccountService {
public boolean addAccount(Account account) throws DataAccessException;
public Account getAccountById(int id) throws DataAccessException;
public List<Account> getAllAccount() throws DataAccessException;
}
接口实现
package com.springmvcmybatis.service.impl;
import java.util.List;
import javax.annotation.Resource;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Component;
import com.springmvcmybatis.dao.AccountDao;
import com.springmvcmybatis.exception.ServiceImplException;
import com.springmvcmybatis.model.Account;
import com.springmvcmybatis.service.AccountService;
@Component("accountService")
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
public AccountDao getAccountDao() {
return accountDao;
}
@Resource(name = "accountDao")
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
public boolean addAccount(Account account) throws DataAccessException {
if (account == null) {
throw new ServiceImplException(Account.class.getName() + "对象参数信息为Empty");
}
return accountDao.addAccount(account);
}
public Account getAccountById(int id) throws DataAccessException {
return accountDao.getAccountById(id);
}
public List<Account> getAllAccount() throws DataAccessException {
return accountDao.getAllAccount();
}
}
上面用到了一个自定义的异常信息,代码如下:
package com.springmvcmybatis.exception;
import org.springframework.dao.DataAccessException;
public class ServiceImplException extends DataAccessException {
private static final long serialVersionUID = 1L;
public ServiceImplException(String msg) {
super(msg);
}
public ServiceImplException(String msg, Throwable cause) {
super(msg, cause);
}
}
这里只是简单的继承,如果还有其他的异常业务或需求可以进行具体的实现
13.springMVC的控制器,AccountController代码如下:
package com.springmvcmybatis.controller;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import com.springmvcmybatis.model.Account;
import com.springmvcmybatis.service.AccountService;
@Controller
@RequestMapping("/account")
public class AccountController {
private AccountService accountService;
public AccountService getAccountService() {
return accountService;
}
@Resource(name = "accountService")
public void setAccountService(AccountService accountService) {
this.accountService = accountService;
}
@RequestMapping("/add")
public String addAccount(Account account) {
accountService.addAccount(account);
return "redirect:/account/list";
}
@RequestMapping("/get")
public String getAccountById(int id, Model model) {
model.addAttribute(accountService.getAccountById(id));
return "show";
}
@RequestMapping("/list")
public String getAllAccount(Model model) {
model.addAttribute("list", accountService.getAllAccount());
return "list";
}
@ExceptionHandler(Exception.class)
public String exception(Exception e, HttpServletRequest request) {
request.setAttribute("exception", e);
return "error";
}
}
14.基本页面代码
/jsp/index.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>mybatis-3.2.3整合spring-3.1.4</title>
</head>
<body>
<h3>mybatis-3.2.3整合spring-3.1.4</h3>
<a href="account/list">查询所有</a>
<br />
<a href="account/add?username=zhangsan&password=123132">添加</a>
<br />
<a href="account/get?id=2">查询</a>
<br />
</body>
</html>
/jsp/list.jsp
<%@ page language="java" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>all Account Result</title>
</head>
<body>
<c:forEach items="${list}" var="data">
id: ${data.accountId }---name: ${data.username }---password: ${data.password }<hr />
</c:forEach>
</body>
</html>
/jsp/show.jsp
<%@ page language="java" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>show Account</title>
</head>
<body>
${account }
<br />
${account.username }#${account.password }
</body>
</html>
/jsp/error.jsp
<%@ page language="java" import="java.io.PrintWriter" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>Error Page</title>
</head>
<body>
<H2>Exception: ${exception }</H2>
<a href="javascript:document.getElementById('show').style.display = 'block';void(0);">详细信息 </a>
<div id="show" style="color: red; display: none;">
<%
Exception e = (Exception) request.getAttribute("exception");
e.printStackTrace(new PrintWriter(out));
%>
</div>
</body>
</html>
15.以上就基本上完成了整个SpringMVC+MyBatis的整合了。如果想添加事务管理,得在applicationContext-beans.xml中加入如下配置(在service层进行事务管理,这里只配置了addAccount方法的事务管理,有人可能会问这个方法里面只做了一次数据库操作,加事务不是多此一举嘛,声明下,这里纯粹只是为了举例事务的管理配置,在实际项目上,具体的问题还得具体处理):
<!-- 配置事务管理器,注意这里的dataSource和SqlSessionFactoryBean的dataSource要一致,不然事务就没有作用了 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 定义建议,使用transactionManager事务管理者 -->
<tx:advice id="transactionAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="addAccount" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<aop:config>
<!-- 定义一个切入点 -->
<aop:pointcut id="businessService" expression="execution(public * com.springmvcmybatis.service..*.*(..))"/>
<aop:advisor pointcut-ref="businessService" advice-ref="transactionAdvice"/>
</aop:config>
同时还需要加入aopalliance.jar和aspectjweaver.jar两个jar包
16.为了查错方便,这里顺便配置下日志文件
在web.xml中添加log4j的配置,内容如下:
<!-- Log4j 配置 -->
<context-param>
<param-name>log4jRefreshInterval</param-name>
<param-value>60000</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
在src新建文件log4j.properties,内容如下:
log4j.rootLogger=DEBUG, stdout, fileout
#log4j.logger.test=info
#log4j.logger.org.apache.jasper = DEBUG
#log4j.logger.org.apache.catalina.startup.TldConfig = DEBUG
#log4j.logger.org.apache.catalina.session.ManagerBase = DEBUG
log4j.logger.com.fiscal = DEBUG
log4j.logger.com.system = DEBUG
log4j.logger.com.ibatis = DEBUG
log4j.logger.com.ibatis.common.jdbc.SimpleDataSource = DEBUG
log4j.logger.com.ibatis.common.jdbc.ScriptRunner = DEBUG
log4j.logger.com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate = DEBUG
log4j.logger.java.sql.Connection = DEBUG
log4j.logger.java.sql.Statement = DEBUG
log4j.logger.java.sql.PreparedStatement = DEBUG
log4j.logger.java.sql.ResultSet = DEBUG
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.fileout=org.apache.log4j.RollingFileAppender
log4j.appender.fileout.File=C:\\ibatis.log
log4j.appender.fileout.MaxFileSize=10000KB
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH:mm:ss} %m%n
log4j.appender.fileout.layout=org.apache.log4j.PatternLayout
log4j.appender.fileout.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH:mm:ss} %m%n
|
|
|