原文:http://www.po-soft.com/blog/yongtree/937.html
Web 应用程序中一个常见的用法是,先对请求进行处理然后将请求重定向到另外一个控制器、servlet或其他对象。这种做法本身没什么问题,但是当请求被重定向时它会创建一个崭新的request,并将原本保存在request属性中的数据全都清除掉,因此重定向的目标操作就无法再获得这些数据。当我们使用struts2的actionmessage的时候,遇到重定向,这些消息全都over了。
有些开发者为了避免上述情况的发生而将这些信息保存在session中。这种做法很好,但开发人员会经常忘记清除临时数据,并且需要开发人员自行维护session的状态。无疑增加了程序的开发的复杂性和无畏的性能浪费。
为了解决这个问题,Grails模仿Rails引入了Flash Scope。flash对象只将数据保存在下一次的请求中,在下一次请求之后会自动清除其中的数据。这样不仅减小了开发人员的负担,也使我们能够专注于当前的问题而不用担心其他问题。
Flash
作用域的确可以很好的解决这个问题,可惜我们常用的SSH框架中,却一直缺少这样一个作用域,不知道Struts2的开发者能不能在以后的版本中增加这样的一个功能。等不了他了,还是我们自己手工创造这样一个对象来解决现有的问题吧。
最简单的办法,就是将Grails的实现移植到Struts2中。
首先我们下载Grails的源代码包,并找到Flash对象,将其实现按步照班的移植到struts2中。主要修改主要包括两个部分。第一是将Grails的request上下文改成struts2的;第二删掉我们不适用的Grails对错误信息的处理。
下面就开始简单的介绍修改后的程序,主要有三个类。
第一我们定义一个Flash对象的接口:FlashScope.java
Java代码
- public interface FlashScope extends Map, Serializable {
- /**
- * 设置一个flash作用域经过新的请求到下个状态。
- */
- void next();
- /**
- * 返回flash对象现有的状态,如果你不希望在下面的请求中使用包含的变量。
- *
- * @return A map
- */
- Map getNow();
- }
第二开始编写该接口
Struts2
的实现:
StrutsFlashScope.java
Java代码
- public class StrutsFlashScope implements FlashScope {
- private Map current = new ConcurrentHashMap();
- private Map next = new ConcurrentHashMap();
- public static final String FLASH_SCOPE = "com.posoft.web.servlet.FLASH_SCOPE" ;
- public StrutsFlashScope() {
- }
- public void next() {
- current.clear();
- current = new ConcurrentHashMap(next);
- next.clear();
- }
- public Map getNow() {
- return current;
- }
- public int size() {
- return current.size() + next.size();
- }
- public void clear() {
- current.clear();
- next.clear();
- }
- public boolean isEmpty() {
- return size() == 0 ;
- }
- public boolean containsKey(Object key) {
- return (current.containsKey(key) || next.containsKey(key));
- }
- public boolean containsValue(Object value) {
- return (current.containsValue(value) || next.containsValue(value));
- }
- public Collection values() {
- Collection c = new ArrayList();
- c.addAll(current.values());
- c.addAll(next.values());
- return c;
- }
- public void putAll(Map t) {
- for (Map.Entry<Object, Object> entry : ((Map<Object, Object>) t)
- .entrySet()) {
- put(entry.getKey(), entry.getValue());
- }
- }
- public Set entrySet() {
- Set keySet = new HashSet();
- keySet.addAll(current.entrySet());
- keySet.addAll(next.entrySet());
- return keySet;
- }
- public Set keySet() {
- Set keySet = new HashSet();
- keySet.addAll(current.keySet());
- keySet.addAll(next.keySet());
- return keySet;
- }
- public Object get(Object key) {
- if (next.containsKey(key))
- return next.get(key);
- return current.get(key);
- }
- public Object remove(Object key) {
- if (current.containsKey(key))
- return current.remove(key);
- else
- return next.remove(key);
- }
- public Object put(Object key, Object value) {
- // create the session if it doesn't exist
- registerWithSessionIfNecessary();
- if (current.containsKey(key)) {
- current.remove(key);
- }
- if (value == null )
- return next.remove(key);
- else
- return next.put(key, value);
- }
- private void registerWithSessionIfNecessary() {
- Map<String, Object> session = ActionContext.getContext().getSession();
- if (session.get(FLASH_SCOPE) == null )
- session.put(FLASH_SCOPE, this );
- }
- }
这个实现很好理解,无非内部定义了两个
Map
,将保存在里面的数据,在两个
Map
里来回的转移,这样就保证在下一次重定向请求时,我们只需要将其中一个
Map
的数据转移到另外一个
Map
中,而清楚掉一个
Map
。这样就保证在重定向时,该作用域下依然保存数据。而在第二次的请求时,如果没有新的数据加进来,原来的数据将会被清空。通过这种方式,
Flash
的作用域的数据只能保持在下一次的重定向请求中。
第三步也是很关键的一步,如果我们不去清理该作用域下的数据,那么这个作用域就无法达到应有的效果。这就需要我们在每次重定向的时候要执行作用域的
next()
方法,来清理数据。
我们编写的是
Struts2
的实现,我们就需要在
Struts2
的过滤器中植入对
Flash Scope
处理的操作。看
OecpStruts2FilterDispatcher.java
Java代码
- public class OecpStruts2FilterDispatcher extends StrutsPrepareAndExecuteFilter {
- @Override
- public void doFilter(ServletRequest req, ServletResponse res,
- FilterChain chain) throws IOException, ServletException {
- HttpServletRequest request = (HttpServletRequest) req;
- HttpServletResponse response = (HttpServletResponse) res;
- try {
- prepare.setEncodingAndLocale(request, response);
- prepare.createActionContext(request, response);
- prepare.assignDispatcherToThread();
- if (excludedPatterns != null
- && prepare.isUrlExcluded(request, excludedPatterns)) {
- chain.doFilter(request, response);
- } else {
- request = prepare.wrapRequest(request);
- ActionMapping mapping = prepare.findActionMapping(request,
- response, true );
- if (mapping == null ) {
- boolean handled = execute.executeStaticResourceRequest(
- request, response);
- if (!handled) {
- chain.doFilter(request, response);
- }
- } else {
- /**
- * 更新flash作用域
- */
- FlashScope fs = (FlashScope) ActionContext.getContext()
- .getSession().get(StrutsFlashScope.FLASH_SCOPE);
- if (fs != null ) {
- fs.next();
- }
- execute.executeAction(request, response, mapping);