[JAVA] Zusammenfassung dessen, was ich in Spring Batch gelernt habe

Ich habe zusammengefasst, was ich in Spring Batch gelernt habe, also werde ich einen Artikel schreiben. In Bezug auf die Umgebungskonstruktion von Spring Batch habe ich sie basierend auf dem folgenden Artikel erstellt.

Ich werde wütend, wenn ich keinen Tisch für Spring Batch habe

Als ich versuchte, es in der Umgebung auszuführen, die ich beim Erstellen der Umgebung mit Bezug auf verschiedene Sites erstellt hatte, war ich wütend, dass es keine Tabelle wie "BATCH_JOB_EXECUTION" gab. Es scheint notwendig zu sein, eine dedizierte Tabelle vorzubereiten, um Spring Batch auszuführen. Unten finden Sie die erforderlichen Tabellen.

Es scheint jedoch schwierig zu sein, diese selbst einzufügen. Daher bereitet der Frühling SQL für verschiedene Plattformen vor. Wenn Sie nach "spring batch schema-〇〇 (Plattformname) .sql" suchen, werden Sie einen Treffer finden. Ich habe postgresql verwendet, also habe ich "shema-postgresql.sql" verwendet. Ich bezog mich auf Folgendes.

・ [Schema-postgresql.sql](https://github.com/spring-projects/spring-batch/blob/master/spring-batch-core/src/main/resources/org/springframework/batch/core/schema -postgresql.sql)

Initialisieren Sie die Tabelle, wenn die Anwendung ausgeführt wird

Ich denke, dass Sie die App viele Male starten müssen, um den Betrieb der App zu überprüfen, aber ich denke, es ist schwierig, jedes Mal Daten zu erstellen. Daher werden wir jedes Mal die Tabelle initialisieren. Spring Boot bietet einen Mechanismus zum Initialisieren der Tabelle, wenn die Anwendung ausgeführt wird. Ich habe auf die folgende Seite verwiesen.

Es scheint, dass es automatisch gestartet wird, wenn Sie "schema-〇〇.sql" unter "src / main / resources" platzieren, das beim Erstellen des Spring Boot-Projekts erstellt wurde. Ich habe postgresql verwendet, also habe ich Folgendes getan:

Beschreiben Sie Folgendes in application.properties

application.properties


spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost:5432/testdb
#spring.datasource.username=postgres
#spring.datasource.password=postgres
spring.datasource.initialization-mode=always

Es scheint, dass SpringBoot automatisch Beans für DataSource definiert und Ingenieure nur die DB-Einstellungen in application.properties beschreiben müssen.

Bereiten Sie SQL vor

Zusätzlich zu dem, was ich in "[Ich werde wütend, wenn es keine Tabelle für Spring Batch gibt](https://qiita.com/kyabetsuda/items/f011533621cff7f53c63# Ich werde wütend, wenn es keine Tabelle für Spring Batch gibt)" bestätigt habe, ist es wie folgt. SQL ist vorbereitet.

schema-all.sql


DROP TABLE IF EXISTS people;

CREATE TABLE people  (
    person_id SERIAL NOT NULL PRIMARY KEY,
    first_name VARCHAR(20),
    last_name VARCHAR(20)
);

-- Autogenerated: do not edit this file
DROP TABLE  IF EXISTS BATCH_STEP_EXECUTION_CONTEXT;
DROP TABLE  IF EXISTS BATCH_JOB_EXECUTION_CONTEXT;
DROP TABLE  IF EXISTS BATCH_STEP_EXECUTION;
DROP TABLE  IF EXISTS BATCH_JOB_EXECUTION_PARAMS;
DROP TABLE  IF EXISTS BATCH_JOB_EXECUTION;
DROP TABLE  IF EXISTS BATCH_JOB_INSTANCE;

DROP SEQUENCE  IF EXISTS BATCH_STEP_EXECUTION_SEQ ;
DROP SEQUENCE  IF EXISTS BATCH_JOB_EXECUTION_SEQ ;
DROP SEQUENCE  IF EXISTS BATCH_JOB_SEQ ;

CREATE TABLE BATCH_JOB_INSTANCE  (
	JOB_INSTANCE_ID BIGINT  NOT NULL PRIMARY KEY ,
	VERSION BIGINT ,
	JOB_NAME VARCHAR(100) NOT NULL,
	JOB_KEY VARCHAR(32) NOT NULL,
	constraint JOB_INST_UN unique (JOB_NAME, JOB_KEY)
) ;

CREATE TABLE BATCH_JOB_EXECUTION  (
	JOB_EXECUTION_ID BIGINT  NOT NULL PRIMARY KEY ,
	VERSION BIGINT  ,
	JOB_INSTANCE_ID BIGINT NOT NULL,
	CREATE_TIME TIMESTAMP NOT NULL,
	START_TIME TIMESTAMP DEFAULT NULL ,
	END_TIME TIMESTAMP DEFAULT NULL ,
	STATUS VARCHAR(10) ,
	EXIT_CODE VARCHAR(2500) ,
	EXIT_MESSAGE VARCHAR(2500) ,
	LAST_UPDATED TIMESTAMP,
	JOB_CONFIGURATION_LOCATION VARCHAR(2500) NULL,
	constraint JOB_INST_EXEC_FK foreign key (JOB_INSTANCE_ID)
	references BATCH_JOB_INSTANCE(JOB_INSTANCE_ID)
) ;

CREATE TABLE BATCH_JOB_EXECUTION_PARAMS  (
	JOB_EXECUTION_ID BIGINT NOT NULL ,
	TYPE_CD VARCHAR(6) NOT NULL ,
	KEY_NAME VARCHAR(100) NOT NULL ,
	STRING_VAL VARCHAR(250) ,
	DATE_VAL TIMESTAMP DEFAULT NULL ,
	LONG_VAL BIGINT ,
	DOUBLE_VAL DOUBLE PRECISION ,
	IDENTIFYING CHAR(1) NOT NULL ,
	constraint JOB_EXEC_PARAMS_FK foreign key (JOB_EXECUTION_ID)
	references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID)
) ;

CREATE TABLE BATCH_STEP_EXECUTION  (
	STEP_EXECUTION_ID BIGINT  NOT NULL PRIMARY KEY ,
	VERSION BIGINT NOT NULL,
	STEP_NAME VARCHAR(100) NOT NULL,
	JOB_EXECUTION_ID BIGINT NOT NULL,
	START_TIME TIMESTAMP NOT NULL ,
	END_TIME TIMESTAMP DEFAULT NULL ,
	STATUS VARCHAR(10) ,
	COMMIT_COUNT BIGINT ,
	READ_COUNT BIGINT ,
	FILTER_COUNT BIGINT ,
	WRITE_COUNT BIGINT ,
	READ_SKIP_COUNT BIGINT ,
	WRITE_SKIP_COUNT BIGINT ,
	PROCESS_SKIP_COUNT BIGINT ,
	ROLLBACK_COUNT BIGINT ,
	EXIT_CODE VARCHAR(2500) ,
	EXIT_MESSAGE VARCHAR(2500) ,
	LAST_UPDATED TIMESTAMP,
	constraint JOB_EXEC_STEP_FK foreign key (JOB_EXECUTION_ID)
	references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID)
) ;

CREATE TABLE BATCH_STEP_EXECUTION_CONTEXT  (
	STEP_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY,
	SHORT_CONTEXT VARCHAR(2500) NOT NULL,
	SERIALIZED_CONTEXT TEXT ,
	constraint STEP_EXEC_CTX_FK foreign key (STEP_EXECUTION_ID)
	references BATCH_STEP_EXECUTION(STEP_EXECUTION_ID)
) ;

CREATE TABLE BATCH_JOB_EXECUTION_CONTEXT  (
	JOB_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY,
	SHORT_CONTEXT VARCHAR(2500) NOT NULL,
	SERIALIZED_CONTEXT TEXT ,
	constraint JOB_EXEC_CTX_FK foreign key (JOB_EXECUTION_ID)
	references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID)
) ;

CREATE SEQUENCE BATCH_STEP_EXECUTION_SEQ MAXVALUE 9223372036854775807 NO CYCLE;
CREATE SEQUENCE BATCH_JOB_EXECUTION_SEQ MAXVALUE 9223372036854775807 NO CYCLE;
CREATE SEQUENCE BATCH_JOB_SEQ MAXVALUE 9223372036854775807 NO CYCLE;

