Java基础

66 阅读20分钟

Java基础

Java 简介

  • 语言特点:Java 是一种面向对象的编程语言,具有平台无关性(通过 JVM 实现“一次编写,到处运行”)、安全性、稳定性和丰富的类库支持。
  • 发展历程:自 1995 年发布以来,Java 经历了多个版本的迭代,目前主要用于企业级开发、移动应用(Android)以及大数据处理等领域。

开发环境与基本设置

  • JDK 与 JRE:开发 Java 程序需要安装 JDK(Java Development Kit),其中包含编译器、调试工具和 JRE(Java Runtime Environment)。
  • IDE 工具:常用的开发环境包括 Eclipse、IntelliJ IDEA、NetBeans 等,能够帮助管理工程、调试和代码提示。

基本语法与结构

  • 程序入口:每个 Java 应用都有一个 main 方法,格式如下:

    public class HelloWorld {
        public static void main(String[] args) {
            System.out.println("Hello, world!");
        }
    }
    
  • 类与对象:Java 是纯面向对象语言(基本数据类型除外),通过类来定义对象的属性和行为。类中的成员变量、方法和构造函数构成了类的基本组成部分。

  • 标识符与命名规范:Java 区分大小写;类名一般首字母大写;变量和方法名一般采用驼峰命名法;常量名通常全部大写。


数据类型与变量

  • 基本数据类型:包括整型(byte、short、int、long)、浮点型(float、double)、字符型(char)和布尔型(boolean)。
  • 引用数据类型:如类、数组、接口等。
  • 变量声明:变量在声明时需要指定类型,如 int num = 10;。对象的引用变量在创建时需要用 new 关键字。

控制结构

  • 条件判断:使用 if...elseswitch 语句控制程序流程。switch 语句用于多分支选择,要求 case 标签的值为常量。
  • 循环结构:包括 for 循环、while 循环和 do...while 循环,适用于重复执行操作。Java 也支持增强型 for 循环,用于遍历数组和集合。

面向对象编程(OOP)

  • 封装:通过类的私有成员和公共方法(getter/setter)实现数据隐藏与保护。
  • 继承:使用 extends 关键字实现子类继承父类的属性与方法,支持方法重写(override)。
  • 多态:允许父类引用指向子类对象,通过动态绑定实现运行时多态。
  • 抽象类与接口:抽象类(abstract class)可以包含抽象方法和具体方法;接口(interface)只包含抽象方法(Java 8 之后也支持默认方法),用于定义规范。

多态(Polymorphism)是面向对象编程的核心特性,指同一方法或操作在不同对象上可能表现出不同的行为。具体说明如下:

  1. 多态的实现

    • 在 Java 中,多态主要通过方法重写(Override)来体现,即父类引用指向子类对象,在运行时调用的是子类中重写的方法。这种方式属于运行时多态。
    • 方法重载(Overload)则是编译时多态,根据方法的参数类型和个数在编译阶段确定调用哪个方法,但严格来说,多态通常指的是运行时的动态绑定。
  2. 行为时机

    • 运行时多态:通过方法重写实现的多态在运行时根据对象的实际类型决定调用哪个方法,体现为动态绑定。
    • 编译时多态:方法重载是在编译期间就决定调用哪个方法,属于静态多态。

因此,说“Java里通过方法重载和方法重写来体现多态”是不完全准确的。更准确的说法是:

  • 方法重载体现了静态多态(编译时多态),而方法重写体现了动态多态(运行时多态)。

异常处理

  • 异常机制:使用 try...catch...finally 结构捕获和处理异常,保证程序健壮性。关键字 throw 用于抛出异常,throws 用于声明可能抛出的异常类型。
  • 自定义异常:可以通过继承 Exception 类来创建自定义异常类。

