├── .github └── workflows │ └── gradle.yml ├── .gitignore ├── LICENSE ├── README.md ├── build.gradle.kts ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── renovate.json ├── settings.gradle.kts └── src ├── main ├── java │ └── sample │ │ ├── Application.java │ │ ├── ApplicationConfiguration.java │ │ ├── entity │ │ ├── Account.java │ │ ├── Amount.java │ │ ├── BannerData.java │ │ ├── Category.java │ │ ├── Inventory.java │ │ ├── Item.java │ │ ├── Order.java │ │ ├── OrderLineItem.java │ │ ├── OrderStatus.java │ │ ├── Product.java │ │ ├── Profile.java │ │ └── Signon.java │ │ ├── formatter │ │ ├── AmountFormatter.java │ │ └── LocalDateTimeFormatter.java │ │ ├── model │ │ ├── Cart.java │ │ └── CartItem.java │ │ ├── repository │ │ ├── AccountRepository.java │ │ ├── CategoryRepository.java │ │ ├── ItemRepository.java │ │ ├── OrderRepository.java │ │ └── ProductRepository.java │ │ ├── service │ │ ├── AccountService.java │ │ ├── CategoryService.java │ │ ├── ItemService.java │ │ ├── OrderService.java │ │ └── ProductService.java │ │ └── web │ │ ├── Constants.java │ │ ├── ErrorController.java │ │ ├── IndexController.java │ │ ├── WebMvcConfiguration.java │ │ ├── WebSecurityConfiguration.java │ │ ├── account │ │ ├── AbstractAccountForm.java │ │ ├── AccountController.java │ │ ├── AddAccountForm.java │ │ ├── EditAccountForm.java │ │ └── PasswordValidator.java │ │ ├── cart │ │ ├── CartController.java │ │ ├── CartForm.java │ │ └── CartItemForm.java │ │ ├── category │ │ └── CategoryController.java │ │ ├── history │ │ └── HistoryController.java │ │ ├── item │ │ └── ItemController.java │ │ ├── order │ │ └── OrderController.java │ │ ├── product │ │ └── ProductController.java │ │ ├── search │ │ └── SearchController.java │ │ └── signin │ │ └── SigninController.java └── resources │ ├── ValidationMessages_ja.properties │ ├── application.properties │ ├── data.sql │ ├── schema.sql │ ├── static │ ├── css │ │ └── jpetstore.css │ └── images │ │ ├── banner_birds.gif │ │ ├── banner_cats.gif │ │ ├── banner_dogs.gif │ │ ├── banner_fish.gif │ │ ├── banner_reptiles.gif │ │ ├── bird1.gif │ │ ├── bird2.gif │ │ ├── birds_icon.gif │ │ ├── cart.gif │ │ ├── cat1.gif │ │ ├── cat2.gif │ │ ├── cats_icon.gif │ │ ├── dog1.gif │ │ ├── dog2.gif │ │ ├── dog3.gif │ │ ├── dog4.gif │ │ ├── dog5.gif │ │ ├── dog6.gif │ │ ├── dogs.gif │ │ ├── dogs_icon.gif │ │ ├── fish.gif │ │ ├── fish1.gif │ │ ├── fish2.gif │ │ ├── fish3.gif │ │ ├── fish4.gif │ │ ├── fish_icon.gif │ │ ├── lizard1.gif │ │ ├── logo-topbar.gif │ │ ├── reptiles_icon.gif │ │ ├── separator.gif │ │ ├── sm_birds.gif │ │ ├── sm_cats.gif │ │ ├── sm_dogs.gif │ │ ├── sm_fish.gif │ │ ├── sm_reptiles.gif │ │ ├── snake1.gif │ │ └── splash.gif │ └── templates │ ├── 404.html │ ├── account │ ├── add.html │ ├── edit.html │ └── fields.html │ ├── cart │ ├── checkout.html │ └── list.html │ ├── category │ └── list.html │ ├── error.html │ ├── history │ ├── detail.html │ └── list.html │ ├── index.html │ ├── item │ └── detail.html │ ├── layout.html │ ├── order │ └── confirm.html │ ├── product │ └── list.html │ ├── search │ └── list.html │ └── signin │ └── signin.html └── test └── java └── sample └── ApplicationTest.java /.github/workflows/gradle.yml: -------------------------------------------------------------------------------- 1 | name: Java CI with Gradle 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v3 16 | - name: Set up JDK 11 17 | uses: actions/setup-java@v3 18 | with: 19 | distribution: 'zulu' 20 | java-version: 11 21 | - name: Grant execute permission for gradlew 22 | run: chmod +x gradlew 23 | - name: Build with Gradle 24 | run: ./gradlew build 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .apt_generated/ 2 | .gradle/ 3 | .metadata/ 4 | .settings/ 5 | bin/ 6 | build/ 7 | target/ 8 | .classpath 9 | .project 10 | .factorypath 11 | .idea 12 | out 13 | .sdkmanrc 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | https://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | https://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | JPet Store Sample [![Java CI with Gradle](https://github.com/domaframework/spring-boot-jpetstore/workflows/Java%20CI%20with%20Gradle/badge.svg)](https://github.com/domaframework/spring-boot-jpetstore/actions?query=workflow%3A%22Java+CI+with+Gradle%22) 2 | ======================================== 3 | 4 | This sample shows how easy to integrate [Doma][doma] with [Spring Boot][spring-boot] . 5 | 6 | Besides, this sample is useful as a reference to combine the following libraries: 7 | 8 | - Spring Security 9 | - Thymeleaf 10 | - Hibernate Validator 11 | 12 | You need Java 11 or later to build and run this sample. 13 | 14 | Clone 15 | -------- 16 | 17 | ```sh 18 | git clone https://github.com/domaframework/spring-boot-jpetstore.git 19 | ``` 20 | 21 | Run 22 | -------- 23 | 24 | ```sh 25 | cd spring-boot-jpetstore 26 | ``` 27 | 28 | ```sh 29 | ./gradlew bootRun 30 | ``` 31 | 32 | Access 33 | -------- 34 | 35 | ``` 36 | http://localhost:8080/ 37 | ``` 38 | 39 | Edit 40 | -------- 41 | 42 | ### IntelliJ IDEA 43 | 44 | Import this sample as a Gradle project. 45 | 46 | ### Eclipse 47 | 48 | Generate all Eclipse files with Gradle. 49 | 50 | ```sh 51 | ./gradlew eclipse 52 | ``` 53 | 54 | [doma]: https://github.com/domaframework/doma 55 | [spring-boot]: https://github.com/spring-projects/spring-boot 56 | 57 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("java") 3 | id("com.diffplug.eclipse.apt") version "3.40.0" 4 | id("com.diffplug.spotless") version "6.12.0" 5 | id("org.springframework.boot") version "2.7.6" 6 | id("org.domaframework.doma.compile") version "2.0.0" 7 | } 8 | 9 | apply(plugin = "io.spring.dependency-management") 10 | 11 | spotless { 12 | java { 13 | googleJavaFormat("1.7") 14 | } 15 | } 16 | 17 | java { 18 | sourceCompatibility = JavaVersion.VERSION_11 19 | targetCompatibility = JavaVersion.VERSION_11 20 | } 21 | 22 | springBoot { 23 | mainClass.set("sample.Application") 24 | } 25 | 26 | repositories { 27 | mavenCentral() 28 | mavenLocal() 29 | maven(url = "https://repo.spring.io/milestone") 30 | } 31 | 32 | dependencies { 33 | val domaVersion: String by project 34 | val domaSpringBootVersion: String by project 35 | annotationProcessor("org.seasar.doma:doma-processor:${domaVersion}") 36 | implementation("org.springframework.boot:spring-boot-starter-thymeleaf") 37 | implementation("org.springframework.boot:spring-boot-starter-web") 38 | implementation("org.springframework.boot:spring-boot-starter-jdbc") 39 | implementation("org.springframework.boot:spring-boot-starter-security") 40 | implementation("org.springframework.boot:spring-boot-starter-validation") 41 | implementation("org.seasar.doma:doma-core:${domaVersion}") 42 | implementation("org.seasar.doma:doma-slf4j:${domaVersion}") 43 | implementation("org.seasar.doma.boot:doma-spring-boot-starter:${domaSpringBootVersion}") 44 | implementation("com.h2database:h2:2.1.214") 45 | implementation("org.webjars:jquery:3.6.1") 46 | implementation("nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect:3.1.0") 47 | developmentOnly("org.springframework.boot:spring-boot-devtools") 48 | testImplementation("org.springframework.boot:spring-boot-starter-test") { 49 | exclude(group = "org.junit.vintage", module = "junit-vintage-engine") 50 | } 51 | } 52 | 53 | eclipse { 54 | classpath { 55 | file { 56 | whenMerged { 57 | val classpath = this as org.gradle.plugins.ide.eclipse.model.Classpath 58 | classpath.entries.removeAll { 59 | when (it) { 60 | is org.gradle.plugins.ide.eclipse.model.Output -> it.path == ".apt_generated" 61 | else -> false 62 | } 63 | } 64 | } 65 | withXml { 66 | val node = asNode() 67 | node.appendNode("classpathentry", mapOf("kind" to "src", "output" to "bin/main", "path" to ".apt_generated")) 68 | } 69 | } 70 | } 71 | jdt { 72 | javaRuntimeName = "JavaSE-11" 73 | } 74 | } 75 | 76 | tasks { 77 | test { 78 | useJUnitPlatform() 79 | } 80 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | domaVersion=2.53.1 2 | domaSpringBootVersion=1.7.0 -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/domaframework/spring-boot-jpetstore/b7e87c655933a1974d9710154b76235e381ef8fe/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-all.zip 4 | networkTimeout=10000 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | # This is normally unused 84 | # shellcheck disable=SC2034 85 | APP_BASE_NAME=${0##*/} 86 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 87 | 88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | 142 | # Increase the maximum file descriptors if we can. 143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 144 | case $MAX_FD in #( 145 | max*) 146 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 147 | # shellcheck disable=SC3045 148 | MAX_FD=$( ulimit -H -n ) || 149 | warn "Could not query maximum file descriptor limit" 150 | esac 151 | case $MAX_FD in #( 152 | '' | soft) :;; #( 153 | *) 154 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 155 | # shellcheck disable=SC3045 156 | ulimit -n "$MAX_FD" || 157 | warn "Could not set maximum file descriptor limit to $MAX_FD" 158 | esac 159 | fi 160 | 161 | # Collect all arguments for the java command, stacking in reverse order: 162 | # * args from the command line 163 | # * the main class name 164 | # * -classpath 165 | # * -D...appname settings 166 | # * --module-path (only if needed) 167 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 168 | 169 | # For Cygwin or MSYS, switch paths to Windows format before running java 170 | if "$cygwin" || "$msys" ; then 171 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 172 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 173 | 174 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 175 | 176 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 177 | for arg do 178 | if 179 | case $arg in #( 180 | -*) false ;; # don't mess with options #( 181 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 182 | [ -e "$t" ] ;; #( 183 | *) false ;; 184 | esac 185 | then 186 | arg=$( cygpath --path --ignore --mixed "$arg" ) 187 | fi 188 | # Roll the args list around exactly as many times as the number of 189 | # args, so each arg winds up back in the position where it started, but 190 | # possibly modified. 191 | # 192 | # NB: a `for` loop captures its iteration list before it begins, so 193 | # changing the positional parameters here affects neither the number of 194 | # iterations, nor the values presented in `arg`. 195 | shift # remove old arg 196 | set -- "$@" "$arg" # push replacement arg 197 | done 198 | fi 199 | 200 | # Collect all arguments for the java command; 201 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 202 | # shell script including quotes and variable substitutions, so put them in 203 | # double quotes to make sure that they get re-expanded; and 204 | # * put everything else in single quotes, so that it's not re-expanded. 205 | 206 | set -- \ 207 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 208 | -classpath "$CLASSPATH" \ 209 | org.gradle.wrapper.GradleWrapperMain \ 210 | "$@" 211 | 212 | # Stop when "xargs" is not available. 213 | if ! command -v xargs >/dev/null 2>&1 214 | then 215 | die "xargs is not available" 216 | fi 217 | 218 | # Use "xargs" to parse quoted args. 219 | # 220 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 221 | # 222 | # In Bash we could simply go: 223 | # 224 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 225 | # set -- "${ARGS[@]}" "$@" 226 | # 227 | # but POSIX shell has neither arrays nor command substitution, so instead we 228 | # post-process each arg (as a line of input to sed) to backslash-escape any 229 | # character that might be a shell metacharacter, then use eval to reverse 230 | # that process (while maintaining the separation between arguments), and wrap 231 | # the whole thing up as a single "set" statement. 232 | # 233 | # This will of course break if any of these variables contains a newline or 234 | # an unmatched quote. 235 | # 236 | 237 | eval "set -- $( 238 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 239 | xargs -n1 | 240 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 241 | tr '\n' ' ' 242 | )" '"$@"' 243 | 244 | exec "$JAVACMD" "$@" 245 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "github>domaframework/renovate-config" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "spring-boot-jpetstore" 2 | -------------------------------------------------------------------------------- /src/main/java/sample/Application.java: -------------------------------------------------------------------------------- 1 | package sample; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class Application { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(Application.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/sample/ApplicationConfiguration.java: -------------------------------------------------------------------------------- 1 | package sample; 2 | 3 | import org.seasar.doma.jdbc.NoCacheSqlFileRepository; 4 | import org.seasar.doma.jdbc.SqlFileRepository; 5 | import org.springframework.context.MessageSource; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.context.support.ReloadableResourceBundleMessageSource; 9 | import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; 10 | 11 | @Configuration 12 | public class ApplicationConfiguration { 13 | 14 | @Bean 15 | public SqlFileRepository sqlFileRepository() { 16 | return new NoCacheSqlFileRepository(); 17 | } 18 | 19 | @Bean 20 | public LocalValidatorFactoryBean localValidatorFactoryBean() { 21 | var localValidatorFactoryBean = new LocalValidatorFactoryBean(); 22 | localValidatorFactoryBean.setValidationMessageSource(messageSource()); 23 | return localValidatorFactoryBean; 24 | } 25 | 26 | @Bean 27 | public MessageSource messageSource() { 28 | var messageSource = new ReloadableResourceBundleMessageSource(); 29 | messageSource.setBasename("classpath:ValidationMessages"); 30 | messageSource.setDefaultEncoding("UTF-8"); 31 | return messageSource; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/sample/entity/Account.java: -------------------------------------------------------------------------------- 1 | package sample.entity; 2 | 3 | import java.io.Serializable; 4 | import org.seasar.doma.Column; 5 | import org.seasar.doma.Entity; 6 | import org.seasar.doma.Id; 7 | import org.seasar.doma.Metamodel; 8 | import org.seasar.doma.Transient; 9 | 10 | @Entity(metamodel = @Metamodel) 11 | public class Account implements Serializable { 12 | 13 | private static final long serialVersionUID = 1L; 14 | 15 | @Id 16 | @Column(name = "USERID") 17 | private String username; 18 | 19 | private String email; 20 | 21 | private String firstName; 22 | 23 | private String lastName; 24 | 25 | private String status; 26 | 27 | @Column(name = "ADDR1") 28 | private String address1; 29 | 30 | @Column(name = "ADDR2") 31 | private String address2; 32 | 33 | private String city; 34 | 35 | private String state; 36 | 37 | private String zip; 38 | 39 | private String country; 40 | 41 | private String phone; 42 | 43 | @Transient private Profile profile = new Profile(); 44 | @Transient private Signon signon = new Signon(); 45 | @Transient private BannerData bannerdata = new BannerData(); 46 | 47 | public String getUsername() { 48 | return username; 49 | } 50 | 51 | public void setUsername(String username) { 52 | this.username = username; 53 | profile.setUsername(username); 54 | signon.setUsername(username); 55 | } 56 | 57 | public String getPassword() { 58 | return signon.getPassword(); 59 | } 60 | 61 | public void setPassword(String password) { 62 | signon.setPassword(password); 63 | } 64 | 65 | public String getEmail() { 66 | return email; 67 | } 68 | 69 | public void setEmail(String email) { 70 | this.email = email; 71 | } 72 | 73 | public String getFirstName() { 74 | return firstName; 75 | } 76 | 77 | public void setFirstName(String firstName) { 78 | this.firstName = firstName; 79 | } 80 | 81 | public String getLastName() { 82 | return lastName; 83 | } 84 | 85 | public void setLastName(String lastName) { 86 | this.lastName = lastName; 87 | } 88 | 89 | public String getStatus() { 90 | return status; 91 | } 92 | 93 | public void setStatus(String status) { 94 | this.status = status; 95 | } 96 | 97 | public String getAddress1() { 98 | return address1; 99 | } 100 | 101 | public void setAddress1(String address1) { 102 | this.address1 = address1; 103 | } 104 | 105 | public String getAddress2() { 106 | return address2; 107 | } 108 | 109 | public void setAddress2(String address2) { 110 | this.address2 = address2; 111 | } 112 | 113 | public String getCity() { 114 | return city; 115 | } 116 | 117 | public void setCity(String city) { 118 | this.city = city; 119 | } 120 | 121 | public String getState() { 122 | return state; 123 | } 124 | 125 | public void setState(String state) { 126 | this.state = state; 127 | } 128 | 129 | public String getZip() { 130 | return zip; 131 | } 132 | 133 | public void setZip(String zip) { 134 | this.zip = zip; 135 | } 136 | 137 | public String getCountry() { 138 | return country; 139 | } 140 | 141 | public void setCountry(String country) { 142 | this.country = country; 143 | } 144 | 145 | public String getPhone() { 146 | return phone; 147 | } 148 | 149 | public void setPhone(String phone) { 150 | this.phone = phone; 151 | } 152 | 153 | public String getFavouriteCategoryId() { 154 | return profile.getFavouriteCategoryId(); 155 | } 156 | 157 | public void setFavouriteCategoryId(String favouriteCategoryId) { 158 | profile.setFavouriteCategoryId(favouriteCategoryId); 159 | } 160 | 161 | public String getLanguagePreference() { 162 | return profile.getLanguagePreference(); 163 | } 164 | 165 | public void setLanguagePreference(String languagePreference) { 166 | profile.setLanguagePreference(languagePreference); 167 | } 168 | 169 | public boolean isListOption() { 170 | return profile.isListOption(); 171 | } 172 | 173 | public void setListOption(boolean listOption) { 174 | profile.setListOption(listOption); 175 | } 176 | 177 | public boolean isBannerOption() { 178 | return profile.isBannerOption(); 179 | } 180 | 181 | public void setBannerOption(boolean bannerOption) { 182 | profile.setBannerOption(bannerOption); 183 | } 184 | 185 | public String getBannerName() { 186 | return bannerdata.getBannerName(); 187 | } 188 | 189 | public void setBannerName(String bannerName) { 190 | bannerdata.setBannerName(bannerName); 191 | } 192 | 193 | public Profile getProfile() { 194 | return profile; 195 | } 196 | 197 | public void setProfile(Profile profile) { 198 | this.profile = profile; 199 | } 200 | 201 | public Signon getSignon() { 202 | return signon; 203 | } 204 | 205 | public void setSignon(Signon signon) { 206 | this.signon = signon; 207 | } 208 | 209 | public BannerData getBannerData() { 210 | return bannerdata; 211 | } 212 | 213 | public void setBannerData(BannerData bannerdata) { 214 | this.bannerdata = bannerdata; 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /src/main/java/sample/entity/Amount.java: -------------------------------------------------------------------------------- 1 | package sample.entity; 2 | 3 | import java.io.Serializable; 4 | import java.math.BigDecimal; 5 | import org.seasar.doma.Domain; 6 | 7 | @Domain(valueType = BigDecimal.class) 8 | public class Amount implements Serializable { 9 | 10 | private static final long serialVersionUID = 1L; 11 | 12 | public static final Amount ZERO = new Amount(BigDecimal.ZERO); 13 | 14 | private final BigDecimal value; 15 | 16 | public Amount(int value) { 17 | this(new BigDecimal(value)); 18 | } 19 | 20 | public Amount(BigDecimal value) { 21 | if (value == null) { 22 | this.value = ZERO.value; 23 | } else { 24 | this.value = value; 25 | } 26 | } 27 | 28 | public BigDecimal getValue() { 29 | return value; 30 | } 31 | 32 | public Amount add(Amount amount) { 33 | return new Amount(value.add(amount.getValue())); 34 | } 35 | 36 | public Amount add(int quantity) { 37 | return new Amount(value.add(new BigDecimal(quantity))); 38 | } 39 | 40 | public Amount multiply(Amount amount) { 41 | return new Amount(value.multiply(amount.getValue())); 42 | } 43 | 44 | public Amount multiply(int quantity) { 45 | return new Amount(value.multiply(new BigDecimal(quantity))); 46 | } 47 | 48 | @Override 49 | public String toString() { 50 | return value.toPlainString(); 51 | } 52 | 53 | @Override 54 | public int hashCode() { 55 | final var prime = 31; 56 | var result = 1; 57 | result = prime * result + ((value == null) ? 0 : value.hashCode()); 58 | return result; 59 | } 60 | 61 | @Override 62 | public boolean equals(Object obj) { 63 | if (this == obj) { 64 | return true; 65 | } 66 | if (obj == null) { 67 | return false; 68 | } 69 | if (getClass() != obj.getClass()) { 70 | return false; 71 | } 72 | var other = (Amount) obj; 73 | if (value == null) { 74 | if (other.value != null) { 75 | return false; 76 | } 77 | } else if (!value.equals(other.value)) { 78 | return false; 79 | } 80 | return true; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/sample/entity/BannerData.java: -------------------------------------------------------------------------------- 1 | package sample.entity; 2 | 3 | import org.seasar.doma.Column; 4 | import org.seasar.doma.Entity; 5 | import org.seasar.doma.Id; 6 | import org.seasar.doma.Metamodel; 7 | import org.seasar.doma.Table; 8 | 9 | @Entity(metamodel = @Metamodel) 10 | @Table(name = "BANNERDATA") 11 | public class BannerData { 12 | 13 | @Id 14 | @Column(name = "FAVCATEGORY") 15 | private String favouriteCategoryId; 16 | 17 | @Column(name = "BANNERNAME") 18 | private String bannerName; 19 | 20 | public String getFavouriteCategoryId() { 21 | return favouriteCategoryId; 22 | } 23 | 24 | public void setFavouriteCategoryId(String favouriteCategoryId) { 25 | this.favouriteCategoryId = favouriteCategoryId; 26 | } 27 | 28 | public String getBannerName() { 29 | return bannerName; 30 | } 31 | 32 | public void setBannerName(String bannerName) { 33 | this.bannerName = bannerName; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/sample/entity/Category.java: -------------------------------------------------------------------------------- 1 | package sample.entity; 2 | 3 | import java.io.Serializable; 4 | import org.seasar.doma.Column; 5 | import org.seasar.doma.Entity; 6 | import org.seasar.doma.Id; 7 | import org.seasar.doma.Metamodel; 8 | 9 | @Entity(metamodel = @Metamodel) 10 | public class Category implements Serializable { 11 | 12 | private static final long serialVersionUID = 1L; 13 | 14 | @Id 15 | @Column(name = "CATID") 16 | private String categoryId; 17 | 18 | private String name; 19 | 20 | @Column(name = "DESCN") 21 | private String description; 22 | 23 | @Override 24 | public String toString() { 25 | return "Category [categoryId=" 26 | + categoryId 27 | + ", name=" 28 | + name 29 | + ", description=" 30 | + description 31 | + "]"; 32 | } 33 | 34 | public String getCategoryId() { 35 | return categoryId; 36 | } 37 | 38 | public void setCategoryId(String categoryId) { 39 | this.categoryId = categoryId; 40 | } 41 | 42 | public String getName() { 43 | return name; 44 | } 45 | 46 | public void setName(String name) { 47 | this.name = name; 48 | } 49 | 50 | public String getDescription() { 51 | return description; 52 | } 53 | 54 | public void setDescription(String description) { 55 | this.description = description; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/sample/entity/Inventory.java: -------------------------------------------------------------------------------- 1 | package sample.entity; 2 | 3 | import org.seasar.doma.Column; 4 | import org.seasar.doma.Entity; 5 | import org.seasar.doma.Id; 6 | import org.seasar.doma.Metamodel; 7 | import org.seasar.doma.Table; 8 | 9 | @Entity(metamodel = @Metamodel) 10 | @Table(name = "INVENTORY") 11 | public class Inventory { 12 | 13 | @Id 14 | @Column(name = "ITEMID") 15 | private String itemId; 16 | 17 | @Column(name = "QTY") 18 | private Integer quantity; 19 | 20 | public String getItemId() { 21 | return itemId; 22 | } 23 | 24 | public void setItemId(String itemId) { 25 | this.itemId = itemId; 26 | } 27 | 28 | public Integer getQuantity() { 29 | return quantity; 30 | } 31 | 32 | public void setQuantity(Integer quantity) { 33 | this.quantity = quantity; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/sample/entity/Item.java: -------------------------------------------------------------------------------- 1 | package sample.entity; 2 | 3 | import java.io.Serializable; 4 | import java.math.BigDecimal; 5 | import org.seasar.doma.Column; 6 | import org.seasar.doma.Entity; 7 | import org.seasar.doma.Id; 8 | import org.seasar.doma.Metamodel; 9 | import org.seasar.doma.Transient; 10 | 11 | @Entity(metamodel = @Metamodel) 12 | public class Item implements Serializable { 13 | 14 | private static final long serialVersionUID = 1L; 15 | 16 | @Id private String itemId; 17 | 18 | @Column(name = "PRODUCTID") 19 | private String productId; 20 | 21 | private Amount listPrice; 22 | 23 | private BigDecimal unitCost; 24 | 25 | @Column(name = "SUPPLIER") 26 | private int supplierId; 27 | 28 | private String status; 29 | 30 | @Column(name = "ATTR1") 31 | private String attribute1; 32 | 33 | @Column(name = "ATTR2") 34 | private String attribute2; 35 | 36 | @Column(name = "ATTR3") 37 | private String attribute3; 38 | 39 | @Column(name = "ATTR4") 40 | private String attribute4; 41 | 42 | @Column(name = "ATTR5") 43 | private String attribute5; 44 | 45 | @Transient private Inventory inventory = new Inventory(); 46 | 47 | @Transient private Product product = new Product(); 48 | 49 | public String getItemId() { 50 | return itemId; 51 | } 52 | 53 | public void setItemId(String itemId) { 54 | this.itemId = itemId; 55 | } 56 | 57 | public String getProductId() { 58 | return productId; 59 | } 60 | 61 | public void setProductId(String productId) { 62 | this.productId = productId; 63 | } 64 | 65 | public String getProductName() { 66 | return product.getName(); 67 | } 68 | 69 | public void setProductName(String productName) { 70 | product.setName(productName); 71 | } 72 | 73 | public String getProductCategoryId() { 74 | return product.getCategoryId(); 75 | } 76 | 77 | public void setProductCategoryId(String productCategoryId) { 78 | product.setCategoryId(productCategoryId); 79 | } 80 | 81 | public String getProductDescription() { 82 | return product.getDescription(); 83 | } 84 | 85 | public void setProductDescription(String productDescription) { 86 | product.setDescription(productDescription); 87 | } 88 | 89 | public Amount getListPrice() { 90 | return listPrice; 91 | } 92 | 93 | public void setListPrice(Amount listPrice) { 94 | this.listPrice = listPrice; 95 | } 96 | 97 | public BigDecimal getUnitCost() { 98 | return unitCost; 99 | } 100 | 101 | public void setUnitCost(BigDecimal unitCost) { 102 | this.unitCost = unitCost; 103 | } 104 | 105 | public int getSupplierId() { 106 | return supplierId; 107 | } 108 | 109 | public void setSupplierId(int supplierId) { 110 | this.supplierId = supplierId; 111 | } 112 | 113 | public String getStatus() { 114 | return status; 115 | } 116 | 117 | public void setStatus(String status) { 118 | this.status = status; 119 | } 120 | 121 | public String getAttribute1() { 122 | return attribute1; 123 | } 124 | 125 | public void setAttribute1(String attribute1) { 126 | this.attribute1 = attribute1; 127 | } 128 | 129 | public String getAttribute2() { 130 | return attribute2; 131 | } 132 | 133 | public void setAttribute2(String attribute2) { 134 | this.attribute2 = attribute2; 135 | } 136 | 137 | public String getAttribute3() { 138 | return attribute3; 139 | } 140 | 141 | public void setAttribute3(String attribute3) { 142 | this.attribute3 = attribute3; 143 | } 144 | 145 | public String getAttribute4() { 146 | return attribute4; 147 | } 148 | 149 | public void setAttribute4(String attribute4) { 150 | this.attribute4 = attribute4; 151 | } 152 | 153 | public String getAttribute5() { 154 | return attribute5; 155 | } 156 | 157 | public void setAttribute5(String attribute5) { 158 | this.attribute5 = attribute5; 159 | } 160 | 161 | public Integer getQuantity() { 162 | return inventory.getQuantity(); 163 | } 164 | 165 | public void setQuantity(Integer quantity) { 166 | inventory.setQuantity(quantity); 167 | } 168 | 169 | public Inventory getInventory() { 170 | return inventory; 171 | } 172 | 173 | public void setInventory(Inventory inventory) { 174 | this.inventory = inventory; 175 | } 176 | 177 | public Product getProduct() { 178 | return product; 179 | } 180 | 181 | public void setProduct(Product product) { 182 | this.product = product; 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /src/main/java/sample/entity/Order.java: -------------------------------------------------------------------------------- 1 | package sample.entity; 2 | 3 | import java.io.Serializable; 4 | import java.time.LocalDateTime; 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | import org.seasar.doma.Column; 8 | import org.seasar.doma.Entity; 9 | import org.seasar.doma.GeneratedValue; 10 | import org.seasar.doma.GenerationType; 11 | import org.seasar.doma.Id; 12 | import org.seasar.doma.Metamodel; 13 | import org.seasar.doma.SequenceGenerator; 14 | import org.seasar.doma.Table; 15 | import org.seasar.doma.Transient; 16 | 17 | @Entity(metamodel = @Metamodel) 18 | @Table(name = "ORDERS") 19 | public class Order implements Serializable { 20 | 21 | private static final long serialVersionUID = 1L; 22 | 23 | @Id 24 | @GeneratedValue(strategy = GenerationType.SEQUENCE) 25 | @SequenceGenerator(sequence = "ORDERS_SEQ", initialValue = 1001, allocationSize = 10) 26 | private Integer orderId; 27 | 28 | @Column(name = "USERID") 29 | private String username; 30 | 31 | private LocalDateTime orderDate; 32 | 33 | @Column(name = "SHIPADDR1") 34 | private String shipAddress1; 35 | 36 | @Column(name = "SHIPADDR2") 37 | private String shipAddress2; 38 | 39 | private String shipCity; 40 | 41 | private String shipState; 42 | 43 | private String shipZip; 44 | 45 | private String shipCountry; 46 | 47 | @Column(name = "BILLADDR1") 48 | private String billAddress1; 49 | 50 | @Column(name = "BILLADDR2") 51 | private String billAddress2; 52 | 53 | private String billCity; 54 | 55 | private String billState; 56 | 57 | private String billZip; 58 | 59 | private String billCountry; 60 | 61 | private String courier; 62 | 63 | private Amount totalPrice; 64 | 65 | private String billToFirstName; 66 | 67 | private String billToLastName; 68 | 69 | private String shipToFirstName; 70 | 71 | private String shipToLastName; 72 | 73 | private String creditCard; 74 | 75 | @Column(name = "EXPRDATE") 76 | private String expiryDate; 77 | 78 | private String cardType; 79 | 80 | private String locale; 81 | 82 | @Transient private OrderStatus orderStatus = new OrderStatus(); 83 | 84 | @Transient private final List lineItemList = new ArrayList<>(); 85 | 86 | public Integer getOrderId() { 87 | return orderId; 88 | } 89 | 90 | public void setOrderId(Integer orderId) { 91 | this.orderId = orderId; 92 | } 93 | 94 | public String getUsername() { 95 | return username; 96 | } 97 | 98 | public void setUsername(String username) { 99 | this.username = username; 100 | } 101 | 102 | public LocalDateTime getOrderDate() { 103 | return orderDate; 104 | } 105 | 106 | public void setOrderDate(LocalDateTime orderDate) { 107 | this.orderDate = orderDate; 108 | orderStatus.setTimestamp(orderDate.toLocalDate()); 109 | } 110 | 111 | public String getShipAddress1() { 112 | return shipAddress1; 113 | } 114 | 115 | public void setShipAddress1(String shipAddress1) { 116 | this.shipAddress1 = shipAddress1; 117 | } 118 | 119 | public String getShipAddress2() { 120 | return shipAddress2; 121 | } 122 | 123 | public void setShipAddress2(String shipAddress2) { 124 | this.shipAddress2 = shipAddress2; 125 | } 126 | 127 | public String getShipCity() { 128 | return shipCity; 129 | } 130 | 131 | public void setShipCity(String shipCity) { 132 | this.shipCity = shipCity; 133 | } 134 | 135 | public String getShipState() { 136 | return shipState; 137 | } 138 | 139 | public void setShipState(String shipState) { 140 | this.shipState = shipState; 141 | } 142 | 143 | public String getShipZip() { 144 | return shipZip; 145 | } 146 | 147 | public void setShipZip(String shipZip) { 148 | this.shipZip = shipZip; 149 | } 150 | 151 | public String getShipCountry() { 152 | return shipCountry; 153 | } 154 | 155 | public void setShipCountry(String shipCountry) { 156 | this.shipCountry = shipCountry; 157 | } 158 | 159 | public String getBillAddress1() { 160 | return billAddress1; 161 | } 162 | 163 | public void setBillAddress1(String billAddress1) { 164 | this.billAddress1 = billAddress1; 165 | } 166 | 167 | public String getBillAddress2() { 168 | return billAddress2; 169 | } 170 | 171 | public void setBillAddress2(String billAddress2) { 172 | this.billAddress2 = billAddress2; 173 | } 174 | 175 | public String getBillCity() { 176 | return billCity; 177 | } 178 | 179 | public void setBillCity(String billCity) { 180 | this.billCity = billCity; 181 | } 182 | 183 | public String getBillState() { 184 | return billState; 185 | } 186 | 187 | public void setBillState(String billState) { 188 | this.billState = billState; 189 | } 190 | 191 | public String getBillZip() { 192 | return billZip; 193 | } 194 | 195 | public void setBillZip(String billZip) { 196 | this.billZip = billZip; 197 | } 198 | 199 | public String getBillCountry() { 200 | return billCountry; 201 | } 202 | 203 | public void setBillCountry(String billCountry) { 204 | this.billCountry = billCountry; 205 | } 206 | 207 | public String getCourier() { 208 | return courier; 209 | } 210 | 211 | public void setCourier(String courier) { 212 | this.courier = courier; 213 | } 214 | 215 | public Amount getTotalPrice() { 216 | return totalPrice; 217 | } 218 | 219 | public void setTotalPrice(Amount totalPrice) { 220 | this.totalPrice = totalPrice; 221 | } 222 | 223 | public String getBillToFirstName() { 224 | return billToFirstName; 225 | } 226 | 227 | public void setBillToFirstName(String billToFirstName) { 228 | this.billToFirstName = billToFirstName; 229 | } 230 | 231 | public String getBillToLastName() { 232 | return billToLastName; 233 | } 234 | 235 | public void setBillToLastName(String billToLastName) { 236 | this.billToLastName = billToLastName; 237 | } 238 | 239 | public String getShipToFirstName() { 240 | return shipToFirstName; 241 | } 242 | 243 | public void setShipToFirstName(String shipToFirstName) { 244 | this.shipToFirstName = shipToFirstName; 245 | } 246 | 247 | public String getShipToLastName() { 248 | return shipToLastName; 249 | } 250 | 251 | public void setShipToLastName(String shipToLastName) { 252 | this.shipToLastName = shipToLastName; 253 | } 254 | 255 | public String getCreditCard() { 256 | return creditCard; 257 | } 258 | 259 | public void setCreditCard(String creditCard) { 260 | this.creditCard = creditCard; 261 | } 262 | 263 | public String getExpiryDate() { 264 | return expiryDate; 265 | } 266 | 267 | public void setExpiryDate(String expiryDate) { 268 | this.expiryDate = expiryDate; 269 | } 270 | 271 | public String getCardType() { 272 | return cardType; 273 | } 274 | 275 | public void setCardType(String cardType) { 276 | this.cardType = cardType; 277 | } 278 | 279 | public String getLocale() { 280 | return locale; 281 | } 282 | 283 | public void setLocale(String locale) { 284 | this.locale = locale; 285 | } 286 | 287 | public String getStatus() { 288 | return orderStatus.getStatus(); 289 | } 290 | 291 | public void setStatus(String status) { 292 | orderStatus.setStatus(status); 293 | } 294 | 295 | public OrderStatus getOrderStatus() { 296 | orderStatus.setOrderId(orderId); 297 | orderStatus.setLineNumber(orderId); 298 | return orderStatus; 299 | } 300 | 301 | public void setOrderStatus(OrderStatus orderStatus) { 302 | this.orderStatus = orderStatus; 303 | } 304 | 305 | public void addLineItem(OrderLineItem lineItem) { 306 | lineItemList.add(lineItem); 307 | } 308 | 309 | public List getLineItemList() { 310 | lineItemList.forEach(it -> it.setOrderId(getOrderId())); 311 | return lineItemList; 312 | } 313 | } 314 | -------------------------------------------------------------------------------- /src/main/java/sample/entity/OrderLineItem.java: -------------------------------------------------------------------------------- 1 | package sample.entity; 2 | 3 | import java.io.Serializable; 4 | import org.seasar.doma.Column; 5 | import org.seasar.doma.Entity; 6 | import org.seasar.doma.Id; 7 | import org.seasar.doma.Metamodel; 8 | import org.seasar.doma.Table; 9 | import org.seasar.doma.Transient; 10 | 11 | @Entity(metamodel = @Metamodel) 12 | @Table(name = "LINEITEM") 13 | public class OrderLineItem implements Serializable { 14 | 15 | private static final long serialVersionUID = 1L; 16 | 17 | @Id private Integer orderId; 18 | 19 | @Id 20 | @Column(name = "LINENUM") 21 | private int lineNumber; 22 | 23 | private int quantity; 24 | 25 | private String itemId; 26 | 27 | private Amount unitPrice; 28 | 29 | @Transient private Item item = new Item(); 30 | 31 | public Integer getOrderId() { 32 | return orderId; 33 | } 34 | 35 | public void setOrderId(Integer orderId) { 36 | this.orderId = orderId; 37 | } 38 | 39 | public int getLineNumber() { 40 | return lineNumber; 41 | } 42 | 43 | public void setLineNumber(int lineNumber) { 44 | this.lineNumber = lineNumber; 45 | } 46 | 47 | public int getQuantity() { 48 | return quantity; 49 | } 50 | 51 | public void setQuantity(int quantity) { 52 | this.quantity = quantity; 53 | } 54 | 55 | public String getItemId() { 56 | return itemId; 57 | } 58 | 59 | public void setItemId(String itemId) { 60 | this.itemId = itemId; 61 | } 62 | 63 | public Amount getUnitPrice() { 64 | return unitPrice; 65 | } 66 | 67 | public void setUnitPrice(Amount unitPrice) { 68 | this.unitPrice = unitPrice; 69 | } 70 | 71 | public Amount getListPrice() { 72 | return item.getListPrice(); 73 | } 74 | 75 | public String getProductName() { 76 | return item.getProductName(); 77 | } 78 | 79 | public String getAttribute1() { 80 | return item.getAttribute1(); 81 | } 82 | 83 | public String getAttribute2() { 84 | return item.getAttribute2(); 85 | } 86 | 87 | public String getAttribute3() { 88 | return item.getAttribute3(); 89 | } 90 | 91 | public String getAttribute4() { 92 | return item.getAttribute4(); 93 | } 94 | 95 | public String getAttribute5() { 96 | return item.getAttribute5(); 97 | } 98 | 99 | public Amount getTotal() { 100 | return getListPrice().multiply(quantity); 101 | } 102 | 103 | public Item getItem() { 104 | return item; 105 | } 106 | 107 | public void setItem(Item item) { 108 | this.item = item; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/main/java/sample/entity/OrderStatus.java: -------------------------------------------------------------------------------- 1 | package sample.entity; 2 | 3 | import java.time.LocalDate; 4 | import org.seasar.doma.Column; 5 | import org.seasar.doma.Entity; 6 | import org.seasar.doma.Id; 7 | import org.seasar.doma.Metamodel; 8 | import org.seasar.doma.Table; 9 | 10 | @Entity(metamodel = @Metamodel) 11 | @Table(name = "ORDERSTATUS") 12 | public class OrderStatus { 13 | 14 | @Id 15 | @Column(name = "ORDERID") 16 | private Integer orderId; 17 | 18 | @Id 19 | @Column(name = "LINENUM") 20 | private Integer lineNumber; 21 | 22 | @Column(name = "TIMESTAMP") 23 | private LocalDate timestamp; 24 | 25 | @Column(name = "STATUS") 26 | private String status; 27 | 28 | public Integer getOrderId() { 29 | return orderId; 30 | } 31 | 32 | public void setOrderId(Integer orderId) { 33 | this.orderId = orderId; 34 | } 35 | 36 | public Integer getLineNumber() { 37 | return lineNumber; 38 | } 39 | 40 | public void setLineNumber(Integer lineNumber) { 41 | this.lineNumber = lineNumber; 42 | } 43 | 44 | public LocalDate getTimestamp() { 45 | return timestamp; 46 | } 47 | 48 | public void setTimestamp(LocalDate timestamp) { 49 | this.timestamp = timestamp; 50 | } 51 | 52 | public String getStatus() { 53 | return status; 54 | } 55 | 56 | public void setStatus(String status) { 57 | this.status = status; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/sample/entity/Product.java: -------------------------------------------------------------------------------- 1 | package sample.entity; 2 | 3 | import java.io.Serializable; 4 | import org.seasar.doma.Column; 5 | import org.seasar.doma.Entity; 6 | import org.seasar.doma.Id; 7 | import org.seasar.doma.Metamodel; 8 | 9 | @Entity(metamodel = @Metamodel) 10 | public class Product implements Serializable { 11 | 12 | private static final long serialVersionUID = 1L; 13 | 14 | @Id private String productId; 15 | 16 | @Column(name = "CATEGORY") 17 | private String categoryId; 18 | 19 | private String name; 20 | 21 | @Column(name = "DESCN") 22 | private String description; 23 | 24 | @Override 25 | public String toString() { 26 | return "Product [productId=" 27 | + productId 28 | + ", categoryId=" 29 | + categoryId 30 | + ", name=" 31 | + name 32 | + ", description=" 33 | + description 34 | + "]"; 35 | } 36 | 37 | public String getProductId() { 38 | return productId; 39 | } 40 | 41 | public void setProductId(String productId) { 42 | this.productId = productId; 43 | } 44 | 45 | public String getCategoryId() { 46 | return categoryId; 47 | } 48 | 49 | public void setCategoryId(String categoryId) { 50 | this.categoryId = categoryId; 51 | } 52 | 53 | public String getName() { 54 | return name; 55 | } 56 | 57 | public void setName(String name) { 58 | this.name = name; 59 | } 60 | 61 | public String getDescription() { 62 | return description; 63 | } 64 | 65 | public void setDescription(String description) { 66 | this.description = description; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/sample/entity/Profile.java: -------------------------------------------------------------------------------- 1 | package sample.entity; 2 | 3 | import java.io.Serializable; 4 | import org.seasar.doma.Column; 5 | import org.seasar.doma.Entity; 6 | import org.seasar.doma.Id; 7 | import org.seasar.doma.Metamodel; 8 | 9 | @Entity(metamodel = @Metamodel) 10 | public class Profile implements Serializable { 11 | 12 | private static final long serialVersionUID = 1L; 13 | 14 | @Id 15 | @Column(name = "USERID") 16 | private String username; 17 | 18 | @Column(name = "FAVCATEGORY") 19 | private String favouriteCategoryId; 20 | 21 | @Column(name = "LANGPREF") 22 | private String languagePreference; 23 | 24 | @Column(name = "MYLISTOPT") 25 | private boolean listOption; 26 | 27 | @Column(name = "BANNEROPT") 28 | private boolean bannerOption; 29 | 30 | @Override 31 | public String toString() { 32 | return "Profile [username=" 33 | + username 34 | + ", favouriteCategoryId=" 35 | + favouriteCategoryId 36 | + ", languagePreference=" 37 | + languagePreference 38 | + ", listOption=" 39 | + listOption 40 | + ", bannerOption=" 41 | + bannerOption 42 | + "]"; 43 | } 44 | 45 | public String getUsername() { 46 | return username; 47 | } 48 | 49 | public void setUsername(String username) { 50 | this.username = username; 51 | } 52 | 53 | public String getFavouriteCategoryId() { 54 | return favouriteCategoryId; 55 | } 56 | 57 | public void setFavouriteCategoryId(String favouriteCategoryId) { 58 | this.favouriteCategoryId = favouriteCategoryId; 59 | } 60 | 61 | public String getLanguagePreference() { 62 | return languagePreference; 63 | } 64 | 65 | public void setLanguagePreference(String languagePreference) { 66 | this.languagePreference = languagePreference; 67 | } 68 | 69 | public boolean isListOption() { 70 | return listOption; 71 | } 72 | 73 | public void setListOption(boolean listOption) { 74 | this.listOption = listOption; 75 | } 76 | 77 | public boolean isBannerOption() { 78 | return bannerOption; 79 | } 80 | 81 | public void setBannerOption(boolean bannerOption) { 82 | this.bannerOption = bannerOption; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/sample/entity/Signon.java: -------------------------------------------------------------------------------- 1 | package sample.entity; 2 | 3 | import java.io.Serializable; 4 | import org.seasar.doma.Entity; 5 | import org.seasar.doma.Id; 6 | import org.seasar.doma.Metamodel; 7 | 8 | @Entity(metamodel = @Metamodel) 9 | public class Signon implements Serializable { 10 | 11 | private static final long serialVersionUID = 1L; 12 | 13 | @Id private String username; 14 | 15 | private String password; 16 | 17 | @Override 18 | public String toString() { 19 | return "Signon [username=" + username + ", password=" + password + "]"; 20 | } 21 | 22 | public String getUsername() { 23 | return username; 24 | } 25 | 26 | public void setUsername(String username) { 27 | this.username = username; 28 | } 29 | 30 | public String getPassword() { 31 | return password; 32 | } 33 | 34 | public void setPassword(String password) { 35 | this.password = password; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/sample/formatter/AmountFormatter.java: -------------------------------------------------------------------------------- 1 | package sample.formatter; 2 | 3 | import java.math.BigDecimal; 4 | import java.text.ParseException; 5 | import java.util.Locale; 6 | import org.springframework.format.Formatter; 7 | import org.springframework.format.number.NumberStyleFormatter; 8 | import sample.entity.Amount; 9 | 10 | public class AmountFormatter implements Formatter { 11 | 12 | private final NumberStyleFormatter formatter; 13 | 14 | public AmountFormatter() { 15 | formatter = new NumberStyleFormatter("$#,##0.00"); 16 | } 17 | 18 | @Override 19 | public String print(Amount amount, Locale locale) { 20 | return formatter.print(amount.getValue(), locale); 21 | } 22 | 23 | @Override 24 | public Amount parse(String text, Locale locale) throws ParseException { 25 | var value = (BigDecimal) formatter.parse(text, locale); 26 | return new Amount(value); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/sample/formatter/LocalDateTimeFormatter.java: -------------------------------------------------------------------------------- 1 | package sample.formatter; 2 | 3 | import java.time.LocalDateTime; 4 | import java.time.format.DateTimeFormatter; 5 | import java.util.Locale; 6 | import org.springframework.format.Formatter; 7 | 8 | public class LocalDateTimeFormatter implements Formatter { 9 | 10 | @Override 11 | public String print(LocalDateTime temporal, Locale locale) { 12 | var formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); 13 | return formatter.format(temporal); 14 | } 15 | 16 | @Override 17 | public LocalDateTime parse(String text, Locale locale) { 18 | return LocalDateTime.parse(text); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/sample/model/Cart.java: -------------------------------------------------------------------------------- 1 | package sample.model; 2 | 3 | import java.io.Serializable; 4 | import java.util.ArrayList; 5 | import java.util.HashMap; 6 | import java.util.List; 7 | import java.util.Map; 8 | import org.springframework.context.annotation.Scope; 9 | import org.springframework.context.annotation.ScopedProxyMode; 10 | import org.springframework.stereotype.Component; 11 | import sample.entity.Amount; 12 | import sample.entity.Item; 13 | 14 | @Component 15 | @Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS) 16 | public class Cart implements Serializable { 17 | 18 | private static final long serialVersionUID = 1L; 19 | 20 | private final Map itemMap = new HashMap<>(); 21 | 22 | private final List itemList = new ArrayList<>(); 23 | 24 | public List getCartItemList() { 25 | return itemList; 26 | } 27 | 28 | public CartItem getCartItem(String itemId) { 29 | return itemMap.get(itemId); 30 | } 31 | 32 | public int getNumberOfItems() { 33 | return itemList.size(); 34 | } 35 | 36 | public boolean containsItemId(String itemId) { 37 | return itemMap.containsKey(itemId); 38 | } 39 | 40 | public void addItem(Item item, boolean isInStock) { 41 | var cartItem = itemMap.get(item.getItemId()); 42 | if (cartItem == null) { 43 | cartItem = new CartItem(); 44 | cartItem.setItem(item); 45 | cartItem.setQuantity(0); 46 | cartItem.setInStock(isInStock); 47 | itemMap.put(item.getItemId(), cartItem); 48 | itemList.add(cartItem); 49 | } 50 | cartItem.incrementQuantity(); 51 | } 52 | 53 | public void removeItemById(String itemId) { 54 | var cartItem = itemMap.remove(itemId); 55 | if (cartItem != null) { 56 | itemList.remove(cartItem); 57 | } 58 | } 59 | 60 | public void incrementQuantityByItemId(String itemId) { 61 | var cartItem = itemMap.get(itemId); 62 | cartItem.incrementQuantity(); 63 | } 64 | 65 | public void setQuantityByItemId(String itemId, int quantity) { 66 | var cartItem = itemMap.get(itemId); 67 | cartItem.setQuantity(quantity); 68 | } 69 | 70 | public Amount getSubTotal() { 71 | var subTotal = Amount.ZERO; 72 | for (var cartItem : itemList) { 73 | var item = cartItem.getItem(); 74 | var listPrice = item.getListPrice(); 75 | subTotal = subTotal.add(listPrice.multiply(cartItem.getQuantity())); 76 | } 77 | return subTotal; 78 | } 79 | 80 | public boolean isEmpty() { 81 | return itemList.isEmpty(); 82 | } 83 | 84 | public void clear() { 85 | itemMap.clear(); 86 | itemList.clear(); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/sample/model/CartItem.java: -------------------------------------------------------------------------------- 1 | package sample.model; 2 | 3 | import java.io.Serializable; 4 | import sample.entity.Amount; 5 | import sample.entity.Item; 6 | 7 | public class CartItem implements Serializable { 8 | 9 | private static final long serialVersionUID = 1L; 10 | 11 | private Item item; 12 | private int quantity; 13 | private boolean inStock; 14 | private Amount total; 15 | 16 | public boolean isInStock() { 17 | return inStock; 18 | } 19 | 20 | public void setInStock(boolean inStock) { 21 | this.inStock = inStock; 22 | } 23 | 24 | public Amount getTotal() { 25 | return total; 26 | } 27 | 28 | public Item getItem() { 29 | return item; 30 | } 31 | 32 | public void setItem(Item item) { 33 | this.item = item; 34 | calculateTotal(); 35 | } 36 | 37 | public int getQuantity() { 38 | return quantity; 39 | } 40 | 41 | public void setQuantity(int quantity) { 42 | this.quantity = quantity; 43 | calculateTotal(); 44 | } 45 | 46 | public void incrementQuantity() { 47 | quantity++; 48 | calculateTotal(); 49 | } 50 | 51 | private void calculateTotal() { 52 | if (item != null && item.getListPrice() != null) { 53 | total = item.getListPrice().multiply(quantity); 54 | } else { 55 | total = null; 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/sample/repository/AccountRepository.java: -------------------------------------------------------------------------------- 1 | package sample.repository; 2 | 3 | import org.seasar.doma.jdbc.SqlLogType; 4 | import org.seasar.doma.jdbc.criteria.Entityql; 5 | import org.springframework.stereotype.Repository; 6 | import sample.entity.Account; 7 | import sample.entity.Account_; 8 | import sample.entity.BannerData_; 9 | import sample.entity.Profile_; 10 | import sample.entity.Signon_; 11 | 12 | @Repository 13 | public class AccountRepository { 14 | 15 | private final Entityql entityql; 16 | 17 | public AccountRepository(Entityql entityql) { 18 | this.entityql = entityql; 19 | } 20 | 21 | public Account selectAccountByUsername(String username) { 22 | var a = new Account_(); 23 | var p = new Profile_(); 24 | var s = new Signon_(); 25 | var b = new BannerData_(); 26 | 27 | return entityql 28 | .from(a) 29 | .innerJoin(p, on -> on.eq(a.username, p.username)) 30 | .innerJoin(s, on -> on.eq(a.username, s.username)) 31 | .innerJoin(b, on -> on.eq(p.favouriteCategoryId, b.favouriteCategoryId)) 32 | .where(c -> c.eq(a.username, username)) 33 | .associate(a, p, Account::setProfile) 34 | .associate(a, s, Account::setSignon) 35 | .associate(a, b, Account::setBannerData) 36 | .fetchOne(); 37 | } 38 | 39 | public void insertAccount(Account account) { 40 | var a = new Account_(); 41 | var p = new Profile_(); 42 | var s = new Signon_(); 43 | 44 | entityql.insert(a, account).execute(); 45 | 46 | entityql.insert(p, account.getProfile()).execute(); 47 | 48 | entityql 49 | .insert(s, account.getSignon(), settings -> settings.setSqlLogType(SqlLogType.RAW)) 50 | .execute(); 51 | } 52 | 53 | public void updateAccount(Account account) { 54 | var a = new Account_(); 55 | var p = new Profile_(); 56 | var s = new Signon_(); 57 | 58 | entityql.update(a, account).execute(); 59 | 60 | entityql.update(p, account.getProfile()).execute(); 61 | 62 | var signon = account.getSignon(); 63 | if (signon.getPassword() != null && signon.getPassword().length() > 0) { 64 | entityql.update(s, signon, settings -> settings.setSqlLogType(SqlLogType.RAW)).execute(); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/sample/repository/CategoryRepository.java: -------------------------------------------------------------------------------- 1 | package sample.repository; 2 | 3 | import org.seasar.doma.jdbc.criteria.Entityql; 4 | import org.springframework.stereotype.Repository; 5 | import sample.entity.Category; 6 | import sample.entity.Category_; 7 | 8 | @Repository 9 | public class CategoryRepository { 10 | 11 | private final Entityql entityql; 12 | 13 | public CategoryRepository(Entityql entityql) { 14 | this.entityql = entityql; 15 | } 16 | 17 | public Category selectCategory(String categoryId) { 18 | var ca = new Category_(); 19 | 20 | return entityql.from(ca).where(c -> c.eq(ca.categoryId, categoryId)).fetchOne(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/sample/repository/ItemRepository.java: -------------------------------------------------------------------------------- 1 | package sample.repository; 2 | 3 | import static org.seasar.doma.jdbc.criteria.expression.Expressions.sub; 4 | 5 | import java.util.List; 6 | import org.seasar.doma.jdbc.criteria.Entityql; 7 | import org.seasar.doma.jdbc.criteria.NativeSql; 8 | import org.springframework.stereotype.Repository; 9 | import sample.entity.Inventory_; 10 | import sample.entity.Item; 11 | import sample.entity.Item_; 12 | import sample.entity.Product_; 13 | 14 | @Repository 15 | public class ItemRepository { 16 | 17 | private final Entityql entityql; 18 | private final NativeSql nativeSql; 19 | 20 | public ItemRepository(Entityql entityql, NativeSql nativeSql) { 21 | this.entityql = entityql; 22 | this.nativeSql = nativeSql; 23 | } 24 | 25 | public void updateInventoryQuantity(String itemId, Integer increment) { 26 | var i = new Inventory_(); 27 | 28 | nativeSql 29 | .update(i) 30 | .set(c -> c.value(i.quantity, sub(i.quantity, increment))) 31 | .where(c -> c.eq(i.itemId, itemId)) 32 | .execute(); 33 | } 34 | 35 | public Integer selectInventoryQuantity(String itemId) { 36 | var i = new Inventory_(); 37 | 38 | return nativeSql.from(i).where($ -> $.eq(i.itemId, itemId)).select(i.quantity).fetchOne(); 39 | } 40 | 41 | public Item selectItem(String itemId) { 42 | var it = new Item_(); 43 | var in = new Inventory_(); 44 | var p = new Product_(); 45 | 46 | return entityql 47 | .from(it) 48 | .innerJoin(in, on -> on.eq(it.itemId, in.itemId)) 49 | .innerJoin(p, on -> on.eq(it.productId, p.productId)) 50 | .where(c -> c.eq(it.itemId, itemId)) 51 | .associate(it, in, Item::setInventory) 52 | .associate(it, p, Item::setProduct) 53 | .fetchOne(); 54 | } 55 | 56 | public List selectItemsByProduct(String productId) { 57 | var i = new Item_(); 58 | var in = new Inventory_(); 59 | var p = new Product_(); 60 | 61 | return entityql 62 | .from(i) 63 | .innerJoin(in, on -> on.eq(i.itemId, in.itemId)) 64 | .innerJoin(p, on -> on.eq(i.productId, p.productId)) 65 | .where(c -> c.eq(i.productId, productId)) 66 | .associate(i, in, Item::setInventory) 67 | .associate(i, p, Item::setProduct) 68 | .fetch(); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/sample/repository/OrderRepository.java: -------------------------------------------------------------------------------- 1 | package sample.repository; 2 | 3 | import java.util.List; 4 | import org.seasar.doma.jdbc.criteria.Entityql; 5 | import org.springframework.stereotype.Repository; 6 | import sample.entity.Inventory_; 7 | import sample.entity.Item; 8 | import sample.entity.Item_; 9 | import sample.entity.Order; 10 | import sample.entity.OrderLineItem; 11 | import sample.entity.OrderLineItem_; 12 | import sample.entity.OrderStatus_; 13 | import sample.entity.Order_; 14 | import sample.entity.Product_; 15 | 16 | @Repository 17 | public class OrderRepository { 18 | 19 | private final Entityql entityql; 20 | 21 | public OrderRepository(Entityql entityql) { 22 | this.entityql = entityql; 23 | } 24 | 25 | public Order selectOrder(int orderId) { 26 | var order_ = new Order_(); 27 | var orderStatus_ = new OrderStatus_(); 28 | var orderLineItem_ = new OrderLineItem_(); 29 | var item_ = new Item_(); 30 | var inventory_ = new Inventory_(); 31 | var product_ = new Product_(); 32 | 33 | return entityql 34 | .from(order_) 35 | .innerJoin(orderStatus_, on -> on.eq(order_.orderId, orderStatus_.orderId)) 36 | .leftJoin(orderLineItem_, on -> on.eq(order_.orderId, orderLineItem_.orderId)) 37 | .leftJoin(item_, on -> on.eq(orderLineItem_.itemId, item_.itemId)) 38 | .innerJoin(inventory_, on -> on.eq(item_.itemId, inventory_.itemId)) 39 | .innerJoin(product_, on -> on.eq(item_.productId, product_.productId)) 40 | .where(c -> c.eq(order_.orderId, orderId)) 41 | .associate(order_, orderStatus_, Order::setOrderStatus) 42 | .associate(order_, orderLineItem_, Order::addLineItem) 43 | .associate(orderLineItem_, item_, OrderLineItem::setItem) 44 | .associate(item_, inventory_, Item::setInventory) 45 | .associate(item_, product_, Item::setProduct) 46 | .fetchOne(); 47 | } 48 | 49 | public List selectOrdersByUsername(String username) { 50 | var o = new Order_(); 51 | var os = new OrderStatus_(); 52 | 53 | return entityql 54 | .from(o) 55 | .innerJoin(os, on -> on.eq(o.orderId, os.orderId)) 56 | .where(c -> c.eq(o.username, username)) 57 | .orderBy(c -> c.asc(o.orderDate)) 58 | .associate(o, os, Order::setOrderStatus) 59 | .fetch(); 60 | } 61 | 62 | public void insertOrder(Order order) { 63 | var o = new Order_(); 64 | var os = new OrderStatus_(); 65 | var ol = new OrderLineItem_(); 66 | 67 | entityql.insert(o, order).execute(); 68 | 69 | entityql.insert(os, order.getOrderStatus()).execute(); 70 | 71 | entityql.insert(ol, order.getLineItemList()).execute(); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/sample/repository/ProductRepository.java: -------------------------------------------------------------------------------- 1 | package sample.repository; 2 | 3 | import static org.seasar.doma.jdbc.criteria.expression.Expressions.lower; 4 | 5 | import java.util.List; 6 | import org.seasar.doma.jdbc.criteria.Entityql; 7 | import org.seasar.doma.jdbc.criteria.option.LikeOption; 8 | import org.springframework.stereotype.Repository; 9 | import sample.entity.Product; 10 | import sample.entity.Product_; 11 | 12 | @Repository 13 | public class ProductRepository { 14 | 15 | private final Entityql entityql; 16 | 17 | public ProductRepository(Entityql entityql) { 18 | this.entityql = entityql; 19 | } 20 | 21 | public Product selectProduct(String productId) { 22 | var p = new Product_(); 23 | 24 | return entityql.from(p).where(c -> c.eq(p.productId, productId)).fetchOne(); 25 | } 26 | 27 | public List selectProductsByCategory(String categoryId) { 28 | var p = new Product_(); 29 | 30 | return entityql.from(p).where(c -> c.eq(p.categoryId, categoryId)).fetch(); 31 | } 32 | 33 | public List selectProductList(List keywords) { 34 | var p = new Product_(); 35 | return entityql 36 | .from(p) 37 | .where( 38 | c -> { 39 | for (var keyword : keywords) { 40 | c.or(() -> c.like(lower(p.name), keyword.toLowerCase(), LikeOption.infix())); 41 | c.or(() -> c.like(lower(p.categoryId), keyword.toLowerCase(), LikeOption.infix())); 42 | c.or(() -> c.like(lower(p.description), keyword.toLowerCase(), LikeOption.infix())); 43 | } 44 | }) 45 | .fetch(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/sample/service/AccountService.java: -------------------------------------------------------------------------------- 1 | package sample.service; 2 | 3 | import java.util.Collections; 4 | import org.springframework.security.core.userdetails.User; 5 | import org.springframework.security.core.userdetails.UserDetails; 6 | import org.springframework.security.core.userdetails.UserDetailsService; 7 | import org.springframework.security.core.userdetails.UsernameNotFoundException; 8 | import org.springframework.stereotype.Service; 9 | import sample.entity.Account; 10 | import sample.repository.AccountRepository; 11 | 12 | @Service 13 | public class AccountService implements UserDetailsService { 14 | 15 | private final AccountRepository accountRepository; 16 | 17 | public AccountService(AccountRepository accountRepository) { 18 | this.accountRepository = accountRepository; 19 | } 20 | 21 | public Account getAccount(String username) { 22 | return accountRepository.selectAccountByUsername(username); 23 | } 24 | 25 | public void insertAccount(Account account) { 26 | accountRepository.insertAccount(account); 27 | } 28 | 29 | public void updateAccount(Account account) { 30 | accountRepository.updateAccount(account); 31 | } 32 | 33 | @Override 34 | public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { 35 | var account = accountRepository.selectAccountByUsername(username); 36 | if (account == null) { 37 | throw new UsernameNotFoundException(username + " not found"); 38 | } 39 | return new User(account.getUsername(), account.getPassword(), Collections.emptyList()); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/sample/service/CategoryService.java: -------------------------------------------------------------------------------- 1 | package sample.service; 2 | 3 | import org.springframework.stereotype.Service; 4 | import sample.entity.Category; 5 | import sample.repository.CategoryRepository; 6 | 7 | @Service 8 | public class CategoryService { 9 | 10 | private final CategoryRepository categoryRepository; 11 | 12 | public CategoryService(CategoryRepository categoryRepository) { 13 | this.categoryRepository = categoryRepository; 14 | } 15 | 16 | public Category getCategory(String categoryId) { 17 | return categoryRepository.selectCategory(categoryId); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/sample/service/ItemService.java: -------------------------------------------------------------------------------- 1 | package sample.service; 2 | 3 | import java.util.List; 4 | import org.springframework.stereotype.Service; 5 | import sample.entity.Item; 6 | import sample.repository.ItemRepository; 7 | 8 | @Service 9 | public class ItemService { 10 | private final ItemRepository itemRepository; 11 | 12 | public ItemService(ItemRepository itemRepository) { 13 | this.itemRepository = itemRepository; 14 | } 15 | 16 | public boolean isItemInStock(String itemId) { 17 | var i = itemRepository.selectInventoryQuantity(itemId); 18 | return (i != null && i > 0); 19 | } 20 | 21 | public Item getItem(String itemId) { 22 | return itemRepository.selectItem(itemId); 23 | } 24 | 25 | public List getItemsByProduct(String productId) { 26 | return itemRepository.selectItemsByProduct(productId); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/sample/service/OrderService.java: -------------------------------------------------------------------------------- 1 | package sample.service; 2 | 3 | import java.time.LocalDateTime; 4 | import java.util.List; 5 | import org.springframework.stereotype.Service; 6 | import sample.entity.Order; 7 | import sample.entity.OrderLineItem; 8 | import sample.model.Cart; 9 | import sample.repository.AccountRepository; 10 | import sample.repository.ItemRepository; 11 | import sample.repository.OrderRepository; 12 | 13 | @Service 14 | public class OrderService { 15 | 16 | private final ItemRepository itemRepository; 17 | private final OrderRepository orderRepository; 18 | private final AccountRepository accountRepository; 19 | 20 | public OrderService( 21 | ItemRepository itemRepository, 22 | OrderRepository orderRepository, 23 | AccountRepository accountRepository) { 24 | this.itemRepository = itemRepository; 25 | this.orderRepository = orderRepository; 26 | this.accountRepository = accountRepository; 27 | } 28 | 29 | public void insertOrder(Order order) { 30 | for (var lineItem : order.getLineItemList()) { 31 | itemRepository.updateInventoryQuantity(lineItem.getItemId(), lineItem.getQuantity()); 32 | } 33 | orderRepository.insertOrder(order); 34 | } 35 | 36 | public Order getOrder(int orderId) { 37 | return orderRepository.selectOrder(orderId); 38 | } 39 | 40 | public List getOrdersByUsername(String username) { 41 | return orderRepository.selectOrdersByUsername(username); 42 | } 43 | 44 | public Order createNewOrder(String username, Cart cart) { 45 | var account = accountRepository.selectAccountByUsername(username); 46 | 47 | var order = new Order(); 48 | order.setUsername(account.getUsername()); 49 | order.setOrderDate(LocalDateTime.now()); 50 | order.setShipToFirstName(account.getFirstName()); 51 | order.setShipToLastName(account.getLastName()); 52 | order.setShipAddress1(account.getAddress1()); 53 | order.setShipAddress2(account.getAddress2()); 54 | order.setShipCity(account.getCity()); 55 | order.setShipState(account.getState()); 56 | order.setShipZip(account.getZip()); 57 | order.setShipCountry(account.getCountry()); 58 | order.setBillToFirstName(account.getFirstName()); 59 | order.setBillToLastName(account.getLastName()); 60 | order.setBillAddress1(account.getAddress1()); 61 | order.setBillAddress2(account.getAddress2()); 62 | order.setBillCity(account.getCity()); 63 | order.setBillState(account.getState()); 64 | order.setBillZip(account.getZip()); 65 | order.setBillCountry(account.getCountry()); 66 | order.setTotalPrice(cart.getSubTotal()); 67 | order.setCreditCard("999 9999 9999 9999"); 68 | order.setExpiryDate("12/03"); 69 | order.setCardType("Visa"); 70 | order.setCourier("UPS"); 71 | order.setLocale("CA"); 72 | order.setStatus("P"); 73 | 74 | var i = 0; 75 | for (var cartItem : cart.getCartItemList()) { 76 | var lineItem = new OrderLineItem(); 77 | lineItem.setLineNumber(++i); 78 | lineItem.setQuantity(cartItem.getQuantity()); 79 | lineItem.setItemId(cartItem.getItem().getItemId()); 80 | lineItem.setUnitPrice(cartItem.getItem().getListPrice()); 81 | order.addLineItem(lineItem); 82 | } 83 | 84 | return order; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/sample/service/ProductService.java: -------------------------------------------------------------------------------- 1 | package sample.service; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.StringTokenizer; 6 | import org.springframework.stereotype.Service; 7 | import sample.entity.Product; 8 | import sample.repository.ProductRepository; 9 | 10 | @Service 11 | public class ProductService { 12 | 13 | private final ProductRepository productRepository; 14 | 15 | public ProductService(ProductRepository productRepository) { 16 | this.productRepository = productRepository; 17 | } 18 | 19 | public Product getProduct(String productId) { 20 | return productRepository.selectProduct(productId); 21 | } 22 | 23 | public List getProductListByCategory(String categoryId) { 24 | return productRepository.selectProductsByCategory(categoryId); 25 | } 26 | 27 | public List searchProductList(String keywords) { 28 | List keywordList = new ArrayList<>(); 29 | for (var tokenizer = new StringTokenizer(keywords.toLowerCase(), " ", false); 30 | tokenizer.hasMoreTokens(); ) { 31 | keywordList.add(tokenizer.nextToken()); 32 | } 33 | return productRepository.selectProductList(keywordList); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/sample/web/Constants.java: -------------------------------------------------------------------------------- 1 | package sample.web; 2 | 3 | import java.util.List; 4 | 5 | public final class Constants { 6 | 7 | public static final List CARD_TYPE_LIST; 8 | 9 | static { 10 | CARD_TYPE_LIST = List.of("Visa", "MasterCard", "American Express"); 11 | } 12 | 13 | public static final List LANGUAGE_LIST; 14 | 15 | static { 16 | LANGUAGE_LIST = List.of("english", "japanese"); 17 | } 18 | 19 | public static final List CATEGORY_LIST; 20 | 21 | static { 22 | CATEGORY_LIST = List.of("FISH", "DOGS", "REPTILES", "CATS", "BIRDS"); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/sample/web/ErrorController.java: -------------------------------------------------------------------------------- 1 | package sample.web; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | 6 | @Controller 7 | public class ErrorController { 8 | 9 | @RequestMapping("/404") 10 | public String notFound() { 11 | return "404"; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/sample/web/IndexController.java: -------------------------------------------------------------------------------- 1 | package sample.web; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.web.bind.annotation.GetMapping; 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | 7 | @Controller 8 | @RequestMapping("/") 9 | public class IndexController { 10 | 11 | @GetMapping 12 | public String index() { 13 | return "index"; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/sample/web/WebMvcConfiguration.java: -------------------------------------------------------------------------------- 1 | package sample.web; 2 | 3 | import org.springframework.boot.web.server.ErrorPage; 4 | import org.springframework.boot.web.server.WebServerFactoryCustomizer; 5 | import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.format.FormatterRegistry; 9 | import org.springframework.http.HttpStatus; 10 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 11 | import sample.formatter.AmountFormatter; 12 | import sample.formatter.LocalDateTimeFormatter; 13 | 14 | @Configuration 15 | public class WebMvcConfiguration implements WebMvcConfigurer { 16 | 17 | @Override 18 | public void addFormatters(FormatterRegistry registry) { 19 | registry.addFormatter(new AmountFormatter()); 20 | registry.addFormatter(new LocalDateTimeFormatter()); 21 | } 22 | 23 | @Bean 24 | public WebServerFactoryCustomizer 25 | webServerFactoryCustomizer() { 26 | return new ServletContainerCustomizer(); 27 | } 28 | 29 | protected static class ServletContainerCustomizer 30 | implements WebServerFactoryCustomizer { 31 | 32 | public void customize(ConfigurableServletWebServerFactory factory) { 33 | factory.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/404")); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/sample/web/WebSecurityConfiguration.java: -------------------------------------------------------------------------------- 1 | package sample.web; 2 | 3 | import javax.sql.DataSource; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 7 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 8 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 9 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 10 | import org.springframework.security.crypto.password.PasswordEncoder; 11 | import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl; 12 | import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository; 13 | import sample.service.AccountService; 14 | 15 | @Configuration 16 | public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { 17 | 18 | private final DataSource dataSource; 19 | private final AccountService accountService; 20 | 21 | public WebSecurityConfiguration(DataSource dataSource, AccountService accountService) { 22 | this.dataSource = dataSource; 23 | this.accountService = accountService; 24 | } 25 | 26 | @Bean 27 | public PersistentTokenRepository persistentTokenRepository() { 28 | var tokenRepository = new JdbcTokenRepositoryImpl(); 29 | tokenRepository.setDataSource(dataSource); 30 | return tokenRepository; 31 | } 32 | 33 | @Override 34 | protected void configure(HttpSecurity http) throws Exception { 35 | http.authorizeRequests() 36 | .antMatchers( 37 | "/", 38 | "/cart/**", 39 | "/category/**", 40 | "/product/**", 41 | "/item/**", 42 | "/search/**", 43 | "/account/add", 44 | "/images/**", 45 | "/css/**", 46 | "/js/**", 47 | "/webjars/**") 48 | .permitAll() 49 | .anyRequest() 50 | .authenticated(); 51 | http.formLogin() 52 | .loginPage("/signin") 53 | .permitAll() 54 | .and() 55 | .logout() 56 | .logoutUrl("/signout") 57 | .permitAll(); 58 | http.rememberMe().tokenRepository(persistentTokenRepository()); 59 | } 60 | 61 | @Bean 62 | public PasswordEncoder passwordEncoder() { 63 | return new BCryptPasswordEncoder(); 64 | } 65 | 66 | @Override 67 | protected void configure(AuthenticationManagerBuilder auth) throws Exception { 68 | auth.userDetailsService(accountService).passwordEncoder(passwordEncoder()); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/sample/web/account/AbstractAccountForm.java: -------------------------------------------------------------------------------- 1 | package sample.web.account; 2 | 3 | import javax.validation.constraints.NotBlank; 4 | import javax.validation.constraints.NotNull; 5 | import javax.validation.constraints.Size; 6 | 7 | public abstract class AbstractAccountForm { 8 | 9 | @NotBlank 10 | @Size(max = 30) 11 | private String email; 12 | 13 | @NotBlank 14 | @Size(max = 30) 15 | private String firstName; 16 | 17 | @NotBlank 18 | @Size(max = 30) 19 | private String lastName; 20 | 21 | @NotBlank 22 | @Size(max = 30) 23 | private String address1; 24 | 25 | @NotBlank 26 | @Size(max = 30) 27 | private String address2; 28 | 29 | @NotBlank 30 | @Size(max = 30) 31 | private String city; 32 | 33 | @NotBlank 34 | @Size(max = 30) 35 | private String state; 36 | 37 | @NotBlank 38 | @Size(max = 20) 39 | private String zip; 40 | 41 | @NotBlank 42 | @Size(max = 20) 43 | private String country; 44 | 45 | @NotBlank 46 | @Size(max = 20) 47 | private String phone; 48 | 49 | @NotBlank 50 | @Size(max = 30) 51 | private String favouriteCategoryId; 52 | 53 | @NotBlank 54 | @Size(max = 30) 55 | private String languagePreference; 56 | 57 | @NotNull private boolean listOption; 58 | 59 | @NotNull private boolean bannerOption; 60 | 61 | public String getEmail() { 62 | return email; 63 | } 64 | 65 | public void setEmail(String email) { 66 | this.email = email; 67 | } 68 | 69 | public String getFirstName() { 70 | return firstName; 71 | } 72 | 73 | public void setFirstName(String firstName) { 74 | this.firstName = firstName; 75 | } 76 | 77 | public String getLastName() { 78 | return lastName; 79 | } 80 | 81 | public void setLastName(String lastName) { 82 | this.lastName = lastName; 83 | } 84 | 85 | public String getAddress1() { 86 | return address1; 87 | } 88 | 89 | public void setAddress1(String address1) { 90 | this.address1 = address1; 91 | } 92 | 93 | public String getAddress2() { 94 | return address2; 95 | } 96 | 97 | public void setAddress2(String address2) { 98 | this.address2 = address2; 99 | } 100 | 101 | public String getCity() { 102 | return city; 103 | } 104 | 105 | public void setCity(String city) { 106 | this.city = city; 107 | } 108 | 109 | public String getState() { 110 | return state; 111 | } 112 | 113 | public void setState(String state) { 114 | this.state = state; 115 | } 116 | 117 | public String getZip() { 118 | return zip; 119 | } 120 | 121 | public void setZip(String zip) { 122 | this.zip = zip; 123 | } 124 | 125 | public String getCountry() { 126 | return country; 127 | } 128 | 129 | public void setCountry(String country) { 130 | this.country = country; 131 | } 132 | 133 | public String getPhone() { 134 | return phone; 135 | } 136 | 137 | public void setPhone(String phone) { 138 | this.phone = phone; 139 | } 140 | 141 | public String getFavouriteCategoryId() { 142 | return favouriteCategoryId; 143 | } 144 | 145 | public void setFavouriteCategoryId(String favouriteCategoryId) { 146 | this.favouriteCategoryId = favouriteCategoryId; 147 | } 148 | 149 | public String getLanguagePreference() { 150 | return languagePreference; 151 | } 152 | 153 | public void setLanguagePreference(String languagePreference) { 154 | this.languagePreference = languagePreference; 155 | } 156 | 157 | public boolean isListOption() { 158 | return listOption; 159 | } 160 | 161 | public void setListOption(boolean listOption) { 162 | this.listOption = listOption; 163 | } 164 | 165 | public boolean isBannerOption() { 166 | return bannerOption; 167 | } 168 | 169 | public void setBannerOption(boolean bannerOption) { 170 | this.bannerOption = bannerOption; 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /src/main/java/sample/web/account/AccountController.java: -------------------------------------------------------------------------------- 1 | package sample.web.account; 2 | 3 | import org.springframework.beans.BeanUtils; 4 | import org.springframework.security.core.annotation.AuthenticationPrincipal; 5 | import org.springframework.security.core.userdetails.User; 6 | import org.springframework.security.crypto.password.PasswordEncoder; 7 | import org.springframework.stereotype.Controller; 8 | import org.springframework.transaction.annotation.Transactional; 9 | import org.springframework.ui.Model; 10 | import org.springframework.validation.BindingResult; 11 | import org.springframework.validation.annotation.Validated; 12 | import org.springframework.web.bind.WebDataBinder; 13 | import org.springframework.web.bind.annotation.GetMapping; 14 | import org.springframework.web.bind.annotation.InitBinder; 15 | import org.springframework.web.bind.annotation.PostMapping; 16 | import org.springframework.web.bind.annotation.RequestMapping; 17 | import sample.entity.Account; 18 | import sample.service.AccountService; 19 | import sample.web.Constants; 20 | 21 | @Controller 22 | @RequestMapping("/account") 23 | @Transactional 24 | public class AccountController { 25 | 26 | private final AccountService accountService; 27 | private final PasswordEncoder passwordEncoder; 28 | private final PasswordValidator passwordValidator; 29 | 30 | public AccountController( 31 | AccountService accountService, 32 | PasswordEncoder passwordEncoder, 33 | PasswordValidator passwordValidator) { 34 | this.accountService = accountService; 35 | this.passwordEncoder = passwordEncoder; 36 | this.passwordValidator = passwordValidator; 37 | } 38 | 39 | @InitBinder("addAccountForm") 40 | public void initBinder(WebDataBinder binder) { 41 | binder.addValidators(passwordValidator); 42 | } 43 | 44 | @GetMapping("add") 45 | public String add(Model model) { 46 | return modelAndViewForAdd(model, new AddAccountForm()); 47 | } 48 | 49 | @PostMapping("add") 50 | public String add( 51 | @Validated AddAccountForm accountForm, BindingResult bindingResult, Model model) { 52 | if (bindingResult.hasErrors()) { 53 | return modelAndViewForAdd(model, accountForm); 54 | } 55 | var account = new Account(); 56 | BeanUtils.copyProperties(accountForm, account); 57 | var rawPassword = accountForm.getPassword(); 58 | var encodedPassword = passwordEncoder.encode(rawPassword); 59 | account.setPassword(encodedPassword); 60 | accountService.insertAccount(account); 61 | return "redirect:/signin"; 62 | } 63 | 64 | private String modelAndViewForAdd(Model model, AddAccountForm accountForm) { 65 | model.addAttribute(accountForm); 66 | model.addAttribute("languageList", Constants.LANGUAGE_LIST); 67 | model.addAttribute("categoryList", Constants.CATEGORY_LIST); 68 | return "account/add"; 69 | } 70 | 71 | @GetMapping("/edit") 72 | public String edit(Model model, @AuthenticationPrincipal User user) { 73 | var account = accountService.getAccount(user.getUsername()); 74 | var accountForm = new EditAccountForm(); 75 | BeanUtils.copyProperties(account, accountForm, "password"); 76 | return modelAndViewForEdit(model, accountForm, user); 77 | } 78 | 79 | @PostMapping("/edit") 80 | public String edit( 81 | @Validated EditAccountForm accountForm, 82 | BindingResult bindingResult, 83 | Model model, 84 | @AuthenticationPrincipal User user) { 85 | if (bindingResult.hasErrors()) { 86 | return modelAndViewForEdit(model, accountForm, user); 87 | } 88 | var account = accountService.getAccount(user.getUsername()); 89 | BeanUtils.copyProperties(accountForm, account); 90 | account.setUsername(user.getUsername()); 91 | accountService.updateAccount(account); 92 | return "redirect:/"; 93 | } 94 | 95 | private String modelAndViewForEdit(Model model, EditAccountForm accountForm, User user) { 96 | model.addAttribute(accountForm); 97 | model.addAttribute("username", user.getUsername()); 98 | model.addAttribute("languageList", Constants.LANGUAGE_LIST); 99 | model.addAttribute("categoryList", Constants.CATEGORY_LIST); 100 | return "account/edit"; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/sample/web/account/AddAccountForm.java: -------------------------------------------------------------------------------- 1 | package sample.web.account; 2 | 3 | import javax.validation.constraints.NotBlank; 4 | import javax.validation.constraints.Size; 5 | 6 | public class AddAccountForm extends AbstractAccountForm { 7 | 8 | @NotBlank 9 | @Size(max = 20) 10 | private String username; 11 | 12 | @NotBlank 13 | @Size(min = 8) 14 | private String password; 15 | 16 | @NotBlank private String repeatedPassword; 17 | 18 | public String getUsername() { 19 | return username; 20 | } 21 | 22 | public void setUsername(String username) { 23 | this.username = username; 24 | } 25 | 26 | public String getPassword() { 27 | return password; 28 | } 29 | 30 | public void setPassword(String password) { 31 | this.password = password; 32 | } 33 | 34 | public String getRepeatedPassword() { 35 | return repeatedPassword; 36 | } 37 | 38 | public void setRepeatedPassword(String repeatedPassword) { 39 | this.repeatedPassword = repeatedPassword; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/sample/web/account/EditAccountForm.java: -------------------------------------------------------------------------------- 1 | package sample.web.account; 2 | 3 | public class EditAccountForm extends AbstractAccountForm {} 4 | -------------------------------------------------------------------------------- /src/main/java/sample/web/account/PasswordValidator.java: -------------------------------------------------------------------------------- 1 | package sample.web.account; 2 | 3 | import org.springframework.stereotype.Component; 4 | import org.springframework.validation.Errors; 5 | import org.springframework.validation.Validator; 6 | 7 | @Component 8 | public class PasswordValidator implements Validator { 9 | 10 | @Override 11 | public boolean supports(Class clazz) { 12 | return AddAccountForm.class.isAssignableFrom(clazz); 13 | } 14 | 15 | @Override 16 | public void validate(Object target, Errors errors) { 17 | var form = (AddAccountForm) target; 18 | var password = form.getPassword(); 19 | var repeatedPassword = form.getRepeatedPassword(); 20 | if (password == null) { 21 | return; 22 | } 23 | if (!password.equals(repeatedPassword)) { 24 | errors.rejectValue( 25 | "password", 26 | "PasswordValidator.addAccountForm.password", 27 | "password and repeated password must be same."); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/sample/web/cart/CartController.java: -------------------------------------------------------------------------------- 1 | package sample.web.cart; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.transaction.annotation.Transactional; 5 | import org.springframework.ui.Model; 6 | import org.springframework.validation.BindingResult; 7 | import org.springframework.validation.annotation.Validated; 8 | import org.springframework.web.bind.annotation.DeleteMapping; 9 | import org.springframework.web.bind.annotation.GetMapping; 10 | import org.springframework.web.bind.annotation.PathVariable; 11 | import org.springframework.web.bind.annotation.PostMapping; 12 | import org.springframework.web.bind.annotation.RequestMapping; 13 | import sample.model.Cart; 14 | import sample.service.ItemService; 15 | 16 | @Controller 17 | @RequestMapping("/cart") 18 | @Transactional 19 | public class CartController { 20 | 21 | private final ItemService itemService; 22 | private final Cart cart; 23 | 24 | public CartController(ItemService itemService, Cart cart) { 25 | this.itemService = itemService; 26 | this.cart = cart; 27 | } 28 | 29 | @GetMapping 30 | public String view(Model model) { 31 | var cartForm = new CartForm(); 32 | for (var item : cart.getCartItemList()) { 33 | var cartItemForm = new CartItemForm(); 34 | cartItemForm.setQuantity(item.getQuantity()); 35 | cartForm.getItems().put(item.getItem().getItemId(), cartItemForm); 36 | } 37 | model.addAttribute("cart", cart); 38 | model.addAttribute("cartForm", cartForm); 39 | return "cart/list"; 40 | } 41 | 42 | @PostMapping 43 | public String updateAll(@Validated CartForm cartForm, BindingResult result, Model model) { 44 | if (result.hasErrors()) { 45 | model.addAttribute("cart", cart); 46 | model.addAttribute("cartForm", cartForm); 47 | return "cart/list"; 48 | } 49 | for (var entry : cartForm.getItems().entrySet()) { 50 | var itemId = entry.getKey(); 51 | var cartItem = cart.getCartItem(itemId); 52 | if (cartItem == null) { 53 | continue; 54 | } 55 | var cartItemForm = entry.getValue(); 56 | if (cartItemForm.getQuantity() < 1) { 57 | cart.removeItemById(itemId); 58 | } else { 59 | cart.setQuantityByItemId(itemId, cartItemForm.getQuantity()); 60 | } 61 | } 62 | return "redirect:/cart"; 63 | } 64 | 65 | @PostMapping("/item/{itemId}") 66 | public String addItem(@PathVariable String itemId, Model model) { 67 | if (cart.containsItemId(itemId)) { 68 | cart.incrementQuantityByItemId(itemId); 69 | } else { 70 | var isInStock = itemService.isItemInStock(itemId); 71 | var item = itemService.getItem(itemId); 72 | cart.addItem(item, isInStock); 73 | } 74 | model.addAttribute(cart); 75 | return "redirect:/cart"; 76 | } 77 | 78 | @DeleteMapping("/item/{itemId}") 79 | public String removeItem(@PathVariable String itemId) { 80 | cart.removeItemById(itemId); 81 | return "redirect:/cart"; 82 | } 83 | 84 | @GetMapping("/checkout") 85 | public String checkout(Model model) { 86 | model.addAttribute("cart", cart); 87 | return "cart/checkout"; 88 | } 89 | 90 | @PostMapping("/checkout") 91 | public String checkout() { 92 | return "redirect:/order"; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/sample/web/cart/CartForm.java: -------------------------------------------------------------------------------- 1 | package sample.web.cart; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | import javax.validation.Valid; 6 | import javax.validation.constraints.NotNull; 7 | 8 | public class CartForm { 9 | 10 | @Valid @NotNull private Map items = new HashMap<>(); 11 | 12 | public Map getItems() { 13 | return items; 14 | } 15 | 16 | public void setItems(Map itemIds) { 17 | this.items = itemIds; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/sample/web/cart/CartItemForm.java: -------------------------------------------------------------------------------- 1 | package sample.web.cart; 2 | 3 | import javax.validation.constraints.Max; 4 | import javax.validation.constraints.NotNull; 5 | 6 | public class CartItemForm { 7 | 8 | @Max(99) 9 | @NotNull 10 | private Integer quantity; 11 | 12 | public Integer getQuantity() { 13 | return quantity; 14 | } 15 | 16 | public void setQuantity(Integer quantity) { 17 | this.quantity = quantity; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/sample/web/category/CategoryController.java: -------------------------------------------------------------------------------- 1 | package sample.web.category; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.transaction.annotation.Transactional; 5 | import org.springframework.ui.Model; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.PathVariable; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | import sample.service.CategoryService; 10 | import sample.service.ProductService; 11 | 12 | @Controller 13 | @RequestMapping("/category") 14 | @Transactional 15 | public class CategoryController { 16 | 17 | private final CategoryService categoryService; 18 | private final ProductService productService; 19 | 20 | public CategoryController(CategoryService categoryService, ProductService productService) { 21 | this.categoryService = categoryService; 22 | this.productService = productService; 23 | } 24 | 25 | @GetMapping("/{id}") 26 | public String category(@PathVariable String id, Model model) { 27 | model.addAttribute("category", categoryService.getCategory(id)); 28 | model.addAttribute("productList", productService.getProductListByCategory(id)); 29 | return "category/list"; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/sample/web/history/HistoryController.java: -------------------------------------------------------------------------------- 1 | package sample.web.history; 2 | 3 | import org.springframework.security.core.annotation.AuthenticationPrincipal; 4 | import org.springframework.security.core.userdetails.User; 5 | import org.springframework.stereotype.Controller; 6 | import org.springframework.transaction.annotation.Transactional; 7 | import org.springframework.ui.Model; 8 | import org.springframework.web.bind.annotation.GetMapping; 9 | import org.springframework.web.bind.annotation.PathVariable; 10 | import org.springframework.web.bind.annotation.RequestMapping; 11 | import sample.service.OrderService; 12 | 13 | @Controller 14 | @RequestMapping("/history") 15 | @Transactional 16 | public class HistoryController { 17 | 18 | private final OrderService orderService; 19 | 20 | public HistoryController(OrderService orderService) { 21 | this.orderService = orderService; 22 | } 23 | 24 | @GetMapping 25 | public String viewList(Model model, @AuthenticationPrincipal User user) { 26 | var orderList = orderService.getOrdersByUsername(user.getUsername()); 27 | model.addAttribute("orderList", orderList); 28 | return "history/list"; 29 | } 30 | 31 | @GetMapping("{orderId}") 32 | public String viewDetail(@PathVariable int orderId, Model model) { 33 | var order = orderService.getOrder(orderId); 34 | model.addAttribute("order", order); 35 | return "history/detail"; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/sample/web/item/ItemController.java: -------------------------------------------------------------------------------- 1 | package sample.web.item; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.transaction.annotation.Transactional; 5 | import org.springframework.ui.Model; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.PathVariable; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | import sample.service.ItemService; 10 | 11 | @Controller 12 | @RequestMapping("/item") 13 | @Transactional 14 | public class ItemController { 15 | 16 | private final ItemService itemService; 17 | 18 | public ItemController(ItemService itemService) { 19 | this.itemService = itemService; 20 | } 21 | 22 | @GetMapping("/{itemId}") 23 | public String viewDetail(@PathVariable String itemId, Model model) { 24 | model.addAttribute("item", itemService.getItem(itemId)); 25 | return "item/detail"; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/sample/web/order/OrderController.java: -------------------------------------------------------------------------------- 1 | package sample.web.order; 2 | 3 | import org.springframework.security.core.annotation.AuthenticationPrincipal; 4 | import org.springframework.security.core.userdetails.User; 5 | import org.springframework.stereotype.Controller; 6 | import org.springframework.transaction.annotation.Transactional; 7 | import org.springframework.ui.Model; 8 | import org.springframework.web.bind.annotation.GetMapping; 9 | import org.springframework.web.bind.annotation.PostMapping; 10 | import org.springframework.web.bind.annotation.RequestMapping; 11 | import org.springframework.web.servlet.mvc.support.RedirectAttributes; 12 | import sample.model.Cart; 13 | import sample.service.OrderService; 14 | 15 | @Controller 16 | @RequestMapping("/order") 17 | @Transactional 18 | public class OrderController { 19 | 20 | private final OrderService orderService; 21 | private final Cart cart; 22 | 23 | public OrderController(OrderService orderService, Cart cart) { 24 | this.orderService = orderService; 25 | this.cart = cart; 26 | } 27 | 28 | @GetMapping 29 | public String confirm( 30 | Model model, @AuthenticationPrincipal User user, RedirectAttributes redirectAttributes) { 31 | if (cart.isEmpty()) { 32 | return fillMessageAndredirectToIndex(redirectAttributes); 33 | } 34 | var order = orderService.createNewOrder(user.getUsername(), cart); 35 | model.addAttribute("order", order); 36 | return "order/confirm"; 37 | } 38 | 39 | @PostMapping 40 | public String confirm(@AuthenticationPrincipal User user, RedirectAttributes redirectAttributes) { 41 | if (cart.isEmpty()) { 42 | return fillMessageAndredirectToIndex(redirectAttributes); 43 | } 44 | var order = orderService.createNewOrder(user.getUsername(), cart); 45 | orderService.insertOrder(order); 46 | cart.clear(); 47 | redirectAttributes.addFlashAttribute("message", "Thank you!"); 48 | return "redirect:/"; 49 | } 50 | 51 | protected String fillMessageAndredirectToIndex(RedirectAttributes redirectAttributes) { 52 | redirectAttributes.addFlashAttribute("message", "Your Cart is Empty."); 53 | return "redirect:/"; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/sample/web/product/ProductController.java: -------------------------------------------------------------------------------- 1 | package sample.web.product; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.transaction.annotation.Transactional; 5 | import org.springframework.ui.Model; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.PathVariable; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | import sample.service.ItemService; 10 | import sample.service.ProductService; 11 | 12 | @Controller 13 | @RequestMapping("/product") 14 | @Transactional 15 | public class ProductController { 16 | 17 | private final ProductService productService; 18 | private final ItemService itemService; 19 | 20 | public ProductController(ProductService productService, ItemService itemService) { 21 | this.productService = productService; 22 | this.itemService = itemService; 23 | } 24 | 25 | @GetMapping("/{productId}") 26 | public String product(@PathVariable String productId, Model model) { 27 | model.addAttribute("product", productService.getProduct(productId)); 28 | model.addAttribute("itemList", itemService.getItemsByProduct(productId)); 29 | return "product/list"; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/sample/web/search/SearchController.java: -------------------------------------------------------------------------------- 1 | package sample.web.search; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.transaction.annotation.Transactional; 5 | import org.springframework.ui.Model; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.RequestParam; 9 | import sample.service.ProductService; 10 | 11 | @Controller 12 | @RequestMapping("/search") 13 | @Transactional 14 | public class SearchController { 15 | 16 | private final ProductService productService; 17 | 18 | public SearchController(ProductService productService) { 19 | this.productService = productService; 20 | } 21 | 22 | @GetMapping 23 | public String search( 24 | @RequestParam(required = false, defaultValue = "") String keyword, Model model) { 25 | var productList = productService.searchProductList(keyword); 26 | model.addAttribute("productList", productList); 27 | return "search/list"; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/sample/web/signin/SigninController.java: -------------------------------------------------------------------------------- 1 | package sample.web.signin; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.transaction.annotation.Transactional; 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | import org.springframework.web.bind.annotation.RequestMapping; 7 | 8 | @Controller 9 | @RequestMapping("/signin") 10 | @Transactional 11 | public class SigninController { 12 | 13 | @GetMapping 14 | public String signin() { 15 | return "signin/signin"; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/resources/ValidationMessages_ja.properties: -------------------------------------------------------------------------------- 1 | PasswordValidator.addAccountForm.password=パスワードが一致していません -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.thymeleaf.cache=false 2 | 3 | doma.dialect=H2 4 | doma.jdbc-logger=SLF4J 5 | 6 | logging.level.org.seasar.doma=DEBUG 7 | -------------------------------------------------------------------------------- /src/main/resources/data.sql: -------------------------------------------------------------------------------- 1 | INSERT INTO sequence VALUES('ordernum', 1000); 2 | 3 | INSERT INTO signon VALUES('doma','$2a$10$xjXoQgEljOr6rpYL1.PhSe4xp0gMRTrM3Ue0Rix8NTp5eDqAJ5Sp6'); 4 | INSERT INTO signon VALUES('ACID','$2a$10$Me1d4vJb1bMZiOfdg.oTU.64nGQUSB9xvJDwnaUJ1z6m3hRG3pq1S'); 5 | 6 | INSERT INTO account VALUES('doma','yourname@yourdomain.com','ABC', 'XYX', 'OK', '901 San Antonio Road', 'MS UCUP02-206', 'Palo Alto', 'CA', '94303', 'USA', '555-555-5555'); 7 | INSERT INTO account VALUES('ACID','acid@yourdomain.com','ABC', 'XYX', 'OK', '901 San Antonio Road', 'MS UCUP02-206', 'Palo Alto', 'CA', '94303', 'USA', '555-555-5555'); 8 | 9 | INSERT INTO profile VALUES('doma','english','DOGS',1,1); 10 | INSERT INTO profile VALUES('ACID','english','CATS',1,1); 11 | 12 | INSERT INTO bannerdata VALUES ('FISH',''); 13 | INSERT INTO bannerdata VALUES ('CATS',''); 14 | INSERT INTO bannerdata VALUES ('DOGS',''); 15 | INSERT INTO bannerdata VALUES ('REPTILES',''); 16 | INSERT INTO bannerdata VALUES ('BIRDS',''); 17 | 18 | INSERT INTO category VALUES ('FISH','Fish',' Fish'); 19 | INSERT INTO category VALUES ('DOGS','Dogs',' Dogs'); 20 | INSERT INTO category VALUES ('REPTILES','Reptiles',' Reptiles'); 21 | INSERT INTO category VALUES ('CATS','Cats',' Cats'); 22 | INSERT INTO category VALUES ('BIRDS','Birds',' Birds'); 23 | 24 | INSERT INTO product VALUES ('FI-SW-01','FISH','Angelfish','Salt Water fish from Australia'); 25 | INSERT INTO product VALUES ('FI-SW-02','FISH','Tiger Shark','Salt Water fish from Australia'); 26 | INSERT INTO product VALUES ('FI-FW-01','FISH', 'Koi','Fresh Water fish from Japan'); 27 | INSERT INTO product VALUES ('FI-FW-02','FISH', 'Goldfish','Fresh Water fish from China'); 28 | INSERT INTO product VALUES ('K9-BD-01','DOGS','Bulldog','Friendly dog from England'); 29 | INSERT INTO product VALUES ('K9-PO-02','DOGS','Poodle','Cute dog from France'); 30 | INSERT INTO product VALUES ('K9-DL-01','DOGS', 'Dalmation','Great dog for a Fire Station'); 31 | INSERT INTO product VALUES ('K9-RT-01','DOGS', 'Golden Retriever','Great family dog'); 32 | INSERT INTO product VALUES ('K9-RT-02','DOGS', 'Labrador Retriever','Great hunting dog'); 33 | INSERT INTO product VALUES ('K9-CW-01','DOGS', 'Chihuahua','Great companion dog'); 34 | INSERT INTO product VALUES ('RP-SN-01','REPTILES','Rattlesnake','Doubles as a watch dog'); 35 | INSERT INTO product VALUES ('RP-LI-02','REPTILES','Iguana','Friendly green friend'); 36 | INSERT INTO product VALUES ('FL-DSH-01','CATS','Manx','Great for reducing mouse populations'); 37 | INSERT INTO product VALUES ('FL-DLH-02','CATS','Persian','Friendly house cat, doubles as a princess'); 38 | INSERT INTO product VALUES ('AV-CB-01','BIRDS','Amazon Parrot','Great companion for up to 75 years'); 39 | INSERT INTO product VALUES ('AV-SB-02','BIRDS','Finch','Great stress reliever'); 40 | 41 | INSERT INTO supplier VALUES (1,'XYZ Pets','AC','600 Avon Way','','Los Angeles','CA','94024','212-947-0797'); 42 | INSERT INTO supplier VALUES (2,'ABC Pets','AC','700 Abalone Way','','San Francisco ','CA','94024','415-947-0797'); 43 | 44 | INSERT INTO item (itemid, productid, listprice, unitcost, supplier, status, attr1) VALUES('EST-1','FI-SW-01',16.50,10.00,1,'P','Large'); 45 | INSERT INTO item (itemid, productid, listprice, unitcost, supplier, status, attr1) VALUES('EST-2','FI-SW-01',16.50,10.00,1,'P','Small'); 46 | INSERT INTO item (itemid, productid, listprice, unitcost, supplier, status, attr1) VALUES('EST-3','FI-SW-02',18.50,12.00,1,'P','Toothless'); 47 | INSERT INTO item (itemid, productid, listprice, unitcost, supplier, status, attr1) VALUES('EST-4','FI-FW-01',18.50,12.00,1,'P','Spotted'); 48 | INSERT INTO item (itemid, productid, listprice, unitcost, supplier, status, attr1) VALUES('EST-5','FI-FW-01',18.50,12.00,1,'P','Spotless'); 49 | INSERT INTO item (itemid, productid, listprice, unitcost, supplier, status, attr1) VALUES('EST-6','K9-BD-01',18.50,12.00,1,'P','Male Adult'); 50 | INSERT INTO item (itemid, productid, listprice, unitcost, supplier, status, attr1) VALUES('EST-7','K9-BD-01',18.50,12.00,1,'P','Female Puppy'); 51 | INSERT INTO item (itemid, productid, listprice, unitcost, supplier, status, attr1) VALUES('EST-8','K9-PO-02',18.50,12.00,1,'P','Male Puppy'); 52 | INSERT INTO item (itemid, productid, listprice, unitcost, supplier, status, attr1) VALUES('EST-9','K9-DL-01',18.50,12.00,1,'P','Spotless Male Puppy'); 53 | INSERT INTO item (itemid, productid, listprice, unitcost, supplier, status, attr1) VALUES('EST-10','K9-DL-01',18.50,12.00,1,'P','Spotted Adult Female'); 54 | INSERT INTO item (itemid, productid, listprice, unitcost, supplier, status, attr1) VALUES('EST-11','RP-SN-01',18.50,12.00,1,'P','Venomless'); 55 | INSERT INTO item (itemid, productid, listprice, unitcost, supplier, status, attr1) VALUES('EST-12','RP-SN-01',18.50,12.00,1,'P','Rattleless'); 56 | INSERT INTO item (itemid, productid, listprice, unitcost, supplier, status, attr1) VALUES('EST-13','RP-LI-02',18.50,12.00,1,'P','Green Adult'); 57 | INSERT INTO item (itemid, productid, listprice, unitcost, supplier, status, attr1) VALUES('EST-14','FL-DSH-01',58.50,12.00,1,'P','Tailless'); 58 | INSERT INTO item (itemid, productid, listprice, unitcost, supplier, status, attr1) VALUES('EST-15','FL-DSH-01',23.50,12.00,1,'P','With tail'); 59 | INSERT INTO item (itemid, productid, listprice, unitcost, supplier, status, attr1) VALUES('EST-16','FL-DLH-02',93.50,12.00,1,'P','Adult Female'); 60 | INSERT INTO item (itemid, productid, listprice, unitcost, supplier, status, attr1) VALUES('EST-17','FL-DLH-02',93.50,12.00,1,'P','Adult Male'); 61 | INSERT INTO item (itemid, productid, listprice, unitcost, supplier, status, attr1) VALUES('EST-18','AV-CB-01',193.50,92.00,1,'P','Adult Male'); 62 | INSERT INTO item (itemid, productid, listprice, unitcost, supplier, status, attr1) VALUES('EST-19','AV-SB-02',15.50, 2.00,1,'P','Adult Male'); 63 | INSERT INTO item (itemid, productid, listprice, unitcost, supplier, status, attr1) VALUES('EST-20','FI-FW-02',5.50, 2.00,1,'P','Adult Male'); 64 | INSERT INTO item (itemid, productid, listprice, unitcost, supplier, status, attr1) VALUES('EST-21','FI-FW-02',5.29, 1.00,1,'P','Adult Female'); 65 | INSERT INTO item (itemid, productid, listprice, unitcost, supplier, status, attr1) VALUES('EST-22','K9-RT-02',135.50, 100.00,1,'P','Adult Male'); 66 | INSERT INTO item (itemid, productid, listprice, unitcost, supplier, status, attr1) VALUES('EST-23','K9-RT-02',145.49, 100.00,1,'P','Adult Female'); 67 | INSERT INTO item (itemid, productid, listprice, unitcost, supplier, status, attr1) VALUES('EST-24','K9-RT-02',255.50, 92.00,1,'P','Adult Male'); 68 | INSERT INTO item (itemid, productid, listprice, unitcost, supplier, status, attr1) VALUES('EST-25','K9-RT-02',325.29, 90.00,1,'P','Adult Female'); 69 | INSERT INTO item (itemid, productid, listprice, unitcost, supplier, status, attr1) VALUES('EST-26','K9-CW-01',125.50, 92.00,1,'P','Adult Male'); 70 | INSERT INTO item (itemid, productid, listprice, unitcost, supplier, status, attr1) VALUES('EST-27','K9-CW-01',155.29, 90.00,1,'P','Adult Female'); 71 | INSERT INTO item (itemid, productid, listprice, unitcost, supplier, status, attr1) VALUES('EST-28','K9-RT-01',155.29, 90.00,1,'P','Adult Female'); 72 | 73 | INSERT INTO inventory (itemid, qty ) VALUES ('EST-1',10000); 74 | INSERT INTO inventory (itemid, qty ) VALUES ('EST-2',10000); 75 | INSERT INTO inventory (itemid, qty ) VALUES ('EST-3',10000); 76 | INSERT INTO inventory (itemid, qty ) VALUES ('EST-4',10000); 77 | INSERT INTO inventory (itemid, qty ) VALUES ('EST-5',10000); 78 | INSERT INTO inventory (itemid, qty ) VALUES ('EST-6',10000); 79 | INSERT INTO inventory (itemid, qty ) VALUES ('EST-7',10000); 80 | INSERT INTO inventory (itemid, qty ) VALUES ('EST-8',10000); 81 | INSERT INTO inventory (itemid, qty ) VALUES ('EST-9',10000); 82 | INSERT INTO inventory (itemid, qty ) VALUES ('EST-10',10000); 83 | INSERT INTO inventory (itemid, qty ) VALUES ('EST-11',10000); 84 | INSERT INTO inventory (itemid, qty ) VALUES ('EST-12',10000); 85 | INSERT INTO inventory (itemid, qty ) VALUES ('EST-13',10000); 86 | INSERT INTO inventory (itemid, qty ) VALUES ('EST-14',10000); 87 | INSERT INTO inventory (itemid, qty ) VALUES ('EST-15',10000); 88 | INSERT INTO inventory (itemid, qty ) VALUES ('EST-16',10000); 89 | INSERT INTO inventory (itemid, qty ) VALUES ('EST-17',10000); 90 | INSERT INTO inventory (itemid, qty ) VALUES ('EST-18',10000); 91 | INSERT INTO inventory (itemid, qty ) VALUES ('EST-19',10000); 92 | INSERT INTO inventory (itemid, qty ) VALUES ('EST-20',10000); 93 | INSERT INTO inventory (itemid, qty ) VALUES ('EST-21',10000); 94 | INSERT INTO inventory (itemid, qty ) VALUES ('EST-22',10000); 95 | INSERT INTO inventory (itemid, qty ) VALUES ('EST-23',10000); 96 | INSERT INTO inventory (itemid, qty ) VALUES ('EST-24',10000); 97 | INSERT INTO inventory (itemid, qty ) VALUES ('EST-25',10000); 98 | INSERT INTO inventory (itemid, qty ) VALUES ('EST-26',10000); 99 | INSERT INTO inventory (itemid, qty ) VALUES ('EST-27',10000); 100 | INSERT INTO inventory (itemid, qty ) VALUES ('EST-28',10000); 101 | -------------------------------------------------------------------------------- /src/main/resources/schema.sql: -------------------------------------------------------------------------------- 1 | CREATE SEQUENCE orders_seq START WITH 1000 INCREMENT BY 10; 2 | create table supplier (suppid int not null,name varchar(80) null,status varchar(2) not null,addr1 varchar(80) null,addr2 varchar(80) null,city varchar(80) null,state varchar(80) null,zip varchar(5) null,phone varchar(80) null,constraint pk_supplier primary key (suppid)); 3 | create table signon (username varchar(25) not null,password varchar(100) not null,constraint pk_signon primary key (username)); 4 | create table account (userid varchar(80) not null,email varchar(80) not null,firstname varchar(80) not null,lastname varchar(80) not null,status varchar(2) null,addr1 varchar(80) not null,addr2 varchar(40) null,city varchar(80) not null,state varchar(80) not null,zip varchar(20) not null,country varchar(20) not null,phone varchar(80) not null,constraint pk_account primary key (userid)); 5 | create table profile (userid varchar(80) not null,langpref varchar(80) not null,favcategory varchar(30),mylistopt int,banneropt int,constraint pk_profile primary key (userid)); 6 | create table bannerdata (favcategory varchar(80) not null,bannername varchar(255) null,constraint pk_bannerdata primary key (favcategory)); 7 | create table orders (orderid int not null,userid varchar(80) not null,orderdate timestamp not null,shipaddr1 varchar(80) not null,shipaddr2 varchar(80) null,shipcity varchar(80) not null,shipstate varchar(80) not null,shipzip varchar(20) not null,shipcountry varchar(20) not null,billaddr1 varchar(80) not null,billaddr2 varchar(80) null,billcity varchar(80) not null,billstate varchar(80) not null,billzip varchar(20) not null,billcountry varchar(20) not null,courier varchar(80) not null,totalprice decimal(10,2) not null,billtofirstname varchar(80) not null,billtolastname varchar(80) not null,shiptofirstname varchar(80) not null,shiptolastname varchar(80) not null,creditcard varchar(80) not null,exprdate varchar(7) not null,cardtype varchar(80) not null,locale varchar(80) not null,constraint pk_orders primary key (orderid)); 8 | create table orderstatus (orderid int not null,linenum int not null,timestamp date not null,status varchar(2) not null,constraint pk_orderstatus primary key (orderid, linenum)); 9 | create table lineitem (orderid int not null,linenum int not null,itemid varchar(10) not null,quantity int not null,unitprice decimal(10,2) not null,constraint pk_lineitem primary key (orderid, linenum)); 10 | create table category (catid varchar(10) not null,name varchar(80) null,descn varchar(255) null,constraint pk_category primary key (catid)); 11 | create table product (productid varchar(10) not null,category varchar(10) not null,name varchar(80) null,descn varchar(255) null,constraint pk_product primary key (productid),constraint fk_product_1 foreign key (category)references category (catid)); 12 | create index productCat on product (category); 13 | create index productName on product (name); 14 | create table item (itemid varchar(10) not null,productid varchar(10) not null,listprice decimal(10,2) null,unitcost decimal(10,2) null,supplier int null,status varchar(2) null,attr1 varchar(80) null,attr2 varchar(80) null,attr3 varchar(80) null,attr4 varchar(80) null,attr5 varchar(80) null,constraint pk_item primary key (itemid),constraint fk_item_1 foreign key (productid)references product (productid),constraint fk_item_2 foreign key (supplier)references supplier (suppid)); 15 | create index itemProd on item (productid); 16 | create table inventory (itemid varchar(10) not null,qty int not null,constraint pk_inventory primary key (itemid)); 17 | create table persistent_logins (username varchar(64) not null, series varchar(64) primary key, token varchar(64) not null, last_used timestamp not null); 18 | CREATE TABLE sequence(name varchar(30) not null,nextid int not null,constraint pk_sequence primary key (name)); 19 | 20 | -------------------------------------------------------------------------------- /src/main/resources/static/css/jpetstore.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0ex 10ex 0ex 10ex; 3 | padding: 0ex; 4 | font-family: helvetica, tahoma, arial, verdana, sans-serif; 5 | font-size: 2ex; 6 | color: #333; 7 | background-color: #444; 8 | } 9 | 10 | pre { 11 | font-family: "Courier New", Courier, mono; 12 | 13 | font-style: normal; 14 | background-color: #FFFFFF; 15 | white-space: pre 16 | } 17 | 18 | h1 { 19 | margin: 1ex 0ex 1ex 0ex; 20 | padding: 0ex; 21 | 22 | line-height: 3ex; 23 | font-weight: 900; 24 | color: #666; 25 | } 26 | 27 | h2 { 28 | margin: 2ex 0ex 1ex 0ex; 29 | padding: 0ex; 30 | 31 | line-height: 2ex; 32 | font-weight: 700; 33 | color: #444; 34 | } 35 | 36 | h3 { 37 | margin: 1ex 0ex 1ex 0ex; 38 | padding: 0ex; 39 | 40 | line-height: 1.6ex; 41 | font-weight: 700; 42 | color: #222; 43 | } 44 | 45 | p { 46 | font-family: helvetica, tahoma, arial, verdana, sans-serif; 47 | 48 | margin: 0ex 0ex 0ex 0ex; 49 | padding: 2ex; 50 | } 51 | 52 | img { 53 | border: 0; 54 | } 55 | 56 | li { 57 | font-family: helvetica, tahoma, arial, verdana, sans-serif; 58 | 59 | margin: 0ex 0ex 0ex 0ex; 60 | padding: 0ex; 61 | } 62 | 63 | table { 64 | border-width: 0; 65 | empty-cells: show; 66 | } 67 | 68 | td, th { 69 | empty-cells: show; 70 | padding: .3ex .3ex; 71 | vertical-align: top; 72 | text-align: left; 73 | border-width: 0; 74 | border-spacing: 0; 75 | background-color: #ececec 76 | } 77 | 78 | th { 79 | font-weight: bold; 80 | background-color: #e2e2e2; 81 | } 82 | 83 | a, a:visited, a:link { 84 | color: #039; 85 | 86 | text-decoration: none; 87 | font-family: helvetica, tahoma, arial, verdana, sans-serif; 88 | } 89 | 90 | a:hover { 91 | color: #69f; 92 | } 93 | 94 | a.Button, a.Button:link, a.Button:visited { 95 | padding: .3ex; 96 | color: #fff; 97 | background-color: #005e21; 98 | text-decoration: none; 99 | font-family: helvetica, tahoma, arial, verdana, sans-serif; 100 | font-size: 1.5ex; 101 | } 102 | 103 | a.Button:hover { 104 | color: #000; 105 | background-color: #54c07a; 106 | } 107 | 108 | #Logo { 109 | width: 33%; 110 | height: 9ex; 111 | margin: 0ex 0ex 0ex 0ex; 112 | padding: 0ex 0ex 0ex 0ex; 113 | border-width: 0ex 0ex .3ex 0px; 114 | border-style: solid; 115 | border-color: #ccc; 116 | float: left; 117 | background-color: #000; 118 | color: #fff; 119 | line-height: 9ex; 120 | voice-family: "\"}\""; 121 | voice-family: inherit; 122 | height: 9ex; 123 | } 124 | 125 | body>#Logo { 126 | height: 9ex; 127 | } 128 | 129 | #Menu { 130 | width: 33%; 131 | height: 9ex; 132 | margin: 0ex 0ex 0ex 0ex; 133 | padding: 0ex 0ex 0ex 0ex; 134 | border-width: 0ex 0ex .3ex 0px; 135 | border-style: solid; 136 | border-color: #ccc; 137 | float: left; 138 | background-color: #000; 139 | color: #eaac00; 140 | text-decoration: none; 141 | font-family: helvetica, tahoma, arial, verdana, sans-serif; 142 | text-align: center; 143 | line-height: 9ex; 144 | voice-family: "\"}\""; 145 | voice-family: inherit; 146 | height: 9ex; 147 | } 148 | 149 | #Menu, #Menu a, #Menu a:link, #Menu a:visited, #Menu a:hover { 150 | color: #eaac00; 151 | text-decoration: none; 152 | font-family: helvetica, tahoma, arial, verdana, sans-serif; 153 | } 154 | 155 | body>#Menu { 156 | height: 9ex; 157 | } 158 | 159 | { 160 | } 161 | 162 | #Search { 163 | width: 34%; 164 | height: 9ex; 165 | margin: 0ex 0ex 0ex 0ex; 166 | padding: 0ex 0ex 0ex 0ex; 167 | border-width: 0ex 0ex .3ex 0px; 168 | border-style: solid; 169 | border-color: #ccc; 170 | float: left; 171 | text-align: center; 172 | background-color: #000; 173 | color: #eaac00; 174 | line-height: 9ex; 175 | voice-family: "\"}\""; 176 | voice-family: inherit; 177 | height: 9ex; 178 | } 179 | 180 | body>#Search { 181 | height: 9ex; 182 | } 183 | 184 | #Search input { 185 | border-width: .1ex .1ex .1ex .1ex; 186 | border-style: solid; 187 | border-color: #aaa; 188 | background-color: #666; 189 | color: #eaac00; 190 | } 191 | 192 | #QuickLinks { 193 | text-align: center; 194 | background-color: #FFF; 195 | width: 100%; 196 | } 197 | 198 | #PoweredBy { 199 | width: 30%; 200 | height: 9ex; 201 | margin: 0ex 0ex 0ex 0ex; 202 | padding: 0ex 0ex 0ex 0ex; 203 | border-width: .3ex 0ex .3ex 0px; 204 | border-style: solid; 205 | border-color: #ccc; 206 | float: left; 207 | background-color: #000; 208 | color: #fff; 209 | line-height: 9ex; 210 | voice-family: "\"}\""; 211 | voice-family: inherit; 212 | height: 9ex; 213 | } 214 | 215 | body>#PoweredBy { 216 | height: 9ex; 217 | } 218 | 219 | #Banner { 220 | width: 100%; 221 | height: 9ex; 222 | margin: 0ex 0ex 0ex 0ex; 223 | padding: 0ex 0ex 0ex 0ex; 224 | border-width: .3ex 0ex .3ex 0px; 225 | border-style: solid; 226 | border-color: #ccc; 227 | float: left; 228 | background-color: #000; 229 | color: #fff; 230 | line-height: 9ex; 231 | voice-family: "\"}\""; 232 | voice-family: inherit; 233 | height: 9ex; 234 | } 235 | 236 | body>#Banner { 237 | height: 9ex; 238 | } 239 | 240 | #Content { 241 | margin: 0; 242 | padding: 0ex 0ex 0ex 0ex; 243 | width: 100%; 244 | color: #333; 245 | background-color: #FFF; 246 | border-width: 0; 247 | } 248 | 249 | #Separator { 250 | clear:both; 251 | margin: 0; 252 | height:0; 253 | } 254 | 255 | #Welcome { 256 | margin: 0; 257 | padding: 1ex; 258 | color: #333; 259 | background-color: #FFF; 260 | } 261 | 262 | #Main { 263 | margin: 0; 264 | padding: 1ex; 265 | color: #333; 266 | background-color: #FFF; 267 | border-width: 1ex 0ex 2ex 0px; 268 | border-style: solid; 269 | border-color: #fff; 270 | } 271 | 272 | #Sidebar { 273 | float: left; 274 | background:inherit; 275 | width: 30%; 276 | } 277 | 278 | #MainImage { 279 | float: left; 280 | background:inherit; 281 | text-align:center; 282 | width: 50%; 283 | } 284 | 285 | #Catalog { 286 | padding: 1ex; 287 | background:inherit; 288 | text-align:center; 289 | background-color: #FFF; 290 | } 291 | 292 | #Catalog input[type="submit"]{ 293 | padding: .3ex; 294 | color: #fff; 295 | background-color: #005e21; 296 | text-decoration: none; 297 | font-family: helvetica, tahoma, arial, verdana, sans-serif; 298 | font-size: 1.5ex; 299 | border-width:0; 300 | } 301 | #Catalog input[type="submit"]:hover { 302 | color: #000; 303 | background-color: #54c07a; 304 | cursor:pointer; 305 | } 306 | 307 | #Catalog table{ 308 | margin-left:auto; 309 | margin-right:auto; 310 | } 311 | 312 | #BackLink{ 313 | padding: 1ex; 314 | float: right; 315 | border-width: .1ex 0ex .1ex 0px; 316 | border-style: solid; 317 | border-color: #000; 318 | } 319 | 320 | #Cart{ 321 | width: 69.99%; 322 | float: left; 323 | background-color:#fff; 324 | } 325 | 326 | #MyList{ 327 | width: 30%; 328 | float: left; 329 | background-color:#ccc; 330 | text-align:left; 331 | } 332 | 333 | .fieldError { 334 | border: 1px solid red; 335 | } 336 | -------------------------------------------------------------------------------- /src/main/resources/static/images/banner_birds.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/domaframework/spring-boot-jpetstore/b7e87c655933a1974d9710154b76235e381ef8fe/src/main/resources/static/images/banner_birds.gif -------------------------------------------------------------------------------- /src/main/resources/static/images/banner_cats.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/domaframework/spring-boot-jpetstore/b7e87c655933a1974d9710154b76235e381ef8fe/src/main/resources/static/images/banner_cats.gif -------------------------------------------------------------------------------- /src/main/resources/static/images/banner_dogs.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/domaframework/spring-boot-jpetstore/b7e87c655933a1974d9710154b76235e381ef8fe/src/main/resources/static/images/banner_dogs.gif -------------------------------------------------------------------------------- /src/main/resources/static/images/banner_fish.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/domaframework/spring-boot-jpetstore/b7e87c655933a1974d9710154b76235e381ef8fe/src/main/resources/static/images/banner_fish.gif -------------------------------------------------------------------------------- /src/main/resources/static/images/banner_reptiles.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/domaframework/spring-boot-jpetstore/b7e87c655933a1974d9710154b76235e381ef8fe/src/main/resources/static/images/banner_reptiles.gif -------------------------------------------------------------------------------- /src/main/resources/static/images/bird1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/domaframework/spring-boot-jpetstore/b7e87c655933a1974d9710154b76235e381ef8fe/src/main/resources/static/images/bird1.gif -------------------------------------------------------------------------------- /src/main/resources/static/images/bird2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/domaframework/spring-boot-jpetstore/b7e87c655933a1974d9710154b76235e381ef8fe/src/main/resources/static/images/bird2.gif -------------------------------------------------------------------------------- /src/main/resources/static/images/birds_icon.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/domaframework/spring-boot-jpetstore/b7e87c655933a1974d9710154b76235e381ef8fe/src/main/resources/static/images/birds_icon.gif -------------------------------------------------------------------------------- /src/main/resources/static/images/cart.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/domaframework/spring-boot-jpetstore/b7e87c655933a1974d9710154b76235e381ef8fe/src/main/resources/static/images/cart.gif -------------------------------------------------------------------------------- /src/main/resources/static/images/cat1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/domaframework/spring-boot-jpetstore/b7e87c655933a1974d9710154b76235e381ef8fe/src/main/resources/static/images/cat1.gif -------------------------------------------------------------------------------- /src/main/resources/static/images/cat2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/domaframework/spring-boot-jpetstore/b7e87c655933a1974d9710154b76235e381ef8fe/src/main/resources/static/images/cat2.gif -------------------------------------------------------------------------------- /src/main/resources/static/images/cats_icon.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/domaframework/spring-boot-jpetstore/b7e87c655933a1974d9710154b76235e381ef8fe/src/main/resources/static/images/cats_icon.gif -------------------------------------------------------------------------------- /src/main/resources/static/images/dog1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/domaframework/spring-boot-jpetstore/b7e87c655933a1974d9710154b76235e381ef8fe/src/main/resources/static/images/dog1.gif -------------------------------------------------------------------------------- /src/main/resources/static/images/dog2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/domaframework/spring-boot-jpetstore/b7e87c655933a1974d9710154b76235e381ef8fe/src/main/resources/static/images/dog2.gif -------------------------------------------------------------------------------- /src/main/resources/static/images/dog3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/domaframework/spring-boot-jpetstore/b7e87c655933a1974d9710154b76235e381ef8fe/src/main/resources/static/images/dog3.gif -------------------------------------------------------------------------------- /src/main/resources/static/images/dog4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/domaframework/spring-boot-jpetstore/b7e87c655933a1974d9710154b76235e381ef8fe/src/main/resources/static/images/dog4.gif -------------------------------------------------------------------------------- /src/main/resources/static/images/dog5.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/domaframework/spring-boot-jpetstore/b7e87c655933a1974d9710154b76235e381ef8fe/src/main/resources/static/images/dog5.gif -------------------------------------------------------------------------------- /src/main/resources/static/images/dog6.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/domaframework/spring-boot-jpetstore/b7e87c655933a1974d9710154b76235e381ef8fe/src/main/resources/static/images/dog6.gif -------------------------------------------------------------------------------- /src/main/resources/static/images/dogs.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/domaframework/spring-boot-jpetstore/b7e87c655933a1974d9710154b76235e381ef8fe/src/main/resources/static/images/dogs.gif -------------------------------------------------------------------------------- /src/main/resources/static/images/dogs_icon.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/domaframework/spring-boot-jpetstore/b7e87c655933a1974d9710154b76235e381ef8fe/src/main/resources/static/images/dogs_icon.gif -------------------------------------------------------------------------------- /src/main/resources/static/images/fish.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/domaframework/spring-boot-jpetstore/b7e87c655933a1974d9710154b76235e381ef8fe/src/main/resources/static/images/fish.gif -------------------------------------------------------------------------------- /src/main/resources/static/images/fish1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/domaframework/spring-boot-jpetstore/b7e87c655933a1974d9710154b76235e381ef8fe/src/main/resources/static/images/fish1.gif -------------------------------------------------------------------------------- /src/main/resources/static/images/fish2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/domaframework/spring-boot-jpetstore/b7e87c655933a1974d9710154b76235e381ef8fe/src/main/resources/static/images/fish2.gif -------------------------------------------------------------------------------- /src/main/resources/static/images/fish3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/domaframework/spring-boot-jpetstore/b7e87c655933a1974d9710154b76235e381ef8fe/src/main/resources/static/images/fish3.gif -------------------------------------------------------------------------------- /src/main/resources/static/images/fish4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/domaframework/spring-boot-jpetstore/b7e87c655933a1974d9710154b76235e381ef8fe/src/main/resources/static/images/fish4.gif -------------------------------------------------------------------------------- /src/main/resources/static/images/fish_icon.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/domaframework/spring-boot-jpetstore/b7e87c655933a1974d9710154b76235e381ef8fe/src/main/resources/static/images/fish_icon.gif -------------------------------------------------------------------------------- /src/main/resources/static/images/lizard1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/domaframework/spring-boot-jpetstore/b7e87c655933a1974d9710154b76235e381ef8fe/src/main/resources/static/images/lizard1.gif -------------------------------------------------------------------------------- /src/main/resources/static/images/logo-topbar.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/domaframework/spring-boot-jpetstore/b7e87c655933a1974d9710154b76235e381ef8fe/src/main/resources/static/images/logo-topbar.gif -------------------------------------------------------------------------------- /src/main/resources/static/images/reptiles_icon.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/domaframework/spring-boot-jpetstore/b7e87c655933a1974d9710154b76235e381ef8fe/src/main/resources/static/images/reptiles_icon.gif -------------------------------------------------------------------------------- /src/main/resources/static/images/separator.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/domaframework/spring-boot-jpetstore/b7e87c655933a1974d9710154b76235e381ef8fe/src/main/resources/static/images/separator.gif -------------------------------------------------------------------------------- /src/main/resources/static/images/sm_birds.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/domaframework/spring-boot-jpetstore/b7e87c655933a1974d9710154b76235e381ef8fe/src/main/resources/static/images/sm_birds.gif -------------------------------------------------------------------------------- /src/main/resources/static/images/sm_cats.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/domaframework/spring-boot-jpetstore/b7e87c655933a1974d9710154b76235e381ef8fe/src/main/resources/static/images/sm_cats.gif -------------------------------------------------------------------------------- /src/main/resources/static/images/sm_dogs.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/domaframework/spring-boot-jpetstore/b7e87c655933a1974d9710154b76235e381ef8fe/src/main/resources/static/images/sm_dogs.gif -------------------------------------------------------------------------------- /src/main/resources/static/images/sm_fish.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/domaframework/spring-boot-jpetstore/b7e87c655933a1974d9710154b76235e381ef8fe/src/main/resources/static/images/sm_fish.gif -------------------------------------------------------------------------------- /src/main/resources/static/images/sm_reptiles.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/domaframework/spring-boot-jpetstore/b7e87c655933a1974d9710154b76235e381ef8fe/src/main/resources/static/images/sm_reptiles.gif -------------------------------------------------------------------------------- /src/main/resources/static/images/snake1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/domaframework/spring-boot-jpetstore/b7e87c655933a1974d9710154b76235e381ef8fe/src/main/resources/static/images/snake1.gif -------------------------------------------------------------------------------- /src/main/resources/static/images/splash.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/domaframework/spring-boot-jpetstore/b7e87c655933a1974d9710154b76235e381ef8fe/src/main/resources/static/images/splash.gif -------------------------------------------------------------------------------- /src/main/resources/templates/404.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 |

