1. 程式人生 > >挑戰常規--搭建gradle、maven私人倉庫很簡單

挑戰常規--搭建gradle、maven私人倉庫很簡單

常規

百度搜索“搭建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,變成微服務