关于框架学习的简单笔记

HTTP请求:
客户端通过发送HTTP请求向服务器请求对资源的访问
HTTP请求由三部分组成,分别是:请求行、消息包头、请求正文
请求行:
——请求行以一个方法符号开头,后面跟着请求URI和协议的版本,以CRLF(回车换行)作为结尾。请求行以空格分隔。除了作为结尾的CRLF外,不允许出现单独的CR或LF字符,格式如下:Method Request-URL HTTP-Version CRLF
——Method表示请求的方法,Request-URL是一个统一资源标识符,标识了要请求的资源,HTTP-Version表示请求的HTTP协议版本,CRLF表示回车换行。例如:GET /test.html HTTP/1.1 (CRLF)
—HTTP请求——方法




HTTP响应
——在接收和解释请求消息后,服务器会返回一个HTTP响应消息
——与HTTP请求类似,HTTP响应也是由三个部分组成,分别是:状态行,消息报头,响应正文
—HTTP响应——状态行
——状态行由协议版本,数字形式的状态代码,相应的状态描述组成,各元素之间以空格分隔,除了结尾的CRLF(回车换行)序列外,不允许出现CR或LF字符。格式如下:HTTP-Version Status-Code Reason-Phrase CRLF
——HTTP-Version表示服务器HTTP协议的版本,Status-Code表示服务器发回的响应代码,Reasion-Phrase表示状态代码的文本描述,例如:HTTP/1.1 200 OK (CRLF)
—HTTP响应——状态代码与状态描述
——状态代码由三位数字组成,表示请求是否被理解或被满足,状态描述给出了光宇状态代码的简短文本描述。
——状态代码的第一个数字定义了响应的类别,后面两个数字没有具体的分类。第一个数字有五种可能的取值:1XX:指示信息,表示请求已接收,继续处理;2XX:成功,表示请求已经被成功接收,理解,接受;3XX:重定向,要完成请求必须进行更进一步的操作;4XX:客户端错误,请求有语法错误或请求无法实现;5XX:服务器端错误,服务器未能实现合法的请求。
—HTTP消息
——HTTP消息由客户端到服务器的请求和服务器到客户端的响应组成。请求消息和响应消息都是由开始行,消息报头,空行(只有CRLF的行),消息正文组成
——对于请求消息,开始行就是请求行,对于响应消息,开始行就是状态行。
—request和response
——request 对象代表的是来自客户端的请求,例如我们的FORM表单中填写的信息等,是最常用的对象。关于它的方法使用较多的是getParameter、getParameterNames和getParameterValues,通过调用的这几个方法来获取请求对象中所包含的参数的值。
——response 对象代表的是对客户端的响应,也就是说可以通过response对象来组织发送到客户端的数据。但是由于组织方式比较底层,所以不建议不同读者使用,需要向客户端发送文字时直接使用out对象即可。
—application和session
——application只是在服务器重新开始的时候才初始化,session是浏览器关了,就初始化了。
—Session的运行机制
——当一个Session开始时,Servlet容器将创建一个HttpSession对象,在HttpSession对象中可以存放客户状态的信息。
——Servlet容器为HttpSession分配一个唯一标志符,称为Session ID。Servlet容器把Session ID作为Cookie保存在客户的浏览器中。
——每次客户发出HTTP请求时,Servlet容器可以从HttpServletRequest对象中读取Session ID,然后根据Session ID 找到相应的HttpSession对象,从而获取客户的状态信息。
—观察者模式
——观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时坚挺某一个主题对象,这个主题对象在状态上发生变化时,会通知所有观察者对象,让他们能够自动更新自己。
——观察者模式的组成
抽象主题角色:把所有对观察者对象的引用保存在一个集合中,每个抽象主题角色都可以有仁义数量的观察者。抽象主题提供了一个接口,可以增加和删除观察者角色。一般用一个抽象类或接口来实现。
抽象观察者角色:为所有具体的观察者定义一个接口,在得到主题的通知时更新自己。
具体主题角色:在具体主题内部状态改变时,给所有登记过的观察者发出通知。具体主题角色通常用一个子类实现。
具体观察者角色:该角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。如果需要,具体观察者角色可以保存一个指向具体主题角色的引用。通常用一个子类实现。
—Servlet过滤器的概念
——Servle过滤器是在Java Servlet规范2.3中定义的,它能够对Servlet容器的请求和响应对象进行检查和修改。
——Servlet过滤器能够在Servlet被调用之前检查Request对象,修改RequestHeader和Request内容;
——在Servlet被调用之后检查Response对戏那个,修改ResponseHeader和Response内容。Servlet过滤器负责过滤的Web组件何以是Servlet、JSP或HTML文件。

——int(FilterConfig):这是Servlet过滤器的初始化方法,Servlet容器穿件Servlet过滤器实例后将调用这个方法。在这个方法中可以读取web.xml文件中Servlet过滤器的初始化参数。
——doFilter(ServletRequest, ServletResponse, FilterChain):这个方法完成实际的过滤操作。当客户请求访问与过滤器关联的URL时,Servlet容器将先调用过滤器的doFilter方法。FilterChain参数用于访问后续过滤器。
——destroy():Servlet容器在销毁过滤器实例前调用该方法,在这个方法中可以释放Servlet过滤器占用的资源。
—关于读取外部properties的方法
——获得:
Properties ps = new Properties();
  try
  {
   ServletContext context = config.getServletContext();
   InputStream in = context.getResourceAsStream("/WEB-INF/messageresource.properties");
   ps.load(in);
   in.close();
   context.setAttribute("ps", ps);
  }

——读取:
Properties ps = (Properties) pageContext.getAttribute("ps",PageContext.APPLICATION_SCOPE);
String message = (String) ps.get(key);//这里就是key的那个名字
pageContext.getOut().print(message);


—关于Struts的MVC模式,才是体现的最好的。
——首先JSP页面,不过提交的时候是通过过滤器,filter;Struts就是很牛的过滤器,对JSP的传值做了过滤后,再调用action的方法,然后再通过过滤器传出去。
1、在web.xml加上如下:这就是配置上Struts的过滤器。
<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>

2、在提交的表单上,如下:这个action可以简写为:login.action,在这个传值的时候,就自动链接到了过滤器(通过struts.xml)。如下login.jsp
<form action="login" method="post">
    username: <input type="text" name="username" size="20"/><br>
    password: <input type="password" name="password" size="20"/><br>
    <input type="submit" value="submit"/>
</form>

3、在struts.xml如下:根据表单上的action="login"就是下面action的name,然后打开class的类。
<struts>
    <package name="struts2" extends="struts-default">
    <action name="login" class="com.test.action.LoginAction">
    <result name="success">/result.jsp</result>
    </action>
    </package>
</struts>

4、注意,这个LoginAction.java是个javabean,都是get和set的方法。但是最后有一个方法,如下:这个方法是Struts的一个方法,返回的值有上面的那个result接收,对比name的值,然后定义下面访问的页面。但是传值是依然的。
public String execute() throws Exception
{
return "success";
}


5、返回值的传值验证之后,在result.jsp里面,如下:
username: ${requestScope.username }<br>
password: ${requestScope.password }

——struts的传值!
struts的传值非常神奇,这也是当年我说的命名的重要性,在上面的例子中可以看出。
在login.jsp里:<input type="text" name="username" size="20"/>
在LoginAction.java的JavaBean里,private String username;这里get和set方法上就是用username必须要一样,而且自动执行赋值的方法。
在struts.xml的<result name="success">/result.jsp</result>传到了result.jsp的时候,注意这里:username: ${requestScope.username }这里的username也一定要一直。
所以说struts的传值,还是非常好的。
—struts的自动转型方式。
——新建的PointAction-conversion.properties的文件, 注意这个properties文件的命名,必须是"action名-conversion.properties",而且一定要和action同一个包下。全局转换器是必须在src的目录下,命名为:xwork-conversion.properties。里面内容是:
point=com.test.converter.PointConverter 这就是这样point通过PointConverter类进行转值。左边写,你要转换的PointAction里的哪一个属性,昨天就写什么属性:point,右边是转换器的名字。注意转换器最好继承StrutsTypeConverter,来写。
—关于源代码的导包
——Struts2的包应该导:struts-2.3.15.1\src\core\src\main\java
—Struts的验证,不合法的提示。默认是validate()方法
——this.addActionError("age invalid");这是自定义的验证提示信息。
——this.addFieldError("age", "field error: age invalid");这是内部写。
——对于RegisterAction.java的验证,用:RegisterAction.properties命名。前面必须是action的的名。properties的内容是:name:invalid.fieldvalue.username;value:用户名不合法。会自动引用。
—对于action的自定义方法的验证
——在struts.xml 的 method="test"的时候,在action里只对test()方法验证的话,就用validateTest()方法。原来的validate()是对整个action验证,现在就只是对执行Test()方法的交互进行验证。
—Struts2的校验框架
——在需要校验的action包下新建:actionname-validation.xml,例如RegisterAction-validation.xml
——这是严格的dtd的xml格式。当然各校验的方法在xwork-2.1.2.jar>com.opemsymphony.xwork2.validator.validatos包下,写法类似于如下:
<validators >
     <field name="username">
         <field-validator type="requiredstring">
             <param name="trim">true</param>
             <message>username invalid</message>
         </field-validator>         
         <field-validator type="stringlength">
             <param name="minLength">6</param>
             <param name="maxLength">10</param>
             <message>username should be between ${minLength} and ${maxLength}</message>
         </field-validator>
     </field>
</validators>
行v——校验过程:1、首先执行类型转换;2、执行对应的校验框架;3、执行特定方法对应的validate验证(test,validateTest);4、执alidate()方法;5、如果在以上所有的过程中,发现了任何错误,都不会再去执行execute方法或指定的特定方法(test),页面转向了struts.xml中inpute这个result所对应的页面。
—全局的用户是否登陆校验。AuthInterceptor
——AuthInterceptor.java:
Map map = invocation.getInvocationContext().getSession();
if(null == map.get("user")){//用户没有登陆
    return Action.LOGIN;//返回到登陆界面
}else{
    return invocation.invoke();
}

——struts.xml
<global-results>
    <result name="login" type="redirect">/login.jsp</result>
    <result name="usernameinvalid">/usernameInvalid.jsp</result>
</global-results>

—全局的Exception
——见struts工程的代码。
—文件上传
——在JSP里注在定义form的时候,要有enctype="multipart/form-data"。这是定义了上传文件的编码,这是固定的。如果不定义或者其他的编码,就无法上传了。
——在UploadAction.java里面,首先定义File对象,这个对象名要和JSP里面的控件同名。然后要注意,如果要得到上传文件的名字,必须是:File名FileName的命名方式。
private File file;//对应真正上传的文件
private String fileFileName; //对应上传文件的名字
—对于连接数据库和数据查询处理的漂亮写法
public class UsersDB
{
private String resource = "users.properties";

private Properties props = null;

// 得到数据库连接
private Connection getConnection()
{
try
{
props = new Properties();
InputStream in = getClass().getResourceAsStream(resource);
props.load(in);

String drivers = props.getProperty("jdbc.drivers");
String url = props.getProperty("jdbc.url");
String username = props.getProperty("jdbc.username");
String password = props.getProperty("jdbc.password");

Class.forName(drivers);//加载数据库驱动
return DriverManager.getConnection(url, username, password);
}
catch (Exception ex)
{
ex.printStackTrace();
System.out.println("连接数据库异常发生 : " + ex.getMessage());
}
return null;

}

// 插入一笔记录
public void save(Users bean)
{
try
{
Connection con = this.getConnection();

String sql = "insert into users(username,password,truename,birthday,registerdate,sex,interest,remark) values(?,?,?,?,?,?,?,?)";
PreparedStatement ps = con.prepareStatement(sql);
ps.setString(1, bean.getUsername());
ps.setString(2, bean.getPassword());
ps.setString(3, bean.getTruename());
ps.setDate(4, bean.getBirthday());
ps.setDate(5, bean.getRegisterdate());
ps.setString(6, bean.getSex());
ps.setString(7, bean.getInterest());
ps.setString(8, bean.getRemark());

ps.executeUpdate(); //完成真正的数据库插入
con.close();

}
catch (Exception ex)
{
System.out.println("增加记录异常发生:" + ex.getMessage());

}
}

// 更新一笔记录
public void update(Users bean)
{
try
{
Connection con = this.getConnection();
String sql = "update users set password=?,truename=?,birthday=?,sex=?,interest=?,remark=? where id=?";
PreparedStatement ps = con.prepareStatement(sql);
ps.setString(1, bean.getPassword());
ps.setString(2, bean.getTruename());
ps.setDate(3, bean.getBirthday());
ps.setString(4, bean.getSex());
ps.setString(5, bean.getInterest());
ps.setString(6, bean.getRemark());
ps.setInt(7, bean.getId());

ps.executeUpdate();//真正完成数据的更新
con.close();
}
catch (Exception ex)
{
System.out.println("修改记录异常发生:" + ex.getMessage());
}
}

// 删除一笔记录
public void remove(int id)
{
try
{
Connection con = this.getConnection();
String sql = "delete from users where id=?";
PreparedStatement ps = con.prepareStatement(sql);
ps.setInt(1, id);

ps.executeUpdate(); //完成真正的删除
con.close();
}
catch (Exception ex)
{
System.out.println("删除记录异常发生:" + ex.getMessage());
}
}

// 查询一笔记录
public Users restore(int id)
{
Users bean = null;
try
{
Connection con = this.getConnection();
String sql = "select * from users where id=?";
PreparedStatement ps = con.prepareStatement(sql);
ps.setInt(1, id);

ResultSet rs = ps.executeQuery();
if (rs.next())
{
bean = new Users();
bean.setId(rs.getInt("id"));
bean.setUsername(rs.getString("username"));
bean.setPassword(rs.getString("password"));
bean.setTruename(rs.getString("truename"));
bean.setBirthday(rs.getDate("birthday"));
bean.setRegisterdate(rs.getDate("registerdate"));
bean.setSex(rs.getString("sex"));
bean.setInterest(rs.getString("interest"));
bean.setRemark(rs.getString("remark"));
}
con.close();
}
catch (Exception ex)
{
System.out.println("查询记录异常发生:" + ex.getMessage());
}
return bean;
}

// 查询所有记录
public ArrayList getAllUsers()
{
ArrayList arrayList = new ArrayList();
Users bean = null;
try
{
Connection con = this.getConnection();
String sql = "select * from users";
PreparedStatement ps = con.prepareStatement(sql);

ResultSet rs = ps.executeQuery();

while (rs.next())
{
bean = new Users();
bean.setId(rs.getInt("id"));
bean.setUsername(rs.getString("username"));
bean.setPassword(rs.getString("password"));
bean.setTruename(rs.getString("truename"));
bean.setBirthday(rs.getDate("birthday"));
bean.setRegisterdate(rs.getDate("registerdate"));
bean.setSex(rs.getString("sex"));
bean.setInterest(rs.getString("interest"));
bean.setRemark(rs.getString("remark"));

arrayList.add(bean);
}

con.close();
}
catch (Exception ex)
{
System.out.println("查询所有记录异常发生:" + ex.getMessage());
}
return arrayList;
}

}
—Hibernate部署的流程
1、在工程右键Myeclipse选项里有add Hibernate,要Copy checked Lib***,要把jar包复制到项目里。
2、配置hibernate.cfg.xml文件
<session-factory>
<property name="show_sql">true</property><!-- 如果为true会在控制台输出SQL语句 -->
<property name="connection.url">jdbc:mysql://localhost/myhibernate</property>
<property name="connection.username">root</property>
<property name="connection.password">tiger</property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<mapping resource="Person.hbm.xml"/><!--这是映射hbm.xml文件 -->
</session-factory>
3、建立数据表后,按照javaBean的规范建立一个类Person.java,必须有一个id属性(对象标识符),Hibernate要求持久化类必须提供一个不带参数的默认构造方法。
4、对Person.java文件创建Hibernate映射文件Person.hbm.xml,Java的实体类是通过配置文件与数据表中的字段相关联,Hibernate在运行时解析配置文件,根据其中的字段名生成相应的SQL语句,该文件放在src目录下。
5、Persion.hbm.xml的写法
<hibernate-mapping>
    <class name="com.hibernate.model.Person" table="person">
        <id name="id" column="id" type="int">
            <generator class="increment"><!-- 主键ID的生长方式为自增,generator主键生成器-->
            </generator>
        </id>
        <property name="username" column="username" type="string"></property>
        <property name="password" column="password" type="string"></property>
        <property name="age" column="age" type="integer"></property>
        <property name="registerdate" column="registerdate" type="date"></property>
    </class>
</hibernate-mapping>

—Hibernate对数据的操作
——Hibernate对数据库的交互
public static void save(Person person)
	{
		Session session = HibernateUtil.currentSession();
		Transaction tx = session.beginTransaction(); //开启事务
		try
		{
			session.save(person);
			tx.commit();
		}
		catch(Exception ex)
		{
			System.out.println("增加用户异常发生!");
			if(null != tx)
			{
				tx.rollback();
			}
		}
		finally
		{
			HibernateUtil.closeSession(session);
		}
		
	}
	/**
	 * 查询出所有用户
	 */
	@SuppressWarnings("unchecked")
	public static List<Person> listAll()
	{
		Session session = HibernateUtil.currentSession();
		Transaction tx = session.beginTransaction(); //开启事务
		List<Person> list = null;
		try
		{
			Query query = session.createQuery("from Person"); //hql语句,Hibernate查询语句	
			list = (List<Person>)query.list();
			
			tx.commit();
		}
		catch(Exception ex)
		{
			System.out.println("增加用户异常发生!");
			if(null != tx)
			{
				tx.rollback();
			}
		}
		finally
		{
			HibernateUtil.closeSession(session);
		}
		
		return list;
	}
——Hibernate在jsp里的标签和对数据的显示
  	<s:iterator value="#request.list" id="person">
  	<tr>
  	<td>
  	<s:a href="getPerson.action?id=%{#person.id}">
  	<s:property value="username" />
  	</s:a>
  	</td>
  	<td>
  	<s:property value="password"/>
  	</td>
  	<td>
  	<s:property value="registerdate"/>
  	</td>
  	<td>
  	<s:property value="age"/>
  	</td>
  	<td>
  	<s:a href="updatePPerson.action?id=%{#person.id}">
  	update
  	</s:a>
  	</td>
  	<td>
  	<s:a href="deletePerson.action?id=%{#person.id}" οnchange="return del();">
  	delete
  	</s:a>
  	</td>
  	</s:iterator>
上面这个功能其实是通过struts传过来的值!看下面这是在action里的做法。
List<Person> list = DBPerson.listAll();
HttpServletRequest request = ServletActionContext.getRequest();
request.setAttribute("list", list);
return SUCCESS;
—Hibernate数据一对多关系的写法
一个Customer对应多个Orders;在Customer.java中添加Set属性添加多个Order,在Order.java中添加Customer属性做外键
——Customer方面是这样写的:
Customer.java
package com.test;
import java.util.Set;
public class Customer 
{
	private Long id;
	private String name;
	private Set orders;
	
	public Customer(String name, Set orders)
	{
		this.name = name;
		this.orders = orders;
	}
	
	public Customer()
	{
	}
	
	public Customer(Set orders)
	{
		this.orders = orders;
	}

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Set getOrders() {
		return orders;
	}

	public void setOrders(Set orders) {
		this.orders = orders;
	}
}
重点是两个的hbm文件的写法。下面是Customer.hbm.xml。
<hibernate-mapping>
	<class name="com.test.Customer" table="customers">
		<id name="id" column="id" type="long">
			<generator class="increment"> <!-- 主键id的生成方式为自增 -->
			</generator>
		</id>
		<property name="name" type="string" not-null="true">
		    <column name="name" length="15"></column>
		</property>
		<!--
		name:设定待映射的持久化类的属性名,这里为Customer类的orders属性
		cascade:当取值为"save-update",表示级联保存和更新。
		inverse:当取值为"true",表示在双向关联中,这一端为镜像端。放弃了关联的权利,被更新
		<set>元素还包含两个子元素:<key>和<one-to-many>,
		<one-to-many>元素设定所关联的持久化类,此处为Order类,<key>元素
		设定与所关联的持久化类对应的表的外键,此处为orders表的customer_id字段
		inverse就是主要维持关系方 -->
		<set name="orders" cascade="save-update" inverse="true">
		    <key column="customer_id"></key><!-- key元素设定与所关联的持久化类对应的表单外键 -->
		    <one-to-many class="com.test.Order"/>
		</set>
	</class>
</hibernate-mapping>
注意set的写法。name是Customer.java的属性名。key是与Customer相关联的数据表Orders的外键!!
cascade是控制各个关系是如何更新数据库的:


——Order方面是这样写的
Order.java
package com.test;
import java.util.Set;
public class Order {
	private Long id;
	private String orderNumber;
	private Customer customer;//多对一,通过该变量可以引用到对应的Customer
	
	public Order(String orderNumber, Customer customer)
	{
		this.orderNumber = orderNumber;
		this.customer = customer;
	}
	
	public Order(){
	}

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public String getOrderNumber() {
		return orderNumber;
	}

	public void setOrderNumber(String orderNumber) {
		this.orderNumber = orderNumber;
	}

	public Customer getCustomer() {
		return customer;
	}

	public void setCustomer(Customer customer) {
		this.customer = customer;
	}
}
下面是Order.hbm.xml
<hibernate-mapping>
	<class name="com.test.Order" table="orders">
		<id name="id" column="id" type="long">
			<generator class="increment"> <!-- 主键id的生成方式为自增 -->
			</generator>
		</id>
		<property name="orderNumber" type="string" not-null="true">
		    <column name="order_number" length="15"></column>
		</property>
		<!-- name都是指关系的类里的那个属性名!而column则是指数据表的外键!而class设定持久化类的属性的类型 -->
		<many-to-one name="customer" column="customer_id" class="com.test.Customer">
		</many-to-one>
	</class>
