Skip to content

JavaEE 学习笔记

wanglinzhizhi edited this page Jul 28, 2016 · 2 revisions
layout: post
title:  "JavaEE 学习笔记"

JavaEE 学习笔记

	**Note**
	这是我自己在学习JavaEE的一些笔记,有些来自于网上的视频,有些来自于书.
	整理的并不是很完整,是自己在学习Java时候记在别的地方的笔记,
	包括了Struts2,Hibernate和Spring的部分.至于为什么要学习Struts2,
	总结起来应该应该算是当时年幼无知,眼界问题.
	听到高年级的学长(虽然我不喜欢这个称呼)和一些老师把Java的三大框架(SSH)吹得如何如何了得,
	就觉得很想学习一下,而等到学到了一些之后才发现,啊,原来现在已经不流行Struts2了,
	人们更多的在使用SpringMVC...虽然如此,我还是硬着头皮把它学完了(总不能学一半就算了吧).
	这是我学习Struts2的过程.

	当然,现在(2015年1月),我肯定会对别人的建议学SpringMVC比Struts要好.

IDEA 常用快捷键

  1. psvm

     ```
     public static void main(String[] args) {
     }
     ```
    
  2. sout

     ```
     System.out.println("validate innoked!");
     ```
    

Struts2

action的作用:

  • 数据校验

  • 类型转换

  • 组装对象。

      Note:不做业务处理,业务逻辑给后面service层,数据库代码更不应该出现在这里。
    

模型驱动

Dispatch 转发

token验证机制 ( 很重要的一样东西)

| 传值 | <result name="success" type="chain"> <param name="actionName">action2</param> <param name="username">${username}</param> <param name="password">${password}</param> <param name="usernameAndPassword">${usernameAndPassword}</param></result> |

| 防止表单重复提交 | <action name="token" class="wang.struts2.TokenAction"> <result name="success">/tokenSuccess.jsp</result> <result name="invalid.token">/tokenFail.jsp</result> <interceptor-ref name="token"></interceptor-ref> <interceptor-ref name="defaultStack"></interceptor-ref></action> |

PS

	```
		<s:token></s:token>放在form里面
	```


拦截器 的定义和使用

  1. 编写interceptor接口的类

     ```
     	public class TheInterceptor1  implements Interceptor{
     	}
     ```
    
  2. 在struts.xml文件中定义拦截器

     ```
     	<interceptors>
     	        <interceptor name="theInterceptor1"
     	        class="wang.interceptor.TheInterceptor1">
     					</interceptor>
     	</interceptors>
     ```
    
  3. 在action中使用拦截器

     ```
     	<action name="login" class="wang.struts2.LoginAction">
     	            <interceptor-ref name="theInterceptor1">
     							</interceptor-ref>
     	</action>
     ```
    

拦截器 intercept

  1. 服务器一启动,拦截器就实例化,然后拦截器立刻调用init()方法
  2. 拦截器只能拦截Action
  3. 很多拦截器struts已经实现,多数时候需要的是使用好它。自定义的时候是少数时候。
  4. 一旦定义了自己的拦截器, 将其配置到action上后,我们需要在action的最后加上默认的拦截器栈:defaultStack

Note

定义拦截器时可以直接继承 AbstractInterceptor 抽象类(该类实现 了 Interceptor 接口,并且对 init 和 destroy 方法进行了空实现), 然后实现其抽象方法 intercept 即可。

方法拦截器 (更精确的,更细粒度)

  1. 方法过滤拦截器 MethodFilterInterceptor,对action指定的方法选择拦截,或者不拦截

  2. 是否拦截,是否导致拦截器的代码是否执行,而不是目标代码是否执行,目标代码该执行还是执行。

  3. 在方法过滤拦截器中,如果既没有指定 includeMethods 参数 ,也 没有指定 execludeMethods 参数,那么所有的方法都会被拦截,也 就是说所有的方法都被认为是 includeMethods 的;如果仅仅指定 了 includeMethods,那么只会拦截 includeMethods 中的方法,没 有包含在 includeMethods 中的方法就不会被拦截。

  4. 每一个action里都要用到的拦截器,需要把排除在外的action的处理逻辑放在action中。

     ```
     public class LoginInterceptor extends AbstractInterceptor{
       @Override
       @SuppressWarnings("unchecked")
       public String intercept(ActionInvocation invocation) throws Exception {
       //如果是登录页面,就不用执行拦截作用,不想对LoginAction进行拦截,
       //因而struts提供了获取action的方法,就提供了获取invocation.getAction()
    
       if(LoginAction.class == invocation.getAction().getClass()){
         return invocation.invoke();
       }
    
       Map map = invocation.getInvocationContext().getSession();
    
       if(null == map.get("userInfo")){
         return Action.LOGIN;
       }
       return invocation.invoke();
       }
     }
    
    
     	对应的struts
    
     	<interceptor-stack name="MyDefaultInterceptorStack">
     	                <interceptor-ref name="loginInterceptor"></interceptor-ref>
     	                <interceptor-ref name="defaultStack"></interceptor-ref>
     	</interceptor-stack>
    
     	<default-interceptor-ref name="MyDefaultInterceptorStack">
     	</default-interceptor-ref>
     ```
    

命名空间 namespace-> 起到路径分割的作用

处理不同的模块的内容放在不同的package下面,用不同的命名空间

做项目的时候将不同的文件放在不同的目录下

