目录
- 回顾
- 使用Servlet MVC Mybatis Jsp完成用户登录
- Service层使用Spring获取Mapper对象
- 问题:
- 解决:
- 实现:
- Controller层使用Spring解耦service层
- 问题:
- 解决:
- 实现:
- 分析java ee web 项目整合的mybatis
- 问题
- spring整合mybatis
- SpringIOC的创建对象的单例多例模式和自动注入
- SpringIOC创建对象的单例和多例模式
- 问题:
- 解决:
- 实现:
- 单例模式(默认):
- 多例模式:
- 使用:
- SpringIOC的自动注入
- 问题:
- 解决:
- 实现:
回顾
我们的java ee web项目,使用mybatis操作数据库,是写了一个mybatis.xml,里面是数据源。之后写了一个公共类,这个公共类就是利用这个xml创建对象,以后在业务层就利用这个公共类,创建mapper层的对象,然后调用mapper层对象里面的方法,实现对数据库的操作
使用Servlet MVC Mybatis Jsp完成用户登录
原生的方法实现用户的登录,步骤为:
①在mysql中创建t_user用户信息表(id,name,pwd). ②使用idea创建一个新的web项目,项目名为 01-springioc-mybatis-login ③在web项目中导入相关jar包(SpringIOC的jar Mybatis的 jar mysql的jar) ④在web项目中创建login.jsp登录页面,并完善发送登录请求 ⑤在web项目中创建UserServlet,并完善代码处理登录请求 ⑥在web项目中创建UserService业务,并完善代码处理登录业务 ⑦在web项目中创建UserMapper,并完善代码根据用户名和密码 查询用户信息
我们写完mybatis.xml ,直接在业务层创建mapper层的对象,不需要使用工具类了
Service层使用Spring获取Mapper对象
问题:
目前我们开发功能的流程中,在service层会手动创建SQLSession对象,并使用SQLSession对象获取Mapper接口的实例化对象,但是我们真正使用的是Mapper接口的对象,目前的代码编写方式极大的影响了开发效率,而且mybatis层和service 层之间的耦合性非常高
解决:
使用SpringIOC技术实现service层和mybatis层的解耦:说白了就是让Spring容器帮我们获取Mapper层接口的实例化 对象,我们直接从Spring容器中获取使用即可.
===================================== 以前我们还要写一个mybatis.xml,里面写数据源,然后在service层创建mapper层的对象。现在我们不写mybatis,xml了,不在这个里面写数据源了,我们在applicationcontext.xml里面直接写数据源,写好数据源之后我们直接在这个里面创建对象,以后哪个地方要mapper层的对象,直接从这个容器里面拿就可以了。
实现:
①导入SpringIOC的jar包 ②在src下创建并配置Spring的配置文件 配置DataSource数据源的bean 配置SQLSessionFactory的工厂bean(DataSource的bean) 配置mapper扫描bean对象(SQLSessionFactory对象,扫 描路径) ③创建Spring容器对象,并获取Mapper接口的实例化对象完成数据库操作
Controller层使用Spring解耦service层
问题:
在业务层使用Spring容器对象获取Mapper接口实例化对象后实现了 service层和mybatis层的解耦,但是在controller层我们依然在Servlet 中直接创建Service对象,耦合性过高.
解决:
将service对象配置为bean对象,Servlet中从Spring容器中 获取Service对象,完成功能开发.
实现:
①在applicationcontext.xml文件中配置service的bean ②在servlet中的service方法中创建Spring容器对象 ③在servlet中的service方法中从Spring容器中获取 service对象 ④使用service对象完成功能处理
分析java ee web 项目整合的mybatis
获取到mapper层对象,需要sqlsession对象,创建sqlsession对象需要sqlsessionFactory 对象,创建sqlsessionFactory 对象需要sqlsessionFactory Builder()里面的方法build()
以上的这些事必须的
之前以上的这些对象都是我们再service层创建,或者写一个公共类,再service层进行调用。代码如下
问题
每次都要写sqlsession对象创建之前的那些代码,代码冗余。我们可以把那些交给spring进行创建,并且放到容器里面。mapper层对象,service层对象也可以放到容器里面,以后直接拿就可以了
spring整合mybatis
①导入的jar包:
②在src下创建并配置applicationcontext.xml文件
也就是不用写mybatis.xml了,直接在applicationcontext.xml文件里面写数据源,并且利用这个数据源创建mapper对象,service层对象
代码语言:javascript复制<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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.xsd">
<!--配置DataSource的bean对象:存储数据库连接参数-->
<bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="url" value="jdbc:mysql://localhost:3306/spring4?characterEncoding=utf8"></property>
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="username" value="root"></property>
<property name="password" value="123456"></property>
</bean>
<!--配置SQLSessionFactory的bean对象:生产SQLSession-->
<bean id="factory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="datasource"></property>
</bean>
<!--配置Mapper扫描的bean对象:使用SQLSession扫描mapper包获取Mapper接口的实例化对象-->
<bean id="a" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactory" ref="factory"></property>
<property name="basePackage" value="com.mapper"></property>
</bean>
<!--配置service对象-->
<bean id="us" class="com.service.UserServiceImpl">
<property name="um" ref="userMapper"></property>
</bean>
</beans>
③在web.xml文件中配置Spring容器对象的配置文件路径 因为项目开始,先走web.xml,所以得让项目找到我们写 的applicationcontext.xml文件,所以需要在web.xml里面进行配置
代码语言:javascript复制<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<!--配置全局参数:被项目中所有servlet共享-->
<context-param>
<param-name>contextConfigLocation</param-name><!--键名-->
<param-value>classpath:applicationcontext.xml</param-value><!--值-->
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
</web-app>
④在Servlet的init方法中完成初始化资源的加载(从Spring容器对象中获取业务层对象)
代码语言:javascript复制package com.controller;
import com.pojo.User;
import com.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.async.WebAsyncUtils;
import org.springframework.web.context.support.WebApplicationContextUtils;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author wuyw2020
* @date 2020/1/8 20:55
*/
@WebServlet(value = "/user", loadOnStartup = 1)
public class UserServlet extends HttpServlet {
UserService userService;
//在初始化方法中完成Spring容器资源的加载
@Override
public void init() throws ServletException {
//获取spring容器对象
ApplicationContext ac = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
//获取业务层对象
userService = (UserService) ac.getBean("us");
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
resp.setCharacterEncoding("utf-8");
String uname = req.getParameter("uname");
String pwd = req.getParameter("pwd");
//处理请求
//调用业务层方法
User user = userService.userLoginService(uname, pwd);
//响应结果
//直接响应
if (user != null) {
resp.getWriter().write("登录成功");
} else {
resp.getWriter().write("登录失败");
}
}
}
⑤在业务层中声明mapper层的属性,并声明对应的get/set方法
代码语言:javascript复制package com.service;
import com.mapper.UserMapper;
import com.pojo.User;
/**
* @author wuyw2020
* @date 2020/1/8 20:48
*/
public class UserServiceImpl implements UserService{
private UserMapper um;//定义mapper层的属性
//定义mapper层的get set 方法
public UserMapper getUm() {
return um;
}
public void setUm(UserMapper um) {
this.um = um;
}
@Override
public User userLoginService(String uname, String pwd) {
User user = um.userLoginMapper(uname, pwd);
return user;
}
}
⑥正常完成功能开发即可
SpringIOC的创建对象的单例多例模式和自动注入
SpringIOC创建对象的单例和多例模式
问题:
Spring容器对象根据配置文件创建对象的时机默认发生在Spring容器对象在被创建的时候,也就是说,我们一旦获取到Spring容器对象,意味着可以直接获取Spring容器中的对象使用了.
那么,如果我对同一个bean对象,连续获取N次,获取到的是不是同一个对象呢?因为spring容器对象底层使用的是map集合存储的bean对象,对map集合按照同一个键名获取数据,获取的是同一个,也就说按照同一个键名从Spring容器中获取的都是同一个对象,
那么如果我们希望相同的键名获取的对象每次都不一样,怎么实现?
解决:
不要在Spring容器对象创建的时候,就完成对象的初始化创建,而是变为,从Spring容器中获取的时候才创建,每次获取都重新创建.
实现:
Spring容器的单例和多例模式创建对象.
单例模式(默认):
设置了单例模式的bean,会在Spring容器对象被创建的时候 就完成初始化创建,无论获取多少次都是同一个对象.
多例模式:
设置了多例模式的bean,在Spring容器对象被创建的时候不会被初 始化创建,每次获取的时候都会重新创建,每次获取的对象都不相同.
使用:
applicationcontext.xml:
代码语言:javascript复制<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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.xsd">
<!--
SpringIOC设置对象的单例模式和多例模式创建对象
单例模式:默认模式,在bean标签上使用scope属性,默认值为singleton
多例模式:在bean标签上使用scope属性设置,值为prototype
-->
<bean id="stu" class="com.pojo.Student" scope="singleton"></bean>
<bean id="tea" class="com.pojo.Teacher" scope="prototype"></bean>
</beans>
代码语言:javascript复制TestIocModel
package com.controller;
import com.pojo.User;
import com.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.async.WebAsyncUtils;
import org.springframework.web.context.support.WebApplicationContextUtils;
import javax.rmi.CORBA.StubDelegate;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author wuyw2020
* @date 2020/1/8 20:55
*/
@WebServlet(value = "/user", loadOnStartup = 1)
public class UserServlet extends HttpServlet {
public static void main(String[] args) {
//获取Spring容器对象
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationcontext.xml");
Student stu =(Student) ac.getBean("stu");
Student stu2 =(Student) ac.getBean("stu");
Teacher teacher = (Teacher) ac.getBean("stu");
Teacher teacher2 = (Teacher) ac.getBean("stu");
System.out.println("学生:" (stu==stu2));
System.out.println("教室:" (teacher==teacher2));
}
}
SpringIOC的自动注入
问题:
在学习了SpringIOC的DI依赖注入后,我们可以根据对象之间的依赖关系的 责任链,让Spring容器对象帮我们创建有一个组装好的对象,比如A中有B,B 中有C,C中有D.将A,B ,C,D都创建为Bean对象,然后使用ref属性告诉Spring 对象之间的依赖关系的组装规则,假如依赖责任链特别长,使用ref注入就会很 麻烦.怎么办?
解决:
不要声明ref属性来指明依赖关系的注入,只需要告诉Spring容器对象依赖关 系的注入规则,Spring容器对象自动根据规则完成依赖关系的注入.
实现:
①根据bean的ID和属性名一致的规则 ②根据bean的类型和属性的类型一致的规则 ③根据构造器形参的类型和bean的类型一致的规则 ④不能使用自动注入,只能手动声明 ⑤使用默认规则
代码语言:javascript复制<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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.xsd"
default-autowire="byName"><!--设置自动注入-->
<!--
自动注入:
在标签上使用autowire属性设置自动注入规则.该属性声明在要注入资源的bean标签上,比如:学生的bean
autowire属性的值:
byName:按照属性名和某个bean的id相同的规则自动注入
byType:按照属性的类型和某个bean的类型相同的规则自动注入.
注意:同类型的bean只能有一个,否则报错.
constructor:
必须声明对应的构造器,根据构造器形参的类型和某个bean的类型相同的规则自动注入.
no:不使用自动注入,必须使用ref手动注入.
default:使用默认注入规则.默认值.
注意:
可以在beans顶层元标记中使用属性default-autowire声明全局自动注入规则.
-->
<bean id="stu" class="com.pojo.Student" autowire="byName">
<!--用构造器的方法,此处要创建一个只有Teacher一个参数的构造器-->
<!--<constructor-arg index="0" type="com.Teacher" ref="tea"></constructor-arg>-->
<property name="sid" value="1"></property>
<property name="sname" value="张三"></property>
</bean>
<bean id="teacher" class="com.Teacher">
<property name="tname" value="liu"></property>
<property name="tid" value="1"></property>
</bean>
</beans>