├── .gitattributes ├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── build.gradle ├── docker-compose.debug.yml ├── docker-compose.yml └── src └── main └── java └── myapp ├── Application.java └── controllers └── HomeController.java /.gitattributes: -------------------------------------------------------------------------------- 1 | * text eol=lf 2 | 3 | # Denote all files that are truly binary and should not be modified. 4 | *.png binary 5 | *.jpeg binary 6 | *.jpg binary 7 | *.ico binary 8 | *.gif binary 9 | *.eot binary 10 | *.otf binary 11 | *.ttf binary 12 | *.woff binary 13 | *.woff2 binary 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OS level ignores 2 | .DS_Store 3 | [Tt]humbs.db 4 | 5 | # Generic stuff to ignore from build tools 6 | node_modules/ 7 | *.log 8 | 9 | # Intellij project 10 | .idea/ 11 | *.iml 12 | 13 | # Gradle ignores 14 | .gradle/ 15 | gradle/ 16 | gradlew* 17 | build/ 18 | out/ 19 | bin/ 20 | 21 | # Custom project stuff 22 | secrets.env 23 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:13 AS build 2 | 3 | RUN mkdir -p /workspace 4 | WORKDIR /workspace 5 | COPY . . 6 | RUN yum install -y wget unzip 7 | RUN wget -O /tmp/gradle.zip https://services.gradle.org/distributions/gradle-6.1-bin.zip && \ 8 | unzip /tmp/gradle.zip -d /opt && \ 9 | mv /opt/gradle-6.1 /opt/gradle 10 | 11 | RUN /opt/gradle/bin/gradle build 12 | 13 | # -- 14 | 15 | FROM openjdk:13 AS deploy 16 | 17 | RUN mkdir -p /opt/app 18 | COPY --from=build /workspace/build/libs/myapp-FINAL.jar /opt/app/myapp.jar 19 | 20 | ENTRYPOINT ["java", "-jar", "/opt/app/myapp.jar"] 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Java REST starter app 2 | 3 | This project is designed to get you bootstrapped immediately by providing a minimum set of code you'll need to begin developing a modern Java REST app that is ready to run natively or in a container. 4 | 5 | ## Getting Started 6 | 7 | docker-compose up --build -d 8 | 9 | The app is now running at [http://localhost:8080/](http://localhost:8080/). 10 | 11 | ## Features 12 | 13 | * Java 13 14 | * Spring MVC 15 | * Spring Boot 16 | - Embedded Tomcat 9 web server 17 | * Gradle 6.1 18 | * Docker 19 | * Compose 20 | 21 | ## Requirements 22 | 23 | To run the code quickly you'll just need: 24 | 25 | * [Docker](https://www.docker.com) 26 | * [Compose](https://docs.docker.com/compose) 27 | 28 | If you plan on writing code: 29 | 30 | * [Java 13 JDK](https://www.oracle.com/technetwork/java/javase/downloads/jdk12-downloads-5295953.html) 31 | * [Tomcat 9](https://tomcat.apache.org/download-90.cgi) 32 | 33 | ## Development 34 | 35 | #### Debug app within Docker container 36 | 37 | ⁣1. Download & Install Tomcat 9 38 | 39 | The download link is provided above. Decompress the archive and place the Tomcat 9 directory somewhere easily accessible, like your user's home directory. 40 | 41 | ⁣2. Configure your IDE to listen to debugger 42 | 43 | In this example I will be using Intellij IDEA. You can add/edit configuration by clicking the run profile drop-down and click "Edit Configurations" at the top-right of the IDE. In this dropdown, select Tomcat Server > Remote. 44 | 45 | You will want to bind the app to the Tomcat 9 binary you downloaded above. You will also want the debug profile 46 | in start-up/connection section to be set to port 8000. 47 | 48 | ⁣3. Start the app in debug mode 49 | 50 | docker-compose -f docker-compose.yml -f docker-compose.debug.yml up --build 51 | 52 | ⁣4. Listen from your IDE 53 | 54 | Start the debug profile here and it should listen to your breakpoints after the docker image has been built and is running. 55 | 56 | ## FAQs 57 | 58 | ### Why isn't feature X inside of this project template? 59 | 60 | The goal of this project is to provide a streamlined initial starting point for a developer to immediately be productive in writing modern Java REST web app. 61 | 62 | ### How should I deploy this app? 63 | 64 | This app is ready to run natively or be shipped in your favorite orchestration technology that supports Docker. 65 | 66 | ### How should I implement HTTPS / SSL? 67 | 68 | #### Load balancer 69 | 70 | If you're in a production environment and need your app to scale, I would look at **AWS app Load Balancer**, **GCP Cloud Load Balancing**, or **Azure Load Balancer**. Most load balancers fully support HTTPS/SSL and will send requests to your instance in your cloud's internal network via HTTP which reduces load at your app and still covers for most security use-cases. 71 | 72 | #### Web server reverse proxy 73 | 74 | If you're running in a non-scalable environment, a single instance in production, or in a staging/development/qa/misc environment I would recommend looking at a reverse proxy using **nginx** or **Apache**. Either of these web servers are great choices and they can provide HTTPS/SSL and proxy all the requests to your app via HTTP internally. 75 | 76 | #### Why not run SSL natively through Java / Tomcat? 77 | 78 | 1. In a scalable environment you typically want to reduce any load at the app layer. In primarily security focused apps, requirements may be different. 79 | 80 | 2. Configuring Java for SSL can be a pain. In my personal experience I have found it much easier to configure a load balancer or web server to serve the latest SSL/TLS ciphers and other security settings than to allow my Java/Tomcat app to do it. 81 | 82 | 3. In general, SSL is more related to infrastructure than app level so there is a developer benefit of separation of concerns here. 83 | 84 | ## Contribute 85 | 86 | Community feedback is welcome. Please feel free to submit an issue or a pull request. 87 | 88 | ## References 89 | 90 | [Spring Boot Getting Started](https://spring.io/guides/gs/spring-boot/) 91 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | mavenCentral() 4 | } 5 | dependencies { 6 | classpath("org.springframework.boot:spring-boot-gradle-plugin:2.2.4.RELEASE") 7 | } 8 | } 9 | 10 | apply plugin: 'java' 11 | apply plugin: 'eclipse' 12 | apply plugin: 'idea' 13 | apply plugin: 'org.springframework.boot' 14 | apply plugin: 'io.spring.dependency-management' 15 | 16 | bootJar { 17 | baseName = 'myapp-FINAL' 18 | } 19 | 20 | repositories { 21 | mavenCentral() 22 | } 23 | 24 | sourceCompatibility = 1.13 25 | targetCompatibility = 1.13 26 | 27 | dependencies { 28 | compile("org.springframework.boot:spring-boot-starter-web") 29 | testCompile('org.springframework.boot:spring-boot-starter-test') 30 | } 31 | -------------------------------------------------------------------------------- /docker-compose.debug.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | myapp: 4 | environment: 5 | - JAVA_TOOL_OPTIONS="-agentlib:jdwp=transport=dt_socket,address=0.0.0.0:8000,server=y,suspend=n" 6 | ports: 7 | - 8000:8000 8 | restart: "no" 9 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | myapp: 4 | build: . 5 | # Uncomment if you'd like to load your env vars from file 6 | # env_file: 7 | # - secrets.env 8 | ports: 9 | - 8080:8080 10 | restart: "always" 11 | -------------------------------------------------------------------------------- /src/main/java/myapp/Application.java: -------------------------------------------------------------------------------- 1 | package myapp; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class Application { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(Application.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/myapp/controllers/HomeController.java: -------------------------------------------------------------------------------- 1 | package myapp.controllers; 2 | 3 | import org.springframework.web.bind.annotation.RequestMapping; 4 | import org.springframework.web.bind.annotation.RequestParam; 5 | import org.springframework.web.bind.annotation.RestController; 6 | 7 | @RestController 8 | public class HomeController { 9 | 10 | @RequestMapping("/") 11 | public String index() { 12 | return "hello world"; 13 | } 14 | } 15 | --------------------------------------------------------------------------------