IDEA 设置 Git-Bash 为默认 Terminal

IDEA 默认集成了 Terminal,但默认使用的终端确是 cmd.exeWindows10 默认则是 PowerShell)。而众所周知,Windows 在命令行上做得确实有够难用的,所以我们可以选择其他的第三方终端进行使用。

这里演示一下使用 Git-Bash 作为默认集成的终端

在设置 Settings > Tools > Terminal 下有一个 Shell path 的选择框。

在里面填写以下内容:

1
"D:\Program\cmder\vendor\git-for-windows\bin\bash.exe"  -login -i

注:这里吾辈直接使用了 cmder 内置的 Git 客户端,关于 cmder 可以参考另外一篇内容:Cmder 启动报错
而且使用 Git-Bash 的话最好确保安装的 Git 是最新版本,否则 IDEA Terminal 有可能出现光标位置偏移的错误。

字符串中的内容是本机上的 Git-Bash 的程序完全路径,后面两个参数则是为了避免在 IDEA 集成的终端下发生有中文时光标异常的问题。

Windows 下 MongoDB 便携版安装与初始化

官网

下载

下载位置

选择一个便携版本下载(.zip 结尾),例如吾辈选择的就是 win32/mongodb-win32-x86_64-2008plus-ssl-4.0.1.zip

配置环境变量

下载完成后解压到本地,将 /bin/ 目录添加环境变量 Path 中以方便使用 mongodb 的命令。

配置完成后验证一下

1
mongo -version

如果环境变量配置正确的话会有类似于下面的这种输出

1
MongoDB shell version v4.0.1

配置日志文件与数据目录

吾辈的 mongodb 的安装目录是 D:\Program\mongodb-win32-x86_64-2008plus-ssl-4.0.1,所以就在安装目录下创建数据与日志目录了。

目录列表如下:

  • mongodb_data
    • log
      • mongodb.log
    • data

指定日志文件的位置

1
mongod --logpath "D:\Program\mongodb-win32-x86_64-2008plus-ssl-4.0.1\mongodb_data\log\mongodb.log"

指定数据存放的目录

1
mongod --dbpath "D:\Program\mongodb-win32-x86_64-2008plus-ssl-4.0.1\mongodb_data\data"

输出

1
2018-08-08T22:26:35.411+0800 I CONTROL  [main] Automatically disabling TLS 1.0, to force-enable TLS 1.0 specify --sslDisabledProtocols 'none'

然后,就停住了,其实这里并未发生错误,仔细看最后一行 NETWORK [listener] connection accepted from 127.0.0.1:12598,指的是正在监听连接 127.0.0.1:12598。所以这个时候在开一个新的 cmd 标签输入 mongo 命令就进入到 mongo shell 里面玩耍啦

安装服务

每次打开都要手动输入命令指定数据目录并启动 mongod 未免麻烦,我们可以将之添加到系统服务中,以后需要的时候只要启动服务就好了,也能设置自动启动什么的了呢

1
mongod --dbpath "D:\Program\mongodb-win32-x86_64-2008plus-ssl-4.0.1\mongodb_data\data" --logpath "D:\Program\mongodb-win32-x86_64-2008plus-ssl-4.0.1\mongodb_data\log\mongodb.log" --auth --install --serviceName "MongoDB"

检查一下系统服务里面是否有 MongoDB,如果没有的话使用管理员权限打开 cmd 再执行一次上面的命令就好了,如果服务没有启动的话就启动它。

这样便安装完成了,在命令行输入 mongo 就可以啦

JavaScript 使用 fetch 上传文件

fetch 是 ES6 的一个新的特性,用来简化处理异步的 Ajax 请求。

fetch 可以参考 MDN 上的教程:https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Using_Fetch

假设后端(Java)有一个用于上传文件的接口

1
2
3
4
5
6
7
8
/**
* 上传文件
* @param imgFile
* @return
*/
@RequestMapping(value = "/uploadFile", method = RequestMethod.POST)
@ResponseBody
public OperationResult uploadFile(@RequestParam("imgFile") MultipartFile imgFile);

前端中只要使用如下代码即可上传一个文件

1
2
<!-- 这里是用来演示的 html 内容 -->
<input id="imgFile" type="file">
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
document.querySelector('#imgFile').addEventListener('change', () => {
// 创建一个 FormData 对象
const fd = new FormData()
// 得到 File 对象
const file = document.querySelector('#imgFile').files[0]
fd.append('imgFile', file)
// 这里的 url 是上传链接,此处为 /uploadFile
fetch(url, {
method: 'POST',
body: fd,
// 注:此处不需要设置 headers
})
.then(res => {
// 之后的处理
})
})

jquery ajax 的感觉差不多,不过能实现效果就好啦

JavaScript 加载全部资源后再使用

场景

客户需要一次性将视频全部缓冲完成再进行观看而非看一段缓冲一段,所以就看了一下有没有什么方法能够做到,结果顺便还写了一个通用的加载资源的方法。

实现