Jetzt werden die für die Ausführung erforderlichen Tabellen nach jeder Ausführung initialisiert.

Jobschleifen auf unbestimmte Zeit

Spring Batch verwendet grundsätzlich die Klassen Reader, Processor und Writer für die Verarbeitung, aber als ich diese selbst definierte, trat eine Endlosschleife auf. Ich hatte viele Probleme, aber die folgende Seite war hilfreich

Spring Batch scheint sich zu wiederholen, bis ItemReader null zurückgibt. Daher muss ItemReader so konzipiert und implementiert werden, dass nach Abschluss der Verarbeitung null zurückgegeben wird. Es wurde auf diese Weise auf den folgenden Websites implementiert.

Das Folgende wird unter Bezugnahme auf die obige Site implementiert.

PersonItemReader.java


import java.util.List;

import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.NonTransientResourceException;
import org.springframework.batch.item.ParseException;
import org.springframework.batch.item.UnexpectedInputException;
import org.springframework.beans.factory.annotation.Autowired;

public class PersonItemReader implements ItemReader<Person>{

	private List<Person> people = null;
	private int nextIndex;
	private final PersonService service;

	public PersonItemReader(PersonService service) {
		this.service = service;
	}

	@Override
	public Person read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {
		if (people == null) {
			people = service.selectAll();
			nextIndex = 0;
		}
		Person person = null;
		if (nextIndex < people.size()) {
            person = people.get(nextIndex);
            nextIndex++;
        }
        return person;
	}

}

Der definierte ItemReader ist eine Bean-Definition.

BatchConfiguration.java


@Configuration
@EnableBatchProcessing
public class BatchConfiguration {

...(Kürzung)...

    @Autowired
    PersonService personService;

    @Bean
    public PersonItemReader reader() {
    	return new PersonItemReader(personService);
    }

...(Kürzung)...

}

Allgemeine Implementierungsmethode von Reader / Processor / Writer

In Spring Batch werden häufig Reader, Prozessor und Writer verwendet, es gibt jedoch für jede Methode allgemeine Implementierungsmethoden. Ich denke, es ist wie ein Designmuster. Unten finden Sie eine Beschreibung der Implementierungsmethode, die ich durchgeführt habe. Erstens ist die Reader-Klasse.

PersonItemReader.java


import java.util.ArrayList;
import java.util.List;

import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.NonTransientResourceException;
import org.springframework.batch.item.ParseException;
import org.springframework.batch.item.UnexpectedInputException;

public class PersonItemReader implements ItemReader<List<Person>>{

	private final PersonService service;
	private final PersonCheckService checkService;

	public PersonItemReaderForTest(PersonService service, PersonCheckService checkService) {
		this.service = service;
		this.checkService = checkService;
	}

	@Override
	public List<Person> read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {
		List<Person> people = service.selectAll();
		List<Person> ret = null;
		for(Person person : people) {
			if(checkService.check(person)) {
				if(ret == null)
					ret = new ArrayList<Person>();
				ret.add(person);
			}
		}
		return ret;
	}

}

Die von der DB erhaltene wird in Form einer Liste an den Prozessor übergeben. Als nächstes kommt die Prozessorklasse.

PersonItemProcessor.java


import java.util.ArrayList;
import java.util.List;

import org.springframework.batch.item.ItemProcessor;

public class PersonItemProcessor implements ItemProcessor<List<Person>, List<Person>> {

	@Override
    public List<Person> process(final List<Person> people) throws Exception {
    	List<Person> transformedPeople = new ArrayList<Person>();
    	for(Person person : people) {
          final String firstName = person.getFirstName().toUpperCase();
          final String lastName = person.getLastName().toUpperCase();
          final Person transformedPerson = new Person(firstName, lastName);
          transformedPeople.add(transformedPerson);
    	}
    	return transformedPeople;
    }

}

Die vom Reader übergebene Liste wird verarbeitet und eine neue Liste zurückgegeben. Als nächstes kommt die Writer-Klasse.

PersonItemWriter.java


import java.util.List;

import org.springframework.batch.item.ItemWriter;

public class PersonItemWriterForTest implements ItemWriter<Object>{

	PersonService service;

	public PersonItemWriterForTest(PersonService service) {
		this.service = service;
	}

	@Override
	public void write(List<? extends Object> items) throws Exception {
		List<Person> people = (List<Person>) items.get(0);
		for(Person person : people) {
			service.updatePerson(person);
		}

	}

}

In der Writer-Klasse wird die vom Prozessor übergebene Liste in der Datenbank registriert. Bemerkenswert ist jedoch der folgende Code in der Writer-Klasse

List<Person> people = (List<Person>) items.get(0);

Um List abzurufen, rufen Sie (0) aus dem Parameter List ab. Mit anderen Worten, List \ <List \ <Person > > wird als Parameter übergeben. Ich fühlte mich ein wenig unwohl damit. Zuerst dachte ich, dass List \ <Person > als Parameter kommen würde, und als ich es implementierte, bemerkte ich, dass das Verhalten seltsam wurde. Ich fragte mich warum und als ich danach suchte, gab es eine Person, die die gleiche Frage hatte.

Das Folgende ist auf der obigen Seite geschrieben.

Typically, the design pattern is:

Reader -> reads something, returns ReadItem Processor -> ingests ReadItem, returns ProcessedItem Writer -> ingests List<ProcessedItem>

If your processor is returning List<Object>, then you need your Writer to expect List<List<Object>>.

In der Regel lautet das Entwurfsmuster Reader, Processor gibt ein einzelnes Element zurück und Writer verarbeitet eine Liste von Elementen. Da die Stapelverarbeitung durchgeführt wird, dachte ich, dass es normal wäre, mehrere von der Datenbank erfasste Daten in Form einer Liste an den Prozessor zu übergeben. In Writer scheint es jedoch so zu sein, dass der Prozessor das zurückgegebene Objekt empfangen kann, wenn es in der Liste gespeichert ist. Wenn Sie ein einzelnes Objekt mit Processor zurückgeben, ist es daher nicht erforderlich, die obige Verarbeitung von items.get (0) durchzuführen. Der Reader verfügt auch über eine Implementierungsmethode, die ein einzelnes Objekt zurückgibt, wie in "[Job-Schleifen unendlich](https://qiita.com/kyabetsuda/items/f011533621cff7f53c63#Job-Schleifen unendlich)" eingeführt. Klingt üblich.

Testen Sie Jobs und Schritte

Spring Batch bietet einen Mechanismus zum Testen von Jobs und Schritten. Verwenden Sie JobLauncherTestUtils zum Testen. Ich habe auf die folgende Seite verwiesen.

Unit Testing

Definieren Sie zunächst eine Bean für die Verwendung von JobLauncherTestUtils.

BatchConfigurationForTest.java


import javax.sql.DataSource;

import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.item.database.BeanPropertyItemSqlParameterSourceProvider;
import org.springframework.batch.item.database.JdbcBatchItemWriter;
import org.springframework.batch.item.database.builder.JdbcBatchItemWriterBuilder;
import org.springframework.batch.test.JobLauncherTestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DriverManagerDataSource;

@Configuration
@EnableBatchProcessing
public class BatchConfigurationForTest {

    @Autowired
    public JobBuilderFactory jobBuilderFactory;

    @Autowired
    public StepBuilderFactory stepBuilderFactory;

    @Autowired
    JobLauncher jobLauncher;

