# Object

Object类是所有类的父类,所有的类都直接或者间接的继承自Object类,一个类如果没有父类,默认继承自Object类

  • toString()方法:返回对象的字符串表示,默认是由类的全路径+'@'+哈希值的十六进制表示。这个表示其实是没有意义的,一般子类都会重写该方法,例如String类,Integer类等等
  • equals() 方法:比较两个对象是否相同。默认情况下,比较的是地址值是否相同。而比较地址值是没有意义的,所以,一般子类也会重写该方法
//使用 Objects.equals 方法判断两个值是否相等时,一定要保证两个入参的类型要一致
Integer a = 1;
long b = 1L;
System.out.println(Objects.equals(a,b));
//结果:false

//如果直接用包装类的 equals 方法,有个问题就是可能存在报空指针异常的风险
String e = null;
String f = "abc";
System.out.println(e.equals(f)); 
//结果:NullPointerException

# System

System.exit(int status) //终止当前的java虚拟机,非零表示异常终止
System.currentTimeMillis() //返回当前的时间(毫秒为单位)
new Scanner(System.in) //System.in代表输入
System.out.println() //System.out代表输出
System.arraycopy(srcArray,0,descArray,0,srcArray.length) //复制的方法
System.gc() //运行垃圾回收器

# 基本类型包装类

# Integer类

//构造函数
public Integer(int value)   
public Integer(String s) //注意:s必须得是数字字符

//常用方法
public static Integer valueOf(int i) //返回int值的Integer实例
//注意:根据String值创建Interger对象,String值只能是数字
public static Integer valueOf(String s) //返回字符串值的Integer实例

public static String toBinaryString(int i):返回二进制                          
public static String toOctalString(int i):返回八进制                       
public static String toHexString(int i):返回16进制
//重写的toString方法,返回radix进制
public static String toString(int i,int radix):进制最大为36进制。因为数字加字母总数为36

int和String的相互转换

public static String valueOf(int i)Stringint。该方法是String类中的方法
public static int parseInt(String s)intString。该方法是Integer类中的方法

# Charactor类

Character类是char类型的包装类,它是对一个字符类型的变量进行操作。其实可以看成是对字符进行操作的一个工具类。

//构造方法:构造一个新分配的Character对象,代表指定的char值。
public Character(char value)      

//常用方法
public static boolean isDigit():判断是否是数字
public static boolean isLetter():判断是否是字母
public static boolean isUpperCase()/isLowerCase():判断是否是大写/小写
public static boolean isWhiteSpace():判断是否为空格
public static char toUpperCase()/toLowerCase():转大写/小写
public static String toString():返回字符的字符串形式,字符串的长度仅为1

# BigInteger类

BigInteger:可以让超过Integer范围内的数据进行运算

//构造方法
public BigInteger(String val) 

//常用方法
public BigInteger add(BigInteger val):public BigInteger subtract(BigInteger val):public BigInteger multiply(BigInteger val):public BigInteger divide(BigInteger val):public BigInteger[] divideAndRemainder(BigInteger val):返回商和余数的数组

# BigDecimal类

由于在运算的时候,float类型和double很容易丢失精度。所以,为了能精确的表示、计算浮点数,Java提供了BigDecimal。 BigDecimal类:不可变的、任意精度的有符号十进制数,可以解决数据丢失问题。

//构造方法
public BigDecimal(String val)

//成员方法
public BigDecimal add(BigDecimal augend)public BigDecimal subtract(BigDecimal subtrahend)public BigDecimal multiply(BigDecimal multiplicand)public BigDecimal divide(BigDecimal divisor)public BigDecimal divide(BigDecimal divisor,int scale,int roundingMode):商,几位小数

# 字符串 String

# String

String类在java.lang包下,所以使用的时候不需要导包
通过new创建字符串对象,每次new都会申请一个栈内存空间,即使内容相同,地址也不会相同

new String():创建一个空白字符串对象,不含有任何内容
new String(char[] chs):根据字符数组的内容,来创建字符串对象
new String(byte[] bys):根据字节数组的内容,来创建字符串对象
new String("abc"):直接赋值的方式

s1.equals(s2):比较字符串s1和s2是否相等(区分大小写)
s1.equalsIgnoreCase(s2):比较字符串s1和s2是否相等(不区分大小写)
s1.contains(s2):判断是否包含字符串s2
s1.startsWith(s2):判断字符串是否以字符串s2开头
s1.endsWith(s2):判断字符串是否以字符串s2结尾
s1.isEmpty():判断字符串是否为空

char charAt(int index):获取索引值为index的字符
int indexOf(int ch):返回指定字符在该字符串里出现的第一次位置的索引
int indexOf(String str):返回指定符串在该字符串里出现的第一次位置的索引
int indexOf(int ch,int fromIndex):返回指定字符在此字符串中从指定位置后第一次出现处的索引
int indexOf(String str,int fromIndex):返回指定字符串在此字符串中从指定位置后第一次出现处的索引
String subString(int start) 从指定位置开始截取字符串,默认到末尾。包含start这个索引
String subString(int start ,int end) 从指定位置开始到指定位置结束截取字符串。左包右不包

byte getBytes() 字符串转字节数组
char[] toCharArray() 字符串转字符数组
static valueof(……) 可以将任意类型的数据转换为字符串,经常用这个方法
String toLowerCase()/toUpperCase() 转小写/大写
String concat(String str) 与字符串str拼接

