笔记:Apache Chemistry OpenCMIS Client端开发2
来源:互联网 发布:加盟农村淘宝怎么盈利 编辑:程序博客网 时间:2024/06/06 01:47
CMIS对象类型
如何获取Document对象的类型定义
如何获取Document对象的属性
如何显式获取对象属性值
如何根据属性ID获取属性对象
如何基于SQL-92语法查询CMIS对象
cmis:document被称为虚拟表,cmis:name被称为虚拟列。
如何处理CMIS中的异常
如果使用ATOMPUB绑定,可以从CmisBaseException.getErrorContent()得到服务器端的异常详情。
如何禁用对象缓存
如何获取Document对象的变体(Rendition)
如何获取从第5个元素开始的下一页CmisObject对象
如何实现翻页查看
如何检测Repository支持CMIS规范的哪些能力(capabilities)
如何检测Document对象上有哪些可执行Action
如何实现多档(Multi-filing)
如何实现反多档(Unfiling)
版本
版本术语
如何对文档进行check-out和check-in操作
如何查询一棵文档树中的所有变体(Rendition)
如何查询自定义子类型对象
关系Relationship
如何创建关系
如何检测关系适用的源对象和目标对象
访问控制列表(Access Control List)
每个ACE的构成有三部分
对于direct=false的ACE,你可以通过设置传播方式PROPOGATION来告知Repository如何处理子对象
OBJECTONLY
PROPOGATE
REPOSITORYDETERMINED
如何获取权限
如何给文档对象添加ACL
- Repository必须支持的: cmis:document, cmis:folder
- Repository可能支持的: cmis:relationship, cmis:policy
- 可以从上述四个基本类型中扩展出子类型
- CMIS1.0不支持创建子类型,但可以读取子类型结构和定义
如何获取Document对象的类型定义
System.out.println("Getting type definition for doc type");ObjectType objectType = session.getTypeDefinition(doc.getType().getId());System.out.println("isBaseType() returns " + (objectType.isBaseType() ? "true" : "false"));ObjectType baseType = objectType.getBaseType();if (baseType == null) { System.out.println("getBaseType() returns null");} else { System.out.println("getBaseType() returns " + baseType.getDisplayName());}ObjectType parentType = objectType.getParentType();if (parentType == null) { System.out.println("getParentType() returns null");} else { System.out.println("getParentType() returns " + parentType.getDisplayName());}System.out.println("Listing child types of " + objectType.getDisplayName());for (ObjectType o : objectType.getChildren()) { System.out.println("\t" + o.getDisplayName());}System.out.println("Getting immediate descendant types of " + objectType.getDisplayName());for (Tree<ObjectType> o : objectType.getDescendants(1)) { System.out.println("\t" + o.getItem().getDisplayName());}
执行结果Getting type definition for doc typeisBaseType() returns truegetBaseType() returns nullgetParentType() returns nullListing child types of CMIS Document My Type 1 Level 1 My Type 2 Level 1 Complex type with properties, Level 1 Document type with properties, Level 1 VersionedTypeGetting immediate descendant types of CMIS Document My Type 1 Level 1 My Type 2 Level 1 Complex type with properties, Level 1 Document type with properties, Level 1 VersionedType
如何获取Document对象的属性
List<Property<?>> props = doc.getProperties();for (Property<?> p : props) { System.out.println(p.getDefinition().getDisplayName() + "=" + p.getValuesAsString());}
执行结果Is Latest Major Version=[false]Content Stream Length=[26]Content Stream Id=[store://2011/5/20/12/54/0d69ee48-ef03-4715-ae23-b84b4342315c.bin]Version Series Checked Out By=[]Object Type Id=[cmis:document]Version Series Checked Out Id=[]Name=[test.txt]Content Stream MIME Type=[text/plain; charset=UTF-8]Version series id=[workspace://SpacesStore/3cd2cbbf-1a00-4653-8ea8-1e91515c6092]Creation Date=[Fri May 20 12:54:47 BST 2011]Change token=[]Version Label=[0.0]Is Latest Version=[true]Is Version Series Checked Out=[false]Last Modified By=[admin]Created by=[admin]Checkin Comment=[]Object Id=[workspace://SpacesStore/3cd2cbbf-1a00-4653-8ea8-1e91515c6092]Is Immutable=[false]Is Major Version=[false]Base Type Id=[cmis:document]Content Stream Filename=[test.txt]Last Modified Date=[Fri May 20 12:54:47 BST 2011]
如何显式获取对象属性值
System.out.println("VersionLabel property on " + doc.getName() + " is " + doc.getVersionLabel());System.out.println("Is this the latest version of " + doc.getName() + " ?: " + (doc.isLatestVersion() ? "yes" : "no"));GregorianCalendar calendar = doc.getCreationDate();String DATE_FORMAT = "yyyyMMdd";SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);System.out.println("Creation date of " + doc.getName() + " is " + sdf.format(calendar.getTime()));
如何根据属性ID获取属性对象
List<Property<?>> props = doc.getProperties();Property<?> someProperty = props.get(0);System.out.println(someProperty.getDisplayName() + " property on " + doc.getName() + " (by getPropertValue()) is " + doc.getPropertyValue(someProperty.getId()));
如何基于SQL-92语法查询CMIS对象
String query = "SELECT * FROM cmis:document WHERE cmis:name LIKE 'test%'";ItemIterable<QueryResult> q = session.query(query, false);// Did it work?System.out.println("***results from query " + query);int i = 1;for (QueryResult qr : q) { System.out.println("--------------------------------------------\n" + i + " , " + qr.getPropertyByQueryName("cmis:objectTypeId").getFirstValue() + " , " + qr.getPropertyByQueryName("cmis:name").getFirstValue() + " , " + qr.getPropertyByQueryName("cmis:createdBy").getFirstValue() + " , " + qr.getPropertyByQueryName("cmis:objectId").getFirstValue() + " , " + qr.getPropertyByQueryName("cmis:contentStreamFileName").getFirstValue() + " , " + qr.getPropertyByQueryName("cmis:contentStreamMimeType").getFirstValue() + " , " + qr.getPropertyByQueryName("cmis:contentStreamLength").getFirstValue()); i++;}
cmis:document被称为虚拟表,cmis:name被称为虚拟列。
如何处理CMIS中的异常
Folder root = session.getRootFolder();HashMap<String, String> newFolderProps = new HashMap<String, String>();newFolderProps.put(PropertyIds.OBJECT_TYPE_ID, "cmis:folder");newFolderProps.put(PropertyIds.NAME, "ADGFolderTest");Folder folderTest = root.createFolder(newFolderProps);Map<String, String> newFileProps = new HashMap<String, String>();newFileProps.put(PropertyIds.OBJECT_TYPE_ID, "cmis:badtype");newFileProps.put(PropertyIds.NAME, "ADGFileTest");try { folderTest.createDocument(newFileProps, null, VersioningState.MAJOR);} catch (CmisObjectNotFoundException e) { System.err.println("server error page :\n" + e.getErrorContent()); System.err.println("\nClient stack trace :\n"); e1.printStackTrace();}
如果使用ATOMPUB绑定,可以从CmisBaseException.getErrorContent()得到服务器端的异常详情。
执行结果server error page :Apache Chemistry OpenCMIS - objectNotFound errorHTTP Status 404 - objectNotFound[...]Client stack trace :org.apache.chemistry.opencmis.commons.exceptions.CmisObjectNotFoundException: Not Found [...] at org.apache.chemistry.opencmis.client.runtime.SessionImpl.createDocument(SessionImpl.java:651) at org.apache.chemistry.opencmis.client.runtime.FolderImpl.createDocument(FolderImpl.java:87) at org.apache.chemistry.opencmis.client.runtime.FolderImpl.createDocument(FolderImpl.java:409) at org.apache.chemistry.opencmis.doc.TestingException.main(TestingException.java:104)
如何禁用对象缓存
OperationContext operationContext = session.createOperationContext();operationContext.setCacheEnabled(false);CmisObject object = session.getObject(id, operationContext);
如何获取Document对象的变体(Rendition)
OperationContext operationContext = session.createOperationContext();operationContext.setRenditionFilterString("cmis:thumbnail");CmisObject oo = session.getObject(o.getId(), operationContext);List<Rendition> rl = oo.getRenditions();
如何获取从第5个元素开始的下一页CmisObject对象
OperationContext operationContext = session.createOperationContext();operationContext.setMaxItemsPerPage(3);ItemIterable<CmisObject> children1 = folderPaging.getChildren(operationContext);int count = 0;for (CmisObject child : children1.skipTo(5).getPage()) { System.out.println("object " + count + " in page of " + children1.getPageNumItems() + " is " + child.getName()); count++;}
如何实现翻页查看
System.out.println("Getting complete result set in pages of 3");OperationContext operationContext = session.createOperationContext();operationContext.setMaxItemsPerPage(3);children1 = folderPaging.getChildren(operationContext);int pageNumber = 0;boolean finished = false;count= 0;while (!finished) { ItemIterable<CmisObject> currentPage = children1.skipTo(count).getPage(); System.out.println("page " + pageNumber + " has " + currentPage.getPageNumItems() + " items"); for (CmisObject item : currentPage) { System.out.println("object " + count + " is " + item.getName()); count++; } pageNumber++; if (!currentPage.getHasMoreItems()) finished = true;}
如何检测Repository支持CMIS规范的哪些能力(capabilities)
System.out.println("Printing repository capabilities...");final RepositoryInfo repInfo = session.getRepositoryInfo();RepositoryCapabilities cap = repInfo.getCapabilities();System.out.println("\nNavigation Capabilities");System.out.println("-----------------------");System.out.println("Get descendants supported: " + (cap.isGetDescendantsSupported()?"true":"false"));System.out.println("Get folder tree supported: " + (cap.isGetFolderTreeSupported()?"true":"false"));System.out.println("\nObject Capabilities");System.out.println("-----------------------");System.out.println("Content Stream: " + cap.getContentStreamUpdatesCapability().value());System.out.println("Changes: " + cap.getChangesCapability().value());System.out.println("Renditions: " + cap.getRenditionsCapability().value()); System.out.println("\nFiling Capabilities");System.out.println("-----------------------"); System.out.println("Multifiling supported: " + (cap.isMultifilingSupported()?"true":"false"));System.out.println("Unfiling supported: " + (cap.isUnfilingSupported()?"true":"false"));System.out.println("Version specific filing supported: " + (cap.isVersionSpecificFilingSupported()?"true":"false"));System.out.println("\nVersioning Capabilities");System.out.println("-----------------------"); System.out.println("PWC searchable: " + (cap.isPwcSearchableSupported()?"true":"false"));System.out.println("PWC updatable: " + (cap.isPwcUpdatableSupported()?"true":"false"));System.out.println("All versions searchable: " + (cap.isAllVersionsSearchableSupported()?"true":"false"));System.out.println("\nQuery Capabilities");System.out.println("-----------------------"); System.out.println("Query: " + cap.getQueryCapability().value());System.out.println("Join: " + cap.getJoinCapability().value());System.out.println("\nACL Capabilities");System.out.println("-----------------------"); System.out.println("ACL: " + cap.getAclCapability().value()); System.out.println("End of repository capabilities");
如何检测Document对象上有哪些可执行Action
System.out.println("Getting the current allowable actions for the " + doc.getName() + " document object...");for (Action a: doc.getAllowableActions().getAllowableActions()) { System.out.println("\t" + a.value());}if (doc.getAllowableActions().getAllowableActions().contains(Action.CAN_CHECK_OUT)) { System.out.println("can check out " + doc.getName());} else { System.out.println("can not check out " + doc.getName());}
如何实现多档(Multi-filing)
if (!(cap.isMultifilingSupported())) { System.out.println("Multifiling not supported by this repository");} else { // Add a new folder to the root folder System.out.println("Creating 'ADGNewFolder 2' in the root folder"); Map<String, Object> newFolderProps = new HashMap<String, Object>(); newFolderProps.put(PropertyIds.OBJECT_TYPE_ID, "cmis:folder"); newFolderProps.put(PropertyIds.NAME, "ADGNewFolder 2"); newFolder2 = root.createFolder(newFolderProps); System.out.println("Adding " + textFileName + "to 'ADGNewFolder 2' in the root folder"); doc.addToFolder(newFolder2, true); // Did it work? ItemIterable<CmisObject>children = newFolder.getChildren(); System.out.println("Now finding the following objects in the 'ADGNewFolder' folder:-"); for (CmisObject o : children) { System.out.println(o.getName()); } children = newFolder2.getChildren(); System.out.println("Now finding the following objects in the 'ADGNewFolder 2' folder:-"); for (CmisObject o : children) { System.out.println(o.getName()); }}
如何实现反多档(Unfiling)
if (!(cap.isUnfilingSupported())) { System.out.println("Unfiling not supported by this repository");} else { // remove our document from both folders System.out.println("removing :" + doc.getName() + "from 'ADGNewFolder':-"); doc.removeFromFolder(newFolder); System.out.println("removing :" + doc.getName() + "from 'ADGNewFolder 2':-"); doc.removeFromFolder(newFolder2); // Did it work? Document docTest = (Document) session.getObject(id); if (docTest != null) { System.out.println(docTest.getName() + " still exists"); }}
版本
- 只有文档对象才有版本特性
- 目录(Folder)和关系(Relationship)不支持版本
版本术语
- 版本序列(Version Series) - 每套版本序列拥有一个唯一的序列号
- 最新版本(Latest Version)
- 主版本(Major Version)
如何对文档进行check-out和check-in操作
- PWC(Private Working copy)
- Repositories可以只允许最新版本的Document被check-out,也可以允许所有版本check-out
- 支持服务器端PWC的Repository可以允许其他用户从服务端工作区中查看文档或搜索文档
- 只支持客户端PWC的Repository则不允许其他用户访问
if (versionable) { Document pwc = (Document) session.getObject(doc.checkOut()); // default values if the document has no content String filename = "version.txt"; String mimetype = "text/plain; charset=UTF-8"; String content = ""; // get the orginal content ContentStream contentStream = doc.getContentStream(); if (contentStream != null) { filename = contentStream.getFileName(); mimetype = contentStream.getMimeType(); content = getContentAsString(contentStream); } String updatedContents = content + "\nLine added in new version"; byte[] buf = updatedContents.getBytes("UTF-8"); ByteArrayInputStream input = new ByteArrayInputStream(buf); contentStream = session.getObjectFactory().createContentStream( filename, buf.length, mimetype, input); // Check in the pwc try { pwc.checkIn(false, null, contentStream, "minor version"); } catch (CmisBaseException e) { e.printStackTrace(); System.out.println("checkin failed, trying to cancel the checkout"); pwc.cancelCheckOut(); } System.out.println("Document version history"); { List<Document> versions = doc.getAllVersions(); for (Document version : versions) { System.out.println("\tname: " + version.getName()); System.out.println("\tversion label: " + version.getVersionLabel()); System.out.println("\tversion series id: " + version.getVersionSeriesId()); System.out.println("\tchecked out by: " + version.getVersionSeriesCheckedOutBy()); System.out.println("\tchecked out id: " + version.getVersionSeriesCheckedOutId()); System.out.println("\tmajor version: " + version.isMajorVersion()); System.out.println("\tlatest version: " + version.isLatestVersion()); System.out.println("\tlatest major version: " + version.isLatestMajorVersion()); System.out.println("\tcheckin comment: " + version.getCheckinComment()); System.out.println("\tcontent length: " + version.getContentStreamLength() + "\n"); } }}
如何查询一棵文档树中的所有变体(Rendition)
if (session.getRepositoryInfo().getCapabilities().getRenditionsCapability() .equals(CapabilityRenditions.NONE)) { System.out.println("Repository does not support renditions");} else { System.out.println("Finding first object in repository with thumbnail renditions - start"); Folder node = root; Stack<Folder> stack = new Stack<Folder>(); while (node != null) { children = node.getChildren(); for (CmisObject o : children) { if ((o.getType().isBaseType() && o.getType().getId().equals("cmis:folder")) || o.getBaseType().getId().equals("cmis:folder")) { stack.push((Folder) o); } else { OperationContext context = session.createOperationContext(); context.setRenditionFilterString("cmis:thumbnail"); CmisObject oo = session.getObject(o.getId(), context); List<Rendition> rl = oo.getRenditions(); if (!rl.isEmpty()) { System.out.println("found " + o.getName() + " of type " + o.getType().getDisplayName() + "that has renditions..."); for (Rendition rendition : rl) { System.out.print("kind: " + rendition.getKind()); System.out.print("\tmimetype: " + rendition.getMimeType()); System.out.print("\twidth: " + rendition.getWidth()); System.out.print("\theight: " + rendition.getHeight()); System.out.println("\tstream id: " + rendition.getStreamId()); } break; // Just show the first object with // renditions. Remove this // Break to show them all } } } if (stack.isEmpty()) { node = null; } else { node = (Folder) stack.pop(); } } System.out.println("Finding first object in repository with thumbnail renditions - end");}
如何查询自定义子类型对象
if (session.getRepositoryInfo().getCapabilities().getQueryCapability() .equals(CapabilityQuery.METADATAONLY)) { System.out.println("Full search not supported");} else { String query = "SELECT * FROM ia:calendarEvent"; ItemIterable<QueryResult> queryResult = session.query(query, false); for (QueryResult item : queryResult) { System.out.println("Found " + item.getPropertyByQueryName("cmis:name").getFirstValue() + " of type " + item.getPropertyByQueryName("cmis:objectTypeId").getFirstValue()); System.out.println("property ia:descriptionEvent is " + item.getPropertyByQueryName("ia:descriptionEvent").getFirstValue()); System.out.println("property ia:toDate is " + item.getPropertyByQueryName("ia:toDate").getFirstValue()); System.out.println("property ia:fromDate is " + item.getPropertyByQueryName("ia:fromDate").getFirstValue()); }}
关系Relationship
- 关系是有方向的,从source到target
- 非侵入式的,它并不修改source和target
- 关系也是有类型的,cmis:relationship
- 可以建立关系对象的有:document, folder, policy
- 关系自身不含有内容流(content stream)
- Repository对关系的支持不是必须的
如何创建关系
// Check if the repo supports relationshipsObjectType relationshipType = null;try { relationshipType = session.getTypeDefinition("cmis:relationship");} catch (CmisObjectNotFoundException e) { relationshipType = null;}if (relationshipType == null) { System.out.println("Repository does not support cmis:relationship objects");} else { ObjectType cmiscustomRelationshipType = null; try { cmiscustomRelationshipType = session.getTypeDefinition("R:cmiscustom:assoc"); } catch (CmisObjectNotFoundException e) { cmiscustomRelationshipType = null; } if (cmiscustomRelationshipType == null) { System.out.println("Repository does not support R:cmiscustom:assoc objects"); } else { System.out.println("Creating folders for relationships example"); newFolderProps = new HashMap<String, String>(); newFolderProps.put(PropertyIds.OBJECT_TYPE_ID, "cmis:folder"); newFolderProps.put(PropertyIds.NAME, "ADGFolderAssociations"); Folder folderAssociations = root.createFolder(newFolderProps); newFileProps = new HashMap<String, String>(); newFileProps.put(PropertyIds.OBJECT_TYPE_ID, "D:cmiscustom:document"); newFileProps.put(PropertyIds.NAME, "ADGFileSource"); Document sourceDoc = folderAssociations.createDocument(newFileProps, null, VersioningState.MAJOR); newFileProps.put(PropertyIds.OBJECT_TYPE_ID, "cmis:document"); newFileProps.put(PropertyIds.NAME, "ADGFileTarget"); Document targetDoc = folderAssociations.createDocument(newFileProps, null, VersioningState.MAJOR); Map<String, String> relProps = new HashMap<String, String>(); relProps.put("cmis:sourceId", sourceDoc.getId()); relProps.put("cmis:targetId", targetDoc.getId()); relProps.put("cmis:objectTypeId", "R:cmiscustom:assoc"); ObjectId relId = session.createRelationship(relProps, null, null, null); System.out.println("created relationship"); }}
如何检测关系适用的源对象和目标对象
RelationshipType relType = (RelationshipType) relationship.getType();System.out.println(relType.getDisplayName() + "has the following allowed source types:");for (ObjectType objectType : relType.getAllowedSourceTypes()) { System.out.println("\t" + objectType.getDisplayName());}System.out.println(relType.getDisplayName() + "has the following allowed target types:");for (ObjectType objectType : relType.getAllowedTargetTypes()) { System.out.println("\t" + objectType.getDisplayName());}
访问控制列表(Access Control List)
- Document对象的访问可以由ACL或者Policy进行控制
- ACL由ACE(Access Control Entry)构成
- CMIS预定义3种基本权限: [cmis:read, cmis:write, cmis:all]
每个ACE的构成有三部分
- 一个成员:包括用户、组、角色
- 一个或多个权限字段
- direct标志:true表示直接赋予,false表示经由继承得到
对于direct=false的ACE,你可以通过设置传播方式PROPOGATION来告知Repository如何处理子对象
OBJECTONLY
PROPOGATE
REPOSITORYDETERMINED
如何获取权限
System.out.println("getting ACL capabilities");AclCapabilities aclCapabilities = session.getRepositoryInfo().getAclCapabilities();System.out.println("Propogation for this repository is " + aclCapabilities.getAclPropagation().toString());System.out.println("permissions for this repository are: ");for (PermissionDefinition definition : aclCapabilities.getPermissions()) { System.out.println(definition.toString()); }System.out.println("\npermission mappings for this repository are: ");Map<String, PermissionMapping> repoMapping = aclCapabilities.getPermissionMapping();for (String key: repoMapping.keySet()) { System.out.println(key + " maps to " + repoMapping.get(key).getPermissions()); }
如何给文档对象添加ACL
// Check if the repo supports ACLsif (!session.getRepositoryInfo().getCapabilities().getAclCapability() .equals(CapabilityAcl.MANAGE)) { System.out.println("Repository does not allow ACL management");} else { System.out.println("Repository allows ACL management"); System.out.println("Creating folders for permissions example"); HashMap<String, String> newFolderProps = new HashMap<String, String>(); newFolderProps.put(PropertyIds.OBJECT_TYPE_ID, "cmis:folder"); newFolderProps.put(PropertyIds.NAME, "ADGFolderPermissions"); Folder folderAssociations = session.getRootFolder().createFolder(newFolderProps); HashMap<String, String> newFileProps = new HashMap<String, String>(); ContentStream contentStream = new ContentStreamImpl("permissions.txt", null, "plain/text", new ByteArrayInputStream("some content".getBytes())); newFileProps.put(PropertyIds.OBJECT_TYPE_ID, "cmis:document"); newFileProps.put(PropertyIds.NAME, "ADGFilePermissions"); Document testDoc = folderAssociations.createDocument(newFileProps, contentStream, VersioningState.MAJOR); OperationContext operationContext = new OperationContextImpl(); operationContext.setIncludeAcls(true); testDoc = (Document) session.getObject(testDoc, operationContext); System.out.println("ACL before adding an ace..."); for (Ace ace : testDoc.getAcl().getAces()) { System.out.println("Found ace: " + ace.getPrincipalId() + " toString "+ ace.toString()); } List<String> permissions = new ArrayList<String>(); permissions.add("cmis:write"); String principal = "admin"; Ace aceIn = session.getObjectFactory().createAce(principal, permissions); List<Ace> aceListIn = new ArrayList<Ace>(); aceListIn.add(aceIn); testDoc.addAcl(aceListIn, AclPropagation.REPOSITORYDETERMINED); testDoc = (Document) session.getObject(testDoc, operationContext); System.out.println("ACL after adding an ace..."); for (Ace ace : testDoc.getAcl().getAces()) { System.out.println("Found ace: " + ace.getPrincipalId() + " toString "+ ace.toString()); } }
0 0
- 笔记:Apache Chemistry OpenCMIS Client端开发
- 笔记:Apache Chemistry OpenCMIS Client端开发2
- Apache-Chemistry(OpenCMIS Client API Developer's Guide)
- Apache OpenCMIS客户端API简介
- 关于 Apache Http Client 的使用笔记
- Chemistry
- 【Apache Mina2.0开发之一】搭建Apache Mina框架并实现Server与Client端的简单消息传递!
- 【Apache Mina2.0开发之一】搭建Apache Mina框架并实现Server与Client端的简单消息传递!
- 【Apache Mina2.0开发之一】搭建Apache Mina框架并实现Server与Client端的简单消息传递!
- 【Apache Mina2.0开发之一】搭建Apache Mina框架并实现Server与Client端的简单消息传递!
- 【APACHE MINA2.0开发之一】搭建APACHE MINA框架并实现SERVER与CLIENT端的简单消息传递!
- 【Apache Mina2.0开发之二】自定义实现Server/Client端的编解码工厂(自定义编码与解码器)!
- 【Apache Mina2.0开发之二】自定义实现Server/Client端的编解码工厂(自定义编码与解码器)!
- 【APACHE MINA2.0开发之二】自定义实现SERVER/CLIENT端的编解码工厂(自定义编码与解码器)!
- redis 学习笔记(2)-client端示例代码
- redis 学习笔记(2)-client端示例代码
- redis 学习笔记(2)-client端示例代码
- redis 学习笔记(2)-client端示例代码
- nginx初体验
- 加速WEB访问:使用DNSmasq与squid代理并过滤广告
- Java开发中JDBC连接数据库的步骤
- HTML常用标签之文本标签
- 服务端架构中的“网关服务器”
- 笔记:Apache Chemistry OpenCMIS Client端开发2
- Spring MVC中@RequestMapping 6个基本用法小结
- 影响语音交互普及起来的心理因素有哪些?
- 看数据结构写代码(16)顺序队列的实现(循环队列)
- 函数模版和类模版
- JS模块化感悟
- 多态
- C语言的相关学习
- c/c++时间函数