How to Loop in React

In this tutorial we'll see how to loop an array in React.

Loop in React JSX using map function

Preferred way in React is to use a map() function to iterate an array.

Syntax of map function is as given below

array.map(function(element, index, arr), thisValue)

Parameters in the map function are-

  1. function- map function calls the specified function once for each element in an array.

    The arguments of the callback function are-

    • element- The current element being processed in the array.
    • index- The index of the current element being processed in the array. This argument is optional.
    • arr- The array map was called upon. This argument is optional.
  2. thisArg- Optional parameter. Value to use as this when executing callbackFn.

You can also use arrow function to define the callback function in the map.

map((element, index, arr) => { /* … */ })

Looping in React example

In the example there is an array of product catalogue which is iterated using map function to render each product item.

// Initial list of products
const productList = [
    { id: 1, name: 'Laptop', price: 455.50 },
    { id: 2, name: 'Mouse', price: 15.89 },
    { id: 3, name: 'USB', price: 10.00 },
    { id: 4, name: 'HDD', price: 55.50 },
];
const Products = () => {

    return (
        <div className="container">
            <ul>
                {productList.map((product) => 
                    <li key={product.id}>{product.id} {product.name} {product.price}</li>
                )}
            </ul>
        </div>
    );
}
export default Products;

On running it, you should see a rendered list of product items.

.	1 Laptop 455.5
.	2 Mouse 15.89
.	3 USB 10
.	4 HDD 55.5

You can also store the array returned by map() function to a variable and then render that array instead. This will help in keeping your JSX clean.

// Initial list of products
const productList = [
    { id: 1, name: 'Laptop', price: 455.50 },
    { id: 2, name: 'Mouse', price: 15.89 },
    { id: 3, name: 'USB', price: 10.00 },
    { id: 4, name: 'HDD', price: 55.50 },
];
const Products = () => {
    const productItems = productList.map((product) => 
        <li key={product.id}>{product.id} {product.name} {product.price}</li>
    );
    return (
        <div className="container">
            <ul>
                {productItems}
            </ul>
        </div>
    );
}

export default Products;

Why key attribute is required

You must have noticed a key attribute being used with value as product id in the above example.

<li key={product.id}>

If you don't use a unique key for each element, you will get a warning

"Warning: Each child in a list should have a unique key prop."

This Key attribute helps React to identify which elements have changed, added, or are removed. Keys should be given to the elements inside the array to give the elements a stable identity.

The best way to pick a key is to use a string that uniquely identifies a list item among all the other items. Most often you will have unique IDs in your data that can be used as keys.

If the item you're trying to loop through does not have a unique element which can be used as a key, you can use the item index as a key for each iterated item.