String replace(char old,char new) 把字符串中含有的所有的指定的字符替换为新的字符
String replace(String old,String new)  把字符串中含有的所有的指定的字符串 替换为新的字符串 
String trim() 去除字符串两边的空格并返回
int compareTo(String str)  按字典返回两个字符串的大小

注意 split | (竖线)

在java中直接用split("|")是不行的,需要转义

String line = "866|10|1824261|214|";
String[] cells = line.split("\\|");

# StringBuilder

StringBuilder类在java.lang包下,是一个内容可变的字符串类
String对字符串进行拼接操作,每次拼接都会构建一个新的String对象,即耗时又浪费你内存
String对字符串进行拼接操作

sb.reverse():返回相反的字符序列

# StringBuffer

StringBuilder类在java.lang包下,StringBuffer是线程安全的,所以在多线程程序中也可以很方便的进行使用,但是程序的执行效率相对来说就要稍微慢一些

String s = “abc”;
StringBuffer s1 = new StringBuffer(123);
StringBuffer s2 = new StringBuffer(s); //String转换为StringBuffer
String X = s1.toString(); //StringBuffer转换为String

//常用方法
StringBuffer append(boolean b):追加内容到当前StringBuffer对象的末尾
StringBuffer deleteCharAt(int index):删除指定位置的字符,然后将剩余的内容形成新的字符串
StringBuffer insert(int offset, boolean b):在StringBuffer对象中插入内容,然后形成新的字符串
StringBuffer reverse():将StringBuffer对象中的内容反转,然后形成新的字符串
void setCharAt(int index, char ch):修改对象中索引值为index位置的字符为新的字符ch
void trimToSize():将StringBuffer对象的中存储空间缩小到和字符串长度一样的长度,减少空间的浪费
void replace(int start,int end,String string):将StringBuffer对象中指定字符串进行替换

# 数组 Array

Arrays类位于 java.util 包中,主要包含了操纵数组的各种方法

public static String toString(int[] a):返回指定数组的内容以字符串的形式表示
public static void sort(int[] a):按照数字顺序排列指定的数组

# 冒泡排序

一种排序方式,对要进行排序的数据中相邻的数据进行两两比较,将较大的数据放在后面,依次对所有的数据进行操作,直到所有的数据按要求完成排序

# split方法详解

# 单个分隔符

public class Test {
    public static void main(String[] args) {
        String str="2018,text,今天";
        //单个分隔符用引号括起来即可
        String[] data = str.split(",");
        for(int i=0;i< data.length;i++){
            System.out.println(data[i]);
			//输出:2018 text 今天
        } 
    }
}
  • 对点进行处理
@Test
public void test0001(){
    String str = "asczscx.xsa";
    String[] split = str.split("[.]");
    for (String s : split){
        System.out.println(s);
    }
}
  • 对竖进行处理
public class Test {
  public static void main(String[] args) {
	 String str="a|bc|8";
	 //java中\\表示一个普通\,\+特殊字符表示字符本身
	 String[] data = str.split("\\|");
	 for(int i=0;i< data.length;i++){
		 System.out.println(data[i]);
		 //输出:a bc 8
	 }
  }
}
  • 对星号进行处理
@Test
public void test0001(){
	String str = "asczscx*xsa";
    String[] split = str.split("\\*");
    for (String s : split){
        System.out.println(s);
    }
}
  • 对斜线进行处理
@Test
public void test0001(){
    String str = "asczscx\\xsa";
    String[] split = str.split("\\\\");
    for (String s : split){
        System.out.println(s);
    }
}
  • 对中括号的进行处理
@Test
public void test0001(){
    String str = "asczscx[]xsa";
    String[] split = str.split("\\[\\]");
    for (String s : split){
        System.out.println(s);
    }
}

# 多个分隔符

public class Test {
    public static void main(String[] args) {
        String str="2021年11月18日;英语,数学,语文;";
        //多个分隔符用引号括起来,并且用“|”进行分割
        String[] data = str.split(",|;");
        for(int i=0;i< data.length;i++){
            System.out.println(data[i]);
			//输出:2021年11月18日 英语 数学 语文
        } 
    }
}

# 数据输出 print

System.out.println("输出内容带换行");
System.out.print("输出内容不带换行");
System.out.print();//起到换行的作用

# 数据输入Scanner

主要用于获取键盘输入的内容,在java.util包下

# 构造方法

Scanner sc = new Scanner(System.in);

# 基本方法

  • hasNext():判断是否有值输入
  • hasNextXxx():判断输入的值是否为Xxx型的
  • nextXxx():用于返回键盘输入的Xxx类型的值。该方法可以使用多次 int i = sc.nextInt();

# next()和nextLine()方法的区别

  • nextLine()方法仅仅是以Enter键为结束符,返回的是Enter键前面的所有字符,包括空格、Tab键等等
  • next()方法结束符比nextLine()多,Enter键、空格、Tab键都是结束符。不过只有在输入有效字符之后,next()方法才将其后输入的空格键、Tab键或Enter键等视为分隔符或结束符。即如果一开始就输入空格键、Tab键或Enter键,它是被无视
  • 简单的说,就是next()方法无法获取带有空格、Tab键的字符串,而nextLine()方法则可以

# 随机数Random

  • 导包:import java.util.Random;
  • 创建对象:Random r = new Random();
  • 接收数据:int num = r.nextInt(10); 大于等于0小于10的数
