跳至主要內容

SpringBoot环境配置

wangdx大约 13 分钟

自定义启动 Banner

自定义启动 Banner

  • 每一个 SpringBoot 程序启动时,都会在控制台利用指定的艺术结构生成有 Spring 启动 Banner 信息,同时考虑项目个性化的需要,也可以由使用者自定义启动 Banner

banneropen in new window

1、http://patorjk.com/software/taag/#p=display&f=Graffiti&t=Type%20Something%20

2、
                                                  __   __
__  _  ____  _  ____  _  __  ___.__. ____   _____/  |_|  | __     ____  ____   _____
\ \/ \/ /\ \/ \/ /\ \/ \/ / <   |  |/  _ \ /  _ \   __\  |/ /   _/ ___\/  _ \ /     \
 \     /  \     /  \     /   \___  (  <_> |  <_> )  | |    <    \  \__(  <_> )  Y Y  \
  \/\_/    \/\_/    \/\_/ /\ / ____|\____/ \____/|__| |__|_ \ /\ \___  >____/|__|_|  /
                          \/ \/                            \/ \/     \/            \/

3、org.springframework.boot.Banner


4、
package org.springframework.boot;

import java.io.PrintStream;

import org.springframework.core.env.Environment;
@FunctionalInterface // 此为函数式接口
public interface Banner {   // 由SpringBoot所提供的内部接口

    /**
     * 通过指定PrintStream(打印流)来实现启动Banner输出
     * @param environment 项目启动时所指派的profile
     * @param sourceClass 应用程序类
     * @param out 实现Banner信息输出
     */
    void printBanner(Environment environment, Class<?> sourceClass, PrintStream out);
    enum Mode { // Banner的启动的模式
        OFF,    // 不输出Banner信息
        CONSOLE, // 在控制台输出Banner
        LOG // 在日志中输出Banner
    }

}

5、
           .___                             __   __
  ____   __| _/_ __    ___.__. ____   _____/  |_|  | __     ____  ____   _____
_/ __ \ / __ |  |  \  <   |  |/  _ \ /  _ \   __\  |/ /   _/ ___\/  _ \ /     \
\  ___// /_/ |  |  /   \___  (  <_> |  <_> )  | |    <    \  \__(  <_> )  Y Y  \
 \___  >____ |____/ /\ / ____|\____/ \____/|__| |__|_ \ /\ \___  >____/|__|_|  /
     \/     \/      \/ \/                            \/ \/     \/            \/


6、
package com.yootk.banner;

import org.springframework.boot.Banner;
import org.springframework.core.env.Environment;

import java.io.PrintStream;
import java.util.Random;

// 如果现在只有一个Banner可以直接基于Lambda表达式来进行配置
public class YootkBanner implements Banner { // 实现了自定义的Banner输出
    private static final String[] YOOTK_BANNER = {
        "                                                  __   __",
        "__  _  ____  _  ____  _  __  ___.__. ____   _____/  |_|  | __     ____  ____   _____",
        "\\ \\/ \\/ /\\ \\/ \\/ /\\ \\/ \\/ / <   |  |/  _ \\ /  _ \\   __\\  |/ /   _/ ___\\/  _ \\ /     \\",
        " \\     /  \\     /  \\     /   \\___  (  <_> |  <_> )  | |    <    \\  \\__(  <_> )  Y Y  \\",
        "  \\/\\_/    \\/\\_/    \\/\\_/ /\\ / ____|\\____/ \\____/|__| |__|_ \\ /\\ \\___  >____/|__|_|  /",
        "                          \\/ \\/                            \\/ \\/     \\/            \\/ "
    }; // 所有的Banner信息如果是复合的结构则必须使用数组进行配置
    private static final String[] EDU_BANNER = {
        "           .___                             __   __                             ",
        "  ____   __| _/_ __    ___.__. ____   _____/  |_|  | __     ____  ____   _____  ",
        "_/ __ \\ / __ |  |  \\  <   |  |/  _ \\ /  _ \\   __\\  |/ /   _/ ___\\/  _ \\ /     \\ ",
        "\\  ___// /_/ |  |  /   \\___  (  <_> |  <_> )  | |    <    \\  \\__(  <_> )  Y Y  \\",
        " \\___  >____ |____/ /\\ / ____|\\____/ \\____/|__| |__|_ \\ /\\ \\___  >____/|__|_|  /",
        "     \\/     \\/      \\/ \\/                            \\/ \\/     \\/            \\/ ",
    };
    private static final String MUYAN_BANNER = "沐言科技:www.yootk.com"; // 普通文本
    private static final Random RANDOM = new Random();
    @Override
    public void printBanner(Environment environment, Class<?> sourceClass, PrintStream out) { // 方法覆写
        out.println(); // 输出一个换行
        int num = RANDOM.nextInt(10); // 生成一个0 ~ 9的随机数字
        if (num == 0) { // 第一种情况
            for (String line : YOOTK_BANNER) {
                out.println(line);
            }
        } else if (num % 2 == 1) {
            for (String line : EDU_BANNER) {
                out.println(line);
            }
        } else {
            out.println(MUYAN_BANNER);
        }
        out.println(); // 输出一个换行
        out.flush(); // 强制清空缓存
    }
}


