0%

用到的java

1 idea maven配置

maven home directory 也要调整成
E:/progam/apache-maven-3.3.9
user settings file:
E:\progam\apache-maven-3.3.9\conf\settings.xml
local repository:
E:\mavenws

2 IoC

一个bean就是一个组件

  1. 用XML创建组件和说明组件之间的关系
    <property name=”” ref=””或value=””>
    使用set()或者构造函数注入

  2. 用注释配置
    @Component 定义一个Bean
    @Autowired 注入一个Bean

@Configuration 配置类,在调用AnnotationConfigApplicationContext()时必须传入1个标注了 @Configuration 的类名
@ComponentScan 自动搜索当前类所在的包和子包,找出所有 @Component 的Bean自动创建出来,并在 @Autowired 自动装配
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) // @Scope(“prototype”) 每次创建一个新的实例
@Order(1) 创建实例时的顺序,可以注入List<>
@Bean 在 @Configuration 类中创建一个组件,管理第三方bean,Spring对标记为@Bean的方法只调用一次,因此返回的Bean仍然是单例;
@PostConstruct 创建后的初始化
@PreDestroy 销毁前清理
@Qualifier(“utc8”) 指定别名, 可以用@Bean(“name”)指定别名,也可以用@Bean+@Qualifier(“name”)指定别名
@Value(“classpath:/logo.txt”) private Resource resource; 注入资源文件
@PropertySource 自动读取配置, @Value(“${app.zone:Z}”) 注入
@Profile(“!test”), @Profile({ “test”, “master” }) 条件装配, -Dspring.profiles.active=test,master
@ConditionalOnProperty(name=”app.smtp”, havingValue=”true”)

3 连接数据库

  • 使用JDBC连接
    JDBC: java定义的关系型数据库统一接口
    javax.sql.DataSource: JDBC连接池统一接口,实现有: HikariCP, C3P0, BoneCP, Druid

    1. 创建全局DataSource实例,表示数据库连接池;
    2. 在需要读写数据库的方法内部,按如下步骤访问数据库:
      从全局DataSource实例获取Connection实例;
      通过Connection实例创建PreparedStatement实例;
      执行SQL语句,如果是查询,则通过ResultSet读取结果集,如果是修改,则获得int结果。
  • 使用spring连接

  1. JdbcTemplate 对 JDBC 的一种简单封装
    使用IoC创建并管理一个DataSouce实例,然后spring提供了一个 JdbcTemplate,方便操作JDBC,通常会实例化一个JdbcTemplate
    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
    @Configuration
    @ComponentScan
    @PropertySource("jdbc.properties")
    public class AppConfig {

    @Value("${jdbc.url}")
    String jdbcUrl;

    @Value("${jdbc.username}")
    String jdbcUsername;

    @Value("${jdbc.password}")
    String jdbcPassword;

    @Bean
    DataSource createDataSource() {
    HikariConfig config = new HikariConfig();
    config.setJdbcUrl(jdbcUrl);
    config.setUsername(jdbcUsername);
    config.setPassword(jdbcPassword);
    config.addDataSourceProperty("autoCommit", "true");
    config.addDataSourceProperty("connectionTimeout", "5");
    config.addDataSourceProperty("idleTimeout", "60");
    return new HikariDataSource(config);
    }

    @Bean
    JdbcTemplate createJdbcTemplate(@Autowired DataSource dataSource) {
    return new JdbcTemplate(dataSource);
    }
    }
    // 通过@PropertySource("jdbc.properties")读取数据库配置文件;
    // 通过@Value("${jdbc.url}")注入配置文件的相关配置;
    // 创建一个DataSource实例,它的实际类型是HikariDataSource,创建时需要用到注入的配置;
    // 创建一个JdbcTemplate实例,它需要注入DataSource,这是通过方法参数完成注入的。
    JdbcTemplate方法:
    jdbcTemplate.execute((Connection conn)->{})
    jdbcTemplate.execute(“SELECT * FROM users WHERE name = ?”, (PreparedStatement ps)->{})
    jdbcTemplate.queryForObject(“SELECT * FROM users WHERE email = ?”, (ResultSet rs, int rowNum) -> {}, email)
    jdbcTemplate.update(“UPDATE users SET name = ? WHERE id = ?”, user.getName(), user.getId())

JTA: java transaction API, 分布式事务
@EnableTransactionManagement: 开启声明式事务
@Transactional 表示一个方法需要事务支持

