Spring Boot ile Login Page(Confirm password) Oluşturma

 

Önce Gerekli dependency leri https://start.spring.io/ sayfasından alıyoruz:

Thymeleaf

Spring Boot Dev Tools

Spring Web

Dizin Yapısı:

— pom.xml —-

<?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>3.5.6</version>
       <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>login4</groupId>
    <artifactId>login4</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>login4</name>
    <description>Demo project for Spring Boot</description>
    <url/>
    <licenses>
       <license/>
    </licenses>
    <developers>
       <developer/>
    </developers>
    <scm>
       <connection/>
       <developerConnection/>
       <tag/>
       <url/>
    </scm>
    <properties>
       <java.version>17</java.version>
       <lombok.version>1.18.30</lombok.version>
    </properties>
    <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>

       <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-devtools</artifactId>
          <scope>runtime</scope>
          <optional>true</optional>
       </dependency>
       <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-test</artifactId>
          <scope>test</scope>
       </dependency>
       <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-validation</artifactId>
       </dependency>
       <dependency>
          <groupId>nz.net.ultraq.thymeleaf</groupId>
          <artifactId>thymeleaf-layout-dialect</artifactId>
          <version>3.0.0</version>
       </dependency>
       <dependency>
          <groupId>org.projectlombok</groupId>
          <artifactId>lombok</artifactId>
          <version>1.18.30</version>
          <scope>provided</scope>
       </dependency>
    </dependencies>

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

Validation klasörünün üçünde PasswordMatch.java ve PasswordMatchValidator.java dosyalarını oluşturuyoruz.

— PasswordMatch.java —

package login4.login4.validation;

import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import java.lang.annotation.*;


@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {PasswordMatchValidator.class})
@Documented
public @interface PasswordMatch {
    String message() default "Passwords don't match";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

—-  PasswordMatchValidator.java  —

package login4.login4.validation;

import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import login4.login4.model.LoginModel;

public class PasswordMatchValidator implements ConstraintValidator<PasswordMatch, LoginModel> {
    @Override
    public void initialize(PasswordMatch constraintAnnotation) {
    }

    @Override
    public boolean isValid(LoginModel loginModel, ConstraintValidatorContext context) {
        return loginModel.getPassword() != null &&
                loginModel.getPassword().equals(loginModel.getConfirmPassword());
    }
}

—- LoginModel.java   —

package login.login.model;

import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotEmpty;

public class LoginModel {

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSurname() {
        return surname;
    }

    public void setSurname(String surname) {
        this.surname = surname;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getConfirmPassword() {
        return confirmPassword;
    }

    public void setConfirmPassword(String confirmPassword) {
        this.confirmPassword = confirmPassword;
    }

    @NotEmpty(message = "Name is required")
    private String name;

    @NotEmpty(message = "Surname is required")
    private String surname;

    @Email(message = "Please provide a valid email address")
    @NotEmpty(message = "Email cannot be empty")
    private String email;

    @NotEmpty(message = "Password is required")
    private String password;

    @NotEmpty(message = "Confirm password is required")
    private String confirmPassword;
}

— LoginController.java —

package login.login.controller;
import jakarta.validation.Valid;
import login4.login4.model.LoginModel;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/login")
public class LoginController {

    @GetMapping("/")
    public String displayLoginPage(Model model) {
        model.addAttribute("loginModel", new LoginModel());
        return "loginForm";  // Changed from "LoginForm" to "login"
    }

    @PostMapping("/processLogin")
    public String processLogin(@Valid @ModelAttribute("loginModel") LoginModel loginModel,
                               BindingResult result,
                               Model model) throws Exception {

        // Check for validation errors
        if (result.hasErrors()) {
            return "loginForm";
        }

        // Check password match
        if (!loginModel.getPassword().equals(loginModel.getConfirmPassword())) {
            result.rejectValue("confirmPassword", "error.confirmPassword", "Passwords do not match");
            return "loginForm";
        }

        // If everything is valid, proceed to results page
        return "loginresults";  // Make sure this template exists
    }
}

—  LoginForm.html —


<!DOCTYPE html>
<html layout:decorate="layouts/defaultLayout" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.w3.org/1999/xhtml">

<body>

<h1 style="margin-left:7em">Login Page</h1>
<div class="container my-5" layout:fragment="content">
    <div class="row">
        <div class="col-md-6">  <!-- This makes it take up half the container width -->
            <form th:action="@{/login/processLogin}" method="post" th:object="${loginModel}">
                <!-- Global errors -->
                <div th:if="${#fields.hasGlobalErrors()}" class="alert alert-danger">
                    <p th:each="err : ${#fields.globalErrors()}" th:text="${err}"></p>
                </div>