7、
package com.yootk; // 父包,这个包中的所有子包的类会被自动扫描

import com.yootk.banner.YootkBanner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication // 一个注解解决所有的问题
public class StartSpringBootApplication {
    public static void main(String[] args) {
        SpringApplication springApplication = new SpringApplication(
                StartSpringBootApplication.class); // 获取实例化对象
        springApplication.setBanner(new YootkBanner()); // 配置自定义的Banner生成器
        springApplication.run(args); // 运行SpringBoot程序
    }
}


8、
package com.yootk; // 父包,这个包中的所有子包的类会被自动扫描

import com.yootk.banner.YootkBanner;
import org.springframework.boot.Banner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication // 一个注解解决所有的问题
public class StartSpringBootApplication {
    public static void main(String[] args) {
        SpringApplication springApplication = new SpringApplication(
                StartSpringBootApplication.class); // 获取实例化对象
        springApplication.setBannerMode(Banner.Mode.OFF); // 关闭Banner输出
        springApplication.setBanner(new YootkBanner()); // 配置自定义的Banner生成器
        springApplication.run(args); // 运行SpringBoot程序
    }
}

导入 Spring 配置文件

1、
package com.yootk.service;

public interface IMessageService { // 创建业务接口
    public String echo(String msg);
}


2、
package com.yootk.service.impl;

import com.yootk.service.IMessageService;
import org.springframework.stereotype.Service;

@Service // 原始的Spring开发需要配置扫描包
public class MessageServiceImpl implements IMessageService {
    @Override
    public String echo(String msg) {
        return "【ECHO】" + msg;
    }
}


3、
package com.yootk.action;

import com.yootk.service.IMessageService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController // 直接基于Rest架构进行处理,省略了@ResponseBody注解
@RequestMapping("/message/*") // 添加父路径
public class MessageAction { // 控制层的实现类
    @Autowired
    private IMessageService messageService;
    private static final Logger LOGGER = LoggerFactory.getLogger(MessageAction.class); // 获取日志对象
    @RequestMapping("echo") // 子路径
    public String echo(String msg) { // 进行请求参数的接收以及请求内容的回应
        LOGGER.info("接收msg的请求参数,内容为:{}", msg); // 日志输出
        return this.messageService.echo(msg); // 直接进行Rest响应
    }
}


4、
localhost:8080/message/echo?msg=沐言科技:www.yootk.com

5、
package com.yootk.service.impl;

import com.yootk.service.IMessageService;

public class MessageServiceImpl implements IMessageService {
    @Override
    public String echo(String msg) {
        return "【ECHO】" + msg;
    }
}


6、
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation=" http://www.springframework.org/schema/beans
                            http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--  依据Spring的配置要求配置指定的程序Bean对象(向Spring容器之中注册Bean)  -->
    <bean id="messageService" class="com.yootk.service.impl.MessageServiceImpl"/>
</beans>

