作者存档
20144 月8

Nutz:结合Jedis实现Redis消息订阅和缓存队列(支持自动重连)

仅作参考。 编辑配置Nutz redis配置文件:

var ioc = {
        jedisConfig : {
            type : 'cn.xuetang.common.redis.JedisConfig',
            fields : {
                maxTotal : 200,
                maxIdle : 10,
                maxWaitMillis:10001,
                testOnBorrow:true,
                redisUrl:'127.0.0.1',
                redisPort:6379,
                redisTimeout:1000
            }
        }
}
package cn.xuetang.common.redis;

/**
 * Created by Wizzer on 14-4-8.
 */
public class JedisConfig {
    private int maxTotal;
    private int maxIdle;
    private int maxWaitMillis;
    private boolean testOnBorrow;
    private String redisUrl;
    private int redisPort;
    private int redisTimeout;//redis断开后自动重新连接间隔时间

    public int getMaxTotal() {
        return maxTotal;
    }

    public void setMaxTotal(int maxTotal) {
        this.maxTotal = maxTotal;
    }

    public int getMaxIdle() {
        return maxIdle;
    }

    public void setMaxIdle(int maxIdle) {
        this.maxIdle = maxIdle;
    }

    public int getMaxWaitMillis() {
        return maxWaitMillis;
    }

    public void setMaxWaitMillis(int maxWaitMillis) {
        this.maxWaitMillis = maxWaitMillis;
    }

    public boolean isTestOnBorrow() {
        return testOnBorrow;
    }

    public void setTestOnBorrow(boolean testOnBorrow) {
        this.testOnBorrow = testOnBorrow;
    }

    public String getRedisUrl() {
        return redisUrl;
    }

    public void setRedisUrl(String redisUrl) {
        this.redisUrl = redisUrl;
    }

    public int getRedisPort() {
        return redisPort;
    }

    public void setRedisPort(int redisPort) {
        this.redisPort = redisPort;
    }

    public int getRedisTimeout() {
        return redisTimeout;
    }

    public void setRedisTimeout(int redisTimeout) {
        this.redisTimeout = redisTimeout;
    }
}

Nutz入口类加载配置文件,config路径:

@Modules(scanPackage=true)
@Ok("raw")
@Fail("http:500")
@IocBy(type=ComboIocProvider.class,args={
    "*org.nutz.ioc.loader.json.JsonLoader","config",
    "*org.nutz.ioc.loader.annotation.AnnotationIocLoader","cn.xuetang"})
@SetupBy(value=StartSetup.class)
@UrlMappingBy(value=UrlMappingSet.class)
public class MainModule {
}

初始化配置参数,新建订阅消息处理线程:

    public static JedisConfig REDIS_CONFIG;
    //声明全局的redis连接池
    public static ShardedJedisPool SHARDEDJEDIS_POOL=null;
    public static JedisPool JEDIS_POOL=null;

    public static void InitRedisConfig() {//初始化redis
        REDIS_CONFIG = Mvcs.ctx.getDefaultIoc().get(JedisConfig.class);
        JedisPoolUtil jedisPoolUtil=new JedisPoolUtil();
        SHARDEDJEDIS_POOL = jedisPoolUtil.getShardedJedisPool();
        JEDIS_POOL = jedisPoolUtil.getJedisPool();
    }

    new Thread(Mvcs.getIoc().get(ImageTask.class)).start();

  创建Jedis连接池工具类:

package cn.xuetang.common.redis;

import cn.xuetang.common.config.Globals;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisShardInfo;
import redis.clients.jedis.ShardedJedisPool;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by Wizzer on 14-4-8.
 */
public class MyJedis {
    private String redisUrl;
    private int redisPort;
    public JedisPoolConfig jedisPoolConfig(){
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxTotal(Globals.REDIS_CONFIG.getMaxTotal());
        jedisPoolConfig.setMaxIdle(Globals.REDIS_CONFIG.getMaxIdle());
        jedisPoolConfig.setMaxWaitMillis(Globals.REDIS_CONFIG.getMaxWaitMillis());
        jedisPoolConfig.setTestOnBorrow(Globals.REDIS_CONFIG.isTestOnBorrow());
        return jedisPoolConfig;
    }
    public JedisShardInfo jedisShardInfo(){
        return new JedisShardInfo(redisUrl, redisPort);
    }
    public JedisPool jedisPool(){
        return new JedisPool(jedisPoolConfig(),redisUrl, redisPort);
    }
    public ShardedJedisPool shardedJedisPool(){
        this.redisUrl=Globals.REDIS_CONFIG.getRedisUrl();
        this.redisPort=Globals.REDIS_CONFIG.getRedisPort();
        List jedisList = new ArrayList();
        jedisList.add(jedisShardInfo());
        return new ShardedJedisPool(jedisPoolConfig(), jedisList);
    }

}

实现自己的监听类:

package cn.xuetang.common.redis;

import org.nutz.log.Log;
import org.nutz.log.Logs;
import redis.clients.jedis.JedisPubSub;

/**
 * 订阅监听类
 * Created by Wizzer on 14-4-8.
 */
public class MyJedisListenter extends JedisPubSub {
    private final static Log log = Logs.get();
    // 取得订阅的消息后的处理
    public void onMessage(String channel, String message) {
        log.info(channel + "=" + message);
    }

    // 初始化订阅时候的处理
    public void onSubscribe(String channel, int subscribedChannels) {
        log.info(channel + "=" + subscribedChannels);
    }

    // 取消订阅时候的处理
    public void onUnsubscribe(String channel, int subscribedChannels) {
        log.info(channel + "=" + subscribedChannels);
    }

    // 初始化按表达式的方式订阅时候的处理
    public void onPSubscribe(String pattern, int subscribedChannels) {
        log.info(pattern + "=" + subscribedChannels);
    }

    // 取消按表达式的方式订阅时候的处理
    public void onPUnsubscribe(String pattern, int subscribedChannels) {
        log.info(pattern + "=" + subscribedChannels);
    }

    // 取得按表达式的方式订阅的消息后的处理
    public void onPMessage(String pattern, String channel, String message) {
        log.info(pattern + "=" + channel + "=" + message);
    }
}

  获取单例Jedis连接池:

package cn.xuetang.common.redis;

import cn.xuetang.common.config.Globals;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.ShardedJedisPool;

import java.util.Date;

/**
 * Created by Wizzer on 14-4-8.
 */
public class JedisPoolUtil {
    private final static Log log = Logs.get();

    public synchronized ShardedJedisPool getShardedJedisPool() {
        if (Globals.SHARDEDJEDIS_POOL == null) {
            MyJedis myJedis=new MyJedis();
            Globals.SHARDEDJEDIS_POOL = myJedis.shardedJedisPool();
        }
        return Globals.SHARDEDJEDIS_POOL;
    }

    public synchronized JedisPool getJedisPool() {
        if (Globals.JEDIS_POOL== null) {
            MyJedis myJedis=new MyJedis();
            Globals.JEDIS_POOL = myJedis.jedisPool();
        }
        return Globals.JEDIS_POOL;
    }
}

数据入列同时发布订阅消息:

ShardedJedis shardedJedis=Globals.SHARDEDJEDIS_POOL.getResource();
                txt.put("appid", appInfo.getId());
                shardedJedis.lpush("image", Json.toJson(txt));
                Jedis jedis=Globals.JEDISPOOL.getResource();
                jedis.publish("newimage","true");

 

处理订阅消息的类:

 

package cn.xuetang.common.task;

import cn.xuetang.common.action.BaseAction;
import cn.xuetang.common.config.Globals;
import cn.xuetang.common.redis.MyJedisListenter;
import cn.xuetang.common.util.DateUtil;
import cn.xuetang.modules.baby.bean.Baby_image;
import cn.xuetang.modules.baby.bean.Baby_info;
import cn.xuetang.modules.user.bean.User_conn_wx;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json;
import org.nutz.lang.Strings;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.ShardedJedis;

import java.util.*;

/**
 * Created by Wizzer on 14-3-31.
 */
@IocBean
public class ImageTask extends BaseAction implements Runnable {
    @Inject
    protected Dao dao;
    private final static Log log = Logs.get();

    public void run() {
        try {
            log.info("ImageTask start!");
            final JedisPoolUtil jedisPoolUtil = new JedisPoolUtil();
            boolean isEnable = false;
            while (!isEnable) {
                try {
                    jedisPoolUtil.getShardedJedisPool().getResource();
                    isEnable = true;
                } catch (Exception e) {
                    log.info("The redis connection is not successful,wait " + Globals.REDIS_CONFIG.getRedisTimeout() + "ms try again.");

                }
                try {
                    wait(Globals.REDIS_CONFIG.getRedisTimeout());
                } catch (Exception e) {

                }
            }
            final ShardedJedis shardedJedis = jedisPoolUtil.getShardedJedisPool().getResource();
            final Jedis jedis = jedisPoolUtil.getJedisPool().getResource();
            MyJedisListenter listenter = new MyJedisListenter() {
                @Override
                public void onMessage(String channel, String message) {
                    //业务代码具体实现
                    while (shardedJedis.exists("image")) {
                        String data = shardedJedis.rpop("image");
                    }
                }
            };
            jedis.subscribe(listenter, "newimage");

        } catch (Exception e) {
            log.error(e);
        }

    }

}

 

 

20144 月8

Nutz:POST数据的常用方法

 Request req = Request.create("http://127.0.0.1/api/user/sendtext?mykey=" + mykey, Request.METHOD.POST);
                            JsonFormat jsonFormat=new JsonFormat();
                            jsonFormat.setAutoUnicode(true);//防止中文乱码,以unicode编码,根据需要设置
                            req.setData(Json.toJson(map,jsonFormat));
                            req.getHeader().set("Content-Type","application/octet-stream");//设置以字节流传送数据
                            Response resp = Sender.create(req).send();
                            if (resp.isOK()) {
                                log.info(resp.getContent());

                            }

20143 月29

吃巧克力

昨天在公交车站等车,看见一小孩子拿了一大包巧克力在吃,一会儿吃了半袋子。我出于好心说了句:小孩子巧克力不能多吃,吃多了会得病。小孩子对我说:我爷爷今年103岁了。我说:因为吃巧克力?小孩说:不是,因为他从来不管闲事。

20143 月11

基于Nutz的CMS内容管理系统大功告成

功能比较类似于JEECMS,基于Nutz 所以二次开发非常容易,并且UI表现层完全和JEECMS不一样,主要是ajax+弹出窗口的方式。

Q-Q: 1162-4317

Q群:2631-0065      合肥Android/Java开发-GDG

演示地址:http://wizzer.duapp.com/

运行效果:

 

QQ图片20140311163652
20143 月5

领导在门外用门夹核桃

领导在门外用门夹核桃,我从门口路过,顺嘴说了一句,用门夹过的核桃还能补脑吗?领导愣了愣,把核桃扔垃圾篓了。刚经过领导电脑桌前,看到领导在百度:门夹过的核桃为什么不能补脑?我滴个天哪,度娘你可给点靠谱答案吧,不然他不得揍死我啊。ps,领导刚从美国回来不久。。。。

20143 月5

Nutz:结合quartz-2.2.1实现定时任务

StartSetup 项目启动时新建线程:

package com.hits.core;

import com.hits.modules.cms.task.LoadTask;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import org.nutz.mvc.NutConfig;
import org.nutz.mvc.Setup;

import com.hits.common.config.Globals;
import org.quartz.SchedulerException;
import org.quartz.impl.StdSchedulerFactory;

/**
 * 类描述: 创建人:Wizzer 联系方式:www.wizzer.cn 创建时间:2013-11-26 下午2:11:13
 */
public class StartSetup implements Setup {
    private final static Log log = Logs.get();

    @Override
    public void destroy(NutConfig config) {

    }

    @Override
    public void init(NutConfig config) {
        try {
            //初始化Quartz任务
            Globals.SCHEDULER = StdSchedulerFactory.getDefaultScheduler();
            new Thread(config.getIoc().get(LoadTask.class)).start();
        } catch (SchedulerException e) {
            log.error(e);
        } catch (Exception e) {
            log.error(e);
        }
    }

}
LoadTask.java 从任务表中加载任务,定时执行类方法:
package com.hits.modules.cms.task;

