自学内容整理

学习最全地址 : http://pan.baidu.com/share/home?uk=4076915866&view=share#category/type=0 //个人
http://pan.baidu.com/share/home?uk=3560277524&view=share#category/type=0 //传智博客

16/12/22 - >   

        Java 线程学习 http://www.cnblogs.com/paddix/archive/2016/05/04/5381958.html
          wait(必须在synchronized条件下 ,放弃对象monitor锁,等待被唤醒,或者到时间自动执行,期间其他线程可以执行)
        notify / notifyAll(唤醒对象锁,线程进入执行)
        wait notify/ notifyAll 是object对象 都有monitor monitor被占用 变为锁定状态
        sleep(不放弃锁,到时间自动执行,期间其他线程等待)
        join(子线程都执行后再执行当前线程,实际底层为wait方法) http://uule.iteye.com/blog/1101994
        yield(暂停当前线程,让其他线程可以继续执行 ,得不到保证 可能会被任务调度器忽略) Runnning - > Runnable

        共享性 对共享变量操作,在多线程环境下很容易出现各种意想不到的的结果 (全局变量count 10个线程 每个加100个1 ,结果!=1000)
        互斥性 synchronized条件下
        原子性 synchronized条件下或者加锁(lock)
        可见性 两个线程 A-B A对x变量写了 B读取时不一定是A写过的 时间无法判断

        http://sakyone.iteye.com/blog/668091
        volatile关键字就是Java中提供的另一种解决可见性和有序性问题的方案(不能实现原子性)
        用在多线程,同步变量。 线程为了提高效率,将某成员变量(如A)拷贝了一份(如B),线程中对A的访问其实访问的是B。
        只在某些动作时才进行A和B的同步。因此存在A和B不一致的情况。volatile就是用来避免这种情况的。volatile告诉jvm,
        它所修饰的变量不保留拷贝,直接访问主内存中的(也就是上面说的A)
        volatile只是在线程内存和“主”内存间同步某个变量的值,而synchronized通过锁定和解锁某个监视器同步所有变量的值。
        显然synchronized要比volatile消耗更多资源

        声明为volatile的简单变量如果当前值与该变量以前的值相关,那么volatile关键字不起作用,
        也就是说如下的表达式都不是原子操作:
        n = n + 1 ;
        n ++ ;
        原子操作如:
        n = m + 1 (运算没有自身的参与)

        JAVA中的反射机制 Class.forName("java.lang.String") / 类名.class / 对象.getClass()
        invoke(class, method) :
        就是调用类中的方法,最简单的用法是可以把方法参数化
        比如你Test类里有一系列名字相似的方法setValue1、setValue2等等
        可以把方法名存进数组v[],然后循环里invoke(test,v[i]),就顺序调用了全部setValue

17/01/11补

         Class.newInstance ->实例化新对象 Object类型
        Class model = Class.forName("test.Model");
        //获得Model类的实例
        Object object = model.newInstance();

        //获得Model类的set方法,参数为String类型
        Method setMethod = model.getMethod("set" + "Id", String.class);

        //调用set方法
        setMethod.invoke(object, MODELDATA[i]);

16/12/26 - >     SSM 整合学习 http://www.tuicool.com/articles/Fru26n
        mybatis 插入数据 返回数据主键(keyProperty="userId") 其中userId是插入数据主键 https://my.oschina.net/crazybird/blog/379635?p=1
        1->多 collection 标签内写多
        <collection property="orderList" ofType="com.kerwin.mybatis.pojo.Orders" column="pid">
          <id column="o_id" property="id"/>
          <result column="price" property="price"/>
        </collection>
        多->1 association 标签内写1
        <association property="person" javaType="com.kerwin.mybatis.pojo.Person">
          <id column="p_id" property="id"/>
          <result column="name" property="name"/>
        </association>

        Dubbo -> 视频 学习 http://www.roncoo.com/course/view/f614343765bc4aac8597c6d8b38f06fd#Dubbo#

17/01/19补 SSM在定义sqlSessionFactory时需要指定MyBatis主配置文件(applicationContext.xml) :
        <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
          ...
        </bean>

        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
          <!-- 数据库连接池 -->
          <property name="dataSource" ref="dataSource" />
          <!-- 加载Mybatis全局配置文件 -->
          <property name="configLocation" value="classpath:mybatis-config.xml" />
        </bean>

        <!-- 配置mapper扫描器 -->
        <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
          <!-- 扫描包路径,如果需要扫描多个包中间用半角逗号隔开 -->
          <property name="basePackage" value="com.ssm.mapper"></property> //SqlMapConfig.xml 在这个包下
          <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
        </bean>

        SqlMapConfig.xml
        <typeAliases>
          <!-- 批量定义别名 ,指定包名,自动扫描包中的类,别名即为类名,首字母大小写无所谓-->
          <package name="com.ssm.po"/>
        </typeAliases>

        <!-- 数据库连接用数据库连接池 -->

        <mappers>
          <!-- 通过扫描包的方式来进行批量加载映射文件 -->
          <package name="com.ssm.mapper"/>
        </mappers>
        具体的mapper类就是dao的具体实现了

16/12/27 - > Spring 学习 http://jinnianshilongnian.iteye.com/blog/1752171
        Inversion of Control(控制反转) : 别找我们,我们找你”;即由IoC容器帮对象找相应的依赖对象并注入,而不是由对象主动去找。
        Dependency Injection(DI):由容器动态的将某个依赖关系注入到组件之中
        ●谁依赖于谁:当然是应用程序依赖于IoC容器;
        ●为什么需要依赖:应用程序需要IoC容器来提供对象需要的外部资源;
        ●谁注入谁:很明显是IoC容器注入应用程序某个对象,应用程序依赖的对象;
        ●注入了什么:就是注入某个对象所需要的外部资源(包括对象、资源、常量数据)。
        IoC和DI由什么关系: 其实它们是同一个概念的不同角度描述