7、
package com.yootk; // 父包,这个包中的所有子包的类会被自动扫描

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ImportResource;

@SpringBootApplication // 一个注解解决所有的问题
@ImportResource(locations = {"classpath:META-INF/spring/spring-*.xml"})
public class StartSpringBootApplication {
    public static void main(String[] args) {
        SpringApplication.run(StartSpringBootApplication.class,args); // 运行SpringBoot程序
    }
}

项目热部署

sorng-boot-devtools

  • 在 SpringBoot 项目开发中,如果要想获取每次代码更新后的结果往往都需要重新启项目,但是这样的方式在代码开发阶段并不友好,所以为了解决这一问题 Spring 提供了一个“spring-boot-devtools”热部署组件库,可以在项目运行期间动态的加载更新后的 Java 程序类。
  • spring-boot-devtools 使用了两个不同的 ClassLoader,-个 ClassLoader 加载那些不会被改变的程序类(例如:Jar 包中的类),另外一个 ClassLoader 加载用户开发的程序类

同时按住 Ctrl + Shift + Alt + / 然后进入 Registry ,勾选自动编译并调整延时参数。

SpringBoot 在 IDEA 里实现热部署open in new window

SpringBoot 热部署 2023 最新版 IDEA 详细步骤open in new window

1、
package com.yootk.action;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController // 直接基于Rest架构进行处理,省略了@ResponseBody注解
@RequestMapping("/message/*") // 添加父路径
public class MessageAction { // 控制层的实现类
    private static final Logger LOGGER = LoggerFactory.getLogger(MessageAction.class); // 获取日志对象
    @RequestMapping("echo") // 子路径
    public String echo(String msg) { // 进行请求参数的接收以及请求内容的回应
        LOGGER.info("接收msg的请求参数,内容为:{}", msg); // 日志输出
        return "【ECHO】" + msg; // 直接进行Rest响应
    }
}


2、
// https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-devtools
implementation group: 'org.springframework.boot', name: 'spring-boot-devtools', version: '2.4.3'

3、
subprojects {   // 子模块
    dependencies {  // 公共依赖库管理
        compile('org.springframework.boot:spring-boot-devtools') // 允许进行项目的热部署
    }
}

整合 JUnit5 用例测试

1、
// https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-test
testImplementation group: 'org.springframework.boot', name: 'spring-boot-starter-test', version: '2.4.3'

// https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api
testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.7.1'

// https://mvnrepository.com/artifact/org.junit.vintage/junit-vintage-engine
testImplementation group: 'org.junit.vintage', name: 'junit-vintage-engine', version: '5.7.1'

// https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-engine
testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.7.1'

// https://mvnrepository.com/artifact/org.junit.platform/junit-platform-launcher
testImplementation group: 'org.junit.platform', name: 'junit-platform-launcher', version: '1.7.1'

// https://mvnrepository.com/artifact/org.junit/junit-bom
implementation group: 'org.junit', name: 'junit-bom', version: '5.7.1', ext: 'pom'


2、
ext.versions = [    // 定义所有要使用的版本号
        springboot:                         '2.4.1', // SpringBoot版本号
        junit:                              '5.7.1', // 配置JUnit测试工具的版本编号
        junitPlatformLauncher:              '1.7.1'  // JUnit测试工具运行平台版本编号
]
ext.libraries = [   // 定义所有的依赖库
        // 以下的配置为SpringBoot项目所需要的核心依赖
        'spring-boot-gradle-plugin': "org.springframework.boot:spring-boot-gradle-plugin:${versions.springboot}",
        // 以下的配置为与项目用例测试有关的依赖
        'junit-jupiter-api': "org.junit.jupiter:junit-jupiter-api:${versions.junit}",
        'junit-vintage-engine': "org.junit.vintage:junit-vintage-engine:${versions.junit}",
        'junit-jupiter-engine': "org.junit.jupiter:junit-jupiter-engine:${versions.junit}",
        'junit-platform-launcher': "org.junit.platform:junit-platform-launcher:${versions.junitPlatformLauncher}",
        'junit-bom': "org.junit:junit-bom:${versions.junit}",
]

3、
package com.yootk.test;

