14、SSM框架整合案例
SSM框架整合
1、创建Maven项目,导入相关依赖
1.1、导包
-
Spring和SpringMVC的坐标
-
<!-- spring坐标 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.3.16</version> </dependency> <!-- springmvc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.3.16</version> </dependency>
-
-
Mysql,c3p0,jdbc模板
-
<!-- mysql配置 --> <!-- 导入mysql依赖环境 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.38</version> </dependency> <!-- 引入c3p0数据源 --> <dependency> <groupId>c3p0</groupId> <artifactId>c3p0</artifactId> <version>0.9.1.2</version> </dependency> <!-- jdbc工具JdbcTemplate --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.3.16</version> </dependency>
-
-
Mybatis坐标和Spring整合Mybatis框架的坐标
-
<!-- mybatis依赖 --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.9</version> </dependency> <!-- spring整合Mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.1</version> </dependency>
-
-
AOP事务控制
-
<!-- 事物控制 --> <!-- AOP的第三方包aspectjweaver --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.9</version> </dependency> <!-- 事物控制 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.3.16</version> </dependency>
-
-
Servlet和JSP坐标
-
<!-- Servlet --> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> </dependency> <!-- JSP --> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.0</version> </dependency>
-
-
JSTL标签和标签库
-
<!-- jstl标签库和taglibs标签的依赖来使用jstl --> <dependency> <groupId>jstl</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>taglibs</groupId> <artifactId>standard</artifactId> <version>1.1.2</version> </dependency>
-
-
JSON数据礼包
-
<!-- JSON数据类型 --> <dependency> <!-- 这个是最核心的 --> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.11.4</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.11.4</version> </dependency> <!-- 注解相关的 --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.11.4</version> </dependency>
-
-
日志文件和Junit和test
-
<!-- 打印日志文件 --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.12</version> </dependency> <!-- 单元测试 --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13.2</version> <scope>test</scope> </dependency> <!-- spring集成的单元测试类 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.3.16</version> </dependency>
-
1.2、创建三层架构

1.3、实体类User参数

2、配置resources目录
2.1、Spring核心配置文件(applicationContext.xml)
两步,引入context命名空间;对包结构进行组件扫描
-
引入context命名空间
-

-
进行组件扫描
-
<!-- 引入context的命名空间进行我们的包扫描 --> <context:component-scan base-package="com.waves" > <!-- 不扫描Controller层的组件,让springmvc配置文件去扫描 --> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan>
-
2.2、SpringMVC核心配置文件
导入命名空间,context,mvc
-
导入context和mvc的命名空间
-

