@huynh
2016-06-06T17:20:09.000000Z
字数 12702
阅读 1832
package hust.webservice.service;
import hust.webservice.domain.SqlRequest;
import hust.webservice.domain.SqlResponse;
import javax.jws.WebService;
/**
* Sql操作服务接口,参数必须有数据库名。<br>
* <p>
* 1.如果是单表操作,则还需传入表名和参数<br>
* 2.如果是多表复杂操作,则提供sql语句,该sql语句可以是完全的sql,也可以是mybatis带参数形式的sql<br>
* 3.详细参数见SqlRequest说明<br>
* </p>
* 所有操作参数都封装在SqlRequest中,本接口所有方法只有该参数。<br>
* 所有操作的返回值均封装在了SqlResponse中。
* @date 2016年4月8日
* @author huynh
*/
@WebService
public interface SqlService {
/**
* Select
* @param sqlRequest
* @return
*/
SqlResponse select(SqlRequest sqlRequest);
/**
* 查询总数
* @param sqlRequest
* @return
*/
SqlResponse selectCount(SqlRequest sqlRequest);
/**
* Insert<br>
* 注意插入日期,需要将日期序列化为"yyyy-MM-dd HH:mm:ss"字符串,下面是使用fastjson注解实体类属性<br>
* <pre class="code">
* {@code
\@JSONField (format="yyyy-MM-dd HH:mm:ss",name="register_time")
private Date registerTime;<br>
}
</pre>
实体类必须先使用JSON.toJSONString(javaBean)序列化<br>
* @param sqlRequest
* @return
*/
SqlResponse insert(SqlRequest sqlRequest);
/**
* Update <br>
* 只能根据主键或者唯一字段更新
* @param sqlRequest
* @return
*/
SqlResponse update(SqlRequest sqlRequest);
/**
* Delete <br>
* paramter和condition只能用其一
* @param sqlRequest
* @return
*/
SqlResponse delete(SqlRequest sqlRequest);
/**
* 多组更新操作需要在一个事务中完成
* @param sqls 多组操作的sql语句,使用英文分号;隔开。注意sql的执行顺序
* @return 只有返回1表示执行成功,其他情况均为失败
*/
int updateTransaction(String databaseName,String sqls);
}
package hust.webservice.service;
import hust.webservice.domain.SqlCondition;
import hust.webservice.domain.SqlConditionRule;
import hust.webservice.domain.SqlRequest;
import hust.webservice.domain.SqlResponse;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import org.apache.commons.lang.StringUtils;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.apache.cxf.transport.http.HTTPConduit;
import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 本类为SqlService的代理实现类,供客户端使用,所有业务类都应该使用本类进行WebService的服务调用<br>
* 在spring中将本类配置为非单例,配置如下:<br>
*
* <pre class="code">
* {@code
* <bean id="sqlService" class="hust.dbservice.webservice.SqlServiceProxy" scope="prototype">
* <constructor-arg index="0">
* <value type="java.lang.String"> WebService服务地址 </value>
* </constructor-arg>
* </bean>
* }
* </pre>
*
* @date 2016年4月12日
* @author huynh
*/
public class SqlServiceProxy implements SqlService {
private static final Logger logger = LoggerFactory.getLogger(SqlServiceProxy.class);
private final SqlService sqlService;
private final JaxWsProxyFactoryBean jaxWsProxyFactoryBean;
public SqlServiceProxy(String wsdlAddress) {
if (StringUtils.isBlank(wsdlAddress)) {
throw new RuntimeException("服务地址不能为空!");
}
jaxWsProxyFactoryBean = new JaxWsProxyFactoryBean();
try {
sqlService = generateProxyClient(SqlService.class, wsdlAddress);
} catch (Exception e) {
logger.error("Fail to create webservice of SqlService! wsdlAddress={}",new Object[]{wsdlAddress,e});
throw new RuntimeException("Fail to create SqlServiceProxy! Could not connect to CXF WebService,WSDL address is " + wsdlAddress);
}
if (sqlService != null) {
logger.info("The webservice of sqlService is created successfully!");
}
}
/**
* 生成CXF服务接口代理类
*
* @param classType
* 服务接口
* @return 服务接口代理类
* @throws Exception 可能抛出网络连接异常
*
*/
private <T> T generateProxyClient(Class<T> classType, String wsdlAddress) throws Exception {
jaxWsProxyFactoryBean.setServiceClass(classType);
jaxWsProxyFactoryBean.setAddress(wsdlAddress);
T service = (T) jaxWsProxyFactoryBean.create();
Client proxy = ClientProxy.getClient(service);
HTTPConduit conduit = (HTTPConduit) proxy.getConduit();
HTTPClientPolicy policy = new HTTPClientPolicy();
policy.setConnectionTimeout(40000); // 连接超时时间,默认30000
policy.setReceiveTimeout(40000);// 请求超时时间,默认60000
policy.setAllowChunking(false);// 取消块编码
conduit.setClient(policy);
return service;
}
@Override
public SqlResponse select(SqlRequest sqlRequest) {
return sqlService.select(sqlRequest);
}
@Override
public SqlResponse selectCount(SqlRequest sqlRequest) {
return sqlService.selectCount(sqlRequest);
}
@Override
public SqlResponse insert(SqlRequest sqlRequest) {
return sqlService.insert(sqlRequest);
}
@Override
public SqlResponse update(SqlRequest sqlRequest) {
return sqlService.update(sqlRequest);
}
@Override
public SqlResponse delete(SqlRequest sqlRequest) {
return sqlService.delete(sqlRequest);
}
@Override
public int updateTransaction(String databaseName, String sqls) {
return sqlService.updateTransaction(databaseName, sqls);
}
}
注:SqlServuceProxy使用方式: 本类为SqlService的代理实现类,供客户端使用,所有业务类都应该使用本类进行WebService的服务调用
在spring中将本类配置为非单例,配置如下:
<bean id="sqlService" class="hust.webservice.service.SqlServiceProxy" scope="prototype">
<constructor-arg>
<value type="java.lang.String">wsdl地址</value>
</constructor-arg>
</bean>
数据库服务请求参数的实体类是hust.webservice.domain.ServiceRequest,这个类是固定的。建议所有服务请求参数的包名均为hust.webservice.domain
参数名称 | 参数类型 | 是否为空 | 参数说明 |
databaseName | string | 不能为空 | 数据库名,选择数据源使用 |
tableName | string | 仅当sqlId不为空时,该参数可以为空 | 数据库表名 |
sql | string | 单表操作可以为空,其他多表必须指定 | 自定义数据库操作的sql语句,可以是MyBatis的带参数的sql |
paramter | String | 可以为空 | 数据库操作条件部分字段对应参数,使用equal和and连接,JSONObject类型。 |
isPage | bool | 默认为false | 是否进行分页查询 |
pageNo | int | 可以为空 | 分页查询页码 |
pageSize | int | 可以为空 | 分页查询页大小 |
orderBy | String | 可以为空 | 排序字段,单表使用,如 根据id排序: orderBy = "id asc" |
sqlCondition | SqlCondition | 可以为空,如果不为空,优先使用此参数,而忽略tableField参数 | 单表操作条件 |
请求Sql服务的示例(详细可参见服务中单例测试)
//创建数据库服务请求参数实例
SqlRequest sqlRequest = new SqlRequest();
//指定数据库
sqlRequest.setDatabaseName("smartshop");
//设置数据库表名
sqlRequest.setTableName("user");
//设置分页查询
sqlRequest.setPage(true);
sqlRequest.setPageNo(1);
sqlRequest.setPageSize(2);
sqlRequest.setOrderBy("buildingnumber desc");//分页查询支持排序
//设置查询参数
User user = new User();
user.setUsername("huynh")
//将SqlRequest序列化到ServiceRequest中
sqlRequest.setParamter(JSON.toJSONString(user));
//调用Web服务
SqlResponse sqlResponse = sqlService.select(sqlRequest);
//执行的sql = select * from user where username='huynh'
//创建数据库服务请求参数实例
SqlRequest sqlRequest = new SqlRequest();
//指定数据库
sqlRequest.setDatabaseName("smartshop");
//设置数据库表名
sqlRequest.setTableName("user");
//指定要查询的字段
sqlRequest.setQueryField("distinct username,password");
//设置查询参数
User user = new User();
user.setUsername("huynh")
//将SqlRequest序列化到ServiceRequest中
sqlRequest.setParamter(JSON.toJSONString(user));
//调用Web服务
SqlResponse sqlResponse = sqlService.select(sqlRequest);
//执行的sql = select distinct username,password from user where username='huynh'
SqlRequest sqlRequest = new SqlRequest();
sqlRequest.setDatabaseName("smartshop");
sqlRequest.setTableName("cart");
//设置复杂条件
List<SqlConditionRule> conditions = new ArrayList<SqlConditionRule>();
SqlConditionRule condition = new SqlConditionRule();
condition.setField("total_price");
condition.setOperation("<");
condition.setValue(5);
conditions.add(condition);
condition = new SqlConditionRule();
condition.setField("id");
condition.setOperation("<");
condition.setValue(37);
conditions.add(condition);
SqlCondition sqlCondition = new SqlCondition("and", conditions, null);
sqlRequest.setSqlCondition(sqlCondition);
SqlResponse sqlResponse = sqlService.select(sqlRequest);
//执行的sql = select * from cart where total_price<5 and id < 37
SqlRequest sqlRequest = new SqlRequest();
sqlRequest.setDatabaseName("smartshop");
sqlRequest.setTableName("user");
//创建sql语句,这里的语句包含了#{}参数形式
sqlRequest.setSql("select a.username,b.name from user as a,shop as b where a.id = b.user_id and a.id = #{id}");
//设置参数值
sqlRequest.setParamter("{\"id\":1}");
SqlResponse sqlResponse = sqlService.select(sqlRequest);
数据库服务响应参数的实体类是hust.webservice.domain.SqlResponse,这个类是固定的。
参数名称 | 参数类型 | 参数说明 |
success | boolean | 服务是否调用成功 |
errorMsg | String | 服务调用失败错误信息 |
queryResult | JSON | 数据库查询结果 |
updateResult | int | 对数据库做更新操作后被影响的行数,如果是插入单条记录,且数据库字段是自增的,则返回插入成功后的id |
insertId | int | 仅仅针对MySql表主键为id且自增,当插入成功会返回被插入的id |
totalCount | long | 查询满足条件的总数,对应selectCout方法返回值 |
totalPage | int | 分页查询后总页数 |
1.先增加数据源配置
位置在dbservice-dal/resource/datasource
<?xml version="1.0" encoding="GBK"?>
<!-- 商城数据源 -->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-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/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<!-- 配置数据源,使用alibaba的DruidDataSource -->
<bean id="smartshopDataSource" class="com.alibaba.druid.pool.DruidDataSource"
init-method="init" destroy-method="close">
<!-- 基本连接配置 -->
<property name="driverClassName" value="${jdbc.driver}" />
<property name="url"
value="jdbc:mysql://222.20.95.248:3306/smartshop?characterEncoding=utf8" />
<property name="username" value="root" />
<property name="password" value="Idc+123456" />
<!-- 配置初始化大小、最小、最大 -->
<property name="initialSize" value="${initialSize}" />
<property name="minIdle" value="${minIdle}" />
<property name="maxActive" value="${maxActive}" />
<!-- 配置获取连接等待超时的时间 -->
<property name="maxWait" value="${maxWait}" />
<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis" value="${timeBetweenEvictionRunsMillis}" />
<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
<property name="minEvictableIdleTimeMillis" value="${minEvictableIdleTimeMillis}" />
</bean>
<!-- 线程安全类,可以是单例。用于对数据库的基本操作 -->
<bean id="smartshopSqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!-- 构造函数中需要传入会话工厂 -->
<constructor-arg index="0" ref="smartshopSqlSessionFactory" />
</bean>
<!-- MyBatis的会话工厂 -->
<bean id="smartshopSqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="smartshopDataSource" />
<!-- 指定 MyBatis XML 映射器文件的位置 <property name="mapperLocations" value="classpath:mapper_smartshop/*.xml"
/> -->
<!-- 配置别名包 使用的时候可以省略包名 <property name="typeAliasesPackage" value="cscec3.dbservice.smartshop.model"
/> -->
<!-- 配置插件 -->
<property name="plugins">
<array>
<!-- 配置分页插件 -->
<bean class="com.github.pagehelper.PageHelper">
<!-- 这里的几个配置主要演示如何使用,如果不理解,一定要去掉下面的配置 -->
<property name="properties">
<value>
dialect=mysql
reasonable=true
supportMethodsArguments=true
params=count=countSql
autoRuntimeDialect=true
</value>
</property>
</bean>
</array>
</property>
</bean>
<!-- 配置 spring 事务管理 -->
<bean id="smartshopTransactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="smartshopDataSource" />
</bean>
<!-- 由于声明式事务不支持多数据源切换,因此使用的是编程式事务,所以不需要此注解 -->
<!--<tx:annotation-driven transaction-manager="transactionManager"/> -->
</beans>
2.将1增加的配置写入总配置
位置在dbservice-dal/resource/hust-dbservice-dal.xml
<?xml version="1.0" encoding="GBK"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-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/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"
>
<!-- 测试用的 <import resource="classpath:datasource/spring-mybatis_test.xml"
/> -->
<!-- 指定jdbc属性配制文件位置 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 正式用的 -->
<!-- 配置物业数据源 -->
<import resource="classpath:datasource/datasource_smartproperty.xml" />
<!-- 配置权限管理数据源 -->
<import resource="classpath:datasource/datasource_authorization.xml" />
<!-- 配置商城数据源 -->
<import resource="classpath:datasource/datasource_smartshop.xml" />
</beans>
3.将数据源和事务管理器配置当作SqlServiceImpl的属性注入
位置在dbservice-biz/resource/bean/hust-dbservice-bean.xml
<?xml version="1.0" encoding="GBK"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans default-autowire="byName">
<!-- 配置数据库服务实例 -->
<bean id="sqlService" class="hust.dbservice.webservice.impl.SqlServiceImpl" >
<!-- 这里配置不同数据源的SqlSessionTemplate实例 -->
<constructor-arg index="0">
<map>
<entry key="smartshop" value-ref="smartshopSqlSession" />
<entry key="smartproperty" value-ref="smartpropertySqlSession" />
<entry key="authorization" value-ref="authorizationSqlSession" />
</map>
</constructor-arg>
<!-- 这里配置不同数据源的TransactionManager实例 -->
<constructor-arg index="1">
<map>
<entry key="smartshop" value-ref="smartshopTransactionManager" />
<entry key="smartproperty" value-ref="smartpropertyTransactionManager" />
<entry key="authorization" value-ref="authorizationTransactionManager" />
</map>
</constructor-arg>
</bean>
</beans>