博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
给JFinal添加了类似ROR的Flash功能。
阅读量:6865 次
发布时间:2019-06-26

本文共 6979 字,大约阅读时间需要 23 分钟。

  hot3.png

最近在用JFinal开发一个小型的项目,使用的是个人比较认可的HTTL模板引擎。过几天不忙了把相关集成的东西发出了。

今天先发一个:给JFinal添加了类似ROR的Flash功能。

在使用JFinal做开发时,经常会用到如下代码:

if(webUser.update()){        this.setSessionAttr("msg", "更新成功");	this.redirect("detail?id="+webUser.getLong("id"));	return;}this.setAttr("msg", "更新失败");render("edit.html");
使用redirect后,会重定向到另一个页面,要传送一些信息,要么使用Session,要么拼装重定向的url地址来做。使用Session的话,需要考虑何时清除的问题,还有就是性能问题,Session中应该少放东西,少放大东西。使用拼装url地址的方法比较麻烦,容易出现错误,另外负责对象难以通过这种方式传输。当然如果系统设计成后端全是服务,返回json,这种问题就不会有了。只是个人习惯传统的页面跳转方式所以需要解决这个问题。

如何解决这个问题,想到RoR中的Flash操作,通过Fash保存数据,这些数据仅能在下次请求时获取,获取后随即清楚。最终通过Jfina的ehcache插件解决了此问题。

思路如下:

基于ehCache构建了一个FlashManager,负责将Flash保存在cache中。这个FlashManager是全局的,为了区分每个用户,使用了sessionKey(这个其实是SessionId);

package com.jfinal.core;import java.util.HashMap;import java.util.Map;import java.util.concurrent.locks.ReentrantLock;import com.jfinal.plugin.ehcache.CacheKit;/** * * Flash管理器 * * @author dafei * */public class FlashManager {	/**	 * 全局静态flash管理器	 */	private static FlashManager flashManager = new FlashManager();	/**	 * falsh 存放在cache中的值。	 */	private final String flashCacheName = "flashCache";	/**	 * 读写锁	 */	private ReentrantLock lock = new ReentrantLock();	/**	 * 构造函数,不允许初始化	 */	private FlashManager() {	}	/**	 * 单例方法	 *	 * @return flash管理器	 */	public static FlashManager getInstance() {		return flashManager;	}	/**	 * 添加flash信息到缓存中。	 *	 * @param sessionKey	 *            session路径	 * @param curAction	 *            当前ActionPath	 * @param key	 *            键	 * @param value	 *            值	 */	@SuppressWarnings("unchecked")	public void setFlash(String sessionKey, String curAction, String key,			Object value) {		sessionKey = sessionKey + curAction.replace("/", "_");		lock.lock();		Object obj = CacheKit.get(flashCacheName, sessionKey);		Map
map = null; if (obj != null) { map = (Map
) obj; } else { map = new HashMap
(); CacheKit.put(flashCacheName, sessionKey, map); } map.put(key, value); lock.unlock(); } /*** * 在调用redirect forwardAction * 时调用此接口,将以当前actionPath为key更替为下一个请求actionPath作为key。 * * @param sessionKey * session的Id值 * @param curAction * 当前ActionPath * @param nextAction * 下一个ActionPath */ public void updateFlash(String sessionKey, String curAction, String nextAction) { String oldKey = sessionKey + curAction.replace("/", "_"); String newkey = sessionKey + nextAction.replace("/", "_"); lock.lock(); Object obj = CacheKit.get(flashCacheName, oldKey); if (obj != null) { CacheKit.remove(flashCacheName, oldKey); CacheKit.put(flashCacheName, newkey, obj); } lock.unlock(); } /** * 从cache中取得Flash的Map * * @param sessionKey * session路径 * @param curAction * 当前ActionPath * @return Flash的Map */ @SuppressWarnings("unchecked") public Map
getFlash(String sessionKey, String curAction) { String sessionActionKey = sessionKey + curAction.replace("/", "_"); Map
map = null; lock.lock(); Object obj = CacheKit.get(flashCacheName, sessionActionKey); if (obj != null) { map = (Map
) obj; CacheKit.remove(flashCacheName, sessionActionKey); } lock.unlock(); return map; }}

修改Controler中相关代码:

增加了一个变量,用来记录是否设定了Flash信息

增加了两个方法:

/**	 * 根据当前路径构造将要跳转的路径的完整Action	 * @param currentActionPath 当前路径,类似 /sau/index	 * @param url 下一个路径,类似/au/login, detail?,admin/detail.	 * @return 下一个Action的完整路径()	 */	public String parsePath(String currentActionPath, String url){		if(url.startsWith("/")){//完整路径			return url.split("\\?")[0];		}else if(!url.contains("/")){//类似于detail的路径。			return "/"+ currentActionPath.split("/")[1] + "/" + url.split("\\?")[0];		}else if(url.contains("http:")|| url.contains("https:")){			return null;		}		///abc/def","bcd/efg?abc		return currentActionPath + "/" + url.split("\\?")[0];	}	/**	 * 设定Flash,该flash中的所有信息将会出现在下一个请求中。	 * 该操作一般用在forwardAction 及redirect操作前。	 * 在设定Falsh拦截器后,拦截器会自动注入所有当前Action中设定的Flash信息到request中。	 * 且仅注入一次。	 * @param key 键	 * @param value 值	 */	public void setFlash(String key, Object value){		String sessionKey = this.getSession(false).getId();		String actionPath = this.request.getRequestURI();		FlashManager.getInstance().setFlash(sessionKey,actionPath, key, value);		setFlashFalg = true;	}

修改了三个方法:

public void forwardAction(String actionUrl) {		if(setFlashFalg){//若有新加入的Flash。更换key。			String sessionKey = this.getSession(false).getId();			String actionPath = this.request.getRequestURI();			//将以当前actionPath为key更替为下一个请求actionPath作为key			FlashManager.getInstance().updateFlash(sessionKey, actionPath, actionUrl);			setFlashFalg =false;		}		render = new ActionRender(actionUrl);	}

public void redirect(String url) {		if(setFlashFalg){			String sessionKey = this.getSession(false).getId();			String actionPath = this.request.getRequestURI();			String newActionPath = parsePath(actionPath, url);			FlashManager.getInstance().updateFlash(sessionKey, actionPath, newActionPath);			setFlashFalg = false;		}		render = renderFactory.getRedirectRender(url);	}
public void redirect(String url, boolean withQueryString) {		if(setFlashFalg){			String sessionKey = this.getSession(false).getId();			String actionPath = this.request.getRequestURI();			String newActionPath = parsePath(actionPath, url);			FlashManager.getInstance().updateFlash(sessionKey, actionPath, newActionPath);			setFlashFalg = false;		}		render = renderFactory.getRedirectRender(url, withQueryString);	}

这些解决了Flash的记录问题,怎样将数据在适当的时候可以让程序访问到呢?想到了拦截器。实现一个。

package com.jfinal.ext.interceptor;import java.util.Map;import java.util.Map.Entry;import com.jfinal.aop.Interceptor;import com.jfinal.core.ActionInvocation;import com.jfinal.core.Controller;import com.jfinal.core.FlashManager;/** * Flash拦截器。 * @author dafei * */public class Flash implements Interceptor{	@Override	/**	 * 该拦截器取得当前ActionPath,从Cache中检查是否有传送给当前Action的Flash对象Map     * 若有,则遍历Map,并将所有key,value注入到当前的request请求中。	 */	public void intercept(ActionInvocation ai) {		String sessionKey = ai.getController().getSession(false).getId();		String curAction = ai.getViewPath()+ai.getMethodName();		Map
flashMap = FlashManager.getInstance().getFlash(sessionKey, curAction); if(flashMap != null){ Controller c = ai.getController(); for(Entry
flashEntry: flashMap.entrySet()){ c.setAttr(flashEntry.getKey(), flashEntry.getValue()); } } ai.invoke(); }}

实现完毕。

如何使用:

在ehcache.xml中添加一个

在Controller上或者需要传入数据的Action上启动Flash拦截器。

@Before({SessionInterceptor.class,Flash.class})public class SmsApiUserController extends Controller @Before(Flash.class)public void detail(){  。。。}
如何调用

if(webUser.update()){						this.setFlash("msg", "更新成功");			this.redirect("detail?id="+webUser.getLong("id"));			return;		}		this.setAttr("msg", "更新失败");		render("edit.html");

总结一下:这个Flash实现主要解决 两个请求间的仅且一次的数据传递问题,当然这两个请求是有要求的:一个请求和其发起的另一个请求(redirect,forwardAction操作)。

目前用起来还不错。个人对JFinal初学,实现难免考虑不周。

目前该实现没有考虑到同一个Session中多个请求同时发起同一个请求的情况。

还请 波总指导。

转载于:https://my.oschina.net/myaniu/blog/135490

你可能感兴趣的文章
LINUX学习笔记高度浓缩版之一 :用户管理、启动过程、硬盘管理
查看>>
JavaScript创建对象的方法
查看>>
『ExtJS』01 009. ExtJS 4 方法重载
查看>>
org.springframework.data.mapping.PropertyReferenceException: No property xxxx found for type Xxxx
查看>>
我的友情链接
查看>>
我的友情链接
查看>>
AIX查看端口被占用
查看>>
GUN sed高级用法,sed脚本编写
查看>>
我的友情链接
查看>>
HTML 5 Web Workers
查看>>
基于koajs的web项目构建-心得篇
查看>>
通过minify将项目中js和css文件的打包
查看>>
提取Windows用户密钥文件cachedump
查看>>
自定义grains_module pillar
查看>>
log file sycn 概述
查看>>
Javascript对于不同浏览器的兼容性
查看>>
开源在线阅读技术资源
查看>>
慎用jQuery中的submit()方法
查看>>
淘宝样式初始化代码
查看>>
Gson解析json数据 亲自测试可用
查看>>