-
包扫描,扫描Controller层的组件
-
<!-- 引入context的命名空间进行我们的包扫描 --> <context:component-scan base-package="com.waves.controller" />
-
-
引入SpringMVC的注解开发
-
<!-- 注解开发,JSON自动转换 --> <mvc:annotation-driven/>
-
-
配置视图解析器
-
内部进行前后缀的设计
-
<!-- 配置视图解析器 --> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/jsp/"></property> <property name="suffix" value=".jsp"></property> </bean>
-
-
静态资源的扫描
-
<!-- 静态资源全扫描 --> <mvc:default-servlet-handler/>
-
2.3、XML文件配置SpringMVC前端控制器和Spring的监听器
1、Spring监听器的配置
-
指定Spirng核心配置文件的位置
-
<!-- 指定spring配置文件位置 --> <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、SpringMVC前端控制器
-
配置DispatcherServlet
-
<!-- 配置SpringMVC的前端控制器 --> <servlet> <servlet-name>DispatcherServlet</servlet-name> <servletclass> org.springframework.web.servlet.DispatcherServlet </servlet-class> <!--当这个Servlet创建的时候,告诉他配置文件在哪里--> <!-- 初始化Servlet --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-mvc.xml</param-value> </init-param> <!-- 当程序运行的时候就创建我们的前端控制器 --> <load-on-startup>1</load-on-startup> </servlet>
-
-
配置缺省目录
-
/的目的是所有的请求都通过SpringMVC的前端控制器
-
<!-- 配置映射地址 --> <servlet-mapping> <!-- 缺省地址 --> <servlet-name>DispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
-
-
配置过滤器Filter,解决UTF-8乱码的问题
-
<!-- 配置全局过滤器识别UTF-8 --> <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>
-
2.4、Mybatis核心配置文件
configuration开始配置;properties引入外部资源文件;typeAliases为实体类起别名,environments,配置数据库环境;transactionManager:事物管理对象;datasource:数据库信息
-
引入外部资源文件--jdbc.properties
-
<!-- 引入外部的properties文件 --> <properties resource="jdbc.properties"/>
-
-
为创建的实体类起别名
-
简便写法,使用package标签,这个标签只需要写根路径,该路径下的所有实体类都会自动起别名,别名为User or user(大写或小写都可以使用)
-
<!-- 为创建的实体类其别名 --> <typeAliases> <package name="com.waves.pojo"/> </typeAliases>
-
-
配置数据库环境
-
事物管理,数据池,连接池各参数
-
<!-- 数据库环境的配置 --> <environments default="development"><!-- 默认使用第一个配置方式 --> <!-- 配置Mysql连接池信息 --> <environment id="development"> <!-- 事务管理器 --> <transactionManager type="JDBC"></transactionManager> <!-- 数据池 --> <dataSource type="POOLED"> <!-- 配置连接池各参数 --> <property name="driver" value="${jdbc.driver}" /> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </dataSource> </environment>
-
-
配置映射关系
-
该包下的所有接口均注册为映射器
-
<!-- 配置映射关系 --> <mappers> <package name="com.waves.mapper"></package> </mappers>
-
3、三层架构详细配置
3.1、Controller
1、注解设置为控制层,是一个组件;设置顶级目录user
@Controller
// 访问一级目录
@RequestMapping("/user")
public class UserController {
}
2、注入业务层对象(调用业务层方法)
@Autowired
//业务层对象注入
private UserService userService;
3、设置第一个资源路径--test
-
设置我们的第一个资源路径test
-
@RequestMapping("/test")
-
-
是否进行页面跳转?不进行--@ResponseBody
-
// 不进行视图跳转 @ResponseBody
-
-
编写方法
-
public String test(){ return "good!"; }
-
-
开始测试
-
3.2、Service
1、设置业务层的接口--UserService

