Commit 32995fd0 authored by Guillaume Cornut's avatar Guillaume Cornut
Browse files

init: Create spring boot backend with gradle build and initial configuration. GNP-5451.

parent c069a37b
......@@ -4,7 +4,10 @@
<exclude-output />
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.gradle" />
<excludeFolder url="file://$MODULE_DIR$/.idea" />
<excludeFolder url="file://$MODULE_DIR$/backend/build" />
<excludeFolder url="file://$MODULE_DIR$/build" />
<excludeFolder url="file://$MODULE_DIR$/frontend/.gradle" />
<excludeFolder url="file://$MODULE_DIR$/frontend/dist" />
<excludeFolder url="file://$MODULE_DIR$/frontend/tmp" />
</content>
......
......@@ -2,8 +2,11 @@
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/modules/frontend/frontend.iml" filepath="$PROJECT_DIR$/.idea/modules/frontend/frontend.iml" group="frontend" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/backend/backend.iml" filepath="$PROJECT_DIR$/.idea/modules/backend/backend.iml" group="backend" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/backend/backend_main.iml" filepath="$PROJECT_DIR$/.idea/modules/backend/backend_main.iml" group="backend" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/backend/backend_test.iml" filepath="$PROJECT_DIR$/.idea/modules/backend/backend_test.iml" group="backend" />
<module fileurl="file://$PROJECT_DIR$/.idea/gpds.iml" filepath="$PROJECT_DIR$/.idea/gpds.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/frontend/gpds-frontend.iml" filepath="$PROJECT_DIR$/.idea/modules/frontend/gpds-frontend.iml" group="frontend" />
</modules>
</component>
</project>
\ No newline at end of file
......@@ -32,10 +32,30 @@ cd frontend
npm install
```
### Install Java JDK8
See instructions for your operating system
## Run backend development server
If you just need access to API (to run the Angular serve on top) without the frontend interface, you can run:
```sh
./gradlew bootRun
```
Otherwise, for the complete server (backend API + frontend interface), you can run:
```sh
./gradlew assemble && java -jar backend/build/libs/gpds.jar
```
The server should then be accessible at http://localhost:8080/gnpis-core
## Run frontend development server
The frontend requests are redirected to the production server API of GnpIS core
(https://urgi.versailles.inra.fr/gnpis-core-srv/swagger-ui.html) via the
The frontend requests are redirected to the local backend API server (see instructions above to launch) via the
Angular proxy.
You can run the development server with the following command:
......
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
import org.springframework.boot.gradle.tasks.buildinfo.BuildInfo
import org.springframework.boot.gradle.tasks.bundling.BootJar
import org.springframework.boot.gradle.tasks.run.BootRun
buildscript {
repositories {
mavenLocal()
mavenCentral()
}
}
plugins {
java
jacoco
id("org.springframework.boot") version "2.1.1.RELEASE"
id("com.gorylenko.gradle-git-properties") version "1.5.2"
id("io.spring.dependency-management") version "1.0.6.RELEASE"
}
java {
sourceCompatibility = JavaVersion.VERSION_1_8
}
repositories {
mavenCentral()
}
val snippetsDir = file("build/generated-snippets")
tasks {
withType(JavaCompile::class.java) {
// make sur the parameter names are writtn in the byte code and available using reflection.
// this is useful for Jackson and Spring to automatically deduce propert names or path variable names
// based on the name of the parameter
options.compilerArgs.add("-parameters")
}
getByName<Copy>("processResources") {
inputs.property("app", "gnpis")
filesMatching("bootstrap.yml") {}
}
// this task is always out-of-date because it generates a properties file with the build time inside
// so the bootJar task is also always out of date, too, since it depends on it
// but it's better to do that than using the bootInfo() method of the springBoot closure, because that
// makes the test task out of date, which makes the build much longer.
// See https://github.com/spring-projects/spring-boot/issues/13152
val buildInfo by creating(BuildInfo::class) {
destinationDir = file("$buildDir/buildInfo")
}
val bootJar by getting(BootJar::class) {
archiveName = "${rootProject.name}.jar"
dependsOn(":frontend:assemble")
dependsOn(buildInfo)
into("BOOT-INF/classes/static") {
from("${project(":frontend").projectDir}/dist/frontend")
}
into("BOOT-INF/classes/META-INF") {
from(buildInfo.destinationDir)
}
launchScript()
}
val test by getting(Test::class) {
useJUnitPlatform()
testLogging {
exceptionFormat = TestExceptionFormat.FULL
}
outputs.dir(snippetsDir)
}
val jacocoTestReport by getting(JacocoReport::class) {
reports {
xml.setEnabled(true)
html.setEnabled(true)
}
}
}
dependencyManagement {
imports {
mavenBom("org.springframework.cloud:spring-cloud-dependencies:Finchley.SR1")
}
}
dependencies {
annotationProcessor("org.springframework.boot:spring-boot-configuration-processor")
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-actuator")
implementation("org.springframework.cloud:spring-cloud-starter-config")
implementation("io.swagger:swagger-annotations:1.5.21")
// Elasticsearch
implementation("org.elasticsearch:elasticsearch:6.5.1")
implementation("org.elasticsearch.client:transport:6.5.1")
testImplementation("org.springframework.boot:spring-boot-starter-test") {
exclude(module = "junit")
}
testImplementation("org.junit.jupiter:junit-jupiter-api")
testImplementation("org.junit.jupiter:junit-jupiter-params")
testImplementation("org.mockito:mockito-junit-jupiter:2.23.0")
testImplementation("org.junit-pioneer:junit-pioneer:0.3.0")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
}
package fr.inra.urgi.gpds;
import fr.inra.urgi.gpds.config.GPDSProperties;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.scheduling.annotation.EnableAsync;
/**
* The main gpds Application
* @author gcornut
*/
@SpringBootApplication
@EnableAsync
@EnableConfigurationProperties(GPDSProperties.class)
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
package fr.inra.urgi.gpds;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
/**
* Filter that forwards all GET requests to non-static and non-api resources to index.html. This filter is necessary
* to support deep-linking for URLs generated by the Angular router.
*
* @author JB Nizet
*/
@Component
@WebFilter("/*")
public class IndexFilter implements Filter {
@Override
public void doFilter(ServletRequest req,
ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
if (mustForward(request)) {
request.getRequestDispatcher("/index.html").forward(request, response);
return;
}
chain.doFilter(request, response);
}
private boolean mustForward(HttpServletRequest request) {
if (!request.getMethod().equals("GET")) {
return false;
}
String fullUri = request.getRequestURI();
String contextPath = request.getContextPath();
String uri = fullUri.substring(contextPath.length());
return !(isApi(uri) || isStaticResource(uri));
}
private boolean isApi(String uri) {
return uri.startsWith("/brapi") || uri.startsWith("/actuator") || uri.startsWith("/gnpis/v1");
}
private boolean isStaticResource(String uri) {
if (uri.startsWith("/index.html")) {
return true;
}
List<String> suffixes = Arrays.asList(
".js", ".css", ".ico", ".png", ".jpg", ".gif", ".eot", ".svg", ".woff2", ".ttf", ".woff"
);
for (String suffix : suffixes) {
if (uri.endsWith(suffix)) return true;
}
return false;
}
@Override
public void init(FilterConfig filterConfig) {
// nothing to do
}
@Override
public void destroy() {
// nothing to do
}
}
package fr.inra.urgi.gpds.api.brapi.v1;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
/**
* @author gcornut
*
* Copyright (c) 2019 INRA URGI
*/
@Api(tags = { "Breeding API" }, description = "BrAPI endpoints")
@RestController
@RequestMapping("/brapi/v1/calls")
public class CallsController {
/**
* @link https://github.com/plantbreeding/API/blob/master/Specification/Calls/Calls.md
*/
@ApiOperation("List implemented Breeding API calls")
@ResponseBody
@GetMapping
public String calls() {
return "ok";
}
}
package fr.inra.urgi.gpds.api.gnpis.v1;
import io.swagger.annotations.Api;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
/**
* @author gcornut
*
* Copyright (c) 2019 INRA URGI
*/
@Api(tags = { "GnpIS API", "Data discovery" }, description = "GnpIS API data discovery endpoint")
@RestController
@RequestMapping("/gnpis/v1/datadiscovery")
public class DataDiscoveryController {
@ResponseBody
@PostMapping("/suggest")
public String calls() {
return "ok";
}
}
package fr.inra.urgi.gpds.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* Properties class holding the properties of the application (typically stored in application.yml)
*
* @author gcornut
*/
@ConfigurationProperties(prefix = "gpds")
public class GPDSProperties {
}
data:
elasticsearch:
cluster:
name: es-gpds
host: 127.0.0.1
port: 9300
management:
endpoint:
health:
show-details: 'always'
endpoints:
web:
exposure:
include: '*'
server:
compression:
enabled: true
mime-types:
- application/json
- application/javascript
- text/html
- text/css
logging.level:
root: ERROR
org.springframework:
boot.web.embedded.tomcat.TomcatWebServer: INFO
web.client.RestTemplate: DEBUG
---
spring:
profiles: gnpis
cloud.config.name: gpds
server:
port: 8080
servlet:
context-path: /gnpis-core
spring:
application:
name: gpds
cloud:
config:
uri: ${SPRING_CONFIG_URI:http://localhost:8888}
profiles:
active: gnpis
......@@ -47,7 +47,6 @@ tasks {
// Build assemble
val assemble by getting {
dependsOn("npm_run_build")
dependsOn(lint)
}
}
......
......@@ -4,7 +4,7 @@ const PROXY_CONFIG = [
"/brapi",
"/gnpis",
],
target: "https://urgi.versailles.inra.fr/beta/gnpis-core-srv",
target: "http://localhost:8080/gnpis-core",
secure: false
}
];
......
......@@ -3,7 +3,7 @@
<head>
<meta charset="utf-8">
<title>GnpIS Plant Data Search</title>
<base href="/">
<base href="./">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
......
rootProject.name = "gpds"
include("frontend")
include("backend", "frontend")
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment