一、JSP与Servlet
1、 基础语法
1.1声明 <%! int i = 0; %>
1.2表达式 <%= i %>
1.3脚本段 <% sth %>
1.4 Page指令用于定义JSP文件中的全局属性 <%@page [language=”java”][import=””]%>
1.5 include指令用于在JSP中包含一个静态文件,同时解析这个JSP文件中的JSP语句。<[email protected] include file=”test.jsp: %> 文件名一般是相对路径
1.6 Taglib定义一个标签库以及其自定义标签的前缀
<%@ taglib uri=”http://www.baidu.com” prefix=”public %>
<public:loop>
<% %>
</public:loop>
1.7 八个动作指令
页面跳转<jsp:forward> <jsp:forward page=”test.jsp”><jsp:paramname=”test” value=”test”/></ jsp:forward>
包含页面<jsp:include>包含一个静态或动态文件 <jsp:include page=”test.jsp” flush=”true”/> 可有param,flush必须是true
创建Bean<jsp:useBean>,创建一个Bean实例并指定它的名字和作用范围
<jsp:useBean id=”test” scope=”application”/*page|request|session|application*/class=”session.Test” />
设置Bean属性jsp:setProperty <jsp:setProperty name=”test” property=”*”/> property可以是 <… property=”username”/>、<…property=”username”
value=”Alex”/>
获得Bean属性<jsp:getProperty>,可获取属性值
使用Applet插件<jsp:plugin>,用于在浏览器中播放或显示一个对象,而这种显示需要浏览器中的Java插件
<jsp:plugin type=applet code=”MediaPlay.class”codebase=”../classes”>
<jsp:params><..></jsp:params>
<jsp:fallback><p>Unable to loadapplet</p></jsp:fallback>
</jsp:plugin>
插件定义参数<jsp:param>
插件错误提示<jsp:fallback>
1.8内置对象
Request 请求对象
Response 响应对象
Session 会话对象
Application应用程序对象
Out 输出对象
Config 配置对象
Page 页面对象
PageContext 页面上下文对象
Exception 例外对象
1.9 JDBC访问数据库
Connection conn = DriverManager.getConnection(“jdbc:mysql:datasource”,“usr” “pwd”);
Statement stmt = conn.creatStatement();
ResultSet rs = stmt.executeQuery(“SELECT aFROM table1”);
While (rs.next()) …
用完及时关闭
2、 创建JSP页面
1.1第一行是JSP固定设置语句
1.2通过request对象取得当前上下文路径的Path,并通过request对象取得协议、主机名、端口,将这四个变量组合起来形成一个URL的路径。
1.3设置HTML的head信息,将取得的URL路径设置到<base>标签中,这样当前页面就拥有了访问路径的属性。
<%@ pagelanguage=”java” import=”java.util.*” pageEncoding=”UTF-8” %>
<%
String path =request.getContextPath();
String basePath=request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTMLPUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<basehref="<%=basePath%>">
<title>My JSP ‘login.jsp‘ startingpage</title>
<meta …/>
<!--
<linkrel="stylesheet" type="text/css"href="styles.css">
-->
</head>
<body>
</body>
</html>
3、mysql语句大全
创建数据库 CREATE DATABASE test
删除数据库 DROP DATABASE test
进入数据库 USE TEST
创建新表 create table table1(col1 type1[not null][primary key],col2 type2 [not null]);
插入 insert into table1(f1,f2) values(value1,value2);
4、JavaBean
4.1使用DBAccess和UserBean来处理数据库
public
class DBAccess {
private String
drv = "com.mysql.jdbc.Driver";
private String
url = "jdbc:mysql://localhost:3306/test";
private String
usr = "root";
private String
pwd = "12345";
//数据连接对象
private Connection
conn = null;
//数据库声明对象
private Statement
stm = null;
//数据库结果集对象
private ResultSet
rs = null;
public
boolean createConn() {
boolean b =
false;
try {
Class.forName(drv).newInstance();
conn =DriverManager.getConnection(url,
usr, pwd);
b = true;
} catch(SQLException e) {
} catch(InstantiationException e) {
} catch(IllegalAccessException e) {
} catch(ClassNotFoundException e) {
}
return b;
}
public
boolean update(String sql) {
boolean b =
false;
try {
stm = conn.createStatement();
stm.execute(sql);
b = true;
} catch(Exception e) {
}
return b;
}
public
void query(String sql) {
try {
stm = conn.createStatement();
rs = stm.executeQuery(sql);
} catch(Exception e) {
}
}
/*移动操作*/
public
boolean next() {
boolean b =
false;
try {
if (rs.next())b =
true;
} catch(Exceptione) {
}
return b;
}
/*移动到目标行后取值*/
public String getValue(String field) {
String value = null;
try {
if (rs !=
null) value =
rs.getString(field);
} catch(Exception e) {
}
return value;
}
public
void closeRs() {
try {
if (rs !=
null) {
rs.close();
}
} catch(SQLException e) {
e.printStackTrace();
}
}
public
void closeStm() {
try {
if (stm !=
null) {
stm.close();
}
} catch(SQLException e) {
e.printStackTrace();
}
}
public
void closeConn() {
try {
if (conn !=
null) {
conn.close();
}
} catch(SQLException e) {
e.printStackTrace();
}
}
(set,get…)
}
4.2开发javabean业务逻辑组件UserBean
public
class UserBean {
public
boolean isValid(String username, String password) {
boolean isValid =false;
DBAccess db = newDBAccess();
if(db.createConn()) {
String sql =
"select * from user whereusername=‘" + username +
"‘ and password=‘" + password + "‘";
db.query(sql);
if(db.next()){
isValid =
true;
}
db.closeConn();
db.closeRs();
db.closeStm();
}
return isValid;
}
public
boolean isExist(String username) {
boolean isExist =false;
DBAccess db = newDBAccess();
if(db.createConn()) {
String sql =
"select * from user whereusername=‘" + username +
"‘";
db.query(sql);
if(db.next()) {
isExist =
true;
}
db.closeConn();
db.closeRs();
db.closeStm();
}
return isExist;
}
public
void add(String username, String password) {
DBAccess db = newDBAccess();
if(db.createConn()) {
String sql =
"insert into user(username,password)values (‘" + username +
"‘,‘" + password + "‘)";
db.update(sql);
db.closeConn();
db.closeRs();
db.closeStm();
}
}
}
5、Servlet
action=”login.action.jsp” 可替换为 acton=”UserServlet.do?method=login”
二、Hibernate
6、关于Hibernate
配置文件,在src下添加hibernate.cfg.xml
<?xml
version="1.0"encoding="UTF-8"?>
<!DOCTYPE
hibernate-configuration
PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property
name="myeclipse.connection.profile">JDBC for MySQL</property>
<property
name="connection.url">jdbc:mysql://localhost:3306/demo</property>
<property
name="connection.username">root</property>
<property
name="connection.password">12345</property>
<property
name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property
name="dialect">org.hibernate.dialect.MySQLDialect</property>
<mapping
resource="com/demo/hibernate/beans/User.hbm.xml"/>
</session-factory>
</hibernate-configuration>
映射文件,负责持久化类与数据库表之间的映射,其根元素为hibernate-mapping,并通过属性package指定类所在的包。每一个表使用一个class定义,name属性表表示;类的名称,table表示关联的表名,通过property子元素来映射类的变量名与数据库表字段名之间的映射关系。
1.根元素<hibernate-mapping>
schema和catalog属性,指明了这个映射所连接的表所在的shema和/或catalog名称。
auto-import属性默认让我们在查询语言中可以使用非全限定名的类名。假设有两个持久化类,它们的非全限定名一样(类名一样,在不同包里),则应该设置auto-import=false,否则会抛出异常。
2.<class>定义类,用于定义一个持久化类与数据表的映射关系
mutable=”false”,则不可以被应用程序更新或删除
3.<id>定义主键,Hibernate使用对象标识符来标识对象的唯一性
若是联合主键
<composite-id>
<key-propertyname=”username”/>
<key-propertyname=”password” />
</composite-id>
4.<generator>设置主键生成方式,可用<param>传参。通过一个class属性指定生成器对应的类
assigned-主键由外部程序负责生成
hilo-使用hi/lo高/低位算法高效地生成long、short、int类型的标识符
seqhilo-与hilo类似,只是主键历史状态保存在Sequence中,适用于如Oracle
increment-标识主键按数值顺序递增。同一数据库有多个实例访问时,此方法必须避免使用。
identity-采用数据库提供的主键生成机制
sequence-采用数据库提供的sequence机制生成主键
native-根据底层数据库自行判断采用identity、hilo、sequence中的一种
uuid.hex、uuid.string、foregin
select-通过数据库触发器选择一些唯一主键的行为并返回主键值来分配一个主键
5.<property>定义属性
6.<one-to-one>配置一对一映射
<one-to-one name=”person” class=”Person”/>
<one-to-one name=”employee” class=”Employee”constrained=”true” />
必须确保PERSON和EMPLOYEE中相关的字段是相等的
<class name="person"table="Person">
<id name="id"column="ID" type="integer">
<generatorclass="native" />
</id>
。。。
<one-to-onename=”employee” class=”Employee” constrained=”true” />
</class>
6.<many-to-one>配置多对一映射,定义一种与另一个持久化类的关联
这个表的一个外键引用目标表的主键字段
<many-to-one name=”id” colum=”ID” unique=”true”/>
在com.demo.hibernate.beans包添加User.hbm.xml
<?xml
version="1.0"encoding="UTF-8"?>
<!DOCTYPE
hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping
package="com.demo.hibernate.beans">
<class
name="User"
table="user">
<id
name="id"column="ID"
type="integer">
<generator
class="native"/>
</id>
<property
name="username"column="username"
type="string"/>
<property
name="password"column="password"
type="string"/>
</class>
</hibernate-mapping>
编写持久化类User.java,一张数据库表对应一个持久化类,通过getter和setter方法访问属性。
package com.demo.hibernate.beans;
public
class User {
private java.lang.Integer
id;
private java.lang.String
username;
private java.lang.String
password;
(get,set…)
}
辅助类HibernateSessionFactory.javaHibernate的Session,是一个持久化管理器,通过它从数据库中存取User。
首先从sessioinFactory中获取一个Session
这个类不但在它的静态初始器中使用了SessionFactory,还使用了一个ThreadLocal变量来保存Session作为当前工作线程。ThreadLocal?
packagecom.demo.hibernate.util;
importorg.hibernate.*;
importorg.hibernate.cfg.Configuration;
public classHibernateSessionFactory {
private static StringCONFIG_FILE_LOCALTION ="/hibernate.cfg.xml";
private static final ThreadLocalthreadLocal = new ThreadLocal();
private static final Configurationcfg = new Configuration();
private static org.hibernate.SessionFactorysessionFactory;
//取得session
public static SessioncurrentSession() throws HibernateException {
Session session =(Session) threadLocal.get();
if (session == null){
if(sessionFactory == null) {
try{
cfg.configure(CONFIG_FILE_LOCALTION);
sessionFactory= cfg.buildSessionFactory();
}catch (Exception e) {
System.err.println("%%%%Erro Create SessionFactory %%%%");
e.printStackTrace();
}
}
session= sessionFactory.openSession();
threadLocal.set(session);
}
return session;
}
//关闭session对象
public static void closeSession()throws HibernateException {
Session session =(Session)threadLocal.get();
threadLocal.set(null);
if (session != null){
session.close();
}
}
}
DAO(数据访问接口)类,DAO层只负责调用Hibernate API实现CRUD操作,Service层面向用户负责调用DAO层的代码。
以下实现一个getUser()函数,根据用户名查询一个对象,通过session执行事务、创建查询对象、返回查询的数据对象。操作session的代码都是Hibernate提供的API。
packagecom.demo.hibernate.dao;
import ..;
public classUserDAO {
public User getUser(Stringusername) throws HibernateException {
Session session =null;
Transaction tx =null;
User user = null;
try {
session= HibernateSessionFactory.currentSession();
tx =session.beginTransaction();
Queryquery = session.createQuery("from User where username=?");
query.setString(0,username.trim());
user =(User) query.uniqueResult();
query= null;
tx.commit();
} catch(HibernateException e) {
throwe;
} finally {
if (tx!= null) {
tx.rollback();
}
HibernateSessionFactory.closeSession();
}
return user;
}
}
Service类,Service层即服务层,也就是面向用户服务,定义的方法都是与实际的业务相关的,可调用DAO层。
以下有一个函数valid(),根据用户名和密码来判断用户是否存在。然后编写一个main()入口函数,调用valid()函数执行业务的调用。
package com.demo.hibernate.service;
public
class UserService {
public
boolean valid(String username, String password) {
UserDAO test = new UserDAO();
User user = test.getUser("root");
if (user.getPassword().equals(password)) {
return
true;
} else {
return
false;
}
}
public
static void main(String[] args) {
UserService service = new UserService();
boolean login = service.valid("root",
"12345");
System.out.print("验证结果为:" + login);
}
}
7、Hibernate接口
1.Configuration装载配置
Configuration实例是一个启动期间的对象,一旦SessionFactory创建完成它就被丢弃了。
1.1为Configuration指定映射文件
直接实例化Configuration来获取一个实例,并为它指定XML映射定义文件。如果映射定义文件在类路径(classpath)中,则使用addResource()
Configuration cfg = new Configuration().addResource(“com/demo/hibernate/beans/User.hbm.xml”);
1.2为Configuration指定持久化类
指定被映射的类,让Hibernate寻找映射定义文件
Configuration cfg = newConfiguration().addClass(com.demo.hibernate.beans.User.class);
1.3为Configuration指定配置属性
Configuration cfg = new Configuration().addClass(com.demo.hibernate.beans.User.class)
.setProperty(“hibernate.dialect”, “org.hibernate.dialect.MySQLInnoDBDialect”)
.setProperty(“hibernate.connection.datasource”, “java:comp/env/jdbc/test”);
1.4Configuration三种加载方法
使用Hibernate.cfg.xml
Configuration cfg = new Configuration();
cfg.configuration(“hibernate.cfg.xml”);
使用Hibernate.properties
需要通过硬编码的方式指定映射文件或POJO类,Hibernate会自动找到另一方
Configuration cfg = new Configuration();
cfg.configuration(“/hibernate.propertiesl”);
cfg. addClass(com.demo.hibernate.beans.User.class); //或者addResource()
完全在构造是进行硬编码设置
Configuration cfg = newConfiguration().addClass(com.demo.hibernate.beans.User.class)
.setProperty(“hibernate.dialect”, “org.hibernate.dialect.MySQLInnoDBDialect”)
.setProperty(“hibernate.connection.datasource”, “java:comp/env/jdbc/test”)
.setProperty(“hibernate.order_updates”, “true”);
2.使用SessionFactory创建Session
SessionFactory在Hibernate中实际起到了一个缓冲区的作用
SessionFactory sessionFactory =cfg.buildSessionFactory();
一个项目通常只需要一个SessionFactory就够了。为当前用户的访问定义一个本地线程变量:
Private static final ThreadLocal threadLocal = new ThreadLocal();
该线程变量是静态的,对每一个访问该线程的用户产生一个实例。在要取得Session对象时,首先从当前用户的线程中取得Session对象,若还没有创建,则再去创建。
Session session = (Session)
threadLocal.get();
if (session ==
null) {
if (sessionFactory ==
null) {
try {
cfg.configure(CONFIG_FILE_LOCALTION);
sessionFactory =
cfg.buildSessionFactory();
} catch (Exception e) {
e.printStackTrace();
}
}
session = sessionFactory.openSession();
threadLocal.set(session);
}
ThreadLocal是用于在并发环境下避免竞争、简化编程的机制,它在并发环境下提供了一个逻辑上全局的访问点,来访问线程本地对象。它为每一个使用使用该变量的线程都提供一个变量值的副本,使每一个线程都可以独立第改变自己的副本,而不会和其他线程的副本冲突。从=线程角度看,就好像每一个线程都完全拥有该变量。
3.使用Session操纵数据库 所有操作都要放在事务中
3.1使用save()保存对象
save()用于将一个新实例化的对象持久化,保存到数据库中。
session = HibernateSessionFactory.currentSession();
Transaction tx = session.beginTransaction();
User user = new User();
user.setId(5);
user.setUsername("test");
user.setPassword("12345");
session.save(user);
tx.commit();
System.out.println(user.getUsername());
3.2使用load()装载对象
当知道某个实例的持久化标识(如 1),就可以使用Session的load()方法来获取它。此外,还可以覆盖掉该实例原来的数据。
session = HibernateSessionFactory.currentSession();
User user = new User();
user.setUsername("oldname");
session.load(user, new Integer("1"));
System.out.println(user.getUsername());
3.3使用get()装载对象
当不确定是否有匹配的行记录存在,应该使用get()方法,它会立刻访问数据库,如果没有对用的行,则返回null。
session = HibernateSessionFactory.currentSession();
User user = (User) session.get(User.class,
new Integer("4"));
if (user ==
null) {
user = new User();
user.setUsername("Alice");
user.setPassword("12345");
session.save(user);
}
System.out.println(user.getUsername());
3.4使用flush()强制提交刷新
当一个实例被更改,可以使用flush()将更改后的实例对象强制保存到数据库中
session = HibernateSessionFactory.currentSession();
User user = (User) session.get(User.class,
new Integer("1"));
user.setUsername("updateRoot");
session.flush();
System.out.println(user.getUsername());
3.5使用update()提交游离状态的对象
update()用于根据给定的detached(游离状态)对象实例的标识更新对应的持久化实例
3.6使用delete()移除持久化对象
该函数用于从数据库中删除对象对应的记录
以下先使用get()加载标识符为4的实例对象,然后删除该对象,并强制执行刷新。
session = HibernateSessionFactory.currentSession();
User user = (User) session.get(User.class,
new Integer("2"));
session.delete(user);
session.flush();
System.out.println(user.getUsername());
3.7使用refresh()强制装载对象
任何时候都可以使用refresh()方法强迫装载对象和它的集合。
4.使用Transaction管理事务
Transaction接口是对实际事务实现的一个抽象,是为了让开发者能够使用一个统一事务的操作界面,使得自己的项目可以在不同的环境和容器之间方便地移植。
一个典型的事务:在创建完Session对象后即使用beginTransaction()启用事务,从此开始直到commit()之间的代码,都会处于同一个事务中。这两个函数之间的所有的数据库代码都会在commit()时一次性提交,在提交时,如果某一句代码执行出现异常,就会回滚这一次事务之间的所有执行代码。
public User getUser(String username)
throws HibernateException{
Session session = null;
Transaction tx = null;
User user = null;
try {
session = HibernateSessionFactory.currentSession();
tx = session.beginTransaction();
Query query = session.createQuery("from User where username=?");
query.setString(0, username.trim());
user = (User) query.uniqueResult();
query = null;
tx.commit();
} catch (HibernateException e) {
throw e;
} finally {
if (tx !=
null) {
tx.rollback();
}
HibernateSessionFactory.closeSession();
}
return user;
}
Tips:如果Session抛出了异常,事务必须回滚,Session也会被废弃。在异常发生后,Session的内部状态可能会与数据库失去同步。
5.使用Query进行HQL语句查询
Query经常被用来绑定查询参数、限制查询记录数量,并最终执行查询操作。
要取得Query对象,需要使用Session的creareQuery()函数来执行查询。其查询的对象是Hebernate的持久化对象名,Hibernate会根据该对象名找到要查找的表名。
5.1不带参数的查询
当不确定是否有匹配的行记录存在,应该使用get()方法,它会立刻访问数据库,如果没有对用的行,则返回null。
Query query = session.createQuery(“from User”);
5.2带参数的查询
接口Query提供了对命名参数、JDBC风格的问号(?)参数两种参数绑定方法。
命名参数在查询字符串中是形如:name的标示符。命名参数的优点是:
命名参数与其在查询串中出现的顺序无关;
它们可在统一查询串中多次出现;
它们本身是自我说明的。
Query query =session.createQuery("from User whereusername=:username");
query.setString("username",
"root");
也可以是集合型参数。
List names = new ArrayList();
names.add("root");
names.add("alex");
Query query =session.createQuery("from User whereusername in (:nameList)");
query.setParameterList("nameList", names);
Query使用问号参数时与JDBC不同,Hibernate对参数从0开始计数。
Query query =session.createQuery("from User whereusername=?");
query.setString(0, "root");
5.3取得List结果集
以上只是取得了一个Query查询的对象,一个查询通常在调用List()时被执行,执行结果会完全装载进内存中的一个集合。
List list = query.list();
5.4取得迭代列表结果集
某些情况下,使用iterate()可以得到更好的性能。Iterate()比list()慢。
有两种方法可以取得迭代结果集,一种是使用Query的iterat()方法,另一种是使用list()后再执行iterator()方法。第二种方法的效率比第一种高。
Iterator it1 = query.iterate();
Iterator it2 =query.list().iterator();
while (it2.hasNext()) {
User user = (User) it2.next();
}
5.5取得一个对象
当知道当前查询只会返回一个对象,则可使用list()的快捷方式uniqueResult()来取得一个对象。
比如,现在我们知道数据库中Username是唯一的:
Query query =session.createQuery("from User whereusername=?");
query.setString(0, "root");
user = (User) query.uniqueResult();
5.6标量查询
查询可以在select从句中指定类的属性,甚至可以调用SQL统计函数。属性或统计结果被认定为“标量(Scalar)“的结果(而不是持久的实体)。
以下使用count()计数函数来取得一个标量结果
Iterator result =session.createQuery(
"selectuser.username,count(user.password) from User user " +
"group by user.username").list().iterator();
5.7分页查询
需要指定结果集的范围(希望返回的最大行数/或考试的行数)时
以下通过setFirstResult()来设置起始位置,通过setMaxResultd()来设置结束位置
Query query = session.createQuery("from User");
query.setFirstResult(10);
query.setMaxResults(20);
List list = query.list();
5.8创建SQL查询
可以使用createAQLQuery()方法,用普通的SQL来描述查询,并由Hibernate处理将结果集转换成对象的工作。Hibernate3允许使用手写的SQL来完成所有的create、update、delete、和load操作。其中的SQL别名需要大括号包围起来。
List users = session.createSQLQuery("SELECT{user.*} FROM User {user}").list();
6.使用Criteria进行条件查询
6.1创建Criteria实例
与Query的方法类似,不同的是其参数是持久化类的名称。
Criteria criteria = session.createCriteria(User.class);
criteria.setMaxResults(50);
List users = criteria.list();
6.2添加查询条件
查询条件是通过org.hibernate.Criteria.Restrictions类来实现的,用来模拟SQL语句中的条件关键字,例如like、between、and、or等。通过调用add()来添加多个Restrictions实例。
Criteria criteria = session.createCriteria(User.class);
criteria.add(Restrictions.like("username",
"root%"));
criteria.add(Restrictions.between("ID", 1, 10));
List users = criteria.list();
6.3添加排序条件
可以使用org.hibernate.Criteria.Order来为查询结果排序,它共包含两个方法,asc()和desc(),分别实现SQL语句中的asc和desc关键字。
List users = session.createCriteria(User.class)
.add(Restrictions.like("username",
"root%"))
.addOrder(Order.asc("username"))
.addOrder(Order.asc("password"))
.setMaxResults(50).list();
6.4使用实例查询
可以使用org.hibernate.Criteria.Example类允许通过一个给定实例来创建一个条件查询
User user = new User();
user.setUsername("root");
List results = session.createCriteria(User.class)
.add(Example.create(user))
.list();
三、Struts
1、MVC模式
|
||
|
||
|
|
|
(蓝色箭头为方法调用,绿色箭头为事件)
Struts体系结构实现MVC设计模式:Controller负责控制流程,由ActionServlet负责读取struts-config.xml,并使用ActionMapping来查找对应的Action;Model由系统状态Bean ActionForm和商业逻辑的JavaBean来构建;View是由JSP和Struts提供的自定义标签来实现。
2、Structs核心组件
类 |
描述(对应的MVC组件的职责) |
ActionServlet |
控制器,接受用户请求和状态改变,以及发出视图选择 |
ActionMapping |
状态改变事件 |
Action |
控制器的一部分,用于模型交互,执行状态或状态查询,以及告诉ActionServlet下一个选择的视图 |
ActionForward |
用户指向或者视图选择 |
ActionForm |
状态改变的数据 |
Tips:每个Action都只建立一个instance。Action不是线程安全的。不要在Action中包含任何业务逻辑操作,而是应该调用一个Model层的JavaBean来实现业务逻辑操作。
3、Structs的六个类 需要开发的类只有Action和ActionForm Bean
3.1 ActionServlet
是Struts的核心控制器,一个系统中只需要一个。可以通过继承该类来扩展一个新的Servlet,但通常直接使用默认的ActionServlet,只需要在web.xml中配置ActionServlet的相关属性即可。
3.2 ActionMapping
是struts-config.xml中配置元素的实例对象,该类与struts-config.xml中的元素和属性相匹配。该类是一个通用类,不需要开发人员开发。
3.3 RequestProcessor
是ActionServlet的代理处理类,与ActionServlet相似,通常使用默认类即可。若要扩展新的功能,只需要实现一个继承该类的新的处理类即可。
3.4 Action
是struts-config.xml中<action>元素对应的处理类,该配置文件可指向多个Action处理类,不同的业务需要不同的Action。Action需要自己开发,新开发的类需要继承Action基类。
Structs提供了多种Action供选择使用。普通的Action只能通过调用execute执行一项任务,而DispatchAction可以根据配齐参数执行,而不是仅进入execute()函数,这样可以执行多种任务,如insert、update等。LookupDispatchAction可以根据提交表单按钮的名称来执行函数。
3.5 ActionForm Bean
是struts-conig.xml中配置的<form-bean>元素对应的类,表示吧不同的处理表单。由于不同的HTML处理表单包含的表单元素不同,因此也需要开发多个ActionForm类。
3.6 ActionForward
用于根据struts-conig.xml中action的配置进行页面转发,是一个通用类,不需要开发。
4、Structs开发流程
首先添加structs 1.2
4.1 编写输入表单
Input.jsp中添加一个表单,表单元素<form>的提交地址为Struts的响应地址,以“.do”为扩展名。
<form
action="test.do"method="post">
<input
type="text"
name="str1"/>
<br/>
<input
type="text"
name="str2"/>
<br/>
<input
type="submit"
/>
</form>
4.2 配置struts-config.xml
<form-bean>元素配置<action>中引用的表单testForm,对应的ActionForm Bean类名为com.demo.struts.forms.TestForm。
<action>元素配置了JSP页面中表单请求的地址“/test”,引用的表单组件名为“testForm”,对应的Action类名为com.demo.struts.actions.TestAction,并定义了两个局部转发地址,“success”表示成功时转发到“success.jsp”,“failure”表示失败时转发到“error.jsp”。
<form-beans>
<form-bean
name="testForm"type="com.demo.struts.forms.TestForm"
/>
</form-beans>
<action-mappings>
<action
path="/test"name="testForm"
scope="request"
type="com.demo.struts.actions.TestAction"input="/input.jsp">
<forward
name="success"path="/success.jsp"
/>
<forward
name="failure"path="/error.jsp"
/>
</action>
</action-mappings>
4.3 编写ActionForm类TestForm.java
当用户单机该页面的“提交”按钮时,会由ActionServlet接收该请求。ActionServlet会依次做如下的工作:
·根据struts-config.xml中“/test”的<action>配置,找到当前使用的表单类为com.demo.struts.forms.TestForm;
·从Request对象中取得input.jsp页面中输入的表单参数,分别与类com.demo.struts.forms.TestForm中的属性相对应。Input.jsp中有几个表单参数,该类中就必须有几个对应的同名属性;
·然后传递给<action>中指定的Action处理类com.demo.struts.actions.TestAction来处理。
public
class TestForm extends ActionForm {
protected String
str1 = null;
protected String
str2 = null;
public String getStr1() {
return
str1;
}
public
void setStr1(String str1) {
this.str1 = str1;
}
public String getStr2() {
return
str2;
}
public
void setStr2(String str2) {
this.str2 = str2;
}
}
4.4 编写Action处理类TestAction.java
Action类接收到处理任务后,默认使用execute()函数来进行处理。需要依次编写:
·定义相关的ActionErrors、ActionForward、TestForm对应变量,并从函数参数form中取得testForm的表单数据对象;
·然后根据testForm取得用户输入,并根据输入的参数将str1和str2保存在request对象中。如果出现逻辑异常,就需要往error对象中保存错误信息;
·最后根据是否有错误信息,确定返回ssuccess或failure的转发对象,返回ActionForward对象即可。
public
class TestAction extends DispatchAction {
public ActionForward execute(ActionMapping mapping, ActionFormform,
HttpServletRequest request, HttpServletResponseresponse)
throws Exception {
ActionErrors errors = new ActionErrors();
ActionForward forward = new ActionForward();
TestForm testForm = (TestForm) form;
try {
//取得表单参数
String str1 = testForm.getStr1();
String str2 = testForm.getStr2();
//调用JavaBean执行处理逻辑
request.setAttribute("str1", str1);
request.setAttribute("str2", str2);
} catch(Exception e) {
}
//根据处理逻辑返回成功或失败的页面
if (!errors.isEmpty()) {
saveErrors(request, errors);
forward = mapping.findForward("failure");
} else {
forward = mapping.findForward("success");
}
return forward;
}
}
4.5 编写返回JSP页面success.jsp
在该页面中显示处理的结果信息。同时,也可以编写erro.jsp。
str1=<%=request.getAttribute("str1")
%>
str2=<%=request.getAttribute("str2")
%>
5、开发Structs核心功能
5.1 struts-config.xml配置
配置数据源:<data-sources>元素。每一个数据源对应一个<data-source>子元素。如下:
<data-sources>
<data-source
key="mysql">
<set-property
property="diverClass"value="org.gjt.mm.mysql.Driver"
/>
<set-property
property="url"value="jdbc:mysql//localhost:3306/demo"
/>
<set-property
property="user"value="root"
/>
<set-property
property="password"value="12345"
/>
<set-property
property="mincount"value="5"
/>
</data-source>
在Action中访问数据源时 ds = getDataSource(request, “mysql”); conn = ds.getConnection();
5.2 配置ActionForm:<form-beans>元素
<form-beans>元素主要用来配置表单验证的类,是将要绑定到Action的FormBean的实例。必须的属性:name——用于指定ActionForm Bean的唯一标识;type——用于指定ActioonForm的完整类名。如果是动态的,还必须配置form-bean元素的form-property子元素。
5.3 配置全局异常处理<global-exceptions>元素
<global-exceptions>主要配置异常处理,它的exception子元素代表全局的异常配置。Key——指定在Resource Bundle中描述该异常的消息key;path——指定当异常发生时的转发路径;type——指定所需处理异常类的名字。
下例配置了一个异常元素,用于跳转到错误页面:
<global-exceptions>
<exception
key="global.erro.invalidlogin"
path="/error.jsp"
scope="request"
type="com.hn.tree"/>
</global-exceptions>
5.4 配置全局跳转:<global-forwards>元素
<global-forwards>元素主要用来声明全局的转发关系,它可以定义多个<forward>子元素。
<global-forwards>
<forward
name="form1"
path="/a.do"/>
<forward
name="form2"
path="/nb.jsp"/>
</global-forwards>
5.5 配置映射关系:<action-mappings>元素
描述从特定的请求路径到相应的Action类的映射,可定义多个<action>子元素。forward、include、type属性只能选中其中一项。子元素<forward>是指局部的转发路径。
<action-mappings>
<action
path="/test"name="testForm"
scope="request"
type="com.demo.struts.actions.TestAction"input="/input.jsp">
<forward
name="success"path="/success.jsp"
/>
<forward
name="failure"path="/error.jsp"
/>
</action>
</action-mappings>
5.6 配置Plug-in插件:<plug-in>元素
<plug-in>元素用来配置Struts的Plug-in插件。有一个属性className,指向插件类名,此类必须实现org.apache.struts.acion.PlugIn接口。可包含多个<set-property>子元素。如下例,配置了Struts的Validator校验插件:
<plug-in
className="org.apache.struts.validator.ValidatorPlugIn">
<set-property
property="pathnames"
value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"/>
</plug-in>
5.7 分离Struts配置文件
为了在web.xml中指定多个配置文件,Struts中引进模块的概念,一个模块就是一个独立的子系统,可在其中进行任意所需的配置。Name表示为config/XXX的形式,其中XXX为对应的模块名。下例说明应用有两个模块,默认模块和custom。
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
<init-param>
<param-name>config/customer</param-name>
<param-value>/WEB-INF/struts-config2.xml</param-value>
</init-param>
实现模块间的转发有两种方法:在<forward>(全局或本地)种定义;利用org.apache.struts.actions.SwitchAction。
全局的例子:
<global-forwards>
<forward name=”toModuleB”contextRelative=”true” path=”/module/index.do” redirect=”true” />
</global-forwards>
只需在原有的path上加上模块名,同时将contextRelative设置为true即可。此外,也可以在<action>中定义一个类似的本地<forward>
<action
path="/test"name="testForm"
scope="request"
type="com.demo.struts.actions.TestAction"input="/input.jsp">
<forward
name="success"contextRelative="true"
path="/moduleA/success.do"/>
<forward
name="failure"path="/error.jsp"
/>
</action>
如果在其他模块中需要转回默认模块,直接转回即可。path="/login.do"
此外,也可以使用org.apache.struts.actions.SwitchAction。如:
<action-mappings>
<action path=”/toModule” type=”org.apache.struts.actions.SwitchAction”/>
</action-mappings>
6、Action组件开发技术
6.1 默认的Action
继承Action基类,必须实现父类的execute()方法。
public
class TestAction extends Action {
public ActionForward execute(ActionMapping mapping, ActionFormform,
HttpServletRequest request, HttpServletResponseresponse) {
}
}
Tips:视图级的验证工作放在ActionForm中,比如输入不能为空、输入格式等;与具体业务相关的验证放入Action中。
6.2 可直接转发的ForwardAction
从一个页面或资源转换到另一个资源时。通常会使用JSP页面的直接转发来进行,但这并不是一个好的方法。在Struts中,我们仍应该通过控制器,使用ForwardAction来完成。当控制器使用ForwardAcion时,它会使用属性parameter所设定的路径进行forward的动作。
<action path=”/index” type=”org.apache.struts.actions.ForwardAction”parameter=”/index.jsp” />
然后在JSP页面中使用如下的请求:<html:link page=”/index.do”>
当点击页面链接之后,ActionServlet就会把请求转发给ForwardAction,ForwardAction再把请求转发给parameter元素中指定的index.jsp页面。
6.3 可包含文件的IncludeAction
引入一个页面或资源时
<action path=”/header” type=”org.apache.struts.actions.IncludeAction”parameter=”/header.jsp” />
然后在JSP页面中使用如下的请求:<html:include page=”/header.do”>
当点击页面链接之后,ActionServlet就会把请求转发给IncludeAction,IncludeAction再把请求转发给parameter元素中指定的header.jsp页面。
6.4 可自动分发的DispatchAction
继承默认的Action类,只能完成一种业务操作。要完成一组业务操作,如对用户进行update、insert等操作,则需要建立多个操作类,分别来接收响应。
而现在可以将这些类合并,并且将相同的部分提出来,由DispatchAction来实现函数的分发。如之前的TestAction。
步骤为:
1、 在<action>元素中添加一个参数parameter,用来指定函数入口的参数名。
<action-mappings>
<action
path="/test"parameter="method"
name="testForm"
scope="request"
type="com.demo.struts.actions.TestAction"input="/input.jsp">
<forward
name="success"path="/success.jsp"
/>
<forward
name="failure"path="/error.jsp"
/>
</action>
</action-mappings>
2、 在<form>请求地址中传递了参数“method=test”
<form
action="test.do?method=test"
method="post">
<input
type="text"
name="str1"/>
<input
type="text"
name="str2"/>
<input
type="submit"
/>
</form>
3、 在Action类中新建参数值对应的函数。例如,在TestAction中新建test()函数
public ActionForward test(ActionMapping mapping, ActionFormform,
HttpServletRequest request, HttpServletResponseresponse)
throws Exception {}
然后发送该请求表单时,就会调用TestAction中名称为test()的函数来处理该请求。
6.5 可进行多个提交的LookupDispatchAction
LookupDispatchAction主要应用于在一个表单中有多个“提交”按钮,而这些按钮又有一个共同的名字的场合。这些按钮的名字和具体的ActionMapping的parameter属性相对应。
配置LookupDispatchAction时,应该在<action>元素中,把parameter属性设置为“action”,使它和<html:submit>标签的property属性相一致。
实现过程:
1、 编写如下一个表单,该表单有4个“提交”按钮,其property属性均为“action”,key值分别指向引用资源文件的4个标签,表示加减乘除。
<html:form action="/test.do"method="post">
<html:text property="str1" />
<html:text property="str2" />
<html:submit property="action"key="button.sum" />
<html:submit property="action"key="button.minus" />
<html:submit property="action"key="button.multiply" />
<html:submit property="action"key="button.divide" />
</html:form>
2、 在资源文件中新建4个标签
button.sum=sum
button.minus=minus
button.multiply=multiply
button.divide=divide
3、 在dtruts-config.xml中配置parameter属性为action
<action-mappings>
<action
path="/test"name="testForm"
scope="request"parameter="action"
type="com.demo.struts.actions.TestAction"input="/input.jsp">
<forward
name="success"
path="/success.jsp"/>
<forward
name="failure"path="/error.jsp"
/>
</action>
</action-mappings>
4、 编写TestLoginAction类
在该类中实现方法getKeyMethodMap(),用以返回一个Map对象。该对象的key值与资源文件中的key相对应,value值与类TestLoginAction.java中的业务方法名相对应。并为该类编写4个业务方法,并实现业务逻辑。
public
class TestLoginAction extends LookupDispatchAction {
@Override
protected Map getKeyMethodMap() {
Map map = new HashMap();
map.put("button.sum","sum");
map.put("button.minus","minus");
map.put("button.multiply","multiply");
map.put("button.divide","divide");
return map;
}
public ActionForward sum(ActionMapping mapping, ActionFormform,
HttpServletRequest request, HttpServletResponseresponse)
throws Exception {
}
}
6.6 可实现交换的SwitchAction
SwitchAction用于从一个模块转移到另一个模块。模块之间的转换有两种方法,一种是使用相对于Context的路径来进行forward查找,也就是之前那个方法;另一种就是使用SwitchAction,它需要在请求中带两个参数,prefix用来指定模块前缀名称,page用来指定相对于模块的资源路径。
<actionpath="/moduleA"type="org.apache.struts.actions.SwitchAction" />
四、Spring
IOC(控制反转),AOP(面向层面的编程)
1、 Spring框架的七个模块
1.1 Spring核心容器(Core)
提供Spring框架的基本功能。核心容器的主要组件是BeanFactory,它是工厂模式的实现。BeanFactory使用控制反转(IoC)模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。
1.2 Spring上下文(Context)
是一个配置文件,向Spring框架提供上下文信息。Spring上下文包括企业服务,例如JNDI、EJB、电子邮件、国际化、校验和调度功能。
1.3 Spring AOP
通过配置管理特性,Spring AOP模块直接将面向方面的编程功能集成到了Spring框架中。Spring AOP模块为基于Spring的应用程序中的对象提供了事务管理服务。通过使用Spring AOP,不用依赖EJB组件,就可以将声明性事务管理集成到应用程序中。
1.4 Spring DAO
JDBC DAO抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO的面向JDBC的异常遵从通用的DAO异常层次结构。
1.5 Spring ORM
Spring框架插入了若干个ORM框架,从而提供了ORM的对象关系工具。所有这些都遵从Spring的通用事务和DAO异常层次结构。
1.6 Spring Web模块
Web上下文模块建立在应用程序上下文模块之上,为基于Web的应用程序提供了上下文。Spring框架支持与Jakarta Struts的集成。Web模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。
1.7 Spring MVC框架
Spring的MVC框架是一个全功能的构建Web应用程序的MVC实现。
2、 控制反转IoC IoC容器颠覆了“使用对象之前必须创建”的基本Java语言定律
IoC就是由容器来控制业务对象之间的依赖关系,而非传统方式中由代码来直接操控。控制反转的本质,是控制权由应用代码转到了外部容器,控制权的转移即是所谓的反转。这降低了业务对象之间的依赖程度,即实现了解耦。
软件设计模式,共有三种调用方法:自己创建、工厂模式、外部注入,形象地表示就是new、get、set。IoC是依赖注入。
2.1 利用Java反射机制实现IoC容器
IoC好比是一个大工厂,要生成的对象都是在XML文件中给出定义的,然后利用Java的“反射”编程,根据XML中给出的类名生成相应的对象。
以下配置定义了两个图书的对象bookA和bookB,在student1的属性中设置了bookA,在student2的属性中设置了bookB。IoC的容器会读取这一段配置,通过Java反射机制来创建对象bookA、bookB、student1、student2,依然通过方法机制来为student1设置bookA,为student2设置bookB,并分别调用learn()方法即可完成调用。
<bean
name="bookA"class="BookA"
/>
<bean
name="bookB"class="BookB"
/>
<bean
name="student1"class="Student">
<property
name="book"value="bookA"
/>
</bean>
<bean
name="student2"class="Student">
<property
name="book"
value="bookB"/>
</bean>
反射中常用的操作方法:
1、 创建一个类
可直接Class clazz = MyClass.class; 但如果需要从外部读取类名时,需要使用一个类装入器来查找类信息,如下:
String name = "MyClass";
Class clazz = null;
try {
clazz = Class.forName(name);
} catch (ClassNotFoundException e) {
}
如果已经装入了类,将得到现有的MyClass信息;如果未装入,类装入器将现在装入并返回新创建的类实例。
2、 使用类的构造函数创建一个实例
Constructor[]getConstructors():获得类的所有公共构造函数;
Constructor[]getConstructors(Class[] params):获得使用特殊的参数类型的公共构造函数;
Constructor[]getDeclaredConstructors():获得类的所有构造函数;
Constructor[]getDeclaredConstructors(Class[] params):获得使用特定参数类型的构造函数。
以上函数都返回一个或多个java.lang.reflect.Constructor对象,表示类的构造对象,可通过Constructor类的newInstance方法来创建该类的对象。
public
class MyClass {
private String
str1;
private String
str2;
public MyClass(String s1, String s2) {
str1 = s1;
str2 = s2;
}
public
static void main(String[] args) {
try {
Class[] types = new Class[]{String.class, String.class};
Constructor cons = MyClass.class.getConstructor(types);
Object[] objs = new Object[]{"a",
"b"};
MyClass clazz = (MyClass) cons.newInstance(objs);
System.out.print(clazz.toString());
} catch (Exception e) {
}
}
}
3、 操作类的字段
FieldgetField(String name):获得命名的公共字段;
Field[]getFields():获得类的所有公共字段;
FieldgetDeclaredField(String name):获得类声明的命名的字段;
FieldgetDeclaredFields():获得类声明的所有字段
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
public
class MyClass {
private String
str1;
private String
str2;
public MyClass(String s1, String s2) {
str1 = s1;
str2 = s2;
}
(get,set…)
public
static void main(String[] args) {
try {
//创建类的对象
Class[] types = new Class[]{String.class, String.class};
Constructor cons = MyClass.class.getConstructor(types);
Object[] objs = new Object[]{"a",
"b"};
MyClass clazz = (MyClass) cons.newInstance(objs);
//创建类的字段
Field field = MyClass.class.getDeclaredField("str1");
//操作字段的值
field.set(clazz, "xxx");
System.out.print(field.get(clazz)); / System.out.print(clazz.getStr1());
} catch (Exception e) {
}
}
}
4、 操作类的方法
MethodgetMethod(String name, Class[] params):使用特定的参数类型,获得命名的公共方法;
Method[]getMethods():获得类的所有公共方法;
MethodgetDeclaredMethod(String name, Class[] params):使用特定的参数类型,获得类声明的命名的方法;
Method[]getDeclaredMethods():获得类声明的所有方法
public
class MyClass {
private String
str1;
private String
str2;
public MyClass(String s1, String s2) {
str1 = s1;
str2 = s2;
}
(get,set…)
public String sayHello(String name) {
return
"Hello" + name;
}
public
static void main(String[] args) {
try {
//创建类的对象
Class[] types = new Class[]{String.class, String.class};
Constructor cons = MyClass.class.getConstructor(types);
Object[] objs = new Object[]{"a",
"b"};
MyClass clazz = (MyClass) cons.newInstance(objs);
//创建类的方法
Class[] types2 = new Class[]{String.class};
Method method = MyClass.class.getMethod("sayHello", types2);
//调用方法
Object[] strs = new Object[]{"World"};
Object result = method.invoke(clazz, strs);
System.out.print(result.toString());
} catch (Exception e) {
System.out.print(e.toString());
}
}
}
Spring中IoC容器的实现方式
BeanFactory最常用的定义是XmlBeanFactory,它根据XML文件中的定义装入Bean
BeanFactoryfactory = new XMLBeanFactory(newFileInputSteam(“mybean.xml”));
在XML文件中定义的Bean是被消极加载的,在需要Bean之前,Bean本身不会被初始化。要从BeanFactory检索Bean,只需调用getBean()方法,传入名称即可。
Studentstudent1 = (Student) factory.getBean(“student1”);
2.2 依赖注入DI的类型
1、Type 1 接口注入
借助接口来将调用者与实现者分离
Publicclass Student {
private IBook bookA;
public init() {
bookA= (IBook)Class.forName(“BookA”).newInstance();
}
}
2、Type 2 构造注入
依赖关系通过类构造函数建立,容器通过调用类的构造方法,将其所需的依赖关系注入其中。
例如下例是Spring的实现方式。
Publicclass Student {
private IBook bookA;
public Student(BookA bookA) {
this.bookA = bookA;
}
public void learn() {
bookA.learn();
}
}
然后在配置文件mybean.xml中添加如下的注入配置:
<bean
name="bookA"class="BookA"
/>
<bean
name="student1"class="Student">
<property
name="book"value="bookA"
/>
</bean>
此时取得的对象student1已经拥有令人属性bookA,也就可以调用learn()方法了。
BeanFactory factory = new XMLBeanFactory(new FileInputSteam(“mybean.xml”));
Student student1 =(Student)factory.getBean(“student1”);
student1.learn();
3、Type 3 设值注入
应用最广泛。
受控对象通过属性来表达自己所依赖的对象和所需配置的值。为调用类添加setter方法即可。
例如下例中,是Spring的实现方式。、public class Student {
private BookA bookA;
public BookA getBookA() {
return bookA;
}
public void setBookA(BookA bookA) {
this.bookA = bookA;
}
public void learn() {
bookA.learn();
}
}
然后在配置文件mybean.xml中添加如下的注入配置(同2):
<bean
name="bookA"class="BookA"
/>
<bean
name="student1"class="Student">
<property
name="book"value="bookA"
/>
</bean>
2.3 Spring的IoC容器装载机制
1、BeanFactory的使用步骤
在Spring中,它是IoC容器的核心接口,职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。
1.1配置XML元数据
将在顶层的<beans>元素中配置一个或多个<bean>元素,<bean>与应用程序中实际使用的对象一一对应。以下是一个基于XML的配置元数据的基本结构:
<?xml
version="1.0"encoding="UTF-8"?>
<beans
xmlns="https://www/springframework.org/schema/beans"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframeword.org/schema/beans/spring-beans.xsd">
<bean
id="..."class="..."></bean>
</beans>
1.2实例化容器
假设上面编写的XML文件为beans.xml,并且放在默认的classpath目录下,则可以通过如下的三种方式来实例化容器:
Resource resource =
new FileSystemResource("beans.xml");
BeanFactory factory = new XmlBeanFactory(resource);
或
ClassPathResource resoruce =
new ClassPathResource("beans.xml");
BeanFactory factory = new XmlBeanFactory(resource);
或
ApplicationContext context =
new ClassPathXmlApplicationContext(
new String[]{"beans.xml",
"beans-part1.xml"});
BeanFactory factory = new XmlBeanFactory(resource);
第三种方式用于加载多个XML配置文件。另一种方法是使用<import>元素来从另外的文件加载Bean定义。如
<beans>
<import
resource="beans.xml"/>
<import
resource="part/beans-part1.xml"/>
<bean
id="..."class="..."></bean>
</beans>
1.3 调用BeanFactory进行Bean操作
BeanFactory提供的方法极其简单,它仅提供了六种方法供客户代码调用。
Boolean containsBean(String) 是否有给定名字的实例
Object getBean(String) 返回给定名字的实例
Object getBean(String,Class) 返回给定名字的实例,并转化为给定class类型的实例
Class getType(String name) 返回给定名字的Bean的Class
Boolean isSingleton(String) 判断给定名字的Bean定义(或实例)是否为singleton模式
String[] getAliases(String) 返回给定Bean名字的所有别名
3、ApplicationContext
ApplicationContext覆盖了BeanFactory的所有功能,所以通常优先采用ApplicationContext。
3、构建Spring开发环境
3.1 在applicationContext.xml中添加Bean配置元素
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean
id="HelloWorld"class="com.demo.spring.test.HelloWorld"
>
<property
name="message">
<value>World</value>
</property>
</bean>
</beans>
这里配置了一个id为“HelloWorld”的Bean对象,并为该类的属性“message”设置一个注入的值“World”。
3.2 新建Bean类
public
class HelloWorld {
protected String
message;
(get,set…)
public String execute(String str) {
return
"Hello" + getMessage();
}
}
3.3 运行测试类
public
class Test {
public
static void main(String[] args) {
// TODO Auto-generatedmethod stub
ApplicationContext ctx = new FileSystemXmlApplicationContext(
"src/applicationContext.xml");
HelloWorld hello = (HelloWorld) ctx.getBean("HelloWorld");
System.out.print(hello.execute("World"));
}
}
4、Spring的MVC技术框架
Spring不仅作为一个IoC的容器,还要作为Web应用的MVC框架,控制Web应用的整个流程。
Spring体系结构实现了MVC设计模式的概念。Controller负责控制流程,由DispatcherServlet负责读取读取applicationContext.xml,并使用HandlerMapping来查找对应的Controller组件;Model由系统状态Bean Form和商业逻辑的JavaBean来构建;View是由JSP和Spring提供的自定义标签来实现的。
Spring MVC的核心组件是DispatcherServlet,该类既作为整个MVC框架的前端控制器,同时又负责调动框架中其他组件协同工作完成对一个请求的处理。处理一个请求的大致流程如下:
1、配置文件applicationContext.xml:当DispatcherServlet接收HTTP请求信息时,如何决定把用户请求转发给哪个Controller对象呢?这需要一些描述用户请求路径和Controller映射关系的配置信息。在Spring中,这些配置映射信息都存储在特定的XML文件applicationContext.xml中。这些配置信息在系统启动时会被读入内存,供Spring在运行期间使用。
2、请求首先由DispatcherServlet截获,DispatcherServlet把请求交给HandlerMapping,寻找相应的逻辑处理单元;
3、HandlerMapping根据请求的不同,返回对应的Controller处理器,并通过HandlerAdapter来执行Controller的方法。使用HandlerAdapter的目的,是因为Spring MVC并不关心Controller实现了什么样的接口,只要提供相应的HandlerAdapter,Spring MVC就知道如何执行Controller;
4、处理结束后返回一个包含了模型和视图的对象ModelAndView。DispatcherServlet把返回的ModelAndView对象交给ViewResolver,通过ViewResolver返回一个合适的View对象。最后DispatcherServlet调用View对象的render方法把模型中的数据和视图融合,返回给用户。
Spring的web.xml配置
和其他Servlet一样,DiapatcherServlet定义在Web应用的web.xml文件里。DiapatcherServlet处理的请求必须在同一个web.xml文件里使用url-mapping定义映射。配置DiapatcherServlet:
<servlet>
<servlet-name>Dispatcher</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/src/application.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Dispatcher</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
所有以.do结尾的请求都会有名为Dispatcher的DispatcherServlet处理。该Servlet配置了初始化参数contextConfigLocation。设置了IoC配置文件的名称。
在基于Struts+Spring的联合应用中,接收请求的Servlet是由Struts的ActionServlet来配置的,因此就不能使用DispatcherServlet来接收请求了。为了在此时能够加载Spring的Bean配置,可以在web.xml中配置一个监听器,并通过<context-param>指定XML文件名,如下所示:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/src/applicatioContext.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
5、 Spring的MVC开发流程
六个类,需要我们开发的类只有Controller和Form Bean
1、DispatcherServlet是Spring的核心控制器,一个系统只需要一个。可通过继承该类来扩展一个新的Servlet,但通常直接使用默认的DispatcherServlet,只需在web.xml中配置DispatcherServlet的相关属性即可。
2、HandlerMapping是applicatioContext.xml中配置元素的实例对象,该类与applicatioContext.xml中的元素和属性相匹配。由于applicatioContext.xml文件的元素类型已经由Spring设计者定义完成了,因此类HandlerMapping是一个通用类,不需要开发,只需使用Spring默认的HandlerMapping实现来配置Mapping映射即可
<bean
id="testMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property
name="mappings">
<props>
<prop
key="/test.do">testAction</prop>
</props>
</property>
</bean>
3、Controller是applicatioContext.xml中配置的响应处理类,不同的业务需要不同的Controller类。因此Controller需要自己开发,新开发的类需要继承它。例如上面的testMapping映射中指定了“/test.do”映射处理类为testAction,因此这里需要配置一个对应的处理类:
<bean
id="testAction"
class="com.demo.spring.actions.TestAction">
</bean>
4、Form Bean是applicatiContext.xml中为处理类配置的commandClass元素,表示要接收的处理表单。由于不同的HTML处理表单包含的表单元素不同,因此也需要开发多个Form类。例如我们为testAction配置一个处理表单。
<bean
id="testAction"
class="com.demo.spring.actions.TestAction">
<property
name="commandClass">
<value>com.demo.spring.forms.TestForm</value>
</property>
</bean>
5、ModelAndView是处理类在完成业务处理后返回的对象,该对象与处理类的配置属性相关联。我们只需配置即可。例如我们为testionAction配置如下的两个返回对象:
<bean
id="testAction"
class="com.demo.spring.actions.TestAction">
<!-- 指定失败要返回的页面 -->
<property
name="formView">
<value>input</value>
</property>
<!-- 指定成功要返回的页面 -->
<property
name="successView">
<value>success</value>
</property>
</bean>
在TestAction处理结束后,我们就可以使用下面的方式来返回ModelAndView:
return new ModelAndView(getSuccessView());
return new ModelAndView(getFormView());
6、ViewResolver是ModelAndView返回后对应页面的解析器,它将根据返回页面的扩展名来查找不同的解析器。Spring提供了许多默认的视图解析器,也可以通过继承来开发自己的解析器。例如对于JSP扩展名,我们可以配置如下的解析器:
<bean
id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property
name="viewClass">
<value>
org.springframework.web.servlet.view.InternalResourceView
</value>
</property>
<!-- JSP都放在/目录下 -->
<property
name="prefix">
<value>/</value>
</property>
<!-- JSP页面的后缀都设计.JSP -->
<property
name="suffix">
<value>.jsp</value>
</property>
</bean>
Spring的MVC开发流程
5.1 编写输入表单页面input.jsp
<form
action="test.do"method="post">
<input
type="text"
name="str1"/>
<input
rype="text"
name="str2"/>
<input
type="submit"
/>
</form>
表单元素<form>的提交地址为Spring的响应地址,以“.do”为扩展名
5.2 配置处理器映射和处理器
applicationContext.xml中添加:
<!-- 定义映射 -->
<bean
id="testMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property
name="mappings">
<props>
<prop
key="/test.do">testAction</prop>
</props>
</property>
</bean>
<!-- 定义Action -->
<bean
id="testAction"
class="com.demo.spring.actions.TestAction">
<property
name="commandClass">
<value>com.demo.spring.forms.TestForm</value>
</property>
<!-- 指定失败要返回的页面 -->
<property
name="formView">
<value>input</value>
</property>
<!-- 指定成功要返回的页面 -->
<property
name="successView">
<value>success</value>
</property>
</bean>
<!-- 定义视图 -->
<bean
id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property
name="viewClass">
<value>
org.springframework.web.servlet.view.InternalResourceView
</value>
</property>
<!-- JSP都放在/目录下 -->
<property
name="prefix">
<value>/</value>
</property>
<!-- JSP页面的后缀都设计.JSP -->
<property
name="suffix">
<value>.jsp</value>
</property>
</bean>
这里配置了两个元素:
1、 Mapping配置:表示可以接收input.jsp页面中表单的请求地址“/test.do”的请求,该请求交由testAction来处理;
2、 Controller配置:配置了一个处理器元素testAction,负责处理“/test.do”的请求。该处理器配置了一个commandClass属性,指定了输入的表单类为com.demo.spring.forms.TestForm。并指定了成功返回页面和失败返回页面,名称分别为TestAction类中的属性,这里即是利用了IoC来为TestAction注入两个属性。这两个返回对象指向的页面分别为success.jsp和input.jsp,在这里不需要指定jsp的扩展名。
5.3 编写Form类com.demo.struts.forms.TestForm.java
5.4 编写处理类com.demo.spring.actions.TestAction.java
TestAction类接收到处理任务后,默认使用onSubmit()函数来进行处理。需要依次编写:
1、该类继承自SimpleFormController,它提供了请求的入口函数onSubmit(),注入变量sucessView和formView,以及这两个变量的getter/setter函数
2、在函数中,首先通过强制类型转换,取得用户的表单对象testForm
3、然后实现业务逻辑。比如,若满足条件,则将两个变量保存在Session中,调用父类的getSuccessView返回ModelAndView对象;否则,取得错误对象model,将testForm保存在modle中,然后返回一个ModelAndView对象,其中第一个参数为getFormView(),表示返回input.jsp页面,第二个参数为Model,表示传递错误映射列表。
public
class TestAction extends SimpleFormController {
protected ModelAndView onSubmit(HttpServletRequest request,
HttpServletResponse response, Object command,BindException errors)
throws Exception {
TestForm testForm = (TestForm) command;
if (testForm.getStr1().equals("root") &&testForm.getStr2().equals("12345")) {
request.getSession().setAttribute("str1",testForm.getStr1());
request.getSession().setAttribute("str2",testForm.getStr2());
return
new ModelAndView(getSuccessView());
//与response.sengRedirect(“login.do”);之类的效果类似
} else {
Map modle = errors.getModel();
modle.put("testForm", testForm);
return
new ModelAndView(getFormView(), modle);
}
}
}
5.5 配置JSP视图解析器
在TestAction中返回了ModelAndView后,会交给DispatcherServlet查找对应的页面。为了能够解释jsp页面,我们需要在applicationContext.xml中配置一个视图解析器:
<!-- 定义视图 -->
<bean
id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property
name="viewClass">
<value>
org.springframework.web.servlet.view.InternalResourceView
</value>
</property>
<!-- JSP都放在/目录下 -->
<property
name="prefix">
<value>/</value>
</property>
<!-- JSP页面的后缀都设计.JSP -->
<property
name="suffix">
<value>.jsp</value>
</property>
</bean>
5.6 编写返回JSP页面success.jsp
6、Spring MVC三大组件
6.1 HandlerMapping处理器映射
通过处理器映射,可将Web请求映射到正确的处理器Controller上。当接收到请求时,DispatcherServlet将请求交给HandlerMapping处理器映射,让它检查请求并找到适当的HandlerExceptionChain,这个HandlerExceptionChain包含一个能处理该请求的处理器Controller。然后DispatcherServlet执行定义在HandlerExceptionChain中的处理器Controller。
Spring中常用的两个处理器映射,SimpleUrlHandlerMapping和BeanNameUrlHandlerMapping:
1、 SimpleUrlHandlerMapping
<bean
class="org.springframework.web.sevlet.handler.SimpleUrlHandlerMapping">
<property
name="mappings">
<props>
<prop
key="/**/help.do">helpAction</prop>
<prop
key="/ex/view*.do">helpAction</prop>
<prop
key="/*/account.do">accountAction</prop>
<prop
key="/*/editAccount.do">accountAction</prop>
</props>
</property>
</bean>
<bean
id="helpAction"class="org.springframework.web.servlet.mvc.UrlFilenameViewController"/>
<bean
id="accountAction"class="org.springframework.web.servlet.mvc.SimpleFormController">
<property
name="formView"value="account"
/>
<property
name="successView"value="account-created"
/>
<property
name="commandName"value="Account"
/>
<property
name="commandClass"value="samples.Account"
/>
</bean>
这个处理器映射首先将对所有目录中文件名为help.do的请求传递给helpAction,它是一个UrlFilenameViewController。对ex目录中所有以view开始,以.do结尾的请求都会被传递给helpAction。同样地,也为accountAction定义了两个映射,所有account.do和editAccount.do的请求都交由它处理。
2、 BeanNameUrlHandlerMapping
BeanNameUrlHandlerMapping将收到的HTTP请求映射到Bean的名字上。例如,为了实现一个用户新建账号的功能,我们提供了FormController和显示表单的JSP视图(或Velocity模板)。当使用BeanNameUrlHandlerMapping
时,我们用如下方式将包含http://samples.com/editAccount.do的访问请求映射到指定的FormController上:
<bean
id="handlerMapping"class="org.springframework.web.sevlet.handler.BeanNameUrlHandlerMapping"/>
<bean
name="/editAccount.do"class="org.springframework.web.servlet.mvc.SimpleFormController">
<property
name="formView"value="account"
/>
<property
name="successView"value="account-created"
/>
<property
name="commandName"value="Account"
/>
<property
name="commandClass"value="samples.Account"
/>
</bean>
要使用BeanNameUrlHandlerMapping,无须定义,默认情况下如果上下文中没有找到处理器映射,DispatcherServlet会为你创建一个BeanNameUrlHandlerMapping。
3、 拦截器(HandlerInterceptor)
Spring的处理器映射支持拦截器,可用来为某些请求提供特殊功能,例如对用户进行身份验证。
处理器映射中的拦截器必须实现org.springframework.web.sevlet包中的HandlerInterceptor接口。这个接口定义了三个方法,一个在处理器执行前被调用,一个在处理器执行后被调用,另一个在整个请求处理完后调用。
下例提供了一个拦截器,它拦截account.do和editAccount.do的请求:
<bean
id="handlerMapping"class="org.springframework.web.sevlet.handler.BeanNameUrlHandlerMapping/">
<property
name="interceptors">
<list>
<ref
bean="officeHoursInterceptor"/>
</list>
</property>
<property
name="mappings">
<props>
<prop
key="/*/accountAction.do">accountAction</prop>
<prop
key="/*/editAccount.do">accountAction</prop>
</props>
</property>
</bean>
<bean
id="officeHourInterceptior"class="samples.TimeBasedAccessInterceptor">
<property
name="openingTime"value="9"
/>
<property
name="closingTime"value="18"
/>
</bean>
拦截器TimeBasedAccessInterceptor必须继承HandlerInterceptorAdapter。该拦截器的作用是,如果当前时间不是在上午9点到下午6点,它将用户重定向到某个页面。
public
class TimeBasedAccessInterceptor extends HandlerInterceptorAdapter {
private
int openingTime;
private
int closingTime;
(get,set..)
public
boolean preHandle(
HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
Calendar calendar = Calendar.getInstance();
int hour = calendar.getTime().getHours();
if (openingTime <= hour && hour <
closingTime) {
return
true;
} else {
response.sendRedirect("...");
}
return
false;
}
}
所有的请求都将被TimeBasedAccessInterceptor截获,若当前时间不合法,用户会被重定向到另一个页面。
6.2 Controller处理器
Spring提供了许多功能强大的Controller的实现,可选择继承一个合适的Controller来简化编码,相对于Struts或WebWork,Spring提供的Controller层次极为丰富,包含表单处理器、命令处理器、向导型处理器等多种控制器。
1、 AbstractController
所有的Spring控制器都继承了AbstractController。当从AbstractController继承时,需要实现handleRequestInternal(HttpServletRequest request,HttpServletResponse response)抽象方法,该方法用来实现自己的逻辑,并返回一个ModelAndView对象。
public
class SampleController extends AbstractController {
protected ModelAndView handleRequestInternal(HttpServletRequestrequest,
HttpServletResponse response) throws Exception {
ModelAndView mav = new ModelAndView("hello");
mav.addObject("message",
"HelloWorld!");
return mav;
}
}
在applicationContext.xml中进行配置:
<bean
id="sanpleController"class="samples.SampleController">
<property
name="cacheSeconds"value="120"
/>
</bean>
Spring提供的众多控制器可减轻负担,如:
ParameterizableViewController基本上和上例一样,不同的是,可在applicationContext.xml中指定返回视图名从而避免了硬编码;
UrlFilenameController会检查URL,获取文件请求的文件名,并把它作为视图名加以使用。例如:http://www.springframework.org/index.html对应的视图文件名是index。
2、 MultiActionController
MultiActionController将多个行为(action)合并在一个处理器里,这样可以把相关功能组合在一起,它通过将请求映射到正确的方法名来调用方法。如果需要处理多个类似的请求,可用MultiActionController来实现,而不必分别编写多个单一功能的Controller。该类类似于Structs中的DispatchAction类,可以分发多个请求的函数。
例如,对某一个表的数据编写一个模块,包含CRUD(增删改查)四项功能,依次在处理器类中也需要实现四个不同的函数:
public
class UserAction extends MultiActionController {
public ModelAndView create(HttpServletRequest request,
HttpServletResponse response) throws Exception {
return ModelAndView("create", model);
}
..update/delete/retrieve(…) …
}
为了选择不同的方法入口,需要在applicationContext.xml中定义方法解析器:
<bean
id="methodNameResolver"class="org.springframework.web.servlet.mvc.multiaction.ParameterMethodNameResolver">
<property
name="paramName"value="method"
/>
<property
name="defaultMethodName"value="retrieve"
/>
</bean>
该解析器使用了Spring的默认解析器实现类ParameterMethodNameResolver,并制定提取方法名的参数为method,默认的方法名为retrieve。
这样,ParameterMethodNameResolver根据URL的method参数来确定方法名称。将methodNameResolver注入到ViewProfileController后,若用户请求“/*.do?method=create”,则methodNameResolver将根据参数method=create来决定调用UserAction的create()方法来处理用户请求(其他类似);若没有找到method参数,则methodNameResolver根据defalutMethodName属性来调用retrieve()方法。
3、 BaseCommandController命令处理器
它的功能与Struts中的ActionForm有点相像,不过在Spring中,无须实现任何接口来实现数据绑定。可使用的命令处理器:
3.1 AbstractCommandController 它能够将请求参数绑定到指定的数据对象上。不提供任何表单功能,但是提供验证功能,并且让你在自雷中区实现如何处理由请求参数产生的命令对象。
3.2AbstractFormController 一个支持表单提交的抽象处理类。使用它,可以定义表单,并使用从控制器获取的数据对象构建表单。子类需要实现自己的方法来指定采用哪个视图来显示输入表三,哪个视图显示表单正确提交后的结果。不在上下文中指定显示给用户的视图时使用。
3.3SimpleFormController 这是一个form controller。可为其指定一个命令对象,显示表单的视图名,当表单提交成功后显示给用户的视图名等。
3.4CancellableFormController 与SimpleFormController类似,它实现了取消表单提交的功能。
3.5AbstractWizardFormController 抽象类,可实现向导功能。如果表单项很多,需要在多页中进行翻页显示输入时,可以使用该类。
4、SimpleFormController
通常最常使用的是SimpleFormController,它可以处理简单的表单,可以同时完成显示表单和提交表单两个功能。显示表单无须编码,Spring会自动处理,我们只须处理提交表单。
SimpleFormController主要通过以下几个属性来决定如何显示和提交表单:
4.1 commandClass 表单类(或称为命令类),在Spring中表单对象呗称为Command对象,与Struts中的ActionForm类似,但Spring中不要求实现任何特定接口。
4.2formView 显示表单的视图名称
4.3successView 提交表单成功后的视图名称
6.3 ViewResolver视图解析器
ViewResolver和View是Spring的视图处理方式中特别重要的两个接口。ViewResolver提供从视图名称到实际视图的映射;View处理请求的准备工作,并将该请求提交给某种具体的视图技术。
1、 视图解析器 (见前例)
2、 Velocity解析器
Velocity是一种模板技术,能够通过模板生成任何文本内容。所有Velocity相关组件均是在XML中配置Velocity解析器。
3、 FreeMarker解析器
FreeMarker是取代JSP的又一种视图技术,与Velocity非常类似,但比Velocity多了一个格式化的功能,因此使用较Velocity方便一点,但语法也稍微复杂一些。
7、使用Spring标签进行页面国际化
在web.xml中要加入
<servlet>
<servlet-name>SpringContextServlet</servlet-name>
<servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
7.1 Spring标签基础
1、Spring表单标签库 使用标签库需要按照以下步骤:
1.1配置标案标签库
在web.xml中添加该标签库的引用:
<jsp-config>
<taglib>
<taglib-uri>/spring-form</taglib-uri>
<taglib-location>/WEB-INF/spring-form.tld</taglib-location>
</taglib>
</jsp-config>
1.2在JSP文件中引用标签
如果想在JSP页面中使用这些标签,需要在JSP代码的起始部分加入下面这行声明:
<%@ taglib prefix=”form” uri=”/spring-form”%>
1.3在request中保存JavaBean
在所有的表单标签中,<form:form>标签中保存了PageContext的JavaBean对象,该标签是其他所有标签的父标签,其他的标签都需要包含在该标签内。这样,<form:form>标签就表示了JavaBean的对象,而其内部的标签则表示JavaBean的属性。
为了进行演示,首先新建一个JavaBean类User(略)。然后在JSP页面中创建一个User对象,并保存在request对象中,命名变量为user:
<%
User user = new User();
request.setAttribute(“user”, user);
%>
1.4绑定JavaBean对象
<from:form>表单代表了JavaBean的对象,可以使用commandName属性来与之绑定,其值为在request中保存的变量名user。
<form:form commandName=”user”</form>
1.5绑定JavaBean属性
在<form:form>元素内部的表单用来显示JavaBean的属性,可以使用path属性来与JavaBean的属性进行绑定。
<form:form
commandName="user">
姓名:<form:input
path="username"
/><br/>
密码:<form:password
path="password"
/><br/>
性别:男<form:radiobutton
path="sex"
value="M"/>
女<form:radiobutton
path="sex"
value="F"/><br/>
兴趣:Struts:<form:checkbox
path="interests"
value="Struts"/>
Spring:<form:checkbox
path="interests"
value="Spring"/>
<form:textarea
path="username"
rows="3"cols="20"
/>
</form:form>
3、 Spring基础标签库
web.xml配置:
<jsp-config>
<taglib>
<taglib-uri>/spring </taglib-uri>
<taglib-location>/WEB-INF/spring.tld</taglib-location>
</taglib>
</jsp-config>
然后在JSP页面起始部分加入:<%@ taglib prefix=”form” uri=”/spring-form” %>
该标签库中包含的几个标签:
1.<spring:hasBindErrors>
该标签用于绑定对象的errors,标记被用到的话,关于这个对象的错误将在页面上显示出来。使用它的前提是要先使用<spring:bind>标记,且<spring:hasBindErrors>不能用来表示对象的状态、仅可绑定对象本身和对象的属性。如下,其中name属性石要被检查的Bean的名字:
<spring:hasBindErrors name=”priceIncrease”>
<b>Please fix all errors!</b>
</spring:hasBindErrors>
2.<spring:bind>
该标签用来为某个Bean或Bean的属性赋值,通常和form一起用,用以指明表单要提交到哪个类或类的属性中去,其中path属性石必须的,指明转到的类的路径:
<form
method="post">
<spring:bind
path="command.username">
姓名:<input
type="text"
name="${status.expression}"value="${status.value}"
/>
<font
color="red">${status.erroMessage}</font>
</spring:bind>
</form>
3.<spring:transform>
该标签用来转换表单中不与Bean中的属性一一对应的那些属性,通常和<spring:bind>一起使用,<spring:transform>标记为<spring:bind>使用提供了更好的支持。
4.<spring:message>
该标签用来帮助Spring框架支持国际化。
例如,要输出资源文件中的login.username,则:
<spring:message code=”login.username”/>
8、Spring + Hibernate框架
Spring部分
8.1先按“Spring的MVC开发流程5.2
配置处理器映射和处理器”进行配置
8.2开发用户登录功能
1、新建登录页面login.jsp
<form
name="form"action="login.do"
method="post">
<table
width="200"
border="1">
<tr>
<td
colspan="2">登录窗口</td>
</tr>
<tr>
<td>用户名</td>
<td><input
type="text"
name="username"size="10"/></td>
</tr>
<tr>
<td>密码</td>
<td><input
type="password"
name="password"size="10"/></td>
</tr>
<tr>
<td
colspan="2">
<input
type="submit"
name="submit"value="登录"/>
<a
href="register.do?method=init">注册新用户</a>
</td>
</tr>
</table>
</form>
2、配置处理器映射与处理器
登录页面login.jsp的<form>提交地址为login.do,因此在applicationContext.xml需要添加处理器映射
<bean
id="loginMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property
name="mappings">
<props>
<prop
key="/login.do">loginAction</prop>
</props>
</property>
</bean>
定义处理器
<bean
id="loginAction"
class="com.demo.spring.actions.LoginAction">
<property
name="commandClass">
<value>com.demo.spring.forms.LoginForm</value>
</property>
<!-- 指定失败要返回的页面 -->
<property
name="formView">
<value>login</value>
</property>
<!-- 指定成功要返回的页面 -->
<property
name="successView">
<value>welcome</value>
</property>
</bean>
3、新建登录表单类com.demo.spring.forms.LoginForm.java
4、新建登录处理器com.demo.spring.actions.LoginAction
public
class LoginAction extends SimpleFormController {
//接收表单提交
protected ModelAndView onSubmit(HttpServletRequest request,
HttpServletResponse response, Object command,BindException errors) {
LoginForm loginForm = (LoginForm) command;
if (isValid(loginForm)) {
request.getSession().setAttribute(Constants.USERNAME_KEY,loginForm.getUsername());
return
new ModelAndView(getSuccessView());
} else {
Map modle = errors.getModel();
modle.put("loginForm", loginForm);
return
new ModelAndView(getFormView(), modle);
}
}
private
boolean isValid(LoginForm loginForm) {
if (loginForm.getUsername().equals(“root” && …) {
return
true;
} else {
return
false;
}
}
8.3开发用户退出功能
1、配置处理器映射与处理器 类似上面,表单类为LoginForm
2、新建退出处理器com.demo.spring.forms.LogoutAction.java
public
class LogoutAction extends SimpleFormController {
protected ModelAndView onSubmit(HttpServletRequest request,
HttpServletResponse response, Object command,BindException errors)
throws Exception {
request.getSession().invalidate();
response.sendRedirect("login.do");
return
null;
}
tips:这里使用重定向返回login.do而不是login.jsp,是为了让返回的页面由Spring容器来处理
8.4开发用户注册功能
1、新建登录页面register.jsp
<form
name="form1"action="register.do?method=register"
method="post">
<table
width="300"border="1">
<tr>
<td
colspan="2">注册窗口</td>
</tr>
<tr>
<td>用户名</td>
<td><input
type="text"name="username"
size="10"/></td>
</tr>
<tr>
<td>密码</td>
<td><input
type="password"name="password1"
size="10"/></td>
</tr>
<tr>
<td>确认密码</td>
<td><input
type="password"name="password2"
size="10"/></td>
</tr>
<tr>
<td
colspan="2">
<input
type="submit"
name="submit"value="注册"/>
<a
href="login.do">返回</a>
</td>
</tr>
</table>
</form>
2、配置处理器映射与处理器 类似上面
3、新建注册表单类com.demo.spring.forms.RegisterForm.java
4、新建注册处理器com.demo.spring.actions.RegisterAction.java
需要实现以下函数:
*请求处理入口函数 onSubmit()
*初始化处理函数init()
*注册函数register()
*判断用户是否存在函数isExist()
*新增用户函数add() 该函数目前为空,后文会增加数据库操作功能
public
class RegisterAction extends SimpleFormController {
public ModelAndView onSubmit(HttpServletRequest request,
HttpServletResponse response, Object command,BindException errors)
throws Exception {
String method = request.getParameter("method");
if (method ==
null || method.equals("init")) {
return init(command, errors);
} else
if (method.equals("register")) {
return register(request, response, command, errors);
} else {
RegisterForm registerForm = (RegisterForm) command;
Map modle = errors.getModel();
modle.put(getFormSessionAttributeName(), registerForm);
return
new ModelAndView(getFormView(), modle);
}
}
public ModelAndView init(Object command, BindException errors)
throws Exception {
RegisterForm registerForm = (RegisterForm) command;
Map modle = errors.getModel();
modle.put(getFormSessionAttributeName(), registerForm);
return
new ModelAndView(getFormView(), modle);
}
public ModelAndView register(HttpServletRequest request,
HttpServletResponse response, Object command,BindException errors)
throws IOException {
RegisterForm registerForm = (RegisterForm) command;
if (!isExist(registerForm)) {
add(registerForm);
Map modle = errors.getModel();
modle.put(getSuccessView(), registerForm);
//response.sendRedirect("login.do");
return
new ModelAndView(getSuccessView());
} else {
Map modle = errors.getModel();
modle.put(getFormView(), modle);
return
new ModelAndView(getFormView(), modle);
}
}
public
boolean isExist(RegisterForm registerForm) {
if(registerForm.getUsername().equals("root")) {
returntrue;
}else {
return false;
}
}
public
void add(RegisterForm registerForm) {
}
}
加上Hibeanate
8.1 配置数据源、SessionFactory、事务及DAO
1、数据源配置
<bean
id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property
name="driverClassName">
<value>com.mysql.jdbc.Driver</value>
</property>
<property
name="url">
<value>jdbc:mysql://localhost:3306/demo</value>
</property>
<property
name="username">
<value>root</value>
</property>
<property
name="password">
<value>12345</value>
</property>
</bean>
2、SessionFactory配置
配置SessionFactory对象,为DAO层提供Hibernate的数据库连接对象。其中需要注入上面配置的dataSource对象
<bean
id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property
name="dataSource">
<ref
local="dataSource"/>
</property>
<property
name="mappingResources">
<list>
<value>com/demo/hibernate/beans/User.hbm.xml</value>
</list>
</property>
<property
name="hibernateProperties">
<props>
<prop
key="hibernate.dialect">
org.hibernate.dialect.MySQLDialect
</prop>
<prop
key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
3、配置事务
为SessionFactory增加事务配置组件,并注入上面配置的SessionFactory对象。
<bean
id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property
name="sessionFactory">
<ref
local="sessionFactory"/>
</property>
</bean>
4、配置DAO组件
例如我们开发了一个基于HibernateTemplate的DAO类com.demo.hibernate.dao.UserDAO.java,则配置该组件的Bean对象,并为该对象注入SessionFactory对象。
<bean
id="userDAO"class="com.demo.hibernate.dao.UserDAO">
<property
name="sessionFactory">
<ref
local="sessionFactory"/>
</property>
</bean>
5、配置DAO事务
为上面配置的DAO对象配置事务组件,使得对userDAO的访问都在Spring的事务监管之下。该组件需要注入上面配置的事务对象transactionManager、DAO对象uerDAO,并配置事务管理的策略。
<bean
id="UserDAOProxy"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property
name="transactionManager">
<ref
bean="transactionManager"/>
</property>
<property
name="target">
<ref
local="userDAO"
/>
</property>
<property
name="transactionAttributes">
<props>
<prop
key="insert*">PROPAGATION_REQUIRED</prop>
<prop
key="*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean>
8.2 创建Hibernate DAO类
1、首先创建一个接口类com.demo.hibernate.dao.IUserDAO.java。创建接口的原因是为了让Spring的AOP机制能够进行事务的管理,因为事务的管理师基于AOP实现的。
public
interface IUserDAO {
//判断用户登录
public
boolean isValid(final String username,
final String password);
//判断用户是否存在
public
boolean isExist(String username);
//插入用户对象
public
void insertUser(User user);
//取得用户对象
public User getUser(String userid);
//取得所有用户
public
List getUsers();
//删除用户对象
public
void deleteUser(String userid);
}
2、根据用户登录和用户注册的实际操作逻辑,实现这些函数。
public
class UserDAO extends HibernateDaoSupport
implements IUserDAO {
//判断用户是否存在
public
boolean isExist(final String username) {
List list = (List)getHibernateTemplate().execute(new HibernateCallback(){
public Object doInHibernate(Session session)
throws HibernateException {
List result = session.createCriteria(User.class).add(
Restrictions.eq("username", username)).list();
return result;
}
});
if (list.size() > 0) {
return
true;
} else {
return
false;
}
}
//判断用户登录
public
boolean isValid(final String username,
final String password) {
List list = (List)getHibernateTemplate().execute(newHibernateCallback() {
public Object doInHibernate(Session session)
throws HibernateException, SQLException {
List result = session.createCriteria(User.class).add(
Restrictions.eq("username", username)).add(
Restrictions.eq("password", password)).list();
return result;
}
});
if (list.size() > 0) {
return
true;
} else {
return
false;
}
}
public List getUsers() {
return getHibernateTemplate().find("from User");
}
public
void insertUser(User user) {
getHibernateTemplate().saveOrUpdate(user);
}
public
void deleteUser(String userid) {
Object obj = getHibernateTemplate().load(User.class,
new Integer(userid));
getHibernateTemplate().delete(obj);
}
public User getUser(String userid) {
return (User)getHibernateTemplate().get(User.class,
new Integer(userid));
}
}
8.3 修改LoginAction访问UserDAO进行登录验证
1、首先需要为LoginAction添加一个变量
UserDAO userDAO;
get,set…
2、为application.xml中loginAction的配置注入userDAO变量,见粗体:
<bean
id="loginAction"
class="com.demo.spring.actions.LoginAction">
<property
name="commandClass">
<value>com.demo.spring.forms.LoginForm</value>
</property>
<!-- 指定DAO类 -->
<property
name="userDAO">
<ref
local="userDAO"
/>
</property>
<!-- 指定失败要返回的页面 -->
<property
name="formView">
<value>login</value>
</property>
<!-- 指定成功要返回的页面 -->
<property
name="successView">
<value>welcome</value>
</property>
</bean>
3、修改LoginAction处理类中用户登录验证的函数isValid()。它使用被注入对象userDAO的isValid()函数,即可查找。
private
boolean isValid(LoginForm loginForm) {
if (userDAO.isValid(loginForm.getUsername(), loginForm.getPassword())){
return
true;
} else {
return
false;
}
}
8.4 修改RegisterAction访问UserDAO进行用户注册
1、首先需要为RegisterAction添加一个变量,如上。
2、为application.xml中RegisterAction的配置注入userDAO变量,如上。
3、修改RegisterAction处理类中isExist()。
public
boolean isExist(RegisterForm registerForm) {
if (userDAO.isExist(registerForm.getUsername())) {
return
true;
} else {
return
false;
}
}
4、修改RegisterAction处理类中处理函数add(),它使用被注入对象userDAO的insertUser()函数,即可往数据库中插入一个新的用户数据。
public
void add(RegisterForm registerForm) {
User user = new User();
user.setUsername(registerForm.getUsername());
user.setPassword(registerForm.getPassword1());
userDAO.insertUser(user);
}
五、Struts 2
从开发者角度看,需要显示给用户的数据可以直接从Action中获取,而不像Struts那样必须把相应的Bean存到Page、Request或者Session中才能获取。
1、Struts 2的体系结构
在Struts 2中共包含两个配置文件
*struts.properties定义了Struts 2运行的属性配置,通过修改这些属性也可以控制Struts 2的行为;
*struts.xml供开发者添加用户请求的映射列表,通过该列表可以将用户的请求与Action类对应起来。
Struts2的请求时由FilterDispatcher来进行拦截的,当接收用户的请求时,它会在struts.xml中查找对应的请求映射配置,得到使用哪些拦截器Interceptors、Action类和返回结果Result的信息,然后依次做如下操作
1.1请求通过一系列的拦截器
Interceptors是Struts 2中的一种过滤机制,它基于AOP的四项进行设计,通常可以用于日志记录、权限限制等。
1.2调用Action
产生一个新的Action对象实例,并提供请求所调用的处理逻辑的方法,并调用Model层执行业务逻辑的操作,然后返回映射配置中指定的Result页面。
1.3业务处理
业务逻辑通常由JavaBean或EJB组件来实现,以实现文件、数据库、通信等的相关操作。
1.4调用相应的Result
通过匹配处理Action方法之后的返回值,获取相应Result类,生成并调用它的实例。处理Result可能产生的结果之一就是对UI模板(但并非只有一个)进行渲染,来产生HTML。如果是此情况,模板中的Struts 2 tags可以直接从Action中获取要被渲染的值。
1.5响应被返回给用户
最后一步是将控制权交还给Servlet引擎。最常见的结果是把渲染后的HTML返回给用户,但返回的也可能是指定的HTTP头或者进行HTTP重定向。
2、Struts 2开发流程
2.1编写输入表单input.jsp
2.2配置struts.xml
在struts.xml中添加程序 web.xml里选择用/*,则所有的都可以进入
<constant
name="struts.action.extension"value="action,do"
/>
<package
name="Test"
namespace="/"extends="struts-default">
<action
name="test"
class="com.test.action.TestAction">
<result
name="success">/success.jsp</result>
</action>
</package>
这里配置了一个<action>元素,它包含两个属性:
*name属性:请求的映射地址
*class属性:请求的Action处理类
并通过<result>子元素添加了两个返回映射地址
*success:表示成功的返回地址success.jsp
*input:表示失败的返回地址input.jsp
2.3编写处理类TestAction.java
public
class TestAction extends ActionSupport {
private String
str1;
private String
str2;
(get,set…)
public String execute()
throws Exception {
System.out.println("****enterTestAction****");
if (!str1.equals("") && !str2.equals(""))
{
ActionContext.getContext().getSession().put("str1",
str1);
ActionContext.getContext().getSession().put("str2",
str2);
return Action.SUCCESS;
} else {
return Action.INPUT;
}
}
}
struts 2框架会接收Input.jsp中的参数并进行赋值,然后调用默认的excute()函数来执行请求任务。
2.4编写返回JSP页面success.jsp
(String)session.getAttribute("str1")取值
3、Struts 2核心组件
3.1映射文件struts.xml
1、属性定义元素<constant> 该属性与struts.properties中的属性重名,并覆struts.properties中的该属性的值。这样做的好处是,如果使用了多个映射文件,允许每一个文件都使用不同的属性。
2、导入子文件元素<include>
3、包定义元素<package>
<package>定义了一组<action>和拦截器元素,可以定义多个<action>元素,name表示包的名字,extends表示继承自struts-default.xml(位于Struts 2的核心jar包的根目录)中所定义的包的名字。在struts-default.xml中默认定义了struts-default的包名,继承包的意义是,被继承包中的拦截器都可以在其继承的包中使用。
4、Action映射配置元素<action>
Action mappings能指定一系列的Result、异常处理器以及拦截器。<action>元素的所有属性中只有name是必需的,其他属性都是可选的。不指定method属性的话,默认调用execute()函数进行处理,可调用自己编写在类中的其他函数。
如果一个Action类处理多个请求,可用!。!之前的名字“login”是action的name属性名,之后的名字login()、logout()分别是Action中的函数名。
<action name=”login” class=”com.demo.struts.actions.LoginAction”>
<result name=”success”>welcome.jsp</result>
<result name=”input”>login.jsp</result>
</action>
然后分别使用以下两个请求地址来实现对两个函数的调用
…/demo/login!login.do
…/demo/login!logout.do
5、Result配置元素<result>
返回不同的结果。有时我们的Result在运行前是未知的,这时可用动态的Result。如下:
public String getNextAction() {
returnnextAction;
}
<action name=”test”>
<resultname=”next” type=”redirect-action”>${nextAction}</result>
</action>
6、配置全局映射元素<global-results> 定义在<action>元素中的<result>称之为局部<result>,此外可定义全局的,全局的<result>会被多个<action>共享。框架会先寻找局部,无匹配则再寻找全局。如下:
<global-results>
<resultname=”error”>/error.jsp</result>
</global-results>
7、配置拦截器<interceptors> 拦截器是以Java类的形式实现的,因此每一个拦截器都有一个唯一的类名。默认的拦截器会作用于<package>中的每个<action>上,<action>也可以定义自己的本部栈。
<interceptors>
<interceptor name=”security” class=”com.demo.security.SecurityInterceptor”/>
<interceptor-stack name=”secureStack”>
<interceptor-refname=”security” />
<interceptor-refname=”defaultStack” />
</interceptor-stack>
</interceptors》
局部:
<action …>
<result name=”success”>success.jsp</result>
interceptor-refname=”defaultComponentStack” />
</action>
3.2Action处理器
Struts 2中,任何的POJO类都可以用作Action类。如:
public class LoginAction{
publicString execute() throws Exception {
returnsuccess;
}
}
Struts 2中的Action不再继承与任何类或需要实现任何接口,而且任何声明为publicString methodName()的方法都能通过配置来调用Action
函数的返回对象不是ActionForward,而是String
处理Action过程中调用的方法是不带参数的,但允许使用ActionContext和ServletActionContext来取得系统的Session、Request、Response、Application等对象
所以,能让Action和框架完全解耦。
理论上Struts 2无须实现任何借口或继承任何类型,但为了方便实现Action,大多数情况下回继承com.opensymphony.xwork2.ActionSupport类,并重载此类中的execute()方法。
在Action中取得表单数据 即get,set..
在Action中访问上下文变量,如request、response、session等:
1、非IoC方式
可直接使用com.opensymphony.xwork2.ActionContext类,可通过它的getContext()获取当前Action的上下文对象。此外,org.apache.struts 2.ServletActionContext作为辅助类,可快捷地获得这几个对象。用法:
HttpServletRequest request =ServletActionContext.getRequest();
HttpServletResponse response =ServletActionContext.getResponse();
HttpSession session = request.getSession();
如果只是想访问session的属性(Attribute),也可通过ActionContext.getContext().getSession()获取或添加session范围(Scoped)的对象。如下:
ActionContext.getContext().getSession().put("msg",
"Hello");
2、IoC方式
要使用IoC方式,首先要告诉IoC容器想取得某个对象的意愿,通过实现相应的接口做到这点。包括SessionAware、ServletRequestAware、ServletResponseAware,这样即可在该类中定义相应的变量(要添加setter)。
public
class IocServlet extends ActionSupport
implementsSessionAware,ServletRequestAware,ServletResponseAware {
private Map
attrubutes;
private HttpServletRequest
request;
private HttpServletResponse
response;
(get,set…)
…
}
4、 Struts 2标签库
4.1映射文件struts.xml
1、属性定义元素<constant> 该属性与struts.properties中的属性重名,并覆struts.properties中的该属性的值