17/01/11补 jdom 读取xml文件 结合java反射模拟实现依赖注入

        bean配置 : 每个bean可以有多个ID和 多个name,指定id和name,id就是标识符,而name就是别名,(id和name不能相同)必须在Ioc容器中唯一;
        alias : 别名
        静态工厂方式实例化Bean,使用这种方式除了指定必须的class属性,还要指定factory-method
        <bean id="bean3" class="cn.javass.spring.chapter2.HelloApiStaticFactory" factory-method="newInstance">
        使用实例工厂方法实例化Bean,使用这种方式不能指定class属性,此时必须使用factory-bean属性来指定工厂Bean,factory-method属性指定实例化Bean的方法
        <bean id="bean4" factory-bean="beanInstanceFactory" factory-method="newInstance">

        依赖注入
        构造器->注入
        <!-- 通过构造器参数索引方式依赖注入 -->
        <bean id="byIndex" class="cn.javass.spring.chapter3.HelloImpl3">
          <constructor-arg index="0" value="Hello World!"/>
          <constructor-arg index="1" value="1"/>
        </bean>
        <!-- 通过构造器参数类型方式依赖注入 -->
        <bean id="byType" class="cn.javass.spring.chapter3.HelloImpl3">
          <constructor-arg type="java.lang.String" value="Hello World!"/>
          <constructor-arg type="int" value="2"/>
        </bean>
        <!-- 通过构造器参数名称方式依赖注入 -->
        <bean id="byName" class="cn.javass.spring.chapter3.HelloImpl3">
          <constructor-arg name="message" value="Hello World!"/>
          <constructor-arg name="index" value="3"/>
        </bean>
        setter->注入
        <bean id="bean" class="cn.javass.spring.chapter3.HelloImpl4">
          <property name="message" value="Hello World!"/>
          <property name="index">
            <value>1</value>
          </property>
        </bean>

        setter注入需求:
          该类必须要有公共的无参构造器,如public HelloImpl4() {};
          属性为private访问级别,不建议public,如private String message;
          属性必要时通过一组setter(修改器)和getter(访问器)方法来访问;
          setter方法,以“set” 开头,后跟首字母大写的属性名,如“setMesssage”,简单属性一般只有一个方法参数,方法返回值通常为“void”;
          getter方法,一般属性以“get”开头,对于boolean类型一般以“is”开头,后跟首字母大写的属性名,如“getMesssage”,“isOk”;
          还有一些其他特殊情况,比如属性有连续两个大写字母开头,如“URL”,则setter/getter方法为:“setURL”和“getURL”,
          其他一些特殊情况请参看“Java Bean”命名规范。

        ref 引用bean最简单配置
        <!-- 定义依赖Bean -->
        <bean id="helloApi" class="cn.javass.spring.chapter2.helloworld.HelloImpl"/>
        <!-- 通过构造器注入 -->
        <bean id="bean1" class="cn.javass.spring.chapter3.bean.HelloApiDecorator">
          <constructor-arg index="0" ref="helloApi"/>
        </bean>

        null值处理
        <property name="asd"><null/><property/>

        总结
        一、构造器注入:
        1)常量值
          简写:<constructor-arg index="0" value="常量"/>
          全写:<constructor-arg index="0"><value>常量</value></constructor-arg>
        2)引用
          简写:<constructor-arg index="0" ref="引用"/>
          全写:<constructor-arg index="0"><ref bean="引用"/></constructor-arg>

        二、setter注入:
        1)常量值
          简写:<property name="message" value="常量"/>
          全写:<property name="message"><value>常量</value></ property>
        2)引用
          简写:<property name="message" ref="引用"/>
          全写:<property name="message"><ref bean="引用"/></ property>
        3)数组:<array>没有简写形式
        4)列表:<list>没有简写形式
        5)集合:<set>没有简写形式
        6)字典
        简写:

          <map>
            <entry key="键常量" value="值常量"/>
            <entry key-ref="键引用" value-ref="值引用"/>
          </map>
        全写:

          <map>
            <entry><key><value>键常量</value></key><value>值常量</value></entry>
            <entry><key><ref bean="键引用"/></key><ref bean="值引用"/></entry>
          </map>
        7)Properties:没有简写形式

        构造器循环依赖 : (A依赖B B依赖C C依赖A)表示通过构造器注入构成的循环依赖,此依赖是无法解决的,只能抛出
        BeanCurrentlyInCreationException异常表示循环依赖。
        setter注入可以避免构造器循环依赖

        延迟初始化beans : 延迟初始化的Bean通常会在第一次使用时被初始化;或者在被非延迟初始化Bean作为依赖对象注入时在会随着初始化该Bean时被初始化,
        因为在这时使用了延迟初始化Bean。
        (lazy-init="true")

        depends-on : 是指指定Bean初始化及销毁时的顺序
        <bean id="helloApi" class="cn.javass.spring.chapter2.helloworld.HelloImpl"/>
        <bean id="decorator" class="cn.javass.spring.chapter3.bean.HelloApiDecorator" depends-on="helloApi">
          <property name="helloApi"><ref bean="helloApi"/></property>
        </bean>
        “decorator”指定了“depends-on”属性为“helloApi”,所以在“decorator”Bean
        初始化之前要先初始化“helloApi”,而在销毁“helloApi”之前先要销毁“decorator”

        Bean的作用域 : 在面向对象程序设计中一般指对象或变量之间的可见范围。
        而在Spring容器中是指其创建的Bean对象相对于其他Bean对象的请求可见范围。

        scope="prototype" : 每次请求创建一个新的bean
        scope="singelton" : 放入缓存池 全部取一个(spring IOC容器中只该bean实例只有一个)
        scope="request" : 表示每个请求需要容器创建一个全新Bean,比如提交表单的数据必须是
        对每次请求新建一个Bean来保持这些表单数据,请求结束释放这些数据
        scope="session" : 表示每个会话需要容器创建一个全新Bean
        scope="global Session" : 类似于session作用域,只是其用于portlet环境的web应用,
        如果在非portlet环境将视为session作用域.

        AOP 面向切面->基础概念:
        连接点(Jointpoint): 在AOP中表示为“在哪里干
        切入点(Pointcut) : 在AOP中表示为“在哪里干的集合
        通知(Advice) : 在AOP中表示为“干什么
        方面/切面(Aspect) : 在AOP中表示为“在哪干和干什么集合
        引入(inter-type declaration): 在AOP中表示为“干什么(引入什么)
        目标对象(Target Object): 在AOP中表示为“对谁干
        AOP代理(AOP Proxy) : 通过代理来对目标对象应用切面
        织入(Weaving) : 织入是一个过程,是将切面应用到目标对象从而创建出AOP代理对象的过程,
        织入可以在编译期、类装载期、运行期进行。
        前置通知(Before Advice): 在切入点选择的连接点处的方法之前执行的通知,该通知不影响正常程序执行流程
        后置通知(After Advice): 在切入点选择的连接点处的方法之后执行的通知,包括如下类型的后置通知:
        后置返回通知(After returning Advice): 在切入点选择的连接点处的方法正常执行完毕时执行的通知,
        必须是连接点处的方法没抛出任何异常正常返回时才调用后置通知
        <aop:after-returning pointcut="切入点表达式" pointcut-ref="切入点Bean引用" method="后置返回通知实现方法名"
          arg-names="后置返回通知实现方法参数列表参数名字"
          returning="返回值对应的后置返回通知实现方法参数名" />
        后置异常通知(After throwing Advice): 在切入点选择的连接点处的方法抛出异常返回时执行的通知,
        必须是连接点处的方法抛出任何异常返回时才调用异常通知。
        <aop:after-throwing pointcut="切入点表达式" pointcut-ref="切入点Bean引用"  method="后置异常通知实现方法名"
        arg-names="后置异常通知实现方法参数列表参数名字"
        throwing="将抛出的异常赋值给的通知实现方法参数名"/>

        后置最终通知(After finally Advice): 在切入点选择的连接点处的方法返回时执行的通知,不管抛没抛出异常都执行,
        类似于Java中的finally块。
        <aop:after pointcut="切入点表达式" pointcut-ref="切入点Bean引用"
          method="后置最终通知实现方法名"
          arg-names="后置最终通知实现方法参数列表参数名字"/>


        环绕通知(Around Advices):环绕着在切入点选择的连接点处的方法所执行的通知,环绕通知可以在方法调用之前和之后
        自定义任何行为,并且可以决定是否执行连接点处的方法、替换返回值、抛出异常等等。
        <aop:around pointcut="切入点表达式" pointcut-ref="切入点Bean引用"
          method="后置最终通知实现方法名"
          arg-names="后置最终通知实现方法参数列表参数名字"/>
        ->实例
        <bean id="helloWorldService" class="cn.javass.spring.chapter6.service.impl.HelloWorldService"/>
        <bean id="aspect" class="cn.javass.spring.chapter6.aop.HelloWorldAspect"/>
        <aop:config>
          <aop:pointcut id="pointcut" expression="execution(* cn.javass..*.*(..))"/>
          <aop:aspect ref="aspect">
            <aop:before pointcut-ref="pointcut" method="beforeAdvice"/>
            <aop:after pointcut="execution(* cn.javass..*.*(..))" method="afterFinallyAdvice"/>
          </aop:aspect>
        </aop:config>

        ->基于Schema的AOP
        <aop:pointcut> :用来定义切入点,该切入点可以重用
        <aop:advisor> :用来定义只有一个通知和一个切入点的切面
        <aop:aspect> :用来定义切面,该切面可以包含多个切入点和通知,而且标签内部的通知和切入点定义是无序的;
        和advisor的区别就在此,advisor只包含一个通知和一个切入点

        <!--为了使用注释 声明AutowiredAnnotationBeanPostProcessor等4个bean-->
        <context:annotation-config/>
        <!--扫描包里的内容-->
        <context:component-scan base-package=”xxx.xxx.xxx”>
        @Component @service @contorller @Reporsitory (将对象装配到容器当中)
        @Autowired 默认按类型注入 可以指定名称(@qualifired(name="xxx")) -> 没有情况下按类型注入
        @Resource 默认按名称注入 可以指定名称