基本思路是使用 ajax(fetch) 将资源先加载到本地,然后生成一个本地的 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
41
42
43
/**
* 将 url 中的内容加载到元素上
* 注:domSelector 必须有 src 属性用以将加载完成的资源赋值给其,加载默认是异步的
* @param {string} url url 资源
* @param {document} domSelector dom 选择器
* @param {object} init 初始化参数, 实为 fetch() 的参数以及一些自定义的参数
* 关于 fetch 具体可以参考 <https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Using_Fetch>
* 自定义的参数有:
* before: 加载之前的方法,例如可以设置一个弹窗或者遮罩告诉用户资源正在加载中
* after: 加载完成之后的方法,例如可以设置一个加载完成的动画提醒一下用户
* error: 发生异常时的方法,例如可以设置一个错误提示通知用户加载异常需要刷新了
*/
function loadResource(url, domSelector, init) {
if (!init) {
init = {}
}
if (init.before && typeof init.before === 'function') {
init.before()
}
// 如果没有自定义缓存的话就设置缓存
init.cache = init.cache || 'force-cache';
// 如果没有自定义错误处理就设置一下错误处理
init.error = init.error || (error => console.log(`request was wrong: ${error}`));
fetch(url, init)
// 判断返回的状态是否正常
.then(rep => {
if (rep.status === 200) {
return rep;
} else {
throw new Error(`response status error ${rep.status}`);
}
})
// 转换资源
.then(data => data.blob())
.then(blob => {
// 生成一个本地的 url 并赋值给 src 属性
domSelector.src = window.URL.createObjectURL(blob);
if (init.after && typeof init.after === 'function') {
init.after();
}
})
.catch(init.error)
}

使用示例

假如有一个 video 元素需要加载视频

1
<video id="video" controls></video>

那么使用该方法的 JavaScript 代码就是

1
2
3
4
5
6
7
8
9
10
11
12
13
// 要加载的 url 资源
var url = '/html/testVideo.m4';
// 资源的容器,这里是一个视频元素
var video = document.querySelector('#video');

// 此处使用第三个参数仅为演示,不需要的话忽略即可。。。
loadResource(url, video, {
before: () => console.log('video load before'),
after: () => console.log('video load after'),
error: error => console.log(`video load error: ${error}`)
})
// 即可以:
loadResource(url, video)

注:此方法不仅可以加载视频,也可以加载 audio, img 等拥有 src 属性的二进制资源

这个方法同样也已经丢到了 GitHub Gist 上面啦

IDEA 激活

前言

目前不再更新该文章,如有需要可以使用学生认证/开源项目免费使用它。如有能力,请支持正版!这里吾辈之所以提供激活的原因在于,希望暂时没有能力的人也能使用上这个工具,绝非为了免费使用 IDEA,吾辈自己(在工作后)也早已入正。

购买凭证

使用本地注册码(不需要在线)的方式激活

注: 此方法对 IDEA 2018.01-2018.02 版本无效,但对 IDEA 2018.03 EAP 是有效的

  1. 修改 hosts 文件,Windows 系统上的位置是 C:\Windows\System32\drivers\etc\hosts,将之复制到其他位置并在文件的最末尾添加一句话。

    1
    0.0.0.0 account.jetbrains.com

    然后将 hosts 文件复制到原本的位置覆盖一下就好。

    注:该操作是必要的,因为不修改 hosts 文件的话获得的激活码是会直接提示非法的!

  2. http://idea.iteblog.com/ 获得到一个注册码(用户名和 PC 用户名保持一致),将注册码用于激活 IDEA 即可。

使用本地 Jar 文件

注:该方法适用于 IDEA 2018.01-2018.02,在 IDEA 2018.03 已经失效

  1. 下载破解 Jar:JetbrainsCrack

    然后放到一个合适的位置(你不会随意删除的位置,推荐直接放到 IDEA 的安装目录下)

  2. 修改 IDEA 的一个配置文件(位置在 ${idea.home}/bin/idea64.exe.vmoptions),在最后一行添加:-javaagent:这里是你上面下载的那个 Jar 的绝对路径

    然后在激活对话框中选 Activation code 随意输入然后点击 OK 即可。

  3. Pass:其实下面还有一步的,不过做不做都可以,运行上面的就已经完成激活了,不过激活信息显示的不是你的名字。当然,我们可以去变成自己的名字,如果我们在 Activation code 里填写合适的 json 信息的话。

    1. 首先运行刚才下载的 Jar,然后会得到一个激活信息的 json 字符串,大致是下面这样:

      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
      {
      "licenseId": "ThisCrackLicenseId",
      "licenseeName": "Rover12421",
      "assigneeName": "Rover12421",
      "assigneeEmail": "rover12421@163.com",
      "licenseRestriction": "By Rover12421 Crack, Only Test! Please support genuine!!!",
      "checkConcurrentUse": false,
      "products": [
      { "code": "II", "paidUpTo": "2099-12-31" },
      { "code": "DM", "paidUpTo": "2099-12-31" },
      { "code": "AC", "paidUpTo": "2099-12-31" },
      { "code": "RS0", "paidUpTo": "2099-12-31" },
      { "code": "WS", "paidUpTo": "2099-12-31" },
      { "code": "DPN", "paidUpTo": "2099-12-31" },
      { "code": "RC", "paidUpTo": "2099-12-31" },
      { "code": "PS", "paidUpTo": "2099-12-31" },
      { "code": "DC", "paidUpTo": "2099-12-31" },
      { "code": "RM", "paidUpTo": "2099-12-31" },
      { "code": "CL", "paidUpTo": "2099-12-31" },
      { "code": "PC", "paidUpTo": "2099-12-31" },
      { "code": "DB", "paidUpTo": "2099-12-31" },
      { "code": "GO", "paidUpTo": "2099-12-31" },
      { "code": "RD", "paidUpTo": "2099-12-31" }
      ],
      "hash": "2911276/0",
      "gracePeriodDays": 7,
      "autoProlongated": false
      }
    2. 修改其中的 licenseeName, assigneeName, assigneeEmail 为你的名字和邮箱,然后将修改后的 json 字符串丢到 Activation code 里面就好啦

IDEA 激活服务器

注: 此方法随时可能失效

使用方法

  • 在 idea 首次使用时会要求输入注册码,选择第三个选项卡,即 License Server,然后填入上面的激活服务器即可。
  • 进入 idea 后,选择 Help->Register,就会弹出一个输入注册码的窗口了,以上面那种方法输入就行啦。

使用 Spring 时进行测试

前置要求

  • Java
  • Spring/SpringMVC
  • Maven

概略