2、设置接口内部方法的实现--UserServiceImpl
-
将其注册为组件
-
实现内部方法就不写了,这是个大概,会在功能中补上
3.3、Dao--Mapper--Utils
底层数据是使用的Myabtis,对数据库内容进行查询,但是我们可以使用工具类来获取Myabtis的SqlSessionFactory工厂对象
3.4、Utils--获取Mybatis工厂对象
public class SqlSessionFactoryUtil {
// 静态变量,提升作用域
private static SqlSessionFactory sqlSessionFactory;
// 设置静态代码块,静态代码块会随着类的加载执行一次
// 且只会执行一次,第一次执行的时候加载我们的静内存
static{
try {
// 扫描核心配置文件得到输出流
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
// 获取Mybatis的会话工厂对象
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
// 设置一个静态方法,该方法返回一个SqlSessionFactory工厂对象
public static SqlSessionFactory getSqlSessionFactoryutils(){
return sqlSessionFactory;
}
}
4、功能实现
4.1、登录功能
我们从底层业务开始编写,分析功能
1、Mapper
-
分析前端传递过来的数据是什么;User对象还是字符串?
-
设计登录这个功能,接口的方法
-
根据需求编写登陆功能所需要的SQL语句
-
这个功能比较简单我们就不使用配置文件的方式了
-
@Select("select * from student where username = " + "#{username} and password=#{password}")
-
2、Service
-
被Controller调用,其内部执行Mapper接口的调用
-
前端是什么功能需要我这个业务的调用?--规划我们的业务层的接口--UserService的方法
-

-
我们现在是登录功能,所以我们开始编写登录功能的业务处理
-
使用工具类获取到我们的工厂对象
-

-
通过会话工厂得到会话对象SqlSession
-
//2.获取SqlSession的对象,用它来执行sql SqlSession sqlSession = sqlSessionFactory.openSession();
-
-
通过会话获取Mapper接口的代理对象--getMapper()
-
//3.获取Mapper接口的代理对象 UserMapper usermapper = sqlSession.getMapper(UserMapper.class);
-
-
使用代理对象去执行需要执行的方法-Login
-
User login = usermapper.Login(user); return login;
-
判断部分让控制层判断好了,业务层这边暂时不处理
3、Controller
首先,客户端请求我这个登陆功能的资源路径下的方法--Login
-
设置访问路径--二级目录
-
// 登录操作 @RequestMapping("/login")
-
-
不进行页面跳转
-
@ResponseBody
-
-
参数获取,我要使用什么类型来接前端的参数--User对象,因为我实体类的属性名和请求发送过来的属性名一致,可以直接进行注入
-
其次,调用咱们业务层的Login方法,获取到返回的用户数据,然后进行一个判断
-
public String Login(User user){ //System.out.println("获取到的账号:"+user.getUsername()+"\n"+"获取到的密码是:"+user.getPassword()); User login = userService.Login(user); if(login==null){ return "Login Error!"; } return "Success!"; }
-
4、测试
-
我的登录页面一开始
-
查看结果
-
演示正确信息
4.2、注册功能的实现
注册的数据是用户姓名,登陆账号,密码
1、Mapper
业务层传递过来的参数是什么?User对象
-
判断注册的用户名(username)是否存在(判断)
-

-

-
编写UserMapper.xml配置文件
-
<!-- 注册用户 --> <insert id="insertUser" parameterType="User"> insert into student values( #{id},#{name},#{username},#{password}, #{sex},#{college},#{dormitory} ) </insert>
-
2、Service层设计
需要的参数为控制层传递过来的User对象
-
注册用户:返回值为int类型,为影响的行数
-

-
实现类实现该方法
-
首先获取工厂对象,借由工厂对象得到代理对象mapper
-
// 使用工具类获得工厂的会话对象 SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactoryutils(); //2.获取SqlSession的对象,用它来执行sql SqlSession sqlSession = sqlSessionFactory.openSession(true); //3.获取Mapper接口的代理对象 UserMapper usermapper = sqlSession.getMapper(UserMapper.class);
-
-
使用mapper代理对象中的方法
- 首先查询用户名是否存在
- 不存在可以继续注册,否则返回0(注册失败)
-
补全业务方法
-
// 如果不为空,说明用户存在 if(user1!=null){ // 注册失败 return 0; } // 为空,说明不存在,可以继续注册 Integer integer = usermapper.insertUser(user); // 注册中出现异常 if(integer!=1){ // 注册失败 return 0; } // 注册成功! return 1;
-
3、Controller
接受前段传递过来的参数进行封装,封装到User对象中
-
需要返回视图对象--!=@ResponseBody不需要
-
设置二级目录访问路径
-
注册用户
-
// 注册新用户 @RequestMapping("/register")
-
-
设置方法,该方法需要返回一个视图对象
-
// 注册新用户 @RequestMapping("/register") public ModelAndView register(User user){ // 调用业务层的方法 Integer register = userService.Register(user); ModelAndView model = new ModelAndView(); // 返回视图对象 return model; }
-
-
调用业务层对象,进行用户注册,并进行判断
-
注册成功,转发到登录页面
-
注册失败,转发到失败页面打印失败信息
-
@RequestMapping("/register") public ModelAndView register(User user){ // 调用业务层的方法 Integer register = userService.Register(user); // 创建视图对象 ModelAndView model = new ModelAndView(); // 是否注册成功? if(register==1){ // 转发到登录页面 model.setViewName("login"); // 返回视图对象 return model; } // 注册失败,设置失败信息 model.addObject("failed","Registration failed!"); // 转发到失败页面 model.setViewName("registerError"); // 返回视图对象 return model; }
-
4、测试
-
没有账号?点击注册!
-
先看看注册失败的
-
那么正式注册
-
-
登录我们刚刚创建的用户(username=000000,psw=000000)
-

-

-
完美!
4.3、展示全部学生(修改原登录成功,我们进行重定向到其他页面)
重新设置我们的登录需求
1、Mapper
-
定义UserMapper接口的方法--查询全部
-

-
在配置文件中规划SQL语句
-

-
测试
-
@Test public void selectAll(){ List<User> users = mapper.selectAll(); for (User user : users) { System.out.println(user); } }
-
-
结果
2、Serivce
调用Mapper的查询全部方法
-
定义接口中的查询全部学生的方法
-

-
实现接口中的方法
-
查询成功返回一坨用户数据
-
@Override public List<User> findAll() { SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactoryutils(); //2.获取SqlSession的对象,用它来执行sql SqlSession sqlSession = sqlSessionFactory.openSession(); //3.获取Mapper接口的代理对象 UserMapper usermapper = sqlSession.getMapper(UserMapper.class); List<User> users = usermapper.selectAll(); return users; }
-
3、Controller
对原先的登录方法进行修改,登录成功与否都返回视图
-
方法体设计
-
返回视图对象,页面跳转
-
// 新登录用户--跳转到主页面 @RequestMapping("/login") public ModelAndView Login(User user){ // 创建视图对象 ModelAndView model = new ModelAndView(); renturn model; }
-
-
调用Service层的登录方法,返回一条用户数据
-
如果用户为空,设置模型和视图的数据
-
// 调用业务层的方法 User login = userService.Login(user); // 用户为空 if(login==null){ System.out.println("登录失败!"); // 设置视图跳转 model.setViewName("registerError"); // 设置错误信息 model.addObject("LoginFailed","登陆失败!"); return model; }
-
-
非空,则进行视图跳转
-
System.out.println("登录成功!"); // 调用查询全部的业务层方法 List<User> users = userService.findAll(); // 设置视图跳转 model.setViewName("DMT2"); // 将用户数据存储在模型当中 model.addObject("users",users); // 将用户名存储在模型中 model.addObject("username",user.getUsername()); // 页面跳转 return model;
-
-
JSP页面设计
-
台头获取模型当中设置的用户名
-

-
JSTL标签对用户数据进行遍历
-
<%-- 书写c:foreach表达式 --%> <c:forEach items="${users}" var="user"> <tr> <td>${user.getId()}</td> <td>${user.getName()}</td> <td>${user.getUsername()}</td> <td>${user.getPassword()}</td> <td>${user.getSex()}</td> <td>${user.getCollege()}</td> <td>${user.getDormitory()}</td> <td><a>修改</a> <a>删除</a></td> </tr> </c:forEach>
-
-
完成
4、测试
-
先测试登录失败的
-
页面效果
-
控制台效果
-
测试登录成功的
-

5、Spring整合Mybatis
将工厂交给Spring容器进行管理,然后我们直接从容器中获取Mapper的代理对象即可;将事物的提交和资源释放交给Spring容器进行声明式事物控制
5.1、图解

5.2、思考
我能不能将工厂的代理对象Mapper注入到容器当中让Spring帮我进行管理,然后我再从容器当中获取到这个Mapper代理对象,注入到我的Service层当中(注入到UserService中)?
5.3、在Spring配置文件当中手动配置第三方的Bean
哪些Bean?我们现在要注入SqlSessionFactory的工厂对象,Mybatis核心配置文件中需要配什么东西?数据源嘛,数据源是不是要导入外部的配置文件?(解耦合)我们先配置这个
1、配置数据源dataSource
-
导入外部的jdbc配置文件
-
<!-- 导入JDBC的配置文件 --> <context:property-placeholder location="jdbc.properties"/>
-
-
配置数据源
-
我们使用的是c3p0的数据源-ComboPooledDataSource
-
<!-- 配置数据源信息 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <!-- 内部就配置我们数据源的各属性 --> <!-- 驱动 --> <property name="driverClass" value="${jdbc.driver}"></property> <!-- 地址 --> <property name="jdbcUrl" value="${jdbc.url}"></property> <!-- 数据库账号 --> <property name="user" value="${jdbc.user}"></property> <!-- 密码 --> <property name="password" value="${jdbc.password}"></property> </bean>
-
2、配置Spring整合Mybatis
我们现在是不是需要将工厂对象注入到Spring容器当中?但是SqlSessionFactory是个接口啊,那该怎么办?

在我们的pom.xml文件中,我们导入了一个这个包
<!-- spring整合Mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.1</version>
</dependency>
2.1、这个包当中有个SqlSessionFactory的工厂的实现类,这个实现类就是专门返回一个工厂对象的,我们将这个实现类注入到Spring当中即可

这个就是我们工厂类的实现类,我们注入他
<!-- 注入Spring整合Mybatis的工厂类实现 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 它内部需要什么? -->
<property name=""></property>
</bean>
2.2、它内部需要什么?
他在帮我们进行SqlSession会话对象获取的时候,他是不是要借助于操作数据库?是不是他需要底层通过Connection?而Connection源于谁?是不是源于我们的数据源配置(datasource)?所以我们需要先注入datasource
配置好数据源以后,工厂对象是不是要加载我们mybatis的核心配置文件的信息?他如何才能知道?它内部有个属性--configLocation属性,我们对其进行值的设置
<!-- 注入Spring整合Mybatis的工厂类实现 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 它内部需要什么? -->
<!-- 数据源 -->
<property name="dataSource" ref="dataSource"></property>
<!-- 工厂内部也是需要读取配置文件的,我们把配置文件的位置告诉他 -->
<property name="configLocation" value="mybatis-config.xml"></property>
<!-- -->
</bean>
2.3、Bean(MapperScannerConfigurer)扫描mapper所在的包,为mapper创建实现类(代理对象)
我们核心配置文件的mappers属性也可以让他帮我们配置
<!-- 扫描mapper所在的包,为其创建实现类 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.waves.mapper"></property>
</bean>
这个实际上是什么意思?我们实用工厂的对象的步骤是什么?
- 通过工厂对象,读取核心配置文件
- 读取完核心配置文件得到我们的会话对象
- 借助这个会话对象我们得到Mapper的代理对象,而这个代理对象,就是我们最后一步扫描mapper所在包的步骤
2.4、扫描完包之后会帮我们创建好Mapper的实现类,直接注入即可
3、测试遇到的问题
Method com/mchange/v2/c3p0/impl/NewProxyResultSet.isClosed()Z is abstract
这个是因为版本都是最新的,但是这个c3p0的数据源是旧版本,所以我们要把它换成新的版本

4、测试方法
// 指定Spring作为测试的内核帮我进行测试
@RunWith(SpringJUnit4ClassRunner.class)
// 让其帮我读取配置文件,创建上下文的对象,就是加载配置文件
@ContextConfiguration("classpath:applicationContext.xml")
public class testSpringMybatis {
// 注入Mapper
@Autowired
private UserMapper userMapper;
// 测试数据,查询全部
@Test
public void SpringMyabtis(){
List<User> users = userMapper.selectAll();
for (User user : users) {
System.out.println(user);
}
}
}
其实当注入Mapper的时候已经可以看到蓝色的小鸟了























浙公网安备 33010602011771号