고객은 일반적으로 제출된 양식 데이터를 CSV 형식으로 내보내려고 합니다. 이 문서에서는 CSV 형식으로 양식 데이터를 내보내는 데 필요한 단계를 강조 표시합니다. 이 문서에서는 양식 제출이 RDBMS 테이블에 저장된다고 가정합니다. 다음 스크린샷에서는 양식 제출을 저장하는 데 필요한 최소 테이블 구조를 자세히 설명합니다.
이 샘플은 스키마 또는 양식 데이터 모델을 기반으로 하지 않는 응용 Forms에서만 작동합니다
이 스키마 안에는 다음과 같은 열이 정의된 테이블 양식 제출이 있습니다
테이블 이름과 두 열 이름은 아래 스크린샷에 표시된 대로 OSGi 구성 속성으로 표시됩니다.
코드는 이러한 값을 읽고 실행할 적절한 SQL 쿼리를 구성합니다. 예를 들어 위의 값을 기준으로 다음 쿼리가 실행됩니다
SELECT formdata FROM aemformstutorial.formsubmissions where formname=timeoffrequestform
위의 쿼리에서 양식(timeoffrequestform)의 이름이 요청 매개 변수로 서블릿에 전달됩니다.
다음 OSGI 서비스가 생성되어 제출된 데이터를 CSV 형식으로 내보냅니다.
37호선: Apache Sling 연결의 풀링된 데이터 소스에 액세스합니다.
89호선: 서비스의 시작 지점입니다.메서드 getCSVFile(..)
formName을 입력 매개 변수로 사용하고 제공된 양식 이름과 관련하여 제출된 데이터를 가져옵니다.
이 코드에서는 사용자가 Felix 웹 콘솔에서 "emformstutorial"이라는 연결 풀링된 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());
}
}
}