利用动态代理来实现DAO层中的方法

动态代理实现接口

动态代理机制是jdk1.3版本以后引入的,在下面我主要用动态代理来实现接口,并且用注释来代替查询语句注释
DAO方法如下

package com.yf.dao;

import java.util.List;

import com.yf.annotation.Result;
import com.yf.annotation.SQL;
import com.yf.entity.Hero;
import com.yf.enums.HandlerType;

public interface HeroDao {
	// 英雄查询总数量
	@SQL("select count(*) from hero where power=#{powerId}")
	@Result(handlerType = HandlerType.SCARLAR)
	int getHeroCountByPowerId(int powerId);

	// 根据势力ID查询英雄 #{。。。}为占位符
	@SQL("select h.id id,h.name name ,p.name powername from hero h,power p where p.id=h.power and power=#{powerid} limit #{startnum},#{pageSize}")
	@Result(handlerType = HandlerType.BEANLIST, javaType = Hero.class)
	List<Hero> selectHero(int powerid, int startnum, int pageSize);
}

定义常量类:在代码中尽量不要出现常量,常量被称为 魔鬼数字,因为在后期对代码进行修改时,会比较麻烦,然后当我们定义常量类以后,可以让我们轻松的修改常量

package constant;
//常量类
public class TypeConstant {
	//请求地址后缀名
	public static final String URI_SUFFIX=".action";
	//类名后缀
	public static final String MODEL_SUFFIX="Model";
	//包名
	public  static final String MODEL_PACKAGE="com.yf.model";
	//重定向的字符前缀
	public static final String REDIRECT_PREFIX="redirect:";

}

定义注解的类

这是定义数据类型的注解类
package com.yf.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import com.yf.enums.HandlerType;

@Retention(RetentionPolicy.RUNTIME) //指定注解保留到程序运行的时间 
@Target(ElementType.METHOD)//给方法进行注解
public @interface Result {
	// 定义查询返回封装数据类型
	HandlerType handlerType();

	// 定义查询中的类类型
	Class<?> javaType() default Object.class;
}
定义sql语句的注解类
package com.yf.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)  //指定注解保留到程序运行的时间 
@Target(ElementType.METHOD)//给方法进行注解
public @interface SQL {

	String value();
}

定义数据类型的枚举类

package com.yf.enums;

public enum HandlerType {
	BEAN, BEANLIST, COLUMNLIST, ID, ROWS, SCARLAR
}

动态代理的方法

package com.yf.proxy;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ColumnListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;

import com.yf.annotation.Result;
import com.yf.annotation.SQL;
import com.yf.enums.HandlerType;
import com.yf.util.DBUtil;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import ognl.Ognl;
import ognl.OgnlContext;

public class DaoProxy {
	@SuppressWarnings("unchecked")
		/*
	 * 实现所有接口的动态代理
	 */
	 // T为不确定什么类型,然后用T代替 
	public static <T> T getDaoInstance(Class<?> calzz) {
		// 定义加强器
		Enhancer enh = new Enhancer();
		// 设置要被代理的接口
		enh.setSuperclass(calzz);
		enh.setCallback(new MethodInterceptor() {

			@Override
			public Object intercept(Object arg1, Method method, Object[] objs, MethodProxy arg3) throws Throwable {
				// method为被代理的方法,objs为方法中的参数值构成的数组
				// 获取dao中的sql语句
				SQL sqlannotation = method.getDeclaredAnnotation(SQL.class);
				String sql = "";
				if (sqlannotation != null) {
					sql = sqlannotation.value();
				}
				// 获取result注解的结果类型
				Class<?> javatype = null;
				HandlerType handlertype = null;
				// 从Dao接口中获取类型
				Result resultannotation = method.getDeclaredAnnotation(Result.class);
				if (resultannotation != null) {
					javatype = resultannotation.javaType();
					handlertype = resultannotation.handlerType();
				}
				QueryRunner qr = new QueryRunner(DBUtil.getDs());
				System.out.println("查询前" + sql);
				// 可以用Ognl工具来替代的Map集合
				OgnlContext ognicontext = new OgnlContext();
				// 通过反射获取方法中所有的参数
				
				Parameter[] parameters = method.getParameters();
				// 利用循环把参数加入到map集合中
				
				for (int i = 0; i < parameters.length; i++) {
					
					ognicontext.put(parameters[i].getName(), objs[i]);
				}
				// 寻找需要替换的占位符
				Matcher matcher = Pattern.compile("(\\#|\\$)\\{(\\w*\\.)*\\w*\\}").matcher(sql);
				// 找到需要替换的字符
				while (matcher.find()) {
					// 寻找占位符#{}
					String paramstr = matcher.group();
					
					Object paramValue = null;
					// 判断字符串是不是以#开头
					if (paramstr.startsWith("#")) {
						// 获取参数值
						paramValue = Ognl.getValue(paramstr.replace("#{", "").replace("}", ""), ognicontext);
						
						
					} else {
						paramValue = Ognl.getValue(paramstr.replace("${", "").replace("}", ""), ognicontext);
					}
				
					// 获取参数类型
					Class<?> paramtype = paramValue.getClass();
					
					if (paramtype == String.class) {
						// 当参数为字符串时,加上''符号
						if (paramstr.startsWith("#")) {
							sql = sql.replace(paramstr, "'" + paramValue + "'");
						} else {
							sql = sql.replace(paramstr, String.valueOf(paramValue));
						}

					} else {
						sql = sql.replace(paramstr, String.valueOf(paramValue));
					}
				}
				System.out.println("更改后的语句" + sql);
				// 调用DBUtil方法中返回结果
				Object result = null;
				// 结果类型不同,运用不同的方法,可以实现不同的sql语句
				if (handlertype == HandlerType.BEAN) {
					result = qr.query(sql, new BeanHandler<>(javatype));
				}
				if (handlertype == HandlerType.BEANLIST) {
					result = qr.query(sql, new BeanListHandler<>(javatype));
				}
				if (handlertype == HandlerType.SCARLAR) {
					result = qr.query(sql, new ScalarHandler<>());
				}
				if (handlertype == HandlerType.COLUMNLIST) {
					result = qr.query(sql, new ColumnListHandler<>());
				}
				if (handlertype == HandlerType.ID) {
					result = qr.insert(sql, new ScalarHandler<>());
				}
				if (handlertype == HandlerType.ROWS) {
					result = qr.update(sql);
				}
				return result;
			}
		});
		return (T) enh.create();

	}


	// 定义私有的构造方法
	private DaoProxy() {

	}
}

动态代理可以在不修改源码的情况下,对内容进行一些增加,因为很多软件或网址,几乎都会进行增加功能,这时动态代理就可以提供很大的方便,但是也有缺点,因为动态代理只能够代理接口,不可以代理类

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值