0%

使用js进行跳转url

将form表单的值,通过重写onclick方法重写掉原本的点击事件,重写form的onKeyDown保留点击回车跳转

1
2
3
4
5
6
7
<script language="javascript">
function rwurl(myform) {
if (myform.wd.value != "") {
window.location.href = '/search/' + myform.wd.value + '.html'
}
}
</script>

1
2
3
4
5
<form onkeydown="if (event.keyCode == 13 ) rwurl(this)" action="#">
<input class="text" autocomplete="off" type="text" id="wd" placeholder="✎... 一期一会,世当珍惜~">
<input class="button" type="button" id="search" onclick="rwurl(this.form)"
value="☯">
</form>

匹配两个字符串A与B中间的字符串包含A与B:

表达式: A.*?B(“.“表示任意字符,“?”表示匹配0个或多个)
示例: Awww.letvim.comB
结果: Awww.letvim.comB

匹配两个字符串A与B中间的字符串包含A但是不包含B:

表达式: A.*?(?=B)
示例: Awww.letvim.comB
结果: Awww.letvim.com

匹配两个字符串A与B中间的字符串且不包含A与B:

表达式: (?<=A).*?(?=B)
示例: Awww.letvim.comB
结果: www.letvim.com

简介

Elasticsearch是一个高度可扩展的开源的分布式Restful全文搜索和分析引擎。它允许用户快速的(近实时的)存储、搜索和分析海量数据。它通常用作底层引擎技术,为具有复杂搜索功能和要求的应用程序提供支持。
以下是ES可用于的一些场景:

  1. 电商网站提供搜索功能:可使用ES来存储产品的目录和库存,并为它们提供搜索和自动填充建议。
  2. 收集日志和交易数据,并进行分析:可使用Logstash来收集、聚合和解析数据, 然后让Logstash将此数据提供给ES。然后可在ES中搜索和聚合开发者感兴趣的信息。
  3. 需要快速调查、分析、可视化查询大量数据的特定问题:可以使用ES存储数据,然后使用Kibana构建自定义仪表板,来可视化展示数据。还可以使用ES的聚合功能针对这些数据进行复杂的商业分析。

安装

在Mac上可以使用brew快速安装Elasticsearch

安装Elasticsearch

brew install elasticsearch

安装位置
image.png

安装完成后可使用elasticsearch –version查看ES版本信息
image.png

执行启动命令:

elasticsearch

启动成功后,ES的默认端口是9200,可在浏览器中看到ES的基本信息

image.png

安装Kibana

Kibana是ES的一个配套工具,让用户在网页中可以直接与ES进行交互。
安装命令:

brew install kibana

安装完成后直接执行kibana命令启动Kibana
Kibana的默认端口是5601
image.png

两数之和 Two Sum

1
2
3
4
5
6
Given an array of integers, return indices of the two numbers such that they add up to a specific target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
Example:
Given nums = [2, 7, 11, 15], target = 9,
Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].

在第一次迭代中,我们将每个元素的值和它的索引添加到表中。
然后,在第二次迭代中,我们将检查每个元素所对应的目标元素(target - nums[i])是否存在于表中。
注意,该目标元素不能是 nums[i]nums[i] 本身!

1
2
3
4
5
6
7
8
9
10
11
12
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
Integer integer = map.get(target - nums[i]);
if (integer != null && integet != i) {
return new int[]{i, integer};
} else {
map.put(nums[i], i);
}
}
return null;
}

三数之和

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public List<List<Integer>> threeSum(int[] nums) {
Set<List<Integer>> result = new HashSet<>();
// 排序数组
Arrays.sort(nums);
// 固定指针k
for (int k = 0; k < nums.length - 2; k++) {
int j = nums.length - 1;
int i = k + 1;
// 当 nums[k] > 0 时直接break跳出:因为 nums[j] >= nums[i] >= nums[k] > 0,即 33 个数字都大于 00 ,在此固定指针 k 之后不可能再找到结果了。
if (nums[k] > 0) {
break;
}
// 当 k > 0且nums[k] == nums[k - 1]时即跳过此元素nums[k]:因为已经将 nums[k - 1] 的所有组合加入到结果中,本次双指针搜索只会得到重复组合。
if (k > 0 && nums[k] == nums[k - 1]) {
continue;
}
while (i < j) {
int s = nums[i] + nums[k] + nums[j];
if (s == 0) {
ArrayList<Integer> temp = new ArrayList<>();
System.out.println("" + i + j + k);
temp.add(nums[i]);
temp.add(nums[j]);
temp.add(nums[k]);
result.add(temp);
i++;
j--;
} else if (s < 0) {
i++;
} else {
j--;
}
}

}
return new ArrayList<>(result);
}