// Scenario where products have no IDs
const productItems = productList.map((product, index) => 
     <li key={index}>{product.name} {product.price}</li>
Though use index only as a last resort. As per React documentation-

We don't recommend using indexes for keys if the order of items may change. This can negatively impact performance and may cause issues with component state.

Using forEach to iterate array

Though map() function is the preferred way to iterate an array in React but you do have other choices like forEach, for-of, traditional for loop. Here is an example using forEach to iterate an array.

// Initial list of products
const productList = [
    { id: 1, name: 'Laptop', price: 455.50 },
    { id: 2, name: 'Mouse', price: 15.89 },
    { id: 3, name: 'USB', price: 10.00 },
    { id: 4, name: 'HDD', price: 55.50 },
];
const Products = () => {
    const getProductItems = () => {
        let productItems = [];
        productList.forEach((product) => {
            productItems.push(<li key={product.id}>{product.id} {product.name} {product.price}</li>)
        });
        return productItems;
    };
    return (
        <div className="container">
            <ul>
                {getProductItems()}
            </ul>
        </div>
    );
}

export default Products;

Looping in React to render as Table

Here is another example where the array of products is iterated and each product item is rendered in a table as a table row. Uses react-bootstrap for styling.

import Table from 'react-bootstrap/Table';

// Initial list of products
const productList  = [
    { id: 1, name: 'Laptop', price: 455.50 },
    { id: 2, name: 'Mouse', price: 15.89 },
    { id: 3, name: 'USB', price: 10.00 },
    { id: 4, name: 'HDD', price: 55.50 },
];
const Products = () => {
    return (
        <div className="container">

            <Table striped bordered hover size="sm">
                <thead>
                    <tr>
                        <th>ID</th>
                        <th>NAME</th>
                        <th>PRICE</th>
                    </tr>
                </thead>
                <tbody>
                {productList.map((product) => 
                    <tr key={product.id}>
                        <td>{product.id}</td>
                        <td>{product.name}</td>
                        <td>{product.price}</td>
                    </tr>

                )}
                </tbody>
            </Table>
        </div>
    );
}
export default Products;
Loop in React

Keeping in separate component while looping

You may want to have separate component for rendering each iterated element. In that case you should keep the key in the tag for the Component itself.

For example, if there is a separate ProductItem component to render each product item.

ProductItem.js

const ProductItem = (props) => {
    return (
        <tbody>
            <tr>
                <td>{props.item.id}</td>
                <td>{props.item.name}</td>
                <td>{props.item.price}</td>
            </tr>
        </tbody>
    )
}
export default ProductItem;

Products.js

import ProductItem from "./ProductItem";
import Table from 'react-bootstrap/Table';

// Initial list of products
const productList = [
    { id: 1, name: 'Laptop', price: 455.50 },
    { id: 2, name: 'Mouse', price: 15.89 },
    { id: 3, name: 'USB', price: 10.00 },
    { id: 4, name: 'HDD', price: 55.50 },
];
const Products = () => {
    return (
        <div className="container">
            <Table striped bordered hover size="sm">
                <thead>
                    <tr>
                        <th>ID</th>
                        <th>NAME</th>
                        <th>PRICE</th>
                    </tr>
                </thead>
                {productList.map((val, key) => <ProductItem key={key} item={val} />)}
            </Table>
        </div>
    );
}
export default Products;

As you can see here <ProductItem> tag itself has the key attribute.

<ProductItem key={key} item={val} />

That's all for the topic How to Loop in React. If something is missing or you have something to share about the topic please write a comment.


You may also like

React useEffect Hook With Examples

In this tutorial you'll learn about useEffect() hook in React which performs side-effects in functional components.

What is a side effect

Side effect is some task that you want to separate from rendering. Some examples of what can be termed as side effect are-

  1. Send Http Requests for storing or fetching data to Backend servers
  2. Manipulating DOM directly
  3. Setting and managing timer functions

Syntax of useEffect

useEffect(callback, [dependencies]);

The useEffect hook takes two arguments.

First argument- A callback function containing the side-effect logic. It should be executed after component rendering, if the specified dependencies (second parameter) changes.

Second argument- Dependencies of this effect which is an optional argument and passed as an array. The useEffect hook executes the callback function (first parameter) only if the dependencies changed.

When does useEffect run

When does useEffect run depends on the dependencies passed.

  1. If no dependencies are passed the side-effect is executed after every rendering.
    useEffect(() => {
      // callback logic
    });
    
  2. If an empty array is passed as dependency then the side-effect runs only once after initial render.
    useEffect(() => {
      // callback logic
    }, []);
    
  3. When dependency array has state or props passed with in the array then the side-effect runs after initial render and then only when the dependency value changes.
    useEffect(() => {
      // callback logic
    }, [prop, state]);
    

useEffect Example

Here is a simple useEffect React hook example where we have a counter stored in a state. Every click of button increments the counter by 1 (changes the state).

Every time value of counter changes we also want to log the current counter value. This logging logic should be implemented as a side-effect.

Since execution of side-effect depends on the counter value so the state variable should be passed as dependency in the useEffect hook.

Counter.js

import { useEffect, useState } from "react";
import { Button } from "react-bootstrap";

const Counter = () => {
    const [count, setCount] = useState(0);

    function countChangeHandler(){
        setCount(count + 1);
    };
    useEffect(() => {
        console.log("Count has been updated " + count)
    }, [count])
    return(
        <div>
            <p>You clicked {count} times</p>
            <Button variant="primary" onClick={countChangeHandler}>Click Me</Button>
        </div>
    );
   
}

export default Counter;

on running it by adding following tags in App.js

return (
    <Counter></Counter>
);
useEffect with dependency

As you can see log message is logged to show count till 4 if button is clicked 4 times.

Now if you change the useEffect to have an empty array as a dependency and then run it.

useEffect(() => {
        console.log("Count has been updated " + count)
    }, [])
React useEffect without dependency

As you can notice now even if button is clicked 4 times, message is logged only once after initial render.

Component rendering and side-effect logic are separate

Component rendering and side-effect logic should be kept separate. Any side effect logic should be written as a function with in a useEffect hook.

Performing a side-effect directly in the component may affect the component rendering. If we need to perform a side effect, it should be done after component rendering is finished.

You can think of useEffect Hook as a combination of componentDidMount, componentDidUpdate, and componentWillUnmount Component lifecycle methods.

To show how it may affect the rendering if side-effect logic is placed directly in the component we'll show the frequently used login example. There are 3 components in this example one for top header, then for login page and last for landing page.

Here are the images to show the final pages.

Login Page

Landing Page after login

TopHeader.js (Uses react-bootstrap)

import { Container, Nav, Navbar } from "react-bootstrap"
const TopHeader = (props) => {
    return (
        <Navbar bg="dark" variant="dark" expand="lg">
          <Container>
            <Navbar.Brand href="#home">Login Page</Navbar.Brand>
            <Navbar.Toggle aria-controls="basic-navbar-nav" />
            <Navbar.Collapse id="basic-navbar-nav">
              <Nav className="me-auto">
                <Nav.Link href="#admin">Admin</Nav.Link>
              </Nav>
              {props.isUserAuthenticated && (
              <Nav className="justify-content-end">
                <Nav.Item>
                  <Nav.Link onClick={props.onLogout}>Logout</Nav.Link>
                </Nav.Item>
              </Nav>
              )}
            </Navbar.Collapse>
          </Container>
        </Navbar>
    );
}
export default TopHeader;

Login.js

import Form from 'react-bootstrap/Form';
import Button from 'react-bootstrap/Button';
import { Card } from 'react-bootstrap';
import { useState } from 'react';

const Login = (props) => {
    const [user, setUser] = useState('');
    const userChangeHandler = (event) => {
        setUser(event.target.value);
    }
    const submitHandler =(event) => {
        event.preventDefault();
        props.onLogin(user);
    }
    return (
        <Card className="mt-3 mx-auto" style={{ width: '25rem' }}>
            <Form onSubmit={submitHandler}  className="mx-4">
                <Form.Group className="mb-3">
                <Form.Label>User Name</Form.Label>
                <Form.Control type="text" name="name" 
                    placeholder="Enter user name"  value={user}
                    onChange={userChangeHandler} />
                </Form.Group>
                <Form.Group className="mb-3">
                <Form.Label>Password</Form.Label>
                <Form.Control type="password" name="password" 
                    placeholder="Enter password"  />
                </Form.Group>
                <div className="text-center mb-3">
                    <Button variant="primary" type='submit'>Login</Button>
                </div>
            </Form>
        </Card>
    );
}
export default Login;

LandingPage.js

const LandingPage = (props) => {
    return(
    <p>User logged in, welcome to our site</p>
    );
}
export default LandingPage;

If you want to ensure that user remains logged in if you refresh the page after user has logged in then you need to store the log in state. Suppose you do it as given below in App.js without using useEffect hook.

App.js

import { useEffect, useState} from "react";
import { Fragment } from "react";
import TopHeader from "./Components/Examples/TopHeader";
import Login from "./Components/Examples/Login";
import LandingPage from "./Components/Examples/LandingPage";
function App() {

  const [isLoggedIn, setIsLoggedIn] = useState(false);

  const loginActionHandler = (userName) => {
    // store the logged in state
    localStorage.setItem('userLoggedIn', true);
    setIsLoggedIn(true);
  }

  const logoutActionHandler = () => {
    localStorage.removeItem('userLoggedIn');
    setIsLoggedIn(false);
  }
  
  // side-effect logic Written directly
  const loggedIn = localStorage.getItem('userLoggedIn');
  if(loggedIn){
    setIsLoggedIn(true);
  }


  return (
    <Fragment>
    <TopHeader isUserAuthenticated={isLoggedIn} onLogout={logoutActionHandler}></TopHeader>
    {!isLoggedIn && <Login onLogin={loginActionHandler}></Login>}
    {isLoggedIn && <LandingPage onLogout={logoutActionHandler}></LandingPage>}
    </Fragment>
  );
};

export default App;

With this way you will get the following error for the infinite re-rendering.

Error: Too many re-renders. React limits the number of renders to prevent an infinite loop.

This happens because you are changing the state again in the if condition. It triggers component rendering because of state change comes back to the same if condition and again triggers component rendering resulting in infinite loop.

if(loggedIn){
    setIsLoggedIn(true);
  }

That is why side-effect logic, which in this case is to verify whether user is already logged in while rendering should be written as a callback function with in the useEffect hook.

  useEffect(()=>{
    const loggedIn = localStorage.getItem('userLoggedIn');
    if(loggedIn){
      setIsLoggedIn(true);
    }
  }, []);

With that change Login and Logout logic should work fine, even if page is refreshed after user logs in.

cleanup function in useEffect

Some side-effects require a clean up in order to avoid memory leaks. Some examples are clear timers, close subscriptions, close sockets.

With in your useEffect hook return a function with the cleanup logic. This function is considered the side-effect cleanup function by useEffect.

useEffect(() => {
  // Side-effect logic
  ...
  return function cleanup() {
    // cleanup logic
    ...
  };
}, [dependencies]);

Here is an example when the side-effect cleanup is used. Again, we have a counter that is incremented every second, to do that setTimeout function is used. To cleanup this side-effect timer is stopped by returning a clearTimeout function.

import { useEffect, useState } from "react";

const Counter = () => {
    const [count, setCount] = useState(0);

    function countChangeHandler(){
        setCount(count + 1);
    };
    useEffect(() => {
        let timer = setTimeout(
            () => {
                setCount(count + 1);
            }, 1000);
        // cleanup
        return () => clearTimeout(timer);
    }, [count])
    return(
        <div>
            <p>Current count is {count}</p>
        </div>
    );
   
}

export default Counter;

That's all for the topic React useEffect Hook With Examples. If something is missing or you have something to share about the topic please write a comment.


You may also like

Spring Boot MVC Form Validation Example

In this Spring Boot MVC tutorial we’ll see how to validate form fields using standard validation annotations.

Form validation is important part of web applications where user input is required so that users can’t enter invalid values. You will also see how to display error messages in front of the field with invalid value so that the user can re-enter input to make it valid.

Starter dependencies

Starter dependencies that you will be selecting for this Spring Boot form validation example are-

spring-boot-starter-web spring-boot-starter-thymeleaf spring-boot-devtools

Example uses Thymeleaf templates for view thus the thymeleaf starter.

Applications that use spring-boot-devtools will automatically restart whenever files on the classpath change, so you don't have to rebuild and restart the server yourself every time.

Maven – pom.xml

pom.xml with the above mentioned starter dependencies.

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- For hot swapping -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-devtools</artifactId>
  <optional>true</optional>
</dependency>

Bean Validation API and Hibernate Validator

For form fields validation, Bean Validation API is used which defines some annotations that reside in javax.validation.constraints package.

Note that Bean Validation API just provide the interfaces, Hibernate Validator is the implementation of the API.

You will get required jars just by including the spring-boot-starter-web. All you need to do is to use the annotations with the fields to specify the constraints.

Some of the annotations that are defined in Java Bean Validation API are as follows-

  • @NotBlank- The annotated element must not be null and must contain at least one non-whitespace character.
  • @NotEmpty- The annotated element must not be null nor empty.
  • @NotNull- The annotated element must not be null.
  • @Size- The annotated element size must be between the specified boundaries. Boundaries can be specifies using main and max attributes.
  • @Digits- The annotated element must be a number within accepted range.
  • @Max- The annotated element must be a number whose value must be lower or equal to the specified maximum.
  • @Min- The annotated element must be a number whose value must be higher orequal to the specified minimum.
  • @Email- The string has to be a well-formed email address.

Spring Boot form validation example steps

What we are building here is a Thymeleaf view which is a form for User registration. The classes that are needed are-

  1. A Model bean class (User.java) with fields annotated with required constraints.
  2. userform.html Thymeleaf template which is the user registration form UI.
  3. When submit button is clicked in the registration form Validation for the fields happen, if there is any error registration form is shown again with the error messages. If there is no error then entered user data is displayed using user.html Thymeleaf template.

Screen shot of the form with validation errors-

Spring Boot form validation

Spring Boot form validation - Model class

There is a model class User with the fields and the constraints.

import javax.validation.constraints.Email;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Size;

public class User {
  @NotEmpty(message = "Field can't be left empty")
  @Size(min=2, max=20, message = "Has to be in 2-20 chars range")
  private String firstName;
  @NotEmpty
  @Size(min=2, max=20)
  private String lastName;
  @NotEmpty
  @Email
  private String email;
  public String getFirstName() {
    return firstName;
  }
  public void setFirstName(String firstName) {
    this.firstName = firstName;
  }
  public String getLastName() {
    return lastName;
  }
  public void setLastName(String lastName) {
    this.lastName = lastName;
  }
  public String getEmail() {
    return email;
  }
  public void setEmail(String email) {
    this.email = email;
  }	
}

As you can see fields are annotated with the required constraints.

  • firstName can’t be null or empty and must have 2 to 20 characters.
  • lastName can’t be null or empty and must have 2 to 20 characters.
  • email can’t be empty and should be a well formed email.

You can specify your own messages using ‘message’ attribute if no message is specified then default message is displayed.

Spring Boot form validation - Thymeleaf templates

In src/main/resources/templates create a userform.html file.

<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Spring Boot form validation</title>
<link rel="stylesheet" th:href="@{/css/style.css}"/>
</head>
<body>
  <h1>User Registration Form</h1>
  <form action="#" th:action="@{/showUser}" th:object="${user}" method="post">
    <table>
      <tr>
        <td>First Name:</td>
        <td><input type="text" th:field="*{firstName}" placeholder="Enter First Name"/></td>
        <td th:if="${#fields.hasErrors('firstName')}" th:errors="*{firstName}" class="error"></td>
      </tr>
      <tr>
        <td>Last Name:</td>
        <td><input type="text" th:field="*{lastName}" placeholder="Enter Last Name"/></td>
        <td th:if="${#fields.hasErrors('lastName')}" th:errors="*{lastName}" class="error"></td>
      </tr>
      <tr>
        <td>Email:</td>
        <td><input type="text" th:field="*{email}" placeholder="email"/></td>
        <td th:if="${#fields.hasErrors('email')}" th:errors="*{email}" class="error"></td>
      </tr>
      <tr>
        <td><button type="submit">Submit</button></td>
      </tr>
    </table>
  </form>
</body>
</html>

In the form tag action is specified as “/showUser” (th:action="@{/showUser}") and the method is post. Object this form is bound with is the user object (th:object="${user}")

With every field a new column is added for rendering validation error message.

<td th:if="${#fields.hasErrors('firstName')}" th:errors="*{firstName}" class="error"></td>

Another template that is used for displaying User data src/main/resources/templates/user.html

<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
  <h1>User Details</h1>
  <table>
    <tr><td th:text="'First Name: ' + ${user.firstName}"></td> </tr>
    <tr><td th:text="'Last Name: ' + ${user.lastName}"></td> </tr>
    <tr><td th:text="'Email: ' + ${user.email}"></td> </tr>
  </table>
</body>
</html>

There is also a CSS class used for styling the error messages, you would have noticed its usage in src/main/resources/templates/userform.html file.

<link rel="stylesheet" th:href="@{/css/style.css}"/>

And here

<td th:if="${#fields.hasErrors('email')}" th:errors="*{email}" class="error">

So create a file src/main/resources/static/css/style.css

.error {
  color: red;
  font-style: italic;
}

Spring Boot form validation – Controller class

In UserController.java class there are handler methods mapped to URL paths.

import javax.validation.Valid;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import com.knpcode.sb.model.User;

@Controller
public class UserController {
  @GetMapping(value = "/registerUser")
  public String registerUser(Model model) { 
    model.addAttribute("user", new User());
    return "userform";
  }
	
  @PostMapping(value="/showUser")
  public String showUser(@Valid @ModelAttribute("user") User user, BindingResult result, Model model) { 
    if(result.hasErrors()) {
      return "userform";
    }
    model.addAttribute("user", user);
    return "user";
  }
}

In the showUser method there is a @Valid annotation used with the User class object. Using @Valid annotation ensures that the constraints defined on the object and its properties are to be validated.

If there are validation errors or not is checked using instance of BindingResult. If there are validation errors registration form is rendered again with the error messages otherwise logical view name “user” is returned which renders the user.html template.

Application class

You can run the application by executing the application class which has the main method.

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringBootProjectApplication {
  public static void main(String[] args) {
    SpringApplication.run(SpringBootProjectApplication.class, args);
  }
}

Once the application has successfully started you can access the application using the URL’s as per the controller mapping.

http://localhost:8080/registerUser

Spring Boot MVC

http://localhost:8080/showUser

With validation errors

Spring Boot MVC form

That's all for the topic Spring Boot MVC Form Validation Example. If something is missing or you have something to share about the topic please write a comment.


You may also like

Spring Boot With JSP Example

In this Spring Boot with JSP as view example we’ll see how to use JSP as a view with Spring Boot and what extra configuration is needed to do that.

First thing to do is to select packaging as “war” while creating Maven project.

If you are using STS then while creating new Spring starter project, choose packaging as war in “New Spring Starter Project”.

STS maven packaging option

If you are using eclipse then choose a webapp project in the archetype selection while creating Maven project.

See example of creating Spring Boot application using STS here- Spring Boot Example Using Spring Tool Suite (STS)

Starter dependencies that are needed-

  • spring-boot-starter-web
  • spring-boot-starter-tomcat

Project structure

Project structure for this Spring Boot JSP example should be as given below.

Spring Boot JSP project

Maven – pom.xml

pom.xml should have the given dependencies. Following dependency is needed for compiling the JSP files.

<dependency>
	<groupId>org.apache.tomcat.embed</groupId>
	<artifactId>tomcat-embed-jasper</artifactId>
	<scope>provided</scope>
</dependency>

<?xml version="1.0" encoding="UTF-8"?>
  <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.2.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
  </parent>
  <groupId>com.example</groupId>
  <artifactId>springbootwebdemo</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>
  <name>SpringBootWebDemo</name>
  <description>Demo project for Spring Boot</description>

  <properties>
    <java.version>1.8</java.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-tomcat</artifactId>
      <scope>provided</scope>
    </dependency>
     <!-- To compile JSP files -->
    <dependency>
      <groupId>org.apache.tomcat.embed</groupId>
      <artifactId>tomcat-embed-jasper</artifactId>
      <scope>provided</scope>
    </dependency>
        
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jstl</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
      <exclusions>
        <exclusion>
          <groupId>org.junit.vintage</groupId>
          <artifactId>junit-vintage-engine</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>
</project>

Spring Boot MVC - JSP files

In the example these are 3 JSP files.

  1. home.jsp- Landing page which gives the link to start the user registration process.
  2. userregister.jsp- JSP with input box to enter data for the user which is bound to a user object.
  3. user.jsp- Displays the user data using the user object which is bound in previous “userregister” page.

home.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html>

<html>
<head>
<meta charset="ISO-8859-1">
<title>Spring BOOT MVC Example - Home JSP</title>
</head>
<body>
<body>
  <div>${message}</div>
  <a href="/registerUser">Register User</a>
</body>
</body>
</html>
userregister.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>User Registration</title>
</head>
<body>
  <!-- Values entered here are bound to the properties of 
      user object assigned here to modelAttribute -->
  <form:form action="/showUser" modelAttribute="user" method="post">
    <table>
      <tr>
        <td>
          <form:label path="firstName">First Name</form:label>
        </td>
        <td>
          <form:input path="firstName" id="firstname" />
        </td>
      </tr>
      <tr>
        <td>
          <form:label path="lastName">Last Name</form:label>
        </td>
        <td>
          <form:input path="lastName" id="lastname" />
        </td>
      </tr>
      <tr>
        <td><input type="submit" value="Submit"></td>
      </tr>
    </table>
  </form:form>
</body>
</html>

user.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>User Data</title>
</head>
<body>
<table>
<tr>
<td>First Name: ${User.firstName}</td>
</tr>
<tr>
<td>Last Name: ${User.lastName}</td>
</tr>
</table>
</body>
</html>

Spring Boot MVC - Controller class

UserController.java file which specifies URL mapping to methods.

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.example.model.User;

@Controller
@RequestMapping(value = "/")
public class UserController {
  @GetMapping("/register")
  public String showHome(Model model) {
    model.addAttribute("message", "Spring Boot MVC Example");
    return "home";
  }
	
  @RequestMapping(value = "/registerUser", method = RequestMethod.GET)
  public String registerUser(Model model) { 
    // Add new user to model to be bound with view (JSP)
    model.addAttribute(new User());
    return "userregister";
  }
	
  @RequestMapping(value = "/showUser", method = RequestMethod.POST)
  public String showUser(@ModelAttribute("user") User user, Model model) { 
    model.addAttribute("User", user);
    return "user";
  }
}

Spring Boot application class

Application class with main method extends SpringBootServletInitializer class and overrides its configure method.

SpringBootServletInitializer is an opinionated WebApplicationInitializer to run a SpringApplication from a traditional WAR deployment. It binds Servlet, Filter and ServletContextInitializer beans from the application context to the server.

To configure your web application you need to override the configure(SpringApplicationBuilder) method.

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

@SpringBootApplication
public class SpringBootWebDemoApplication extends SpringBootServletInitializer{
  @Override
  protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
    return application.sources(SpringBootWebDemoApplication.class);
  }
  public static void main(String[] args) {
    SpringApplication.run(SpringBootWebDemoApplication.class, args);
  }
}

Configuring view resolver

To resolver view to the JSP file you can configure InternalResourceViewResolver in the application.properties as given below.

application.properties

spring.mvc.view.prefix: /WEB-INF/JSP/
spring.mvc.view.suffix: .jsp

Running the application

You can run the application by executing the SpringBootWebDemoApplication class which has the main method.

Once the application has successfully started you can access the application using the URL’s as per the controller mapping.

http://localhost:8080/register

Spring Boot JSP example

http://localhost:8080/registerUser

http://localhost:8080/showUser

That's all for the topic Spring Boot With JSP Example. If something is missing or you have something to share about the topic please write a comment.


You may also like

Spring Boot + Spring Data JPA + MySQL + Spring RESTful

In this tutorial we’ll see how to create Spring Boot + Spring Data JPA + MySQL + Spring RESTful Webservice. There is already a similar example in the post Spring Data JPA Example. By using Spring Boot you will see a significant reduction in required configuration.

If you want to see how to create Maven project, please check this post- Create Java Project Using Maven in Eclipse

Maven Dependencies

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.knpcode</groupId>
  <artifactId>SpringBootProject</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.6.RELEASE</version>
  </parent>
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- MySQL Driver -->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <scope>runtime</scope>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>
</project>

In our configuration, Spring Boot version is 2.1.6 so Spring Boot gets the dependencies which support this version.