集合框架

  • 常用集合类:Java 集合框架提供了多种数据结构,如 List、Set、Map 和 Queue,分别适用于不同的数据存储和处理需求。

    • List:有序且可重复(如 ArrayList、LinkedList)。
    • Set:无序且不重复(如 HashSet、TreeSet)。
    • Map:键值对存储(如 HashMap、TreeMap)。
  • 迭代器:通过 Iterator 接口遍历集合元素。


多线程与并发

  • 线程创建:可以通过继承 Thread 类或实现 Runnable 接口来创建线程。
  • 同步机制:通过 synchronized 关键字、Lock 接口、volatile 变量等机制控制线程间的协作与数据一致性。
  • 并发工具:Java 提供了诸如 CountDownLatch、CyclicBarrier、Semaphore 等工具类,简化并发编程。

文件 I/O 与网络编程

  • 文件 I/O:利用 java.iojava.nio 包提供的类(如 File、InputStream、OutputStream、Reader、Writer)进行文件读写操作。
  • 网络编程:使用 java.net 包中的 Socket、ServerSocket 类实现客户端和服务器端通信。

其他关键特性

  • 泛型:Java 泛型允许在类、接口和方法中定义类型参数,提高代码复用性和类型安全性。
  • 注解(Annotations) :用于在代码中嵌入元数据,常见的注解如 @Override@Deprecated 等。
  • Lambda 表达式(Java 8+):简化匿名内部类的写法,使得函数式编程成为可能。
  • 流 API(Java 8+):基于 Lambda 表达式的集合操作,支持过滤、映射、排序和聚合等操作。

参考链接

数据结构和算法基础

数据结构

数据结构是指在计算机中组织、存储和管理数据的方式,它直接影响算法的效率和系统性能。常见的数据结构包括:

线性结构

  • 数组(Array)

    • 固定大小的同类型元素集合,支持通过索引进行快速访问。
    • 缺点:在插入和删除时需要移动元素,灵活性较差。
  • 链表(Linked List)

    • 由一系列节点构成,每个节点包含数据和指向下一个节点的指针。
    • 单链表、双向链表和循环链表等变种,适合频繁插入和删除操作,但随机访问效率较低。
  • 栈(Stack)

    • 先进后出(LIFO)结构,常用于表达式求值、递归调用的实现等场景。
  • 队列(Queue)

    • 先进先出(FIFO)结构,适用于任务调度、消息传递等场景。
    • 还有双端队列(Deque),支持两端操作。

树形结构

  • 二叉树(Binary Tree)

    • 每个节点最多有两个子节点,常用于表达式解析、二叉搜索树(BST)等。
  • 平衡树(Balanced Tree)

    • 如 AVL 树、红黑树等,保持树的平衡,保证查找、插入、删除的时间复杂度为 O(log n)。
  • 堆(Heap)

    • 特殊的完全二叉树,用于实现优先队列,常见有最大堆和最小堆。

图(Graph)

  • 用于表示网络结构,由节点(顶点)和边构成。
  • 可分为有向图和无向图,常见算法包括遍历(DFS、BFS)、最短路径(Dijkstra、Bellman-Ford)和最小生成树(Kruskal、Prim)等。

哈希表(Hash Table)

  • 通过哈希函数将键映射到存储位置,实现高效的查找、插入和删除操作。
  • 需要处理冲突问题,如链式法、开放地址法等。

算法

算法是指解决问题的一系列有限步骤。优秀的算法不仅要解决问题,还要求高效、节省资源。常见的算法分类包括:

排序算法

  • 常见排序算法:冒泡排序、选择排序、插入排序、归并排序、快速排序、堆排序等。
  • 排序算法的效率通常以时间复杂度(如 O(n²)、O(n log n))来衡量,适用于不同规模数据的排序需求。

搜索算法

  • 线性搜索:逐个查找,适用于无序数组,时间复杂度 O(n)。
  • 二分搜索:适用于有序数组,时间复杂度 O(log n)。

分治与递归

  • 分治法:将问题分解为若干子问题解决后,再合并结果,如归并排序、快速排序。
  • 递归:函数调用自身来解决问题,常见于树的遍历、斐波那契数列等场景。

动态规划

  • 将问题拆分为子问题,保存中间结果避免重复计算,适用于最优子结构问题,如最长公共子序列、背包问题等。

贪心算法

  • 在每一步都选择当前最优解,适用于某些特定问题(如活动选择问题、最小生成树算法中的 Kruskal 和 Prim 算法)。

图算法

  • 遍历算法:深度优先搜索(DFS)、广度优先搜索(BFS)。
  • 最短路径:Dijkstra 算法、Bellman-Ford 算法、A* 算法。
  • 最小生成树:Kruskal 算法、Prim 算法。
  • 拓扑排序:用于有向无环图(DAG)的排序。

数据结构与算法的综合应用

数据结构与算法往往密切相关:

  • 合理选择数据结构(如使用哈希表代替数组)能极大提高算法效率。
  • 许多算法(如排序、搜索、图算法)都依赖于特定的数据结构来优化性能。
  • 学习和掌握这些基础知识,对于编写高效、健壮的软件系统至关重要。

参考链接

日常实践

进程和线程

在Java中,进程线程是操作系统用于管理程序执行的两种基本单位。

进程是操作系统分配资源的基本单位,每个进程都有独立的内存空间和资源。进程之间相互独立,一个进程的崩溃不会直接影响其他进程。

线程是进程的执行单位,一个进程可以包含多个线程。线程共享进程的内存空间和资源,但每个线程有自己的程序计数器、栈和局部变量。线程之间的切换开销较小,适合用于并发执行任务。

多进程与多线程的区别:

  • 资源占用: 进程占用更多的系统资源,线程占用较少。
  • 通信方式: 进程间通信复杂,需要使用进程间通信机制;线程间通信简单,可以通过共享内存直接访问。
  • 稳定性: 进程间相互独立,一个进程崩溃不会影响其他进程;线程间相互依赖,一个线程崩溃可能导致整个进程崩溃。

创建线程的方式:

  1. 继承Thread类:

    • 创建一个类继承Thread,重写run()方法,定义线程执行的任务。
    • 创建该类的实例,调用start()方法启动线程。
    class MyThread extends Thread {
        @Override
        public void run() {
            // 线程执行的任务
        }
    }
    
  2. 实现Runnable接口:

    • 创建一个类实现Runnable接口,重写run()方法,定义线程执行的任务。
    • 创建Thread对象,将Runnable实例传入,调用start()方法启动线程。
    class MyRunnable implements Runnable {
        @Override
        public void run() {
            // 线程执行的任务
        }
    }
    
  3. 实现Callable接口:

    • 创建一个类实现Callable接口,重写call()方法,定义线程执行的任务。
    • 通过ExecutorService提交任务,获取Future对象以获取返回值。
    class MyCallable implements Callable<Integer> {
        @Override
        public Integer call() throws Exception {
            // 线程执行的任务
            return result;
        }
    }
    

线程池的使用:

线程池用于管理线程的创建、调度和销毁,避免频繁创建和销毁线程带来的性能开销。

  • 创建线程池:

    • 使用Executors工厂类创建线程池。

      ExecutorService executor = Executors.newFixedThreadPool(10);
      
  • 提交任务:

    • 通过submit()方法提交任务。

      executor.submit(new MyRunnable());
      
  • 关闭线程池:

    • 使用shutdown()方法关闭线程池。

      executor.shutdown();
      

线程间的同步与通信:

  • 同步:

    • 使用synchronized关键字确保同一时刻只有一个线程可以执行被同步的方法或代码块。

      public synchronized void method() {
          // 同步代码
      }
      
  • 通信:

    • 使用wait()notify()notifyAll()方法实现线程间的通信。

      synchronized (lock) {
          while (condition) {
              lock.wait();
          }
          // 执行任务
          lock.notify();
      }
      

线程池的类型:

  • FixedThreadPool:

    • 创建一个固定大小的线程池,适用于负载较重的任务。
  • CachedThreadPool:

    • 创建一个可缓存的线程池,适用于执行很多短期异步任务的小程序。
  • SingleThreadExecutor:

    • 创建一个单线程化的线程池,适用于需要保证顺序执行的任务。
  • ScheduledThreadPool:

    • 创建一个定长线程池,支持定时及周期性任务执行。

使用线程池可以有效管理线程的生命周期,避免频繁创建和销毁线程带来的性能开销。

在实际开发中,合理使用线程池和线程同步机制,可以提高程序的并发性能和稳定性。

sleep和wait的区别

sleep:睡眠 进入冻结状态 直到时间结束自动醒来 不再抢夺cpu 但是不释放锁 醒来后不意味着立即就能执行 仍然要抢到cpu才能执行

wait: 进入冻结状态 不再抢夺cpu 并且释放锁 直到被其他线程notify唤醒才能从等待状态中醒来 接着执行 并不意味着一定能立即执行 仍然需要抢夺到锁和cpu后才能执行

sleep方法需要指定沉睡的时间,到点之后自然清醒,在沉睡期间,没有释放锁对象,释放CPU,释放执行权,被设计在了Thread类上

wait方法没有指定时间,需要notify去唤醒,在等待期间,释放锁对象,释放CPU,释放执行权,被设计在了Object类上

类型互转

String 转 int

可以使用 Integer.parseInt() 方法将 String 转换为 int 类型。

String id = "123";
int ids = Integer.parseInt(id);
System.out.println(ids);  // 输出:123

int 转 String

使用 String.valueOf() 方法或 Integer.toString() 方法来将 int 转换为 String 类型。

int ids = 123;
String idStr = String.valueOf(ids);
System.out.println(idStr);  // 输出:"123"

int 转 long

可以通过强制类型转换将 int 转换为 long 类型:

int ids = 123;
long longValue = (long) ids;
System.out.println(longValue);  // 输出:123

int 转 double

同样可以通过强制类型转换将 int 转换为 double 类型:

int ids = 123;
double doubleValue = (double) ids;
System.out.println(doubleValue);  // 输出:123.0

double 保留两位小数

可以使用 DecimalFormatString.format() 来保留 double 类型的小数位数。

使用 DecimalFormat

double value = 123.456789;
DecimalFormat df = new DecimalFormat("#.00");
System.out.println(df.format(value));  // 输出:123.46

使用 String.format()

double value = 123.456789;
String formattedValue = String.format("%.2f", value);
System.out.println(formattedValue);  // 输出:123.46

枚举中根据一个参数获取另外一个

假设有一个枚举 ProcessStatus,你可以根据某个参数(例如 String)来获取枚举中的其它值(如 Message):

public enum ProcessStatus {
    SUCCESS("200", "Success"),
    ERROR("300", "Error");

    private String code;
    private String message;

    ProcessStatus(String code, String message) {
        this.code = code;
        this.message = message;
    }

    public String getCode() {
        return code;
    }

    public String getMessage() {
        return message;
    }

    public static ProcessStatus getProcessStatus(String code) {
        for (ProcessStatus status : values()) {
            if (status.getCode().equals(code)) {
                return status;
            }
        }
        return null;  // 如果没有找到对应的状态,可以返回null
    }
}

获取枚举中的值:

System.err.println(ProcessStatus.getProcessStatus("300").getMessage());  // 输出:"Error"

报错:jdk版本问题

你提到的 jdk版本问题 是因为在你的 pom.xml 中配置了较低的 JDK 版本。以下是你给出的 Maven 配置:

<plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>2.3.2</version>
    <configuration>
        <source>1.6</source>
        <target>1.6</target>
    </configuration>
</plugin>

这段代码指定了 maven-compiler-plugin 使用 JDK 1.6。如果你使用的 JDK 版本较高,可能会遇到版本不兼容的问题。你可以更新为 JDK 1.8 或更高版本,像这样:

<plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.8.1</version>
    <configuration>
        <source>1.8</source>
        <target>1.8</target>
    </configuration>
</plugin>

通过将 sourcetarget 改为 1.8 或更高版本,你可以避免版本不兼容的问题。

Math方法

Math.min 方法是用于比较两个数字大小,并返回较小的那个数值。它是 Math 类的一个静态方法,支持多种数据类型:intfloatdoublelong。根据输入的类型,返回的值类型也会相应变化。

方法签名:

public static int min(int a, int b)
public static long min(long a, long b)
public static float min(float a, float b)
public static double min(double a, double b)

用法示例:

1. int 类型:

int a = 4, b = 6;
int c = Math.min(a, b);
System.out.println(c);  // 输出结果:4

这里,Math.min(a, b) 会比较 ab,返回较小的那个,即 4

2. float 类型:

float a = 2.0f, b = 3.0f;
float c = Math.min(a, b);
System.out.println(c);  // 输出结果:2.0

此时,Math.min(a, b) 会比较 ab,返回较小的那个,即 2.0

3. double 类型:

double a = 5.5, b = 7.7;
double c = Math.min(a, b);
System.out.println(c);  // 输出结果:5.5

Math.min(a, b) 会比较 ab,返回较小的那个,即 5.5

4. long 类型:

long a = 10000000000L, b = 9999999999L;
long c = Math.min(a, b);
System.out.println(c);  // 输出结果:9999999999

对于 long 类型,Math.min(a, b) 会返回较小的数值 9999999999L

注意事项:

  • Math.min 方法会自动进行类型提升,如果传入的参数类型不同,Math 会根据规则将它们转换为共同的较大类型进行比较。例如,如果一个参数是 int 类型,另一个是 double 类型,则 int 会自动提升为 double 类型来进行比较。
  • 如果输入的两个值相等,Math.min 会返回它们中的任意一个。

cron表达式

👉 在线 Cron 表达式生成器

常见的 cron 表达式格式

秒 分 时 日 月 星期 [年]
  • * 代表任意值
  • ? 代表不指定值(通常用于“日”和“星期”字段)
  • - 代表区间,例如 9-12 代表 9 点到 12 点
  • / 代表步长,例如 */5 代表每 5 单位触发一次
  • L 代表最后一天,例如 L 在“日”字段中表示月末,在“星期”字段中表示该月的最后一个星期几
  • W 代表最近的工作日,例如 15W 代表离 15 号最近的工作日
  • # 代表某月的第几个星期几,例如 6#3 代表每月的第三个星期五

常见 cron 表达式示例

表达式触发时间
0 0 10,14,16 * * ?每天上午 10 点、下午 2 点、下午 4 点
0 0/30 9-17 * * ?朝九晚五工作时间内,每半小时触发
0 0 12 ? * WED每周三中午 12 点触发
0 15 10 ? * MON-FRI周一到周五上午 10:15 触发
0 0/5 14 * * ?每天下午 2 点到 2:55,每 5 分钟触发
0 15 10 L * ?每月最后一天上午 10:15 触发
0 15 10 ? * 6#3每月的第三个星期五上午 10:15 触发
0 15 10 ? * 6L每月的最后一个星期五上午 10:15 触发

Spring Boot 常用注释

1. 核心注解

  • @SpringBootApplication:这是一个组合注解,包含了 @Configuration@EnableAutoConfiguration@ComponentScan。它标识一个类为 Spring Boot 应用的入口,启用自动配置和组件扫描。

  • @Configuration:用于定义配置类,表示该类可以使用 Spring IoC 容器作为 bean 定义的来源。

    • @Configuration不可以是final类型;
    • @Configuration不可以是匿名类;
    • 嵌套的configuration必须是静态类。
  • @EnableAutoConfiguration:启用 Spring Boot 的自动配置机制,根据项目的依赖自动配置 Spring 应用程序。

  • @ComponentScan:用于扫描指定包下的组件,自动发现和注册被 @Component@Service@Repository@Controller 等注解标注的类。

