【Spring】【Spring Boot】【SpringMVC】【MyBatis】【Redis】框架总结

  1. spring mvc框架:
  servlet 控制器controller 只做三件事    遵守MVC开发模型
    1.获取数据
	2.基于获取的数据调用业务方法
	3.根据业务的返回结果做跳转/响应
        跳转:转发和重定向   转发只能jsp页面 重定向可以是jsp和html
        响应:把服务端的json字符串响应给客户端(浏览器,android,ios等)
 spring mvc: 
  遵守MVC开发模型
    1.获取数据        恭喜你,spring mvc框架帮你做了
	2.基于获取的数据调用业务方法    程序员只需要重点关注业务
	3.根据业务的返回结果做跳转/响应    恭喜你,spring mvc框架帮你做了
        跳转:转发和重定向   转发只能jsp页面 重定向可以是jsp和html
        响应:把服务端的json字符串响应给客户端(浏览器,android,ios等)

在这里插入图片描述 2. mybatis框架:

持久层框架
  原生jdbc  开发效率低,执行效率高                     手洗衣服
  基于原生jdbc衍生出来CommonDao 开发效率稍高          手工搓衣板
  spring jdbc      开发效率同CommonDao                品牌搓衣板
  mybatis框架  开发效率继续提高                       半自动洗衣机
  hibernate框架  开发效率最高                         全自动洗衣机
  1. spring框架
  替换了原有的servlet和jdbc项目开发中的对象管理 
  原来:对象的创建都是由程序员根据业务的需求来适时的new对象和管理对象
       而且程序员要管理对象的依赖关系  
  用spring框架不但能帮程序员创建对象,而且还能管理对象之间的关系

  对象之间的依赖关系,组合关系(has a) ,继承关系(is a)
    比如:
	  在UserServiceImpl类中需要组合一个UserDaoImpl对象
	  在UserServiceImpl类中实现了一个UserService接口
  1. spring 框架:
spring是一个开源的轻量级的应用开发框架,其目的用于企业级应用程序开发,减少侵入(降低耦合)
    开源:开放源代码,框架提供源代码
	轻量级:相互依赖越少,越轻量级
	减少侵入/降低耦合:
	  耦合的分类:/零耦合:类和类之间没有任何关系
		抽象耦合:在本类中耦合另一个类的抽象(接口(推荐),抽象类(不推荐))
        具体耦合:在本类中耦合的是另一个具体的类
    抽象耦合:依赖的是抽象
	  比如:
	    //在UserServiceImpl类中 is a UserService
	    public class UserServiceImpl implements UserService{
			//在本类UserServiceImpl中 has a UserDao
			//userDao能接收UserDao接口任意子实现
			private UserDao userDao;
		}

    具体耦合:依赖的是具体类
        public class UserServiceImpl implements UserService{
			//在本类UserServiceImpl中 has a UserDaoImpl
			//userDao只能接收UserDaoImpl类型的对象
			private UserDaoImpl userDao;
		}

  结论:别人做好的框架,用来集中管理项目中的所有的对象
       框架的整合SSM   其中有一个框架是Spring框架
	   spring负责管理spring mvc中和mybatis中和程序中
	   所有使用的所有的对象,不但能管理对象,还能创建对象
srpring IOC 控制反转  Inversion og Control(IOC),
    就是把new对象不放在具体类中去new,new对象的控制权反转给
	第三方spring容器中去new对象
IOC 控制反转   
  创建对象
  管理对象
    把对象放在容器中
	容器中的对象还有依赖关系
	
spring DI 依赖注入 Dependency injection(DI),
    就是把spring容器中new完的对象,从spring容器中取出并注入到需要
	的地方
	注入的方式分为:
	   构造注入
	   setter注入
为什么要用到spring:
    spring的本质核心就管理应用程序中的对象
	因为代码中是抽象耦合,那么把new具体的类对象放在spring框架中管理
	通过spring框架,根据用户的需求,把对象注入到需要的地方
	相当于在代码中没有使用任何具体的子类的实现
何时使用spring:
    当需要大量管理具体实现类的时候,用spring创建和管理具体实现类
	的对象;有类的地方,就一定需要类的对象,有对象的地方就一定
	需要spring框架来管理

总结:
    1.能够创建对象和管理对象IOC
	2.从spring容器中取出对象来使用DI
	3.用spring框架可以减少侵入/降低耦合
使用spring IOC的步骤:
1.创建工程(jar ,war)               工程是基础
2.导入spring的jar包                spring框架给提供的功能
3.创建java类(一个或多个)           准备把这些类的对象交给spring容器管理
4.创建spring清单文件(xml格式)      在清单文件中指定哪些类需要spring来管理
5.直接启动spring容器               启动时会加载清单文件(dom4j)
6.从spring容器中取出需要的对象,备用
导入jar包
  方式一:
    手动拷贝,需要下载spring的开发包
	http://repo.springsource.org/libs-release-local/org/springframework/spring/
    http://repo.spring.io/release/org/springframework/spring/
    spring-context.jar
	spring-aop.jar
	spring-beans.jar
	spring-core.jar
	spring-expression.jar
  方式二:
    maven方式下载
	<dependency>
	  <groupId>org.springframework</groupId>
	  <artifactId>spring-context</artifactId>
	  <version>4.3.7.RELEASE</version>
	</dependency>
创建清单文件:超级建议从具体版本的文档中拷贝清单文件的模板
  原始清单文件模板:
   <?xml version="1.0" encoding="UTF-8"?>
	<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans.xsd">
	<bean id="..." class="...">
	<!-- collaborators and configuration for this bean go here -->
	</bean>
	<bean id="..." class="...">
	<!-- collaborators and configuration for this bean go here -->
	</bean>
	<!-- more bean definitions go here -->
	</beans>  
  修改原始清单文件
    <?xml version="1.0" encoding="UTF-8"?>
	<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans.xsd">
		<!-- 用清单文件告知spring框架对哪些类实例化对象 -->
		<bean id="hello" class="cn.tedu.ioc.Hello"></bean>
		
	</beans>
初始化spring容器:
   方式一:本地文件系统方式
     ApplicationContext context =
				new FileSystemXmlApplicationContext("c:/spring.xml");
   方式二:类路径方式
     ApplicationContext context =
				new ClassPathXmlApplicationContext("conf/spring.xml");   
 
  注意:
     ApplicationContext context =
				new ClassPathXmlApplicationContext();
	 会从类路径的根目录自动寻找applicationContext.xml文件
	 
从spring容器中获取对象
   Hello hello=(Hello)context.getBean("hello");
   
IOC容器实例化对象的若干常见错误:
  在eclipse mar2版本及以前的版本
  如果有caused by字样,看最后一个caused by
  在eclipse mar2以后的版本就没有caused by 提示
  
1.Caused by: java.lang.ClassNotFoundException: cn.tedu.ioc.Hello1
  类没有发现异常
  建议用ctrl+鼠标
2.org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Bean name 'hello' is already used in this <beans> element
  报的是spring异常,说明id不能重复
  id标识符要在多个配置文件中不能有重复
3.还有另一种写法,不推荐
  <bean name="hello" class=""/>
4.指定清单文件不存在
  java.io.FileNotFoundException: class path resource [conf/spring1.xml] cannot be opened because it does not exist
  清单文件取自于类路径中的配置文件
  不是src/main/resources中的配置文件
5.从容器中取出对象
  org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'hello1' available
  说明容器中没有指定id的对象
6.缺少无参数构造函数
Caused by: java.lang.NoSuchMethodException: cn.tedu.ioc.Hello.<init>()
spring 原理:
  启动spring容器
  ApplicationContext context =
	new ClassPathXmlApplicationContext("conf/spring.xml");
  a.spring一定要正确加载和解析spring.xml文件
  b.把spring.xml中的bean节点的内容解析出来并存储给map集合
  c.循环遍历map集合中的所有数据
    取出class属性的值,通过反射实例化对象
    Object obj=Class.forName("包名.类名").newInstance();
  d.把创建完的对象存储到另一个map集合,用bean的id做key,对象作为value
    其实spring容器就是一个map集合
  e.如果属性需要注入,spring矿建就帮程序员注入数据(此步骤属于di,后面讲)

getBean方法:
  getBean(String)//根据id获取容器中的对象,需要强制转换
  getBean(Class)//根据类的类型获取容器中的对象,Class类型在容器唯一  
  getBean(String,Class)//根据id和类同时具备条件获取容器中的对象,id在容器中必须唯一

spring的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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	file:///c:/schema/beans/spring-beans-4.3.xsd">
		<!-- 用清单文件告知spring框架对哪些类实例化对象 -->
		<!-- id属性是对象在spring容器中的对象唯一标识,不可以重复,标识符中可以带有特殊符号
			 class属性是对象的类类型,ctrl+鼠标可以确认路径是否正确
			 name属性不能放特殊符号
		-->
		<bean id="hello" class="cn.tedu.ioc.Hello" >
		</bean>
		<bean id="hello1" class="cn.tedu.ioc.Hello"></bean>
		
	</beans>
spring容器:
1.同一个类类型,可以实例化多次,但是id的名称不能重复
  <bean id="hello" class="cn.tedu.ioc.Hello" ></bean>
  <bean id="hello1" class="cn.tedu.ioc.Hello"></bean>
2.一个类的对象被spring容器实例化,可以通过getBean方法获取多次
spring容器实例化和管理对象的四种方式
1.通过无参数构造函数实例化对象(推荐,重要,用的最多)
  <bean id="hello" class="cn.tedu.ioc.Hello" ></bean>
  特点:
      spring帮你创建对象,把创建的对象放在spring容器中
	  spring也管理这个对象,
2.静态工厂
	<?xml version="1.0" encoding="UTF-8"?>
		<beans xmlns="http://www.springframework.org/schema/beans"
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		xsi:schemaLocation="http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
			<!-- 用清单文件告知spring框架对哪些类实例化对象 -->
			<!-- 静态工厂 
				所谓的静态工厂,通过类的名字调用类中的静态的方法,
				由静态方法生产一个对象,把生产出来的对象交个spring容中管理
				id是spring容器中的对象id
				class是一个类,可以是抽象类,可以是普通类
				factory-method一定是类中的静态方法
			-->
			<bean id="hello" 
				  class="cn.tedu.factory.StaticFactory"
				  factory-method="getObject"></bean>
			<bean id="calendar"
				  class="java.util.Calendar"
				  factory-method="getInstance"></bean>
			
		</beans>
  特点:
      对象是在别的渠道创建的,但交给了spring容器管理
	必备的要求
	  a.必须有一个类(自定义,系统)
	  b.类里必须有静态方法
	  c.静态方法必须返回一个对象

3.实例工厂
	<!-- 实例工厂 
	所谓的实例工厂,生产对象的方法一定是非静态的
	首先要创建一个实例工厂的对象,
	通过对象来调用非静态的方法
	  Hello hello1=if.getObject();
	  返回的对象交给spring容器来管理
	  
	-->
	<bean id="if" 
	      class="cn.tedu.factory.InstanceFactory"></bean>
	<bean id="hello1"
	      factory-bean="if"
	      factory-method="getObject"></bean>
  特点:
      对象是在别的渠道创建的,但交给了spring容器管理
	必备要求:
	  a.必须有一个类,但不能抽象类
	  b.类里有方法,但方法一定不能是静态方法
	  c.方法类一定要返回一个对象