</hibernate-mapping>
注意这里的<many-to-one>
——一对多的关系这样添加
这种关系,在调用添加的时候是这样写的
		Session session = sessionFactory.openSession();
		Transaction tx = null;
			tx = session.beginTransaction();
			
			Customer customer = new Customer("zhangsi", new HashSet());
			Order order1 = new Order();
			order1.setOrderNumber("zhangsi_order1");
			order1.setCustomer(customer);
			customer.getOrders().add(order1);
			
			Order order2 = new Order();
			order2.setOrderNumber("zhangsi_order2");
			order2.setCustomer(customer);
			customer.getOrders().add(order2);
			
			session.save(customer);
			tx.commit();
将Order放到一个Set里,就是这样。Hibernate自动将Set里的值写到Orders表中,而且Orders表里的外键customer_id的值也自动附上customers的id。

—Hibernate数据自身树形关系的写法
例子是:食物(水果、蔬菜),水果(苹果、橘子),蔬菜(西红柿)
			tx = session.beginTransaction();
			//食品类别
			Category foodCategory = new Category("food", null, new HashSet());
			
			//水果类别
			Category fruitCategory = new Category("fruit", null, new HashSet());
			
			//蔬菜类别
			Category vegetableCategory = new Category("vegetable", null, new HashSet());
			
			//苹果类别
			Category appleCategory = new Category("apple", null, new HashSet());
			
			//橘子类别
			Category orangeCategory = new Category("orange", null, new HashSet());
			
			//西红柿类别
			Category tomatoCategory = new Category("tomato", null, new HashSet());

			foodCategory.getChildCategories().add(fruitCategory);
			fruitCategory.setParentCategory(foodCategory);
			
			foodCategory.getChildCategories().add(vegetableCategory);
			vegetableCategory.setParentCategory(foodCategory);
			
			fruitCategory.getChildCategories().add(appleCategory);
			appleCategory.setParentCategory(fruitCategory);
			
			fruitCategory.getChildCategories().add(appleCategory);
			orangeCategory.setParentCategory(fruitCategory);
			
			vegetableCategory.getChildCategories().add(tomatoCategory);
			tomatoCategory.setParentCategory(vegetableCategory);

			session.save(foodCategory);//级联保存所有的关联对象
Category.hbm.xml这样写
<hibernate-mapping>
	<class name="com.test.Category" table="categories">
		<id name="id" column="id" type="long">
			<generator class="increment"> <!-- 主键id的生成方式为自增 -->
			</generator>
		</id>
		<property name="name">
		    <column name="name" length="15"></column>
		</property>
		<set name="childCategories" cascade="all" inverse="true">
		    <key column="category_id"></key>
		    <one-to-many class="com.test.Category"/>
		</set>
		<many-to-one name="parentCategory" column="category_id" class="com.test.Category">
		</many-to-one>
	</class>
</hibernate-mapping>

—Hibernate数据一对一关系的写法
这种一对一关系类似于:人和身份证的关系
——第一种方法:是将 Certificate的id与Student的id关联起来,在hbm的文件中能体现Certificate的id根据Student的id生成的。
Student.java的属性有:
	private String id; // 标识id
	private String cardId; // 学号
	private String name; // 学生姓名
	private int age; // 岁数	
	private Certificate cer;// 身分证	
	private Team team;// 班级
Strudent.hbm.xml
<hibernate-mapping>
	<class name="model.Student" table="student" lazy="true"><!--把类和数表关联起来-->
		<id name="id" unsaved-value="null"><!--id的产生方式是uuid.hex-->
			<generator class="uuid.hex" />
		</id>
		<property name="cardId" type="string" /><!--映射号-->
		<property name="name" type="string" /><!--映射学生名-->
		<property name="age" type="int" /><!--映射学生岁数-->
		<one-to-one name="cer" class="model.Certificate"  fetch="join" cascade="all"  /><!--映射对应的身分证对象-->
	</class>
</hibernate-mapping> 
Certificate.java的属性有:
	private String id;	
	private String describe;	
	private Student stu;
Certificate.hbm.xml;注意下面的id是怎么写的。他这个意思是根据Certificate.java里的stu的外键的Student.java的id来定主键。
<hibernate-mapping>
	<class name="model.Certificate" table="certificate" lazy="true">
		<id name="id">
			<generator class="foreign">
				<param name="property">stu</param>
			</generator>
		</id>
		<property name="describe" column="`describe`" type="string" /> 
		<one-to-one name="stu" class="model.Student" fetch="select"
			constrained="true" cascade="none"/><!-- 因为是人来决定的,所以身份证这里是none -->
	</class>
</hibernate-mapping>
在写添加的时候只用写cascade="true"的那位:
		//设定学生与身份证之间的关联关系
		stu.setCer(cer);
		cer.setStu(stu);
		StudentDAO.saveObj(stu);
——第二种方法:将多对一的方法特殊化,在Certifica.java中添加一个stu_id的属性作为外键进行关联。
改的东西不多,重点就是Certificate.hbm.xml的id修改
<hibernate-mapping>
	<class name="model.Certificate" table="certificate" lazy="true">		
		<id name="id">
			<generator class="uuid.hex" />
		</id>		
		<property name="describe" column="`describe`" type="string" />		
		<many-to-one name="stu" 
			class="model.Student"  
			unique="true" 
			column="stu_id"
			/><!-- 唯一的多对一,实际也就变成一对一关系了 -->		
	</class>
</hibernate-mapping>

—Hibernate数据多对多关系的写法
这个多对多关系例子:学生和选课;这里必须就要建立三个表了:student,course,student_course。同理在bean里面,Student.java和Course.java里面有对方的set。
——Student的写法
Student.java
	private String id; // 标识id
	private String cardId; // 学号
	private String name; // 学生姓名
	private int age; // 岁数
	private Set Courses;// 课程
Student.hbm.xml;注意set里的写法。这里关联的table是中间的那个student_course表
<hibernate-mapping>
	<class name="model.Student" table="student" 
		select-before-update="true"><!--把类和数表关联起来-->
		<id name="id" unsaved-value="null"><!--id的产生方式是uuid.hex-->
			<generator class="uuid.hex" />
		</id>
		<property name="cardId" type="string" /><!--映射号-->
		<property name="name" type="string" /><!--映射学生名-->
		<property name="age" type="int" /><!--映射学生岁数-->
		<set name="courses" table="student_course"
			cascade="none" inverse="true">
			<!-- 这里的inverse必须有一个是none不然,如果都关联就会重复数据了
				这里cascade设置成none是因为,多对多的时候不一定一个删除了另外一个就删除,所以不关联。
				 -->
			<key column="stu_id" />
			<many-to-many class="model.Course"
				column="course_id" />
		</set>
	</class>
</hibernate-mapping>
——student_course的写法
student_course这个表在项目里没有表现,只是数据库中有。他的用法是通过hbm的文件比如上面<set name="courses" table="student_course"的方使用。
——Course的写法
	private String id;
	private String name;
	private Set Students = new HashSet();
Course.hbm.xml的写法;因为是与Student对student_course表关联,所以写法差不多。只是注意inverse和cascade的写法。
<hibernate-mapping>
	<class name="model.Course" table="course" 
		select-before-update="true"><!--把类和数表关联起来-->
		<id name="id" unsaved-value="null" ><!--id的产生方式是uuid.hex-->
			<generator class="uuid.hex" />
		</id>
		<property name="name" type="string" /><!--映射课程名-->
		<set name="students" table="student_course"
			cascade="save-update">
			<key column="course_id" />
			<many-to-many class="model.Student"
				column="stu_id" />
		</set>
	</class>
</hibernate-mapping>
——添加方式
			stu = (Student) session.createQuery(
					"from Student s where s.name ='tomclus'").uniqueResult();
			course = (Course) session.createQuery(
					"from Course c where c.name='ecnomic'").uniqueResult();
			stu.getCourses().add(course);
			course.getStudents().add(stu);

—域对象在持久化层的三种状态
Session的缓存的作用;Session清理缓存的时间点;对象的临时状态、持久化状态和有力状态;用Session的update()方法使游离对象状变为持久化对象
——理解Session的缓存

注意理解各缓存的生命周期

—Hibernate的检索策略
这是因为特别是一对多的关系检索时,经常检索一同时会自动检索出多,这样严重影响效率和速度。所以一般通过延迟检索策略或者强迫左外连接检索策略
——延迟检索策略,重点是lazy,当true则是,检索只是检索一,当在事务提交前用到了多,就会提交时检索一和多。
<set name="orders" inverse="true" lazy="true">
——强迫外连接检索
把hbm文件的<many-to-one>元素的outer-join属性设为true,就总是使用迫切左外连接检索策略。
左外连接的SQL语句:
select * from ORDERS left outer join CUSTOMERS on ORDERS.CUSTOMER_ID=CUSTOMERS.ID where ORDERS.ID=1
或者用HQL语句:session.find("from Customer as c left join fetch c.orders");

—Hibernate的分页查询
setFirstResult(int firstResult):设定从哪个对象开始检索,firstResult表示查询的其实位置,初试值为0。
setMaxResult(int maxResults)L设定一次最多检索出的对象数目,默认检索出所有的对象。

—Spring的两个最重要的设计模式
——IOC(Inverse of Control)控制反转 = DI(Dependency Injection)依赖注入
——AOP(Aspect-oriented Programming)
主要讲解的还是传说中的工厂模式。只是将工厂模式的筛选用xml来反映了。

—Spring的部署流程
——在程序的右键MyEclipse的add Spring。。。如果只是单纯的Spring项目就只要选:Spring 3.0 Core Libraries;如果是与Hibernate整合,那就要把:Spring 3.0 Persistence Core Libraries选上,这时候就会自动把AOP Libraries选上。是因为Spring就是通过AOP的功能解析Hibernate的。如果是Spring与struts整合的话,还要添加Spring 3.0 Web Libraries这个包。
——如果是WEB项目,一定要记得Copy cheched Library contents to project folder,把jar包拷贝到项目下。这样项目就算拷贝到其他地方,也都可以运行,不会有缺少jar包的问题。
——不要选择Enable AOP Builder
——在Spring与struts整合的时候,在web.xml里一定要记得添加Spring的监听:
	<listener>
	    <listener-class>
	        org.springframework.web.context.ContextLoaderListener
	    </listener-class>
	</listener>
——在Spring与Hibernate整合的时候,Spring是可以代替Hibernate的配置文件的。

—Spring的程序写法
主要思想就是,实例都要继承其总类别的接口。比如:Person.java接口和Chinese.java的实例;Axe.java的接口SteelAxe.java,StoneAxe.java的实例。然后中国人用钢斧和石斧。。。
Person.java
public interface Person
{
	public void useAxe();
}
Chinese.java
public class Chinese implements Person
{
	private Axe axe;
	public Chinese()
	{
	}
	public void setAxe(Axe axe)
	{
		this.axe = axe;
	}
	public void useAxe()
	{
		System.out.println(axe.chop());
	}
}
同理Axe.java接口和实现这个接口的 SteelAxe.java,StoneAxe.java;工厂模式的桥梁就是applicationContext.xml
<bean id="chinese" class="com.test.Chinese">
		<property name="axe">
			<ref local="stoneAxe"/>
		</property>
	</bean>
	<bean id="stoneAxe" class="com.test.StoneAxe"></bean>
	<bean id="steelAxe" class="com.test.SteelAxe"></bean>