2. 组件注解

  • @Component:泛指组件,当组件不好归类的时候,可以使用这个注解进行标注。
  • @Service:用于标注服务层的组件,表示业务逻辑层的 bean。
  • @Repository:用于标注数据访问层的组件,表示 DAO 层的 bean,并支持异常转译。
  • @Controller:用于标注控制层的组件,处理 HTTP 请求并返回视图。
  • @RestController:是 @Controller@ResponseBody 的组合,表示这是一个 RESTful 风格的控制器,返回的结果直接写入 HTTP 响应体中。

3. 依赖注入注解

  • @Autowired:用于自动注入依赖的 bean,默认按类型注入。
  • @Qualifier:与 @Autowired 一起使用,用于指定注入 bean 的名称。
  • @Resource:按名称自动注入依赖对象,也可以按类型注入。

4. 配置相关注解

  • @Bean:用于定义一个 bean,可以指定初始化和销毁方法,以及 bean 的作用域。
  • @Value:用于注入配置文件中的属性值。
  • @ConfigurationProperties:用于将配置文件中的属性映射到一个类的字段上。
  • @EnableConfigurationProperties:启用 @ConfigurationProperties 注解的类。
  • @Import:用于导入其他配置类。
  • @ImportResource:用于导入 XML 配置文件。

5. Web 相关注解

  • @RequestMapping:用于映射 HTTP 请求到处理方法上,可以用于类或方法上。
  • @GetMapping@PostMapping@PutMapping@DeleteMapping:分别用于处理 GET、POST、PUT、DELETE 请求的快捷注解。
  • @RequestParam:用于将请求参数绑定到方法的参数上。
  • @PathVariable:用于将 URL 模板中的变量绑定到方法的参数上。
  • @RequestBody:用于将 HTTP 请求体转换为 Java 对象。
  • @ResponseBody:用于将方法的返回值直接写入 HTTP 响应体中。

6. 异常处理注解

  • @ControllerAdvice:用于定义全局的异常处理、数据绑定和模型属性等。

    • import com.bigdata.exception.GeneralException;
      import com.bigdata.model.Response;
      import org.springframework.web.bind.annotation.ControllerAdvice;
      import org.springframework.web.bind.annotation.ExceptionHandler;
      import org.springframework.web.bind.annotation.ResponseBody;
      import org.springframework.web.bind.annotation.RestController;
      
      import javax.servlet.http.HttpServletRequest;
      
      @RestController
      @ControllerAdvice
      public class GlobalExceptionHandler {
      
          @ExceptionHandler(value = GeneralException.class)
          @ResponseBody
          public Response<String> generalExceptionHandler(
          HttpServletRequest req, GeneralException e) throws Exception {
              Response<String> res = new Response<>();
              res.setCode(e.getCode());
              res.setData(e.getMessage());
              return res;
          }
      }
      
  • @ExceptionHandler:用于处理控制器方法抛出的特定异常。

    • @ExceptionHandler(value = GeneralException.class)
        @ResponseBody
        public Response<String> generalExceptionHandler(
            HttpServletRequest req, GeneralException e) throws Exception {
            Response<String> res = new Response<>();
            res.setCode(e.getCode());
            res.setData(e.getMessage());
            return res;
        }
      

7. 其他常用注解

  • @Scheduled:用于定义计划任务,支持多种类型的计划任务,如 cron 表达式、固定延迟、固定速率等。

  • @EnableScheduling:启用 Spring 的计划任务功能。

  • @Async:用于标注异步方法,方法会在独立的线程中执行。

  • @EnableAsync:启用 Spring 的异步方法执行功能。

  • @Transactional:用于标注事务方法,方法会在事务中执行。

  • @EnableTransactionManagement:启用注解驱动的事务管理功能。

  • @Cacheable:用于标注缓存方法,方法的返回值会被缓存。

  • @EnableCaching:启用 Spring 的缓存功能。

  • @Profile:用于指定 bean 在特定的环境下生效。

  • @Conditional:用于根据条件来决定是否注册某个 bean。

  • @PropertySource:用于加载外部的属性文件。

  • @Scope:用于指定 bean 的作用域,如单例、原型等。

  • @Lazy:用于延迟初始化 bean,只有在第一次使用时才会被初始化。

  • @PostConstruct@PreDestroy:用于在 bean 初始化后和销毁前执行特定操作。

  • @JsonProperty 注解用于将 Java 对象的属性与 JSON 数据中的字段进行映射。通过在属性上使用 @JsonProperty,可以指定序列化和反序列化时对应的 JSON 字段名称。

    • @JsonProperty("top_row")
      private String topRow;
      
      @JsonProperty("last_row")
      private String lastRow;
      
    • <dependency>
          <groupId>com.fasterxml.jackson.core</groupId>
          <artifactId>jackson-databind</artifactId>
          <version>2.5.3</version>
      </dependency>
      

日常问题

json对接错误

com.alibaba.fastjson.JSONException: syntax error, pos 1
at com.alibaba.fastjson.parser.DefaultJSONParser.parse(DefaultJSONParser.java:1083)
at com.alibaba.fastjson.parser.DefaultJSONParser.parse(DefaultJSONParser.java:1009)
at com.alibaba.fastjson.JSON.parse(JSON.java:89)
at com.alibaba.fastjson.JSON.parse(JSON.java:80)
at com.alibaba.fastjson.JSON.parseObject(JSON.java:151)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:708)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:98)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:262)

2、错误原因

@Override
public Object getQueryStudent()throws Exception{
     JSONObject json = this.getData(CDKM);
     return queryStudent(json);
} 

当this.getData(CDKM)没有返回值或者无值时,json就会报这个错误

3、解决办法

给json对象赋值前先判断有无数据,如果有直接这样赋值;否则返回null

json空值问题

Post传进来的数据
{"newdate":"2018-01-21","merchantid":"002","sockid":"bf49ff6c0cf66628d869ff10893e91ed","userdimension":{"number":{"new_users":25,"number_users":617520},"classification":{"repeat_borrowing":null,"only_registered":null,"first_loan":null,"remaining_tube":null}},"transactiondimension":{"marketing":{"marketing_expenses":0},"loan":{"loan_principal":null,"loan_number":null},"remaining":{"amount_contract":929585677.21,"contract_number":81774},"overdue":{"principal_overdue_one":8256129.82,"principal_overdue_two":5802853.3,"principal_overdue_three":511544900.68},"repayment":{"data":{"stock_principal":408077683.8},"dataline":{"should_principal":1263500048}},"repayment_interest":{"data":{"interest_received":37741097.56},"dataline":{"should_interest":109309213.51}}},"cashdimension":{"cash_flow":{"flow_out":null,"inflow":288620.9}}}

我接收的数据
{"userdimension":{"number":{"number_users":617520,"new_users":25},"classification":{}},"merchantid":"002","sockid":"bf49ff6c0cf66628d869ff10893e91ed","cashdimension":{"cash_flow":{"inflow":288620.9}},"newdate":"2018-01-21","transactiondimension":{"marketing":{"marketing_expenses":0},"loan":{},"repayment_interest":{"dataline":{"should_interest":109309213.51},"data":{"interest_received":37741097.56}},"overdue":{"principal_overdue_two":5802853.3,"principal_overdue_three":511544900.68,"principal_overdue_one":8256129.82},"remaining":{"amount_contract":929585677.21,"contract_number":81774},"repayment":{"dataline":{"should_principal":1263500048},"data":{"stock_principal":408077683.8}}}}

解决方法一

Null字符串可以 “null”

java.io.IOException

报错:java.io.IOException Server returned HTTP response code 400 for URL

解决办法:label=URLEncoder.encode(label,"utf-8");//对含有空格的参数进行处理;