对于JFinal用Redis感兴趣的读者,本文将提供您所需要的所有信息,并且为您提供关于beetl+jfinal框架下用redis做缓存、jfinal2.2集成redis、jfinalItisindi
对于JFinal用Redis感兴趣的读者,本文将提供您所需要的所有信息,并且为您提供关于beetl+jfinal框架下用redis做缓存、jfinal 2.2 集成redis、jfinal It is indirectly referenced from required、Jfinal redirect 传参的宝贵知识。
本文目录一览:- JFinal用Redis
- beetl+jfinal框架下用redis做缓存
- jfinal 2.2 集成redis
- jfinal It is indirectly referenced from required
- Jfinal redirect 传参
JFinal用Redis
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
public class JedisUtil {
private static JedisPool pool;
public static void start() {
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxTotal(100);
jedisPoolConfig.setMaxIdle(95);
jedisPoolConfig.setMinIdle(5);
jedisPoolConfig.setMaxWaitMillis(1000);
pool = new JedisPool(new JedisPoolConfig(), "localhost");
}
public static void close() {
if (pool != null) {
pool.destroy();
}
}
public static Jedis getJedis() {
return pool.getResource();
}
}
import com.jfinal.plugin.IPlugin;
public class JedisPlugin implements IPlugin {
@Override
public boolean start() {
JedisUtil.start();
return true;
}
@Override
public boolean stop() {
JedisUtil.close();
return true;
}
public void setExTime(String name, Integer time) {
JCacheKit.setExTime(name, time);
}
}
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.HashMap;
import java.util.Map;
import redis.clients.jedis.Jedis;
public class JCacheKit {
private static final Map<String, Integer> EX_TIME = new HashMap<String, Integer>();
protected static void setExTime(String name, Integer time) {
EX_TIME.put(name, time);
}
protected static Integer getExTime(String name) {
return EX_TIME.get(name);
}
public static void put(String name, String key, Object value) {
if (value == null || key == null) {
return;
}
Integer exT = getExTime(name);
if (exT == null) {
throw new RuntimeException("the ex_time with " + name + " is not found.");
}
Jedis jedis = JedisUtil.getJedis();
byte[] val = toBytes(value);
if (val == null) {
return;
}
jedis.setex((name + "." + key).getBytes(), exT, val);
jedis.close();
}
public static Object get(String name, String key) {
if (name == null || key == null) {
return null;
}
Jedis jedis = JedisUtil.getJedis();
byte[] gets = jedis.get((name + "." + key).getBytes());
jedis.close();
if (gets == null) {
return null;
}
Object obj = toObject(gets);
return obj;
}
private static Object toObject(byte[] arr) {
Object obj = null;
ByteArrayInputStream bin = new ByteArrayInputStream(arr);
try {
ObjectInputStream obin = new ObjectInputStream(bin);
obj = obin.readObject();
} catch (Exception e) {
e.printStackTrace();
}
return obj;
}
private static byte[] toBytes(Object object) {
byte[] bytes = null;
ByteArrayOutputStream obj = new ByteArrayOutputStream();
try {
ObjectOutputStream out = new ObjectOutputStream(obj);
out.writeObject(object);
bytes = obj.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return bytes;
}
}
代码简单 序列化部分有问题
beetl+jfinal框架下用redis做缓存
jfinal的默认插件里面是没有redis的,所以用了扒皮的Jfinal-ext(扒皮好像已经好久没有更新了)。里面的redis缓存用法只是按照SQL语句对查询结果进行缓存,感觉没有jfinal中对ehcache插件那样的注解式写法方便和高效。所以自己打算这一个注解式的写法,这样就能保证在拦截器中就直接返回结果,不会再进入到actioin了。
节约字数,就把import和package给省了。JedisKit是jfinal-ext的,Const.CACHE_ACTION_PREFIX就是一个字符串,自定义的,这里是"ACTION-"。
先说一下用法。
1.CacheKey注解可以省略,不省略的话,CacheKey就是"ACTION-ccc"。省略之后会自动生成CacheKey("ACTION-"+请求的路径+url传递的参数),本例中就是"ACTION-/user/a"(此处用了jfinal-ext的自动绑定路径功能)。注:post传递参数不会被记录到CacheKey中,所以尽量不要用post,不过一般需要cache的都是get之类的请求吧。
2.EvictKey注解也可以省略,省略的话就会将这个Controller下的所有cache都清除,本例匹配规则:ACTION-/user*。EvivtKey可以是数组(考虑到可能会出现一个操作影响多个缓存的情况)。
public class UserController extends BaseController<UserModel> {
@Before(CacheAction.class)
@CacheKey("ccc")//可省略
public void a(){
setAttr("beetl", "beetl success");
render("a");
}
@Before(EvictCache.class)
@EvictKey("ccc")//可省略;可以是数组如:@EvictKey({"ccc","bbb"})
public void b(){
setAttr("beetl", "beetl right");
render("a");
}
}
考虑过直接用注解,类似@CacheAction("ccc")这种形式的写法,但是这样的话,就意味着要加一个全局的拦截器,然后所有请求都要判断是否含有@CacheAction。总感觉这样未免小题大做,所以还是用@Before这个高效的注解吧。
下面是源码。
--拦截器CacheAction.java,其实就是修改了jfinal的CacheInterceptor.java。
public class CacheAction implements Interceptor {
private static final String renderKey = "$renderKey$";
private static volatile ConcurrentHashMap<String, ReentrantLock> lockMap = new ConcurrentHashMap<String, ReentrantLock>();
private ReentrantLock getLock(String key) {
ReentrantLock lock = lockMap.get(key);
if (lock != null)
return lock;
lock = new ReentrantLock();
ReentrantLock previousLock = lockMap.putIfAbsent(key, lock);
return previousLock == null ? lock : previousLock;
}
final public void intercept(ActionInvocation ai) {
Controller controller = ai.getController();
String key = buildKey(ai, controller);
Map<String, Object> cacheData = JedisKit.get(key);
if (cacheData == null) {
Lock lock = getLock(key);
lock.lock(); // prevent cache snowslide
try {
cacheData = JedisKit.get(key);
if (cacheData == null) {
ai.invoke();
cacheAction(key, controller);
return ;
}
} finally {
lock.unlock();
}
}
useCacheDataAndRender(cacheData, controller);
}
/**
* 通过post传递参数的请求不能被缓存。
* @param ai
* @param controller
* @return
*/
private String buildKey(ActionInvocation ai, Controller controller) {
CacheKey cacheKey = ai.getMethod().getAnnotation(CacheKey.class);
if (cacheKey != null)
return Const.CACHE_ACTION_PREFIX + cacheKey.value();
StringBuilder sb = new StringBuilder();
sb.append(Const.CACHE_ACTION_PREFIX);
sb.append(ai.getActionKey());
String urlPara = controller.getPara();
if (urlPara != null)
sb.append("/").append(urlPara);
String queryString = controller.getRequest().getQueryString();
if (queryString != null)
sb.append("?").append(queryString);
return sb.toString();
}
private void cacheAction(String key, Controller controller) {
HttpServletRequest request = controller.getRequest();
HashMap<String, Object> cacheData = new HashMap<String, Object>();
for (Enumeration<String> names=request.getAttributeNames(); names.hasMoreElements();) {
String name = names.nextElement();
cacheData.put(name, request.getAttribute(name));
}
cacheData.put(renderKey, controller.getRender()); // cache render
JedisKit.set(key, cacheData);
}
private void useCacheDataAndRender(Map<String, Object> cacheData, Controller controller) {
HttpServletRequest request = controller.getRequest();
Set<Entry<String, Object>> set = cacheData.entrySet();
for (Iterator<Entry<String, Object>> it=set.iterator(); it.hasNext();) {
Entry<String, Object> entry = it.next();
request.setAttribute(entry.getKey(), entry.getValue());
}
request.removeAttribute(renderKey);
controller.render((Render)cacheData.get(renderKey)); // set render from cacheData
}
}
----拦截器EvictCache.java,其实就是修改了jfinal的EvictInterceptor.java。
public class EvictCache implements Interceptor {
final public void intercept(ActionInvocation ai) {
ai.invoke();
JedisKit.del(buildKeys(ai));
}
private String[] buildKeys(ActionInvocation ai) {
EvictKey evictKeys = ai.getMethod().getAnnotation(EvictKey.class);
if (evictKeys != null){
String[] keyArray = evictKeys.value();
for(int i=0; i<keyArray.length; i++){
keyArray[i] = Const.CACHE_ACTION_PREFIX + keyArray[i];
}
return keyArray;
}
StringBuilder sb = new StringBuilder();
sb.append(Const.CACHE_ACTION_PREFIX);
sb.append(ai.getControllerKey());
sb.append("/*");
Set<String> keySet = JedisKit.keys(sb.toString());
String[] keys = keySet.toArray(new String[keySet.size()]);
return keys;
}
}
--CacheKey.java
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface CacheKey {
String value();
}
--EvictKey.java
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface EvictKey {
String[] value();
}
-----------------------------------------------------------------------------
这样弄好之后运行时会出现java.io.NotSerializableException: org.beetl.core.GroupTemplate报错。这是因为模板引擎用了beetl的缘故。
拦截器在进行缓存的时候会把render和request中的参数全都保存起来。jfinal的Render接口是可序列化的,Beetl实现了Render接口,但是和其他的Render不同的是,beetl自带的jfinal插件BeetlRender中有一个属性是GroupTemplate。
public class BeetlRender extends Render
{
GroupTemplate gt = null;
private transient static final String encoding = getEncoding();
private transient static final String contentType = "text/html; charset=" + encoding;
......
......
......
}
这个GroupTemplate没有实现Serializable,所以不能存入redis。并且,如果每个缓存的render里面都有一个GroupTemplate,也会浪费内存,所以还是自己写个BeetlRender为妙。
下面给出我自己的RnBeetlRender和RnBeetlRenderFactory
public class RnBeetlRenderFactory implements IMainRenderFactory {
public static String viewExtension = ".html";
public static GroupTemplate groupTemplate = null;
public RnBeetlRenderFactory() {
if (groupTemplate != null) {
groupTemplate.close();
}
try {
Configuration cfg = Configuration.defaultConfiguration();
WebAppResourceLoader resourceLoader = new WebAppResourceLoader();
groupTemplate = new GroupTemplate(resourceLoader, cfg);
} catch (IOException e) {
throw new RuntimeException("加载GroupTemplate失败", e);
}
}
public Render getRender(String view) {
return new RnBeetlRender(view + viewExtension);
}
public String getViewExtension() {
return viewExtension;
}
}
public class RnBeetlRender extends Render {
private static final long serialVersionUID = 1L;
private transient static final String encoding = getEncoding();
private transient static final String contentType = "text/html; charset=" + encoding;
public RnBeetlRender(String view) {
this.view = view;
}
@Override
public void render() {
try{
response.setContentType(contentType);
WebRender webRender = new WebRender(
RnBeetlRenderFactory.groupTemplate);
webRender.render(view, request, response);
} catch (BeetlException e) {
throw new RenderException(e);
}
}
}
然后在JFinalConfig继承类里面配置即可。
public void configConstant(Constants me) {
me.setMainRenderFactory(new RnBeetlRenderFactory());
}
如有问题和建议,请多多指教。
jfinal 2.2 集成redis
想在现有系统中集成redis,jfinal使用的是2.2。想请问与之搭配的redis版本最好选择哪个版本?谢谢!jfinal It is indirectly referenced from required
今天使用 jfinal 的 controller 进行 request 请求方法的判断 method = getRequest().getMethod();
一直报错
HttpServletRequest refers to the missing type String
It is indirectly referenced from required
新建工程时 选的 dynamic web,
解决:configure build path -> libraries ->Add Libary
->Server Runtime->Tomcat
Jfinal redirect 传参
@JFinal 你好,想跟你请教个问题:我在使用redirect(url, true),进行重定向传参的时候,结果没有传成功?这个应该怎么解决呢?
今天关于JFinal用Redis的分享就到这里,希望大家有所收获,若想了解更多关于beetl+jfinal框架下用redis做缓存、jfinal 2.2 集成redis、jfinal It is indirectly referenced from required、Jfinal redirect 传参等相关知识,可以在本站进行查询。
本文标签: