常规
百度搜索“搭建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,变成微服务