最接近的三数之和

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

public int threeSumClosest(int[] nums, int target) {
int min = Integer.MAX_VALUE;
int result = 0;
Arrays.sort(nums);

// 固定指针k
for (int k = 0; k < nums.length; k++) {
int leftLink = k + 1;
int rightLink = nums.length - 1;

while (leftLink < rightLink) {
// 三个数相加必须最接近target
int sum = nums[leftLink] + nums[rightLink] + nums[k];
int offset = Math.abs(target - sum);

if (offset <= min) {
result = sum;
min = offset;
}
if (sum > target) {
rightLink--;
} else {
leftLink++;
}

}
}
return result;
}

四数之和

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> result = new ArrayList<>();
Arrays.sort(nums);
if (nums.length < 4) {
return result;
}
int size = nums.length;
for (int i = 0; i < size - 3; i++) {
// 排序后,如果相邻两数相同,则第二个数运算的结果,是第一个数运算结果的一个子集,可以排除
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
// 如果四个数之和已经大于目标值,后面永远是不可能有解的
if (nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target) {
break;
}
// 当前数和后面最大的数相加都比目标值小,直接进入下一次循环
if (nums[i] + nums[size - 1] + nums[size - 2] + nums[size - 3] < target) {
continue;
}
for (int j = i + 1; j < size - 2; j++) {
//去重
if (j > i + 1 && nums[j] == nums[j - 1]) {
continue;
}
int leftLink = j + 1;
int rightLink = size - 1;
while (leftLink < rightLink) {
int sum = nums[leftLink] + nums[rightLink] + nums[i] + nums[j];
if (sum == target) {
result.add(Arrays.asList(nums[i], nums[j], nums[leftLink], nums[rightLink]));
while (leftLink < rightLink && nums[rightLink] == nums[--rightLink]) ;
while (leftLink < rightLink && nums[leftLink] == nums[++leftLink]) ;

} else if (sum > target) {
// 右指针向左移动
while (leftLink < rightLink && nums[rightLink] == nums[--rightLink]) ;

} else {
// 左指针向右移动
while (leftLink < rightLink && nums[leftLink] == nums[++leftLink]) ;
}
}

}
}
return result;

}

从JDK 1.2版本开始,对象的引用被划分为4种级别,从而使程序能更加灵活地控制对象的生命周期。这4种级别由高到低依次为:强引用、软引用、弱引用和虚引用。

主要是用于给GC回收而使用,软引用和弱引用多用于处理缓存方面,如ThreadLocal
持有的map对象就是属于弱引用,在GC的时候会自动回收以免出现OOM的异常。

四种类型

强引用:无论啥情况下,只要持有就不会被回收
软引用:内存不足时引用对象可被虚拟机回收,但是system.gc对其无效
弱引用:同软引用,在对象没有其他引用的情况下,调用system.gc对象可被虚拟机回收
虚引用:就只是一个标识,对象的生命周期不受期影响

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
public class TestReference {
private Integer _10M = 1024 * 10;
private Integer _1M = 1024;

/**
* 强引用的资源回收情况
* 因为不会被GC,最终会引发OOM
* ![](http://pic.ztianzeng.com/20190918151513.png)
*/
public void testStrongReference() {
ArrayList<byte[]> strongList = new ArrayList<>();
try {
while (true) {
strongList.add(new byte[_1M]);
Thread.sleep(2);
}
} catch (OutOfMemoryError | InterruptedException e) {
e.printStackTrace();
}
}

/**
* 弱引用
* 这种永远不会内存溢出,因为一旦发现了只具有弱引用的对象,GC时不管当前内存空间足够与否,都会回收它的内存
* ![](http://pic.ztianzeng.com/20190918141112.png)
*/
public void testWeakReference() {
ArrayList<WeakReference<byte[]>> strongList = new ArrayList<>();
try {
while (true) {
strongList.add(new WeakReference<>(new byte[_10M]));
}
} catch (OutOfMemoryError e) {
e.printStackTrace();
}
}

/**
* 软引用,内存不足时回收
* 这种永远不会内存溢出,因为一旦发现了只具有弱引用的对象,只有在当前内存空间不够了,才会回收它的内存
* ![](http://pic.ztianzeng.com/20190918161245.png)
*/
public void testSoftReference() {
ArrayList<SoftReference<byte[]>> strongList = new ArrayList<>();
try {
while (true) {
strongList.add(new SoftReference<>(new byte[_10M]));
}
} catch (OutOfMemoryError e) {
e.printStackTrace();
}
}

/**
* 虚引用
* 虚引用必须和引用队列联合使用。
* 当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。
*/
public void testPhantomReference() {
ArrayList<PhantomReference<byte[]>> strongList = new ArrayList<>();
ReferenceQueue queue = new ReferenceQueue();
System.out.println(queue.poll() == null);
try {
while (true) {
strongList.add(new PhantomReference<>(new byte[_10M], queue));
}
} catch (OutOfMemoryError e) {
e.printStackTrace();
}
System.out.println(queue.poll() == null);
}

public static void main(String[] args) {
TestReference t = new TestReference();
t.testPhantomReference();
}
}

Linux crontab是用来定期执行程序的命令

linux任务调度的工作主要分为以下两类:

  1. 系统执行的工作:系统周期性所要执行的工作,如备份系统数据、清理缓存
  2. 个人执行的工作:某个用户定期要做的工作,例如每隔10分钟检查邮件服务器是否有新信,这些工作可由每个用户自行设置

crontab服务状态

1
2
3
4
5
sudo service crond start     #启动服务
sudo service crond stop #关闭服务
sudo service crond restart #重启服务
sudo service crond reload #重新载入配置
sudo service crond status #查看服务状态

语法

crontab [ -u user ] file 或 `crontab [ -u user ] { -l | -r | -e }

  • 查看crontab定时任务 crontab -l
  • 编辑定时任务【删除-添加-修改】 crontab -e

crontab配置文件位置

  • /var/spool/cron/ 该目录下存放的是每个用户(包括root)的crontab任务,文件名以用户名命名
  • /etc/cron.d/ 这个目录用来存放任何要执行的crontab文件或脚本。
  • /etc/crontab 这个文件负责安排由系统管理员制定的维护系统以及其他任务的crontab。

    crontab时间配置

    1
    2
    3
    4
    5
    6
    7
    # .---------------- minute (0 - 59) 每分钟
    # | .------------- hour (0 - 23) 每小时
    # | | .---------- day of month (1 - 31) 每天
    # | | | .------- month (1 - 12) OR jan,feb,mar,apr ... 每月
    # | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat 每周
    # | | | | |
    # * * * * * user-name command to be executed

基于SpringBoot引入依赖

1
2
3
4
 <dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>

JSR 303规范

空检查

注解 详情
@Null 验证对象是否为null
@NotNull 验证对象是否不为null, 无法查检长度为0的字符串
@NotBlank 检查约束字符串是不是Null还有被Trim的长度是否大于0,只对字符串,且会去掉前后空格.
@NotEmpty 检查约束元素是否为NULL或者是EMPTY.

Booelan检查

注解 详情
@AssertTrue 验证 Boolean 对象是否为 true
@AssertFalse 验证 Boolean 对象是否为 false

长度检查

注解 详情
@Size(min=, max=) 验证对象(Array,Collection,Map,String)长度是否在给定的范围之内
@Length(min=, max=) Validates that the annotated string is between min and max included.

日期检查

注解 详情
@Past 验证 Date 和 Calendar 对象是否在当前时间之前,验证成立的话被注释的元素一定是一个过去的日期
@Future 验证 Date 和 Calendar 对象是否在当前时间之后 ,验证成立的话被注释的元素一定是一个将来的日期
@Pattern 验证 String 对象是否符合正则表达式的规则,被注释的元素符合制定的正则表达式,regexp:正则表达式 flags: 指定 Pattern.Flag 的数组,表示正则表达式的相关选项。

数值检查

建议使用在Stirng,Integer类型,不建议使用在int类型上,因为表单值为“”时无法转换为int,但可以转换为Stirng为”“,Integer为null

注解 详情
@Min 验证 Number 和 String 对象是否大等于指定的值
@Max 验证 Number 和 String 对象是否小等于指定的值
@DecimalMax 被标注的值必须不大于约束中指定的最大值. 这个约束的参数是一个通过BigDecimal定义的最大值的字符串表示.小数存在精度
@DecimalMin 被标注的值必须不小于约束中指定的最小值. 这个约束的参数是一个通过BigDecimal定义的最小值的字符串表示.小数存在精度
@Digits 验证 Number 和 String 的构成是否合法
@Digits(integer=,fraction=) 验证字符串是否是符合指定格式的数字,interger指定整数精度,fraction指定小数精度。
@Range(min=, max=) 被指定的元素必须在合适的范围内
@Valid 递归的对关联对象进行校验, 如果关联对象是个集合或者数组,那么对其中的元素进行递归校验,如果是一个map,则对其中的值部分进行校验.(是否进行递归验证)
@CreditCardNumber 信用卡验证
@Email 验证是否是邮件地址,如果为null,不进行验证,算通过验证。
@ScriptAssert(lang= ,script=, alias=) 指定校验方法
@URL(protocol=,host=, port=,regexp=, flags=) 校验URL

校验工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/**
* 校验参数
*
*/
public class VerifyUtils {

/**
* 使用Validator框架校验类
*
* @param detail 要校验的类
* @param exception 是否直接抛出异常
* @return 校验失败的字段。。只会返回其中一个
*/
public static <T> String verifyObject(T detail, boolean exception) {
String res = verifyObject(detail);
if (exception) {
if (StringUtils.isNotBlank(res)) {
throw new Exception(ResultCode.PRECONDITION_CHECK_ERROR, res);
}
}
return res;
}

/**
* 使用Validator框架校验类
*
* @param detail 要校验的类
* @return 校验失败的字段。。只会返回其中一个
*/
public static <T> String verifyObject(T detail) {
ValidatorFactory vf = Validation.buildDefaultValidatorFactory();
Validator validator = vf.getValidator();
Set<ConstraintViolation<T>> set = validator.validate(detail);
for (ConstraintViolation<T> constraintViolation : set) {
return constraintViolation.getPropertyPath().toString() + constraintViolation.getMessage();
}
return null;
}

}

Controller

在Controller中开启,需要在controller上加上@Validated注解。

1
2
3
4
5
6
7
8
9
10
11
12
import javax.validation.Valid;
import org.springframework.validation.annotation.Validated;

@RestController
@RequestMapping("/test")
@Validated
public class TestController{

public void createProcess(@RequestBody @Valid TestParam param) {

}
}

在校验不通过时会抛出MethodArgumentNotValidException异常,可使用@ExceptionHandler对这种参数异常统一返回结果

阿里云OSS在访问资源文件的时候,必须的指定到具体的资源文件中,比如访问 www.abc.com/a/ ,必须指定为 www.abc.com/a/index.html.

Next主题目前不支持这种配置,只能够更改源码实现这种功能。

环境版本

1
2
3
Hexo: 3.8.0

hexo-theme-next: 7.4.0

标签云

修改 \node_modules\hexo\lib\plugins\helper\tagcloud.js

1
2
3
4
result.push(
修改前:`<a href="${self.url_for(tag.path)} " style="${style}">${transform ? transform(tag.name) : tag.name}</a>`
修改后:`<a href="${self.url_for(tag.path)}index.html" style="${style}">${transform ? transform(tag.name) : tag.name}</a>`
);

菜单跳转

修改主题配置文件中的 menu 项目,把菜单地址加上 index.html

1
2
3
4
5
6
menu:
home: / || home
archives: /archives/index.html || archive
categories: /categories/index.html || th
tags: /tags/index.html || tags
about: /about/index.html || user

文章标签

修改 \themes\next\layout_macro\post.swig

1
2
3
4
5
6

修改前:#}<a href="{{ url_for(cat.path) }}" itemprop="url" rel="index">{#
修改后:#}<a href="{{ url_for(cat.path) }}index.html" itemprop="url" rel="index">{#

修改前:<a href="{{ url_for(tag.path) }}" rel="tag"><i class="fa fa-tag"></i> {{ tag.name }}</a>
修改后:<a href="{{ url_for(tag.path) }}index.html" rel="tag"><i class="fa fa-tag"></i> {{ tag.name }}</a>

分页链接

修改 \node_modules\hexo\lib\plugins\helper\paginator.js

1
2
修改前:const link = i => this.url_for(i === 1 ? base : base + format.replace('%d', i));
修改后:const link = i => this.url_for(i === 1 ? base : base + format.replace('%d', i)) + 'index.html';

分类链接

\node_modules\hexo\lib\plugins\helper\list_categories.js

1
2
修改前: const { style = 'list', transform, separator = ', ', suffix = '' } = options;
修改后: const { style = 'list', transform, separator = ', ', suffix = 'index.html' } = options;

标签链接

\node_modules\hexo\lib\plugins\helper\list_categories.js

1
2
修改前: const { style = 'list', transform, separator = ', ', suffix = '' } = options;
修改后: const { style = 'list', transform, separator = ', ', suffix = 'index.html' } = options;

使用Docker对Mysql进行升级

因为公司是使用docker对mysql进行安装,所以只要将原本的版本号替换掉就行

原有:docker-compose.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
version: '2'
services:
mysql:
image: mysql:5.6.37
container_name: mysql
restart: always
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: 123456
volumes:
- /etc/localtime:/etc/localtime
- ./conf:/etc/mysql/conf.d
- /data/mysql/data:/var/lib/mysql

修改成:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
version: '2'
services:
mysql:
image: mysql:5.7.18
container_name: mysql
restart: always
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: 123456
volumes:
- /etc/localtime:/etc/localtime
- ./conf:/etc/mysql/conf.d
- /data/mysql/data:/var/lib/mysql

然后使用docker-compose restart就行。

启动成功后,使用 Native连接数据库 会报系统表找不到的错误

Native table ‘performance_schema’.’events_statements_summary_by_program’ has the wrong structure

需要到容器中更新系统表

进入到容器当中,执行 mysql_upgrade -u root -p –force,再重启docker容器

1
2
3
4
docker exec -it mysql bash 

# 进容器后执行
mysql_upgrade -u root -p --force

这样就完成了mysql的升级

Java的多态是如何实现的

多态概念

一个对象变量可以指示多种实际类型的现象称为多态。
允许不同类的对象对同一消息做出响应。方法的重载、类的覆盖正体现了多态。

多态分为两种:编译时多态和运行时多态。
方法的重载就是编译时多态的一种体现,编译时多态在编译的时候就知道自己要调用的是什么方法。与之不同的这是运行时多态,也就是在编译的过程中是不知道需要调用的是哪个方法,只有在实际执行的过程中才能能够知道。

多态实现

多态通常有两种实现方法,一个是子类继承父类(子类重写父类的方法),另一种则是类实现接口。在使用时,声明的总是父类类型或接口类型,创建的是实际类型。

多态在JVM中是怎么做的

无论是什么类执行,都需要将类加载进JVM中才能够执行。

根据Java虚拟机规范中,定义的调用方法的指令有四个:

  • invokestatic: 调用静态方法。
  • invokespecial: 调用超类的构造方法,实例初始化方法,私有方法。
  • invokesvirtual: 调用实例方法。
  • invokeinterface: 调用接口方法。

前两个是静态的,后两个是进行动态调用的。

有A、B三个类,A是B的父类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class A {
void print() {
System.out.println("I am A");
}
public void print2() {
System.out.println("I am A2");
}
}
public class B extends A{
@Override
public void print() {
System.out.println("I am B");
}
}

执行,则会打印出”I am B” “I am A2”

1
2
3
A b = new B();
b.print();
b.print2();

通过classpy解析main方法:

00:创建B的对象并压入栈顶
03:复制栈顶数值B并将复制值压入栈顶
04:执行B的构造函数
07:栈顶引用数值B存入第二个局部变量
08:将第二个局部变量B推送到栈顶
09:调用invokevirtual执行B的print方法
12:再将第二个局部变量B推送到栈顶
13:调用invokevirtual执行B的print2方法

在invokevirtual执行的过程中假设在当前的变量中没有寻找到对应的方法,会到其父类上寻找,直到找到Object中,如果都没有则抛出AbstractMethodError.

如果将A换成接口Interface的话,解析出来的class则是这样的:

最大的区别则是09那步,从invokevirtual变成了invokeinterface,invokeinterface与invokevirtual相比就是无法确定方法在方法表中的位置,invokevirtual的偏移量是固定的,invokeinterface由于无法得知方法的具体位置,则需要通过查找来找到需要执行的方法。

每种虚拟机查找的方法都个有不同,因此,在性能上,调用接口引用的方法通常总是比调用类的引用的方法要慢。所以采用有接口的设计并不总是正确。