[JAVA] J'ai fait Mugenkura Sushi Gacha

La campagne GoToEat a débuté en octobre. L'utilisez-vous? Campagne GoToEat du Ministère de l'agriculture, des forêts et de la pêche

J'avais l'habitude de l'utiliser souvent, mais il semble que "Mugenkura Sushi" soit populaire dans les rues. Vous pouvez manger aux points que vous obtenez avec GoToEat, et vous pouvez à nouveau obtenir des points avec ce repas, de sorte que vous pouvez manger des sushis Kura plusieurs fois à un bon prix. (Mis à part l'histoire morale) Page officielle de la campagne GoToEat de Kurasushi

Afin de recevoir des points chez GoToEat, il faut manger au moins 500 yens TTC pour le déjeuner et 1000 yens TTC pour le dîner chez Kura Sushi. Par conséquent, j'ai fait "Mugen Kura Sushi Gacha" qui est affiché aléatoirement sur le menu de Kura Sushi quand il dépasse le prix correspondant.

Cliquez ici pour l'application web que j'ai créée ↓ ** Mugenkura Sushi Gacha **

Cette fois, j'ai utilisé le framework "Spring Boot". Le code complet est disponible sur github ↓ https://github.com/yutwoking/eternalKurazushi

Je laisserai cet article comme une étape dans la création de ces applications à l'avenir.

Prérequis tels que l'environnement de création d'application et le cadre d'utilisation

Écoulement brutal

  1. Mise en œuvre de la partie logique --La partie lecture du menu du site officiel de Kura Sushi --Partie stockée / extraite dans la base de données
  1. Partie du framework Spring Boot --build.gradle description --Création d'un lanceur --Création d'un contrôleur --html creation (création de vue)

  2. Publication d'applications Web (AWS)

1. Mise en œuvre de la partie logique

Menu de lecture du site officiel de Kura Sushi

Tout d'abord, chargez le menu depuis le site officiel. Il est nécessaire d'analyser le html du Site officiel du menu. Analysez à l'aide d'une bibliothèque appelée Jsoup.

Comment utiliser la référence Jsoup https://www.codeflow.site/ja/article/java-with-jsoup

La mise en œuvre de la partie analyse est la suivante

LoadMenu.java


private static List<MenuModel>  loadMenuFromSite(String url) throws IOException{
    	List<MenuModel> models = new LinkedList<>();

    	Document doc = Jsoup.connect(url).get();
    	Elements menusBySection = doc.select(".section-body");
    	for (Element section : menusBySection) {
    		String sectionName  = section.select(".menu-section-header h3").text();
    		if (!StringUtils.isEmpty(sectionName)) {
    			Elements menus  = section.select(".menu-list").get(0).select(".menu-item");
    			for (Element menu : menus) {
    				String name = menu.select(".menu-name").text();
    				Elements summary = menu.select(".menu-summary li");

    				if (summary.size() >2) {
    					int price  = stringToInt(summary.get(0).select("p").get(0).text());
    					int kcal  = stringToInt(summary.get(0).select("p").get(1).text());
    					String area = summary.get(1).select("p").get(1).text();
    					boolean takeout = toBoolean(summary.get(2).select("p").get(1).text());
    					models.add(new MenuModel(name, price, kcal, area, takeout, sectionName));
    				} else if (summary.size() == 2) {
    					int price  = stringToInt(summary.get(0).select("p").get(0).text());
    					int kcal  = stringToInt(summary.get(0).select("p").get(1).text());
    					String area = "";
    					boolean takeout = toBoolean(summary.get(1).select("p").get(1).text());
    					models.add(new MenuModel(name, price, kcal, area, takeout, sectionName));
    				}
    			}
    		}
    	}
    	return models;
    }

En tant qu'utilisation de base de JSoup,


Document doc = Jsoup.connect(url).get();

Lire l'url html avec

Elements elements = doc.select(".section-body");

Utilisez la méthode de sélection comme celle-ci pour extraire l'élément pertinent.

