1.pojo类
2.hbm映射
3.dao接口
4.dao实现类
5.daoContext
6.数据库表
7.service 接口
8.service 业务逻辑组件
9.vo 封装
10.applicationContext.xml
11.action类
12.拦截器
13.jsp页面
14.struts.xml
****************************************************
一
1. hashcode()是干什么用的?
2. 如果我实现了comparable接口,重写了equals(),为什么还要重写hashCode()呢?默认的equals()是比的hashCode吗?hashCode是基于内存地址计算出来的,可是一个类的两个实例是放在堆区不同的地址空间的,为什么计算出的hash码还是一样的呢?
1.hashcode是用来查找的,如果你学过数据结构就应该知道,在查找和排序这一章有
例如内存中有这样的位置
0 1 2 3 4 5 6 7
而我有个类,这个类有个字段叫ID,我要把这个类存放在以上8个位置之一,如果不用hashcode而任意存放,那么当查找时就需要到这八个位置里挨个去找,或者用二分法一类的算法。
但如果用hashcode那就会使效率提高很多。
我们这个类中有个字段叫ID,那么我们就定义我们的hashcode为ID%8,然后把我们的类存放在取得得余数那个位置。比如我们的ID为9,9除8的余数为1,那么我们就把该类存在1这个位置,如果ID是13,求得的余数是5,那么我们就把该类放在5这个位置。这样,以后在查找该类时就可以通过ID除8求余数直接找到存放的位置了。
2.但是如果两个类有相同的hashcode怎么办那(我们假设上面的类的ID不是唯一的),例如9除以8和17除以8的余数都是1,那么这是不是合法的,回答是:可以这样。那么如何判断呢?在这个时候就需要定义 equals了。
也就是说,我们先通过 hashcode来判断两个类是否存放某个桶里,但这个桶里可能有很多类,那么我们就需要再通过 equals 来在这个桶里找到我们要的类。
那么。重写了equals(),为什么还要重写hashCode()呢?
想想,你要在一个桶里找东西,你必须先要找到这个桶啊,你不通过重写hashcode()来找到桶,光重写equals()有什么用啊
1.hashCode()方法使用来提高Map里面的搜索效率的,Map会根据不同的hashCode()来放在不同的桶里面,Map在搜索一个对象的时候先通过hashCode()找到相应的桶,然后再根据equals()方法找到相应的对象.要正确的实现Map里面查找元素必须满足一下两个条件:
(1)当obj1.equals(obj2)为true时obj1.hashCode() == obj2.hashCode()必须为true
(2)当obj1.hashCode() != obj2.hashCode()为true时obj.equals(obj2)必须为true
任何class如果覆写了equals()方法,就必须覆写hashCode()。
这样作的目的就是为了你的类就能够很好的与java的集合框架协同工作。如果我们能够确认我们定义的类不会和java集合类产生关系,那么我们完全没有必要在覆写equals()方法的时候覆写hashCode。
针对HashSet:
Set不允许重复
允许 null,重复的null只算一个
判断是否存在一个数据(是否重复),先判断其hashCode是否存在,若存在再逐个判断hashCode相同的数据是否相等
判断是否相等,除了hashCode相等外,还要判断对象引用相等(==),或者 equals
如果一个对象的hashCode变动了,会造成找不到这个对象,也就出现了内存泄漏的危险。
---------------------------------------------------------------------------------------------------------------------------------------------
二
我想知道Hibernate 中lazy的作用?写不写有区别么?什么时候要写?
延迟加载
比如查询一张表时,有外键对应另一张表
可以使用延迟加载
这样就不会把外键对应表的数据加载
----------------------------------------------------------------------------------------------------------------------------------------------
三
inverse=true的含义: 由双向关联另一方维护该关联,己方不维护该关联(只能进行查询操作)。
-----------------------------------------------------------------------------------------------------------------------------------------------
最近在负责一个大项目,项目组成员包括项目经理大概10个人左右。项目技术用struts+spring+hibernate实现。项目的规模相对来说是比较大的,总共有10大模块,每个大模块又分为有十几个、甚至几十个小模块。开发工具用eclipse,由于在开发阶段,项目开发成员需要频繁重启服务器。在启动服务器的时候,每次启动时间总是会超过1分钟。记得以前在做另外一个项目时,启动时间不到5秒钟,相差了10倍,而且项目规模是差不多的。
从初步分析来说,应该是hibernate解释hbm.xml时花费时间,或者可能是spring容器启动并解释所有的bean配置文件。诊断了一下,发现1分钟消耗的时间主要分布在hibernate解释hbm.xml花费5秒;spring容器从启动到解释bean配置文件竟然花了58秒,真是太嚣张了。当时非常怀疑spring的效率问题。企图从网上搜索相关资料,看看有什么优化措施。
首先是找到了hibernate的启动优化 http://www.hibernate.org/194.html 里面的主要思想是通过将xml序列花到本地的文件里,每次读取的时候根据情况,从本地文件读取并反序列化,节省了hibernate xml的解析时间。按照这个方式测试了一下,发现hibernate的启动时间从5秒降低到3秒,但是这个优化对于整个启动过程是杯水车薪的,毫无用处。
没办法,又仔细查看了spring的资料,终于发现spring的容器是提供了lazy-load的,即默认的缺省设置是bean没有lazy- load,该属性处于false状态,这样导致spring在启动过程导致在启动时候,会默认加载整个对象实例图,从初始化ACTION配置、到 service配置到dao配置、乃至到数据库连接、事务等等。这么庞大的规模,难怪spring的启动时间要花将近1分钟。尝试了一下,把beans的 default-lazy-init改为true就,再次启动,速度从原来的55秒,降到8秒钟!!Great!虽然是非常小一个改动,但是影响确实非常大。一个项目组10个人,假若每个人一天平均需要在eclipse下启动测试服务器50次。那么一天项目组需要重启500次,每次节省50秒的话,就是 25000秒,将近几个小时,差不多一个工作日,多么可观的数字!
不过在运行期间第一次点页面的时候,由于spring做了lazy-load,现在就需要启动一部分需要的beans,所以稍微慢2-3秒钟,但是明显比等几十秒要快很多,值得一鉴。
以上是针对开发阶段的spring容器启动优化,在部署到实际环境中,倒是没必要设置为lazy-load。毕竟部署到实际环境中不是经常的事,每次启动1分钟倒不是大问题。
-------------------------------------------------------------------------------------------------------------------------------------------
String dutyDay = new java.sql.Date(
System.currentTimeMillis()).toString();
System.currentTimeMillis():currentTimeMillis
public static long currentTimeMillis()返回以毫秒为单位的当前时间。注意,当返回值的时间单位是毫秒时,值的粒度取决于底层操作系统,并且粒度可能更大。例如,许多操作系统以几十毫秒为单位测量时间。 返回:
当前时间与协调世界时 1970 年 1 月 1 日午夜之间的时间差(以毫秒为单位测量)。
java.sql.Date.toString:把此 Date 对象转换为以下形式的 String: dow mon dd hh:mm:ss zzz yyyy 其中: dow 是一周中的某一天 (Sun, Mon, Tue, Wed, Thu, Fri, Sat)。
---------------------------------------------------------------------------------------------------------------------------------
4.只读
该标志可以设定为true,表明该事物不修改任何持久性状态。更多的情况下,这只是个提示,因为不是所有的事务性资源都可以利用这个设定。
在使用Hibernate的时候,它尤为有用,因为它告知Hibernate不要在只读事务中检测和刷新变化
不要搞清AOP的事务管理模式,就一定要搞清AOP的概念先。
SPRING中的事务管理一般这样实现:
1、定义事务管理器(死的)
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
2、定义advice(决策),主要是定义当调用什么方法时,用什么事务模式
<tx:advice id="txAdvice" transaction-manager="txManager">
<!-- the transactional semantics... -->
<tx:attributes>
<!-- all methods starting with 'get' are read-only -->
<tx:method name="get*" read-only="true" />
<tx:method name="statistic" read-only="true" />
<tx:method name="is*" read-only="true" />
<tx:method name="list*" read-only="true" />
<tx:method name="select*" read-only="true" />
<tx:method name="get*AndUpdate*" />
<!-- other methods use the default transaction settings (see below) -->
<tx:method name="*" />
</tx:attributes>
</tx:advice>
上面的例子代码是定义在某些方法时,事务是read-only的,比如get*(以get开头的方法名),还有些事务是write的,比如 get*AndUpdate*,表示匹配get开头,中间有AndUpdate的方法都是写事务。最后的*最后起作用,因此就是上面未定义的方法名匹配都是写事务。
3、规划需要管理事务的类和方法,最好把它们放都到同一个包里面,这样定义起来方便一些。
4、定义切入点,即什么类会被切入而进入advice:
<aop:config>
<aop:pointcut id="xxxxTxPointcut"
expression="execution(* com.xxx.yyy.service.**.*(..))" />
<aop:advisor advice-ref="txAdvice"
pointcut-ref="xxxxTxPointcut" order="1" />
</aop:config>
上面的例子是定义com.xxx.yyy.service包内的及其子包的类会被切入。
这样,如果你有一个类:com.xxx.yyy.service.UserService,里面有一个方法 newUser();
按照上面的设置,当你调用UserService.newUser方法时,SPRING的事务管理器就启动一个事务,当整个方法执行完成,并且未出现异常,那么事务管理器自动提交。如果调用中出现异常,事务管理器就rollback
假设newUser你修改了2个表,比如用户ID表和用户信息表,只有当2个表的操作均未出异常,事务管理器才会提交。
-------------------------------------------------------------------------------------------------------------------------------
struts2 OGNL,struts2 表达式语言,Struts2 中OGNL表达式的用法,Struts2 #,表达式语言的好处,Struts2 $,struts2 井号,星号,百分号
表达式语言主要有以下几大好处:
1. 避免(MyType) request.getAttribute()和myBean.getMyProperty()之类的语句,使页面更简洁;
2. 支持运算符(如+-*/),比普通的标志具有更高的自由度和更强的功能;
3. 简单明了地表达代码逻辑,使用代码更可读与便于维护。
Struts2 中OGNL表达式的用法:
OGNL(Object-Graph Navigation Language),可以方便地操作对象属性的开源表达式语言;
“#”主要有三种用途:
1. 访问OGNL上下文和Action上下文,#相当于ActionContext.getContext();下表有几个ActionContext中有用的属性:
名称 作用 例子
parameters 包含当前HTTP请求参数的Map #parameters.id[0]作用相当于request.getParameter("id")
request 包含当前HttpServletRequest的属性(attribute)的Map #request.userName相当于request.getAttribute("userName")
session 包含当前HttpSession的属性(attribute)的Map #session.userName相当于session.getAttribute("userName")
application 包含当前应用的ServletContext的属性(attribute)的Map #application.userName相当于application.getAttribute("userName")
attr 用于按request > session > application顺序访问其属性(attribute) #attr.userName相当于按顺序在以上三个范围(scope)内读取userName属性,直到找到为止
2. 用于过滤和投影(projecting)集合,如books.{?#this.price<100};
3. 构造Map,如#{'foo1':'bar1', 'foo2':'bar2'}。
“%”的用途是在标志的属性为字符串类型时,计算OGNL表达式的值。例如在Ognl.jsp中加入以下代码:
<hr />
<h3>%的用途</h3>
<p><s:url value="#foobar['foo1']" /></p>
<p><s:url value="%{#foobar['foo1']}" /></p>
“$”有两个主要的用途 :
1. 用于在国际化资源文件中,引用OGNL表达式,例子请参考《在Struts 2.0中国际化(i18n)您的应用程序》
2. 在Struts 2配置文件中,引用OGNL表达式,如
<action name="AddPhoto" class="addPhoto">
<interceptor-ref name="fileUploadStack" />
<result type="redirect">ListPhotos.action?albumId=${albumId}</result>
</action>
--------------------------------------------------------------------------------------------------------------------------------
如何自定义一个拦截器?
自定义一个拦截器需要三步:
1 自定义一个实现Interceptor接口(或者继承自AbstractInterceptor)的类。
2 在strutx.xml中注册上一步中定义的拦截器。
3 在需要使用的Action中引用上述定义的拦截器,为了方便也可将拦截器定义为默认的拦截器,这样在不加特殊声明
的情况下所有的Action都被这个拦截器拦截。
Interceptor接口声明了三个方法:
public interface Interceptor extends Serializable {
void destroy();
void init();
String intercept(ActionInvocation invocation) throws Exception;
}
Init方法在拦截器类被创建之后,在对Action镜像拦截之前调用,相当于一个post-constructor方法,
使用这个方法可以给拦截器类做必要的初始话操作。
Destroy方法在拦截器被垃圾回收之前调用,用来回收init方法初始化的资源。
Intercept是拦截器的主要拦截方法,如果需要调用后续的Action或者拦截器,只需要在该方法中调用
invocation.invoke()方法即可,在该方法调用的前后可以插入Action调用前后拦截器需要做的方法。
如果不需要调用后续的方法,则返回一个String类型的对象即可,例如Action.SUCCESS。
另外AbstractInterceptor提供了一个简单的Interceptor的实现,这个实现为:
public abstract class AbstractInterceptor implements Interceptor {
public void init() {
}
public void destroy() {
}
public abstract String intercept(ActionInvocation invocation) throws Exception;
}
在不需要编写init和destroy方法的时候,只需要从AbstractInterceptor继承而来,实现intercept方法即可。
我们尝试编写一个Session过滤用的拦截器,该拦截器查看用户Session中是否存在特定的属性(LOGIN属性)
如果不存在,中止后续操作定位到LOGIN,否则执行原定操作,代码为:
public class CheckLoginInterceptor extends AbstractInterceptor {
public static final String LOGIN_KEY = "LOGIN";
public static final String LOGIN_PAGE = "global.login";
public String intercept(ActionInvocation actionInvocation) throws Exception {
System.out.println("begin check login interceptor!");
// 对LoginAction不做该项拦截
Object action = actionInvocation.getAction();
if (action instanceof LoginAction) {
System.out.println("exit check login, because this is login action.");
return actionInvocation.invoke();
}
// 确认Session中是否存在LOGIN
Map session = actionInvocation.getInvocationContext().getSession();
String login = (String) session.get(LOGIN_KEY);
if (login != null && login.length() > 0) {
// 存在的情况下进行后续操作。
System.out.println("already login!");
return actionInvocation.invoke();
} else {
// 否则终止后续操作,返回LOGIN
System.out.println("no login, forward login page!");
return LOGIN_PAGE;
}
}
}
注册拦截器
<interceptors>
<interceptor
name="login"
class="com.jpleasure.teamware.util.CheckLoginInterceptor"/>
<interceptor-stack name="teamwareStack">
<interceptor-ref name="login"/>
<interceptor-ref name="defaultStack"/>
</interceptor-stack>
</interceptors>
将上述拦截器设定为默认拦截器:
<default-interceptor-ref name="teamwareStack"/>
这样在后续同一个package内部的所有Action执行之前都会被login拦截。
------------------------------------------------------------------------------------------------------------
索引的用法
如果指定了status,每次的迭代数据都有IteratorStatus的实例,它有以下几个方法
int getCount()返回当前迭代了几个元素
int getIndex()返回当前元素索引
boolean isEven()当然的索引是否偶数
boolean isFirst()当前是否第一个元素
boolean isLast()
boolean isOdd()当前元素索引是否奇数
<s:iterator value="{'a','b','c'}" id='char' status='st'>
<s:if test="#st.Even">
现在的索引是奇数为:<s:property value='#st.index'/>
</s:if>
当前元素值:<s:property value='char'/>
</s:iterator>
-------------------------------------------------------------------------------------------------------------
<interceptor-ref name="basicStack"/>
拦截器栈
<interceptor-stack name="basicStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="servlet-config"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="params"/>
<interceptor-ref name="conversionError"/>
</interceptor-stack>
---------------------------------------------------------------------------------------------------------------
任务调度
<!-- 定义触发器来管理任务Bean -->
<bean id="cronTriggerPay"class="org.springframework.scheduling.quartz.CronTriggerBean">
//jobDetail指定
<property name="jobDetail">
<!-- 使用嵌套Bean的方式来定义任务Bean -->
<bean class="org.springframework.scheduling.quartz.JobDetailBean">
<!-- 指定任务Bean的实现类 -->
//jobClass指定
<property name="jobClass"
value="org.qjkt.hrsystem.schedule.PayJob"/>
<!-- 为任务Bean注入属性 -->
//jobDataAsMap指定
<property name="jobDataAsMap">
<map>
<entry key="empMgr" value-ref="empManager"/>
</map>
</property>
</bean>
</property>
<!-- 指定Cron表达式:每月3日2时启动 -->
// //cronExpression指定
<property name="ceonExpression" value="0 0 2 3 * ? *"/>
</bean>
<!-- 定义触发器来管理任务Bean -->
<bean id="cronTriggerPunch"
class="org.springframework.scheduling.quartz.CronTriggerBean">
//jobDetail指定
<property name="jobDetail">
<!-- 使用嵌套Bean的方式来定义任务Bean -->
<bean
class="org.springframework.scheduling.quartz.JobDetailBean">
<!-- 指定任务Bean的实现类 -->
//jobClass指定
<property name="jobClass"
value="org.qjkt.hrsystem.schedule.PunchJob"/>
<!-- 为任务Bean注入属性 -->
//jobDataAsMap指定
<property name="jobDataAsMap">
<map>
<entry key="empMgr" value-ref="empManager"/>
</map>
</property>
</bean>
</property>
<!-- 指定Cron表达式:周一到周五7点、12点执行调度 -->
//cronExpression指定
<property name="cronExpression"
value="0 0 7,12 ? * MON-FRI"/>
</bean>
<bean
class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
//triggers指定
<property name="triggers">
<list>
<ref local="cronTriggerPay"/>
<ref local="cronTriggerPunch"/>
</list>
</property>
</bean>
--------------------------------------------------------------------------------------------------------------------
Message Store Interceptor
一个拦截器存储ValidationAware Action的消息/错误和字段错误到Http Session,这样它将被重新获取在最后阶段.这允许Action的消息/错误和字段错误长期有效在特定的http请求.
在’STORE’模式中,拦截器将重新获取存储的Action 消息/错误和字段错误并且放他们到ValidationAware Action.
拦截器在’NONE’模式中什么也不做,其中一个是默认的.
操作模式可以被交换使用:
1]设置拦截器参数例子.
<action name="submitApplication" ...>
<interceptor-ref name="store">
<param name="operationMode">STORE</param>
</interceptor-ref>
<interceptor-ref name="defaultStack" />
....
</action>
2]通过请求参数(allowRequestParameterSwitch 必需为’true’,是默认的)
// the request will have the operation mode in 'STORE'
http://localhost:8080/context/submitApplication.action?operationMode=STORE
参数
. allowRequestParameterSwitch-开启请求参数可以交换拦截器的操作模式.
. requestParameterSwitch-指示拦截器中使用什么样的请求参数.
.operationMode-这个拦截器使用的操作模式(‘STORE’,’RETRIEVE’或’NONE’其中一个).’NONE’为默认.
扩展拦截器
下面的方法将被覆盖:
. getRequestOperationMode-获取拦截器的操作模式基于请求参数.
.mergeCollection-合并两个集合.
.mergeMap – 合并两个map
例子
<action name="submitApplication" ....>
<interceptor-ref name="store">
<param name="operationMode">STORE</param>
</interceptor-ref>
<interceptor-ref name="defaultStack" />
<result name="input" type="redirect">applicationFailed.action</result>
<result type="dispatcher">applicationSuccess.jsp</result>
</action>
<action name="applicationFailed" ....>
<interceptor-ref name="store">
<param name="operationMode">RETRIEVE</param>
</interceptor-ref>
<result>applicationFailed.jsp</result>
</action>
同上面的例子, 'submitApplication.action'有Action消息/错误/字段错误存储到Http会话中.以后需要的时候,在这种情况下,’applicationFailed.action’被激活,它将获取Action 消息/错误/字段错误存储在HTTP会话中并且放回到Action.
______________________________________________________________________________________________________________________________________________________________________________________________
与Servlet API耦合的访问方式
直接访问Servlet API将使你的Action与Servlet环境耦合在一起,我们知道对于HttpServletRequest、HttpServletResponse和ServletContext这些对象,它们都是由Servlet容器来构造的,与这些对象绑定在一起,测试时就需要有Servlet容器,不便于Action的单元测试。但有时候,我们又确实需要直接访问这些对象,那么当然是以完成任务需求为主。
要直接获取HttpServletRequest和ServletContext对象,可以使用org.apache.struts2. ServletActionContext类,该类是ActionContext的子类,在这个类中定义下面两个静态方法:
public static HttpServletRequest getRequest()
得到HttpServletRequest对象。
public static ServletContext getServletContext()
得到ServletContext对象。
此外,ServletActionContext类还给出了获取HttpServletResponse对象的方法,如下:
public static HttpServletResponse getResponse()
ServletActionContext类并没有给出直接得到HttpSession对象的方法,HttpSession对象可以通过HttpServletRequest对象来得到。
除了上述的方法调用得到HttpServletRequest和ServletContext对象外,还可以调用ActionContext对象的get()方法,传递ServletActionContext.HTTP_REQUEST和ServletActionContext.SERVLET_CONTEXT键值来得到HttpServletRequest和ServletContext对象,如下所示:
ActionContext.getContext().get(ServletActionContext.HTTP_REQUEST);
得到与ServletActionContext.HTTP_REQUEST键值绑定的HttpServletRequest对象。
ActionContext.getContext().get(ServletActionContext.SERVLET_CONTEXT);
得到与ServletActionContext.SERVLET_CONTEXT键值绑定的ServletContext对象。
同样的,也可以向ActionContext的get()方法传递ServletActionContext.HTTP_ RESPONSE键值来得到HttpServletResponse对象,如下:
ActionContext.getContext().get(ServletActionContext.HTTP_RESPONSE);
建议读者采用第一种方式来获取HttpServletRequest和ServletContext对象,这样简单而又清晰。
我们看例3-14。
例3-14 通过ServletActionContext来获取HttpServletRequest和ServletContext对象的LoginAction3
package org.sunxin.struts2.ch03.action.way2;import javax.servlet.ServletContext;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpSession;
import org.apache.struts2.ServletActionContext;
import org.sunxin.struts2.ch03.model.User;
import com.opensymphony.xwork2.Action;
public class LoginAction3 implements Action
{
...
@Override
public String execute() throws Exception
{
if("zhangsan".equals(user.getUsername())
&& "1234".equals(user.getPassword()))
{
HttpServletRequest request = ServletActionContext.getRequest();
HttpSession session = request.getSession();
ServletContext context = ServletActionContext.getServletContext();
/*ActionContext ctx = ActionContext.getContext();
HttpServletRequest request = (HttpServletRequest)ctx.get(Servlet ActionContext.HTTP_REQUEST);
HttpSession session = request.getSession();
ServletContext context = (ServletContext)ctx.get(ServletAction Context.SERVLET_CONTEXT);*/
//在请求中放置欢迎信息。
request.setAttribute("greeting", "欢迎您来到程序员之家");
//在session中保存user对象
session.setAttribute("user", user);
//统计用户访问量,在application中保存用户访问量数据
Integer count = (Integer)context.getAttribute("counter");
if(null == count)
count=1;
else
count++;
context.setAttribute("counter", count);
return SUCCESS;
}
else
{
return ERROR;
}
}
}
完整的代码请参看本书配套光盘中的ch03_4目录,测试时,输入URL:
http://localhost:8080/ch03_4/login3.jsp
除了利用ServletActionContext来获取HttpServletRequest对象和ServletContext对象这种方式外,Action类还可以实现ServletRequestAware和ServletContextAware接口,由Struts 2框架向Action实例注入HttpServletRequest和ServletContext对象。
org.apache.struts2.interceptor.ServletRequestAware接口只有一个方法,如下所示:
void setServletRequest(HttpServletRequest request)
org.apache.struts2.util.ServletContextAware接口也只有一个方法,如下所示:
void setServletContext(ServletContext context)
ServletRequestAware接口和ServletContextAware接口不属于同一个包,前者在org.apache.struts2.interceptor包中,后者在org.apache.struts2.util包中,这很让人迷惑。
我们看例3-15。
例3-15 通过接口注入来获取HttpServletRequest和ServletContext对象的LoginAction4
package org.sunxin.struts2.ch03.action.way2;import javax.servlet.ServletContext;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpSession;
import org.apache.struts2.interceptor.ServletRequestAware;
import org.apache.struts2.util.ServletContextAware;
import org.sunxin.struts2.ch03.model.User;
import com.opensymphony.xwork2.Action;
public class LoginAction4 implements Action, ServletRequestAware, ServletContextAware
{
private HttpServletRequest request;
private ServletContext context;
…
@Override
public String execute() throws Exception
{
if ("zhangsan".equals(user.getUsername())
&& "1234".equals(user.getPassword()))
{
HttpSession session = request.getSession();
//在请求中放置欢迎信息。
request.setAttribute("greeting", "欢迎您来到程序员之家");
//在session中保存user对象
session.setAttribute("user", user);
//统计用户访问量,在application中保存用户访问量数据
Integer count = (Integer) context.getAttribute("counter");
if (null == count)
count = 1;
else
count++;
context.setAttribute("counter", count);
return SUCCESS;
}
else
{
return ERROR;
}
}
@Override
public void setServletRequest(HttpServletRequest request)
{
this.request = request;
}
@Override
public void setServletContext(ServletContext context)
{
this.context = context;
}
}
LoginAction4类实现了ServletRequestAware和ServletContextAware接口,框架在运行时会调用这两个接口中的方法,向LoginAction4注入HttpServletRequest和ServletContext对象。在execute()方法中不再需要访问ServletActionContext,因此我们删除了与之相关的代码。
完整的代码请参看本书配套光盘中的ch03_4目录,测试时,输入URL:
http://localhost:8080/ch03_4/login4.jsp
-----------------------------------------------------------------------------------------------------------------------------------------
太奇怪了
主页面login.jsp 调用页面header.jsp
<%@ page contentType="text/html; charset=gb2312"%>
<%@ include file="header.jsp"%>
login.jsp的必须要与header.jsp看齐!!!! header.jsp向login.jsp看齐则不行!
------------------------------------------------------------------------------
return (List<Employee>)getHibernateTemplate().find("from Employee as b where "+
"b.manager=?",mgr);
第一种对 第二种错
return (List<Employee>)getHibernateTemplate().find("from Employee as b where"+
"b.manager=?",mgr);