4.spring工厂
	<!-- spring 工厂 
	  所谓的spring工厂要求类必须实现自FactoryBean接口
	 返回的对象放在spring容器中
	 调用重写getObject方法,此方法返回一个对象,并放在spring容器中
	 自动调用重写接口方法
	-->      
	<bean id="hello2"
	      class="cn.tedu.factory.SpringFactory"></bean>    
  特点:
      对象是在别的渠道创建的,但交给了spring容器管理
   必备要求:
    a.类必须实现自BeanFactory接口
	b.重写getObject方法,且一定要返回一个对象
	c.spring容器会自动调用getObject方法,然后把对象放置到spring容器中
	
	spring创建对象是单例还是多例
	1.spring容器默认情况下,创建的对象是单例
	  说明对象在容器中只有一个,可以从容器中取出多次
	  对象的生命周期跟spring容器的生命周期相同
	  <bean id="hello" class="cn.tedu.ioc.Hello" ></bean>
	  等同于
	  <bean id="hello" class="cn.tedu.ioc.Hello" scope="singleton" ></bean>
	2.spring容器 多例对象 scope="prototype"
	  什么时候getBean,什么时候才实例化对象,并把对象返回用户
	  对象的生命周期不是由spring容器掌控,由用户来掌控
	  <bean id="hello" class="cn.tedu.ioc.Hello" scope="prototype" ></bean>
  1. spring容器的生命周期
1.何时创建的容器,spring容器初始化的时候
  AbstractApplicationContext context =
				new ClassPathXmlApplicationContext("conf/spring.xml");

2.spring容器何时销毁的
  context.close();
	 
spring容器中的对象生命周期
  spring容器创建对象时,调用无参数构造
  对象创建完后会自动调用init方法(如果有)
    a.局部初始化
	init是类中的一个方法名称
	<bean id="hello" class="cn.tedu.ioc.Hello" init-method="init" ></bean>
	
	b.全局初始化
    <beans  default-init-method="init" ></beans>
  在对象销毁的时候自动调用destroy方法(如果有),容器销毁,对象才销毁
    a.局部销毁
	destroy是类中的一个方法名称
	<bean id="hello" class="cn.tedu.ioc.Hello" destroy-method="destroy" ></bean>
	
	b.全局销毁
     <beans  default-destroy-method="destroy" ></beans>


  注意:
    单例时,局部初始化和局部销毁,都会调用
	多例时,局部初始化会被调用,局部销毁不会调用
    尽量用局部,少用全局
spring容器中的对象的懒加载
  控制对象的创建的时机
  <bean id="hello" 
        class="cn.tedu.ioc.Hello"
		scope="singleton"
		lazy-init="true"></bean>
		
  虽然scope="singleton" ,但是如果懒加载为true,
  就是不在容器初始化的时候创建对象,而是在
  第一次getBean的时候才创建对象,对象还是单例对象
 
  懒加载的全局:
    <beans default-lazy-init="true"></beans>
	
   lazy-init         scope       对象的创建结果
    true             sington       单例对象 懒加载
	true             prototype     多例对象 懒加载
	default/flase    singleton     单例对象 立即加载
	default/false    prototype     多例对象 懒加载
	
在spring的配置文件中导入其他的spring的配置
   <beans>
      <import resource="xxx.xml"/>
	  <import resource="yyy.xml"/>
	  <import resource="zzz.xml"/>
   </beans>
spring DI dependency  injection 依赖注入

  从spring容器中取出容器中的对象,然后把对象注入到需要的地方
注入的方式:
  setter方式
  构造函数方式
  
  
setter方式注入:
  对象注入,单值注入,集合注入,表达式注入,空值注入
  
对象注入:
	<!-- 
	<bean 节点用来告知spring实例化或管理对象
	<property 节点,是用来告知spring有对象注入关系,相当于告知spring要做对象的关系管理
	  每一个property节点都必须对应一个setter方法	  
	   name属性 其实对应的是class属性指定的类中的setter方法
	   name="userDao"  userDao->UserDao->setUserDao
	   把name属性的值的第一个字母大写,前面加上set,构建出字符串setUserDao
	   拿这个setUserD字符串,去UserServiceImpl类中寻找是否有此名称的方法
	   如果有setter方法,就反射调用这个setter方法
	   ref="userDao" ref:referenece 引用  要引用一个对象,且对象的名称叫userDao
	   注意:ref引用的对象,一定是引自spring容器, userDao是容器中的唯一的id
	   
	 -->      
	<bean id="userService"
	      class="cn.tedu.service.impl.UserServiceImpl">
		<property name="userDao" ref="userDao"></property>      
	</bean>
单值注入:
	<!-- 
	  bean节点告知spring要实例化对象
	  property节点告知spring做数据注入 ,对应setter方法
	  value="18"  双引号不是数据的内容,是数据的分隔符号
	  value="北京"  双引号不是数据的内容,是数据的分隔符号
	  
	 -->
	<bean id="valueInject"
	      class="cn.tedu.value.ValueInject">
		<property name="age" value="20"></property>      
	    <property name="address">
	        <value>北京</value>
	    </property>
	</bean>
	
集合注入(直接集合注入和间接集合注入)
  直接集合注入:
    <!-- 用清单文件告知spring框架对哪些类实例化对象 -->
	<bean id="hello"
	      class="cn.tedu.ioc.Hello" />
	
	<!-- 直接集合注入 -->
	<bean id="message" 
	      class="cn.tedu.collection.Message">
		<property name="list">
			<list>
				<value>北京</value>
				<value>上海</value>
				<value>广州</value>
				<ref bean="hello"/>
			</list>
		</property>
		<property name="set">
			<set>
				<value>北京</value>
				<value>上海</value>
				<value>广州</value>
				<ref bean="hello"/>
			</set>
		</property>
		<property name="map">
			<map>
				<entry key="bj" value="北京"></entry>
				<entry key="sh" value="上海"></entry>
				<entry key="gz" value="广州"></entry>
				<entry key="h" value-ref="hello" ></entry>
			</map>
		</property>
		<property name="props">
			<props>
				<prop key="bj">北京</prop>
				<prop key="sh">上海</prop>
				<prop key="gz">广州</prop>
			</props>
		</property>      
	</bean>  
  间接集合注入:
   前提:xmlns:util="http://www.springframework.org/schema/util" 
        http://www.springframework.org/schema/util 
        http://www.springframework.org/schema/util/spring-util.xsd
	<!-- 间接集合 -->
	<!-- 集合的对象要交给spring容器来管理 -->
	<util:list id="uList">
		<value>北京</value>
		<value>上海</value>
		<value>广州</value>
		<ref bean="hello"/>
	</util:list>
	
	<util:map id="uMap">
		<entry key="bj" value="北京"></entry>
		<entry key="sh" value="上海"></entry>
		<entry key="gz" value="广州"></entry>
		<entry key="h" value-ref="hello" ></entry>
	</util:map>
	
	<util:set id="uSet">
		<value>北京</value>
		<value>上海</value>
		<value>广州</value>
		<ref bean="hello"/>
	</util:set>
	
	<util:properties id="uProps">
	    <prop key="bj">北京</prop>
		<prop key="sh">上海</prop>
		<prop key="gz">广州</prop>
	</util:properties>

	<bean id="message1"
          class="cn.tedu.collection.Message">
    	<property name="list" ref="uList"></property> 
    	<property name="set" ref="uSet"></property>     
        <property name="map" ref="uMap"></property>
        <property name="props" ref="uProps"></property>
    </bean>	
	
表达式注入:
  前提:
       必须有属性文件,表达式注入就是把属性文件的数据通过spring
       注入给某个对象中
    mysql.properties
	  jdbc_driverClass=com.mysql.jdbc.Driver
	  jdbc_url=jdbc:mysql://localhost:3306/tesdb
	  jdbc_userName=root
	  jdbc_userPassword=root
	page.properties
	  pageSize=3
      showNum_a=5
属性注入的方式有两种     	
 ${}方式
   清单文件文件中有context的命名空间的定义
   <!-- 属性注入   用$方式 
	 location属性可以放置多个属性文件,用逗号间隔,建议用类路径classpath取,
	  仅针对spring框架
	  把属性文件的数据加载到spring容器中-->
	<context:property-placeholder location="classpath:conf/mysql.properties,classpath:conf/page.properties"/>
	
	<bean id="jdbcUtil"
	      class="cn.tedu.expression.JDBCUtil">
		<property name="driverClass" value="${jdbc_driverClass}"></property>
		<property name="url" value="${jdbc_url}"></property>
		<property name="username" value="${jdbc_userName}"></property>
		<property name="userpassword" value="${jdbc_userPassword}"></property>      
	</bean>	
	<bean id="pageUtil"
	      class="cn.tedu.expression.PageUtil">
		<property name="pageSize" value="${pageSize}"></property>
		<property name="showNum_a" value="${showNum_a}"></property>      
	</bean>


 #{}方式 
   清单文件中要求有util的命名空间
   <!-- 属性注入  #{} 多个文件用逗号间隔 ,必须给一个id
	把属性文件的数据存储给spring容器,容器中以manyProperty,值是若干属性键值对
	-->
	<util:properties 
	   id="manyProperty"
	   location="classpath:conf/mysql.properties,classpath:conf/page.properties"></util:properties>
	
	<bean id="jdbcUtil"
	      class="cn.tedu.expression.JDBCUtil">
		<property name="driverClass" value="#{manyProperty.jdbc_driverClass}"></property>
		<property name="url" value="#{manyProperty.jdbc_url}"></property>
		<property name="username" value="#{manyProperty.jdbc_userName}"></property>
		<property name="userpassword" value="#{manyProperty.jdbc_userPassword}"></property>      
	</bean>	
	<bean id="pageUtil"
	      class="cn.tedu.expression.PageUtil">
		<property name="pageSize" value="#{manyProperty.pageSize}"></property>
		<property name="showNum_a" value="#{manyProperty.showNum_a}"></property>      
	</bean>
	
空值注入:
    <bean id="kong"
	      class="cn.tedu.kong.Kong">
		<property name="str1" value=""></property>
		<property name="str2">
			<null></null>
		</property>
	</bean>	
	
注意:
  对象注入和单值注入,都是setter注入  ,的一个新的写法
  <!-- 新的写法 
	如果没有ref 就是老的写法的value  ,单值注入
	有ref 就是老的写法的ref,对象注入,引用容器中的一个对象
	p:就是代表的就是老写法的property节点
	p:后的字符串就是property节点中的name属性的值
	-->
	<bean id="setternew1"
	      class="cn.tedu.setternew.SetterNew"
	      p:name="王五"
	      p:age="22"
	      p:hello-ref="hello"
	      p:userDao-ref="userDao">
	</bean>
	
构造函数注入:
	<bean id="hello" class="cn.tedu.ioc.Hello"/>
	<bean id="ci"
	      class="cn.tedu.constructor.ConstructorInject">
		<constructor-arg index="0" ref="hello"></constructor-arg>
		<constructor-arg index="1" value="张三"></constructor-arg>
	</bean>
	
结论:
   setter注入方式在开发中常用
   构造函数注入方式在框架源码中使用,在开发中也可以使用   
  1. spring DI中常见的错误:
1.Bean property 'userDao1' is not writable
  说明属性没有setter方法
  需要检查两个地方
     类里是否有setter方法
	 清单文件Property节点的name属性值是否正确
2.No bean named 'userDao1' available
  容器中没有指定id名称的对象
3.Unsatisfied dependency expressed through constructor parameter 0: 
Ambiguous argument values for parameter of type [cn.tedu.ioc.Hello] - did you specify the correct bean references as arguments?
	说明构造函数的参数的位置设定有问题
