# Full Stack MVC

### Overview

* Initialize local workspace
* Create Git repository
* Create and configure JPA project
* Create and configure Spring Boot project
* Connect Spring Boot with JPA project
* *Create and configure MySQL database*
* *Update Controllers*
* *Write JUnit test and run smoke test*

#### Initialize local workspace

Start by preparing space on your local environment where your project files will be stored.

* Open a terminal

  * Change directory to where your workspace will be
    * `cd ~/Documents/sites`
  * Create `.gitignore` file
    * `atom .gitignore`
  * Add the following and save the file:

  ```
  .DS_Store
  Servers
  target
  build
  bin
  .metadata
  # .settings
  .gradle
  *.war
  *.bak
  ```

#### Create Git repository

We will use Git as the version control system.

* Create a new repository at GitHub.com
* Initialize your local folder as a `git` repository and perform an initial commit:

```
echo "# MyProject" >> README.md
git init
git add README.md
git commit -m "first commit"
git branch -M main
git remote add origin https://github.com/myUsername/MyProject.git
git push -u origin main
```

#### Create and configure JPA project

Set up the Java Persistence API project in Spring Tool Suite (STS).

* Set or confirm in STS > `Preferences`:
  * `Gradle > Specific Gradle version: 7.4.2`
  * `Java > Compiler > Compiler compliance level: 1.8`
  * `General > Workspace > Show full workspace path`
  * `Console (search for) > Limit console output (uncheck)`