17/01/15补 动态代理实现AOP
        1.生成要加的日志逻辑 实现invocationHandler
        class logInterceptor implements invocationHandler {
          private Object target;

          public void beforeMethod () {
            syso(save method);
          }

          public Object invoke (Object proxy, Method m, Object[] args) {
            beforeMethod();
            m.invoke(target, args);
            return null;

          }


          public set() {
            target
          }

          public get() {
            target
          }
        }

        2.产生代理对象
        1.生成被代理对象
          UserDao userDao = new UserDaoImpl();
        2.被代理对象交给代理对象handler, logInterceptor实现了invoktionHandller接口
          logInterceptor li = new logInterceptor();
          li.setTarget(userDao);
        3.根据被代理对象产生一个代理对象 Proxy -> java refulex 下对象
          UserDao userDaoProxy = null;
          userDaoProxy = (UserDao)Proxy.newProxyInstance(userDao.getCalss.getClassLoader() , new Class[]{UserDao.class} , li)
          (被代理对象.getClass.getClassLoader , 被代理对象应实现接口.class , 处理代理对象的handler)
        4.调用proxy方法,调用add方法之前就会加上beforeMethod方法
          userDaoProxy.add();
          **代理对象调用add方法时,实际调用li的invoke方法,add作为Method参数传入

        3.cglib 如果aop 目标类没有实现接口 那么就用cglib 字节码生成目标类的子类 再生成代理对象进行处理

16/12/28 -> SpringJDBC学习 概述 : Spring通过抽象JDBC访问并提供一致的API来简化JDBC编程的工作量,
        我们只需要声明SQL、调用合适的Spring JDBC框架API、处理结果集即可

        实现方式 : Spring主要提供JDBC模板方式、关系数据库对象化方式和SimpleJdbc方式三种方式来简化JDBC编程
        JDBC模板方式 : Spring JDBC框架提供以下几种模板类来简化JDBC编程,实现GoF模板设计模式,
        将可变部分和非可变部分分离,可变部分采用回调接口方式由用户来实现:如JdbcTemplate、
        关系数据库操作对象化方式 : Spring JDBC框架提供了将关系数据库操作对象化的表示形式,
        从而使用户可以采用面向对象编程来完成对数据库的访问;如MappingSqlQuery
        SimpleJdbc方式 : Spring JDBC框架还提供了SimpleJdbc方式来简化JDBC编程,SimpleJdbcInsert、
        SimpleJdbcCall用来简化数据库表插入、存储过程或函数访问

        spring jdbc 框架共有四个模块组成
          support datasource

          core object

        JDBC模板方式 - >Spring JDBC抽象框架core包提供了JDBC模板类,其中JdbcTemplate是core包的核心类,
        所以其他模板类都是基于它封装完成的,JDBC模板类是第一种工作模式
        1.查询一行数据并返回int型结果
          jdbcTemplate.queryForInt("select count(*) from test");
        2. 查询一行数据并将该行数据转换为Map返回
          jdbcTemplate.queryForMap("select * from test where name='name5'");
        3.查询一行任何类型的数据,最后一个参数指定返回结果类型
          jdbcTemplate.queryForObject("select count(*) from test", Integer.class);
        4.查询一批数据,默认将每行数据转换为Map
          jdbcTemplate.queryForList("select * from test");
        5.只查询一列数据列表,列类型是String类型,列名字是name
          jdbcTemplate.queryForList("select name from test where name=?", new Object[]{"name5"}, String.class);
        6.查询一批数据,返回为SqlRowSet,类似于ResultSet,但不再绑定到连接上
          SqlRowSet rs = jdbcTemplate.queryForRowSet("select * from test");
        7.jdbcTemplate.query(sql, new BeanPropertyRowMapper(Class<T> entity));

16/12/30 -> spring ORM映射学习 http://yun.baidu.com/share/home?uk=3560277524#category/type=0(传智播客学习视频 -> 全 )
        概述 : ORM全称对象关系映射(Object/Relation Mapping),指将Java对象状态自动映射到关系数据库中的数据上,
        从而提供透明化的持久化支持,即把一种形式转化为另一种形式。

        ORM解决方案适用于解决透明持久化、小结果集查询等;对于复杂查询,大结果集数据处理还是没有任何帮助的

        Spring对ORM的支持主要表现在以下方面:
        一致的异常体系结构 : 对第三方ORM框架抛出的专有异常进行包装,从而在使我们在Spring中只看到
        DataAccessException异常体系

        一致的DAO抽象支持 : 提供类似与JdbcSupport的DAO支持类HibernateDaoSupport,使用HibernateTemplate模板类
        来简化常用操作,HibernateTemplate提供回调接口来支持复杂操作

        Spring事务管理 : Spring对所有数据访问提供一致的事务管理,通过配置方式,简化事务管理

        spring 事务学习 四个特性 : 原子性(Atomicity),一致性(Consistency),隔离性(Isolation),持久性(Durability)

        事务并发的常见问题 :
        丢失更新:两个事务同时更新一行数据,最后一个事务的更新会覆盖掉第一个事务的更新,从而导致第一个事务
        更新的数据丢失,这是由于没有加锁造成的

        脏读 :一个事务看到了另一个事务未提交的更新数据

        不可重复读:在同一事务中,多次读取同一数据却返回不同的结果;也就是有其他事务更改了这些数据

        幻读 :一个事务在执行过程中读取到了另一个事务已提交的插入数据;即在第一个事务开始时读取到一批数据,
        但此后另一个事务又插入了新数据并提交,此时第一个事务又读取这批数据但发现多了一条,即好像发生幻觉一样。


        解决办法(事务的隔离级别) :
        未提交读(Read Uncommitted): 最低隔离级别,一个事务能读取到别的事务未提交的更新数据,很不安全,
          可能出现丢失更新、脏读、不可重复读、幻读
        提交读(Read Committed) : 一个事务能读取到别的事务提交的更新数据,不能看到未提交的更新数据,
          不可能出现丢失更新、脏读,但可能出现不可重复读、幻读
        可重复读(Repeatable Read) : 保证同一事务中先后执行的多次查询将返回同一结果,不受其他事务影响,
          不可能出现丢失更新、脏读、不可重复读,但可能出现幻读
        序列化(Serializable) : 最高隔离级别,不允许事务并发执行,而必须串行化执行,最安全,不可能出现更新、
          脏读、不可重复读、幻读

        事务的传播特性:
        Required : 必须有逻辑事务,否则新建一个事务,使用PROPAGATION_REQUIRED指定,表示如果当前存在一个逻辑事务,
        则加入该逻辑事务,否则将新建一个逻辑事务

        RequiresNew : 创建新的逻辑事务,使用PROPAGATION_REQUIRES_NEW指定,表示每次都创建新的逻辑事务

        Supports : 支持当前事务,使用PROPAGATION_SUPPORTS指定,指如果当前存在逻辑事务,就加入到该逻辑事务,
        如果当前没有逻辑事务,就以非事务方式执行

        NotSupported : 不支持事务,如果当前存在事务则暂停该事务,使用PROPAGATION_NOT_SUPPORTED指定,即以非事务方式执行,
        如果当前存在逻辑事务,就把当前事务暂停,以非事务方式执行

        Mandatory : 必须有事务,否则抛出异常,使用PROPAGATION_MANDATORY指定,使用当前事务执行,如果当前没有事务,
        则抛出异常(IllegalTransactionStateException)

        Never : 不支持事务,如果当前存在是事务则抛出异常,使用PROPAGATION_NEVER指定,即以非事务方式执行,如果当前存在事务,
        则抛出异常(IllegalTransactionStateException)

        Nested : 嵌套事务支持,使用PROPAGATION_NESTED指定,如果当前存在事务,则在嵌套事务内执行,如果当前不存在事务,
        则创建一个新的事务,嵌套事务使用数据库中的保存点来实现,即嵌套事务回滚不影响外部事务,但外部事务回
        滚将导致嵌套事务回滚
        (RequiresNew每次都创建新的独立的物理事务,而Nested只有一个物理事务;
        Nested嵌套事务回滚或提交不会导致外部事务回滚或提交,但外部事务回滚将导致嵌套事务回滚,
        而 RequiresNew由于都是全新的事务,所以之间是无关联的;)
        eg :
        <!-- 配置事务管理器 -->
        <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
          <property name="sessionFactory">
            <ref bean="mySessionFactory"/>
          </property>
        </bean>

        <!-- 配置事务传播特性 -->
        <tx:advice id="TestAdvice" transaction-manager="transactionManager">
          <tx:attributes>
            <tx:method name="save*" propagation="REQUIRED"/>
            <tx:method name="del*" propagation="REQUIRED"/>
          </tx:attributes>
        </tx:advice>

        <!-- 配置参与事务的类 -->
        <aop:config>
          <aop:pointcut id="allTestServiceMethod" expression="execution(* com.test.testAda.test.model.service.*.*(..))"/>
          <aop:advisor pointcut-ref="allTestServiceMethod" advice-ref="TestAdvice" />
        </aop:config>

