ECE366 - Lesson 6

Intro to Javascript and React

Instructor: Professor Hong

Review & Questions

## JPA
## Java Persistence API (JPA) - Standard Java EE (Jakarta EE) specification for ORM (Object–Relational Mapping) - Allows you to map between objects and database tables - Streamlines persistence to standard format - Reduces JDBC code - Focus on OOP
## application.properties ``` spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect spring.jpa.hibernate.ddl-auto=update spring.datasource.url=jdbc:postgresql://${POSTGRES_HOST}:5432/${POSTGRES_DB} spring.datasource.username=postgres spring.datasource.password=${POSTGRES_PASSWORD} ```
## Hard coded ``` spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect spring.jpa.hibernate.ddl-auto=update spring.datasource.url=jdbc:postgresql://localhost:5432/rps spring.datasource.username=postgres spring.datasource.password=password ```
## pom.xml ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> ```
## Important Annotations - ```@RestController``` - enables API endpoints - ```@Entity``` - a row from the database - ```@Table``` - the table name - ```@Id``` - the ID of a table row - ```@Column``` - a column of the table - ```@GeneratedValue``` - strategies for primary key
## Code Organization for JPA
## User Class data/User.java ``` package com.chrishong.rps.data; import jakarta.persistence.*; @Entity @Table(name="USERS") public class User { @Id @Column(name="USER_ID") @GeneratedValue(strategy = GenerationType.IDENTITY) private long userId; @Column(name="USER_NAME") private String userName; @Column(name="PASSWORD") private String password; @Column(name="TOTAL_GAMES") private int totalGames; @Column(name="TOTAL_WIN") private int totalWin; @Column(name="TOTAL_LOSS") private int totalLoss; @Column(name="TOTAL_TIE") private int totalTie; public long getUserId() { return userId; } public void setUserId(long userId) { this.userId = userId; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public int getTotalGames() { return totalGames; } public void setTotalGames(int totalGames) { this.totalGames = totalGames; } public int getTotalWin() { return totalWin; } public void setTotalWin(int totalWin) { this.totalWin = totalWin; } public int getTotalLoss() { return totalLoss; } public void setTotalLoss(int totalLoss) { this.totalLoss = totalLoss; } public int getTotalTie() { return totalTie; } public void setTotalTie(int totalTie) { this.totalTie = totalTie; } @Override public String toString() { return "User{" + "userId=" + userId + ", userName='" + userName + '\'' + ", password='" + password + '\'' + ", totalGames=" + totalGames + ", totalWin=" + totalWin + ", totalLoss=" + totalLoss + ", totalTie=" + totalTie + '}'; } } ```
## UserRepository Interface data/UserRepository.java ``` package com.chrishong.rps.data; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @Repository public interface UserRepository extends JpaRepository<User, Long> { } ```
## UserService business/UserService ``` package com.chrishong.rps.business; import com.chrishong.rps.data.User; import com.chrishong.rps.data.UserRepository; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.Comparator; import java.util.List; @Service public class UserService { private final UserRepository userRepository; public UserService(UserRepository userRepository) { this.userRepository = userRepository; } public List getUsers(){ Iterable users = this.userRepository.findAll(); List userList = new ArrayList<>(); users.forEach(user->{userList.add(user);}); return userList; } } ```
## WebserviceController webservice/WebserviceController.java ``` package com.chrishong.rps.webservice; import com.chrishong.rps.business.UserService; import com.chrishong.rps.data.User; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; @RestController public class WebserviceController { private final UserService userService; public WebserviceController(UserService userService) { this.userService = userService; } @GetMapping("/users") public List getUsers(){ System.out.println("getUsers"); return this.userService.getUsers(); } @GetMapping("/testuser") public String getTestUser() { return "TEST USERS"; } } ```
## Dockerfile ``` FROM maven:3.9.6-eclipse-temurin-21 AS build ADD . /project WORKDIR /project RUN mvn -e -Dmaven.test.skip package FROM eclipse-temurin:latest COPY --from=build /project/target/rpsjpa-0.0.1-SNAPSHOT.jar /app/rps.jar ENTRYPOINT java -jar /app/rps.jar ``` - Note, the ```-Dmaven.test.skip``` skips tests during the build
## Docker Compose ``` services: db: image: postgres volumes: - $HOME/srv/postgres:/var/lib/postgresql/data environment: - POSTGRES_DB=postgres - POSTGRES_PASSWORD=password expose: - 5432:5432 ports: - 5432:5432 restart: always app: build: . environment: - POSTGRES_HOST=db - POSTGRES_DB=rps2 - POSTGRES_USER=postgres - POSTGRES_PASSWORD=password expose: - 8080:8080 ports: - 8080:8080 depends_on: - db ``` - Don't forget to update the applications.properties file!
## Basic HTML
## What is HTML? - HyperText Markup Language (not a programming language) - Standard markup language for website creation - Maintained World Wide Web Consortium (W3C) - Parts - opening tag, content, closing tag
## New pom.xml Dependency - Building upon last week's JPA example ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> ``` - Thymeleaf templates allow you to create basic web applications
## Web Controller web/UserController ``` package com.chrishong.rps.web; import com.chrishong.rps.business.UserService; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @Controller @RequestMapping("/users") public class UserController { private final UserService userService; public UserController(UserService userService) { this.userService = userService; } @RequestMapping(method = RequestMethod.GET) public String getUsers(Model model){ model.addAttribute("users", this.userService.getUsers()); return "rps-users"; } } ```
## Webservice API webservice/WebserviceController ``` package com.chrishong.rps.webservice; import com.chrishong.rps.business.UserService; import com.chrishong.rps.data.User; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; @RestController @RequestMapping("/api") public class WebserviceController { private final UserService userService; public WebserviceController(UserService userService) { this.userService = userService; } @GetMapping("/users") public List getUsers(){ System.out.println("getUsers"); return this.userService.getUsers(); } } ```
## Index.html resources/static/index.html ``` <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>RPS</title> </head> <body> <h1>Welcome to RPS</h1> <p><a href="/users">Users</a></p> </body> </html> ```
## rps-users.html resources/templates/rps-users.html ``` <!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>RPS: Users</title> </head> <body> <h1>RPS Users</h1> <table> <tr> <td>User ID</td> <td>User Name</td> <td>Password</td> <td>Total Wins</td> </tr> <tr th:each="user: ${users}"> <td th:text="${user.userId}">UserId</td> <td th:text="${user.userName}">UserName</td> <td th:text="${user.password}">Password</td> <td th:text="${user.totalGames}">TotalGames</td> </tr> </table> </body> </html> ```
## Running the Site ``` localhost:8080 localhost:8080/users localhost:8080/api/users ``` You can read more here: [https://www.thymeleaf.org/doc/tutorials/3.0/thymeleafspring.html](https://www.thymeleaf.org/doc/tutorials/3.0/thymeleafspring.html)
## Intro to React
## What is React? - Javascript library - Created at Facebook - Open-sourced in 2013 - Docs: [https://react.dev/reference/react](https://react.dev/reference/react)
## What is Javascript? - High level, interpreted language - Allows you to implement complex features on web pages - Used with HTML and CSS (for styling) - Logging: ```console.log();```
## Setup/Installation - Add React Developer Tools from Chrome Extensions and add to chrome - Inspect Element -> Components - Can also install on Firefox
## React in Index.html ``` <!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <script src="https://unpkg.com/react@17/umd/react.development.js" crossorigin ></script> <script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js" crossorigin ></script> <title>React ⚛️</title> </head> <body> <h1>Getting Started with React</h1> </body> </html> ```
## React in Index.html ``` <!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <script src="https://unpkg.com/react@17/umd/react.development.js" crossorigin></script> <script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js" crossorigin></script> <title>React ⚛️</title> </head> <body> <div id="root"></div> <script type="text/javascript"> ReactDOM.render( React.createElement("h1", null, "Getting Started!"), document.getElementById("root") ); </script> </body> </html> ```
## ReactDOM.render ReactDOM.render() - 2 arguments - what to create: React.createElement("h1", null, "TEXT") - where to put it: document.getElementById("root")
## Variable Names ``` <!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <script src="https://unpkg.com/react@17/umd/react.development.js" crossorigin ></script> <script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js" crossorigin ></script> <title>React ⚛️</title> </head> <body> <div id="root"></div> <script type="text/javascript"> let heading = React.createElement( "h1", { style: { color: "blue" } }, "Heyyyy Everyone!" ); ReactDOM.render( heading, document.getElementById("root") ); </script> </body> </html> ```
## JSX, Babel ``` <!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <script src="https://unpkg.com/react@17/umd/react.development.js" crossorigin></script> <script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js" crossorigin></script> <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> <title>React ⚛️</title> </head> <body> <div id="root"></div> <script type="text/babel"> ReactDOM.render( <ul> <li>🤖</li> <li>🤠</li> <li>🌝</li> </ul>, document.getElementById("root") ); </script> </body> </html> ``` - Javascript XML - Can access variables with ```{``` variable ```}```
## More JSX syntax ``` <!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <script src="https://unpkg.com/react@17/umd/react.development.js" crossorigin ></script> <script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js" crossorigin ></script> <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> <title>React ⚛️</title> </head> <body> <div id="root"></div> <script type="text/babel"> let robot = "🤖"; let cowboy = "🤠"; let moon = "🌝"; let name = "React"; ReactDOM.render( <ul> <li>{robot}</li> <li>{cowboy}</li> <li>{moon}</li> <li>{name.toUpperCase()}</li> <li>{name.length}</li> </ul>, document.getElementById("root") ); </script> </body> </html> ```
## React Components - A function that returns JSX and can be rendered in DOM - Should use capital letter for component/function name - Multiple React components should be wrapped into 1 component - Can be used to display dynamic data
## Component Properties - Add props argument to component functions - A container where you can put any properties in the component
## Example with React Components and Image ``` <!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <script src="https://unpkg.com/react@17/umd/react.development.js" crossorigin ></script> <script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js" crossorigin ></script> <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> <title>RPS</title> </head> <body> <div id="root"></div> <script type="text/babel"> function Header(props) { return ( <header> <h1>{props.name}'s RPS</h1> </header> ); } function Main(props) { return ( <section> <img height={200} src="./rps.png" alt="Rock Paper Scissors" /> <ul> {props.users.map((user) => ( <li key={user.id}> {user.title} </li> ))} </ul> </section> ); } function Footer(props) { return ( <footer> <p>Copyright {props.year}</p> </footer> ); } const users = [ "Alpha", "Beta", "Gamma", ]; const userObjects = users.map( (user, i) => ({ id: i, title: user }) ); function App() { return ( <React.Fragment> <Header name="Cooperps" /> <Main adjective="amazing" users={userObjects} /> <Footer year={new Date().getFullYear()} /> </React.Fragment> ); } ReactDOM.render( <App />, document.getElementById("root") ); </script> </body> </html> ```
## React
## Create React App - Install nodejs - [https://nodejs.org/](https://nodejs.org/) - nodejs on WSL - [https://learn.microsoft.com/en-us/windows/dev-environment/javascript/nodejs-on-wsl](https://learn.microsoft.com/en-us/windows/dev-environment/javascript/nodejs-on-wsl) - Remove old version of node: ``` sudo apt-get purge --auto-remove nodejs ``` - ```node -v``` - to check node version - ```npm -v``` - check npm version - ```npx create-react-app rps``` - ```npm start```
## Important Parts - package.json - dependencies - react, react-dom, react-scripts - src/index.js - entry point of the application, main JS file - renders App - React.StrictMode - additional checks - public/index.html - similar to index.html w/ all your JSX injected ``` npm install npm start ```
## Javascript Destructuring Allows you to get specific elements from an argument/props ``` function App({ myVariable }) { return (