404 Not Found

7 | 8 | 9 | -------------------------------------------------------------------------------- /src/main/resources/templates/account/add.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | Add Account 8 | 9 | 10 |
11 |
12 |
13 |
15 | Validation error 16 |
17 |

User Information

18 | 19 | 20 | 21 | 25 | 26 | 27 | 28 | 32 | 33 | 34 | 35 | 39 | 40 |
User ID: 22 | 23 | Error 24 |
New password: 29 | 30 | Error 31 |
Repeat password: 36 | 37 | Error 38 |
41 |
42 | 43 |
44 |
45 |
46 | 47 | -------------------------------------------------------------------------------- /src/main/resources/templates/account/edit.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | Edit Account 8 | 9 | 10 |
11 |
12 |
13 |
15 | Validation error 16 |
17 |

User Information

18 | 19 | 20 | 21 | 22 |
User ID:
23 |
24 | 25 |
26 | My Orders 27 |
28 |
29 | 30 | -------------------------------------------------------------------------------- /src/main/resources/templates/account/fields.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | Account Fields 8 | 9 | 10 |
11 |

Account Information

12 | 13 | 14 | 15 | 18 | 19 | 22 | 23 | 26 | 27 | 30 | 31 | 34 | 35 | 38 | 39 | 42 | 43 | 46 | 47 | 50 | 51 | 54 | 55 |
First name: 16 | Error 17 |
Last name: 20 | Error 21 |
Email: 24 | Error 25 |
Phone: 28 | Error 29 |
Address 1: 32 | Error 33 |
Address 2: 36 | Error 37 |
City: 40 | Error 41 |
State: 44 | Error 45 |
Zip: 48 | Error 49 |
Country: 52 | Error 53 |
56 |