public int nextInt():返回整型范围内的随机数
public int nextInt(int n):返回0到n范围内的随机数

//获取一个1-100之间的随机数
int x = r.nextInt(100)+1;

# 数字运算Math

没有构造方法,类的成员都是静态的,可以直接通过类名调用

public static int abs(int a):返回参数的绝对值
public static double ceil(double a):向上取整
public static double floor(double a):向下取整
public static int round(float a):四舍五入
public static int max(int a,int b):比较取较大值
public static int min(int a,int b):比较取较小值
public static double pow(double a,double b):返回a的b次幂
public static double random():返回[0.0-1.0]的值,不包含1.0

# 日期 Date

//构造方法
public Date() //根据当前的默认毫秒值创建对象
public Date(long date) //根据给定的毫秒值创建对象

//常用方法
public long getTime() //获取时间,以毫秒为单位
public void setTime() //设置时间,以毫秒为单位

public class Demo_Date {
    public static void main(String[] args) {
		//美国人看的懂的时间 Tue Nov 12 15:46:02 CST 2019  CST东八区
        System.out.println(new Date().toString());  
		//中国人看的懂的时间 2019-11-12 15:46:02
        System.out.println(new Date().toLocaleString());  
        System.out.println(System.currentTimeMillis());//毫秒值
        for (int i=0;i<=1000000;i++){}
        Date d=new Date();
        d.setTime(15735442L);
        System.out.println(d.toLocaleString());//中国人看的懂得时间
        System.out.println(new Date().getTime());//毫秒值
    }
}

# Date与String类互相转换

DateFormat:可以进行日期和字符串的转换,但是由于是抽象类,所以使用具体子类SimpleDateFormat

//构造方法
SimpleDateFormat(String pattern) //pattern模式字符串中:年y  月M   日d  时H   分m  秒s
//常用方法
public final String format(Date date) //按照构造函数中的pattern解析日期为字符串
public Date parse(String s) //按照构造函数中的pattern解析字符串为日期

public class DateFormatDemo {
	public static void main(String[] args) throws ParseException  {
		Date d = new Date();
	
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String s = sdf.format(d);
		System.out.println(s);
		
		String str = "2010-10-10 10:10:10";
		SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Date dd = sdf2.parse(str);
		System.out.println(dd);
	}
}

# 日历 Calendar

  • Calendar提供了一个类方法getInstance()用于获取Calendar对象,其值已用当前日期和时间初始化
  • 在使用Calendar获取月份的时候,要注意Calendar获取月份是从0开始的,所以要+1
Calendar rightNow = Calendar.getInstance();

//常用方法
//设置日历的年、月、日、时、分、秒。
public void set(int year,int month,int date,int hourofday,int minute,int second)
public int get(int field):返回给定日历字段的值。所谓字段就是年、月、日等等。
abstract void add(int field,int amount):按照日历的规则,给指定字段添加或减少时间量。
public long getTimeInMillies():以毫秒为单位返回该日历的时间值

public void setTime(Date date):使用给定的Date设置此日历的时间。Date=>Calendar
public Date getTime():返回一个Date表示此日历的时间。Calendar=>Date

public class CalendarDemo {
	public static void main(String[] args) {
		// 其日历字段已由当前日期和时间初始化:
		Calendar rightNow = Calendar.getInstance(); // 子类对象
		// 获取年
		int year = rightNow.get(Calendar.YEAR);
		// 获取月  月份是从0开始的,所以要+1
		int month = rightNow.get(Calendar.MONTH) + 1;
		// 获取日
		int date = rightNow.get(Calendar.DATE);
		//获取几点
		int hour=rightNow.get(Calendar.HOUR_OF_DAY);
		//获取上午下午
		int moa=rightNow.get(Calendar.AM_PM);
		if(moa==1)
			System.out.println("下午");
		else
			System.out.println("上午");
		
		//给指定字段添加或减少时间量
		rightNow.add(Calendar.YEAR,5);
		rightNow.add(Calendar.DATE, -10);
		
	}
}

# 读取properties

  • 使用getClassLoader,该方式有局限但是如果配置文件在类路径(src)下比较方便
Properties properties = new Properties();
// 使用ClassLoader加载properties配置文件生成对应的输入流,默认路径是src下
ClassLoader classLoader = PropertiesTest.class.getClassLoader();
InputStream in = classLoader.getResourceAsStream("com/jay/ct/b.properties");
// 使用properties对象加载输入流
properties.load(in);
// 获取key对应的value值
String name = properties.getProperty("name");

注意

配置文件在当前类所在的包下,需使用包名限定:com/jay/ct/b.properties;配置文件在src根目录下,直接使用a.properties

  • 基于 InputStream 读取配置文件,该方式的优点在于可以读取任意路径下的配置文件
Properties properties = new Properties();
// 使用InPutStream流读取properties文件
BufferedInputStream b2 = new BufferedInputStream(new FileInputStream("E:/b.properties"));
properties.load(b2);
// 获取key对应的value值
String name = properties.getProperty("name");
  • 通过 java.util.ResourceBundle 类来读取,不需要加.properties后缀名,默认路径是src下
ResourceBundle resource = ResourceBundle.getBundle("a");
String name = resource.getString("name");
  • ResourceUtils获取文件
File file = ResourceUtils.getFile("classpath:excelfile/03版.xls");

# 解析Json