文件上传

  • Struts2 的文件上传实际上是通过 FileUploadInterceptor 拦截器来处 理的。

  • 进行文件上传时,必须将表单的 method 属性设为 post,将 enctype 属性设为 multipart/form-data。

  • getName()的调用,确定是文件的时候才调用

  • Struts2 在进行文件上传操作时,实际上是通过两个步骤实现的:

    1. 首先将客户端上传的文件保存到 struts.multipart.saveDir 键所指 定的目录中,如果该键所对应的目录不存在,那么就保存到 javax.servlet.context.tempdir 环境变量所指定的目录中。 2) Action中所定义的File类型的成员变量file实际上指向的是临时 目录中的临时文件,

    2. 然后在服务器端通过 IO 的方式将临时文件 写入到指定的服务器端目录中。

         ```
      
         OGNL
      
             <s:iterator value="fileFileName" id="f">
      
               file: <s:property value="#f.toUpperCase()"/><br>
      
               </s:iterator>
             List<Person> list
      
             class Person
             {
                     Address address;
             }
      
             class Address
             {
                     A a;
             }
      
             class A
             {
                     String s;
             }
      
             <s:iterator value="list" id="l">
      
             <s:property value=="#l.address.a.s"/>
      
             </s:iterator>
      
      
      

动态的文件下载

	```
	    package com.shengsiyuan.struts2;

	    import java.io.InputStream;

	    import org.apache.struts2.ServletActionContext;

	    import com.opensymphony.xwork2.ActionSupport;

	    public class DownloadAction2 extends ActionSupport
	    {
	            private int number;

	            private String filename;

	            public String getFilename()
	            {
	                    return filename;
	            }

	            public void setFilename(String filename)
	            {
	                    this.filename = filename;
	            }

	            public int getNumber()
	            {
	                    return number;
	            }

	            public void setNumber(int number)
	            {
	                    this.number = number;
	            }

	            public InputStream getDownloadFile()
	            {
	                    try
	                    {
	                     if (1 == number){
	                            this.filename = "test.txt";
	                            this.filename =
	                            new String(this.filename.getBytes("gbk"),"8859_1");


	                return ServletActionContext.getServletContext()
	            .getResourceAsStream("/upload/test.txt");
	                    }else
	                    {
	                    this.filename = "CaptureSprite.exe";

	                 return ServletActionContext.getServletContext()
	                    .getResourceAsStream("/upload/CaptureSprite.exe");
	                            }
	                    }catch (Exception ex){

	                }

	                    return null;
	            }

	            @Override
	            public String execute() throws Exception
	            {
	                    return SUCCESS;
	            }
	    }
	```

Struts2 可以使用 struts2-convention-plugin-2.2.1.1.jar 插件实现基于 注解的配置。

常用的注解:action,interceptor,result 等

	```
		@ParentPackage("struts-default")
		@Action(value = "login", results = {
		        @Result(name = "success", location = "/login.jsp"),
		        @Result(name = "input", location = "/login.jsp") })
		//@InterceptorRef("defaultStack")
		//@InterceptorRefs({@InterceptorRef(""), @InterceptorRef("")})
		//@ExceptionMappings({@ExceptionMapping(),@E.....})

		public class LoginAction extends ActionSupport
		{
		        private String username;

		        private String password;

		        private int age;

		        private Date date;

		        private LoginService loginService = new LoginServiceImpl();

		        public Date getDate()
		        {
		                return date;
		        }

		        public void setDate(Date date)
		        {
		                this.date = date;
		        }

		        public int getAge()
		        {
		                return age;
		        }

		        public void setAge(int age)
		        {
		                this.age = age;
		        }

		        public String getUsername()
		        {
		                return username;
		        }

		        public void setUsername(String username)
		        {
		                this.username = username;
		        }

		        public String getPassword()
		        {
		                return password;
		        }

		        public void setPassword(String password)
		        {
		                this.password = password;
		        }

		        public String execute() throws Exception
		        {
		                // if(!"hello".equals(username))
		                // {
		                // throw new UsernameException("username invalid");
		                // }
		                // if(!"world".equals(password))
		                // {
		                // throw new PasswordException("password invalid");
		                // }
		                //
		                // return SUCCESS;

		        // HttpServletRequest request = ServletActionContext.getRequest();
		        // HttpSession session = request.getSession();
		        //
		        // session.setAttribute("hello", "helloworld");
		        //
		        // ActionContext actionContext = ActionContext.getContext();
		        // Map<String, Object> map = actionContext.getSession();
		        //
		        // Object object = map.get("hello");
		        // System.out.println(object);

		        if (this.loginService.isLogin(username, password))
		        {
		                User user = new User();

		        user.setUsername(username);
		        user.setPassword(password);

		        ActionContext.getContext().getSession().put("userInfo", user);

		        return SUCCESS;
		        }

		        return INPUT;
		        }

		        public String myExecute() throws Exception
		        {
		                System.out.println("myExecute invoked!!");

		        return SUCCESS;
		        }

		        public void validateMyExecute()
		        {
		                System.out.println("validateMyExecute invoked!!");

		        this.addActionError("action error");
		        }

		        @Override
		        public void validate()
		        {
		                // System.out.println("validate invoked!");

		        // this.addActionError("action error");
		        }

		}
	```

Note 注解与struts发生冲突,注解为准。就近原则


Struts 的异步方式 Ajax


Hibernate


Hibernate的配置步骤

  1. 创建Hibernate的配置文件hibernate.cfg.xml

  2. 创建持久化类

  3. 创建对象-关系映射文件hbm

  4. 通过Hibernate API 编写访问数据库的代码

     **Notes: 在向数据库传数据的话,传对象,不要传离散的值。**
    

SessionFactory 接口

Note: sessionFactory提供 的session实例,与http的HttpSession没有任何关系

特点:

  1. 线程安全

  2. 重量级的,不能随意创建实例

     **Note:仅仅在应用在初始化的时候创建,以后就不再创建了**
    

OGNL

当使用OGNL调用静态方法的时候,语法为

	@package.classname@methodname(parameter);

对于OGNL,java.lang.Math是其默认类,

Note:this是指当前待操作的元素

  • 过滤:

      (filtering),collection.{? expression}
    
    
    
       **过滤操作,可以看成是数据库操作的取行操作**
    
  • 投影:

        ```
        collection.{expression}
        ```
    
    
    
        **投影,可以看作数据库的取列操作**
    
  • 在Struts 2 中,根对象就是ValueStack

  • 在Struts 2 的任何流程当中,ValueStack中的最顶层对象一定是Action对象

  • 命名对象:parameter,request ,session ,application,attr

  • Struts 2访问静态方法和静态成员变量的改进

  • @vs@method //vs是ValueStack的简写

      **Notes: 数据放在文件和数据库里,其实性能差不多,因为都是对IO操作,数据库也是放在
               文件系统上的**
    

延迟加载 iterator

hbm

| 一对多域模型 | 面向程序 | | | |

| 一对多参照关系的关系模型 | 面向数据库 |

| | |

一对多是最重要的一种关联关系

| ---- | ---- | | | |

| Note Hibernate 中的一个很著名的一个异常:延迟加载异常 | (org.hibernate.LazyInitializationException) |

延迟加载:当我们在程序中获取到了一的一方,不需要多的那一方,强烈建议使用延迟加载。

自身双向一对多的关联关系


Session的缓存的作用

  1. 当Session的save()方式持久化一个Customer对象时,Customer对象被加入到Session的缓存中,以后即使应用程序中的引用变量不再引用Customer对象,只要Session的缓存还没有被清空,Customer对象仍然处于生命周期中
  2. 当Session的load()方法视图从数据库中加载一个Customer对象时,Session先判断缓存中是否已经存在这个Customer对象,如果存在,就不需要再到数据库中去检索

Session 清理缓存的时间点

  1. 当应用程序调用org.hibernate.Transaction的commit()方法的时候,commit()方法先清理缓存,然后再向数据库提交事务。
  2. 当应用程序显式调用Session的flush()方法的时候。
  • 对象的临时状态,持久化状态和游离状态
  • 用Session的update()方法使游离对象转变为持久化对象

Session级别的缓存叫做一级缓存 不可修改

  • 由于Session对象的生命周期通常对应一个数据库事务或者一个应用事务,因此它的缓存是事务范围的缓存。第一集缓存是必须的,不允许而且事实上也无法被卸载的。在第一级缓存中,持久化类的每个实例都具有唯一的OID

SessionFactory的缓存叫做二级缓存 可修改

  • 第二级缓存是一个可插拔的缓存插件,它由SessionFactory负责管理。由于SessionFactory对象的生命周期和应用程序的整个进程对应,因此第二级缓存是进程范围的缓存。这个缓存中存放的是对象的散装数据。第二级缓存是可选的,可以在每个类或每个集合的粒度上配置第二级缓存。

      Note:对于只读的table,可设置为二级缓存中。
    

使用延迟检索策略

适用范围:

  1. 一对多或者多对多关联
  2. 应用程序不需要立即访问或者根本不会访问的对象。

一对一映射

第1种方式.主键关联

一对一默认使用的是立即加载,如果需要使用延迟加载,那么需要在one-to-one元素中将constrained属性设置为true,并且将待加载的一方的class元素中的lazy属性设置为true(或者不去设置,因为该属性默认为true)。一对一加载时默认使用左外连接,可以通过修改fetch属性为select修改每次发送一条select语句的形式。


第2种方式 外键关联

本质上是一对多的蜕化形式,在many-to-one元素中增加unique=true属性就变成了一对一


多对多 many-to-many

	```
	- 学生选课,
	  对于领域模型的两个类,对于数据库而言是有三张表
	```

一个hbm生成两张表

map属性的应用

	```
		<?xml version="1.0" encoding="UTF-8"?>
		<!-- 指定Hibernate映射文件的DTD信息 -->
		<!DOCTYPE hibernate-mapping PUBLIC
		        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
		        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
		<hibernate-mapping>
		    <!--一个映射文件最终会生成两张表-->
		    <class name="Alan.Team" table="team">

		        <id name="id" column="id" type="string">
		        <!--//name=id,是指主键的名字是id,column是指对应数据库中的哪一列-->
		            <generator class="uuid"/>
		        </id>

		        <property name="teamName" type="string">
		            <column name="teamName"/>
		        </property>

		        <map name="students" table="student">
		            <key column="team_id"/>
		            <!--与team表中对应的关联的student表中外键-->
		            <index column="name" type="java.lang.String"/>
		            <!--指定map中的key值-->
		            <element column="description" type="java.lang.String"/>
		            <!--指定map中的value值-->
		        </map>

		    </class>
		</hibernate-mapping>
	```

Note : map的映射不好掌握,对于初学者(比如我)需用心

  • 如果map中的映射不止一个属性,如上例中的,description,现在有description2,怎么办呢?

      ```
      需要多建立一个java类
      ```
    

示例代码:

	```
		Team.hbm.xml
		<?xml version="1.0" encoding="UTF-8"?>
		<!-- 指定Hibernate映射文件的DTD信息 -->
		<!DOCTYPE hibernate-mapping PUBLIC
		        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
		        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
		<hibernate-mapping>
		    <!--一个映射文件最终会生成两张表-->
		    <class name="H.Team" table="team_Map2">
		        <id name="id" column="id" type="string">
		            <generator class="uuid"/>
		        </id>

		        <property name="teamName" column="teamName" type="string"/>

		        <!--<map name="students" table="student_Map">-->
		            <!--<key column="team_id"/> <!--student_MapE22 的外键-->
		            <!--<index column="name" type="java.lang.String"/><!--键key-->
		            <!--<element column="description" type="java.lang.String"/>
		            <!--值value-->
		        <!--</map>-->


		        <map name="students" table="student_Map2" cascade="all">
		            <!--student_MapE22 的外键-->
		            <key column="team_id"/>

		            <!--键key-->
		            <index column="card_id" type="java.lang.String"/>

		            <!--值value-->
		            <one-to-many class="H.Student"/>
		        </map>
		    </class>
		</hibernate-mapping>



		Student.hbm.xml

		<?xml version="1.0" encoding="UTF-8"?>
		<!-- 指定Hibernate映射文件的DTD信息 -->
		<!DOCTYPE hibernate-mapping PUBLIC
		        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
		        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
		<hibernate-mapping>
		    <!--一个映射文件最终会生成两张表-->
		    <class name="H.Student" table="student_Map2">
		        <id name="id" column="id" type="string">
		            <generator class="uuid"/>
		        </id>

		        <property name="name" column="name" type="string"/>

		        <property name="age" column="age" type="int"/>

		        <property name="cardId" column="card_id" type="string"/>

		        <many-to-one name="team"
		                     column="team_id"
		                     class="H.Team"
		                     cascade="none"
		                     fetch="join"/>
		    </class>
		</hibernate-mapping>
	```

一个对象生成两张表

set的实现

	```
		<set name="students" table="student">
		        <key column="" />
		        <element column="" type="" />
		</set>
	```

map与set标签中的element子标签影射的是原子类型(string,date,int,long……),即能够直接映射到数据库表字段上的类型,而one-to-many映射的则是实体类型(即,程序中的领域对象),指的是无法映射到表的某个字段,而是哟呵映射到整张表的类型。

查询排序

  • 内存排序和数据库排序

  • 数据库排序

      ```
      	Hbm.xml :order-by=" name asc"//name 是数据库的属性
    
      	内存排序
    
      	使用sort属性
      ```
    


联合主键(复合主键)的hbm设置

---> 25E

  • 类中 每个主键属性都对应到数据表中的 每个主键列。Hibernate要求具有联合主键的实现的实体类实现Serializable接口,并且重写hashCode和equals方法,重写这个两个方法的原因在于Hibernate要根据数据库的联合主键来判断某两行记录是否是一样的,如果一样那么就认为是同一个对象,如果不一样,那么就认为是不同的对象。这反映到程序领域中就是根据hashCode与equals方法来判断某两个对象是否能够放到诸如Set这样的集合中。
  • 联合主键实现Serializable接口的原因在于使用get和load方法的时候需要先构建出来该实体的对象,并且将查询依据(联合主键)设置进去,然后作为get和load方法的第二个参数传进去即可。

方法二:26E

  • 将主键所对应的属性提取出一个类(称之为主键类)。并且主键类需要实现Serializable接口,重写equals方法与hashCode方法。

组件

	```
		<?xml version="1.0" encoding="UTF-8"?>
		<!-- 指定Hibernate映射文件的DTD信息 -->
		<!DOCTYPE hibernate-mapping PUBLIC
		        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
		        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
		<hibernate-mapping>
		    <!--一个映射文件最终会生成两张表-->
		    <class name="Douglas.Student" table="studentDouglas">



		        <id name="id" column="id" type="string">
		         <generator class="uuid"/>
		        </id>

		        <property name="name" column="name" type="string"/>

		        <!--这里也可以使用one-to-one 方式-->
		        <component name="address" class="Douglas.Address">
		            <property name="homeAddress" type="string"/>
		            <property name="schoolAddress" type="string"/>
		        </component>



		    </class>

		</hibernate-mapping>


		<?xml version="1.0" encoding="UTF-8"?>
		<!-- 指定Hibernate映射文件的DTD信息 -->
		<!DOCTYPE hibernate-mapping PUBLIC
		        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
		        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
		<hibernate-mapping>
		    <!--一个映射文件最终会生成两张表-->
		    <class name="Andrew.Student" table="studentAndrew11">



		        <id name="id" column="id" type="string">
		        <!--//name=id,是指主键的名字是id,column是指对应数据库中的哪一列-->
		            <generator class="uuid"/>
		        </id>

		        <property name="name" column="name" type="string"/>

		        <!--这里也可以使用one-to-one 方式-->
		        <set name="contacts" table="contact">
		            <key column="student_id"/>
		            <composite-element class="Andrew.Contact">
		                <property name="method" type="string"/>
		                <property name="address" type="string"/>
		            </composite-element>
		        </set>

		    </class>

		</hibernate-mapping>
	```

E27 继承映射

  1. 每个子类一张表。

  2. 多态查询,如果没有对应的hbm文件,则必须把包的名字加上;

E28 继承映射的第二种方式

一张表存储继承体系中的所有类的信息

数据库表实际上是继承体系中所有类的属性的并集所构成的字段

需要在hbm文件中添加:

	```
		<discriminator column="personType" type="string"/>
	```

以下是代码:

	```
		<?xml version="1.0" encoding="UTF-8"?>
		<!-- 指定Hibernate映射文件的DTD信息 -->
		<!DOCTYPE hibernate-mapping PUBLIC
		        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
		        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
		<hibernate-mapping>
		    <!--一个映射文件最终会生成两张表-->
		    <class name="Seth.Person" table="personSeth12">

		        <id name="id" column="id" type="string">
		        <!--//name=id,是指主键的名字是id,column是指对应数据库中的哪一列-->
		            <generator class="uuid"/>
		        </id>

		        <property name="name" column="name" type="string"/>

		        <discriminator column="personType" type="string"/>  
		        <!--一张表存储继承体系中的所有类的信息 必须!!!-->

		        <subclass name="Seth.Student" discriminator-value="student">
		            <property name="cardID" type="string"/>
		        </subclass>

		        <subclass name="Seth.Teacher" discriminator-value="teacher">
		            <property name="salary" type="int"/>
		        </subclass>

		    </class>

		</hibernate-mapping>
	```




继承映射的第三种方式 E28

公共信息放在父类表中,独有信息放在子类表中,每个子类对应一张表。

E29

  • HQL检索方式:
  • QBC检索方式:

检索方式,即查询

Hibernate提供 的检索对象的方式:

  1. 导航对象图检索方式
  2. OID检索方式
  3. HQL检索方式
  4. QBC检索方式

HQL检索步骤

  1. 通过Session的createQuery()方法创建一个Query对象,它包含一个HQL查询语句。HQL可包含命名参数。
  2. 动态绑定参数
  3. 调用Query的list()方法执行查询语句。该方法返回List类型的查询结果,在List集合中存放了符合查询条件的持久化对象

Note: 支持 方法链 的编程风格

	```
		List result=session.createQuery("…")
		                     .setString("customerName","Tom")
		                   .setInteger("customerAge",21)
		                   .list();
	```

内链接????????????????????

学生自己查询自己的课程的时候?是内连接吗?

  • 左外连接:以左表为参照物,右边没有对应的情况下,填null占位

  • 右外连接:以右表为参照物

      ```
      	select * from team left outer join student on team.id =student.team_id;
      ```
    

E31

//命名查询:实体类型

//命名查询:实体类型

	```
	        Team team=(Team)session.get(Team.class,"");

	        //查询学生的年龄大于20的学生

	        Query query3=session.createQuery
	        	("from Student s where s.team=:team and s.age>20");

	        //方法一
	        query3.setParameter("team",team, Hibernate.entity(Team.class));

	        List<Student> list3=query3.list();

	        System.out.println(list3.size());


	        //方法二,更简单:
	        // Query setEntity(String name,Object val)

	        query3.setEntity("team",team);

	        List<Student> list3=query3.list();

	        System.out.println(list3.size());
	```

过滤器 E31

	```
		Query createFilter(Object collection,
		                 String queryString)
	```

Create a Query instance for the given collection and filter string. Contains an implicit FROM element named this which refers to the defined table for the collection elements, as well as an implicit WHERE restriction for this particular collection instance's key value.

E31 QBC

Note:但是推荐使用HQL使用

E32 数据库事务以及并发处理相关的知识

  • 并发问题
  • 设置事务的隔离级别
  • 使用悲观锁解决并发问题
  • 使用乐观锁解决并发问题

事务绝对不能被设计成自动提交,除了查询,对于数据库写操作的行为,绝对不能设计成自动提交。

数据库的四特性:ACID

  • 原子性 Atom
  • 一致性 Consistent
  • 隔离性 Isolation
  • 持久性 Duration

并发问题

  • 第一类丢失更新:撤销一个事务时,把其他事务已提交的更新数据覆盖
  • 脏读:一个事务读到另一个事务未提及的更新数据
  • 虚读:一个事务读到另一个事务已提交的新插入的数据
  • 不可重复读:一个事务读到另一个事务已提交的更新数据。
  • 第二类丢失更新:这是不可重复读的特例,一个事务覆盖另一个事务已提交的更新数据。

Note 对于多数应用程序,可以优先考虑把数据库系统的隔离级别设置为Read Committed ,它能够避免脏读,而且具有较好的并发性能。尽管它会导致不可重复读,虚读和第二类丢失更新这些并发问题,在可能出现这类问题的场合,可以由应用程序采用悲观锁或乐观锁来控制

悲观锁:数据库悲观的认为,任何人都可能对这行数据进行操作。所以它将这个表锁定了,锁定之后,只有当前的用户以操作这个表

在实际开发用得比较少,一般用乐观锁

乐观锁 E34

乐观锁是由应用程序提供的一种机制,这种机制既能保证多个事务并发访问数据,又能防止第二类丢失更新数据。

  1. 版本控制
  2. 时间戳

E34 Hibernate 拦截器与事件 (了解)

E35 二级缓存

	```
		<property name="hibernate.cache.use_second_level_cache">true</property>

		<property name="hibernate.cache.provider_class">Org.hibernate.cache.EhCache
		</property>
	```

Hibernate 二级缓存

  1. transaction:必须在在受管的环境下使用,保证可重复读的事务隔离级别,对于读写比例大,很少更新的数据通常可以采用这种方式。
  2. Read-write:使用timestamp机制维护已提交事务隔离级别,对于读写比例大,很少更新的数据通常可以采用这种方式 。
  3. Nonstict-read-write:二级缓存与数据库中的数据可能会出现不一致的情况。在使用这种策略的时候,应该设置足够短的缓存过期时间,否则就有可能从缓存中读取到脏数据。
  4. read-only:只读,当数据确定不会被改变时,我们可以使用这种缓存策略。

缓存标签:

Note:二级缓存可以保存到内存中,也可以保存到磁盘上。

E38 连接池

使用连接池,就不必每次都在查询或啥的时候建立连接。

数据库连接池(Connection pool)

  • Hibernate 内置,可用于学习但适于真实工程的高并发性->c3p0

  • 工程中:DBCP

  • JNDI :java命名与目录接口->将java资源与一个名字给绑定起来了。可以通过这个名字访问到对应资源的名字。

  • 连接池,应用程序来说,透明的

      ```
      	<?xml version='1.0' encoding='utf-8'?>
      	<!DOCTYPE hibernate-configuration PUBLIC
      	        "-//Hibernate/Hibernate Configuration DTD//EN"
      	        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
      	<hibernate-configuration>
      	    <session-factory>
      	        <property name="connection.url">
      	                  jdbc:mysql://localhost:3306/h3</property>
      	        <property name="connection.driver_class">
      	                  org.gjt.mm.mysql.Driver</property>
    
      	        <property name="connection.username">root</property>
      	        <property name="connection.password">nature</property>
      	        <property name="hibernate.dialect">
      	                  org.hibernate.dialect.MySQL57InnoDBDialect</property>
      	        <property name="show_sql">true</property>
      	        <property name="format_sql">true</property>
    
    
      	        <property name="hibernate.cache.use_second_level_cache">true</property>
      	        <property name="hibernate.cache.provider_class">
      	                  org.hibernate.cache.ehcache</property>
    
    
      	        <mapping resource="Student.hbm.xml"/>
      	        <mapping resource="Team.hbm.xml"/>
    
      	        <!--连接池-->
    
      	        <property name="hibernate.c3p0.min_size">10</property>
      	        <!--最少的连接数量-->
      	        <property name="hibernate.c3p0.max_size">40</property>
      	        <property name="hibernate.c3p0.timeout">200</property>
      	        <!--超时时间-->
      	        <property name="hibernate.c3p0.max_statements">30</property>
      	        <property name="hibernate.c3p0.idle_test_period">100</property>
    
      	        <!-- DB schema will be updated if needed -->
      	        <!-- <property name="hbm2ddl.auto">update</property> -->
      	    </session-factory>
      	</hibernate-configuration>
      ```
    

Apache->Jakarta ->DBCP



Spring


Spring 自动装配

E38

但是还是不太建议使用,还是明确指定, 代码的可识别度比较好,写得明明白白对后期维护帮助比较大。

Dependency-check:

  1. simple:会检查简单类型以及集合类型属性的设定
  2. object:会检查对象类型
  3. all:检查以上两者
  • 如果设置了Dependency-check, 必修要设定值,不然就出错,而不会去默认值

  • set方法是被spring 自动调用的

E39 集合对象在applicationContext中设置值


Java 语言的 反射机制Reflection

  • 运行时行为

      ```
      - 在运行时判断任意一个对象所属的类
      ```
    
  • 在运行时构造任意一个类的对象

  • 在运行时判断任意一个类所具有的成员变量和方法

  • 在运行时调用任意一个对象的方法

动态语言:程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言。

Perl,Python,Ruby是动态语言,C++,Java, C#不是动态语言

java有一个突出的与动态相关的机制:Reflection

  • 我们可以在运行时加载,探知,使用编译期间完全未知的classes。

    即Java程序可以加载一个运行时才得知名称的class,获悉其完整构造

    (但不包括methods定义),并生成其对象实体,或对其fields设值、或

    唤起其methods。这种“看透class”的能力(the ability of the program to

    Examine itself) 被称为 introspection;

用来实现java反射机制的重要:

  • Class类:
  • Field类:
  • Method类:
  • Constructor类:
  • Array类:

Note 反射可以改变私有变量的值

对于spring 的配置文件的bean元素,其scope属性有如下几个值:

  1. singleton,单例
  2. prototype ,表示每次从容器中取出bean时,都会生成一个新实例。相当于new出来一个对象。
  3. request,该属性是基于web的,表示每次接受一个请求时,都会生成一个新实例。在这种情况下,request和prototype一样。
  4. session。表示每个session中该对象只有一个。
  5. globalSession,(很少用)。

Note

  1. 所有无状态的对象,都配置成singleton。
  2. 默认的情况下,spring默认设置为scope="singleton"
  3. 对于action来说,一定要将其scope配制成prototype或是request

单例模型

	```
		Public class Singleton{

		        //2.
		        Private satic Singleton singleton=new Singleton();

		        //2.
		        Public satic Singleton getSingleton(){
		                Return singleton;
		        }

		        //1.将构造方法私有
		        Private Singleton(){

		        }

		}
	```

代理模式 E41

角色:

  • 抽象角色:声明真实对象和代理对象的共同接口
  • 代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。
  • 真实角色:代理角色所代表的真实对象,是我们最终要引用 的对象。

动态代理:实际上就是AOP的底层实现

如果要按照上述的方法使用代理模式,那么真实角色必须是事先已经存在的,并将其作为代理对象的内部属性。

但是实际使用时,一个真实的角色必须对应一个代理角色,如果大量使用会导致类的急剧膨胀;此外,如果事先并不知道真实的角色,该如何使用代理呢?这个问题可以通过java的动态代理类来解决。

动态代理类

它是在运行时生成的class,在生成它时,你必须提供一组interface给它,然后该class就宣称它实现了这些interface。你当然可以把该class的实例当作这些interface中的任何一个来用。当然,这个Dynamic Proxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。

动态代理类

被代理的对象可以在运行时动态改变,需要控制的接口可以在运行时改变,控制的方式也可以动态改变,从而实现了非常灵活的动态代理关系。

动态代理的使用场合:

  • 调试
  • 远程方法调用(RMI)
  • AOP

动态代理的步骤

  1. 创建一个实现接口InvocationHandler的类,它必须实现invoke方法
  2. 创建被代理的类以及接口
  3. 通过proxy的静态方法 newProxyInstance(ClassLoader loader,Class[] interfaces,invocationHandler h)创建一个代理
  4. 通过代理调用方法

AOP技术本质

使用“横切”技术,AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的 多处,而各处都基本相似。比如权限认证,日志,事务处理。AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。

AOP的核心思想就是:将应用程序中的商业逻辑同对其提供支持的 通用服务进行分离。

ProxyFactoryBean ,Spring里面用得最多的一个代理类

E42 权限控制的AOP实现

applicationContext.xml

把所有的struts2.xml和 Hibernate.cfg.xml的内容都写到applicationContext.xml里面去

E45 里面提到了一种避免表单重复提交的方法:type=redirect


2015/4/27

注入:一个类在生成的时候,在配置文件中将属性直接注入进来


Java 搜索引擎:Lucene


  • BeanFactory
  • XMLBeanFactory

getBean(id):通过applicationContext.xml 的id值获得bean的实例

面向接口编程:只有方法声明,没有方法实现。


2015/4/28

建议使用

	```
	ApplicationContextapplicationContext=
	  newFileSystemXmlApplicationContext("SpringDemo_3\\src\\applicationContext.xml");

	Personp=(Person)applicationContext.getBean("chinese");
	p.useAxe();
	```

而不要使用:

	```
		ClassPathResourceclassPathResource=
		     newClassPathResource("applicationContext.xml");
		XmlBeanFactoryfactory=newXmlBeanFactory(classPathResource);
		Personp=(Chinese)factory.getBean("chinese");




		<!--手动装配-->
		<beanid="chinese1"class="com.test.Chinese">
		<propertyname="dog"ref="gundog"></property>
		</bean>


		<beanid="gundog"class="com.test.GunDog">
		<propertyname="name">
		<value>花花</value>
		</property>
		</bean>

		<!--自动装配-->
		<beanid="chinese2"class="com.test.Chinese"autowire="byType"></bean>

		<beanid="gundog"class="com.test.GunDog">
		<propertyname="name">
		<value>花花</value>
		</property>
		</bean>
	```

Note :

Spring在执行依赖注入的时候,对于bean可以只设置其set方法就可以了。

SpringDemo_3 依赖注入以及类,bean对象的实例化顺序

  • Spring 实例化主调bean:Chinese实例……
  • Spring 实例化依赖bean:StoneAxe实例……
  • Spring 执行依赖注入,通过setAxe()
  • Spring 实例化依赖bean:SteelAxe实例……
  • 程序已经实例化BeanFactory
  • 程序中已经完成chinese bean的实例化……
  • 石斧头砍柴真慢啊! ——_______________________——
  • 此人的年纪为: 0

Spring对集合的装配

	```
		<?xmlversion="1.0"encoding="UTF-8"?>
		<beansxmlns="http://www.springframework.org/schema/beans"
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		xsi:schemaLocation=
		"http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd">

		<beanid="stoneAxe"class="StoneAxe">

		</bean>

		<beanid="chinese"class="Chinese">
		<propertyname="school">

		<list>
		<value>小学</value>
		<value>中学</value>
		<value>初中</value>
		<value>高中</value>
		<value>本科</value>
		<value>研究生</value>

		</list>
		</property>

		<propertyname="score">
		<map>
		<entrykey="数学"value="99"/>
		<entrykey="英语"value="100"/>
		<entrykey="计算机"value="99"/>
		<entrykey="政治"value="100"/>
		</map>

		</property>

		<propertyname="health">

		<props>
		<propkey="身高">171</prop>
		<propkey="体重">55</prop>
		</props>
		</property>

		<propertyname="axes">
		<!--set中三个数据,三种类型(分别是字符串,bean,引用),
		     因为Set没有用泛型,所以可以放不同类型的数据-->
		<set>
		<value>字符串斧子</value>
		<beanclass="SteelAxe"></bean>
		<refbean="stoneAxe"></ref>
		<!--从测试结果可以看到,运用bean类型时,
		    其实重新生成一个bean实例,而用ref,使用的还是原来的实例-->
		</set>
		</property>
		</bean>


		</beans>
	```

Java 语言的反射机制

SPringDemo_6 ,SpringDemo_7 关于反射

	```
		Public void afterPropertiesSet()throwsException{
		System.out.println("正在执行初始化方法:afterPropertiesSet()....");
		}

		这个的执行,是在所有的set都执行完成之后,
	```

如果想让一个类的实例 在属性都已经准备好之后,就让它自动执行某些方法,有两种方式:

  1. afterPropertiesSet

    这个需要实现相应的接口。

  2. init()或ini2(),等等,然后在applicationContext.xml中

        ```
        		<beanid="chinese"class="Chinese"init-method="init">
        		<propertyname="axe">
        		<refbean="stoneAxe"></ref>
        		</property>
        		</bean>
        ```
    

推荐使用第二种方式,原因减少耦合

两种销毁的方式:

  1. DisposableBean接口
  2. Destory-method

strutsspring整合原理:

	```
	struts的解析顺序:

	        1. Struts-default.xml
	        2. Struts-plugin.xml
	        3. 自定义的Struts.xml
	```

Struts.objectFactory = spring. 将struts默认的对象工厂用spring来overridden

	```
		<!--spring的启动类,服务器一启动,listener这个类就被实例化,被运行,
		    spring通过通过这个listener一启动,spring整个框架就运行起来了,
		    之后spring就掌管整个系统的一切,
		    有什么需要创建,它负责创建,
		    有什么需要销毁,它负责销毁-->

		    <listener>
		    	<listener-class>
		    	  org.springframework.web.context.ContextLoaderListener
		        </listener-class>
		    </listener>


		Web.xml中
	```
  • 被action调用,怎么让action知道?

    这是由Spring帮我们完成的,我们只需在action里面声明这个action所需要的服务接口是什么

    注意:在spring与struts合作中,struts中的class=”“,这里的action的name,是来自元spring中定义的action的名字(bean的id的名字)

无状态对象都配置scope=singleton,比如说Service。一个对象可以服务所有的。

  • 对于action来说,一定要将其scope配置成prototype或是request
  • 对于servlet,一定都是singleton的

依赖注入:(3种方式)

  1. 设值注入setXXX()方法 (推荐)
  2. 构造注入
  3. 接口注入 (不支持)
  • 依赖注入:工厂模式
  • AOP:代理模式

怎么在java中定义一个类:

  1. 在一个.java文件中,class A{…}

  2. 在java中还可以动态的去定义一个类,借助于动态代理类DynamicProxy

     ```
     packagecom.test.dynamicProxy;
    
     importjava.lang.reflect.InvocationHandler;
     importjava.lang.reflect.Proxy;
    
     /**
     *Createdbywanglinzhizhion2015/4/30.
     */
     publicclassClient{
     	publicstaticvoidmain(String[]args){
    
     		RealSubjectrealSubject=newRealSubject();
    
     		InvocationHandlerhandler=newProxySubject(realSubject);
    
     		//获得subject所对应的对象
     		Class<?>clazz=realSubject.getClass();
    
     		//为其一次性生成代理
     		Subjectsubject=(Subject)Proxy.
     		newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),handler);
    
     		//subject是代理
     		subject.request();
     	}
     }
    
    
     ```
    

Note:

	```
	源代码中调用最后一句:subject.request()的时候会自动调用
	Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),handler);
	调用handler又自动转到ProxySubject中,
	又自调用invoke方法中的method.invoke(object,args)。
	在这时候完成代理的衔接。
	```

WSDL,使用代理,在不同的异构的网络上,实现不同语言的贡献

动态代理的步骤

  1. 创建一个实现接口InvacationHandler的类,它必须实现invoke方法
  2. 创建被代理的类以及接口
  3. 通过Proxy的静态方法newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHander handler)创建一个代理
  4. 通过代理调用方法

AOP的核心思想就是“ 将应用程序的商业逻辑同对其提供辅助支持的通用服务进行分离。”

AOP技术的两大类:

  1. 采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行。
  2. 采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码。

**使用HibernateDaoSupport 需要将Sessionfactory 注入,而sessionFactory从哪儿来呢?->sessionFactory是由spring来管理的。

XXXX.hbm.xml 这个文件是必须要有的,hibernate是根据这张表来生成对应的sql语句的。**

Spring对于事务是通过AOP是方式解决的

基本原理:

  1. DAO
  2. 对于DAO,生成代理
  3. 增加代理,功能性增强,在方法开始的时候开启事务,在结束后,关闭事务

Spring的事务类

HibernateTransactionManager

对某一个类的某一个方法或某几个方法增加事务的话。做两件事:

  1. 声明好HibernateTransactionManager这样的bean

     ```
     	<!--代理声明类,id可以随便取-->
     	<bean id="transactionManager"
     	      class="org.springframework.orm.hibernate4.HibernateTransactionManager">
         		<propertyname="sessionFactory"ref="sessionFactory"/>
     	</bean>
     ```
    
  2. 然后利用这个bean去增强我们的需要使用事务的目标类

     ```
     <!--ServiceuserServiceTaget约定的命名,为它生成代理,他是目标对象,
    	    这是事务增强的目标对象-->
    
     <bean id="userServiceTarget" class="com.test.service.impl.UserServiceImpl">
     	<property name="userDao" ref="userDao"/>
     </bean>
    
     <!--代理声明式的代理-->
     <bean id="userService"
           class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
           scope="singleton">
     		<propertyname="target"ref="userServiceTarget"/>
     		<propertyname="transactionManager"ref="transactionManager"/>
     		<propertyname="transactionAttributes">
             		<props>
             		<propkey="find*">PROPAGATION_REQUIRED,readOnly</prop>
             		<!--读-->
             		<propkey="*">PROPAGATION_REQUIRED</prop>
             		<!--其他-->
             		</props>
     		</property>
     </bean>
     ```
    

Note: 通常事务操作配置到Service 层

原因:通过Service引用了若干个DAO,使得它所引用的不管几个DAO方法都具备了事务,在一个事务之内,要么同时成功,要么同时失败。

之所以不配知道DAO层是因为, 有可能一个Service用到了两个DAO方法


声明性事务管理

```
<!--1-->
<!--代理声明类,id可以随便取1是独立的-->
<beanid="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<propertyname="sessionFactory"ref="sessionFactory"/>
</bean>

<!--2-->
<!--ServiceuserServiceTaget约定的命名,为它生成代理,他是目标对象,这是事务增强的目标对象-->
<beanid="userServiceTarget"class="com.test.service.impl.UserServiceImpl">
<propertyname="userDao"ref="userDao"/>
</bean>

<!--3-->
<!--代理声明式的代理-->
<beanid="userService"
  class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
scope="singleton">

<!--TransactionProxyFactoryBean这货是Factory-->

<!--原始对象/真实对象是:userServiceTarget-->
<propertyname="target"ref="userServiceTarget"/>
<!--这个代理,代理谁?--><!--代理对象内部必须具有一个真是对象的引用-->

<!--引用之前声明的事务管理器-->
<propertyname="transactionManager"ref="transactionManager"/>

<propertyname="transactionAttributes">
<props>
<!--所有find开头的方法,设置PROPAGATION_REQUIRED,表示如果已经存在这个事务,
     就用这个事务,如果不存在这个事务,则新创建一个事务-->
<propkey="find*">PROPAGATION_REQUIRED,readOnly</prop>
<!--读-->
<propkey="*">PROPAGATION_REQUIRED</prop>
<!--其他-->
</props>
</property>

</bean>

```

常见的架构设计策略

目前流行的轻量级Java EE 应用的架构基本比较统一,通常会使用Spring 作为核心,向上整合MVC框架,向下整合ORM框架。使用Spring 的Ioc容器来管理各组件之间的依赖关系时,Spring的声明式事务将负责业务逻辑层组件的事务管理。

虽然大体上的结构设计保持相似,但在具体的技术组合上可能存在较小的变化,当我们决定采用某种架构设计时,我们主要考虑这种架构是否成功的将规范和实现分离了,从而可以提供较好的可扩展性,可修改性。最理想的情况是,当我们修改企业级应用的某个组件时,应用中其他组件收到的影响很小,或者不受到任何影响……这就为整个系统后期的扩展提供了无限可能性。

  • 贫血模式
  • 领域对象模型
  • 合并业务逻辑对象与DAO对象
  • 合并业务逻辑对象和Domain Object
  • 抛弃业务逻辑层

P753        轻量级JavaEE 


Spring 中包含的关键特性

  1. 强大的基于 JavaBeans 的采用控制翻转(Inversion of Control,IoC)原则的配置管理,使得应用程序的组建更加快捷简易。
  2. 一个可用于从 applet 到 Java EE 等不同运行环境的核心 Bean 工厂。
  3. 数据库事务的一般化抽象层,允许宣告式(Declarative)事务管理器,简化事务的划分使之与底层无关。
  4. 内建的针对 JTA 和 单个 JDBC 数据源的一般化策略,使 Spring 的事务支持不要求 Java EE 环境,这与一般的 JTA 或者 EJB CMT 相反。
  5. JDBC 抽象层提供了有针对性的异常等级(不再从SQL异常中提取原始代码), 简化了错误处理, 大大减少了程序员的编码量. 再次利用JDBC时,你无需再写出另一个 '终止' (finally) 模块. 并且面向JDBC的异常与Spring 通用数据访问对象 (Data Access Object) 异常等级相一致.
  6. 以资源容器,DAO 实现和事务策略等形式与 Hibernate,JDO 和 iBATIS SQL Maps 集成。利用众多的翻转控制方便特性来全面支持, 解决了许多典型的Hibernate集成问题. 所有这些全部遵从Spring通用事务处理和通用数据访问对象异常等级规范。
  7. 灵活的基于核心 Spring 功能的 MVC 网页应用程序框架。开发者通过策略接口将拥有对该框架的高度控制,因而该框架将适应于多种呈现(View)技术,例如 JSP,FreeMarker,Velocity,Tiles,iText 以及 POI。值得注意的是,Spring 中间层可以轻易地结合于任何基于 MVC 框架的网页层,例如 Struts,WebWork,或 Tapestry。
  8. 提供诸如事务管理等服务的面向方面编程框架。
Clone this wiki locally