17/01/03 -> hibernate 学习(缓存) hibernate get不支持延迟加载 load方法支持延迟加载,load没有查询到数据返回异常,
        此方法hibernate认为数据库一定有数据(ObjectNotFoundException),get没有查找到数据返回null

        Hibernate 缓存机制 http://www.cnblogs.com/wean/archive/2012/05/16/2502724.html
        why : 为了降低应用程序对物理数据源访问的频次,从而提高应用程序的运行性能
        缓存内的数据是对物理数据源中的数据的复制,应用程序在运行时从缓存读写数据,
        在特定的时刻或事件会同步缓存和物理数据源的数据

        Hibernate缓存包括两大类 :
        Hibernate一级缓存(session):
        Session内置不能被卸载,Session的缓存是事务范围的缓存
        Session session=HibernateSessionFactory.getSession();
        User user = new User(1, "812135023", "一缕阳光", '男', 21, true, "本科");
        session.save(user);//执行后,对象user已经加入到一级缓存
        session.close(); //执行后,user会从一级缓存中清除出去

        hibernate提供了clear和evict,contains等3个方法来管理一级缓存 :
        session.evict(user);//从一级缓存中清除单个指定对象
        session.clear();//清除一级缓存内的所有对象
        boolean flag=session.contains(user);//检测一级缓存内是否存在某个对象

        Hibernate二级缓存(sessionFactory):
        适合二级缓存的数据 :
        ● 很少被修改的数据。
        ● 不是很重要的数据,允许出现偶尔并发的数据。
        ● 不会被并发访问的数据。
        ● 参考数据。
        第二级缓存是可选的,有多种缓存,是一个可配置的插件,默认下SessionFactory不会启用这个插件
        eg : (ehcache) http://blog.csdn.net/u013410747/article/details/48558941
        1.Hibernate配置文件中设置开启二级缓存(通常文件为hibernate.cfg.xml)
        <!-- 配置是否开启2级缓存 -->
        <property name="cache.use_second_level_cache">true</property>
        <!-- 配置2级缓存产品的Hibernate接口类 -->
        <property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
        <!--特别说明二级缓存策略:
          1. read-only
          2. read-write
          3. nonstrict-read-write
          4. transcational
        -->
        <class-cache usage="read-write"/>
        <!-- 开启查询缓存的支持 -->a
        <property name="hibernate.cache.use_query_cache">true</property>
        <!-- 指定配置文件 -->
        <property name="hibernate.cache.provider_configuration_file_resource_path">
          ehcache.xml
        </property>
        2.在src下创建ehcache.xml文件,文件名必须是ehcache(不然要改配置才能-name属性划分区域给User对象,默认区域)
        <?xml version="1.0" encoding="UTF-8"?>
        <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="ehcache.xsd">
        <diskStore path="java.io.tmpdir" />
        <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            overflowToDisk="true"
            diskPersistent="false"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU" />
        </ehcache>
        3.设置映射文件
        <class name="cn.java.test.model.User" table="TBL_USER">
          <cache usage="read-write"/>(指定并发缓存策略)
          ......
        </class>

        4.Query或Criteria接口查询时设置其setCacheable(true),开启缓存

        5.缓存策略 :
        ● NONSTRICT_READ_WRITE:实体非严格读/写缓存
          允许更新,更新后缓存失效,需再查询一次。
          允许新增,新增记录自动加到二级缓存中。
          整个过程不加锁
        ● READ_WRITE:实体读/写缓存
          允许更新,更新后自动同步到缓存
          允许新增,新增记录后自动同步到缓存
        ● TRANSACTIONAL:实体事务缓存
          缓存支持事务,发生异常的时候,缓存也能够回滚,只支持jta环境
        ● Collection集合缓存
          <hibernate-mapping>
            <class name="cn.java.test.model.UserModel" table="TBL_USER">
              <cache usage="read-write" /> (指定并发缓存策略)
              <set name="farms" cascade="all" inverse="true" lazy="false">
                <cache usage="read-write"/> (指定并发缓存策略)
                <key column="fk_user_id"/>
                <one-to-many class="cn.java.test.model.FarmModel"/>
              </set>
            </class>
          </hibernate-mapping>

17/01/04 -> hibernate基础学习 hibernate存在原因 :
        1、 解决阻抗不匹配的问题;
        2、 目前不存在完整的面向对象的数据库(目前都是关系型数据库);
        3、 JDBC操作数据库很繁琐
        4、 SQL语句编写并不是面向对象
        5、 可以在对象和关系表之间建立关联来简化编程
        6、 O/RMapping简化编程
        7、 O/RMapping跨越数据库平台

        优点 :
        1、 不需要编写的SQL语句(不需要编辑JDBC),只需要操作相应的对象就可以了,就可以能够存储、更新、删除、
          加载对象,可以提高生产效;
        2、 因为使用Hibernate只需要操作对象就可以了,所以我们的开发更对象化了;
        3、 使用Hibernate,移植性好(只要使用Hibernate标准开发,更换数据库时,只需要配置相应的配置文件就可以了,
          不需要做其它任务的操作);
        4、 Hibernate实现了透明持久化:当保存一个对象时,这个对象不需要继承Hibernate中的任何类、实现任何接口,
          只是个纯粹的单纯对象—称为POJO对象(最纯粹的对象—这个对象没有继承第三方框架的任何类和实现它的任何接口)
        5、 Hibernate是一个没有侵入性的框架,没有侵入性的框架我们一般称为轻量级框架
        6、 Hibernate代码测试方便

        适用范围 :
        1.针对某一个对象,简单的将它加载、编辑、修改,且修改只是对单个对象(而不是批量的进行修改),这种情况比较适用;
        2.对象之间有着很清晰的关系(例:多个用户属于一个组(多对一)、一个组有多个用户(一对多));
        3.聚集性操作:批量性添加、修改时,不适合使用Hibernate(O/映射框架都不适合使用);
        4.要求使用数据库中特定的功能时不适合使用,因为Hibernate不使用SQL语句;

        读取配置文件configuration类 :
        * 读取hibernate配置文件(hibernate.cfg.xml或hiberante.properties)的.
        * new Configuration()默认是读取hibernate.properties
        * 所以使用new Configuration().configure();来读取hibernate.cfg.xml配置文件
        * 注释情况下,org.hibernate.cfg.AnnotationConfiguration来创建Configuration,这样就可以使用Annotation

SessionFactory :
SessionFactory是线线程安全的,一个数据库对应一个sessionFactory

