第三章 ssm
1 spring
1.1 IOC
什么是IOC?
IOC 含义:
全称 Inverse Of Control:控制反转,指的是将 bean 对象的创建、对象关联关系的维护由原来我们自己去创建一个对象,自己通过硬编码的方式维护对象之间的关联关系,反转给 spring 的容器来创建对象,及维护对象之间的关联关系[属性赋值]。
IOC 作用:
解决了上层建筑严重依赖下层建筑的问题,实现了上层建筑对下层建筑的控制。
IOC底层原理:xml 解析+反射+容器+设计模式
1.2 获取容器的三种方式
获取容器的三种方式:
第一种:ClassPathXmlApplicationContext,默认是去src目录下找配置文件,必须掌握
第二种:FileSystemXmlApplicationContext:默认是去本地磁盘中找对应的配置文件
第三种:XmlBeanFactory:已过时,了解即可。
1.3 从容器中获取 bean 对象的两种方式及区别
从容器中获取bean对象的两种方式:
1.通过字节码的方式 eg:Test.class
2.通过容器中bean对象的id值或者name(name相当于别名)值的方式区别:
第一个:参数类型不同,一个是字符串类型,一个是字节码类型
第二个:返回值类型,一个是Object类型,一个是指定字节码类型
第三个:如果我们传递的参数是字节码类型:要求容器中有该类型的唯一bean对象,
没有:报NoSuchBeanDefinitionException
有一个:就将容器中的该类型的唯一bean对象赋值给该变量
有多个[两个及以上]:报 NoUniqueBeanDefinitionException
bean标签:每一个bean标签都对应一个类对象,相当于以前new 类
属性:
class属性:指定对象的全类名[包名+类名]
id属性:全称identifier,唯一标识符,必须在当前配置文件中保持唯一,不能重复,方便其它对象引用当前对象
name属性:当前bean对象的别名,和id属性的作用一致,一般也是要保持唯一,可以随便写
实际开发中,id属性和name属性没有必要都存在,只需要存在一个即可。
1.4 在 spring 容器中创建 bean 对象的三种方式
<!--在容器中创建bean对象的三种方式:
第一种:构造器【无参、有参构造器】,最常用
第二种:静态工厂:指的通过类的静态方法返回的对象
第三种:实例工厂:通过类对象的普通方法的得到的对象
-->
<!-- 第一种:构造器【无参、有参构造器】 -->
<bean id="book2" class="com.atguigu.bean.Book">
<constructor-arg name="bid" value="120"></constructor-arg>
<constructor-arg name="bookname" value="斗破苍穹"></constructor-arg>
<constructor-arg name="price" value="199.8"></constructor-arg>
</bean>
<!-- 静态工厂:指的通过类的静态方法返回的对象 -->
<bean id="book3" class="com.atguigu.web.StaticFactory" factory-method="getBook"></bean>
<!-- 实例工厂:通过类对象的普通方法的得到的对象 -->
<bean id="instanceFactory" class="com.atguigu.web.InstanceFactory" ></bean>
<bean id="book4" factory-bean="instanceFactory" factory-method="getBook02"></bean>
Book.class
public class Book { //getter/setter方法
private Integer bid;
private String bookname;
private double price;
public Book(Integer bid, String bookname, double price) {
this.bid = bid;
this.bookname = bookname;
this.price = price;
}}
StaticFactory:
public class StaticFactory {
public static Book getBook(){
return new Book(101,"斗罗大陆",199);
}}
InstanceFactory:
public class InstanceFactory {
public Book getBook02(){
return new Book(102,"三体",90);
}}
1.5 基于注解的方式给对象的属性赋值
不用提供属性对应的 setter 方法
@Value:取代 xml 文件中的 value 属性的,给基本类型的属性赋值的。
@Autowired:取代 xml 文件中的 ref 属性的,给引用类型的属性赋值,spring 中的
@Resource:取代 xml 文件中的 ref 属性的,给引用类型的属性赋值,jdk 自带的
@Autowired 注解的原理:
先根据该属性的类型去容器中找类型的唯一bean对象
第一种:如果容器中没有该类型的唯一bean对象,报错BeanCreationException
第二种:如果容器中有该类型的唯一bean对象,就将容器中的对象赋值该属性
第三种:如果容器中有多个该类型的bean对象:
1) 在根据当前属性的名字去容器中看看有没有一个bean对象的id值和当前属性名保持一致,如果有就将容器中的对象赋值给该属性
2) 如果容器中没有一个bean对象id值和当前属性的名字保持一致,再检查当前属性有没有@Qualifer,如果没有,直接报错,如果有,会再根据@Qualifer 的 value 属性值去容器中找一个 id 为@Qualifer的 value 属性值对象,如果能找到,就将这个对象赋值给该属性,如果找不着,报错
@Autowired(根据属性类型注入)
@Qualifer(根据id值从容器中进行匹配)
1.6 AOP
什么是aop?
AOP含义:
全称:Aspect Oreinted Programming:面向切面编程,AOP和OOP不存在谁取代谁的情况,他们之间是相互补充,相互促进的,Aop是在不改变原有OOP类代码的前提下,对原来类的功能进行拓展。
AOP作用:解决了软件工程中提出的关注点分离问题,让系统的架构变得高内聚低耦合。
AOP底层原理:动态代理[jdk动态代理+cglib动态代理]
AOP具体应用:声明式事务、通用缓存、通用日志、全局异常处理。
aop涉及的概念
通知[advice]:拓展的功能称之为通知[本质:方法]
切面[aspect]: 通知所在的类,称之为切面[本质:类]
切入点[PointCut]:用来确定对谁进行拓展的[本质:表达式]
连接点[JoinPoint]:通知和目标方法的交点称之为连接点
目标对象[Target]:目标方法所在的类对象称之为目标对象
织入[Weaving]:将通知应用到目标方法的过程,称之为织入
步骤
1.将被拓展的类和拓展的类加入到容器中,扫描包+类上加注解
2.在 spring 的配置文件开启基于注解的切面支持,并在拓展的类上@Aspect
3.在拓展的类的方法上指定切入点表达式。
@Component
@Aspect//该注解标记在类上,表示当前类是一个切面类
public class LogAspect {
//目标方法签名
@Before(value = "execution(public int com.atguigu.aop.CaculatorImpl.add(int,int))")
public void beforeLog(){
System.out.println("目标方法执行之前输出的日志");
}}
aop底层原理
静态代理
是指只能代理某一个接口的类对象
Payment 接口:
public interface Payment {
public void pay(double money);
}
RealPayment 实现类:
public class RealPayment implements Payment {
@Override
public void pay(double money) {
System.out.println("作为真实用户,我们只关注付了"+money);
}}
AliPay 代理类:
public class AliPay implements Payment {
private Payment payment;
public AliPay(Payment payment) {
this.payment=payment;
}
public void beforePay() {
System.out.println("支付宝把钱从银行取出来");
}
@Override
public void pay(double money) {
beforePay();
this.payment.pay(money);
afterPay();
}
public void afterPay() {
System.out.println("支付宝把钱支付给商家");
}}
测试代码:
@Test
public void testPay(){ //只能代理Payment类型的
AliPay aliPay = new AliPay(new RealPayment());
aliPay.pay(30);
}
动态代理
动态代理:可以代理任意接口的类对象
public void testDynamicProxy(){
/************************************************************
1.Proxy.newProxyInstance方法可以创建任意接口的代理类对象参数:
第一个参数:被代理类的类加载器
第二个参数:被代理类的实现的接口
第三个参数: InvocationHandler接口的实现类对象,在InvocationHandler接口的实现类我们可以对被代理类进行拓展
返回值:代理类对象
************************************************************/
// RealPayment realPayment = new RealPayment(); WeiPayImpl weiPay=new WeiPayImpl(); //代理类对象
WeiPay o =(WeiPay)Proxy.newProxyInstance(weiPay.getClass().getClassLoader(),
weiPay.getClass().getInterfaces(), new MyInvocationHandler(weiPay));
o.pay(40.3);
}
InvocationHandler 接口实现类:
public class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target) { this.target=target;}
/************************************************************
method:被代理类的方法
args:调用被代理类方法的时候传递的参数
proxy:不适用,不用管。
************************************************************/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("动态代理把钱从银行取出来......");
//调用被代理的方法
Object result = method.invoke(target, args); System.out.println("动态代理把钱付给商家......"); return result;
}}
静态代理和动态代理的区别
相同点:
第一点:都是在不改变原有类代码的基础之上对被代理类进行拓展
第二点:都需要实现接口,都要求被代理类和代理类实现相同接口
不同点:
静态代理只能代理某一个接口的类对象,动态代理可以代理任意接口的类对象
1.7 切面中的五种通知
前置通知[@Before]:在目标方法执行之前执行
后置通知[@After]:无论目标方法有没有执行成功,后置通知都会执行
返回通知[@AfterReturning]:在目标方法之后,只有目标方法执行成功的情况下,返回通知才执行
异常通知[@AfterThrowing]:在目标方法之后, 只有目标方法执行出现异常的情况下,异常通知才执行
环绕通知[@Around]:以一抵四
通知的底层原理
切入点表达式
作用:在切面中用来定位对谁进行拓展的
语法:
execution([权限修饰符] [返回值类型] [全类名].[方法名] ([参数类型列表]))
最简洁:
execution(* *.*(..))
注意:权限修饰符和返回值类型只能合用一个*,两个会报错
..代表多参,相当于args ...
最复杂:
execution(public int com.fjw.Test.add(int,int))
切入点重用
支持 &&
||
!
操作
execution(* *.add(int,int)) || execution(* *.sub(int,int))
获取目标方法的信息
获取目标方法的返回结果
注意:returning的result和下面的形参必须保持一致,且形参类型必须为object
1.8 环绕通知
@Component
@Aspect
public class TransactionAspect {
/************************************************************
环绕通知要求:
1.方法返回值类型必须为Object类型
2.参数类型:ProceedingJoinPoint
3.要求获取到目标方法的结果之后一定要返回
************************************************************/
@Around(value = "com.atguigu.aop.LogAspect.myPoint()")
public Object around(ProceedingJoinPoint joinPoint){
String name = joinPoint.getSignature().getName(); Object[] args = joinPoint.getArgs();
Object proceed = null;
try{
try{
System.out.println("事务切面 前置通知,目标方法名为:"+name+",传递给目标方法的参数值为:"+ Arrays.asList(args));
//调用目标方法
proceed = joinPoint.proceed();
}finally {
System.out.println("事务切面 后置通知");
}
System.out.println("事务切面 返回通知,目标方法的返回结果为:"+proceed);
}catch (Throwable ex){
ex.printStackTrace();
System.out.println("事务切面 异常通知,目标方法的异常信息为:"+ex.getMessage());
}
return proceed;
}
}
1.9 多切面优先级
多切面情况下,各个切面的优先级是由切面类上的@Order 注解的 value
属性值决定的,谁的 value 属性值越小,优先级越高。
1.10声明式事务
在 spring 的配置文件配置数据源事务管理器,开启基于注解的事务支持,在 service 层的类上或者方法上加@Transactional 注解
<!--1.配置扫描包 -->
<context:component-scan base-package="com.atguigu"></context:component-scan>
<!-- 2.加载 properties 文件 -->
<context:property-placeholder
location="classpath:jdbc.properties"></context:property-placeholder>
<!-- 3.配置数据源 -->
<bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="username" value="${abc.userName}"/>
<property name="password" value="${abc.password}"/>
<property name="url" value="${abc.jdbcUrl}"/>
<property name="driverClassName" value="${abc.driverClass}"/> </bean>
<!-- 4.配置 JdbcTemplate -->
<bean class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="druidDataSource"></property>
</bean>
<!-- 5.配置数据源事务管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="druidDataSource"></property> </bean>
<!--6.开启基于注解的事务支持 -->
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
1.11声明式事务的五大属性
1、传播机制
propagation:指的一个带有事务的方法 A 运行在另一个带有事务的方法 B 的内部时候,内层方法 A 是使用自己的事务还是使用外层方法 B 的事务,这就是事务的传播机制。
propagation:常用取值有Required、supports、requires_new
Required【默认值】:
如果外层方法B有事务,内层方法A 就用外层方法B的事务。
如果外层方法B没有事务,内层方法A 就用自己的事务
requires_new:
无论外层方法有没有事务,内层方法都使用自己的事务。
supports:
如果外层方法B有事务,内层方法A 就用外层方法B的事务如果外层方法B没有事务,内层方法A 不用事务了。
结论:多个内层方法,最后一个内层方法前面的事务的传播机制不能设置requires_new,有可能导致前面的事务提交,后面的错误导致回滚不了。
2、隔离级别
isolation:主要是针对并发访问的
READ_UNCOMMITED: 读未提交
READ_COMMITED: 读已提交,在一个事务A操作过程中,如果其它事务B修改了某个数据,并且已经提交了,事务A就可以读取到。
REPEATABLE_READ: 可重复读(默认):在一个事务内部多次读取的结果永远是一致的
SERIALIZABLE: 序列化读,不允许并发
不同的数据库默认的隔离级别不一样,mysql默认的隔离级别是可重复读,oracle默认的隔离级别是读已提交。
3、回滚属性:rollbackFor
事务默认只是在遇到运行时异常的时候才会回滚,遇到编译时异常,不会回滚。
注意:在 spring 框架底层将 SQLException 转换为 RuntimeException!
spring 框架并没有将 IOException 转换为 RuntimeException (rollbackFor可以处理异常回滚)
rollbackFor:针对的主要是非运行时异常
noRollbackFor:针对运行时异常的
4、超时属性
事务在执行过程中,势必会占用着数据库资源,为了防止一个事务长时间占用着数据库资源, 导致其它事务无法进行,有必要给事务设置一个超时时间,一旦一个事务超过了指定的超时时间,就可以让事务进行回滚。
timeout:指的在当前事务内部,多次对数据表的增删改操作的之间的总时间不能超过指定值。(从开始对库的操作到结束对库的操作)
5、只读属性
readOnly:为了加快查询效率,如果我们给事务设置 readOnly=true,就意味着在当前方法只能有对数据表的查询操作,不能有增删改操作。告诉数据库把锁设置为共享锁;
1.12基于 xml 配置的声明式事务
<aop:config>
<!-- 指定切入点表达式 -->
<aop:pointcut id="myPointCut" expression="execution(* com.atguigu.service.BookService.*(..))"/>
<!-- 2. 将切入点表达式和事务联系起来-->
<aop:advisor advice-ref="dsada" pointcut-ref="myPointCut"></aop:advisor> </aop:config>
<!-- 配置事务 -->
<tx:advice id="dsada" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="buyBook"/>
<tx:method name="get*" read-only="true"/>
<tx:method name="find*" read-only="true"/>
<tx:method name="query*" read-only="true"/>
<tx:method name="update*" ></tx:method>
<tx:method name="insert*" ></tx:method>
<tx:method name="delete*" ></tx:method>
</tx:attributes>
</tx:advice>
2 springMVC
2.1 基本配置
2.1.1在 web.xml 文件中配置 springmvc 的前端控制器
<!-- 1.配置springmvc的前端控制器 -->
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class >
<!--2.加载springmvc的配置文件 -->
<init-param>
<param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!--3.用来映射浏览器请求的 -->
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
2.1.2在 springmvc.xml 文件中配置内部资源视图解析器和扫描包
<!--1.配置扫描包 -->
<context:component-scan base-package="com.atguigu"></context:component-scan>
<!--2.配置内部资源视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/"/>
<property name="suffix" value=".jsp"/>
</bean>
2.2 常见问题
web.xml 文件中
2.2.1 load-on-startup:
0 和正整数:在 tomcat 服务器启动的时候,当前 servlet 对象就被创建了
负整数: 在第一次请求到达的时候,当前 servlet 对象才被创建。
2.2.2 url-pattern 值:
/:拦截当前项目下所有的请求, 不包括 jsp
/*:拦截当前项目下所有的请求,包括 jsp
2.2.3 InternalResourceViewResolver:内部资源视图解析器
作用一:将逻辑视图解析为物理视图
prefix+returnval+suffix
作用二:转发到对应的 jsp 页面
2.3 请求相关操作
2.3.1 @RequestMapping
2.3.2 @RequestParam
可以接收数组,集合,如果写了,前端必须有对应的字段(required默认),否则报错
2.3.3 @PathVariable [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EZwPmleV-1660813088288)(./image/image-20220228100600224.png)]
2.3.4 @RequestHeader
2.3.5 @CookieValue
如上类似
2.3.6 原生API
HttpServletRequest、HttpServletResponse、HttpSession
2.3.7 支持数据、pojo对象
数组:
POJO对象:
2.3.8 @RequestBody
将http的输入流装配到目标类,会根据json字符串中的key来匹配对应实体类的属性,通过无参构造调用setter赋值给属性
2.3.9 @ResponseBody
@ResponseBody的作用其实是将java对象转为json格式的数据
2.4 处理post请求乱码
2.5 <mvc:view-controller path=“”/>标签
2.6 类型转换器
Springmvc 实际上自带了简单的类型转换器,例如:
String ----> Integer/double
String–> true/false
2.6.1 全局类型转换器
全局类型转换器:在 springmvc.xml 文件中配置一次,对所有 controller 层代码都起作用
实现全局类型转换器:
1. 自定义类型转换器类,实现 converter<S,T>接口,并加入到容器中
2. 在 springmvc.xml 文件中配置一个
注意dateTimeConverter是自定义Converter接口的实现类,spring管理
2.6.2 局部类型转换器
局部类型转换器:在每个方法使用的时候,使用一次配置一次
2.7 静态资源的访问
不加annotation-driven 接口无法访问
2.8 后端返回json数据
第一步:导入 json 的 jar 包
第二步:在方法上加@ResponseBody注解
第三步:在 springmvc.xml 配置文件中配置<mvc:annotation-driven>标签返回的
json 数据类型:
Map:必须是自己 new 出来的 Map,不能是参数中的 map(异步接收不了map)
POJO:json对象
List<Pojo>:json数组
String
Integer
2.9 文件上传与下载
2.9.1 上传
前端要求:
-
form 表单请求方式为 POST
-
form 表单的 encytype 属性值:multipart/form-data
-
type=file
后端要求:
-
必须在 springmvc.xml 文件中配置多媒体解析器
-
在目标 handler 方法使用 MultiPartFile 类型的参数来接收文件
-
导入文件上传所需的 jar 包 commons-fileupload、commons-io 包
2.9.2 文件下载
要求:
目标方法返回值类型为:ResponseEntity<byte[]>
设置响应头:2 个
2.10 拦截器
拦截器类似于我们 javaweb 部分学过的 Filter,都是在请求到达目标方法之前拦截请求,对请求进行过滤操作。
拦截器作用:权限验证、记录日志。
2.10.1 自定义拦截器
-
自定义一个拦截器类,实现 HanlderInceptor 接口,实现接口中的方法
-
在 springmvc.xml 文件中配置mvc:interceptors标签自定义拦截器类
在 springmvc.xml 文件中配置:
流程:
2.10.2 多拦截器
谁在 springmvc.xml 文件的 mvc:interceptors 标签内部先声明,就会先执行谁。
对拦截器详细设置时:
2.11 异常处理
2.11.1 基于注解的统一异常处理
-
加上mvc:annotation-driven标签
-
在全局异常处理类上加@ControllerAdvice 注解
-
全局异常处理类方法上加@ExceptionHandler 注解,用于处理异常信息!注意:
2.11.2 基于 xml 配置的异常处理
如果希望对所有异常进行统一处理,可以使用 SimpleMappingExceptionResolver,它将异常类名映射为 视图名,即发生异常时使用对应的视图报告异常
2.12 父子容器
mvc是子容器里面放的是controller,spring是父容器,里面放的是service和dao
子容器可以调父容器,父容器不可以调子容器
2.13 扫描包问题
spring.xml
<context:component-scan base-package="com.xx">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<context:exclude-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
</context:component-scan>
springmvc.xml
<!--use-default-filters="false"不在全包扫描,只扫下面包括的-->
<context:component-scan base-package="com.xx" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
</context:component-scan>
2.14 mvc运行流程图
3 mybatis
3.1 二级缓存
3.1.1一级缓存
SqlSession 级别的,默认是开启的。
一级缓存失效的四种情况:
1.SqlSession对象不同
2.SqlSession对象相同,但是查询条件不同
3.SqlSession对象相同,查询条件也相同,但是在两次查询之间做了增删改操作
4.SqlSession对象相同,查询条件也相同,但是在两次查询之间手动清理了缓存
3.1.2二级缓存
Mapper[namespace]级别,默认是关闭的,需要手动开启。
二级缓存使用前提条件【4 个】:
1. 必须在 mybatis-config.xml 文件中开启二级缓存
2. 在对应 mapper 接口的 SQL 映射文件中加一个 cache 标签
3. 放入到二级缓存中的数据必须实现序列化接口
4. 必须是一级缓存关闭的情况下,一级缓存中的数据才会跑到二级缓存中。
3.2 mybatis优势
第一个:MyBatis 本身是一个框架,除了对数据表的数据进行增删改查之外,还有缓存、字段映射等机制。
第二个:MyBatis 支持动态 SQL【根据传递不同字符串生成不同的 SQL 语句】
第三个:MyBatis 支持将 java 代码和 SQL 语句进行分离开来。
第四个:MyBatis 支持将表的关联关系直接映射为 POJO 对象的关联关系。
第五个: MyBatis 是一个半自动化 ORM 框架 。 ORM 全称: Object RelationShip Mapping:
3.3 mybatis全局配置文件(了解)
需要注意:在全局配置文件中的这些标签是有顺序的
1. properties
作用:加载 properties 文件的。
<!--1.properties标签是用来加载properties文件的
resource:默认就是去加载src目录下的properties文件url:本地磁盘或者网络资源-->
<properties resource="jdbc.properties" ></properties>
2. settings
settings 标签有多个 setting 标签,每个 setting 标签都对应 mybatis 的一项配置
<settings>
<!-- 1.可以将表中以下划线分隔的列(img_path)映射到pojo对象的驼峰式命名的属性(imgPath)中 -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
3. typeAliases
作用:该标签底下有多个 typeAlias 标签,每个 typeAlias 对应一种类型别名
<!--类型别名处理器:实际开发中,不建议使用。 -->
<typeAliases>
<!-- 该typeAlias标签可以为类型起别名,
type:指定类的全类名,默认的别名是:简类名,别名不区分大小写
alias:指定类的别名,一旦自己指定了别名,再使用别名的时候,就只能使用自己指定的别名
批量起别名:package,指定一个包名,表示为这个包下的所有类都起一个别名,默认的别名是:
简类名
-->
<package name="com.atguigu.bean"/>
</typeAliases>
4. typeHandlers
作用:将数据库中的类型转换为 java 中的类型
5. environments
environments 标签中有很多个 environment 标签,每个 environment 标签都对应一种环境。
<!--
1.environments标签的default属性值:可以切换为environment标签的id值,表示当前使用是哪种环境
在每个environment标签底下又有transactionManager和dataSource两个子标签:
transactionManager:标签进行事务管理,type属性指定管理事务的类取值:
JDBC: 支持事务
MANAGED:不支持事务
dataSource:
取值:
UNPOOLED: 不支持数据库连接池
POOLED: 支持数据库连接池,性能比较高
JNDI: 过时的,过。
-->
<environments default="development">
<!-- 1.开发人员使用的开发环境:开发人员的数据库 -->
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driverClass}"/>
<property name="url" value="${jdbc.jdbcUrl}"/>
<property name="username" value="${jdbc.userName}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
<!-- 2.测试人员使用的测试环境:测试人员的数据库 -->
<environment id="test">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.test.driverClass}"/>
<property name="url" value="${jdbc.test.jdbcUrl}"/>
<property name="username" value="${jdbc.test.userName}"/>
<property name="password" value="${jdbc.test.password}"/>
</dataSource>
</environment>
</environments>
6. databaseIdProvider
该标签的作用:是给数据库厂商服务器起别名。mysql、oracle、sqlserver、db2
<databaseIdProvider type="DB_VENDOR">
<!-- 指定数据库厂商服务器的别名:name表示服务器的名字, value表示的服务器的别名,可以自己随意指定-->
<property name="SQL Server" value="sqlserver"/> <property name="DB2" value="db2"/>
<property name="Oracle" value="oracle" />
<property name="MySQL" value="mysql"/>
</databaseIdProvider>
在 SQL 映射文件中引用数据库服务器的别名即可:databaseId
<select id="selectBlog" resultType="com.atguigu.bean.Book" databaseId="mysql"> select id,title,author,price,sales,stock,img_path from book where id = #{id}
</select>
<select id="selectBlog" resultType="com.atguigu.bean.Book" databaseId="oracle"> select id,title,author,price,sales,stock,img_path from book where id = #{id}
</select>
7. mappers
<!--
mappers里面可以有多个mapper标签,每个mapper标签都可以加载SQL映射文件或者Mapper接口
每个mapper标签:
属性:
resource:用来加载SQL映射文件
url:一般不用
class:加载Mapper接口,有两个要求:
要求:1.Mapper接口和SQL映射文件必须在同一个包下
2.要求Mapper接口的名字和SQL映射文件的名字必须相同。
package标签:批量加载mapper接口
要求:1.Mapper接口和SQL映射文件必须在同一个包下
2.要求Mapper接口的名字和SQL映射文件的名字必须相同。
-->
<mappers>
<package name="com.atguigu.dao"/>
</mappers>
3.4 sql映射文件(重要)
1. 插入数据的时候获取数据表的自增主键
有两种方式:都要求参数类型为 pojo 类型:
第一种方式:只适用于数据表能自增主键的数据库:mysql、sqlserver
在 insert 标签上指定 useGeneratedKeys="true" keyProperty="id"(bean属性)
第二种方式:适用于所有的数据库:
<insert id="insert">
<!--
selectKey专门用来查询主键
属性:
keyColumn:查询数据表的哪个列
keyProperty:将查询出来的主键封装到pojo类的哪个属性上
resultType: 主键的类型
order:表示该sql语句的执行顺序,AFTER表示在insert语句执行之后执行-->
<selectKey keyProperty="id" keyColumn="id" resultType="integer" order="AFTER">
select last_insert_id()
</selectKey>
insert into book
values(null,#{title},#{author},#{price},#{sales},#{stock},#{imgPath})
</insert>
2. sql标签
该标签的作用:做 SQL 语句重用的
<!-- sql片段做sql语句重用 -->
<sql id="querySql">
id,title,author,price,sales,stock,img_path </sql>
<select id="getBookById" resultType="com.atguigu.bean.Book">
select <include refid="querySql"></include> from book where id = #{id}
</select>
3. resultMap 标签
当表的列名和 pojo 类的属性名不对应的时候,怎么能映射上?
第一种方案:给表的列名起别名
第二种方案:在 mybatis-config.xml 配置 mapUnderscoreToCamelCase 设置
第三种方案:ResultMap 标签
<!-- resultMap:做查询结果映射-->
<resultMap id="getBookByBidResultMap" type="com.atguigu.bean.Book">
<!-- 主键映射用id标签:column属性对应着数据表的列名,property对应着pojo类的属性名 -->
<id column="id" property="id"></id>
<!-- 普通字段映射用result标签 -->
<result column="title" property="title"></result>
<result column="author" property="author"></result>
<result column="price" property="price"></result>
<result column="sales" property="sales"></result>
<!-- 当表的列名和pojo类的属性名一致的时候,默认就能映射上,虽然这样,但是实际开发中,建议写出来了--> <result column="img_path" property="imgPath"></result>
</resultMap>
<!--注意:select标签的resultType属性和resultMap属性只能同时存在一个。-->
<select id="getBookByBid" resultMap="getBookByBidResultMap">
select id,title,author,price,sales,stock,img_path from book where id = #{id}
</select>
ResultMap 标签作用:
第一个:做结果映射
第二个:处理关联表的映射的时候就必须使用这个标签,这个功能是resultType属性锁不具备的,resultType属性只能处理单表的映射。
4. #{}与${}的区别
${}类似于 javaweb 部分学过的 statement,是将参数直接拼接到 SQL 语句中的,这种是存在 SQL 注入问题的,是不安全的。
#{}类似于 javaweb 部分学过的 preparestatement 对象,是以占位符、预编译的方式将参数设置到 SQL 语句中的,不存在 SQL 注入问题.
实际开发中,大部分情况,都使用#{},但是特殊情况下,就必须使用${},比如:获取表名、排序字段、模糊查询的时候也会用到${}。
mapper接口:
public Book getBookByBid(@Param("id") Integer id,
@Param("da") String tablename,
@Param("orderByField")String orderByField,
@Param("title")String title);
sql 映射文件:
<select id="getBookByBid" resultMap="getBookByBidResultMap">
select id,title,author,price,sales,stock,img_path from ${da} where title like concat(concat('%','${title}'),'%') order by ${orderByField} desc limit 0,1
</select>
接口参数
接口中各种各样的参数:
1.一个基本数据类型: int、Integer、String、boolean、float、double, :#{随便写}
2.多个基本类型的参数[两个、两个以上]:建议在每个普通参数前面加一个@Param注解,:#{@Param的value属性值}
3.Bean对象 :#{bean对象的属性名}
4.List<Bean>、Collection<Bean>、 :#{list[下标]}
5.Map: :#{map的key}
6.数组: :#{array[下标]}
7.复杂类型:上面任意组合得到:建议在每个普通参数前面加一个@Param注解, :#{param注解的value属性值}
接口的返回值
/**
1.基本类型:int、Integer、double、Double、boolean
增删改: 只需要在接口中声明返回值类型,在SQL映射文件中无须指定resultType属性
查询: 需要在接口中声明返回值类型,在SQL映射文件中需要指定resultType属性
2.pojo对象: 只需要在接口中声明返回值类型,在SQL映射文件中的resultType属性指定为pojo类的全类名
3.POJO对象列表:只需要在接口中声明返回值类型,在SQL映射文件中的resultType属性指定集合中元素的数据类型
4.Map类型: :
返回单行数据:在接口中声明返回值类型Map<String,Object>,,在SQL映射文件中的resultType属性值为MAP类型返回多行数据:在接口中声明返回值类型Map<表中主键的类型,POJO类>,在SQL映射文件中的resultType属性值为MAP
**/
@MapKey("uid")//专门用来指定将表的哪一列作为Map的key map多行
public Map<Integer,User> getAllUsers();
3.5 关联查询(重要)
表与表的关联关系:一对一、一对多、多对一、多对多四种关联关系
1 x对一[三种解决方案]
一对一
多对一:订单项和订单、员工和部门
需求:以员工和部门为例讲解 x 对一的关联关系。当查询员工信息的时候,把该员工所属的部门信息一起查询出来。
表:
create table dept(
did int primary key auto_increment comment '部门id', dept_name varchar(30) not null comment '部门名称')
create table employee(
eid int primary key auto_increment comment '员工id', ename varchar(30) not null comment '员工名称', did int,
FOREIGN key(did) REFERENCES dept(did)
)
bean:
public class Department { //提供getter、setter、toString()
private Integer did;
private String deptName;
}
public class Employee {//提供getter、setter、toString()
private Integer eid;
private String ename;
private Department department;
}
第一种解决方案:
<resultMap id="getEmployeeByEidResultMap" type="com.atguigu.bean.Employee">
<id column="eid" property="eid"/>
<result column="ename" property="ename"/>
<!-- 第一种解决方案:连缀的方式 -->
<result column="did" property="department.did"></result>
<result column="dept_name" property="department.deptName"></result>
</resultMap>
<select id="getEmployeeByEid" resultMap="getEmployeeByEidResultMap"> select e.eid,e.ename,d.did,d.dept_name
from employee e
left join dept d
on e.did = d.did
where e.eid =#{eid}
</select>
第二种解决方案:使用 association 标签
<resultMap id="getEmployeeByEidResultMap" type="com.atguigu.bean.Employee">
<id column="eid" property="eid"/>
<result column="ename" property="ename"/>
<!-- 第二种解决方案:使用association标签:解决对x一关联关系属性:
property:指定关联的属性名
javaType: 指定关联属性的类型
-->
<association property="department" javaType="com.atguigu.bean.Department">
<id column="did" property="did"></id>
<result column="dept_name" property="deptName"></result>
</association>
</ResultMap>
第三种解决方案:分步查询
EmployeeMapper.xml
<resultMap id="getEmployeeByEidResultMap" type="com.atguigu.bean.Employee">
<id column="eid" property="eid"/>
<result column="ename" property="ename"/>
<!--第三种解决方案:使用association标签
select:表示将哪个select语句的返回结果赋值给关联的属性
column:当前sql语句调用另一个Sql的时候,传递的列名
-->
<association property="department" select="com.atguigu.dao.DepartmentMapper.dddd"
column="did"></association>
</resultMap>
<select id="getEmployeeByEid" resultMap="getEmployeeByEidResultMap">
select eid,ename,did
from employee
where eid= #{eid}
</select>
DepartmentMapper.xml
<select id="dddd" resultType="com.atguigu.bean.Department">
select did,dept_name deptName
from dept
where did = #{did}
</select>
注意:对于分步查询,存在懒加载机制。
懒加载分为:局部懒加载+全局懒加载两种
局部懒加载:适合当前项目中只有个别 SQL 需要懒加载的时候使用。
在 association 标签设置 fetchType:lazy[懒加载] | eager[立即加载,默认值]
全局懒加载: 适合当前项目中有较多的 SQL 需要懒加载的时候使用
在 mybatis 的全局配置文件中设置:
<settings>
<!--开启全局懒加载 -->
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
2 X 对多[两种解决方案]
x 对多关联关系:
一对多:部门和员工、订单和订单项
多对多:学生和老师【中间表】
需求:以部门和员工为例,讲解对多的关联关系。对多的关联关系都有两种解决方案。查询部门信息的时候,将该部门所有的员工信息一起查询出来。
表:
create table dept(
did int primary key auto_increment comment '部门id',
dept_name varchar(30) not null comment '部门名称'
)
create table employee(
eid int primary key auto_increment comment '员工id', ename varchar(30) not null comment '员工名称',
did int,
FOREIGN key(did) REFERENCES dept(did)
)
bean:
//员工表
public class Employee { //提供getter、setter、toString方法
private Integer eid;
private String ename;
}
//部门表
public class Department {
private Integer did;
private String deptName;
private List<Employee> emps;
}
第一种方案:
<resultMap id="getDepartmentWithEmployeesByDidResultMap" type="com.atguigu.bean.Department">
<result column="did" property="did"/>
<result column="dept_name" property="deptName"/>
<!--
collection标签用于处理对多的关联关系。
属性:
property:指定关联属性的名字
ofType: 指定集合中元素的数据类型
-->
<collection property="emps" ofType="com.atguigu.bean.Employee">
<result column="eid" property="eid"/>
<result column="ename" property="ename"/>
</collection>
</resultMap>
<select id="getDepartmentWithEmployeesByDid"
resultMap="getDepartmentWithEmployeesByDidResultMap">
select d.did,d.dept_name,e.eid,e.ename
from dept d
left join employee e
on d.did = e.did
where d.did = #{dsdsds}
</select>
第二种解决方案:
<select id="queryEmployeesByDid" resultType="com.atguigu.bean.Employee">
select eid,ename
from employee
where did= #{ddsdsdsdsds}
</select>
<resultMap id="getDepartmentWithEmployeesByDidResultMap" type="com.atguigu.bean.Department">
<result column="did" property="did"/>
<result column="dept_name" property="deptName"/>
<!--
collection标签用于处理对多的关联关系。
属性:
property:指定关联属性的名字
ofType: 指定集合中元素的数据类型
select: 指定要引用的Select语句的id值
column: 调用另一条SQL语句的时候,要传递的数据列
-->
<collection property="emps" select="queryEmployeesByDid" column="did"> </collection>
</resultMap>
<select id="getDepartmentWithEmployeesByDid" resultMap="getDepartmentWithEmployeesByDidResultMap">
select did,dept_name
from dept
where did = #{did}
</select>
3.6 多对多 一对一表创建
1 多对多表的创建:
create table student(
sid int primary key auto_increment,
sname varchar(30) not null
)
create table teacher(
tid int primary key auto_increment,
tname varchar(30) not null
)
create table student_teacher(
sid int,
tid int,
primary key(sid,tid),
FOREIGN key(sid) REFERENCES student(sid),
FOREIGN key(tid) REFERENCES teacher(tid)
)
2 一对一表的创建:
第一种方式:(在多对一的基础上,对多的一端的外键加 unique 约束即可)
create table wife(
id int primary key auto_increment,
wifename varchar(30) not null
)
create table husband(
hid int primary key auto_increment,
husband_name varchar(30) not null,
wid int unique,
FOREIGN key(wid) REFERENCES wife(id)
)
第二种
create table wife(
wid int primary key auto_increment,
wname varchar(30) not null
)
create table husband(
hid int primary key,
husband_name varchar(30) not null,
FOREIGN key(hid) REFERENCES wife(wid)
)
3.7 动态sql
所谓动态 SQL:是指根据传递过来的不同参数生成不同的 SQL 语句。动态 SQL 中主要包含以下标签:
• if :相当于javaweb学过的<c:if>进行单分支判断
• choose (when, otherwise):相当于javaweb学过的<c:choose>进行多分支判断
• trim (where, set):trim可以对sql语句修改,where标签可代替sql中where关键字,set标签可代替sql语句中的set关键字。
• foreach:类似javaweb学过的<c:foreach>遍历集合使用的
1 if 标签
作用:相当于 javaweb 学过的<c:if>
进行单分支判断
需求:如果携带了标题,就用标题查,如果携带了作者信息,就用作者查询,如果携带了价格查询,如果这些参数都携带了,就用所有的参数查询。总之,携带了哪些条件,就使用哪些条件查询
<select id="getBookByMap" resultType="com.atguigu.bean.Book">
select id,title,author,price,sales,stock,img_path imgPath from book
where
<if test="title != null and title != '' ">
title = #{title}
</if>
<if test="author != null and author != '' ">
and author = #{author}
</if>
<if test="price > 0.0">
and price = #{price}
</if>
</select>
注意:上述的 SQL 语句还是有问题的。当我们不传递 title 过来的时候,where 后面会多出一个 and 关键字,
解决:
第一种解决方案:在 where 关键字后面加一个 1=1
<select id="getBookByMap" resultType="com.atguigu.bean.Book">
select id,title,author,price,sales,stock,img_path imgPath from book
where 1=1
<if test="title != null and title != '' ">
and title = #{title}
</if>
<if test="author != null and author != '' ">
and author = #{author}
</if>
<if test="price > 0.0">
and price = #{price}
</if>
</select>
第二种解决方案:使用 where 标签代替 where 关键字
2 where 标签
where 标签就是专门用来代替 where 关键字的,where 标签默认能将 where 标签内部的 sql 语句最前面
的 and 或者 or 关键字给去掉。
<select id="getBookByMap" resultType="com.atguigu.bean.Book">
select id,title,author,price,sales,stock,img_path imgPath from book
<where>
<if test="title != null and title != '' ">
title = #{title}
</if>
<if test="author != null and author != '' ">
and author = #{author}
</if>
<if test="price > 0.0">
and price = #{price}
</if>
</where>
</select>
注意:目前还有问题,就是如果 and 或者 or 关键字不是写在前面,而是写在后面,where标签也不能将 where 标签内部的 sql 语句中的最后面的 and 或者 or 关键字给去掉。那如果就像把它去掉,怎么办呢?这里可以借助于 trim 标签
3 trim 标签
trim 标签类似于 java 基础中字符串的 trim 方法,可以对 sql 语句最前面或者最后面进行修改
<select id="getBookByMap" resultType="com.atguigu.bean.Book">
select id,title,author,price,sales,stock,img_path imgPath from book
where
<!-- trim标签可以修改sql语句
属性:
prefix:前缀,表示trim标签内部的sql拼接完毕之后,最前面加的关键字
prefixOverrides:前缀覆盖,表示可以指定一个sql关键字将trim标签内部的
sql拼接完毕之后最前面多出来的指定关键字给删除掉。
suffix;后缀,表示trim标签内部的sql拼接完毕之后,最后面加的关键字
suffixOverrides:后缀覆盖。表示可以指定一个sql关键字将trim标签内部的
sql拼接完毕之后最后面多出来的指定关键字给删除掉。
-->
<trim prefixOverrides="and|or" suffixOverrides="and|or">
<if test="title != null and title != '' ">
title = #{title} and
</if>
<if test="author != null and author != '' ">
author = #{author} and
</if>
<if test="price > 0.0">
price = #{price}
</if>
</trim>
</select>
4 set 标签
set 标签作用:可以代替 set 关键字,set 标签可以将 set 标签内部最后面的,
给去掉
需求:如果携带了标题就修改标题,如果携带了作者信息就修改作者,如果都携带了,都修改。
<update id="updateBookByMap">
update book
set
<if test="title != null and title != '' ">
title = #{title},
</if>
<if test="author != null and author != '' ">
author= #{author}
</if>
where id=#{id}
</update>
针对这种问题,有两种解决方案:
第一种解决方案:使用 set 标签代替 set 关键字
<update id="updateBookByMap">
update book
<set>
<if test="title != null and title != '' ">
title = #{title},
</if>
<if test="author != null and author != '' ">
author= #{author}
</if>
</set>
where id=#{id}
</update>
第二种解决方案:使用 trim 标签
<update id="updateBookByMap">
update book
<trim prefix="set" prefixOverrides="," suffixOverrides=",">
<if test="title != null and title != '' ">
title = #{title},
</if>
<if test="author != null and author != '' ">
author= #{author}
</if>
</trim>
where id=#{id}
</update>
5 choose (when, otherwise)
choose (when, otherwise):相当于 javaweb 学过的<c:choose>进行多分支判断需求:如果携带书名,就用书名查询,如果携带了作者就用作者查询,如果携带了价格,就用价格查询。如果这三个条件都携带了,就按着顺序查询(只能走其中条件。) choose、when、otherwise 使用是有顺序的。只会走其中一个条件
<select id="getBooksByMap" resultType="com.atguigu.bean.Book">
select id,title,author,price,sales,stock,img_path imgPath from book
where
<choose>
<when test="title != null and title != ''">
title = #{title}
</when>
<when test="author != null and author != ''">
author = #{author}
</when>
<when test="price != null ">
price = #{price}
</when>
<otherwise>
1=1
</otherwise>
</choose>
</select>
6 foreach 标签
foreach 标签:类似 javaweb 学过的<c:foreach>遍历集合|数组使用的
批量查询操作:
遍历集合
<select id="getBooksByIds" resultType="com.atguigu.bean.Book">
select id,title,author,price,sales,stock,img_path imgPath
from book
where
id in
<!--
foreach标签:遍历集合和数组
collection:表示要遍历的集合
item:指定一个变量接收集合中遍历出来的元素
separator:指定元素与元素之间的分隔符
open:当foreach标签遍历完集合中所有的元素之后,在元素的最前面加的sql字符串
close:当foreach标签遍历完集合中所有的元素之后,在元素的最后面加的sql字符串
-->
<foreach collection="list" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</select>
遍历数组:
<select id="getBooksByIds" resultType="com.atguigu.bean.Book">
select id,title,author,price,sales,stock,img_path imgPath
from book
where
id in
<foreach collection="array" item="id" separator="," open="(" close=")"> <!--array-->
#{id}
</foreach>
</select>
批量插入操作
<insert id="batchInsert">
insert into user values
<foreach collection="list" item="user" separator="," > <!--按照表的顺序-->
(#{user.uid},#{user.username},#{user.password},#{user.email})
</foreach>
</insert>
7 特殊字符
遇到&,“”,<等 mybatis 不支持的特殊字符,换成他们的实体名称。(W3SCHOOL 手册)
针对 SQL 语句中的特殊字符,有两种解决方案:
第一种:使用特殊字符的实体名称
第二种:使用<![CDATA[sql 语句]]>
3.8 逆向工程
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>
<!--
无Example等内容
<context id="Mysql" targetRuntime="MyBatis3Simple" defaultModelType="flat">
-->
<!-- 有Example查询条件内容 -->
<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/bookstore?serverTimezone=GMT%2B8&useSSL=false"
userId="root"
password="abc123">
</jdbcConnection>
<!-- 默认false,把JDBC DECIMAL 和 NUMERIC 类型解析为 Integer,为 true时把JDBC DECIMAL 和NUMERIC 类型解析为java.math.BigDecimal -->
<javaTypeResolver>
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<!-- targetProject:生成Entity类的路径 -->
<javaModelGenerator targetProject=".\src\main\java" targetPackage="com.fjw.bean">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<property name="enableSubPackages" value="false" />
<!-- 从数据库返回的值被清理前后的空格 -->
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!-- targetProject:XXXMapper.xml映射文件生成的路径 -->
<sqlMapGenerator targetProject=".\src\main\java" targetPackage="com.fjw.dao">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<property name="enableSubPackages" value="false" />
</sqlMapGenerator>
<!-- targetPackage:Mapper接口生成的位置 -->
<javaClientGenerator type="XMLMAPPER" targetProject=".\src\main\java" targetPackage="com.fjw.dao">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<property name="enableSubPackages" value="false" />
</javaClientGenerator>
<!-- 数据库表名字和我们的entity类对应的映射指定 -->
<table tableName="books" domainObjectName="Book"/>
<!-- 有些表的字段需要指定java类型
<table schema="" tableName="">
<columnOverride column="" javaType="" />
</table> -->
</context>
</generatorConfiguration>
pom.xml
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<!-- mybatis-generator-core -->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.7</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.7</version>
<configuration>
<configurationFile>src/main/resources/generatorConfig.xml</configurationFile>
<verbose>true</verbose>
<overwrite>true</overwrite>
</configuration>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
在maven的plugins 点击即可生成
4 ssm整合
第一步:导入 jar 包:
Spring+SpringMVC+MyBatis+MyBatis-spring 、 mysql 、 druid 、 JSTL 、Commons-fileupload、Commons-io、Json 的 3 个 jar 包、log4j
第二步:在 web.xml 文件中配置 Spring 的 ContextLoaderListener,SpringMVC的前端控制器、两个 Filter
第三步:
创建 springmvc.xml
扫描包[@controller+@ControllerAdvice]
配置内部资源视图解析器
mvc:default-servlet-handler
mvc:annotation-driven
创建 applicationContext.xml
扫描包[除了@controller+@ControllerAdvice]
context:property-placeholder location
属性配置数据源对象
配置数据源事务管理器
tx:annotation-driven transaction-manager=”” SqlSessionFatcoryBean 对象
dataSource:
configLocation:加载 mybatis 的全局配置文件的
MapperScannerConfigurer 对象:
批量扫描 dao 层的 mapper 接口
创建 mybatis-config.xml
需要在配
第四步:编写软件三层架构,并进行测试
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--1 配置spring的ContextLoaderListener-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!--2 配置springmvc前端控制器-->
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern><!--不会匹配到*.jsp-->
</servlet-mapping>
<!--3 配置字符编码拦截器-->
<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>
<!--4 将post转换为put|delete-->
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
applicationContext.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:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--1 配置扫描包-->
<context:component-scan base-package="com.xx">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<context:exclude-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
</context:component-scan>
<!--2 加载jdbc配置文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--3 配置数据源信息-->
<bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource" >
<property name="url" value="${jdbc.jdbcUrl}"/>
<property name="driverClassName" value="${jdbc.driverClass}"/>
<property name="username" value="${jdbc.userName}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--4 配置数据源事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="druidDataSource"></property>
</bean>
<!--5 开启基于注解的事务支持-->
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
<!--6 sqlSessionFactoryBean-->
<bean class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="druidDataSource"></property>
<property name="configLocation" value="classpath:mybatis-config.xml"></property>
</bean>
<!--7 MapperScannerConfigurer 扫描-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.xx.dao"></property>
</bean>
</beans>
springMVC.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:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--1 配置扫描controller use-default-filters="false"不在全包扫描,只扫下面包括的-->
<context:component-scan base-package="com.xx" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<context:include-filter type="annotation"
expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
</context:component-scan>
<!--2 配置内部资源视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!--多部件解析器 文件上传 id值是固定,变了就错-->
<bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--指定文件上传的编码格式-->
<property name="defaultEncoding" value="UTF-8"></property>
<!--指定文件上传文件的最大值-->
<property name="maxUploadSize" value="#{500*1024*1024}"></property>
</bean>
<!--3 处理静态资源-->
<mvc:default-servlet-handler/>
<!--4.处理静态资源带来的接口不能访问-->
<mvc:annotation-driven/>
</beans>
rScannerConfigurer">
###### springMVC.xml
```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:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--1 配置扫描controller use-default-filters="false"不在全包扫描,只扫下面包括的-->
<context:component-scan base-package="com.xx" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<context:include-filter type="annotation"
expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
</context:component-scan>
<!--2 配置内部资源视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!--多部件解析器 文件上传 id值是固定,变了就错-->
<bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--指定文件上传的编码格式-->
<property name="defaultEncoding" value="UTF-8"></property>
<!--指定文件上传文件的最大值-->
<property name="maxUploadSize" value="#{500*1024*1024}"></property>
</bean>
<!--3 处理静态资源-->
<mvc:default-servlet-handler/>
<!--4.处理静态资源带来的接口不能访问-->
<mvc:annotation-driven/>
</beans>