Создание записи в даталисте и прикрепления файла к нему
Пишу первый раз в блог. Так что не пинайте сильно.
Пусть несколько сумбурно, но надеюсь что многим начинающим будет полезно.
Начал я с изучения статьи Ангелины http://www.ossportal.org/technologies/alfresco/blogs/572
и к статьи https://forums.alfresco.com/forum/developer-discussions/repository-servi...
<UPDATED>
Будет очень полезно посмотреть вот эту статью
http://confluence.ecm-alfresco.ru/display/workingexamples/Custom+DataList
</UPDATED>
Очень полезная статья. Но не хватает освещения еще двух очень важных вопросов:
1. как программно на яве добавить запись в даталист.
2. как программно на яве привязать файл из репозиторя к даталисту.
Итак, начнем.
Откуда растут ноги?
Стоит задача получать документы из биллинга (счета и счета фактуры) Это файлы с описаниями. Создавать бизнес процессы по отправке и отслеживанию, что бы не дай бог, клиенты не вовремя заплатили...
Для этого был создан собственный тип реестра в Alvex.
Оставалась сущая безделица: создать программно запись в дата лист.
Основное, что нужно помнить, что все в альфреске - это Node из XML (как в линуксе все файл).
Задача получения документов сводится к нескольким маленьким:
1. нужно найти родительский нод (реестр) куда будем делать записи.
2. создать список необходимых аттрибутов у нового нода. (Ну в самом деле, зачем создавать пустой нод).
3. создать дочерний нод (запись) у родительского нода. Самое главное именно того типа, который требуется в используемом реестре, иначе не будут работать формы реестра. И отображение информации будет искажено.
4. Создать файл в репозитории альфреско.
( Почему именно там?
1. Базовый тип alvexdt:object не содержит полей типа cm:content, значит содержимое файла некуда записать.
2. Содержит ассоциацию alvexdt:files. Которая является ссылкой на файл.
Есть рекомендация пользоваться ссылками, вместо использования содержимого, скорость работы сильно от этого зависит.)
5. Привязать созданный файл к новой записи. Т.е. банально заполнить ссылку.
В тексте кода вебскрипта привел комментарии, что бы можно было понять какой код за что отвечает.
Так же сделал указания на что нужно обратить внимание.
Вообщем-то все достаточно просто. Главное внимание.
Описание модели:
<?xml version="1.0" encoding="UTF-8"?>
<model
name="alvexoutdocskr:documents_model"
xmlns="http://www.alfresco.org/model/dictionary/1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.alfresco.org/model/dictionary/1.0 modelSchema.xsd">
<imports>
<import uri="http://www.alfresco.org/model/dictionary/1.0" prefix="d"/>
<import uri="http://www.alfresco.org/model/content/1.0" prefix="cm"/>
<import uri="http://www.alfresco.org/model/system/1.0" prefix="sys"/>
<import uri="http://www.alfresco.org/model/datalist/1.0" prefix="dl"/>
<import uri="http://alvexcore.com/prefix/alvexdt" prefix="alvexdt"/>
</imports>
<namespaces>
<namespace uri="http://alvexcore.com/prefix/alvexoutdocskr" prefix="alvexoutdocskr"/>
</namespaces>
<constraints>
</constraints>
<types>
<type name="alvexoutdocskr:document_outdocskr">
<parent>alvexdt:object</parent>
<properties>
<property name="alvexoutdocskr:publishedDate">
<type>d:date</type>
</property>
<property name="alvexoutdocskr:authorisedBy">
<type>d:text</type>
</property>
<property name="alvexoutdocskr:sumContract">
<type>d:float</type>
</property>
</properties>
<associations>
<association name="alvexoutdocskr:contractManagerkr">
<title>Contract Manager</title>
<source>
<mandatory>false</mandatory>
<many>true</many>
</source>
<target>
<class>cm:person</class>
</target>
</association>
<association name="alvexoutdocskr:contractManagerkrControl">
<title>Control Contract Manager</title>
<source>
<mandatory>false</mandatory>
<many>true</many>
</source>
<target>
<class>cm:person</class>
</target>
</association>
</associations>
<mandatory-aspects>
<aspect>alvexoutdocskr:withVendorInfokr</aspect>
</mandatory-aspects>
</type><----->
</types>
<aspects>
<aspect name="alvexoutdocskr:withVendorInfokr">
<properties>
<property name="alvexoutdocskr:vendorCompanyNamekr">
<type>d:text</type>
<index enabled="true">
<atomic>true</atomic>
<stored>true</stored>
<tokenised>both</tokenised>
</index>
</property>
</properties>
</aspect>
</aspects>
</model>
описание форм:
<alfresco-config>
<config evaluator="model-type" condition="alvexoutdocskr:document_outdocskr">
<forms>
<form id="datagrid">
<field-visibility>
<show id="alvexdt:id" />
<show id="alvexdt:company" />
<show id="alvexdt:contractor" />
<show id="alvexoutdocskr:vendorCompanyNamekr" />
<show id="alvexdt:signingDate" />
<show id="alvexdt:expiryDate" />
<show id="alvexoutdocskr:sumContract" />
</field-visibility>
<appearance>
<field id="alvexdt:id" isSortKey="true" />
<field id="alvexdt:relatedDocuments">
<control template="Alvex.DatagridRecordRenderer"/>
</field>
</appearance>
</form>
<form>
<field-visibility>
<show id="alvexdt:id" />
<show id="alvexdt:registerDate" />
<show id="alvexdt:company" />
<show id="alvexdt:agreementType" />
<show id="alvexdt:agreementSummary" />
<show id="alvexdt:contractor" />
<show id="alvexdt:relatedDocuments" />
<show id="alvexdt:documentManager" />
<show id="alvexoutdocskr:vendorCompanyNamekr" />
<show id="alvexoutdocskr:contractManagerkr" />
<show id="alvexoutdocskr:contractManagerkrControl" />
<show id="alvexdt:signingDate" />
<show id="alvexdt:expiryDate" />
<show id="alvexdt:signatory" />
<show id="alvexdt:renew" />
<show id="alvexdt:location" />
<show id="alvexdt:files" />
<show id="alvexoutdocskr:publishedDate"/>
<show id="alvexoutdocskr:authorisedBy"/>
<show id="alvexoutdocskr:sumContract"/>
</field-visibility>
<create-form template="/alvex-form.ftl" />
<appearance>
<set id="id" appearance="" label="" template="/org/alfresco/components/form/3-column-set.ftl"/>
<set id="company" appearance="" label="" template="/org/alfresco/components/form/3-column-set.ftl"/>
<set id="vendor" appearance="" label="" template="/org/alfresco/components/form/2-column-set.ftl"/>
<set id="date" appearance="" label="" template="/org/alfresco/components/form/3-column-set.ftl"/>
<set id="renew"/>
<set id="summary" appearance="" label="" />
<set id="files" appearance="" label=""/>
<set id="related" appearance="" label="" />
<set id="location" />
<set id="manager" />
<set id="sums" />
<field set="id" id="alvexdt:id">
<control template="/alvex-auto-numberer.ftl"/>
</field>
<field set="date" id="alvexdt:registerDate"/>
<field set="id" id="alvexdt:agreementType">
<control template="/alvex-masterData-select.ftl"/>
</field>
<field set="company" id="alvexdt:company">
<control template="/alvex-masterData-select.ftl"/>
</field>
<field set="company" id="alvexdt:contractor">
<control template="/alvex-masterData-select.ftl"/>
</field>
<field set="company" id="alvexoutdocskr:vendorCompanyNamekr">
<control template="/orgchart-picker.ftl" />
</field>
<field set="vendor" id="alvexoutdocskr:vendorCompanyNamekr" >
<control template="/org/alfresco/components/form/controls/textfield.ftl">
<control-param name="style">width: 98%</control-param>
</control>
</field>
<field set="date" id="alvexdt:signingDate"/>
<field set="date" id="alvexdt:expiryDate"/>
<field set="date" id="alvexdt:signatory">
<control template="/orgchart-picker.ftl" />
</field>
<field set="date" id="alvexoutdocskr:publishedDate"/>
<field set="manager" id="alvexoutdocskr:authorisedBy"/>
<field set="renew" id="alvexdt:renew"/>
<field set="summary" id="alvexdt:agreementSummary">
<control template="/alvex-mltext.ftl">
<control-param name="style">width: 98%</control-param>
</control>
</field>
<field set="files" id="alvexdt:files">
<control template="/alvex-uploader.ftl">
<control-param name="uploadDirectory">uploads</control-param>
<control-param name="createUploadDirectory">true</control-param>
<control-param name="viewType">mini</control-param>
</control>
</field>
<field set="related" id="alvexdt:relatedDocuments">
<control template="/alvex-docreg-picker.ftl"/>
</field>
<field set="location" id="alvexdt:location">
<control template="/share-site-picker.ftl"/>
</field>
<field set="manager" id="alvexoutdocskr:contractManagerkr" />
<field set="manager" id="alvexoutdocskr:contractManagerkrControl" />
<field set="sums" id="alvexoutdocskr:sumContract" />
</appearance>
</form>
</forms>
</config>
<config evaluator="node-type" condition="alvexoutdocskr:document_outdocskr">
<forms>
<form>
<field-visibility>
<show id="alvexdt:id" />
<show id="alvexdt:registerDate" />
<show id="alvexdt:company" />
<show id="alvexdt:agreementType" />
<show id="alvexdt:agreementSummary" />
<show id="alvexdt:contractor" />
<show id="alvexdt:relatedDocuments" />
<show id="alvexdt:documentManager" />
<show id="alvexoutdocskr:vendorCompanyNamekr" />
<show id="alvexdt:signingDate" />
<show id="alvexdt:expiryDate" />
<show id="alvexdt:signatory" />
<show id="alvexdt:renew" />
<show id="alvexdt:location" />
<show id="alvexdt:files" />
<show id="alvexoutdocskr:contractManagerkr" />
<show id="alvexoutdocskr:contractManagerkrControl" />
<show id="alvexoutdocskr:publishedDate"/>
<show id="alvexoutdocskr:authorisedBy"/>
<show id="alvexoutdocskr:sumContract"/>
</field-visibility>
<view-form template="/alvex-form.ftl" />
<edit-form template="/alvex-form.ftl" />
<appearance>
<set id="id" appearance="" label="" template="/org/alfresco/components/form/3-column-set.ftl"/>
<set id="company" appearance="" label="" template="/org/alfresco/components/form/3-column-set.ftl"/>
<set id="date" appearance="" label="" template="/org/alfresco/components/form/3-column-set.ftl"/>
<set id="renew"/>
<set id="summary" appearance="" label="" />
<set id="files" appearance="" label=""/>
<set id="related" appearance="" label="" />
<set id="location" />
<set id="manager" />
<set id="sums" />
<field set="id" id="alvexdt:id">
<control template="/alvex-auto-numberer.ftl"/>
</field>
<field set="id" id="alvexdt:registerDate"/>
<field set="id" id="alvexdt:agreementType">
<control template="/alvex-masterData-select.ftl"/>
</field>
<field set="company" id="alvexdt:company">
<control template="/alvex-masterData-select.ftl"/>
</field>
<field set="company" id="alvexdt:contractor">
<control template="/alvex-masterData-select.ftl"/>
</field>
<field set="company" id="alvexdt:documentManager">
<control template="/orgchart-picker.ftl" />
</field>
<field set="vendor" id="alvexoutdocskr:vendorCompanyNamekr" />
<field set="date" id="alvexdt:signingDate"/>
<field set="date" id="alvexdt:expiryDate"/>
<field set="date" id="alvexdt:signatory">
<control template="/orgchart-picker.ftl" />
</field>
<field set="date" id="alvexoutdocskr:publishedDate"/>
<field set="manager" id="alvexoutdocskr:authorisedBy"/>
<field set="renew" id="alvexdt:renew"/>
<field set="summary" id="alvexdt:agreementSummary">
<control template="/alvex-mltext.ftl">
<control-param name="style">width: 98%</control-param>
</control>
</field>
<field set="files" id="alvexdt:files">
<control template="/alvex-uploader.ftl">
<control-param name="uploadDirectory">uploads</control-param>
<control-param name="createUploadDirectory">true</control-param>
<control-param name="viewType">mini</control-param>
</control>
</field>
<field set="related" id="alvexdt:relatedDocuments">
<control template="/alvex-docreg-picker.ftl"/>
</field>
<field set="location" id="alvexdt:location">
<control template="/share-site-picker.ftl"/>
</field>
<field set="manager" id="alvexoutdocskr:contractManagerkr" />
<field set="manager" id="alvexoutdocskr:contractManagerkrControl" />
<field set="sums" id="alvexoutdocskr:sumContract" />
</appearance>
</form>
</forms>
</config>
</alfresco-config>
И сам текст вебскрипта:
package ru.kristall.webscripts;
import java.io.*;
import java.util.*;
import org.springframework.extensions.webscripts.AbstractWebScript;
import org.springframework.extensions.webscripts.WebScriptException;
import org.springframework.extensions.webscripts.WebScriptRequest;
import org.springframework.extensions.webscripts.WebScriptResponse;
import org.springframework.extensions.webscripts.servlet.WebScriptServletRequest;
import org.springframework.extensions.surf.RequestContext;
import org.json.JSONException;
import org.json.JSONObject;
import org.alfresco.repo.workflow.*;
import org.alfresco.service.cmr.workflow.*;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.security.AuthenticationService;
import org.alfresco.repo.model.*;
import org.alfresco.service.namespace.*;
import org.alfresco.service.cmr.repository.*;
import org.alfresco.util.ISO8601DateFormat;
import org.alfresco.model.ContentModel;
import org.alfresco.model.DataListModel;
import org.alfresco.repo.jscript.ScriptLogger;
public class createRecord extends AbstractWebScript {
ScriptLogger logger = new ScriptLogger();
private ServiceRegistry registry;
private Repository repository;
private NodeService nodeService;
private String WFHISTORY_FOLDER_NAME = "WFHISTORY";
private String WFHISTORY_FILE_NAME= "wfhistory";
/* Так как мы будем работать с историей workflow и репозиторием
нам нужны текущие объекты ServiceRegistry и Repository
*/
public void setServiceRegistry (ServiceRegistry registry) {
this.registry = registry;
}
public void setRepository (Repository repository) {
this.repository = repository;
}
/* Метод, находящий узел в альфреске
*/
protected NodeRef getNodeRef(NodeRef parent, String path) {
List<String> pathElements = new ArrayList<String>();
StringTokenizer tokenizer = new StringTokenizer(path, "/");
while (tokenizer.hasMoreTokens()) {
String childName = tokenizer.nextToken();
pathElements.add(childName);
}
NodeRef nodeRef = null;
try {
nodeRef = this.registry.getFileFolderService().resolveNamePath(parent, pathElements).getNodeRef();
} catch(Exception fnfe) {}
return nodeRef;
}
/***
* Получаем каталог, где создавать записи.
* @return
*/
public NodeRef getHome(String dir) {
NodeRef pNode = null;
NodeRef companyHomeRef = this.repository.getCompanyHome();
logger.error("================================= CompanyHome="+companyHomeRef.toString());
if (companyHomeRef!=null) {
pNode = getNodeRef(companyHomeRef, dir);
if (pNode!=null) {
logger.error("================================= pNode="+pNode.toString());
} else logger.error("Unable to locate "+dir+" path");
}
return pNode;
}
public void writeFile2Node(NodeRef target, NodeRef dir, String nameF, InputStream inp) throws IOException {
//// запись файла в нод даталиста
// нод создаваемого файла
NodeRef fileNode = null;
// Объявляем, что этот нод это содержимое файла
QName contentQName = QName.createQName("{http://www.alfresco.org/model/content/1.0}content");
// создаем файл в выбранном каталоге альфреско ( помним что это нод)
fileNode = this.registry.getFileFolderService().create(dir, nameF, contentQName).getNodeRef();
// Нод нужно наполнить содержимым
ContentWriter writer = this.registry.getFileFolderService().getWriter(fileNode);
writer.putContent(inp);
// А теперь привяжем созданный файл к новой записи в даталисте.
// Обратите внимание на типизацию!!!! Создаем ассоциацию, и указываем базовый тип.
nodeService.createAssociation(target, fileNode, QName.createQName(
"http://alvexcore.com/prefix/alvexdt", "files"));
}
/*
точка запуска вебскрипта
*/
public void execute(WebScriptRequest req, WebScriptResponse res) throws IOException {
logger.error("Execute my webScript DirectiveHistory");
// Ищем реестр, куда будем добавлять записи
NodeRef rr =getHome("Сайты/test2/dataLists/Invoice");
nodeService = registry.getNodeService();
String dlName =(String) nodeService.getProperty(rr, ContentModel.PROP_TITLE);
logger.error("dlName="+dlName);
// Дата в Альфреске пишется вот таким образом.
GregorianCalendar cal = new GregorianCalendar();
cal.set(Calendar.YEAR, 2014);
cal.set(Calendar.MONTH, 10);
cal.set(Calendar.DAY_OF_MONTH, 9);
cal.set(Calendar.HOUR, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.MILLISECOND, 0);
cal.set(Calendar.SECOND, 0);
String isoStartDate = ISO8601DateFormat.format(cal.getTime());
//
/*
Создаем запись в даталисте
*/
/*
Заполним данными запись, Запись заполняется как набор типизованных свойств.
Обратите внимание как типизируются свойства и как задаются значения, Это ВАЖНО.
Шаг вправо, шаг влево - попытка побега, прыжок на месте попытка улететь.
Я заполнил только обязательные данные
*/
Map<QName, Serializable> dataListProperties =new HashMap<QName, Serializable>();
dataListProperties.put(ContentModel.PROP_NAME, "33");
dataListProperties.put(QName.createQName("http://alvexcore.com/prefix/alvexdt","id"),"33");
dataListProperties.put(QName.createQName("http://alvexcore.com/prefix/alvexdt","registerDate"),isoStartDate);
dataListProperties.put(QName.createQName("http://alvexcore.com/prefix/alvexoutdocskr","publishedDate"),isoStartDate);
// Создание нода дата листа отчета
/*
Вот так, одним методом создается запись в даталисте. И опять очень ВАЖНА типизация
свойств. Имя это имя нода, т.е. вы сами называете как хотите. У меня значение берется как id
*/
ChildAssociationRef dataList =nodeService.createNode(rr,
ContentModel.ASSOC_CONTAINS,
QName.createQName("http://www.alfresco.org/model/content/1.0","33"),
QName.createQName("http://alvexcore.com/prefix/alvexoutdocskr","document_outdocskr"),
dataListProperties);
String name= "Test";
/*
Мне было очень интересно как альфреска заполняет данные
*/
List<ChildAssociationRef> children = nodeService.getChildAssocs(rr);
for (ChildAssociationRef childAssoc : children) {
NodeRef child = childAssoc.getChildRef();
logger.error( "======!!!!====="+(String) nodeService.getProperty(child, ContentModel.PROP_NAME));
logger.error( "======Class====="+child.getClass().getName());
Map<QName, Serializable> properties = nodeService.getProperties(child);
Iterator iterator = properties.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry mapEntry = (Map.Entry) iterator.next();
logger.error("The key is: " + mapEntry.getKey() + ", value is :" + mapEntry.getValue());
try {
logger.error("sThe key is: " + mapEntry.getKey().toString() + ", value is :" + mapEntry.getValue().toString());
}
catch (Exception ex) {
logger.error("null The key is: " + mapEntry.getKey() + ", value is :" + mapEntry.getValue());
}
}
}
/*
Получил нод вновь созданной записи
Она нам понадобиться когда будем привязывать файл к ней. А привязывать будем потому, что это кастомный тип, расширяющий базовый тип alvexdt:object, котрый сам не имеет поля типа cm:content а содержит только ассоциацию alvexdt:files. (Есть рекомндация, что использование ассоциация улучшает скорость работы, по сравнению со своими свойствами.)
*/
NodeRef child = dataList.getChildRef();
logger.error("=====Write file");
// это содержимое файла
String test = "TESIK \n\r Тестик \n\r";
byte[] b = test.getBytes();
// превращаем его в поток, ну мне так кажется что это универсальнее
InputStream inp = new ByteArrayInputStream(b);
logger.error("before getHome ");
// ищем каталог в альфреске, куда будем писать файл.
NodeRef rr1 =getHome("WFHISTORY");
logger.error("before writefile2node ");
// создаем и привязываем файл.
writeFile2Node(child,rr1, "Test.txt", inp);
logger.error("after writefile2node ");
}
}
Пусть несколько сумбурно, но надеюсь что многим начинающим будет полезно.
Начал я с изучения статьи Ангелины http://www.ossportal.org/technologies/alfresco/blogs/572
и к статьи https://forums.alfresco.com/forum/developer-discussions/repository-servi...
<UPDATED>
Будет очень полезно посмотреть вот эту статью
http://confluence.ecm-alfresco.ru/display/workingexamples/Custom+DataList
</UPDATED>
Очень полезная статья. Но не хватает освещения еще двух очень важных вопросов:
1. как программно на яве добавить запись в даталист.
2. как программно на яве привязать файл из репозиторя к даталисту.
Итак, начнем.
Откуда растут ноги?
Стоит задача получать документы из биллинга (счета и счета фактуры) Это файлы с описаниями. Создавать бизнес процессы по отправке и отслеживанию, что бы не дай бог, клиенты не вовремя заплатили...
Для этого был создан собственный тип реестра в Alvex.
Оставалась сущая безделица: создать программно запись в дата лист.
Основное, что нужно помнить, что все в альфреске - это Node из XML (как в линуксе все файл).
Задача получения документов сводится к нескольким маленьким:
1. нужно найти родительский нод (реестр) куда будем делать записи.
2. создать список необходимых аттрибутов у нового нода. (Ну в самом деле, зачем создавать пустой нод).
3. создать дочерний нод (запись) у родительского нода. Самое главное именно того типа, который требуется в используемом реестре, иначе не будут работать формы реестра. И отображение информации будет искажено.
4. Создать файл в репозитории альфреско.
( Почему именно там?
1. Базовый тип alvexdt:object не содержит полей типа cm:content, значит содержимое файла некуда записать.
2. Содержит ассоциацию alvexdt:files. Которая является ссылкой на файл.
Есть рекомендация пользоваться ссылками, вместо использования содержимого, скорость работы сильно от этого зависит.)
5. Привязать созданный файл к новой записи. Т.е. банально заполнить ссылку.
В тексте кода вебскрипта привел комментарии, что бы можно было понять какой код за что отвечает.
Так же сделал указания на что нужно обратить внимание.
Вообщем-то все достаточно просто. Главное внимание.
Описание модели:
<?xml version="1.0" encoding="UTF-8"?>
<model
name="alvexoutdocskr:documents_model"
xmlns="http://www.alfresco.org/model/dictionary/1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.alfresco.org/model/dictionary/1.0 modelSchema.xsd">
<imports>
<import uri="http://www.alfresco.org/model/dictionary/1.0" prefix="d"/>
<import uri="http://www.alfresco.org/model/content/1.0" prefix="cm"/>
<import uri="http://www.alfresco.org/model/system/1.0" prefix="sys"/>
<import uri="http://www.alfresco.org/model/datalist/1.0" prefix="dl"/>
<import uri="http://alvexcore.com/prefix/alvexdt" prefix="alvexdt"/>
</imports>
<namespaces>
<namespace uri="http://alvexcore.com/prefix/alvexoutdocskr" prefix="alvexoutdocskr"/>
</namespaces>
<constraints>
</constraints>
<types>
<type name="alvexoutdocskr:document_outdocskr">
<parent>alvexdt:object</parent>
<properties>
<property name="alvexoutdocskr:publishedDate">
<type>d:date</type>
</property>
<property name="alvexoutdocskr:authorisedBy">
<type>d:text</type>
</property>
<property name="alvexoutdocskr:sumContract">
<type>d:float</type>
</property>
</properties>
<associations>
<association name="alvexoutdocskr:contractManagerkr">
<title>Contract Manager</title>
<source>
<mandatory>false</mandatory>
<many>true</many>
</source>
<target>
<class>cm:person</class>
</target>
</association>
<association name="alvexoutdocskr:contractManagerkrControl">
<title>Control Contract Manager</title>
<source>
<mandatory>false</mandatory>
<many>true</many>
</source>
<target>
<class>cm:person</class>
</target>
</association>
</associations>
<mandatory-aspects>
<aspect>alvexoutdocskr:withVendorInfokr</aspect>
</mandatory-aspects>
</type><----->
</types>
<aspects>
<aspect name="alvexoutdocskr:withVendorInfokr">
<properties>
<property name="alvexoutdocskr:vendorCompanyNamekr">
<type>d:text</type>
<index enabled="true">
<atomic>true</atomic>
<stored>true</stored>
<tokenised>both</tokenised>
</index>
</property>
</properties>
</aspect>
</aspects>
</model>
описание форм:
<alfresco-config>
<config evaluator="model-type" condition="alvexoutdocskr:document_outdocskr">
<forms>
<form id="datagrid">
<field-visibility>
<show id="alvexdt:id" />
<show id="alvexdt:company" />
<show id="alvexdt:contractor" />
<show id="alvexoutdocskr:vendorCompanyNamekr" />
<show id="alvexdt:signingDate" />
<show id="alvexdt:expiryDate" />
<show id="alvexoutdocskr:sumContract" />
</field-visibility>
<appearance>
<field id="alvexdt:id" isSortKey="true" />
<field id="alvexdt:relatedDocuments">
<control template="Alvex.DatagridRecordRenderer"/>
</field>
</appearance>
</form>
<form>
<field-visibility>
<show id="alvexdt:id" />
<show id="alvexdt:registerDate" />
<show id="alvexdt:company" />
<show id="alvexdt:agreementType" />
<show id="alvexdt:agreementSummary" />
<show id="alvexdt:contractor" />
<show id="alvexdt:relatedDocuments" />
<show id="alvexdt:documentManager" />
<show id="alvexoutdocskr:vendorCompanyNamekr" />
<show id="alvexoutdocskr:contractManagerkr" />
<show id="alvexoutdocskr:contractManagerkrControl" />
<show id="alvexdt:signingDate" />
<show id="alvexdt:expiryDate" />
<show id="alvexdt:signatory" />
<show id="alvexdt:renew" />
<show id="alvexdt:location" />
<show id="alvexdt:files" />
<show id="alvexoutdocskr:publishedDate"/>
<show id="alvexoutdocskr:authorisedBy"/>
<show id="alvexoutdocskr:sumContract"/>
</field-visibility>
<create-form template="/alvex-form.ftl" />
<appearance>
<set id="id" appearance="" label="" template="/org/alfresco/components/form/3-column-set.ftl"/>
<set id="company" appearance="" label="" template="/org/alfresco/components/form/3-column-set.ftl"/>
<set id="vendor" appearance="" label="" template="/org/alfresco/components/form/2-column-set.ftl"/>
<set id="date" appearance="" label="" template="/org/alfresco/components/form/3-column-set.ftl"/>
<set id="renew"/>
<set id="summary" appearance="" label="" />
<set id="files" appearance="" label=""/>
<set id="related" appearance="" label="" />
<set id="location" />
<set id="manager" />
<set id="sums" />
<field set="id" id="alvexdt:id">
<control template="/alvex-auto-numberer.ftl"/>
</field>
<field set="date" id="alvexdt:registerDate"/>
<field set="id" id="alvexdt:agreementType">
<control template="/alvex-masterData-select.ftl"/>
</field>
<field set="company" id="alvexdt:company">
<control template="/alvex-masterData-select.ftl"/>
</field>
<field set="company" id="alvexdt:contractor">
<control template="/alvex-masterData-select.ftl"/>
</field>
<field set="company" id="alvexoutdocskr:vendorCompanyNamekr">
<control template="/orgchart-picker.ftl" />
</field>
<field set="vendor" id="alvexoutdocskr:vendorCompanyNamekr" >
<control template="/org/alfresco/components/form/controls/textfield.ftl">
<control-param name="style">width: 98%</control-param>
</control>
</field>
<field set="date" id="alvexdt:signingDate"/>
<field set="date" id="alvexdt:expiryDate"/>
<field set="date" id="alvexdt:signatory">
<control template="/orgchart-picker.ftl" />
</field>
<field set="date" id="alvexoutdocskr:publishedDate"/>
<field set="manager" id="alvexoutdocskr:authorisedBy"/>
<field set="renew" id="alvexdt:renew"/>
<field set="summary" id="alvexdt:agreementSummary">
<control template="/alvex-mltext.ftl">
<control-param name="style">width: 98%</control-param>
</control>
</field>
<field set="files" id="alvexdt:files">
<control template="/alvex-uploader.ftl">
<control-param name="uploadDirectory">uploads</control-param>
<control-param name="createUploadDirectory">true</control-param>
<control-param name="viewType">mini</control-param>
</control>
</field>
<field set="related" id="alvexdt:relatedDocuments">
<control template="/alvex-docreg-picker.ftl"/>
</field>
<field set="location" id="alvexdt:location">
<control template="/share-site-picker.ftl"/>
</field>
<field set="manager" id="alvexoutdocskr:contractManagerkr" />
<field set="manager" id="alvexoutdocskr:contractManagerkrControl" />
<field set="sums" id="alvexoutdocskr:sumContract" />
</appearance>
</form>
</forms>
</config>
<config evaluator="node-type" condition="alvexoutdocskr:document_outdocskr">
<forms>
<form>
<field-visibility>
<show id="alvexdt:id" />
<show id="alvexdt:registerDate" />
<show id="alvexdt:company" />
<show id="alvexdt:agreementType" />
<show id="alvexdt:agreementSummary" />
<show id="alvexdt:contractor" />
<show id="alvexdt:relatedDocuments" />
<show id="alvexdt:documentManager" />
<show id="alvexoutdocskr:vendorCompanyNamekr" />
<show id="alvexdt:signingDate" />
<show id="alvexdt:expiryDate" />
<show id="alvexdt:signatory" />
<show id="alvexdt:renew" />
<show id="alvexdt:location" />
<show id="alvexdt:files" />
<show id="alvexoutdocskr:contractManagerkr" />
<show id="alvexoutdocskr:contractManagerkrControl" />
<show id="alvexoutdocskr:publishedDate"/>
<show id="alvexoutdocskr:authorisedBy"/>
<show id="alvexoutdocskr:sumContract"/>
</field-visibility>
<view-form template="/alvex-form.ftl" />
<edit-form template="/alvex-form.ftl" />
<appearance>
<set id="id" appearance="" label="" template="/org/alfresco/components/form/3-column-set.ftl"/>
<set id="company" appearance="" label="" template="/org/alfresco/components/form/3-column-set.ftl"/>
<set id="date" appearance="" label="" template="/org/alfresco/components/form/3-column-set.ftl"/>
<set id="renew"/>
<set id="summary" appearance="" label="" />
<set id="files" appearance="" label=""/>
<set id="related" appearance="" label="" />
<set id="location" />
<set id="manager" />
<set id="sums" />
<field set="id" id="alvexdt:id">
<control template="/alvex-auto-numberer.ftl"/>
</field>
<field set="id" id="alvexdt:registerDate"/>
<field set="id" id="alvexdt:agreementType">
<control template="/alvex-masterData-select.ftl"/>
</field>
<field set="company" id="alvexdt:company">
<control template="/alvex-masterData-select.ftl"/>
</field>
<field set="company" id="alvexdt:contractor">
<control template="/alvex-masterData-select.ftl"/>
</field>
<field set="company" id="alvexdt:documentManager">
<control template="/orgchart-picker.ftl" />
</field>
<field set="vendor" id="alvexoutdocskr:vendorCompanyNamekr" />
<field set="date" id="alvexdt:signingDate"/>
<field set="date" id="alvexdt:expiryDate"/>
<field set="date" id="alvexdt:signatory">
<control template="/orgchart-picker.ftl" />
</field>
<field set="date" id="alvexoutdocskr:publishedDate"/>
<field set="manager" id="alvexoutdocskr:authorisedBy"/>
<field set="renew" id="alvexdt:renew"/>
<field set="summary" id="alvexdt:agreementSummary">
<control template="/alvex-mltext.ftl">
<control-param name="style">width: 98%</control-param>
</control>
</field>
<field set="files" id="alvexdt:files">
<control template="/alvex-uploader.ftl">
<control-param name="uploadDirectory">uploads</control-param>
<control-param name="createUploadDirectory">true</control-param>
<control-param name="viewType">mini</control-param>
</control>
</field>
<field set="related" id="alvexdt:relatedDocuments">
<control template="/alvex-docreg-picker.ftl"/>
</field>
<field set="location" id="alvexdt:location">
<control template="/share-site-picker.ftl"/>
</field>
<field set="manager" id="alvexoutdocskr:contractManagerkr" />
<field set="manager" id="alvexoutdocskr:contractManagerkrControl" />
<field set="sums" id="alvexoutdocskr:sumContract" />
</appearance>
</form>
</forms>
</config>
</alfresco-config>
И сам текст вебскрипта:
package ru.kristall.webscripts;
import java.io.*;
import java.util.*;
import org.springframework.extensions.webscripts.AbstractWebScript;
import org.springframework.extensions.webscripts.WebScriptException;
import org.springframework.extensions.webscripts.WebScriptRequest;
import org.springframework.extensions.webscripts.WebScriptResponse;
import org.springframework.extensions.webscripts.servlet.WebScriptServletRequest;
import org.springframework.extensions.surf.RequestContext;
import org.json.JSONException;
import org.json.JSONObject;
import org.alfresco.repo.workflow.*;
import org.alfresco.service.cmr.workflow.*;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.security.AuthenticationService;
import org.alfresco.repo.model.*;
import org.alfresco.service.namespace.*;
import org.alfresco.service.cmr.repository.*;
import org.alfresco.util.ISO8601DateFormat;
import org.alfresco.model.ContentModel;
import org.alfresco.model.DataListModel;
import org.alfresco.repo.jscript.ScriptLogger;
public class createRecord extends AbstractWebScript {
ScriptLogger logger = new ScriptLogger();
private ServiceRegistry registry;
private Repository repository;
private NodeService nodeService;
private String WFHISTORY_FOLDER_NAME = "WFHISTORY";
private String WFHISTORY_FILE_NAME= "wfhistory";
/* Так как мы будем работать с историей workflow и репозиторием
нам нужны текущие объекты ServiceRegistry и Repository
*/
public void setServiceRegistry (ServiceRegistry registry) {
this.registry = registry;
}
public void setRepository (Repository repository) {
this.repository = repository;
}
/* Метод, находящий узел в альфреске
*/
protected NodeRef getNodeRef(NodeRef parent, String path) {
List<String> pathElements = new ArrayList<String>();
StringTokenizer tokenizer = new StringTokenizer(path, "/");
while (tokenizer.hasMoreTokens()) {
String childName = tokenizer.nextToken();
pathElements.add(childName);
}
NodeRef nodeRef = null;
try {
nodeRef = this.registry.getFileFolderService().resolveNamePath(parent, pathElements).getNodeRef();
} catch(Exception fnfe) {}
return nodeRef;
}
/***
* Получаем каталог, где создавать записи.
* @return
*/
public NodeRef getHome(String dir) {
NodeRef pNode = null;
NodeRef companyHomeRef = this.repository.getCompanyHome();
logger.error("================================= CompanyHome="+companyHomeRef.toString());
if (companyHomeRef!=null) {
pNode = getNodeRef(companyHomeRef, dir);
if (pNode!=null) {
logger.error("================================= pNode="+pNode.toString());
} else logger.error("Unable to locate "+dir+" path");
}
return pNode;
}
public void writeFile2Node(NodeRef target, NodeRef dir, String nameF, InputStream inp) throws IOException {
//// запись файла в нод даталиста
// нод создаваемого файла
NodeRef fileNode = null;
// Объявляем, что этот нод это содержимое файла
QName contentQName = QName.createQName("{http://www.alfresco.org/model/content/1.0}content");
// создаем файл в выбранном каталоге альфреско ( помним что это нод)
fileNode = this.registry.getFileFolderService().create(dir, nameF, contentQName).getNodeRef();
// Нод нужно наполнить содержимым
ContentWriter writer = this.registry.getFileFolderService().getWriter(fileNode);
writer.putContent(inp);
// А теперь привяжем созданный файл к новой записи в даталисте.
// Обратите внимание на типизацию!!!! Создаем ассоциацию, и указываем базовый тип.
nodeService.createAssociation(target, fileNode, QName.createQName(
"http://alvexcore.com/prefix/alvexdt", "files"));
}
/*
точка запуска вебскрипта
*/
public void execute(WebScriptRequest req, WebScriptResponse res) throws IOException {
logger.error("Execute my webScript DirectiveHistory");
// Ищем реестр, куда будем добавлять записи
NodeRef rr =getHome("Сайты/test2/dataLists/Invoice");
nodeService = registry.getNodeService();
String dlName =(String) nodeService.getProperty(rr, ContentModel.PROP_TITLE);
logger.error("dlName="+dlName);
// Дата в Альфреске пишется вот таким образом.
GregorianCalendar cal = new GregorianCalendar();
cal.set(Calendar.YEAR, 2014);
cal.set(Calendar.MONTH, 10);
cal.set(Calendar.DAY_OF_MONTH, 9);
cal.set(Calendar.HOUR, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.MILLISECOND, 0);
cal.set(Calendar.SECOND, 0);
String isoStartDate = ISO8601DateFormat.format(cal.getTime());
//
/*
Создаем запись в даталисте
*/
/*
Заполним данными запись, Запись заполняется как набор типизованных свойств.
Обратите внимание как типизируются свойства и как задаются значения, Это ВАЖНО.
Шаг вправо, шаг влево - попытка побега, прыжок на месте попытка улететь.
Я заполнил только обязательные данные
*/
Map<QName, Serializable> dataListProperties =new HashMap<QName, Serializable>();
dataListProperties.put(ContentModel.PROP_NAME, "33");
dataListProperties.put(QName.createQName("http://alvexcore.com/prefix/alvexdt","id"),"33");
dataListProperties.put(QName.createQName("http://alvexcore.com/prefix/alvexdt","registerDate"),isoStartDate);
dataListProperties.put(QName.createQName("http://alvexcore.com/prefix/alvexoutdocskr","publishedDate"),isoStartDate);
// Создание нода дата листа отчета
/*
Вот так, одним методом создается запись в даталисте. И опять очень ВАЖНА типизация
свойств. Имя это имя нода, т.е. вы сами называете как хотите. У меня значение берется как id
*/
ChildAssociationRef dataList =nodeService.createNode(rr,
ContentModel.ASSOC_CONTAINS,
QName.createQName("http://www.alfresco.org/model/content/1.0","33"),
QName.createQName("http://alvexcore.com/prefix/alvexoutdocskr","document_outdocskr"),
dataListProperties);
String name= "Test";
/*
Мне было очень интересно как альфреска заполняет данные
*/
List<ChildAssociationRef> children = nodeService.getChildAssocs(rr);
for (ChildAssociationRef childAssoc : children) {
NodeRef child = childAssoc.getChildRef();
logger.error( "======!!!!====="+(String) nodeService.getProperty(child, ContentModel.PROP_NAME));
logger.error( "======Class====="+child.getClass().getName());
Map<QName, Serializable> properties = nodeService.getProperties(child);
Iterator iterator = properties.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry mapEntry = (Map.Entry) iterator.next();
logger.error("The key is: " + mapEntry.getKey() + ", value is :" + mapEntry.getValue());
try {
logger.error("sThe key is: " + mapEntry.getKey().toString() + ", value is :" + mapEntry.getValue().toString());
}
catch (Exception ex) {
logger.error("null The key is: " + mapEntry.getKey() + ", value is :" + mapEntry.getValue());
}
}
}
/*
Получил нод вновь созданной записи
Она нам понадобиться когда будем привязывать файл к ней. А привязывать будем потому, что это кастомный тип, расширяющий базовый тип alvexdt:object, котрый сам не имеет поля типа cm:content а содержит только ассоциацию alvexdt:files. (Есть рекомндация, что использование ассоциация улучшает скорость работы, по сравнению со своими свойствами.)
*/
NodeRef child = dataList.getChildRef();
logger.error("=====Write file");
// это содержимое файла
String test = "TESIK \n\r Тестик \n\r";
byte[] b = test.getBytes();
// превращаем его в поток, ну мне так кажется что это универсальнее
InputStream inp = new ByteArrayInputStream(b);
logger.error("before getHome ");
// ищем каталог в альфреске, куда будем писать файл.
NodeRef rr1 =getHome("WFHISTORY");
logger.error("before writefile2node ");
// создаем и привязываем файл.
writeFile2Node(child,rr1, "Test.txt", inp);
logger.error("after writefile2node ");
}
}