For Spring Data JPA you need to add spring-boot-starter-data-jpa that will get Spring Data, Hibernate and other jars required for JPA.

Since we are developing a web service, we add a spring-boot-starter-web dependency, that adds the necessary dependencies required for creating a Spring web application.

spring-boot-maven-plugin is also added, this plugin provides many convenient features-

  • It helps to create an executable jar (├╝ber-jar), which makes it more convenient to execute and transport your service.
  • It also searches for the public static void main() method to flag the class having this method as a runnable class.

With these dependencies added Spring Boot takes care of getting the required jar dependencies, even an embedded web server (Tomcat in this case) because of the starter web dependency.

DB table Query

MySQL DB table used for this Spring Boot and Spring data JPA example can be created using the following query.

CREATE TABLE `employee` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `first_name` varchar(45) DEFAULT NULL,
  `last_name` varchar(45) DEFAULT NULL,
  `department` varchar(45) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

JPA Entity class

Entity class which maps to the employee table in DB.

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="employee")
public class Employee {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private int id;
  @Column(name="first_name")
  private String firstName;
  @Column(name="last_name")
  private String lastName;
  @Column(name="department")
  private String dept;
  public int getId() {
    return id;
  }
  public void setId(int id) {
    this.id = id;
  }
  public String getFirstName() {
    return firstName;
  }
  public void setFirstName(String firstName) {
    this.firstName = firstName;
  }
  public String getLastName() {
    return lastName;
  }
  public void setLastName(String lastName) {
    this.lastName = lastName;
  }
  public String getDept() {
    return dept;
  }
  public void setDept(String dept) {
    this.dept = dept;
  }

  @Override
  public String toString() {
    return "Id= " + getId() + " First Name= " + 
           getFirstName() + " Last Name= " + getLastName() + 
           " Dept= "+ getDept();
  }
}

@Entity annotation specifies that this model class is an entity.

@Table annotation specifies the primary table for the entity.

@Id annotation specifies the primary key of the entity.

@GeneratedValue specifies the primary key generation strategy which is autoincrement in this case.

@Column annotation specifies the mapped table column name for the field.

Spring Data JPA Repository Class

import java.util.List;
import org.springframework.data.repository.CrudRepository;
import com.knpcode.springbootproject.model.Employee;

public interface EmployeeRepository extends CrudRepository<Employee, Integer> {	
  List<Employee> findByLastName(String lastName);
}

EmployeeRepository interface extends CrudRepository which takes the domain class to manage (Employee in this case) as well as the id type of the domain class as type arguments.

That is all the data access code you need for your CRUD functionality, no need to write a class that implements this interface. Spring takes care of automatically implementing this repository interface.

Apart from the methods inherited from CrudRepository there is one more method findByLastName added in the Repository. Custom queries can be generated automatically or you can write the query as Named query or by using @Query annotation with in the repository.

To see an example of @Query annotation, check this post- Spring Data JPA @Query Annotation Example

