一、Assert.notNull
Assert.notNull(status, "HttpStatus must not be null"); //判断传进来的参数值是否不为空值
二、@Transactional 详解
接口实现类或接口实现方法上,而不是接口类中。
@Transactional 注解应该只被应用到 public 方法上
三、@SelectKey
@SelectKey(statement=“SELECT LAST_INSERT_ID()”, keyProperty=“boardId”, before=false, resultType=String.class)
主要是用于在进行sql语句的操作时,将一些数据查询出来放入到对象的字段中。即有时候新增一条数据不仅仅知道成功就行了,后面的逻辑可能还需要这个新增的主键,这时候可以避免再次查询数据库。
在Mybatis中是为了解决Insert数据时不支持主键自动生成的问题。
参考
四、Optional.ofNullable
Optional.ofNullable(tIpBoard) 实际内容就是返回tipBoard的值
五、java执行顺序
父类静态变量–》父类静态代码块–》–》子类静态变量–》子类静态代码块–》父类非静态变量–》父类非静态代码块–》 父类构造方法–》子类非静态变量–》子类非静态代码块–》子类构造方法
六、Math.toIntExact
当我们需要将一个long类型的值,转换成int类型的值的时候,我们可以使用Math.toIntExact来完成转换。
七、DATE_FORMAT
DATE_FORMAT(date,format) date 参数是合法的日期。format 规定日期/时间的输出格式。
1、获取年月日
DATE_FORMAT(a.ts
, ‘%Y-%m-%d’) //2020-11-02
2、获取时分秒
DATE_FORMAT(a.ts
, ‘%T’) 或者 DATE_FORMAT(a.ts
, ‘%H:%i:%s’)
八、public void method(),void前面的泛型T是什么?
public <T>这个T是个修饰符的功能,表示是个泛型方法,就像有static修饰的方法是个静态方法一样。
注意<T> 不是返回值,此处的返回值是void ,此处的<T> 表示传入参数有泛型,<T>存在的作用,是为了保证参数中能够出现T这种数据类型。
e.g: public static <T> list<T> Method(T t,Object obj,...) ;
第一个 <T>表示Method()是泛型方法,第二个<T>表示返回值是list类型,且list里面都是<T>类型的值,即list 中只能存T类型的数据。
九、Class
在Java中,每个 class 都有一个相应的 Class 对象。也就是说,当我们编写一个类,编译完成后,在生成的.class文件中,就会产生一个 Class 对象,用于表示这个类的类型信息
获取 Class 实例的三种方式:
(1) :利用 对象调用 getClass()方法 获取该对象的Class实例;
(2) :使用 Class类的静态方法 forName(),用类的名字获取一个Class实例(staticClass forName(String className) Returns the Classobject associated with the class or interface with the given stringname. );
(3) :运用 .class 的方式来获取 Class 实例,对于基本数据类型的封装类,还可以采用 .TYPE 来获取相对应的基本数据类型的Class实例
九、ServletOutputStream
HttpServletResponse response = null;
ServletOutputStream outputStream = response.getOutputStream();
这是一个由 Servlet 引擎使用的抽象类。Servlet 通过使用 ServletResponse 接口的使用获得了对一个这种类型的对象的说明。利用这个输出流可以将数据返回到客户端。
在这个接口中, 当一个刷新或关闭的方法被调用时。 所有数据缓冲区的信息将会被发送到客户端,也就是说响应被提交了。请注意,关闭这种类型的对象时不一定要关闭隐含的socket 流。
更多
十、响应头部
//去除首部空白行
response.reset();
//跨域——则允许所有域名的脚本访问该资源
response.setHeader("Access-Control-Allow-Origin", "*");
缓存控制
在http中,控制缓存开关的字段有两个:Pragma 和 Cache-Control。
——Pragma
Pragma有两个字段Pragma和Expires。Pragma的值为no-cache时,表示禁用缓存,Expires的值是一个GMT时间,表示该缓存的有效时间。Pragma是旧产物,已经逐步抛弃。
如果一个报文中同时出现,优先级从高到低是 Pragma -> Cache-Control -> Expires
——Cache-Control
Cache-Control除了在响应中使用,在请求中也可以使用
————在请求中使用Cache-Control 时,它可选的值有:
————在响应中使用Cache-Control 时,它可选的值有:
response.setHeader("Cache-Control", "no-cache");
十一、response.setContentType(MIME)
response.setContentType(MIME)的作用是使客户端浏览器,区分不同种类的数据,并根据不同的MIME调用浏览器内不同的程序嵌入模块来处理相应的数据。
response.setContentType("application/vnd.ms-excel;charset=utf-8");//让浏览器知道返回的是excel
十二、常用请求头、消息头
常用请求头
Accept: 接收类型,表示浏览器支持的MIME类型 (对标服务端返回的Content-Type)
Accept-Encoding:浏览器支持的压缩类型,如gzip等,超出类型不能接收
Content-Type:客户端发送出去实体内容的类型
Cache-Control: 指定请求和响应遵循的缓存机制,如no-cache
If-Modified-Since:对应服务端的Last-Modified,用来匹配看文件是否变动,只能精确到1s之内,http1.0中
Expires:缓存控制,在这个时间内不会请求,直接使用缓存,http1.0,而且是服务端时间
Max-age:代表资源在本地缓存多少秒,有效时间内不会请求,而是使用缓存,http1.1中
If-None-Match:对应服务端的ETag,用来匹配文件内容是否改变(非常精确),http1.1中
Cookie: 有cookie并且同域访问时会自动带上
Connection: 当浏览器与服务器通信时对于长连接如何进行处理,如keep-alive
Host:请求的服务器URL
Origin:最初的请求是从哪里发起的(只会精确到端口),Origin比Referer更尊重隐私
Referer:该页面的来源URL(适用于所有类型的请求,会精确到详细页面地址,csrf拦截常用到这个字段)
User-Agent:用户客户端的一些必要信息,如UA头部等
常用响应头
Access-Control-Allow-Headers: 服务器端允许的请求Headers
Access-Control-Allow-Methods: 服务器端允许的请求方法
Access-Control-Allow-Origin: 服务器端允许的请求Origin头部(譬如为*)
Content-Type:服务端返回的实体内容的类型
Date:数据从服务器发送的时间
Cache-Control:告诉浏览器或其他客户,什么环境可以安全的缓存文档
Last-Modified:请求资源的最后修改时间
Expires:应该在什么时候认为文档已经过期,从而不再缓存它
Max-age:客户端的本地资源应该缓存多少秒,开启了Cache-Control后有效
ETag:请求变量的实体标签的当前值
Set-Cookie:设置和页面关联的cookie,服务器通过这个头部把cookie传给客户端
Keep-Alive:如果客户端有keep-alive,服务端也会有响应(如timeout=38)
Server:服务器的一些相关信息
十三、状态码
1xx——指示信息,表示请求已接收,继续处理 2xx——成功,表示请求已被成功接收、理解、接受
3xx——重定向,要完成请求必须进行更进一步的 操作 4xx——客户端错误,请求有语法错误或请求无法实现
5xx——服务器端错误,服务器未能实现合法的请求
200–表明请求被成功的完成,所请求的资源发送回客户端 304–自从上次请i去后,请求的网页没有修改,请客户端使用本地缓存
400–客户端请求有错误(可能是安全等模块拦截了) 401–请求未经授权 403–禁止访问(比如未登录时的禁止访问)
404–资源找不到 500–服务器内部错误 503–服务不可用
十四、Content-disposition
一、作用:
1)希望某类或者某已知MIME类型的文件(比如:.doc;.jpg;*.htm)能够在访问时弹出"文件下载对话框"
2)希望客户端下载时以指定文件名显示
3)希望某文件被点击后才弹出文件下载对话框
二、使用语句:
response.setHeader(“Content-disposition”, “attachment;filename=” +filename);
Content-disposition:属性名
attachment:表示以附件方式下载,如果要在页面中打开,可以改为inline.
注意:filename如果是中文会出现乱码:解决办法:
1、将filename 替换为 new String(filename.getBytes(), “ISO8859-1”);
2、将filename 替换为 URLEncoder.encode(filename, “utf-8”);
如:
response.setHeader("Content-Disposition", "attachment;filename=" + new String((fileName + ".xls").getBytes(), "utf-8"));
十五、@NumberFormat
@NumberFormat(pattern=“#,###”) 用来格式化货币(这样前端得传形如1,000。而不能是1000了,如果小数位后边有多个,只取3个。
十六、构建者模式
在实体类中定义本类名的静态内,并具有和实体类形同的属性(称为构建器),必要的参数在Build的构造方法写,不必要的类似set写,但是不加set。简单设置请参考地址和地址2。
@Builder注解:
@Builder 可以放在类,构造函数或方法上。 虽然放在类上和放在构造函数上这两种模式是最常见的用例,但 @Builder 最容易用放在方法的用例来解释。
参考
lombok 基础注解之 @Singular
- 作用于集合字段,需要配合 @Builder 使用
- 使用 @Singular 注解一个集合字段(如果没有指定 value 属性值,那么集合字段名需要是复数形式),会生成两个添加元素方法
一个向集合添加单个元素(方法名:集合字段名的单数形式 / value 属性值)
一个将另一个集合的所有元素添加到集合中(方法名:集合字段名) - 还生成了 clear 方法(方法名:clear + 集合字段名,驼峰命名)。 这些 singular
构建器相对而言是有些复杂的,主要是来保证以下特性: 在调用 build 方法时,生成的集合是不可变的 在调用 build
方法之后调用其中一个添加元素方法或 clear 方法不会修改任何已经生成的对象。如果对集合修改之后,再调用 build
方法,则会创建一个基于上一个对象创建的对象实体 生成的集合将被压缩到最小的可行格式,同时保持高效 - @Singular 只能应用于 lombok 已知的集合类型。目前,支持的类型有: Iterable、Collection、List
(一般情况下,生成的不可修改的 ArrayList) Set、SortedSet、NavigableSet
(一般情况下,生成可变大小不可修改的 HashSet 或者 TreeSet) Map、SortedMap、NavigableMap
(一般情况下,生成可变大小不可修改的 HashMap 或者 TreeMap) - 在调用 build 方法来创建实例对象时, 并没有直接使用 Collections.unmodifiableList(Collection
c) 此方法来创建实例,而是分为三种情况 第一种,当集合中没有元素时,创建一个空集合
第二种,当集合中存在一个元素时,创建一个不可变的单元素集合 第三种,根据当前集合的元素数量创建对应合适大小的集合
参考和参考2
十七、Integer包装类
public void test(){
Integer i1 = 10;
Integer i2 = 10;
Integer i3 = new Integer(10);//新对象
Integer i4 = new Integer(10);//新对象
Integer i5 = Integer.valueOf(10);//从缓存池里面获取。
Integer i6 = Integer.valueOf(128);
Integer i7 = 128;
System.out.println(i1 == i2); // true
System.out.println(i2 == i3); // false
System.out.println(i3 == i4); // false
System.out.println(i1 == i5); // true
System.out.println(i6 == i7); // false
}
//运行结果:
true
false
false
true
false
为啥Integer i1 =10 跟Integer.valueOf(10) 是相等的?
因为Integer i1 = 10 底层原理是 Integer i1 = Integer.valueof(10)
为啥Integer i1 =128 跟Integer.valueOf(128) 是不相等的?
因为超过-128~127 这个范围,就不在缓存池里面,不能共享都是新new 出来的
问题:包装类对象池是不是 JVM 常量池的一种?
包装类的对象池是池化技术的应用,并非是虚拟机层面的东西,而是 Java 在类封装里实现的,IntegerCache 是 Integer在内部维护的一个静态内部类,用于对象缓存。
Integer 对象池在底层实际上就是一个变量名为 cache 的数组,里面包含了 -128 ~ 127 的 Integer 对象实例。使用对象池的方法就是通过 Integer.valueOf() 返回 cache 中的对象,像 Integer i = 10这种自动装箱实际上也是调用 Integer.valueOf() 完成的
这和常量池中字面量的保存有很大区别,Integer 不需要显示地出现在代码中才添加到池中,初始化时它已经包含了所有需要缓存的对象
十八、String常量池
案例:
public static void main(String[] args) {
String a = "a";
String b = "b";
String c = "a" + "b";
//生成两个对象 一个"ab" ,一个新的String 对象value 值是ab
//public String(String original) {
// this.value = original.value;
// this.hash = original.hash;
//}
String d = new String("ab");
String e = a + "b";
String f = a + b;
String g = "ab";
System.out.println(e == c);
System.out.println(c == d);
System.out.println(f == c);
System.out.println(g == c);
String e1 = e.intern();
String c2 = c.intern();
System.out.println(e1 == c2);
System.out.println(e1 == c);
}
//运行结果
false
false
false
true
true
true
String c =“a” + “b” 和String c = “a” + b (String b= “b”)的区别
String b = “b”;
String c = “a” + “b”; 等价于 String c =“ab”
String c1 = “a” + b;
“a” + b(变量)
先new 了StringBuilder 对象,并初始化init
然后bulider.append(“a”)
从变量1(b)中取出值"b"
然后执行了bulider.append(“b”)
最后执行了builder.toString() 方法 给变量3( c1)进行赋值
new string(“abc”)创建了几个对象
是两个 ,new string(xxxx)方法,xxxx传入的是String对象。说明xxxx也是String对象。
解析public native String intern() 方法
如果常量池中存在当前字符串, 就会直接返回当前字符串. 如果常量池中没有此字符串, 会将此字符串放入常量池中后, 再返回
参考
十九、instanceof
instanceof是Java的一个保留关键字,左边是对象,右边是类,返回类型是Boolean类型。它的具体作用是测试左边的对象是否是右边类或者该类的子类创建的实列对象,是,则返回true,否则返回false。
instanceof使用注意事项
1、先有继承关系,再有instanceof的使用
2、当该测试对象创建时右边的声明类型和左边的类其中的任意一个跟测试类必须得是继承树的同一分支或存在继承关系,否则编译器会报错
二十、String,StringBuffer与StringBuilder的区别?
String 字符串常量
StringBuffer 字符串变量(线程安全)
StringBuilder 字符串变量(非线程安全)
- String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变的对象, 因此在每次对 String
类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象 - 每次结果都会对 StringBuffer 对象本身进行操作,而不是生成新的对象,再改变对象引用。所以在一般情况下我们推荐使用
StringBuffer ,特别是字符串对象经常改变的情况下。 - 在大部分情况下 StringBuffer > String
- 在大部分情况下 StringBuilder > StringBuffer
二十一、String常用方法
1.字符和字符串
2.字节和字符串
字节使用byte描述,字节一般主要用于数据的传输或编码的转换,而在String类里面提供了将字符串转换为字节数组的操作,就是为了传输已经编码转换。
3.字符串比较
compare()方法在比较字符串大小时,根据字符串数据的编码差值的方式来判断(如果第一个相同则继续后续内容判断)。如果要结合分支或循环语句来操作则可以利用compareTo()的返回结果数值来作为判断条件
4.字符串查找
5.字符串替换
观察替换的结果:
package stringmethon;
/**
* 字符串的替换
*/
public class StringDemo {
public static void main(String[] args) {
String str="helloworld";//实例化字符串对象
String stra=str.replaceAll("l","*");//全部替换
String strb=str.replaceFirst("l","&");//替换首个
System.out.println(stra);
System.out.println(strb);
//程序执行结果为: he**owor*d
// he&loworld
}
}
注意:这两个方法都会返回替换完成后的新字符串内容
6.字符串截取
7.字符串拆分
进行全部拆分
package stringmethon;
/**
* 字符串全部拆分
*/
public class StringDemo{
public static void main(String[] args) {
String str="he ij wqs dwed sda f";//定义字符串,中间用空格隔开
String[] data=str.split(" ");//字符串拆分
//遍历数组
for (int i = 0; i < data.length; i++) {
System.out.print(data[i]+"、");
}
//程序执行结果为:he、ij、wqs、dwed、sda、f、
}
}
如果使用空字符串则表示根据每个字符拆分(不是null)
package stringmethon;
/**
* 字符串全部拆分
*/
public class StringDemo {
public static void main(String[] args) {
String str="he ij wqs dwed sda f";//定义字符串,中间用空格隔开
String[] data=str.split("");//字符串拆分
//遍历数组
for (int i = 0; i < data.length; i++) {
System.out.print(data[i]+"、");
}
//程序执行结果为:h、e、 、i、j、 、w、q、s、 、d、w、e、d、 、s、d、a、 、f、
}
}
拆分为指定个数
package stringmethon;
/**
* 字符串指定个数拆分
*/
public class StringDemo {
public static void main(String[] args) {
String str="diwd wf frew fwfc sac e c";//定义字符串,中间用空格隔开
String[] data=str.split(" ",3);//字符串拆分
//遍历数组
for (int i = 0; i < data.length; i++) {
System.out.println(data[i]);
}
//程序输出结果为:diwd
// wf
// frew fwfc sac e c
}
}
实际上split()方法的字符串拆分能否正常进行,与正则表达式有关,所以有些时候会出现无法拆分的情况。例如:给出一个IP地址(192.168.1.2),那么肯定首先想的是根据".“进行拆分,而如果直接使用”.“是不可能进行拆分的,如果想要正常执行,就必须对要拆分的”. “进行转义,使用”\"进行描述
package stringmethon;
/**
* 转义操作进行拆分
*/
public class StringDemo {
public static void main(String[] args) {
String str="192.168.1.2";//定义字符串
String[] data=str.split("\\.");//字符串拆分
//遍历数组
for (int i = 0; i < data.length; i++) {
System.out.print(data[i]+"、");
}
//程序执行结果为:192、168、1、2、
}
}
复杂拆分
package stringmethon;
/**
* 字符串的复杂拆分
*/
public class StringDemo {
public static void main(String[] args) {
String str="张三:20|李四:21|王五:22";//定义字符串
String[] data=str.split("\\|");//第一次拆分
//遍历数组
for (int i = 0; i < data.length; i++) {
String[] temp=data[i].split(":"); //第二次拆分
System.out.println("姓名:"+temp[0]+" "+"年龄:"+temp[1]);
}
}
}
//程序运行结果为:姓名:张三 年龄:20
// 姓名:李四 年龄:21
// 姓名:王五 年龄:22
其他方法:
二十二、Integer常用方法
装箱 Integer a = new Integer (1);
自动装箱 Integer a = 1;
二十三、@Options(useGeneratedKeys=true, keyProperty=“id”)
useGeneratedKeys =true 这个表示插入数据之后返回一个自增的主键id给你对应实体类中的主键属性。通过这个设置可以解决在主键自增的情况下通过实体的getter方法获取主键(当然还需要keyproperty指明数据库中返回的主键id给实体类中的哪个属性)。
keyproperty=主键,这样就可以解决在主键自增的情况下获取主键。
十二四、@Param注解的用法
- 当使用了@Param注解来声明参数的时候,SQL语句取值使用#{},${}取值都可以。
- 当不使用@Param注解声明参数的时候,必须使用的是#{}来取参数。使用${}方式取值会报错。
更多
二十五、@Valid
如果不是SpringBoot项目,需要引入如下依赖:
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.4.1.Final</version>
</dependency>
需要在实体类上引入类似如下注解:
public class Employee {
/** 姓名 */
@NotBlank(message = "请输入名称")
@Length(message = "名称不能超过个 {max} 字符", max = 10)
public String name;
/** 年龄 */
@NotNull(message = "请输入年龄")
@Range(message = "年龄范围为 {min} 到 {max} 之间", min = 1, max = 100)
public Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
在 Controller 对应方法上,对这个员工标上 @Valid 注解,表示我们对这个对象属性需要进行验证
既然验证,那么就肯定会有验证结果,所以我们需要用一个东西来存放验证结果,做法也很简单,在参数直接添加一个BindingResult,具体如下:
对应获取验证结果的代码如下:
@Valid与@Validated区别
@Validated:可以用在类型、方法和方法参数上。但是不能用在成员属性(字段)上,不支持嵌套检测
@Valid:可以用在方法、构造函数、方法参数和成员属性(字段)上,支持嵌套检测
注意:SpringBoot使用@Valid注解需要引入如下POM
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
Vaild和Validated需要配合使用
参考
二十六、@Qualifier和@Autowire
是否可以单独使用Qualifier?
- 修饰 成员变量,此时必须搭配 @Autowired 使用
- 修饰 方法形参,可单独使用
@Autowired会先按byType去找,如果没找到,则会按照byName去找
@Resource会先按byName去找,如果没找到则会byType去找。如果设置了name属性,则只会按byName去找,找不到就报错。