我们接着上一篇讲,上一篇,我们已经成功搭建了我们的POM聚合Maven工程,其中ssm-web-test为Maven Module,项目类型为war;我们也成功运行了项目,我们再次看一下整个项目的目录结构:
1、在 src/main/java下创建5个包
com.appleyk.controller(spring mvc 控制器类)
com.appleyk.pojo (对应数据结构的表,pojos对象,本项目来自于myb逆向工程)
com.appleyk.mapper(接口类和接口类映射的XML文件 本项目来自于mybatis逆向工程)
com.appleyk.service(我们自己定义的接口类)
com.appleyk.service.serviceImpl(自定义接口的 实现类)
2、在src/main/resources创建三个文件夹:
spring-mybatis(里面存放spring+mybatis的整合XML,spring-mybatis.xml)
properties(里面放属性文件,这里我们放mysql的数据连接配置,mysql.properties)
springMVC(放Spring MVC配置XML,Spring-MVC.xml)
我们先配置mysql.properties属性文件的内容:
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf-8
jdbc.username=root
jdbc.password=
我们接着整合Spring和Mybatis的XML文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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-4.0.xsd">
<!-- 加载配置文件 -->
<context:property-placeholder location="classpath:properties/*.properties" />
<!-- 数据库连接池 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
destroy-method="close">
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="driverClassName" value="${jdbc.driver}" />
<property name="maxActive" value="10" />
<property name="minIdle" value="5" />
</bean>
<!-- 让spring管理sqlsessionfactory 使用mybatis和spring整合包中的 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 数据库连接池 name 等于 上面的 bean id=‘dataSource’ -->
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 添加mapper spring bean 组件 后面可以根据spring 上下文对象 getBean获得这个mapper接口中的类实例 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.appleyk.mapper" />
</bean>
<!-- 事务管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 数据源 -->
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 包扫描器,扫描带@Service注解的类 -->
<context:component-scan base-package="com.appleyk.service"></context:component-scan>
</beans>
3、我们先不急着配置Spring MVC,看下目前我们的项目结构目录:
ok,接下来,我们进行验证,Spring+Mybatis框架是整合了,但是整合后的项目是否能够运行,运行的效果怎么样,目前我们还看不出来,因为,我们的web项目中暂且只是一些配置文件,并没有实质上的接口、类和对象。
我们测试,肯定是要数据的,数据从哪来呢?肯定是从我们的mysql数据库来,但是这个构建pojo和接口实现的过程,我们要自己来吗?
当然不是,这里,我们通过Mybatis的逆向工程帮助我们实现数据库记录的映射。
逆向工程一般都是写好的Java Project,引入几个必须的jar包,然后在配置一下generatorConfig.xml文件(配置是关键),最后执行一下GeneratorSqlmap类即可生成pojos和mapper,其他基本不用改什么,很方便:
4、我们在项目中,import导入一个已经存在的项目到当前的工作空间中:
导入成功后,我们的逆向工程项目generatorSqlmapCustom文件目录结构图如下:
最关键的一个是jar包,就那几个,一个是generatorConfig.xml,一个是默认包下的GeneratorSqlmap.java,还有一个日志单元的属性文件(基本上不用再自己写demo):
generatorConfig.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<context id="testTables" targetRuntime="MyBatis3">
<commentGenerator>
<!-- 是否去除自动生成的注释 true:是 : false:否 -->
<property name="suppressAllComments" value="true" />
</commentGenerator>
<!--数据库连接的信息:驱动类、连接地址、用户名、密码 -->
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/test" userId="root"
password="">
</jdbcConnection>
<!-- 默认false,把JDBC DECIMAL 和 NUMERIC 类型解析为 Integer,为 true时把JDBC DECIMAL 和
NUMERIC 类型解析为java.math.BigDecimal -->
<javaTypeResolver>
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<!-- targetProject:生成PO类的位置 -->
<javaModelGenerator targetPackage="com.appleyk.pojo"
targetProject=".\src">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<property name="enableSubPackages" value="false" />
<!-- 从数据库返回的值被清理前后的空格 -->
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!-- targetProject:mapper映射文件xml生成的位置 -->
<sqlMapGenerator targetPackage="com.appleyk.mapper"
targetProject=".\src">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<property name="enableSubPackages" value="false" />
</sqlMapGenerator>
<!-- targetPackage:mapper接口生成的位置 -->
<javaClientGenerator type="XMLMAPPER"
targetPackage="com.appleyk.mapper"
targetProject=".\src">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<property name="enableSubPackages" value="false" />
</javaClientGenerator>
<!-- 指定逆向数据库表 -->
<table schema="" tableName="user"></table>
</context>
</generatorConfiguration>
log4j.properties:
og4j.rootLogger=DEBUG, Console
#Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
log4j.logger.java.sql.ResultSet=INFO
log4j.logger.org.apache=INFO
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
GeneratorSqlmap.java:
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.exception.XMLParserException;
import org.mybatis.generator.internal.DefaultShellCallback;
public class GeneratorSqlmap {
public void generator() throws Exception{
List<String> warnings = new ArrayList<String>();
boolean overwrite = true;
File configFile = new File("generatorConfig.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config,
callback, warnings);
myBatisGenerator.generate(null);
}
public static void main(String[] args) throws Exception {
try {
GeneratorSqlmap generatorSqlmap = new GeneratorSqlmap();
generatorSqlmap.generator();
} catch (Exception e) {
e.printStackTrace();
}
}
}
.xml文件里面的这几个地方需要注意:
我们执行一下GeneratorSqlmap类的Main方法:
让我们的类根据xml配置文件去生成相应的包:
这时候我们在项目上刷新后发现多了两个包,正是我们xml里面配置,同时,也是我们ssm-web-test项目中需要的两个包:
至此,我们Mybatis逆向工程部分结束,下面我们继续。
5、将上述两个package,copy(覆盖)到ssm-web-test指定位置下:
展开com.appleyk.mapper包,如下:
定义一个接口:
UserService.java:
package com.appleyk.service;
import com.appleyk.pojo.User;
public interface UserService {
public User getUserById(int userID);
}
定义了接口,我们还差一个实现,因此,我们需要在Impl包下创建一个对应的实现接口的类:
UserServiceImpl.java:
package com.appleyk.service.Impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.appleyk.mapper.UserMapper;
import com.appleyk.pojo.User;
import com.appleyk.service.UserService;
/**
*
* @author appleyk
* 2017-8-31 13:45:00
*
@Service("userService")注解是告诉Spring,当Spring要创建UserServiceImpl的的实例时,
bean的名字必须叫做"userService",这样当Action需要使用UserServiceImpl的的实例时,
就可以由Spring创建好的"userService",然后注入给Action:
在Action只需要声明一个名字叫“userService”的变量来接收由Spring注入的"userService"即可,
[我们也可以用xml标准来配置bean]
具体代码如下:
// 注入userService
@Resource(name = "userService")
private UserService userService;
*/
@Service("userService")
public class UserServiceImpl implements UserService{
@Autowired //@Autowired 注释 :对类成员变量、方法及构造函数进行标注,完成自动装配的工作
private UserMapper uMapper = null ;
@Override
public User getUserById(int userID) {
User user = uMapper.selectByPrimaryKey(userID);//通过主键返回user
return user;
}
}
ok,到这里,我们基本上算是完成了service层和dao层的工作了,我们屡一下思路:
(1)定义一个接口,接口定义一个方法,方法根据userID返回一个User
(2)实现接口,利用注解,帮助我们完成工作(@service注解下面会说到,怎么用)
(3)如何使用?如何测试?
我们前面说过,我们所有的测试工作都放在src/test/java下面,因此,我们新建一个测试类,UserTest:
UserTest.java
import javax.annotation.Resource;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.appleyk.pojo.User;
import com.appleyk.service.UserService;
public class UserTest {
//1、 拿到spring上下文对象
private ApplicationContext aContext = null ;
@Resource(name = "userService")
private UserService userService ;
@Test
public void Test() throws Exception{
try{
aContext = new ClassPathXmlApplicationContext("classpath:spring-mybatis/spring-mybatis.xml");
userService = (UserService)aContext.getBean("userService");
User user = userService.getUserById(1);
System.out.println(user);
}
catch(Exception ex){
ex.printStackTrace();
}
}
}
有几个地方需要说明一下,如下图:
一切就绪后,我们现在只差运行这个test,看看是不是有数据返回,如果成功返回,证明我们的Spring+Mybatis整合成功,如果失败,说明,我们还有一些工作要做,我们右键run as JUnit Test,运行结果如下:
我们稍作调整,因为user是一个pojo对象,因此,里面包含了各个属性,使用如下:
我们也可采用下面的方式,直接获得UserMapper的代理实例,通过实例我们实现无条件查询,返回所有数据,因此,我们修改下UserTest类:
import java.util.List;
import javax.annotation.Resource;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.alibaba.druid.sql.ast.expr.SQLCaseExpr.Item;
import com.appleyk.mapper.UserMapper;
import com.appleyk.pojo.User;
import com.appleyk.pojo.UserExample;
import com.appleyk.service.UserService;
public class UserTest {
//1、 拿到spring上下文对象
private ApplicationContext aContext = null ;//1、 拿到spring上下文对象
//@Resource(name = "userService")
//private UserService userService ;
@Test
public void Test() throws Exception{
try{
aContext = new ClassPathXmlApplicationContext("classpath:spring-mybatis/spring-mybatis.xml");
// 第一种方法,使用java反射机制获得实现UserService接口的实例
// userService = (UserService)aContext.getBean("userService");
// User user = userService.getUserById(1);
// System.out.println(user.getId().toString()+','+user.getName()+','
// +user.getAge().toString()+','+user.getPassword());
//第二种方法,我们使用spring上下文获得UserMapper代理实例 实现无条件查询
UserMapper uMapper = null;
uMapper = aContext.getBean(UserMapper.class);//拿到uMapper的代理
UserExample example = new UserExample();
List<User> list = uMapper.selectByExample(example);
if(list!=null & list.size()>0){
int i = 0;
for(User item : list){
System.out.println(item.getName()+","+item.getEmail()+(i+1));
i++;
//输出表中所有结果,如果表里面的数据太大,我们还可以使用Mybatis的分页插件PageHelper
}
}
}
catch(Exception ex){
ex.printStackTrace();
}
}
}
我们执行一下我们的上述测试类如下:
我们对比一下我们的 mysql数据库里面的记录数:
到这里,关于Spring+Mybatis的整合就算完成了,回顾一下,我们简单的配置了一下我们的整合XML(spring 一部分,Mybatis一部分),使用了Mybatis逆向工程生成pojos和mapper,我们自己定义了接口和接口的实现类,实现类中我们使用了spring注解方式,事实,证明这种注解方式很方便,因为,我们在JUnit Test中测试了一下,而且成功返回了我们的预期,接下来,我们会讲spring MVC框架的配置,我们发现,到目前为止,我们整个项目的web.xml里面,并没有写任何内容:
我们也依然可以在Tomcat上运行我们现有的框架:
小插曲:
如果出现上述错误,请将你当前项目引用Java环境 从JRE改成JDK:
然后,我们重新运行下整个项目:
浏览器,输入http://localhost:8080:
折腾一圈,我们又绕回来了,我们的项目,没有被折腾坏,O(∩_∩)O
这个时候,如果还要执行一下JUnit测试会是什么样的效果呢?这里,我要讲一个很有意思的地方:
我们测试之后,紧接着运行了Maven Clean重新运行了项目,我们返回来再来看一下,我们的测试demo是否还起作用:
原因就在于,我们重新运行整个项目的时候,Maven Clean会将编译好的class文件清理掉,但是maven会自动帮我们再编译一遍,所以项目又可以正常运行,也许Maven不顾及放在test下面的class文件,觉得它们是测试编译的,所以就不上心,因此,重启Maven项目的时候,我们测试时候编译的好的class不仅已经被清除掉了,而且也不会自动再次编译,因此最终,我们再次运行JUnit的时候,提示我们找不到UserTest class 。
下面是正常情况下项目中编译好的UserTest.class:
我们看一下,重新运行项目后的ssm-web-test/target下面少了哪些文件夹:
怎么办,我们的项目是运行起来了,可我们还想测试啊?
这里提供一个解决方案,将整个project clean掉,然后我们观察效果:
点击ok后,我们观察一下ssm-web-test\target下面的文件夹,有哪些文件夹新增了:
此时,我们的控制台输出还停留在:
既然我们找回了UserTest.class(虽然每次运行测试的时候,都要project clean一次,有点麻烦,不过,测试本来就是服务的,存在感比较低),我们更加有底气了,so,让我们再来一次Test吧:
由于篇幅限制,本篇结束!下一篇我们继续,该讲我们 Spring MVC的配置了。