❤️🔥B站学习视频:https://www.bilibili.com/video/BV1WZ4y1P7Bp
本人记录学习笔记,谢谢各位关注❤️🔥

轻量级开发中,常对Web分为以下几层:
| 包名 | 名称 | 作用 |
|---|---|---|
| dao | 数据访问层(创建接口) | 封装对数据库的操作,与数据库有关的操作都存放在这个包下面 |
| Entity | 实例类 | 一般与数据库的表相对应,封装dao层取出来的数据为一个对象 |
| Service | 业务逻辑(接口) | 写业务逻辑的 |
| Service-impl | 业务逻辑的实现 | 实现业务的接口,事务控制一般都写在这里 |
| Controller | MVC控制器 | SpringMVC就是在这里发挥作用的 |
| Mapper | 数据库具体操作 | 包含xxxMapper.xml 和xxxMapper.java二者互相对应 |
说明:
other 包:
| 文件名 | 文件名解释 | 内容(说明) |
|---|---|---|
| spring-dao.xml | spring数据链接配置 | 配置数据连接池、sqlSessionFactory对象、扫描dao接口 |
| spring-service.xml | spring服务配置 | 扫描service包下注解、配置事务管理器、基于注解的事务 |
| spring-mvc.xml | Spring MVC配置 | 开启框架注解模式、处理静态资源、配置jsp、扫描controller |
| jdbc.proties | 数据库链接参数 | 配置jdbc、数据库URL、用户名、密码等 |
| mybatis-config.xml | myBatis配置文件 | 开启自增主键、使用列别名、驼峰转换 |
| log4j.properties | web日志输出参数 | web输出参数 |
| application.xml | Spring与Mybatis整合配置 | 数据库连接池、sqlSeesionFactory对象、扫描dao接口 |
| webapp | 前端与配置文件 | |
| web.xml | 配置Spring需要加载的配置文件、启用disapatcher转发处理所有的请求、指定编码格式 |
导入 Spring 开发的基本包坐标
编写 Dao 接口和实现类
创建 Spring 核心配置文件 xml
在 Spring 配置文件中配置 UserDaoImpl
使用 Spring 的 API 获得 Bean 实例
导入坐标
编辑Bean
创建applicationContext.xml
获得Bean实例
Bean的实例化时机:当Spring核心文件被加载时,实例化配置的Bean实例
Bean的实例化时机:当调用getBean()方法时实例化Bean
依赖注入:是Spring 框架核心Ioc的具体实现
构造方法 (有参和无参)
配置文件

set方法
引入命名空间

配置文件的设置 (简便方式)

实际开发中配置文件比较多,导致Spring配置繁杂,不方便读取,so将其进行部分配置拆解到其他配置文件中 通过 import标签加载,根据业务进行拆解配置文件

接口


通过id获取
通过类型获取
常见的数据源 : DBCP , C2P0 , BoneCP 、Druid等
底层=不一样,API的修改
里面的数据账号密码必须的本机的账号和密码
让容器产生getBean
- 将DataSource的创建权由Spring容器完成
注解配置提高开发效率
Spring原始注解主要是代替的配置


步骤
ApplicationContext应用获取上下文
在Web项目中
使用ServletContextListener监听Web应用的启动,Web应用启动时,就加载Spring的配置文件,创建应用上下文对象ApplicationContext,
在将其存储到最大的域servletContext域中,则可以在任意位置从域中获得应用上下文ApplicationContext对象。
概述: 基于java实现的MVC设计模型的请求驱动请谅解Web框架 , 通过一套注解 使用一个简单的Java类成为请求的控制器,无需实现任何接口,还具有RESTful编程风格请求。
访问控制图:




@RequestMapping :用于建立请求URL与处理请求方法之间的对应关系
属性 :
value: 用于指定请求的URL
method:指定请求的方式 GET/POST
params : 用于指定限制请求参数的条件 只能支持简单的表达式
params = {"username"} // 必须携带有username 参数
页面跳转
回写数据
直接返回字符串形式

