mybatis如何将接口实现

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/telrob/article/details/80065524

        在使用spring 项目中一般会使用的mybatis,一个接口就可以查询出数据库中的数据,是不是感觉很神奇?好吧,今天就来揭开她神秘的面纱吧。

    思路  :

  1. 项目启动时扫描特定的包或者特定注解的接口。
  2. 为对应的接口添加动态代理。
  3. 在接口调用时实现对应的方法。

好了废话少说,将已一个通过接口直接发送http请求的小项目来实现。

/**
 * 基于注解发送http请求
 * @author acer
 *
 */
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface HttpConnect {

}
/**
 * 用于请求参数
 * @author acer
 *
 */
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface HttpParam {
	String name();
}
/**
 * 在方法上注解,用于指明请求的方式,请求url,请求头
 * @author acer
 *
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface HtttpHead {
	public static final String GET="GET";
	public static final String POST="POST";
	String url();
	String method() default GET;
	String[] header() default{};
	int timeout() default 5000;
}
/**
 * 代理工厂
 * @author acer
 *
 * @param <T>
 */
public class MyProxyFactory<T> implements FactoryBean<T> {

    private Class<T> interfaceClass;
    public Class<T> getInterfaceClass() {
        return interfaceClass;
    }
    public void setInterfaceClass(Class<T> interfaceClass) {
        this.interfaceClass = interfaceClass;
    }
    @Override
    public T getObject() throws Exception {
        return (T) new MyProxy().bind(interfaceClass);
    }

    @Override
    public Class<?> getObjectType() {
        return interfaceClass;
    }

    @Override
    public boolean isSingleton() {
        // 单例模式
        return true;
    }

}
@Component
@Lazy(true)
public class MyRegistryBean implements ApplicationContextAware,BeanDefinitionRegistryPostProcessor{

    private ApplicationContext ctx;
    //最后执行
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    	 //Map<String, Object> map=beanFactory.getBeansWithAnnotation(AnalysisActuator.class);
    	 //for(String key:map.keySet()) {
    	//	 System.out.println("key:"+key);
    	// }
    }
  //第二执行
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
    	// 需要被代理的接口,可以通过扫描包来查找对应的类
    	List<Class>classList=new ArrayList<Class>();
    	ClassPathScanningCandidateComponentProvider p=new ClassPathScanningCandidateComponentProvider(false);
    	p.addIncludeFilter(new TypeFilter() {
			public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
					throws IOException {
				AnnotationMetadata an=metadataReader.getAnnotationMetadata();
				Set<String> string=an.getAnnotationTypes();
				String annName=HttpConnect.class.getName();
				ClassMetadata classm=metadataReader.getClassMetadata();
				if(string.contains(annName)) {
					try {
						classList.add(Class.forName(classm.getClassName()));
					} catch (ClassNotFoundException e) {
					}
				}
				return false;
			}
		});
    	p.findCandidateComponents("com.trilink.common");
    	for(Class<?>cls:classList) {
    		
    		//Class<?> cls = Hello.class;
    		BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(cls);
    		GenericBeanDefinition definition = (GenericBeanDefinition) builder.getRawBeanDefinition();
    		definition.getPropertyValues().add("interfaceClass", definition.getBeanClassName());
    		definition.setBeanClass(MyProxyFactory.class);
    		definition.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_TYPE);
    		// 注册bean名,一般为类名首字母小写
    		String name=cls.getName();
    		name=getClassName(name);
    		beanDefinitionRegistry.registerBeanDefinition(name, definition);
    	}
    }
    //最先执行
    @Override
    public void setApplicationContext(ApplicationContext ctx) throws BeansException {
    	this.ctx = ctx;
    }
    /**
     * 将类转换成首字母小写的名字
     * @param name
     * @return
     */
    public String getClassName(String name) {
    	int index=name.lastIndexOf(".");
		if(index>0) {
			name=name.substring(index+1,name.length());
		}
		char[] nameChar=name.toCharArray();
		nameChar[0]=(char) (nameChar[0]+32);
		name=new String(nameChar);
		return name;
    }
}
/**
 * 代理类
 * @author acer
 *
 */
public class MyProxy implements InvocationHandler {
	
	private Class<?> interfaceClass;