To see an example of @NamedQuery annotation, check this post- Spring Data JPA @NamedQuery Annotation Example

Service class

From the service layer we’ll call the DAO layer methods. Since all we need is a repository in case of spring data so we’ll call methods of repository from the service class. Notice that repository instance has to be injected in the service class.

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.knpcode.springbootproject.model.Employee;
import com.knpcode.springbootproject.repository.EmployeeRepository;

@Service
public class EmployeeService {
  @Autowired
  private EmployeeRepository repository;

  public Employee getEmployeeById(int id) {
    return repository.findById(id).get();
  }

  public List<Employee> getAllEmployees(){
    return (List<Employee>) repository.findAll();
  }

  public void deleteEmployeeById(int id){
    repository.deleteById(id);
  }

  public Employee addEmployee(Employee emp) {
    return repository.save(emp);
  }

  public List<Employee> getEmployeeByLastName(String lastName) {
    return repository.findByLastName(lastName);
  }
}

Controller class

Using a Rest controller class we’ll map the path to the methods that are to be called for the requests.

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import com.knpcode.springbootproject.model.Employee;
import com.knpcode.springbootproject.service.EmployeeService;

@RestController
@RequestMapping("/employee")
public class EmployeeController {
  @Autowired
  EmployeeService empService;

  @GetMapping("/{id}")
  public Employee getEmployeeById(@PathVariable int id) {
    return empService.getEmployeeById(id);
  }

  @GetMapping
  public List<Employee> getAllEmployees(){
    return empService.getAllEmployees();
  }

  @DeleteMapping("/{id}")
  @ResponseStatus(HttpStatus.OK)
  public void deleteEmployeeById(@PathVariable int id){
    empService.deleteEmployeeById(id);
  }
  @PostMapping
  @ResponseStatus(HttpStatus.CREATED)
  public Employee addEmployee(@RequestBody Employee emp) {
    return empService.addEmployee(emp);
  }
  @GetMapping("/lastname/{lastName}")
  public List<Employee> getEmployeeByLastName(@PathVariable String lastName) {
    return empService.getEmployeeByLastName(lastName);
  }
}

DB Configuration