* Create JPA Project
  * `File > New > Other > JPA Project > Next`
  * Add source folders to structure:
    * `src/main/java`
    * `src/main/resources`
    * `src/test/java`
    * `src/test/resources`
  * Click Next
    * `JPA Implementation > Disable Library Configuration (select)`
  * Finish (don't open JPA Perspective if prompted)
* In the `Project Explorer` panel:
  * Drag the `META-INF` folder from `src/main/java` down one level to `src/main/resources`

Add Gradle using the following steps:

* Right-click your project folder and select `Configure > Add Gradle Nature`
* Reveal Gradle Tasks by clicking: `Window > Show View > Other > Gradle Tasks`
* On the Gradle Tasks panel, select: `Build > init (double-click)`
* Open the Console panel: accept defaults for the 4 prompts by hitting `enter`
* Right-click the project folder and select: `Refresh`

Update `build.gradle`:

```
apply plugin: 'java'
apply plugin: 'eclipse'

/*
name your project's dependency group and give it an initial version.
the 'artifactId' is assigned automatically based on the project's name.
*/
group = 'com.myorganization'
version = '0.0.1-SNAPSHOT'

// JDK versioning for compilation and generated bytecode
sourceCompatibility = 1.8
targetCompatibility = 1.8

eclipse {
  classpath {
    downloadSources = true
  }
}

// set query location for dependencies
repositories {
  jcenter()
}

/*
 set the version of hibernate to use to keep your dependencies DRY and
 consistent across artifactIds
*/
ext {
  hibernateVersion = "5.4.32.Final"
  mySqlConnectorVersion = "8.0.27"
  junit5Version = "5.8.2"
}

// define project specific dependencies
dependencies {
  implementation "mysql:mysql-connector-java:$mySqlConnectorVersion"
  implementation "log4j:log4j:1.2.17"
  implementation "org.hibernate:hibernate-core:$hibernateVersion"
  implementation "org.hibernate:hibernate-c3p0:$hibernateVersion"
  
  testImplementation("org.junit.jupiter:junit-jupiter:$junit5Version")
}

test {
    useJUnitPlatform()
}
```

Run `Gradle Refresh` by right-clicking the project and selecting `Gradle > Refresh Gradle Project`

Create `log4j.properties` file under `src/main/resources` and `src/test/resources` with the following contents:

```
// Logging levels, from least verbose to most, are:
// OFF, FATAL, ERROR, WARN, INFO, DEBUG, TRACE, and ALL
// Change this line from WARN to INFO for more detailed logging
log4j.rootLogger=WARN, stdout
log4j.logger.org.hibernate.type=WARN
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
```

Under the `META-INF` folder, update `persistence.xml` using the following as a guideline:

```
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.2"
	xmlns="http://xmlns.jcp.org/xml/ns/persistence"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
	<persistence-unit name="JPAMyProject">
		<provider>org.hibernate.jpa.HibernatePersistenceProvider
    </provider>

		<!-- List Entities Here -->
		<class>com.myorganization.myproject.entities.User</class>

		<properties>
			<property name="javax.persistence.jdbc.url"
				value="jdbc:mysql://localhost:3306/MYPROJECTDB?useSSL=false&amp;useLegacyDatetimeCode=false&amp;serverTimezone=US/Mountain" />
			<property name="javax.persistence.jdbc.user" value="MYUSER" />
			<property name="javax.persistence.jdbc.password" value="MYPASSWORD" />
			<property name="javax.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver" />

			<property name="hibernate.show_sql" value="true" />
			<property name="hibernate.format_sql" value="true" />

			<property name="hibernate.dialect"
				value="org.hibernate.dialect.MySQLDialect" />
			<property name="hibernate.connection.provider_class"
				value="org.hibernate.connection.C3P0ConnectionProvider" />

			<property name="hibernate.c3p0.max_size" value="5" />
			<property name="hibernate.c3p0.min_size" value="0" />
			<property name="hibernate.c3p0.acquire_increment" value="1" />
			<property name="hibernate.c3p0.idle_test_period" value="300" />
			<property name="hibernate.c3p0.max_statements" value="0" />
			<property name="hibernate.c3p0.timeout" value="60" />
		</properties>

	</persistence-unit>
</persistence>
```

Copy the fully-qualified name from your listed entity and navigate to `src/main/java (right-click) > New > Class`

In the `Name`, paste the text from your clipboard as copied from the `persistence.xml` file above (it should auto-populate the package name), i.e. `com.myorganization.myproject.entities.User`

**Stub out JUnit test**

* Create a new package under `src/test/java` for entities, i.e. `com.myorganization.myproject.entities`
* Create `New > JUnit Test`&#x20;
  * Ensure `JUnit Jupiter Test` is selected
  * Name: `UserTest`
  * Add: `@Before` and `@After` annotations

Run Gradle refresh again, then commit and push your updates to the project repository.

#### Create and configure Spring Boot project

* Get the package name from the JPA project you just created, i.e. `com.myorganization.myproject`
* In STS, click `New > Spring Starter Project`
  * Project name: *Name of your project*
  * `Gradle buildship 2.x`
  * Package name: *Must match with JPA project*
  * Create packages and add empty stub class to each package
  * Include Spring dependencies:
    * *Spring Web*
    * Spring Data JPA
    * MySQL Driver
  * Click `Finish`

Configure JPA and JSTL dependencies. In `build.gradle` add the following:

```
implementation 'javax.servlet:jstl:1.2'
implementation 'org.apache.tomcat.embed:tomcat-embed-jasper'
```

Save and perform Gradle refresh.

#### **Connect Spring Boot and JPA Projects**

* JPA projec&#x74;**:** `settings.gradle` > copy project name, i.e. `'JPAMyProject'`
* Boot project: `settings.gradle` > add: `includeFlat 'JPAMyProject'`
* Boot project: `build.gradle` > add: `implementation project(':JPAMyProject')`

Save all files and perform another Gradle refresh. Verify by expanding the `Projects and External Dependencies` folder (in the Spring Boot project) and see `JPAMyProject` at the bottom.

Commit (`Create Spring Boot MVC Project, add JPA Project dependency`) and push.

#### **Create web folder**

Create the `webapp/WEB-INF` folder under `src/main`

* In Package Explorer, expand `src/main` and right-click to select `New > Folder` and give it a name: `webapp/WEB-INF`&#x20;
* In it, create `New > Other > JSP File` and give it a name: `home`
* Add a tag to pass data into from the backend: `${DEBUG}`

#### Create Packages

Packages are folders that house separate concerns in a project. Create the following packages in the same level as `com.myorganization.myproject:`

* *Controllers*
  * `com.myorganization.myproject.controllers`
    * `HomeController.java`
* *Data*
  * `com.myorganization.myproject.data`
    * `UserDAO.java`
    * `UserDaoJpaImpl.java`

**Controllers**

```
new HomeController
@Controller
@RequestMapping(path = {"/", "home.do"})
```

**Data**

In the `data` package, select `New > Interface` and give it a name (i.e. `UserDAO`

Add a method to find a user by ID (import with `CMD + O`)

`User findById(int userId);`

In the package explorer, expand and right-click the purple `I` icon and select `New > Class` and give it a name:

`UserDaoJpaImpl`

* `@Service`
* `@Transactional`&#x20;
* `@PersistenceContext`&#x20;
  * `private Entity Manager em;`

File `UserDaoImpl.java`

```
package com.myorganization.myproject.data;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.transaction.Transactional;

import org.springframework.stereotype.Service;

import com.myorganization.myproject.entities.User;

@Service
@Transactional
public class UserDaoImpl implements UserDAO {

	@PersistenceContext
	private EntityManager em;

	@Override
	public User findById(int userId) {
		return em.find(User.class, userId);
	}

}
```

#### Update application.properties

File `src/main/resources/application.properties`&#x20;

```
#### PORT CONFIG ####
##### Alternate Tomcat port
server.port=8081


#### JSP VIEW RESOLVER ####
##### Include if you used a ViewResolver to shorten the names of your views
spring.mvc.view.prefix: /WEB-INF/
spring.mvc.view.suffix: .jsp


#### MYSQL DATASOURCE ####
##### Configure to match your Database
spring.datasource.url=jdbc:mysql://localhost:3306/FIXME?useSSL=false&useLegacyDatetimeCode=false&serverTimezone=US/Mountain
spring.datasource.username=FIXME
spring.datasource.password=FIXME
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver


#### LOGGING ####
##### Set to WARN for fewer log messages
logging.level.root=WARN
logging.level.org.springframework.web=DEBUG
logging.level.org.hibernate.SQL=WARN
logging.level.org.hibernate.type=WARN
spring.jpa.show-sql=true


#### TOMCAT ####
spring.datasource.tomcat.max-active=10
spring.datasource.dbcp2.max-idle=8
spring.datasource.dbcp2.max-wait-millis=10000
spring.datasource.dbcp2.min-evictable-idle-time-millis=1000
spring.datasource.dbcp2.min-idle=8
spring.datasource.dbcp2.time-between-eviction-runs-millis=1
```

*Commit and push*

`git commit -m 'Configure Spring, stub MVC code'`

`git pull`&#x20;

`git push`


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://adroit.andycary.com/software-engineering/project-setup/full-stack-mvc.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