# List转Json

使用Gson类中的toJson()方法

Gson gson = new Gson();
String listToJsonString = gson.toJson(list); 

# 对象序列化/反序列化

Jackson是当前使用比较广泛的序列化和反序列化 json 开源框架,由三部分组成:

  • jackson-core: 核心包,提供基于"流模式"解析的相关 API,它包括 JsonPaser 和 JsonGenerator。 Jackson内部实现正是通过高性能的流模式API的JsonGenerator 和 JsonParser 来生成和解析 json
  • jackson-annotations: 注解包,提供标准注解功能
  • jackson-databind: 数据绑定包, 提供基于"对象绑定" 解析的相关 API ( ObjectMapper ) 和"树模型" 解析的相关 API (JsonNode);基于"对象绑定" 解析的 API 和"树模型"解析的 API 依赖基于"流模式"解析的 API

Jackson提供了ObjectMapper来供程序员调用writeValue()序列化 或 调用readValue()反序列化方法之前,往往需要设置 ObjectMapper 的相关配置信息

# 忽略未知字段

默认情况下Jackson要求JSON字符串消息 和 Java类中的字段必须一一相对应,否则反序列解析JSON字符串时会报错。当然也可以通过配置Jackson的ObjectMapper属性使Jackson在反序列化时,忽略在 json字符串中存在但 Java 对象不存在的属性

//java对象属性
@Data
public class User implements Serializable {
    private Integer age;
    private String name;
}
 
//需要反序列化JSON字符串
public static void main(String[] args) throws Exception {
	ObjectMapper objectMapper = new ObjectMapper();
	String json = "{\"age\":10,\"name\":\"曹操\",\"class\":\"语文\"}";
	#会报错:因为json字符串的属性和java对象属性没有一一对应
	User user = objectMapper.readValue(json, User.class);
	System.out.println(user);
}
 
//异常
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "class"
 
//解决办法:忽略未知字段 DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES默认是true。
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

# 属性为NULL不被序列化

如果java对象的属性为NULL则不参与序列化,即java对象序列化后的json串里不出现属性为null的字段。该功能可以使用@JsonInclude注解,也可以设置objectMapper属性

//java对象属性
@Data
public class User implements Serializable {
    private Integer age;
    private String name;
}
 
//序列化属性有为null的对象
public static void main(String[] args) throws Exception {
	ObjectMapper objectMapper = new ObjectMapper();
	User user = new User();
	user.setAge(10);
	String string = objectMapper.writeValueAsString(user);
	System.out.println(string);
}
//输出:json字段带null
{"age":10,"name":null}
 
//解决办法:
//1、注解可以加到类或属性上,加到类上表示多所有属性都有效
@JsonInclude(JsonInclude.Include.NON_NULL)
//2、设置objectMapper属性
objectMapper.setSerializationInclusion(Include.NON_NULL)

# 对象属性为空时,默认序列化会失败

默认情况下ObjectMapper序列化没有属性的空对象时会抛异常。可以通过SerializationFeature.FAIL_ON_EMPTY_BEANS设置当对象没有属性时,让其序列化能成功,不抛异常

//java对象属性:没有任何属性
@Data
public class User implements Serializable {
}
 
//默认序列化失败,会抛异常
public static void main(String[] args) throws Exception {
	ObjectMapper objectMapper = new ObjectMapper();
	#默认是true,空对象不让序列化
	//objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, true);
	User user = new User();
	String string = objectMapper.writeValueAsString(user); #会抛异常
	System.out.println(string);
}
//抛异常:com.fasterxml.jackson.databind.exc.InvalidDefinitionException
 
//解决办法:关闭空对象不让序列化功能
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);

# json字符串值带反斜杠(""),默认反序列化会失败

当反序列化的JSON串里带有反斜杠时,默认objectMapper反序列化会失败,抛出异常Unrecognized character escape。可以通过Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER来设置当反斜杠存在时,能被objectMapper反序列化

//java对象属性
@Data
public class User implements Serializable {
    private Integer age;
    private String name;
}
 
//反序列化字符串带反斜杠,会抛异常。
public static void main(String[] args) throws Exception {
	ObjectMapper objectMapper = new ObjectMapper();
	#objectMapper默认是false
	objectMapper.configure(Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER, false);
	#name的值带反斜杠,默认情况下objectMapper解析器会反序列化失败
	String json = "{\"age\":10,\"name\":\"曹\\操\"}";
	User user = objectMapper.readValue(json, User.class);
	System.out.println(user);
}
//输出:
//com.fasterxml.jackson.databind.JsonMappingException: Unrecognized character escape '操'
 
//解决办法:设置解析能识别JSON串里的注释符
objectMapper.configure(Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER, true);

# json字符串带注释符,默认反序列化会失败

当json字符串里带注释符时,默认情况下解析器不能解析。Feature.ALLOW_COMMENTS特性决定解析器是否允许解析使用Java/C++ 样式的注释(包括'/'+'*' 和'//' 变量)

//例如:如下反序列化JSON串里带注释,默认情况下objectMapper不能反序列化解析成对象
{
	"age": 10
	//,
	//"name": "曹操"
}
 