We have already seen how Spring Data takes the responsibility of deriving queries for the query methods so you don’t have to write boiler plate code for CRUD functionality. Now see the magic of Spring Boot and the reduction in configuration that is required.

By default Spring boot reads properties file at this location src/main/resources/application.properties

You must define the DB connection attributes and Hibernate related properties in the application.properties file.

spring.datasource.url=jdbc:mysql://localhost:3306/knpcode
spring.datasource.username=
spring.datasource.password=

spring.jpa.properties.hibernate.sqldialect=org.hibernate.dialect.MySQLInnoDBDialect
spring.jpa.properties.hibernate.showsql=true

Notice the keys used in the key/value pair stored in properties file, ensure that the same keys are used.

With this properties file and the jars in classpath for Hibernate and MySQL, Spring Boot can automatically configure Hibernate as JPA Vendor and set the DataSource using the DB connection attributes defined in application.properties file.

Create Spring Boot Application Class

Here is an application class with the main method which is the entry point for Spring Boot application.

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class JPAApp {
  public static void main(String[] args) {
    SpringApplication.run(JPAApp.class, args);
  }
}

@SpringBootApplication is a convenience annotation that adds all of the following annotations-

  1. @Configuration annotation tags the class as a source of bean definitions for the application context.
  2. @EnableAutoConfiguration tells Spring Boot to enable auto configuration so that beans are created automatically based on classpath settings, other beans, and various property settings. For example starter spring-boot-starter-web adds Tomcat and Spring MVC so the auto-configuration assumes that you are developing a web application and sets up Spring accordingly which includes setting up a DispatcherServlet.
  3. @ComponentScan tells Spring to look recursively for other components, configurations and services inside this package and register them.

The main method is the application entry point which delegates to Spring Boot’s SpringApplication class by calling run. SpringApplication bootstraps this Spring Data JPA application, starting Spring, which, in turn, starts the embedded Tomcat web server.

Running the application

1- You can run it as a stand alone Java application by running the class with the main method (JPAApp.java) from Eclipse IDE itself.

Right click JPAApp.java – Run As – Java Application

If everything works fine you should see a message on console similar to following (part from messages for Initializing WebApplicationContext, Hibernate configuration)

Tomcat started on port(s): 8080 (http) with context path ''
com.knpcode.springbootproject.JPAApp     : Started JPAApp

2- Dependency spring-boot-starter-parent also provides a run goal that you can use to start the application. Type mvn spring-boot:run from the root project directory to start the application.

F:\knpcode\Spring WorkSpace\SpringBootProject>mvn spring-boot:run
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building SpringBootProject 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] >>> spring-boot-maven-plugin:2.1.6.RELEASE:run (default-cli) > test-compile @ SpringBootProject >>>

2019-09-23 19:08:36.733  INFO 8476 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2019-09-23 19:08:36.748  INFO 8476 --- [           main] com.knpcode.springbootproject.JPAApp     : Started JPAApp in 4.958 seconds (JVM running for 22.892)

3- You can also create a completely self-contained executable jar file using run mvn package from the command line.

F:\knpcode\Spring WorkSpace\SpringBootProject>mvn package

[INFO]
[INFO] --- maven-jar-plugin:3.1.2:jar (default-jar) @ SpringBootProject ---
[INFO] Building jar: F:\knpcode\Spring WorkSpace\SpringBootProject\target\SpringBootProject-0.0.1-SNAPSHOT.jar
[INFO]
[INFO] --- spring-boot-maven-plugin:2.1.6.RELEASE:repackage (repackage) @ SpringBootProject ---
[INFO] Replacing main artifact with repackaged archive
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS

To run application using the created jar, use the java -jar command, as follows-

java -jar target\SpringBootProject-0.0.1-SNAPSHOT.jar

Once the application is deployed on Tomcat Server, using any of the options given above, you can test the webservice using Postman client.

Adding employee

Spring Boot Spring Data JPA

Note that the request selected is POST and the URL is http://localhost:8080/SpringJPAProject/employee

Data is sent as request body in JSON format. In the response added Employee data is sent back.

Get all employees

Spring RESTful

Get Employee by last name

You can also also send requests directly from browser as done for this request.

spring data

Delete Employee by ID

Delete Employee

That's all for the topic Spring Boot + Spring Data JPA + MySQL + Spring RESTful. If something is missing or you have something to share about the topic please write a comment.


You may also like

UnsupportedClassVersionError in Java and Resolution

In this post we’ll discuss about java.lang.UnsupportedClassVersionError and how to fix it.

When is UnsupportedClassVersionError in Java thrown

UnsupportedClassVersionError is thrown when the Java Virtual Machine attempts to read a class file whose major and minor version numbers are not supported by the current JVM version. To understand it better you need some background on class file format and what are major and minor versions.

Java Virtual Machine class file format contains many sections, for UnsupportedClassVersionError the section of interest is the second section which tells the version of the class file format. This section is of 4 bytes, where 2 bytes are allotted to minor_version and 2 bytes to major_version. Together, a major and a minor version number determine the version of the class file format.

If the class file version is greater than what JVM supports java.lang.UnsupportedClassVersionError is thrown. The release level of the Java SE platform to which a Java Virtual Machine implementation conforms is responsible for determining the range of the major and minor versions supported by the JVM.

The major version number of a class file is derived from the Java version being used.

