在网上没有找到java版的向github仓库上传文件的工具,于是便自己查api封装一个

为了方便我们可以通过代码执行上传相应文件到github指定仓库,做实时的公共文档或图片存储,github给我们提供一个便利的方式,通过api即可实现文件的上传查询和删除等操作,当时用github存图片时一直没有找到java版本封装好的类库,于是决定自己一边查资料一边巩固自学的java知识,封装一个;

一 申请令牌(github token)

github登录成功后,点击此处直接跳转到token申请页面,或通过用户头像->Settings-> Developer settings->Personal access tokens-> Tokens (classic):

Java实现GZip菜鸟教程 java操作github_java

点击 Generate new token创建新的token,并根据自己的实际情况输入token描述,时间以及权限,权限至少勾选repo:

Java实现GZip菜鸟教程 java操作github_java_02

点击最下方的Generate token生成token,注意token只显示一次,记得记录保存好:

Java实现GZip菜鸟教程 java操作github_java_03

二 查阅github的api文档

点击此处跳转到官方文档,查阅api的调用方式.简单来说,github采用普通的http方式来实现文件的查询,新增和删除,在这里,我们只针对新增进行封装;

点击create-or-update-file-contents直接查看文件上传的api.

Java实现GZip菜鸟教程 java操作github_github_04

我们可以看到一个非常简单的例子,通过put请求,将进行好base64编码的内容上传到仓库中,

/repos/"+username[用户名]+"/"+depository[仓库名]+"/contents/"+fileName[路径及文件名];

既然该有的我们都有了,接下来我们准备封装工具类

三 使用java封装

1 配置项

在项目工程的resources文件夹下配置yml文件:

githubclub:
  config:
    username: tangyuxian #用户名
    token: #token填写在这里
    depository: blog_image #仓库名
    message: fromJavaServe #描述
    domain: https://cdn.jsdelivr.net/gh/tangyuxian/blog_image@latest #cdn加速域名
2 封装工具类
1) HttpUtils.java

这个工具类用于创建http请求

public class HttpUtils {

    private CloseableHttpClient httpClient;

    /**
     * 与Spring集成初始化HttpClient
     * 在Spring启动后会调用init方法
     */
    @PostConstruct
    public void init() {
        httpClient = HttpClients.custom().build();
    }

    /**
     * application-json方式提交
     * @param url http路径
     * @param json json字符串 {"key":"value"}
     * @return 响应内容字符串
     */
    public String postJson(String url, String json) {
        HttpPost httpPost = new HttpPost(url);
        httpPost.setEntity(new StringEntity(json, ContentType.APPLICATION_JSON));
        try(CloseableHttpResponse response = httpClient.execute(httpPost)) {
            return EntityUtils.toString( response.getEntity());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * application/x-www-form-urlencoded 方式提交
     * @param url http路径
     * @param kvMap key与value组成的map
     * @return 响应内容字符串
     */
    public String postForm(String url, Map<String, String> kvMap) {
        HttpPost httpPost = new HttpPost(url);
        List<NameValuePair> nvps = new ArrayList<>();
        kvMap.forEach((key, value) -> nvps.add(new BasicNameValuePair(key, value)));
        httpPost.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8));
        try(CloseableHttpResponse response = httpClient.execute(httpPost)) {
            return EntityUtils.toString(response.getEntity());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * get请求
     * @param url http路径 (后可跟参数?p1=aaa&p2=bbb&p3=ccc)
     * @return 响应内容字符串
     */
    public String getString(String url) {
        HttpGet httpget = new HttpGet(url);
        try(CloseableHttpResponse response = httpClient.execute(httpget)) {
            return EntityUtils.toString(response.getEntity());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * get请求
     * @param url http路径 (后可跟参数?p1=aaa&p2=bbb&p3=ccc)
     * @return 响应内容
     */
    public byte[] getBytes(String url) {
        HttpGet httpget = new HttpGet(url);
        try(CloseableHttpResponse response = httpClient.execute(httpget)) {
            return EntityUtils.toByteArray(response.getEntity());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    /**
     * application-json方式提交
     * @param url http路径
     * @param json json字符串 {"key":"value"}
     * @return 响应内容字符串
     */
    public String putJson(String url, String json,Map<String, String> headerMap) {
        HttpPut httpPut = new HttpPut(url);
        headerMap.entrySet().forEach(entry->httpPut.addHeader(entry.getKey(), entry.getValue()));
        httpPut.setEntity(new StringEntity(json, ContentType.APPLICATION_JSON));
        try(CloseableHttpResponse response = httpClient.execute(httpPut)) {
            return EntityUtils.toString( response.getEntity());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    /**
     * 与Spring集成销毁HttpClient
     * 在Spring关闭后会调用destroy方法
     */
    @PreDestroy
    public void destroy() throws Exception {
        httpClient.close();
    }
}
2) GithubClubUtil.java

这个工具类用来封装文件上传功能

@Component
@ConfigurationProperties(prefix = "githubclub.config")
public class GithubClubUtil {
    @Autowired
    HttpUtils httpUtils;
    /**
     * 用户名
     */
    private String username;

    /**
     * token
     */
    private String token;

    /**
     * 仓库名
     */
    private String depository;

    /**
     * 统一提交信息
     */
    private String message;

    /**
     * 自定义域名
     */
    private String domain;

    private String GITHUBAPI = "https://api.github.com";

    /**
     * 文件推送到github
     * @param fileName  文件名
     * @param content json 数据格式 {"message":"test commit","content":"bXkgbmV3IGZpbGUgY29udGVudHM="}
     * @return
     */
    public HashMap<String, Object> contentFile(String fileName, String content){
        String url = GITHUBAPI + "/repos/"+username+"/"+depository+"/contents/"+fileName;
        HashMap<String, String> header = new HashMap<>();
        header.put("Authorization","token "+token);
        header.put("Accept","Accept: application/vnd.github.v3+json");
        String json = "{\"message\":\""+message+"\",\"content\":\""+content+"\"}";
        String res = httpUtils.putJson(url, json, header);
        return filterResultForContentFile(res,fileName);
    }

    /**
     * 处理调用接口后返回的值
     * @param res
     * @param fileName
     * @return
     */
    private HashMap<String,Object> filterResultForContentFile(String res,String fileName){
        Map<String, Object> map = JsonUtil.jsonToMap(res);
        Map<String, Object> commit = (Map<String, Object>) map.get("commit");
        HashMap<String, Object> result = new HashMap<>();
        if(commit.get("message").equals(message)){
            result.put("success",true);
            result.put("data",domain+fileName);
        }else{
            result.put("success",false);
        }
        return result;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getToken() {
        return token;
    }

    public void setToken(String token) {
        this.token = token;
    }

    public String getDepository() {
        return depository;
    }

    public void setDepository(String depository) {
        this.depository = depository;
    }
    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public String getDomain() {
        return domain;
    }

    public void setDomain(String domain) {
        this.domain = domain;
    }
}
3) GithubClubConfig.java

配置信息注入到Bean

public class GithubClubConfig {
    @Bean
    public GithubClubUtil githubClubUtil(){return new GithubClubUtil();}
}
3 测试工具类
1) 测试下是否可用
@GetMapping("/uploadFile")
public R uploadFile(){
    String fileName = "test/test3.txt";
    String content = "bXkgbmV3IGZpbGUgY29udGVudHM=";
    HashMap map =  githubClubUtil.contentFile(fileName,content);
    if((Boolean)map.get("success")){
        return R.ok();
    }else{
        return R.err();
    }
}
2) 提供一个文件上传的方法

具体细节根据自己实际情况进一步封装即可

@PostMapping("/upload")
public R uploadOld(@RequestParam("file") MultipartFile file) {
    System.out.println(file.getOriginalFilename());
    System.out.println(file.getName());
    System.out.println(file.getContentType());

    String name = file.getOriginalFilename();
    String sname =name.substring(name.lastIndexOf("."));
    String fileName = "/test/"+"tyx_"+ RandomStringUtils.getRandomString(10)+sname;
    Base64 base64Encoder = new Base64();
    byte[] imageBytes = null;
    String base64EncoderImg="";
    try{
        imageBytes = file.getBytes();
        base64EncoderImg = base64Encoder.encodeToString(imageBytes);
        HashMap map =  githubClubUtil.contentFile(fileName,base64EncoderImg);
        if((Boolean)map.get("success")){
            return R.ok(map.get("data"));
        }else{
            return R.err();
        }
    }catch (Exception e){
        throw new RuntimeException(e);
    }
}

大功告成啦!