//默认情况下,上面这种带注释的JSON串,objectMapper解析器是不能解析的
public static void main(String[] args) throws Exception {
	ObjectMapper objectMapper = new ObjectMapper();
	//默认是false,不能解析带注释的JSON串
	objectMapper.configure(Feature.ALLOW_COMMENTS, true);
	String json  = "{"
		+"\"age\"" + ":" + 10 +
		"/*" + "," +
		"\"name\"" + ":" + "\"曹操\"*/" + 
	"}";
	//Feature.ALLOW_COMMENTS打开时,JSON里的注释符会被过滤掉,解析器能解析
	User user = objectMapper.readValue(json, User.class);
	System.out.println(user);
}
 
//输出:User(age=10, name=null)

# Json字符串里数字类型值为正无穷、负无穷或NaN时,默认反序列化会失败

objectMapper解析器默认不能识别识别 "Not-a-Number" (NaN)标识集合作为一个合法的浮点数 或 一个int数,objectMapper默认该功能是关闭的

//例如:反序列化的JSON串里包含了数字类型的属性值为NaN,默认objectMapper解析器是不能解析的
{
	"age": NaN,
	"name": "曹操"
}
//java对象属性:age是数字类型
@Data
public class User implements Serializable {
    private Integer age;
    private String name;
}
 
//数字类型 或 浮点类型值为NaN时,默认objectMapper解析器是不能解析的
public static void main(String[] args) throws Exception {
	ObjectMapper objectMapper = new ObjectMapper();
	//需要开启Feature.ALLOW_NON_NUMERIC_NUMBERS
	objectMapper.configure(Feature.ALLOW_NON_NUMERIC_NUMBERS, true);
	String json = "{\"age\":NaN, \"name\":\"曹操\"}";
	User user = objectMapper.readValue(json, User.class);
	System.out.println(user);
	//输出是无穷大
	System.out.println(0.0/0.0);
}
//输出:
User(age=NaN, name=曹操)
NaN
 
//注意:浮点类型 或 数字类型都可以接受NaN值,反序列化需要开启Feature.ALLOW_NON_NUMERIC_NUMBERS

# 反序列化可解析以"0"为开头的数字

默认情况下objectMapper解析器是不能解析以"0"为开头的数字,需要开启Feature.ALLOW_NUMERIC_LEADING_ZEROS才能使用

//例如java对象属性age是int类型
@Data
public class User implements Serializable {
    private Integer age;
    private String name;
}
 
//JSON字符串的age值是"0"为开头的数字,objectMapper默认是不能解析的
public static void main(String[] args) throws Exception {
	ObjectMapper objectMapper = new ObjectMapper();
	objectMapper.configure(Feature.ALLOW_NUMERIC_LEADING_ZEROS, true);
	//“0”开头的数字
	String json = "{\"age\":0012, \"name\":\"曹操\"}";
	User user = objectMapper.readValue(json, User.class);
	System.out.println(user);
}
//输出:User(age=12, name=曹操)
 
//注意:除了int类型,浮点数也一样

# Json反序列化可以解析单引号包住的属性名称和字符串值

parser解析器默认情况下不能识别单引号包住的属性和属性值,默认下该属性也是关闭的。需要设置JsonParser.Feature.ALLOW_SINGLE_QUOTES为true

public static void main(String[] args) throws Exception {
	ObjectMapper objectMapper = new ObjectMapper();
	//需要开启单引号解析属性,默认是false
	objectMapper.configure(Feature.ALLOW_SINGLE_QUOTES, true);
	String json = "{'age':12, 'name':'曹操'}";
	User user = objectMapper.readValue(json, User.class);
	System.out.println(user);
}
//输出:如果Feature.ALLOW_SINGLE_QUOTES设置为false时,解析器会解析失败
User(age=12, name=曹操)

# 反序列Json字符串中包含制控制字符

Feature.ALLOW_UNQUOTED_CONTROL_CHARS该特性决定parser是否允许JSON字符串包含非引号控制字符(值小于32的ASCII字符,包含制表符\t、换行符\n和回车\r)。 如果该属性关闭,则如果遇到这些字符,则会抛出异常

//处理问题:JSON串里属性或属性值包含控制字符,解析器能解析。
{
	"age": 12,
	"name": "曹操\n"
}
 