                <div class="mb-3">
                    <label for="name" class="form-label">Name</label>
                    <input th:field="*{name}" type="text" class="form-control" id="name">
                    <div class="text-danger" th:if="${#fields.hasErrors('name')}" th:errors="*{name}"></div>
                </div>

                <div class="mb-3">
                    <label for="surname" class="form-label">Surname</label>
                    <input th:field="*{surname}" type="text" class="form-control" id="surname">
                    <div class="text-danger" th:if="${#fields.hasErrors('surname')}" th:errors="*{surname}"></div>
                </div>

                <div class="mb-3">
                    <label for="email" class="form-label">E-mail</label>
                    <input th:field="*{email}" type="email" class="form-control" id="email">
                    <div class="text-danger" th:if="${#fields.hasErrors('email')}" th:errors="*{email}"></div>
                </div>

                <div class="mb-3">
                    <label for="password" class="form-label">Password</label>
                    <input th:field="*{password}" type="password" class="form-control" id="password">
                    <div class="text-danger" th:if="${#fields.hasErrors('password')}" th:errors="*{password}"></div>
                </div>

                <div class="mb-3">
                    <label for="confirmPassword" class="form-label">Confirm Password</label>
                    <input th:field="*{confirmPassword}" type="password" class="form-control" id="confirmPassword">
                    <div class="text-danger" th:if="${#fields.hasErrors('confirmPassword')}" th:errors="*{confirmPassword}"></div>
                </div>

                <button type="submit" class="btn btn-primary">Login</button>
            </form>

        </div>
    </div>
</div>

</body>
</html>

— loginresults.html —

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
  <title>Login Results</title>
  <link href="/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container ml-0">
  <br/><br/>
  <h2>Login Results</h2><hr>
  <p>Name: <span th:text="${loginModel.name}"></span></p>
  <p>Surname: <span th:text="${loginModel.surname}"></span></p>
  <p>E-mail: <span th:text="${loginModel.email}"></span></p>
  <p>Password: <span th:text="${loginModel.password}"></span></p>
  <p>Confirm Password: <span th:text="${loginModel.confirmPassword}"></span></p>
  <form th:action="@{/login/}" method="get">
    <button type="submit" class="btn btn-primary">Logout</button>
  </form>
</div>
</body>
</html>

— commonFooter.html —-

<div th:fragment="header" xmlns:th="http://www.w3.org/1999/xhtml">
  <nav class="navbar navbar-expand-lg bg-body-tertiary bg-primary" data-bs-theme="dark">
    <div class="container-fluid">
      <a class="navbar-brand" href="#">Navbar</a>
      <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
      </button>
      <div class="collapse navbar-collapse" id="navbarSupportedContent">
        <ul class="navbar-nav me-auto mb-2 mb-lg-0">
          <li class="nav-item">
            <a class="nav-link active" aria-current="page" href="#">Home</a>
          </li>
          <li class="nav-item">
            <a class="nav-link" href="#">Link</a>
          </li>
          <li class="nav-item dropdown">
            <a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
              Dropdown
            </a>
            <ul class="dropdown-menu">
              <li><a class="dropdown-item" href="#">Action</a></li>
              <li><a class="dropdown-item" href="#">Another action</a></li>
              <li><hr class="dropdown-divider"></li>
              <li><a class="dropdown-item" href="#">Something else here</a></li>
            </ul>
          </li>
          <li class="nav-item">
            <a class="nav-link disabled" aria-disabled="true">Disabled</a>
          </li>
        </ul>
        <form class="d-flex" role="search">
          <input class="form-control me-2" type="search" placeholder="Search" aria-label="Search"/>
          <button class="btn btn-outline-success" type="submit">Search</button>
        </form>
      </div>
    </div>
  </nav>
</div>

—-  defaultLayout.html  —-

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="">
<head>
  <meta charset="UTF-8">
  <title>Login Page</title>
  <link href="/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>

<!--header -->
<div th:replace="layouts/commonHeader :: header"> My header is that</div>

<!--content -->
<section layout:fragment="content">
  <div> <p>This is Content</p></div>
</section>

<!--footer -->
<div th:replace="layouts/commonFooter :: footer"> My footer is that</div>
<script src="/js/bootstrap.bundle.min.js"></script>
</bod
</html>

— application.properties  —

spring.application.name=login
server.port=2022
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.enabled=true

Login4Application.java dosyasını Run Ettirdiğimizde (Tetiklediğimizde) ve Tarayıcımızın URL kısmına http://localhost:2022/login/ yazdıktan sonra uygulamamız çalışır.

Deneme amaçlı password ve Confim password bilgilerini farklı girelim.

password ve Confim password bilgilerini aynı girersek;

Uygulamanın Github linki: https://github.com/ergunalper/Creating_Web_Apps_With_Spring_Boot

Posted in Uncategorized

Write a comment