{myVariable

); } ``` - Also Array destructuring allows you to get certain elements from an array
## Changing States with useState App.js ``` import "./App.css"; import { useState } from "react"; function App() { const [emotion, setEmotion] = useState("happy"); return ( <div className="App"> <h1>Current emotion is {emotion}</h1> <button onClick={() => setEmotion("sad")}> Sad </button> <button onClick={() => setEmotion("excited")} > Excited </button> </div> ); } export default App; ```
## Side Effects with useEffect ``` import "./App.css"; import { useState, useEffect } from "react"; function App() { const [emotion, setEmotion] = useState("happy"); const [secondary, setSecondary] = useState("tired"); useEffect(() => { console.log(`It's ${emotion} around here!`); }, [emotion]); useEffect(() => { console.log(`It's ${secondary} around here!`); }, [secondary]); return ( <div className="App"> <h1>Current emotion is {emotion}</h1> <button onClick={() => setEmotion("sad")}> Sad </button> <button onClick={() => setEmotion("excited")} > Excited </button> <h2> Current secondary emotion is {secondary}. </h2> <button onClick={() => setSecondary("grateful")} > Grateful </button> </div> ); } export default App; ``` - dependencyArray is the 2nd argument for useEffect - No argument makes it called everytime - Empty array makes it called once
## Fetching Data from Service fetch is built into the browser to make an HTTP request to get data ``` import "./App.css"; import { useState, useEffect } from "react"; function App() { const [data, setData] = useState(null); useEffect(() => { fetch( `http://localhost:8080/api/users` ) .then((response) => response.json()) .then(setData); }, []); if (data) return ( <pre>{JSON.stringify(data, null, 2)}</pre> ); return <h1>Data</h1>; } export default App; ```
## Update CORS in Spring Boot server WebserviceController.java ``` @CrossOrigin @GetMapping("/users") ```