//示列
public static void main(String[] args) throws Exception {
	ObjectMapper objectMapper = new ObjectMapper();
	//开启单引号解析
	objectMapper.configure(Feature.ALLOW_SINGLE_QUOTES, true);
	//开启JSON字符串包含非引号控制字符的解析(\n换行符)
	objectMapper.configure(Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
	String json = "{'age':12, 'name':'曹操\n'}";
	User user = objectMapper.readValue(json, User.class);
	System.out.println(user);
}
//输出:输出有换行效果
User(age=12, name=曹操)

# 反序列Json字符串中属性名没有双引号

默认情况下,标准的json串里属性名字都需要用双引号引起来。比如:{age:12, name:"曹操"}非标准的json串,解析器默认不能解析,需要设置Feature.ALLOW_UNQUOTED_FIELD_NAMES属性来处理这种没有双引号的json串

{
	age: 12,
	name: "曹操"
}
//示列
public static void main(String[] args) throws Exception {
	ObjectMapper objectMapper = new ObjectMapper();
	//开启单引号解析
	objectMapper.configure(Feature.ALLOW_SINGLE_QUOTES, true);
	//开启属性名没有双引号的非标准json字符串
	objectMapper.configure(Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
 
	String json = "{age:12, name:'曹操'}";
	User user = objectMapper.readValue(json, User.class);
	System.out.println(user);
}
//输出:
User(age=12, name=曹操)

# 时间格式化

Jackson对时间(Date)序列化的转换格式默认是时间戳,可以取消时间的默认时间戳转化格式;默认时间戳转化格式取消后在序列化时日期格式默认为 yyyy-MM-dd'T'HH:mm:ss.SSSZ,同时需要设置要展现的时间格式

//Jackson对时间(Date)序列化的转换格式默认是时间戳
public static void main(String[] args) throws JsonProcessingException {
	ObjectMapper mapper = new ObjectMapper();
	//WRITE_DATES_AS_TIMESTAMPS属性值默认就是true
	//mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, true);
	String date = mapper.writeValueAsString(new Date());
	System.out.println("默认是时间戳格式:" + date);
}
//输出:
//默认是时间戳格式:1605848842390
 
//取消时间的默认时间戳转化格式后,再序列化时日期格式默认为 yyyy-MM-dd'T'HH:mm:ss.SSSZ
public static void main(String[] args) throws JsonProcessingException {
	ObjectMapper mapper = new ObjectMapper();
	//WRITE_DATES_AS_TIMESTAMPS属性值默认就是true
	mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
	String date = mapper.writeValueAsString(new Date());
	System.out.println("默认时格式:" + date);
}
//输出:
//默认时格式:"2020-11-20T05:12:22.868+0000"
 
//取消Jackson时间的默认时间戳转化格式,并设置需要展现的时间格式
public static void main(String[] args) throws JsonProcessingException {
    ObjectMapper mapper = new ObjectMapper();
    //取消时间的转化格式默认是时间戳,可以取消,同时需要设置要表现的时间格式
    mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
    mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
 
    String date = mapper.writeValueAsString(new Date());
    System.out.println("指定时间时格式:" + date);
}
//输出:
//指定时间时格式:"2020-11-20 13:14:56"

Springboot使用的默认json解析框架是jackjson框架,在格式化Model时对Date属性指定时间格式方式有以下三种方法

//配置文件:将spring的jackson日期格式写在配置文件中即可。
spring:
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: GMT+8
    serialization:
      write-dates-as-timestamps: false
 
//或者写成以下格式(主要取决于配置文件是什么格式的)
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8
spring.jackson.serialization.write-dates-as-timestamps=false
 
//注解:在实体Date类型的字段上使用@JsonFormat注解格式化日期
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT + 8")
private Date createTime;
 
//设置ObjectMapper属性:通过下面方式取消timestamps形式,并设置时间格式
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));

# 解析XML

工具类,可以解析html或xml文档,返回Document,需要先导入jar包(jsoup-1.11.2.jar)

# parse解析html或xml文档

  • parse​(File in, String charsetName):解析xml或html文件的
  • parse​(String html):解析xml或html字符串
  • parse​(URL url, int timeoutMillis):通过网络路径获取指定的html或xml的文档对象
<?xml version='1.0'?>
<students>
    <student id="1">
        <name>Adair</name>
        <age>18</age>
        <gender>male</gender>
    </student>

    <student id="2">
        <name>Mary</name>
        <age>17</age>
        <gender>female</gender>
    </student>
</students>
//2.获取Document对象,根据xml文档获取
//2.1获取student.xml的path
String path = JsoupDemo1.class.getClassLoader().getResource("./com/student.xml").getPath();
//2.2解析xml文档,加载文档进内存,获取dom树--->Document
Document document = Jsoup.parse(new File(path), "utf-8");
//3.获取元素对象 Element
Elements elements = document.getElementsByTag("name");
//elements是一个ArrayList
System.out.println("elements的元素个数:" + elements.size());

//3.1获取第一个name的Element对象
Element element = elements.get(0);
//3.2获取数据
String name = element.text();
System.out.println(name);

# 获取Element对象

  • getElementById​(String id):根据id属性值获取唯一的element对象
  • getElementsByTag​(String tagName):根据标签名称获取元素对象集合
  • getElementsByAttribute​(String key):根据属性名称获取元素对象集合
  • getElementsByAttributeValue​(String key, String value):根据对应的属性名和属性值获取元素对象集合
//1.获取student.xml的path
String path = JsoupDemo1.class.getClassLoader().getResource("./com/student.xml").getPath();
//2.获取Document对象
Document document = Jsoup.parse(new File(path), "utf-8");
//3.获取元素对象
//3.1获取所有的student对象
Elements elements = document.getElementsByTag("student");

//3.2 获取属性名为id的元素对象们
Elements elements1 = document.getElementsByAttribute("id");

//3.3获取 number属性值为1的元素对象
Elements elements2 = document.getElementsByAttributeValue("number", "1");

//3.4获取id属性值的元素对象
Element it_cast1 = document.getElementById("it_cast1");

# 获取属性值及内容

  • string attr(String key):根据属性名称获取属性值
  • String text():获取文本内容
  • String html():获取标签体的所有内容(包括字标签的字符串内容)
//1.获取student.xml的path
String path = JsoupDemo1.class.getClassLoader().getResource("./com/student.xml").getPath();
//2.获取Document对象
Document document = Jsoup.parse(new File(path), "utf-8");
Element element_student = document.getElementsByTag("student").get(0);
Elements element_name = element_student.getElementsByTag("name");

//获取student对象的属性值
String number = element_student.attr("number");

//获取文本内容
String text = element_name.text();
String html = element_name.html();

