BULLETIN

Welcome to my website

公告: 网站正在建设中!!!

BLOG

一、题目描述: 给定一个无重复元素的有序整数数组 nums 。 返回 恰好覆盖数组中所有数字 的 最小有序 区间范围列表。也就是说,nums 的每个元素都恰好被某个区间范围所覆盖,并且不存在属于某个范围但不属于 nums 的数字 x 。 列表中的每个区间范围 [a,b] 应该按如下格式输出: - "a->b" ,如果 a != b - "a" ,如果 a == b 示例 示例 1: >输入:nums = [0,1,2,4,5,7] 输出:["0->2","4->5","7"] 解释:区间范围是: [0,2] --> "0->2" [4,5] --> "4->5" [7,7] --> "7" 示例 2: >输入:nums = [0,2,3,4,6,8,9] 输出:["0","2->4","6","8->9"] 解释:区间范围是: [0,0] --> "0" [2,4] --> "2->4" [6,6] --> "6" [8,9] --> "8->9" 示例 3: >输入:nums = [] 输出:[] 示例 4: >输入:nums = [-1] 输出:["-1"] 示例 5: >输入:nums = [0] 输出:["0"] 提示: >0 <= nums.length <= 20 -231 <= nums[i] <= 231 - 1 nums 中的所有值都 互不相同 nums 按升序排列 二、解答 分析 解题思路: 1. 遍历整个数组,当相邻的数只相差1时,构成一个区间。 2. 当相邻的数相差大于1时,开始一个新的区间。 3. 当判断开始一个新的区间时,我们需要保存前面的区间。 4. 保存一个区间需要两个值分别记录区间开始的值,当前数的前一个数的值。 5. 唯一值得注意的是处理边界问题。 >时间复杂度:O(n),其中 n 为数组的长度。我们只需要遍历一次数组即可。 空间复杂度:O(1)。只需要常数空间存放若干变量。 代码 ```cpp class Solution { public List<String> summaryRanges(int[] nums) { int length = nums.length; List<String> result = new ArrayList<>(); if(length == 0){ return result; } int start = nums[0]; int now = nums[0]; int i = 1; for(;i < length;i++){ if(now + 1 == nums[i]){ now++; } else{ result.add(start == now?String.valueOf(start):start+"->"+now); start = now = nums[i]; } } result.add(start == now?String.valueOf(start):start+"->"+now); return result; } } ``` > 执行用时:7 ms, 在所有 Java 提交中击败了82.54%的用户 内存消耗:36.9 MB, 在所有 Java 提交中击败了53.76%的用户 改进 1. 因为当前数的前一个数的值,我可以通过当前的下标来获取,所以该值完全没有必要记录,所以可以省略该值 2. 省略该值之后,我只要通过下标来判断即可,所以在循环里,我只要判断前一个数加一与当前值不相等即可 ```java public List<String> summaryRanges(int[] nums) { int length = nums.length; List<String> result = new ArrayList<>(); if(length == 0){ return result; } int start = nums[0]; int i = 1; for(;i < length;i++){ if(nums[i - 1] + 1 != nums[i]){ result.add(start == nums[i - 1]?String.valueOf(start):start+"->"+nums[i - 1]); start = nums[i]; } } result.add(start == nums[i - 1]?String.valueOf(start):start+"->"+nums[i - 1]); return result; } ``` 这样做的好处就是节省了一定的空间。 三、官方解答 官方给出的题解也是一次遍历,但是是用双指针的方法,也就是使用维护下标low 和 high 分别记录区间的起点和终点,和我的大致思想也差不多。 ```cpp class Solution { public List<String> summaryRanges(int[] nums) { List<String> ret = new ArrayList<String>(); int i = 0; int n = nums.length; while (i < n) { int low = i; i++; while (i < n && nums[i] == nums[i - 1] + 1) { i++; } int high = i - 1; StringBuffer temp = new StringBuffer(Integer.toString(nums[low])); if (low < high) { temp.append("->"); temp.append(Integer.toString(nums[high])); } ret.add(temp.toString()); } return ret; } } ``` > 参考: > 1、[题目](https://leetcode-cn.com/problems/summary-ranges/) > 2、[官方解答](https://leetcode-cn.com/problems/summary-ranges/solution/hui-zong-qu-jian-by-leetcode-solution-6zrs/) >本文首发于CSDN,作者:lomtom 原文链接:**[https://blog.csdn.net/lomtom/article/details/112306554](https://blog.csdn.net/lomtom/article/details/112306554)** 个人网站:**[https://lomtom.top](https://lomtom.top)**,公众号:**博思奥园**,同步更新。 你的支持就是我最大的动力。 ![](https://img-blog.csdnimg.cn/20200405094243147.png)

2021-01-10

一、题目描述: 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。 注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 示例 示例 1: > **输入:** [7,1,5,3,6,4] 输出: 7 > **解释:** 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 =5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 > 随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。 示例 2: > **输入:** [1,2,3,4,5] 输出: 4 > **解释:** 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 > 注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。 > 因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。 示例 3: > **输入:** [7,6,4,3,1] 输出: 0 > **解释:** 在这种情况下, 没有交易完成, 所以最大利润为 0。 提示: > 1 <= prices.length <= 3 * 10 ^ 4 > 0 <= prices[i] <= 10 ^ 4 二、解答 分析 整个算法的精髓就是:**在最低点买入,在最高点卖出。** 恩,这钱真好赚。 而我们要做的就是找出n天当中的低谷和高谷。 例如七天中:7,1,5,3,6,4,找出低谷:1、3,高谷:5、6 ![](https://img-blog.csdnimg.cn/20201108183309769.pngpic_center) 所以,问题可以继续抽象成,我在数组中找到极小值与极大值 最终,我们可以用后一个是否比前一个小来判断,如果小我就卖出,并且在后一天买入。 这样带来的问题是,如果我最后持续上升 那么我就没办法卖出了(因为我通过后一天是否比前一天小来判断是否卖出),所以在最后再卖出一次。 >时间复杂度:O(n),其中 n 为数组的长度。我们只需要遍历一次数组即可。 空间复杂度:O(1)。只需要常数空间存放若干变量。 代码 ```cpp class Solution { public int maxProfit(int[] prices) { int sum = 0; int length = prices.length; if(length == 0){ return 0; } int temp = prices[0]; int i = 1; for(;i < prices.length;i++){ //后一天是否比前一天小 if(prices[i] < prices[i - 1]){ //计算获得的利润 sum += prices[i - 1] - temp; //重新买入 temp = prices[i]; } } //再卖出一次 sum += prices[i - 1] - temp; return sum; } } ``` > 执行用时:1 ms, 在所有 Java 提交中击败了99.54%的用户 > 内存消耗:38 MB, 在所有 Java提交中击败了96.68%的用户 三、官方解答 官方有两种:一种是动态规划,另一种是贪心算法(比我的更简洁) 贪心: ```cpp class Solution { public int maxProfit(int[] prices) { int ans = 0; int n = prices.length; for (int i = 1; i < n; ++i) { ans += Math.max(0, prices[i] - prices[i - 1]); } return ans; } } ``` > 参考: > 1、[题目](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/) > 2、[官方解答](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/solution/mai-mai-gu-piao-de-zui-jia-shi-ji-ii-by-leetcode-s/)

2020-11-08

由于业务的需求,我需要将每次写好的代码编译好后,并且通过ftp工具远程传到服务器上。 但是,这样的操作带来的问题是:整个的过程变得相当的复杂。 于是,就有了这篇文章。 我们可以这样理解: 1. 当我们把代码提交到github上时 2. github发起一次请求给服务器 3. 服务器接受请求后,执行拉取git的脚本 这样就实现了整个项目的自动部署。 ![](https://img-blog.csdnimg.cn/20201028212818382.pngpic_center) 准备 你需要安装**yum、git、go** 如果你已经安装过,那么你就可以跳过相应的步骤 并且默认你会ssh秘钥配对,如果不会请翻到最后。 一、安装yum ```cpp wget http://yum.baseurl.org/download/3.2/yum-3.2.28.tar.gz tar -xvf yum-3.2.28.tar.gz touch /etc/ yum.conf cd yum-3.2.28 ./yummain.py install yum ``` 二、安装git ```cpp yum install -y git git --version ``` 三、安装Go ```cpp yum install -y golang ``` 四、安装Webhook ```cpp 1、使用go 安装 go get github.com/adnanh/webhook 2、使用apt安装 sudo apt-get install webhook ``` 开源项目地址:https://github.com/adnanh/webhook 五、配置服务器 1、在一个目录下克隆github项目 我的在/root/test下拉取项目,项目名也叫test(拉取的项目存在于/root/test/test) 2、在同级目录新建hooks.json(位于/root/test/hooks.json) >定义一些需要webhook服务的钩子。首先创建一个名为hooks.json. 此文件将包含webhook将提供的钩子数组。查看钩子定义页面,查看钩子可以包含哪些属性以及如何使用它们的详细描述。 ```cpp [ { "id": "deploy", "execute-command": "./deploy.sh", "command-working-directory": "/root/test/" } ] ``` 3、新建你要执行的shell脚本,可以直接执行看脚本是否可用`./deploy.sh` 或者 `sh deploy.sh` 这里为了测试,只有拉取,实际应该比这更复杂 delploy.sh(位于/root/test/deploy.sh) ```cpp ! /bin/bash cd /root/test/test git pull ``` 六、运行 运行webhook,默认端口9000,所以我们需要开放9000端口。 ```cpp /root/go/bin/webhook -hooks hooks.json -verbose ``` ![](https://img-blog.csdnimg.cn/20201028213213798.pngpic_center) 在浏览器中访问,控制台即可打印相应日志 这里的deploy与你上方hooks.json文件中的id一致 ```cpp http://ip:9000/hooks/deploy ``` ![](https://img-blog.csdnimg.cn/2020102821380022.pngpic_center) 七、配置github 如果上方能够测试成功,那么直接复制url到下方配置中,配置好后他会自动发起一次请求。 ![](https://img-blog.csdnimg.cn/20201028214046702.pngpic_center) 八、设置后台运行 使用nohup来使我们的webhook后台运行并且打印日志:log.txt 为存放日志的文件 ```cpp [root@master test] nohup /root/go/bin/webhook -hooks hooks.json -verbose >log.txt 2>&1& [1] 3064 ``` 九、愉快玩耍 然后你就可以在自己电脑上写代码,写好后,他自己就会部署,爽歪歪。 ![](https://img-blog.csdnimg.cn/20201028214518205.pngpic_center) > 参考: > 1、[linux下yum](https://blog.csdn.net/iamhuanggua/article/details/60140867) > 2、[git生成证书](http://www.iimt.me/article/34) >3、 [钩子自动部署](https://blog.csdn.net/enoch612/article/details/105763647) >4、[webhook](https://github.com/adnanh/webhook) >5、[linux后台运行的几种方式](https://www.cnblogs.com/zsql/p/10827587.html)

2020-10-28

**每天一个小知识**,不定期更新 ![](https://img-blog.csdnimg.cn/2020090613504011.jpg?pic_center) 一、问题 之前有人问我这样一个问题: 如果你运行下面的代码,你会得到什么? ```java Integer a = 200, b = 200; Integer c = 100, d = 100; System.out.println(a == b); System.out.println(c == d); ``` 你会得到 ```clike false true ``` 为什么 Java 中`200==200`为false,而`100==100`为true? > 答案只有一个:那就是200没有100帅气,就像正在看这篇文章的你一样没有写这篇文章的我一样帅气。 二、分析 **基本知识:我们知道,如果两个引用指向同一个对象,用`==`表示它们是相等的。如果两个引用指向不同的对象,用`==`表示它们是不相等的,即使它们的内容相同。** 因此,后面一条语句也应该是false 。 这就是它有趣的地方了。如果你看去看 Integer.java 类,你会发现有一个内部私有类,IntegerCache.java,它缓存了从-128到127之间的所有的整数对象。 所以事情就成了,所有的小整数在内部缓存,然后当我们声明类似—— ```clike Integer c = 100; ``` 的时候,它实际上在内部做的是: ```clike Integer i = Integer.valueOf(100); ``` 现在,如果我们去看valueOf()方法,我们可以看到 ```java /** * Returns an {@code Integer} instance representing the specified * {@code int} value. If a new {@code Integer} instance is not * required, this method should generally be used in preference to * the constructor {@link Integer(int)}, as this method is likely * to yield significantly better space and time performance by * caching frequently requested values. * * This method will always cache values in the range -128 to 127, * inclusive, and may cache other values outside of this range. * * @param i an {@code int} value. * @return an {@code Integer} instance representing {@code i}. * @since 1.5 */ public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); } ``` 如果值的范围在-128到127之间,它就从高速缓存返回实例。 所以… ```java Integer c = 100, d = 100; ``` 指向了同一个对象。 这就是为什么我们写 ```java System.out.println(c == d); ``` 我们可以得到true。 现在你可能会问,为什么这里需要缓存? **合乎逻辑的理由是,在此范围内的“小”整数使用率比大整数要高,因此,使用相同的底层对象是有价值的,可以减少潜在的内存占用。** 然而,通过反射API你会误用此功能。 运行下面的代码,享受它的魅力吧 ```java public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException { Class cache = Integer.class.getDeclaredClasses()[0]; //1 Field myCache = cache.getDeclaredField("cache"); //2 myCache.setAccessible(true);//3 Integer[] newCache = (Integer[]) myCache.get(cache); //4 newCache[132] = newCache[133]; //5 int a = 2; int b = a + a; System.out.printf("%d + %d = %d", a, a, b); // } ``` 三、结论 **Integer 缓存是 Java 5 中引入的一个有助于节省内存、提高性能的特性。** **Integer中有个静态内部类IntegerCache,里面有个cache[],也就是Integer常量池,常量池的大小为一个字节(-128~127)。** **这种 Integer 缓存策略仅在自动装箱的时候有用,使用构造器创建的 Integer 对象不能被缓存。(例如in3和in4)** ```java int i = 10; int i1 = 10; Integer in1 = 10; Integer in2 = 10; Integer in3 = new Integer(10); Integer in4 = new Integer(10); Integer in5 = 200; Integer in6 = 200; System.out.println(i == i1); // true System.out.println(i == in1); // true System.out.println(i == in2); // true System.out.println(i == in3); // true System.out.println(in1 == in2); // true System.out.println(in5 == in6); // false System.out.println(in1 == in3); // false System.out.println(in3 == in4); // false ``` 除此之外: - 所有整数类型的类都有类似的缓存机制: 1、有 ByteCache 用于缓存 Byte 对象 2、有 ShortCache 用于缓存 Short 对象 3、有 LongCache 用于缓存 Long 对象 - Byte,Short,Long 的缓存池范围默认都是: -128 到 127。可以看出,Byte的所有值都在缓存区中,用它生成的相同值对象都是相等的。 - 所有整型(Byte,Short,Long)的比较规律与Integer是一样的。 - 同时Character 对象也有CharacterCache 缓存 池,范围是 0 到 127。 - 除了 Integer 可以通过参数改变范围外,其它的都不行。 > [1、为什么Java中1000`==`1000为false而100`==`100为true?原文](http://www.codeceo.com/article/why-java-1000-100.html) > [2、为什么Java中1000`==`1000为false而100`==`100为true?英文](https://dzone.com/articles/why-1000-1000-returns-false-but-100-100-returns-tr) > [3、Integer缓存池(IntegerCache)及整型缓存池](https://blog.csdn.net/maihilton/article/details/80101497) 关注公众号:**博奥思园** 还是那句话:**你的支持是我前进的最大动力** ![](https://img-blog.csdnimg.cn/20200405094243147.png)

概况 在处理后端的业务逻辑是常常会涉及表单数据的提交请求,我们不仅在前端对数据进行验证,而且在后端也需要对数据进行验证,以此来保证数据的完整性,而后端对于表单数据的验证使用的最多的莫过于JSR303。 你能get到的知识点? 1、表单验证的使用 2、由于表单验证引起的异常捕获 1、引入依赖 使用JSR303,我们需要引入依赖,一般来说我们只需要引入`javax.validation`即可,但是对于一些`javax.validation`无法验证的(例如URL)我们就需要引入`hibernate`来进行验证了。 ```xml <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>2.0.1.Final</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>6.0.18.Final</version> <scope>compile</scope> </dependency> ``` 2、自定义验证规则 自定义验证规则,最方便的莫过于使用注解的方式对我们的bean进行验证,并且可以返回我们自己定义的返回消息。 JSR注释: - @NotNull –验证带注释的属性值不为 null - @AssertTrue –验证带注释的属性值为 true - @Size –验证带注释的属性值的大小介于属性 min和 max之间;可以应用于 String, Collection, Map和数组属性 - @Min – v验证带注释的属性的值不小于 value属性 - @Max –验证带注释的属性的值不大于 value属性 - @Email –验证带注释的属性是有效的电子邮件地址 一些注释接受其他属性,但是message属性是所有这些属性共有的。这是通常在相应属性的值未通过验证时呈现的消息。 在JSR中可以找到一些其他注释: - @NotEmpty –验证属性不为null或为空;可以应用于 String, Collection, Map或 Array值 - @NotBlank –只能应用于文本值,并验证该属性不是null还是空格 - @Positive和 @PositiveOrZero –适用于数值并验证其严格为正,或包含0的正数 - @Negative和 @NegativeOrZero –适用于数字值并验证其严格为负数,或包含0的负数 - @Past和 @PastOrPresent –验证日期值是过去还是现在(包括现在);可以应用于日期类型,包括Java 8中添加的日期类型 - @Future和@FutureOrPresent –验证日期值是将来的日期还是将来的日期(包括现在) ```java @Data @TableName("pms_brand") public class BrandEntity implements Serializable { private static final long serialVersionUID = 1L; /** * 品牌id */ @TableId private Long brandId; /** * 品牌名 */ @NotEmpty(message = "品牌名不能为空") private String name; /** * 品牌logo地址 */ @URL(message = "必须是一个合法的地址") private String logo; /** * 介绍 */ @NotEmpty(message = "介绍不能为空") private String descript; /** * 显示状态[0-不显示;1-显示] */ private Integer showStatus; /** * 检索首字母 */ @NotEmpty(message = "检索首字母不能为空") @Pattern(regexp = "/^[a-zA-Z]$/",message = "检索必须是一个字母") private String firstLetter; /** * 排序 */ @NotNull(message = "排序不能为空") @Min(value = 0,message = "排序的数必须大于等于零") private Integer sort; } ``` 3、校验捕获异常错误 第一种:controller捕获 在对bean进行验证后,我们需要捕获我们的验证结果。 1. @Valid:首先使用`@Valid` 为验证级联标记属性、方法参数或方法返回类型。也就是说我们使用这个注解后验证才生效。 2. BindingResult:在验证的bean后紧跟BindingResult,用于获取我们的验证结果,使用`result.hasErrors()`判断是否有异常,使用 `result.getFieldErrors()`获取验证后的详细数据 3. R:我们常常使用JSon数据来进行前后端的数据发送与接收,这里同理,该R为自定的类,如果你不想写自定义的消息类,你可以直接用JSONObject进行数据的保存。 ```java /** * 保存 */ @RequestMapping("/save") public R save(@Valid @RequestBody BrandEntity brand, BindingResult result){ Map<String,String> map = new LinkedHashMap<>(); if (result.hasErrors()){ result.getFieldErrors().forEach(item ->{ String message = item.getDefaultMessage(); String field = item.getField(); map.put(field, message); }); return R.error(400,"数据不合法").put("data",map); }else { brandService.save(brand); return R.ok(); } } ``` 第二种:统一异常捕获 所有的controller制作厂的逻辑处理,我们则需要使用一个统一的controller进行所有异常的捕获 ```csharp 1、正常的控制器处理正常的逻辑 /** * 保存 */ @RequestMapping("/save") public R save(@Valid @RequestBody BrandEntity brand){ brandService.save(brand); return R.ok(); } 2、编写一个controllerAdvice进行异常统一处理 @RestControllerAdvice("com.lomtom.mall.product.controller") public class ExceptionController { @ExceptionHandler(value = MethodArgumentNotValidException.class) public R handleValidException(MethodArgumentNotValidException e){ BindingResult result = e.getBindingResult(); Map<String,String> map = new LinkedHashMap<>(); result.getFieldErrors().forEach(item -> { String message = item.getDefaultMessage(); String field = item.getField(); map.put(field, message); }); return R.error(400, "数据不合法").put("data", map); } } ``` 第三种:统一处理配合枚举 与第二种同理,只是新增枚举统一管理异常的状态码与消息提醒,翻遍代码的修改与查看 ```csharp 1、编写枚举 public enum ExceptionEnum { DATA_EXCEPTION(400,"数据不合法"); private Integer code; private String message; ExceptionEnum(Integer code, String message) { this.code = code; this.message = message; } public Integer getCode() { return code; } public void setCode(Integer code) { this.code = code; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } } 2、与第二种唯一不同的是所有的状态码与消息提示交给枚举 return R.error(ExceptionEnum.DATA_EXCEPTION.getCode(), ExceptionEnum.DATA_EXCEPTION.getMessage()).put("data", map); ``` 4、测试 发送请求获取返回,所有的返回结果都一样,只是实现的方式稍有不同而已。 ```json { "msg": "数据不合法", "code": 400, "data": { "name": "品牌名不能为空", "descript": "介绍不能为空", "sort": "排序不能为空", "firstLetter": "检索首字母不能为空" } } ```

对于经常需要发博客的小伙伴来说,拥有一个属于自己的博客网站,听起来是不是很酷。 今天我就来告诉大家,怎么搭建一个属于自己的博客网站,我们需要的就是使用**hexo+github**来搭建我们自己博客系统。 你能学到什么? > 1. 轻松搭建自己的博客网站 > 2. hexo的基本写作 什么是Hexo? Hexo是一个快速,简单且功能强大的博客框架。相信经常用Markdown写文章的人肯定不会陌生,使用Markdown(或其他标记语言)编写帖子,然后Hexo会在几秒钟内生成带有精美主题的静态文件。 什么是github? GitHub是一个面向开源及私有软件项目的托管平台,因为只支持git作为唯一的版本库格式进行托管,故名GitHub。 GitHub于2008年4月10日正式上线,除了Git代码仓库托管及基本的 Web管理界面以外,还提供了订阅、讨论组、文本渲染、在线文件编辑器、协作图谱(报表)、代码片段分享(Gist)等功能。目前,其注册用户已经超过350万,托管版本数量也是非常之多,其中不乏知名开源项目 Ruby on Rails、jQuery、python 等。 为什么选择hexo和github - 1、全是静态文件,不需要书写自己的后台逻辑,访问速度快 - 2、免费方便,不用花一分钱就可以搭建一个自己的个人博客 - 3、可以集成很多的插件,只需要简单配置 - 4、样式多样可选,hexo有很多主题可供用户选择 - 5、自定义域名,可以绑定自己的域名 - 6、数据绝对安全,基于github的版本管理,历史版本可随意恢复 - 7、数据容易迁移 @[TOC] 一:准备 安装Hexo非常容易,并且只需要以下内容: - Node.js(至少应为Node.js 8.10,建议为10.0或更高版本) - git 如果您的计算机已经有这些,恭喜!您可以直接跳到Hexo安装步骤。 如果没有,请按照以下说明安装所有要求。 1、安装git 下载:[传送门](https://gitforwindows.org/) 2、安装NodeJs 下载:[传送门](https://nodejs.org/en/) 唯一需要注意的是请确保已选中**添加到PATH**(默认情况下已选中)。 3、查看git和node版本: ![](https://img-blog.csdnimg.cn/20200406094244672.pngpic_center) 4、安装hexo(使用npm) 使用npm i -g hexo来安装,一步到位,查看hexo版本。 ![](https://img-blog.csdnimg.cn/20200406094702576.pngpic_center) 二、搭建博客 1、创建仓库 前提是你的有一个自己的github账号,这年头,谁没有个github账号。 注意:创建一个名为username .github.io的存储库,其中username是您在GitHub上的用户名。如果您已经上传到其他存储库,请重命名该存储库。 例如我的github名字是zero028,那么我的仓库名就是zero028.github.io,因为我写这篇文章的时候,我已经创建过了,所以他会报错已存在。 ![](https://img-blog.csdnimg.cn/20200406100639644.png) 2、配置ssh 如果你要使用远程从你的电脑上传文件至你的github仓库,那么,你就需要配置ssh ``` 1、配置全局变量 git config --global user.name "你自己的名字" git config --global user.email "你自己的邮箱" 2、生成ssh密钥 ssh-keygen -t rsa -C "你自己的邮箱" ``` 将你用户目录下`.ssh/id_rsa.pub`里的全部东西粘贴到key里面,名字随便取。 `id_rsa.pub`一般windows会在`C:\Users\用户名\.ssh`目录下 ![](https://img-blog.csdnimg.cn/20200406101007236.png) 验证:输入`ssh -T git@github.com`,如果出现以下信息即为配置成功,到这里你已经成功了一大半了。 ![](https://img-blog.csdnimg.cn/20200406100816892.png) 2、博客初始化 在一个空的文件夹内打开cmd,使用`hexo init` 进行初始化,他会下载一大堆东西。 ![](https://img-blog.csdnimg.cn/20200406094947646.png) ``` 目录结构: . ├── _config.yml ├── package.json ├── scaffolds ├── source | ├── _drafts | └── _posts └── themes ``` 说明: - node_modules:是依赖包 - public:存放的是生成的页面 - scaffolds:命令生成文章等的模板 - source:用命令创建的各种文章 - themes:博客使用的主题 - _config.yml:整个博客的配置 - db.json:source解析所得到的 - package.json:项目所需模块项目的配置信息 3、博客生成 只需要三句话你就能看到你的博客 ``` 1、清除 hexo clean 2、生成 hexo g 3、启动服务 hexo server ``` ![](https://img-blog.csdnimg.cn/20200407183752387.pngpic_center) 这时候你打开,http://localhost:4000,当当当当,那么你就大功告成了。到这里,你看一下你的watch,有没有一个小时,如果超过了的话,当我前面没说(手动狗头)。 ![](https://img-blog.csdnimg.cn/2020040718383389.png) 4、上传至github 当然,如果只能自己看到,这远远是不够的,我们发博客就是为了让我们的文章能够帮助到更多人,这时候你就需要上传到github进行托管,这样别人就可以访问到你的博客,看到你的文章了。 你需要在你的根目录下的_config.yml配置 ```yml Deployment Docs: https://hexo.io/docs/deployment.html deploy: type: git repo: https://github.com/zero028/zero028.github.io.git(你自己的git) branch: master ``` 然后使用`hexo d` 或者 `hexo deploy`上传,它实现的原理就是将您的Hexo文件夹的文件推送到存储库。public/默认情况下,该文件夹不是(也不应该)上传的,请确保该.gitignore文件包含public/行。文件夹结构应与此存储库大致相似,但不包含.gitmodules文件 ``` 1、在此之前请先安装一个插件 npm install hexo-deployer-git --save 2、部署(上传到GitHub) hexo d 或者 hexo deploy ``` 最终,你可以使用你的https://username.github.io访问,例如我的是https://zero028.github.io,咦,我的怎么和你的不一样,那是我配置了域名和使用了其他的主题,如果你想知道我是怎么设置的,请持续关注,谢谢。 ![](https://img-blog.csdnimg.cn/20200407184442678.png) 三:写作 1、创建新文章 要创建新帖子或新页面,可以运行以下命令: ``` $ hexo new [layout] <title> 例如 $ hexo new hello INFO Created: D:\Projects\HEXO\text\source\_posts\hello.md ``` 他就会在`source/_posts`目录下生成一个md文件`hello.md` post是默认设置layout,但您可以提供自己的。您可以通过在中编辑`default_layout`设置来更改默认布局`_config.yml`。 2、语法 前题是文件开头的YAML或JSON块,用于配置作品的设置。使用YAML编写时,前题以三个破折号结尾,而使用JSON编写时,则以三个分号结尾。 ``` --- title: hello date: 2020-04-07 19:12:39 --- 正文。。。。。 ``` 设置及其默认值: 设置 | 描述 | 默认 --|--|-- layout| 布局 title |标题| 文件名(仅帖子) date | 发布日期| 文件创建日期 updated | 更新日期 | 文件更新日期 comments| 为帖子启用评论功能 |true tags | 标签(不适用于页面) categories| 类别(不适用于页面) permalink| 覆盖帖子的默认永久链接 keywords | 仅在meta标签和Open Graph中使用的关键字(不推荐) 分类和标签 只有帖子支持类别和标签的使用。类别按顺序应用于职位,从而导致分类和子分类的层次结构。标签均在同一层次级别上定义,因此它们的显示顺序并不重要。 例 ``` 类别: - 运动 - 棒球 标签: - 伤害 - 搏斗 - 令人震惊 ``` 如果要应用多个类别层次结构,请使用名称列表而不是单个名称。如果Hexo看到在帖子上以此方式定义的任何类别,则它将该帖子的每个类别视为其自己的独立层次结构。 例 ``` 类别: - [体育, 棒球] - [美国职棒大联盟, 美国 联盟, 波士顿 红 红袜] - [美国职棒大联盟, 美国的 同盟, 新的 纽约 洋基队] - 对抗 ``` 作者有话 嗯,确实是挺简单的,前面我花了大量的时间为自己搭建了一个博客网站,从前端到后端都是自己完成,然而,实现的也只是刚好能用而已,很多的体验都不是很完善。 而使用hexo就可以轻松搭建自己的博客,而且学习成本四舍五入为零。 最后,还是那句话,你的支持就是作者最大的动力。 关注公众号:**博奥思园** ,精彩内容不错失![](https://img-blog.csdnimg.cn/20200405094243147.png)

2020-06-25

TODAY'S SHARE

ABOUT ME

I'M LOMTOM

我不想成为一个庸俗的人。十年百年后,当我们死去,质疑我们的人同样死去,后人看到的是裹足不前、原地打转的你,还是一直奔跑、走到远方的我?

CONTACT ME

You can contact me in the following ways

Copyright © 2019-2020 Made with love By LomTom | 湘ICP备19023870号 | 经历风雨 666 天 6 小时 6 分 6 秒