单元测试/集成测试是软件开发时重要的一项流程,而 Spring 对于测试提供了非常强大的支持。

  • 支持主流测试框架 Junit/TestNG
  • 支持在测试中使用依赖注入
  • 支持在测试中事物自动回滚
  • 支持使用各种注解增强功能

那么,测试基本上按照场景分为三种情况:

  • 普通测试:不需要使用 Spring 容器的测试(工具类)
  • Dao/Service 层测试:需要使用 Spring 容器的依赖注入
  • Web 层测试:测试对外部提供的接口

这里新建一个用来测试的项目,吾辈将之丢到了 GitHub 上面

项目链接

你也可以自己创建一个基础的 Maven 项目,项目结构应当如下:

  • /
    • src/
      • main/
        • java/
        • resources/
      • test/
        • java/
    • pom.xml

普通测试

假设吾辈有一个 SpringUtil(路径是 /src/main/java/com/rxliuli/study/springtest/util/SpringUtil.java) 工具类,想要测试怎么办呢?

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
/**
* 用于测试的字符串工具类
*
* @author rxliuli
*/
public class StringUtil {
/**
* 判断是否为空
*
* @param string 要进行判断的字符串
* @return 是否为 null 或者空字符串
*/
public static boolean isEmpty(String string) {
return string == null || string.isEmpty();

}

/**
* 判断是否为空
*
* @param string 要进行判断的字符串
* @return 是否为 null 或者空字符串
*/
public static boolean isNotEmpty(String string) {
return !isEmpty(string);
}

/**
* 判断是否有字符串为空
*
* @param strings 要进行判断的一个或多个字符串
* @return 是否有 null 或者空字符串
*/
public static boolean isAnyEmpty(String... strings) {
return Arrays.stream(strings)
.anyMatch(StringUtil::isEmpty);
}

/**
* 判断字符串是否全部为空
*
* @param strings 要进行判断的一个或多个字符串
* @return 是否全部为 null 或者空字符串
*/
public static boolean isAllEmpty(String... strings) {
return Arrays.stream(strings)
.allMatch(StringUtil::isEmpty);
}
}

首先需要引入以下依赖

  • Junit4:流行的 Java 测试框架。虽然吾辈个人更喜欢 TestNG,但 Junit 的流行度要更高一点,SpringBoot 甚至将之默认引入了,所以这里使用 Junit 框架。
  • AssertJ:流行的 Java 流畅式断言框架。Junit 也有自己的断言方法,但和 AssertJ 相比就是小巫见大巫了。
1
2
3
4
5
6
7
8
9
10
11
12
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.9.1</version>
<scope>test</scope>
</dependency>

注:生产环境中 version 应该放到 properties 节点下,这里只做演示。
此篇不对 JunitAssertJ 进行详细的讲解,如果想要入门了解参考 Junit, AssertJ

然后创建一个对应的测试类 StringUtilTest/src/test/java/com/rxliuli/study/springtest/util/SpringUtilTest.java)直接进行测试即可。

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
/**
* @author rxliuli
*/
public class StringUtilTest {
private String strNull = null;
private String strEmpty = "";
private String strSome = "str";

@Test
public void isEmpty() {
//测试 null
assertThat(StringUtil.isEmpty(strNull))
.isTrue();
//测试 empty
assertThat(StringUtil.isEmpty(strEmpty))
.isTrue();
//测试 some
assertThat(StringUtil.isEmpty(strSome))
.isFalse();
}

@Test
public void isNotEmpty() {
//测试 null
assertThat(StringUtil.isNotEmpty(strNull))
.isFalse();
//测试 empty
assertThat(StringUtil.isNotEmpty(strEmpty))
.isFalse();
//测试 some
assertThat(StringUtil.isNotEmpty(strSome))
.isTrue();
}

@Test
public void isAnyEmpty() {
assertThat(StringUtil.isAnyEmpty(strNull, strEmpty, strSome))
.isTrue();
assertThat(StringUtil.isAnyEmpty())
.isFalse();
}

@Test
public void isAllEmpty() {
assertThat(StringUtil.isAllEmpty(strNull, strEmpty, strSome))
.isFalse();
assertThat(StringUtil.isAnyEmpty(strNull, strEmpty))
.isTrue();
}
}

上面测试流程基本如下:

  • 构建出测试需要的参数(非必需)
  • 调用需要测试的方法
  • 使用 AssertJ 对得到的结果进行断言

Dao/Service 层测试

准确的说是需要使用 Spring 容器的测试,测试方法有 2 种。

  1. 手动使用 ApplicationContext 去获取 Bean 然后进行测试
  2. 使用注解自动加载 Spring 测试环境

手动使用 ApplicationContext 去获取 Bean 然后进行测试

这里先演示手动使用 ApplicationContext 的做法进行测试,为了简化测试,这里直接使用 H2DBSpringJdbcTemplate

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!--spring-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.14.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.14.RELEASE</version>
</dependency>
<!--h2 db-->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.196</version>
<scope>test</scope>
</dependency>

创建初始化 sql 文件 hsqldb/initDatabase.sql

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
drop table if exists user;
create table user (
id int auto_increment not null
comment '编号',
name varchar(20) not null
comment '名字',
sex boolean null
comment '性别',
age int null
comment '年龄'
);

insert into user (id, name, sex, age)
values
(1, '琉璃', false, 17),
(2, '月姬', false, 1000);

Spring 配置文件 spring/spring-context.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!--自动扫描-->
<context:component-scan base-package="com.rxliuli.study.springtest"/>

<jdbc:embedded-database id="dataSource" type="H2">
<!--初始化 db-->
<jdbc:script location="classpath:hsqldb/initDatabase.sql" encoding="UTF-8"/>
</jdbc:embedded-database>