# selector选择器

  • 使用的方法:Elements select​(String cssQuery)
//1.获取student.xml的path
String path = JsoupDemo1.class.getClassLoader().getResource("./com/student.xml").getPath();
//2.获取Document对象
Document document = Jsoup.parse(new File(path), "utf-8");
//3.查询name标签
Elements elements = document.select("name");

//4.查询id值为it_cast1的元素
Elements elements1 = document.select("#it_cast1");

//5.获取student标签并且number属性值为1的age子标签
//5.1.获取student标签并且number属性值为1
Elements elements2 = document.select("student[number='1']");

//5.2获取student标签并且number属性值为1的age子标签
Elements elements3 = document.select("student[number='1'] > age");

# XPath

  • XPath即为XML路径语言,它是一种用来确定XML文档中某部分位置的语言
  • 使用Jsoup的Xpath需要额外导入jar包
//1.获取student.xml的path
String path = JsoupDemo1.class.getClassLoader().getResource("./com/student.xml").getPath();
//2.获取Document对象
Document document = Jsoup.parse(new File(path), "utf-8");
//3.根据document对象,创建JXDocument对象
JXDocument jxDocument = new JXDocument(document);
//4.结合xpath语法查询
//4.1查询所有student标签
List<JXNode> jxNodes = jxDocument.selN("//student");
for(JXNode jxNode : jxNodes){
	System.out.println(jxNode);
}

//4.2查询所有student标签下的name标签
List<JXNode> jxNodes1 = jxDocument.selN("//student/name");
for(JXNode jxNode : jxNodes1){
	System.out.println(jxNode);
}

//4.3查询student标签下带有id属性的name标签
List<JXNode> jxNodes2 = jxDocument.selN("//student/name[@id]");
for (JXNode jxNode : jxNodes2){
	System.out.println(jxNode);
}

//4.4查询student标签下带有id属性的name标签 并且id属性值为it_cast
List<JXNode> jxNodes3 = jxDocument.selN("//student/name[@id='it_cast1']");
for (JXNode jxNode : jxNodes3){
	System.out.println(jxNode);
}

# 操作redis

# Jedis读写Redis数据

//导入坐标
<dependency>
  <groupId>redis.clients</groupId>
  <artifactId>jedis</artifactId>
  <version>2.9.0</version>
</dependency>

//基本使用
public void testJedis() {
	//1.连接Redis
	Jedis jedis = new Jedis("127.0.0.1", 6379);
	//空参时默认值为"127.0.0.1", 6379
	//Jedis jedis = new Jedis();
	//2.操作Redis
	jedis.set("name", "lisi");
	//3,关闭连接
	jedis.close();
}

//操作String
public void testString() {
	Jedis jedis = new Jedis("127.0.0.1", 6379);
	
	jedis.set("name", "lisi");
	String name = jedis.get("name");
	
	jedis.setex("name", 20, "lisi"); //指定过期时间 20秒
	
	jedis.close();
}

//操作Hash集合
public void testHash() {
	Jedis jedis = new Jedis("127.0.0.1", 6379);
	
	jedis.hset("hash", "a1", "b1");
	jedis.hset("hash", "a2", "b2");
	jedis.hset("hash", "a3", "b3");
	
	jedis.hget("hash", "a1")
	Map<String, String> hash = jedis.hgetAll("hash");
	System.out.println(hash);
	
	System.out.println(jedis.hlen("hash"));//获取哈希表中字段的数量
	
	jedis.close();
}

//操作List集合
public void testList() {
	Jedis jedis = new Jedis("127.0.0.1", 6379);
	
	jedis.lpush("list", "a", "b", "c");//添加到表头
	jedis.rpush("list", "x");//添加到表尾
	
	List<String> list = jedis.lrange("list", 0, -1);//从表头取出
	for (String s : list) {
		System.out.println(s);
	}
	
	String element = jedis.lpop("list");
	String element = jedis.rpop("list");
	
	System.out.println(jedis.llen("list")); //获取列表长度
	
	jedis.close();
}

//操作Set集合
public void testSet() {
	Jedis jedis = new Jedis("127.0.0.1", 6379);
	
	jedis.sadd("set", "java", "net"); //可以设置多个值
	Set<String> set = jedis.smembers("set");
	
	jedis.close();
}

//操作Sotedset集合
public void testSotedset() {
	Jedis jedis = new Jedis("127.0.0.1", 6379);
	
	jedis.zset("sotedset", 60, "a");
	jedis.hset("sotedset", 50, "b");
	Set<String> sotedset = jedis.zrange("sotedset", 0, -1);
	
	jedis.close();
}

# Jedis连接池工具类

创建好工具类在使用中就可以不用每次都创建Jedis了,使用是直接调用工具类即可

#Redis连接地址
redis.host=127.0.0.1
#Redis连接ID
redis.port=6379
#最大链接数,设为0表示无限制
redis.maxTotal=30
#最大等待连接中的数量,设 0为没有限制
redis.maxIdle=10
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

import java.util.ResourceBundle;

public class RedisUtils {
    //创建Redis连接池 JedisPool
    private static JedisPool jp = null;
    //创建Redis连接池配置
    private static JedisPoolConfig jpc = null;
    private static String host = null;
    private static int port;
    private static int maxTotal;
    private static int maxIdle;

    /**
     * 静态代码块初始化资源
     */
    static {
        //读取配置文件参数值
        ResourceBundle rb = ResourceBundle.getBundle("redis");
        host = rb.getString("redis.host");
        port = Integer.parseInt(rb.getString("redis.port"));
        maxTotal = Integer.parseInt(rb.getString("redis.maxTotal"));
        maxIdle = Integer.parseInt(rb.getString("redis.maxIdle"));
		//连接池配置
        jpc = new JedisPoolConfig();
        jpc.setMaxTotal(maxTotal);
        jpc.setMaxIdle(maxIdle);
		//连接池
        jp = new JedisPool(jpc, host, port);
    }

    /**
     * 对外访问接口,提供Jedis连接对象,连接从连接池获取
     */
    public static Jedis getJedis() {
        return jp.getResource();
    }
}

# BaseServlet

package cn.itcast.travel.web.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

//不用加注解 因为Baseservlet根本不需要被访问到
public class BaseServlet extends HttpServlet {
 
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) 
	                                               throws ServletException, IOException {
        //System.out.println("baseServlet的service方法被执行了...");

        //完成方法分发
        //1.获取请求路径
        String uri = req.getRequestURI(); //   /travel/user/add
        System.out.println("请求uri:" + uri);//  /travel/user/add
        //2.获取方法名称
        String methodName = uri.substring(uri.lastIndexOf('/') + 1); /即获取add
        System.out.println("方法名称:" + methodName);
        //3.获取方法对象Method
        //谁调用我?我代表谁
		//UserServlet的对象cn.itcast.travel.web.servlet.UserServlet@4903d97e
        System.out.println(this);
        try {
            //获取方法
            Method method = this.getClass().getMethod(methodName, 
			                HttpServletRequest.class, HttpServletResponse.class);
            //4.执行方法
            //暴力反射
            //method.setAccessible(true);
            method.invoke(this, req, resp);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

//要实现的功能的UserServlet
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.beanutils.BeanUtils;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;

// 要用*号,要通配所有的方法名称
@WebServlet("/user/*") // /user/add /user/find
public class UserServlet extends BaseServlet {

    //声明UserService业务对象
    private UserService service = new UserServiceImpl();

    //注册功能
    public void regist(HttpServletRequest request, HttpServletResponse response) 
	                                               throws ServletException, IOException {
        //3.调用service完成注册
        //UserService service = new UserServiceImpl();
        boolean flag = service.regist(user);
        ResultInfo info = new ResultInfo();
        //4.响应结果
        if(flag){
            //注册成功
            info.setFlag(true);
        }else{
            //注册失败
            info.setFlag(false);
            info.setErrorMsg("注册失败!");
        }

        //将info对象序列化为json
        ObjectMapper mapper = new ObjectMapper();
        String json = mapper.writeValueAsString(info);

        //将json数据写回客户端
        //设置content-type
        response.setContentType("application/json;charset=utf-8");
        response.getWriter().write(json);

    }
}

# WebService

需要先安装WebService插件,setting -> pugins

# Apache Axis

Axis不支持Java8及以上的版本

  • 创建普通Java项目
  • 右键Add Framworks Support,选择WebService下的Apache Axis
  • 配置Tomcat,测试项目是否启动成功
  • 通过按两下shift,然后搜索webService,选择webService来打开窗口
  • 修改Service URL,改成tomcat配置的访问地址
  • 添加必要的jar包:Project Structure,如果报错,点击Fix->Add 'JAX-WS-Apache' to the…修复错误
  • 访问WebService的时候;路径为:http://localhost:8080/flight/services

# 通过客户端调用服务端webservice

通过客户端调用服务端webservice (opens new window)

# 通过ajax调用WebService服务

通过ajax调用WebService服务 (opens new window)

# 下载远程文件并打包

String error = "错误图片";
String msg = "";
ZipOutputStream zos = new ZipOutputStream(response.getOutputStream());
try {
	//String downloadFilename = "图片.zip";// 文件的名称
	//downloadFilename = URLEncoder.encode(downloadFilename, "UTF-8");// 转换中文否则可能会产生乱码
	response.setContentType("application/octet-stream;charset=UTF-8");// 指明response的返回对象是文件流
	//response.setHeader("Content-Disposition","attachment;filename="+downloadFilename);// 设置在下载框默认显示的文件名

	for (String imgs : lImgs) {
		msg = imgs;
		//http://124.128.197.14:9300/statics/202337020004/202337020004-茎-20231018150456206.JPEG
		//采集号+文件名
		String imgFolderAndName = imgs.substring(imgs.indexOf("c")+3);
		zos.putNextEntry(new ZipEntry(imgFolderAndName));

		//文件名需要编码
		String imgPath = imgs.substring(0,imgs.lastIndexOf("/")+1);
		String imgName = imgs.substring(imgs.lastIndexOf("/")+1);
		URL url = new URL(imgPath+ URLEncoder.encode(imgName,"UTF-8"));
		// 打开连接
		URLConnection con = url.openConnection();
		//con.addRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko");
		//设置请求超时为30s
		con.setConnectTimeout(300*1000);
		// 输入流
		InputStream fis = con.getInputStream();
		byte[] bytes = new byte[1024];
		int len;
		while ((len = fis.read(bytes)) != -1) {
			zos.write(bytes, 0, len);
		}
		fis.close();
	}
} catch (Exception e) {
	error += ","+msg;
	e.printStackTrace();
} finally {
	zos.flush();
	zos.close();
}