Je regrette que le code d'implémentation soit difficile à voir car les instructions if et for sont imbriquées. .. ..

Partie stockage / extraction dans la base de données

Vient ensuite l'implémentation autour de la base de données. J'utilise un framework d'accès java DB appelé Doma2. Cliquez ici pour le fonctionnaire Doma2

Doma présente les caractéristiques suivantes.

· Utiliser le traitement des annotations pour générer et valider le code au moment de la compilation · Peut mapper les valeurs de colonne de la base de données sur des objets Java comportementaux ・ Un modèle SQL appelé SQL bidirectionnel peut être utilisé. -Java 8 java.time.LocalDate, java.util.Optional et java.util.stream.Stream peuvent être utilisés. -Pas de dépendance vis-à-vis des bibliothèques autres que JRE

C'est un framework que j'utilise souvent car j'aime personnellement le fait qu'il puisse être géré avec des fichiers sql. L'usage est officiel et japonais, il est donc bon de s'y référer. Le code d'implémentation est omis ici. Le code complet est disponible sur github ↓ https://github.com/yutwoking/eternalKurazushi

Partie logique Gacha

Gacha.java



public static List<MenuModelForSearch> getResult(Areas area, boolean isLunch){
		List<MenuModelForSearch> result  = new ArrayList<>();
//Stockez 500 pour le déjeuner et 1000 pour le dîner dans le seuil
		int threshold = getThreshold(isLunch);
//Stocker tous les menus dans les candidats
		List<MenuModelForSearch> candidates = MenuCaches.getSingleton().getMenuList(area, isLunch);

//Vérifiez si la quantité totale du menu acquis dépasse le seuil et ajoutez des menus à partir des candidats au hasard jusqu'à ce qu'il dépasse le seuil.
		while (isOverThreshold(threshold, result) == false) {
			addElement(result, candidates);
		}
//Vérifiez enfin si le menu du déjeuner est inclus. Si le menu du déjeuner est inclus, le résultat sera le menu du déjeuner uniquement.
		checkIncludeLunchMenu(result);

		return result;
	}

Voir Code entier pour chaque méthode.

2. Partie du framework Spring Boot

En ce qui concerne SpringBoot, je me suis référé au site suivant. https://qiita.com/gosutesu/items/961b71a95daf3a2bce96 https://qiita.com/opengl-8080/items/eb3bf3b5301bae398cc2 https://note.com/ymzk_jp/n/n272dc9e5c5d3

Description de build.gradle

Ajoutez des plugins et des bibliothèques à build.gradle afin que gradle puisse utiliser le framework Spring Boot.

La partie où le build.gradle réel de cette époque est commenté en tant que // partie supplémentaire de spring-boot est ajoutée dans ↓.

build.gradle


plugins {
    // Apply the java plugin to add support for Java
    id 'java'

    // Apply the application plugin to add support for building a CLI application
    id 'application'
    id 'eclipse'
    id 'com.diffplug.eclipse.apt' version '3.25.0'

    id 'org.springframework.boot' version '2.3.5.RELEASE' //spring-partie post-scriptum de démarrage
    id 'io.spring.dependency-management' version '1.0.10.RELEASE'//spring-partie post-scriptum de démarrage
}

version = '2.26.0-SNAPSHOT'
ext.dependentVersion = '2.24.0'

task copyDomaResources(type: Sync)  {
    from sourceSets.main.resources.srcDirs
    into compileJava.destinationDir
    include 'doma.compile.config'
    include 'META-INF/**/*.sql'
    include 'META-INF/**/*.script'
}

compileJava {
    dependsOn copyDomaResources
    options.encoding = 'UTF-8'
}

compileTestJava {
    options.encoding = 'UTF-8'
    options.compilerArgs = ['-proc:none']
}

repositories {
    mavenCentral()
    mavenLocal()
    maven {url 'https://oss.sonatype.org/content/repositories/snapshots/'}
}

dependencies {
    // Use JUnit test framework
    testImplementation 'junit:junit:4.12'

    // https://mvnrepository.com/artifact/org.jsoup/jsoup
    compile group: 'org.jsoup', name: 'jsoup', version: '1.13.1'

    // https://mvnrepository.com/artifact/org.apache.commons/commons-lang3
    compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.11'

    annotationProcessor "org.seasar.doma:doma:${dependentVersion}"
    implementation "org.seasar.doma:doma:${dependentVersion}"
    runtimeOnly 'com.h2database:h2:1.3.175'
    // https://mvnrepository.com/artifact/org.postgresql/postgresql
    compile group: 'org.postgresql', name: 'postgresql', version: '42.2.8'

	// https://mvnrepository.com/artifact/com.zaxxer/HikariCP
    compile  group: 'com.zaxxer', name: 'HikariCP', version: '3.4.1'

	// https://mvnrepository.com/artifact/javax.inject/javax.inject
    compile group: 'javax.inject', name: 'javax.inject', version: '1'

    // https://mvnrepository.com/artifact/io.vavr/vavr
	compile group: 'io.vavr', name: 'vavr', version: '0.10.2'

	// https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-thymeleaf
	compile group: 'org.springframework.boot', name: 'spring-boot-starter-thymeleaf', version: '2.3.5.RELEASE'//spring-partie post-scriptum de démarrage

    // https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web
	compile group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '2.3.5.RELEASE'//spring-partie post-scriptum de démarrage

	// https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter
	compile group: 'org.springframework.boot', name: 'spring-boot-starter', version: '2.3.5.RELEASE'//spring-partie post-scriptum de démarrage

}


//spring-Ajout de la tâche bootJar pour transformer le projet de démarrage en service
bootJar { 
    launchScript()
}

application {
    // Define the main class for the application
    mainClassName = 'eternalKurazushi.ServerLuncher'
}

eclipse {
    classpath {
        file {
            whenMerged { classpath ->
                classpath.entries.removeAll { it.path == '.apt_generated' }
            }
            withXml { provider ->
                def node = provider.asNode()
                // specify output path for .apt_generated
                node.appendNode( 'classpathentry', [ kind: 'src', output: 'bin/main', path: '.apt_generated'])
            }
        }
    }
    jdt {
        javaRuntimeName = 'JavaSE-11'
    }
}

Créer un lanceur

ServerLuncher.java



@SpringBootApplication
public class ServerLuncher {

	public static void main(String[] args) throws Exception {
        SpringApplication.run(ServerLuncher.class, args);
        LoadMenu.init();
        MenuCaches.getSingleton().load();
    }

}

Tout ce que vous avez à faire est d'ajouter l'annotation @SpringBootApplication et d'implémenter SpringApplication.run.

LoadMenu.init();
MenuCaches.getSingleton().load();

Cette partie lit le menu au démarrage du serveur et le stocke dans la base de données, de sorte que le menu dispose également d'une mémoire. En fait, avec cette configuration, je n'ai peut-être pas besoin de DB, mais j'utilise également DB au cas où il serait étendu à l'avenir (probablement pas étendu).

Créer un contrôleur

FrontController.java



@Controller
public class FrontController {
	@RequestMapping("/")
	public String index() {
		return "index";
	}