4. Unsatisfied dependency expressed through constructor paramete 2: Ambiguous argument values for parameter of type [int] - did you specify the correct bean references as arguments?	
	说明构造函数的参数个数不匹配
  1. spring中是如何处理继承:
	<!-- 实例化DataSource对象 -->
	<bean id="dataSource"
	      class="cn.tedu.jicheng.DataSource">
		<property name="url" value="jdbc:mysql:///testdb"></property>      
	</bean>
	
	<!-- 实例化BaseDao对象 -->
	<bean id="baseDao"
	      class="cn.tedu.jicheng.BaseDao"
	      abstract="true">
		<property name="dataSource" ref="dataSource"></property>      
	</bean>
	
	<!-- 实例化UserDao -->
	<bean id="userDao"
	      class="cn.tedu.jicheng.UserDao"
	      parent="baseDao">
	</bean>
  spring中继承需要注意的问题:
    1.对象都要交个spring容器管理
  	2.对象的关系也要交给spring来管理
  	3.父类对象是spring创建,而不是由原生java自动创建
  	4.在子类对象中用parent属性执行spring容器中的父类对象
  	5.如果父类是抽象,需要添加一个astract=true
	
在spring中能够提高开发效率的那几种做法(不推荐,原因是降低代码的可读性)
	<!-- 下面的写法可以提高开发效率,但不推荐使用,因为降低的代码的可读性 -->
	<!-- autowire="byName" 按照名称装配
	首先反射cn.tedu.wire.User中的所有的方法,并筛选出setter方法
	把set去掉,把剩下的字符串的第一个字母小写,拿剩下的字符串做为id去
	spring容器中寻找对应的对象,如果找到就反射调用setter方法,注入对象
	如果没有,就什么都不注入
	 -->
	<bean id="user1" 
	      class="cn.tedu.wire.User"
	      autowire="byName">
	</bean>
	<!-- 
	autowire="byType"
	按照类型装配
	 -->
	<bean id="user2" 
	      class="cn.tedu.wire.User"
	      autowire="byType">
	</bean>
  1. spring中的IOC和DI的注解:
注解:可以提高开发效率,注解分为三个部分
     1.定义注解
  	 2.应用注解到指定的地方
  	 3.使用反射的的代码来解析注解
  注解其实就是一个标记
     带有注解能做什么
  	 不带有注解能做什么
  	 带有注解且带有属性能做什么
	 
	 所以需要反射的java的代码来检测注解是否存在,注解是否带有属性
	 然后决定如何做

  完成一个功能:
    1.程序员用java代码实现                       开发效率最低,但执行效率最高
  	2.程序员写部分的java代码+清单文件+框架代码   中庸
  	3.用注解+框架的代码                          开发效率最高,但执行效率最低
spring中提供若干个注解用于替换xml清单文件
  xml版本:
    用bean节点来实例化对象
    用property节点来注入对象数据
  注解版本:
    bean节点用如下注解替换
       @Controller注解  用于实例化控制器的类的对象
  	   @Service注解     用于实例化业务类的对象
  	   @Repository注解  用于实例化dao类的对象
  	   @Component注解   用于实例化无法归类的类的对象

    property节点用如下注解替换
       @Resource注解    用于对象的注入,注解隶属于J2EE规范
  	   @Autowired注解   用于对象的注入,注解隶属于spring规范
  	   @Inject注解      用户对象的注入,注解隶属于jsr330的规范

  注意:
    1.项目中可以全部用清单配置文件方式实现
  	2.项目中可以全部用注解的方式实现
  	3.项目中可以用部分注解方式和部分的清单文件
  	4.项目中只要涉及注解的,就一定要注册一些其他的java类,
  	  用于解析和处理注解
  1. property节点用如下注解替换
   @Resource注解    用于对象的注入,注解隶属于J2EE规范
   @Autowired注解   用于对象的注入,注解隶属于spring规范
   @Inject注解      用户对象的注入,注解隶属于jsr330的规范	
@Resource注解,能注入对象,隶属于J2EE规范,
        有java的环境就可以使用此注解  
  1.按照名称装配,按照名称在spring容器中精确查找
    取出注解的属性name="userDao"的值是userDao,拿这个值去spring容器寻找
    public class UserServiceImpl{
		@Resource(name="userDao")
		private userDao userDao;	
	}
  2.按照属性名称装配,
    属性上要有@Resource注解,如果没有name属性,就找成员变量的属性userdao
	,然后用成员变量的属性名去spring容器中寻找
	public class UserServiceImpl{
		@Resource
		private userDao userDao;	
	}
	
  3.按照类型装配,注意容器中不能有两个以上的相同的类型
    如果成员变量名无法装配,就按照成员变量的
	类型装配,如果找到就注入,如果没有找到就报异常
    public class UserServiceImpl{
		@Resource
		private userDao userDao11;	
	}  

  总结:
    如果按照1方式就直接查找,找到就注入,找不到就报异常,
	         按照名称装配是默认方式,推荐@Resource(name="")
  	如果按照2方式及先按照成员变量的名称装配,找到就注入
  	         找不到就按照3方式,按照类型装配,找到就注入
  			 找不就报异常
			 
	@Resource注解既可以写在属性上(用反射暴力注入)
	@Resource注解也可以写在setter方法上(用反射非暴力注入)
@Autowired注解   用于对象的注入,注解隶属于spring规范   
   @Autowired注解默认是按照类型装配/注入
   1.默认按照类型注入/装配,在容器中不能有相同的两个以上类型
    注意:先按照成员变量的名称去spring容器中寻找,找到就注入
	     找不到就按照类型来装配和注入,类型有匹配的就注入,但不能
		 有两个以上的同类型的对象,类型没有匹配就报异常
    public class UserServiceImpl{
		@Autowired
		private userDao userDao;	
	} 
    public class UserServiceImpl{
	    //false:对象可以为null,true:属性必须存储对象,不能为null
		@Autowired(required=false)
		private userDao userDao;	
	} 	
   2.也可以按照名称注入/装配  需要配合另一个注解@Qualifier
    按照@Qualifer("userDao")中userDao去spring容器中寻找,找到就注入
  	找不到就报异常
  	public class UserServiceImpl{
  		@Autowired
  		@Qualifer("userDao")
  		private userDao userDao;	
  	} 
@Inject注解      用户对象的注入,注解隶属于jsr330的规范	
 此注解不推荐使用,此种做法需要导入一个第三方的jar包
 jsr330.jar
@Value注解  把属性文件中的数据注入给spring容器中的对象
            @Value注解只应用在处理属性文件上
 前提:
   mysql.properties 
    jdbc_driverClass=com.mysql.jdbc.Driver
	jdbc_url=jdbc:mysql://localhost:3306/tesdb
	jdbc_userName=root
	jdbc_userPassword=root
 1.@Value("${属性的key}")
    <!-- 把属性文件的数据交给spring容器来管理 ,多个属性文件用逗号间隔-->
    <context:property-placeholder location="classpath:conf/mysql.properties"/>
    <!-- 
            此配置项用于注册一批java类,这java类用解析和处理指定的注解
        @Resource注解
        @Autowired注解@Qualifier注解
        @Inject注解@Named注解
        @Value注解
            这些java类中写反射代码,用于检测指定的类中是否有注解以及是否有注解的属性
     -->
	<context:annotation-config></context:annotation-config>
	
	<bean id="jdbcutil"
	      class="cn.tedu.util.JDBCUtil">
	</bean>
	
	/**
	 * @value("${属性的key}")
	 * @author admin
	 *
	 */
	public class JDBCUtil {
		@Value("${jdbc_driverClass}")
		private String driverClass;
		@Value("${jdbc_url}")
		private String url;
		@Value("${jdbc_userName}")
		private String userName;
		@Value("${jdbc_userPassword}")
		private String userPasword;
		@Override
		public String toString() {
			return "JDBCUtil [driverClass=" + driverClass + ", url=" + url + ", userName=" + userName + ", userPasword="
					+ userPasword + "]";
		}
		
		
	}

 2.@Value("#{id.属性的key}")
   <!-- 把属性文件的数据交给spring容器来管理 ,多个属性文件用逗号间隔-->
    <util:properties 
        id="manyProperty"
        location="classpath:conf/mysql.properties"></util:properties>
    
    <!-- 
            此配置项用于注册一批java类,这java类用解析和处理指定的注解
        @Resource注解
        @Autowired注解@Qualifier注解
        @Inject注解@Named注解
        @Value注解
            这些java类中写反射代码,用于检测指定的类中是否有注解以及是否有注解的属性
     -->
	<context:annotation-config></context:annotation-config>
	
	<bean id="jdbcutil1"
	      class="cn.tedu.util1.JDBCUtil1">
	</bean>
	
	/**
	 * @value(#{id.属性的key})
	 * @author admin
	 *
	 */
	public class JDBCUtil1 {
		@Value("#{manyProperty.jdbc_driverClass}")
		private String driverClass;
		@Value("#{manyProperty.jdbc_url}")
		private String url;
		@Value("#{manyProperty.jdbc_userName}")
		private String userName;
		@Value("#{manyProperty.jdbc_userPassword}")
		private String userPasword;
		@Override
		public String toString() {
			return "JDBCUtil [driverClass=" + driverClass + ", url=" + url + ", userName=" + userName + ", userPasword="
					+ userPasword + "]";
		}
		
		
	}
bean节点被替换成spring的注解
    @Controller注解  用于实例化控制器的类的对象
  	@Service注解     用于实例化业务类的对象
  	@Repository注解  用于实例化dao类的对象
  	@Component注解   用于实例化无法归类的类的对象

 以上4个注解用法基本相同,都是应用在类上,
 现以@Service注解为例
   1.4个注解都是修饰在类上
   
   2.@Service  修饰在哪个类上,spring就实例化这个类的对象,
               并放在spring容器中管理,以指定规则为id
			   类的第一个字符小写作为容器中的对象的id
			   但前提类的名字必须遵守帕斯卡命名法
   3.@Service(value="名字")
     等价于
	 @Service("名字")
	 修饰在类上,value=是可以省略的,修饰在哪个类上,
	 这个类的对象要交给spring容器来管理,对象的id
	 就是value属性的值
   4.4个注解必须需要一批的java类来解析和处理这些注解
     <context:component-scan base-package="包名"></context:component-scan>
     此配置专门用来解析和处理
	   @Controller注解
	   @Service注解
	   @Repository注解
	   @Component注解
	 和@Resource注解
	   @Autowired注解@Qualifier注解
	   @Inject注解@Named注解
	   @Value注解

     因为此<context:component-scan的配置包含了
	  <context:annotation-config配置
	 所以注册java类包含<context:annotation-config配置中java类
补充几个常见的注解
1.@Scope(value="singleton") 单例    修饰在类上
  @Scope(value="prototype") 多例	修饰在类上
2.@Lazy(value=true|false)   懒加载  修饰在类上
3.@PostConstruct            初始化方法  修饰在方法上
4.@PreDestroy               销毁方法    修饰在方法上

在这里插入图片描述
10. 事务管理:事务的4大特性:简称acid

1.原子性(atomicity)
	  原子性是指事务包含的所有操作,要么全部成功,要么全部失败,即回滚
	  比如:
	   以银行转账为例
	    update t_balance set 余额=余额-1000 where card_id='111';
	    update t_balance set 余额=余额+1000 where card_id='222';	

	2.一致性(consistency)
	  一致性是指事务必须使数据从一个个一致性状态变换到另一个一致性的状态
	  即,事务执行前后,状态是一致的
	  比如:
	    银行转账为例,转账前后,的账面资金是一致的
	3.隔离性(isolation)
	  隔离性是当前多个用户并发访问数据库的时候,数据库为每一个用户开启
	  一个事务,其中某一个事务不能被其他事务操作所干扰,多个并发事务之间
	  相互隔离,即要达到一个效果:对于任意两个并发事务T1和T2,在事务T1来看
	  T2事务要么在T1开始之前就已经结束,要么在T1结束之后才开始执行
	  
	4.持久性(durability)
	  持久性是值一个事务一旦提交了,那么数据库中的数据改变就是永久性的
	  即便是在数据库系统中遇到故障的情况下,也不不会丢失提交事务的操作
		
  1. 数据库的四种隔离级别:
	    1.串行化(Serializable):
			可以避免脏读,不可重复读,幻读的发生
		2.可重复读(repeatable):
			可以避免脏读和不可重复读的发生
		3.读已提交(read commited):
			可以避免脏读的发生
		4.读未提交(read uncommited):最低级别
			任何情况下都可能出问题
	 以上4重隔离级别,串行化级别最高,读未提交级别最低
	 隔离级别越高,执行效率越低
	 mysql的默认隔离级别是repeatable read(可重复读)
	 oracle的数据库只支持串行化和读已提交两种级别,默认是读已提交级别