    @Autowired
    JobRepository jobRepository;

    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("org.postgresql.Driver");
        dataSource.setUrl("jdbc:postgresql://localhost:5432/ec");
//        dataSource.setUsername(username);
//        dataSource.setPassword(password);
        return dataSource;
    }

    @Bean
    PersonService personService() {
    	return new PersonService();
    };

    @Bean
    public PersonItemReader reader() {
    	return new PersonItemReader(personService());
    }

    @Bean
    public PersonItemProcessor processor() {
        return new PersonItemProcessor();
    }

    @Bean
    public JdbcBatchItemWriter<Person> writer(DataSource dataSource) {
        return new JdbcBatchItemWriterBuilder<Person>()
            .itemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<>())
            .sql("INSERT INTO people (first_name, last_name) VALUES (:firstName, :lastName)")
            .dataSource(dataSource)
            .build();
    }

    @Bean
    public NoWorkFoundStepExecutionListener noWorkFoundStepExecutionListener() {
    	return new NoWorkFoundStepExecutionListener();
    }

    @Bean
    public Job importUserJob(Step step1) {
        return jobBuilderFactory.get("importUserJob")
            .incrementer(new RunIdIncrementer())
            .flow(step1)
            .end()
            .build();
    }

    @Bean
    public Step step1(NoWorkFoundStepExecutionListener listener, JdbcBatchItemWriter<Person> writer) {
        return stepBuilderFactory.get("step1")
            .<Person, Person> chunk(1)
            .reader(reader())
            .processor(processor())
            .writer(writer)
            .listener(listener)
            .build();
    }

    @Bean
    public JobLauncherTestUtils jobLauncherTestUtils() {
    	JobLauncherTestUtils utils = new JobLauncherTestUtils();
    	utils.setJob(importUserJob(step1(noWorkFoundStepExecutionListener(), writer(dataSource()))));
    	utils.setJobLauncher(jobLauncher);
    	utils.setJobRepository(jobRepository);
    	return utils;
    }
}

JobLauncherTestUtils wird unten als Bean definiert. Das Obige ist eine neue Definition der Konfigurationsklasse zum Testen. Der Inhalt selbst ändert sich nicht wesentlich von der Konfigurationsklasse. In SpringBatch können Sie nach dem Schritt einen "Listener" festlegen und etwas tun, aber Sie können den Listener auch testen, sodass wir gemeinsam eine Bean definieren (die Lister-Klasse wird auf der obigen Referenzseite beschrieben). Es ist gewesen). Als nächstes kommt die Testklasse. Erstens ist die Klasse, die den Job testet.

JobTest.java


import static org.hamcrest.CoreMatchers.*;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.test.JobLauncherTestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=BatchConfigurationForTest.class)
public class JobTest {

	@Autowired
    private JobLauncherTestUtils jobLauncherTestUtils;

	@Test
	public void testJob() throws Exception {
		JobExecution jobExecution = jobLauncherTestUtils.launchJob();
        Assert.assertThat("COMPLETED", is(jobExecution.getExitStatus().getExitCode()));
	}

}

In der Testklasse ist das Bean-definierte JobLauncherTestUtils Autowired. Der Job wird von launchJob ausgeführt. Welcher Job ausgeführt werden soll, wird bei der Definition der Bean angegeben.

Als nächstes folgt die Klasse, die die Schritte testet.

StepTest.java


import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.test.JobLauncherTestUtils;
import org.springframework.batch.test.MetaDataInstanceFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=BatchConfigurationForTest.class)
public class StepTest {

	@Autowired
    private JobLauncherTestUtils jobLauncherTestUtils;

	@Autowired
	NoWorkFoundStepExecutionListener tested;

	@Test
	public void testStep() {
		JobExecution jobExecution = jobLauncherTestUtils.launchStep("step1");
		Assert.assertThat("COMPLETED", is(jobExecution.getExitStatus().getExitCode()));
	}

	@Test
	public void testAfterStep() {
	    StepExecution stepExecution = MetaDataInstanceFactory.createStepExecution();

	    stepExecution.setExitStatus(ExitStatus.COMPLETED);
	    stepExecution.setReadCount(0);

	    ExitStatus exitStatus = tested.afterStep(stepExecution);
	    assertThat(ExitStatus.FAILED.getExitCode(), is(exitStatus.getExitCode()));
	}
}

Übergeben Sie beim Testen eines Schritts den Namen des auszuführenden Schritts im Argument von launchStep (). testAfterStep () testet den Bean-definierten Listener. setReadCount () gibt die Anzahl der von der Reader-Klasse gelesenen Elemente an. Der auf der Referenzsite beschriebene NoWorkFoundStepExecutionListener wird implementiert, um ExisStatus.FAILED zurückzugeben, wenn getReadCount () == 0.

Dies ist das Ende der Spring Batch-Zusammenfassung.

Recommended Posts

Zusammenfassung dessen, was ich in Spring Batch gelernt habe
Zusammenfassung dessen, was ich über Spring Boot gelernt habe
Was ich gelernt habe
Ich war süchtig nach Spring's @Transactional
Was ich gelernt habe ② ~ Mock ~
Ich habe Spring Batch ausprobiert
Was ich gelernt habe ~ ~ DJUnit ~
Was ich in Java gelernt habe (Teil 2) Was sind Variablen?
Schleifenschritt mit Spring Batch
Was ich über Kotlin gelernt habe
Was ich in Java gelernt habe (Teil 4) Bedingte Verzweigung und Wiederholung
Was ich aus dem Studium von Rails gelernt habe
Spring Framework 5.0 Zusammenfassung der wichtigsten Änderungen
Ich habe am JJUG CCC 2019 Spring teilgenommen
Was ist @Autowired im Spring Boot?
Was ich mit Java Gold gelernt habe
Was ich mit Java Silver gelernt habe
Zusammenfassung von "In Java gelernten Entwurfsmustern (Multithread Edition)" (Teil 7)
Zusammenfassung von "In Java gelernte Entwurfsmuster (Multithread Edition)" (Teil 3)
Zusammenfassung von "In Java gelernten Entwurfsmustern (Multithread Edition)" (Teil 9)
Was ich in Java gelernt habe (Teil 1) Java-Entwicklungsablauf und Überblick
Zusammenfassung von "In Java gelernte Entwurfsmuster (Multithread Edition)" (Teil 4)
Zusammenfassung von "In Java gelernten Entwurfsmustern (Multithread Edition)" (Teil 5)
Zusammenfassung der Probleme, bei denen ich mich nicht bei firebase anmelden konnte
[Anmerkung] Was ich in einem halben Jahr von unerfahrenen (Java) gelernt habe
[Anmerkung] Was ich in einem halben Jahr von unerfahrenen (Java) gelernt habe (1)
Zusammenfassung von "In Java gelernten Entwurfsmustern (Multithread Edition)" (Teil 2)
Zusammenfassung von "In Java-Sprache erlernte Entwurfsmuster (Multi-Thread-Edition)" (Teil 1)
Was ich bei der Migration von der Spring Boot 1.4-Serie zur 2.0-Serie getan habe
[Anmerkung] Was ich in einem halben Jahr von unerfahrenen (Java) gelernt habe (3)
Was ich bei der Migration von der Spring Boot 1.5-Serie zur 2.0-Serie getan habe
Zusammenfassung von "In Java gelernten Entwurfsmustern (Multithread Edition)" (Teil 11)
Zusammenfassung von "In Java gelernten Entwurfsmustern (Multithread Edition)" (Teil 12)
Zusammenfassung von "In Java gelernten Entwurfsmustern (Multithread Edition)" (Teil 8)
Was ich in der Wagby-Entwicklung untersucht habe Anmerkung 1
Zusammenfassung der Stammklassen in verschiedenen Sprachen
Zusammenfassung der Hashes und Symbole in Ruby
Zusammenfassung der Teilnahme am JJUG CCC 2019 Spring
Was ich aus der Java-Geldberechnung gelernt habe
[* Java *] Ich habe am JJUG CCC 2019 Spring teilgenommen
Zusammenfassung der Auswahl von Elementen in Selen
Zusammenfassung der neuen Funktionen, die in Deeplearning4J 1.0.0-beta4 hinzugefügt wurden
Ein kurzer Überblick über Java, das im Unterricht gelernt wurde
Ich benötige eine Validierung der Federdaten für Pageable ~
Ich habe es mit Spring versucht.
Erstes AWS Lambda (Ich habe versucht zu sehen, in welcher Umgebung es funktioniert)
Zusammenfassung der häufig verwendeten Befehle in Rails und Docker
Ein kurzer Überblick über Java, das in Klasse 4 gelernt wurde
[Für Anfänger] DI ~ Die Grundlagen von DI und DI im Frühjahr ~
05. Ich habe versucht, die Quelle von Spring Boot zu löschen
Ich habe versucht, die Kapazität von Spring Boot zu reduzieren
Ich werde sowieso schreiben, was ich über Docker gelernt habe (zweite)
Autoboxing, das ich als NullPointerException im Kurzvergleich gelernt habe
Ich habe im Frühjahr einen Restful-Server und -Client erstellt.
Persönliche Zusammenfassung der in JUnit 4 häufig verwendeten Typen