Сначала в pom.xml пропишем нужные зависимости, а именно:
...
<properties>
<cxf.version>2.4.6</cxf.version>
<spring.version>3.1.0.RELEASE</spring-version>
<dbcp.version>1.4</dbcp.version>
</properties>
...
<dependencies>
<!-- Apache CXF dependencies -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>${cxf.version}</version>
</dependency>
<!-- Spring Dependencies -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- Datasource -->
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>${dbcp.version}</version>
</dependency>
</dependencies>
...
Прежде всего нам нужен сам веб-сервис. У него должен быть только один метод, который собственно и делает запрос. Возвращать он будет массив массивов строк (об этом - ниже). Таким образом получаем что-то вроде:
@WebService
public interface DBProxy {
@WebMethod(operationName = "query")
public String[][] query(@WebParam(name="queryText") String queryText);
}
Теперь займемся реализацией этого интерфейса:
@WebService(endpointInterface = "com.example.dbproxy.DBProxy")
public class DBProxyImpl implements DBProxy {
private DBHelper helper;
@Override
public String[][] query(String queryText) {
return helper.query(queryText);
}
public void setHelper(DBHelper newHelper) {
this.helper = newHelper;
}
}
Тут появился интерфейс DBHelper. Как не сложно заметить за ним будет стоять класс, реализующий механику работы с БД. Почему нельзя было просто написать всю механику в методе query и не усложнять приложение? Потому что веб-сервис и механика БД - это разные задачи, а значит и реализованы должны быть в разных местах. Это придаст сделает приложение модульным и позволит менять механику хоть во время выполнения приложения (для этого тут и есть метод setHelper). Собственно вот как выглядит интерфейс работы с БД:
public interface DBHelper {
String[][] query(String queryText);
}
А теперь самая длинная часть приложения - реализация самой механики. По соглашению с заказчиком первая строка полученного массива строк будет содержать названия колонок, полученных в результате выполнения запроса. Вторая строка - тип этих колонок в числовом виде. Последующие строки - собственно сам результат запроса. Таким образом получаем что-то вроде следующего:
public class JdbcDBHelper implements DBHelper {
private JdbcTemplate db;
private List<List<String>> result;
private SqlRowSet rs;
@Override
public String[][] query(String queryText) {
clearResult();
getResultRowSet(queryText);
addResultHeader();
addQueryResult();
return resultAsArrays();
}
private void clearResult() {
result = new ArrayList<List<String>>();
}
private SqlRowSet getResultRowSet(String queryText) {
rs = getRowSet(queryText);
return rs;
}
private SqlRowSet getRowSet(String queryText) {
return db.queryForRowSet(queryText);
}
private void addResultHeader() {
addColumnNames();
addColumnTypes();
}
private void addColumnNames() {
List<String> columnNames = new ArrayList<String>();
columnNames.addAll(Arrays.asList(rs.getMetaData().getColumnNames()));
result.add(columnNames);
}
private void addColumnTypes() {
List<String> columnTypes = new ArrayList<String>();
for (int i = 1; i < rs.getMetaData().getColumnCount(); i++) {
int columnType = rs.getMetaData().getColumnType(i);
columnTypes.add(Integer.toString(columnType));
}
result.add(columnTypes);
}
private void addQueryResult() {
while (rs.next()) {
List<String> line = new ArrayList<String>();
for (int i = 1; i < rs.getMetaData().getColumnCount(); i++) {
if (rs.getObject(i) != null) {
line.add(rs.getObject(i).toString());
} else {
line.add("null");
}
}
result.add(line);
}
}
private String[][] resultAsArrays() {
String[][] converted = new String[result.size()][];
for (int i = 0; i < result.size(); i++) {
converted[i] = result.get(i).toArray(new String[result.get(i).size()]);
}
return converted;
}
public void setDataSource(DataSource dataSource) {
this.db = new JdbcTemplate(dataSource);
}
}
Теперь добавим немного магии Spring, которая сделает из нашего набора классов работающее приложение:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<!-- Spring manage ServiceBean -->
<bean id="dbproxyServ" class="com.example.dbproxy.DBProxyImpl"><
<property name="helper" ref="dbHelper"/>
</bean>
<!-- JAX-WS Service Endpoint -->
<jaxws:endpoint id="dbproxyService" implementor="#dbproxyServ" address="/dbproxyService" />
<bean id="dbHelper" class="com.example.dbproxy.db.JdbcDBHelper">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- the DataSource (parameterized for configuration via a PropertyPlaceHolderConfigurer) -->
<bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="my_url"/>
<property name="username" value="my_user"/>
<property name="password" value="my_pass"/>
</bean>
</beans>
Последний штрих - добавим дескриптор развёртывания:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>Database proxy web service</display-name>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:application-context.xml</param-value>
</context-param>
<servlet>
<servlet-name>CXFServlet</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
Всё. Теперь можно деплоить полученное приложение и радоваться технологиям, которые позволяют так быстро писать подобные приложения :)
Комментариев нет:
Отправить комментарий
Примечание. Отправлять комментарии могут только участники этого блога.