Validation happens twice: in the browser for fast feedback and on the server because the browser cannot be trusted. Bootstrap then gives the forms a consistent look without hand-written CSS for every element.
All four questions change the Session 4 admission form inside the student-admission project. The listings below are the end-of-session files; each question’s explanation points at the lines that answer it.
Objectives
Do not copy. Read for understanding and the viva- Complete questions 21 to 24 of the manual: form validation, bootstrap and css
- Prepare the deliverable before the lab and finish it during the session
- Be ready to explain every step in the viva
Questions Covered
Do not copy. Read for understanding and the viva| Question | Requirement | Status |
|---|---|---|
| Q21 | Apply the client validation in the form created in the above exercise 4 of session 4,… | Complete |
| Q22 | Write a programme to bind form objects with entity bean in Spring MVC | Complete |
| Q23 | Configure Bootstrap in Spring MVC and use default styling classes in the form and view… | Complete |
| Q24 | Apply custom Styling to your pages in Spring MVC | Complete |
Preparation
Do not copy. Read for understanding and the viva- Server-side validation uses Bean Validation annotations (
@NotBlank,@Size,@Past,@Email) on the form object and@ValidplusBindingResultin the controller. - Client-side validation is HTML5 attributes (
required,pattern,min) or a few lines of JavaScript. - Include Bootstrap from a CDN link in the page head or add the WebJar dependency.
Question 21
Problem Statement
Write in lab recordApply the client validation in the form created in the above exercise 4 of session 4, along with server-side validation.
Solution
Write in lab recordSteps
- Add the
hibernate-validatordependency from the fragment topom.xml; Maven → Update Project. - Replace
AdmissionForm.javawith the annotated version. Every rule is an annotation on the field. - Replace
admission-form.jsp. Client rules are HTML attributes on the inputs (required,minlength,pattern,max); server messages appear throughform:errors. - Client test: rebuild, open
/admission, leave the name empty and press Submit. The browser refuses to send the form and points at the field. - Server test: in the browser’s developer tools add
novalidateto theformelement (or rundocument.querySelector('form').noValidate = truein the console), submit the empty form. The page comes back with red messages under each field.
Program
Lab record: every tab is one file of the answer. Write all of them.
<!-- Q21: add inside <dependencies> of pom.xml. Hibernate Validator is the Bean
Validation 3.0 provider; Spring MVC picks it up automatically for @Valid.
Tomcat 10.1 supplies the Jakarta EL implementation it needs; add
org.glassfish.expressly:expressly:5.0.0 only if you validate outside Tomcat. -->
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>8.0.1.Final</version>
</dependency>package com.ignou.lab.admission.web;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Past;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;
import org.springframework.format.annotation.DateTimeFormat;
import com.ignou.lab.admission.entity.Student;
/** Form-backing object with server-side (Bean Validation) rules. */
public class AdmissionForm {
@NotBlank
@Size(min = 3, max = 80)
private String name;
@NotBlank
@Email
private String email;
@NotBlank
@Pattern(regexp = "[6-9][0-9]{9}", message = "must be a 10-digit Indian mobile number")
private String mobile;
@NotNull
@Past
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
private LocalDate dob;
@NotBlank
@Size(max = 255)
private String address;
@NotBlank
private String programme;
@NotNull(message = "choose Yes or No")
private Boolean hostelRequired;
@NotEmpty(message = "pick at least one course")
private List<String> courses = new ArrayList<>();
/** Q22: bind the form object to the entity bean. */
public Student toStudent() {
Student s = new Student();
s.setName(name);
s.setEmail(email);
s.setMobile(mobile);
s.setDob(dob);
s.setAddress(address);
s.setProgramme(programme);
s.setHostelRequired(hostelRequired);
s.setCourses(String.join(",", courses)); // entity column is one comma-separated string
return s; // enrolmentNo stays null until approval (Session 6)
}
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public String getMobile() { return mobile; }
public void setMobile(String mobile) { this.mobile = mobile; }
public LocalDate getDob() { return dob; }
public void setDob(LocalDate dob) { this.dob = dob; }
public String getAddress() { return address; }
public void setAddress(String address) { this.address = address; }
public String getProgramme() { return programme; }
public void setProgramme(String programme) { this.programme = programme; }
public Boolean getHostelRequired() { return hostelRequired; }
public void setHostelRequired(Boolean hostelRequired) { this.hostelRequired = hostelRequired; }
public List<String> getCourses() { return courses; }
public void setCourses(List<String> courses) { this.courses = courses; }
}<%@ page contentType="text/html;charset=UTF-8" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="c" uri="jakarta.tags.core" %>
<!DOCTYPE html>
<html lang="en">
<head>
<%@ include file="head.jspf" %>
<title>Student Admission Form</title>
</head>
<body>
<nav class="navbar navbar-dark"><div class="container"><span class="navbar-brand">IGNOU Student Admission</span></div></nav>
<div class="container">
<div class="card card-form">
<div class="card-body">
<h1 class="h3 card-title">Student Admission Form</h1>
<form:form modelAttribute="admission" method="post" cssClass="row g-3">
<div class="col-12">
<form:label path="name" cssClass="form-label required">Full name</form:label>
<form:input path="name" cssClass="form-control" cssErrorClass="form-control is-invalid"
required="required" minlength="3" maxlength="80"/>
<form:errors path="name" cssClass="invalid-feedback"/>
</div>
<div class="col-md-6">
<form:label path="email" cssClass="form-label required">Email</form:label>
<form:input path="email" type="email" cssClass="form-control" cssErrorClass="form-control is-invalid"
required="required"/>
<form:errors path="email" cssClass="invalid-feedback"/>
</div>
<div class="col-md-6">
<form:label path="mobile" cssClass="form-label required">Mobile</form:label>
<form:input path="mobile" cssClass="form-control" cssErrorClass="form-control is-invalid"
required="required" pattern="[6-9][0-9]{9}" title="10 digits, starting 6 to 9"/>
<form:errors path="mobile" cssClass="invalid-feedback"/>
</div>
<div class="col-md-6">
<form:label path="dob" cssClass="form-label required">Date of birth</form:label>
<form:input path="dob" type="date" cssClass="form-control" cssErrorClass="form-control is-invalid"
required="required" max="${today}"/>
<form:errors path="dob" cssClass="invalid-feedback"/>
</div>
<div class="col-md-6">
<form:label path="programme" cssClass="form-label required">Programme</form:label>
<form:select path="programme" cssClass="form-select" cssErrorClass="form-select is-invalid" required="required">
<form:option value="" label="-- choose --"/>
<form:options items="${programmes}"/>
</form:select>
<form:errors path="programme" cssClass="invalid-feedback"/>
</div>
<div class="col-12">
<form:label path="address" cssClass="form-label required">Address</form:label>
<form:textarea path="address" rows="3" cssClass="form-control" cssErrorClass="form-control is-invalid"
required="required" maxlength="255"/>
<form:errors path="address" cssClass="invalid-feedback"/>
</div>
<div class="col-md-6">
<label class="form-label required">Hostel required?</label>
<div class="form-check form-check-inline">
<form:radiobutton path="hostelRequired" value="true" cssClass="form-check-input" label=" Yes" required="required"/>
</div>
<div class="form-check form-check-inline">
<form:radiobutton path="hostelRequired" value="false" cssClass="form-check-input" label=" No"/>
</div>
<form:errors path="hostelRequired" cssClass="text-danger small d-block"/>
</div>
<div class="col-md-6">
<label class="form-label required">Courses this semester</label>
<c:forEach items="${courseList}" var="course">
<div class="form-check">
<form:checkbox path="courses" value="${course}" cssClass="form-check-input" label=" ${course}"/>
</div>
</c:forEach>
<form:errors path="courses" cssClass="text-danger small d-block"/>
</div>
<div class="col-12 text-end">
<a class="btn btn-outline-secondary" href="${pageContext.request.contextPath}/">Cancel</a>
<button type="submit" class="btn btn-primary">Submit application</button>
</div>
</form:form>
</div>
</div>
</div>
</body>
</html>Output
Expected, checked by reading, not executed. Client side: Chrome’s bubble “Please fill in this field” on the name box, and “Please match the requested format” with the title text on a mobile number like 12345. Server side (with novalidate), the form returns with these messages under the fields:
Full name must not be blank
Email must not be blank
Mobile must not be blank
Date of birth must not be null
Programme must not be blank
Address must not be blank
Hostel required? choose Yes or No
Courses pick at least one courseA name of two letters with the browser check bypassed returns size must be between 3 and 80; a date of birth in the future returns must be a past date.
Explanation
- Client validation is the HTML5 attributes:
requiredon every field,minlength="3" maxlength="80"on the name,type="email",pattern="[6-9][0-9]{9}"on the mobile,type="date" max="${today}"so the picker cannot choose a future date,requiredon the select and on the first radio (it applies to the whole radio group). Checkboxes have no “at least one” attribute; only the server enforces that rule. - Server validation is Bean Validation:
@NotBlank,@Size,@Email,@Pattern,@Past,@NotNull,@NotEmptyonAdmissionForm. Hibernate Validator is the provider; Spring MVC finds it on the classpath and runs it whenever a handler parameter carries@Valid(see the controller in Q22). - The rules match on both sides (same regex, same length limits) so a user with JavaScript on and a user posting with
curlget the same answer. cssErrorClassswaps the input’s class toform-control is-invalidwhen that field has an error;form:errorsprints the message in aspanwith classinvalid-feedback, which Bootstrap shows only next to an invalid control.
Question 22
Problem Statement
Write in lab recordWrite a programme to bind form objects with entity bean in Spring MVC.
Solution
Write in lab recordSteps
- Replace
AdmissionController.java: the POST handler takes@Valid AdmissionFormand aBindingResult, and on success converts the form to aStudententity and saves it. - Add
save()toStudentRepository.java. - Replace
admission-result.jsp; it now shows the saved entity, including the generated database id. - Rebuild, submit a valid application, then check MySQL:
SELECT id, name, programme, courses FROM ignou.student;.
Program
Lab record: every tab is one file of the answer. Write all of them.
package com.ignou.lab.admission.web;
import java.time.LocalDate;
import java.util.List;
import jakarta.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.ignou.lab.admission.entity.Student;
import com.ignou.lab.admission.repo.StudentRepository;
@Controller
public class AdmissionController {
private static final List<String> PROGRAMMES = List.of("MCA", "BCA", "PGDCA");
private static final List<String> COURSES = List.of(
"MCS-218 Data Communication and Computer Networks",
"MCS-219 Object Oriented Analysis and Design",
"MCS-220 Web Technologies",
"MCS-221 Data Warehousing and Data Mining");
private final StudentRepository repo;
public AdmissionController(StudentRepository repo) {
this.repo = repo;
}
@ModelAttribute("programmes")
public List<String> programmes() {
return PROGRAMMES;
}
@ModelAttribute("courseList")
public List<String> courseList() {
return COURSES;
}
/** used by the date picker's max attribute (client-side @Past) */
@ModelAttribute("today")
public LocalDate today() {
return LocalDate.now();
}
@GetMapping("/admission")
public String showForm(Model model) {
model.addAttribute("admission", new AdmissionForm());
return "admission-form";
}
@PostMapping("/admission")
public String submit(@Valid @ModelAttribute("admission") AdmissionForm form,
BindingResult result, Model model) {
if (result.hasErrors()) {
return "admission-form"; // re-render with form:errors filled in; user input is kept
}
Student saved = repo.save(form.toStudent()); // Q22: form object -> entity bean -> database
model.addAttribute("student", saved);
return "admission-result";
}
}package com.ignou.lab.admission.repo;
import java.util.List;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.ignou.lab.admission.entity.Student;
@Repository
@Transactional
public class StudentRepository {
@PersistenceContext
private EntityManager em;
@Transactional(readOnly = true)
public List<Student> findAll() {
return em.createQuery("from Student s order by s.id", Student.class).getResultList();
}
/** INSERT on commit; the generated id is set on the same object. */
public Student save(Student student) {
em.persist(student);
return student;
}
}<%@ page contentType="text/html;charset=UTF-8" %>
<%@ taglib prefix="c" uri="jakarta.tags.core" %>
<!DOCTYPE html>
<html lang="en">
<head>
<%@ include file="head.jspf" %>
<title>Application saved</title>
</head>
<body>
<nav class="navbar navbar-dark"><div class="container"><span class="navbar-brand">IGNOU Student Admission</span></div></nav>
<div class="container">
<div class="card card-form">
<div class="card-body">
<div class="alert alert-success">Application saved. Database id: <b>${student.id}</b></div>
<table class="table table-striped">
<tbody>
<tr><th scope="row">Name</th><td><c:out value="${student.name}"/></td></tr>
<tr><th scope="row">Email</th><td><c:out value="${student.email}"/></td></tr>
<tr><th scope="row">Mobile</th><td><c:out value="${student.mobile}"/></td></tr>
<tr><th scope="row">Date of birth</th><td>${student.dob}</td></tr>
<tr><th scope="row">Address</th><td><c:out value="${student.address}"/></td></tr>
<tr><th scope="row">Programme</th><td><c:out value="${student.programme}"/></td></tr>
<tr><th scope="row">Hostel required</th><td>${student.hostelRequired ? 'Yes' : 'No'}</td></tr>
<tr><th scope="row">Courses</th><td><c:out value="${student.courses}"/></td></tr>
<tr><th scope="row">Enrolment no</th><td>${empty student.enrolmentNo ? 'pending approval' : student.enrolmentNo}</td></tr>
</tbody>
</table>
<a class="btn btn-primary" href="${pageContext.request.contextPath}/admission">Another application</a>
<a class="btn btn-outline-secondary" href="${pageContext.request.contextPath}/students">All students</a>
</div>
</div>
</div>
</body>
</html>Output
Expected, checked by reading, not executed. Tomcat’s console shows the INSERT Hibernate issued:
Hibernate:
insert
into
student
(address, courses, dob, email, enrolment_no, hostel_required, mobile, name, programme)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?)The result page reads Application saved. Database id: 3 followed by the table of values and Enrolment no: pending approval. The MySQL query returns the new row with id = 3.
Explanation
- Two objects, two jobs.
AdmissionFormis shaped like the screen (aListof ticked courses, aBooleanthat may be null before validation).Studentis shaped like the table (one comma-separatedcoursescolumn, anid).toStudent()is the binding between them: one setter per field, plusString.joinfor the list. - Spring binds the request to the form object first (data binding), validates it (
@Valid), and only then does the code bind the form to the entity. A bad request never reaches the entity or the database. BindingResultmust be the parameter immediately after the@Validone. If it is missing, Spring throwsMethodArgumentNotValidExceptioninstead of letting the controller re-render the form.repo.save()runs inside a transaction (@Transactionalon the class).em.persistschedules the INSERT; commit at method exit executes it and MySQL’s auto-increment value is copied intostudent.getId().- The manual’s Thymeleaf example binds the form straight to the entity class. That works when the two shapes coincide; the separate form object is the pattern that survives Session 6, where
Studentgains relations.
Question 23
Problem Statement
Write in lab recordConfigure Bootstrap in Spring MVC and use default styling classes in the form and view created in the above exercises.
Solution
Write in lab recordSteps
- Create
WEB-INF/views/head.jspfwith the Bootstrap 5.3 CDN link (copy thelinktag from getbootstrap.com; theintegrityattribute is optional and can be pasted from there). - In every JSP replace the
metalines insideheadwith<%@ include file="head.jspf" %>.admission-form.jspandadmission-result.jspfrom Q21 and Q22 already do this; replacehome.jspwith the version below. - Rebuild and reload. The form is centred in a card, inputs have rounded borders, the submit button is blue. A missing link (typo in the URL) shows the unstyled Session 4 look, which is the quickest way to confirm the CDN line is loading.
- The WebJar alternative from the manual: add
org.webjars:bootstrap:5.3.3andorg.webjars:webjars-locator-coreto the pom and link/webjars/bootstrap/css/bootstrap.min.css; the CDN needs no Maven change so it is used here.
Program
Lab record: every tab is one file of the answer. Write all of them.
<%-- /WEB-INF/views/head.jspf : shared <head> contents, pulled in with <%@ include %> --%>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="${pageContext.request.contextPath}/css/admission.css" rel="stylesheet">
<%-- ponytail: no Bootstrap JS bundle; add the script tag when a dropdown or modal appears --%><%@ page contentType="text/html;charset=UTF-8" %>
<!DOCTYPE html>
<html lang="en">
<head>
<%@ include file="head.jspf" %>
<title>Student Admission</title>
</head>
<body>
<nav class="navbar navbar-dark"><div class="container"><span class="navbar-brand">IGNOU Student Admission</span></div></nav>
<div class="container">
<div class="card card-form text-center">
<div class="card-body">
<h1 class="h3 card-title">Welcome to the Lab Project for Student Admission using Spring MVC</h1>
<p class="text-muted">Spring Framework ${springVersion} · server time ${now}</p>
<a class="btn btn-primary btn-lg" href="${pageContext.request.contextPath}/admission">Apply for admission</a>
<a class="btn btn-outline-secondary btn-lg" href="${pageContext.request.contextPath}/students">View students</a>
</div>
</div>
</div>
</body>
</html>Output
Expected, checked by reading, not executed: a dark navigation bar with “IGNOU Student Admission”, below it a white card 760 px wide holding the form in two columns (email beside mobile, date beside programme), inline Yes/No radios, stacked course checkboxes, and a right-aligned Cancel / Submit pair. Invalid fields get a red border and red text underneath. The result page shows a green “Application saved” alert and a striped table.
Explanation
- Bootstrap is only a stylesheet. Configuring it in Spring MVC means one
linktag reaches every page; thejspfinclude keeps that tag in one file, so a version bump is one edit. - Classes used, all Bootstrap defaults: layout
container,row g-3,col-12,col-md-6; form controlsform-label,form-control,form-select,form-check,form-check-inline,form-check-input; validationis-invalid,invalid-feedback; componentscard,card-body,navbar,alert alert-success,table table-striped,btn btn-primary,btn-outline-secondary. - Spring form tags take
cssClassinstead ofclass(andcssErrorClassfor the error state); plain HTML elements in the same page useclassas usual. - No Bootstrap JavaScript is included because nothing on these pages needs it; add the bundle script tag when a dropdown menu or modal appears.
Question 24
Problem Statement
Write in lab recordApply custom Styling to your pages in Spring MVC.
Solution
Write in lab recordSteps
- Create
src/main/webapp/css/admission.css(outsideWEB-INF, so the browser can fetch it). - Replace
WebConfig.javawith the version that adds a resource handler for/css/**. Without it theDispatcherServlet, mapped on/, tries to find a controller for/css/admission.cssand returns 404. head.jspfalready links/css/admission.cssafter Bootstrap, so the custom rules win over Bootstrap’s on equal specificity.- Rebuild, hard-reload (Ctrl+Shift+R) and open
http://localhost:8080/student-admission/css/admission.cssdirectly to confirm it is served.
Program
Lab record: every tab is one file of the answer. Write all of them.
/* src/main/webapp/css/admission.css : custom styling on top of Bootstrap */
:root {
--ignou-maroon: #7b1e3c;
--ignou-sand: #f6f1ea;
}
body {
background: var(--ignou-sand);
}
.navbar {
background: var(--ignou-maroon);
}
.card-form {
max-width: 760px;
margin: 2rem auto;
border: 0;
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.08);
}
.card-title {
color: var(--ignou-maroon);
border-bottom: 2px solid var(--ignou-maroon);
padding-bottom: 0.5rem;
margin-bottom: 1.25rem;
}
.btn-primary {
background: var(--ignou-maroon);
border-color: var(--ignou-maroon);
}
.btn-primary:hover {
background: #5d1630;
border-color: #5d1630;
}
/* red asterisk after every mandatory label */
label.required::after {
content: " *";
color: #dc3545;
}
/* the lab record is printed: hide navigation, keep the data */
@media print {
.navbar, .btn { display: none; }
.card-form { box-shadow: none; max-width: none; margin: 0; }
}package com.ignou.lab.admission;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
@Configuration
@EnableWebMvc
@ComponentScan("com.ignou.lab.admission")
public class WebConfig implements WebMvcConfigurer {
@Bean
public InternalResourceViewResolver viewResolver() {
return new InternalResourceViewResolver("/WEB-INF/views/", ".jsp");
}
/** Q24: /css/** is served from src/main/webapp/css instead of going to a controller. */
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/css/**").addResourceLocations("/css/");
}
}Output
Expected, checked by reading, not executed: sand-coloured page background, maroon navigation bar and maroon primary buttons instead of Bootstrap blue, card title underlined in maroon, a red asterisk after each mandatory label, and in print preview (Ctrl+P) the navigation bar and buttons disappear while the form data stays.
Explanation
addResourceHandlersmaps a URL pattern to a location inside the WAR; Spring serves the file with caching headers and never involves a controller.- Custom CSS overrides by cascade order: same selector specificity, loaded later, wins.
.btn-primaryand.navbarredefine Bootstrap’s colours; the:rootvariables keep the brand colour in one place. label.required::afteradds the asterisk from CSS, so the JSP only sets a class; the mandatory marker cannot drift from therequiredattribute if both come from the same template line.- The
@media printblock exists because the lab record is printed; hiding navigation is the difference between a page and a form.
Viva Questions
Do not copy. Read for understanding and the viva- Q: Why validate on both client and server? A: Client checks give instant feedback; the server check is the only one that cannot be bypassed (disable JavaScript, use curl, edit the DOM).
- Q: What does
@Validdo? A: Tells Spring to run Bean Validation on the bound object before calling the handler and to record violations in the followingBindingResult. - Q: What happens if
BindingResultis not the next parameter? A: Spring throws the validation exception and the user sees an error page instead of the form with messages. - Q: Difference between
@NotNull,@NotEmptyand@NotBlank? A:@NotNullrejects null;@NotEmptyalso rejects empty strings or collections;@NotBlankalso rejects whitespace-only strings. - Q: Why a separate form object instead of binding to the entity? A: The screen and the table have different shapes; the form object carries validation rules and screen-only fields without polluting the entity.
- Q: Why does the CSS file live outside
WEB-INF? A: Anything underWEB-INFis never served directly; a stylesheet must be fetched by the browser. - Q: CDN or WebJar for Bootstrap? A: CDN: no build change, browser may already have it cached, needs internet. WebJar: version pinned in the pom, works offline.
Common Mistakes
Do not copy. Read for understanding and the viva- Adding validation annotations and forgetting
@Validon the parameter; every submission passes. - Testing only in the browser and concluding the server rules work. Bypass the browser once (
novalidate) to see them. - Writing
class="form-control"on aform:inputtag; the attribute iscssClass. - Mapping
/css/**but putting the folder underWEB-INF; the resource handler cannot serve it. - Loading the custom stylesheet before Bootstrap, so Bootstrap overrides the custom colours.
Session Summary
Write in lab record- Question 21: HTML5 attributes on the form plus Bean Validation on
AdmissionForm, messages rendered withform:errors - Question 22:
@ValidandBindingResultinAdmissionController,toStudent()binding the form to theStudententity,StudentRepository.save()inserting the row - Question 23: Bootstrap 5.3 from the CDN through
head.jspf, default classes on the form, result and home pages - Question 24:
admission.cssserved through a resource handler, brand colours, required-field marker and print rules