Сначала в 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>Всё. Теперь можно деплоить полученное приложение и радоваться технологиям, которые позволяют так быстро писать подобные приложения :)
Комментариев нет:
Отправить комментарий
Примечание. Отправлять комментарии могут только участники этого блога.