2 SpringMvc
2 SpringMvc
Supplementary Reading
functionality
●
Page 1: 2 input fields for first name and last name of person, 1 button
●
Page 2: output “Hello” + data from page 1
needed Software artefacts
●
1 controller class (Java)
●
1 model class (Java)
●
2 views (FreeMarker templates)
@GetMapping("/firstExample")
public String editPerson() {
return "firstExample/editPerson";
}
<body>
<h2>Edit Person</h2>
<form method="POST">
<label for="firstName">First
Name:</label>
<input type="text"
name="firstName"/>...
@PostMapping("/firstExample")
public ModelAndView showPerson(Person
person) {
ModelAndView mv = new ModelAndView();
mv.addObject(person);
mv.setViewName
("firstExample/showPerson");
return mv;
}
public class Person {
private String firstName;
demo private String lastName;...}
http://localhost:8081/fi Hello ${person.firstName}
rstExampleStart.html ${person.lastName}!
Client
Servlet-Engine
Servlet
Browser HTTP Servlet
Servlet
Web-
Server
HttpServlet {abstract}
shows uses
User
changes
reads data
View Controller
Model
informs on state change manipulates
dependencies in pom.xml
●
spring-boot-devtools
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
– makes application development easier
●
switch off caching during testing
●
automatic restart
dependencies in pom.xml
●
develop web application using tomcat and Spring MVC
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
●
use FreeMarker template engine
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
redirect message
●
return “redirect: <URL>”;
●
sends redirect response with <URL> to browser
●
browser sends GET request with <URL> to server
●
2 additional messages between browser and server
●
reload after GET repeats GET request (no harm GET used correctly)
returning redirect in ModelAndView object possible
values in model get lost when using redirect
●
use interface RedirectAttributes as parameter instead of
length of
label does capture label
not and input
influence field quickly
layout
structure
selector {
property1 : value1; notice semicolon
property2 : value2;
property3 : value3;
}
selector
●
defines HTML element for which CSS instruction is defined
property
●
defines for what properties values can be defined, taken from predefined
set
value
●
possible values: predefined string or number
link
●
can have any css property
●
make additional states distinguishable
– a:link – unvisited link
– a:visited – visited link
– a:hover – mouse pointer over link
– a:active – link which is clicked actually
●
example
– a:hover { color: hotpink; }
– demo
https://www.w3schools.com/css/tryit.asp?filename=trycs
s_link
properties of border
●
border-style: possible values: dotted, dashed, solid, double
●
demo
https://www.w3schools.com/css/tryit.asp?filename=trycss_border-style
width of border
●
border-width: <n>px | thin | medium | thick
colour of border
●
border-color: name | #012345
all properties together
●
border: 5px solid red;
●
demo
https://www.w3schools.com/css/tryit.asp?filename=trycss_border
display
●
display: defines whether or how element is shown
●
display: block
– element starts in new line and fills available width
– is default for elements: div, h1 – h6, p, form
– demo
https://www.w3schools.com/css/tryit.asp?filename=trycss_display_
block
●
display: inline
– element is in same line and has only as much width as needed
– is default for elements: span, a, img
– demo
https://www.w3schools.com/css/tryit.asp?filename=trycss_display_i
nline_list
●
display: none
– element not shown
display
●
display: inline-block
– additional element aside as far as space is sufficient
– demo
https://www.w3schools.com/css/tryit.asp?filename=trycss_inline-bl
ock
●
default value for element can be overwritten by value defined in CSS
file
example
@media screen and (min-width: 480px) {
body {
background-color: lightgreen;
}
}
●
demo
https://www.w3schools.com/css/tryit.asp?filename=tryresponsive_medi
aquery
style
●
basic: .btn
●
primary; btn-primary
size: .btn-lg, .btn-md, .btn-sm, .btn-xs
disabled: .disabled
button classes can be used on <a>, <button>, or <input>
demo
https://www.w3schools.com/bootstrap5/tryit.asp?filename=trybs_button_styl
es&stacked=h
hide navigation links and replace them with button that should reveal them
when clicked on → collapsible navigation bar
create collapsible navigation bar
●
button with class="navbar-toggler", data-bs-toggle="collapse" and data-
bs-target="#thetarget"
●
wrap navbar content (links, etc) inside <div> element with
class="collapse navbar-collapse", followed by id that matches data-bs-
target of button: "thetarget"
demo
https://www.w3schools.com/bootstrap5/tryit.asp?filename=trybs_navbar_coll
apse
Overview
●
basic principle
●
template
●
directives
●
expressions
●
build-ins
●
handling missing values
template
Hello ${person.firstName} ${person.lastName}!
data
public class Person {
private String firstName;
private String lastName;
// + set- / get- methods
data passed to template in controller
public ModelAndView showPerson(Person person) {
ModelAndView mv = new ModelAndView();
mv.addObject(person).setViewName("firstExample/showPerson");
return mv;
}
scalar types
●
String: simple text
●
Number: integer numbers and decimal numbers not distinguished
●
Boolean: true or false
●
Date: date or time or date-time → see later for more details
container types
●
Hash: associates unique lookup name with each of its sub variables
– no ordering
●
Sequence: associates integer number with each of its sub variables
– but type of the sub variable values need not be the same
first
●
first sub variable of sequence
●
template processing creates error if sequence is empty
last
●
last sub variable of sequence
●
template processing creates error if sequence is empty
reverse: sequence in reversed order
size: number of sub variables in sequence
demo http://localhost:8081/view.html#sequences
keys
●
sequence that contains all lookup keys in hash
values
●
sequence that contains all variables (values in key-value pairs) in hash
example
<#list myHash?keys as key>
${key}
</#list>
demo http://localhost:8081/view.html#hashes
accessing missing value will create error and abort template processing
special operators suppress errors
default value operator
●
syntax: unsafe_expr!default_expr or unsafe_expr!
●
default value omitted
→ will be empty string and empty sequence and empty hash at same
time
→ cannot omit default value if it should be 0 or false
●
example
${person.name!} outputs name when available and empty string else
syntax
●
simplest form for listing sequence
<#list sequence as item>
Part repeated for each item
</#list>
●
listing hash
<#list hash?keys as key>
Part repeated for each key: ${hash[key]...}
</#list>
syntax syntax
●
empty sequence possible ●
output something once
<#list sequence as item> <#list sequence>
Part repeated for each item Part executed once if we
have more than 0 items
<#else>
<#items as item>
Part executed when there Part repeated for each
are 0 items item
</#list> </#items>
Part executed once if we
have more than 0 items
<#else>
Part executed when there
are 0 items
</#list>
example
<#list users as user>
<p>${user}
<#else>
<p>No users
</#list>
else directive used when there are 0 items
items directive used to print something before first list item, and after last list
item, as far as there's at least 1 item
sep used to display something between each item (but not before first item
or after last item)
example: <#list users as user>${user}<#sep>, </#list>
break directive: exit iteration at any point
class CustomDateEditor
●
parses user-entered number strings into Date properties of beans
●
date format entered as string in class SimpleDateFormat
●
registration in method with annotation @InitBinder("<object name>")
binder.registerCustomEditor(Date.class, "date",
new CustomDateEditor(dateFormatter, true));
●
different formats for different attributes possible
customize error message in messages.properties
●
structure same as for standard converter
show error in template with macro
<@spring.showErrors separator, classOrStyle/>
demo http://localhost:8081/model.html#customconverter
Web Applications V3.1 113
Validation
example
●
class ValidationModel
@AssertTrue private boolean checkTrue;
●
message.properties
AssertTrue.validationModel.checkTrue = Check True must be marked.
output error message in template
●
use macro @spring.showErrors from file spring.ftl
demo http://localhost:8081/model.html#validation
example
●
two time fields: Start Time and End Time
●
validate that Start Time is before End Time
annotation for field not possible
→ create annotation for class
@Target(TYPE)
@Retention(RUNTIME)
@Constraint(validatedBy = TimeOrderValidator.class)
public @interface TimeOrder {
String message() default "Start time must be earlier than end time.";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
Web Applications V3.1 124
Custom Validation for Several Fields (2)
annotation implementation
public class TimeOrderValidator implements
ConstraintValidator<TimeOrder, Appointment> {
@Override public void initialize (TimeOrder constraintAnnotation) { }
@Override
public boolean isValid (Appointment value,
ConstraintValidatorContext context) {
if (value.getStartTime() != null && value.getEndTime() != null) {
return value.getStartTime().before(value.getEndTime());
}
return true; // ← no validation for empty fields
}
}
usage of validators
@TimeOrder
public class Appointment {
@NotWeekend
private Date date;
private Date startTime;
private Date endTime;
…}
in controller method
●
ObjectError
– example
String [ ] codes = {"application.someError"};
ObjectError oe = new ObjectError ("appointment", codes, null, null);
bindingResult.addError (oe);
●
error message displayed in template same way as validation errors at
class level
●
no internationalisation needed → pass error message as data to
template
<#if errorMessage??>
<div class="bg-danger" style="margin-bottom: 10px;">
${errorMessage}
</div>
</#if>
in controller method
●
FieldError
FieldError(String objectName, String field, Object rejectedValue,
boolean bindingFailure, String[] codes, Object[] arguments,
String defaultMessage)
– subclass of ObjectError
– objectName: name of affected object
– field: affected field of object
– rejectedValue: must be of same type as field in model
– bindingFailure: false (= validation failure)
– codes → codes in ObjectError
– arguments → see arguments in ObjectError
– defaultMessage → see default message in ObjectError
in controller method
●
FieldError
– example
add validations
●
course name and lecturer must not be empty
●
course names must be unique
implement LocaleResolver
@SpringBootApplication
public class App implements WebMvcConfigurer {
@Bean
public CookieLocaleResolver localeResolver(){
CookieLocaleResolver localeResolver = new CookieLocaleResolver();
localeResolver.setDefaultLocale(Locale.ENGLISH);
localeResolver.setCookieName("my-locale-cookie");
localeResolver.setCookieMaxAge(3600);
return localeResolver;
}…}
do some checks and redirect to another page when checks not fulfilled
called for all requests or requests with defined URL pattern
example
●
check whether login is valid for some pages
– login check not really needed because Spring has its own security
package
implementation of filter
●
implement interface javax.servlet.Filter
– void init(FilterConfig fc)
– void destroy()
– void doFilter(ServletRequest sr, ServletResponse sr1, FilterChain fc)
implementation of filter
●
check implemented in doFilter
– ServletRequest contains incoming message
– has to be cast to HttpServletRequest
– call redirect when check fails
– call fc.doFilter when check is ok
implementation of filter
●
example
public void doFilter(ServletRequest sr, ServletResponse sr1,
FilterChain fc) throws IOException, ServletException {
String url = ((HttpServletRequest) sr).getRequestURL().toString();
if (url.contains("/filter/secure")) {
User user = (User) ((HttpServletRequest)
sr).getSession().getAttribute("user");
if (user == null || user.getUsername() == null ||
! user.getUsername().equals("admin")) {
((HttpServletResponse) sr1).sendRedirect("/filter/login");
return;
}
}
fc.doFilter(sr, sr1);
}
Web Applications V3.1 152
Filter (4)
Template
<head>
<meta ...>
<script src="/webjars/jquery/5.1.0/jquery.min.js"></script>
<script src="/js/togglePerson.js"></script>
</head>
<body>
<h2>Using JQuery</h2>
<p><button id="togglePerson" value="Hide">Hide</button></p>
<p id="person">
Name of person<br>
${person.firstName} ${person.lastName}
</p>
</body>
Web Applications V3.1 157
Toggle DOM Element (2)
JavaScript file
$(document).ready(function () {
$('button').click(function () {
var button = $('#togglePerson');
button.html() === 'Show' ? button.html('Hide') : button.html('Show');
$('#person').slideToggle(1000);
});
});
JavaScript
$(document).ready( function(){
$("p a").click(function (event) {
event.preventDefault();
var path = $(this).attr("data-path");
var parent = $(this).parent();
$.ajax({url: path, type: "GET",
success: function (person) { parent.append('<div>' + person.firstName
+ ' ' + person.lastName + ' ' + person.birthday + '</div>');
}});
$(this).off('click');
$(this).click(function (event) { event.preventDefault();
}); });});
Web Applications V3.1 160
Asynchronous Read with AJAX (3)
define neighbours
neighbors = {
area1: ["area2", "area3", "area5"],
area2: ["area1", "area4", "area5"],
area3: ["area1", "area4"],
area4: ["area2", "area3"],
area5: ["area1", "area2"]
}; area to drag man
drag man with mouse
$('#person').draggable({
containment: '#content', man in foreground always
stack: '#person',
revert: 'invalid' element returns to old place
}); when not put on droppable area