DAO: Data Access Object,编写数据访问层时使用DAO模式,就是操作数据库
spring提供了一个 JdbcDaoSupport 虚拟类, 方便DAO模式编写
DAO模式就是一个简单的数据访问模式

Hibernate: 自动ORM,将数据字段映射为 java bean, 用于替换 JdbcTemplate,但是配置复杂, 不怎么用
JPA:Java Persistence API: JavaEE定义的ORM接口, 也不怎么用
MyBatis: 介于全自动ORM如Hibernate和手写全部如JdbcTemplate之间,半自动的ORM

JDBC: java操作数据库接口
ORM: java数据和数据库数据之间的自动映射
JPA: Spring提供的一种ORM

简单的就是 JdbcTemplate, 大项目就是 MyBatis

springboot 配置项

@Configuration
@ConfigurationProperties(“storage.local”)

@Autowired
StorageConfiguration storageConfig;
logger.info(“Load configuration: root-dir = {}”, storageConfig.getRootDir());

以下这几个注解, 只有 @Repository 会自动处理传输异常
@Component :通用的注解,可标注任意类为 Spring 组件。如果一个 Bean 不知道属于哪个层,可以使用@Component 注解标注。
@Repository : 对应持久层即 Dao 层,主要用于数据库相关操作。会自动捕获程序的特殊异常,转成spring的数据异常再抛出;
@Service : 对应服务层,主要涉及一些复杂的逻辑,需要用到 Dao 层。
@Controller : 对应 Spring MVC 控制层, 用于传入用户数据和给用户展示,主要用户接受用户请求并调用 Service 层返回数据给前端页面。通常配合 @RequestMapping
@RestController注解是@Controller和@ResponseBody的合集,表示这是个控制器 bean,并且是将函数的返回值直 接填入 HTTP 响应体中,是 REST 风格的控制器。

@Scope(“singleton”)
singleton : 唯一 bean 实例,Spring 中的 bean 默认都是单例的。
prototype : 每次请求都会创建一个新的 bean 实例。
request : 每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP request 内有效。
session : 每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP session 内有效。

@Configuration 一般用来声明配置类,可以使用 @Component注解替代,不过使用Configuration注解声明配置类更加语义化。

@Value(“${property}”) 读取比较简单的配置信息:
@ConfigurationProperties(prefix = “library”)读取配置信息并与 bean 绑定

所有的注解,推荐使用 JSR 注解,即javax.validation.constraints,而不是org.hibernate.validator.constraints
一些常用的字段验证的注解
@NotEmpty 被注释的字符串的不能为 null 也不能为空
@NotBlank 被注释的字符串非 null,并且必须包含一个非空白字符
@Null 被注释的元素必须为 null
@NotNull 被注释的元素必须不为 null
@AssertTrue 被注释的元素必须为 true
@AssertFalse 被注释的元素必须为 false
@Pattern(regex=,flag=)被注释的元素必须符合指定的正则表达式
@Email 被注释的元素必须是 Email 格式。
@Min(value)被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@Max(value)被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@DecimalMin(value)被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Size(max=, min=)被注释的元素的大小必须在指定的范围内
@Digits (integer, fraction)被注释的元素必须是一个数字,其值必须在可接受的范围内
@Past被注释的元素必须是一个过去的日期
@Future 被注释的元素必须是一个将来的日期

@EnableScheduling+@Scheduled, 通过@EnableScheduling启用定时任务,@Scheduled定义任务
cron:cron表达式,指定任务在特定时间执行;
fixedDelay:表示上一次任务执行完成后多久再次执行,参数类型为long,单位ms;
fixedDelayString:与fixedDelay含义一样,只是参数类型变为String;
fixedRate:表示按一定的频率执行任务,参数类型为long,单位ms;
fixedRateString: 与fixedRate的含义一样,只是将参数类型变为String;
initialDelay:表示延迟多久再第一次执行任务,参数类型为long,单位ms;
initialDelayString:与initialDelay的含义一样,只是将参数类型变为String;
zone:时区,默认为当前时区,一般没有用到。

容器

List
List list = new ArrayList<>();
List list = new LinkedList<>();
List list = List.of(1, 2, 5)
Set
Set set = new HashSet<>();
Map
Map<String, Student> map = new HashMap<>();
Queue
Queue q = new LinkedList<>();

maven使用 protobuf 插件

org.xolstice.maven.plugins protobuf-maven-plugin 0.5.1 src/main/resources/proto/protoc.exe src/main/resources/proto src/main/java false compile test-compile

4. fastjson

maven依赖

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

java对象和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
29
30
31
32
33
34
public class Person {
     
    @JSONField(name = "AGE")
    private int age;
 
    @JSONField(name = "FULL NAME")
    private String fullName;
 
    @JSONField(name = "DATE OF BIRTH")
    private Date dateOfBirth;
 
    public Person(int age, String fullName, Date dateOfBirth) {
        super();
        this.age = age;
        this.fullName= fullName;
        this.dateOfBirth = dateOfBirth;
    }
 
    // 标准 getters & setters
}

@JSONField(name = "AGE", serialize = false)

// java -> json
String jsonOutput= JSON.toJSONString(Person);
// 或
private List<Person> PersonsList = new ArrayList<Person>();
String jsonOutput= JSON.toJSONString(PersonsList);

// json string -> java
Person newPerson = JSON.parseObject(jsonOutput, Person.class);

// json string -> JSONObject
JSONObject j = JSONObject.parseObject(str);

创建 json

只需使用 JSONObject(fastJson提供的json对象) 和 JSONArray(fastJson提供json数组对象) 对象即可。

1
2
3
4
5
6
7
8
9
10
11
12
@Test
public void whenGenerateJson_thanGenerationCorrect() throws ParseException {
JSONArray jsonArray = new JSONArray();
for (int i = 0; i < 2; i++) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("AGE", 10);
jsonObject.put("FULL NAME", "Doe " + i);
jsonObject.put("DATE OF BIRTH", "2016/12/12 12:12:12");
jsonArray.add(jsonObject);
}
String jsonOutput = jsonArray.toJSONString();
}

JSONPath

使用jsonpath访问json字段
List list_of_string = (List) JSONPath.eval(ds.getMsg(), “$.BaseLocationInfo.ListOfObject”);

5. protobuf使用

  1. 定义proto结构 Person.proto

    1
    2
    3
    4
    5
    6
    syntax = "proto3";

    message Person {
    string name = 1;
    int32 age = 2;
    }
  2. 生成java类
    protoc -I=./ –java_out=./ Person.proto
    生成 Person.java 文件

Builder 可以修改,Message不可以修改

  1. 序列化

    1
    2
    3
    4
    5
    6
    7
    Person person = Person.newBuilder()
    .setName("张三")
    .setAge(25)
    .build();

    // 转换成字节流
    byte[] data = person.toByteArray();
  2. 反序列化

    1
    2
    3
    4
    5
    byte[] receivedData =...;
    Person receivedPerson = Person.parseFrom(receivedData);

    String name = receivedPerson.getName();
    int age = receivedPerson.getAge();

时间

  • 时间戳
    System.currentTimeMillis()

  • Date
    Date date = new Date(); // 当前时间
    date.toString() // 转换为String
    date.toGMTString() // 转GMT时区
    date.toLocaleString(); // 转本地时区
    (new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss.SSS”)).format(date) // 转格式

Date 1. 不能转时区,总是以计算机当前时区为基础; 2. 不能加减

  • Calendar
    比Date多了一个日期和时间运算

Calendar c = Calendar.getInstance(); // 当前时间
利用Calendar.getTime()可以将一个Calendar对象转换成Date对象,然后就可以用SimpleDateFormat进行格式化了。

  • TimeZone
    比 Date 和 Calendar 多了时区转换

TimeZone tzDefault = TimeZone.getDefault(); // 当前时区
TimeZone tzGMT9 = TimeZone.getTimeZone(“GMT+09:00”); // GMT+9:00时区

加入时区的时间转换
// 当前时间:
Calendar c = Calendar.getInstance();
// 清除所有:
c.clear();
// 设置为北京时区:
c.setTimeZone(TimeZone.getTimeZone(“Asia/Shanghai”));
// 设置年月日时分秒:
c.set(2019, 10 /* 11月 */, 20, 8, 15, 0);

  • LocalDateTime, 8开始的新API,最常用, 不涉及时区的都能用这个
    LocalDateTime dt = LocalDateTime.now(); // 当前日期和时间

注意ISO 8601规定的日期和时间分隔符是T。标准格式如下:
日期:yyyy-MM-dd
时间:HH:mm:ss
带毫秒的时间:HH:mm:ss.SSS
日期和时间:yyyy-MM-dd’T’HH:mm:ss
带毫秒的日期和时间:yyyy-MM-dd’T’HH:mm:ss.SSS
LocalDateTime dt = LocalDateTime.parse(“2019-11-19T15:16:17”);

// 自定义格式化:
DateTimeFormatter dtf = DateTimeFormatter.ofPattern(“yyyy/MM/dd HH:mm:ss”);
dtf.format(LocalDateTime.now());
// 用自定义格式解析:
LocalDateTime dt2 = LocalDateTime.parse(“2019/11/30 15:16:17”, dtf);

// 加5天减3小时:
LocalDateTime dt2 = dt.plusDays(5).minusHours(3);

// 两时刻间隔
Duration d = Duration.between(start, end);
// 两时间天数
Period p = LocalDate.of(2019, 11, 19).until(LocalDate.of(2020, 1, 9));

缺点: LocalDateTime无法与时间戳进行转换,因为LocalDateTime没有时区,无法确定某一时刻; ZonedDateTime 可以

  • ZonedDateTime: LocalDateTime + ZoneId

ZonedDateTime zbj = ZonedDateTime.now();

  • Instant 当前时间戳
    Instant now = Instant.now();
    System.out.println(now.getEpochSecond()); // 秒
    System.out.println(now.toEpochMilli()); // 毫秒

// 以指定时间戳创建Instant:
Instant ins = Instant.ofEpochSecond(1568568760);
ZonedDateTime zdt = ins.atZone(ZoneId.systemDefault());

几个时间的总体关系
LocalDateTime + ZoneId = ZonedDateTime <—> Instant <—> long

spring boot 单元测试

org.springframework.boot spring-boot-starter-test test

文件

  • 接口
    字节流
    InputStream
    OutputStream

  • 基础数据来源
    FileInputStream
    ByteArrayInputStream
    ServletInputStream

  • 附加功能
    BufferedInputStream
    DigestInputStream
    CipherInputStream

try (InputStream input = new FileInputStream(“src/readme.txt”)) {
int n;
while ((n = input.read()) != -1) {
System.out.println(n);
}
} // 编译器在此自动为我们写入finally并调用close()

  • ByteArrayInputStream会模拟一个输入流
    byte[] data = { 72, 101, 108, 108, 111, 33 };
    try (InputStream input = new ByteArrayInputStream(data)) {}

  • 字符流接口
    Reader

try (Reader reader = new FileReader(“src/readme.txt”, StandardCharsets.UTF_8) {
// TODO
}

CharArrayReader,StringReader 模拟输入流

  • spring 读入文件
    Resource res = new FileSystemResourceLoader().getResource(“classpath:test-car-info.txt”);
    try (BufferedReader r = new BufferedReader(new InputStreamReader(res.getInputStream(), StandardCharsets.UTF_8))) {
    r.lines().forEach(l -> {

带值初始化列表

  1. List list = Arrays.asList(“foo”, “bar”);
    固定长度,元素共享;因为底层用的是 String[] 固定长度数组

  2. List list = Stream.of(“foo”, “bar”).collect(Collectors.toList());
    8开始

  3. List list = List.of(“foo”, “bar”, “baz”);
    9开始

map insert or update

m.put(key, m.getOrDefault(key, 0)+ 10);

字符和字符串

byte[] 字节流, 8位
char[] 字符流, 保存1个 Unicode 字符, 占2字节
Java的String和char在内存中总是以Unicode编码表示

格式化字符串 String.format(“%.2f”, 0.2F);

类型转换
String.valueOf(123F);

  • char[] –> String
    char[] cs = “Hello”.toCharArray();

  • byte[] <–> string
    byte[] bs = “Hello”.getBytes();
    byte[] bs = “Hello”.getBytes(“UTF-8”);
    byte[] bs = “Hello”.getBytes(StandardCharsets.UTF_8); // 转成其他编码
    String s = new String(bs, “GBK”); // byte[] 转成String

  • byte[] -> hex
    HexFormat hf = HexFormat.of();
    String hex = hf.formatHex(bs);

byte[] bs = HexFormat.of().parseHex(“48656c6c6f”);

springboot 启动时执行任务

两种方式:

  1. CommandLineRunner
    实现 run 方法;
    如果有多个实现,按照 @Order 顺序执行;
    参数是main传入的参数;

  2. ApplicationRunner
    实现 run 方法;
    如果有多个实现,按照 @Order 顺序执行;
    参数是 ApplicationArguments

遍历 map

(1) 如果只获取 key 或者 value, 推荐使用 keySet() 或 values() 方法;
(2) 如果需要同时获取 key 和value, 推荐使用 entrySet;
(3) 如果需要在遍历过程中删除元素, 推荐使用 Iterator;
(4) 如果需要在遍历过程中添加元素, 可以新建一个临时 Map 存放新增的元素, 遍历结束后, 再把临时 Map 添加到原 Map 中.