Spring TODO App code (#1)
* first commit * fixed README * fixed README * fixed README
This commit is contained in:
Родитель
0721da8cde
Коммит
c7bedc7545
|
@ -1,23 +1,15 @@
|
|||
# Compiled class file
|
||||
*.class
|
||||
# Eclipse
|
||||
.settings/
|
||||
.classpath
|
||||
.project
|
||||
bin/
|
||||
|
||||
# Log file
|
||||
*.log
|
||||
# IntelliJ IDEA
|
||||
.idea
|
||||
*.iml
|
||||
|
||||
# BlueJ files
|
||||
*.ctxt
|
||||
# Maven
|
||||
target/
|
||||
|
||||
# Mobile Tools for Java (J2ME)
|
||||
.mtj.tmp/
|
||||
|
||||
# Package Files #
|
||||
*.jar
|
||||
*.war
|
||||
*.nar
|
||||
*.ear
|
||||
*.zip
|
||||
*.tar.gz
|
||||
*.rar
|
||||
|
||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||
hs_err_pid*
|
||||
# Local scripts
|
||||
.scripts/
|
||||
|
|
107
README.md
107
README.md
|
@ -1,5 +1,106 @@
|
|||
# Spring Todo App
|
||||
|
||||
# Contributing
|
||||
This Spring TODO app is a Java application
|
||||
built using [Spring Boot](https://spring.io/projects/spring-boot),
|
||||
[Spring Data for
|
||||
Cosmos DB](https://docs.microsoft.com/en-us/java/azure/spring-framework/configure-spring-boot-starter-java-app-with-cosmos-db?view=azure-java-stable) and
|
||||
[Azure Cosmos DB](https://docs.microsoft.com/en-us/azure/cosmos-db/sql-api-introduction).
|
||||
|
||||
## Requirements
|
||||
|
||||
| [Azure CLI](http://docs.microsoft.com/cli/azure/overview) | [Java 8](https://www.azul.com/downloads/azure-only/zulu) | [Maven 3](http://maven.apache.org/) | [Git](https://github.com/) |
|
||||
|
||||
## Create Azure Cosmos DB
|
||||
|
||||
Create Azure Cosmos DB
|
||||
using [Azure CLI 2.0](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest)
|
||||
|
||||
### STEP A - LOGIN to Azure
|
||||
Login your Azure CLI, and set your subscription
|
||||
|
||||
```bash
|
||||
az login
|
||||
az account set -s <your-subscription-id>
|
||||
```
|
||||
### STEP B - Create Resource Group
|
||||
|
||||
Create an Azure Resource Group, and note down the resource group name
|
||||
|
||||
```bash
|
||||
az group create -n <your-azure-group-name> \
|
||||
-l <your-resource-group-region>
|
||||
```
|
||||
|
||||
### STEP C - Create COSMOS DB
|
||||
|
||||
Create Azure Cosmos DB with GlobalDocumentDB kind.
|
||||
The name of Cosmos DB must use only lower case letters. Note down the `documentEndpoint` field in the response
|
||||
|
||||
```bash
|
||||
az cosmosdb create --kind GlobalDocumentDB \
|
||||
-g <your-azure-group-name> \
|
||||
-n <your-azure-COSMOS-DB-name-in-lower-case-letters>
|
||||
```
|
||||
|
||||
### STEP D - Get COSMOS DB Key
|
||||
|
||||
Get your Azure Cosmos DB key, get the `primaryMasterKey`
|
||||
|
||||
```bash
|
||||
az cosmosdb list-keys -g <your-azure-group-name> -n <your-azure-COSMOSDB-name>
|
||||
```
|
||||
|
||||
## Running Spring TODO App locally
|
||||
|
||||
### STEP 1 - Checkout Spring TODO app
|
||||
|
||||
```bash
|
||||
git clone https://github.com/Microsoft/spring-todo-app.git
|
||||
cd spring-todo-ap
|
||||
```
|
||||
|
||||
### STEP 2 - Configure the app
|
||||
|
||||
Set environment variables using a script file. Start with
|
||||
the supplied template in the repo:
|
||||
|
||||
```bash
|
||||
cp set-env-variables-template.sh .scripts/set-env-variables.sh
|
||||
```
|
||||
|
||||
Edit .scripts/set-env-variables.sh and supply Azure
|
||||
Cosmos DB connection info. Particularly:
|
||||
|
||||
```bash
|
||||
export COSMOSDB_URI=<put-your-COSMOS-DB-documentEndpoint-URI-here>
|
||||
export COSMOSDB_KEY=<put-your-COSMOS-DB-primaryMasterKey-here>
|
||||
export COSMOSDB_DBNAME=<put-your-COSMOS-DB-name-here>
|
||||
```
|
||||
|
||||
|
||||
Set environment variables:
|
||||
|
||||
```bash
|
||||
source .scripts/set-env-variables.sh
|
||||
```
|
||||
|
||||
### STEP 3 - Run Spring TODO App locally
|
||||
|
||||
```bash
|
||||
mvn package spring-boot:run
|
||||
```
|
||||
You can access Spring TODO App here: [http://localhost:8080/](http://localhost:8080/).
|
||||
|
||||
## Clean up
|
||||
|
||||
You can delete Azure resources that you created deleting
|
||||
the Azure Resource Group:
|
||||
|
||||
```bash
|
||||
az group delete -y --no-wait -n <your-resource-group-name>
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
This project welcomes contributions and suggestions. Most contributions require you to agree to a
|
||||
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
|
||||
|
@ -12,3 +113,7 @@ provided by the bot. You will only need to do this once across all repos using o
|
|||
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
|
||||
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
|
||||
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
||||
|
||||
## Useful link
|
||||
- [Azure Spring Boot Starters](https://github.com/Microsoft/azure-spring-boot)
|
||||
- [Azure for Java Developers](https://docs.microsoft.com/en-us/java/azure/)
|
||||
|
|
|
@ -0,0 +1,296 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!DOCTYPE module PUBLIC
|
||||
"-//Puppy Crawl//DTD Check Configuration 1.3//EN"
|
||||
"http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
|
||||
|
||||
<!-- This is a checkstyle configuration file. For descriptions of
|
||||
what the following rules do, please see the checkstyle configuration
|
||||
page at http://checkstyle.sourceforge.net/config.html -->
|
||||
|
||||
<module name="Checker">
|
||||
|
||||
<module name="SuppressionFilter">
|
||||
</module>
|
||||
|
||||
<module name="Header">
|
||||
<property name="header"
|
||||
value="/**\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See LICENSE in the project root for\n * license information.\n */"/>
|
||||
<property name="fileExtensions" value="java, js"/>
|
||||
</module>
|
||||
|
||||
<module name="FileTabCharacter">
|
||||
<!-- Checks that there are no tab characters in the file.
|
||||
-->
|
||||
</module>
|
||||
|
||||
<module name="NewlineAtEndOfFile">
|
||||
<property name="lineSeparator" value="lf"/>
|
||||
</module>
|
||||
|
||||
<module name="RegexpSingleline">
|
||||
<!-- Checks that FIXME is not used in comments. TODO is preferred.
|
||||
-->
|
||||
<property name="format" value="((//.*)|(\*.*))FIXME"/>
|
||||
<property name="message"
|
||||
value='TODO is preferred to FIXME. e.g. "TODO(johndoe): Refactor when v2 is released."'/>
|
||||
</module>
|
||||
|
||||
<module name="RegexpSingleline">
|
||||
<!-- Checks that TODOs are named. (Actually, just that they are followed
|
||||
by an open paren.)
|
||||
-->
|
||||
<property name="format" value="((//.*)|(\*.*))TODO [^(]"/>
|
||||
<property name="message"
|
||||
value='All TODOs should be named. e.g. "TODO (johndoe): Refactor when v2 is released."'/>
|
||||
</module>
|
||||
|
||||
<!-- All Java AST specific tests live under TreeWalker module. -->
|
||||
<module name="TreeWalker">
|
||||
|
||||
<!--
|
||||
|
||||
IMPORT CHECKS
|
||||
|
||||
-->
|
||||
|
||||
<module name="RedundantImport">
|
||||
<!-- Checks for redundant import statements. -->
|
||||
<property name="severity" value="error"/>
|
||||
</module>
|
||||
|
||||
<!--
|
||||
|
||||
NAMING CHECKS
|
||||
|
||||
-->
|
||||
|
||||
<!-- Item 38 - Adhere to generally accepted naming conventions -->
|
||||
|
||||
<module name="PackageName">
|
||||
<!-- Validates identifiers for package names against the
|
||||
supplied expression. -->
|
||||
<!-- Here the default checkstyle rule restricts package name parts to
|
||||
seven characters, this is not in line with common practice at Google.
|
||||
-->
|
||||
<property name="format" value="^[a-z]+(\.[a-z][a-z0-9]{1,})*$"/>
|
||||
<property name="severity" value="warning"/>
|
||||
</module>
|
||||
|
||||
<module name="TypeNameCheck">
|
||||
<!-- Validates static, final fields against the
|
||||
expression "^[A-Z][a-zA-Z0-9]*$". -->
|
||||
<metadata name="altname" value="TypeName"/>
|
||||
<property name="severity" value="warning"/>
|
||||
</module>
|
||||
|
||||
<module name="ConstantNameCheck">
|
||||
<!-- Validates non-private, static, final fields against the supplied
|
||||
public/package final fields "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$". -->
|
||||
<metadata name="altname" value="ConstantName"/>
|
||||
<property name="applyToPublic" value="true"/>
|
||||
<property name="applyToProtected" value="true"/>
|
||||
<property name="applyToPackage" value="true"/>
|
||||
<property name="applyToPrivate" value="false"/>
|
||||
<property name="format" value="^([A-Z][A-Z0-9]*(_[A-Z0-9]+)*|FLAG_.*)$"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Variable ''{0}'' should be in ALL_CAPS (if it is a constant) or be private (otherwise)."/>
|
||||
<property name="severity" value="warning"/>
|
||||
</module>
|
||||
|
||||
<module name="StaticVariableNameCheck">
|
||||
<!-- Validates static, non-final fields against the supplied
|
||||
expression "^[a-z][a-zA-Z0-9]*_?$". -->
|
||||
<metadata name="altname" value="StaticVariableName"/>
|
||||
<property name="applyToPublic" value="true"/>
|
||||
<property name="applyToProtected" value="true"/>
|
||||
<property name="applyToPackage" value="true"/>
|
||||
<property name="applyToPrivate" value="true"/>
|
||||
<property name="format" value="^[a-z][a-zA-Z0-9]*_?$"/>
|
||||
<property name="severity" value="warning"/>
|
||||
</module>
|
||||
|
||||
<module name="MemberNameCheck">
|
||||
<!-- Validates non-static members against the supplied expression. -->
|
||||
<metadata name="altname" value="MemberName"/>
|
||||
<property name="applyToPublic" value="true"/>
|
||||
<property name="applyToProtected" value="true"/>
|
||||
<property name="applyToPackage" value="true"/>
|
||||
<property name="applyToPrivate" value="true"/>
|
||||
<property name="format" value="^[a-z][a-zA-Z0-9]*$"/>
|
||||
<property name="severity" value="warning"/>
|
||||
</module>
|
||||
|
||||
<module name="MethodNameCheck">
|
||||
<!-- Validates identifiers for method names. -->
|
||||
<metadata name="altname" value="MethodName"/>
|
||||
<property name="format" value="^[a-z][a-zA-Z0-9]*(_[a-zA-Z0-9]+)*$"/>
|
||||
<property name="severity" value="warning"/>
|
||||
</module>
|
||||
|
||||
<module name="ParameterName">
|
||||
<!-- Validates identifiers for method parameters against the
|
||||
expression "^[a-z][a-zA-Z0-9]*$". -->
|
||||
<property name="severity" value="warning"/>
|
||||
</module>
|
||||
|
||||
<module name="LocalFinalVariableName">
|
||||
<!-- Validates identifiers for local final variables against the
|
||||
expression "^[a-z][a-zA-Z0-9]*$". -->
|
||||
<property name="severity" value="warning"/>
|
||||
</module>
|
||||
|
||||
<module name="LocalVariableName">
|
||||
<!-- Validates identifiers for local variables against the
|
||||
expression "^[a-z][a-zA-Z0-9]*$". -->
|
||||
<property name="severity" value="warning"/>
|
||||
</module>
|
||||
|
||||
<module name="FinalLocalVariable">
|
||||
<!-- Checks that local variables that never have their values changed are declared final. -->
|
||||
<property name="tokens" value="VARIABLE_DEF"/>
|
||||
<property name="validateEnhancedForLoopVariable" value="true"/>
|
||||
</module>
|
||||
|
||||
<!--
|
||||
|
||||
LENGTH and CODING CHECKS
|
||||
|
||||
-->
|
||||
|
||||
<module name="LineLength">
|
||||
<!-- Checks if a line is too long. -->
|
||||
<property name="max" value="120"/>
|
||||
<property name="severity" value="error"/>
|
||||
|
||||
<!--
|
||||
The default ignore pattern exempts the following elements:
|
||||
- import statements
|
||||
- long URLs inside comments
|
||||
-->
|
||||
|
||||
<property name="ignorePattern"
|
||||
value="${com.puppycrawl.tools.checkstyle.checks.sizes.LineLength.ignorePattern}"
|
||||
default="^(package .*;\s*)|(import .*;\s*)|( *\* *https?://.*)$"/>
|
||||
</module>
|
||||
|
||||
<module name="LeftCurly">
|
||||
<!-- Checks for placement of the left curly brace ('{'). -->
|
||||
<property name="severity" value="warning"/>
|
||||
</module>
|
||||
|
||||
<module name="RightCurly">
|
||||
<!-- Checks right curlies on CATCH, ELSE, and TRY blocks are on
|
||||
the same line. e.g., the following example is fine:
|
||||
<pre>
|
||||
if {
|
||||
...
|
||||
} else
|
||||
</pre>
|
||||
-->
|
||||
<!-- This next example is not fine:
|
||||
<pre>
|
||||
if {
|
||||
...
|
||||
}
|
||||
else
|
||||
</pre>
|
||||
-->
|
||||
<property name="option" value="same"/>
|
||||
<property name="severity" value="warning"/>
|
||||
</module>
|
||||
|
||||
<!-- Checks for braces around if and else blocks -->
|
||||
<module name="NeedBraces">
|
||||
<property name="severity" value="warning"/>
|
||||
<property name="tokens" value="LITERAL_IF, LITERAL_ELSE, LITERAL_FOR, LITERAL_WHILE, LITERAL_DO"/>
|
||||
</module>
|
||||
|
||||
<module name="UpperEll">
|
||||
<!-- Checks that long constants are defined with an upper ell.-->
|
||||
<property name="severity" value="error"/>
|
||||
</module>
|
||||
|
||||
<module name="FallThrough">
|
||||
<!-- Warn about falling through to the next case statement. Similar to
|
||||
javac -Xlint:fallthrough, but the check is suppressed if a single-line comment
|
||||
on the last non-blank line preceding the fallen-into case contains 'fall through' (or
|
||||
some other variants which we don't publicized to promote consistency).
|
||||
-->
|
||||
<property name="reliefPattern"
|
||||
value="fall through|Fall through|fallthru|Fallthru|falls through|Falls through|fallthrough|Fallthrough|No break|NO break|no break|continue on"/>
|
||||
<property name="severity" value="error"/>
|
||||
</module>
|
||||
|
||||
|
||||
<!--
|
||||
|
||||
MODIFIERS CHECKS
|
||||
|
||||
-->
|
||||
|
||||
<module name="ModifierOrder">
|
||||
<!-- Warn if modifier order is inconsistent with JLS3 8.1.1, 8.3.1, and
|
||||
8.4.3. The prescribed order is:
|
||||
public, protected, private, abstract, static, final, transient, volatile,
|
||||
synchronized, native, strictfp
|
||||
-->
|
||||
</module>
|
||||
|
||||
|
||||
<!--
|
||||
|
||||
WHITESPACE CHECKS
|
||||
|
||||
-->
|
||||
|
||||
<module name="WhitespaceAround">
|
||||
<!-- Checks that various tokens are surrounded by whitespace.
|
||||
This includes most binary operators and keywords followed
|
||||
by regular or curly braces.
|
||||
-->
|
||||
<property name="tokens" value="ASSIGN, BAND, BAND_ASSIGN, BOR,
|
||||
BOR_ASSIGN, BSR, BSR_ASSIGN, BXOR, BXOR_ASSIGN, COLON, DIV, DIV_ASSIGN,
|
||||
EQUAL, GE, GT, LAND, LE, LITERAL_CATCH, LITERAL_DO, LITERAL_ELSE,
|
||||
LITERAL_FINALLY, LITERAL_FOR, LITERAL_IF, LITERAL_RETURN,
|
||||
LITERAL_SYNCHRONIZED, LITERAL_TRY, LITERAL_WHILE, LOR, LT, MINUS,
|
||||
MINUS_ASSIGN, MOD, MOD_ASSIGN, NOT_EQUAL, PLUS, PLUS_ASSIGN, QUESTION,
|
||||
SL, SL_ASSIGN, SR_ASSIGN, STAR, STAR_ASSIGN"/>
|
||||
<property name="severity" value="error"/>
|
||||
</module>
|
||||
|
||||
<module name="WhitespaceAfter">
|
||||
<!-- Checks that commas, semicolons and typecasts are followed by
|
||||
whitespace.
|
||||
-->
|
||||
<property name="tokens" value="COMMA, SEMI, TYPECAST"/>
|
||||
</module>
|
||||
|
||||
<module name="NoWhitespaceAfter">
|
||||
<!-- Checks that there is no whitespace after various unary operators.
|
||||
Linebreaks are allowed.
|
||||
-->
|
||||
<property name="tokens" value="BNOT, DEC, DOT, INC, LNOT, UNARY_MINUS,
|
||||
UNARY_PLUS"/>
|
||||
<property name="allowLineBreaks" value="true"/>
|
||||
<property name="severity" value="error"/>
|
||||
</module>
|
||||
|
||||
<module name="NoWhitespaceBefore">
|
||||
<!-- Checks that there is no whitespace before various unary operators.
|
||||
Linebreaks are allowed.
|
||||
-->
|
||||
<property name="tokens" value="SEMI, DOT, POST_DEC, POST_INC"/>
|
||||
<property name="allowLineBreaks" value="true"/>
|
||||
<property name="severity" value="error"/>
|
||||
</module>
|
||||
|
||||
<module name="ParenPad">
|
||||
<!-- Checks that there is no whitespace before close parens or after
|
||||
open parens.
|
||||
-->
|
||||
<property name="severity" value="warning"/>
|
||||
</module>
|
||||
|
||||
</module>
|
||||
</module>
|
|
@ -0,0 +1,225 @@
|
|||
#!/bin/sh
|
||||
# ----------------------------------------------------------------------------
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Maven2 Start Up Batch script
|
||||
#
|
||||
# Required ENV vars:
|
||||
# ------------------
|
||||
# JAVA_HOME - location of a JDK home dir
|
||||
#
|
||||
# Optional ENV vars
|
||||
# -----------------
|
||||
# M2_HOME - location of maven2's installed home dir
|
||||
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||
# e.g. to debug Maven itself, use
|
||||
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
if [ -z "$MAVEN_SKIP_RC" ] ; then
|
||||
|
||||
if [ -f /etc/mavenrc ] ; then
|
||||
. /etc/mavenrc
|
||||
fi
|
||||
|
||||
if [ -f "$HOME/.mavenrc" ] ; then
|
||||
. "$HOME/.mavenrc"
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
# OS specific support. $var _must_ be set to either true or false.
|
||||
cygwin=false;
|
||||
darwin=false;
|
||||
mingw=false
|
||||
case "`uname`" in
|
||||
CYGWIN*) cygwin=true ;;
|
||||
MINGW*) mingw=true;;
|
||||
Darwin*) darwin=true
|
||||
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
|
||||
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
if [ -x "/usr/libexec/java_home" ]; then
|
||||
export JAVA_HOME="`/usr/libexec/java_home`"
|
||||
else
|
||||
export JAVA_HOME="/Library/Java/Home"
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -z "$JAVA_HOME" ] ; then
|
||||
if [ -r /etc/gentoo-release ] ; then
|
||||
JAVA_HOME=`java-config --jre-home`
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$M2_HOME" ] ; then
|
||||
## resolve links - $0 may be a link to maven's home
|
||||
PRG="$0"
|
||||
|
||||
# need this for relative symlinks
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG="`dirname "$PRG"`/$link"
|
||||
fi
|
||||
done
|
||||
|
||||
saveddir=`pwd`
|
||||
|
||||
M2_HOME=`dirname "$PRG"`/..
|
||||
|
||||
# make it fully qualified
|
||||
M2_HOME=`cd "$M2_HOME" && pwd`
|
||||
|
||||
cd "$saveddir"
|
||||
# echo Using m2 at $M2_HOME
|
||||
fi
|
||||
|
||||
# For Cygwin, ensure paths are in UNIX format before anything is touched
|
||||
if $cygwin ; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME=`cygpath --unix "$M2_HOME"`
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
|
||||
[ -n "$CLASSPATH" ] &&
|
||||
CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
|
||||
fi
|
||||
|
||||
# For Migwn, ensure paths are in UNIX format before anything is touched
|
||||
if $mingw ; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME="`(cd "$M2_HOME"; pwd)`"
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
|
||||
# TODO classpath?
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
javaExecutable="`which javac`"
|
||||
if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
|
||||
# readlink(1) is not available as standard on Solaris 10.
|
||||
readLink=`which readlink`
|
||||
if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
|
||||
if $darwin ; then
|
||||
javaHome="`dirname \"$javaExecutable\"`"
|
||||
javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
|
||||
else
|
||||
javaExecutable="`readlink -f \"$javaExecutable\"`"
|
||||
fi
|
||||
javaHome="`dirname \"$javaExecutable\"`"
|
||||
javaHome=`expr "$javaHome" : '\(.*\)/bin'`
|
||||
JAVA_HOME="$javaHome"
|
||||
export JAVA_HOME
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$JAVACMD" ] ; then
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
else
|
||||
JAVACMD="`which java`"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
echo "Error: JAVA_HOME is not defined correctly." >&2
|
||||
echo " We cannot execute $JAVACMD" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ] ; then
|
||||
echo "Warning: JAVA_HOME environment variable is not set."
|
||||
fi
|
||||
|
||||
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
|
||||
|
||||
# traverses directory structure from process work directory to filesystem root
|
||||
# first directory with .mvn subdirectory is considered project base directory
|
||||
find_maven_basedir() {
|
||||
|
||||
if [ -z "$1" ]
|
||||
then
|
||||
echo "Path not specified to find_maven_basedir"
|
||||
return 1
|
||||
fi
|
||||
|
||||
basedir="$1"
|
||||
wdir="$1"
|
||||
while [ "$wdir" != '/' ] ; do
|
||||
if [ -d "$wdir"/.mvn ] ; then
|
||||
basedir=$wdir
|
||||
break
|
||||
fi
|
||||
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
|
||||
if [ -d "${wdir}" ]; then
|
||||
wdir=`cd "$wdir/.."; pwd`
|
||||
fi
|
||||
# end of workaround
|
||||
done
|
||||
echo "${basedir}"
|
||||
}
|
||||
|
||||
# concatenates all lines of a file
|
||||
concat_lines() {
|
||||
if [ -f "$1" ]; then
|
||||
echo "$(tr -s '\n' ' ' < "$1")"
|
||||
fi
|
||||
}
|
||||
|
||||
BASE_DIR=`find_maven_basedir "$(pwd)"`
|
||||
if [ -z "$BASE_DIR" ]; then
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
|
||||
echo $MAVEN_PROJECTBASEDIR
|
||||
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME=`cygpath --path --windows "$M2_HOME"`
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
|
||||
[ -n "$CLASSPATH" ] &&
|
||||
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
|
||||
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
|
||||
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
|
||||
fi
|
||||
|
||||
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
exec "$JAVACMD" \
|
||||
$MAVEN_OPTS \
|
||||
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
|
||||
"-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
|
||||
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
|
|
@ -0,0 +1,143 @@
|
|||
@REM ----------------------------------------------------------------------------
|
||||
@REM Licensed to the Apache Software Foundation (ASF) under one
|
||||
@REM or more contributor license agreements. See the NOTICE file
|
||||
@REM distributed with this work for additional information
|
||||
@REM regarding copyright ownership. The ASF licenses this file
|
||||
@REM to you under the Apache License, Version 2.0 (the
|
||||
@REM "License"); you may not use this file except in compliance
|
||||
@REM with the License. You may obtain a copy of the License at
|
||||
@REM
|
||||
@REM http://www.apache.org/licenses/LICENSE-2.0
|
||||
@REM
|
||||
@REM Unless required by applicable law or agreed to in writing,
|
||||
@REM software distributed under the License is distributed on an
|
||||
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
@REM KIND, either express or implied. See the License for the
|
||||
@REM specific language governing permissions and limitations
|
||||
@REM under the License.
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM ----------------------------------------------------------------------------
|
||||
@REM Maven2 Start Up Batch script
|
||||
@REM
|
||||
@REM Required ENV vars:
|
||||
@REM JAVA_HOME - location of a JDK home dir
|
||||
@REM
|
||||
@REM Optional ENV vars
|
||||
@REM M2_HOME - location of maven2's installed home dir
|
||||
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
|
||||
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
|
||||
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||
@REM e.g. to debug Maven itself, use
|
||||
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
|
||||
@echo off
|
||||
@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
|
||||
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
|
||||
|
||||
@REM set %HOME% to equivalent of $HOME
|
||||
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
|
||||
|
||||
@REM Execute a user defined script before this one
|
||||
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
|
||||
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
|
||||
if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
|
||||
if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
|
||||
:skipRcPre
|
||||
|
||||
@setlocal
|
||||
|
||||
set ERROR_CODE=0
|
||||
|
||||
@REM To isolate internal variables from possible post scripts, we use another setlocal
|
||||
@setlocal
|
||||
|
||||
@REM ==== START VALIDATION ====
|
||||
if not "%JAVA_HOME%" == "" goto OkJHome
|
||||
|
||||
echo.
|
||||
echo Error: JAVA_HOME not found in your environment. >&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||
echo location of your Java installation. >&2
|
||||
echo.
|
||||
goto error
|
||||
|
||||
:OkJHome
|
||||
if exist "%JAVA_HOME%\bin\java.exe" goto init
|
||||
|
||||
echo.
|
||||
echo Error: JAVA_HOME is set to an invalid directory. >&2
|
||||
echo JAVA_HOME = "%JAVA_HOME%" >&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||
echo location of your Java installation. >&2
|
||||
echo.
|
||||
goto error
|
||||
|
||||
@REM ==== END VALIDATION ====
|
||||
|
||||
:init
|
||||
|
||||
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
|
||||
@REM Fallback to current working directory if not found.
|
||||
|
||||
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
|
||||
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
|
||||
|
||||
set EXEC_DIR=%CD%
|
||||
set WDIR=%EXEC_DIR%
|
||||
:findBaseDir
|
||||
IF EXIST "%WDIR%"\.mvn goto baseDirFound
|
||||
cd ..
|
||||
IF "%WDIR%"=="%CD%" goto baseDirNotFound
|
||||
set WDIR=%CD%
|
||||
goto findBaseDir
|
||||
|
||||
:baseDirFound
|
||||
set MAVEN_PROJECTBASEDIR=%WDIR%
|
||||
cd "%EXEC_DIR%"
|
||||
goto endDetectBaseDir
|
||||
|
||||
:baseDirNotFound
|
||||
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
|
||||
cd "%EXEC_DIR%"
|
||||
|
||||
:endDetectBaseDir
|
||||
|
||||
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
|
||||
|
||||
@setlocal EnableExtensions EnableDelayedExpansion
|
||||
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
|
||||
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
|
||||
|
||||
:endReadAdditionalConfig
|
||||
|
||||
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
|
||||
|
||||
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
|
||||
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
|
||||
if ERRORLEVEL 1 goto error
|
||||
goto end
|
||||
|
||||
:error
|
||||
set ERROR_CODE=1
|
||||
|
||||
:end
|
||||
@endlocal & set ERROR_CODE=%ERROR_CODE%
|
||||
|
||||
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
|
||||
@REM check for post script, once with legacy .bat ending and once with .cmd ending
|
||||
if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
|
||||
if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
|
||||
:skipRcPost
|
||||
|
||||
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
|
||||
if "%MAVEN_BATCH_PAUSE%" == "on" pause
|
||||
|
||||
if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
|
||||
|
||||
exit /B %ERROR_CODE%
|
|
@ -0,0 +1,95 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.microsoft.springframework.samples</groupId>
|
||||
<artifactId>spring-todo-app</artifactId>
|
||||
<version>2.0-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>spring-todo-app</name>
|
||||
<description>A Simple Spring Boot TODO list application using AngularJS and
|
||||
Azure DocumentDB Spring boot starter</description>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.0.6.RELEASE</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<maven.build.timestamp.format>yyMMddHHmmssSSS</maven.build.timestamp.format>
|
||||
<java.version>1.8</java.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.azure</groupId>
|
||||
<artifactId>azure-spring-boot-bom</artifactId>
|
||||
<version>2.0.6</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.azure</groupId>
|
||||
<artifactId>azure-cosmosdb-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
<version>2.17</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>validate</id>
|
||||
<phase>validate</phase>
|
||||
<configuration>
|
||||
<configLocation>${project.basedir}/checkstyle.xml</configLocation>
|
||||
<encoding>UTF-8</encoding>
|
||||
<consoleOutput>true</consoleOutput>
|
||||
<failsOnError>true</failsOnError>
|
||||
<failOnViolation>true</failOnViolation>
|
||||
<includeTestSourceDirectory>true</includeTestSourceDirectory>
|
||||
<resourceIncludes>**/*</resourceIncludes>
|
||||
</configuration>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<linkXRef>false</linkXRef>
|
||||
</configuration>
|
||||
<inherited>true</inherited>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,4 @@
|
|||
#!/usr/bin/env bash
|
||||
export COSMOSDB_URI=<put-your-COSMOS-DB-documentEndpoint-URI-here>
|
||||
export COSMOSDB_KEY=<put-your-COSMOS-DB-primaryMasterKey-here>
|
||||
export COSMOSDB_DBNAME=<put-your-COSMOS-DB-name-here>
|
|
@ -0,0 +1,17 @@
|
|||
/**
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for
|
||||
* license information.
|
||||
*/
|
||||
package com.microsoft.springframework.samples;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class TodoApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(TodoApplication.class, args);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
/**
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for
|
||||
* license information.
|
||||
*/
|
||||
package com.microsoft.springframework.samples.controller;
|
||||
|
||||
import com.microsoft.springframework.samples.dao.TodoItemRepository;
|
||||
import com.microsoft.springframework.samples.model.TodoItem;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
public class TodoListController {
|
||||
|
||||
@Autowired
|
||||
private TodoItemRepository todoItemRepository;
|
||||
|
||||
public TodoListController() {
|
||||
}
|
||||
|
||||
@RequestMapping("/home")
|
||||
public Map<String, Object> home() {
|
||||
System.out.println(new Date() + " ======= /home =======");
|
||||
final Map<String, Object> model = new HashMap<String, Object>();
|
||||
model.put("id", UUID.randomUUID().toString());
|
||||
model.put("content", "home");
|
||||
return model;
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP GET
|
||||
*/
|
||||
@RequestMapping(value = "/api/todolist/{index}",
|
||||
method = RequestMethod.GET, produces = {MediaType.APPLICATION_JSON_VALUE})
|
||||
public ResponseEntity<?> getTodoItem(@PathVariable("index") String index) {
|
||||
System.out.println(new Date() + " GET ======= /api/todolist/{" + index
|
||||
+ "} =======");
|
||||
try {
|
||||
return new ResponseEntity<TodoItem>(todoItemRepository.findById(index).get(), HttpStatus.OK);
|
||||
} catch (Exception e) {
|
||||
return new ResponseEntity<String>(index + " not found", HttpStatus.NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP GET ALL
|
||||
*/
|
||||
@RequestMapping(value = "/api/todolist", method = RequestMethod.GET, produces = {MediaType.APPLICATION_JSON_VALUE})
|
||||
public ResponseEntity<?> getAllTodoItems() {
|
||||
System.out.println(new Date() + " GET ======= /api/todolist =======");
|
||||
try {
|
||||
return new ResponseEntity<>(todoItemRepository.findAll(), HttpStatus.OK);
|
||||
} catch (Exception e) {
|
||||
return new ResponseEntity<>("Nothing found", HttpStatus.NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP POST NEW ONE
|
||||
*/
|
||||
@RequestMapping(value = "/api/todolist", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
public ResponseEntity<String> addNewTodoItem(@RequestBody TodoItem item) {
|
||||
System.out.println(new Date() + " POST ======= /api/todolist ======= " + item);
|
||||
try {
|
||||
item.setID(UUID.randomUUID().toString());
|
||||
todoItemRepository.save(item);
|
||||
return new ResponseEntity<String>("Entity created", HttpStatus.CREATED);
|
||||
} catch (Exception e) {
|
||||
return new ResponseEntity<String>("Entity creation failed", HttpStatus.CONFLICT);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP PUT UPDATE
|
||||
*/
|
||||
@RequestMapping(value = "/api/todolist", method = RequestMethod.PUT, consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
public ResponseEntity<String> updateTodoItem(@RequestBody TodoItem item) {
|
||||
System.out.println(new Date() + " PUT ======= /api/todolist ======= " + item);
|
||||
try {
|
||||
todoItemRepository.deleteById(item.getID());
|
||||
todoItemRepository.save(item);
|
||||
return new ResponseEntity<String>("Entity updated", HttpStatus.OK);
|
||||
} catch (Exception e) {
|
||||
return new ResponseEntity<String>("Entity updating failed", HttpStatus.NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP DELETE
|
||||
*/
|
||||
@RequestMapping(value = "/api/todolist/{id}", method = RequestMethod.DELETE)
|
||||
public ResponseEntity<String> deleteTodoItem(@PathVariable("id") String id) {
|
||||
System.out.println(new Date() + " DELETE ======= /api/todolist/{" + id
|
||||
+ "} ======= ");
|
||||
try {
|
||||
todoItemRepository.deleteById(id);
|
||||
return new ResponseEntity<String>("Entity deleted", HttpStatus.OK);
|
||||
} catch (Exception e) {
|
||||
return new ResponseEntity<String>("Entity deletion failed", HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
/**
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for
|
||||
* license information.
|
||||
*/
|
||||
package com.microsoft.springframework.samples.dao;
|
||||
|
||||
import com.microsoft.springframework.samples.model.TodoItem;
|
||||
import com.microsoft.azure.spring.data.cosmosdb.repository.DocumentDbRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface TodoItemRepository extends DocumentDbRepository<TodoItem, String> {
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
/**
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for
|
||||
* license information.
|
||||
*/
|
||||
package com.microsoft.springframework.samples.model;
|
||||
|
||||
import com.microsoft.azure.spring.data.cosmosdb.core.mapping.Document;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@Document
|
||||
public class TodoItem {
|
||||
private String id;
|
||||
private String description;
|
||||
private String owner;
|
||||
private boolean finished;
|
||||
|
||||
public TodoItem() {
|
||||
}
|
||||
|
||||
public TodoItem(String id, String description, String owner) {
|
||||
this.description = description;
|
||||
this.id = id;
|
||||
this.owner = owner;
|
||||
this.finished = false;
|
||||
}
|
||||
|
||||
public boolean isFinished() {
|
||||
return finished;
|
||||
}
|
||||
|
||||
public void setFinish(boolean finished) {
|
||||
this.finished = finished;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
public void setOwner(String owner) {
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
public String getID() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setID(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof TodoItem)) {
|
||||
return false;
|
||||
}
|
||||
final TodoItem group = (TodoItem) o;
|
||||
return Objects.equals(this.getDescription(), group.getDescription())
|
||||
&& Objects.equals(this.getOwner(), group.getOwner())
|
||||
&& Objects.equals(this.getID(), group.getID());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(description, id, owner);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (id != null)
|
||||
return id + ": " + description;
|
||||
else return description;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
azure.cosmosdb.uri=${COSMOSDB_URI}
|
||||
azure.cosmosdb.key=${COSMOSDB_KEY}
|
||||
azure.cosmosdb.database=${COSMOSDB_DBNAME}
|
|
@ -0,0 +1,17 @@
|
|||
/**
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for
|
||||
* license information.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
angular.module('todoApp', ['ngRoute'])
|
||||
.config(['$routeProvider', function ($routeProvider) {
|
||||
$routeProvider.when('/Home', {
|
||||
controller: 'homeCtrl',
|
||||
templateUrl: 'Views/Home.html',
|
||||
}).when('/TodoList', {
|
||||
controller: 'todoListCtrl',
|
||||
templateUrl: 'Views/TodoList.html',
|
||||
}).otherwise({redirectTo: '/Home'});
|
||||
}]);
|
|
@ -0,0 +1,13 @@
|
|||
/**
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for
|
||||
* license information.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
angular.module('todoApp')
|
||||
.controller('homeCtrl', ['$scope', '$location', function ($scope, $location) {
|
||||
$scope.isActive = function (viewLocation) {
|
||||
return viewLocation === $location.path();
|
||||
};
|
||||
}]);
|
|
@ -0,0 +1,95 @@
|
|||
/**
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for
|
||||
* license information.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
angular.module('todoApp')
|
||||
.controller('todoListCtrl', ['$scope', '$location', 'todoListSvc', function ($scope, $location, todoListSvc) {
|
||||
$scope.error = '';
|
||||
$scope.loadingMessage = '';
|
||||
$scope.todoList = null;
|
||||
$scope.editingInProgress = false;
|
||||
$scope.newTodoCaption = '';
|
||||
|
||||
$scope.editInProgressTodo = {
|
||||
description: '',
|
||||
id: 0,
|
||||
finish: false
|
||||
};
|
||||
|
||||
$scope.finishSwitch = function (todo) {
|
||||
todoListSvc.putItem(todo).error(function (err) {
|
||||
todo.finished = !todo.finished;
|
||||
$scope.error = err;
|
||||
$scope.loadingMessage = '';
|
||||
})
|
||||
};
|
||||
|
||||
$scope.editSwitch = function (todo) {
|
||||
todo.edit = !todo.edit;
|
||||
if (todo.edit) {
|
||||
$scope.editInProgressTodo.description = todo.description;
|
||||
$scope.editInProgressTodo.id = todo.id;
|
||||
$scope.editInProgressTodo.finished = todo.finished;
|
||||
$scope.editingInProgress = true;
|
||||
} else {
|
||||
$scope.editingInProgress = false;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.populate = function () {
|
||||
todoListSvc.getItems().success(function (results) {
|
||||
$scope.todoList = results;
|
||||
}).error(function (err) {
|
||||
$scope.error = err;
|
||||
$scope.loadingMessage = '';
|
||||
})
|
||||
};
|
||||
|
||||
$scope.delete = function (id) {
|
||||
todoListSvc.deleteItem(id).success(function (results) {
|
||||
$scope.populate();
|
||||
$scope.loadingMessage = results;
|
||||
$scope.error = '';
|
||||
}).error(function (err) {
|
||||
$scope.error = err;
|
||||
$scope.loadingMessage = '';
|
||||
})
|
||||
};
|
||||
|
||||
$scope.update = function (todo) {
|
||||
todoListSvc.putItem($scope.editInProgressTodo).success(function (results) {
|
||||
$scope.populate();
|
||||
$scope.editSwitch(todo);
|
||||
$scope.loadingMessage = results;
|
||||
$scope.error = '';
|
||||
}).error(function (err) {
|
||||
$scope.error = err;
|
||||
$scope.loadingMessage = '';
|
||||
})
|
||||
};
|
||||
|
||||
$scope.add = function () {
|
||||
function getUser() {
|
||||
var user = localStorage.getItem('user') || 'unknown';
|
||||
localStorage.setItem('user', user);
|
||||
return user;
|
||||
}
|
||||
|
||||
todoListSvc.postItem({
|
||||
'description': $scope.newTodoCaption,
|
||||
'owner': getUser(),
|
||||
'finish': 'false'
|
||||
}).success(function (results) {
|
||||
$scope.newTodoCaption = '';
|
||||
$scope.populate();
|
||||
$scope.loadingMessage = results;
|
||||
$scope.error = '';
|
||||
}).error(function (err) {
|
||||
$scope.error = err;
|
||||
$scope.loadingMsg = '';
|
||||
})
|
||||
};
|
||||
}]);
|
|
@ -0,0 +1,30 @@
|
|||
/**
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for
|
||||
* license information.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
angular.module('todoApp')
|
||||
.factory('todoListSvc', ['$http', function ($http) {
|
||||
return {
|
||||
getItems: function () {
|
||||
return $http.get('api/todolist');
|
||||
},
|
||||
getItem: function (id) {
|
||||
return $http.get('api/todolist/' + id);
|
||||
},
|
||||
postItem: function (item) {
|
||||
return $http.post('api/todolist/', item);
|
||||
},
|
||||
putItem: function (item) {
|
||||
return $http.put('api/todolist/', item);
|
||||
},
|
||||
deleteItem: function (id) {
|
||||
return $http({
|
||||
method: 'DELETE',
|
||||
url: 'api/todolist/' + id
|
||||
});
|
||||
}
|
||||
};
|
||||
}]);
|
|
@ -0,0 +1,5 @@
|
|||
<div class="jumbotron" style="background-color:transparent !important;">
|
||||
<h1>Todo List App</h1>
|
||||
<p>This project uses Spring Boot, Spring Data Cosmos DB
|
||||
to create a simple todo list app.</p>
|
||||
</div>
|
|
@ -0,0 +1,32 @@
|
|||
<div ng-init="populate()" style="margin-bottom: 40px !important;">
|
||||
<div style="height: 70px !important;">
|
||||
<div class="alert alert-danger" data-ng-show="error && error !== ''"><strong>Failure!</strong> {{error}}</div>
|
||||
<div class="alert alert-success" data-ng-show="loadingMessage && loadingMessage !== ''"><strong>Success!</strong> {{loadingMessage}}</div>
|
||||
</div>
|
||||
<div class="panel">
|
||||
<div class="input-group" style="margin-bottom: 20px !important;">
|
||||
<input ng-model="newTodoCaption" class="form-control"/>
|
||||
<span class="input-group-btn">
|
||||
<button ng-click="add()" class="btn btn-primary">Add</button>
|
||||
</span>
|
||||
</div>
|
||||
<ul class="list-group" id="todolist">
|
||||
<div class="list-group-item list-group-item-action flex-column align-items-start" data-ng-repeat="item in todoList">
|
||||
<div data-ng-hide="item.edit">
|
||||
<button type="button" class="btn btn-success float-right btn-sm" ng-disabled="item.finished" data-ng-click="editSwitch(item)">Edit</button>
|
||||
<button type="button" class="btn btn-danger float-right btn-sm" data-ng-click="delete(item.id)">Delete</button>
|
||||
<input type="checkbox" data-ng-model="item.finished" data-ng-change="finishSwitch(item)"/>
|
||||
<span data-ng-hide="item.finished">{{item.description}}</span>
|
||||
<span data-ng-show="item.finished"><del>{{item.description}}</del></span>
|
||||
</div>
|
||||
<div data-ng-show="item.edit" class="input-group">
|
||||
<input class="form-control" data-ng-model="editInProgressTodo.description" />
|
||||
<span class="input-group-btn">
|
||||
<button type="button" data-ng-click="update(item)" class="btn btn-primary float-right btn-sm">Save</button>
|
||||
<button type="button" data-ng-click="editSwitch(item)" class="btn btn-secondary float-right btn-sm">Cancel</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,44 @@
|
|||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<title>Todo List App</title>
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" />
|
||||
<style>
|
||||
.list-group-item { word-wrap: break-word; }
|
||||
#todolist button { margin-left: 5px; }
|
||||
</style>
|
||||
</head>
|
||||
<body ng-app="todoApp" ng-controller="homeCtrl" role="document">
|
||||
<nav class="navbar fixed-top navbar-expand-sm navbar-dark bg-dark">
|
||||
<div class="container">
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navBarToggler" aria-controls="navBarToggler" aria-expanded="false" aria-label="Azure Spring Boot Sample">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navBarToggler">
|
||||
<a class="navbar-brand" href="#/Home">Todo List</a>
|
||||
<ul class="navbar-nav">
|
||||
<li ng-class="{ active: isActive('/Home') }"><a class="nav-link" href="#/Home">Home</a></li>
|
||||
<li ng-class="{ active: isActive('/TodoList') }"><a class="nav-link" href="#/TodoList">Todo List</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container" role="main" style="margin-top: 80px !important;">
|
||||
<div ng-view class="panel-body">
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.25/angular.min.js"></script>
|
||||
<script src="https://code.angularjs.org/1.2.25/angular-route.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js"></script>
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/js/bootstrap.min.js"></script>
|
||||
<script src="Scripts/app.js"></script>
|
||||
<script src="Scripts/homeCtrl.js"></script>
|
||||
<script src="Scripts/todoListCtrl.js"></script>
|
||||
<script src="Scripts/todoListSvc.js"></script>
|
||||
</html>
|
|
@ -0,0 +1,167 @@
|
|||
/**
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for
|
||||
* license information.
|
||||
*/
|
||||
package com.microsoft.springframework.samples;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.BDDMockito.*;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.forwardedUrl;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.microsoft.springframework.samples.controller.TodoListController;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
import com.microsoft.springframework.samples.dao.TodoItemRepository;
|
||||
import com.microsoft.springframework.samples.model.TodoItem;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@TestPropertySource(locations = "classpath:test.properties")
|
||||
@WebMvcTest(TodoListController.class)
|
||||
public class TodoApplicationTest {
|
||||
static final String MOCK_ID = "mockId";
|
||||
static final String MOCK_DESC = "Mock Item";
|
||||
static final String MOCK_OWNER = "Owner of mock item";
|
||||
final Map<String, TodoItem> repository = new HashMap<>();
|
||||
final TodoItem mockItemA = new TodoItem(MOCK_ID + "-A", MOCK_DESC + "-A", MOCK_OWNER + "-A");
|
||||
final TodoItem mockItemB = new TodoItem(MOCK_ID + "-B", MOCK_DESC + "-B", MOCK_OWNER + "-B");
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@MockBean
|
||||
private TodoItemRepository todoItemRepository;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
repository.clear();
|
||||
repository.put(mockItemA.getID(), mockItemA);
|
||||
repository.put(mockItemB.getID(), mockItemB);
|
||||
|
||||
given(this.todoItemRepository.save(any(TodoItem.class))).willAnswer((InvocationOnMock invocation) -> {
|
||||
final TodoItem item = invocation.getArgument(0);
|
||||
if (repository.containsKey(item.getID())) {
|
||||
throw new Exception("Conflict.");
|
||||
}
|
||||
repository.put(item.getID(), item);
|
||||
return item;
|
||||
});
|
||||
|
||||
given(this.todoItemRepository.findById(any(String.class))).willAnswer((InvocationOnMock invocation) -> {
|
||||
final String id = invocation.getArgument(0);
|
||||
return Optional.of(repository.get(id));
|
||||
});
|
||||
|
||||
given(this.todoItemRepository.findAll()).willAnswer((InvocationOnMock invocation) -> {
|
||||
return new ArrayList<TodoItem>(repository.values());
|
||||
});
|
||||
|
||||
willAnswer((InvocationOnMock invocation) -> {
|
||||
final String id = invocation.getArgument(0);
|
||||
if (!repository.containsKey(id)) {
|
||||
throw new Exception("Not Found.");
|
||||
}
|
||||
repository.remove(id);
|
||||
return null;
|
||||
}).given(this.todoItemRepository).deleteById(any(String.class));
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
repository.clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldRenderDefaultTemplate() throws Exception {
|
||||
mockMvc.perform(get("/")).andDo(print()).andExpect(status().isOk()).andExpect(forwardedUrl("index.html"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canGetTodoItem() throws Exception {
|
||||
mockMvc.perform(get(String.format("/api/todolist/%s", mockItemA.getID()))).andDo(print())
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().json(String.format("{\"id\":\"%s\",\"description\":\"%s\",\"owner\":\"%s\"}",
|
||||
mockItemA.getID(), mockItemA.getDescription(), mockItemA.getOwner())));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canGetAllTodoItems() throws Exception {
|
||||
mockMvc.perform(get("/api/todolist")).andDo(print()).andExpect(status().isOk()).andExpect(content()
|
||||
.json(String.format("[{\"id\":\"%s\"}, {\"id\":\"%s\"}]", mockItemA.getID(), mockItemB.getID())));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canSaveTodoItems() throws Exception {
|
||||
final int size = repository.size();
|
||||
final TodoItem mockItemC = new TodoItem(null, MOCK_DESC + "-C", MOCK_OWNER + "-C");
|
||||
mockMvc.perform(post("/api/todolist").contentType(MediaType.APPLICATION_JSON_VALUE).content(String
|
||||
.format("{\"description\":\"%s\",\"owner\":\"%s\"}", mockItemC.getDescription(), mockItemC.getOwner())))
|
||||
.andDo(print()).andExpect(status().isCreated());
|
||||
assertTrue(size + 1 == repository.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canDeleteTodoItems() throws Exception {
|
||||
final int size = repository.size();
|
||||
mockMvc.perform(delete(String.format("/api/todolist/%s", mockItemA.getID()))).andDo(print())
|
||||
.andExpect(status().isOk());
|
||||
assertTrue(size - 1 == repository.size());
|
||||
assertFalse(repository.containsKey(mockItemA.getID()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canUpdateTodoItems() throws Exception {
|
||||
final String newItemJsonString = String.format("{\"id\":\"%s\",\"description\":\"%s\",\"owner\":\"%s\"}",
|
||||
mockItemA.getID(), mockItemA.getDescription(), "New Owner");
|
||||
mockMvc.perform(put("/api/todolist").contentType(MediaType.APPLICATION_JSON_VALUE).content(newItemJsonString))
|
||||
.andDo(print()).andExpect(status().isOk());
|
||||
assertTrue(repository.get(mockItemA.getID()).getOwner().equals("New Owner"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canNotDeleteNonExistingTodoItems() throws Exception {
|
||||
final int size = repository.size();
|
||||
mockMvc.perform(delete(String.format("/api/todolist/%s", "Non-Existing-ID"))).andDo(print())
|
||||
.andExpect(status().isNotFound());
|
||||
assertTrue(size == repository.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT should be idempotent.
|
||||
*/
|
||||
@Test
|
||||
public void idempotenceOfPut() throws Exception {
|
||||
final String newItemJsonString = String.format("{\"id\":\"%s\",\"description\":\"%s\",\"owner\":\"%s\"}",
|
||||
mockItemA.getID(), mockItemA.getDescription(), "New Owner");
|
||||
mockMvc.perform(put("/api/todolist").contentType(MediaType.APPLICATION_JSON_VALUE).content(newItemJsonString))
|
||||
.andDo(print()).andExpect(status().isOk());
|
||||
final TodoItem firstRes = repository.get(mockItemA.getID());
|
||||
mockMvc.perform(put("/api/todolist").contentType(MediaType.APPLICATION_JSON_VALUE).content(newItemJsonString))
|
||||
.andDo(print()).andExpect(status().isOk());
|
||||
final TodoItem secondRes = repository.get(mockItemA.getID());
|
||||
assertTrue(firstRes.equals(secondRes));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/**
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for
|
||||
* license information.
|
||||
*/
|
||||
package com.microsoft.springframework.samples.model;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class TodoItemTest {
|
||||
|
||||
@Test
|
||||
public void testEqualsObject() {
|
||||
final TodoItem itemA = new TodoItem();
|
||||
final TodoItem itemB1 = new TodoItem("B", "Item B", "Owner of Item B");
|
||||
final TodoItem itemB2 = new TodoItem("B", "Item B", "Owner of Item B");
|
||||
final Object nonTodoItem = new Object();
|
||||
assertTrue(itemA.equals(itemA));
|
||||
assertFalse(itemA.equals(null));
|
||||
assertFalse(itemA.equals(nonTodoItem));
|
||||
assertFalse(itemA.equals(itemB1));
|
||||
assertTrue(itemB1.equals(itemB2));
|
||||
assertFalse(itemB1.equals(itemA));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
azure.keyvault.enabled=false
|
Загрузка…
Ссылка в новой задаче