├── .github ├── dependabot.yml └── workflows │ └── maven.yml ├── .gitignore ├── .mvn └── wrapper │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── README.md ├── compose.yml ├── img ├── SwaggerUI.png ├── list.png └── swagger2.png ├── mvnw ├── mvnw.cmd ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── hendisantika │ │ └── springboot │ │ └── swagger │ │ ├── SpringbootSwaggerApplication.java │ │ ├── config │ │ ├── JacksonConfig.java │ │ └── SwaggerConfig.java │ │ ├── controller │ │ └── StudentController.java │ │ ├── model │ │ └── Student.java │ │ └── service │ │ └── StudentService.java └── resources │ └── application.yml └── test └── java └── com └── hendisantika └── springboot └── swagger └── SpringbootSwaggerApplicationTests.java /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: maven 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: '21:00' 8 | timezone: Asia/Jakarta 9 | open-pull-requests-limit: 10 10 | -------------------------------------------------------------------------------- /.github/workflows/maven.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-maven 3 | 4 | # This workflow uses actions that are not certified by GitHub. 5 | # They are provided by a third-party and are governed by 6 | # separate terms of service, privacy policy, and support 7 | # documentation. 8 | 9 | name: Java CI with Maven 10 | 11 | on: 12 | push: 13 | branches: [ "master" ] 14 | pull_request: 15 | branches: [ "master" ] 16 | 17 | jobs: 18 | build: 19 | 20 | runs-on: ubuntu-latest 21 | 22 | steps: 23 | - uses: actions/checkout@v4 24 | - name: Set up JDK 21 25 | uses: actions/setup-java@v3 26 | with: 27 | java-version: '21' 28 | distribution: 'temurin' 29 | cache: maven 30 | - name: Build with Maven 31 | run: mvn -B package --file pom.xml 32 | 33 | # Optional: Uploads the full dependency graph to GitHub to improve the quality of Dependabot alerts this repository can receive 34 | - name: Update dependency graph 35 | uses: advanced-security/maven-dependency-submission-action@571e99aab1055c2e71a1e2309b9691de18d6b7d6 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | .mvn/ 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | 12 | ### IntelliJ IDEA ### 13 | .idea/ 14 | *.iws 15 | *.iml 16 | *.ipr 17 | 18 | ### NetBeans ### 19 | nbproject/private/ 20 | build/ 21 | nbbuild/ 22 | dist/ 23 | nbdist/ 24 | .nb-gradle/ 25 | ### Java template 26 | # Compiled class file 27 | *.class 28 | 29 | # Log file 30 | *.log 31 | 32 | # BlueJ files 33 | *.ctxt 34 | 35 | # Mobile Tools for Java (J2ME) 36 | .mtj.tmp/ 37 | 38 | # Package Files # 39 | *.jar 40 | *.war 41 | *.ear 42 | *.zip 43 | *.tar.gz 44 | *.rar 45 | 46 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 47 | hs_err_pid* 48 | ### JetBrains template 49 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 50 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 51 | 52 | # User-specific stuff: 53 | .idea/**/workspace.xml 54 | .idea/**/tasks.xml 55 | .idea/dictionaries 56 | 57 | # Sensitive or high-churn files: 58 | .idea/**/dataSources/ 59 | .idea/**/dataSources.ids 60 | .idea/**/dataSources.xml 61 | .idea/**/dataSources.local.xml 62 | .idea/**/sqlDataSources.xml 63 | .idea/**/dynamic.xml 64 | .idea/**/uiDesigner.xml 65 | 66 | # Gradle: 67 | .idea/**/gradle.xml 68 | .idea/**/libraries 69 | 70 | # Mongo Explorer plugin: 71 | .idea/**/mongoSettings.xml 72 | 73 | ## File-based project format: 74 | *.iws 75 | 76 | ## Plugin-specific files: 77 | 78 | # IntelliJ 79 | /out/ 80 | 81 | # mpeltonen/sbt-idea plugin 82 | .idea_modules/ 83 | 84 | # JIRA plugin 85 | atlassian-ide-plugin.xml 86 | 87 | # Crashlytics plugin (for Android Studio and IntelliJ) 88 | com_crashlytics_export_strings.xml 89 | crashlytics.properties 90 | crashlytics-build.properties 91 | fabric.properties 92 | 93 | src/main/resources/static/ 94 | src/main/resources/templates/ 95 | -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hendisantika/spring-boot-swagger/ced8ab0c1d574e69f99147ff26a016d3b4f4f4a5/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Spring Boot Swagger 2 | 3 | RESTful API Documentation Using Swagger and Spring Boot 4 | 5 | 6 | What is Swagger 7 | 8 | Swagger is a specification for documenting REST APIs. It describes the api format including URL, method, and representation to describe REST web services. Swagger is meant to enable the service producer to update the service documentation in real time so that client and documentation systems are moving at the same pace as the server. The methods, parameters, and models description are tightly integrated into the server code, thereby maintaining the synchronization in APIs and its documentation. The specification asks you to include information like: 9 | 10 | What are all the operations that your API supports? 11 | What are your API’s parameters and what does it return? 12 | Does your API need some authorization? 13 | And even fun things like terms, contact information and license to use the API. 14 | 15 | Swagger is created by Wordnik, which defines the specification and framework for their internal development use for “develop.wordnik.com” and underlying system. They started developing the framework in early 2010—being released, is currently also used by Wordnik’s APIs, which powers both internal and external API clients. Here in this post we will create a Spring Boot project for a RESTful Api which is documented with Swagger. To integrate Swagger with Spring Boot we need to include the following maven dependencies in our pom.xml file. 16 | 17 | 18 | ``` 19 | 20 | 21 | io.springfox 22 | springfox-swagger2 23 | 24 | 25 | 26 | io.springfox 27 | springfox-swagger-ui 28 | 29 | ``` 30 | 31 | All the Swagger annotations for documenting the controller are self explanatory. Following are some of the annotation used here 32 | 33 | @Api → Narrates the description about what in general is the responsibility of the controller. 34 | 35 | @ApiOperation → Narrates the responsibility of the specific method. 36 | 37 | @ApiParam → Narrates the parameter the method is expecting and also tells whether it is mandatory or not. 38 | 39 | Run this project by this command : `mvn spring-boot:run -Dspring-boot.run.jvmArguments="--add-opens java.base/java.lang=ALL-UNNAMED" 40 | ` 41 | 42 | Open your browser : 43 | 44 | `http://localhost:8080/swagger-ui.html` 45 | 46 | ![List API Page](img/list.png "List API Page") 47 | 48 | New Swagger Path: 49 | 50 | `http://localhost:8080/swagger-ui/index.html` 51 | 52 | ![List API Page](img/swagger2.png "List API Page") 53 | -------------------------------------------------------------------------------- /compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | db: 3 | image: mysql:9.1.0 4 | restart: always 5 | environment: 6 | MYSQL_DATABASE: 'swaggerDB' 7 | MYSQL_USER: 'yu7i' 8 | MYSQL_PASSWORD: '53cret' 9 | MYSQL_ROOT_PASSWORD: '53cret' 10 | ports: 11 | - '3306:3306' 12 | expose: 13 | - '3306' 14 | volumes: 15 | - my-db:/var/lib/mysql 16 | # Names our volume 17 | volumes: 18 | my-db: 19 | -------------------------------------------------------------------------------- /img/SwaggerUI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hendisantika/spring-boot-swagger/ced8ab0c1d574e69f99147ff26a016d3b4f4f4a5/img/SwaggerUI.png -------------------------------------------------------------------------------- /img/list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hendisantika/spring-boot-swagger/ced8ab0c1d574e69f99147ff26a016d3b4f4f4a5/img/list.png -------------------------------------------------------------------------------- /img/swagger2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hendisantika/spring-boot-swagger/ced8ab0c1d574e69f99147ff26a016d3b4f4f4a5/img/swagger2.png -------------------------------------------------------------------------------- /mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven2 Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /etc/mavenrc ] ; then 40 | . /etc/mavenrc 41 | fi 42 | 43 | if [ -f "$HOME/.mavenrc" ] ; then 44 | . "$HOME/.mavenrc" 45 | fi 46 | 47 | fi 48 | 49 | # OS specific support. $var _must_ be set to either true or false. 50 | cygwin=false; 51 | darwin=false; 52 | mingw=false 53 | case "`uname`" in 54 | CYGWIN*) cygwin=true ;; 55 | MINGW*) mingw=true;; 56 | Darwin*) darwin=true 57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 59 | if [ -z "$JAVA_HOME" ]; then 60 | if [ -x "/usr/libexec/java_home" ]; then 61 | export JAVA_HOME="`/usr/libexec/java_home`" 62 | else 63 | export JAVA_HOME="/Library/Java/Home" 64 | fi 65 | fi 66 | ;; 67 | esac 68 | 69 | if [ -z "$JAVA_HOME" ] ; then 70 | if [ -r /etc/gentoo-release ] ; then 71 | JAVA_HOME=`java-config --jre-home` 72 | fi 73 | fi 74 | 75 | if [ -z "$M2_HOME" ] ; then 76 | ## resolve links - $0 may be a link to maven's home 77 | PRG="$0" 78 | 79 | # need this for relative symlinks 80 | while [ -h "$PRG" ] ; do 81 | ls=`ls -ld "$PRG"` 82 | link=`expr "$ls" : '.*-> \(.*\)$'` 83 | if expr "$link" : '/.*' > /dev/null; then 84 | PRG="$link" 85 | else 86 | PRG="`dirname "$PRG"`/$link" 87 | fi 88 | done 89 | 90 | saveddir=`pwd` 91 | 92 | M2_HOME=`dirname "$PRG"`/.. 93 | 94 | # make it fully qualified 95 | M2_HOME=`cd "$M2_HOME" && pwd` 96 | 97 | cd "$saveddir" 98 | # echo Using m2 at $M2_HOME 99 | fi 100 | 101 | # For Cygwin, ensure paths are in UNIX format before anything is touched 102 | if $cygwin ; then 103 | [ -n "$M2_HOME" ] && 104 | M2_HOME=`cygpath --unix "$M2_HOME"` 105 | [ -n "$JAVA_HOME" ] && 106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 107 | [ -n "$CLASSPATH" ] && 108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 109 | fi 110 | 111 | # For Migwn, ensure paths are in UNIX format before anything is touched 112 | if $mingw ; then 113 | [ -n "$M2_HOME" ] && 114 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 115 | [ -n "$JAVA_HOME" ] && 116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 117 | # TODO classpath? 118 | fi 119 | 120 | if [ -z "$JAVA_HOME" ]; then 121 | javaExecutable="`which javac`" 122 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 123 | # readlink(1) is not available as standard on Solaris 10. 124 | readLink=`which readlink` 125 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 126 | if $darwin ; then 127 | javaHome="`dirname \"$javaExecutable\"`" 128 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 129 | else 130 | javaExecutable="`readlink -f \"$javaExecutable\"`" 131 | fi 132 | javaHome="`dirname \"$javaExecutable\"`" 133 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 134 | JAVA_HOME="$javaHome" 135 | export JAVA_HOME 136 | fi 137 | fi 138 | fi 139 | 140 | if [ -z "$JAVACMD" ] ; then 141 | if [ -n "$JAVA_HOME" ] ; then 142 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 143 | # IBM's JDK on AIX uses strange locations for the executables 144 | JAVACMD="$JAVA_HOME/jre/sh/java" 145 | else 146 | JAVACMD="$JAVA_HOME/bin/java" 147 | fi 148 | else 149 | JAVACMD="`which java`" 150 | fi 151 | fi 152 | 153 | if [ ! -x "$JAVACMD" ] ; then 154 | echo "Error: JAVA_HOME is not defined correctly." >&2 155 | echo " We cannot execute $JAVACMD" >&2 156 | exit 1 157 | fi 158 | 159 | if [ -z "$JAVA_HOME" ] ; then 160 | echo "Warning: JAVA_HOME environment variable is not set." 161 | fi 162 | 163 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 164 | 165 | # traverses directory structure from process work directory to filesystem root 166 | # first directory with .mvn subdirectory is considered project base directory 167 | find_maven_basedir() { 168 | 169 | if [ -z "$1" ] 170 | then 171 | echo "Path not specified to find_maven_basedir" 172 | return 1 173 | fi 174 | 175 | basedir="$1" 176 | wdir="$1" 177 | while [ "$wdir" != '/' ] ; do 178 | if [ -d "$wdir"/.mvn ] ; then 179 | basedir=$wdir 180 | break 181 | fi 182 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 183 | if [ -d "${wdir}" ]; then 184 | wdir=`cd "$wdir/.."; pwd` 185 | fi 186 | # end of workaround 187 | done 188 | echo "${basedir}" 189 | } 190 | 191 | # concatenates all lines of a file 192 | concat_lines() { 193 | if [ -f "$1" ]; then 194 | echo "$(tr -s '\n' ' ' < "$1")" 195 | fi 196 | } 197 | 198 | BASE_DIR=`find_maven_basedir "$(pwd)"` 199 | if [ -z "$BASE_DIR" ]; then 200 | exit 1; 201 | fi 202 | 203 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} 204 | echo $MAVEN_PROJECTBASEDIR 205 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 206 | 207 | # For Cygwin, switch paths to Windows format before running java 208 | if $cygwin; then 209 | [ -n "$M2_HOME" ] && 210 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 211 | [ -n "$JAVA_HOME" ] && 212 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 213 | [ -n "$CLASSPATH" ] && 214 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 215 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 216 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` 217 | fi 218 | 219 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 220 | 221 | exec "$JAVACMD" \ 222 | $MAVEN_OPTS \ 223 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 224 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 225 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 226 | -------------------------------------------------------------------------------- /mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM http://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' 39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 40 | 41 | @REM set %HOME% to equivalent of $HOME 42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 43 | 44 | @REM Execute a user defined script before this one 45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 49 | :skipRcPre 50 | 51 | @setlocal 52 | 53 | set ERROR_CODE=0 54 | 55 | @REM To isolate internal variables from possible post scripts, we use another setlocal 56 | @setlocal 57 | 58 | @REM ==== START VALIDATION ==== 59 | if not "%JAVA_HOME%" == "" goto OkJHome 60 | 61 | echo. 62 | echo Error: JAVA_HOME not found in your environment. >&2 63 | echo Please set the JAVA_HOME variable in your environment to match the >&2 64 | echo location of your Java installation. >&2 65 | echo. 66 | goto error 67 | 68 | :OkJHome 69 | if exist "%JAVA_HOME%\bin\java.exe" goto init 70 | 71 | echo. 72 | echo Error: JAVA_HOME is set to an invalid directory. >&2 73 | echo JAVA_HOME = "%JAVA_HOME%" >&2 74 | echo Please set the JAVA_HOME variable in your environment to match the >&2 75 | echo location of your Java installation. >&2 76 | echo. 77 | goto error 78 | 79 | @REM ==== END VALIDATION ==== 80 | 81 | :init 82 | 83 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 84 | @REM Fallback to current working directory if not found. 85 | 86 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 87 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 88 | 89 | set EXEC_DIR=%CD% 90 | set WDIR=%EXEC_DIR% 91 | :findBaseDir 92 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 93 | cd .. 94 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 95 | set WDIR=%CD% 96 | goto findBaseDir 97 | 98 | :baseDirFound 99 | set MAVEN_PROJECTBASEDIR=%WDIR% 100 | cd "%EXEC_DIR%" 101 | goto endDetectBaseDir 102 | 103 | :baseDirNotFound 104 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 105 | cd "%EXEC_DIR%" 106 | 107 | :endDetectBaseDir 108 | 109 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 110 | 111 | @setlocal EnableExtensions EnableDelayedExpansion 112 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 113 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 114 | 115 | :endReadAdditionalConfig 116 | 117 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 118 | 119 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 120 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 121 | 122 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 123 | if ERRORLEVEL 1 goto error 124 | goto end 125 | 126 | :error 127 | set ERROR_CODE=1 128 | 129 | :end 130 | @endlocal & set ERROR_CODE=%ERROR_CODE% 131 | 132 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 133 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 134 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 135 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 136 | :skipRcPost 137 | 138 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 139 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 140 | 141 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 142 | 143 | exit /B %ERROR_CODE% 144 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.hendisantika.springboot.swagger 7 | springboot-swagger 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | spring-boot-swagger 12 | Demo project for Spring Boot Swagger 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 3.5.0 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 21 25 | 1.0.0 26 | SNAPSHOT 27 | 1.20.4 28 | 29 | 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-starter-web 34 | 35 | 36 | org.springframework.boot 37 | spring-boot-starter-test 38 | test 39 | 40 | 41 | org.springframework.boot 42 | spring-boot-starter-data-jpa 43 | 44 | 45 | org.springframework.boot 46 | spring-boot-starter-actuator 47 | 48 | 49 | org.springframework.boot 50 | spring-boot-docker-compose 51 | runtime 52 | true 53 | 54 | 55 | org.springframework.boot 56 | spring-boot-configuration-processor 57 | true 58 | 59 | 60 | 61 | com.mysql 62 | mysql-connector-j 63 | 64 | 65 | 66 | org.projectlombok 67 | lombok 68 | 1.18.38 69 | provided 70 | 71 | 72 | org.springdoc 73 | springdoc-openapi-starter-webmvc-ui 74 | 2.8.9 75 | 76 | 77 | 78 | org.jfairy 79 | jfairy 80 | 0.3.0 81 | 82 | 83 | com.fasterxml.jackson.datatype 84 | jackson-datatype-joda 85 | 2.19.0 86 | 87 | 88 | org.testcontainers 89 | junit-jupiter 90 | test 91 | 92 | 93 | org.testcontainers 94 | mysql 95 | test 96 | 97 | 98 | 99 | 100 | 101 | 102 | org.apache.maven.plugins 103 | maven-compiler-plugin 104 | 105 | 106 | 107 | org.projectlombok 108 | lombok 109 | 110 | 111 | org.springframework.boot 112 | spring-boot-configuration-processor 113 | 114 | 115 | 116 | 117 | 118 | org.springframework.boot 119 | spring-boot-maven-plugin 120 | 121 | 122 | 123 | org.projectlombok 124 | lombok 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | -------------------------------------------------------------------------------- /src/main/java/com/hendisantika/springboot/swagger/SpringbootSwaggerApplication.java: -------------------------------------------------------------------------------- 1 | package com.hendisantika.springboot.swagger; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | 8 | @SpringBootApplication 9 | public class SpringbootSwaggerApplication { 10 | private final static Logger logger = LoggerFactory.getLogger(SpringbootSwaggerApplication.class); 11 | 12 | public static void main(String[] args) { 13 | SpringApplication.run(SpringbootSwaggerApplication.class, args); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/hendisantika/springboot/swagger/config/JacksonConfig.java: -------------------------------------------------------------------------------- 1 | package com.hendisantika.springboot.swagger.config; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | import com.fasterxml.jackson.datatype.joda.JodaModule; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | 8 | /** 9 | * Created by IntelliJ IDEA. 10 | * Project : spring-boot-swagger 11 | * User: hendisantika 12 | * Email: hendisantika@gmail.com 13 | * Telegram : @hendisantika34 14 | * Date: 16/12/24 15 | * Time: 17.35 16 | * To change this template use File | Settings | File Templates. 17 | */ 18 | @Configuration 19 | public class JacksonConfig { 20 | @Bean 21 | public ObjectMapper objectMapper() { 22 | ObjectMapper mapper = new ObjectMapper(); 23 | mapper.registerModule(new JodaModule()); 24 | return mapper; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/hendisantika/springboot/swagger/config/SwaggerConfig.java: -------------------------------------------------------------------------------- 1 | package com.hendisantika.springboot.swagger.config; 2 | 3 | import io.swagger.v3.oas.models.OpenAPI; 4 | import org.springframework.beans.factory.annotation.Value; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | 8 | /** 9 | * Created by hendisantika on 4/24/17. 10 | */ 11 | 12 | @Configuration 13 | public class SwaggerConfig { 14 | @Bean 15 | public OpenAPI notifOpenAPI(@Value("${application-description}") String appDescription, @Value("${application" + 16 | "-version}") String appVersion) { 17 | OpenAPI openAPI = new OpenAPI(); 18 | openAPI.info(new io.swagger.v3.oas.models.info.Info() 19 | .title("Sample Service API") 20 | .description(appDescription) 21 | .version(appVersion) 22 | .contact(new io.swagger.v3.oas.models.info.Contact() 23 | .name("Hendi Santika") 24 | .url("https://s.id/hendisantika") 25 | .email("hendisantika@yahoo.co.id")) 26 | .termsOfService("TOC") 27 | .license(new io.swagger.v3.oas.models.info.License().name("License").url("https://s.id/hendisantika"))); 28 | return openAPI; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/hendisantika/springboot/swagger/controller/StudentController.java: -------------------------------------------------------------------------------- 1 | package com.hendisantika.springboot.swagger.controller; 2 | 3 | import com.hendisantika.springboot.swagger.model.Student; 4 | import com.hendisantika.springboot.swagger.service.StudentService; 5 | import io.swagger.v3.oas.annotations.Operation; 6 | import io.swagger.v3.oas.annotations.Parameter; 7 | import io.swagger.v3.oas.annotations.Parameters; 8 | import io.swagger.v3.oas.annotations.tags.Tag; 9 | import lombok.RequiredArgsConstructor; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | import org.springframework.http.HttpStatus; 13 | import org.springframework.http.ResponseEntity; 14 | import org.springframework.web.bind.annotation.GetMapping; 15 | import org.springframework.web.bind.annotation.PathVariable; 16 | import org.springframework.web.bind.annotation.RequestHeader; 17 | import org.springframework.web.bind.annotation.RequestMapping; 18 | import org.springframework.web.bind.annotation.RequestParam; 19 | import org.springframework.web.bind.annotation.RestController; 20 | 21 | import java.util.List; 22 | 23 | /** 24 | * Created by hendisantika on 4/24/17. 25 | */ 26 | 27 | @RestController 28 | @RequestMapping(value = "/students") 29 | @RequiredArgsConstructor 30 | @Tag(name = "Student", 31 | description = "This API provides the capability to search Student from a Student Repository") 32 | public class StudentController { 33 | private final Logger logger = LoggerFactory.getLogger(this.getClass()); 34 | 35 | private final StudentService studentService; 36 | 37 | @Operation( 38 | summary = "Get All Student Data", 39 | description = "Get All Student Data." 40 | ) 41 | @GetMapping(value = "/all") 42 | public ResponseEntity getAllStudents() { 43 | logger.debug("Getting All students ......"); 44 | List student = null; 45 | try { 46 | student = studentService.getAll(); 47 | logger.debug("Getting All students ...... ::"); 48 | } catch (Exception ex) { 49 | logger.error("Error occurred in searchStudentById >>", ex, ex.getMessage()); 50 | return new ResponseEntity(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); 51 | } 52 | return new ResponseEntity(student, HttpStatus.OK); 53 | } 54 | 55 | @Operation( 56 | summary = "Search Student by studentId", 57 | description = "Search Student by studentId." 58 | ) 59 | @GetMapping(value = "/{studentId}") 60 | public ResponseEntity searchStudentById( 61 | @Parameter(name = "studentId", 62 | description = "The Id of the Student to be viewed", 63 | required = true) 64 | @PathVariable Integer studentId) { 65 | logger.debug("Searching for student with studentId ::{}", studentId); 66 | Student student = null; 67 | try { 68 | student = studentService.getStudentById(studentId); 69 | logger.debug("Student found with studentId ::" + studentId); 70 | } catch (Exception ex) { 71 | logger.error("Error occurred in searchStudentById >>", ex, ex.getMessage()); 72 | return new ResponseEntity<>(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); 73 | } 74 | return new ResponseEntity<>(student, HttpStatus.OK); 75 | } 76 | 77 | @Operation(summary = "Search for all Students whose age is greater than input age") 78 | @GetMapping(value = "/greaterThanAge/{age}") 79 | public ResponseEntity filterStudentsByAge( 80 | @Parameter(name = "age", 81 | description = "filtering age", 82 | required = true) @PathVariable Integer age) { 83 | List studentList = null; 84 | try { 85 | studentList = studentService.filterByAge(age); 86 | } catch (Exception ex) { 87 | logger.error("Error occurred in filterStudentsByAge >>", ex, ex.getMessage()); 88 | return new ResponseEntity(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); 89 | } 90 | return new ResponseEntity(studentList, HttpStatus.OK); 91 | } 92 | 93 | @Operation(summary = "Search for all Students who are from input city") 94 | @GetMapping(value = "/fromCity/{cityName}") 95 | public ResponseEntity filterStudentsByCity( 96 | @Parameter(name = "cityName", description = "filtering city name", required = true) 97 | @PathVariable String cityName) { 98 | List studentList = null; 99 | try { 100 | studentList = studentService.filterByCity(cityName); 101 | } catch (Exception ex) { 102 | logger.error("Error occurred in filterStudentsByCity >>", ex, ex.getMessage()); 103 | return new ResponseEntity<>(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); 104 | } 105 | return new ResponseEntity<>(studentList, HttpStatus.OK); 106 | } 107 | 108 | @Operation(summary = "Search for all students who are from given city and " 109 | + "whose age are greater than input age") 110 | @Parameters({ 111 | @Parameter(name = "schoolId", description = "School Id", required = true), 112 | @Parameter(name = "age", description = "Age of Student", required = true), 113 | @Parameter(name = "cityName", description = "City of Student", required = true)}) 114 | @GetMapping(value = "/filterByAgeAndCity") 115 | public ResponseEntity filterStudentsByAgeAndCity(@RequestHeader(name = "schoolId") String userId, 116 | @RequestParam Integer age, @RequestParam String cityName) { 117 | 118 | List studentList = null; 119 | try { 120 | studentList = studentService.filterByAgeAndCity(age, cityName); 121 | } catch (Exception ex) { 122 | logger.error("Error occurred in filterStudentsByAgeAndCity >>", ex, ex.getMessage()); 123 | return new ResponseEntity<>(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); 124 | } 125 | return new ResponseEntity<>(studentList, HttpStatus.OK); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/main/java/com/hendisantika/springboot/swagger/model/Student.java: -------------------------------------------------------------------------------- 1 | package com.hendisantika.springboot.swagger.model; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import org.jfairy.producer.person.Address; 7 | import org.jfairy.producer.person.Person; 8 | import org.joda.time.DateTime; 9 | 10 | /** 11 | * Created by hendisantika on 4/24/17. 12 | */ 13 | 14 | @Data 15 | @AllArgsConstructor 16 | @NoArgsConstructor 17 | public class Student { 18 | private Integer studentId; 19 | private Address address; 20 | private String firstName; 21 | private String middleName; 22 | private String lastName; 23 | private String email; 24 | private Person.Sex sex; 25 | private String telephoneNumber; 26 | private DateTime dateOfBirth; 27 | private Integer age; 28 | private String companyEmail; 29 | private String nationalIdentityCardNumber; 30 | private String nationalIdentificationNumber; 31 | 32 | public Student(int studentId, Person p) { 33 | this.studentId = studentId; 34 | this.nationalIdentityCardNumber = p.nationalIdentificationNumber(); 35 | this.address = p.getAddress(); 36 | this.firstName = p.firstName(); 37 | this.middleName = p.middleName(); 38 | this.lastName = p.lastName(); 39 | this.email = p.email(); 40 | this.sex = p.sex(); 41 | this.telephoneNumber = p.telephoneNumber(); 42 | this.dateOfBirth = p.dateOfBirth(); 43 | this.age = p.age(); 44 | this.nationalIdentificationNumber = p.nationalIdentificationNumber(); 45 | this.companyEmail = p.companyEmail(); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/hendisantika/springboot/swagger/service/StudentService.java: -------------------------------------------------------------------------------- 1 | package com.hendisantika.springboot.swagger.service; 2 | 3 | import com.hendisantika.springboot.swagger.model.Student; 4 | import jakarta.annotation.PostConstruct; 5 | import lombok.RequiredArgsConstructor; 6 | import org.jfairy.Fairy; 7 | import org.springframework.stereotype.Service; 8 | 9 | import java.util.HashMap; 10 | import java.util.List; 11 | import java.util.Map; 12 | import java.util.stream.Collectors; 13 | 14 | /** 15 | * Created by hendisantika on 4/24/17. 16 | */ 17 | @Service 18 | @RequiredArgsConstructor 19 | public class StudentService { 20 | private static Map studentDB; 21 | private final Fairy fairy = Fairy.create(); 22 | 23 | @PostConstruct 24 | public void init() throws Exception { 25 | studentDB = new HashMap<>(); 26 | for (int i = 0; i < 100; i++) { 27 | Student student = new Student(i, fairy.person()); 28 | studentDB.put(i, student); 29 | } 30 | } 31 | 32 | public List getAll(){ 33 | List studentList = studentDB.entrySet().stream() 34 | .map(Map.Entry::getValue).collect(Collectors.toList()); 35 | return studentList; 36 | } 37 | 38 | public Student getStudentById(Integer studentId) { 39 | return studentDB.get(studentId); 40 | } 41 | 42 | public List filterByAge(Integer age) { 43 | List studentList = studentDB.entrySet().stream().filter(e -> e.getValue().getAge() > age) 44 | .map(Map.Entry::getValue).collect(Collectors.toList()); 45 | return studentList; 46 | } 47 | 48 | public List filterByCity(String cityName) { 49 | List studentList = studentDB.entrySet().stream() 50 | .filter(e -> e.getValue().getAddress().getCity().equals(cityName)).map(Map.Entry::getValue) 51 | .collect(Collectors.toList()); 52 | return studentList; 53 | } 54 | 55 | public List filterByAgeAndCity(Integer age, String cityName) { 56 | List studentList = studentDB.entrySet().stream() 57 | .filter(e -> e.getValue().getAddress().getCity().equals(cityName) && e.getValue().getAge() > age) 58 | .map(Map.Entry::getValue).collect(Collectors.toList()); 59 | return studentList; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | logging: 2 | level: 3 | org.springframework.web: ERROR 4 | com.hendisantika.springboot.swagger: DEBUG 5 | pattern: 6 | console: "%d{yyyy-MM-dd HH:mm:ss} - %msg%n" 7 | file: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n" 8 | file: ./logs/application.log 9 | spring: 10 | datasource: 11 | url: jdbc:mysql://localhost:3306/swaggerDB?createDatabaseIfNotExist=true&useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Jakarta&useSSL=false 12 | username: yu7i 13 | password: 53cret 14 | driver-class-name: com.mysql.cj.jdbc.Driver 15 | jpa: 16 | properties: 17 | hibernate: 18 | format_sql: true 19 | # dialect: org.hibernate.dialect.MySQL8Dialect 20 | 21 | springdoc: 22 | api-docs: 23 | path: /v3/api-doc 24 | swagger-ui: 25 | path: /swagger-ui 26 | application-description: '@project.description@' 27 | application-version: '@project.version@' 28 | -------------------------------------------------------------------------------- /src/test/java/com/hendisantika/springboot/swagger/SpringbootSwaggerApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.hendisantika.springboot.swagger; 2 | 3 | import com.hendisantika.springboot.swagger.service.StudentService; 4 | import org.junit.jupiter.api.BeforeEach; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.boot.test.context.SpringBootTest; 7 | import org.testcontainers.junit.jupiter.Testcontainers; 8 | 9 | import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; 10 | 11 | @Testcontainers 12 | @SpringBootTest( 13 | properties = { 14 | "management.endpoint.health.show-details=always", 15 | "spring.datasource.url=jdbc:tc:mysql:8.4.0:///bankDB" 16 | }, 17 | webEnvironment = RANDOM_PORT 18 | ) 19 | public class SpringbootSwaggerApplicationTests { 20 | 21 | @Autowired 22 | private StudentService studentService; 23 | 24 | @BeforeEach 25 | void deleteAll() { 26 | studentService.getAll(); 27 | } 28 | 29 | } 30 | --------------------------------------------------------------------------------