srm smartDao

来源:互联网 发布:英雄无敌6加点 知乎 编辑:程序博客网 时间:2024/05/16 10:28
package com.fujitsu.cn.fnst.framework.smartdao;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.apache.shiro.config.ConfigurationException;
import org.nutz.castor.Castors;
import org.springframework.aop.framework.ReflectiveMethodInvocation;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;

import com.fujitsu.cn.fnst.framework.dao.BaseDao;
import com.fujitsu.cn.fnst.framework.smartdao.annotation.Arguments;
import com.fujitsu.cn.fnst.framework.smartdao.annotation.Hql;
import com.fujitsu.cn.fnst.framework.smartdao.annotation.Sql;
import com.fujitsu.cn.fnst.framework.util.FreemarkerParseFactory;
import com.fujitsu.cn.fnst.framework.util.ReflectUtils;
import com.fujitsu.cn.fnst.framework.util.SmartDaoUtil;

/**
 * 智能Dao自动代理类处理器 The Class SmartDaoInterceptor.<br>
 *
 * @author FNST)韋 燦楽
 * @version 0.1
 */
public class SmartDaoInterceptor implements MethodInterceptor {

    private static final Logger logger = Logger.getLogger(SmartDaoInterceptor.class);
    private JdbcTemplate jdbcTemplate;
    private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
    private BaseDao baseDao;
    private boolean showsql;

    private LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();

    public SmartDaoInterceptor() {
    }

    public Object invoke(MethodInvocation methodInvocation) throws Throwable {

        // 如果是代理类,就需要获取代理。getThis会取到null
        Object srcObj;
        if (methodInvocation instanceof ReflectiveMethodInvocation) {
            srcObj = ((ReflectiveMethodInvocation) methodInvocation).getProxy();
        } else {
            srcObj = methodInvocation.getThis();
        }
        Method method = methodInvocation.getMethod();
        Object args[] = methodInvocation.getArguments();

        Object returnObj = null;

        String templateSql = null;

        Map<String, Object> sqlParamsMap = new HashMap<String, Object>();

        if (!SmartDaoUtil.isAbstract(method))
            return methodInvocation.proceed();

        Map<String, Object> rs = new HashMap<String, Object>();
        // BaseDao接口中的方法,由BaseDaoImpl处理
        if (processWithBaseDao(srcObj, rs, method, args)) {
            return rs.get("returnObj");
        }
        // 非BaseDao接口的方法
        else {
            templateSql = setupSqlAndParam(srcObj, method, sqlParamsMap, args);

            String executeSql = parseSqlTemplate(method, templateSql, sqlParamsMap);

            returnObj = getReturnResult(method, executeSql, sqlParamsMap);
            return returnObj;
        }
    }

    /**
     * BaseDao接口中的方法,由BaseDaoImpl处理
     *
     * @param rs
     *            运行结果
     * @param method
     *            方法
     * @param args
     *            方法参数
     * @return 是否使用BaseDao进行处理
     */
    private boolean processWithBaseDao(Object src, Map<String, Object> rs, Method method,
            Object args[]) {
        Class clz2 = null;
        try {
            Type genType = src.getClass().getInterfaces()[0].getGenericInterfaces()[0];
            Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
            clz2 = (Class) params[0];
        } catch (Exception e) {
            logger.warn("didn't set the ParameterizedType of BaseDao");
        }

        String methodName = method.getName();
        if ("getHibernateTemplate".equals(methodName)) {
            rs.put("returnObj", baseDao.getHibernateTemplate());
            return true;
        }
        if ("save".equals(methodName)) {
            baseDao.save(args[0]);
            return true;
        }
        if ("update".equals(methodName)) {
            baseDao.update(args[0]);
            return true;
        }
        if ("saveOrUpdate".equals(methodName)) {
            baseDao.saveOrUpdate(args[0]);
            return true;
        }
        if ("delete".equals(methodName)) {
            baseDao.delete(args[0]);
            return true;
        }
        if ("deleteEntityById".equals(methodName)) {
            if (args.length > 1) {
                Class<?> clz = (Class<?>) args[0];
                baseDao.deleteEntityById(clz, (Serializable) args[1]);
            } else {
                baseDao.deleteEntityById(clz2, (Serializable) args[0]);
            }
            return true;
        }
        if ("get".equals(methodName)) {
            if (args.length > 1) {
                Class<?> clz = (Class<?>) args[0];
                rs.put("returnObj", baseDao.get(clz, (Serializable) args[1]));
            } else {
                rs.put("returnObj", baseDao.get(clz2, (Serializable) args[0]));
            }
            return true;
        }
        if ("getByExample".equals(methodName)) {
            rs.put("returnObj", baseDao.getByExample(args[0]));
            return true;
        }
        if ("listAll".equals(methodName)) {
            if (args.length > 0) {
                Class<?> clz = (Class<?>) args[0];
                rs.put("returnObj", baseDao.listAll(clz));
            } else {
                rs.put("returnObj", baseDao.listAll(clz2));
            }
            return true;
        }
        return false;
    }

    /**
     * 用Freemarker解析SQL模版
     *
     * @param method
     *            方法
     * @param templateSql
     *            SQL模版
     * @param sqlParamsMap
     *            SQL参数
     * @return
     */
    private String parseSqlTemplate(Method method, String templateSql,
            Map<String, Object> sqlParamsMap) {
        String executeSql = null;
        if (StringUtils.isNotEmpty(templateSql)) {
            executeSql = (new FreemarkerParseFactory()).parseTemplateContent(templateSql,
                    sqlParamsMap);
        } else {
            // TODO sql maker ?
        }

        logger.debug("SmartDao-execute sql:\n" + executeSql + "\n");
        if (showsql) {
            System.out.println("SmartDao-execute sql:\n" + executeSql + "\n");
        }
        return executeSql;
    }

    /**
     * 执行SQL,获取结果
     *
     * @param method
     * @param executeSql
     * @param paramMap
     * @return
     */
    private Object getReturnResult(Method method, String executeSql, Map<String, Object> paramMap) {
        // 指定@Hql注解的方法,通过Hibernate执行HQL
        if (method.isAnnotationPresent(Hql.class)) {
            if (paramMap != null && !paramMap.isEmpty()) {
                String[] allParamNames = paramMap.keySet().toArray(new String[0]);

                List<String> paramNames = new ArrayList<String>();
                List<Object> paramValues = new ArrayList<Object>();

                for (String paramName : allParamNames) {
                    Object parmaValue = paramMap.get(paramName);
                    // 值为null的参数过滤掉不传递给Hibernate,否则Hibernate会报错;
                    // 但是同时需要保证传给Hibernate的SQL里面也应该没有这个参数,比如:userName
                    if (parmaValue != null) {
                        paramNames.add(paramName);
                        paramValues.add(parmaValue);
                    }
                }

                return baseDao.getHibernateTemplate().findByNamedParam(executeSql,
                        paramNames.toArray(new String[0]), paramValues.toArray(new Object[0]));
            } else {
                return baseDao.getHibernateTemplate().find(executeSql);
            }
        }

        String methodName = method.getName();

        // 如果是更新,插入,删除 操作,则返回值为整型
        if (isUpdateSql(methodName)) {
            if (paramMap != null)
                return Integer.valueOf(namedParameterJdbcTemplate.update(executeSql, paramMap));
            else
                return Integer.valueOf(jdbcTemplate.update(executeSql));
        }

        Class<?> returnType = method.getReturnType();

        SqlParameterSource sqlParam = null;
        if (paramMap != null) {
            sqlParam = new MapSqlParameterSource(paramMap);
        }

        // 各种类型分解
        if (returnType.isPrimitive()) {
            Object o = null;
            if (paramMap != null) {
                o = namedParameterJdbcTemplate.queryForObject(executeSql, sqlParam, returnType);
            } else {
                o = jdbcTemplate.queryForObject(executeSql, returnType);
            }
            return Castors.me().cast(o, o.getClass(), returnType);
        } else if (returnType.isAssignableFrom(List.class)) {
            List<Map<String, Object>> result;
            if (paramMap != null)
                result = namedParameterJdbcTemplate.queryForList(executeSql, sqlParam);
            else
                result = jdbcTemplate.queryForList(executeSql);

            if (result == null) {
                return null;
            }

            ParameterizedType genType = (ParameterizedType) method.getGenericReturnType();
            Type comptype = genType.getActualTypeArguments()[0];
            Class<?> compclz = (Class<?>) comptype;

            ArrayList objList = new ArrayList();

            if (compclz.isPrimitive() || Number.class.isAssignableFrom(compclz)
                    || CharSequence.class.isAssignableFrom(compclz)
                    || "Date".equals(compclz.toString())) {
                Object o = null;
                for (Map<String, Object> map : result) {
                    o = map.values().iterator().next();
                    objList.add(Castors.me().cast(o, o.getClass(), compclz));
                }
                return objList;
            }

            for (Map<String, Object> map : result) {
                Object o;
                o = ReflectUtils.convert(map, compclz);
                if (o != null) {
                    objList.add(o);
                }
            }
            return objList;
        } else if (returnType.isAssignableFrom(Map.class)) {
            if (paramMap != null)
                return namedParameterJdbcTemplate.queryForMap(executeSql, sqlParam);
            else
                return jdbcTemplate.queryForMap(executeSql);
        } else if (returnType.isAssignableFrom(String.class)) {
            try {
                if (paramMap != null)
                    return namedParameterJdbcTemplate.queryForObject(executeSql, sqlParam,
                            String.class);
            } catch (EmptyResultDataAccessException e) {
                return null;
            }
            return jdbcTemplate.queryForObject(executeSql, String.class);
        } else if (SmartDaoUtil.isWrapClass(returnType)) {
            try {
                if (paramMap != null)
                    return namedParameterJdbcTemplate.queryForObject(executeSql, sqlParam,
                            returnType);
            } catch (EmptyResultDataAccessException e) {
                return null;
            }
            return jdbcTemplate.queryForObject(executeSql, returnType);
        }

        // RowMapper<?> rm =
        // ParameterizedBeanPropertyRowMapper.newInstance(returnType);
        Map<String, Object> map;
        if (paramMap != null) {
            try {
                map = namedParameterJdbcTemplate.queryForMap(executeSql, sqlParam);
            } catch (EmptyResultDataAccessException e) {
                map = null;
            }
        } else {
            map = jdbcTemplate.queryForMap(executeSql);
        }

        return map == null ? null : ReflectUtils.convert(map, returnType);
    }

