Exemple d'application utilisant MongoDB de Spring Boot

Ceci est une réimpression du README de ce référentiel.

Ceci est un exemple d'application métier qui utilise Spring Boot côté serveur et AngularJS côté client pour accéder au backend MongoDB.

La base de données contient une collection de marques, de modèles, de voitures et de performances de vente. Il a la capacité d'ajouter, de mettre à jour, de supprimer et de rechercher ces collections, ainsi que de représenter graphiquement les performances des ventes.

Ce document est une note sur les thèmes techniques clés nécessaires pour comprendre l'application. Pour accélérer votre compréhension, c'est une bonne idée de parcourir les didacticiels de la page de guide de Spring (https://spring.io/guides).

*Mise en garde Toutes les fonctionnalités ne fonctionnent pas correctement pour le moment car ce projet n'a pas fini de développer des fonctionnalités. *

Je vais le déplacer pour le moment

Installez MongoDB et démarrez mongod à l'avance. Laissez la fonction d'authentification mongodb non configurée. (Il est dans un état où il est installé et démarré sans rien paramétrer)

Git clone ce projet. Créez un répertoire approprié et exécutez la commande suivante dans ce répertoire.

$ git clone https://github.com/kazz12211/simple-mongo-crud-app.git

Exécutez la commande suivante dans le même répertoire pour démarrer l'application.

$ ./mvnw spring-boot:run

Accédez à l'URL suivante depuis votre navigateur.

http://localhost:8080

Environnement de développement

Relatif au printemps

Projet Maven

Cette application est un projet Spring Boot Maven. Voir pom.xml pour les bibliothèques dépendantes.

RestController

Générez RestController avec l'annotation @RestController. Dans les applications CRUD, il semble courant de mapper respectivement les insertions, les mises à jour, les suppressions et les recherches de données sur POST, PUT, DELETE et GET des requêtes HTTP.

	package jp.tsubakicraft.mongocrud.controller;

	import java.util.List;
	
	import org.springframework.beans.factory.annotation.Autowired;
	import org.springframework.data.domain.Page;
	import org.springframework.data.domain.PageRequest;
	import org.springframework.data.domain.Pageable;
	import org.springframework.data.domain.Sort;
	import org.springframework.web.bind.annotation.RequestBody;
	import org.springframework.web.bind.annotation.RequestMapping;
	import org.springframework.web.bind.annotation.RequestMethod;
	import org.springframework.web.bind.annotation.RequestParam;
	import org.springframework.web.bind.annotation.RestController;
	
	import jp.tsubakicraft.mongocrud.model.Brand;
	import jp.tsubakicraft.mongocrud.service.BrandRepository;
	
	@RestController
	public class BrandController {
	
		@Autowired
		private BrandRepository repo;
	
		@RequestMapping(value = "/api/brands/listAll", method = RequestMethod.GET)
		public List<Brand> listAll() {
			Sort sort = new Sort(Sort.Direction.ASC, "name");
			return repo.findAll(sort);
		}
	
		@RequestMapping(value = "/api/brands", method = RequestMethod.GET)
		public Page<?> listBrands(@RequestParam(value = "page", required = true) int page,
				@RequestParam(value = "limit", required = true) int limit,
				@RequestParam(value = "sortColumn", required = true) String column,
				@RequestParam(value = "sortDir", required = true) String dir) {
			Sort sort = new Sort(
					new Sort.Order("asc".equalsIgnoreCase(dir) ? Sort.Direction.ASC : Sort.Direction.DESC, column));
			Pageable pageRequest = new PageRequest(page, limit, sort);
			Page<Brand> p = repo.findAll(pageRequest);
			return p;
		}
	
		@RequestMapping(value = "/api/brands", method = RequestMethod.PUT)
		public Brand updateBrand(@RequestBody Brand brand) {
			Brand b = repo.findOne(brand.id);
			if (b != null) {
				b.name = brand.name;
				repo.save(b);
			}
			return b;
		}
	
		@RequestMapping(value = "/api/brands", method = RequestMethod.DELETE)
		public Brand deleteBrand(@RequestBody Brand brand) {
			repo.delete(brand.id);
			return brand;
		}
	
		@RequestMapping(value = "/api/brands", method = RequestMethod.POST)
		public Brand createBrand(@RequestBody Brand brand) {
			Brand b = new Brand();
			b.name = brand.name;
			repo.save(b);
			return b;
		}
	}

Cette application implémente la fonction de nation de page en utilisant ui-bootstrap dans l'interface utilisateur, mais pour rechercher des objets page par page, utilisez PageRequest. Par exemple, pour rechercher les objets de 11e à 20e marque, appelez findAll () de PagingAndSortingRepository avec PageRequest comme argument comme suit.

	int page = 1;
	int size = 10;
	Pageable pageRequest = new PageRequest(page, size);
	Page<Brand> page = repo.findAll(pageRequest);

Traitement de l'erreur de page introuvable lors de l'utilisation d'itinéraires naturels

	package jp.tsubakicraft.mongocrud.controller;
	
	import org.springframework.stereotype.Controller;
	import org.springframework.web.bind.annotation.RequestMapping;
	
	@Controller
	public class ErrorHandler {
		@RequestMapping(value = "/{[path:[^\\.]*}")
		public String redirect() {
		  return "forward:/";
		}
	}

Lié à AngularJS

Partage du modèle HTML (à l'aide de $ routeProvider)

	in app.js
	
	var app = angular.module("app", ['ngRoute', 'ngDialog', 'ui.bootstrap', 'chart.js']);
	
	app.config(['$routeProvider', function($routeProvider) {
			
	    $routeProvider
		.when("/", {
			controller: 'home_controller',
			templateUrl: 'views/home.html'
		})
		.when("/brand/", {
			controller: 'brand_controller',
			templateUrl: 'views/brands.html'
		})
		.when("/newbrand/", {
			controller: 'brand_controller',
			templateUrl: 'views/newBrand.html'
		})
		.when("/model/", {
			controller: 'model_controller',
			templateUrl: 'views/models.html'
		})
		.when("/newmodel/", {
			controller: 'model_controller',
			templateUrl: 'views/newModel.html'
		})
		.when("/car/", {
			controller: 'car_controller',
			templateUrl: 'views/cars.html'
		})
		.when("/newcar/", {
			controller: 'car_controller',
			templateUrl: 'views/newCar.html'
		})
		.when("/sales/", {
			controller: 'sales_controller',
			templateUrl: 'views/sales.html'
		})
		.when("/newsales/", {
			controller: 'sales_controller',
			templateUrl: 'views/newSales.html'
		})
		.otherwise({
			redirectTo: "/"
		});
	}]);
	app.config(['$locationProvider', function($locationProvider) {
		$locationProvider.html5Mode(true);
	}]);

Appel d'API REST (en utilisant $ http)

Par exemple, pour faire une requête GET à la racine / api / Brands de BrandController (REST Controller), utilisez $ http.get (). (Voir brand_controller.js)

	app.controller("brand_controller", function($scope, $http, $location, $q, ngDialog) {
		$scope.brands = [];
	....
	....
		$scope.listBrands = function() {
			$http.get("/api/brands", {params: {page: $scope.page, limit: $scope.limit, sortColumn: $scope.sortColumn, sortDir: $scope.sortDir}}).then(function(response) {
				//J'ai pu recevoir les données normalement
				$scope.brands = response.data;
				....
				....
			}, function(error) {
				//La requête HTTP a échoué
				....
			});
		};
	....
	....
	
		$scope.listBrands();
	});

Vérification de la saisie du formulaire

La validation peut être effectuée dans le modèle HTML, mais dans cette application, elle est effectuée dans le contrôleur. (Voir brand_controller.js)

	....
	....
	$scope.createBrand = function() {
		if(!$scope.validateForm()) {
			$http.post("/api/brands", $scope.brand).then(function(response) {
		        $scope.show = true;
		        $scope.hide = true;
		        $scope.hideObj = false;
		        $scope.showObj = false;
		        $scope.brandId = "";
		    	$location.path("/brand");
			}, function(error) {
				$scope.error = error;
			});
		}
	};
	....
	....
	$scope.validateForm = function() {
		$scope.validationMessages = [];
		if($scope.brand.name == null || $scope.brand.name == null) {
			$scope.validationMessages.push("Name is required.");
		}
		$scope.hasErrors =  $scope.validationMessages.length > 0;
		return $scope.hasErrors;
	};

Du côté du modèle HTML, préparez un bloc à afficher en cas d'erreur (hasErrors of $ scope est true).

	<div class="panel panel-default">
		<div class="panel-heading">ADD A BRAND</div>
		<form name="brand-form">
			<div ng-show="hasErrors">
				<div class="alert alert-danger" role="alert">
					<div ng-repeat="message in validationMessages">
						<strong>{{message}}</strong></br/>
					</div>
				</div>
			</div>
			<div class="form-group">
				<label for="brand-name">Name</label> <input name="brand-name"
					type="text" class="form-control" ng-model="brand.name" required>
			</div>
			<button class="btn btn-primary" type="submit" ng-click="createBrand()">
				<span class="glyphicon glyphicon-ok" aria-hidden="true"></span>
				Save
			</button>
	
			<button class="btn btn-default" ng-click="linkTo('/brand/')">
				<span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
				Cancel
			</button>
		</form>
	</div>

Pagenation (en utilisant ui-bootstrap)

La page ui-bootstrap (https://angular-ui.github.io/bootstrap/) explique comment procéder.

Tri des colonnes du tableau

Code côté contrôleur. Spécifiez le nom de la colonne à trier et la méthode de tri. (Pour cette application, il existe deux méthodes de tri, ASC et DESC) La fonction sort () est appelée à partir du modèle HTML avec le nom de la colonne comme argument. Si la colonne passée en argument est la même que la colonne précédente, basculez entre l'ordre croissant et décroissant, et si la colonne est différente de la précédente, définissez-la dans l'ordre croissant et mettez à jour le nom de la colonne. Enfin, recherchez à nouveau la base de données. (Comme il s'agit d'une recherche paginée, le trafic vers la base de données généré par une recherche est faible, nous sommes donc en train de relancer la recherche, mais si le nombre de recherches est important, il peut être préférable de trier en mémoire)

	app.controller("model_controller", function($scope, $http, $location, $q, ngDialog) {
		....
		....
	
		$scope.sortColumn = "name";
		$scope.sortDir = "ASC";
		....
		....
		$scope.sort = function(column) {
			if($scope.sortColumn == column) {
				$scope.sortDir = $scope.sortDir == "ASC" ? "DESC" : "ASC";
			} else {
				$scope.sortDir = "ASC";
				$scope.sortColumn = column;
			}
			$scope.listModels();
		};
	
	});

Du côté du modèle HTML, spécifiez la fonction de contrôleur à exécuter lorsque le clic de souris est effectué sur l'en-tête de colonne.

	<th class="col-xs-3 col-ms-3 col-md-3 col-lg-4 sortableTableColumn" ng-click="sort('name')">Name</th>

Si vous utilisez une bibliothèque telle que DataTable.js, qui a des fonctions telles que la pagination et le tri des données affichées dans un tableau, cela peut être fait plus facilement, donc lors du développement d'une application. Veuillez considérer.

Concernant BootStrap

Remplacement CSS Bootstrap

Ce n'est pas limité au CSS Bootstrap, mais c'est un moyen de remplacer le CSS. Le code suivant remplace le style de la barre de navigation Bootstrap. Définissez la partie du fichier HTML qui charge le CSS à charger après le CSS Bootstrap.

	.navbar {
		margin-bottom: 1px;
	        border-radius: 0px;
	}
	
	.navbar-inverse {
		background-color: rgb(12, 140, 213);
		border-color: rgb(12,140,213);	
	}
	
	.navbar-inverse .navbar-brand {
		color: #fff;
	}
	
	.navbar-inverse .navbar-nav>li>a {
		color: #fff;
	}

Concernant le référentiel Mongo

MongoRepository est une sous-interface de PagingAndSortingRepository qui a des fonctions d'insertion, de mise à jour, de suppression, de recherche et de pagination de données.

Configuration MongoDB

Code qui définit la sélection de base de données MongoDB.

	package jp.tsubakicraft.mongocrud.config;
	
	import org.springframework.context.annotation.Configuration;
	import org.springframework.data.mongodb.config.AbstractMongoConfiguration;
	
	import com.mongodb.Mongo;
	import com.mongodb.MongoClient;
	
	@Configuration
	public class MongoConfiguration extends AbstractMongoConfiguration {
	
		@Override
		protected String getDatabaseName() {
			return "simplecrud";
		}
	
		@Override
		public Mongo mongo() throws Exception {
			return new MongoClient("127.0.0.1", 27017);
		}
	
	}

Entité MongoDB

Exemples d'entités de marque et de modèle. L'entité Model fait référence à l'entité Brand avec l'annotation @DBRef. Dans ce cas, la recherche de Modèle recherchera et combinera également les Marques référencées.

jp.tsubakicraft.mongocrud.model.Brand.java

	package jp.tsubakicraft.mongocrud.model;
	
	import org.springframework.data.annotation.Id;
	import org.springframework.data.mongodb.core.mapping.Document;
	
	
	@Document(collection="brand")
	public class Brand {
	
		@Id public String id;
		public String name;
		
		public Brand(String id) {
			this.id = id;
		}
		
		public Brand() {
		}
	}

jp.tsubakicraft.mongocrud.model.Model.java

	 package jp.tsubakicraft.mongocrud.model;
	
	
	import org.springframework.data.annotation.Id;
	import org.springframework.data.mongodb.core.mapping.DBRef;
	import org.springframework.data.mongodb.core.mapping.Document;
	
	
	@Document(collection="model")
	public class Model {
		
		@Id public String id;
		public String name;
		@DBRef public Brand brand;
		
		public Model() {
			
		}
		
		public Model(String id) {
			this.id = id;
		}
	}

Extension du référentiel Mongo

Comment spécifier les propriétés DBRef dans les critères de recherche.

	@Query(value="{brand.$id : ?0}")
	public List<Model> findByBrandId(ObjectId brandId);

Comment obtenir le nombre de collections. Définissez count = true comme paramètre de l'annotation @Query.

	@Query(value="{brand.$id : ?0}", count=true)
	public Long countBrandModel(ObjectId brandId);

Page Nation avec le référentiel Mongo

Appelez la méthode MongoRepository à l'aide de PageRequest.

	@Autowired
	private BrandRepository repo;
	...
	@RequestMapping(value="/api/brands", method=RequestMethod.GET)
	public Page<Brand> listBrands(@RequestParam(value="page", required=true) int page, @RequestParam(value="limit", required=true) int limit) {
		Pageable pageRequest = new PageRequest(page, limit);
		return repo.findAll(pageRequest);
	}

Recommended Posts

Exemple d'application utilisant MongoDB de Spring Boot
Python: Application de la reconnaissance d'image à l'aide de CNN
Ceci est un exemple d'application de fonction dans dataframe.
Application Web utilisant Bottle (1)
Exemple d'utilisation de lambda
Application de Python 3 vars