最后运行的主函数是:
ApplicationContext ctx = new FileSystemXmlApplicationContext(
				"applicationContext.xml");

		Person p = (Person) ctx.getBean("chinese");

		p.useAxe();
注意:这里的p其实就是一个Chinese.java的对象,但是这里并没有看到new Chinese()。这其实那个getBean("chinese")就是对应applicationContext.xml里的id="chinese"然后根据class找到Chinese类。注意在<property name="">的属性中,可以自动提示的,自动对应的Chinese类里的属性axe,然后直接ref赋值,本例子中赋的是下面bean里的stoneAxe
—Spring添加最后自动执行的方法
——初始化后自动执行的方法
	<bean id="chinese" class="lee.Chinese" init-method="init2">
		<property name="axe">
			<ref local="steelAxe"/>
		</property>
	</bean>
注意那个init-method的属性,就是在完成初始化后,自动执行这个方法——init2(),当然这个方法名是自定义的。在Chinese类里有这个方法。
——整个类用完后自动执行的调用的方法
与上面的一样只是属性改为:destroy-method="close3",这样就每次这个对象都执行完之后,会自动调用close3()的方法。
—Spring反应的Java的反射机制
这个反射就是,通过类名反射出他的属性和方法,而且可以这样动态赋值或者更改方法。在上面的 applicationContext.xml里的<property name="axe"><ref local="stoneAxe"/></property>其实就用了反射机制,查询到有axe的属性,然后自动调用set的方法,把stoneAxe设置进去。这个反射的底层实现可能是这样的:
		//获得对象的类型
		Class classType = object.getClass();
		System.out.println("Class:" + classType.getName());
		
		// 通过默认构造方法创建一个新的对象
		Object objectCopy = classType.getConstructor(new Class[] {})
				.newInstance(new Object[] {});
		//Object o = new Customer();
		// 获得对象的所有属性
		Field fields[] = classType.getDeclaredFields();
		for (int i = 0; i < fields.length; i++)
		{
			Field field = fields[i];
			String fieldName = field.getName();//获得属性的名字,比如:axe
			String firstLetter = fieldName.substring(0, 1).toUpperCase();//获得第一个字符,并且大写:A
			// 获得和属性对应的getXXX()方法的名字
			String getMethodName = "get" + firstLetter + fieldName.substring(1);//这里就是:get + A + xe 
			// 获得和属性对应的setXXX()方法的名字
			String setMethodName = "set" + firstLetter + fieldName.substring(1);
			// 获得和属性对应的getXXX()方法
			Method getMethod = classType.getMethod(getMethodName,
					new Class[] {});//这里getMethodName就是刚才的获得的get名字,这里就获得get方法的对象。
			// 获得和属性对应的setXXX()方法
			Method setMethod = classType.getMethod(setMethodName,
					new Class[] { field.getType() });
			// 调用原对象的getXXX()方法,这种调用方式好奇怪!
			Object value = getMethod.invoke(object, new Object[] {});
			System.out.println(fieldName + ":" + value);
			// 调用拷贝对象的setXXX()方法
			setMethod.invoke(objectCopy, new Object[] { value });
		}
		return objectCopy;
—applicationContext.xml里bean的一个重要配置scope
	<bean id="loginService" class="com.test.service.impl.LoginServiceImpl" scope="singleton"></bean>
	<bean id="loginAction" class="com.test.action.LoginAction" scope="prototype">
		<property name="loginService" ref="loginService"></property>
	</bean>
对于Spring的配置文件的bean元素,其scope属性有如下几种值。
1、singleton,单例,只有一个实例
2、prototype,表示每次从容器中取出bean时,都会生成一个新实例,相当于new出来一个对象。
3、request,该属性是基于web的,表示每次接受一个请求时都会生成一个新实例。
4、session,表示在每个Session中该对象只有一个
对于action来说,一定要将其scope配制成prototype或者request不然就直接影响正确性。

—单例模式的小例子
就是有时候对于服务端而言,有的对象是同一个,是固定的。而不是根据时间和请求不同而产出不同的对象。写法很多种,下面是推荐写法:
Singleton.java这是固定的类。
public class Singleton 
{
	private static Singleton singleton = new Singleton();
	public static Singleton getInstance()
	{
		return singleton;
	}
	private Singleton()
	{
		//这样就不能new出来了
	}
}
调用方式如下,输出的结果是true,这就是个简单的单例模式。
public static void main(String args[])
	{
		Singleton singleton1 = Singleton.getInstance();
		Singleton singleton2 = Singleton.getInstance();
		System.out.println(singleton1 == singleton2);
	}

—Spring与Struts整合例子
文件布局如下:当然不仅要放入struts需要的jar包,而且需要导入struts包里的struts2-spring-plugin-2.1.6.jar;然后还要添加Spring的各驱动包
——applicationContext.xml里面的内容,这是配置索要连接的action,这里的id是在struts.xml里面的action,在这里调用。连接到class里的真正action里。并且可以为action里的属性进行赋值。
	<bean id="loginService" class="com.test.service.impl.LoginServiceImpl" scope="singleton"></bean>
	<bean id="loginAction" class="com.test.action.LoginAction" scope="prototype">
		<property name="loginService" ref="loginService"></property>
	</bean>