import com.yootk.StartSpringBootApplication;
import com.yootk.action.MessageAction;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.web.WebAppConfiguration;

@ExtendWith(SpringExtension.class) // 使用JUnit5测试工具
@WebAppConfiguration // 启动WEB运行环境
@SpringBootTest(classes = StartSpringBootApplication.class) // 配置程序启动类
public class TestMessageAction { // 编写测试类
    @Autowired
    private MessageAction messageAction; // 注入MessageAction的对象实例
    @BeforeAll
    public static void init() {
        System.err.println("【@BeforeAll】TestMessageAction类开始执行测试操作。");
    }
    @AfterAll
    public static void after() {
        System.err.println("【@AfterAll】TestMessageAction类测试完成。");
    }
    @Test
    public void testEcho() {    // 进行响应测试
        String content = this.messageAction.echo("沐言科技:www.yootk.com");
        String value = "【ECHO】沐言科技:www.yootk.com";
        System.err.println("【@Test】测试echo()方法返回值,当前放回结果为:" + content);
        Assertions.assertEquals(content, value); // 测试相等
    }
}

4、
package com.yootk.service.impl;

import com.yootk.service.IMessageService;
import org.springframework.stereotype.Service;

@Service
public class MessageServiceImpl implements IMessageService {
    @Override
    public String echo(String msg) {
        return "【ECHO】" + msg;
    }
}


5、
package com.yootk.test;

import com.yootk.StartSpringBootApplication;
import com.yootk.service.IMessageService;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.web.WebAppConfiguration;

@ExtendWith(SpringExtension.class) // 使用JUnit5测试工具
@WebAppConfiguration // 启动WEB运行环境
@SpringBootTest(classes = StartSpringBootApplication.class) // 配置程序启动类
public class TestMessageService { // 编写测试类
    @Autowired
    private IMessageService messageService;
    @Test
    public void testEcho() {    // 进行响应测试
        String content = this.messageService.echo("沐言科技:www.yootk.com");
        String value = "【ECHO】沐言科技:www.yootk.com";
        System.err.println("【@Test】测试echo()方法返回值,当前放回结果为:" + content);
        Assertions.assertEquals(content, value); // 测试相等
    }
}

Lombok 简介与配置

1、
package com.yootk.test.vo;

public class Dept {
    private Long deptno;
    private String dname;
    private String loc;

}


2、
compileOnly group: 'org.projectlombok', name: 'lombok', version: '1.18.18'
// https://mvnrepository.com/artifact/org.projectlombok/lombok
compileOnly group: 'org.projectlombok', name: 'lombok', version: '1.18.30'


3、
ext.versions = [    // 定义所有要使用的版本号
        springboot                         :'2.4.1', // SpringBoot版本号
        junit                              :'5.7.1', // 配置JUnit测试工具的版本编号
        junitPlatformLauncher              :'1.7.1',  // JUnit测试工具运行平台版本编号
        lombok                             :'1.18.18' // Lombok插件对应的版本号
]
ext.libraries = [   // 定义所有的依赖库
        // 以下的配置为SpringBoot项目所需要的核心依赖
        'spring-boot-gradle-plugin': "org.springframework.boot:spring-boot-gradle-plugin:${versions.springboot}",
        // 以下的配置为与项目用例测试有关的依赖
        'junit-jupiter-api': "org.junit.jupiter:junit-jupiter-api:${versions.junit}",
        'junit-vintage-engine': "org.junit.vintage:junit-vintage-engine:${versions.junit}",
        'junit-jupiter-engine': "org.junit.jupiter:junit-jupiter-engine:${versions.junit}",
        'junit-platform-launcher': "org.junit.platform:junit-platform-launcher:${versions.junitPlatformLauncher}",
        'junit-bom': "org.junit:junit-bom:${versions.junit}",
        // 以下的配置为Lombok组件有关的依赖
        'lombok': "org.projectlombok:lombok:${versions.lombok}"
]
3.
dependencies {                    // 公共依赖库管理
        // 以下为Lombok插件的相关依赖配置
        implementation(libraries.'lombok') // 编译时生效
        annotationProcessor(libraries.'lombok') // 注解时生效
        testCompileOnly(libraries.'lombok') // 注解时生效
        testAnnotationProcessor(libraries.'lombok') // 注解时生效
}