    private String setupSqlAndParam(Object src, Method method, Map<String, Object> sqlParamsMap,
            Object args[]) throws Exception {
        String templateSql = null;

        if (method.isAnnotationPresent(Arguments.class)) {
            Arguments argms = method.getAnnotation(Arguments.class);
            if (argms.value().length != args.length) {
                throw new ConfigurationException("SQL参数与方法参数个数不同: " + method.getName());
            }

            for (int i = 0; i < args.length; i++) {
                sqlParamsMap.put(argms.value()[i], args[i]);
            }

        } else {
            String[] params = u.getParameterNames(method);
            if (params == null) {
                // 取不到接口参数名
                for (int i = 0; i < args.length; i++) {
                    sqlParamsMap.put("arg" + i, args[i]);
                }
            } else {
                // 使用接口参数名
                for (int i = 0; i < args.length; i++) {
                    sqlParamsMap.put(params[i], args[i]);
                }
            }
        }

        if (method.isAnnotationPresent(Sql.class)) {
            Sql sql = (Sql) method.getAnnotation(Sql.class);
            if (StringUtils.isNotEmpty(sql.value())) {
                templateSql = sql.value();
            } else if (StringUtils.isNotEmpty(sql.file())) {
                templateSql = SmartDaoUtil.getTemplateSql(method.getClass().getClassLoader(),
                        sql.file());
            }
        } else {
            // 默认文件中的默认sql
            Class[] interfacse = src.getClass().getInterfaces();
            if (interfacse.length > 0) {
                String path = interfacse[0].getName();
                path = path.replace('.', '/');
                templateSql = SmartDaoUtil.loadSQL(path, method.getName());
            } else {
                // 否则怎么办?直接用代理类或实现类试试吧
                String path = src.getClass().getName();
                path = path.replace('.', '/');
                templateSql = SmartDaoUtil.loadSQL(path, method.getName());
            }

        }

        logger.debug((new StringBuilder("Sql------------------------------------------")).append(
                templateSql).toString());

        return templateSql;
    }

    private static boolean isUpdateSql(String methodName) {
        String keys[] = "add,create,insert,edit,modify,update,store,remove,delete".split(",");
        for (int i = 0; i < keys.length; i++) {
            String s = keys[i];
            if (methodName.startsWith(s))
                return true;
        }
        return false;
    }