返回ModelandView
直接返回字符串(回写数据)
通过SpringMVC框架注入的response对象,使用response.getWriter().print(“hello world”) 回写数据,不需要进行页面跳转
✔若是直接返回字符串,需要通过**@ResponseBody注解告知SpringMVC框架**,方法返回的字符串不是跳转,而是直接在http响应体中返回
返回对象和集合
格式:name = value & name= value … …
SpringMVC可以接受以下参数类型
Controller中的业务方法的参数名称要与请求参数的name一致,参数值会自动映射匹配。
在业务方法中的参数就是想要得到的参数内容 例如下面的代码
@RequestMapping(value="/quick11")
@ResponseBody // 不进行页面跳转 在控制台得到输出的内容
public void save11(String username,int age) throws IOException {
System.out.println(username);
System.out.println(age);
}
Controller中的业务方法的POJO参数的属性名与请求参数的name一致,参数值会自动映射匹配。
先定义一个User类 有String username,int age 两个私有变量
@RequestMapping(value="/quick12")
@ResponseBody
public void save12(User user) throws IOException {
System.out.println(user);
}
Controller中的业务方法的数组名称与请求参数的name一致,参数值会自动映射匹配。
访问的形式localhost:8080/quick13?username = zhangsan &age = 13
@RequestMapping(value="/quick13")
@ResponseBody
public void save13(String[] strs) throws IOException {
System.out.println(Arrays.asList(strs));
}
1 获取集合参数时,要将集合参数包装到一个POJO对象中 ,称为View对象
2 当使用ajax提交时,可以指定contentType为json形式,那么在方法参数位置使用**@RequestBody可以直接接收集合数据而无需使用POJO进行包装**。
在xml文件中要**设置开放资源(一般是静态资源)访问:
在创建一个ajax.jsp文件
<%-- 引入jQuery--%>
在控制台的访问形式:在方法参数中添加@RequestBody 存放数据在指定的集合中 List userList
@RequestMapping(value="/quick15")
@ResponseBody
public void save15(@RequestBody List<User> userList) throws IOException {
System.out.println(userList);
}
开启静态资源的方式
1.相对具体文件来进行比较麻烦每一个静态的文件都要设置一次 资源访问
<mvc:resources mapping="/js/**" location="/js/"/>
<mvc:resources mapping="/img/**" location="/img/"/>
2.简单粗暴形式 就能把所有的静态资源权限都打开都能访问到
<mvc:default-servlet-handler/>
设置一个过滤器进行过滤代码
配置全局的filter
<filter>
<filter-name>CharacterEncodingFilterfilter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
<init-param>
<param-name>encodingparam-name>
<param-value>UTF-8param-value>
init-param>
filter>
<filter-mapping>
<filter-name>CharacterEncodingFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
@RequestMapping(value="/quick16")
@ResponseBody
// required = false 没有name 参数 也可以进行 ,若是true 没有name 则会报错
public void save16(@RequestParam(value="name",required = false,defaultValue = "itcast") String username) throws IOException {
System.out.println(username);
}
Restful是一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。主要用于客户端和服务器交互类的软件,基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存机制等。
Restful风格的请求方式:“url + 请求方式” 有以下四种

上述url地址/user/1中的1就是要获得的请求参数,在SpringMVC中可以使用占位符进行参数绑定。地址/user/1可以写成/user/[id),占位符lid)对应的就是1的值。在业务方法中我们可以使用**@PathVariable注解进行占位符的匹配获取工作**。