因为有了并发事务,多个事务同时执行,根据数据库的隔离级别,就会产生如下问题:(达到口述)
		1、脏读:
			指在一个事务处理的过程中,读取另一个未提交的事务中的数据
			比如:
				银行转账为例
				update t_balance set 余额=余额-1000 where card_id='111';
	    		update t_balance set 余额=余额+1000 where card_id='222';
	    	  如果发生这样情况就属于脏读:
	    	   在执行玩第一个更新语句的时候,但还没执行第二行更新语句,
	    	   另一个事务读物t_balance表的数据,余额被减,通知用户余额减过了,
	    	   但是还没有执行第二条更新语句就回滚了,此时已经提示过用户余额减过了
	    	   	
		2、不可重复读:
			针对数据库中的某个数据,一个事务范围内多次查询却返回不同的数据值,这是由于
			在查询的间隔被另外一个事务把数据修改并提交了
			比如:
				事务T1在读取某一个数据,而事务T2修改了这个数据,并提交了事务,
				事务T1再次读取这个数据,就与上一次T1事务读取值不同,发生了不可重复读
		 **不可重复读和脏读的区别:
		 	脏读是某个事务读取了另一个事务未提交的数据
		 	不可重读则是读取了上一个事务提交的数据
		 **注意:
		 	在某些情况下,不可重复读不是问题,无论数据被改变了多少次,且提交,
		 	只需要获得最后提交的数据即可

		3、幻读:
			事务非独立执行时,发生的一种现象
			比如:
				事务T1对一个表中的所有行的某个数据项做了从”1“修改到”2“的操作,
				这时,事务T2又对这张表添加了一行数据,而这行中指定列的数据项是”1“,
				并且提交给了数据库,这是操作事务T1的用户查询此数据表就会发现有一行没有
				从”1“修改到”2”,此种情况就是幻读
		 幻读和不可重复读都是读取了另一个提交的事务
		 脏读是读取的另一个未提交的事务数据
		 不可重复读查询的是同一个数据项
		 而幻读针对对一批数据的整体中的某个数据项
在mysql中如何让设置隔离级别:
		1、在mysql中设置
			在mysql的黑白界面中
			 set tx_isolation='隔离级别的名称';
		2、在java代码中设置:
			Connection con=null;
			try{
				con=CommonDao.getConnection();
				//设置数据库得隔离级别,只针对当前的连接有效
				con.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE)
				con.setAutoCommit(false);//开始事务
				。。。
				con.commit();
			}catch(Exception e){
				con.rollback();
			}
代理设计模式:
			有一个需求:原有的业务不做任何修改,添加额外的新功能,实现需求方式
			方式一:
				在原有的代码的前面添加新的功能
				在原有的代码的后面添加新的功能
				因为直接修改代码,破坏了开闭原则,单一职责
		    方式二:用代理设计模式来实现
		    	原有的业务到吗能够正常运行,也没有修改源代码
		    	通过代理设计模式,就能够实现在原有的功能前面或者后面添加新功能

		   比如:
		     事务的案例:
		     	在业务的前面添加事务的开启
		     	在业务的后面添加事务的提交或者回滚

		     	事务:是一个新的功能业务
		     	把事务的功能业务横切到老的业务的前面或者后面
		     	就横切性编程
		1、实现代理的步骤:
			1.1、必须有能够正常运行的业务代码
			1.2、必须有要额外添加的新的业务功能代码,且能正确执行
			1.3、必须有一个类把原有的业务跟新的业务耦合(推荐用组合,即就是把新的业务功能横切或
				植入到需要的业务方法前面或者后面)
		2、代理的分类:
			2.1、静态代理:执行效率高,开发效率低
			2.2、动态代理:开发效率高,执行效率低
				a.jdk动态代理,jdk自带的
				b.cglib动态代理  需要第三方jar依赖
		3、静态代理的实现:
			3.1、需要准备原有的业务功能
					UserDao.java  UserDAoImpl.java
					UserService.java   UserServiceImpl.java
			3.2、新的业务功能:
				TransactionManager.java
			3.3、静态代理类:
				负责把老的业务和新的业务耦合在一起
				StaticProxy.java
		4、总结:
			4.1、没有修改原有的源代码,没有破坏开闭原则,符合单一职责
			4.2、新的业务功能也是符合单一职责
			4.3、新建了一个静态代理类,把原有的业务和新的业务功能耦合在一起
				4.3.1、要求静态代理类要实现业务的接口,因为要保证业务的完整性
				4.3.2、有多少个业务类,就有多少个静态代理类
						比如:
						  UserService    对应  public class StaticProxy1 implements UserService
						  ProductService 对应  public class StaticProxy1 implements ProductService
						 典型从一个代码泥潭跳到另一个代码的泥潭业务的代码成倍增长
				4.3.3、静态代理类不满足单一职责,因为静态代理类中明显的耦合了原有的业务和新的
						业务功能,但是还是要尽量单一
				4.3.4、StaticProxy是静态代理类,此类的对象是代理对象
				4.3.5、静态代理类在编译期间就已经确定原有的业务和新的业务的耦合模型
				4.3.6、开发效率低,但是执行效率高
		5、衍生出来的若干名词:
			5.1、原有的业务模型  
				5.1.1、目标类
				5.1.2、目标对象
			5.2、新的业务模型
				5.2.1、切面类,新的功能是切面
				5.2.2、切面类的对象,用新的功能类实例化的对象
			5.3、横切和织入  把新的业务横切到老的业务方法上
			5.4、耦合 --->老的业务和新业务的耦合
			5.5、代理类--->代理人一样,在代理类中体现出老业务和新业务的耦合
			5.6、代理对象--->是用代理类实例化的对象
		6、动态代理:
			在运行期间,动态的创建代理类
			在创建代理对象之前,由程序动态的在运行期间创建代理类
			6.1、动态代理分类:
				jdk动态代理
				cglib动态代理
			6.2、jdk动态代理:用jdk类库创建代理对象,但之前由jdk的类库创建代理类
			6.3、动态代理的三个层次:
				层次1:能写出动态代理的实现即可,耦合新的功能和老的功能即可;(正常授课)
				层次2:能够熟练并清晰的了解动态代理的调用关系
				层次3:能够了解jdk底层的创建代理类的过程,并且清晰的了解动态代理类的内容
  1. jdk动态代理:
  1.老的业务功能  UserServiceImpl.java   UserService.java
  2.新的业务功能  TransactionManager.java 
  3.创建一个java类,类中有一个java工厂方法,这个方法是专门
    创建代理对象,传递进去目标对象,出来的是代理对象
  4.创建一个java类,必须实现自InvocationHandler接口
    接口实现方法invoke中,耦合老的业务功能和新的业务功能

在这里插入图片描述

jdk动态代理的若干要求:
  1.目标类必须接口
  2.代理类和目标类是兄弟关系,隶属于同一个接口
  3.代理类存储在内存中,第一创建代理对象的时候,会自动创建代理类
  4.用内存的代理类实例化代理对象
  5.用代理对象打点调用目标方法,方法在代理类重写接口的方法
  6.在代理类的重写的方法中调用InvocationHandler接口的方法
  7.调用invoke方法中耦合了老的业务和新的业务
