• Readme.MD 例子


    了解一个项目,恐怕首先都是通过其Readme文件了解信息。如果你以为Readme文件都是随便写写的那你就错了。github,oschina git gitcafe的代码托管平台上的项目的Readme.MD文件都是有其特有的语法的。称之为Markdown语法。基本规则如下:

    1. Markdown 语法速查表  
    2. 1 标题与文字格式  
    3. 标题  
    4. # 这是 H1 <一级标题>  
    5. ## 这是 H2 <二级标题>  
    6. ###### 这是 H6 <六级标题>  
    7. 文字格式  
    8. **这是文字粗体格式**  
    9. *这是文字斜体格式*  
    10. ~~在文字上添加删除线~~  
    11. 2 列表  
    12. 无序列表  
    13. * 项目1  
    14. * 项目2  
    15. * 项目3  
    16. 有序列表  
    17. 1. 项目1  
    18. 2. 项目2  
    19. 3. 项目3  
    20.    * 项目1  
    21.    * 项目2  
    22. 3 其它  
    23. 图片  
    24. ![图片名称](http://gitcafe.com/image.png)  
    25. 链接  
    26. [链接名称](http://gitcafe.com)  
    27. 引用  
    28. > 第一行引用文字  
    29. > 第二行引用文字  
    30. 水平线  
    31. ***  
    32. 代码  
    33. `<hello world>`  
    34. 代码块高亮  
    35. ```ruby  
    36.   def add(a, b)  
    37.     return a + b  
    38.   end  
    39. ```  
    40. 表格  
    41.   表头  | 表头  
    42.   ------------- | -------------  
    43.  单元格内容  | 单元格内容  
    44.  单元格内容l  | 单元格内容  

    如果直接记语法,那似乎困难了些。这里OneCoder推荐两个Markdown的编辑器。

    在线编辑器:stackedit
    网址:https://stackedit.io/

    Mac下离线编辑器Mou
    下载地址:http://mouapp.com/


    OneCoder这里使用的是后者为自己的shurnim-storage项目写Readme。至于这个项目是什么,见Readme文档,OneCoder也会在另外的博文做一些补充说明。成品Readme如下:

    1. # shurnim-storage  
    2.   
    3. ![Shurnim icon](http://onecoder.qiniudn.com/8wuliao/DLPii2Jx/rEBO.jpg)  
    4.   
    5. ## 目录  
    6. * [背景介绍](#背景介绍)  
    7. * [项目介绍](#项目介绍)  
    8. * [使用说明](#使用说明)  
    9.   * [获取代码](#获取代码)  
    10.   * [开发插件](#开发插件)  
    11.   * [使用ShurnimStorage接口](#使用ShurnimStorage接口)  
    12.        * [接口介绍](#接口介绍)  
    13.        * [使用样例](#使用样例)  
    14. * [其他](#其他)  
    15.   
    16. <a name="背景介绍"></a>  
    17. ## 背景介绍  
    18.   
    19. *Shurnim*,是我和我老婆曾经养过的一只仓鼠的名字。<br/>  
    20. *shurnim-storage*,是一个插件式云存储/网盘同步管理工具。是在参加又拍云开发大赛的过程中设计并开发。  
    21.   
    22. <a name="项目介绍"></a>  
    23. ## 项目介绍  
    24.   
    25. *shurnim-storage* 的设计初衷是给大家提供一个可方便扩展的云存储/网盘同步工具。分后端接口和前端UI界面两部分。<br>  
    26.   
    27. 由于目前各种云存储和网盘系统层出不穷,单一工具往往支持支持某几个特定存储之间的同步,如**又拍云**到**七牛云存储**的同步工具,此时如若想同步到其他存则可能需要新的工具,给用户带来不便。*shurnim-storage*  正是为了解决此问题而设计的。  
    28.   
    29. 在*shurnim-storage*中,用户使用的固定的统一的后端接口。而所有云存储/网盘API的支持则是以插件的形式部署到系统中的。如此,如果用户想要一个从**又拍云**到**Dropbox**的同步工具,则只需要在原有基础上,增加**Dropbox**的插件,即可实现互通,方便快捷。<br/>  
    30.   
    31. 同时,后端统一接口的设计也考虑到界面开发的需求,可直接通过后端提供的接口开发具有上述扩展功能的云存储UI工具。<br>  
    32.   
    33. 目前,后端整体框架的核心部分已经基本开发完成。只需逐步补充后端接口和插件开发接口的定义即可。但由于个人时间和能力所限,UI部分没有开发,有兴趣的同学可以一试。  
    34.   
    35. <a name="使用说明"></a>  
    36. ## 使用说明  
    37.   
    38. <a name="获取代码"></a>  
    39. ### 获取代码  
    40.   
    41. * gitcafe项目主页: <https://gitcafe.com/onecoder/shurnim-storage-for-UPYUN>  
    42. * OSChina项目主页: <http://git.oschina.net/onecoder/shurnim-storage><br>  
    43. OSChina上的会持续更新。  
    44.   
    45. 另外你也可以通过OSChina的Maven库获取依赖,或者自己编译jar包。  
    46.   
    47. * maven  
    48.   
    49.      1. 加入OSC仓库  
    50.      
    51.                     <repositories>  
    52.                       <repository>  
    53.                            <id>nexus</id>  
    54.                            <name>local private nexus</name>  
    55.                            <url>http://maven.oschina.net/content/groups/public/</url>  
    56.                            <releases>  
    57.                                 <enabled>true</enabled>  
    58.                            </releases>  
    59.                            <snapshots>  
    60.                                 <enabled>false</enabled>  
    61.                            </snapshots>  
    62.                       </repository>  
    63.                  </repositories>  
    64.   
    65.      2. 加入依赖  
    66.      
    67.                <dependency>  
    68.                  <groupId>com.coderli</groupId>  
    69.                  <artifactId>shurnim-storage</artifactId>  
    70.                   <version>0.1-alpha</version>  
    71.                </dependency>  
    72. * Gradle 编译Jar  
    73.   
    74. 在项目目录执行  
    75.      
    76.      gradle jar  
    77.      
    78. <a name="开发插件"></a>  
    79. ### 开发插件  
    80.   
    81. 在*shurnim-storage*中,插件就像一块一块的积木,不但支撑着框架的功能,也是框架可扩展性的基石。开发一个插件,仅需两步:  
    82.   
    83. 1. 实现PluginAPI接口  
    84.   
    85. ```  
    86. package com.coderli.shurnim.storage.plugin;  
    87.   
    88. import java.io.File;  
    89. import java.util.List;  
    90.   
    91. import com.coderli.shurnim.storage.plugin.model.Resource;  
    92.   
    93. /**  
    94. * 各种云存储插件需要实现的通用接口  
    95. *  
    96. * @author OneCoder  
    97. * @date 2014年4月22日 下午9:43:41  
    98. * @website http://www.coderli.com  
    99. */  
    100. public interface PluginAPI {  
    101.   
    102.      /**  
    103.       * 初始化接口  
    104.       *  
    105.       * @author OneCoder  
    106.       * @date 2014年5月19日 下午10:47:40  
    107.       */  
    108.      void init();  
    109.   
    110.      /**  
    111.       * 获取子资源列表  
    112.       *  
    113.       * @param parentPath  
    114.       * @return  
    115.       * @author OneCoder  
    116.       * @date 2014年4月24日 下午11:29:14  
    117.       */  
    118.      List<Resource> getChildResources(String parentPath);  
    119.   
    120.      /**  
    121.       * 下载特定的资源  
    122.       *  
    123.       * @param parentPath  
    124.       *            目录路径  
    125.       * @param name  
    126.       *            资源名称  
    127.       * @param storePath  
    128.       *            下载资源保存路径  
    129.       * @return  
    130.       * @author OneCoder  
    131.       * @date 2014年4月24日 下午11:30:19  
    132.       */  
    133.      Resource downloadResource(String parentPath, String name, String storePath);  
    134.   
    135.      /**  
    136.       * 创建文件夹  
    137.       *  
    138.       * @param path  
    139.       *            文件夹路径  
    140.       * @param auto  
    141.       *            是否自动创建父目录  
    142.       * @return  
    143.       * @author OneCoder  
    144.       * @date 2014年5月15日 下午10:10:04  
    145.       */  
    146.      boolean mkdir(String path, boolean auto);  
    147.   
    148.      /**  
    149.       * 上传资源  
    150.       *  
    151.       * @param parentPath  
    152.       *            父目录路径  
    153.       * @param name  
    154.       *            资源名称  
    155.       * @param uploadFile  
    156.       *            待上传的本地文件  
    157.       * @return  
    158.       * @author OneCoder  
    159.       * @date 2014年5月15日 下午10:40:13  
    160.       */  
    161.      boolean uploadResource(String parentPath, String name, File uploadFile);  
    162. }  
    163. ```  
    164.   
    165. 目前插件的接口列表仅为同步资源设计,如果想要支持更多操作(如删除,查找等),可扩展该接口定义。<br/><br/>  
    166. 接口中,所有的参数和返回值均为*shurnim-storage*框架中定义的通用模型。因此,您在开发插件过程中需要将特定SDK中的模型转换成接口中提供的模型。<br/><br/>  
    167. 插件实现类只要与*shurnim-storage*工程在同一个classpath即可使用。您既可以直接在源码工程中开发插件,就如工程里提供的*upyun*和*qiniu*插件一样,也可以作为独立工程开发,打成jar,放置在同一个classpath下。<br/><br/>  
    168. *upyun*插件样例(功能不完整):  
    169.   
    170. ```    
    171. package com.coderli.shurnim.storage.upyun.plugin;  
    172.   
    173. import java.io.File;  
    174. import java.util.List;  
    175.   
    176. import com.coderli.shurnim.storage.plugin.AbstractPluginAPI;  
    177. import com.coderli.shurnim.storage.plugin.model.Resource;  
    178. import com.coderli.shurnim.storage.plugin.model.Resource.Type;  
    179. import com.coderli.shurnim.storage.upyun.api.UpYun;  
    180.   
    181. public class UpYunPlugin extends AbstractPluginAPI {  
    182.   
    183.      private UpYun upyun;  
    184.      private String username;  
    185.      private String password;  
    186.      private String bucketName;  
    187.   
    188.      public UpYun getUpyun() {  
    189.           return upyun;  
    190.      }  
    191.   
    192.      public void setUpyun(UpYun upyun) {  
    193.           this.upyun = upyun;  
    194.      }  
    195.   
    196.      public String getUsername() {  
    197.           return username;  
    198.      }  
    199.   
    200.      public void setUsername(String username) {  
    201.           this.username = username;  
    202.      }  
    203.   
    204.      public String getPassword() {  
    205.           return password;  
    206.      }  
    207.   
    208.      public void setPassword(String password) {  
    209.           this.password = password;  
    210.      }  
    211.   
    212.      public String getBucketName() {  
    213.           return bucketName;  
    214.      }  
    215.   
    216.      public void setBucketName(String bucketName) {  
    217.           this.bucketName = bucketName;  
    218.      }  
    219.   
    220.      /*  
    221.       * (non-Javadoc)  
    222.       *  
    223.       * @see  
    224.       * com.coderli.shurnim.storage.plugin.PluginAPI#getChildResources(java.lang  
    225.       * .String)  
    226.       */  
    227.      @Override  
    228.      public List<Resource> getChildResources(String parentPath) {  
    229.           return null;  
    230.      }  
    231.   
    232.      /*  
    233.       * (non-Javadoc)  
    234.       *  
    235.       * @see  
    236.       * com.coderli.shurnim.storage.plugin.PluginAPI#downloadResource(java.lang  
    237.       * .String, java.lang.String, java.lang.String)  
    238.       */  
    239.      @Override  
    240.      public Resource downloadResource(String parentPath, String name,  
    241.                String storePath) {  
    242.           File storeFile = new File(storePath);  
    243. //          if (!storeFile.exists()) {  
    244. //               try {  
    245. //                    storeFile.createNewFile();  
    246. //               } catch (IOException e) {  
    247. //                    e.printStackTrace();  
    248. //               }  
    249. //          }  
    250.           String filePath = getFullPath(parentPath, name);  
    251.           upyun.readDir("/api");  
    252.           if (upyun.readFile(filePath, storeFile)) {  
    253.                Resource result = new Resource();  
    254.                result.setName(name);  
    255.                result.setPath(parentPath);  
    256.                result.setType(Type.FILE);  
    257.                result.setLocalFile(storeFile);  
    258.                return result;  
    259.           }  
    260.           return null;  
    261.      }  
    262.   
    263.      String getFullPath(String parentPath, String name) {  
    264.           if (!parentPath.endsWith(File.separator)) {  
    265.                parentPath = parentPath + File.separator;  
    266.           }  
    267.           return parentPath + name;  
    268.      }  
    269.   
    270.      /*  
    271.       * (non-Javadoc)  
    272.       *  
    273.       * @see com.coderli.shurnim.storage.plugin.PluginAPI#mkdir(java.lang.String,  
    274.       * boolean)  
    275.       */  
    276.      @Override  
    277.      public boolean mkdir(String path, boolean auto) {  
    278.           // TODO Auto-generated method stub  
    279.           return false;  
    280.      }  
    281.   
    282.      /*  
    283.       * (non-Javadoc)  
    284.       *  
    285.       * @see  
    286.       * com.coderli.shurnim.storage.plugin.PluginAPI#uploadResource(java.lang  
    287.       * .String, java.lang.String, java.io.File)  
    288.       */  
    289.      @Override  
    290.      public boolean uploadResource(String parentPath, String name,  
    291.                File uploadFile) {  
    292.           // TODO Auto-generated method stub  
    293.           return false;  
    294.      }  
    295.   
    296.      /*  
    297.       * (non-Javadoc)  
    298.       *  
    299.       * @see com.coderli.shurnim.storage.plugin.AbstractPluginAPI#init()  
    300.       */  
    301.      @Override  
    302.      public void init() {  
    303.           upyun = new UpYun(bucketName, username, password);  
    304.      }  
    305.   
    306. }  
    307. ```  
    308.   
    309.   
    310. 2. 编写插件配置文件  
    311.   
    312. ```  
    313. <?xml version="1.0" encoding="UTF-8"?>  
    314. <plugin>  
    315.      <id>qiniu</id>  
    316.      <name>七牛云存储</name>  
    317.      <api>  
    318.           <className>com.coderli.shurnim.storage.qiniu.QiniuPlugin</className>  
    319.           <params>  
    320.                <param name="access_key" displayName="ACCESS_KEY">EjREKHI_GFXbQzyrKdVhhXrIRyj3fRC1s9UmZPZO  
    321.                </param>  
    322.                <param name="secret_key" displayName="SECRET_KEY">88NofFWUvkfJ6T6rGRxlDSZOQxWkIxY2IsFIXJLX  
    323.                </param>  
    324.                <param name="bucketName" displayName="空间名">onecoder  
    325.                </param>  
    326.           </params>  
    327.      </api>  
    328. </plugin>  
    329. ```  
    330.    * **id** 为该插件在*shurnim-storage*框架下的唯一标识,不可重复,必填。  
    331.     * **name** 为显示值,为UI开发提供可供显示的有语义的值。  
    332.     * **className** 为插件接口实现类的完整路径。必填  
    333.     * **params/param** 为插件需要用户配置的参数列表。其中  
    334.          * *name* 代表参数名,需要与接口实现类中的参数名严格一致,且必须有相应的set方法的格式要求严格,即set+首字母大写的参数名。例如:setAccess_key(String arg); 目前只支持*String*类型的参数。  
    335.          * *displayName* 为参数显示名,同样是为了UI开发的考虑,方便用户开发出可根据参数列表动态显示的UI界面。  
    336.          * 参数的值可以直接配置在配置文件中,也可以在运行期动态赋值。直接配置值,对于直接使用后端接口来说较为方便。对于UI开发来说,运行期动态赋值更为合理。<br/></br>  
    337.   
    338.      在使用源码工程时,插件配置文件统一放置在工程的*plugins*目录下。你也可以统一放置在任何位置。此时,在构造后端接口实例时,需要告知接口该位置。  
    339.      
    340. <a name="使用ShurnimStorage接口"></a>  
    341. ### 使用*ShurnimStorage*接口  
    342.   
    343. <a name="接口介绍"></a>  
    344. #### 接口介绍  
    345.   
    346. **ShurnimStorage**接口是*shurinm-storage*框架全局的也是唯一的接口,目前定义如  
    347.   
    348. ```  
    349. package com.coderli.shurnim.storage;  
    350.   
    351. import java.util.List;  
    352. import java.util.Map;  
    353.   
    354. import com.coderli.shurnim.storage.plugin.model.Plugin;  
    355. import com.coderli.shurnim.storage.plugin.model.Resource;  
    356.   
    357. /**  
    358. * 后台模块的全局接口<br>  
    359. * 通过该接口使用后台的全部功能。<br>  
    360. * 使用方式:<br>  
    361. <li>  
    362. * 1.先通过{@link #getSupportedPlugins()}方法获取所有支持的平台/插件列表。 <li>  
    363. * 2.将列表中返回的ID传入对应的接口参数中,进行对应的平台的相关操作。<br>  
    364. * 需要注意的是,不同平台的插件需要给不同的参数赋值,该值可以直接配置在配置文件中。<br>  
    365. * 也可以在运行期动态赋值。(会覆盖配置文件中的值。)<br>  
    366. *  
    367. * 参数列表的设计,方便UI开发人员动态的根据参数列表生成可填写的控件。并给参数赋值。增强了可扩展性。  
    368. *  
    369. * @author OneCoder  
    370. * @date 2014年4月22日 下午9:21:58  
    371. * @website http://www.coderli.com  
    372. */  
    373. public interface ShurnimStorage {  
    374.   
    375.      /**  
    376.       * 获取当前支持的插件列表<br>  
    377.       * 没有支持的插件的时候可能返回null  
    378.       *  
    379.       * @return  
    380.       * @author OneCoder  
    381.       * @date 2014年5月7日 下午8:53:25  
    382.       */  
    383.      List<Plugin> getSupportedPlugins();  
    384.   
    385.      /**  
    386.       * 给指定的插件的对应参数赋值<br>  
    387.       * 此处赋值会覆盖配置文件中的默认值  
    388.       *  
    389.       * @param pluginId  
    390.       *            插件ID  
    391.       * @param paramsKV  
    392.       *            参数键值对  
    393.       * @author OneCoder  
    394.       * @date 2014年5月9日 上午12:41:53  
    395.       */  
    396.      void setParamValues(String pluginId, Map<String, String> paramsKV);  
    397.   
    398.      /**  
    399.       * 获取插件对应目录下的资源列表  
    400.       *  
    401.       * @param pluginId  
    402.       *            插件ID  
    403.       * @param path  
    404.       *            指定路径  
    405.       * @return  
    406.       * @author OneCoder  
    407.       * @date 2014年5月11日 上午8:52:00  
    408.       */  
    409.      List<Resource> getResources(String pluginId, String path);  
    410.   
    411.      /**  
    412.       * 同步资源  
    413.       *  
    414.       * @param fromPluginId  
    415.       *            待同步的插件Id  
    416.       * @param toPluginIds  
    417.       *            目标插件Id  
    418.       * @param resource  
    419.       *            待同步的资源  
    420.       * @return 同步结果  
    421.       * @author OneCoder  
    422.       * @date 2014年5月11日 上午11:41:24  
    423.       */  
    424.      boolean sycnResource(String fromPluginId, String toPluginId,  
    425.                     Resource resource) throws Exception;  
    426. }  
    427. ```      
    428.   
    429. 当前接口实际仅包含了获取资源列表*getResources*和同步资源*sycnResource*功能,*getSupportedPlugins*和*setParamValues*实际为辅助接口,在UI开发时较为有用。<br/><br/>  
    430. 同样,您也可以扩展开发该接口增加更多的您喜欢的特性。例如,同时删除给定存储上的文件。当然,这需要插件接口的配合支持。<br/><br/>  
    431.   
    432. 这里,*sycnResource*设计成插件间一对一的形式,是考虑到获取同步是否成功的结果的需求。如果您想开发一次同步到多个存储的功能,建议您重新开发您自己的接口实现类,因为默认实现会多次下次资源(每次同步后删除),造成网络资源的浪费。  
    433.   
    434. 接口的默认实现类是: **DefaultShurnimStorageImpl**  
    435.   
    436. <a name="使用样例"></a>  
    437. #### 使用样例  
    438. ```        
    439. package com.coderli.shurnim.test.shurnimstorage;  
    440.   
    441. import org.junit.Assert;  
    442. import org.junit.BeforeClass;  
    443. import org.junit.Test;  
    444.   
    445. import com.coderli.shurnim.storage.DefaultShurnimStorageImpl;  
    446. import com.coderli.shurnim.storage.ShurnimStorage;  
    447. import com.coderli.shurnim.storage.plugin.model.Resource;  
    448. import com.coderli.shurnim.storage.plugin.model.Resource.Type;  
    449.   
    450. /**  
    451. * 全局接口测试类<br>  
    452. * 时间有限,目前仅作整体接口测试。细粒度的单元测试,随开发补充。  
    453. *  
    454. * @author OneCoder  
    455. * @date 2014年5月19日 下午10:50:27  
    456. * @website http://www.coderli.com  
    457. */  
    458. public class ShurnimStorageTest {  
    459.   
    460.      private static ShurnimStorage shurnim;  
    461.   
    462.      @BeforeClass  
    463.      public static void init() {  
    464.           shurnim = new DefaultShurnimStorageImpl(  
    465.                     "/Users/apple/git/shurnim-storage-for-UPYUN/plugins");  
    466.      }  
    467.   
    468.      @Test  
    469.      public void testSycnResource() {  
    470.           Resource syncResource = new Resource();  
    471.           syncResource.setPath("/api");  
    472.           syncResource.setName("api.html");  
    473.           syncResource.setType(Type.FILE);  
    474.           try {  
    475.                Assert.assertTrue(shurnim.sycnResource("upyun", "qiniu",  
    476.                          syncResource));  
    477.           } catch (Exception e) {  
    478.                e.printStackTrace();  
    479.           }  
    480.      }  
    481. }  
    482. ```  
    483. <a name="其他"></a>  
    484. ## 其他  
    485.   
    486. 时间仓促,功能简陋,望您包涵。OneCoder(Blog:[http://www.coderli.com](http://www.coderli.com))特别希望看到该项目对您哪怕一点点的帮助。任意的意见和建议,欢迎随意与我沟通,联系方式:  
    487.   
    488. * Email: <wushikezuo@gmail.com>  
    489. * QQ:57959968  
    490. * Blog:[OneCoder](http://www.coderli.com)  
    491.   
    492. 项目的Bug和改进点,可在OSChina上以issue的方式直接提交给我。  
    效果预览:

    原文:http://www.coderli.com/write-readme-for-your-project/

  • 相关阅读:
    [leetcode] Combinations
    Binary Tree Level Order Traversal I II
    [leetcode] Remove Duplicates from Sorted Array I II
    [leetcode] Permutations II
    [leetcode] Permutations
    如何在线程间进行事件通知?
    如何实现迭代对象和迭代器对象?
    如何判断字符串a是否以字符串 b开头或者结尾?
    如何实现用户的历史记录功能(最多n条)?
    如何让字典保持有序?
  • 原文地址:https://www.cnblogs.com/xiang--liu/p/9710296.html
Copyright © 2020-2023  润新知