<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.0.xsd" default-lazy-init="false"> <!-- 加载资源文件 --> <context:property-placeholder location="classpath:jdbc.properties" /> <!-- 配置数据源 dataSource--> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="${jdbc.driver}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </bean> <!-- 定义事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="insert*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception" /> <tx:method name="save*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception" /> <tx:method name="update*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception" /> <tx:method name="modify*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception" /> <tx:method name="delete*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception" /> <tx:method name="find*" propagation="SUPPORTS" /> <tx:method name="get*" propagation="SUPPORTS" /> <tx:method name="select*" propagation="SUPPORTS" /> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut id="bizMethods" expression="execution(* com.it.springbiz.*.service.*.*(..)) or execution(* com.it.springbiz.*.*.service.*.*(..))" /> <aop:advisor advice-ref="txAdvice" pointcut-ref="bizMethods" /> </aop:config> <!-- 编程式事务模板来完成Spring的编程式事务 --> <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"> <property name="transactionManager" ref="transactionManager" /> </bean> <!-- jdbcTemplate 用来操作数据库--> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"/> </bean> <!-- namedParameterJdbcTemplate支持命名参数特性 简化数据库操作--> <bean id="namedParameterJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate"> <constructor-arg index="0" ref="dataSource"></constructor-arg> </bean> <!-- Spring 扫描使用注解的包路径 --> <context:component-scan base-package="com.it" /> <!-- 提供注解接口服务的注册功能 --> <bean id="httpServiceProxy" class="com.iteye.http.HttpClientBeanPostProcessor"> </bean> <import resource="classpath*:/bean/*-bean.xml" /> </beans>
package com.iteye.http.annotation; import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.Target; /** * 〈一句话功能简述〉<br> * 〈功能详细描述〉 * * @see [相关类/方法](可选) * @since [产品/模块版本] (可选) */ @Target(ElementType.METHOD) @Retention(RUNTIME) public @interface HttpMethod { String requestUrl(); /** * 操作编码 */ String operation(); /** * 编码 */ String enCode() default "UTF-8"; /** * 连接超时时间 */ int reqConnectTimeout() default 1000; /** * 请求返回超时时间 */ int repTimeout() default 5000; }
package com.iteye.http.annotation; import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.Retention; import java.lang.annotation.Target; /** * * 〈一句话功能简述〉<br> * 〈功能详细描述〉 * * @see [相关类/方法](可选) * @since [产品/模块版本] (可选) */ @Target(TYPE) @Retention(RUNTIME) public @interface HttpService { /** * 服务代码 * * @return */ String serviceCode(); /** * 请求方系统代码 * * @return */ String appCode(); }
package com.iteye.http.annotation; import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.Target; /** * 在需要注入HttpService的类中的字段或者set方法上添加该注解,后置处理器会处理使用该注解的接口为其生成代理类<br> * 〈功能详细描述〉 * * @see [相关类/方法](可选) * @since [产品/模块版本] (可选) */ @Target({ ElementType.FIELD, ElementType.METHOD }) @Retention(RUNTIME) public @interface HttpWired { }
package com.iteye.http.dto; /** * 〈一句话功能简述〉<br> * 〈功能详细描述〉 * * @see [相关类/方法](可选) * @since [产品/模块版本] (可选) */ public class RequestDto { /** * 系统编码 */ private String appCode; /** * 服务编码 */ private String serviceCode; /** * 操作编码 */ private String operation; /** * 编码 */ private String enCode; /** * 连接超时时间 */ private int reqConnectTimeout; /** * 请求返回超时时间 */ private int repTimeout; /** * 报文体内容 */ private String requestBody; public String getRequestBody() { return requestBody; } public void setRequestBody(String requestBody) { this.requestBody = requestBody; } public String getAppCode() { return appCode; } public void setAppCode(String appCode) { this.appCode = appCode; } public String getServiceCode() { return serviceCode; } public void setServiceCode(String serviceCode) { this.serviceCode = serviceCode; } public String getOperation() { return operation; } public void setOperation(String operation) { this.operation = operation; } public String getEnCode() { return enCode; } public void setEnCode(String enCode) { this.enCode = enCode; } public int getReqConnectTimeout() { return reqConnectTimeout; } public void setReqConnectTimeout(int reqConnectTimeout) { this.reqConnectTimeout = reqConnectTimeout; } public int getRepTimeout() { return repTimeout; } public void setRepTimeout(int repTimeout) { this.repTimeout = repTimeout; } }
package com.iteye.http; import java.beans.BeanInfo; import java.beans.IntrospectionException; import java.beans.PropertyDescriptor; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; import com.iteye.http.annotation.HttpService; import com.iteye.http.annotation.HttpWired; /** * 〈通过BeanPostProcessor后置处理器为代理接口生成代理类〉<br> * 〈功能详细描述〉 * * @see [相关类/方法](可选) * @since [产品/模块版本] (可选) */ public class HttpClientBeanPostProcessor implements BeanPostProcessor { /** * 服务接口Class与代理对象的关系列表 */ private Map<String, Object> httpServiceProxys = new HashMap<String, Object>(); /** * * 此方法在每个Bean实例化、依赖注入完成之后执行,在调用afterPropertiesSet(实现InitializingBean接口)、init-method方法前执行 <br> * 〈在这里为HttpService代理接口生成代理类,这样调用代理接口的方法其实调用的是代理类的方法,在代理类方法中完成HttpClient发送xml报文的代码封装〉 * * @param bean * @param beanName * @return * @throws BeansException * @see [相关类/方法](可选) * @since [产品/模块版本](可选) */ @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { // 为HttpService代理接口生成代理类 wireHttpServiceBean(bean, beanName); return bean; } /** * * 为HttpService代理接口生成代理类 <br> * 〈功能详细描述〉 * * @param bean * @param beanName * @see [相关类/方法](可选) * @since [产品/模块版本](可选) */ private void wireHttpServiceBean(Object bean, String beanName) { // 扫描当前处理的Bean中的所有set方法使用了@HttpWired注解属性 Class<?> clazz = bean.getClass(); BeanInfo beanInfo = null; try { beanInfo = java.beans.Introspector.getBeanInfo(clazz); } catch (IntrospectionException e) { throw new RuntimeException("Wiring bean=[" + beanName + "] meet error.", e); } // 获取当前Bean中的所有属性描述列表 PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors(); for (PropertyDescriptor propertyDescriptor : propertyDescriptors) { // 如果没有提供set方法 Method writeMethod = propertyDescriptor.getWriteMethod(); if (writeMethod == null) { continue; } // 如果set方法上没有使用@HttpWired注解 if (!writeMethod.isAnnotationPresent(HttpWired.class)) { continue; } // 获取注解接口的类型 Class<?> httpServiceClass = propertyDescriptor.getPropertyType(); // 获取代理接口对象 Object httpServiceProxy = getHttpServiceProxy(httpServiceClass); try { // 调用set方法为代理接口注入代理对象 writeMethod.invoke(bean, httpServiceProxy); } catch (Exception e) { throw new RuntimeException(e.getMessage(), e); } } } /** * * 获取代理接口对象 <br> * 〈功能详细描述〉 * * @param httpServiceClass * @return * @see [相关类/方法](可选) * @since [产品/模块版本](可选) */ private Object getHttpServiceProxy(Class<?> httpServiceClass) { // 该接口是否使用了@HttpService注解 if (!httpServiceClass.isAnnotationPresent(HttpService.class)) { throw new RuntimeException(httpServiceClass + "该接口上没有使用@HttpService注解"); } String key = httpServiceClass.hashCode() + httpServiceClass.getName(); Object proxyObject = httpServiceProxys.get(key); // 判断该代理对象是否已经存在,因为不同的Bean中都会注入该@HttpService注解对象,防止重复创建代理对象 if (proxyObject != null) { return proxyObject; } HttpServiceProxy httpServiceProxy = new HttpServiceProxy(); // 设置代理的接口 httpServiceProxy.setHttpServiceClass(httpServiceClass); // 生成代理对象 proxyObject = httpServiceProxy.createHttpServiceProxy(); httpServiceProxys.put(key, proxyObject); return proxyObject; } /** * * 此方法在每个Bean实例化、依赖注入、在调用afterPropertiesSet(实现InitializingBean接口)、init-method方法之后执行: <br> * 〈功能详细描述〉 * * @param bean * @param beanName * @return * @throws BeansException * @see [相关类/方法](可选) * @since [产品/模块版本](可选) */ @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean; } }
package com.iteye.http; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import org.springframework.util.ClassUtils; /** * 〈动态代理实现方式〉<br> * 〈功能详细描述〉 * * @see [相关类/方法](可选) * @since [产品/模块版本] (可选) */ public class HttpServiceDramaticProxy implements InvocationHandler { /** * 代理的接口类型 */ private Class<?> httpServiceClass; public void setHttpServiceClass(Class<?> httpServiceClass) { this.httpServiceClass = httpServiceClass; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println(method); System.out.println(args[0]); return "1111"; } public Object createHttpServiceProxy() { // 实现的接口 Class<?>[] interfaces = { httpServiceClass }; // 通过动态代理为代理接口生成代理对象 Object proxy = Proxy.newProxyInstance(ClassUtils.getDefaultClassLoader(), interfaces, this); return proxy; } }
package com.iteye.http; import java.lang.reflect.Method; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; import org.springframework.aop.framework.ProxyFactory; import org.springframework.util.ClassUtils; import com.iteye.http.annotation.HttpMethod; import com.iteye.http.annotation.HttpService; /** * 〈一句话功能简述〉<br> * 〈功能详细描述〉 * * @see [相关类/方法](可选) * @since [产品/模块版本] (可选) */ public class HttpServiceProxy implements MethodInterceptor { /** * 代理的接口类型 */ private Class<?> httpServiceClass; public void setHttpServiceClass(Class<?> httpServiceClass) { this.httpServiceClass = httpServiceClass; } @Override public Object invoke(MethodInvocation invocation) throws Throwable { // 获取接口调用的方法 Method method = invocation.getMethod(); // 方法上是否有HttpMethod注解 if (!method.isAnnotationPresent(HttpMethod.class)) { throw new RuntimeException(method + "方法上没有使用HttpMethod注解"); } Object[] args = invocation.getArguments(); if (args == null || args.length != 1 || !(args[0] instanceof String)) { throw new RuntimeException("方法体的参数有且只能有一个,且类型是String"); } String requestBody = (String) args[0]; HttpMethod httpMethod = method.getAnnotation(HttpMethod.class); HttpService httpService = httpServiceClass.getAnnotation(HttpService.class); // 获取请求的报文 String requestXml = getRequestXml(httpService, httpMethod, requestBody); // 以post方式发送请求报文并返回响应信息 String responseXml = HttpClientUtils.postHttpRequest(requestXml, httpMethod.requestUrl(), httpMethod.reqConnectTimeout(), httpMethod.repTimeout(), httpMethod.enCode()); return responseXml; } /** * * 获取请求的报文 <br> * 〈功能详细描述〉 * * @param httpService * @param httpMethod * @return * @see [相关类/方法](可选) * @since [产品/模块版本](可选) */ private String getRequestXml(HttpService httpService, HttpMethod httpMethod, String requestBody) { String requestXml="<MbfService>"+ "<input1>"+ "<MbfHeader>"+ "<ServiceCode>"+httpService.serviceCode()+"</ServiceCode>"+ "<Operation>"+httpMethod.operation()+"</Operation>"+ "</MbfHeader>"+ "<MbfBody>"+ requestBody+ "</MbfBody>"+ "</input1>"+ "</MbfService>"; return requestXml; } public Object createHttpServiceProxy() { // proxy是一个实现了serviceInterface接口的代理对象,当调用proxy的某个方法的时候,就会调用this的invoke方法 Object proxy = new ProxyFactory(httpServiceClass, this).getProxy(ClassUtils.getDefaultClassLoader()); return proxy; } }
package com.iteye.http; import java.io.IOException; import java.io.InputStream; import java.net.ConnectException; import java.net.SocketTimeoutException; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.HttpVersion; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpPost; import org.apache.http.conn.ConnectTimeoutException; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.params.CoreConnectionPNames; import org.apache.http.params.CoreProtocolPNames; import org.apache.http.params.HttpParams; /** * 〈一句话功能简述〉<br> * 〈功能详细描述〉 * * @see [相关类/方法](可选) * @since [产品/模块版本] (可选) */ public class HttpClientUtils { /** * * 以Post方式发送Http请求 <br> * 〈功能详细描述〉 * * @throws IOException * @throws ClientProtocolException * @see [相关类/方法](可选) * @since [产品/模块版本](可选) */ public static String postHttpRequest(String requestXml, String requestUrl, int reqConnectTimeout, int repTimeout, String enCode) { HttpPost httpPost = null; try { // 定义HttpPost请求 httpPost = new HttpPost(requestUrl); // 定义请求实体 HttpEntity requestEntity = new StringEntity(requestXml, enCode); httpPost.setEntity(requestEntity); // 定义HttpClient HttpClient httpClient = new DefaultHttpClient(); HttpParams httpParams = httpClient.getParams(); // 设置Http协议的版本 httpParams.setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1); // 设置请求连接超时时间 httpParams.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, reqConnectTimeout); // 设置请求响应超时时间 httpParams.setParameter(CoreConnectionPNames.SO_TIMEOUT, repTimeout); // 以post方式发送Http请求 HttpResponse httpResponse = httpClient.execute(httpPost); // 获取响应实体 HttpEntity responsetEntity = httpResponse.getEntity(); InputStream inputStream = responsetEntity.getContent(); StringBuilder reponseXml = new StringBuilder(); byte[] b = new byte[2048]; int length = 0; while ((length = inputStream.read(b)) != -1) { reponseXml.append(new String(b, 0, length)); } return reponseXml.toString(); } catch (Exception e) { // 释放请求的连接 if (httpPost != null) { httpPost.abort(); } if (SocketTimeoutException.class.isInstance(e)) { throw new RuntimeException("Http请求响应超时", e); } else if (ConnectTimeoutException.class.isInstance(e)) { throw new RuntimeException("Http请求连接超时", e); } else if (ConnectException.class.isInstance(e)) { throw new RuntimeException("Http请求异常", e); } else { throw new RuntimeException(e); } } } }