Profile Information

57 | 58 | 59 | 63 | 64 | 68 | 69 | 70 | 71 | 72 | 73 |
Language Preference: 60 |
Favourite Category: 65 |
Enable MyList
Enable MyBanner
74 |
75 | 76 | -------------------------------------------------------------------------------- /src/main/resources/templates/cart/checkout.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | Cart Checkout 8 | 9 | 10 |
11 | 14 |
15 | 16 | 17 | 43 | 46 | 47 |
18 |

Checkout Summary

19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 37 | 38 |
Item ID Product ID Description In Stock?Quantity List Price Total Cost
35 | Sub Total: 36 |
39 |
40 | 41 |
42 |
44 |   45 |
48 |
49 |
50 | 51 | -------------------------------------------------------------------------------- /src/main/resources/templates/cart/list.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | Cart 8 | 9 | 10 |
11 | 14 |
15 |
16 |

Shopping Cart

17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 28 | 29 | 31 | 32 | 36 | 37 | 38 | 41 | 42 | 43 | 47 | 48 | 49 |
Item ID Product ID Description In Stock?Quantity List Price Total Cost  
Your cart is empty.
26 | 27 | 30 | 33 | 34 | Incorrect date 35 | 39 | Remove 40 |
44 | Sub Total: 45 | 46 |  
50 |
51 |
52 | Proceed to Checkout 53 |
54 |
 