    public Class<BaseDao> getBaseDaoDeclare(Class c) {
        Class root = c;
        if (root.equals(BaseDao.class)) {
            return root;
        } else {
            Class[] clzs = root.getInterfaces();
            for (Class class1 : clzs) {
                Class clz = getBaseDaoDeclare(class1);
                if (clz != null) {
                    return clz;
                }
            }
        }

        return null;
    }

    public NamedParameterJdbcTemplate getNamedParameterJdbcTemplate() {
        return namedParameterJdbcTemplate;
    }

    public void setNamedParameterJdbcTemplate(NamedParameterJdbcTemplate namedParameterJdbcTemplate) {
        this.namedParameterJdbcTemplate = namedParameterJdbcTemplate;
    }

    public JdbcTemplate getJdbcTemplate() {
        return jdbcTemplate;
    }

    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    /**
     * @return the baseDao
     */
    public BaseDao getBaseDao() {
        return baseDao;
    }

    /**
     * @param baseDao
     *            the baseDao to set
     */
    public void setBaseDao(BaseDao baseDao) {
        this.baseDao = baseDao;
    }

    /**
     * @return the showsql
     */
    public boolean getShowsql() {
        return showsql;
    }

    /**
     * @param showsql
     *            the showsql to set
     */
    public void setShowsql(boolean showsql) {
        this.showsql = showsql;
    }

}







分割线---------------------------------------------------------------------------------------------




package com.fujitsu.cn.fnst.framework.smartdao;

import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.aop.framework.ProxyFactoryBean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

import com.fujitsu.cn.fnst.framework.smartdao.annotation.SmartDao;
import com.fujitsu.cn.fnst.framework.util.PackagesToScanUtil;
import com.fujitsu.cn.fnst.framework.util.SmartDaoUtil;

/**
 * 智能Dao自动代理工厂
 * The Class SmartDaoBeanFactory.<br>
 *
 * @author FNST)韋 燦楽
 * @version 0.1
 */
public class SmartDaoBeanFactory implements BeanFactoryPostProcessor {
    
    private List<String> packagesToScan;
    private List<String> interceptorNames;
    
    public SmartDaoBeanFactory() {
    }

    /**
     * 扫描可以自动代理的接口
     * 業務機能メソッドを実装する。<br>
     *
     * @return 復帰値>0:正常(後続処理なし)、<br>
     *         復帰値=0:正常終了、<br>
     *         復帰値<0:異常終了、<br>
     */
    public void postProcessBeanFactory(
            ConfigurableListableBeanFactory beanFactory) throws BeansException {

        logger.debug("===============SmartDaoBeanFactory_init===================");

        try {
            for (Iterator<String> iterator = packagesToScan.iterator(); iterator
                    .hasNext();) {
                String pack = (String) iterator.next();
                if (StringUtils.isNotEmpty(pack)) {
                    Set<Class> classSet = PackagesToScanUtil.getClasses(pack);
                    for (Iterator<Class> iterator1 = classSet.iterator(); iterator1.hasNext();) {
                        Class daoClass = (Class) iterator1.next();
                        if (daoClass.isAnnotationPresent(SmartDao.class)) {
                            ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
                            proxyFactoryBean.setBeanFactory(beanFactory);
                            proxyFactoryBean.setInterfaces(new Class[] { daoClass });
                            proxyFactoryBean.setInterceptorNames(interceptorNames.toArray(new String[0]));
                            String beanName = SmartDaoUtil.getFirstSmall(daoClass.getSimpleName());
                            if (!beanFactory.containsBean(beanName)) {
                                logger.info("SmartDao proxy ["+daoClass.getName()+"] as '"+beanName+"'");
                                beanFactory.registerSingleton(beanName,
                                        proxyFactoryBean.getObject());
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public List<String> getPackagesToScan() {
        return packagesToScan;
    }

    public void setPackagesToScan(List<String> packagesToScan) {
        this.packagesToScan = packagesToScan;
    }

    private static final Logger logger = Logger
            .getLogger(SmartDaoBeanFactory.class);

    public List<String> getInterceptorNames() {
        return interceptorNames;
    }

    public void setInterceptorNames(List<String> interceptorNames) {
        this.interceptorNames = interceptorNames;
    }
}







0 0