1.0.0
- Get the project
- clone
git clone https://github.com/csc340-uncg/f25-mvc-demo.git - OR download zip.
 
 - clone
 - Open the project in VS Code.
 - This project is built to run with jdk 21.
 - Dependencies to JPA, Postgres, and Freemarker, in addition to the usual. JPA handles the persistence, Postgres is the database to be used, FreeMarker generates HTML templates.
 /src/main/resources/application.propertiesfile is the configuration for the app.- You MUST have the database up and running before running the project!
- Login to your neon.tech account.
 - Locate your database project.
 - On the project dashboard, click on "Connect" and select Java.
 - Copy the connection string provided.
 - Paste it as a value for the property 
spring.datasource.url. No quotation marks. 
 - Build and run the main class. You should see a new table created in the Neon database.
 
- We are using ORM (Object-Relational Mapping) to deal with databases. This is a technique that allows us to interact with a relational database using object-oriented programming principles.
 - JPA (Jakarta Persistence, formerly Java Persistence API) is a specification that defines ORM standards in Java. It provides an abstraction layer for ORM frameworks to make concrete implementations.
 - Hibernate: Hibernate is a popular ORM framework that implements JPA. It simplifies database operations by mapping Java objects to database tables and handling queries efficiently. Spring ORM allows seamless integration of Hibernate and JPA, making database interactions more manageable and reducing boilerplate code.
 
- Entity
- The Student class is annotated as an 
@Entity. This is used to map class attributes to database tables and SQL types. - We also annotated with 
@Tableto give Hibernate directions to use this specific table name. This is optional but it helps with naming conventions. - Any Entity must have at least one attribute that is annotated as an 
@Id. In our case it's conveniently thestudentIdattribute.- We are also using an autogeneration strategy for the ID. This way we are not manually assigning IDs to our students. This is optional.
- For this reason, we also added a constructor to make a Student without an ID.
 
 
 - We are also using an autogeneration strategy for the ID. This way we are not manually assigning IDs to our students. This is optional.
 - An Entity must have a no-argument constructor.
 
 - The Student class is annotated as an 
 - Repository
- We are using an extension of the JPA Repository that comes with prebuilt database operations such as select all, select by id, select by any other reference, insert, delete, etc.
 - Annotate it as a 
@Repository. - We parametrize this using our object and its ID type.
public interface StudentRepository extends JpaRepository<Student, Long>=> We want to apply the JPA repository operations on theStudenttype. TheStudenthas an ID of typelong.
 - If we need special database queries that are not the standard ones mentioned above, we can create a method with a special purpose query as shown. This is an interface so no implementation body.
 
 - Service
- Annotated as a 
@Service. - It is the go-between from controller to database. In here we define what functions we need from the repository. A lot of the functions are default functions that our repository inherits from JPA (save, delete, findAll, findByX), some of them are custom made (getHonorsStudents, getStudentsByName).
 - It asks the repository to perform SQL queries.
 - The Repository class is 
@Autowired. This is for injecting the dependency to the repository. 
 - Annotated as a 
 - Controller
- Note this is a 
@Controllerand not a@RestController. This is the MVC Controller that returns views instead of objects. - All the methods return view names. The template engine will find the template with this name and render a view.
 - Return 
"redirect:/link/to/redirect"- if there is not necessarily a view attached to an action. e.g. going back to list after deleting one item. - Model attribute names and objects using 
model.addAttribute("studentsList", service.getAllStudents()); - The Service class is 
@Autowired. 
 - Note this is a 
 - Views
- All views live in 
src/main/resources/templates.- These are 
.ftlhfiles. They are FreeMarker templates. They work exactly like html to build pages, but they are used by the server to append data from the database. - You should configure you Visual Studio Code to associate 
.ftlhfiles withhtml.- Settings (Control +comma) -> Search "association" Add Item -> Key: *.ftlh, value: html ->OK.
 
 - You can also create subfolders in the templates folder. For example if you wanted views for the student to be in one folder you can create a 
studentssubfolder and put all the student views in there. Then your Controller would have toreturn "students/students-list"; 
 - These are 
 student-list.ftlh<#list studentsList as student>=> "Loop through Student list and make a table row for each Student"<td>${student.name}</td>=> "The text content for this this table data element should be whatever the student name is".
- For any form that sends POST requests with a form body, the input attribute "name" should match the data field.
- E.g for the student major 
<input type="text" id="major" name="major" placeholder="Major"/>we usename="major"to use the setters to match that field. If you do not include the input name attribute, a null will be insterted for that field. 
 - E.g for the student major 
 - Remember that any view must have a correspoding mapping. Any web page that is displayed MUST have a mapping in a controller to show the view.
- If you wanted to have a page that is a standalone form, you must make a mapping in the controller that returns the form page as a view.
 - Our server is running on Port 8081, if you open the web page directly in the browser, it is not served on localhost, it is just a file and will not have data from the database. If you open it from VSCode, it is hosted on Port 3000, which also will not connect to our database and server.
 - In this example, the form for creating a new student is its own page, therefore we must have a mapping to show that page.
- We have a 
@GetMappingthat shows us the form in our controller. - Clicking on the Create New Student button will hit this endpoint and return the form as a view.
 
 - We have a 
 - Same with the form for updating a Student. 
@GetMappingfor displaying the form.- Clicking on Edit for any student will hit this endpoint and return the form as a view.
 - Note we also use the model here to carry the Student data that we want to update so it will be shown on the form.
 
 - PLEASE NOTE: Web Browsers only allow GET and POST requests (unless you use additional JavaScript)! So we replace PUT mappings with POST mappings, and the DELETE with a GET!
 - Saving the updated data calls the corresponding POST mapping.
- When we get our Student data from a form, we do not need the 
@RequestBodyannotation. - NB: Saving and Updating in Hibernate uses the same method. If an entity exists it gets updated, else it gets created. This is why we attach an ID to our update form.
 
 - When we get our Student data from a form, we do not need the 
 
 
 - All views live in 
 - On the browser go to: 
http://localhost:8080/students