import com.hits.common.action.BaseAction;
import com.hits.common.config.Globals;
import com.hits.modules.cms.task.bean.Cms_task;
import org.apache.commons.lang.StringUtils;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.integration.quartz.NutQuartzJobFactory;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;

import java.util.*;

/**
 * Created by Wizzer on 14-3-4.
 */
@IocBean
public class LoadTask extends BaseAction implements Runnable {
    @Inject
    protected Dao dao;
    private final static Log log = Logs.get();

    public void run() {
        List tasks = daoCtl.list(dao, Cms_task.class, Cnd.where("is_enable", "=", 0));
        Globals.SCHEDULER.setJobFactory(new NutQuartzJobFactory());
        for (int i = 0; i < tasks.size(); i++) {
            Cms_task task = tasks.get(i);
            try {
                Map map = new HashMap();
                if (task.getTask_type() == 2 || task.getTask_type() == 3) {
                    map.put("site_id", task.getSite_id());
                    map.put("channel_id", task.getParam_value());
                } else if (task.getTask_type() == 1) {
                    map.put("site_id", task.getSite_id());
                }
                JobBuilder jobBuilder = JobBuilder.newJob(getClassByTask(task.getJob_class()));
                jobBuilder.setJobData(getJobDataMap(map));
                TriggerBuilder triggerBuilder = TriggerBuilder.newTrigger();
                if (StringUtils.isNotBlank(task.getTask_code())) {
                    jobBuilder.withIdentity(task.getTask_code(), Scheduler.DEFAULT_GROUP);
                    triggerBuilder.withIdentity(task.getTask_code(), Scheduler.DEFAULT_GROUP);
                } else {
                    UUID uuid = UUID.randomUUID();
                    jobBuilder.withIdentity(uuid.toString(), Scheduler.DEFAULT_GROUP);
                    triggerBuilder.withIdentity(uuid.toString(), Scheduler.DEFAULT_GROUP);
                    task.setTask_code(uuid.toString());
                    daoCtl.update(dao, task);
                }
                triggerBuilder.withSchedule(getCronScheduleBuilder(getCronExpressionFromDB(task)));
                //调度任务

                Globals.SCHEDULER.scheduleJob(jobBuilder.build(), triggerBuilder.build());

            } catch (SchedulerException e) {
                log.error(e);
            } catch (ClassNotFoundException e) {
                log.error(e);
            } catch (Exception e) {
                log.error(e);
            }
        }
        if(tasks.size()>0){
            Globals.SCHEDULER.start();
        }

    }

    public static CronScheduleBuilder getCronScheduleBuilder(String cronExpression) {
        return CronScheduleBuilder.cronSchedule(cronExpression);
    }
    public String getCronExpressionFromDB(Cms_task task) {
        if (task.getExecycle() == 2) {
            return task.getCron_expression();
        } else {
            int execycle = task.getTask_interval_unit();
            String excep = "";
            if (execycle == 5) {//月
                excep = "0  " + task.getMinute() + " " + task.getHour() + " " + task.getDay_of_month() + " * ?";
            } else if (execycle == 4) {//周
                excep = "0  " + task.getMinute() + " " + task.getHour() + " " + " ? " + " * " + task.getDay_of_week();
            } else if (execycle == 3) {//日
                excep = "0  " + task.getMinute() + " " + task.getHour() + " " + " * * ?";
            } else if (execycle == 2) {//时
                excep = "0 0 */" + task.getInterval_hour() + " * * ?";
            } else if (execycle == 1) {//分
                excep = "0  */" + task.getInterval_minute() + " * * * ?";
            }
            return excep;
        }
    }

    /**
     * @param params 任务参数
     * @return
     */
    private JobDataMap getJobDataMap(Map params) {
        JobDataMap jdm = new JobDataMap();
        Set keySet = params.keySet();
        Iterator it = keySet.iterator();
        while (it.hasNext()) {
            String key = it.next();
            jdm.put(key, params.get(key));
        }
        return jdm;
    }

    /**
     * @param taskClassName 任务执行类名
     * @return
     * @throws ClassNotFoundException
     */
    @SuppressWarnings("unchecked")
    private Class getClassByTask(String taskClassName) throws ClassNotFoundException {
        return Class.forName(taskClassName);
    }
}
quartz-2.2.1 配置文件:
# Default Properties file for use by StdSchedulerFactory
# to create a Quartz Scheduler Instance, if a different
# properties file is not explicitly specified.
#
# 跳过版本检查 #
org.quartz.scheduler.skipUpdateCheck=true
org.quartz.scheduler.instanceName = DefaultQuartzScheduler
org.quartz.scheduler.rmi.export = false
org.quartz.scheduler.rmi.proxy = false
org.quartz.scheduler.wrapJobExecutionInUserTransaction = false
# 用NutIoc接管Quartz的JobFactory,实现用户需要的注入功能 #
org.quartz.scheduler.jobFactory.class=org.nutz.integration.quartz.NutQuartzJobFactory

org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 10
org.quartz.threadPool.threadPriority = 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true

org.quartz.jobStore.misfireThreshold = 60000
# 使用内存JobStore #
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore

NutQuartzJobFactory.java 下载地址:

https://github.com/nutzam/nutzmore/blob/master/src/org/nutz/integration/quartz/NutQuartzJobFactory.java

20141 月2

Nutz:使用第三方JS控件实现多文件上传的方法

适用于 Nutz+SWFUpload、Nutz+plupload 、Ueditor 等控件文件上传,验证用户身份。

   /**
     * 验证用户帐号,保存文件
     *
     * @param tmpFile
     * @param filetype
     * @param file_password
     * @param file_username
     * @param errCtx
     * @return
     */
    @At
    @Ok("raw")
    @AdaptBy(type = UploadAdaptor.class, args = "ioc:upload")
    public JSONObject uploadOneSave(@Param("Filedata") TempFile tmpFile, @Param("ueditor") String ueditor1, @Param("filetype") String filetype, @Param("title") String title, @Param("file_password") String file_password, @Param("file_username") String file_username, AdaptorErrorContext errCtx) {
        boolean ueditor = false;//是否是百度编辑器,编辑器对应的JS要做相应的修改
        if ("true".equals(StringUtil.null2String(ueditor1)))
            ueditor = true;
        System.out.println("ueditor::::::::::"+ueditor);
        JSONObject js = new JSONObject();
        if (errCtx != null) {
            if (errCtx.getAdaptorErr() != null) {
                if (ueditor) {
                    js.put("state", errorMsg(errCtx.getAdaptorErr()));
                } else {
                    js.put("error", errorMsg(errCtx.getAdaptorErr()));
                    js.put("msg", "");
                }
                System.out.println("js1::::::::::"+js.toString());
                return js;
            }
            for (Throwable e : errCtx.getErrors()) {
                if (e != null) {
                    if (ueditor) {
                        js.put("state", errorMsg(e));
                    } else {
                        js.put("error", errorMsg(e));
                        js.put("msg", "");
                    }
                    return js;
                }
            }
        }
        if ("".equals(StringUtil.null2String(file_username)) || "".equals(StringUtil.null2String(file_password))) {
            if (ueditor) {
                js.put("state", "错误:请配置文件服务器用户名及密码!");
            } else {
                js.put("error", "错误:请配置文件服务器用户名及密码!");
                js.put("msg", "");
            }
            return js;
        }
        Ioc ioc = new NutIoc(new JsonLoader("config/fileserver.json"));
        String u = ioc.get(FileServer.class, "fileserver").getUsername();
        String p = ioc.get(FileServer.class, "fileserver").getPassword();
        if (!u.equals(file_username) || !p.equals(DecodeUtil.Decrypt(file_password))) {
            if (ueditor) {
                js.put("state", "错误:文件服务器用户名或密码不正确!");
            } else {
                js.put("error", "错误:文件服务器用户名或密码不正确!");
                js.put("msg", "");
            }
            return js;
        }
        if (tmpFile == null || tmpFile.getFile().length() < 10) {
            if (ueditor) {
                js.put("state", "错误:文件大小不可小于10B!");
            } else {
                js.put("error", "错误:文件大小不可小于10B!");
                js.put("msg", "");
            }
            return js;

        }
        String filename = tmpFile.getMeta().getFileLocalName();
        File file = tmpFile.getFile();
        String suffixname = Files.getSuffixName(file).toLowerCase();
        String ss = FileType.getSuffixname(upload, filetype);
        if (!ss.contains(suffixname)) {
            if (ueditor) {
                js.put("state", "错误:不允许的文件扩展名,允许:" + ss);
            } else {
                js.put("error", "错误:不允许的文件扩展名,允许:" + ss);
                js.put("msg", "");
            }
            return js;
        }

        long len = tmpFile.getFile().length();

        filename = filename.substring(0, filename.lastIndexOf(".")) + "." + suffixname;
        String date = DateUtil.getToday();
        String uuid = UUID.randomUUID().toString().replaceAll("-", "");
        String fname = uuid + "." + Files.getSuffixName(file).toLowerCase();
        String dest = webPath(date, fname, suffixname);
        try {
            Files.move(file, new File(dest));
        } catch (IOException e) {
            e.printStackTrace();
            if (ueditor) {
                js.put("state", "错误:文件服务器IO异常!");
            } else {
                js.put("error", "错误:文件服务器IO异常!");
                js.put("msg", "");
            }
            return js;
        }
        JSONObject fs = new JSONObject();
        if (ueditor) {
            js.put("state", "SUCCESS");
            js.put("original", filename);
            js.put("url", "/upload/" + FileType.getFileType(upload, suffixname) + "/" + date + "/" + fname);
            js.put("title", title);
        } else {
            fs.put("filename", filename);
            fs.put("filepath", "/upload/" + FileType.getFileType(upload, suffixname) + "/" + date + "/" + fname);
            fs.put("filesize", StringUtil.getFileSize(len, 2));
            js.put("error", "");
            js.put("msg", fs);
        }
        return js;

    }

    /**
     * 获取上传路径,根据文件类型+日期生成路径
     *
     * @param date
     * @param fname
     * @param suffixname
     * @return
     */
    public String webPath(String date, String fname, String suffixname) {
        String newfilepath = Mvcs.getServletContext().getRealPath(
                "/upload/" + FileType.getFileType(upload, suffixname) + "/" + date
                        + "/");
        Files.createDirIfNoExists(newfilepath);
        return newfilepath + "\\" + fname;
    }

    /**
     * 根据异常提示错误信息
     *
     * @param t
     * @return
     */
    private String errorMsg(Throwable t) {
        if (t == null || t.getClass() == null) {
            return "错误:未知system错误!";
        } else {
            String className = t.getClass().getSimpleName();
            if (className.equals("UploadUnsupportedFileNameException")) {
                String name = upload.getContext().getNameFilter();
                return "错误:无效的文件扩展名,支持的扩展名:" + name.substring(name.indexOf("(") + 1, name.lastIndexOf(")")).replace("|", ",");
            } else if (className.equals("UploadUnsupportedFileTypeException")) {
                return "错误:不支持的文件类型!";
            } else if (className.equals("UploadOutOfSizeException")) {
                return "错误:文件超出" + StringUtil.getFileSize(upload.getContext().getMaxFileSize(), 2) + "MB";
            } else if (className.equals("UploadStopException")) {
                return "错误:上传中断!";
            } else {
                return "错误:未知错误!";
            }
        }
    }

项目部署根目录增加:crossdomain.xml 文件,解决上传控件跨域上传的问题(应用和文件服务器分开部署):

  
  
      
      
    
20141 月2

swfupload:动态传递参数的方法

SWFUpload.prototype.setPostParams = function (paramsObject) { this.settings.post_params = paramsObject; this.callFlash(“SetPostParams”, [paramsObject]); };

 