——struts.xml;这里的action的class就是Spring里applicationContext.xml的bean的id
    <struts>
    	<package name="strutsspring" extends="struts-default">
    	    <action name="login" class="loginAction">
    	        <result name="success">/success.jsp</result>
    	        <result name="error">/error.jsp</result>
    	    </action>
    	</package>
    </struts>
——两个框架的的调用过程
1、由jsp页面的action="login"传到struts.xml里面的<action name="login" class="loginAction">,然后根据class传到acpplicationContext.xml里的bean下,根据这里的class进入com.test.action.LoginAction下。注意这里的写法: LoginAction.java
public class LoginAction extends ActionSupport {
	private String username;
	private String password;
	private LoginService loginService;

	public LoginService getLoginService() {
		return loginService;
	}
	public void setLoginService(LoginService loginService) {
		this.loginService = loginService;
	}
	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 {
		//action里面永远不要写业务逻辑,一般都是验证逻辑
		if(loginService.isLogin(username, password))
		{
			return SUCCESS;
		}
		else
		{
			return ERROR;
		}
	}
}
注意上面的黑体中loginService的赋值,这是通过Spring赋值的,通过ref="loginService"然后又<bean id="loginService" class="com.test.service.impl.LoginServiceImpl" scope="singleton"></bean>;然而在action里的loginService只是一个LoginService 接口。但是其实是在Spring的xml文件里赋了LoginServiceImpl的真实对象。这就是需要思考的地方。

—静态代理模式(对SpringAOP的学习重要)
——代理模式的作用是:为其他对象提供一种代理,以控制对这个对象的访问。在某些情况下一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
1、抽象角色:声明真实对象和代理对象的共同接口
2、代理角色:代理对象角色内部含有对真实对象的引用,提供与真实对象相同的接口,以便任何时刻能代替真实对象。封装真实对象。
3、真实角色:最终引用的对象。
——实现:就是房东,代理,和买房者的例子。
1、首先是他们的抽象类及抽象角色 Subject.java。这里主要定义的是相同接口reqeust();
public abstract class Subject 
{
	public abstract void request();
}
2、然后是真实的房东和代理都继承Subject
房东:RealSubject.java
public class RealSubject extends Subject {
	public void request() 
	{
		System.out.println("from real subject");
	}
}
3、代理:ProxySubject.java;如下这个代理不仅有request()方法,而且把perRequest()和postRequest()方法添加进去,做了其他的处理。
public class ProxySubject extends Subject {
	private RealSubject realSubject;
	public void request() 
	{
		this.preRequest();
		if(null == realSubject)
		{
			realSubject = new RealSubject();
		}
		realSubject.request();
		this.postRequest();
	}
	private void preRequest()
	{
		System.out.println("pre request");
	}
	public void postRequest()
	{
		System.out.println("post request");
	}
}
4、客户的调用Client.java
	public static void main(String args[])
	{
		Subject subject = new ProxySubject();
		subject.request();
	}
5、反思这种代理模式
如果要按照这种代理模式,真实角色必须是实现已经存在的,并作为代理对象的内部属性。但是实际使用时,一个真实角色必须对应一个代理角色,如果大量使用会导致类的几句膨胀;此外如果实现并不知道真实角色,该如何使用代理呢,这就要通过Java的动态代理类来解决。

—动态代理模式(是SpringAOP的底层实现了)
——动态代理的步骤
1、创建一个实现接口InvocationHandler的类,他必须实现invoke方法:ProxySubject.java
public class ProxySubject implements InvocationHandler 
{
	private Object object;
	public ProxySubject(Object object)
	{
		this.object = object;
	}
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable 
	{
		System.out.println("pre processing");
		method.invoke(object, args);
		System.out.println("post processing");
		return null;
	}
}
2、创建被代理的类以及接口和实现类:Subject.java、RealSubject.java
Subject.java
public interface Subject 
{
	public void request();
}
RealSubject.java
public class RealSubject implements Subject {
	public void request() {
		System.out.println("From real subject");
	}
}
3、通过Proxy的静态方法:newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h);创建一个代理。
	public static void main(String args[])
	{
		RealSubject subject = new RealSubject();
		InvocationHandler ih = new ProxySubject(subject);
		Class<?> clazz = subject.getClass();
		Subject s = (Subject)Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), ih);
		s.request();
	}
4、通过代理调用方法
这个理解挺麻烦的,s是Proxy静态类的动态添加subject.getClass()。这个ih是ProxySubject(subject)的实例。等等~~

—SSH三个框架配置和部署
——首先配置struts
1、7个jar文件拷贝到lib目录下。
2、在web.xml下写struts的<filter>的配置程序,这样就支持了struts2;而且还要添加Spring的监听器!
	<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>
	<listener>
	    <listener-class>
	        org.springframework.web.context.ContextLoaderListener
	    </listener-class>
	</listener>
3、编写struts.xml的内容
<struts>
    	<package name="ssh2" extends="struts-default">
    	</package>
    </struts>
4、拷贝struts官方文件夹下的lib目录下的struts2-spring-plugin**.jar包,以保证支持整合Spring
——增加Hibernate
1、右击添加Hibernate,勾选把jar包拷贝到lib目录下。这样就有了Hibernate的能力
——添加Spring
1、依然右击添加Spring。这时候选添加的jar包:见上面的web方面Spring的jar包添加法:4个jar包。而且也要注意把jar包勾选到lib目录下。还有那个配置文件,不要放到src目录下,默认会在WEB-INF目录下,所以改成这个目录下。
——数据库方面的支持
要把数据库的驱动包:mysql-connector-java**.jar和commons-dbcp.jar;commons-pool.jar三个jar包一同拷贝到lib目录下。
——下面是真个程序的架构,其中细节和代码请到项目里查看!!



































  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值