生成类操作结构

1、
package com.yootk.vo;

import lombok.Data;

import java.util.Date;
@Data // 这就是Lombok注解,这个注解使用的是最频繁的
public class Message {
    private String title;
    private Date pubdate;
    private String content;
}

2、http://java-decompiler.github.io/

3、
package com.yootk.test;

import com.yootk.vo.Message;

public class TestMessage {
    public static void main(String[] args) {
        Message message = new Message(); // 调用无参构造进行对象实例化
        message.setTitle("沐言科技"); // 自动生成setter方法
        message.setContent("www.yootk.com"); // 自动生成setter方法
        System.out.println(message); // 调用toString()输出
    }
}


4、
package com.yootk.vo;

import lombok.Data;
import lombok.NonNull;

@Data // 本身不会生成构造(默认的无参构造)
public class Dept {
    @NonNull // 该属性不允许为空
    private Long deptno;
    @NonNull // 该属性不允许为空
    private String dname;
    private String loc; // loc属性没有是否强制为空的限制
}

5、
package com.yootk.vo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;

@Data // 会与@NonNull注解相集合生成有参构造
@NoArgsConstructor // 要求当前的类自动的生成无参构造方法
@AllArgsConstructor // 生成的是一个全参构造
public class Emp {
    @NonNull // 一旦要生成无参构造,这个注解就有冲突了,该注解失效
    private Long empno;
    @NonNull // 一旦要生成无参构造,这个注解就有冲突了,该注解失效
    private String ename;
    private Double salary;
}

6、
package com.yootk.vo;

import lombok.*;

@Data // 会与@NonNull注解相集合生成有参构造
@NoArgsConstructor // 要求当前的类自动的生成无参构造方法
@AllArgsConstructor // 生成的是一个全参构造
@RequiredArgsConstructor(staticName="empno,ename")
public class Emp {
    @NonNull // 一旦要生成无参构造,这个注解就有冲突了,该注解失效
    private Long empno;
    @NonNull // 一旦要生成无参构造,这个注解就有冲突了,该注解失效
    private String ename;
    private Double salary;
}

Accessor

Accessor

  • Accessor 是在 Java 编程中提供的一种属性访问器,可以基于代码链的形式实现对象中所有属性的设置操作,在 Lombok 中提供了“@Accessors”注解可以直接生成相应代码,而在生成时提供有三种模式:fluent、chain、prefix,下面通过具体的定义以及生成的代码结果来对这三种模式进行说明。

fluent 模式

  • 将属性操作的 setter/getter 方法的名称全部更换为属性名称,这样在进行属性设置以及属性获取时直接采用“属性名称()”的形式调用即可。

chain 模式

  • 类中正常生成传统的“setter/getter”方法,但是在生成的 setter 方法时不再使用 void 作为返回值类型,而是直接返回当前对象实例,就可以采用代码链的方式实现对象属性设置。

prefix 模式

  • 在根据属性生成 setter/getter 方法时可以排除特定的名称前缀后生成
1、
package com.yootk.vo;

import lombok.Data;
import lombok.experimental.Accessors;

import java.util.Date;
@Data
@Accessors(fluent=true)
public class Message {
    private String title;
    private Date pubdate;
    private String content;
}


2、
package com.yootk.test;

import com.yootk.vo.Message;

public class TestMessage {
    public static void main(String[] args) {
        Message message = new Message(); // 调用无参构造进行对象实例化
        message.title("沐言科技").content("www.yootk.com"); // 代码链形式访问
        System.out.println(message); // 调用toString()输出
    }
}

3
、
package com.yootk.vo;

import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;

import java.util.Date;
@Data
@Accessors(fluent=true)
@Setter // 生成setter方法
@Getter // 生成getter方法
public class Message {
    private String title;
    private Date pubdate;
    private String content;
}

4、
package com.yootk.vo;

import lombok.Data;
import lombok.experimental.Accessors;

