고객은 일반적으로 제출된 양식 데이터를 CSV 형식으로 내보내기를 원합니다. 이 문서에서는 양식 데이터를 CSV 형식으로 내보내는 데 필요한 단계를 강조 표시합니다. 이 문서에서는 양식 제출이 RDBMS 테이블에 저장되어 있다고 가정합니다. 다음 스크린샷에서는 양식 제출을 저장하는 데 필요한 최소 테이블 구조를 자세히 설명합니다.
이 샘플은 스키마 또는 양식 데이터 모델을 기반으로 하지 않는 적응형 Forms에서만 작동합니다
스키마 이름을 볼 수 있듯이 aemformstutorial입니다. 이 스키마 내부에는 다음 열이 정의된 테이블 formsubmissions가 있습니다
테이블 이름 및 2열 이름은 아래 스크린샷과 같이 OSGi 구성 속성으로 표시됩니다.
이 코드는 이러한 값을 읽고 실행할 적절한 SQL 쿼리를 구성합니다. 예를 들어 다음 쿼리는 위의 값을 기반으로 실행됩니다
SELECT formdata FROM aemformstutorial.formsubmissions where formname=timeoffrequestform
위의 쿼리에서 양식(timeoffrequestform)의 이름이 요청 매개 변수로 서블릿에 전달됩니다.
제출된 데이터를 CSV 형식으로 내보내기 위해 다음과 같은 OSGI 서비스가 생성되었습니다.
37행: Apache Sling 연결의 풀링된 데이터 소스에 액세스합니다.
89행: 서비스의 진입점입니다.메서드 getCSVFile(..)
는 formName을 입력 매개 변수로 사용하고 지정된 양식 이름과 관련된 제출된 데이터를 가져옵니다.
이 코드는 사용자가 Felix 웹 콘솔에서 "aemformstutorial"이라는 연결 풀링된 DataSource를 정의했다고 가정합니다. 또한 이 코드는 사용자가 aemformstutorial이라는 데이터베이스에 스키마를 가지고 있다고 가정합니다
package com.aemforms.storeandexport.core;
import java.io.IOException;
import java.io.StringReader;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import javax.sql.DataSource;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
@Component(service = StoreAndExport.class)
public class StoreAndExportImpl implements StoreAndExport {
private final Logger log = LoggerFactory.getLogger(getClass());
@Reference
StoreAndExportConfigurationService config;
@Reference(target = "(&(objectclass=javax.sql.DataSource)(datasource.name=aemformstutorial))")
private DataSource dataSource;
private List<String> getRowValues(String row) {
List<String> rowValues = new ArrayList<String>();
//API to obtain DOM Document instance
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = null;
try {
builder = factory.newDocumentBuilder();
Document doc = builder.parse(new InputSource(new StringReader(row)));
XPathFactory xpf = XPathFactory.newInstance();
XPath xpath = xpf.newXPath();
Node dataNode = (Node) xpath.evaluate("//afData/afUnboundData/data", doc, XPathConstants.NODE);
NodeList dataElements = dataNode.getChildNodes();
for (int i = 0; i < dataElements.getLength(); i++) {
log.debug("The name of the node is" + dataElements.item(i).getNodeName() + " the node value is " + dataElements.item(i).getTextContent());
rowValues.add(i, dataElements.item(i).getTextContent());
}
return rowValues;
} catch (Exception e) {
log.debug(e.getMessage());
}
return null;
}
private List<String> getHeaderValues(String row) {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
List<String> rowValues = new ArrayList<String>();
DocumentBuilder builder = null;
try {
//Create DocumentBuilder with default configuration
builder = factory.newDocumentBuilder();
Document doc = builder.parse(new InputSource(new StringReader(row)));
XPathFactory xpf = XPathFactory.newInstance();
XPath xpath = xpf.newXPath();
Node dataNode = (Node) xpath.evaluate("//afData/afUnboundData/data", doc, XPathConstants.NODE);
NodeList dataElements = dataNode.getChildNodes();
for (int i = 0; i < dataElements.getLength(); i++) {
rowValues.add(i, dataElements.item(i).getNodeName());
}
return rowValues;
} catch (Exception e) {
log.debug(e.getMessage());
}
return null;
}
@Override
public StringBuilder getCSVFile(String formName) {
log.debug("In get CSV File");
String selectStatement = "SELECT " + config.getFORM_DATA_COLUMN() + " FROM aemformstutorial." + config.getTABLE_NAME() + " where " + config.getFORM_NAME_COLUMN() + "='" + formName + "'" + "";
log.debug("The select statment is " + selectStatement);
Connection con = getConnection();
Statement st = null;
ResultSet rs = null;
CSVUtils csvUtils = new CSVUtils();
try {
st = con.createStatement();
rs = st.executeQuery(selectStatement);
log.debug("Got Result Set in getCSVFile");
StringBuilder sb = new StringBuilder();
while (rs.next()) {
if (rs.isFirst()) {
sb = csvUtils.writeLine(getHeaderValues(rs.getString(1)), sb);
}
sb = csvUtils.writeLine(getRowValues(rs.getString(1)), sb);
log.debug("$$$$The current strng buffer is " + sb.toString());
}
return sb;
} catch (Exception e) {
log.debug(e.getMessage());
} finally {
try {
rs.close();
} catch (Exception e) { /* ignored */ }
try {
st.close();
} catch (Exception e) { /* ignored */ }
try {
con.close();
} catch (Exception e) { /* ignored */ }
}
return null;
}
private Connection getConnection() {
log.debug("Getting Connection ");
Connection con = null;
try {
con = dataSource.getConnection();
log.debug("got connection");
return con;
} catch (Exception e) {
log.debug("not able to get connection ");
log.debug(e.getMessage());
}
return null;
}
@Override
public void inserFormData(String formData) {
String formDataColumn = config.getFORM_DATA_COLUMN();
String formNameColumn = config.getFORM_NAME_COLUMN();
String tableName = config.getTABLE_NAME();
String insertStatement = "Insert into aemformstutorial." + tableName + "(" + formDataColumn + "," + formNameColumn + ") VALUES(?,?)";
log.debug("The insert statment is" + insertStatement);
Connection con = getConnection();
PreparedStatement pstmt = null;
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = null;
builder = factory.newDocumentBuilder();
Document xmlDoc = builder.parse(new InputSource(new StringReader(formData)));
XPath xPath = javax.xml.xpath.XPathFactory.newInstance().newXPath();
org.w3c.dom.Node submittedFormNameNode = (org.w3c.dom.Node) xPath.compile("/afData/afSubmissionInfo/afPath").evaluate(xmlDoc, javax.xml.xpath.XPathConstants.NODE);
String paths[] = submittedFormNameNode.getTextContent().split("/");
String formName = paths[paths.length - 1];
log.debug("The form name submiited is" + formName);
pstmt = null;
pstmt = con.prepareStatement(insertStatement);
pstmt.setString(1, formData);
pstmt.setString(2, formName);
log.debug("Executing the insert statment " + pstmt.execute());
con.commit();
} catch (SQLException e) {
log.debug(e.getMessage());
} catch (ParserConfigurationException e) {
log.debug(e.getMessage());
} catch (SAXException e) {
log.debug(e.getMessage());
} catch (IOException e) {
log.debug(e.getMessage());
} catch (XPathExpressionException e) {
log.debug(e.getMessage());
} finally {
try {
pstmt.close();
} catch (Exception e) { /* ignored */ }
try {
con.close();
} catch (Exception e) { /* ignored */ }
}
}
}
다음 세 가지 속성을 OSGI 구성 속성으로 노출했습니다. SQL 쿼리는 런타임에 이러한 값을 읽는 방식으로 구성됩니다.
package com.aemforms.storeandexport.core;
import org.osgi.service.metatype.annotations.AttributeDefinition;
import org.osgi.service.metatype.annotations.ObjectClassDefinition;
@ObjectClassDefinition(name="Store and Export Configuration", description = "Details on the Database ")
public @interface StoreAndExportConfiguration {
@AttributeDefinition(name = "Table Name", description = "Name of the table to store the submitted data")
String tableName() default "formsubmissions";
@AttributeDefinition(name = "Form Data Column Name", description = "Column name to hold submitted form data")
String formDataColumn() default "formdata";
@AttributeDefinition(name = "Form Name Column Name", description = "Column name to hold submitted form name")
String formNameColumn() default "formname";
}
다음은 를 호출하는 서블릿 코드입니다. getCSVFile(..)
서비스 메서드. 이 서비스는 StringBuffer 개체를 반환한 다음 호출 응용 프로그램으로 다시 스트리밍합니다.
package com.aemforms.storeandexport.core.servlets;
import java.io.IOException;
import javax.servlet.Servlet;
import javax.servlet.ServletOutputStream;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import com.aemforms.storeandexport.core.StoreAndExport;
@Component(
service = {Servlet.class},
property = {"sling.servlet.methods=get", "sling.servlet.paths=/bin/streamformdata"}
)
public class StreamCSVFile extends SlingAllMethodsServlet {
private static final long serialVersionUID = -3703364266795135086L;
@Reference
StoreAndExport createCSVFile;
protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) {
StringBuilder stringToStream = createCSVFile.getCSVFile(request.getParameter("formName"));
response.setHeader("Content-Type", "text/csv");
response.setHeader("Content-Disposition", "attachment;filename=\"formdata.csv\"");
try {
final ServletOutputStream sout = response.getOutputStream();
sout.print(stringToStream.toString());
} catch (IOException e) {
log.debug(e.getMessage());
}
}
}