注释学习(Annotation) : http://blog.csdn.net/a345203172/article/details/51771382
* @Entity 表示下面的这个Teacher是一个实体类
* @Table 表示映射到数据表中的表名,其中的name参数表示"表名称"
* @Column 映射表的列
eg :
@Column(name="BIRTH",nullable="false",columnDefinition="DATE")
public String getBithday() {
return birthday;
}
* @Id 表示主键Id,一般放在getXXX前面
* @Version - 可以在实体bean中使用@Version注解,通过这种方式可添加对乐观锁定的支持
* @Basic - 用于声明属性的存取策略:
@Basic(fetch=FetchType.EAGER) 即时获取(默认的存取策略)
@Basic(fetch=FetchType.LAZY) 延迟获取
* @Temporal(value=TemporalType)来注解表示日期和时间的注解
TemporalType.DATE 表示yyyy-MM-dd
TemporalType.TIME 表示HH:mm:ss
TemporalType=TIMESTAMP 两者兼具
* 实体类的某个成员属性不需要存入数据库中Annotation:使用@Transient 进行注解就可以了
* @Enumerated(value=EnumType)来注解表示此成员属性为枚举映射到数据库
EnumType有二个值 : ①EnumType.STRING 表示直接将枚举名称存入数据库
②EnumType.ORDINAL 表示将枚举所对应的数值存入数据库
* @GeneratedValue(strategy=GenerationType)注解可以定义该标识符的生成策略
①.AUTO- 可以是identity column类型,或者sequence类型或者table类型,取决于不同的底层数据库.
相当于native
②.TABLE- 使用表保存id值
③.IDENTITY- identity column
④.SEQUENCE- sequence
* 为Oracle指定定义的Sequence :
@SequenceGenerator(name="SEQ_Name",sequenceName="SEQ_DB_Name")
参数注意:SEQ_Name : 表示为申明的这个Sequence指定一个名称,以便使用
SEQ_DB_Name : 表示为数据库中的Sequence指定一个名称(两个参数名称可以相同)
eg :
@Entity
@SequenceGenerator(name="teacherSEQ" , sequenceName = "teacherSEQ_DB")
public class Teacher {
private int id;
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE , generator="teacherSEQ")
public int getId() {
return id;
}
}

一对多 多对一 多对多共通属性
fetch - 配置加载方式。取值有
Fetch.EAGER - 及时加载,多对一默认是Fetch.EAGER
Fetch.LAZY - 延迟加载,一对多默认是Fetch.LAZY
cascade - 设置级联方式,取值有:
CascadeType.PERSIST - 保存
CascadeType.REMOVE - 删除
CascadeType.MERGE - 修改
CascadeType.REFRESH - 刷新
CascadeType.ALL - 全部
targetEntity - 配置集合属性类型,如:@OneToMany(targetEntity=Book.class)

* @JoinColumn - 可选,用于描述一个关联的字段(一般就是外键)
* @OneToOne – 表示一个一对一的映射
@OneToOne(cascade = CascadeType.ALL)
@PrimaryKeyJoinColumn
public B getB(){
Return b;
}
* @ManyToOne
订单 Order 和用户 User 是一个 ManyToOne 的关系
在 Order 类中定义
@ManyToOne()
@JoinColumn(name="USER")
public User getUser() {
return user;
}
* @OneToMany //指定一对多关系
@Cascade(value={CascadeType.SAVE_UPDATE}) //设定级联关系
@JoinColumn(name="xxx_id")
private Set<xxx类> emp = new HashSet<xxx类>();
* mappedby
manyToMany(mappedby = "Student") 被拥有方的 其实就是主表
@JoinTable(
name="teacher_student",
joinColumns={@JoinColumn(name="teacher_id",referencedColumnName="tid")},
inverseJoinColumns={@JoinColumn(name="student_id",referencedColumnName="sid")}
)
注释情况下 : AnnotationConfiguration

主键生成策略 :
increment : 用于为long,short或者int类型生成唯一标识,只有在没有其他进程往同一张表中插入数据时才能使用,在集群下不要使用
identity : 对DB2,MySQL, MS SQL Server,Sybase和HypersonicSQL的内置标识字段提供支持。
返回的标识符是long, short 或者int类型的。 (数据库自增)
sequence : 在DB2,PostgreSQL, 【Oracle】, SAPDB, McKoi中使用序列(sequence), 而在Interbase中使用生成器(generator)。
返回的标识符是long, short或者 int类型的。(数据库自增)
uuid : 用一个128-bit的UUID算法生成字符串类型的标识符, 这在一个网络中是唯一的(使用了IP地址)。
UUID被编码为一个32位16进制数字的字符串,它的生成是由hibernate生成,一般不会重复。
UUID包含IP地址,JVM的启动时间(精确到1/4秒),系统时间和一个计数器值(在JVM中唯一)
native : 根据底层数据库的能力选择identity,sequence 或者hilo中的一个。(数据库自增)

一般优化 :
1.延迟加载 :
当调用Session上的load()方法加载一个实体时,会采用延迟加载。
当Session加载某个实体时,会对这个实体中的集合属性值采用延迟加载。(one-to-many)
当Session加载某个实体时,会对这个实体所单端关联(one-to-one, many-to-one)的另一个实体对象采用延迟加载
当相关联的session没有关闭时,访问这些懒加载对象(代理对象)的属性(getId和getClass除外)hibernate会初始化这些代理,
或用Hibernate.initialize(proxy)来初始化代理对象;当相关联的session关闭后,再访问懒加载的对象将出现异常。
关闭延迟加载 : lazy=“false”

2.抓取策略 :
通过配置“抓取策略”来直接影响session的get()和load()方法的查询效果

①.连接抓取(Join fetching) - Hibernate通过 在SELECT语句使用OUTER JOIN(外连接)来获得对象的关联实例或者关联集合,原本多次
查询用连接查询一次全部查询出来(set中没有大量数据时候有效,延迟加载失效)
eg :
<hibernate-mapping package="com.purking.strategys.endUpOne">
<class name="Customer" table="Customer_Table" lazy="true">
<id name="id">
<generator class="native" />
</id>
<property name="name" length="20" column="Cus_Name" />
<!-- 这里关闭懒加载是为了试验明显 -->
<set name="orders" inverse="true" fetch="join" lazy="false">
<key column="Cus_ID" />
<one-to-many class="Order"/>
</set>
</class>
</hibernate-mapping>

select x_id,x_name from x left left outer join y on x_id = y_id;

②.查询抓取(Select fetching) - 另外发送一条 SELECT 语句抓取当前对象的关联实体或集合。除非你显式的指定lazy="false"来
禁止延迟抓取(lazy fetching),否则只有当你真正访问关联关系的时候,才会执行第二条select语句,这是集合默认的抓取策略,
也就是我们常会出现N+1次查询的查询策略;
eg : 为两条查询语句,查询出one数据,再通过one_id查询出many数据
select x_id, x_name from x;
select y_id, y_name where y_id = x_id;

③.子查询抓取(Subselect fetching 【有in的语句】) - 另外发送一条SELECT 语句抓取在前面查询到(或者抓取到)的所有实体对象的关联集合。
除非你显式的指定lazy="false" 禁止延迟抓取(lazy fetching),否则只有当你真正访问关联关系的时候,才会执行第二条
select语句;
eg : 为两条查询语句,第一次查询出结果作为第二次的where条件进行处理
select x_id,x_name from xxx;
select y_id,y_name from y where y.x_id in (select x_id from xxx)

④.批量抓取(Batch fetching) - 对查询抓取的优化方案, 通过指定一个主键或外键列表,Hibernate使用单条SELECT语句
获取一批对象实例或集合;
eg :
<hibernate-mapping package="com.purking.strategys.endUpOne">
<class name="Customer" table="Customer_Table" lazy="true">
<id name="id">
<generator class="native" />
</id>
<property name="name" length="20" column="Cus_Name" />
<set name="orders"
inverse="true"
fetch="select"
lazy="true"
batch-size="3"> (设置一个有效的数值也是策略的必须考虑地方)
<key column="Cus_ID" />
<one-to-many class="Order" />
</set>
</class>
</hibernate-mapping>