55 |
56 | 66 |
67 | 68 | -------------------------------------------------------------------------------- /src/main/resources/templates/category/list.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | Category 8 | 9 | 10 |
11 | 14 |
15 |

Category

16 | 17 | 18 | 19 | 20 | 21 | 22 |
Product ID Name
23 |
24 |
25 | 26 | -------------------------------------------------------------------------------- /src/main/resources/templates/error.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 |

Error Page

7 |
[[${timestamp}]]
8 |
There was an unexpected error (type=[[${error}]], status=[[${status}]]).
9 |
[[${message}]]
10 | 11 | 12 | -------------------------------------------------------------------------------- /src/main/resources/templates/history/detail.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | Order History Detail 8 | 9 | 10 |
11 |
12 | 13 | 17 | 20 | 23 | 26 | 29 | 32 | 35 | 38 | 41 | 44 | 47 | 50 | 53 | 56 | 59 | 62 | 84 |
14 | Order # 15 | 16 |
18 | Payment Details 19 |
21 | Card Type: 22 |
24 | Card Number: * Fake number! 25 |
27 | Expiry Date (MM/YYYY): 28 |
30 | Billing Address 31 |
33 | First name: 34 |
36 | Last name: 37 |
39 | Address 1: 40 |
42 | Address 2: 43 |
45 | City: 46 |
48 | State: 49 |
51 | Zip: 52 |
54 | Country: 55 |
57 | Courier: 58 |
60 | Status: 61 |
63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 81 | 82 |
Item IDDescriptionQuantityPriceTotal Cost
Total: 80 |
83 |
85 |
86 |
87 | 88 | 89 | -------------------------------------------------------------------------------- /src/main/resources/templates/history/list.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | Order History List 8 | 9 | 10 |
11 |
12 |

