Java Spring Boot 笔记

Collection、Map、Set 与 List

  • Collection(容器)是集合接口,保存一组对象(Object)
  • Map 类似于 Python 的 dict,用来保存映射,HashMap 是 Map 的一种实现
  • List 类似于 Python 数组,用下标来取值,LinkedList、Vector 都是其实现
  • Set 是集合,只能通过游标来取值,HashMap 是其的一种实现

泛型

平常的对象和函数都是接受固定类型的变量作为参数,但是泛型接受的参数可以是不确定的,可以接受任意数据类型的变量作为参数,当然除了基本类型

Optional

Optional 对象相当于是一个容器,它的值可以为 null。如果值存在则 isPresent() 方法会返回 true,此时调用 get() 方法就会返回容器中的对象。

这个类的主要作用就是把 null 用容器装起来了,可以不用显示地进行控制检测,可以有效解决空指针异常。

@jsonignore

在 JSON 返回的时候,有些值我们不想让它显示给客户端,比如密码,因此可以用这个注释来忽视掉这些属性

JavaBeans

JavaBeans 是 Java 中一种特殊的类,其中:

  • 所有属性为private
  • 提供默认构造方法
  • 提供getter和setter
  • 实现serializable接口

这样做是因为 Java 语言欠缺属性、事件、多重继承功能。

-> 表达式

和 JS 类似,Java 的 -> 表达式定义的也是一个匿名函数,在这里叫做 Lambda 表达式,格式如下:

1
2
3
(parameters) -> expression

(parameters) ->{ statements; }

表达式的特点为:

  • 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
  • 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
  • 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
  • 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。

Arrays.asList()

这个方法是用来把参数包装成一个 List,可以接受数组作为参数。

Spring Boot 关键构件

Entity

类似于 Flask 中的 Model 类,用来表示数据库的结构。

Repository

直接与数据库进行交互,类似于 Flask 中的 db.session 需要自己定义相应的方法来实现一些对数据库的 CURD 操作。

Controller

相当于 Flask 中的 view,表示业务逻辑的代码

SQL Dialect

不同的 SQL 数据库都有不同的 SQL 扩展,这种扩展就是“方言”

SQL Server 中文显示为问号

这个是字符集(collate)顺序的锅,默认的字符集不显示中文,我使用了下面的语句来更改数据库的字符集顺序:

1
alter database dbname collate Chinese_PRC_CI_AS

以及下面的语句更改表中列的字符集:

1
alter table tbname alter column clname cltype collate Chinese_PRC_CI_AS

结果改了之后查询以及插入值再查询后依然是问号,但是重新创建数据库之后就可以正确显示中文了:

1
create database dbname collate chinese_prc_ci_as

真的好坑,不知道是不是我人品比较差不能直接修改。

参考资料:

List 用法

取出 List 中的元素

1
list.get(1)  // 数字为 index

检查 List 是否为空

1
list.isEmpty()

查看 List 的大小

1
list.size()

JPA 中的查询方法

和 SQLAlchemy 类似,除非指定返回一个结果,JPA 中返回的结果也是按照集合来表示的,因此也要用 List 等来保存结果。

如果指定了 findFirstByXXX 或者 findOneByXXX 就可以只返回一个结果。

@RequestBody 的用法

在 REST 应用中,我们一般接受 JSON 作为传入的参数,使用 @RequestBody 之后就只能接受 JSON 作为参数了,不能接受 form-data 等,而此时的 Content-Type 要为 application/json

这个地方和 Python 的还不一样,Flask-RestFul 不仅仅可以接受 JSON 作为参数,还可以解析出很多其他种类的数据。

如果直接使用相应的 Entity 作为参数,那这样的参数就只能识别 form-data,而其他的都不能识别了。

参考教程:http://blog.csdn.net/rickyit/article/details/70242218

JPA 使用 DateTime 与 数据库相联系

在 Java 中直接使用 Date 来新建一个实时间的变量,然后在数据库里面对应的就是 DateTime 类型的了。

其中数据库时间戳类型要根据 @Temporal 注解来指定,相应代码如下:

1
2
3
@Column(name="DATE_CREATED")
@Temporal(TemporalType.TIMESTAMP)
private java.util.Date dateCreated;

参考教程:https://stackoverflow.com/questions/9409342/handle-datetime-in-jpa2

JPA 中的一对多关系

使用 @OneToMany 以及 @ManyToOne 注解来定义,详细教程看这个这个,其中双向映射是可以从任意一个对象引用另一个对象,而单向则是只有一边才可以

JPA 设置默认时间

每次插入数据时候生成的时间用 @CreationTimestamp 来表示,每次更新数据生成的时间用 @UpdateTimestamp 来表示

参考教程:http://blog.csdn.net/sushengmiyan/article/details/50360451

fastjson 使用

fastjson 是阿里所编写的 Java 处理 JSON 的模块,据说有超高的速度。

Maven 依赖:

1
2
3
4
5
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.41</version>
</dependency>

把 JSON 字符串解析为 JSON 对象:

1
JSONObject jsonResult = JSONObject.parseObject(strResult);

把 JSON 字符串解析为 JSON 数组:

1
JSONArray jsonArray = JSONObject.parseArray(strResult)

把 Map 转换为 JSON 字符串:

1
2
Map param<String, Object> = ...;
String JSONString = JSON.toJSONString(param);

HTTPClient 发送 HTTP 请求

Maven 依赖

1
2
3
4
5
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5</version>
</dependency>

Get 请求

建立 HTTP 客户端:

1
CloseableHttpClient client = HttpClients.createDefault();

建立 Get 请求:

1
HttpGet getRequest = new HttpGet(url);

发送 Get 请求并且保存返回结果:

1
HttpResponse response = client.execute(getRequest);

获取状态码:

1
response.getStatusLine().getStatusCode()

Post 请求

建立客户端:

1
CloseableHttpClient client = HttpClients.createDefault();

建立 Post 请求:

1
HttpPost postRequest = new HttpPost(url);

构建 Post JSON 请求体:

1
2
Map<String, Object> param = new LinkedHashMap<String, Object>();
param.put("appid", "wxgegfegffe");

把 Map 转换为 JSON 字符串:

1
String JSONString = JSON.toJSONString(param);

设置实体编码,防止中文乱码:

1
StringEntity entity = new StringEntity(JSONString, "utf-8");

设置 HTTP 中的编码:

1
2
entity.setContentEncoding("UTF-8");
entity.setContentType("application/json");

把实体包含到 Post 请求中:

1
postRequest.setEntity(entity);

发送 HTTP 请求:

1
HttpResponse response = client.execute(postRequest);

构建 token

Maven 依赖

1
2
3
4
5
<dependency>
<groupId>com.nimbusds</groupId>
<artifactId>nimbus-jose-jwt</artifactId>
<version>5.1</version>
</dependency>

生成 token

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
// Generate random 256-bit (32-byte) shared secret
SecureRandom random = new SecureRandom();
byte[] sharedSecret = new byte[32];
random.nextBytes(sharedSecret);

// Create HMAC signer
// 需要接受一个 256-bit 的内容作为参数
JWSSigner signer = new MACSigner(sharedSecret);

// Prepare JWT with claims set
// 也就是封装进去的一些信息
JWTClaimsSet claimsSet = new JWTClaimsSet.Builder()
.subject("alice")
.issuer("https://c2id.com")
.expirationTime(new Date(new Date().getTime() + 60 * 1000))
.build();

// 使用 HAMC 来保护这个 claimSet
// HAMC 是 hash-based message authentication code
SignedJWT signedJWT = new SignedJWT(new JWSHeader(JWSAlgorithm.HS256), claimsSet);

// Apply the HMAC protection
signedJWT.sign(signer);

// Serialize to compact form, produces something like
// eyJhbGciOiJIUzI1NiJ9.SGVsbG8sIHdvcmxkIQ.onO9Ihudz3WkiauDO2Uhyuz0Y18UASXlSc1eS0NkWyA
// 这就是生成的 token
String token = signedJWT.serialize();

验证 token

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// On the consumer side, parse the JWS and verify its HMAC
signedJWT = SignedJWT.parse(token);

// 通过这个共享密码来检测
JWSVerifier verifier = new MACVerifier(sharedSecret);

// assert 是 Junit 中的方法
// 如果共享密码是正确的那么这个结果就为真
assertTrue(signedJWT.verify(verifier));

// Retrieve / verify the JWT claims according to the app requirements
// 和 Python 相应的模块不同,这里要手动进行相应的检验
assertEquals("alice", signedJWT.getJWTClaimsSet().getSubject());
assertEquals("https://c2id.com", signedJWT.getJWTClaimsSet().getIssuer());
assertTrue(new Date().before(signedJWT.getJWTClaimsSet().getExpirationTime()));