生成的代理类:
  package com.sun.proxy;

  import cn.tedu.entity.User;
  import cn.tedu.service.UserService;
  import java.lang.reflect.InvocationHandler;
  import java.lang.reflect.Method;
  import java.lang.reflect.Proxy;
  import java.lang.reflect.UndeclaredThrowableException;

  public final class $Proxy0
    extends Proxy
    implements UserService
  {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m4;
    private static Method m0;
    
    public $Proxy0(InvocationHandler paramInvocationHandler)
    {
    super(paramInvocationHandler);
    }
    
    public final boolean equals(Object paramObject)
    {
    try
    {
      return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
    }
    
    public final String toString()
    {
    try
    {
      return (String)this.h.invoke(this, m2, null);
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
    }
    
    public final Boolean addUser(User paramUser)
    {
    try
    {
      return (Boolean)this.h.invoke(this, m3, new Object[] { paramUser });
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
    }
    
    public final Boolean updateUser(User paramUser)
    {
    try
    {
      return (Boolean)this.h.invoke(this, m4, new Object[] { paramUser });
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
    }
    
    public final int hashCode()
    {
    try
    {
      return ((Integer)this.h.invoke(this, m0, null)).intValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
    }
    
    static
    {
    try
    {
      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
      m3 = Class.forName("cn.tedu.service.UserService").getMethod("addUser", new Class[] { Class.forName("cn.tedu.entity.User") });
      m4 = Class.forName("cn.tedu.service.UserService").getMethod("updateUser", new Class[] { Class.forName("cn.tedu.entity.User") });
      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      return;
    }
    catch (NoSuchMethodException localNoSuchMethodException)
    {
      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
    }
    catch (ClassNotFoundException localClassNotFoundException)
    {
      throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
    }
    }
  }
cglib动态代理:
  cglib是第三方的工具jar包提供的用来生成cglib代理对象
  cglib要有业务类(目标类)有无接口皆可
  但必须要求业务类(目标类)不能是final类
  因为cglib的代理类是目标类的子类
cglib动态代理的实现步骤
  1.有老的业务实现,必须跑通,且老的业务类不能final2.有新的业务类,必须跑通
  3.创建一个java类,CGLIBProxy.java,专门用来生产cglib的代理对象
  4.创建一个java类,必须实现自MethodInterceptor接口
    在接口的实现方法intercept中,耦合老的业务和新的业务
  
补充一个知识点:
    TransactionHandler implements InvocationHandler接口
     重写invoke方法
     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      Object returnValue=null;
      System.out.println("2-->"+targetObject);
      System.out.println("4-->"+proxy.getClass());
      //实例化新的业务功能对象
      TransactionManager tm=new TransactionManager();
      try{
        tm.begin();
        //执行老的业务功能,用反射的方式
        returnValue=method.invoke(targetObject, args);
        tm.commit();
      }catch(Exception e){
        tm.rollback();
        e.printStackTrace();
      }
      
      return returnValue;
    }
       

    TransactionInterceptor implements MethodInterceptor
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
      Object returnValue=null;
      TransactionManager tm=new TransactionManager();
      try{
        tm.begin();
        //用java原生反射调用老的业务方法
        returnValue=method.invoke(targetObject, args);
        //用cglib封装类来调用老的业务方法,其底层还是原生反射api
        //returnValue=methodProxy.invoke(targetObject, args);
        tm.commit();
      }catch(Exception e){
        tm.rollback();
        e.printStackTrace();
      } 
      
      return returnValue;
    }
结论:
 上面两个例子中的returnValue的值就是老的业务方法的返回值
 但最后写的是return returnValue;此处的返回值不一定就是
 老的业务的返回值,可以经过再次处理后返回
动态代理的总结:
    1.原有的业务功能没有被修改,新的业务功能也添加上了,遵守了开闭原则,单一职责
    2.静态代理类是由程序员创建的,动态代理类是由工具创建的(jdk,cglib)
    3.每一个业务类都对应至少一个静态代理类,编译期间确定代理类, 
      开发效率低,执行效率高
    4.根据具体的目标对象,来动态的创建代理类,在运行期间才会有动态代理类
      开发效率高,执行效率低;利用缓存代理类,来尽量提升执行效率
    5.静态代理类和动态代理类还是必须要出现的
      静态代理类是由程序员写的
      动态代理类是由工具创建的
    6.用静态代理或动态代理,只能给业务方法的前或后横切/织入新功能
    7.静态代理是用静态代理类把原有的业务和新的业务耦合在一起
      动态代理是回调指定接口的实现
         a.jdk动态代理,回调的是InvocationHandler接口方法invoke,耦合老和新功能
       b.cglib动态代理,回调的是MethodInterceptor接口方法intercept,耦合老和新功能
    8.静态代理类和动态代理类都必须实现业务接口
    9.通过jdk或cglib生成的代理类,通过代理可以实例化很多的代理对象
  1. jdk和cglib的区别:
  jdk动态代理:
    1.目标业务类必须要有接口
    2.必须实现自InvocationHandler接口,在接口实现方法中耦合老和新的功能
    3.代理类和目标业务类是兄弟关系,因为隶属于同一个接口
    4.用jdk创建代理,创建代理类块,执行代理类慢
  cglib动态代理:
    1.业务类有无接口皆可
    2.必须实现自MethodInterceptor接口,在接口的实现方法中耦合老和新功能
    3.代理和业务类是父子关系,业务类是父类,代理类子类
    4.用asm和cglib创建代理类,创建慢,执行块
    5.业务类不能是final
  1. Spring JDBC+声明式事务 Annotation版本: 项目(TestMavenSpring-Jdbc_Annotation)
    在这里插入图片描述
1.创建项目
2.导入jar包
  spring-context.jar
  spring-aspects.jar
  aspectjweaver.jar
  aopalliance.jar
  mysql驱动包   mysql-connector-java
  druid.jar  阿里巴巴连接池
  spring-jdbc
  spring-tx   事务包
3.创建java类
  老的业务功能
  UserDao.java   UserDaoImpl.java
  UserService.java    UserServiceImpl.java

4.清单文件
    a.实例化老的业务对象
      <context:component-scan basePackage="cn.tedu.dao"></context:component>
      <context:component-scan basePackage="cn.tedu.service"></context:component>
        @Repository  @Service  @Resource  
    b.写spring aop独有的配置   <aop:config></aop:config>
    c.写spring声明式事务配置,spring独有的
    d.druid阿里巴巴的数据库连接池的对象的创建   --->不能用注解替换
    e.spring jdbc的模板类的对象的创建   --->不能用注解替换
  b.c步骤用spring声明式事务注解替换
  需要解析这个注解
5.启动spring容器,加载和解析xml清单文件
6.从spring容器中取出对象备用
编程式事务:
    方式一:
        public class SimpleService implements Service {
        // single TransactionTemplate shared amongst all methods in this instance
        private final TransactionTemplate transactionTemplate;
        // use constructor-injection to supply the PlatformTransactionManager
        public SimpleService(PlatformTransactionManager transactionManager) {
        Assert.notNull(transactionManager, "The 'transactionManager' argument must not be null.");
        this.transactionTemplate = new TransactionTemplate(transactionManager);
        }
        public Object someServiceMethod() {
        return transactionTemplate.execute(new TransactionCallback() {
        // the code in this method executes in a transactional context
        public Object doInTransaction(TransactionStatus status) {
        updateOperation1();
        return resultOfUpdateOperation2();
        }
        });
        }
        }
    方式二:
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        // explicitly setting the transaction name is something that can only be done programmatically
        def.setName("SomeTxName");
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        TransactionStatus status = txManager.getTransaction(def);
        try {
        // execute your business logic here
        }
        catch (MyException ex) {
        txManager.rollback(status);
        throw ex;
        }
        txManager.commit(status);
  1. Spring MVC框架:
    1.什么是MVC:
        M:Model  模型:Model的职责是负责代码逻辑,包含如下:
          数据访问层  dao
          业务逻辑层  Service
          辅助工具层  util
          实体对象    entity,vo,domain,pojo,bean
        V:View  视图:负责显示交互页面,和收集页面的数据,包含如下:
            HTML
            CSS
            JavaScript
            图片,视频
            等web资源
        C:controller 控制器:负责Model和View之间的桥梁,用于控制流程
          V的页面数据提交给C
          C调用M处理数据
          把M的处理结果通过C响应给V
          V显示处理完的数据结果
    2.项目的三层:
        业务表示层:专门用来控制显示数据,把数据显示给用户,起到交互的作用
            HTML,CSS,JS,JSP,Servlet,controller
        业务逻辑层:专门用来控制项目的具体的业务,业务的复杂程度取决于需求的复杂程度,
                   业务获取表示层的数据,基于数据业务处理,
                   一个业务可能调用多次数据访问层,把业务的结果返回给controller
                一般情况下,用Service或biz来代表业务逻辑层
        数据访问层:专门用来控制数据库操作(增删改查)
                   数据访问层接受业务逻辑的数据
                   把数据库返回的结果返回给业务逻辑层
        三层更侧重项目的功能划分,便于团队的开发和维护项目
    3.什么是Spring MVC?
        spring的web MVC简称为Spring MVC,是Spring框架的一个非常重要的功能模块
        实现了MVC的开发模型,便于简单快捷的开发MVC结构web程序
    4.原来Servlet(C)做三件事:
        4.1.获取页面的数据
        4.2.基于数据调用业务处理数据
        4.3.基于业务的返回结果
          4.3.1.跳转/响应:
                  转发和重定向
                  响应json数据给JS客户端
    5.现在的Spring MVC:
        5.1.获取页面的数据  ---->Spring MVC帮你做了
        5.2.基于数据调用业务处理数据--->程序员专注于的实现
        5.3.基于业务的返回结果--------->Spring MVC帮你做了
          5.3.1.跳转/响应:
                  转发和重定向
                  响应json数据给JS客户端
    6.要想学习好一个MVC的框架:
        6.1.在controller中获取客户端提交过来的数据
        6.2.把业务的结果数据返回给客户端
        6.3.客户端包含:浏览器,Android,iOS等
    7.Spring MVC项目的搭建步骤:   项目(TestMavenSpring_MVC)  参见达内文档V.The Web 10267.1.创建项目war/web项目
        7.2.导入jar包
            spring-context     Spring的必备依赖包  IOC+DI+AOP(部分的AOP)
            spring-web         Spring MVC的必备依赖包
            spring-webmvc      Spring MVC的必备依赖包
            jackson-core       Spring MVC辅助依赖包com.fasterxml.jackson.core.jackson-core.jar)
            jackson-databijd   Spring MVC的辅助依赖包(com.fasterxml.jackson.core.jackson-databind.jar) 处理json
                               专门用来处理json数据,把controller中的对象转换成json字符转,并响应给客户端
          <!-- Servlet 依赖包 -->
          <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
          </dependency>
          <!-- jstl 只能在servlet使用-->
          <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
          </dependency>
          <!-- Spring的必备依赖包  IOC+DI+AOP(部分的AOP) -->
          <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.3.7.RELEASE</version>
          </dependency>
          <!-- spring-web         Spring MVC的必备依赖包 -->
          <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>4.3.7.RELEASE</version>
          </dependency>
          <!-- spring-webmvc      Spring MVC的必备依赖包 -->
          <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>4.3.7.RELEASE</version>
          </dependency>
          <!-- jackson-core   Spring MVC辅助依赖包com.fasterxml.jackson.core.jackson-core.jar) 处理json-->
          <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.8.1</version>
          </dependency>
          <!-- jackson-databind   Spring MVC的辅助依赖包(com.fasterxml.jackson.core.jackson-databind.jar) -->
          <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.8.1</version>
          </dependency>
        7.3.创建java类:
              添加一个包:controller,包中创建若干Controller类
        7.4.创建Spring清单文件
              spring_context.xml
                项目中的公用的对象的创建和注入(IOC+DI)
                例如:util(工具包)
              spring_mvc.xml
                项目中的有关MVC的对象的创建和注入

              spring_mybatis.xml---->暂时不用
              spring_redis.xml---->暂时不用
              spring_rabbitmq.xml---->暂时不用
        7.5.写web项目的入口配置文件  web.xml
        7.6.创建页面
        7.7.启动Tomcat
        7.8.从Spring容器中获取对象,并使用对象
  8.Spring MVC执行的原理步骤:
    8.1.发送请求给服务器
    8.2.DispatcherServlet拦截*.do的请求
    8.3.根据进入DispatcherServlet的Service方法
      8.3.1.根据请求的URL去HandlerMapping集合中的寻找是否有指定的Controller和方法
            HandlerMapping中维护的map集合是从Spring MVC子容器中取出
      8.3.2.通过HandlerAdapter(处理器适配器)调用和执行controller中的方法
            controller独享是从Spring MVC子容器中取出
      8.3.3.调用controller类中的方法,返回ModelAndView
      8.3.4.从ModelAndView中的Model中取出数据,渲染数据到页面上
            从ModelAndView中的View中取出ViewName,拼装目标URL
      8.3.5.把拼装完的页面响应给客户端
    8.4.响应结束
  9.学好Spring MVC的web项目,重点掌握两个步骤:
      9.1.客户端的数据,提交给Spring MVC 的controller的方法中
        9.1.1.
      9.2.把controller中方法调用的业务返回的结果,返回给客户端
  10.Spring MVC和Servlet,客户端数据提交给Controller或Servlet中的方法
      所以Spring MVC框架和servlet数据是线程安全的
  11.restful架构:资源状态转换
      11.1.资源:软件资源,图片资源,网页资源,视屏资源,文字资源,文件资源等...
      11.2.在软件资源相互转换的时候,需要做资源定位(通过URL做资源定位)
      11.3.在资源转换的过程中细分了若干种动作:
        get:获取资源
        post:创建资源,部分的更新
        put:修改资源
        delete:删除资源
        等等...
      11.4.综合上面的解释,总结restful架构:
          11.4.1.每一个URL代表一个资源
          11.4.2.客户端和服务器之间,传递资源或转换资源,在表现层,表示资源转换的结果
          11.4.3.客户端通过四个HTTP动词,对服务器端的资源进行操作,以达到资源转换的目的
  12.form表单提交:下面的做法是可以交互组合的
      12.1.客户端的数据提交给服务端
        12.1.1.<input name="userName">  login(String userName)
        12.1.2.<input name="userName">  login(@RequestPram("userName") String name)
        12.1.3.<input name="userName">  login(User user); User类中有setUserName方法
        12.1.4.<input name="userName">  
      12.2.把服务端的数据响应给客户端
          12.2.1.转发:ViewName结合Spring_MVC.xml中的内部资源视图解析拼装目标URL
              public ModelAndView login(){} Model存储数据  View存储viewName
              public String login(Model model){} Model存储数据  String返回viewName
  13.Spring MVC上传文件:
    13.1.Spring mvc上传文件也是用Apache的commons-fileupload
    13.2.客户端的用法
      方式一:用form表单上传
        <form action="目标的URL(restful)" method="post" enctype="multipart/form-data">
          <input type="file" name="" />
        </form>

      方式二:用ajax JS来上传文件
        1.借助第三方工具ajaxfileupload.js
        <form>
         <input type="file" name="" id="" />
        </form>
        $.ajaxFileUpload({...});

        2.用原生的js上传文件
        <form id="formid">
         <input type="file" name="" id="" />
        </form>
        var data=new FormData(doucument.getElement("formid"));
        $.ajax({...});
    13.3.服务端的用法
      方式一:用Servlet来处理上传文件
          1.判断request对象是否有附件文件
          2.通过commons-fileupload组件包转换request对象为List<FileItem>集合
          3.遍历集合,判断每一个FileItem是否是FormField(表单字段)
            是表单字段,说明是非文件域
            否则就是文件域
          4.如果是文件域,执行FileItem的write方法的API把文件写入到指定的

      方式二:用Spring MVC来处理上传文件
          在pom.xml:添加commons-fileupload.jar和commons-io.jar
          在spring_mvc.xml文件中:
             <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
              <!-- 最大上传文件的大小 -->
              <property name="maxUploadSize" value="4194304"/>
            </bean>
          springmvc底层用的还是commons-fileupload组件,但上传的api方法
          就不用commons-fileupload的api,用spring mvc封装commons-fileupload组件后的api,
          org.springframework.web.multipart.commons.CommonsMultipartResolver

          注意:
            Spring MVC不只是针对commons-fileupload封装
            spring MVC还可以针对cos的上传组件封装

    14.spring mvc拦截器:
      14.1.spring mvc的<HandlerMapping>处理器支持拦截器的应用,当需要为某些请求提供功能的时候,添加拦截器
      14.2.拦截器常见的应用:身份验证,就是在所有的请求前面都要判断是否已经登录,
          已经登录就直接访问资源,没有登录就跳转到登录页面
          拦截器的概念,就是横切了一个身份验证的切面
      14.3.拦截器必须实现自HandlerInterceptor接口,
            此接口有三个方法:
              1.preHandle()方法:
                处理器被执行前调用,方法返回true,表示会继续调用其他的拦截器,
                如果没有其他的拦截器,就调用对应的处理器,处理controller
                返回值为false,表示终止流程,不会执行后续的拦截器和处理器

              2.postHandle()方法:
                处理器执行之后,视图处理前调用,此时可以通过ModelAndView对象模型
                对model的数据和view的数据更改,以达到在传送不同的数据和跳转不同的目标

              3.afterCompletion()方法
                整个请求处理完毕后,调用此方法,如果性能监控我们在此记录结束的事件
                只有preHandle返回true,才会调用此方法
      14.4.实现Spring MVC拦截器的步骤:
        14.4.1.建立一个类实现自HandlerInterceptor接口
          也可以继承自HandlerInterceptorAdaptor类
        14.4.2.在spring_mvc.xml的配置文件中,写拦截器的配置
          14.4.2.1.把拦截器纳入spring容器中来管理
          14.4.2.2.指定拦截谁,不拦截谁
  1. MyBatis框架:

在这里插入图片描述

 1.ORM映射:
      O:对象端,也叫java端  mapping->映射   R:关系型数据库
    1.1.JDBC:手动映射
      在java端sql语句是字符串,把数据库的数据手动转换为List集合
    1.2.CommonDao:手动映射  
      在java端sql语句是字符串,把数据库的数据手动转换为List集合,代码可以复用
    1.3.Spring JDBC:手动映射
      在java端sql语句是字符串,把数据库的数据手动转换为List集合,代码可以复用
    1.4.MyBatis:半自动映射
      在Java端,把sql语句写到XML的配置文件中,
      把数据库的数据转换成List,Map,其他数据格式
    1.5.Hibernate:全自动映射
      没有sql语句了,只管写好配置文件
  2.MyBatis框架: 优秀的orm映射框架
    最早来自于Apache基金会,是一个开源的项目,20106月前框架名称是ibatis,
    然后改成MyBatis,项目从Apache基金会移植到Google code上,并对MyBatis做了很多性能优化,
    性能提升很多
  3.MyBatis支持普通的SQL语句,还可以应用数据的特性
    例如:存储过程,视图,索引等数据的特性
    用MyBatis的封装的jdbc提高了开发效率,可以写SQL语句,也可以SQL语句优化
    MyBatis用xml配置SQL语句,用MyBatis封装jdbc极大提高了开发效率和性能

  4.MyBatis的框架搭建:
    1.创建工程(jar/war)
    2.导入jar包
      <!-- mybatis 依赖 -->
      <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.4.5</version>
      </dependency>
      <!-- mysql connector -->
      <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.0.8</version>
      </dependency>
    3.创建java类
      UserDao.java  UserDaoImpl.java
    4.总清单文件(只有一个)
        加载mysql.properties
        连接数据库(需要4)
        可以加载子清单文件(增删改查的SQL语句)
    5.用MyBatis框架自己的API来加载和解析总清单文件
    6.通过MyBatis提供的API做增删改查
  5.MyBatis的增删改查的操作方式:
    方式一:原生的MyBatis的API--->(项目TestMavenMyBatis):insert();:delete();:update();:selectOne();-->查一条语句  selectList();-->查多个语句  selectMap();   select()
      上面的增删改查语句对应的Mapper子清单XML文件写法::<insert id="" parameterType="">插入SQL语句</insert>:<delete id="" parameterType="">删除SQL语句</delete>:<update id="" parameterType="">修改SQL语句</update>:<select id="" parameterType="" resultType="">查询SQL语句</select>

    方式二:Mapper接口+jdk动态代理方式 (重点在于设计理念)(推荐)  --->(项目TestMavenMyBatis)
        其底层用的还是MyBatis的原生api
        用此种方式可以大大提高开发效率,一定降低了执行效率
          1.创建代理类需要时间
          2.动态代理本身就比静态代理慢
    方式三:注解用发(不推荐)
          其实是不需要写子清单文件
            package org.mybatis.example;
            public interface BlogMapper {
              @Select("SELECT * FROM blog WHERE id = #{id}")
              Blog selectBlog(int id);
            }
          原因:SQL语句可读性差,因为都写在一行上了,要频繁的要SQL优化
  6.Mapper接口方式的项目的搭建:
      1.创建工程
      2.带入jar包
          <!-- mybatis 依赖 -->
          <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.5</version>
          </dependency>
          <!-- mysql connector -->
          <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.0.8</version>
          </dependency>
      3.创建java类,一定是接口
          UserMapper.java  接口
      4.总清单文件(只有一个)
          加载mysql.properties
          连接数据库(需要4)
          可以加载子清单文件(增删改查的SQL语句)
      5.用MyBatis框架自己的API来加载和解析总清单文件
      6.通过MyBatis提供的API做增删改查
  7.SQL标签:sql语句的复用
       <!-- sql标签,用于SQL复用 -->
       <sql id="select_user">
        select
          id,
          username name,
          userpassword password,
          age,
          address,
          head,
          point
        from t_user 
        
       </sql>
       
      <select id="findUserById" 
          resultType="User"
          parameterType="java.lang.Integer">
        <include refid="select_user"></include>
        where id = #{id}
      </select>
  8.resultMap:mysql中的一个重要的标签
      分析:
        resultType:       结果类型
        parameterType:    参数类型
       有关于增删改查的节点中的两个属性
         parameterMap   MyBatis框架中准备淘汰的用法
         resultMap      结果映射,和HashMap或者Map是没有关系的
      resultMap属性id代表:<resultMap id="名字" ></resultMap>
      resultMap标签/元素节点是用来做结果集列名字和实体属性的名字不匹配问题
  9.MyBatis的动态SQL(非常重要):
      动态SQL解决了SQL语句拼装的问题
    if标签:
        <!-- if标签
        test="name != null"  name->Name->getName
        用getName去parameterType="User"指定的类中寻找是否有此方法
        如果有就反射调用
        调用完会返回结果,返回结果不为null就拼装SQL语句条件
        返回值为null,就不拼装SQL语句的条件
      
        如果两个条件都不为null,
          select * form t_user where age=20 and username like ? and address like ?
       -->
      <select id="findUsersByIf" parameterType="User" resultMap="user_map">
        <include refid="select_user1"></include>
        where age=20
        <if test="name != null">
          and username like #{name}
        </if>
        <if test="address != null">
          and address like #{address}
        </if>
      </select>

    choose when otherwise标签:

     where标签:

     Set标签:只能用于更新语句

     trim标签:可以替换where和set

     foreach标签

  
  11.补充数据库的相关内容:
      11.1.数据库的设计步骤:
        11.1.1.充分读取需求文档:
              a.只有需求的文档
              b.有需求文档,和页面的设计
        11.1.2.写出一个数据库的开发文档:
            a.写出若干数据表,首先尽量画出e-r图:
                1).涉及到表格的设计:
                    一范式:所有的列必须是原则性的,即列不可以再次拆分
                    二范式:每张数据表,只表达一件事,尽量少冗余
                    三范式:当前表中的列之间,是不能有传递依赖的
                        商品名称  依赖于  商品id
                        商品id    依赖于  订单id
                      T_product表(商品表)
                      product_id(pk)  product_name  

                      T_order(订单表)
                      order_id(fk)
               **范式要求越严格,表格拆份就越多,表和表之间必须有关系列,
                有关系列就会有冗余的数据,查询性能就降低,
                所以不是范式越高越好
                  如果不遵守范式,那么所有的数据都必须放在一张数据表中,
                  会导致
                  数据大量的冗余(尽量少的冗余),
                  增加数据异常,
                    例如:订单信息和商品的信息在一张表中
                        插入一条产品信息,不一定非要添加订单信息
                  删除数据异常,
                    例如:订单信息和商品的信息在一张表中
                        如果,一个订单只订了一个商品,删除这个商品,连带着订单也会被删除
                        但是商品被删除,不代表订单被删除,这样会导致异常
                  修改数据异常.
            b. 把e-r图转换到word(开发文档)中以表格的方式表达数据表
                例如:
                  字段名    类型     长度     默认值        备注     约束
                  id        char      25      无            uuid     主键
                  uname     varchar   20      wu            用户名
                  head      varchar   20      default.png   用户头像
            c.把一些相关的页面的截图放在表格的下面,可以配文字说明
            d.把word文档中的表的结构按照说明写出SQL脚本
                包含:
                  1).创建数据库
                  2).创建数据表
                  3).给表添加约束
                        一般添加:
                        主键约束-->列的内容是唯一的且不能为null
                        唯一约束:列的数据 唯一,可以为null ,但是null只能有一个
                        检查约束:列的数据必须符合指定范围,比如:age在1-99之间
                        外键约束:列的数据必须引用自主表中的主键列中的数据
                        默认约束:列的数据要放置默认值,比如:head头像  default.pang
                        非空约束:列的数据不能为null
                  4).给表添加测试数据
                  5).查询数据表
  10.MyBatis的关联映射:
        ORM映射在MyBatis中有明确的处理方式
        实际上就是MyBatis的多表操作
    10.1.多表的关联关系:
       10.1.1.在关系端(数据库端),多表的关联关系是用主外键来表示
              有主外键,一定有关联的关系列,
              有关系列,不一定有主外键
          主外键目的:用来约束外键列的数据必须引用自主表的主键列的数据
       10.1.2.在java端:是用对象的包含关系
    10.2.关联关系的分类:
        一对一关联:一个人只能哟一个身份证号
        一对多关联:一个组中,可以有多个用户
        多对一关联:多个用户隶属于一个组
        多对多关联:多个学生可以被多个老师教
                   多个老师可以教多个学生
            多对多的关联需要借助第三张表来表达多对多的关联
    10.3.MyBatis的关联关系:
        对一关联:
        对多关联:
  12.MyBatis的缓存机制:
      一级缓存:SqlSession级别的缓存
          把查询出来的数据存储给SqlSession对象,
          如果Sqlsession对象不关闭,只需要查询一次数据库
          其余都是从缓存中获取
          如果SqlSession对象关闭,则一级缓存的数据丢失

      二级缓存:SqlSessionFactory级别缓存
          MyBatis自带了一个缓存的实现
          也可以利用第三方缓存产品设置给MyBatis
          要求实体必须序列化   例如:User implements Serializable
          MyBatis二级缓存,默认是打开的
            <settings>
              <!-- 默认设置是true,不写也可以 -->
              <setting name="cacheEnabled" value="true"/>
            </settings>
          是否能够使用二级缓存,还需要设置子清单文件:
            添加<cache />配置使用的是MyBatis的自带的二级缓存的实现(产品)
            添加<cache type="xxx.yyy.zzz.CacheProduct"/>
        注意:
          MyBatis查询数据的时候,是先从二级缓存中查找是否有缓存的数据,
          如果没有,就从一级缓存查找,一级缓存中也没有,就去数据库中找,会发送SQL语句查找数据库
总结:
  spring 框架      清单文件 spring_context.xml
    主要:
      IOC 
      DI 
      AOP(事务管理)
  Spring MVC框架   清单文件  spring_mvc.xml
    主要:
      客户端的数据提交给controller
      把业务的数据返回给客户端

  MyBatis框架     清单文件 spring_mybatis.xml
    主要:
      方式一:
        原生的MyBatis的API
      方式二:
        用Mapper接口+JDK动态代理
  1. SSM整合: spring + spring MVC + MyBatis
1.jar包
    spring4.37(context,mvc,jdbc,tx)
    jackson2.81:做json数据转换
    MyBatis3.4.5
     mybatis-spring 1.3.1
    druid1.0.14 数据库连接池
    mysql-connector-java   mysql连接驱动包
    commons-fileupload   文件上传
    poi  带出表格
  注意:spring框架没有提供整合MyBatis的功能,
        MyBatis的开发团队开发了一个框架,用于把MyBatis对象交给spring容器管理
        mybatis-spring.jar
        把SQLSessionFactory对象,SqlSession对象Mapper接口代理对象等
        都放在spring容器中
  2.搭建SSM项目:
      2.1.创建web项目
      2.2.导入jar包
      2.3.创建java类
          cn.tedu.dao       数据接口
          cn.tedu.service   业务接口
          cn.tedu.service.impl  业务的接口实现
          cn.tedu.controller    spring MVC的controller类
          cn.tedu.entity     实体类  序列化
          cn.tedu.vo         值对象  序列化
          cn.tedu.util       工具类
      2.4.清单文件
          web.xml  项目的入口
              全局配置文件加载    spring.xml   spring_mybatis.xml
              监听器     servletContext创建后,会初始化spring容器
              过滤器     只处理post请求的乱码
              Spring MVC前端控制器   spring_mvc.xml   负责初始化SpringMVC的子容器
                  方式一:  *.do方式
                  方式二:/方式
          spring_context.xml 文件    公共的对象放在spring容器中
          spring_mybatis.xml文件     MyBatis的对象放在spring容器中
              辅助文件:configuration.xml  总的清单文件   
                      若干子清单文件  增删改查的语句  resultMap  cache 动态SQL语句
          spring_mvc.xml:
            抛掉静态资源的拦截
            扫描controller包
            <mvc:annotation-driven>
            拼装目标URL:只局限于转发和重定向
            文件的上传
      2.5.添加静态资源:
          HTML JSP CSS  JavaScript  image video等
      2.6.空项目跑成功
      2.7.在空项目中添加新的功能
  3.写ajax的异步提交的项目的流程:
      3.1.确认js文件是否加载并执行
          1.在js文件中第一行写检测语句,检测js是否执行
             console.log("test")
             或者
             alert("test");
          2.在文件中写下面的代码来检测
              window.onload=function(){
                 console.log("test")
                 或者
                 alert("test");
              }
              或
              $(function(){
                 console.log("test")
                 或者
                 alert("test");
              });
          3.//@sourceURL=main.js     动态加载时需要写
              在浏览器的调试界面查看js是否被加载
      3.2.确认js文件中指定的js方法是否被执行
          一定注意:js文件中某个js语句的错误,会导致整个js不会执行
          调试js代码三种方式:
            方式一:console.log("test");
            方式二:alert("test");
            方式三:利用浏览器的debug工具
          a.方法中只有下面代码用于确认js方法是否执行
             console.log("test")
             或者
             alert("test");
             或
             js调试工具
          b.在js方法中的某个位置执行如下代码用于检测js方法能执行哪些js语句
            **注意:js方法中的某个语句错误,有可能错误语句前面的代码段是能执行的
                       console.log("test")
                       或者
                       alert("test");
                       或
                       js调试工具
          c.打开浏览器的console控制台,在控制台上会显示异常信息
      3.3.确认js方法中的ajax异步请求:
          1.在controller方法中写System.out.println("test");
          2.用postman工具单独测试服务端代码
      3.4.在controller方法中获取前端的数据
        1.在controller方法中写System.out.println(前段提交的数据名称);
        2.用postman工具发送数据给服务端
      3.5.根据页面提交的数据调用具体的业务:
        1.暂时不调用业务,直接响应结果给前端
        2.调用具体业务
            -在controller方法中调用业务方法
            -在业务方法中调用dao,结合sql语句
              建议在可视化工具,先写好SQL语句并测试成功,
              再把正确的SQL语句黏贴到子清单文件中
            -访问数据库
            -业务方法得到dao的返回结果
            -controller方法得到业务的方法返回结果
            -把业务的返回的结果响应给前端
      3.6.在前端js中接受服务端响应的数据
        a.用console或alert或debug调试,查看响应的数据
        b.用ponstman获取响应的数据
      7.解析响应的数据做dom编程,对页面局部的内容刷新
  4.基于restful架构项目结构:
      html+jquery+ajax-->controller<-->service<-->dao<-->数据库
    4.1.HTML加载:
        静态加载:直接请求xxx.html
        动态加载:节点对象.load("xxx.html", function(){加载完HTML回调此方法});
    4.2.JS加载:
      静态加载:<script src"xxx.js"></script>
      动态加载:$.getScript("xxx.js" , function(){加载完js后回调此方法});
    4.3.CSS加载:
      静态加载:<link rel="stylesheet" href="xxx.css" />
      先加载HTML,有静态的css,则加载加载CSS
      如果有静态的js,则加载静态的js,但是不执行,HTML和CSS都加载完毕后,
      才会执行window.onload=function(){} 或者 $(function(){});
  1. shiro安全框架:(主要讲登录认证和登出,授权认证,加密)