select x_id, x_name from x where x_id in(1,2,3,4);
select y_id, y_name from y where y.x_id in(1,2,3);
select y_id, y_name from y where y.x_id = 4 ;
(batch-size分配 in 条件的数据)

缓存的应用 :
①.一级缓存不能控制缓存的数量,所以要注意大批量操作数据时可能造成内存溢出;可以用
evict(Object obj):从缓存中清除指定的持久化对象。
clear():清空缓存中所有持久化对象。
flush(): 进行清理缓存(此时缓存中的数据并不丢失)的操作,让缓存和数据库同步 执行一些列sql语句,但不提交事务
commit():先调用flush() 方法,然后提交事务. 则意味着提交事务意味着对数据库操作永久保存下来
定期清理session的缓存
当做批量插入或批量更新时,必须通过经常调用Session的flush()以及稍后调用clear()来控制一级缓存的大小,
这样内存才能保证足够的空间

②.合理使用二级缓存

Hibernate中inverse="true"的理解
inverse的意思是反转,用来设置关系哪一方是拥有者owner
inverse="false" 是默认情况,此时没有反转,则 Set/Collection 关系由包含它的“一”这一方来维;
inverse="true" 时,表示 Set/Collection 关系由另一方来维护,由不包含这个关系的一方来维护这个关系,所以才称为“反转”了。
eg :
Parent类和Child类有一个one-to-many的关系,如果要Parent增加一个Child,在inverse="true"时,
由Child的一方来维护关系,应该这样调用:
Child child = new Child();
child.setParent(parent);
此时调用 parent.getChildren().add(child) 是不会生效的。
为了简化编程,一般的做法是在 Parent 类里面加一个 addChild的方法:
public void addChild( Child child ) {
child.setParent(this);
this.children.add(child);
}

17/01/09 -> mysql 基础复习学习 基础语句 :
1.登录 mysql -h 主机名 -u 用户名 -p
2.创建数据库 create database 数据库名 [其他选项]; eg : (create database samp_db character set gbk;)
3.选择要操作的数据库 mysql -D 所选择的数据库名 -h 主机名 -u 用户名 -p
eg : mysql -D samp_db -u root -p
4.修改 root 用户密码 mysqladmin -u root -p password 新密码
5.执行sql文件 mysql -D samp_db -u root -p < createtable.sql(sql文件处于同一路径下)

nextday -> 6.sql语句优化
①.inner join内连接也叫等值连接是,left/rightjoin是外连接,能用inner join连接尽量使用inner join连接

②.子查询速度慢于外连接查询,尽量用外连接查询代替子查询

③.left join 左边表结果尽量小,如果后面有条件(where语句)应该放到左边先处理,right join同理反向

④.索引,不仅仅是主键和唯一键,也可以是其他的任何列
select *from A where name like ‘xxx%’; name有索引 会使用name的索引
select *from A where name like ‘%xxx’; name有索引 不会使用name索引 %代表不确定字符

⑤.复合索引
查询多个条件时,可以使用复合索引
eg : 创建(area,age,salary)复合索引实际创建了三个索引(area,age,salary),(area,age),(area)三个索引,
这样称为最佳左前缀特性,因此我们在创建复合索引的应该将最常用作限制条件的列放在最左边,依次递减

⑥.null值的列不要做索引,在MySQL中,含有空值的列很难进行查询优化,因为它们使得索引、
索引的统计信息以及比较运算更加复杂。你应该用0、一个特殊的值或者一个空串代替空值,null值复合索引会失效

⑦.排序索引
Mysql查询只是用一个索引,因此如果where子句中已经使用了索引的话,那么order by中的列是不会使用索引的。
因此数据库默认排序可以符合要求情况下不要使用排序操作;尽量不要包含多个列的排序,如果需要最好给这些列创建复合索引。

⑧.尽量避免Select * 命令

⑨.尽量不要使用BY RAND()命令,如果您真需要随机显示你的结果,有很多更好的途径实现。而这个函数可能会为表中每一个独立的行
执行BY RAND()命令—这个会消耗处理器的处理能力,然后给你仅仅返回一行

⑩.利用limit 1取得唯一行

11.尽量少排序,尽量少OR(很多时候用union 或者 union all 代替 or 会有很好的效果)

12.union和union all的差异主要是前者需要将两个(或者多个)结果集合并后再进行唯一性过滤操作(数据排序,加大cpu运算)如果
确认没有重复结果集或者不在乎重复结果集 就用union

13.不要在列上进行运算,尽量不要使用NOT IN和<>操作

14.程序中如果一次性对同一个表插入多条数据,比如以下语句
insert into person(name,age) values(‘xboy’, 14), (‘xgirl’, 15),(‘nia’, 19);

15.参数类型要与数据库字段类型一致

16.尽量不要用SELECT INTO语句。SELECT INTO 语句会导致表锁定,阻止其他用户访问该表

17.WHERE + ORDER BY + LIMIT组合的索引优化,形如:
SELECT [column1],[column2],…. FROM [TABLE] WHERE [columnX] = [VALUE] ORDER BY [sort] LIMIT [offset],[LIMIT];
这个语句,如果你仍然采用第一个例子中建立索引的方法,虽然可以用到索引,但是效率不高。
更高效的方法是建立一个联合索引(columnX,sort)

数据库乐观锁
在数据库中加一个版本号或者时间戳,查询出结果时候记录版本号或者时间戳,修改时候再取下时间戳或者版本号进行对比,如果相同则update
否则回滚

数据库悲观锁
对表进行锁定,其余事务进行修改操作时候都要进行等待或者抛出异常,只能等待释放锁定
特点如下 :
在对任意记录进行修改前,先尝试为该记录加上排他锁(exclusive locking)
如果加锁失败,说明该记录正在被修改,那么当前查询可能要等待或者抛出异常
如果成功加锁,那么就可以对记录做修改,事务完成后就会解锁了
其间如果有其他对该记录做修改或加排他锁的操作,都会等待我们解锁或直接抛出异常

数据库读写分离
有待学习

17/01/11 -> io流 字节流 :
输入流InputStream
eg :
InputStream streamReader = streamReader=newFileInputStream(new File("D:/David/files/tiger.jpg")); //文件输入流
while(streamReader.read()!=-1) { //读取文件字节,并递增指针到下一个字节
count++;
}
System.out.println("---长度是: "+count+" 字节")
streamReader.close();

输出流fileOutputStream
eg :
byte[] buffer = new byte[512];
FileInputStream input = new FileInputStream("D:/David/tiger.jpg");
FileOutputStream out = new FileOutputStream("D:/David/tiger2.jpg");;
while ((numberRead = input.read(buffer))!=-1) { //numberRead的目的在于防止最后一次读取的字节小于buffer长度,
out.write(buffer, 0, numberRead); //否则会自动被填充0
}
input.close();
out.close();

参数说明 :
public void write(byte[] b, int off, int len)
b -- 缓冲源。
off -- 数据偏移开始位置。
len -- 要写入的字节数。

字符流 :
FileReader / PrintWriter
eg :
char[] buffer = new char[512];
FileReader reader = new FileReader("D:/David/copy1.txt"); //读取字符文件的流
PrintWriter writer = new PrintWriter(System.out); //PrintWriter可以输出字符到文件,也可以输出到控制台
while ((numberRead = reader.read(buffer))!=-1) {
writer.write(buffer, 0, numberRead);
}
reader.close();
writer.close();

BufferedWriter 和 BufferedReader 用文件级联的方式进行写入,即将多个文件写入到同一文件中
(自带缓冲区的输出输出流BufferedReader和BufferedWriter,该流最常用的属readLine()方法了,读取一行数据,并返回String)
eg :
BufferedReader reader = new BufferedReader(new FileReader("D:/David/copy1.txt"));
BufferedWriter writer = new BufferedWriter(new FileWriter("D:/David/copy2.txt"));
while ((str = reader.readLine())!=null) {
writer.write(str);
writer.newLine();
}