My Orders

13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
Order ID Date Total Price
21 |
22 |
23 | 24 | -------------------------------------------------------------------------------- /src/main/resources/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | Menu 8 | 9 | 10 |
11 |
12 |
13 | Welcome 14 | 15 |
16 |
17 |
18 | 46 |
47 |
48 | Birds 49 | Fish 50 | Dogs 51 | Reptiles 53 | Cats 54 | Birds 55 | 56 | 57 |
58 |
59 |
 
60 |
61 |
62 | 67 | 68 | -------------------------------------------------------------------------------- /src/main/resources/templates/item/detail.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | Item 8 | 9 | 10 |
11 | 14 |
15 | 16 | 17 | 20 | 21 | 22 | 25 | 26 | 28 | 29 | 30 | 31 | 32 | 34 | 37 |
18 | Description 19 |
23 | id 24 |
27 |
Back ordered.[[${item.quantity}]] in stock.
33 |
35 | Add to Cart 36 |
38 |
39 |
40 | 50 |
51 | 52 | -------------------------------------------------------------------------------- /src/main/resources/templates/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | JPetStore Demo 8 | 9 | 10 | 11 | 12 | 58 |
59 |

Page content goes here

60 |
61 | 65 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /src/main/resources/templates/order/confirm.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | Cart 8 | 9 | 10 |
11 | 12 | 15 | 16 |
17 | 18 | Please confirm the information below and then press continue... 19 | 20 | 21 | 25 | 26 | 29 | 32 | 35 | 38 | 41 | 44 | 47 | 50 | 53 |
22 | Order 23 |
24 |
27 | Billing Address 28 |
30 | First name: 31 |
33 | Last name: 34 |
36 | Address 1: 37 |
39 | Address 2: 40 |
42 | City: 43 |
45 | State: 46 |
48 | Zip: 49 |
51 | Country: 52 |
54 | 55 |
56 | 57 |
58 | 59 |
60 | 61 |
62 | 63 | -------------------------------------------------------------------------------- /src/main/resources/templates/product/list.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | Product 8 | 9 | 10 |
11 | 14 |
15 |

