Статьи

Spring MVC и REST в Google App Engine

Некоторое время назад я писал о том, как реализовать ваш Restful Web API с помощью Spring MVC . Прочитайте мой предыдущий пост, чтобы узнать об этом.

В этом посте был разработан простой пример отдыха. Для тестирования приложения файл был скопирован на веб-сервер (например, Tomcat ), а затем был возвращен доступ к http: // localhost: 8080 / RestServer / characters / 1 информации символа 1.

В этом посте я собираюсь объяснить, как преобразовать это приложение в Google App Engine и внедрить в инфраструктуру Google с помощью Maven . Конечно, в этом случае мы собираемся развернуть приложение Rest Spring MVC , но тот же подход можно использовать для переноса веб-приложения Spring MVC (или любого другого приложения, разработанного с другой веб-средой) в GAE.

Прежде всего, очевидно, вы должны создать учетную запись Google и зарегистрировать новое приложение (запомните имя, потому что оно будет использовано на следующем шаге). После этого вы можете начать миграцию.

Требуются три изменения: создайте appengine-web.xml, определяющий имя приложения; добавьте тег сервера в settings.xml с информацией об учетной записи Google и измените pom.xml для добавления плагина GAE и его зависимостей.

Начнем с appengine-web.xml . Этот файл используется GAE для настройки приложения и создается в каталоге WEB-INF (на том же уровне web.xml ).

01
02
03
04
05
06
07
08
09
10
11
12
<?xml version="1.0" encoding="utf-8"?>
    <application>alexsotoblog</application>
    <version>1</version>
 
    <system-properties>
        <property name="java.util.logging.config.file" value="WEB-INF/classes/logging.properties"/>
    </system-properties>
    <precompilation-enabled>false</precompilation-enabled>
    <sessions-enabled>true</sessions-enabled>
</appengine-web-app>

Наиболее важным полем является тег приложения . Этот тег содержит название нашего приложения (определяется при регистрации нового приложения Google).

Другие теги — это версия, системные свойства и переменные среды, а также разные конфигурации, например, если вы хотите, чтобы прекомпиляция повысила производительность, или если вашему приложению требуются сеансы.

И ваш проект больше не должен изменяться, теперь будут затронуты только файлы Maven .

В settings.xml необходимо добавить информацию об учетной записи:

01
02
03
04
05
06
07
08
09
10
11
12
13
  <localRepository>/media/share/maven_repo</localRepository>
  <servers>
        <server>
            <id>appengine.google.com</id>
            <username>my_account@gmail.com</username>
            <password>my_password</password>
        </server>
 
    </servers>
   
</settings>

Убедитесь, что это так же просто, как зарегистрировать любой другой сервер в Maven .

И, наконец, самая нудная часть, модифицирующая pom.xml .

Прежде всего, добавление новых свойств:

1
2
3
4
5
6
7
<gae.home>/media/share/maven_repo/com/google/appengine/appengine-java-sdk/1.5.5/appengine-java-sdk-1.5.5</gae.home>
<gaeApplicationName>alexsotoblog</gaeApplicationName>
<gaePluginVersion>0.9.0</gaePluginVersion>
<gae.version>1.5.5</gae.version>
 
<!-- Upload to http://test.latest.<applicationName>.appspot.com by default -->
<gae.application.version>test</gae.application.version>

В первой строке мы определяем расположение Appengine Java SDK . Если вы уже установили, вставьте местоположение в этот тег, если нет, скопируйте то же местоположение этого pom и просто замените каталог репозитория maven , в моем случае / media / share / maven_repo , на ваш. Обычно ваше хранилище Maven будет /home/user/.m2/repositories . Maven загрузит SDK для вас во время развертывания.

Следующий шаг — добавление репозитория Maven GAE .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
<repositories>
 <repository>
  <id>maven-gae-plugin-repo</id>
  <name>maven-gae-plugin repository</name>
 </repository>
</repositories>
 
<pluginRepositories>
 <pluginRepository>
  <id>maven-gae-plugin-repo</id>
  <name>Maven Google App Engine Repository</name>
 </pluginRepository>
</pluginRepositories>

Поскольку наш проект — фиктивный проект, Datanucleus не используются. В случае более сложных проектов такой доступ к базе данных требуется, например, с помощью JDO, следует добавить следующие зависимости:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<dependency>
 <groupId>javax.jdo</groupId>
 <artifactId>jdo2-api</artifactId>
 <version>2.3-eb</version>
 <exclusions>
  <exclusion>
   <groupId>javax.transaction</groupId>
   <artifactId>transaction-api</artifactId>
  </exclusion>
 </exclusions>
</dependency>
 
<dependency>
 <groupId>com.google.appengine.orm</groupId>
 <artifactId>datanucleus-appengine</artifactId>
 <version>1.0.6.final</version>
</dependency>
 
<dependency>
 <groupId>org.datanucleus</groupId>
 <artifactId>datanucleus-core</artifactId>
 <version>1.1.5</version>
 <scope>runtime</scope>
 <exclusions>
  <exclusion>
   <groupId>javax.transaction</groupId>
   <artifactId>transaction-api</artifactId>
  </exclusion>
 </exclusions>
</dependency>
 
<dependency>
 <groupId>com.google.appengine</groupId>
 <artifactId>geronimo-jta_1.1_spec</artifactId>
 <version>1.1.1</version>
 <scope>runtime</scope>
</dependency>
 
 
<dependency>
 <groupId>com.google.appengine</groupId>
 <artifactId>geronimo-jpa_3.0_spec</artifactId>
 <version>1.1.1</version>
 <scope>runtime</scope>
</dependency>

И если вы используете Datanucleus , maven-datanucleus-plugin должен быть зарегистрирован. Позаботьтесь о том, чтобы правильно настроить его в зависимости от вашего проекта.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<plugin>
            <groupId>org.datanucleus</groupId>
            <artifactId>maven-datanucleus-plugin</artifactId>
            <version>1.1.4</version>
            <configuration>
                <!--
                    Make sure this path contains your persistent
                    classes!
                -->
                <mappingIncludes>**/model/*.class</mappingIncludes>
                <verbose>true</verbose>
                <enhancerName>ASM</enhancerName>
                <api>JDO</api>
            </configuration>
            <executions>
                <execution>
                    <phase>compile</phase>
                    <goals>
                        <goal>enhance</goal>
                    </goals>
                </execution>
            </executions>
            <dependencies>
                <dependency>
                    <groupId>org.datanucleus</groupId>
                    <artifactId>datanucleus-core</artifactId>
                    <version>1.1.5</version>
                    <exclusions>
                        <exclusion>
                            <groupId>javax.transaction</groupId>
                            <artifactId>transaction-api</artifactId>
                        </exclusion>
                    </exclusions>
                </dependency>
                <dependency>
                    <groupId>org.datanucleus</groupId>
                    <artifactId>datanucleus-rdbms</artifactId>
                    <version>1.1.5</version>
                </dependency>
                <dependency>
                 <groupId>org.datanucleus</groupId>
                 <artifactId>datanucleus-enhancer</artifactId>
                <version>1.1.5</version>
           </dependency>
       </dependencies>
</plugin>

Теперь добавлены зависимости Google App Engine .

01
02
03
04
05
06
07
08
09
10
11
<dependency>
 <groupId>com.google.appengine</groupId>
 <artifactId>appengine-api-1.0-sdk</artifactId>
 <version>${gae.version}</version>
</dependency>
 
<dependency>
 <groupId>com.google.appengine</groupId>
 <artifactId>appengine-tools-api</artifactId>
 <version>1.3.7</version>
</dependency>

Затем, если вы хотите проверить функциональность GAE (не используется в нашем фиктивном проекте), добавляются следующие библиотеки GAE :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
<dependency>
 <groupId>com.google.appengine</groupId>
 <artifactId>appengine-api-labs</artifactId>
 <version>${gae.version}</version>
 <scope>test</scope>
</dependency>
 
<dependency>
 <groupId>com.google.appengine</groupId>
 <artifactId>appengine-api-stubs</artifactId>
 <version>${gae.version}</version>
 <scope>test</scope>
</dependency>
 
<dependency>
 <groupId>com.google.appengine</groupId>
 <artifactId>appengine-testing</artifactId>
 <version>${gae.version}</version>
 <scope>test</scope>
</dependency>

Следующее изменение — это модификация maven-war-plugin, включающая appengine-web.xml в сгенерированный пакет:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
<plugin>
 <groupId>org.apache.maven.plugins</groupId>
 <artifactId>maven-war-plugin</artifactId>
 <configuration>
  <webResources>
   <resource>
    <directory>src/main/webapp</directory>
    <filtering>true</filtering>
    <includes>
     <include>**/appengine-web.xml</include>
    </includes>
   </resource>
  </webResources>
 </configuration>
</plugin>

И, наконец, добавление maven-gae-plugin и настройка его для загрузки приложения в appspot .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
<plugin>
 <groupId>net.kindleit</groupId>
 <artifactId>maven-gae-plugin</artifactId>
 <version>${gaePluginVersion}</version>
 <configuration>
  <serverId>appengine.google.com</serverId>
 </configuration>
 <dependencies>
  <dependency>
   <groupId>net.kindleit</groupId>
   <artifactId>gae-runtime</artifactId>
   <version>${gae.version}</version>
   <type>pom</type>
  </dependency>
 </dependencies>
</plugin>

Обратите внимание, что тег <serviceId> содержит имя сервера, определенное ранее в файле settings.xml .

Также, если вы используете maven-release-plugin, вы можете автоматически загрузить приложение в appspot , во время выпуска: выполнить цель:

1
2
3
4
5
6
7
8
<plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-release-plugin</artifactId>
        <version>2.2.1</version>
        <configuration>
              <goals>gae:deploy</goals>
        </configuration>
</plugin>

Теперь запустите gae: разверните цель. Если вы уже установили Appengine Java SDK , то ваше приложение будет загружено на ваш сайт GAE . Но если вы запускаете плагин в первый раз, вы получите сообщение об ошибке. Не паникуйте, эта ошибка возникает из-за того, что плагин Maven не находит Appengine SDK в каталоге, указанном вами в теге <gae.home>. Но если вы настроили расположение gae.home в своем локальном репозитории Maven , просто запустите gae: unpack goal, и SDK будет установлен правильно, поэтому при повторном запуске gae: развертывание приложения будет загружено в инфраструктуру Google.

В примере с постом вы можете перейти по адресу http://alexsotoblog.appspot.com/characters/1http://alexsotoblog.appspot.com/characters/1, и информация о символах в формате JSON отобразится в вашем браузере.

Как я уже отмечал в начале поста, один и тот же процесс можно использовать для любого веб-приложения, а не только для Spring Rest MVC .

Из-за цели обучения все модификации были внесены в приложение. Я советую вам создать родительский pom с тегами, связанными с GAE , поэтому каждый проект, который должен быть загружен в Google App Engine, начинается с одного файла pom.

Я желаю, чтобы вы нашли этот пост полезным.

На этой неделе я нахожусь в devoxx , встречайте меня там;) Я буду говорить в четверг 17 в 13:00 о том, как ускорить Javascript и время загрузки CSS с агрегацией и минимизацией .

Полный файл POM :

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
<?xml version="1.0" encoding="UTF-8"?>
 <modelVersion>4.0.0</modelVersion>
 <groupId>org.springframework</groupId>
 <artifactId>rest</artifactId>
 <name>Rest</name>
 <packaging>war</packaging>
 <version>1.0.0-BUILD-SNAPSHOT</version>
 <properties>
  <java-version>1.6</java-version>
  <org.springframework-version>3.0.4.RELEASE</org.springframework-version>
  <org.aspectj-version>1.6.9</org.aspectj-version>
  <org.slf4j-version>1.5.10</org.slf4j-version>
  <!-- Specify AppEngine version for your project. It should match SDK version
   pointed to by ${gae.home} property (Typically, one used by your Eclipse plug-in) -->
 
  <gae.home>/home/alex/.m2/repository/com/google/appengine/appengine-java-sdk/1.5.5/appengine-java-sdk-1.5.5</gae.home>
  <gaeApplicationName>alexsotoblog</gaeApplicationName>
  <gaePluginVersion>0.9.0</gaePluginVersion>
  <gae.version>1.5.5</gae.version>
 
  <!-- Upload to http://test.latest.<applicationName>.appspot.com by default -->
  <gae.application.version>test</gae.application.version>
 </properties>
 <dependencies>
 
  <!-- Rest -->
  <dependency>
   <groupId>com.sun.xml.bind</groupId>
   <artifactId>jaxb-impl</artifactId>
   <version>2.2.4-1</version>
  </dependency>
  <dependency>
   <groupId>org.codehaus.jackson</groupId>
   <artifactId>jackson-core-lgpl</artifactId>
   <version>1.8.5</version>
  </dependency>
  <dependency>
   <groupId>org.codehaus.jackson</groupId>
   <artifactId>jackson-mapper-lgpl</artifactId>
   <version>1.8.5</version>
  </dependency>
 
  <!-- GAE libraries for local testing as described here: http://code.google.com/appengine/docs/java/howto/unittesting.html -->
  <dependency>
   <groupId>com.google.appengine</groupId>
   <artifactId>appengine-api-labs</artifactId>
   <version>${gae.version}</version>
   <scope>test</scope>
  </dependency>
 
  <dependency>
   <groupId>com.google.appengine</groupId>
   <artifactId>appengine-api-stubs</artifactId>
   <version>${gae.version}</version>
   <scope>test</scope>
  </dependency>
 
  <dependency>
   <groupId>com.google.appengine</groupId>
   <artifactId>appengine-testing</artifactId>
   <version>${gae.version}</version>
   <scope>test</scope>
  </dependency>
 
 
  <dependency>
   <groupId>com.google.appengine</groupId>
   <artifactId>appengine-api-1.0-sdk</artifactId>
   <version>${gae.version}</version>
  </dependency>
 
  <dependency>
   <groupId>com.google.appengine</groupId>
   <artifactId>appengine-tools-api</artifactId>
   <version>1.3.7</version>
  </dependency>
 
  <!-- Spring -->
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-context</artifactId>
   <version>${org.springframework-version}</version>
   <exclusions>
    <!-- Exclude Commons Logging in favor of SLF4j -->
    <exclusion>
     <groupId>commons-logging</groupId>
     <artifactId>commons-logging</artifactId>
    </exclusion>
   </exclusions>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-webmvc</artifactId>
   <version>${org.springframework-version}</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-oxm</artifactId>
   <version>${org.springframework-version}</version>
  </dependency>
 
  <!-- AspectJ -->
  <dependency>
   <groupId>org.aspectj</groupId>
   <artifactId>aspectjrt</artifactId>
   <version>${org.aspectj-version}</version>
  </dependency>
 
  <!-- Logging -->
  <dependency>
   <groupId>org.slf4j</groupId>
   <artifactId>slf4j-api</artifactId>
   <version>${org.slf4j-version}</version>
  </dependency>
  <dependency>
   <groupId>org.slf4j</groupId>
   <artifactId>jcl-over-slf4j</artifactId>
   <version>${org.slf4j-version}</version>
   <scope>runtime</scope>
  </dependency>
  <dependency>
   <groupId>org.slf4j</groupId>
   <artifactId>slf4j-log4j12</artifactId>
   <version>${org.slf4j-version}</version>
   <scope>runtime</scope>
  </dependency>
  <dependency>
   <groupId>log4j</groupId>
   <artifactId>log4j</artifactId>
   <version>1.2.15</version>
   <exclusions>
    <exclusion>
     <groupId>javax.mail</groupId>
     <artifactId>mail</artifactId>
    </exclusion>
    <exclusion>
     <groupId>javax.jms</groupId>
     <artifactId>jms</artifactId>
    </exclusion>
    <exclusion>
     <groupId>com.sun.jdmk</groupId>
     <artifactId>jmxtools</artifactId>
    </exclusion>
    <exclusion>
     <groupId>com.sun.jmx</groupId>
     <artifactId>jmxri</artifactId>
    </exclusion>
   </exclusions>
   <scope>runtime</scope>
  </dependency>
 
  <!-- @Inject -->
  <dependency>
   <groupId>javax.inject</groupId>
   <artifactId>javax.inject</artifactId>
   <version>1</version>
  </dependency>
 
  <!-- Servlet -->
  <dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>servlet-api</artifactId>
   <version>2.5</version>
   <scope>provided</scope>
  </dependency>
  <dependency>
   <groupId>javax.servlet.jsp</groupId>
   <artifactId>jsp-api</artifactId>
   <version>2.1</version>
   <scope>provided</scope>
  </dependency>
  <dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>jstl</artifactId>
   <version>1.2</version>
  </dependency>
 
  <!-- Test -->
  <dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>4.7</version>
   <scope>test</scope>
  </dependency>
 
 </dependencies>
 <repositories>
  <!-- For testing against latest Spring snapshots -->
  <repository>
   <id>org.springframework.maven.snapshot</id>
   <name>Spring Maven Snapshot Repository</name>
   <releases>
    <enabled>false</enabled>
   </releases>
   <snapshots>
    <enabled>true</enabled>
   </snapshots>
  </repository>
  <!-- For developing against latest Spring milestones -->
  <repository>
   <id>org.springframework.maven.milestone</id>
   <name>Spring Maven Milestone Repository</name>
   <snapshots>
    <enabled>false</enabled>
   </snapshots>
  </repository>
  <!-- GAE repositories -->
  <repository>
   <id>maven-gae-plugin-repo</id>
   <name>maven-gae-plugin repository</name>
  </repository>
 </repositories>
 
 <pluginRepositories>
  <pluginRepository>
   <id>maven-gae-plugin-repo</id>
   <name>Maven Google App Engine Repository</name>
  </pluginRepository>
 </pluginRepositories>
 
 <build>
  <plugins>
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
     <source>${java-version}</source>
     <target>${java-version}</target>
    </configuration>
   </plugin>
 
   <!-- Adding appengine-web into war -->
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-war-plugin</artifactId>
    <configuration>
     <webResources>
      <resource>
       <directory>src/main/webapp</directory>
       <filtering>true</filtering>
       <includes>
        <include>**/appengine-web.xml</include>
       </includes>
      </resource>
     </webResources>
     <warName>abc</warName>
    </configuration>
   </plugin>
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
     <execution>
      <id>install</id>
      <phase>install</phase>
      <goals>
       <goal>sources</goal>
      </goals>
     </execution>
    </executions>
   </plugin>
   <plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>aspectj-maven-plugin</artifactId>
    <!-- Have to use version 1.2 since version 1.3 does not appear to work
     with ITDs -->
    <version>1.2</version>
    <dependencies>
     <!-- You must use Maven 2.0.9 or above or these are ignored (see MNG-2972) -->
     <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjrt</artifactId>
      <version>${org.aspectj-version}</version>
     </dependency>
     <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjtools</artifactId>
      <version>${org.aspectj-version}</version>
     </dependency>
    </dependencies>
    <executions>
     <execution>
      <goals>
       <goal>compile</goal>
       <goal>test-compile</goal>
      </goals>
     </execution>
    </executions>
    <configuration>
     <outxml>true</outxml>
     <source>${java-version}</source>
     <target>${java-version}</target>
    </configuration>
   </plugin>
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <configuration>
     <junitArtifactName>junit:junit</junitArtifactName>
    </configuration>
   </plugin>
   <plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>tomcat-maven-plugin</artifactId>
    <version>1.0-beta-1</version>
   </plugin>
   <!-- The actual maven-gae-plugin. Type "mvn gae:run" to run project, "mvn
    gae:deploy" to upload to GAE. -->
   <plugin>
    <groupId>net.kindleit</groupId>
    <artifactId>maven-gae-plugin</artifactId>
    <version>${gaePluginVersion}</version>
    <configuration>
     <serverId>appengine.google.com</serverId>
    </configuration>
    <dependencies>
     <dependency>
      <groupId>net.kindleit</groupId>
      <artifactId>gae-runtime</artifactId>
      <version>${gae.version}</version>
      <type>pom</type>
     </dependency>
    </dependencies>
   </plugin>
  </plugins>
 </build>
</project>

Скачать код.
Музыка: http://www.youtube.com/watch?v=Nba3Tr_GLZU

Ссылка: Spring MVC и REST в Google App Engine от нашего партнера по JCG Алекса Сото в блоге One Jar To Rule All .

Статьи по Теме :