TongHui的博客 - JAVA
type: channel
link: https://tonghui.domcer.com/index.php/category/JAVA/
description: JAVA
items: Java 关闭同源策略
items: Spring Boot 单服务解决前端跨域问题的配置
items: 根据HTML内容转成图片
items: 多线程基础
items: API网络请求工具类
items: IO流
items: IO流-总结
items: 字符集
items: 集合概述和分类
items: 正则表达式

Java 关闭同源策略
type: item
date: 2024-05-10T21:11:00+08:00
description: @Configuration public class GlobalCorsConfig { @Bean public CorsFilter corsFilter() { //1. 添加 CORS配置信息 CorsConfiguration config = new CorsConfiguration(); //放行哪些原始域 config.addAllowedOrigin("https://staff-backend.domcer.com/"); //是否发送 Cookie config.setAllowCredentials(true); //放行哪些请求方式 config.addAllowedMethod("*"); //放行哪些原始请求头部信息 config.addAllowedHeader("*"); //暴露哪些头部信息 config.addExposedHeader("*"); //2. 添加映射路径 UrlBasedCorsConfigurationSource corsConfigurationSource = new UrlBasedCorsConfigurationSource(); corsConfigurationSource.registerCorsConfiguration("/**",config); //3. 返回新的CorsFilter return new CorsFilter(corsConfigurationSource); } }

Spring Boot 单服务解决前端跨域问题的配置
type: item
date: 2023-08-28T16:16:00+08:00
description: @Configuration public class GlobalCorsConfig { /** * 允许跨域调用的过滤器 */ @Bean public CorsFilter corsFilter() { // 创建一个跨域的配置类 CorsConfiguration config = new CorsConfiguration(); // 允许白名单域名进行跨域调用 // 这个是配置允许哪些域名进行跨域调用 *代表所有域名 // 这个配置可以写多个 config.addAllowedOrigin("*"); // 允许跨越发送 cookie config.setAllowCredentials(true); // 放行全部原始头信息 config.addAllowedHeader("*"); // 允许所有请求方法跨域调用 // 这个配置也可以写多个 POST PUT GET DELETE OPTIONS config.addAllowedMethod("*"); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); // 访问这个项目的所有请求都会跨域调用 source.registerCorsConfiguration("/**", config); return new CorsFilter(source); } }

根据HTML内容转成图片
type: item
date: 2023-08-13T20:42:00+08:00
description: Div to Image with Width Hello, Div to Image! This is a simple example. Convert to Image

多线程基础
type: item
date: 2023-06-13T19:55:19+08:00
description: 多线程基础相关概念多线程多线程就是同时执行多个应用程序 需要硬件支持效果上来说就是CPU在多个程序之间快速切换 给人一种多个软件同时执行的感觉并发: 某一个时刻 多个任务同时在执行 在同一时刻 有多个指令在多个CPU上同时执行并发: 某个时间段 多个任务同时执行 但是某个时刻只有一个任务在执行 在某一时间段 有多个指令在单个CPU上交替执行当下电脑执行过程中两种情况会同时存在并发: 是因为目前的cpu都是多核心的 每个核心执行一个指令多个核心就同时在执行多个指令并发:每个核心在某一刻 只能执行一个程序指令 之后某一刻 可能在执行其他软件的命令进程正在运行的软件独立性 进程是一个能独立运行的基本单位 同时也是系统分配资源和调度的独立单位动态性 进程的是指是程序的一次执行过程 进程是动态产生的 动态消亡的并发性 任何进程都可以同其他进程一起并发执行线程是进程中的单个循序控制流 是一条执行路径 应用程序中能做的某个事情随机性: 一个宪曾在某个时间段内在执行 但是这段时间的某个时刻不一定在执行 此时cpu可以能在执行另一个软件 cpu可以在多个线程 随机快速切换执行多线程的实现方式jdk原生支持的1.继承thread类2.实现runnable接口3.实现callable接口继承Thread类方法void run()想要多线程中执行的代码写在这个方法中 在线程启动后此方法将自动被调用执行void start()启动线程的方法 之后java虚拟机会调用run()方法实现步骤定义一个类MyThread继承Thread类在MyThread类中重写run()方法创建MyThread类的对象使用线程对象的start()启动线程public class ThreadDemo01 { public static void main(String[] args) { // 3. 创建MyThread类的对象 MyThread mth1 = new MyThread(); MyThread mth2 = new MyThread(); // 4. 使用线程对象的start()启动线程 mth1.start(); mth2.start(); } } // 1. 定义一个类MyThread继承Thread类 class MyThread extends Thread{ @Override // 2. 在MyThread类中重写run()方法 public void run() { // 这里的代码会在对应的线程启动后自动被执行 for (int i = 0; i < 100; i++) { System.out.println("新的线程开始执行代码了"+i); } } } 重点解析问:为什么要冲洗run()方法因为run()是用封装被线程执行代码的 我们可以想要在多线程环境下运行的代码写在run()方法中 这些代码可以称之为任务问: run()方法和start()方法的区别run() 封装多线程执行的代码 封装任务代码的如果直接调用该方法 就是main方法线程中执行普通方法 也就是普通方法的调用start() 启动线程开启一个新线程 在新县城中执行代码 由jvm调用此线程的run方法执行run中的任务代码实现Runnalbe接口Thread构造方法Thread(Runnable target) 分配一个新的Thread对象Thread(Runnable target,String name) 分配一个新的Thread对象Runnable接口中方法run() 任务方法内部编写要在多线程环境下执行的代码实现步骤定义一个类MyRunnable实现Runnale接口在Myrunnable类中重写run()方法 编写需要在多线程环境下运行的代码

API网络请求工具类
type: item
date: 2023-05-05T15:45:00+08:00
description: import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; public class NetworkAPIUtils { /** * 发送GET请求 * @param url 请求的URL * @return 响应结果 * @throws IOException */ public static String sendGetRequest(String url) throws IOException { String result = ""; HttpURLConnection conn = null; InputStream is = null; try { conn = (HttpURLConnection) new URL(url).openConnection(); conn.setRequestMethod("GET"); conn.setConnectTimeout(5000); // 设置连接超时 conn.setReadTimeout(5000); // 设置读取超时 conn.connect(); // 建立连接 if (conn.getResponseCode() == 200) { is = conn.getInputStream(); byte[] buffer = new byte[1024]; int len = -1; while ((len = is.read(buffer)) != -1) { result += new String(buffer, 0, len); } } } finally { if (is != null) { is.close(); } if (conn != null) { conn.disconnect(); } } return result; } /** * 发送POST请求 * @param url 请求的URL * @param postData POST请求体数据 * @return 响应结果 * @throws IOException */ public static String sendPostRequest(String url, String postData) throws IOException { String result = ""; HttpURLConnection conn = null; InputStream is = null; try { conn = (HttpURLConnection) new URL(url).openConnection(); conn.setRequestMethod("POST"); conn.setConnectTimeout(5000); // 设置连接超时 conn.setReadTimeout(5000); // 设置读取超时 conn.setDoOutput(true); // 设置该连接是可以输出数据 conn.setRequestProperty("Content-Type", "application/json"); // 设置请求头的内容类型 conn.connect(); // 建立连接 conn.getOutputStream().write(postData.getBytes()); // 发送POST请求体数据 if (conn.getResponseCode() == 200) { is = conn.getInputStream(); byte[] buffer = new byte[1024]; int len = -1; while ((len = is.read(buffer)) != -1) { result += new String(buffer, 0, len); } } } finally { if (is != null) { is.close(); } if (conn != null) { conn.disconnect(); } } return result; } }使用方法try { // 发送GET请求 String url1 = "https://webapi.domcer.com/match/mw"; String response1 = NetworkAPIUtils.sendGetRequest(url1); System.out.println(response1); // 发送POST请求 String url2 = "https://jsonplacehold…

IO流
type: item
date: 2021-05-19T16:53:00+08:00
description: 概念IO：输入/输出(Input/Output)，视角为内存视角。流：是一种抽象概念，是对数据传输的总称。也就是说数据在设备间的传输称为流，流的本质是数据传输IO流就是用来处理设备间数据传输问题的。常见的应用场景: 文件复制; 文件上传; 文件下载、文件查看IO流的分类按照数据的流向输入流：读数据输出流：写数据按照数据类型来分字节流(万能流)字节输入流（InputStream）字节输出流（OutputStream）字符流字符输入流（Reader）字符输出流（Writer）字符流指的是传递字符的流，建议只用于读写纯文本文件；纯文本文件：如果某个文件用系统自带的记事本打开并且能够轻松看懂，就是纯文本文件。字节流指的是传递字节的流，可以读写任意文件。又称万能流。3. 字节流字节流就是以字节为单位操作数据的流。3.1 字节输出流：写3.1.1 基本使用：写一个字节相关方法说明方法签名说明FileOutputStream FileOutputStream(File file)基于一个File封装一个FileOutputStream对象FileOutputStream FileOutputStream(String pathName)基于一个字符串格式的文件路径封装一个FileOutputStream对象void write(int b)把指定的内容写入文件void close()关闭流释放资源 三个步骤创建字节输出流(FileOutputStream)对象写出数据关闭流释放资源注释// FileOutputStream FileOutputStream(String pathName) 基于一个字符串格式的文件路径封装一个FileOutputStream对象 // FileOutputStream FileOutputStream(File file) 基于一个File封装一个FileOutputStream对象 // void write(int b) 把指定的内容写入文件 // void close() 关闭流释放资源演示代码 /** * 字节输出流入门案例：写一个字节 */ public class ByteStreamDemo01 { public static void main(String[] args) throws IOException { // FileOutputStream FileOutputStream(String pathName) 基于一个字符串格式的文件路径封装一个FileOutputStream对象 // FileOutputStream FileOutputStream(File file) 基于一个File封装一个FileOutputStream对象 // void write(int b) 把指定的内容写入文件 // void close() 关闭流释放资源 // 创建自己输入流对象 // 创建输出流对象时，会判断关联的文件是否存在； // 如果不存在，会自动创建一个空白的文件 // 如果存在，则清空文件内容 FileOutputStream fos = new FileOutputStream("d:\\file\\a.txt"); // 写出数据 // 字节输入流，操作的是字节；写97其实写的不是97这两个字符，而是一个码点/码值； // 程序会把他当做一个字节写入到文件。我们查看，把这个字节的数字作为码点，查询字符集中对应的字符，后展示。 fos.write(98); // 关闭流释放资源 // 创建输入流对象时，会自动关联对应的文件；这个时候，可以理解为当前这个Java程序独占了该文件 // 其他的程序想要操作相同文件时，会有问题。 // 所以使用完之后，要关闭流，释放对文件的独占 fos.close(); } }3.1.2 写入一个字节数组相关方法说明方法签名说明void write(int b)一次写一个字节数据(编码值)到指定位置（文件）void write(byte[] b)一次写一个字节数组数据到指定位置（文件）void write(byte[] b,int off,int len)一次写一个字节数组的部分到指定位置（文件）注释// void write(byte[] b) 一次写一个字节数组数据到指定位置（文件） // void write(byte[] b,int off,int len)一次写一个字节数组的部分到指定位置（文件） 演示代码 public class ByteSteamDemo01 { public static void main(String[] args) throws IOException { // 1. 创建字节输出流(`FileOutput…

IO流-总结
type: item
date: 2021-05-18T19:49:00+08:00
description: Java中的IO流主要分为四类：字节流、字符流、字节缓冲流和字符缓冲流输入和输出字符流字符流是专门为读取文本数据而生的FileReader类这是字符输入流，用来将文件中的字符数据读取到程序中来创建字符输入流通道FileReader(File file) 创建字符输入流管道与源文件接通 FileReader(String pathname) 创建字符输入流管道与源文件接通FileReader读取文件的步骤如下：//第一步：创建FileReader对象与要读取的源文件接通 //第二步：调用read()方法读取文件中的字符 //第三步：调用close()方法关闭流read()每次读取一个字符返回,没有发现没有数据可读会返回-1read(char[] buffer)每次会一个字符数组去读取数据,返回字符数读取了多少个字符,如果没有发现数据可读会返回-1read()的应用public class FileReaderTest1 { public static void main(String[] args) { try ( // 1、创建一个文件字符输入流管道与源文件接通 Reader fr = new FileReader("text.txt"); ){ // 2、一个字符一个字符的读（性能较差） // 记住每次读取的字符编号。 int c; while ((c = fr.read()) != -1){ System.out.print((char) c); } } catch (Exception e) { e.printStackTrace(); } } }read(byte[] buffer)的应用public class FileReaderTest1 { public static void main(String[] args) { try ( //创建一个文件字符输入流管道与源文件接通 Reader fr = new FileReader("io-app2\\src\\itheima01.txt"); ){ //每次读取多个字符。（性能是比较不错的！） char[] buffer = new char[3]; int len; // 记住每次读取了多少个字符。 while ((len = fr.read(buffer)) != -1){ // 读取多少倒出多少 System.out.print(new String(buffer, 0, len)); } } catch (Exception e) { e.printStackTrace(); } } }FileWriter类它可以将程序中的字符数据写入文件FileWriter往文件中写字符数据的步骤如下：第一步：创建FileWirter对象与要读取的目标文件接通 第二步：调用write(字符数据/字符数组/字符串)方法读取文件中的字符 第三步：调用close()方法关闭流创建字节输出流管道与源文件对象接通//会覆盖原文件内容 FileWriter(File file) 创建字节输出流管道与源文件对象接通 FileWirter(String filePath) 创建字节输出流管道与源文件对象接通 //可以追加内容 FileWriter(File file,boolean append) 创建字节输出流管道与源文件对象接通 可以追加内容 FileWirter(String filePath,boolean append) 创建字节输出流管道与源文件对象接通 可以追加内容write(int c)写一个字符write(String str)写一个字符串write(String str,int off,int len)写一个字符串的一部分wirte(char[] cbuf)写入一个字符数组wirte(char[] cbuf,int off,int len)写入字符数组的一部分前提try ( // 0、创建一个文件字符输出流管道与目标文件接通。 // 覆盖管道 // Writer fw = new FileWriter("io-app2/src/itheima02out.txt"); // 追加数据的管道 Writer fw = new FileWriter("io-app2/src/itheima02out.txt", true); ){ //下面内容 } catch (Exception e) { e.printStackTrace(); }write(int c)的应用// 1、public void write(int c):写一个字符出去 fw.write('a'); fw.write(97); //fw.write('磊'); // 写一个字符出去 fw.write("…

字符集
type: item
date: 2021-05-18T16:43:00+08:00
description: 字符集计算机只能处理0和1组成的二进制数据，为了让计算机能够存储处理字符，计算机的设计者美国人就把他们会用到的每一个字符进行了编码（所谓编码，就是人为的为每一个字符关联一个数字（称为码点）），计算机在存储某个字符时，存储的就是字符对应码点的二进制数据。ASCII字符集：《美国信息交换标准代码》，包含英文字母、数字、标点符号、控制字符 特点：1个字符占1个字节 GBK字符集：中国人自己的字符集，兼容ASCII字符集，还包含2万多个汉字 特点：1个字母占用1个字节；1个汉字占用2个字节 Unicode字符集：包含世界上所有国家的文字，有三种编码方案，最常用的是UTF-8 UTF-8编码方案：英文字母、数字占1个字节兼容(ASCII编码)、汉字字符占3个字节相关方法（String类中方法） 方法名说明编byte[] getBytes()使用平台的默认字符集将一个字符串编码为字节数组码byte[] getBytes(String charsetName)使用指定的字符集将一个字符串编码为字节数组解String(byte[] bytes)使用平台的默认字符集解码指定的字节数组来创建字符串码String(byte[] bytes, String charsetName)通过指定的字符集解码指定的字节数组来创建字符串注释// byte[] getBytes () 使用平台的默认字符集将一个字符串编码为字节数组 // byte[] getBytes (String charsetName)使用指定的字符集将一个字符串编码为字节数组 // String( byte[] bytes)使用平台的默认字符集解码指定的字节数组来创建字符串 | // String( byte[] bytes, String charsetName)通过指定的字符集解码指定的字节数组来创建字符串public static void main(String[] args) throws UnsupportedEncodingException { // byte[] getBytes () 使用平台的默认字符集将一个字符串编码为字节数组 // byte[] getBytes (String charsetName)使用指定的字符集将一个字符串编码为字节数组 // String( byte[] bytes)使用平台的默认字符集解码指定的字节数组来创建字符串 | // String( byte[] bytes, String charsetName)通过指定的字符集解码指定的字节数组来创建字符串 // 1. 编码 // 从字符串 -> 码点数字 String str1 = "中国"; // byte[] getBytes () 使用平台的默认字符集将一个字符串编码为字节数组 byte[] str1U8Bytes = str1.getBytes(); // str1U8Bytes = [-28, -72, -83, -27, -101, -67] System.out.println("str1U8Bytes = " + Arrays.toString(str1U8Bytes)); // byte[] getBytes (String charsetName)使用指定的字符集将一个字符串编码为字节数组 byte[] strGbkBytes = str1.getBytes("GBK"); // strGbkBytes = [-42, -48, -71, -6] System.out.println("strGbkBytes = " + Arrays.toString(strGbkBytes)); // 2.解压 // 从 码点数字(字节数组) -> 字符串 ====> 字符串构造方法 // 使用默认字符集：U8 // String( byte[] bytes)使用平台的默认字符集解码指定的字节数组来创建字符串 String str2 = new String(new byte[]{-28, -72, -83, -27, -101, -67}); // str2 = 中国 System.out.println("str2 = " + str2); // 使用指定字符集:GBK // String( byte[] bytes, String charsetName)通过指定的字符集解码指定的字节数组来创建字符串 String str3 = new String(new byte[]{-42, -48, -71, -6},"gbk"); // str3 = 中国 System.out.println("str3 = " + str3); // 演示乱码 // 编解码使用不同的字符集：UT…

集合概述和分类
type: item
date: 2021-05-17T17:38:00+08:00
description: 集合概述和分类集合的分类前面我们已经学习过了ArrayList集合，但是除了ArrayList集合，Java还提供了很多种其他的集合，如下图所示：这些集合一共分两大类，如下图所示：一类是单列集合元素是一个一个的，另一类是双列集合元素是一对一对的。主要学习Collection单列集合。Collection是单列集合的根接口，Collection接口下面又有两个子接口List接口、Set接口，List和Set下面分别有不同的实现类，如下图所示：上图中各种集合的特点如下图所示：可以自己写代码验证一下，各种集合的特点//简单确认一下Collection集合的特点 ArrayList<String> list = new ArrayList<>(); //存取顺序一致，可以重复，有索引 list.add("java1"); list.add("java2"); list.add("java1"); list.add("java2"); System.out.println(list); //[java1, java2, java1, java2] HashSet<String> list = new HashSet<>(); //存取顺序不一致，不重复，无索引 list.add("java1"); list.add("java2"); list.add("java1"); list.add("java2"); list.add("java3"); System.out.println(list); //[java3, java2, java1] Collection集合的常用方法Collection集合的一些常用方法，这些方法所有Collection实现类都可以使用。 这里我们以创建ArrayList为例，来演示Collection<String> c = new ArrayList<>(); //1.public boolean add(E e): 添加元素到集合 c.add("java1"); c.add("java1"); c.add("java2"); c.add("java2"); c.add("java3"); System.out.println(c); //打印: [java1, java1, java2, java2, java3] //2.public int size(): 获取集合的大小 System.out.println(c.size()); //5 //3.public boolean contains(Object obj): 判断集合中是否包含某个元素 System.out.println(c.contains("java1")); //true System.out.println(c.contains("Java1")); //false //4.pubilc boolean remove(E e): 删除某个元素，如果有多个重复元素只能删除第一个 System.out.println(c.remove("java1")); //true System.out.println(c); //打印: [java1,java2, java2, java3] //5.public void clear(): 清空集合的元素 c.clear(); System.out.println(c); //打印：[] //6.public boolean isEmpty(): 判断集合是否为空 是空返回true 反之返回false System.out.println(c.isEmpty()); //true //7.public Object[] toArray(): 把集合转换为数组 Object[] array = c.toArray(); System.out.println(Arrays.toString(array)); //[java1,java2, java2, java3] //8.如果想把集合转换为指定类型的数组，可以使用下面的代码 String[] array1 = c.toArray(new String[c.size()]); System.out.println(Arrays.toString(array1)); //[java1,java2, java2, java3] //9.还可以把一个集合中的元素，添加到另一个集合中 Collection<String> c1 = new ArrayList<>(); c1.add("java1"); c1.add("java2"); Collection<String> c2 = new ArrayList<>(); c2.add("java3")…

正则表达式
type: item
date: 2021-05-17T17:30:00+08:00
description: 正则表达式正则表达式其实是由一些特殊的符号组成的，它代表的是某种规则。正则表达式的作用1：用来校验字符串数据是否合法正则表达式的作用2：可以从一段文本中查找满足要求的内容正则表达式初体验现在，我们就以QQ号码为例，来体验一下正则表达式的用法。注意：现在仅仅只是体验而已，我们还没有讲正则表达式的具体写法。不使用正则表达式，校验QQ号码代码是这样的public static boolean checkQQ(String qq){ // 1、判断qq号码是否为null if(qq == null || qq.startsWith("0") || qq.length() < 6 || qq.length() > 20){ return false; } // 2、qq至少是不是null,不是以0开头的，满足6-20之间的长度。 // 判断qq号码中是否都是数字。 // qq = 2514ghd234 for (int i = 0; i < qq.length(); i++) { // 根据索引提取当前位置处的字符。 char ch = qq.charAt(i); // 判断ch记住的字符，如果不是数字，qq号码不合法。 if(ch < '0' || ch > '9'){ return false; } } // 3、说明qq号码肯定是合法 return true; }用正则表达式代码是这样的public static boolean checkQQ1(String qq){ return qq != null && qq.matches("[1-9]\\d{5,19}"); }使用正则表达式，大大简化的了代码的写法。正则表达式书写规则前面我们已经体验到了正则表达式，可以简化校验数据的代码书写。这里需要用到一个方法叫matches(String regex)。这个方法时属于String类的方法。这个方法是用来匹配一个字符串是否匹配正则表达式的规则，参数需要调用者传递一个正则表达式。但是正则表达式不能乱写，是有特定的规则的。下面我们就学习一下，正则表达式的规则。从哪里学呢？在API中有一个类叫做Pattern，我们可以到API文档中搜索，关于正则表达式的规则，这个类都告诉我们了。我这里把常用的已经给大家整理好了。我们将这些规则，在代码中演示一下/** * 目标：掌握正则表达式的书写规则 */ public class RegexTest2 { public static void main(String[] args) { // 1、字符类(只能匹配单个字符) System.out.println("a".matches("[abc]")); // [abc]只能匹配a、b、c System.out.println("d".matches("[^abc]")); // [^abc] 不能是abc // 2、预定义字符(只能匹配单个字符) . \d \D \s \S \w \W // \转义 System.out.println("\""); // \n \t System.out.println("3".matches("\\d")); // \d: 0-9 System.out.println("a".matches("\\d")); //false // 3、数量词： ? * + {n} {n, } {n, m} System.out.println("1".matches("[0-9]?")); // ? 代表0次或1次 System.out.println("123".matches("[0-9]*")); // * 代表0次或多次 } }正则表达式应用案例学习完正则表达式的规则之后，我们看几个实际案例。正则表达式校验手机号码/** * 目标：校验用户输入的电话、邮箱、时间是否合法。 */ public class RegexTest3 { public static void main(String[] args) { checkPhone(); } public static void checkPhone(){ while (true) { System.out.println("请您输入您的电话号码(手机|座机): "); Scanner sc = new Scanner(System.in); String phone = sc.nextLine(); // 1. 手机号码，以1开头，第二位是3-9中的任意一个数字，后面跟着9个数字。 // 2. 座机号码，以0开头，后面跟着2-7位数字，然后可能会有一个横杠（“-”），后面是4-19位数字。 if(phone.matches("(1[3-9]\\d{9})|(0\\d{…