@Data // 本身不会生成构造(默认的无参构造)
@Accessors(chain = true)
public class Dept {
    private Long deptno;
    private String dname;
    private String loc;
}

5、
package com.yootk.test;

import com.yootk.vo.Dept;

public class TestDept {
    public static void main(String[] args) {
        Dept dept = new Dept();
        dept.setDname("沐言科技教学部").setLoc("北京").setDeptno(10L);
        System.out.println(dept);
    }
}


6、
package com.yootk.vo;

import lombok.Data;
import lombok.experimental.Accessors;

@Data // 会与@NonNull注解相集合生成有参构造
@Accessors(prefix = "yootk") // 配置前缀
public class Emp {
    private Long yootkEmpno; // 要在属性上增加前缀
    private String yootkEname; // 要在属性上增加前缀
    private Double yootkSalary; // 要在属性上增加前缀
}

建造者模式

1、
package com.yootk.vo;

import lombok.Builder;
import lombok.Data;

import java.util.Date;
@Data
@Builder // 构建者模式
public class Message {
    private String title;
    private Date pubdate;
    private String content;
}

2、
package com.yootk.test;

import com.yootk.vo.Message;

public class TestMessage {
    public static void main(String[] args) {
        // 此时将基于Lombok生成的构建者模式来进行Message对象的生成以及属性配置
        Message message = Message.builder().title("沐言科技").content("www.yootk.com").build();
        System.out.println(message);
    }
}

异常处理

1、

package com.yootk.lombok;

public class MessageHandle { // 在此时进行异常的控制
    public static void print(String message) {  // 信息输出
        if (message == null) {  // 内容为空
            try {
                throw new Exception("传递的message参数内容为空,你疯了吗?");
            } catch (Exception e) {}
        }
        System.out.println(message.toUpperCase()); // 打印信息
    }
}

2、
package com.yootk.lombok;

import lombok.SneakyThrows;

public class MessageHandle { // 在此时进行异常的控制
    @SneakyThrows // 会自动的生成try...catch
    public static void print(String message) {  // 信息输出
        if (message == null) {  // 内容为空
            throw new Exception("传递的message参数内容为空,你疯了吗?");
        }
        System.out.println(message.toUpperCase()); // 打印信息
    }
}

IO 流自动关闭

package com.yootk.lombok;

import lombok.Cleanup;
import lombok.Data;
import lombok.NonNull;
import lombok.SneakyThrows;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;

@Data // 此时的程序会自动生成一个双参构造
public class MessageRead { // 在此时进行异常的控制
    @NonNull
    private String filePath; // 文件路径
    @NonNull
    private String fileName; // 文件名称
    @SneakyThrows // 帮助用户手工处理异常
    public String load() {  // 数据读取
        @Cleanup InputStream input = new FileInputStream(new File(this.filePath, this.fileName));
        byte data [] = new byte[1024];
        int len = input.read(data); // 数据读取
        return new String(data, 0, len);
    }
}

同步方法

1、
package com.yootk.lombok;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.SneakyThrows;
import lombok.Synchronized;

import java.util.concurrent.TimeUnit;

@Data
@AllArgsConstructor // 生成一个全参构造
public class SaleTicket {
    private int ticket; // 设置票数

    @SneakyThrows // 处理中断异常
    @Synchronized // 同步处理
    public void sale() {    // 售票操作
        while (this.ticket > 0) {   // 此时有票
            if (this.ticket > 0) {  // 准备售票
                TimeUnit.SECONDS.sleep(1); // 模拟异常
                System.err.println("【" + Thread.currentThread().getName() + "】售票,ticket = " + this.ticket--);
            }
        }
    }
}


2、

package com.yootk.test;

import com.yootk.lombok.SaleTicket;

public class TestSaleTicket {
    public static void main(String[] args) {
        SaleTicket saleTicket = new SaleTicket(10); // 一共10张票
        for (int x = 0; x < 10; x++) {
            new Thread(()->{
                saleTicket.sale(); // 售票操作
            }, "票贩子 - " + x).start();
        }
    }
}

demo


上次编辑于: