Spring ¶
简介 ¶
Spring:春天—->给软件行业带来了春天
2002,首次推出 Spring 框架雏形:interface 21 框架
Spring 框架即以 interface 21框架为基础,经过重新设计,并不断丰富其内涵,于2004/3/24 发布了 Srping 1.0正式版
Rod Johnson,Spring Framework创始人,他是悉尼博士,专业确实音乐
Spring 理念:是现有技术更加容易使用,是一个大杂烩,整合现有技术框架
SSH:Struct2 + Spring + Hibernate
SSM:SpringMVC + Spring +Mybatis
官方下载地址: https://repo.spring.io/release/org/springframework/spring
github地址: https://github.com/spring-projects/spring-framework
maven导入
xml1<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc --> 2<dependency> 3 <groupId>org.springframework</groupId> 4 <artifactId>spring-webmvc</artifactId> 5 <version>5.2.14.RELEASE</version> 6</dependency> 7<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc --> 8<dependency> 9 <groupId>org.springframework</groupId> 10 <artifactId>spring-jdbc</artifactId> 11 <version>5.2.14.RELEASE</version> 12</dependency>
优点 ¶
- Spring 是一个开源的免费框架(容器)
- Spring 是一个轻量级的,非侵入式的框架
- 控制反转(IOC)、面向切面编程(AOP)
- 支持事务的处理,对框架整合的支持
总结:Spring 是一个轻量级的控制反转(IOC)与面向切面编程(AOP)的框架
组成 ¶

扩展 ¶
- Spring boot
- 一个快速开发的脚手架
- 基于 SpringBoot 可以快速开发单个微服务
- 约定大于配置
- Spring Cloud
- SpringCloud 是基于 SpringBoot 实现的
因为现在大多公司都在使用 SpringBoot 进行快速开发,学习 SpringBoot的前提是掌握 Spring 和SrpingMVC,承上启下的作用
Spring 弊端:发展太久,违背了原来的理念,配置十分繁琐,“配置地狱”
IOC ¶
理论推导 ¶
以前的业务中
1UserDao
2 UserMysqlDaoImpl
3 UserOrcleDaoImpl
4
5UserService
6 UserServiceImpl #保留一个dao的变量,并实例化
7
8#当dao新增时,需要修改UserviceImpl中代码,现在采用一个 setter 设置dao变量值,由调用者判断使用哪一个 dao,当dao新增时不需要修改UserServiceImpl中代码,实现控制反转HelloSpring ¶
编写HelloService类
1public class HelloService {
2 private String name;
3
4 public void say() {
5 System.out.println("我的名字是:" + name);
6 }
7
8 public String getName() {
9 return name;
10 }
11
12 public void setName(String name) {
13 this.name = name;
14 }
15}**在 classpath 下编写 bean 配置文件 spring-beans.xml **
1<?xml version="1.0" encoding="UTF-8"?>
2<beans xmlns="http://www.springframework.org/schema/beans"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xsi:schemaLocation="http://www.springframework.org/schema/beans
5 https://www.springframework.org/schema/beans/spring-beans.xsd">
6
7 <!-- 声明 bean,默认 scope 为 singleton 单例 -->
8 <bean id="helloService" class="org.lei.ch01.service.HelloService">
9 <!-- 通过 set 方法设置属性值 -->
10 <property name="name" value="小唐"/>
11 </bean>
12
13</beans>Main 方法
1public class Main {
2 public static void main(String[] args) {
3 // 在 classpath 下加载 spring-beans.xml bean 配置文件
4 ApplicationContext context = new ClassPathXmlApplicationContext("spring-beans.xml");
5 // 通过 class 获取实例(也可通过名字获取实例)
6 HelloService helloService = context.getBean(HelloService.class);
7 // 调用实例方法
8 helloService.say();
9 }
10}Hello对象由Spring创建,开发者不创建,这个叫做控制反转
IOC 即 对象由spring创建、管理、装配
IOC创建对象的方法 ¶
默认调用无参构造
java1 <bean id="hello" class="com.lei.Hello"> 2 <property name="name" value="小唐"></property> 3</bean>有参构造
通过下标
xml1<bean id="hello" class="com.lei.Hello"> 2 <constructor-arg index="0" value="小唐"/> 3 <constructor-arg index="1" value="21"/> 4</bean>通过参数类型
xml1<bean id="hello" class="com.lei.Hello"> 2 <constructor-arg type="java.lang.String" value="小唐"/> 3 <constructor-arg type="int" value="21"/> 4</bean>通过参数名字
xml1<bean id="hello" class="com.lei.Hello"> 2 <constructor-arg name="name" value="小唐" /> 3 <constructor-arg name="age" value="18" /> 4</bean>
在bean配置文件加载时,容器管理的对象就已经初始化了
依赖注入 ¶
构造器注入
1<bean id="hello" class="com.lei.Hello">
2 <constructor-arg name="name" value="小唐" />
3 <constructor-arg name="student" ref="student" />
4</bean>Set方式注入
- 依赖注入,本质是
Set注入- 依赖:bean 对象的创建依赖于容器
- 注入:bean 对象中的所有属性,由容器注入
1<!-- 以下为一个bean中的属性常用的注入方式 -->
2<bean id="user" class="com.lei.beans.User">
3 <!-- 普通注入 -->
4 <property name="name" value="小唐"/>
5 <property name="age" value="23"/>
6 <!-- bean 注入 -->
7 <property name="address" ref="address"/>
8 <!-- list 注入 -->
9 <property name="books">
10 <list>
11 <value>三国演义</value>
12 <value>水浒传</value>
13 </list>
14 </property>
15 <!-- set注入 -->
16 <property name="hobbies">
17 <set>
18 <value>打游戏</value>
19 <value>打羽毛球</value>
20 </set>
21 </property>
22 <!-- properties 注入 -->
23 <property name="config" >
24 <props>
25 <prop key="user">lei</prop>
26 <prop key="password">123456</prop>
27 </props>
28 </property>
29 <!-- map 注入-->
30 <property name="people">
31 <map>
32 <entry key="name" value="小明" />
33 <entry key="age" value="二十九"/>
34 </map>
35 </property>
36</bean>扩展方式注入
可以使用 cnamespace 和 pnamespace 进行注入
导入 c/p 命名空间约束
xml1<beans ... 2 xmlns:p="http://www.springframework.org/schema/p" 3 xmlns:c="http://www.springframework.org/schema/c"> 4 5</beans>注入方式
xml1 <!-- p 命名空间,属性注入--> 2 <bean id="student" class="com.lei.beans.Student" p:name="小唐" p:age="18"/> 3 <!-- c 命名空间,构造器注入--> 4 <bean id="student1" class="com.lei.beans.Student" c:name="小明" c:age="21"/>
Bean的作用域 ¶
| Scope | Description |
|---|---|
| singleton | 单例模式,从容器中取得的是唯一对象,Spring默认机制 |
| prototype | 原型模式,每次从容器中取得都会产生一个新对象 |
| request | web 开发中使用 |
| session | web 开发中使用 |
| application | web 开发中使用 |
| websocket | Scopes a single bean definition to the lifecycle of a WebSocket. Only valid in the context of a web-aware Spring ApplicationContext. |
有关作用域配置
1<!-- 单例模式,默认机制 -->
2<bean id="student" class="com.lei.beans.Student" p:name="小唐" scope="singleton"/>
3
4<!-- 原型模式 -->
5<bean id="student" class="com.lei.beans.Student" p:name="小唐" scope="prototype"/>Bean的自动装配 ¶
- 自动装配是 Spring 满足 bean 依赖的一种方式
- Spring 会在上下文自动寻找,并自动给 bean 装配
Spring中有三种装配方式
- 在xml中显示的配置
- 在java中显示的配置,autowire
- 隐式的自动装配 bean,注解开发(重点)
autowire
1<!-- 自动在beans配置文件的上下文找到需要装配的 bean进行装配 -->
2
3<!-- byName,配置的beans上下文中,需要装配的bean名字唯一 -->
4<bean id="student" class="com.lei.beans.Student" autowire="byName"/>
5
6<!-- byType,配置的beans上下文中,需要装配的 bean 类型唯一-->
7<bean id="student" class="com.lei.beans.Student" autowire="byType"/>注解实现装配
导入注解注入依赖,并开启配置
xml1<?xml version="1.0" encoding="UTF-8"?> 2<beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:context="http://www.springframework.org/schema/context" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans 6 https://www.springframework.org/schema/beans/spring-beans.xsd 7 http://www.springframework.org/schema/context 8 https://www.springframework.org/schema/context/spring-context.xsd"> 9 10 <!-- 开启上下文通过注解装配beans --> 11 <context:annotation-config/> 12 13</beans>@Autowired 默认按照 byNmae 注入
java1/* 2* @Autowired 自动从beans中找到对应的bean并装配 3* 可用在set方法上,也可以用在字段上,用在字段上时可以省略set方法,通过byName匹配 4* @Autowired注解,有一个属性 required,默认为true,如果为 false,当 beans 中没有找到指定的 bean 也不会报错 5* 可以与@Qualifier注解联合使用,通过该注解的 value 属性指定需要匹配bean的id名 6*/ 7public class User { 8 private String name; 9 @Autowired(required = false) 10 @Qualifier(value = "dog1") 11 private Dog dog; 12 @Autowired 13 private Cat cat; 14}@Resource 默认按照 byType注入
需要导入反射依赖
xml1<dependency> 2 <groupId>javax.annotation</groupId> 3 <artifactId>javax.annotation-api</artifactId> 4 <version>1.3.2</version> 5</dependency>使用方法如下
java1/* 2* @Resource 是可以给其 name 属性指定需要注解 bean 的id 3* @Resource 是通过 byType 进行匹配的 4*/ 5public class User { 6 private String name; 7 @Resource(name = "dog") 8 private Dog dog; 9 @Resource(name = "cat") 10 private Cat cat; 11}
注解开发 ¶
Spring4后,使用注解开发必须导入spring-aop包
xml与注解
- xml更加万能,适用于任何注解,维护方便简单
- 注解 不是自己的类是用不了,维护相对麻烦
xml与注解最佳实战
xml 用来管理bean
注解负责完成属性的注入
使用过程中需要注意让注解生效:必须开启注解功能支持
xml1<!-- 开启上下文通过注解装配beans --> 2<context:annotation-config/> 3 4<!-- 开启自动扫描使用注解的包,并装配beans,比 annotation-config 多个指定扫描包的功能 --> 5<context:component-scan base-package="com.lei.beans"/>
JavaConfig实现配置 ¶
- 使用 JavaConfig 进行配置,完全脱离 xml 文件配置
- 和 xml 文件配置类似,可以定义需要扫描的包,配置类的引入以及Bean的定义及命名等
1@Configuration //代表该类为配置类
2@Import(Config2.class) //导入另一个配置类
3@ComponentScan("com.lei.dao") //自动扫描某个包
4public class AppConfig {
5 @Bean // Bean,方法名为 bean的 id,也可以通过 @Bean(value="oname")定义名字
6 @Scope("prototype") //bean 作用域(单例、原型)
7 User geer(){
8 return new User();
9 }
10
11 public static void main(String[] args) {
12 // 通过配置文件上下文获取容器中组件
13 ApplicationContext context=new AnnotationConfigApplicationContext(AppConfig.class);
14 User user=context.getBean("geer",User.class);
15 System.out.println(user);
16 }
17}AOP ¶
代理模式 ¶
代理模式
- 代理模式分类
- 静态代理
- 动态代理
- 代理模式的好处
- 可以使真实角色的操作更加纯粹,不需要关注一些公共业务
- 公共业务可以交给代理角色,实现业务分工
- 公共业务发生扩展时,容易管理
静态代理
- 抽象角色:一般使用接口或者抽象类
- 真实角色:被代理的角色
- 代理角色:代理真实角色,代理后,一般需要做附属操作
- 客户:访问代理对象的人
动态代理
- 动态代理底层都是通过反射来实现
- 动态代理与静态代理角色一样
- 动态代理的代理类是动态生成的
- 动态代理分为两类
- 基于接口:JDK 动态代理
- 基于类:cglib
- java字节码实现:javasist
- JDK动态代理与cglib区别
- java动态代理–利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。(基于接口)
- cglib动态代理–利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。(基于继承)
- 对比:cglib代理比jdk代理快
jdk实现动态代理
1/*
2* 代理对象执行方法 实现 InvocationHandler这个接口,并重写invoke(Object proxy, Method method, Object[] args)方法
3* proxy:代理对象
4* method:代理对象执行的方法
5* args:代理对象执行的方法参数
6*/
7public class MiddleManInvocationHandler implements InvocationHandler {
8 Object target; //target为被代理的对象
9 public MiddleMan(Object target) {
10 this.target = target;
11 }
12 public Object getProxy(){
13 return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),this);
14 }
15 @Override
16 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
17 System.out.println(proxy.getClass().getName());
18 method.invoke(target,args);
19 return null;
20 }
21}
22
23/*
24* 通过 newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) 可以获取代理对象
25* loader:被代理对象类加载器
26* interfaces:被代理对象实现接口
27* h:代理对象方法执行
28*/
29Business proxy= (Business) Proxy.newProxyInstance(Business.class.getClassLoader(), Business.class.getInterfaces(),handler);AOP简介 ¶
- 意为面向切面编程,OOP 把系统看作多个对象的交互,AOP把系统分解为不同的关注点,或者称之为切面(Aspect),本质上为动态代理
- 切面(ASPECT):横切关注点 被模块化 的特殊对象。即,他是一个类
- 通知(Advice):切面必须要完成的工作。即,他是类中的一个方法
- 目标(Target):被通知对象
- 代理(Proxy):向目标对象应用通知之后创建的对象
- 切入点(PointCut):切面通知 执行的“地点”的定义
- 连接点(JointPoint):与切入点匹配的执行点
在Java平台上,对于AOP的织入,有3种方式:
- 编译期:在编译时,由编译器把切面调用编译进字节码,这种方式需要定义新的关键字并扩展编译器,AspectJ就扩展了Java编译器,使用关键字aspect来实现织入;
- 类加载器:在目标类被装载到JVM时,通过一个特殊的类加载器,对目标类的字节码重新“增强”;
- 运行期:目标对象和切面都是普通Java类,通过JVM的动态代理功能或者第三方库实现运行期动态织入。
AOP装配 ¶
引入依赖,spring对 aop的支持
1<dependency>
2 <groupId>org.springframework</groupId>
3 <artifactId>spring-aspects</artifactId>
4 <version>5.2.14.RELEASE</version>
5</dependency>使用xml配置文件进行aop装配(两种方式)
方法一:Spring原生接口,切面实现某个类
创建接口 People
创建接口实现类 Student
创建切面,并实现对应接口
MethodBeforeAdvice在目标方法执行前执行AfterReturningAdvice在目标方法执行后执行
java1public class LogAop implements MethodBeforeAdvice { 2/** 3 * @param method 要执行的目标对象方法 4 * @param objects 参数列表 5 * @param o 目标对象,即我们原本需要从容器中取得的对象,现在从容器中取得的对象是动态代理生成的 6 * */ 7@Override 8 public void before(Method method, Object[] objects, Object o) throws Throwable { 9 System.out.println("日志打印"+method.getName()); 10 } 11}配置beans
xml1<?xml version="1.0" encoding="UTF-8"?> 2<beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:aop="http://www.springframework.org/schema/aop" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans 6 https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> 7 8 <bean id="user" class="com.lei.beans.Student"/> 9 <bean id="log" class="com.lei.beans.LogAop"/> 10 11<!--方式一:使用 spring 原生接口;配置aop需要导入aop约束--> 12 <aop:config> 13<!-- 切入点,execution:表达式,execution(要执行的位置***)--> 14 <aop:pointcut id="pointcut" expression="execution(* com.lei.beans.Student.*(..))" /> 15<!-- 执行环绕增加--> 16 <aop:advisor advice-ref="log" pointcut-ref="pointcut" /> 17 </aop:config> 18</beans>此时创建切面(aop)已经装配成功,调用Student的方法,会自动在相应时机执行通知(自定义方法)
注意:从容器中取得的 Student对象必须使用接口 People 进行引用,因为现在从容器取得的为动态代理为spring通过 JDK 原生接口生成的;JDK 动态代理基于接口
方法二:自定义切面
同样创建,接口 People,实现类 Student
创建自定义切面 MyAop,不需要实现某个接口,然后在 beans.xml 配置文件进行配置
java1public class MyAop { 2 public void before(){ 3 System.out.println("方法执行前"); 4 } 5 public void after(){ 6 System.out.println("方法执行后"); 7 } 8}beans 配置
xml1<?xml version="1.0" encoding="UTF-8"?> 2<beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:aop="http://www.springframework.org/schema/aop" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans 6 https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> 7 8 <bean id="user" class="com.lei.beans.User" /> 9 <bean id="myaop" class="com.lei.beans.MyAop"/> 10<!-- 11 使用 自定义切面 12 配置aop需要导入aop约束 13--> 14 <aop:config> 15<!-- 自定义切面--> 16 <aop:aspect ref="myaop"> 17<!-- 自定义切入点--> 18 <aop:pointcut id="point" expression="execution(* com.lei.beans.*.*(..))"/> 19<!-- 自定义通知--> 20 <aop:before method="before" pointcut-ref="point"/> 21 <aop:after method="after" pointcut-ref="point"/> 22 </aop:aspect> 23 </aop:config> 24</beans>
自定义切面 与 使用spring原生api 区别:自定义切面相对简单,但是功能没有 spring原生 api多,不能获取执行的方法名以及需被 切入 的对象
使用注解装配AOP ¶
自定义切面类并添加相关注解
java1@Aspect /*代表该类为一个切面*/ 2public class MyAop { 3 @Before("execution(* com.lei.beans.*.*(..))") /*指定通知、切入点*/ 4 public void before(){ 5 System.out.println("方法执行前"); 6 } 7 @After("execution(* com.lei.beans.*.*(..))") 8 public void after(){ 9 System.out.println("方法执行后"); 10 } 11 @Around("execution(* com.lei.beans.*.*(..))") 12 public void around(ProceedingJoinPoint pjp) throws Throwable{ 13 System.out.println("环绕在前"); 14 //方法执行,可以通过pjp参数获取方法执的信息 15 pjp.proceed(); 16 System.out.println("环绕在后"); 17 } 18}在beans.xml中配置自动识别切面
xml1<!-- 开启注解支持,proxy-target-class目标执行的class,默认为false 表示JDK的Annotation,true 表示 cglib --> 2<aop:aspectj-autoproxy proxy-target-class="true" />拦截器类型(通知)
- @Before:这种拦截器先执行拦截代码,再执行目标代码。如果拦截器抛异常,那么目标代码就不执行了;
- @After:这种拦截器先执行目标代码,再执行拦截器代码。无论目标代码是否抛异常,拦截器代码都会执行;
- @AfterReturning:和@After不同的是,只有当目标代码正常返回时,才执行拦截器代码;
- @AfterThrowing:和@After不同的是,只有当目标代码抛出了异常时,才执行拦截器代码;
- @Around:能完全控制目标代码是否执行,并可以在执行前后、抛异常后执行任意拦截代码,可以说是包含了上面所有功能
使用AOP非常简单,一共需要三步:
- 定义执行方法,并在方法上通过AspectJ的注解告诉Spring应该在何处调用此方法;
- 标记
@Component和@Aspect; - 在
@Configuration类上标注@EnableAspectJAutoProxy。
AOP实例 ¶
使用AOP统一处理controller异常和进入控制器之前设置当前请求上下文
1@Aspect
2@Component
3public class AopException {
4 // value和pointcut都是定义切入位置,定义了pointcut,value属性失效
5 //throwing 指定方法接收异常的形参名
6 @AfterThrowing(value = "execution(* com.lei.controller.*.*(..))",throwing="th")
7 public void chuliException(Throwable th) throws IOException {
8 // RequestContextHolder 通过 ThreadLocal 实现的上下文 request 对象
9 RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
10 HttpServletRequest request = ((ServletRequestAttributes)requestAttributes).getRequest();
11 HttpServletResponse response = ((ServletRequestAttributes)requestAttributes).getResponse();
12 response.reset();
13 response.setCharacterEncoding("UTF-8");
14 response.setHeader("Content-Type", "text/json;charset=UTF-8");
15 String json=JSON.toJSONString(WrapperResponse.fail(th.getMessage()));
16 PrintWriter writer=null;
17 try {
18 writer=response.getWriter();
19 writer.println(json);
20 }catch (Exception e){
21 chuliException(e);
22 }finally {
23 writer.flush();
24 writer.close();
25 }
26 }
27 @Before("execution(public * com.lei.controller.*.*(..))")
28 public void setContext(JoinPoint joinPoint){
29 Object[] args=joinPoint.getArgs();
30 for (Object o:args){
31 if (o instanceof HttpServletRequest){
32 HttpServletRequest request= (HttpServletRequest) o;
33 MyContextHolder.getContext().setProperties("sessionId",request.getSession().getId());
34 }
35 }
36 }
37 @After("execution(public * com.lei.bo.*.*(..))")
38 public void clearContext(){
39 MyContextHolder.clear();
40 }
41}使用注解实现AOP基本使用
1@Component //这个组件一定得加入到容器才行
2@Aspect
3public class SpringLogAspect {
4
5 //定义一个切入点:指定哪些方法可以被切入(如果是别的类需要使用 请用该方法的全类名)
6 @Pointcut("execution(* com.fsx.run.service..*.*(..))")
7 public void pointCut() {
8 }
9
10 @Before("pointCut()")
11 public void doBefore(JoinPoint joinPoint) {
12 System.out.println("AOP Before Advice...");
13 }
14
15 @After("pointCut()")
16 public void doAfter(JoinPoint joinPoint) {
17 System.out.println("AOP After Advice...");
18 }
19
20 @AfterReturning(pointcut = "pointCut()", returning = "returnVal")
21 public void afterReturn(JoinPoint joinPoint, Object returnVal) {
22 System.out.println("AOP AfterReturning Advice:" + returnVal);
23 }
24
25 @AfterThrowing(pointcut = "pointCut()", throwing = "error")
26 public void afterThrowing(JoinPoint joinPoint, Throwable error) {
27 System.out.println("AOP AfterThrowing Advice..." + error);
28 System.out.println("AfterThrowing...");
29 }
30
31 // 环绕通知:此处有一个坑,当AfterReturning和Around共存时,AfterReturning是获取不到返回值的
32 //@Around("pointCut()")
33 //public void around(ProceedingJoinPoint pjp) {
34 // System.out.println("AOP Aronud before...");
35 // try {
36 // pjp.proceed();
37 // } catch (Throwable e) {
38 // e.printStackTrace();
39 // }
40 // System.out.println("AOP Aronud after...");
41 //}
42
43}整合mybatis ¶
步骤
- 导入相关 jar包
- junit
- mybatis
- mysql 数据库
- spring 相关
- aop 织入
- mybatis-spring【new】
- 编写配置文件
- 测试
1<dependencies>
2 <dependency>
3 <groupId>org.springframework</groupId>
4 <artifactId>spring-webmvc</artifactId>
5 <version>5.2.14.RELEASE</version>
6 </dependency>
7 <dependency>
8 <groupId>org.springframework</groupId>
9 <artifactId>spring-aspects</artifactId>
10 <version>5.2.14.RELEASE</version>
11 </dependency>
12 <dependency>
13 <groupId>org.mybatis</groupId>
14 <artifactId>mybatis</artifactId>
15 <version>3.5.7</version>
16 </dependency>
17 <dependency>
18 <groupId>org.mybatis</groupId>
19 <artifactId>mybatis-spring</artifactId>
20 <version>2.0.6</version>
21 </dependency>
22 <dependency>
23 <groupId>mysql</groupId>
24 <artifactId>mysql-connector-java</artifactId>
25 <version>5.1.49</version>
26 </dependency>
27 <dependency>
28 <groupId>org.springframework</groupId>
29 <artifactId>spring-jdbc</artifactId>
30 <version>5.2.14.RELEASE</version>
31 </dependency>
32</dependencies>mybatis回顾 ¶
导入mybatis依赖和mysql驱动
1<dependency>
2 <groupId>org.mybatis</groupId>
3 <artifactId>mybatis</artifactId>
4 <version>3.5.7</version>
5</dependency>
6<dependency>
7 <groupId>mysql</groupId>
8 <artifactId>mysql-connector-java</artifactId>
9 <version>5.1.49</version>
10</dependency>创建dao接口、mapper、model类一一对应数据库表
mapper,一个dao接口对应一个mapper
xml1<?xml version="1.0" encoding="UTF-8" ?> 2<!DOCTYPE mapper 3 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 4 "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 5<!-- namespace叫做命名空间,唯一值的,要求使用dao接口的全限定名称 --> 6<mapper namespace="com.lei.dao.UserDao"> 7 <select id="selectAll" resultType="com.lei.model.User"> 8 select * from user 9 </select> 10 <select id="selectById" resultType="com.lei.model.User"> 11 select * from user where class_id=#{id} and gender=#{gender} 12 </select> 13 <insert id="insertOne" > 14 insert into user (class_id,name,gender,score) values (#{class_id},#{name},#{gender},#{score}) 15 </insert> 16 <select id="selectByArr" resultType="com.lei.model.User"> 17 select * from user where class_id in 18 <foreach collection="array" item="item" open="(" close=")" separator=","> 19 #{item} 20 </foreach> 21 </select> 22<!-- 23paramterType 24 使用简单类型的参数,在 #{} 中的名字可以随便写,parameterType 一般不写,mybatis会自动识别 25 传递多个参数 26 1.使用在方法处使用:@Param命名参数 27 List<Student> selectStuds(@Param("id") String id,@Param("age") Integer age); 28 2.传递对象 29 #{} 中必须为对象的属性 30 3.传递map 31 #{} 中必须为map的key 32 33## 和 $ 34 #{}:占位符,可以防止sql注入 35 ${}:字符串拼接 36 37模糊查询 38 方式1:使用 ${} ,拼接sql(了解,不常用) 39 select * from t_student where name like '%${value}%' 40 方式2:使用 #{} ,占位符,直接传入拼接好的条件字符串 41 String value="%z%"; 42 select * from t_student where name like #{value} 43 方式3:使用 #{} ,占位符,传入条件字符串,在sql中拼接,sql中空格相当于拼接 44 select * from t_student where name like % #{value} % 45 46resultType与resultMap 47 resultType 可以为domain类型(常用),也可以是map;在domain类型封装不了结果类型时,使用map;例如:根据姓名分组,并返回每一个姓名对应的数量,使用map进行封装;查询字段与doamin属性不一致时 都使用map 48 resultMap domain中类型属性名与数据库表字段名一一对应 49 <resultMap id="唯一名称" type="domain类型"> 50 <id property="domain中属性名" column="主键字段" /> 51 <result property="domain中属性名" column="非主键字段" /> 52 </resultMap> 53 <select id="" resultMap="resultMap的唯一id" /> 54 55动态sql:有什么查询条件,在sql语句where后添加什么条件 56 <where>标签里面必有<if>标签,如果有条件,则展现where关键字,如果没有条件则不展现where关键字;并且<where>标签会自动屏蔽掉第一个连接符 and/or 57 <if test=" 属性名1!=null and 属性名1!='' " > </if> 58 <foreach>标签用来遍历传过来的数组,常用在sql语句的in关键字后 59 <where> 60 <if test="条件"> name like '%'#{name}'%' </if> 61 </where> 62 <foreach collection="array/list" item="" open="循环开始符号" close="循环结束符号" separator="元素之间分隔符" /> 63 64sql片段:常用在重复率高且复杂的子查询,大量的sql片段会降低代码的可读性 65 定义:<sql id="sql片段的唯一标识">重复的sql代码</sql> 66 引用:<include refid="sql片段id" /> 67--> 68</mapper>dao接口
java1public interface UserDao { 2 List<User> selectAll(); 3 List<User> selectById(@Param("id") int class_id,@Param("gender") String gender); 4 int insertOne(User user); 5 List<User> selectByArr(int[] class_id); 6}mybatis主配置文件
xml1<?xml version="1.0" encoding="UTF-8" ?> 2<!DOCTYPE configuration 3 PUBLIC "-//mybatis.org//DTD Config 3.0//EN" 4 "http://mybatis.org/dtd/mybatis-3-config.dtd"> 5<configuration> 6 <!--mybatis设置,控制其全局行为--> 7 <settings> 8 <!--设置mybatis输出日志--> 9 <setting name="logImpl" value="STDOUT_LOGGING"/> 10 </settings> 11 <!-- 和spring整合后 environments配置将废除--> 12 <environments default="development"> 13 <environment id="development"> 14 <!-- type="JDBC" 代表使用JDBC的提交和回滚来管理事务 --> 15 <transactionManager type="JDBC" /> 16 <!-- mybatis提供了3种数据源类型,分别是:POOLED,UNPOOLED,JNDI --> 17 <!-- POOLED 表示支持JDBC数据源连接池 --> 18 <!-- UNPOOLED 表示不支持数据源连接池 --> 19 <!-- JNDI 表示支持外部数据源连接池 --> 20 <dataSource type="POOLED"> 21 <property name="driver" value="com.mysql.jdbc.Driver"/> 22 <property name="url" value="jdbc:mysql://139.186.140.120:3312/learn?characterEncoding=utf8"/> 23 <property name="username" value="root"/> 24 <property name="password" value="123456"/> 25 </dataSource> 26 27 </environment> 28 </environments> 29 <mappers> 30 <mapper resource="com\lei\dao\UserDao.xml"/> 31 </mappers> 32</configuration>
mybatis配置文件
1<?xml version="1.0" encoding="UTF-8" ?>
2<!DOCTYPE configuration
3 PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
4 "http://mybatis.org/dtd/mybatis-3-config.dtd">
5<configuration>
6 <!--mybatis设置,控制其全局行为-->
7 <settings>
8 <!--设置mybatis输出日志-->
9 <setting name="logImpl" value="STDOUT_LOGGING"/>
10 </settings>
11 <!-- 和spring整合后 environments配置将废除-->
12 <environments default="development">
13 <environment id="development">
14 <!-- type="JDBC" 代表使用JDBC的提交和回滚来管理事务 -->
15 <transactionManager type="JDBC" />
16 <!-- mybatis提供了3种数据源类型,分别是:POOLED,UNPOOLED,JNDI -->
17 <!-- POOLED 表示支持JDBC数据源连接池 -->
18 <!-- UNPOOLED 表示不支持数据源连接池 -->
19 <!-- JNDI 表示支持外部数据源连接池 -->
20 <dataSource type="POOLED">
21 <property name="driver" value="com.mysql.jdbc.Driver"/>
22 <property name="url" value="jdbc:mysql://139.186.140.120:3312/learn?characterEncoding=utf8"/>
23 <property name="username" value="root"/>
24 <property name="password" value="123456"/>
25 </dataSource>
26
27 </environment>
28 </environments>
29 <mappers>
30 <mapper resource="com\lei\dao\UserDao.xml"/>
31 </mappers>
32</configuration>配置maven过滤,使mapper能被编译到war包中
1<build>
2 <resources>
3 <resource>
4 <directory>src/main/java</directory>
5 <includes>
6 <include>**/*.xml</include>
7 </includes>
8 <filtering>false</filtering>
9 </resource>
10 </resources>
11</build>通过主配置文件构建sqlsession工厂,通过工厂获取
SqlSession对象,并执行对应的 sql 语句
1String resource="mybatis_config.xml";
2try(InputStream in= Resources.getResourceAsStream(resource)){
3
4 SqlSessionFactoryBuilder factoryBuilder=new SqlSessionFactoryBuilder();
5 SqlSessionFactory factory=factoryBuilder.build(in);
6 SqlSession session=factory.openSession();
7 /* 通过定位到对应sql语句的id,然后执行
8 String sqlId="com.lei.dao.UserDao"+"."+"selectAll";
9 List<User> studs=session.selectList(sqlId);
10*/
11 /* 通过反射,获取对应的sql语句执行,注意:id和接口方法名一致 */
12 UserDao userDao=session.getMapper(UserDao.class);
13 List<User> studs=userDao.selectAll();
14 for(User s:studs){
15 System.out.println(s);
16 }
17
18 session.close();
19}catch (Exception e){
20 e.printStackTrace();
21}需要注意的点
mapper映射文件的domain起别名 <typeAliases> 标签中
- <typeAlias type=“com.lei.domain.Student” alias=“Student”/>
- <package name=“com,lei,domain” /> ;name:表示在该包下,别名就是类名
指定mapper映射文件位置,<mappers> 标签中
<mapper resource=“com\lei\dao\StudentDao.xml”/>
<mapper class=“com.lei.dao.StudentDao”/> ;找到Dao接口的全限定路径,因为dao接口与mapper进行了绑定,也能被识别
<package name=“com.lei.dao” />; name:指向dao层包,表示该包下所有mapper映射文件加载
mybatis传参方式
- prameterType:写在mapper文件中的一个属性,表示dao接口中方法的参数的数据类型
- 简单类型参数:mybatis把java的基本数据类型和string都看作简单类型 在mapper中获取一个简单类型参数的值,使用
#{任意字符} - 多个参数,使用@Param命名参数(推荐使用)
- 多个参数,使用对象方式#{属性名,javaType=类型名称,jdbcType=数据类型} ,可以直接使用 #{属性名} 来传入
- 多个参数,按位置顺序传参(了解);mybatis3.4版本后#{arg0},#{arg1}等,获取参数
- map传参,通过key获取value值(了解);#{key1},#{key2}
## 和 $ 区别
- #:可以防止sql注入,占位符,使用预编译对象PrepareStatement执行sql,安全
- $:字符串的连接与替换,直接拼接到sql语句中,使用对象Statement执行sql,可以被sql注入,效率低
mybatis 查询结果返回
- mybatis执行sql语句,得到java对象
- resultType结果类型,指sql语句执行结束后,数据转化为java对象,这个java类型是任意的
- mybatis执行sql语句,然后mybatis调用类的无参构造,创建对象
- mybatis把resultSet指定列的值赋值给对象同名属性
- resultType值有两种:mybatis规定的别名、全限定名称
- resultType 返回map
- 列值是map的value
- 且只能查询一条记录返回,多行记录返回会报错
- 列名与属性名不一致的第二种解决办法(第一种是定义resultMap)
- resultType默认原则,同名的列值赋给同名的属性
- 可以使用别名方式查询,别名应该是java类型的属性名
动态sql
Mybatis-Spring(xml) ¶
spring配置文件中配置 mybatis 相关配置,一般新建一个配置文件,后续在spring主配置文件中导入该文件即可;DataSource、SqlsessionFactory、SqlSessionTemplate
xml1<?xml version="1.0" encoding="UTF-8"?> 2<beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans 5 https://www.springframework.org/schema/beans/spring-beans.xsd"> 6 7<!-- DataSource --> 8 <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> 9 <property name="url" value="jdbc:mysql://139.186.140.120:3312/learn?characterEncoding=utf8"/> 10 <property name="username" value="root"/> 11 <property name="password" value="123456"/> 12 </bean> 13<!-- SqlSessionFactory --> 14 <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> 15 <property name="dataSource" ref="dataSource"/> 16<!-- 绑定 mybatis 配置文件,也可以完全取代不绑定 --> 17 <property name="configLocation" value="classpath:mybatis-config.xml"/> 18 <property name="mapperLocations" value="classpath:com/lei/dao/*.xml" /> 19 </bean> 20<!-- sqlSessionTemplate --> 21 <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate"> 22<!-- 只能使用构造方法注入,因为该类没有 set 方法--> 23 <constructor-arg index="0" ref="sqlSessionFactory"/> 24 </bean> 25</beans>mybatis 原配置文件,一般只保留 设置 和别名,可以直接省略
xml1<?xml version="1.0" encoding="UTF-8" ?> 2<!DOCTYPE configuration 3 PUBLIC "-//mybatis.org//DTD Config 3.0//EN" 4 "http://mybatis.org/dtd/mybatis-3-config.dtd"> 5<configuration> 6 <!--mybatis设置,控制其全局行为--> 7 <settings> 8 <!--设置mybatis输出日志--> 9 <setting name="logImpl" value="STDOUT_LOGGING"/> 10 </settings> 11 <!-- 别名配置 --> 12 <typeAliases> 13 <package name="com/lei/pojo"/> 14 </typeAliases> 15</configuration>spring主配置文件
xml1<?xml version="1.0" encoding="UTF-8"?> 2<beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:context="http://www.springframework.org/schema/context" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans 6 https://www.springframework.org/schema/beans/spring-beans.xsd 7 http://www.springframework.org/schema/context 8 https://www.springframework.org/schema/context/spring-context.xsd"> 9<!-- 导入spring 配置的 mybatis--> 10 <import resource="spring-mybatis.xml"/> 11<!-- 下面的方式一 --> 12 <bean id="userMapper" class="com.lei.dao.UserMapperImpl"> 13 <property name="sqlSession" ref="sqlSession"/> 14 </bean> 15<!-- 下面的方式二 --> 16 <bean id="userMappert" class="com.lei.dao.UserMappert"> 17 <property name="sqlSessionFactory" ref="sqlSessionFactory"/> 18 </bean> 19</beans>编写dao接口的实现类并注册到容器中(两种方式)
- 通过注入一个
SqlSessionTemplate对象,获取SqlSessionTemplate对象 - 通过实现一个抽象类
SqlSessionDaoSupport,并注入sqlSessionFactory对象 ,然后通过调用getSqlSession()方法你会得到一个SqlSessionTemplate
- 通过注入一个
通过 SqlSessionTemplate 对象调用 mapper 中对应的 sql 语句
Mybatis-Spring(appConfig) ¶
1@Configuration
2@EnableAspectJAutoProxy
3@ComponentScan("com.lei.*")
4public class AppConfig {
5 @Bean("dataSource")
6 DataSource dataSource(){
7 return new DriverManagerDataSource("jdbc:mysql://139.186.140.120:3312/learn?characterEncoding=utf8","root","123456");
8 }
9 @Bean("sqlSessionFactory")
10 SqlSessionFactory sqlSessionFactory() {
11 SqlSessionFactoryBean factoryBean=new SqlSessionFactoryBean();
12 factoryBean.setDataSource(dataSource());
13/* 绑定mybatis配置文件,其中须指定mapper所在位置 */
14 Resource resource=new ClassPathResource("mybatis-config.xml");
15 factoryBean.setConfigLocation(resource);
16 try {
17 return factoryBean.getObject();
18 } catch (Exception e) {
19 e.printStackTrace();
20 return null;
21 }
22 }
23 @Bean("sqlSession")
24 SqlSessionTemplate sessionTemplate(){
25 return new SqlSessionTemplate(sqlSessionFactory());
26 }
27}spring事务管理 ¶
事务回顾 ¶
- 确定数据的一致性和完整性
- 一组业务当成一个业务来做,要么都成功,要么都失败
- ACID:原子性、一致性、隔离性、持久性
- 事务隔离
- 读未提交
- 读已提交(默认)
- 可重复读
- 序列化读
传播行为和隔离级别 ¶
参考TransactionDefinition类
1public interface TransactionDefinition {
2
3 /*--------------传播行为--------------------*/
4
5 //支持当前事务;如果不存在,则创建一个新的
6 int PROPAGATION_REQUIRED = 0;
7
8 //支持当前事务;如果不存在,则以非事务方式执行
9 int PROPAGATION_SUPPORTS = 1;
10
11 //支持当前事务;如果当前不存在事务,则抛出异常
12 int PROPAGATION_MANDATORY = 2;
13
14 //创建一个新事务,如果已存在则暂停当前事务
15 int PROPAGATION_REQUIRES_NEW = 3;
16
17 //不支持当前事务;总是以非事务方式执行
18 int PROPAGATION_NOT_SUPPORTED = 4;
19
20 //不支持当前事务;如果当前事务存在则抛出异常
21 int PROPAGATION_NEVER = 5;
22
23 //如果当前事务存在,则在嵌套事务中执行,否则行为类似于 PROPAGATION_REQUIRED
24 int PROPAGATION_NESTED = 6;
25
26 /*--------------隔离级别--------------------*/
27
28 //使用底层数据存储的默认隔离级别
29 int ISOLATION_DEFAULT = -1;
30
31 //读未提交;可能发生脏读、不可重复读和幻读
32 int ISOLATION_READ_UNCOMMITTED = 1; // same as java.sql.Connection.TRANSACTION_READ_UNCOMMITTED;
33
34 //读已提交;可能发生不可重复读取和幻读
35 int ISOLATION_READ_COMMITTED = 2; // same as java.sql.Connection.TRANSACTION_READ_COMMITTED;
36
37 //可重复读;可能发生幻读
38 int ISOLATION_REPEATABLE_READ = 4; // same as java.sql.Connection.TRANSACTION_REPEATABLE_READ;
39
40 //序列化读;
41 int ISOLATION_SERIALIZABLE = 8; // same as java.sql.Connection.TRANSACTION_SERIALIZABLE;
42}脏读:所谓脏读是指一个事务中访问到了另外一个事务未提交的数据;事务A读取事务B修改了数据,然后事务B回滚了事务,事务A读取的就为脏数据
幻读:一个事务读取2次,得到的记录条数不一致;事务A多次读取时,事务B插入了数据,事务A两次读取记录数不一样
不可重复读:一个事务读取同一条记录2次,得到的结果不一致;事务A两次读取期间,事务B修改了数据并进行了提交,事务A两次读取数据不一致
声明式事务 ¶
除了声明式事务,还有编程式事务
声明式事务配置
注册一个
DataSourceTransactionManager对象 ,声明式事务对象xml1<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 2 <constructor-arg ref="dataSource" /> 3</bean> 4 5<!--开启事务支持注解,和下面的aop织入存在一个即可 6 71)、事务的传播性:@Transactional(propagation=Propagation.REQUIRED) 8 如果有事务, 那么加入事务, 没有的话新建一个(默认情况下) 9(2)、事务的超时性:@Transactional(timeout=30) //默认是30秒 10 注意这里说的是事务的超时性而不是Connection的超时性,这两个是有区别的 11(3)、事务的隔离级别:@Transactional(isolation = Isolation.READ_UNCOMMITTED) 12 读取未提交数据(会出现脏读, 不可重复读) 基本不使用 13(4)、回滚: 14 指定单一异常类:@Transactional(rollbackFor=RuntimeException.class) 15 指定多个异常类:@Transactional(rollbackFor={RuntimeException.class, Exception.class}) 16 该属性用于设置需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,则进行事务回滚。 17(5)、只读:@Transactional(readOnly=true) 18 该属性用于设置当前事务是否为只读事务,设置为true表示只读,false则表示可读写,默认值为false。 19 ok 这种注解方式实现事务的配置以及一些属性的定义,其实事务的东西还有很多要注意的事项,如果要深入学习的话要学习的东西还很多,这里只是简单记录一下 20--> 21<tx:annotation-driven transaction-manager="transactionManagerger" />结合AOP实现事务的织入,配置事务通知,需要导入 tx 约束
- advice(建议)的命名:由于每个模块都会有自己的Advice,所以在命名上需要作出规范,初步的构想就是模块名+Advice(只是一种命名规范)
- tx:attribute标签所配置的是作为事务的方法的命名类型。 如<tx:method name=“save*” propagation=“REQUIRED”/>; 其中*为通配符,即代表以save为开头的所有方法,即表示符合此命名规则的方法作为一个事务。propagation=“REQUIRED"代表支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择
- aop:pointcut标签配置参与事务的类,由于是在Service中进行数据库业务操作,配的应该是包含那些作为事务的方法的Service类。首先应该特别注意的是id的命名,同样由于每个模块都有自己事务切面,所以我觉得初步的命名规则因为 all+模块名+ServiceMethod。而且每个模块之间不同之处还在于以下一句:expression=“execution(* com.test.testAda.test.model.service..(..))“其中第一个代表返回值,第二代表service下子包,第三个*代表方法名,“(..)”代表方法参数
- aop:advisor标签就是把上面我们所配置的事务管理两部分属性整合起来作为整个事务管理
xml1<!-- 通过spring的aop织入事务--> 2<!-- 配置事务通知--> 3<tx:advice id="txAdvice" transaction-manager="transactionManagerger"> 4 <!-- 给哪些方法配置事务--> 5 <tx:attributes> 6 <!-- propagation配置事务的传播特性,默认为:REQUIRED --> 7 <tx:method name="*" propagation="REQUIRED"/> 8 <!-- 运行时异常 回滚--> 9 <tx:method name="*" rollback-for="Exception" /> 10 </tx:attributes> 11</tx:advice> 12<!-- 配置事务切入--> 13<aop:config> 14 <aop:pointcut id="txPrintcut" expression="execution(* com.lei.service.*.*(..))"/> 15 <aop:advisor advice-ref="txAdvice" pointcut-ref="txPrintcut"/> 16</aop:config>完整的 mybatis-spring 配置文件
xml1<?xml version="1.0" encoding="UTF-8"?> 2<beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" 4 xmlns:tx="http://www.springframework.org/schema/tx" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd 6 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd 7 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> 8 9<!-- DataSource --> 10 <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> 11 <property name="url" value="jdbc:mysql://139.186.140.120:3312/learn?characterEncoding=utf8"/> 12 <property name="username" value="root"/> 13 <property name="password" value="123456"/> 14 </bean> 15<!-- SqlSessionFactory --> 16 <bean id="sqlSesFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> 17 <property name="dataSource" ref="dataSource"/> 18<!-- 绑定 mybatis 配置文件,也可以完全取代不绑定 --> 19 <property name="configLocation" value="classpath:mybatis-config.xml"/> 20 <property name="mapperLocations" value="classpath:com/lei/dao/*.xml" /> 21 </bean> 22<!-- sqlSessionTemplate --> 23 <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate"> 24<!-- 只能使用构造方法注入,因为该类没有 set 方法--> 25 <constructor-arg index="0" ref="sqlSesFactory"/> 26 </bean> 27<!-- 配置声明式事务--> 28 <bean id="transactionManagerger" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 29 <property name="dataSource" ref="dataSource"/> 30 </bean> 31<!-- 通过spring的aop织入事务--> 32<!-- 配置事务通知--> 33 <tx:advice id="txAdvice" transaction-manager="transactionManagerger"> 34<!-- 给哪些方法配置事务--> 35 <tx:attributes> 36<!-- propagation配置事务的传播特性,默认为:REQUIRED --> 37 <tx:method name="*" propagation="REQUIRED"/> 38 </tx:attributes> 39 </tx:advice> 40<!-- 配置事务切入--> 41 <aop:config> 42 <aop:pointcut id="txPrintcut" expression="execution(* com.lei.dao.*.*(..))"/> 43 <aop:advisor advice-ref="txAdvice" pointcut-ref="txPrintcut"/> 44 </aop:config> 45</beans>通过 Appconfig 配置
声明一个事务管理器,并添加事务支持注解
java1@Configuration 2@EnableAspectJAutoProxy 3@ComponentScan("com.lei.*") 4@EnableTransactionManagement 5public class AppConfig { 6 @Bean("dataSource") 7 DataSource dataSource(){ 8 return new DriverManagerDataSource("jdbc:mysql://139.186.140.120:3312/learn?characterEncoding=utf8","root","123456"); 9 } 10 @Bean("sqlSessionFactory") 11 SqlSessionFactory sqlSessionFactory(){ 12 SqlSessionFactoryBean factoryBean=new SqlSessionFactoryBean(); 13 factoryBean.setDataSource(dataSource()); 14 Resource resource=new ClassPathResource("mybatis-config.xml"); 15 factoryBean.setConfigLocation(resource); 16 try { 17 return factoryBean.getObject(); 18 } catch (Exception e) { 19 e.printStackTrace(); 20 return null; 21 } 22 } 23 @Bean("sqlSession") 24 SqlSessionTemplate sessionTemplate(){ 25 return new SqlSessionTemplate(sqlSessionFactory()); 26 } 27/* 声明事务管理器 */ 28 @Bean("transactionManager") 29 DataSourceTransactionManager transactionManager() { 30 return new DataSourceTransactionManager(dataSource()); 31 } 32}需要事务的类或方法前面添加注解 @Transactional(“transactionManager”)
SpringMVC ¶

执行流程 ¶
- 用户发送请求至前端控制器DispatcherServlet
- DispatcherServlet收到请求调用处理器映射器HandlerMapping。
- 处理器映射器根据请求url找到具体的处理器,生成处理器执行链HandlerExecutionChain(包括处理器对象和处理器拦截器)一并返回给DispatcherServlet。
- DispatcherServlet根据处理器Handler获取处理器适配器HandlerAdapter执行HandlerAdapter处理一系列的操作,如:参数封装,数据格式转换,数据验证等操作
- 执行处理器Handler(Controller,也叫页面控制器)。
- Handler执行完成返回ModelAndView
- HandlerAdapter将Handler执行结果ModelAndView返回到DispatcherServlet
- DispatcherServlet将ModelAndView传给ViewReslover视图解析器
- ViewReslover解析后返回具体View
- DispatcherServlet对View进行渲染视图(即将模型数据model填充至视图中)。
- DispatcherServlet响应用户。
组件说明 ¶
- DispatcherServlet:前端控制器。用户请求到达前端控制器,它就相当于mvc模式中的c,dispatcherServlet是整个流程控制的中心,由它调用其它组件处理用户的请求,dispatcherServlet的存在降低了组件之间的耦合性,系统扩展性提高。由框架实现
- HandlerMapping:处理器映射器。HandlerMapping负责根据用户请求的url找到Handler即处理器,springmvc提供了不同的映射器实现不同的映射方式,根据一定的规则去查找,例如:xml配置方式,实现接口方式,注解方式等。由框架实现
- Handler:处理器。Handler 是继DispatcherServlet前端控制器的后端控制器,在DispatcherServlet的控制下Handler对具体的用户请求进行处理。由于Handler涉及到具体的用户业务请求,所以一般情况需要程序员根据业务需求开发Handler
- HandlAdapter:处理器适配器。通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。由框架实现
- ModelAndView是springmvc的封装对象,将model和view封装在一起
- ViewResolver:视图解析器。ViewResolver负责将处理结果生成View视图,ViewResolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户
- View:是springmvc的封装对象,是一个接口, springmvc框架提供了很多的View视图类型,包括:jspview,pdfview,jstlView、freemarkerView、pdfView等。一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面。
xml 配置 Hello ¶
导入依赖
xml1<dependency> 2 <groupId>org.springframework</groupId> 3 <artifactId>spring-webmvc</artifactId> 4 <version>5.2.14.RELEASE</version> 5</dependency> 6<dependency> 7 <groupId>javax.servlet</groupId> 8 <artifactId>servlet-api</artifactId> 9 <version>2.5</version> 10 <scope>provided</scope> 11</dependency>在 web.xml 中配置
DispatcherServletxml1<?xml version="1.0" encoding="UTF-8"?> 2<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" 5 version="4.0"> 6 <servlet> 7 <servlet-name>dispatherServlet</servlet-name> 8 <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 9<!-- 关联一个srpingmvc 配置文件 --> 10 <init-param> 11 <param-name>contextConfigLocation</param-name> 12 <param-value>classpath:springmvc-servlet.xml</param-value> 13 </init-param> 14<!-- 表示启动时立即加载servlet --> 15 <load-on-startup>1</load-on-startup> 16 </servlet> 17 <servlet-mapping> 18 <servlet-name>dispatherServlet</servlet-name> 19 <url-pattern>/</url-pattern> 20 </servlet-mapping> 21</web-app>编写 控制器 Hello 实现 Controller
java1//这里是实现了 Controller 接口 2public class Hello implements Controller { 3 @Override 4 public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception { 5// ModelAndView 视图和模型 6 ModelAndView mv = new ModelAndView(); 7// 封装对象 8 mv.addObject("msg","hello SpringMVC"); 9// 资源路径 需要跳转的视图,会拼接 springmvc-servlet 配置文件中配置的前缀后缀 10 mv.setViewName("hello"); /WEB-INF/jsp/hello.jsp 11 return mv; 12 } 13}配置 springmvc-servlet
xml1<?xml version="1.0" encoding="UTF-8"?> 2<beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans 5 https://www.springframework.org/schema/beans/spring-beans.xsd"> 6 <!-- 处理映射器 --> 7 <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> 8 <!-- 处理适配器 --> 9 <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/> 10 <!-- 视图解析器, dispatherServlet 给他的 ModelAndView --> 11 <!-- 12 1.获取ModelAndView中数据 13 2.解析视图名字,并拼接 /WEB-INF/jsp/hello.jsp 14 3.将数据渲染到视图 15 --> 16 <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver"> 17 <!-- 前缀 --> 18 <property name="prefix" value="/WEB-INF/jsp/"/> 19 <!-- 后缀 --> 20 <property name="suffix" value=".jsp"/> 21 </bean> 22 23 <!--handler 注意:这里 id 是访问路径 --> 24 <bean id="/hello" class="com.lei.controller.Hello"/> 25</beans>启动 Tomcat,并访问地址 http://localhost:8080/hello
注解实现 Hello ¶
web.xml 中配置 disPathServlet
xml1<?xml version="1.0" encoding="UTF-8"?> 2<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" 5 version="4.0"> 6 <servlet> 7 <servlet-name>disPathServlet</servlet-name> 8 <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 9 <init-param> 10 <param-name>contextConfigLocation</param-name> 11 <param-value>classpath:springmvc-servlet.xml</param-value> 12 </init-param> 13 <load-on-startup>1</load-on-startup> 14 </servlet> 15<!-- / 和 /* 区别 16 /:指定默认servlet,匹配所有请求,不包括jsp 17 /*:匹配所有请求,包括jsp 18--> 19 <servlet-mapping> 20 <servlet-name>disPathServlet</servlet-name> 21 <url-pattern>/</url-pattern> 22 </servlet-mapping> 23</web-app>springmvc-servlet 中配置开启注解支持、映射器、适配器、视图解析器
xml1<?xml version="1.0" encoding="UTF-8"?> 2<beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:context="http://www.springframework.org/schema/context" 5 xmlns:mvc="http://www.springframework.org/schema/mvc" 6 xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd 7 http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd 8 http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> 9<!-- 开启 bean 自动扫描,需要导入约束--> 10 <context:component-scan base-package="com.lei.controller"/> 11<!-- 过滤静态资源 --> 12 <mvc:default-servlet-handler/> 13<!-- driven 代替原来的 映射器 和 适配器 --> 14 <mvc:annotation-driven/> 15<!-- 视图解析器 --> 16 <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver"> 17 <property name="prefix" value="/WEB-INF/jsp/"/> 18 <property name="suffix" value=".jsp"/> 19 </bean> 20</beans>编写控制器,使用
@Controller,@RequestMapping进行标记- 使用
@RequestMapping标记的方法,如果返回的是字符串,会自动去访问资源路径;也可以标记在类上,那么访问路径会将 类上的路径 和 方法上的路径 进行拼接 如:@RequestMapping("/user”) 类{ @RequestMapping("/change”) } ,那么实际访问应该是:/user/change @Controller标记的类,会被spring接管
java1@Controller 2public class Hello { 3 @RequestMapping("/t1") 4 public String t1(Model model){ 5 model.addAttribute("msg","HelloMVC t1"); 6// 返回视图位置,会拼接成 WEB-INF/jsp/hello.jsp 7 return "hello"; 8 } 9 @RequestMapping("/t2") 10 public String t2(Model model){ 11 model.addAttribute("msg","HelloMVC t2"); 12 return "hello"; 13 } 14}- 使用
RestFul风格 ¶
概念
Restful就是一种资源定位及资源操作的风格。不是标准,也不是协议。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制
功能
- 资源:互联网所有的事物都可以被抽象为资源
- 资源操作:使用 POST、DELETE、PUT、GET,使用不同的方法对资源进行操作
- 分别对应 添加、删除、修改、查询
使用
在controller的方法的参数上使用
@PathVariable代表使用路径变量在
@RequestMapping上添加路径,以及方法控制器代码
java1@Controller 2@RequestMapping("/hello") 3public class Hello { 4 @RequestMapping(value = "/t3/{name}/{passwd}",method = RequestMethod.GET ) 5 public ModelAndView t3(@PathVariable String name, @PathVariable String passwd){ 6 ModelAndView mv=new ModelAndView("hello"); 7 mv.addObject("msg",name+" "+passwd); 8 return mv; 9 } 10}访问地址: http://localhost:8080/hello/t3/lei/123
优点
- 路径更加简洁
- 安全
- 高效,支持缓存优化
示例
- 传统:localhost/login?username=lei&password=123
- restful风格:localhost/login/lei/123
重定向与转发 ¶
没有视图解析器时
java1@Controller 2@RequestMapping("/hello") 3public class Hello { 4 @RequestMapping("/t1") 5 public String t1(Model model){ 6/* 转发一:/资源路径 */ 7 return "/WEB-INF/index.jsp"; 8 } 9 10 @RequestMapping("/t2") 11 public String t2(Model model){ 12/* 转发二: */ 13 return "forward:/WEB-INF/index.jsp"; 14 } 15 16 @RequestMapping("/t3") 17 public String t2(Model model){ 18/* 重定向 */ 19 return "redirect:/index.jsp"; 20 } 21}有视图解析器时
java1@Controller 2@RequestMapping("/hello") 3public class Hello { 4 @RequestMapping("/t1") 5 public String t1(Model model){ 6/* 默认找到视图,并渲染 */ 7 return "index"; 8 } 9 public String t2(){ 10/* 转发 */ 11 return "forward:/hello/t1"; 12 } 13 @RequestMapping("/t3") 14 public String t2(Model model){ 15/* 重定向 */ 16 return "redirect:/index.jsp"; 17 } 18}
请求参数获取 ¶
@PathVariable @RequestBody @RequestParam使用方法
PathVariable是路径变量的意思,这个注解主要作用在请求URL路径上的数据绑定,默认传递数值写在URL上,SpringMVC就可以获取到,Restful风格
RequestBody是请求体的意思,这个注解作用在请求体的数据绑定,并且数据必须在写在请求体中,还要以JSON的数据格式发送才符合条件
该注解常用来处理Content-Type: 不是
application/x-www-form-urlencoded编码的内容,例如application/json, application/xml等RequestParam:
springmvc默认,RequestParam是请求参数的意思,这个注解的作用在请求路径和请求体中的数据,因为使用request.getParameter()方式获取参数,所以可以处理get 方式中queryString的值,也可以处理post方式中 body data的值RequestPart:与@RequestParam,RequestParam适用于name-valueString类型的请求域,@RequestPart也支持复杂的请求域(像JSON,XML,文件等)
方法的形参参数名与前端请求参数名一致,可直接获取
使用注解
@RequestParam("请求参数名")注解标记形参,绑定形参与请求参数请求参数是一个对象,可直接使用对象接收参数,需注意:对象字段名与请求参数名一致,否则获取到的对象某个字段为 null
整体流程
- 接收前端传递的参数,判断参数名字,如果在方法上,则直接使用
- 假设前端传递的参数是一个对象,匹配对象中的字段名,匹配上则ok,匹配不上则字段为 null
中文参数后台
乱码问题解决springMVC提供了一个乱码过滤器,直接在 web.xml 中配置即可
xml1<!-- 添加过滤器,spring实现的编码问题解决的过滤器 --> 2<filter> 3 <filter-name>encoding</filter-name> 4 <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> 5 <init-param> 6 <param-name>encoding</param-name> 7 <param-value>utf-8</param-value> 8 </init-param> 9</filter> 10<filter-mapping> 11 <filter-name>encoding</filter-name> 12 <url-pattern>/*</url-pattern> 13</filter-mapping>配置tomcat编码
xml1<Connector port="8080" protocol="HTTP/1.1" 2 connectionTimeout="20000" 3 redirectPort="8443" 4 URIEncoding="UTF-8" />自定义过滤器(极端情况)
java1public class EncodingFilter implements Filter { 2 @Override 3 public void init(FilterConfig filterConfig) throws ServletException {} 4 5 @Override 6 public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { 7 //处理response的字符编码 8 HttpServletResponse myResponse=(HttpServletResponse) servletResponse; 9 myResponse.setContentType("text/html;charset=UTF-8"); 10 // 转型为与协议相关对象 11 HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest; 12 // 对request包装增强 13 HttpServletRequest myrequest = new MyRequest(httpServletRequest); 14 filterChain.doFilter(myrequest,myResponse); 15 } 16 @Override 17 public void destroy() {} 18} 19 20//自定义request对象,HttpServletRequest的包装类 21class MyRequest extends HttpServletRequestWrapper { 22 23 private HttpServletRequest request; 24 //是否编码的标记 25 private boolean hasEncode; 26 //定义一个可以传入HttpServletRequest对象的构造函数,以便对其进行装饰 27 public MyRequest(HttpServletRequest request) { 28 super(request);// super必须写 29 this.request = request; 30 } 31 32 // 对需要增强方法 进行覆盖 33 @Override 34 public Map getParameterMap() { 35 // 先获得请求方式 36 String method = request.getMethod(); 37 if (method.equalsIgnoreCase("post")) { 38 // post请求 39 try { 40 // 处理post乱码 41 request.setCharacterEncoding("utf-8"); 42 return request.getParameterMap(); 43 } catch (UnsupportedEncodingException e) { 44 e.printStackTrace(); 45 } 46 } else if (method.equalsIgnoreCase("get")) { 47 // get请求 48 Map<String, String[]> parameterMap = request.getParameterMap(); 49 if (!hasEncode) { // 确保get手动编码逻辑只运行一次 50 for (String parameterName : parameterMap.keySet()) { 51 String[] values = parameterMap.get(parameterName); 52 if (values != null) { 53 for (int i = 0; i < values.length; i++) { 54 try { 55 // 处理get乱码 56 values[i] = new String(values[i] 57 .getBytes("ISO-8859-1"), "utf-8"); 58 } catch (UnsupportedEncodingException e) { 59 e.printStackTrace(); 60 } 61 } 62 } 63 } 64 hasEncode = true; 65 } 66 return parameterMap; 67 } 68 return super.getParameterMap(); 69 } 70 71 //取一个值 72 @Override 73 public String getParameter(String name) { 74 Map<String, String[]> parameterMap = getParameterMap(); 75 String[] values = parameterMap.get(name); 76 if (values == null) { 77 return null; 78 } 79 return values[0]; // 取回参数的第一个值 80 } 81 82 //取所有值 83 @Override 84 public String[] getParameterValues(String name) { 85 Map<String, String[]> parameterMap = getParameterMap(); 86 String[] values = parameterMap.get(name); 87 return values; 88 } 89}
拦截器(interceptor) ¶
拦截器类似于过滤器,是AOP思想的具体应用
拦截器是SpringMVC框架自己的,拦截器只会拦截访问Controller中的请求;spring5 + 对通过controller访问的静态资源(js..)也会进行拦截
编写拦截器类 MyInterceptor 实现
HandlerInterceptor接口,实现某些方法:preHandle,拦截处理;postHandle和afterCompletion,一般用于添加拦截日志java1public class MyInterCeptor implements HandlerInterceptor { 2 @Override 3 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { 4 System.out.println("拦截前,true表示放行"); 5 return true; 6 } 7}在
springmvc-servlet.xml中配置拦截器xml1<mvc:interceptors> 2 <mvc:interceptor> 3 <!-- 拦截路径 --> 4 <mvc:mapping path="/**"/> 5 <!-- 不拦截静态资源--> 6 <mvc:exclude-mapping path="/static/**"/> 7 <bean class="com.lei.config.LoginInterceptor"/> 8 </mvc:interceptor> 9</mvc:interceptors>
文件上传 ¶
导入依赖
xml1<dependency> 2 <groupId>commons-fileupload</groupId> 3 <artifactId>commons-fileupload</artifactId> 4 <version>1.4</version> 5</dependency>前端form表单需要设置属性
enctype="multipart/form-data",以二进制流形式提交html1<form method="post" enctype="multipart/form-data" action="${pageContext.request.contextPath}/upload2"> 2 <input type="file" name="file"><input type="submit"> 3</form>在
springmvc-servlet.xml中配置文件上传xml1<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> 2 <!-- 请求编码格式,必须和jsp的pageEncoding相同,以便正确读取表单内容,默认为:ISO-8859-1 --> 3 <property name="defaultEncoding" value="utf-8"/> 4 <!-- 设置文件上传大小上限,单位为字节(10485760字节=10m)--> 5 <property name="maxUploadSize" value="10485760"/> 6 <property name="maxInMemorySize" value="40960"/> 7</bean>控制器处理上传文件请求的方法1
java1// @RequestParam 将 name=file控件得到的文件封装成CommonsMultipartFile对象 2// 批量上传 CommonsMultipartFile 设置为数组即可 3@RequestMapping("/upload") 4public String fileUpload(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws Exception { 5 // 获取文件名file.getOriginalFilename 6 String filename = file.getOriginalFilename(); 7 8 // 如果文件为空,返回首页 9 if ("".equals(filename)) { 10 return "redirect:index.jsp"; 11 } 12 System.out.println("上传文件名为:" + filename); 13 14 //上传路径保存设置 15 String path = request.getServletContext().getRealPath("/upload"); 16 System.out.println(request.getServletContext()); 17 18 //如果路径不存在,则创建一个 19 File realPath = new File(path); 20 if (!realPath.exists()) { 21 realPath.mkdir(); 22 } 23 System.out.println("上传文件保存地址为:" + realPath); 24 InputStream in = file.getInputStream(); //输入流 25 OutputStream out = new FileOutputStream(new File(realPath, filename)); 26 27 //读取和写入 28 int len = 0; 29 byte[] buffer = new byte[1024]; 30 while ((len = in.read(buffer)) != -1) { 31 out.write(buffer, 0, len); 32 out.flush(); 33 } 34 in.close(); 35 out.close(); 36 return null; 37}控制器处理上传文件请求的方法2
java1@RequestMapping("/upload2") 2public String fileupload2(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws Exception { 3// 上传路径保存设置 4String path = request.getServletContext().getRealPath("/upload"); 5File realPath = new File(path); 6if (!realPath.exists()) { 7realPath.mkdir(); 8} 9System.out.println("上传文件保存路径" + realPath); 10// 通过 CommonsMultipartFile 的方法直接写入文件 11file.transferTo(new File(realPath + "/" + file.getOriginalFilename())); 12return "redirect:/index.jsp"; 13}文件下载(二进制流方式)
java1@RequestMapping("/download") 2public String download(HttpServletRequest req, HttpServletResponse resp) throws IOException { 3 // 要下载的图片地址 4 String path = req.getServletContext().getRealPath("/upload"); 5 String filename = "1.png"; 6 7 // 1.设置响应头 8 resp.reset(); //设置页面不缓存,清空buffer 9 resp.setCharacterEncoding("UTF-8"); //设置字符编码 10 resp.setContentType("multipart/form-data"); //设置二进制传输数据 11 // 设置响应头 12 resp.setHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(filename, "UTF-8")); 13 File file = new File(path, filename); 14 // 2.读取文件 15 InputStream in = new FileInputStream(file); 16 // 3.输出文件 17 OutputStream out = resp.getOutputStream(); 18 int len = 0; 19 byte[] buffer = new byte[1024]; 20 while ((len = in.read(buffer)) != -1) { 21 out.write(buffer, 0, len); 22 out.flush(); 23 } 24 in.close(); 25 out.close(); 26 return "ok"; 27}
Json ¶
前端
js对象转换为 json:
JSON.stringify(object)json转换为js对象:JSON.parse(jsonString)
html1<script type="text/javascript"> 2 var user={"name":"lei","age":19,"sex":"男"} 3 var jsonString=JSON.stringify(user) //js对象转化为json字符串 4 var user1=JSON.parse(jsonString) //json字符串转化为js对象 5 console.log(user) 6 console.log(jsonString) 7 console.log(user1) 8</script>
java后端生成json对象(fastjson)
导入相关依赖 ,fastjson(阿里开源)
xml1<dependency> 2 <groupId>com.alibaba</groupId> 3 <artifactId>fastjson</artifactId> 4 <version>1.2.76</version> 5</dependency>fastjson 的使用
java1@RequestMapping("/t1") 2public String t1(Model model){ 3 User u1=new User(1,"lei","M"); 4 // Java对象转换为json字符串 5 String jsonString=JSON.toJSONString(u1); 6 // json字符串转换为Java对象 7 User u2=JSON.parseObject(jsonString,User.class); 8 // Java对象转换为json对象 9 JSONObject json= (JSONObject) JSON.toJSON(u1); 10 // json对象转换为Java对象 11 User u3=JSON.toJavaObject(json,User.class); 12 model.addAttribute("msg",jsonString); 13 return "json"; 14}
SSM整合 ¶
pom.xml配置 ¶
1<?xml version="1.0" encoding="UTF-8"?>
2<project xmlns="http://maven.apache.org/POM/4.0.0"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5 <modelVersion>4.0.0</modelVersion>
6
7 <groupId>com.lei</groupId>
8 <artifactId>ch04-ssmbuild</artifactId>
9 <version>1.0-SNAPSHOT</version>
10
11 <properties>
12 <maven.compiler.source>11</maven.compiler.source>
13 <maven.compiler.target>11</maven.compiler.target>
14 </properties>
15 <dependencies>
16 <dependency>
17 <groupId>org.springframework</groupId>
18 <artifactId>spring-webmvc</artifactId>
19 <version>5.2.14.RELEASE</version>
20 </dependency>
21 <dependency>
22 <groupId>org.springframework</groupId>
23 <artifactId>spring-aspects</artifactId>
24 <version>5.2.14.RELEASE</version>
25 </dependency>
26 <dependency>
27 <groupId>mysql</groupId>
28 <artifactId>mysql-connector-java</artifactId>
29 <version>5.1.49</version>
30 </dependency>
31<!-- 数据库连接池 -->
32 <dependency>
33 <groupId>com.mchange</groupId>
34 <artifactId>c3p0</artifactId>
35 <version>0.9.5.5</version>
36 </dependency>
37
38 <dependency>
39 <groupId>org.mybatis</groupId>
40 <artifactId>mybatis</artifactId>
41 <version>3.5.7</version>
42 </dependency>
43 <dependency>
44 <groupId>org.springframework</groupId>
45 <artifactId>spring-jdbc</artifactId>
46 <version>5.2.14.RELEASE</version>
47 </dependency>
48 <dependency>
49 <groupId>org.mybatis</groupId>
50 <artifactId>mybatis-spring</artifactId>
51 <version>2.0.6</version>
52 </dependency>
53 <dependency>
54 <groupId>javax.servlet</groupId>
55 <artifactId>servlet-api</artifactId>
56 <version>2.5</version>
57 <scope>provided</scope>
58 </dependency>
59 <dependency>
60 <groupId>javax.servlet</groupId>
61 <artifactId>jsp-api</artifactId>
62 <version>2.0</version>
63 <scope>provided</scope>
64 </dependency>
65 <dependency>
66 <groupId>javax.servlet</groupId>
67 <artifactId>jstl</artifactId>
68 <version>1.2</version>
69 </dependency>
70 <!-- 可用于实体类,可以使用注解提供构造方法和set get -->
71 <dependency>
72 <groupId>org.projectlombok</groupId>
73 <artifactId>lombok</artifactId>
74 <version>1.18.20</version>
75 <scope>provided</scope>
76 </dependency>
77 <dependency>
78 <groupId>junit</groupId>
79 <artifactId>junit</artifactId>
80 <version>4.13</version>
81 <scope>test</scope>
82 </dependency>
83 </dependencies>
84 <build>
85 <!-- 资源过滤配置 -->
86 <resources>
87 <resource>
88 <directory>src/main/java</directory>
89 <includes>
90 <include>**/*.xml</include>
91 </includes>
92 <filtering>false</filtering>
93 </resource>
94 </resources>
95 </build>
96</project>mybatis层 ¶
mysql连接信息 databases.properties
properties1#MySQL8.0+ 需要增加一个时区配置 &serverTimezone=Asia/Shanghai 2 3jdbc.driver=com.mysql.cj.jdbc.Driver 4jdbc.url=jdbc:mysql://192.168.10.129:3306/crm_manage?useSSL=true&useUnicode=true&characterEncoding=utf8 5jdbc.user=crm_manage 6jdbc.password=JCRMp3LHkrSZ5y6cmybatis-config.xml,mybatis 配置文件
xml1<?xml version="1.0" encoding="UTF-8" ?> 2<!DOCTYPE configuration 3 PUBLIC "-//mybatis.org//DTD Config 3.0//EN" 4 "http://mybatis.org/dtd/mybatis-3-config.dtd"> 5<configuration> 6 <!--mybatis设置,控制其全局行为--> 7 <settings> 8 <!--设置mybatis输出日志--> 9 <setting name="logImpl" value="STDOUT_LOGGING"/> 10 </settings> 11 <!-- 别名配置 --> 12 <typeAliases> 13 <package name="com/lei/pojo"/> 14 </typeAliases> 15 <mappers> 16 <package name="com.lei.dao"/> 17 </mappers> 18</configuration>mybatis-spring.xml 配置文件,整合 mybatis和 spring
xml1<?xml version="1.0" encoding="UTF-8"?> 2<beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:context="http://www.springframework.org/schema/context" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd 6 http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> 7 <!-- 1.关联数据库配置文件--> 8 <context:property-placeholder location="classpath:database.properties"/> 9 <!-- 2.配置连接池,这里使用的 c3p0,有许多特有属性--> 10 <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> 11 <property name="driverClass" value="${jdbc.driver}"/> 12 <property name="jdbcUrl" value="${jdbc.url}"/> 13 <property name="user" value="${jdbc.user}"/> 14 <property name="password" value="${jdbc.password}"/> 15 <!-- c3p0连接池私有属性--> 16 <property name="maxPoolSize" value="20"/> 17 <property name="minPoolSize" value="3"/> 18 <!-- 关闭链接后不自动commit --> 19 <property name="autoCommitOnClose" value="false"/> 20 <!-- 获取链接超时时间--> 21 <property name="checkoutTimeout" value="2000"/> 22 <!-- 获取连接失败时尝试次数--> 23 <property name="acquireIncrement" value="2"/> 24 </bean> 25 <!-- 3.配置SqlSessionFactory--> 26 <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> 27 <property name="dataSource" ref="dataSource"/> 28 <property name="configLocation" value="classpath:mybatis.xml"/> 29 </bean> 30 <!-- 4.配置dao接口自动扫描包,实现了dao接口可以注入到Spring容器中 --> 31 <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> 32 <!-- 注入SqlSessionFactory --> 33 <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> 34 <!-- 要扫描的 dao 包--> 35 <property name="basePackage" value="com.lei.dao"/> 36 </bean> 37</beans>创建实体类 Book
java1@Data 2@AllArgsConstructor 3public class Book { 4 private String name; 5 private String author; 6 private String detail; 7}创建 dao 层接口 BookMapper
java1public interface BookMapper { 2 int insertBook(Book book); 3}创建 dao 层接口对应的 BookMapper.xml
xml1<?xml version="1.0" encoding="UTF-8" ?> 2<!DOCTYPE mapper 3 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 4 "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 5<mapper namespace="com.lei.dao.BookMapper"> 6 <insert id="insertBook" parameterType="Book"> 7 insert into t_books (name,author,detail) values (#{name},#{author},#{detail}) 8 </insert> 9</mapper>创建业务层service接口,BookService
java1public interface Bookservice { 2 int insertBook(Book book); 3}创建业务层实现类,实现 BookService 接口
java1@Service("bookServiceImpl") 2public class BookServiceImpl implements Bookservice{ 3// service层调用dao层:组合dao 4 @Autowired 5 private BookMapper mapper; 6 7 public void setMapper(BookMapper mapper) {this.mapper = mapper;} 8 9 @Override 10 public int insertBook(Book book) { 11 return mapper.insertBook(book); 12 } 13}
spring层 ¶
创建 Spring 主配置文件 applicationContext.xml
xml1<?xml version="1.0" encoding="UTF-8"?> 2<beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:context="http://www.springframework.org/schema/context" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans 6 https://www.springframework.org/schema/beans/spring-beans.xsd 7 http://www.springframework.org/schema/context 8 https://www.springframework.org/schema/context/spring-context.xsd"> 9 <import resource="classpath:spring-mybatis.xml"/> 10 <import resource="classpath:spring-service.xml"/> 11 <import resource="classpath:springmvc-servlet.xml"/> 12</beans>创建spring-mybatis.xml配置文件,整合mybatis
xml1<?xml version="1.0" encoding="UTF-8"?> 2<beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:context="http://www.springframework.org/schema/context" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd 6 http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> 7 <!-- 1.关联数据库配置文件--> 8 <context:property-placeholder location="classpath:database.properties"/> 9 <!-- 2.配置连接池,这里使用的 c3p0,有许多特有属性--> 10 <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> 11 <property name="driverClass" value="${jdbc.driver}"/> 12 <property name="jdbcUrl" value="${jdbc.url}"/> 13 <property name="user" value="${jdbc.user}"/> 14 <property name="password" value="${jdbc.password}"/> 15 <!-- c3p0连接池私有属性--> 16 <property name="maxPoolSize" value="20"/> 17 <property name="minPoolSize" value="10"/> 18 <!-- 关闭链接后不自动commit --> 19 <property name="autoCommitOnClose" value="false"/> 20 <!-- 获取链接超时时间--> 21 <property name="checkoutTimeout" value="1000"/> 22 <!-- 获取连接失败时尝试次数--> 23 <property name="acquireIncrement" value="2"/> 24 </bean> 25 <!-- 3.配置SqlSessionFactory--> 26 <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> 27 <property name="dataSource" ref="dataSource"/> 28 <property name="configLocation" value="classpath:mybatis.xml"/> 29 </bean> 30 <!-- 4.配置dao接口自动扫描包,实现了dao接口可以注入到Spring容器中 --> 31 <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> 32 <!-- 注入SqlSessionFactory --> 33 <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> 34 <!-- 要扫描的 dao 包--> 35 <property name="basePackage" value="com.lei.dao"/> 36 </bean> 37</beans>创建 spring-service.xml,整合 service 层
xml1<?xml version="1.0" encoding="UTF-8"?> 2<beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:context="http://www.springframework.org/schema/context" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd 6 http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> 7 <!-- 1.扫描 service 下的包 --> 8 <context:component-scan base-package="com.lei.service"/> 9 <!-- 2.将所有的service类注入到spring中,可以通过注解 或者 配置--> 10 <!-- 3.配置声明式事务 --> 11 <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 12 <!-- 注入数据源 --> 13 <property name="dataSource" ref="dataSource"/> 14 </bean> 15</beans>
springMVC层 ¶
在 web.xml 中配置 DisPathServlet 、乱码过滤、session过期时间
xml1<?xml version="1.0" encoding="UTF-8"?> 2<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" 5 version="4.0"> 6 <servlet> 7 <servlet-name>dispathServlet</servlet-name> 8 <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 9 <init-param> 10 <param-name>contextConfigLocation</param-name> 11 <param-value>classpath:applicationContext.xml</param-value> 12 </init-param> 13 <load-on-startup>1</load-on-startup> 14 </servlet> 15 <servlet-mapping> 16 <servlet-name>dispathServlet</servlet-name> 17 <url-pattern>/</url-pattern> 18 </servlet-mapping> 19 <filter> 20 <filter-name>encodingFilter</filter-name> 21 <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> 22 <init-param> 23 <param-name>encoding</param-name> 24 <param-value>utf-8</param-value> 25 </init-param> 26 </filter> 27 <filter-mapping> 28 <filter-name>encodingFilter</filter-name> 29 <url-pattern>/*</url-pattern> 30 </filter-mapping> 31 <session-config> 32 <session-timeout>15</session-timeout> 33 </session-config> 34</web-app>创建 springmvc-servlet.xml 配置文件,配置映射器、适配器、视图解析器等
xml1<?xml version="1.0" encoding="UTF-8"?> 2<beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:context="http://www.springframework.org/schema/context" 5 xmlns:mvc="http://www.springframework.org/schema/mvc" 6 xsi:schemaLocation="http://www.springframework.org/schema/beans 7 https://www.springframework.org/schema/beans/spring-beans.xsd 8 http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd 9 http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> 10 <!-- 1.注解驱动 driven 代替原来的 映射器 和 适配器--> 11 <mvc:annotation-driven> 12 <mvc:message-converters> 13 <!-- 解决@ResponseBody返回中文乱码,有许多类处理 ResponseBody,而字符串则用 StringHttpMessageConverter 处理,默认采用了 ISO 编码 --> 14 <bean class="org.springframework.http.converter.StringHttpMessageConverter"> 15 <!-- <property name="defaultCharset" value="UTF-8"/> --> 16 <property name="supportedMediaTypes"> 17 <list> 18 <value>text/html;charset=UTF-8</value> 19 <value>application/json;charset=UTF-8</value> 20 <value>*/*;charset=UTF-8</value> 21 </list> 22 </property> 23 <!-- 用于避免响应头过大 --> 24 <property name="writeAcceptCharset" value="false" /> 25 </bean> 26 </mvc:message-converters> 27 </mvc:annotation-driven> 28 <!-- 2.静态资源过滤,指定一个默认servlet处理静态资源,也可以在 web.xml 中进行配置 --> 29 <mvc:default-servlet-handler/> 30 <!-- 3.扫描包:controller --> 31 <context:component-scan base-package="com.lei.controller"/> 32 <!-- 4.视图解析器 --> 33 <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver"> 34 <property name="prefix" value="/WEB-INF/jsp/"/> 35 <property name="suffix" value=".jsp"/> 36 </bean> 37</beans>创建控制器controller
java1@Controller 2@RequestMapping("/book") 3public class BookController { 4 @Autowired 5 @Qualifier("bookServiceImpl") 6 Bookservice bookservice; 7 public void setBookservice(Bookservice bookservice) { 8 this.bookservice = bookservice; 9 } 10 @RequestMapping("/add") 11 String addBook(Book book,Model model){ 12 int a=bookservice.insertBook(book); 13 System.out.println(book); 14 if (a>0){ 15 model.addAttribute("msg","成功"); 16 } 17 return "book"; 18 } 19}
通过配置类整合SSM ¶
常用注解 ¶
spring ¶
@Scope:作用域,放在类上,默认是单例,可以修改为原型(即每次获取都是一个新的对象)
@Transactional("transactionManager"):标记类,代表该类使用事务管理,也可以标记方法
@Component:组件,放在类上面,说明这个类被Spring管理了,存在几个衍生注解,功能都一样,只是不同标识(有三个类似的注解:@Controller、@Service、@Repository)
@Autowired:自动装配通过名字类型;参数: required=false 允许可选注入@Quanlifier("beanName"):指定某个bean注入@Resource:自动装配,通过类型、名字@Value:值,放在字段上或者set方法上,给属性赋值;也可以放在 org.springframework.core.io.Resource 类型的属性上,直接导入一个资源文件地址;@Value("${key}”) 与 @Vaule("#{bean:filed}"),${}表示从加载的资源文件读取值, #{}表示从JavaBean读取属性 ,即调用 bean 的 get 方法@Nullable:标记字段,说明这个字段可以为 NULL@PostConstruct:标记方法,对象初始化时执行该方法@PreDestroy:标记方法,对象结束时执行该方法@Transactional("transactionManager")
@Configuration:放在类上,表示该类为配置类
@EnableWebMvc :启用springMVC
@EnableAspectJAutoProxy:标记配置类,AOP通过注解自动识别
@Import(Config2.class):标记类,导入另外的配置类
@EnableTransactionManagement:标记配置类,开启事务管理
@ComponentScan("com.lei.beans"):标记类,表示自动扫描哪个包下的 Component
@Bean("getuser"):标记方法,表示该方法为一个组件;可以使用该注解 注册一个第三方Bean,未有@Component注解标记的类@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE):标记方法,表示该方法生成 bean的生命周期@Primary:标记方法,指定该方法注册的 bean 为主,针对多个同类型的 bean 需要进行被注入时,会自动选择有该注解的bean进行注入
@PropertySource("config.properties"):放在类上,表示导入某个资源文件,然后通过 @Value 进行注入就好,如 @Value("${jdbc.user}")
@Aspect:标记类,代表该类为一个切面
Before("execution(* com.lei.*.*(..))"):标记方法,代表方法执行前@After(): 这种拦截器先执行目标代码,再执行拦截器代码。无论目标代码是否抛异常,拦截器代码都会执行@AfterReturning(): 和@After不同的是,只有当目标代码正常返回时,才执行拦截器代码@AfterThrowing (): 和@After不同的是,只有当目标代码抛出了异常时,才执行拦截器代码@Around(): 能完全控制目标代码是否执行,并可以在执行前后、抛异常后执行任意拦截代码,可以说是包含了上面所有功能
springMVC ¶
@EnableWebMvc :标记spring配置类,表示启用springMVC
@Repository:dao
@Service:service
@Controller:标记控制器类,该类会被spring接管
@RequestMapping(value="/hello",method=RequestMethod.GET),produces = "application/json;charset=utf-8":标记方法或类,表示用何种方式访问哪个路径,除此之外还有许多衍生注解,对应各个方法,例如:@GetMapping("/hello")@PathVariable:标记形参,路径变量,与 @RequestMapping 中路径匹配@RequestParam("参数名"):标记形参,表示从前端接收的参数名与其形参匹配
@ResponseBody: 标记类或方法,表示方法的返回值直接以指定的格式写入Http response body中,而不是解析为跳转路径@RestController:标记类,相当于 @Controller和 @ResponseBody两个注解的组合
@Data:标记类上,提供类的所有属性的get、set包括toString、equals、hashCode等方法
@NoArgsConstructor:标记类上,提供无参构造
@AllArgsConstructor:标记类上,提供全参构造方法
Log4j:标记类上,提供一个属性名为 log 的 logj 日志对象
@Setter:标记属性,为该属性提供set方法@Getter:标记属性,为该属性提供get方法