<!--配置 Spring JdbcTemplate-->
<bean class="org.springframework.jdbc.core.JdbcTemplate" id="jdbcTemplate"
p:dataSource-ref="dataSource"/>
</beans>

接下来我们可以编写实体类 com.rxliuli.study.springtest.entity.User,dao 层 com.rxliuli.study.springtest.dao.UserDao 和 dao 对应的测试类 com.rxliuli.study.springtest.dao.UserDaoTest

  • User
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
/**
* @author rxliuli
* @date 2018/7/31
*/
public class User {
private Integer id;
private String name;
private Boolean sex;
private Integer age;

public User() {
}

public User(String name, Boolean sex, Integer age) {
this.name = name;
this.sex = sex;
this.age = age;
}

public User(Integer id, String name, Boolean sex, Integer age) {
this.id = id;
this.name = name;
this.sex = sex;
this.age = age;
}

public Integer getId() {
return id;
}

public User setId(Integer id) {
this.id = id;
return this;
}

public String getName() {
return name;
}

public User setName(String name) {
this.name = name;
return this;
}

public Boolean getSex() {
return sex;
}

public User setSex(Boolean sex) {
this.sex = sex;
return this;
}

public Integer getAge() {
return age;
}

public User setAge(Integer age) {
this.age = age;
return this;
}
}
  • UserDao
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
/**
* @author rxliuli
* @date 2018/7/31
*/
@Repository
public class UserDao {
private final RowMapper<User> userRowMapper = (rs, rowNum) -> new User(
rs.getInt("id"),
rs.getString("name"),
rs.getBoolean("sex"),
rs.getInt("age")
);
@Autowired
private JdbcTemplate jdbcTemplate;

/**
* 根据 id 获取一个对象
*
* @param id id
* @return 根据 id 查询到的对象,如果没有查到则为 null
*/
public User get(Integer id) {
return jdbcTemplate.queryForObject("select * from user where id = ?", userRowMapper, id);
}

/**
* 查询全部用户
*
* @return 全部用户列表
*/
public List<User> listForAll() {
return jdbcTemplate.query("select * from user", userRowMapper);
}
}

注:这里直接使用了 Dao 类,生产过程中最好使用接口。

  • UserDaoTest
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
/**
* @author rxliuli
* @date 2018/7/31
*/
public class UserDaoTest {
private UserDao userDao;

@Before
public void before() {
//使用 spring xml 配置文件初始化 ApplicationContext
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:/spring/spring-context.xml");
//然后使用 ApplicationContext 获取 UserDao 的对象
userDao = context.getBean(UserDao.class);
}

@Test
public void get() {
int id = 1;
User result = userDao.get(id);
//断言 id 和 get id 相同
assertThat(result)
.extracting(User::getId)
.contains(id);
}

@Test
public void listForAll() {
List<User> userList = userDao.listForAll();
//断言不为空
assertThat(userList)
.isNotEmpty();
}
}

手动加载的基本思路就是:

  • 先加载 ApplicationContext 初始化 Spring 环境
    注:这一步实际上就已经加载了 Spring 容器,并且使用 initDatabase.sql 初始化 h2 DB 了
  • 使用 ApplicationContext 对象获得 UserDao 实例
  • 调用被测试的方法
  • 对结果进行断言

但这里实际上,ApplicationContext 是会被初始化两次的,所以会造成浪费和麻烦(例如初始化 sql 脚本也会被执行两次,当然这里吾辈先把 user 表删除后再创建的所以没事)。其实 Spring 早已想到了这一切,并为我们准备了解决方案。

使用 SpringTest 整合测试!

使用注解自动加载 Spring 测试环境

1
2
3
4
5
6
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.3.14.RELEASE</version>
<scope>test</scope>
</dependency>

使用 SpringTest 进行测试

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
/**
* @author rxliuli
* @date 2018/7/31
*/
//加载 Spring 配置文件
@ContextConfiguration(locations = "classpath:/spring/spring-context.xml")
//使用 SpringJUnit4ClassRunner 来运行 test
@RunWith(SpringJUnit4ClassRunner.class)
public class UserDaoSpringTest {
/**
* 直接注入 UserDao 就好了
*/
@Autowired
private UserDao userDao;

@Test
public void get() {
int id = 1;
User result = userDao.get(id);
//断言 id 和 get id 相同
assertThat(result)
.extracting(User::getId)
.contains(id);
}

@Test
public void listForAll() {
List<User> userList = userDao.listForAll();
//断言不为空
assertThat(userList)
.isNotEmpty();
}
}

可以看到,这里我们甚至可以使用 Spring 的自动注入注解 @Autowired

当然,现在还有一个问题就是现在测试对数据库的影响是持久的,也就是说不能重复的测试。
例如删除了一个为 id 为 1 的用户,返回值应当是 1,但第二次删除时,因为 id 为 1 的用户已经不存在了,所以返回值是 0,然后就报错了 23333

我们可以测试一下

  1. 在 UserDao 中新增方法 deleteById
1
2
3
4
5
6
7
8
9
/**
* 根据 id 删除用户
*
* @param id 用户 id
* @return 受影响行数
*/
public int deleteById(Integer id) {
return jdbcTemplate.update("delete from user where id = ?", id);
}

然后在测试类 UserDaoSpringTest 中添加两个删除测试方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Test
public void deleteById() {
int result = userDao.deleteById(1);
assertThat(result)
.isGreaterThan(0);
}

@Test
public void deleteByIdForTransaction() {
//这个仅仅是为了测试事物与自动回滚是否生效
int result = userDao.deleteById(1);
assertThat(result)
.isGreaterThan(0);
}

然后运行测试类,你会得到一个错误

1
2
3
4
5
java.lang.AssertionError:
Expecting:
<0>
to be greater than:
<0>

所以我们需要让所有测试的操作都不影响到数据库,即 全局事物 + 默认回滚

首先需要在 spring-context.xml 中添加数据库事务管理的配置

1
2
3
4
<!--配置数据库事务并开启注解支持-->
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="dataSourceTransactionManager"
p:dataSource-ref="dataSource"/>
<tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>

UserDaoSpringTest 测试类上添加两个注解

1
2
3
4
//为这个测试类开启事物
@Transactional
//默认回滚所有数据库操作
@Rollback

再次运行,一切便都正常了,是不是感觉很棒!但每个测试类头上都加那么一大堆注解也很麻烦,所以我们需要将之抽出一个父类直接继承就好了

以下是一个最简单的测试基类 BaseTest(common.test.BaseTest)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* 简单的测试基类
* <BaseBean> 需要自动注入的 Bean 类型
*
* @author rxliuli
* @date 2018/7/31
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:/spring/spring-context*.xml")
@Transactional
@Rollback
public abstract class BaseTest<BaseBean> {
/**
* 自动注入的 Bean
*/
@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
@Autowired
private BaseBean base;
}

然后创建测试类 UserDaoBaseTest(com.rxliuli.study.springtest.dao.UserDaoBaseTest) 继承 BaseTest 进行测试

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
/**
* @author rxliuli
* @date 2018/7/31
*/
public class UserDaoBaseTest extends BaseTest<UserDao> {
@Test
public void get() {
int id = 1;
User result = base.get(id);
//断言 id 和 get id 相同
assertThat(result)
.extracting(User::getId)
.contains(id);
}

@Test
public void listForAll() {
List<User> userList = base.listForAll();
//断言不为空
assertThat(userList)
.isNotEmpty();
}

@Test
public void deleteById() {
int result = base.deleteById(1);
assertThat(result)
.isGreaterThan(0);
}

@Test
public void deleteByIdForTransaction() {
//这个仅仅是为了测试事物与自动回滚是否生效
int result = base.deleteById(1);
assertThat(result)
.isGreaterThan(0);
}
}

运行结果也是一切正常呢,对 Dao/Service 需要加载 Spring 容器的测试暂且到这里便结束了。。。

Web 层测试

绝大部分时候,很多人喜欢写完代码就到前台页面直接看效果。但人眼是不一定准确的,而且可重复性/可靠性不足。如果是 API,大部分人或许会选择诸如 Postman, IDEA HttpClient 这一类的工具吧,但实际上,SpringTest 已经考虑到了对 Web 层的测试并集成了这些。

首先还是需要添加依赖

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
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.14.RELEASE</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.5</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.5</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.5</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-jaxb-annotations</artifactId>
<version>2.9.5</version>
</dependency>
<!--json-path-assert 对 MockMvc response 中返回的 json 数据进行断言-->
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path-assert</artifactId>
<version>2.4.0</version>
<scope>test</scope>
</dependency>

设置 maven 打包时为 war

1
<packaging>war</packaging>

添加配置文件 spring/spring-mvc.xml

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!--配置支持注解并自动扫描-->
<mvc:annotation-driven/>
<context:component-scan base-package="com.rxliuli.study.springtest">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.RestController"/>
</context:component-scan>
</beans>

添加 web 的根目录 /src/main/webapp 并在 webapp 目录下创建 web.xml(WEB-INF/web.xml)

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
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<!--context configLocation -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:/spring/spring-context*.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>

<!--encoding filter-->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<!--MVC Servlet-->
<servlet>
<servlet-name>springServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:/spring/spring-mvc*.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>

至此,项目中便添加了 web 环境支持。

下面开始编写要测试的接口 UserController(com.rxliuli.study.springtest.web.UserController)

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
/**
* @author rxliuli
* @date 2018/7/31
*/
@RestController
public class UserController {
@Autowired
private UserDao userDao;

/**
* 获取用户信息
*
* @param id 用户 id
* @return 用户对象信息
*/
@GetMapping("/user/{id}")
public User get(@PathVariable("id") Integer id) {
return userDao.get(id);
}

/**
* 获取全部的用户列表
*
* @return 全部的用户列表
*/
@PostMapping("/user/listForAll")
public List<User> listForAll() {
return userDao.listForAll();
}
}

这时候启动 web 项目在浏览器中访问 localhost:8080/{上下文}/user/1 应当会得到一个 User 对象。

注:上下文 IDEA 默认为空,Eclipse 默认为项目名

然而测试却是有两种方法:

  1. 独立安装测试
    手动加载单个 Controller,所以测试其他 Controller 中的接口会发生异常。但测试速度上较快,所以应当优先选择。
  2. 集成 Web 环境测试
    将启动并且加载所有的 Controller, 所以效率上之于 BaseWebUnitTest 来说非常低下, 仅适用于集成测试多个 Controller 时使用。

独立安装测试

简单的独立安装测试类 UserControllerUnitTest(com.rxliuli.study.springtest.web.UserControllerUnitTest)

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
/**
* @author rxliuli
* @date 2018/7/31
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:/spring/spring-*.xml")
@Transactional
@Rollback
@WebAppConfiguration
public class UserControllerUnitTest {
@Autowired
private UserController userController;
/**
* 用于测试 API 的模拟请求对象
*/
private MockMvc mockMvc;

@Before
public void before() {
//模拟一个 Mvc 测试环境,获取一个 MockMvc 实例
mockMvc = MockMvcBuilders.standaloneSetup(userController)
.build();
}

@Test
public void testGet() throws Exception {
//测试能够正常获取
Integer id = 1;
mockMvc.perform(
//发起 get 请求
get("/user/" + id)
)
//断言请求的状态是成功的(200)
.andExpect(status().isOk())
//断言返回对象的 id 和请求的 id 相同
.andExpect(jsonPath("$.id").value(id));
}

@Test
public void listForAll() throws Exception {
//测试正常获取
mockMvc.perform(
//发起 post 请求
post("/user/listForAll")
)
//断言请求状态
.andExpect(status().isOk())
//断言返回结果是数组
.andExpect(jsonPath("$").isArray())
//断言返回数组不是空的
.andExpect(jsonPath("$").isNotEmpty());
}
}

集成 Web 环境测试

简单的独立安装测试类 UserControllerIntegratedTest(com.rxliuli.study.springtest.web.UserControllerIntegratedTest)

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
/**
* @author rxliuli
* @date 2018/7/31
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:/spring/spring-*.xml")
@Transactional
@Rollback
@WebAppConfiguration
public class UserControllerIntegratedTest {
@Autowired
private WebApplicationContext context;
/**
* 用于测试 API 的模拟请求对象
*/
private MockMvc mockMvc;

@Before
public void before() {
//这里把整个 WebApplicationContext 上下文都丢进去了,所以可以测试所有的 Controller
mockMvc = MockMvcBuilders.webAppContextSetup(context)
.build();
}

@Test
public void testGet() throws Exception {
//测试能够正常获取
Integer id = 1;
mockMvc.perform(
//发起 get 请求
get("/user/" + id)
)
//断言请求的状态是成功的(200)
.andExpect(status().isOk())
//断言返回对象的 id 和请求的 id 相同
.andExpect(jsonPath("$.id").value(id));
}

@Test
public void listForAll() throws Exception {
//测试正常获取
mockMvc.perform(
//发起 post 请求
post("/user/listForAll")
)
//断言请求状态
.andExpect(status().isOk())
//断言返回结果是数组
.andExpect(jsonPath("$").isArray())
//断言返回数组不是空的
.andExpect(jsonPath("$").isNotEmpty());
}
}

其实从上面可以看出来主要就是获得 MockMvc 的方式不同,所以其实也可以抽出来公共的测试父类。这里就不再赘述,具体的做法可以参考 测试基类

那么,有关使用 Spring 进行测试的问题就像说到这里啦

附:用了 SpringBoot 之后才觉得 Spring 的各种配置好麻烦。。。

IDEA 使用技巧

IDEA 全局默认配置

使用场景:
使用 IDEA 经常会遇到一种情况,在这个项目自顶了一些设置(Settings 而非 Project Structure,例如 自定义的 Maven,项目字符编码等等),到了新的项目全部恢复了默认值又要重新设定。

解决方案:
通过 IDEA 的默认设置(File > Other Settings > Default Settings)就可以设定全局的 Settings,而不需要在每个项目中重新设定一次。

默认设定按吾辈的理解应该是用于设定那些可以使项目级别的设置,例如 代码检查代码样式 等。毕竟大部分的设置都是全局的嘛

Alt-Enter 操作提示

Alter-Enter 大概是 IDEA 最强大快捷键了,放在不同的位置有不同的功能。

  • 警告(代码下面有黄色波浪线),会自动帮我们修复警告。
    代码重复,代码冗余(1/0 之类),多余的变量(声明完就立刻返回/声明完最多只使用了一次)
  • 错误(代码下面有红色波浪线),一般会提出合适的修复建议。
    代码缺少注解,具体子类有未实现的方法
  • 接口名(接口的名字),一般会提示可以生成实现类或者跳转到实现类
  • 自动修复变量名的问题(不符合驼峰)
  • 普通类名,一般会提示创建测试类,没有 JavaDoc 注释还会提示生成注释
  • 字符串里面,会提示使用 语言注入
  • 跳转到注入语言的编辑面板

Double Shift 任意搜索

这个功能其实是集成了多个搜索,但有时候真的很好用,集成的功能包括

  • 搜索 SettingsCS-A):搜索 IDEA 的设置
  • 搜索 classC-N):搜索代码里的 class 类
  • 搜索 FileCS-N):搜索任何文件
  • 搜索 symbolCSA-N):搜索符号,主要用于搜索 Spring MVC 路径
  • 搜索 Tool WindowsC-Tab):搜索工具窗口
  • 搜索 Run configurationSA-F9/F10):搜索运行的配置项
  • 搜索 ActionAlt-Enter):搜索当前位置的代码可执行操作

如果你知道需要搜索的类型,请尽量使用单独的搜索选项,毕竟速度上会有一些优势

列编辑

列编辑是一个非常有趣的功能,可以让你同时编辑多行文本。

共有下面几种方式触发

  • 使用鼠标中键下拉或上拉选中多行
  • 使用 A-J 依次选择相同的代码片段,并使用 SA-J 取消选择
  • 使用 CSA-J 选中当前文件所有匹配的代码片段
  • 使用 CA-Top/Bottom 向上或向下选择多行(需要添加快捷键 Editor Actions => Clone Caret Above/Clone Caret Below

GIF 演示

GIF 演示

常用快捷键

快捷键想要熟练没有什么好的办法,却是只能多加使用了。如果你还不熟悉 IDEA 的快捷键,可以使用 Key Promoter X 插件来提示你使用快捷键操作。

  • 搜索
    • C-N :搜索类
    • CS-N :搜索文件
    • CSA-N :搜索字段名(包含数据库字段)/方法名
    • SS :搜索接口路径,类名,文件名,字段名/方法名
    • CS-F:全局搜索代码(该快捷键与 Windows10 的默认输入法冲突,可以修改快捷键,或者换用其他输入法)
  • 面板操作
    • ESC:返回到编辑器中
    • C-E :列出最近操作的文件历史以及可操作面板列表,然后可以通过输入单词跳转到对应的面板
    • C-Tab -> *:列出最近操作的文件历史以及可操作面板,并能通过单个字母导航到对应的操作面板(需要一直按住 Ctrl
    • A-Top/Bottom/Left/Right :左右是切换标签页,上下是切换方法
    • F12 :跳转到最后一个使用的面板
    • CS-F12 :收起/显示所有面板
    • C-F12 :在一个悬浮面板上列出所有字段/方法
  • 选择
    • C-W/CS-W :扩大/缩小选择区域范围
    • CS-[/]:选择至当前区域的开始/结束
    • A/SA-J :选中/反选相同的单词进行列编辑(一个个的选中)
    • CSA-J :选中多个相同的单词(当前文件全部选中)
  • 代码跳转
    • CA-Left/Right :跳转到上一个/下一个浏览的位置
    • CS-Backspace :回退到上一个编辑的位置
    • C-Top/Bottom/Left/Right:左右是跳转到上一个/下一个单词,上下是移动屏幕(非移动光标)
    • C-; :屏幕内任意跳转(需要安装 Ace Jumper 插件)
    • Home :跳转到行首/编辑器的最左侧
    • End :跳转到行尾
    • C-Home/End :跳转到文件的开始/结尾
    • C-Page Up/Page Down :跳转到当前屏幕的第一行/最后一行
    • F2/S-F2 :跳转到下一个/上一个错误/警告的位置
    • C-Left/C-Right :跳转到上一个/下一个单词的位置
    • C-B :跳转到变量/方法的声明处
    • CS-B :跳转到变量/方法的具体实现处,如果不止一处就会列出下拉框

      注:这里吾辈修改了快捷键,毕竟 CA-B 单手按起来还真有点麻烦

  • 小键盘专用
    • CS-Number
      • CS-8/2/4/6 :相当于 C-Top/Bottom/Left/Right
      • CS-7/1/9/3 :相当于 C-Home/End/Page Up/Page Down
      • CS-0 :相当于 C-C
      • CS-. :相当于 C-Delete
    • SA-Number
      • SA-8/2/4/6 :相当于 A-Top/Bottom/Left/Right
      • SA-7 :相当于 A-Home
      • SA-0 :相当于 A-Insert

注:在 IDEA 看来左侧字母上面的数字键和右侧小键盘的数字键是不同的!
注: Shift 一般用于 增强/取反 功能。例如 C-F 搜索当前文件,CS-F 搜索所有文件,F2 跳转到下一个错误,S-F2 跳转到上一个错误。

常用插件

  • JRebel for IntelliJ:做 Java Web 开发时真心免不了的 Plugin,能够有效解决 Web 容器(例如 Apache Tomcat)启动速度慢的问题(因为几乎所有的资源都能够热加载,热部署)
  • LiveEdit:提供了 HTML/CSS/JavaScript 的实时预览和刷新功能
  • MybatisX:Mybatis 的一个辅助开发插件,能够比较愉快的使用 Mybatis 框架了
  • Alibaba Java Coding Guidelines:Alibaba 出品的一个 Java 规范检查插件,能够规避一些不好的代码
  • Translation:目前使用感觉最好的翻译插件,能够提供比较长的内容进行翻译(某些翻译插件只能翻译很短的内容)
  • String Manipulation:字符串操作工具,可以方便对变量名或其他字符串修改为其他风格,例如将变量从 驼峰命名(Java 标准命名) 修改为 下划线命名(SQL 标准命名)或者 中缀线命名(HTML/CSS 标准命名)。

    其实这么多命名规范真心坑。。。

  • Key Promoter X:使用鼠标操作时提示对应的快捷键
  • Custom Postfix Templates:提供自定义的后缀模板
  • Markdown Navigator:IDEA 平台的 Markdown 写作插件,比自带的 Markdown Support 要好很多,主要在需要写的 Markdown 内容中含有代码时比较方便
  • Maven Helper:一个 Apache Maven 的辅助操作插件
  • CodeGlance:在编辑器右侧显示一块代码缩略图,主要为了方便使用滑块进行上下滑动
  • Grep Console:自定义控制台的输出颜色
  • .ignore:在使用版本控制时,快速忽略某些文件/文件夹,目前支持广泛
  • CMD support:Cmd 支持,主要是方便在 IDEA 中直接运行 bat 脚本
  • NodeJS:集成了 NodeJS,可以直接在 IDEA 中运行 NodeJS
  • Vue.js:集成 Vue.js 框架
  • ESLint:前端代码规范
  • Prettier:根据上面 ESLint 的规范自动格式化代码
  • Properties to YAML Converter:将 Properties 文件快速转换为 YAML 格式的配置文件
  • WakaTime:统计使用的编程语言,不同 IDE 的记录

语言注入

为某一段区域的注入其他语言,IDEA 最常见的就是在 JavaScript 的字符串中注入了 HTML/CSS/JavaScript,使得在字符串内也有代码提示可用。

此功能常用于 JavaScript 字符串拼接 HTML 代码,当然目前这个需求在 ES6 中由 模板字符串 原生实现了。

我们也可以手动注入,例如为 Java 中的字符串注入 SQL 语言,这样在写 SQL 语句就不用跑到 SQL 编辑器那里写完 SQL 语句在粘贴过来了。

Live Template/Postfix Template 模板

Live Template 模板就是那种在 Java 中输入 sout 就可以生成以下代码的模板功能,而这功能在 IDEA 还可以自定义。

1
System.out.println($END$);

例如吾辈就定义了 autowired 用于生成

1
2
@Autowired private $BeanClass$ $BeanName$;
$END$

或者 thread

1
2
3
new Thread(() -> {
$END$
}).start();

此功能使用得当甚至能大量减少重复编码。不过相比之下另外一个代码生成功能吾辈更加喜欢,但 IDEA 在 2018.2 版本之前并不支持自定义,所以功能上来说就显得稍弱一些,当然吾辈也使用插件(Custom Postfix Templates GitHub)实现了自定义的需求。最新版本 IDEA 原生支持了自定义功能(IDEA 官方介绍),但实现尚不完善。

此功能可以做到另外一种形式的模板字符串,例如输入 "str".var 然后回车会得到

1
String $variableName$ = "str";$END$

或者 "str".sout

1
Sysout.out.println("str");

吾辈也自定义一些,例如输入了 "str".val,会生成

1
final String $variableName$ = "str";$END$

一些有用的配置项

soft wrap 强制换行

IDEA 在一行过长时会出现横向滚动条,那我们不想要它出现以便于能直接使用键盘就能看完要怎么办呢?

可以在 Settings ⇒ Editor ⇒ General ⇒ Soft Wraps 中找到设置,将 Soft-wrap files 的值修改为 * 即可。

强制换行

根据源代码自动滚动项目

可以在跳转文件时,使文件目录自动聚焦在当前编辑的文件上,这在很多时候是有利于查看目录/文件的。

2019.3 之后

Project ⇒ Always Select Opened File 中可以找到这个配置,启用即在整个项目中启用了。

根据源代码自动滚动项目设置

2019.3 之前

Project ⇒ Tool ⇒ Autoscroll from Source 中可以找到这个配置,启用即在整个项目中启用了。

根据源代码自动滚动项目设置

Git 设置和取消代理

设置代理:

1
2
git config --global http.proxy 'socks5://127.0.0.1:1080'
git config --global https.proxy 'socks5://127.0.0.1:1080'

注:此处设置的代理 ip 和端口号都是本地存在的(SS/SSR 默认就是)。

取消代理

1
2
git config --global --unset http.proxy
git config --global --unset https.proxy

Git 全局配置文件位置

根配置文件 /etc/gitconfig

Windows 的话在 Git 安装目录下 /mingw64/etc/gitconfig,不过最好不要动这个
当前用户 Git 配置 ~/.gitconfig

在配置文件里面添加以下内容也可以添加代理:

1
2
3
4
[https]
proxy = socks5://127.0.0.1:1080
[http]
proxy = socks5://127.0.0.1:1080

遇到的坑

设置了代理之后很容易碰到一个问题:Git Push 提示不支持具有 Socks5 方案的代理

具体 Git 相关的内容建议参考 Pro Git

IDEA 设置配置文件的位置

IDEA 虽然有着便携版本,但它的配置文件显然并非如此。默认设置在当前用户目录下,所以为了便携化考虑,还是将配置文件也放到 IDEA 程序的子目录更好一点。

主要需要修改的文件为:
IDEAHome/bin/idea.properties

找到内容为 idea.config.pathidea.system.path 的选项,放开注释,修改为你想要的路径就好了。

  • idea.config.path:IDEA 的配置文件目录,主要有安装的插件,自定义的配置等
  • idea.system.path:IDEA 的缓存文件目录,主要有各个项目单独的配置,项目的索引等

注:${idea.home.path} 代表的是 IDEA 程序的根目录。
例如:IDEA 的文件夹是:C:/Users/rxliuli/Program/ideaIU-2018.1.6.win/。 那么,${idea.home.path}/.IntelliJIdea/ 代表的就是 C:/Users/rxliuli/Program/ideaIU-2018.1.6.win/.IntelliJIdea/

以上便是使用 IDEA 设置配置文件的位置的方法,现在可以将 IDEA 程序和配置一起打包解压即用了呢

自建 Jrebel 反向代理

项目位置:https://gitee.com/gsls200808/JrebelLicenseServerforJava

不喜欢 Gitee 直接 git clone https://gitee.com/gsls200808/JrebelLicenseServerforJava.git 然后自己用 maven 编译一下就好!
或者吾辈也编译了一个 链接

普通启动(其中 -p 指的是端口,服务器必须配置该端口可以访问)

1
java -jar JrebelBrainsLicenseServerforJava-1.0-SNAPSHOT-jar-with-dependencies.jar -p 8181

后台启动 jar(既便退出程序也不会结束)

1
nohup java -jar JrebelBrainsLicenseServerforJava-1.0-SNAPSHOT-jar-with-dependencies.jar -p 8181 > log.log &

> log.log & 指的是将程序的控制台输出写入到某个文件中

查看程序

  1. 使用 job 命令

    1
    jobs

    输出可能是下面这样子:
    [1]+ Running nohup java -jar JrebelBrainsLicenseServerforJava-1.0-SNAPSHOT-jar-with-dependencies.jar -p 8181 > log.log &

    想要结束的话使用 fg 任务 id 将任务调回前台,然后 Ctrl+C 即可。
    这里使用

    1
    2
    fg 1
    Ctrl+C
  2. 使用 Linux 下的 ps 命令

    使用以下命令列出所有含有 Jrebel 的进程

    1
    ps -ef|grep Jrebel

    吾辈启动了好几次,所以有 3 条

    1
    2
    3
    rxliuli   1877  1828  0 23:26 pts/0    00:00:00 java -jar JrebelBrainsLicenseServerforJava-1.0-SNAPSHOT-jar-with-dependencies.jar
    rxliuli 1942 1921 0 23:33 pts/1 00:00:00 java -jar JrebelBrainsLicenseServerforJava-1.0-SNAPSHOT-jar-with-dependencies.jar -p 8181
    rxliuli 1967 1921 0 23:37 pts/1 00:00:00 grep --color=auto Jrebel

    使用 kill -9 进程 id 杀死进程
    例如这里可以使用

    1
    kill -9 1828

    然后再次使用 ps 查看进程就发现已经被杀死了

使用

激活服务器:http://{服务器 id}:{服务器端口, 这里是 8181}/947122a0-7e9a-4bea-814d-876525d3767f
邮箱随意就好(至少格式要正确。。。)

有可能 Jrebel 还会让你输入认证信息,吾辈输入了服务器的 username/password 貌似就没问题了呢