Java Version Supported class version
Java SE 17 61 (0x3D hex)
Java SE 16 60 (0x3C hex)
Java SE 15 59 (0x3B hex)
Java SE 14 58 (0x3A hex)
Java SE 13 57 (0x39 hex)
Java SE 12 56 (0x38 hex)
Java SE 11 55 (0x37 hex)
Java SE 10 54 (0x36 hex)
Java SE 9 53 (0x35 hex)
Java SE 8 52 (0x34 hex)
Java SE 7 51 (0x33 hex)
Java SE 6 50 (0x32 hex)
Java SE 5 49 (0x31 hex)
JDK 1.4 48 (0x30 hex)
JDK 1.3 47 (0x2F hex)
JDK 1.2 46 (0x2E hex)
JDK 1.1 45 (0x2D hex)

UnsupportedClassVersionError in Java example

Here is an example where UnsupportedClassVersionError is thrown. Java file is compiled using Java 12 compiler and then the class is executed using Java 10.

C:\Program Files\Java\jdk-10.0.1\bin>java -classpath F:\knpcodews\src\  com.knpcode.programs.Test
Error: LinkageError occurred while loading main class com.knpcode.programs.Test
        java.lang.UnsupportedClassVersionError: com/knpcode/programs/Test has been compiled by a more recent version of the Java Runtime 
  (class file version 56.0), this version of the Java Runtime only recognizes class file versions up to 54.0

Java UnsupportedClassVersionError hierarchy

UnsupportedClassVersionError is a descendant of java.lang.Error. Since it is of type Error so you can’t do any exception handling to recover from it.
UnsupportedClassVersionError in Java

How to fix UnsupportedClassVersionError

UnsupportedClassVersionError is thrown when the JVM used to compile Java file and the JVM used to execute the Java class are not compatible so there are two options-

  1. Use the higher Java version to execute the Java class.
  2. If you can't use higher Java version then try to compile Java code files using the Java version that is used to run the application.

If you are using Eclipse IDE then you can select the required version of JRE by going to Window – Preferences – Java – Installed JREs. Click on Add and select the JDK from the installed folder.

Eclipse installed JREs

You can also increase or decrease the compiler compliance level based on your requirement. Go to Project (from menu or right click current project) - properties – Java Compiler and then enable project specific settings to set compiler compliance level for the project.

That's all for the topic UnsupportedClassVersionError in Java and Resolution. If something is missing or you have something to share about the topic please write a comment.


You may also like

Checked Vs Unchecked Exception in Java

In this post we’ll see some of the differences between checked and unchecked exceptions in Java. Before going into checked exception Vs unchecked exception let’s try to understand which exception classifies as a checked exception and which one as unchecked.

Checked exception in Java

While writing Java code, for some of the code lines compiler will complain about the unhandled exception. For example, if you create an InputStream object for reading a file in Java.

InputStream is = new FileInputStream(new File("D:\\test.txt"));

This statement will result in compile time error “Unhandled exception type FileNotFoundException”.

This compile time error crops up because of the fact that the above statement may throw the type of exception (FileNotFoundException) which is classified as checked exception in Java.

Unchecked exception in Java

You may have some business logic in your code which may result in an error at runtime, some of the frequent causes are passing null or going beyond the array length. For example-

int[] numArr = {4,5,6};
int num = numArr[4];

The above code will result in ArrayIndexOutOfBoundsException at run time but you won’t get any error at compile time like we saw for checked exception. These types of exceptions for which compiler won’t enforce you to handle them are classified as unchecked exception in Java.

Checked and unchecked exceptions in Java exception class hierarchy

In Java exception class hierarchy Throwable is at the top, parent class of all the exception classes. There are two direct descendants of Throwable class called Exception class and Error class.

Exception class has one subclass called RunTimeException.

checked unchecked exception Java

If an Exception class inherits from Exception (directly or indirectly) but not from RunTimeException class then it is a checked exception.

Any code that may throw a checked exception must be enclosed in a try-catch block to handle that exception or declare it using throws clause in method signature. Not doing so will result in compile time error.

All the exception classes inheriting from RunTimeException class plus the classes inheriting from Error class are collectively known as unchecked exceptions.

For unchecked exceptions there is no need to enclose the code in try-catch block or declare them using throws clause as it is not enforced by the compiler. Note that you can catch unchecked exceptions too or specify using throws clause it’s not enforced like in case of checked exception that’s all.

Checked exception classes in Java

Some of the classes that are classified as checked exception in Java are listed below.

  • ClassNotFoundException
  • CloneNotSupportedException
  • FileNotFoundException
  • InstantiationException
  • IOException
  • ParseException

Unchecked exception classes in Java

Some of the classes that are classified as unchecked exception in Java are listed below.

  • ArithmeticException
  • ArrayIndexOutOfBoundsException
  • ClassCastException
  • IllegalArgumentException
  • NullPointerException
  • NumberFormatException
  • ExceptionInInitializerError
  • OutOfMemoryError
  • StackOverflowError

Checked Vs Unchecked exception in Java

Now let’s try to list some differences between checked and unchecked exceptions in Java.

  1. Checked exceptions are to be caught using try-catch block or specified using throws clause. Not doing that will result in compile time error. Not handling or specifying unchecked exceptions won’t result in a compile time error.
  2. Checked exceptions are child classes of the Exception class where as unchecked exceptions are child classes of the RunTimeException class and child classes of Error class.
  3. Checked exceptions are those exceptions from which you are anticipated to recover from. That’s why checked exceptions are enforced by compiler because that reduces the number of exceptions which are not properly handled. On the other hand unchecked exceptions are mostly programming errors from which you can’t recover so it is not enforced to handle unchecked exception.

That's all for the topic Checked Vs Unchecked Exception in Java. If something is missing or you have something to share about the topic please write a comment.


You may also like