Artifactory 是一个非常好用的私服产品,有两个分支:
一个是开源的OOS(From version 4.8.1, Artifactory OSS is licensed under AGPL 3.0 (previously LGPL 3.0))
一个是需要付费的PRO,10几万,贵的有点离谱,但功能也更丰富。
这里主要是改造开源的那个版本,你可以从他们的网站下载到源代码,然后自己编译调试。
文件的属性,只有PRO版本才会有,但是我们自己写点代码这个可以有。还有就是Rest API,也是只有PRO才会提供,但是我们也可以在不改变原有程序的情况下,添加一个我们自己写的一个类,实现我们需要的API,这个也可以有。
我这里以3.5.3版本为例,描述下:
添加属性的方法,按照下面方法,即可以把属性显示出来 package org.artifactory.addon.wicket;
private static class DisabledPropertiesPanel extends PropertiesPanel { public DisabledPropertiesPanel(String id, String nestedPanelId) { super(id); //add(new DisabledCollapsibleBehavior()); <-- 注释掉这行即可以把属性展示出来 add(new WebMarkupContainer(nestedPanelId)); } @Override protected Component newToolbar(String id) { return new DisabledAddonHelpBubble(id, PROPERTIES); } }
添加自定义的API的方式更简单,只需把我们实现的API放到 package org.artifactory.rest.resource.* 下,我的是放到 package org.artifactory.rest.resource.versions; 下了。
package org.artifactory.rest.resource.versions; import org.artifactory.api.config.CentralConfigService; import org.artifactory.api.module.ModuleInfo; import org.artifactory.api.repo.RepositoryService; import org.artifactory.api.security.AuthorizationService; import org.artifactory.fs.ItemInfo; import org.artifactory.fs.StatsInfo; import org.artifactory.md.Properties; import org.artifactory.model.common.RepoPathImpl; import org.artifactory.model.xstream.fs.PropertiesImpl; import org.artifactory.repo.RepoPath; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; import javax.annotation.security.RolesAllowed; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.*; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import java.util.*; /** * Created by Nelson on 2016-12-06. * VersionMaintenanceResources */ @Component @Scope(BeanDefinition.SCOPE_PROTOTYPE) @Path(VersionMaintenanceResources.PATH_ROOT) @RolesAllowed({AuthorizationService.ROLE_USER, AuthorizationService.ROLE_ADMIN}) public class VersionMaintenanceResources { private static final Logger logger = LoggerFactory.getLogger(VersionMaintenanceResources.class); public static final String PATH_ROOT = "version-maintenance"; @Context private HttpServletRequest request; @Autowired private RepositoryService repoService; @Autowired private CentralConfigService centralConfig; @Autowired private AuthorizationService authorizationService; @GET @Produces({MediaType.APPLICATION_JSON}) @Path("property/get/{repoKey: (?!_any)[^/]+}/{path: (?!_any).+}") public Response getRepoPropertiesByPath(@PathParam("repoKey") String repoKey, @PathParam("path") String path) { Response response = hasPermission(); if (null != response) { return response; } RepoPath repoPath = new RepoPathImpl(repoKey, path); if (repoService.exists(repoPath)) { Properties properties = repoService.getProperties(repoPath); Map<String, String> result = new HashMap<>(); if (null != properties) { for (String key : properties.keySet()) { Set<String> strings = properties.get(key); if (null != strings) { result.put(key, strings.toString()); } } } return Response.ok(result, MediaType.APPLICATION_JSON_TYPE).build(); } return Response.status(Response.Status.BAD_REQUEST) .entity("Repo path not exists") .type(MediaType.APPLICATION_JSON_TYPE) .build(); } @PUT @Produces({MediaType.APPLICATION_JSON}) @Path("property/set/{repoKey: (?!_any)[^/]+}/{path: (?!_any).+}") public Response setRepoPropertiesByPath(@PathParam("repoKey") String repoKey, @PathParam("path") String path) { Response response = hasPermission(); if (null != response) { return response; } RepoPath repoPath = new RepoPathImpl(repoKey, path); if (repoService.exists(repoPath)) { Properties properties = repoService.getProperties(repoPath); if (null == properties) { properties = new PropertiesImpl(); } Map<String, String[]> parameterMap = request.getParameterMap(); if ((null == parameterMap) || parameterMap.isEmpty()) { properties.clear(); } if (null != parameterMap) { for (String propName : parameterMap.keySet()) { if (properties.containsKey(propName)) { properties.removeAll(propName); } String[] values = parameterMap.get(propName); if (null != values) { for (String value : values) { if ((null != value) && (value.trim().length() > 0)) { properties.put(propName, value); } } } } repoService.setProperties(repoPath, properties); return Response.ok("Success", MediaType.APPLICATION_JSON_TYPE).build(); } } return Response.status(Response.Status.BAD_REQUEST) .entity("Repo path not exists") .type(MediaType.APPLICATION_JSON_TYPE) .build(); } @GET @Produces({MediaType.APPLICATION_JSON}) @Path("list/{repoKey: (?!_any)[^/]+}/{path: (?!_any).+|$}") public Response getChildRepoByPath(@PathParam("repoKey") String repoKey, @PathParam("path") String path) { Response response = hasPermission(); if (null != response) { return response; } List<FileInfo> fileInfoList = new ArrayList<>(); RepoPath repoPath = new RepoPathImpl(repoKey, path); if (repoService.exists(repoPath)) { ItemInfo itemInfo = repoService.getItemInfo(repoPath); if (itemInfo.isFolder()) { List<ItemInfo> itemInfoList = repoService.getChildren(repoPath); for (ItemInfo info : itemInfoList) { fileInfoList.add(createFileInfo(info.getRepoPath())); } } else { fileInfoList.add(createFileInfo(itemInfo.getRepoPath())); } return Response.ok() .entity(fileInfoList) .type(MediaType.APPLICATION_JSON_TYPE) .build(); } else { return Response.status(Response.Status.BAD_REQUEST) .entity("Repo path not exists") .type(MediaType.APPLICATION_JSON_TYPE) .build(); } } @DELETE @Produces({MediaType.APPLICATION_JSON}) @Path("remove/{repoKey: (?!_any)[^/]+}/{path: (?!_any).+}") public Response removeRepoByPath(@PathParam("repoKey") String repoKey, @PathParam("path") String path) { Response response = hasPermission(); if (null != response) { return response; } WrongPath result = new WrongPath(); Map<String, String[]> parameterMap = request.getParameterMap(); if ((null != parameterMap) && (parameterMap.size() > 0)) { if (parameterMap.containsKey("versions")) { String[] versions = parameterMap.get("versions"); for (String ver : versions) { RepoPath repoPath; if (path.endsWith("/")) { repoPath = new RepoPathImpl(repoKey, path + ver); } else { repoPath = new RepoPathImpl(repoKey, path + "/" + ver); } if (repoService.exists(repoPath)) { repoService.undeploy(repoPath); } else { result.add(repoPath.toString()); } } } } else { RepoPath repoPath = new RepoPathImpl(repoKey, path); if (repoService.exists(repoPath)) { repoService.undeploy(repoPath); } else { result.add(repoPath.toString()); } } if (result.size() > 0) { return Response.status(Response.Status.BAD_REQUEST) .entity(result) .type(MediaType.APPLICATION_JSON_TYPE) .build(); } else { return Response.ok("Success", MediaType.APPLICATION_JSON_TYPE).build(); } } private Response hasPermission() { if (authorizationService.isAuthenticated() && !authorizationService.isAnonymous()) { return null; } else { if (centralConfig.getDescriptor().getSecurity().isHideUnauthorizedResources()) { return Response.status(Response.Status.NOT_FOUND).build(); } return Response.status(Response.Status.UNAUTHORIZED).build(); } } private FileInfo createFileInfo(RepoPath repoPath) { FileInfo fileInfo = new FileInfo(); fileInfo.setFolder(repoPath.isFolder()); fileInfo.setRepoKey(repoPath.getRepoKey()); fileInfo.setPath(repoPath.getPath()); ItemInfo itemInfo = null; if (repoPath.isFile()) { org.artifactory.fs.FileInfo file; file = repoService.getFileInfo(repoPath); fileInfo.setSize(file.getSize()); fileInfo.setMd5(file.getMd5()); fileInfo.setSha1(file.getSha1()); ModuleInfo moduleInfo = repoService.getItemModuleInfo(repoPath); fileInfo.setGroupId(moduleInfo.getOrganization()); fileInfo.setArtifactId(moduleInfo.getModule()); fileInfo.setVersion(moduleInfo.getBaseRevision()); fileInfo.setExt(moduleInfo.getExt()); fileInfo.setClassifier(moduleInfo.getClassifier()); itemInfo = file; } if (repoPath.isFolder()) { org.artifactory.fs.FolderInfo file; file = repoService.getFolderInfo(repoPath); itemInfo = file; } if (null != itemInfo) { fileInfo.setCreatedBy(itemInfo.getCreatedBy()); fileInfo.setModifiedBy(itemInfo.getModifiedBy()); fileInfo.setCreated(itemInfo.getCreated()); fileInfo.setLastModified(itemInfo.getLastModified()); } StatsInfo statsInfo = repoService.getStatsInfo(repoPath); if (null != statsInfo) { fileInfo.setDownloadCount(statsInfo.getDownloadCount()); fileInfo.setLastDownloaded(statsInfo.getLastDownloaded()); } if (repoService.hasProperties(repoPath)) { Properties properties = repoService.getProperties(repoPath); if (null != properties) { for (String key : properties.keySet()) { Set<String> value = properties.get(key); if (null != value) { fileInfo.getProperties().put(key, value.toString()); } } } } return fileInfo; } public class FileInfo { private boolean isFolder; private String repoKey; private String path; private String createdBy; private long created; private String modifiedBy; private long lastModified; private long size; private String md5; private String sha1; private long downloadCount; private long lastDownloaded; private String groupId; private String artifactId; private String version; private String ext; private String classifier; private Map<String, String> properties = new HashMap<>(); public long getLastModified() { return lastModified; } public void setLastModified(long lastModified) { this.lastModified = lastModified; } public long getCreated() { return created; } public void setCreated(long created) { this.created = created; } public String getModifiedBy() { return modifiedBy; } public void setModifiedBy(String modifiedBy) { this.modifiedBy = modifiedBy; } public String getCreatedBy() { return createdBy; } public void setCreatedBy(String createdBy) { this.createdBy = createdBy; } public String getPath() { return path; } public void setPath(String path) { this.path = path; } public String getRepoKey() { return repoKey; } public void setRepoKey(String repoKey) { this.repoKey = repoKey; } public Map<String, String> getProperties() { return properties; } public void setProperties(Map<String, String> properties) { this.properties = properties; } public boolean isFolder() { return isFolder; } public void setFolder(boolean folder) { isFolder = folder; } public long getDownloadCount() { return downloadCount; } public void setDownloadCount(long downloadCount) { this.downloadCount = downloadCount; } public long getLastDownloaded() { return lastDownloaded; } public void setLastDownloaded(long lastDownloaded) { this.lastDownloaded = lastDownloaded; } public long getSize() { return size; } public void setSize(long size) { this.size = size; } public String getMd5() { return md5; } public void setMd5(String md5) { this.md5 = md5; } public String getSha1() { return sha1; } public void setSha1(String sha1) { this.sha1 = sha1; } public String getGroupId() { return groupId; } public void setGroupId(String groupId) { this.groupId = groupId; } public String getArtifactId() { return artifactId; } public void setArtifactId(String artifactId) { this.artifactId = artifactId; } public String getVersion() { return version; } public void setVersion(String version) { this.version = version; } public String getExt() { return ext; } public void setExt(String ext) { this.ext = ext; } public String getClassifier() { return classifier; } public void setClassifier(String classifier) { this.classifier = classifier; } } public class WrongPath { private String message = "Repo path not exists"; private List<String> paths = new ArrayList<>(); public List<String> getPaths() { return paths; } public void setPaths(List<String> paths) { this.paths = paths; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public void add(String path) { paths.add(path); } public int size() { return paths.size(); } } }
好了,你可以做自己想做的了