挑戰常規--搭建gradle、maven私人倉庫很簡單
阿新 • • 發佈:2018-12-16
常規
百度搜索“搭建maven私有倉庫”,搜尋到的結果幾乎都是使用nexus
不一樣的簡單
如果瞭解maven上傳原理,完全沒必要搞得那麼複雜龐大,區區不足百行程式碼就可以實現一個私有倉庫。
maven上傳的核心本質是:使用Http PUT上傳,使用Http GET下載。再簡單不過的程式碼如下:
@WebServlet("/") public class RepositoryServer extends HttpServlet { /**儲存位置 */ private File path; public void init(ServletConfig config) throws ServletException { super.init(config); //或者指定其他位置 path = new File(config.getServletContext().getRealPath("/repository")); } protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String reqPath = req.getServletPath(); File reqFile = new File(path, reqPath); if (!reqFile.exists()) { resp.sendError(HttpServletResponse.SC_NOT_FOUND); return; } if (reqFile.isDirectory()) { resp.sendError(HttpServletResponse.SC_FORBIDDEN); } else { try (OutputStream out = resp.getOutputStream()) { Files.copy(reqFile.toPath(), out); } } } protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String reqPath = req.getServletPath(); File reqFile = new File(path, reqPath); if (reqPath.endsWith("/")) { reqFile.mkdirs(); } else { File parentDir = reqFile.getParentFile(); if (!parentDir.exists()) { parentDir.mkdirs(); } try (InputStream in = req.getInputStream()) { Files.copy(in, reqFile.toPath(), StandardCopyOption.REPLACE_EXISTING); } } } }
測試上傳和引用(這裡執行gradle使用,maven一樣參考)
apply plugin: 'java' apply plugin: 'maven' version "0.9.9.1" group "cn.heihei.testproject" project.ext.artifactId = "model" repositories { jcenter() } dependencies { testImplementation 'junit:junit:4.12' } tasks.withType(JavaCompile) { options.encoding = "UTF-8" } task sourcesJar(type: Jar) { classifier = 'sources' from sourceSets.main.allSource } artifacts { archives sourcesJar } jar { manifest { attributes('Implementation-Title': project.name, 'Implementation-Version': project.version) } } uploadArchives{ repositories { mavenDeployer{ repository(url:"http://localhost:8080/RepositoryServer/") pom.project{ version project.version groupId project.group packaging 'jar' artifactId project.ext.artifactId } } } }
apply plugin: 'java' repositories { maven{ url "http://localhost:8080/RepositoryServer/" } jcenter() } dependencies { implementation 'cn.heihei.testproject:model:0.9.9.1' testImplementation 'junit:junit:4.12' }
bash結果
ProjectModel>gradle uploadArchives Could not find metadata cn.heihei.testproject:model/maven-metadata.xml in remote (http://localhost:8080/RepositoryServer/) BUILD SUCCESSFUL in 1s 4 actionable tasks: 1 executed, 3 up-to-date
ProjectServer>gradle build Download http://localhost:8080/RepositoryServer/cn/heihei/testproject/model/0.9.9.1/model-0.9.9.1.pom Download http://localhost:8080/RepositoryServer/cn/heihei/testproject/model/0.9.9.1/model-0.9.9.1.jar BUILD SUCCESSFUL in 1s 2 actionable tasks: 2 up-to-date
目錄顯示
if (reqFile.isDirectory()) { if (!reqPath.endsWith("/")) { resp.sendRedirect(req.getContextPath() + reqPath + "/"); return; } resp.setContentType("text/html;charset=utf-8"); try (PrintWriter wr = resp.getWriter()) { wr.println("<html><body>"); wr.println("<h1>" + reqPath + "</h1>"); wr.println("[上一層] <a href='../'>..</a><br>"); File[] fs = reqFile.listFiles(); if (fs != null && fs.length > 0) { for (File f : fs) { if (f.isFile()) { wr.println("[檔案] <a href='" + f.getName() + "'>" + f.getName() + "</a><br>"); } else { wr.println("[目錄] <a href='" + f.getName() + "/'>" + f.getName() + "</a><br>"); } } } wr.println("</body></html>"); } }
安全
作為私鑰倉庫,使用basic 安全認證進行控制訪問
簡單程式碼
private String authorization; public void init(ServletConfig config) throws ServletException { super.init(config); path = new File(config.getServletContext().getRealPath("/repository")); authorization="aGVpaGVpOjY1NDRjNGRmMGM1NjhhNjg5ZDUwN2QwNjJkMTYyNmJk"; //或從其他地方載入 } protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { if(!check(req,resp)) { return; } super.service(req, resp); } private boolean check(HttpServletRequest req, HttpServletResponse resp) throws IOException { String auth=req.getHeader("Authorization"); if(auth!=null&&auth.startsWith("Basic ")) { auth=auth.substring(6); if(auth.equals(authorization)) { return true; } } resp.setHeader("WWW-Authenticate", "Basic realm=\"Need Login\", charset=\"UTF-8\""); resp.sendError(HttpServletResponse.SC_UNAUTHORIZED); return false; }
上傳和引用控制
uploadArchives{ repositories { mavenDeployer{ repository(url:"http://localhost:8080/RepositoryServer/") { authentication(userName: "heihei", password: "6544c4df0c568a689d507d062d1626bd") } pom.project{ version project.version groupId project.group packaging 'jar' artifactId project.ext.artifactId } } } }
repositories { maven{ url "http://localhost:8080/RepositoryServer/" authentication { basic(BasicAuthentication) } credentials { username = 'heihei' password = '6544c4df0c568a689d507d062d1626bd' } } jcenter() }
思考
當然如果僅僅個人非團隊開發,是否本地倉庫更好?
repository(url:"file:///D:/wamp64/www/repository")
也可以使用web容器,如NanoHTTPD、tomcat embeded、etty embeded,變成微服務