	@RequestMapping(value = "/result", method = RequestMethod.POST)
	public String getResult(@RequestParam("radio_1") String eatTime, @RequestParam("radio_2") String areaString, Model model) {
		if (StringUtils.isEmpty(eatTime) || StringUtils.isEmpty(eatTime)) {
			return "error";
		}

		boolean isLunch = eatTime.equals("le déjeuner") ? true : false;
		Areas area = Areas.Japon oriental;
		if (areaString.equals("Japon occidental")) {
			area = Areas.Japon occidental;
		} else if (areaString.equals("Kyushu-Okinawa")) {
			area = Areas.Kyushu;
		}

		List<MenuModelForSearch> gachaResult = Gacha.getResult(area, isLunch);
		model.addAttribute("list", gachaResult);
		model.addAttribute("sum", getSumString(gachaResult));
		model.addAttribute("time", eatTime);
		model.addAttribute("area", areaString);
		return "result";
	}

Implémentez le contrôleur à l'aide de l'annotation @Controller. Spécifiez le chemin correspondant avec l'annotation @RequestMapping. Ceci est similaire à jax-rs. Recevez des valeurs de HTML à l'aide de l'annotation @RequestParam.

model.addAttribute("list", gachaResult);

Vous pouvez transmettre une valeur à html avec addAttribute. Dans cet exemple, la valeur de gachaResult est transmise à html avec la liste des noms de variable.

return "result";

Renvoie le modèle html de / resources / templates / [Valeur de retour du contrôleur] .html. Dans cet exemple, /resources/templates/result.html est lu et renvoyé.

création html (création de vue)

result.html


<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Mugenkura Sushi Gacha</title>
</head>
<body bgcolor=#99FFFF>
	<div style="text-align: center">
		<main>
			<h1>Mugenkura Sushi Gacha</h1>
			<p th:text="${time} + '  /  ' + ${area}" class="description"></p>
			<table border="1" align="center">
				<tr>
					<th>type</th>
					<th>Nom du produit</th>
					<th>Prix (hors taxes)</th>
					<th>calorie</th>
					<!--
					<th>Zone de service</th>
					<th>À emporter</th>
					-->
				</tr>
				<tr th:each="menu : ${list}">
					<td th:text="${menu.type}"></td>
					<td th:text="${menu.name}"></td>
					<td th:text="${menu.price} + 'Cercle'"></td>
					<td th:text="${menu.kcal} + 'kcal'"></td>
					<!--
					<td th:text="${menu.area}"></td>
					<td th:text="${menu.takeout} ? 'Oui' : '不Oui'"></td>
					-->
				</tr>
			</table>
			<h3>
				<p th:text="${sum}" class="sum"></p>
			</h3>
			<br>

			<form method="POST" action="/result">
				<input type="hidden" name="radio_1" th:value="${time}"> <input
					type="hidden" name="radio_2" th:value="${area}">
				<div style="margin: 2rem 0rem">
					<input type="submit" value="Retourner le gacha dans les mêmes conditions"
						style="width: 250px; height: 50px">
				</div>
			</form>
			<form method="GET" action="/">
				<div style="margin: 2rem 0rem">
					<input type="submit" value="Revenir">
				</div>
			</form>
		</main>
	</div>
</body>
</html>

th: value = "$ {nom de la variable}" Ensuite, la valeur reçue du contrôleur peut être utilisée. Vous pouvez transmettre une valeur au contrôleur en créant une entrée et en spécifiant un nom à l'aide de la balise form.

3. Publication d'applications Web (AWS)

Cette fois, j'ai utilisé AWS pour publier une application Web. C'est une application simple, donc je l'ai utilisée

c'est sombre. Recommandé pour les débutants car ce livre est très poli et peut être pratiqué. [Construction du réseau et du serveur à partir de l'édition révisée de base des services Web d'Amazon](https://www.amazon.co.jp/Amazon-Web-Services-%E5%9F%BA%E7%A4%8E%E3%81% 8B% E3% 82% 89% E3% 81% AE% E3% 83% 8D% E3% 83% 83% E3% 83% 88% E3% 83% AF% E3% 83% BC% E3% 82% AF- % E3% 82% B5% E3% 83% BC% E3% 83% 90% E3% 83% BC% E6% A7% 8B% E7% AF% 89 / dp / 4822237443)

finalement

Cela fait un moment que je n'ai pas créé quelque chose en dehors du travail. La programmation de travail est amusante, mais la programmation privée est aussi amusante (sélection d'un framework, création d'un environnement, etc.), j'aimerais donc régulièrement améliorer mes compétences.

Si j'ai le temps, j'aimerais travailler sur ce qui suit.

Recommended Posts

J'ai fait Mugenkura Sushi Gacha
J'ai créé StringUtils.isBlank
J'ai fait une roulette à Java.
J'ai créé une application de chat.