Product

16 | 17 | 19 | 20 | 22 | 23 | 24 | 25 | 26 | 27 |
Item ID Product ID Description List 18 | Price  
21 | item idproduct idAdd to Cart
28 |
29 |
30 | 41 |
42 | 43 | -------------------------------------------------------------------------------- /src/main/resources/templates/search/list.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | Search 8 | 9 | 10 |
11 | 14 |
15 | 16 | 17 | 18 | 19 | 22 | 23 | 24 |
  Product ID Name
20 | 21 |
25 |
26 |
27 | 28 | -------------------------------------------------------------------------------- /src/main/resources/templates/signin/signin.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | Sign in 8 | 9 | 10 |
11 |
12 |
13 |
14 | Invalid username and password. 15 |
16 |
17 | You have been logged out. 18 |
19 |

Please enter your username and password.

20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 |
Username:
Password:
Remember Me:
38 |
39 |

40 |

41 | Need a username and password? 42 | Register Now! 43 |
44 |
45 |
46 | 47 | -------------------------------------------------------------------------------- /src/test/java/sample/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package sample; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | 5 | import org.junit.jupiter.api.Test; 6 | import org.seasar.doma.jdbc.Config; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.boot.test.context.SpringBootTest; 9 | import org.springframework.boot.test.web.client.TestRestTemplate; 10 | import org.springframework.boot.web.server.LocalServerPort; 11 | 12 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 13 | class ApplicationTest { 14 | 15 | @LocalServerPort private int port; 16 | 17 | @Autowired private TestRestTemplate restTemplate; 18 | 19 | @Autowired private Config config; 20 | 21 | @Test 22 | public void fish() { 23 | System.out.println(config.getDialect().getClass()); 24 | 25 | assertThat( 26 | restTemplate.getForObject("http://localhost:" + port + "/category/FISH", String.class)) 27 | .contains("Angelfish"); 28 | } 29 | } 30 | --------------------------------------------------------------------------------