swfu.setPostParams({ path:$(“#path”).val() });

201312 月25

Nutz:上传文件的配置项扩展,实现对文件类型的限制及分类

upload.json 配置文件,增加扩展配置项extOption,内容可以由用户自定义,返回一个Map对象。

我要实现功能是,用户在相册里只允许上传图片文件、视频里只允许上传视频格式的文件等,

结合上传控件和JS,实现在页面级和代码级的文件类型分类限制、分类保存等功能。

Nutz issue 提交需求不被接纳所以只好自己实现了,大家如需要的话可以提issue,希望以后Nutz能内置:

https://github.com/nutzam/nutz/issues/568

upload.json:

var ioc = {
        upload : {
            type : "org.nutz.mvc.upload.UploadAdaptor",
            args : [{refer : "uploadCtx"}]
        },
        uploadCtx : {
            type : "org.nutz.mvc.upload.UploadingContext",
            args : [{refer: "filePool"}],
            fields : {
                ignoreNull : true,
                maxFileSize : 10485760,
                nameFilter : ".+(jpg|gif|png|jpeg|doc|docx|xls|xlsx|ppt|pptx|wps|pdf|txt|chm|mp3|mp4|3gp|rm|swf|flv|asf|wmv|wma|z|zip|rar|ios|jar)",
                extOption: {
                    "images":"jpg,gif,png,jpeg",
                    "document":"doc,docx,xls,xlsx,ppt,pptx,wps,pdf,txt,chm",
                    "music":"mp3",
                    "video":"mp4,3gp,rm,swf,flv,asf,wmv,wma",
                    "archive":"z,zip,rar,ios,jar"                       
                   }
            }
        },
        filePool : {
            type : "com.hits.common.file.FilePool",
            args : ["/temp/", 2000]
        }
};

改写Nutz源码:

org.nutz.mvc.upload.UploadingContext 类,增加代码:

    /**
     * 一个扩展配置项,用户可自定义内容
     */
    private Map extOption;

    public Map getExtOption() {
        return extOption;
    }

    public UploadingContext setExtOption(String extOption) {
        this.extOption = Json.fromJsonAsMap(String.class,extOption);
        return this;
    }

增加一个调用类:

FileType.java

/** 
 * 类描述: 
 * 创建人:Wizzer 
 * 联系方式:www.wizzer.cn
 * 创建时间:2013-12-25 下午1:13:30 
 * @version 
 */
public class FileType { 
    /**
     * 根据文件名获取文件类型,默认返回other
     * @param upload
     * @param suffixname
     * @return
     */
    public static String getFileType(UploadAdaptor upload,String suffixname) {
        Map hm=upload.getContext().getExtOption();
        String str = StringUtil.null2String(suffixname).toLowerCase();
        Set<Map.Entry> set = hm.entrySet();
        for (Iterator<Map.Entry> it = set.iterator(); it.hasNext();) {
            Map.Entry entry = (Map.Entry) it.next();
            if(entry.getValue().toLowerCase().indexOf(str)>-1)
                return entry.getKey();
        }
        return "other";
    }
    /**
     * 根据文件类型获取文件后缀名,默认返回nameFilter配置
     * @param upload
     * @param filetype
     * @return
     */
    public static String getSuffixname(UploadAdaptor upload,String filetype) {
        Map hm=upload.getContext().getExtOption();
        String str = StringUtil.null2String(filetype).toLowerCase();
        if(!"".equals(str)){
            Set<Map.Entry> set = hm.entrySet();
            for (Iterator<Map.Entry> it = set.iterator(); it.hasNext();) {
                Map.Entry entry = (Map.Entry) it.next();
                if(entry.getKey().toLowerCase().equals(str))
                    return entry.getValue();
            }
        }
        String name=upload.getContext().getNameFilter(); 
        return name.substring(name.indexOf("(")+1,name.lastIndexOf(")")).replace("|", ",");
    }
}

使用示例:

    @Inject
    protected UploadAdaptor upload;

    @At
    @Ok("->:/private/file/uploadOne.html")
    public void uploadOne(@Param("filetype") String filetype,HttpServletRequest req){
        req.setAttribute("filetype", filetype);
        req.setAttribute("allowExtensions", FileType.getSuffixname(upload, filetype));

    }

 

如上所述,在限制文件上传类型的同时,还可以将文件分类保存在不同类型的目录下。

201312 月25

CDMA iPhone 4 iOS7.0.4/7.1 越狱并解决联系人括号问题的办法

1、先使用evasi0n7越狱; 2、进入Cydia按照提示更新Cydia到最新版; 3、Cydia软件源添加 http://apt.weiphone.com; 4、Cydia搜索afc2add选择威锋源安装; 5、使用同步助手或其他工具浏览iPhone文件系统: 浏览至目录 /System/Library/PrivateFrameworks/AppSupport.framework 用压缩包里的 Default.phoneformat 替换之,重启后即可。 为防万一最好备份此文件。

绿色evasi0n7及Default.phoneformat 文件下载:http://pan.baidu.com/s/1nt16UgD

 

PS:CDMA iPhone 4 用了快三年了,有些毛病,坚持到明年iPhone6再换。。

201312 月20

Nutz:通过URL路径查找对应的类及入口函数

由于Nutz是零配置的,所以通过URL找到处理类以及跳转的页面,就显得很麻烦,不方便维护。

于是,我在大神兽的指导下,实现如下功能:在项目启动时,将URL路径、类、方法、以及跳转页面写入项目中的一个文件中,方便查看。

@UrlMappingBy(value=UrlMappingSet.class)
public class MainModule { 
}

在Nutz入口类,加入 @UrlMappingBy。

UrlMappingSet.java 实现在 /WEB-INF/ 目录下生成 paths.txt 文件,记录路径,文件格式如下:
       QQ截图20131220094847
UrlMappingSet.java 源码:
package com.hits.core;

import java.io.File;
import java.lang.reflect.Method;

import org.nutz.lang.Files;
import org.nutz.lang.Lang;
import org.nutz.mvc.ActionChainMaker;
import org.nutz.mvc.ActionInfo;
import org.nutz.mvc.Mvcs;
import org.nutz.mvc.NutConfig;
import org.nutz.mvc.impl.UrlMappingImpl;

/**
 * 类描述: 创建人:Wizzer 联系方式:www.wizzer.cn 创建时间:2013-12-19 下午10:36:17
 * 
 * @version
 */
public class UrlMappingSet extends UrlMappingImpl {
    private static int count = 0;

    public void add(ActionChainMaker maker, ActionInfo ai, NutConfig config) {
        super.add(maker, ai, config);
        printActionMappingThis(ai);

    }

    protected void printActionMappingThis(ActionInfo ai) {

        String[] paths = ai.getPaths();
        StringBuilder sb = new StringBuilder();
        if (null != paths && paths.length > 0) {
            sb.append(paths[0]);
            for (int i = 1; i < paths.length; i++)
                sb.append(",").append(paths[i]);
        } else {
            throw Lang.impossible();
        }
        sb.append("\n");
        // 打印方法名
        Method method = ai.getMethod();
        String str;
        if (null != method)
            str = String.format("%-30s : %-10s", Lang.simpleMetodDesc(method),
                    method.getReturnType().getSimpleName());
        else
            throw Lang.impossible();

        sb.append("\t" + ai.getModuleType().getName());
        sb.append("\n\r");
        sb.append("\t" + str);
        sb.append("\n");
        String filepath = Mvcs.getServletContext().getRealPath("/WEB-INF/")
                + "/paths.txt";
        File f = new File(filepath);
        if (count == 0) {
            Files.write(f, sb.toString());
        } else {

            Files.appendWrite(f, sb.toString());
        }
        count++;
    }
}
201312 月15

Nutz:自定义取值区间(可分页查询)

使用示例:

            /**
            你可以自定义取数据区间的值,如下:

            offset=0,count=5     取0到5的记录
            offset=5,count=10    取5到15的记录
            page=3, offset=15,count=20   取15到35的记录
            **/
            int offset=0;
            int count=5;
            ExplicitPager pager=new ExplicitPager(offset,count);
            QueryResult file=daoCtl.listPage(dao, Oa_doc_file.class, cri,pager);

 

ExplicitPager 类源码:

package com.hits.common.page;

import org.nutz.dao.pager.Pager;

/** 
 * 类描述: 
 * 创建人:Wizzer 
 * 联系方式:www.wizzer.cn
 * 创建时间:2013-12-12 下午3:16:21 
 * @version 
 */
public class ExplicitPager extends Pager {

    private static final long serialVersionUID = 1L;
    int offset;
    int count;

    public ExplicitPager(int offset, int count) {
        super();
        this.offset = offset;
        this.count = count;
    }

    public void setOffset( int offset) {
        this.offset = offset;
    }

    public void setSelectCount( int count) {
        this.count = count;
    }

    @Override
    public int getPageSize() {
        return count;
    }

    @Override
    public int getOffset() {
        return offset;
    }

}

分页源代码(可参考上一篇文章,实现自定义SQL多表分页区间取值):

    /**
     * 根据查询条件分页,返回封装好的QueryResult对象
     * 
     * @param dao
     * @param obj
     * @param cnd
     * @param pager
     * @return
     */
    public  QueryResult listPage(Dao dao, Class obj, Condition cnd,Pager pager) { 
        List list = dao.query(obj, cnd, pager);
        pager.setRecordCount(dao.count(obj, cnd));// 记录数需手动设置
        return new QueryResult(list, pager);
    }
    /**
     * 根据自定义SQL分页,返回封装好的QueryResult对象
     * @param dao
     * @param sql
     * @param pager
     * @return
     */
        public 
 QueryResult listPageSql(Dao dao, Sql sql, Pager pager) {
        if(pager==null)
            return null;
        pager.setRecordCount(Daos.queryCount(dao, sql.getSourceSql()));// 记录数需手动设置
        sql.setPager(pager);
        sql.setCallback(Sqls.callback.records());
        dao.execute(sql);  
        return new QueryResult(sql.getList(Map.class), pager);
    }
201312 月15

Nutz:自定义SQL多表多字段分页查询方法

easyui.datagrid 调用示例:

    @At
    @Ok("raw")
    public String test(@Param("page") int curPage, @Param("rows") int pageSize){
        Sql sql=Sqls.create("select a.name,b.loginname From sys_unit a,sys_user b where a.id=b.unitid");
        return daoCtl.listPageJsonSql(dao, sql, curPage, pageSize);
    }

源代码:

    /**
     * 根据自定义SQL分页,返回封装好的QueryResult对象
     * @param dao
     * @param sql
     * @param curPage
     * @param pageSize
     * @return
     */
    public  QueryResult listPageSql(Dao dao, Sql sql, int curPage,int pageSize) {
        Pager pager = dao.createPager(curPage, pageSize);

        pager.setRecordCount(Daos.queryCount(dao, sql.getSourceSql()));// 记录数需手动设置
        sql.setPager(pager);
        sql.setCallback(Sqls.callback.records());
        dao.execute(sql); 
        return new QueryResult(sql.getList(Map.class), pager);
    }
    /**
     * 根据自定义SQL分页,返回封装好的 Easyui.datagrid JSON
     * @param dao
     * @param sql
     * @param curPage
     * @param pageSize
     * @return
     */
    public String listPageJsonSql(Dao dao, Sql sql, int curPage, int pageSize) {
            Pager pager = dao.createPager(curPage, pageSize);
            pager.setRecordCount(Daos.queryCount(dao, sql.toString()));// 记录数需手动设置
            sql.setPager(pager);
            sql.setCallback(Sqls.callback.records());
            dao.execute(sql);
            Map jsonobj = new HashMap();
            jsonobj.put("total", pager.getRecordCount());
            jsonobj.put("rows", sql.getList(Map.class));
            return Json.toJson(jsonobj);
       }
201311 月26

Nutz开发日志

计划基于Nutz开发一套全新的系统管理-权限框架。界面演示:/?p=2586 之前尝试Nutz做过一个demo,但有很多不足,比如没有做防SQL注入、不能兼容多数据库、列表没有实现Ajax等。

基于多年来开发过程接触的各式各样的框架,想整一套开发方便UI简洁的框架,要求有如下功能: 1.开发简便、框架结构清晰 2.性能优越、兼容主流数据库、兼容各版本浏览器 3.UI简洁、开发简单、主流JS插件集成、全Ajax 4.集成权限框架、单点登陆、登陆日志、操作日志 5.工作流引擎、表单自定义 6.代码生成器

JS引入: jquery-1.10.2.min.js ueditor-1.2.6.1 My97Datepicker-4.8 Beta4 zDialog-2.0 ztree-3.5.15

框架引入: Nutz-1.49.r2 log4j-1.2.17 json-1.0 c3p0-0.9.1.2 classes12 mysql-connector-java-5.1.14 ojdbc14 slf4j-api-1.6.1 slf4j-log4j12-1.6.1 sqljdbc4 velocity-1.7 velocity-tools-2.0 velocity-tools-generic-2.0 velocity-tools-view-2.0 json-lib-2.4-jdk15 ezmorph-1.0.6 commons-beanutils-1.7.0 commons-chain-1.1 commons-collections-3.2 commons-digester-1.8 commons-lang-2.2 commons-logging-1.1 commons-validator-1.3.1 待更新。


在Eclipse中处理图片,需要引入两个包: import com.sun.image.codec.jpeg.JPEGCodec; import com.sun.image.codec.jpeg.JPEGImageEncoder; 报错: Access restriction: The type JPEGImageEncoder is not accessible due to restriction on required library C:\Java\jre1.6.0_07\lib\rt.jar

此时解决办法: Eclipse默认把这些受访问限制的API设成了ERROR。只要把Windows-Preferences-Java-Complicer-Errors/Warnings里面的Deprecated and restricted API中的Forbidden references(access rules)选为Warning就可以编译通过。


Nutz开发说明:

您一定了解SSH,还有Strust1+Velocity框架

2013年11月30日(星期六) 晚上7:03给我写信

您一定了解 SSH ,还有 Strust1+Velocity 框架。前者配置文件实在是太多,多层架构,开发一个功能模块涉及很多类、很多关系,一方面上手非常难另外开发效率也不高。后者随着技术发展,对前端技术支持不太友好,比如 Ajax 、 JS 框架等,需要中间跳转页面进行输出,再者也需要配置。

根据项目开发中实际遇到的各种问题,研究各种框架优缺点之后,决定选择 Nutz 国产开源框架作为基础来构建本开发框架。选择 Nutz 有如下优点:

1、 URL“零”配置

您再也不用为繁琐的配置文件烦恼了, Nutz-Mvc 使用全注解的方式来封装 URL ,使用简单的 @At 在类或方法上实现 URL 映射。

2、灵活的多数据源支持

通过 Nutz.Ioc 您只要在数据库配置文件 datasource.json 中配置对象,如 dao1 、 dao2 ,那么在 Action 类中,

@Inject

    protected Dao dao1 ;

@Inject

protected Dao dao2 ;

即可使用 daoCtl 的方法直接操作这两个数据库。 daoCtl 里集成了常用的添加、修改、查询、分页等方法。

3、功能强大的视图

Nutz-Mvc 使用 @Ok @Fail 注解,来实现执行成功或失败后的输出,可以外部重定向、内部重定向、返回字符串、返回 JSON 等等,总之您想要什么结果就能给您返回什么,再也不用使用单独的 Action 类来封装 JSON 数据了,您想要随时都可以有。

4、功能强大的数据库操作

Nutz.Dao 封装了常用的数据库操作,减少自定义 SQL 的编写,提高开发效率和安全性,通过工具类

Cnd.where(“loginname”, “=”, user.getLoginname())

和

        
Sql sql = Sqls.create("DELETE FROM $table WHERE name=@name");

sql.vars().set(“table”,”t_abc”);

sql.params().set(“name”,”Peter”);

中的 sql.params().set() 方法,可以有效的防止 SQL 注入。

更多使用方法请参考本目录下的 nutz 开发手册。

5、 Velocity

对于大家常用的 Velocity 模板语言,本框架也进行了整合。

req.setAttribute(“menulist”, menulist);

将对象输出到页面,在页面上即可直接使用模板语言输出。

 

在 UI 表现层上面,本次框架也进行了调整,原则上支持纯 Ajax 开发。后台集成 jQuery 、 EasyUI 、 zDialog 、 EasyUI.DataGrid 、 ztree 、 My97DatePicker 等 JS 组件。

1、兼容主流浏览器

您再也不用考虑浏览器兼容性问题,只要您的 JS 全部使用 jQuery 来编写,那么还用担心什么呢,本框架目前在 IE6/IE7/IE8/IE9/IE10/IE11 、 Chrome 、 FrieFox 、 360 测试通过。

2、 zDialog的使用更加简便

通过使用 Ajax 以及对 zDialog 的优化,您再也不需要写中间页面进行页面跳转了。您可以在弹出框的父页面进行弹出表单的提交,在父页面写弹出框按钮的事件。

通过 $DW.$(“#form1”).serialize();  获取弹出窗口表单内容

         $DW.$Z(“name”).focus();     操作弹出框内容,赋值等

         $D.close();                                   关闭弹出窗口

让我们看一个完成的示例:

function addSave(){ 

if($DW.Verify.hasError()){

return;

}

jQuery.ajax({

type: ‘POST’,

url : “/private/sys/unit/addSave” ,

data : $DW.$(“#form1”).serialize(),

success : function (res) {

if(res!=””){

$D.close();

Dialog.alert(“ 添加成功! “);

initTree();

view(res);

}else{

Dialog.alert(“ 添加失败! “);

}

return false;

},

fail : function(res) {

Dialog.alert(“ 系统错误 ?!”);

}

});

}

3、 Ajax分页支持

集成 jQuery.Easyui.DataGrid ,从后台封装的 JSON 数据格式,到前台展示,分页查询从来没有如此简便过。

daoCtl.getListPageJson() 封装了 easyui.datagrid 分页所需格式数据,更不用您手动写烦人的 JSON 了。

4、权限控制到按钮

您只需要在 JS 中使用

               Page.initBtn();

$!initBtn

即可控制页面按钮是否可用,当然,在此之前,您需要在资源菜单管理中添加按钮 ID ,在角色管理中对用户分配按钮权限。

 

 

201311 月22

Can’t get hostname for your address

skip-name-resolve #加上这一个属性

201311 月20

新鲜出炉:百度电视云V3.2.2评测

电视型号:创维4K ,39E780U

分辨率:4096×2160

网络链接:有线链接,20M电信光纤

USB:外接2T移动硬盘

1、图片

打开速度很快,无bug,建议按时间倒序排序(或按菜单选择排序方式)。

2、音乐

网盘音乐:列表空白,什么也没有?网盘里明明有几百首。(已绑定帐号)

在线音乐:音乐不能播放。播放不了会自动跳转到下一首,自动跳了几首都不能播放后,按“返回”到歌曲界面,按任何键都没有反应,等半天只有强制关机。歌曲界面“播放”和按钮背景错位。

3、电影

网盘视频:和音乐一样,列表空白啥也木有。加载半天没任何反应,退不出界面,只有按“主页”强制退出。

电影:介绍界面上“收藏”按钮文字和背景错位。《金刚》电影不能播放,其他电影能播放但按“菜单”没有像其他客户端那样有清晰度选项,视频清晰度比其他TV客户端都低。播放比较流畅。按“返回”退出播放,弹出的确定或取消,“确定”文字不显示。

电视剧:介绍界面上的“选集”功能设计的不好,占用了这个屏幕,不像其他客户端那样合理方便。“收藏”按钮文字和背景错位。按“返回”退出播放,弹出的确定或取消,“确定”文字不显示。看《我们结婚吧》半小时左右,中途毫无征兆的自动退出播放,到介绍界面去了。

视频播放:不知道连续长时间播放会不会出现其他TV客户端出现的短暂音画不同步的情况?按这么低的清晰度来说,应该不会出现吧,但队友4K电视来说,这些视频分辨率也太寒碜了。另外能增加电视直播功能、英雄联盟比赛直播等功能就太好了。

4、以下是运行截图

2013-11-20 185200
电视上已安装的软件。
2013-11-20 185221

百度电视云主界面。

 

2013-11-20 185250

设置界面。

 

2013-11-20 185456

照片,速度很快。

 

2013-11-20 185834

网盘音乐空白。

 

2013-11-20 185906

在线音乐按钮太小,错位。

 

2013-11-20 185932

 

在线音乐不能播放,返回后死机。

 

2013-11-20 190303

 

网盘视频空白。

 

2013-11-20 190549

 

在线视频界面。

 

2013-11-20 190605

 

电影介绍,收藏按钮有问题。

 

2013-11-20 190825

 

退出播放,按钮变形。

 

2013-11-20 191510

电视剧介绍界面选集覆盖了整个屏幕,设计不太合理。

 

201311 月20

SSH:id元素中的generator

元素中的用来为该持久化类的实例生成唯一的标识,hibernate提供了很多内置的实现。

Increment:由hibernate自动递增生成标识符,用于为long, short或者int类型生成唯一标识。 identity :由底层数据库生成标识符(自动增长),返回的标识符是 long, short 或者int类型的。 sequence :hibernate根据底层数据库序列生成标识符,返回的标识符 是long, short或者 int类型的。

hilo     :使用一个高/低位算法来高效的生成long, short 或者int类型的标识符。 uuid.hex :用一个128-bit的UUID算法生成32位字符串类型的标识符。 native   :根据底层数据库的能力选择identity, sequence 或者hilo中的一个。 assigned :让应用程序在save()之前为对象分配一个标示符。 foreign :使用另外一个相关联的对象的标识符。和联合一起使用。

201311 月19

Java 加Filter过滤器的时候一定记得设置编码格式

package web;

import web.sys.Globals;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;

public class SqlFilter implements Filter {
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse res = (HttpServletResponse) response;
    req.setCharacterEncoding("GBK");
        res.setCharacterEncoding("GBK");
        //获得所有请求参数名
        Enumeration params = req.getParameterNames();

        String sql = "";
        while (params.hasMoreElements()) {
            //得到参数名
            String name = params.nextElement().toString();
            //得到参数对应值
            String[] value = req.getParameterValues(name);
            for (int i = 0; i < value.length; i++) {
                sql = sql + value[i];
            }
        }

        //有sql关键字,跳转到error.html
        if (sqlValidate(sql)) {
            res.sendRedirect("/"+Globals.APP_BASE_NAME+"/include/404error.html");
            //String ip = req.getRemoteAddr();
        } else {
            chain.doFilter(req, res);
        }
    }

    //效验
    protected static boolean sqlValidate(String str) {
        str = str.toLowerCase();//统一转为小写
        String badStr = "and|exec|execute|insert|create|drop|table|from|grant|use|" +
                "group_concat|column_name|information_schema.columns|table_schema|" +
                "where|select|delete|update|order|by|*|chr|char" +
                "|declare|;|--|+|,|%|#";//过滤掉的sql关键字,可以手动添加  qxmore000400010009
        String[] badStrs = badStr.split("\\|");

        for (int i = 0; i < badStrs.length; i++) {
            if (str.indexOf(badStrs[i]) != -1) {

                return true;
            }
        }
        return false;
    }

    public void init(FilterConfig filterConfig) throws ServletException {
        //throw new UnsupportedOperationException("Not supported yet.");
    }

    public void destroy() {
        //throw new UnsupportedOperationException("Not supported yet.");
    }
}
201311 月7

JS+CSS 幻灯片下载效果非常好

QQ截图20131107163030

使用时候注意两处, 一是图片宽度、高度要固定, 二是如果图片宽度变了,那s.js也要改成一样的。

下载地址:

http://pan.baidu.com/s/1eiYiz

201311 月7

三星GT-P6200 4.0.4国行固件下载

文件名称:Samsung-Updates.com-GT-P6200-CHN-P6200ZCLPR-1363586771

国行Android 4.0.4 版本,,,逛了一圈论坛,要么收费(鄙视之),要么不能用会变砖,,自己从官网翻,墙下到的固件,分享一下。

 

http://yun.baidu.com/s/1h6JRR