重定向和请求转发区别
1.重定向 : 客户端行为,response.sendRedirect()会发出两次请求,第一次到servlet, 调用response方法,证明访问结束,
到页面告诉浏览器再次进行访问(respinse设定URL地址) 再次发出一次请求 地址栏变为response设定地址
(一般为login登录登出或者跳转到外域地址)

2.请求转发 : 服务器行为,request.getRequsetDispatcher().forward(requset,response);是一次请求,
转发后请求对象会保存,地址栏的URL地址不会改变。(服务器内部转发,所有客户端看不到地址栏的改变)

17/01/12 -> struts2学习 struts2没有侵入性 struts1有侵入性

基本流程
1.请求先到达Filter中央控制器
2.然后为Action创建代理类
3.将各个服务存放在拦截器中,执行完拦截器后再去执行action类行action类,action类调用service,再调用dao
4.得到结果字符串,创建result对象
5.转向相应的视图

启动
1.struts2框架是通过Filter启动的(struts.xml)
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

* struts2读取到struts.xml的内容后,以javabean形式存放在内存中,以后struts2对用户的每次请求处理
将使用内存中的数据,而不是每次都读取struts.xml文件

2.基础配置
<struts>
<package name="itcast" namespace="/test" extends="struts-default">
<action name="helloworld" class="cn.itcast.action.HelloWorldAction" method="execute" >
<result name="success">/WEB-INF/page/hello.jsp</result>
</action>
</package>
</struts>

基础知识
1.package : 管理一组相关的action,相关的action都应该放在同一package下
2.name : 配置包时必须指定name属性,该name属性值可以任意取名,但必须唯一,
他不对应java的类包,如果其他包要继承该包,必须通过该属性进行引用
3.namespace : 包的namespace属性用于定义该包的命名空间,命名空间作为访问该包下Action的路径的一部分,
如访问上面例子的Action,访问路径为:/test/helloworld.action,没有namespace的情况下默认为"".
4.extends="struts-default" : 通常每个包都应该继承struts-default包,因为Struts2很多核心的功能都是拦截器来实现
当包继承了struts-default才能使用struts2提供的核心功能,struts2每次都会自动加载
struts-default包


5.访问struts2中action的URL路径由两部份组成:包的命名空间 + action的名称 + 后缀 上面例子 : /test/helloworld.action
(注意:完整路径为:http://localhost:端口/内容路径/test/helloworld)

6.action访问顺序
eg : http://localhost:8080/struts2Project/path1/path2/path3/test.action
1.开始访问namespace为/path1/path2/path3/的package,找到了寻找test.action,如果没有test.action,到默认namespace=""的package下找
action,没有提示找不到
2.寻找namespace为/path1/path2的package,和1内容一样
3.寻找namespace为/path1/的package,和上面2一样
4.寻找namespace为/的package 和上面3一样

7.Action配置中的各项默认值
1.如果没有为action指定class,默认是ActionSupport。
2.如果没有为action指定method,默认执行action中的execute() 方法
3.如果没有指定result的name属性,默认值为success
4.如果没有指定result的type,默认值为dispatcher

8.struts2中提供了多种结果类型,常用的类型有: dispatcher(默认值)、 redirect 、 redirectAction 、 plainText
1.redirect
在result中还可以使用${属性名}表达式访问action中的属性,表达式里的属性名对应action中的属性
eg : <result type="redirect">/view.jsp?id=${id}</result>

2.redirectAction
1.如果重定向的action中同一个包下 :
<result type="redirectAction">helloworld</result>
2.不同包下 :
<result type="redirectAction">
<param name="actionName">helloworld</param>
<param name="namespace">/test</param>
</result>

9.多个Action共享一个视图--全局result配置
<package ....>
<global-results>
<result name="message">/message.jsp</result>
</global-results>
</package>

10.Struts2为Action中的属性提供了依赖注入功能,在struts2的配置文件中,我们可以很方便地为Action中的属性注入值。
(*注意:属性必须提供setter方法)
<action name="xxx" class="xxx" >
<param name="savePath">xxx</param>
<result name="success">/WEB-INF/page/xxx.jsp</result>
</action>

11.设置访问后缀(struts.xml中设置)
<struts>
<constant name="struts.action.extension" value="do"/>
</struts>

12.实现Action方法的几种形式
* jsp代码 :
<form action="sys/login.action" method="post">
<input type="text" name="username">
<input type="submit" value="submit">
</form>
1.继承ActionSupport(Action中直接设置get、set方法)
public class a extend ActionSupport {
public String getUserName() {
xxx
}

public void setUserName(userName username) {
xxx
}
}

2.模型驱动方式,必须要实现ModelDriven<T>接口,对于要传入多个model不是很方便
(必须实现getModel() 方法)
public class a extends ActionSupport implements ModelDriven<User>{
private User user;
public User getModel() {
if (null == user) {
return user = new User();
}
return user;
}
}

3.第三种方式可以完全不实现ModelDriven<T>,也可使用多个model对象的属性(直接用set方法)
***jsp代码 :
<form action="sys/login.action" method="post">
<input type="text" name="user.username">
<input type="text" name="teacher.level">
<input type="submit" value="submit">
</form>

public class sysAction extends ActionSupport{
private User user;
private Teacher teacher;

public void setUser(User user) {
this.user = user;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
}

17/01/16 -> springmvc学习 springMvc核心要素
1.入口程序 —— DispatcherServlet 核心分发器(调用各种handler)
对比普通servlet,多个请求多个servlet不好维护便产生了核心分发器
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup> load-on-startup:表示启动容器时初始化该Servlet
</servlet>

<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>

引入组件 : 通用servlet需求设计
步骤1 —— 对Http请求进行初步处理,查找与之对应的Controller处理类(方法)
步骤2 —— 调用相应的Controller处理类(方法)完成业务逻辑
步骤3 —— 对Controller处理类(方法)调用时可能发生的异常进行处理
步骤4 —— 根据Controller处理类(方法)的调用结果,进行Http响应处理

对应上面servlet需求产生接口
步骤1 —— HandlerMapping (代表一个请求到处理对象的映射)
步骤2 —— HandlerAdapter (SpringMVC 中通过HandlerAdapter的handler方法来调用实际的处理请求的函数)
步骤3 —— HandlerExceptionResolver
步骤4 —— ViewResolver


2.核心配置 —— [servlet-name]-servlet.xml
3.控制逻辑 —— UserController

spring-servlet 配置文件配置
spring执行handler时是按照执行顺序执行的 每个handler都有一个orderid 是从小的开始执行的,如果有结果匹配成功则执行
后面的handler则不执行了
<!-- 开启注释配置 -->
<context:annotation-config />

<!-- 设置使用注解的类所在的jar包 -->
<context:component-scan base-package="controller"></context:component-scan>

<!-- 默认的注解映射的支持 -->
<mvc:annotation-driven />
上面的annotation-driven可以自动注册DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter
是@Controller 和@RequestMapping注解分发请求的必须的bean
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />

<!--Spring3.1开始的注解 HandlerMapping -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
<!--Spring3.1开始的注解 HandlerAdapter -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>

<!-- 对静态资源文件的访问 方案一 (二选一) -->
<mvc:default-servlet-handler/>

<!-- 对静态资源文件的访问 方案二 (二选一)-->
<mvc:resources mapping="/images/**" location="/images/" cache-period="31556926"/>
<mvc:resources mapping="/js/**" location="/js/" cache-period="31556926"/>

<!-- ViewResolver -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- viewClass:JstlView表示JSP模板页面需要使用JSTL标签库,classpath中必须包含jstl的相关jar包 -->
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>

<!-- 拦截器 -->
<mvc:interceptors >
<mvc:interceptor>
<mvc:mapping path="/user/*" /> <!-- /user/* -->
<bean class="com.mvc.MyInteceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>

<!-- 总错误处理-->
<bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="defaultErrorView">
<value>/error/error</value>
</property>
<property name="defaultStatusCode">
<value>500</value>
</property>
<property name="warnLogCategory">
<value>org.springframework.web.servlet.handler.SimpleMappingExceptionResolver</value>
</property>
</bean>

<!-- 上传文件处理 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize">
<value>9242880</value>
</property>
</bean>

springmvc转发与重定向
可以通过redirect/forward:url方式转到另一个Action进行连续的处理。
可以通过redirect:url 防止表单重复提交 。
eg :
return "forward:/order/add";
return "redirect:/index.jsp";

注解springmvc
@Controller:用于标识是处理器类;
@RequestMapping:请求到处理器功能方法的映射规则
@Controller
@RequestMapping(value="/user") //①处理器的通用映射前缀
public class HelloWorldController2
@RequestMapping(value = "/hello2") //②相对于①处的映射进行窄化
public ModelAndView helloWorld()

@RequestParam:请求参数到处理器功能处理方法的方法参数上的绑定;
@ModelAttribute:请求参数到命令对象的绑定;
@SessionAttributes:用于声明session级别存储的属性,放置在处理器类上,通常列出
模型属性(如@ModelAttribute)对应的名称,则这些属性会透明的保存到session中;
@InitBinder:自定义数据绑定注册支持,用于将请求参数转换到命令对象属性的对应类型;

映射式样详解
1.普通URL路径映射
@RequestMapping(value={"/test1", "/user/create"}):多个URL路径可以映射到同一个处理器的功能处理方法
2.URI模板模式映射
@RequestMapping(value="/users/{userId}"):{×××}占位符, 请求的URL可以是 “/users/123456”或
“/users/abcd”,通过6.6.5讲的通过@PathVariable可以提取URI模板模式中的{×××}中的×××变量

@RequestMapping(value="/users/{userId}/create"):这样也是可以的,请求的URL可以是“/users/123/create”

@RequestMapping(value="/users/{userId}/topics/{topicId}"):这样也是可以的,请求的URL可以是“/users/123/topics/123”
3.正则表达式风格的URL路径映射
@RequestMapping(value="/products/{categoryCode:\d+}-{pageNumber:\d+}"):可以匹配“/products/123-1”,
但不能匹配“/products/abc-1”

请求参数数据映射限定
1.eg : 表示请求中有“create”的参数名且请求方法为“GET”即可匹配,如可匹配的
请求URL“http://×××/parameter1?create
@RequestMapping(params="create", method=RequestMethod.GET)
public String showForm()

2.eg : 表示请求中没有“create”参数名且请求方法为“GET”即可匹配,如可匹配的
请求URL“http://×××/parameter1?abc”
@RequestMapping(params="!create", method=RequestMethod.GET):

3.eg : 表示请求中有“submitFlag=create”请求参数且请求方法为“GET”即可匹配,如
请求URL为http://×××/parameter2?submitFlag=create;
②@RequestMapping(params="submitFlag=create", method=RequestMethod.GET)

4.eg : 表示请求中的有“test1”参数名 且 有“test2=create”参数即可匹配,如可匹配的
请求URL“http://×××/parameter3?test1&test2=create
@RequestMapping(params={"test1", "test2=create"}):

5.eg : 表示请求的URL必须为“/header/test4” 且 请求头中必须有“Accept =application/json”参数即可匹配
(其中accept是指接受什么样的请求)
@RequestMapping(value="/header/test4", headers = "Accept=application/json")

数据绑定
1.@RequestParam用于将请求参数区数据映射到功能处理方法的参数上。
(明确使用username进行入参,默认值为zhang,没有值时候会用默认值)
public String requestparam4(@RequestParam(value="username",required=false,defaultValue="zhang") String username)
required是否必须 默认必须 没有报错

当访问参数为url?role=admin&role=user一个参数多个值
public String requestparam8(@RequestParam(value="role") List<String> roleList)
或者
public String requestparam7(@RequestParam(value="role") String[] roleList)

2.@PathVariable用于将请求URL中的模板变量映射到功能处理方法的参数上
@RequestMapping(value="/users/{userId}/topics/{topicId}")
public String test(@PathVariable(value="userId") int userId, @PathVariable(value="topicId") int topicId)

3.@CookieValue用于将请求的Cookie数据映射到功能处理方法的参数上
(@CookieValue也拥有和@RequestParam相同的三个参数,含义一样)
public String test(@CookieValue(value="JSESSIONID", defaultValue="") String sessionId)

4.@RequestHeader用于将请求的头信息区数据映射到功能处理方法的参数上
(@RequestHeader也拥有和@RequestParam相同的三个参数,含义一样)
@RequestMapping(value="/header")
public String test( @RequestHeader("User-Agent") String userAgent, @RequestHeader(value="Accept") String[] accepts)

5.@RequestBody接受请求体中的数据,例如用ajax传数组的话就会放到请求体中,后台就要用@RequestBody来接受
它是通过使用HandlerAdapter 配置的HttpMessageConverters来解析post data body,然后绑定到相应的bean上的
@RequestMapping(value = "/getBooks")
@ResponseBody
public void getBooks(@RequestBody List<Book> list) { //@RequestBody接收string参数 自动注入属性 要求前端和参数属性名相同
return list; //Responsebody自动转json
}

5.@ModelAttribute学习
1.作用于void方法上时
@ModelAttribute
public void populateModel(@RequestParam String abc, Model model) {
model.addAttribute("attributeName", abc);
}

@RequestMapping(value = "/helloWorld")
public String helloWorld() {
return "helloWorld.jsp";
}
在这个代码中,访问控制器方法helloWorld时,会首先调用populateModel方法,
将页面参数abc(/helloWorld.do?abc=text)放到model的attributeName属性中,在视图中可以直接访问
<body>
<c:out value="${attributeName}"></c:out>
</body>

2.@ModelAttribute注释返回具体类的方法
@ModelAttribute
public User populateModel() {
User user=new User();
user.setAccount("ray");
return user;
}

@RequestMapping(value = "/helloWorld2")
public String helloWorld() {
return "helloWorld.jsp";
}
当用户请求 http://localhost:8080/test/helloWorld2.html时,首先访问populateModel方法,返回User对象,
model属性的名称没有指定,它由返回类型隐含表示,如这个方法返回User类型,那么这个model属性的名称是user。
这个例子中model属性名称有返回对象类型隐含表示,model属性对象就是方法的返回值。它无须要特定的参数
<body>
<c:out value="${user.account}"/>
<body/>

指定属性名称
@ModelAttribute(value="myUser")
public User populateModel() {
User user=new User();
user.setAccount("ray");
return user;
}
<body>
<c:out value="${myUser.account}"/>
<body/>

3.对象合并
@ModelAttribute
public User populateModel() {
User user=new User();
user.setAccount("ray");
return user;
}

@RequestMapping(value = "/helloWorld2")
public String helloWorld(User user) { //也可以指定前端访问对象名称 (@ModelAttribute("myUser") User user
user.setName("老王");
return "helloWorld.jsp";
}
<body>
<c:out value="${user.name}"></c:out> // myUser.name
<c:out value="${user.account}"></c:out>
<body/>

4.权限设定
public class BaseController {
@ModelAttribute
public void populateModel() throws Exception {
SysUser user=ContextUtil.getCurrentUser();
if(user.getAccount().equals("admin")){
throw new Exception("没有权限");
}
}
}

@Controller
public class Hello2ModelController extends BaseController {
@RequestMapping(value = "/helloWorld2")
public String helloWorld(@ModelAttribute("myUser") User user) {
user.setName("老王");
return "helloWorld.jsp";
}
}
文件夹截取字符串的时候用 Pattern.quote(System.getProperty("file.separator")) pattern 包用

原文地址:https://www.cnblogs.com/lixuchun/p/8705751.html