@RequestMapping(value="/quick17/{name}",method = POST) //method获取请求方式
@ResponseBody
public void save17(@PathVariable(value="name") String username) throws IOException {
System.out.println(username);
}
自定义类型转换器的步骤:
第一步:定义转换器类实现Converter接口
import org.springframework.core.convert.converter.Converter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateConverter implements Converter<String, Date> {
@Override
public Date convert(String dateStr) {
//将日期字符串转换成日期对象 返回
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
Date date = null;
try {
date = format.parse(dateStr);
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
}
第二步:在配置文件中声明转换器
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="com.itheima.converter.DateConverter">bean>
list>
property>
bean>
第三步:在中引用转挨器
<mvc:annotation-driven conversion-service="conversionService"/>
@RequestMapping(value="/quick18")
@ResponseBody
public void save18(Date date) throws IOException {
System.out.println(date);
}
SpringMVC支持使用原始ServletAPl对象作为控制器方法的参数进行注入,常用的对象如下:
在方法中注释这些参数(形参)
例如:
@RequestMapping(value="/quick19")
@ResponseBody
public void save19(HttpServletRequest request, HttpServletResponse response, HttpSession session) throws IOException {
System.out.println(request);
System.out.println(response);
System.out.println(session);
}
@RequestHeader注解
属性:
value:请求头的名称
required:是否必须携带此请求头 true 的时候,当不是这个头会报错,
@RequestMapping(value="/quick20")
@ResponseBody
public void save20(@RequestHeader(value = "User-Agent",required = false) String user_agent) throws IOException {
System.out.println(user_agent);
}
@CookieValue
直接从cookie的名称获得cookie的值
属性
value:指定cookie的名称
required:是否必须携带此cookie
@RequestMapping(value="/quick21")
@ResponseBody
public void save21(@CookieValue(value = "JSESSIONID") String jsessionId) throws IOException {
System.out.println(jsessionId);
}
文件上传客户端的三要素
原理:
upload.jsp文件
代码 里面是两个表单文件
导入fileupload和io坐标
代码
<dependency>
<groupId>commons-fileuploadgroupId>
<artifactId>commons-fileuploadartifactId>
<version>1.3.1version>
dependency>
<dependency>
<groupId>commons-iogroupId>
<artifactId>commons-ioartifactId>
<version>2.3version>
dependency>
配置文件上传解析器
代码
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="UTF-8"/>
<property name="maxUploadSize" value="500000"/>
bean>
编写文件上传代码
代码
@RequestMapping(value="/quick22")
@ResponseBody //在参数中的上传的文件名字要与表单中设置的value的名字一样
public void save22(String username, MultipartFile uploadFile,MultipartFile uploadFile2) throws IOException {
System.out.println(username);
//保存/存储文件
//1.获得上传文件的名称
String originalFilename = uploadFile.getOriginalFilename();//上传文件原始名称
uploadFile.transferTo(new File("C:\\upload\\"+originalFilename));//将文件到转移到 C:\\upload\\或者是转移到某个服务器上
//这个是另外的文件
String originalFilename2 = uploadFile2.getOriginalFilename();
uploadFile2.transferTo(new File("C:\\upload\\"+originalFilename2));
}
表单
//使用数组上传文件
@RequestMapping(value="/quick23")
@ResponseBody
public void save23(String username, MultipartFile[] uploadFile) throws IOException {
System.out.println(username);
for (MultipartFile multipartFile : uploadFile) {
String originalFilename = multipartFile.getOriginalFilename();
multipartFile.transferTo(new File("C:\\upload\\"+originalFilename));
}
}
它是spring框架中提供的一个对象,是对原始繁琐的JdbcAPI对象的简单封装。spring框架为我们提供了很多的操作模板类。
配置文件
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
bean>
jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test?&useUnicode=true&characterEncoding=utf8
jdbc.username=root
jdbc.password=123456
public void test2() throws PropertyVetoException {
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
JdbcTemplate jdbcTemplate = app.getBean(JdbcTemplate.class);
int row = jdbcTemplate.update("insert into account values(?,?)", "lisi", 5000);
System.out.println(row);
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class JdbcTemplateCRUDTest {
@Autowired
private JdbcTemplate jdbcTemplate;
@Test
public void testQueryCount(){
Long count = jdbcTemplate.queryForObject("select count(*) from account", Long.class);
System.out.println(count);
}
//查询一个
@Test
public void testQueryOne(){
Account account = jdbcTemplate.queryForObject("select * from account where name=?", new BeanPropertyRowMapper(Account.class), "tom");
System.out.println(account);
}
//查询
@Test
public void testQueryAll(){
List accountList = jdbcTemplate.query("select * from account", new BeanPropertyRowMapper(Account.class));
System.out.println(accountList);
}
//更新
@Test
public void testUpdate(){
jdbcTemplate.update("update account set money=? where name=?",10000,"tom");
}
//删除
@Test
public void testDelete(){
jdbcTemplate.update("delete from account where name=?","tom");
}
}
导入spring-jdbc和spring-tx坐标
创建数据库表和实体
创建JdbcTemplate对象
执行数据库操作
更新操作:
jdbcTemplate.update (sql,params)
查询操作:
jdbcTemplate.query (sql,Mapper,params)
jdbcTemplate.queryForobject ( sql,Mapper,params)

创建拦截器类实现Handlerlnterceptor接口
配置拦截器
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/> 对所有的
<bean class="com.itheima.interceptor.MyInterceptor2"/> 对应的拦截器的包
mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.itheima.interceptor.MyInterceptor1"/>
mvc:interceptor>
mvc:interceptors>
测试拦截器的拦截效果
异常抛出的顺序

使用SpringMVC提供的简单异常处理器SimpleMappingExceptionResolver
配置简单异常处理器 :根据情况进行相应异常与视图的映射配置

<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<map>
<entry key="java.lang.ClassCastException" value="error1"/>
<entry key="com.itheima.exception.MyException" value="error2"/>
map>
property>
bean>
使用Spring的异常处理接口HandleExceptionResolver自定义异常
步骤
不用修改方法代码,只要通过修改日志控制方法代码就能控制到目标方法

常用代理对象
JDK代理: 基于接口的动态代理技术
目标对象必须要有接口

public class ProxyTest {
public static void main(String[] args) {
//目标对象
final Target target = new Target();
//增强对象 里面有before()和afterReturning()方法
final Advice advice = new Advice();
//返回值 就是动态生成的代理对象
TargetInterface proxy = (TargetInterface) Proxy.newProxyInstance(
target.getClass().getClassLoader(), //目标对象类加载器
target.getClass().getInterfaces(), //目标对象相同的接口字节码对象数组
new InvocationHandler() {
//调用代理对象的任何方法 实质执行的都是invoke方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
advice.before(); //前置增强
Object invoke = method.invoke(target, args);//执行目标方法
advice.afterReturning(); //后置增强
return invoke;
}
}
);
//调用代理对象的方法
proxy.save();
}
}
**cglib代理:**基于父类的动态代理技术
第三方的代理 可以没有接口

public class ProxyTest {
public static void main(String[] args) {
//目标对象
final Target target = new Target();
//增强对象
final Advice advice = new Advice();
//返回值 就是动态生成的代理对象 基于cglib
//1、创建增强器
Enhancer enhancer = new Enhancer();
//2、设置父类(目标)
enhancer.setSuperclass(Target.class);
//3、设置回调
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
advice.before(); //执行前置
Object invoke = method.invoke(target, args);//反射 执行目标
advice.afterReturning(); //执行后置
return invoke;
}
});
//4、创建代理对象
Target proxy = (Target) enhancer.create();
proxy.save();
}
}
常用术语:
aop:面向切面编程
aop底层实现:基于JDK的动态代理和基于Cglib的动态代理
aop的重点概念:
开发明确事项:
谁是切点(切点表达式配置)
谁是通知(切面类中的增强方法)
将切点和通知进行织入配置
导入AOP相关坐标 在pom.xml中
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjweaverartifactId>
<version>1.8.4version>
dependency>
创建目标接口和目标类(内部有切点)

接口代码
public interface TargetInterface {
public void save();
}
目标类代码
public class Target implements TargetInterface {
@Override
public void save() {
System.out.println("save running.....");
//int i = 1/0;
}
}
创建切面类(内部有增强方法)
切面类代码:
public class MyAspect {
public void before(){
System.out.println("前置增强..........");
}
public void afterReturning(){
System.out.println("后置增强..........");
}
//Proceeding JoinPoint: 正在执行的连接点===切点
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("环绕前增强....");
Object proceed = pjp.proceed();//切点方法
System.out.println("环绕后增强....");
return proceed;
}
public void afterThrowing(){
System.out.println("异常抛出增强..........");
}
public void after(){
System.out.println("最终增强..........");
}
}
将目标类和切面类的对象创建权交给spring
引用applicationContext.xml文件
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop" aop命名空间在
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
">
<bean id="target" class="com.itheima.aop.Target">bean>
<bean id="myAspect" class="com.itheima.aop.MyAspect">bean>
beans>
在applicationContext.xml中配置织入关系
引用applicationContext.xml文件
<aop:config>
<aop:aspect ref="myAspect">
<aop:pointcut id="myPointcut" expression="execution(* com.itheima.aop.*.*(..))">aop:pointcut>
指定com.itheima.aop下的Target类的save()方法
指定com.itheima.aop下的任意类下的任意方法
<aop:around method="around" pointcut-ref="myPointcut"/>
<aop:after method="after" pointcut-ref="myPointcut"/>
aop:aspect>
aop:config>
测试代码
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")//指定配置文件
public class AopTest {
@Autowired
private TargetInterface target;
@Test
public void test1(){
target.save();
}
}
语句:
execution([修饰符] 返回值类型.包名.类名.方法名(参数列表))
<aop:pointcut id="myPointcut" expression="execution(* com.itheima.aop.*.*(..))">aop:pointcut>
<aop:around method="around" pointcut-ref="myPointcut"/>
<aop:after method="after" pointcut-ref="myPointcut"/>
语法
< aop:通知类型method=“切面类中方法名”pointcut=“切点表达式"> < /aop:通知类型>
名称 标签 说明 前置通知 < aop:before> 用于配置前置通知。指定增强的方法在切入点方法之前执行 后置通知 用于配置后置通知。指定增强的方法在切入点方法之后执行 环绕通知 用于配置环绕通知。指定增强的方法在切入点方法之前和之后都执行 异常抛出通知 用于配置异常抛出通知。指定增强的方法在出现异常时执行 最终通知 用于配置最终通知。无论增强方式执行是否有异常都会执行
步骤
创建目标接口和目标类(内部有切点)
创建切面类(内部有增强方法)
将目标类和切面类的对象创建权交给spring
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Kuvm81JX-1666272835950)(ssm.assets/image-20220312181945759.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Iv9QZp0z-1666272835951)(ssm.assets/image-20220312181924100.png)]
在切面类中使用注解配置织入关系
在配置文件中开启组件扫描和AOP的自动代理
<context:component-scan base-package="com.itheima.anno"/>
<aop:aspectj-autoproxy/>
测试
通知配置语法:@通知注解(“切点表达式”)。
| 名称 | 标签 | 说明 |
|---|---|---|
| 前置通知 | < aop:before> | 用于配置前置通知。指定增强的方法在切入点方法之前执行 |
| 后置通知 | 用于配置后置通知。指定增强的方法在切入点方法之后执行 | |
| 环绕通知 | 用于配置环绕通知。指定增强的方法在切入点方法之前和之后都执行 | |
| 异常抛出通知 | 用于配置异常抛出通知。指定增强的方法在出现异常时执行 | |
| 最终通知 | 用于配置最终通知。无论增强方式执行是否有异常都会执行 |
同xml配置aop一样,我们可以将切点表达式抽取。抽取方式是在切面内定义方法,在该方法上使用@Pointcut注解定义切点表达式,然后在在增强注解中进行引用。
在对应的通知使用注解@通知类.抽取的方法
例如:

事务的实现+事务的定义===(运行起来形成了)===事务的状态
了解三个事务控制对象
PlatformTransactionManager(平台事务管理器)
TransactionDefinition (事务定义对象)
是事务的定义信息对象 定义的是参数或者是对象的信息
| 方法 | 说明 |
|---|---|
| int getIsolationLevel() | 获得事务的隔离级别 |
| int getPropogationBehavior ( ) | 称得事务的传播行为 |
| int getTimeout () | 获得超时时间 |
| boolean isReadonly () | 是否只读 |
TransactionStatus
被动的添加,不用我们自己添加
提供的是事务的具体运行状态
| 方法 | 说明 |
|---|---|
| boolean hassavepoint ( ) | 是否存储回滚点 |
| boolean iscompleted ( ) | 事务是否完成 |
| boolean isNewTransaction ( ) | 是否是新事务 |
| boolean sRollbackonly () | 事务是否回滚 |
采用声明的方式来处理事务 是在配置文件声明,用配置文件中声明事务来代替代码式处理事务
Spring声明式事务控制底层就是AOP
需要引入命名空间
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GHPhoeab-1666272835953)(ssm.assets/image-20220314214228102.png)]
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
下面的切点是说要对哪些方法进行增强,这里的method就是说针对某个method应该如何设置事务的属性
<tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/>
<tx:method name="save" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/>
<tx:method name="findAll" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="true"/>
<tx:method name="update*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="true"/>
<tx:method name="*"/>
tx:attributes>
tx:advice>
<aop:config>
<aop:pointcut id="txPointcut" expression="execution(* com.itheima.service.impl.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
aop:config>
要点
xml配置文件
<tx:annotation-driven transaction-manager="transactionManager"/>
service层的文件
@Service("accountService")
@Transactional(isolation = Isolation.REPEATABLE_READ)
public class AccountServiceImpl implements AccountService {
@Autowired //注入
private AccountDao accountDao;
/**
* 上面也有一个Transaction一般以就近的为主
*/
@Override
@Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
public void transfer(String outMan, String inMan, double money) {
accountDao.out(outMan, money);
int i = 1 / 0;
accountDao.in(inMan, money);
}
//多个方法时 一样定义注解
//@Transactional(isolation = Isolation.DEFAULT)
public void xxx() {
}
}
官网: Mybatis https://mybatis.org/mybatis-3/
步骤
pom.xml配置文件
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.5version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.46version>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.13version>
<scope>testscope>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-apiartifactId>
<version>1.7.20version>
dependency>
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-classicartifactId>
<version>1.2.3version>
dependency>
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-coreartifactId>
<version>1.2.3version>
dependency>
mybatis-config.xml
<typeAliases>
目标对象的包
<package name="com.itheima.pojo"/>
typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///mybatis?useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
dataSource>
environment>
<environment id="test">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///mybatis?useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
dataSource>
environment>
environments>
<mappers>
类路径
<package name="com.itheima.mapper"/>
mappers>
Demo.java
/**
* Mybatis 快速入门代码
2、3两点就把之前的jdbc给替换了
*/
public class MyBatisDemo {
public static void main(String[] args) throws IOException {
//1. 加载mybatis的核心配置文件,获取 SqlSessionFactory
//从官网复制过来
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//2. 获取SqlSession对象,用它来执行sql
SqlSession sqlSession = sqlSessionFactory.openSession();
//3. 执行sql 参数是命名空间的名称 test是上一级的名称 selectAll才是想要的查询名称,一级级通过,方便查询
List<User> users = sqlSession.selectList("test.selectAll");
System.out.println(users);
//4. 释放资源
sqlSession.close();
}
}
要安装官方文件的顺序 进行配置
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///mybatis?useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
dataSource>
environment>
<environment id="test">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///mybatis?useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
dataSource>
environment>
environments>
配置文件
实际开发中,习惯将数据源的配置信息单独抽取成一个properties文件,该标签可以加载额外配置的properties文件

前提是必须创建有了user数据库
在mapper.xml文件中进行对SQL语句的编写
<insert id="save" parameterType="com.itheima.domain.User">
insert into user values(#{id},#{username},#{password})
insert>
测试文件java代码
@Test
//插入操作
public void test2() throws IOException {
//模拟user对象
User user = new User();
user.setUsername("DashaX");
user.setPassword("123456789");
//获得核心配置文件
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
//获得session工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
//获得session回话对象
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//执行操作 参数:namespace+id
sqlSession.insert("userMapper.save",user);
//mybatis执行更新操作 提交事务 要有事务的提交才能把数据插入到数据库的表中。
sqlSession.commit();
//释放资源
sqlSession.close();
}
<update id="update" parameterType="com.itheima.domain.User">
update user set username=#{username},password=#{password} where id=#{id}
update>
测试代码 只要修改执行的操作代码 使用执行对应的增删改查的方法
@Test
//修改操作
public void test3() throws IOException {
//模拟user对象
User user = new User();
user.setId(7);
user.setUsername("lucy");
user.setPassword("123");
//获得核心配置文件
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
//获得session工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
//获得session回话对象
SqlSession sqlSession = sqlSessionFactory.openSession();
//执行操作 参数:namespace+id
sqlSession.update("userMapper.update",user);
//mybatis执行更新操作 提交事务
sqlSession.commit();
//释放资源
sqlSession.close();
}
<delete id="delete" parameterType="com.itheima.domain.User">
delete from user where id=#{abc}
delete>
测试代码
@Test
//删除操作
public void test4() throws IOException {
//获得核心配置文件
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
//获得session工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
//获得session回话对象
SqlSession sqlSession = sqlSessionFactory.openSession();
//执行操作 参数:namespace+id 后面的数字是id的值 namespace:命名空间
sqlSession.delete("userMapper.delete",8);
//mybatis执行更新操作 提交事务
sqlSession.commit();
//释放资源
sqlSession.close();
}
<select id="findAll" resultType="com.itheima.domain.User">
select * from user
select>
测试代码
@Test
//查询操作
public void test1() throws IOException {
//获得核心配置文件
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
//获得session工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
//获得session回话对象
SqlSession sqlSession = sqlSessionFactory.openSession();
//执行操作 参数:namespace+id
List<User> userList = sqlSession.selectList("userMapper.findAll");
//打印数据
System.out.println(userList);
//释放资源
sqlSession.close();
}

✔SqlSession sqlSession = sqlSessionFactory.openSession(true);

编写UserDao接口
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YlrOhMoB-1666272835957)(ssm.assets/image-20220317202102478.png)]
//传统方式 比较繁琐 要写接口 实现接口的方法
UserMapper mapper = sqlSession.getMapper();
List<User> all = mapper.findAll();
System.out.println(all);
采用Mybatis的代理开发方式实现DAO层的开发,企业的主流
Mapper接口开发方法只需要程序员编写Mapper接口(相当于Dao接口),由Mybatis框架根据按口疋乂创建按口的动态代理对象,代理对象的方法体同上边Dao接口,实现类方法。
Mapper接口开发需要遵循以下规范:

public class ServiceDemo {
public static void main(String[] args) throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
//创建SqlSessionFactory工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
//代理方式对Dao层实现
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//查询所有
List<User> all = mapper.findAll();
System.out.println(all);
//通过id查询
User user = mapper.findById(1);
System.out.println(user);
}
}
传统的开发形式 (手动dao层实现)
编写接口
实现接口
配置文件中
代理方式开发
以前的简单的不能满足比较复杂的业务逻辑
Dynamic SQl
主要是使用 if 语句 在实际开发中使用的比较多
测试
public class MapperTest {
@Test
public void test1() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//模拟条件user
User condition = new User();
condition.setId(1);
condition.setUsername("zhangsan");
condition.setPassword("123");
List<User> userList = mapper.findByCondition(condition);
System.out.println(userList);
//模拟ids的数据 这个foreach执行sql语句
List<Integer> ids = new ArrayList<Integer>();
ids.add(1);
ids.add(2);
List<User> userList = mapper.findByIds(ids);
System.out.println(userList);
}
}
动态SQL在xml中的抽取
<sql id="selectUser">select * from usersql>
所以在下面的if、foreach语句中的多了include标签 有一个属性refid 就是在抽取中的 id 值
mapper.xml配置文件
<select id="findByCondition" parameterType="user" resultType="user">
<include refid="selectUser">include>
<where>
<if test="id!=0">
and id=#{id}
if>
<if test="username!=null">
and username=#{username}
if>
<if test="password!=null">
and password=#{password}
if>
where>
select>
查询多个内容
在接口类中 创建有方法 findByIds 参数类型值是 list 返回值是user
<select id="findByIds" parameterType="list" resultType="user">
<include refid="selectUser">include>
<where>
<foreach collection="list" open="id in(" close=")" item="id" separator=",">
#{id}
foreach>
where>
select>

若是以上的默认处理器不能满足要求,则自己自定义处理器
步骤:
1.定义TypeHandler
public class DateTypeHandler extends BaseTypeHandler<Date> {
//将java类型 转换成 数据库需要的类型
//参数i表示表中第几个字段,参数s表示表中的字段名,两种表示方式
@Override
public void setNonNullParameter(PreparedStatement preparedStatement, int i, Date date, JdbcType jdbcType) throws SQLException {
// getTime()获取时间的毫秒值
long time = date.getTime();
preparedStatement.setLong(i,time);
}
//将数据库中的类型 转换成java类型
//String参数 : 要转换的字段名称
//ResultSet : 查询出的结果集
@Override
public Date getNullableResult(ResultSet resultSet, String s) throws SQLException {
//获得结果集中需要的数据(long) 转换成Date类型 返回
long aLong = resultSet.getLong(s);
Date date = new Date(aLong);
return date;
}
//将数据库中类型 转换成java类型
@Override
public Date getNullableResult(ResultSet resultSet, int i) throws SQLException {
long aLong = resultSet.getLong(i);
Date date = new Date(aLong);
return date;
}
//将数据库中类型 转换成java类型
@Override
public Date getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
long aLong = callableStatement.getLong(i);
Date date = new Date(aLong);
return date;
}
}
2.注册配置文件
<typeHandlers>
<typeHandler handler="com.itheima.handler.DateTypeHandler">typeHandler>
typeHandlers>
3.mapper中的方法 要创建有user数据表
<insert id="save" parameterType="user">
insert into user values(#{id},#{username},#{password},#{birthday})
insert>
<select id="findById" parameterType="int" resultType="user">
select * from user where id=#{id}
select>
4.测试
//插入数据
@Test
public void test1() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//创建user
User user = new User();
user.setUsername("ceshi");
user.setPassword("abc");
user.setBirthday(new Date());//当前时间
//执行保存造作
mapper.save(user);
sqlSession.commit();
sqlSession.close();
}
//查询
@Test
public void test2() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.findById(15);
System.out.println("user中的birthday:"+user.getBirthday());
sqlSession.commit();
sqlSession.close();
}
MyBatis可以使用第三方的插件来对功能进行扩展,分页助手PageHelper是将分页的复杂操作进行封装,使用简单的方式即可获得分页的相关数据
开发步骤:
首先要把表的全部内容查看以下,方便设置分页
<dependency>
<groupId>com.github.pagehelpergroupId>
<artifactId>pagehelperartifactId>
<version>3.7.5version>
dependency>
<dependency>
<groupId>com.github.jsqlparsergroupId>
<artifactId>jsqlparserartifactId>
<version>0.9.1version>
dependency>
2.配置PageHelper插件
<plugins>
<plugin interceptor="com.github.pagehelper.PageHelper">
<property name="dialect" value="mysql">property>
plugin>
plugins>
4.测试代码
//分页plugins插件
@Test
public void test3() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//设置分页相关参数 当前页(页码) 每页显示的条数(显示的条数)
PageHelper.startPage(3,3);
List<User> userList = mapper.findAll();
for (User user : userList) {
System.out.println(user);
}
//获得与分页相关参数 对象pageInfo
PageInfo<User> pageInfo = new PageInfo<User>(userList);
System.out.println("当前页:"+pageInfo.getPageNum());
System.out.println("每页显示条数:"+pageInfo.getPageSize());
System.out.println("总条数:"+pageInfo.getTotal());
System.out.println("总页数:"+pageInfo.getPages());
System.out.println("上一页:"+pageInfo.getPrePage());
System.out.println("下一页:"+pageInfo.getNextPage());
System.out.println("是否是第一个:"+pageInfo.isIsFirstPage());
System.out.println("是否是最后一个:"+pageInfo.isIsLastPage());
sqlSession.close();
}
MyBatis映射文件配置 标签
创建Order、User、Role实体
OrderMapper、UserMapper接口
创建UserMapper.xml 、 OrderMapper.xml 配置文件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sLaWROzm-1666272835959)(ssm.assets/image-20220318212205284.png)]
加载映射文件
<mappers>
<mapper resource="com/itheima/mapper/UserMapper.xml">mapper>
<mapper resource="com/itheima/mapper/OrderMapper.xml">mapper>
mappers>
OrderMappper配置文件
<mapper namespace="com.itheima.mapper.OrderMapper">
<select id="findAll" resultMap="orderMap">
SELECT *,o.id oid FROM orders o,USER u WHERE o.uid=u.id
select>
<resultMap id="orderMap" type="order">
<id column="oid" property="id">id>
<result column="ordertime" property="ordertime">result>
<result column="total" property="total">result>
<association property="user" javaType="user">
<id column="uid" property="id">id>
<result column="username" property="username">result>
<result column="password" property="password">result>
<result column="birthday" property="birthday">result>
association>
resultMap>
mapper>
User中的订单集合
//描述的是当前用户存在哪些订单 多个订单用集合存储
private List<Order> orderList;
UserMappper.xml
<resultMap id="userMap" type="user">
<id column="uid" property="id">id>
<result column="username" property="username">result>
<result column="password" property="password">result>
<result column="birthday" property="birthday">result>
<collection property="orderList" ofType="order">
<id column="oid" property="id">id>
<result column="ordertime" property="ordertime">result>
<result column="total" property="total">result>
collection>
resultMap>
<select id="findAll" resultMap="userMap">
SELECT *,o.id oid FROM USER u,orders o WHERE u.id=o.uid
select>
测试代码:
@Test
public void test2() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
//一对多模型
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = mapper.findAll();
for (User user : userList) {
System.out.println(user);
}
sqlSession.close();
}

配置文件中的自定义别名
<typeAliases>
<typeAlias type="com.itheima.domain.User" alias="user">typeAlias>
<typeAlias type="com.itheima.domain.Order" alias="order">typeAlias>
<typeAlias type="com.itheima.domain.Role" alias="role">typeAlias>
typeAliases>
User中的角色集合
//描述的是当前用户具备哪些角色
private List<Role> roleList;
UserMappper.xml
<resultMap id="userRoleMap" type="user">
<id column="userId" property="id">id>
<result column="username" property="username">result>
<result column="password" property="password">result>
<result column="birthday" property="birthday">result>
<collection property="roleList" ofType="role">
<id column="roleId" property="id">id>
<result column="roleName" property="roleName">result>
<result column="roleDesc" property="roleDesc">result>
collection>
resultMap>
<select id="findUserAndRoleAll" resultMap="userRoleMap">
SELECT * FROM USER u,sys_user_role ur,sys_role r WHERE u.id=ur.userId AND ur.roleId=r.id
select>
常用的注解
测试代码
public class MyBatisTest {
private UserMapper mapper;
@Before
public void before() throws IOException {
//数据源
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
//构建工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
//事务自动提交
SqlSession sqlSession = sqlSessionFactory.openSession(true);
mapper = sqlSession.getMapper(UserMapper.class);
}
//保存操作
@Test
public void testSave(){
User user = new User();
user.setUsername("tom");
user.setPassword("abc");
mapper.save(user);
}
//更新操作
@Test
public void testUpdate(){
User user = new User();
user.setId(18);
user.setUsername("lucy");
user.setPassword("123");
mapper.update(user);
}
//删除操作
@Test
public void testDelete(){
mapper.delete(18);
}
//根据id查询
@Test
public void testFindById(){
User user = mapper.findById(2);
System.out.println(user);
}
//查询所有
@Test
public void testFindAll(){
List<User> all = mapper.findAll();
for (User user : all) {
System.out.println(user);
}
}
}
sqlMapConfig.xml的配置文件
<mappers>
<package name="com.itheima.mapper">package>
mappers>
UserMapper接口 里面的增删改查的注解
public interface UserMapper {
@Insert("insert into user values(#{id},#{username},#{password},#{birthday})")
public void save(User user);
@Update("update user set username=#{username},password=#{password} where id=#{id}")
public void update(User user);
@Delete("delete from user where id=#{id}")
public void delete(int id);
@Select("select * from user where id=#{id}")
public User findById(int id);
@Select("select * from user")
public List<User> findAll();
}
测试代码
public class MyBatisTest2 {
//OrderMapper
private OrderMapper mapper;
@Before
public void before() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
mapper = sqlSession.getMapper(OrderMapper.class);
}
@Test
public void testSave(){
List<Order> all = mapper.findAll();
for (Order order : all) {
System.out.println(order);
}
}
}
OrderMapper接口 注解方式
这个查询效率比较低,每个结果还要去查询user表
//方式一
//o.id字段的别名oid
@Select("select *,o.id oid from orders o,user u where o.uid=u.id")
@Results({
@Result(column = "oid",property = "id"),
@Result(column = "ordertime",property = "ordertime"),
@Result(column = "total",property = "total"),
@Result(column = "uid",property = "user.id"),
@Result(column = "username",property = "user.username"),
@Result(column = "password",property = "user.password")
})
public List<Order> findAll();
//方式二
@Select("select * from orders")
@Results({
@Result(column = "id",property = "id"),
@Result(column = "ordertime",property = "ordertime"),
@Result(column = "total",property = "total"),
@Result(
property = "user", //要封装的属性名称
column = "uid", //根据那个 字段 去查询user表的数据
javaType = User.class, //要封装的实体类型
//select属性 代表查询那个接口的方法获得数据 从UserMapper中获得id数据 也就是对方的id,使用别人的接口的方法
one = @One(select = "com.itheima.mapper.UserMapper.findById")
)
})
UserMapper接口中的@Result注解方式
@Select("select * from user")
@Results({
//id = true 标识下面的@Result是id
@Result(id=true ,column = "id",property = "id"),
@Result(column = "username",property = "username"),
@Result(column = "password",property = "password"),
@Result(
property = "orderList",
column = "id",//当前的id来使用对方的id
javaType = List.class,
many = @Many(select = "com.itheima.mapper.OrderMapper.findByUid")
)
})
public List<User> findUserAndOrderAll();
测试
public class MyBatisTest2 {
//OrderMapper
private OrderMapper mapper;
@Before
public void before() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
mapper = sqlSession.getMapper(OrderMapper.class);
}
@Test
public void testSave(){
List<Order> all = mapper.findAll();
for (Order order : all) {
System.out.println(order);
}
}
}
RoleMapper的接口方法
@Select("SELECT * FROM sys_user_role ur,sys_role r WHERE ur.roleId=r.id AND ur.userId=#{uid}")
public List<Role> findByUid(int uid);
通过在UserMapper中通过USER的id值,查询到Role中的id值 (对多查询)
UserMapper接口方法
@Select("SELECT * FROM USER")
@Results({
@Result(id = true,column = "id",property = "id"),
@Result(column = "username",property = "username"),
@Result(column = "password",property = "password"),
@Result(
property = "roleList",
column = "id",//是上面sql语句查询出的id值
javaType = List.class,
many = @Many(select = "com.itheima.mapper.RoleMapper.findByUid")
)
})
//User
public List<User> findUserAndRoleAll();
测试
public class MyBatisTest4 {
private UserMapper mapper;
@Before
public void before() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
mapper = sqlSession.getMapper(UserMapper.class);
}
@Test
public void testSave(){
List<User> userAndRoleAll = mapper.findUserAndRoleAll();
for (User user : userAndRoleAll) {
System.out.println(user);
}
}
}
步骤:
2.Spring整合MyBatis
(column = “password”,property = “password”),
@Result(
property = “orderList”,
column = “id”,//当前的id来使用对方的id
javaType = List.class,
many = @Many(select = “com.itheima.mapper.OrderMapper.findByUid”)
)
})
public List findUserAndOrderAll();
测试
```java
public class MyBatisTest2 {
//OrderMapper
private OrderMapper mapper;
@Before
public void before() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
mapper = sqlSession.getMapper(OrderMapper.class);
}
@Test
public void testSave(){
List all = mapper.findAll();
for (Order order : all) {
System.out.println(order);
}
}
}
RoleMapper的接口方法
@Select("SELECT * FROM sys_user_role ur,sys_role r WHERE ur.roleId=r.id AND ur.userId=#{uid}")
public List<Role> findByUid(int uid);
通过在UserMapper中通过USER的id值,查询到Role中的id值 (对多查询)
UserMapper接口方法
@Select("SELECT * FROM USER")
@Results({
@Result(id = true,column = "id",property = "id"),
@Result(column = "username",property = "username"),
@Result(column = "password",property = "password"),
@Result(
property = "roleList",
column = "id",//是上面sql语句查询出的id值
javaType = List.class,
many = @Many(select = "com.itheima.mapper.RoleMapper.findByUid")
)
})
//User
public List<User> findUserAndRoleAll();
测试
public class MyBatisTest4 {
private UserMapper mapper;
@Before
public void before() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
mapper = sqlSession.getMapper(UserMapper.class);
}
@Test
public void testSave(){
List<User> userAndRoleAll = mapper.findUserAndRoleAll();
for (User user : userAndRoleAll) {
System.out.println(user);
}
}
}
步骤:
2.Spring整合MyBatis