├── .gitignore ├── README.md ├── create-maven-archetype.sh ├── pom.xml └── src ├── main ├── java │ └── xxxxxx │ │ └── yyyyyy │ │ └── zzzzzz │ │ ├── App.java │ │ └── GuestbookController.java ├── resources │ ├── application.yml │ └── templates │ │ └── list.html └── webapp │ └── WEB-INF │ ├── appengine-web.xml │ └── web.xml └── test ├── java └── .gitkeep └── resources └── .gitkeep /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | .settings 3 | .classpath 4 | .project 5 | .springBeans 6 | *~ 7 | .git 8 | .idea 9 | *.iml 10 | tmp -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Spring Boot GAE Blank 2 | 3 | Maven archetype to create a GAE-configured maven project for Spring Boot Application 4 | 5 | **Note that this project is not optimized to GAE.** 6 | 7 | ## How to use 8 | 9 | with Bash 10 | 11 | mvn archetype:generate\ 12 | -DarchetypeGroupId=am.ik.archetype\ 13 | -DarchetypeArtifactId=spring-boot-gae-blank-archetype\ 14 | -DarchetypeVersion=1.0.4 15 | 16 | with CommandPrompt (Windows) 17 | 18 | mvn archetype:generate^ 19 | -DarchetypeGroupId=am.ik.archetype^ 20 | -DarchetypeArtifactId=spring-boot-gae-blank-archetype^ 21 | -DarchetypeVersion=1.0.4 22 | 23 | As a default setting, `artifactId` is used as application-id. 24 | 25 | ### Example 26 | 27 | #### Create a project 28 | 29 | ``` 30 | $ mvn archetype:generate -B\ 31 | -DarchetypeGroupId=am.ik.archetype\ 32 | -DarchetypeArtifactId=spring-boot-gae-blank-archetype\ 33 | -DarchetypeVersion=1.0.4\ 34 | -DgroupId=com.example\ 35 | -DartifactId=spring-boot-demo\ 36 | -Dversion=1.0.0-SNAPSHOT 37 | $ cd spring-boot-demo 38 | ``` 39 | 40 | #### Run on dev server 41 | 42 | $ mvn appengine:devserver 43 | 44 | Go to http://localhost:8080 45 | 46 | #### Deploy 47 | 48 | modify application name in src/main/webapp/WEB-INF/appengine-web.xml if needed 49 | 50 | $ mvm clean appengine:update 51 | 52 | Demo site is [here](http://spring-boot-demo.appspot.com/). 53 | 54 | ## License 55 | 56 | Licensed under the Apache License, Version 2.0. 57 | -------------------------------------------------------------------------------- /create-maven-archetype.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | KEYWORD="DELETE THIS LINE" 3 | 4 | rm -rf ./tmp 5 | mkdir tmp 6 | cp -r src pom.xml tmp 7 | pushd tmp 8 | 9 | sed -i -e "s/am\.ik\.archetype/xxxxxx.yyyyyy.zzzzzz/g" pom.xml 10 | sed -i -e "s/spring-boot-gae-blank/projectName/g" pom.xml 11 | sed -i -e "s/github\.com\/making\/projectName/github.com\/making\/spring-boot-gae-blank/g" pom.xml 12 | 13 | mvn archetype:create-from-project 14 | 15 | pushd target/generated-sources/archetype 16 | sed -i -e "/$KEYWORD/d" target/classes/archetype-resources/pom.xml 17 | sed -i -e "s/xxxxxx\.yyyyyy\.zzzzzz/\${package}/g" target/classes/archetype-resources/pom.xml 18 | sed -i -e "s/xxxxxx\.yyyyyy\.zzzzzz/am.ik.archetype/g" pom.xml 19 | sed -i -e "s/projectName/spring-boot-gae-blank/g" pom.xml 20 | sed -i -e "s//ossrh<\/id>https:\/\/oss.sonatype.org\/content\/repositories\/snapshots<\/url><\/snapshotRepository>ossrh<\/id>https:\/\/oss.sonatype.org\/service\/local\/staging\/deploy\/maven2\/<\/url><\/repository><\/distributionManagement>/g" pom.xml 21 | sed -i -e "s//org.sonatype.plugins<\/groupId>nexus-staging-maven-plugin<\/artifactId>1.6.2<\/version>true<\/extensions>ossrh<\/serverId>https:\/\/oss.sonatype.org\/<\/nexusUrl>true<\/autoReleaseAfterClose><\/configuration><\/plugin>org.apache.maven.plugins<\/groupId>maven-gpg-plugin<\/artifactId>1.5<\/version>sign-artifacts<\/id>verify<\/phase>sign<\/goal><\/goals><\/execution><\/executions><\/plugin><\/plugins>/g" pom.xml 22 | 23 | mvn deploy 24 | # mvn install 25 | 26 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | am.ik.archetype 7 | spring-boot-gae-blank 8 | 1.0.5-SNAPSHOT 9 | war 10 | 11 | Spring Boot GAE Blank Project (from https://github.com/making/spring-boot-gae-blank) 12 | 13 | 14 | org.springframework.boot 15 | spring-boot-starter-parent 16 | 1.2.5.RELEASE 17 | 18 | 19 | 20 | 21 | Apache License, Version 2.0 22 | http://www.apache.org/licenses/LICENSE-2.0.txt 23 | repo 24 | 25 | 26 | 27 | https://github.com/making/spring-boot-gae-blank 28 | scm:git:git@github.com:making/spring-boot-gae-blank.git 29 | scm:git:git@github.com:making/spring-boot-gae-blank.git 30 | 31 | https://github.com/making/spring-boot-gae-blank 32 | GAE Blank Project for Spring Boot 33 | 34 | 35 | making 36 | Toshiaki Maki 37 | makingx@gmail.com 38 | https://twitter.com/making 39 | 40 | 41 | 42 | 43 | ossrh 44 | https://oss.sonatype.org/content/repositories/snapshots 45 | 46 | 47 | ossrh 48 | https://oss.sonatype.org/service/local/staging/deploy/maven2/ 49 | 50 | 51 | 52 | 53 | UTF-8 54 | xxxxxx.yyyyyy.zzzzzz.App 55 | 1.7 56 | 1.0.1.RELEASE 57 | 1.9.17 58 | 4.3.2.Final 59 | 60 | 61 | 62 | 63 | org.springframework.boot 64 | spring-boot-starter-web 65 | 66 | 67 | org.springframework.boot 68 | spring-boot-starter-tomcat 69 | 70 | 71 | 72 | 73 | org.springframework.boot 74 | spring-boot-starter-thymeleaf 75 | 76 | 77 | org.springframework.boot 78 | spring-boot-starter-actuator 79 | 80 | 81 | org.springframework.boot 82 | spring-boot-starter-test 83 | test 84 | 85 | 86 | 87 | org.springframework.boot 88 | spring-boot-legacy 89 | ${spring-boot-legacy.version} 90 | 91 | 92 | javax.servlet 93 | servlet-api 94 | 2.5 95 | provided 96 | 97 | 98 | 99 | 100 | com.google.appengine 101 | appengine-api-1.0-sdk 102 | ${appengine.target.version} 103 | 104 | 105 | com.google.appengine 106 | appengine-testing 107 | ${appengine.target.version} 108 | test 109 | 110 | 111 | com.google.appengine 112 | appengine-api-stubs 113 | ${appengine.target.version} 114 | test 115 | 116 | 117 | com.github.kernel164 118 | gmultipart 119 | 0.4 120 | 121 | 122 | 123 | 124 | target/${project.artifactId}-${project.version}/WEB-INF/classes 125 | 126 | 127 | org.springframework.boot 128 | spring-boot-maven-plugin 129 | 130 | 131 | org.apache.maven.plugins 132 | maven-war-plugin 133 | 134 | true 135 | 136 | 137 | 138 | ${basedir}/src/main/webapp/WEB-INF 139 | true 140 | WEB-INF 141 | 142 | 143 | 144 | 145 | 146 | com.google.appengine 147 | appengine-maven-plugin 148 | ${appengine.target.version} 149 | 150 | -1 151 | 152 | 153 | -Dspring.thymeleaf.cache=false 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | jitpack.io 164 | https://jitpack.io 165 | 166 | 167 | -------------------------------------------------------------------------------- /src/main/java/xxxxxx/yyyyyy/zzzzzz/App.java: -------------------------------------------------------------------------------- 1 | package xxxxxx.yyyyyy.zzzzzz; 2 | 3 | import com.google.appengine.api.datastore.DatastoreService; 4 | import com.google.appengine.api.datastore.DatastoreServiceFactory; 5 | import com.google.appengine.api.users.UserService; 6 | import com.google.appengine.api.users.UserServiceFactory; 7 | import org.gmr.web.multipart.GMultipartResolver; 8 | import org.springframework.beans.factory.annotation.Value; 9 | import org.springframework.boot.autoconfigure.SpringBootApplication; 10 | import org.springframework.context.annotation.Bean; 11 | import org.springframework.context.annotation.Scope; 12 | import org.springframework.context.annotation.ScopedProxyMode; 13 | import org.springframework.web.multipart.MultipartResolver; 14 | import org.springframework.web.servlet.DispatcherServlet; 15 | 16 | @SpringBootApplication 17 | public class App { 18 | 19 | @Bean 20 | @Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS) 21 | DatastoreService datastoreService() { 22 | return DatastoreServiceFactory.getDatastoreService(); 23 | } 24 | 25 | @Bean 26 | @Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS) 27 | UserService userService() { 28 | return UserServiceFactory.getUserService(); 29 | } 30 | 31 | @Bean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME) 32 | MultipartResolver multipartResolver(@Value("${multipart.maxFileSize:1048576}") int maxUploadSize) { 33 | GMultipartResolver multipartResolver = new GMultipartResolver(); 34 | multipartResolver.setMaxUploadSize(maxUploadSize); 35 | return multipartResolver; 36 | } 37 | } -------------------------------------------------------------------------------- /src/main/java/xxxxxx/yyyyyy/zzzzzz/GuestbookController.java: -------------------------------------------------------------------------------- 1 | package xxxxxx.yyyyyy.zzzzzz; 2 | 3 | import com.google.appengine.api.datastore.DatastoreService; 4 | import com.google.appengine.api.datastore.Entity; 5 | import com.google.appengine.api.datastore.FetchOptions; 6 | import com.google.appengine.api.datastore.Query; 7 | import com.google.appengine.api.users.User; 8 | import com.google.appengine.api.users.UserService; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.stereotype.Controller; 11 | import org.springframework.ui.Model; 12 | import org.springframework.web.bind.annotation.RequestMapping; 13 | import org.springframework.web.bind.annotation.RequestMethod; 14 | import org.springframework.web.bind.annotation.RequestParam; 15 | 16 | import javax.servlet.http.HttpServletRequest; 17 | import java.util.Date; 18 | import java.util.List; 19 | 20 | @Controller 21 | public class GuestbookController { 22 | @Autowired 23 | DatastoreService datastoreService; 24 | @Autowired 25 | UserService userService; 26 | 27 | @RequestMapping(value = "/", method = RequestMethod.GET) 28 | String list(Model model, HttpServletRequest request) { 29 | Query query = new Query("Greeting").addSort("date", Query.SortDirection.DESCENDING); 30 | List greetings = datastoreService.prepare(query).asList(FetchOptions.Builder.withLimit(30)); 31 | model.addAttribute("greetings", greetings); 32 | 33 | User user = userService.getCurrentUser(); 34 | if (user != null) { 35 | String username = user.getEmail(); 36 | model.addAttribute("username", username.contains("@") ? username.split("@")[0] : username); 37 | model.addAttribute("logoutUrl", userService.createLogoutURL(request.getRequestURI())); 38 | } else { 39 | model.addAttribute("loginUrl", userService.createLoginURL(request.getRequestURI())); 40 | } 41 | return "list"; 42 | } 43 | 44 | @RequestMapping(value = "greet", method = RequestMethod.POST) 45 | String greet(@RequestParam("name") String name, 46 | @RequestParam("content") String content) { 47 | Entity greeting = new Entity("Greeting"); 48 | greeting.setProperty("name", name); 49 | greeting.setProperty("content", content); 50 | greeting.setProperty("date", new Date()); 51 | 52 | datastoreService.put(greeting); 53 | 54 | return "redirect:/"; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | # See http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html 2 | spring: 3 | main.show-banner: false 4 | jmx.enabled: false 5 | endpoints: 6 | metrics.enabled: false 7 | dump.enabled: false 8 | shutdown.enabled: false -------------------------------------------------------------------------------- /src/main/resources/templates/list.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Greeting 6 | 7 | 8 |

Greeting

9 | Login 10 | Logout 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 |
19 |
    20 |
  • 21 | name : 22 | content : 23 | content 24 |
  • 25 |
26 | 27 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/appengine-web.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | projectName 4 | 1 5 | true 6 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | contextConfigLocation 8 | xxxxxx.yyyyyy.zzzzzz.App 9 | 10 | 11 | 12 | org.springframework.boot.legacy.context.web.SpringBootContextLoaderListener 13 | 14 | 15 | 16 | characterEncodingFilter 17 | org.springframework.web.filter.DelegatingFilterProxy 18 | 19 | 20 | 21 | characterEncodingFilter 22 | /* 23 | 24 | 25 | appServlet 26 | org.springframework.web.servlet.DispatcherServlet 27 | 28 | contextAttribute 29 | org.springframework.web.context.WebApplicationContext.ROOT 30 | 31 | 32 | publishEvents 33 | false 34 | 35 | 1 36 | 37 | 38 | 39 | appServlet 40 | / 41 | 42 | 43 | -------------------------------------------------------------------------------- /src/test/java/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/making/spring-boot-gae-blank/50e36ad6c27660431c845320d7529be544de0787/src/test/java/.gitkeep -------------------------------------------------------------------------------- /src/test/resources/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/making/spring-boot-gae-blank/50e36ad6c27660431c845320d7529be544de0787/src/test/resources/.gitkeep --------------------------------------------------------------------------------