…
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就是一个组件
- 用XML创建组件和说明组件之间的关系
<property name=”” ref=””或value=””> ,
使用set()属性注入或者构造函数注入;
- 用注释配置
@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- 创建全局DataSource实例,表示数据库连接池;
- 在需要读写数据库的方法内部,按如下步骤访问数据库:
从全局DataSource实例获取Connection实例;
通过Connection实例创建PreparedStatement实例;
执行SQL语句,如果是查询,则通过ResultSet读取结果集,如果是修改,则获得int结果。
使用spring连接
- JdbcTemplate 对 JDBC 的一种简单封装
使用IoC创建并管理一个DataSouce实例,然后spring提供了一个 JdbcTemplate,方便操作JDBC,通常会实例化一个JdbcTemplateJdbcTemplate方法: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
public class AppConfig {
String jdbcUrl;
String jdbcUsername;
String jdbcPassword;
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);
}
JdbcTemplate createJdbcTemplate( { DataSource dataSource)
return new JdbcTemplate(dataSource);
}
}
// 通过@PropertySource("jdbc.properties")读取数据库配置文件;
// 通过@Value("${jdbc.url}")注入配置文件的相关配置;
// 创建一个DataSource实例,它的实际类型是HikariDataSource,创建时需要用到注入的配置;
// 创建一个JdbcTemplate实例,它需要注入DataSource,这是通过方法参数完成注入的。
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
List
Set
Set
Map
Map<String, Student> map = new HashMap<>();
Queue
Queue
maven使用 protobuf 插件
4. fastjson
maven依赖
1 | <dependency> |
java对象和json字符串转换
1 | public class Person { |
创建 json
只需使用 JSONObject(fastJson提供的json对象) 和 JSONArray(fastJson提供json数组对象) 对象即可。
1 | @Test |
JSONPath
使用jsonpath访问json字段
List
5. protobuf使用
定义proto结构 Person.proto
1
2
3
4
5
6syntax = "proto3";
message Person {
string name = 1;
int32 age = 2;
}生成java类
protoc -I=./ –java_out=./ Person.proto
生成 Person.java 文件
Builder 可以修改,Message不可以修改
序列化
1
2
3
4
5
6
7Person person = Person.newBuilder()
.setName("张三")
.setAge(25)
.build();
// 转换成字节流
byte[] data = person.toByteArray();反序列化
1
2
3
4
5byte[] 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 单元测试
文件
接口
字节流
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 -> {
带值初始化列表
List
list = Arrays.asList(“foo”, “bar”);
固定长度,元素共享;因为底层用的是 String[] 固定长度数组List
list = Stream.of(“foo”, “bar”).collect(Collectors.toList());
8开始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[] 转成Stringbyte[] -> hex
HexFormat hf = HexFormat.of();
String hex = hf.formatHex(bs);
byte[] bs = HexFormat.of().parseHex(“48656c6c6f”);
springboot 启动时执行任务
两种方式:
CommandLineRunner
实现 run 方法;
如果有多个实现,按照 @Order 顺序执行;
参数是main传入的参数;ApplicationRunner
实现 run 方法;
如果有多个实现,按照 @Order 顺序执行;
参数是 ApplicationArguments
遍历 map
(1) 如果只获取 key 或者 value, 推荐使用 keySet() 或 values() 方法;
(2) 如果需要同时获取 key 和value, 推荐使用 entrySet;
(3) 如果需要在遍历过程中删除元素, 推荐使用 Iterator;
(4) 如果需要在遍历过程中添加元素, 可以新建一个临时 Map 存放新增的元素, 遍历结束后, 再把临时 Map 添加到原 Map 中.