1.类似产品:  spring security,学习成本和使用成本过高,控制的粒度细
    1.1.shiro框架相对简单,完全可以使用在企业级项目中
    1.2.Spring MVC的拦截器和servlet的过滤器也可以做到安全管理,但还是比不过shiro
  2.shiro安全框架能做什么:
    2.1.主要的功能:
      2.1.1.登录认证:
          1).shiro   登入:
              通过shiro做登录操作,如果没有登录成功,就跳转到登录页面
              如果登录成功了,就跳转到指定的主页面,而且可以访问项目中的其他敏感资源
              (项目中的任何请求都可以接受),就是用户访问项目中的任何资源都要通过shiro
              的检测,并判断是否登录
          2).shiro   登出:
              借助shiro提供的API,退出系统,清除shiro中的session,目的是因为session存储了
              用户名的信息
      2.1.2.权限认证:
          根据用户权限不同,登录完后,显示的主页的菜单项目不同
          例如:
              管理员:     显示所有的模块信息
              普通账号:   只能显示部分菜单模块
  3.shiro的全模块功能:
      3.1.primary concers:
            Authentication:登录认证
            Authorization:授权认证
            Session Mangement:session管理(shiro的session,不是HTTP的session),
                              可以管理此session共享的数据,
                              shiro登出
            Crypography:shiro的加密管理
      3.2.supportting features:支持的特性
            web support:shiro支持web项目
            caching:使用shiro的缓存机制,缓存数据
            Concurrency:支持高并发
            testing:支持测试
            run as:支持普通java项目
            remember me:支持记住我(类似记住密码,较麻烦,可以自己写一个)
  4.文字版本的shiro工作流程:
      4.1.用户输入用户名和密码,通过shiro把用户名和密码存储给subject
      4.2.subject携带token的令牌数据发送给安全管理中心
      4.3.安全管理中心,会回调登录认证的方法和权限认证的方法
          要求要写AuthorizingRealm类的子类
          或者写Authorizer接口的子实现
          重写:登录认证的方法:protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
                  在登录认证方法中,指定如何从数据库获取数据库或者IO流中获取数据,
                  然后,在安全管理中心做对比
               权限认证的方法
                protected AuthoizationInfo doGetAuthorizationInfo(PrincipalCollection principals)
                  在权限认证中,指定如何从数据库或者IO流的真实的权限数据
                  把权限的数据返回给安全管理中心,安全管理中心拿到权限的数据,
                  由shiro控制页面显示指定的权限
      4.4.总结:就是由shiro的接口的子实现来指定realm的数据是什么
           最终交给shiro的安全管理中心来处理
          其实shiro的底层是用的是动态代理,因为用的时候必须导入Spring AOP的jar包
          环绕通知:
            public Object around(ProceedingJoinPoint pjp){
              Object returnValue=null;
              try{
                //写前置通知的代码
                if(登录过){
                //允许调用
                  returnValue=pjp.proceed();//调用老的业务方法
                }else{
                  //没登录过就跳转到登录页面
                  //登录页面的名称配置到Spring_shiro.xml中
                }
                
                //后置通知的代码
              }catch(Exception e){
                //异常通知的代码
                e.print.....
              }fiunally{
                //写最终通知的代码
              }
              return returnValue;
            }
  5.shiro的使用步骤:
    5.1.创建项目
    5.2.导入jar包
    5.3.创建java类,必须继承或实现接口
    5.4.创建spring_shiro.xml的清单文件
    5.5.启动shiro项目
  1. 消息队列rabbitmq:
  1.虚拟主机
  2.交换机
  3.队列
  4.绑定
一个rabbitmq的服务器可以创建多个虚拟主机
一个虚拟主机中可以创建多个队列和多个交换机
设置虚拟主机的目的就是为了设置权限管理

  一定是先创建交换机,再创建消息队列
  在交换机中配置的是路由key和队列的绑定关系
  每一个交换机对应系统的一个进程(CPU的核),不同的交换机类型,消耗的CPU是不同的,越是范范的匹配,消耗越多
  一个或者多哥路由key可以对应一个队列
  一个路由key,可以对应多个队列

  交换机:
    direct exchange  ->执行效率更高一些   特点:直接根据指定的routing key名称存储到所对应的队列
    topic  exchange  ->执行效率低一些  涉及通配符  "*"->代表一个词组  "#"->代表零个或多个词组
                        特点:直接根据指定的routing key名称存储到所对应的队列
    fanout exchange  ->广播式交换机  特点:会把所有的消息发送给所有交换机绑定的队列
    header exchange  ->待定
  定义队列:

rabbit的配置关系:
  模板:
      模板的名字
      -连接工厂 和 交换机
  队列:
    队列的名字
    是否持久化
    是否自动删除
    是否是私有队列
  交换机:
    名字
    是否持久化
    绑定了队列的名字和routing key的关系
  注意:<!-- 指定连接账号的类型 -->
       <rabbit:admin connection-factory="connectionFactory"/>
  监听:
    连接的工厂
    指定监听的关系
    实例化监听类的对象
总结:rabbitmq
  核心:
    1.系统之间的解耦
    2.在高并发的时候,避免数据高峰 
  1. Redis:
  持久化:
    1.没有格式的文件,没有格式的数据存储到doc,txt,data,xls等文件中
    2.关系型数据库,mysql或者Oracle等,把一些有格式的数据存储到一个文件中
      然后通过rdbms(关系福安里系统),
      把文件中的数据格式化输出
      利用SQL语句增删改查数据,SQL就是结构化查询语言
    3.nosql数据库,就是没有SQL语句,但是通过代码来操作数据
      a.mogodb数据库,底层存储的是json数据
      b.内存数据库
          -redis
          -memcache
redis和memcache的区别:
  1.memcache所有的值都是简单的字符串,redis可以存储更丰富的数据类型
  2.redis的速度要比memcache快
  3.redis可以持久化数据,默认的情况下会把数据存储到本地文件中
什么是redis:
  redis是由一个意大利人salvatore sanfilippo用C语言写的Redis
  re: remote  远程的
  di: Dictionary  字典  衍生意-->数据
  s:  server   服务
  结合叫:远程的数据服务/远程的字典服务
redis:远程的数据服务,是一个key-value存储系统,他支持丰富的数据类型
    String,list,set,zset(sorted set),hash
redis的特点:
  redis以内存作为数据截止,所以读写数据的效率极高,远超数据库
    例如:
      以设置或获取一个256个字符串为例,他的读取的速度可以高达11万次每秒
      写的速度 八万一千次每秒
  redis在服务重启后,还会读取数据回到服务器中,redis服务器重启后数据不丢失
  redis分片的原则:
    1.自定义自定义原则:利用key的hash

    2.hash取余原则:

    3.hash一致性自动分配原则,由jedis中自己封装的分片算法来控制
  1. Spring Boot微服务:
 1.目的:可以解决海量并发的问题
       可以把一个完整的项目功能,拆开成若干个微服务项目
       多个微服务之间可以提供相应的服务
  2.spring boot:通过spring boot可以把一个大的项目拆开成若干个boot项目,每个boot项目代表一个功能

  2.Spring boot特点:(背会--面试用)
    2.1.能独立创建和运行
    2.2. Spring boot可以使用自己的库,也可以使用第三方的库,可以用最少的配置来创建spring boot项目
    2.3. Spring boot项目可以内置Tomcat,可以打成jar包,不一定需要打成war包
    2.4. Spring boot项目可以引用spring boot框架内置的"starter",来快速创建spring boot项目
    2.5. Spring boot可以自动起到配置spring和自动配置第三方的库(其实就是提前加载了若干个类库)
    2.6. Spring boot提供若干外部化配置,比如:健康检查等功能
    2.7. 绝对代码的生成和不需要xml的配置(把xml的配置去掉了,用application.properties属性文件代替)
    2.8. 约定大于配置
  总结:所以业界给spring boot定位了四大神器:
          -auto-configuration 自动配置
          -starters  起步依赖
          -cli       命令行模式
          -actuator  运行监控

  3.如何获取Spring boot资源:
    3.1.spring的官方网站   http://spring/io
        spring boot官方网站   https://spring.io/projects/spring-boot
    3.2.spring的参考文档:
        https://docs.spring.io/spring-boot/docs/2.2.1.RELEASE/reference/html/
    3.3.spring boot的jar或者doc资源:
          https://repo.spring.io/release/org/springframework/boot/
  
  4. Spring Boot项目的搭建:
      方式一:创建spring boot的原始用法
              需要借助spring的官网  start.spring.io
              创建出maven的项目并下载,存储成zip文件
              用eclipse来创建maven项目,然后把zip中的文件拷贝给eclipse的maven项目

      方式二:利用spring-tool-suit工具,此工具是spring官网提供的
              利用此工具创建Spring boot项目,
              其实其本质还是访问的是start.spring.io提供的服务

      方式三:利用IDEA工具,创建spring项目
  5.创建 第一个springboot项目
      web项目 用第二种方式(用jar和war都可以)
        1.在创建项目的时候,添加web的起步依赖
        2.创建controller类,在controller类中写controller方法
          此类必须在主入口类所在的包及其子包中
            @Controller
            @RequestMapping("test/")
            public class TestController {
              @RequestMapping(value="hello",method=RequestMethod.GET)
              @ResponseBody
              public String helloword(String name) {
                return "hello spring boot!";
              }
            }
        3.启动springboot项目
        4.在浏览器中请求controller方法
            http://localhost:8080/test/hello
        5.给springboot项目打包
        6.在cmd控制台中  java -jar xxx.jar/war
  1. Spring Boot原理介绍:
 spring boot的功能介绍:
      spring-boot-start-parent包为基础包
      说明当前springboot项目要继承自这个父包,
      这个parent包是一个特殊starter依赖
      在当前项目中不需要指定其他的starter依赖的版本,
      其他的starter依赖版本自动继承于父包的版本
    结论:继承自父包的依赖还有父包的版本

    其他的starter依赖  spring-boot-starter-xxx   
      xxx:为其他扩展的依赖包的名字
    如何快速获取扩展依赖从文档中获取,要查询springboot官方文档


Spring Boot的配置文件的详解:
    在springboot项目中有且只有一个配置文件application.properties
    此文件不能改名,也不能删除
    但是可以有这样一个文件"application.yml" 或者 "application.yaml"
    yml文件或yaml不是必须的
    这yml文件和yaml文件,properties文件可以同时存在,但是配置项有重复的
    以properties文件为准
  单文件方式:
    properties文件介绍:(有只能提示)
      application.properties
        server.port=8181
        server.servlet.context-path=/abc
    yml和yaml文件介绍(有只能提示):
        application.yml或者application.yaml
          server:
          <tab>port:空格8181
          <tab>servlet:
          <tab><tab>context-path:空格/abc
  多文件方式:
    在application.properties中配置如下:
      spring.profiles.active=xxx,yyy,zzz   多个名字用逗号间隔开
    在application.yml和application.yaml中配置如下;
      spring:
      <tab>profiles:
      <tab><tab>active:空格xxx,yyy,zzz   多个名字用逗号间隔

      xxx:对应 application-xxx.properties  或者  application-xxx.yml/yaml
      yyy:对应 application-yyy.properties  或者  application-yyy.yml/yaml
      zzz:对应 application-zzz.properties  或者  application-zzz.yml/yaml

Spring Bootde beans定义: 即在spring boot中IOC和DI
  -@Configuration+@Bean
  -@ComonentScan
  -@EnableAutoConfiguration  开启自动配置
  -@SpringBootApplication

  ***@Configuration+@Bean : spring boot推荐用法,因为springboot项目中没有xml配置文件
        
        spring的原有做法:
          <beans>
            <bean id="dbcp" class="...BasicDataSource"></bean>
            <bean id="userDao" class="...dao.iml.UserDaoImpl"></bean>
          </beans>
        spring boot推荐用法:@Configuration注解替换了<beans>节点,
            引申义:一个@Configuration注解对应原spring项目中的一个spring清单文件
          用@Bean注解替换了<bean>节点
            引申义:就是用@Bean修饰的,就会产生一个对象,并把对象交给spring容器来管理
        注意:@Configuration注解和@Bean注解,不是springBoot的注解,
            是spring framework的注解,而且是在spring3.x版本中就已经存在了
  补充:
    有关于单元测试的问题:
      1.Junit框架(Junit4/5)
        Junit4 jar
      2.spring单元测试

      3.springboot的单元测试
          public class TestClass1 {
            /**
             * 使用springboot的方式初始化spring容器
             */
            @Test
            public void testMethod1() {
              ApplicationContext context=SpringApplication.run(BeanFactory.class);
              MyDataSource ds=context.getBean("ds1",MyDataSource.class);
              System.out.println(ds.getConnection());
            }
          }
  1. web项目两个主线:

在这里插入图片描述

 1.页面把数据提交给spring mvc的controller的方法中
  2.把业务的返回结果,返回给客户端

  页面把数据提交spring mvc的controller的方法中
    方式一:
      表单提交(jsp页面或HTML页面)
    方式二:
      超链接提交(jsp页面或者HTML页面)
      <a href="目标url?name1=value&name2="value2">测试</a>
    方式三:
      ajax的异步提交(推荐用HTML,不推荐jsp)
        $.ajax({
            url:
            type:
            data:
            dataType:
            success:
            error:
        });
  把业务的返回结果,返回给客户端
    方式一:返回结果为json
             页面接收json数据,用js代码做dom编程,局部更新页面信息
             页面一般都是HTML页面
    方式二:传统的转发和重定向   页面一定是jsp页面,不可以是HTML,因为没法用EL表达式
            返回的值需要通过org.springframework.web.servlet.view.InternalResourceReso..
            内部资源视图解析器,来拼装目标url(前缀和后缀)和渲染jsp的页面
            需要配置前缀和后缀,
            注意:
              1.在application.properties文件中(准备做前缀和后缀的拼装)
                  spring.mvc.view.prefix=/WEB-INF/pages
                  spring.bvc.view.suffix=.jsp
              2.在pom.xml文件中添加jsp的解析器:
                <dependency>
                    <groupId>org.apache.tomcat.embed</groupId>
                    <artifactId>tomcat-embed-dasper</artifactId>
                    <version>9.0.8</version>
                </dependency>
              3.在src/main/webapp目录中添加web组件
              4.创建controller类
                  用Model或者ModelMap或者Map或者ModelAndView对象,把业务的数据转发给jsp页面,而不是重定向
              5.编写jsp页面
          注意:在spring boot 1.5.x版本中需要IDEA工具
              IDEA工具需要添加如下配置(在pom.xml文件):
                <build>
                  <resources>
                    <resuorce>
                      <directory>src/main/java</directory>
                      <includes>
                        <include>**/*.xml</include>
                      </includes>
                    </resource>
                    <resuorce>
                      <directory>src/main/java</directory>
                      <includes>
                        <include>**/*.*</include>
                      </includes>
                    </resource>
                    <resuorce>
                      <directory>src/main/webapp</directory>
                      <targetPath>META-INF/resources</targetPath>
                      <includes>
                        <include>**/*.*</include>
                      </includes>
                    </resource>
                  </resources>
                </build>
  1. Spring Cloud:
用spring cloud来管理若干个boot的微服务
单点登录  大部分用JWT
为什么使用JWT?
随着技术的发展,分布式web应用的普及,通过session管理用户登录状态成本越来越高,因此慢慢发展成为token的方式做登录身份校验,然后通过token去取redis中的缓存的用户信息,随着之后jwt的出现,校验方式更加简单便捷化,无需通过redis缓存,而是直接根据token取出保存的用户信息,以及对token可用性校验,单点登录更为简单。
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
项目描述 在上家公司自己集成的一套系统,用了两个多月的时间完成的:Springboot+Mybatis-plus+ SpringMvc+Shiro+Redis企业级开发系统 Springboot作为容器,使用mybatis作为持久层框架 使用官方推荐的thymeleaf做为模板引擎,shiro作为安全框架,主流技术 几乎零XML,极简配置 两套UI实现(bootstrap+layer ui),可以自由切换 报表后端采用技术: SpringBoot整合SSM(Spring+Mybatis-plus+ SpringMvc),spring security 全注解式的权限管理和JWT方式禁用Session,采用redis存储token及权限信息 报表前端采用Bootstrap框架,结合Jquery Ajax,整合前端Layer.js(提供弹窗)+Bootstrap-table(数据列表展示)+ Bootstrap-Export(各种报表导出SQL,Excel,pdf等)框架,整合Echars,各类图表的展示(折线图,饼图,直方图等),使用了layui的弹出层、菜单、文件上传、富文本编辑、日历、选项卡、数据表格等 Oracle关系型数据库以及非关系型数据库(Redis),Oracle 性能调优(PL/SQL语言,SQL查询优化,存储过程等),用Redis做中间缓存,缓存数据 实现异步处理,定时任务,整合Quartz Job以及Spring Task 邮件管理功能, 整合spring-boot-starter-mail发送邮件等, 数据源:druid 用户管理,菜单管理,角色管理,代码生成 运行环境 jdk8+oracle+redis+IntelliJ IDEA+maven 项目技术(必填) Springboot+Mybatis-plus+ SpringMvc+Shiro+Redis 数据库文件 压缩包内 jar包文件 maven搭建 Springboot+Mybatis-plus+ SpringMvc+Shiro+Redis企业级报表后台管理系统 http://localhost:/8080/login admin admin Springboot+Mybatis-plus+ SpringMvc+Shiro+Redis企业级报表后台管理系统Springboot+Mybatis-plus+ SpringMvc+Shiro+Redis企业级报表后台管理系统Springboot+Mybatis-plus+ SpringMvc+Shiro+Redis企业级报表后台管理系统Springboot+Mybatis-plus+ SpringMvc+Shiro+Redis企业级报表后台管理系统Springboot+Mybatis-plus+ SpringMvc+Shiro+Redis企业级报表后台管理系统
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值