	public Object bind(Class<?> cls) {
	    this.interfaceClass = cls;
	    return Proxy.newProxyInstance(cls.getClassLoader(), new Class[] {interfaceClass}, this);
	}
	
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		return processURL(method,args);
	}
	
	/**
	 * 处理请求
	 * @param method
	 * @param args
	 * @return
	 * @throws Exception 
	 */
	private Object processURL( Method method, Object[] args) throws Exception {
		//将参数转换成map集合以便转换成json
		Map<String,Object>paramMap=new HashMap<String,Object>();
		if(args!=null&&args.length>0) {
			Annotation[][] ann=method.getParameterAnnotations();
			if(ann!=null&&ann.length>0) {
				for(int i=0;i<ann.length;i++) {
					for(int j=0;j<ann[i].length;j++) {
						Annotation a=ann[i][j];
						if(a instanceof HttpParam) {
							HttpParam an=(HttpParam)a;
							paramMap.put(an.name(),args[i]);
						}
					}
				}
			}
		}
		//参数转换成json
		Gson gson=new Gson();
		String json=gson.toJson(paramMap);
		//获取url
		HtttpHead head=method.getDeclaredAnnotation(HtttpHead.class);
		if(head==null) {
			return "not request url";
		}
		
		String url=head.url();
		String menthod=head.method();
		int timeout=head.timeout();
		String[] heads=head.header();
		URL ul=new URL(url);
		HttpURLConnection connect=(HttpURLConnection)(ul.openConnection());
		connect.setRequestMethod(menthod);
		connect.setDoOutput(true);
		connect.setDoInput(true);
		connect.setReadTimeout(timeout);
		//设置json格式
		connect.setRequestProperty("accept","application/json");
		if(heads!=null) {
			for(String h:heads) {
				String[]d=h.split(":");
				connect.setRequestProperty(d[0], d[1]);
			}
		}
		if(!paramMap.isEmpty()) {
			byte[] pm=json.getBytes();
			int length=pm.length;
			connect.setRequestProperty("Content-Length", length+"");
			OutputStream out=connect.getOutputStream();
			out.write(pm);
			out.flush();
			out.close();
		}
		if(connect.getResponseCode()==200) {
			InputStream in=connect.getInputStream();
			int len;
			byte[] bb=new byte[1024];
			ByteArrayOutputStream byteOut=new ByteArrayOutputStream();
			while((len=in.read(bb))>0) {
				byteOut.write(bb,0,len);
			}
			in.close();
			byte[] data=byteOut.toByteArray();
			byteOut.close();
			//开始对结果集处理
			Class<?>returnType=method.getReturnType();
			if(returnType.equals(Map.class)) {
				
			}else if(returnType.equals(byte[].class)||returnType.equals(Byte[].class)) {
				return data;
			}else if(returnType.equals(String.class)) {
				return new String(data);
			}else if(returnType.equals(int.class)||returnType.equals(Integer.class)) {
				String rt=new String(data);
				return Integer.parseInt(rt);
			}else {
				//当为一个对象时直接转换成对象
				String rt=new String(data);
				System.out.println("type:"+returnType.getName());
				return gson.fromJson(rt, returnType);
			}
			
			
		}else {
			throw new Exception("code:"+connect.getResponseCode());
		}
		
		return null;
	}
}
@HttpConnect
public interface Users{
	
	@AnalysisActuator
	public String say();
	
	@HtttpHead(url="http://localhost:8089/AppGoods/queryGoodsById",method=HtttpHead.POST)
	public String hh(@HttpParam(name="goodsId")String oo,@HttpParam(name="li")String hhh);
}
@Controller
@RequestMapping
public class TestController {

	@Autowired
	private Users users;
	
	@RequestMapping("/test")
	@ResponseBody
	public Object test() {
		return users.hh("551155021248", "bbb");
	}
	
	@RequestMapping("/say")
	@ResponseBody
	public Object say() {
		return users.say();
	}
}

总结:在编写这个功能之前也不知如何下手,开发过程中也遇到很多问题,一下是个人心的,只有具体实现的类才能够获取到类参数的名称,这也是mybatis接口中为嘛要使用注解的原因,而spring 的controller 中是具体的方法,所以可以不用注解直接根据参数名称注入。



猜你喜欢

转载自blog.csdn.net/telrob/article/details/80065524
今日推荐