SlideShare a Scribd company logo
Spring MVC
Introduction / Gore
Ted Pennings
NHJUG Co-Founder
16 November 2010
Who’s Ted
✦ Developer with Fortune 100 financial services firm
since July 2008.
✦ Working with Java since late 2008.
✦ Web developer as freelance/hobby since 2001
(LAMP)
✦ Lots of freelancing and web hosting during college
✦ http://ted.pennin.gs / @thesleepyvegan / ted@pennin.gs
What is MVC?
✦ MVC spits code into three areas
✦ Model – data/persistence
layer
✦ View – presentation layer, UI
and client-side scripts
✦ Controller – business logic
that controls data and
execution
✦ Strong design pattern that
emphasizes separation.
MVC Cleanliness
✦ Application logic goes in the controllers.
✦ Data persistence goes in the model.
✦ UI presentation and JavaScript varnish goes in the
views.
✦ Do not try to fight MVC code separation. If you
feel the need to break convention, refactor.
MVC Done Badly – Views
✦Doing actual work in JSPs
<%
try {
String url="jdbc:mysql://localhost/companies?user=larry_ellison&password=yachts";
con=DriverManager.getConnection(url);
stmt=con.createStatement();
} catch(Exception e){ System.err.println(“Unable to acquire companies!”);
e.printStackTrace(); }
if (request.getParameter("action") != null){
String bookname = request.getParameter("company_name");
String author = request.getParameter("price");
stmt.executeUpdate("insert into acquisitions(company_name,price) values
('"+company_name+"','"+price+"')");
rst=stmt.executeQuery("select * from acquisitions");
%>
<html> <body> <center>
<h2>Victim List</h2>
<table border="1" cellspacing="0" cellpadding="0">
Adapted from http://www.roseindia.net/jsp/Accessingdatabase-fromJSP.shtml
MVC Done Badly – Controllers
✦HTML in the controllers
@RequestMapping(“/acquisitions/new”)
public void createAcquisition(Model model) {
Acquisition v = new Acquisition();
model.addAttribute(“newVictim”, v);
model.addAttribute(“newVictimForm”, collectVictimVitalStats(v));
}
private String renderVictimInfoForm(Acquisition v) {
StringBuilder sb = new StringBuilder()
.append("<form action='").append(SERVLET_PATH)
.append("' method='post'><h1>Please enter your information</h1>");
sb.append("<p><label for='name'>Victim Name</label>")
.append("<input type='text' name='name' value='")
.append(v.getName()).append("'/>").append("</p>");
[...]
return sb.toString();
}
Speaking of Bad Things
Oracle CEO Larry Ellison
MVC Done Badly – Models
✦Business logic in the model
public class Victim {
private String name;
private short numberOfYachts;
[. . . ]
public Victim(String name, short numberOfYachts) {
if (numberOfYachts < 4) {
throw new VictimUnworthyException(“Too few yachts. Larry Ellison will not be sated.”);
}
}
[. . . ]
}
✦HTML in methods
public String toString() {
return “<h3 class=‘name’>Why Hello ” + this.name + “!</h3><br/>I admire your”
+ “<strong><font color=“pink”>” + this.numberOfYachts + “</font></strong> yachts”;
}
Spring MVC is Still Spring
✦ Full Dependency Injection and Inversion of Control
✦ XML- and Annotation-based configuration
✦ Heavy use of annotation-based configuration
✦ Application context files are still available, but mostly
unnecessary
✦ <mvc:annotation-driven> and <content:component-scan>
✦ Maven dependencies and archetypes
✦ Convention over configuration
✦ Very few interfaces to implement
“Spring Goodness”
The Basic Annotations
✦ Spring MVC is mostly annotation driven, so here is your
vernacular:
✦ Standard Spring annotations:
✦ @Component, @Service, @Repository,
✦ @Autowired, @Value, @Configuration
✦ @Transactional, @Aspect and JSR 284 + 330
✦ @Controller – an MVC Controller
✦ @RequestMapping
✦ @ModelAttribute
✦ @RequestParam and @PathVariable
✦ @SessionAttributes
How does Spring do MVC?
✦ All requests are sent to Spring’s DispatcherServlet
✦ DispatcherServlet sends requests to @Controllers
✦ THERE ARE NO DEVELOPER-WRITTEN SERVLETS
Diagram from Spring docs on their website
The Simplicity of Controllers
✦ @Controller makes a class a controller “bean”
✦ Specialization of @Component
✦ @RequestMapping defines the URL paths handled by a
controller or method.
✦ It is possible to nest paths, as in example.
✦ Many different RequestMethods can be serviced.
✦ {} define @PathVariable/@ReqParam
✦ Value of Inheritance
✦ Annotation caveat
Controller Example
@Controller
@RequestMapping({ "/yachts", "/mah-boats" })
public class YachtController extends BaseController {
@RequestMapping(value = "/{yachtKey}", method = GET)
public String displayYacht( @PathVariable(“yachtKey”) String
yachtKey, Model model) {
LOG.debug("Displaying Yacht " + yachtKey);
Yacht yacht = service.findYachtByKey(yachtKey);
model.addAttribute("yacht", yacht);
return YACHT_PAGE_VIEW;
}
}
Reading User Input
✦ Typically happens through method parameter annotations
✦ @PathVariable(“var”) / @RequestParam(“var”)
✦ Corresponds to a {var} value in a @RequestMapping
✦ Best practice to be explicit
✦ @ModelAttribute
✦ @RequestBody
✦ Any type can be used.
✦ Be wary of type conversion issues
✦ See PropertyEditorSupport and Spring’s Converter SPI
✦ Use @InitBinder in a controller superclass
✦ JSON payloads can often be unmarshalled on the fly.
Populating The Model
✦ In MVC, dynamic data only appears in views through the model.
✦ Spring MVC enforces this pattern constraint.
✦ Each request receives a fresh new Model (or equivalent).
✦ Two basic approaches
✦ In @Controller method, receive a Model or ModelAndView object
✦ Add directly to it.
✦ No need to return Model/MV object received. (More on that later.)
✦ In @Controller class, annotate methods with @ModelAttribute(“name”)
✦ Used in a @Controller superclass, can be used for template data
✦ User privileges
✦ Pseudo-security hack until full security is implemented
Creating Forms (1/2)
✦ Creating a new object submission form requires manually instantiating your
target object
✦ if you want to create a com.oracle.acquisition.timekeeper.model.TimeEntry(),
in your controller method you must
✦ model.addAttribute(“timeEntry”, new
com.oracle.acquisition.timekeeper.model.TimeEntry());
Assuming:
package com.oracle.acquisition.timekeeper.model;
public class TimeEntry {
private String victimName;
private String projectCode;
private double hours;
private Date timestamp;
[…getters, setters, etc…]
}
✦ This exact object will be used by your JSP (or similar) in the
next step… getter/setter round-tripping on POST
Creating Forms (2/2)
Most new object views can function as an edit view. Conserve code.
<form:form method="post" modelAttribute=“timeEntry"
cssClass="form">
<form:label path=“projectCode">
Project Code <form:errors path=“projectCode"
cssClass="error" />
</form:label>
<form:select items="${userProjectCodes}"
path=“projectCode“ itemLabel=“projectName"/>
<form:label path=“hours">
Hours <form:errors path=“hours" cssClass="error" />
</form:label>
<form:input path=“hours“ />
<button type="submit">Submit</button>
</form:form>
Demo
✦ Working forms
✦ Bean validation
✦ Error messages appear in browser automagically
Bean Validation (JSR-303)
✦ Constraints are defined by
annotations on the actual data
entities
✦ Validation is executed
automagically by framework
✦ User-friendly errors appear
automagically on the view.
✦ Object graphs can be traversed
and nested objects are validated
(or not, if you wish).
@Entity
public class Yacht {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Size(min = 4, max = 35, message = "Key must be
between {min} and {max} characters long.")
@NotEmpty(message = "Key is required.")
@Pattern(regexp = "[A-Za-z0-9_-]*", message = "Only
letters, numbers, underscores and hyphens may be used.")
private String key;
@Size(min = 4, max = 35, message = "Name must be
between {min} and {max} characters long.")
@NotEmpty(message = "Name is required.")
private String name;
@ValidDate
private Date acquisitionDate;
}
Setting Up And Using Bean
Validation
✦ As simple as @Valid
✦ Can be applied inside domain to validate child/2nd degree
objects
✦ BindingResult for errors
✦ MUST be argument after @Valid argument (quirk)
✦ RuntimeException if not
✦ toString() is your friend.
✦ Validating a large object graph is risky.
✦ Complicates future changes
✦ On the other hand, very hard to merge BindingResults
Updated Controller
@Controller
public class YachtController {
@RequestMapping(method = POST)
public ModelAndView saveYacht(@Valid Yacht yacht, BindingResult result,
ModelAndView mv) {
LOG.debug("Attempting to save Yacht: " + yacht.getKey());
if (result.hasErrors()) {
LOG.debug("Submission has errors " + result);
mv.setViewName(MODIFY_YACHT_VIEW);
return mv;
}
service.store(yacht);
FlashMap.setSuccessMessage("Successfully saved Yacht");
return createRedirect(yacht);
}
}
Handling Validation Errors
✦ Ensure that you have a BindingResult.hasErrors() check in @Controller
✦ When returning edit view, ensure all needed model attributes are
present
✦ This includes the object being validated if you construct a new Model/
MV
✦ You may need a call to the root-level form:errors in order to capture object-
level errors (not field-level).
✦ <form:errors path=“” />
✦ Be sure you interrupt flow so you don’t persist invalid objects
✦ VALIDATION ERRORS ARE NOT EXCEPTIONS
✦ There is a Hibernate option to validate pre-persist, but this is nuanced
✦ Legacy objects
✦ May be incompatible with Spring-managed dependencies
Writing Your Own Constraints
✦ Constraints can be combined and composed
✦ For example, @NotEmpty actually means @NotNull, @Size(min=1) &
@ReportAsSingleViolation
✦ Write an annotation class
✦ @Target(ElementType.FIELD)
✦ @Retention(RetentionPolicy.RUNTIME)
✦ @Documented (or not)
✦ @Constraint(validatedBy = YourCustomValidator.class)
✦ Be sure to add a default message
✦ These can be Java properties read from a file (Internationalization/
i18n)
✦ Write a validator
✦ Implement ConstraintValidator<AnnotationType, TargetClass>
✦ Return boolean for isValid(TargetClass object, …)
✦ Statefulness (via initialize() method)
✦ Dependency Injection, Constructors, and Hibernate ORM issue
Writing Unit Tests For Validation
Magic
✦ A lot of JSR-303 is wizardry and magic beans.
✦ Write unit tests so you ensure code execution is predictable.
✦ Easiest to write using Spring’s JUnit Test Runner
✦ Point to an application context field that contains
✦ <bean id="validator“
class="org.springframework.validation.beanvalidation.LocalVa
lidatorFactoryBean" />
✦ Ensure a JSR-303-compliant validator is on your test
classpath
✦ Eg, Hibernate Validator
Example Unit Test
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({ "classpath:your-persistence.xml",
"classpath:your-persistence-test.xml" })
public class YachtValidationTest {
@Autowired
private javax.validation.Validator validator;
private Yacht emptyYacht;
@Before
public void setUpEmptyYacht() {
emptyYacht = new Yacht();
}
@Test
public void theKeyFieldIsRequired() {
Set<ConstraintViolation<Yacht>> constraintViolations = validator
.validate(emptyYacht);
boolean containsYachtKeyViolation = false;
for (ConstraintViolation<Yacht> violation : constraintViolations) {
if ("key".equals(violation.getPropertyPath().toString())
&& violation.getMessageTemplate().contains("required")) {
containsYachtKeyViolation = true;
}
}
assertTrue(containsYachtKeyViolation);
}
}
The Guts of Spring MVC
✦ Method Return Types
✦ View Resolvers
✦ Exception Handling
✦ File Uploads
✦ Servlet-level code (if you have to)
✦ URL Rewriting
Controller Method Return Types
✦ @Controller methods can return many different types. Often:
✦ Model
✦ ModelAndView (use Model.setView(View) or Model.setViewName
(String))
✦ Distinction between View and View Name
✦ String for the view name to display
✦ Can return void if you’ve drank plenty of convention over configuration
koolaid.
✦ Dangerous if you refactor a lot (or the next person does).
✦ Methods can also be annotated with @RequestBody
✦ Used to return a value without going through MVC apparatus
✦ Generally bad form, but good for testing or mock apps.
✦ @ModelAttribute has the same two distinct meanings as
@ModelAttribute
View Resolvers
✦ What is a ViewResolver and how does this differ from a View Name?
✦ Apache Tiles and TilesViewResolver
✦ InternalResourceViewResolver (default)
✦ ContentNegotiatingViewResolver
✦ JSON
✦ XML (if needed)
✦ RSS/Atom
✦ And many, many others… ViewResolver overload….
View options and Apache Tiles
✦ Spring MVC is does not attempt to implement its own view layer
✦ JSTL and JSP/JSPX
✦ Apache Tiles is commonly used for page modularization and
templating
✦ org.springframework.web.servlet.view.tiles2.TilesViewResolver
✦ org.springframework.web.servlet.view.tiles2.TilesConfigurer
✦ Similar options are available for Freemarker, Velocity and others
✦ JSON can be rendered easily via MappingJacksonJsonView
✦ Don’t forget ContentNegotiatingViewResolver and ignoreAcceptHeaders
(true)
✦ Straight JSPs are possible too
✦ Convention over configuration, but often creates complexity/duplication
Handling Exceptions
✦ Implement a HandlerExceptionResolver for application-wide errors
public interface HandlerExceptionResolver {
ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex);
}
✦ @ExceptionHandler can annotate a method for @Controller-specific
exceptions, such as an IOException in a particular method. This only
applies to the controller in which it is declared.
✦ Consider adding web.xml <error-page> handlers too (if your exception
handler throws an exception, or if you think everything may break.)
✦ A separate error @Controller is a good idea, with minimal
dependencies
File Uploads
✦ Uses Commons File Upload
✦ org.springframework.web.multipart.commons.CommonsMultipartResolver
✦ Three easy steps (plus background Spring magic)
✦ Instantiate CommonsMultipartResolver in app context or @Config
✦ Add enctype=“multipart/form-data” to your <form> tag in your view
✦ Add a MultipartFile to your POST @Controller method argument
✦ Use @ModelAttribute for form submission specificity
✦ MultipartFile is your friend
✦ getBytes()*
✦ getContentType() – don’t forget about mime types!
✦ getOriginalFilename()
✦ transferTo(File dest)*
(* but IOException is not)
Burrowing Down To The
Servlets
✦ Sometimes it is necessary to write output
directly to servlets.
✦ Extend AbstractView
✦ In your controller, specify your custom
view
✦ ModelAndView.setViewName(String
name)
✦ ModelAndView.setView(View view)
✦ This is useful for user data in binary form,
such as images.
✦ In general, avoid this approach
@Component
public class ByteArrayView extends AbstractView {
public ByteArrayView() { }
@Override
protected final void renderMergedOutputModel(Map
model,
HttpServletRequest request, HttpServletResponse
response)
throws Exception {
byte[] bytes = (byte[]) model.get("data");
String contentType = (String) model.get
("contentType");
response.setContentType(contentType);
response.setContentLength(bytes.length);
ServletOutputStream out =
response.getOutputStream();
FileCopyUtils.copy(bytes, out);
}
}
URL Rewriting
✦ URL rewriting implemented as a servlet-level filter (web.xml):
✦ org.tuckey.web.filters.urlrewrite.UrlRewriteFilter
✦ Uses a urlrewrite.xml file, typically in the WEB-INF:
<rule>
<from>/sun/*</from>
<to>/oracle/$1</to>
</rule>
✦ Rules are standard regular expressions (java.util.regex.Pattern).
✦ Used extensively to separate dynamic content requests from static content
requests (eg, css, images, javascript).
✦ Can be used to route multiple different request paths to the same
DispatcherServlet instance (thereby conserving memory).
Demo
✦ Creating a new project from the Maven
archetype/template in STS IDE
✦ maven-tomcat-plugin, maven-jetty-plugin
✦ Live coding!
References
✦ Spring Docs (3.0.x)
Manual: http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/
JavaDocs: http://static.springsource.org/spring/docs/3.0.x/javadoc-api/
✦ Maven Jetty Plugin (mvn jetty:run)
http://docs.codehaus.org/display/JETTY/Maven+Jetty+Plugin
✦ Miscellaneous
✦ Spring Roo Keynote
http://www.youtube.com/watch?v=GQHlhIIxCIc
Questions? Comments?

More Related Content

What's hot (20)

PDF
Introduction to Spring MVC
Richard Paul
 
PPTX
Angular 5
Bartłomiej Narożnik
 
PDF
Vaadin & Web Components
Joonas Lehtinen
 
KEY
Introduction to ASP.NET MVC
LearnNowOnline
 
PDF
AngularJS Project Setup step-by- step guide - RapidValue Solutions
RapidValue
 
PPTX
AngularJs presentation
Phan Tuan
 
PDF
Vaadin and Spring at Devoxx UK 2015
Sami Ekblad
 
PPSX
Angular js
Arun Somu Panneerselvam
 
PDF
Top 7 Angular Best Practices to Organize Your Angular App
Katy Slemon
 
PDF
Testdrive AngularJS with Spring 4
Oliver Wahlen
 
PDF
AngularJS - Services
Nir Kaufman
 
PPTX
Angular Mini-Challenges
Jose Mendez
 
PDF
Gdg dev fest hybrid apps your own mini-cordova
Ayman Mahfouz
 
PDF
Seven Versions of One Web Application
Yakov Fain
 
PPTX
Asp.Net MVC Intro
Stefano Paluello
 
PDF
Vaadin Components @ Angular U
Joonas Lehtinen
 
PPT
Angular App Presentation
Elizabeth Long
 
PPTX
Introduction to Google Guice
Knoldus Inc.
 
PPTX
Introduction to angular js for .net developers
Mohd Manzoor Ahmed
 
PPTX
Comparing Angular and React JS for SPAs
Jennifer Estrada
 
Introduction to Spring MVC
Richard Paul
 
Vaadin & Web Components
Joonas Lehtinen
 
Introduction to ASP.NET MVC
LearnNowOnline
 
AngularJS Project Setup step-by- step guide - RapidValue Solutions
RapidValue
 
AngularJs presentation
Phan Tuan
 
Vaadin and Spring at Devoxx UK 2015
Sami Ekblad
 
Top 7 Angular Best Practices to Organize Your Angular App
Katy Slemon
 
Testdrive AngularJS with Spring 4
Oliver Wahlen
 
AngularJS - Services
Nir Kaufman
 
Angular Mini-Challenges
Jose Mendez
 
Gdg dev fest hybrid apps your own mini-cordova
Ayman Mahfouz
 
Seven Versions of One Web Application
Yakov Fain
 
Asp.Net MVC Intro
Stefano Paluello
 
Vaadin Components @ Angular U
Joonas Lehtinen
 
Angular App Presentation
Elizabeth Long
 
Introduction to Google Guice
Knoldus Inc.
 
Introduction to angular js for .net developers
Mohd Manzoor Ahmed
 
Comparing Angular and React JS for SPAs
Jennifer Estrada
 

Similar to Spring MVC Intro / Gore - Nov NHJUG (20)

PDF
Spring 3: What's New
Ted Pennings
 
PPT
Spring MVC Basics
Bozhidar Bozhanov
 
PDF
Spring_Course_Content
MV Solutions
 
PDF
quickguide-einnovator-7-spring-mvc
jorgesimao71
 
ODP
Java Spring MVC Framework with AngularJS by Google and HTML5
Tuna Tore
 
ODP
springmvc-150923124312-lva1-app6892
Tuna Tore
 
PDF
My04_MVC.pdf
Alfas3
 
PDF
Spring mvc
Guo Albert
 
PDF
Spring MVC
Aaron Schram
 
PDF
Spring MVC introduction HVA
Peter Maas
 
PPT
Spring MVC 3.0 Framework
Ravi Kant Soni ([email protected])
 
PPTX
Advance java session 13
Smita B Kumar
 
PPTX
Unit 38 - Spring MVC Introduction.pptx
AbhijayKulshrestha1
 
PPT
Spring Framework
nomykk
 
PDF
Multi Client Development with Spring - Josh Long
jaxconf
 
PDF
MVC 1.0 als alternative Webtechnologie
OPEN KNOWLEDGE GmbH
 
PPTX
Spring mvc
Pravin Pundge
 
PPTX
Spring MVC framework features and concepts
AsmaShaikh478737
 
PDF
Advance Java Training in Bangalore | Best Java Training Institute
TIB Academy
 
PPTX
Spring framework in depth
Vinay Kumar
 
Spring 3: What's New
Ted Pennings
 
Spring MVC Basics
Bozhidar Bozhanov
 
Spring_Course_Content
MV Solutions
 
quickguide-einnovator-7-spring-mvc
jorgesimao71
 
Java Spring MVC Framework with AngularJS by Google and HTML5
Tuna Tore
 
springmvc-150923124312-lva1-app6892
Tuna Tore
 
My04_MVC.pdf
Alfas3
 
Spring mvc
Guo Albert
 
Spring MVC
Aaron Schram
 
Spring MVC introduction HVA
Peter Maas
 
Spring MVC 3.0 Framework
Ravi Kant Soni ([email protected])
 
Advance java session 13
Smita B Kumar
 
Unit 38 - Spring MVC Introduction.pptx
AbhijayKulshrestha1
 
Spring Framework
nomykk
 
Multi Client Development with Spring - Josh Long
jaxconf
 
MVC 1.0 als alternative Webtechnologie
OPEN KNOWLEDGE GmbH
 
Spring mvc
Pravin Pundge
 
Spring MVC framework features and concepts
AsmaShaikh478737
 
Advance Java Training in Bangalore | Best Java Training Institute
TIB Academy
 
Spring framework in depth
Vinay Kumar
 
Ad

Recently uploaded (20)

PDF
The Rise of AI and IoT in Mobile App Tech.pdf
IMG Global Infotech
 
PDF
[Newgen] NewgenONE Marvin Brochure 1.pdf
darshakparmar
 
PDF
"AI Transformation: Directions and Challenges", Pavlo Shaternik
Fwdays
 
PDF
Using FME to Develop Self-Service CAD Applications for a Major UK Police Force
Safe Software
 
PDF
Staying Human in a Machine- Accelerated World
Catalin Jora
 
PPTX
Building Search Using OpenSearch: Limitations and Workarounds
Sease
 
PDF
IoT-Powered Industrial Transformation – Smart Manufacturing to Connected Heal...
Rejig Digital
 
PDF
Newgen 2022-Forrester Newgen TEI_13 05 2022-The-Total-Economic-Impact-Newgen-...
darshakparmar
 
PPTX
Future Tech Innovations 2025 – A TechLists Insight
TechLists
 
PDF
Achieving Consistent and Reliable AI Code Generation - Medusa AI
medusaaico
 
PDF
Smart Trailers 2025 Update with History and Overview
Paul Menig
 
PDF
Newgen Beyond Frankenstein_Build vs Buy_Digital_version.pdf
darshakparmar
 
PDF
Reverse Engineering of Security Products: Developing an Advanced Microsoft De...
nwbxhhcyjv
 
PDF
Mastering Financial Management in Direct Selling
Epixel MLM Software
 
PDF
What Makes Contify’s News API Stand Out: Key Features at a Glance
Contify
 
PPTX
AUTOMATION AND ROBOTICS IN PHARMA INDUSTRY.pptx
sameeraaabegumm
 
PPTX
Webinar: Introduction to LF Energy EVerest
DanBrown980551
 
PDF
CIFDAQ Market Wrap for the week of 4th July 2025
CIFDAQ
 
PDF
"Beyond English: Navigating the Challenges of Building a Ukrainian-language R...
Fwdays
 
PPTX
AI Penetration Testing Essentials: A Cybersecurity Guide for 2025
defencerabbit Team
 
The Rise of AI and IoT in Mobile App Tech.pdf
IMG Global Infotech
 
[Newgen] NewgenONE Marvin Brochure 1.pdf
darshakparmar
 
"AI Transformation: Directions and Challenges", Pavlo Shaternik
Fwdays
 
Using FME to Develop Self-Service CAD Applications for a Major UK Police Force
Safe Software
 
Staying Human in a Machine- Accelerated World
Catalin Jora
 
Building Search Using OpenSearch: Limitations and Workarounds
Sease
 
IoT-Powered Industrial Transformation – Smart Manufacturing to Connected Heal...
Rejig Digital
 
Newgen 2022-Forrester Newgen TEI_13 05 2022-The-Total-Economic-Impact-Newgen-...
darshakparmar
 
Future Tech Innovations 2025 – A TechLists Insight
TechLists
 
Achieving Consistent and Reliable AI Code Generation - Medusa AI
medusaaico
 
Smart Trailers 2025 Update with History and Overview
Paul Menig
 
Newgen Beyond Frankenstein_Build vs Buy_Digital_version.pdf
darshakparmar
 
Reverse Engineering of Security Products: Developing an Advanced Microsoft De...
nwbxhhcyjv
 
Mastering Financial Management in Direct Selling
Epixel MLM Software
 
What Makes Contify’s News API Stand Out: Key Features at a Glance
Contify
 
AUTOMATION AND ROBOTICS IN PHARMA INDUSTRY.pptx
sameeraaabegumm
 
Webinar: Introduction to LF Energy EVerest
DanBrown980551
 
CIFDAQ Market Wrap for the week of 4th July 2025
CIFDAQ
 
"Beyond English: Navigating the Challenges of Building a Ukrainian-language R...
Fwdays
 
AI Penetration Testing Essentials: A Cybersecurity Guide for 2025
defencerabbit Team
 
Ad

Spring MVC Intro / Gore - Nov NHJUG

  • 1. Spring MVC Introduction / Gore Ted Pennings NHJUG Co-Founder 16 November 2010
  • 2. Who’s Ted ✦ Developer with Fortune 100 financial services firm since July 2008. ✦ Working with Java since late 2008. ✦ Web developer as freelance/hobby since 2001 (LAMP) ✦ Lots of freelancing and web hosting during college ✦ http://ted.pennin.gs / @thesleepyvegan / [email protected]
  • 3. What is MVC? ✦ MVC spits code into three areas ✦ Model – data/persistence layer ✦ View – presentation layer, UI and client-side scripts ✦ Controller – business logic that controls data and execution ✦ Strong design pattern that emphasizes separation.
  • 4. MVC Cleanliness ✦ Application logic goes in the controllers. ✦ Data persistence goes in the model. ✦ UI presentation and JavaScript varnish goes in the views. ✦ Do not try to fight MVC code separation. If you feel the need to break convention, refactor.
  • 5. MVC Done Badly – Views ✦Doing actual work in JSPs <% try { String url="jdbc:mysql://localhost/companies?user=larry_ellison&password=yachts"; con=DriverManager.getConnection(url); stmt=con.createStatement(); } catch(Exception e){ System.err.println(“Unable to acquire companies!”); e.printStackTrace(); } if (request.getParameter("action") != null){ String bookname = request.getParameter("company_name"); String author = request.getParameter("price"); stmt.executeUpdate("insert into acquisitions(company_name,price) values ('"+company_name+"','"+price+"')"); rst=stmt.executeQuery("select * from acquisitions"); %> <html> <body> <center> <h2>Victim List</h2> <table border="1" cellspacing="0" cellpadding="0"> Adapted from http://www.roseindia.net/jsp/Accessingdatabase-fromJSP.shtml
  • 6. MVC Done Badly – Controllers ✦HTML in the controllers @RequestMapping(“/acquisitions/new”) public void createAcquisition(Model model) { Acquisition v = new Acquisition(); model.addAttribute(“newVictim”, v); model.addAttribute(“newVictimForm”, collectVictimVitalStats(v)); } private String renderVictimInfoForm(Acquisition v) { StringBuilder sb = new StringBuilder() .append("<form action='").append(SERVLET_PATH) .append("' method='post'><h1>Please enter your information</h1>"); sb.append("<p><label for='name'>Victim Name</label>") .append("<input type='text' name='name' value='") .append(v.getName()).append("'/>").append("</p>"); [...] return sb.toString(); }
  • 7. Speaking of Bad Things Oracle CEO Larry Ellison
  • 8. MVC Done Badly – Models ✦Business logic in the model public class Victim { private String name; private short numberOfYachts; [. . . ] public Victim(String name, short numberOfYachts) { if (numberOfYachts < 4) { throw new VictimUnworthyException(“Too few yachts. Larry Ellison will not be sated.”); } } [. . . ] } ✦HTML in methods public String toString() { return “<h3 class=‘name’>Why Hello ” + this.name + “!</h3><br/>I admire your” + “<strong><font color=“pink”>” + this.numberOfYachts + “</font></strong> yachts”; }
  • 9. Spring MVC is Still Spring ✦ Full Dependency Injection and Inversion of Control ✦ XML- and Annotation-based configuration ✦ Heavy use of annotation-based configuration ✦ Application context files are still available, but mostly unnecessary ✦ <mvc:annotation-driven> and <content:component-scan> ✦ Maven dependencies and archetypes ✦ Convention over configuration ✦ Very few interfaces to implement “Spring Goodness”
  • 10. The Basic Annotations ✦ Spring MVC is mostly annotation driven, so here is your vernacular: ✦ Standard Spring annotations: ✦ @Component, @Service, @Repository, ✦ @Autowired, @Value, @Configuration ✦ @Transactional, @Aspect and JSR 284 + 330 ✦ @Controller – an MVC Controller ✦ @RequestMapping ✦ @ModelAttribute ✦ @RequestParam and @PathVariable ✦ @SessionAttributes
  • 11. How does Spring do MVC? ✦ All requests are sent to Spring’s DispatcherServlet ✦ DispatcherServlet sends requests to @Controllers ✦ THERE ARE NO DEVELOPER-WRITTEN SERVLETS Diagram from Spring docs on their website
  • 12. The Simplicity of Controllers ✦ @Controller makes a class a controller “bean” ✦ Specialization of @Component ✦ @RequestMapping defines the URL paths handled by a controller or method. ✦ It is possible to nest paths, as in example. ✦ Many different RequestMethods can be serviced. ✦ {} define @PathVariable/@ReqParam ✦ Value of Inheritance ✦ Annotation caveat
  • 13. Controller Example @Controller @RequestMapping({ "/yachts", "/mah-boats" }) public class YachtController extends BaseController { @RequestMapping(value = "/{yachtKey}", method = GET) public String displayYacht( @PathVariable(“yachtKey”) String yachtKey, Model model) { LOG.debug("Displaying Yacht " + yachtKey); Yacht yacht = service.findYachtByKey(yachtKey); model.addAttribute("yacht", yacht); return YACHT_PAGE_VIEW; } }
  • 14. Reading User Input ✦ Typically happens through method parameter annotations ✦ @PathVariable(“var”) / @RequestParam(“var”) ✦ Corresponds to a {var} value in a @RequestMapping ✦ Best practice to be explicit ✦ @ModelAttribute ✦ @RequestBody ✦ Any type can be used. ✦ Be wary of type conversion issues ✦ See PropertyEditorSupport and Spring’s Converter SPI ✦ Use @InitBinder in a controller superclass ✦ JSON payloads can often be unmarshalled on the fly.
  • 15. Populating The Model ✦ In MVC, dynamic data only appears in views through the model. ✦ Spring MVC enforces this pattern constraint. ✦ Each request receives a fresh new Model (or equivalent). ✦ Two basic approaches ✦ In @Controller method, receive a Model or ModelAndView object ✦ Add directly to it. ✦ No need to return Model/MV object received. (More on that later.) ✦ In @Controller class, annotate methods with @ModelAttribute(“name”) ✦ Used in a @Controller superclass, can be used for template data ✦ User privileges ✦ Pseudo-security hack until full security is implemented
  • 16. Creating Forms (1/2) ✦ Creating a new object submission form requires manually instantiating your target object ✦ if you want to create a com.oracle.acquisition.timekeeper.model.TimeEntry(), in your controller method you must ✦ model.addAttribute(“timeEntry”, new com.oracle.acquisition.timekeeper.model.TimeEntry()); Assuming: package com.oracle.acquisition.timekeeper.model; public class TimeEntry { private String victimName; private String projectCode; private double hours; private Date timestamp; […getters, setters, etc…] } ✦ This exact object will be used by your JSP (or similar) in the next step… getter/setter round-tripping on POST
  • 17. Creating Forms (2/2) Most new object views can function as an edit view. Conserve code. <form:form method="post" modelAttribute=“timeEntry" cssClass="form"> <form:label path=“projectCode"> Project Code <form:errors path=“projectCode" cssClass="error" /> </form:label> <form:select items="${userProjectCodes}" path=“projectCode“ itemLabel=“projectName"/> <form:label path=“hours"> Hours <form:errors path=“hours" cssClass="error" /> </form:label> <form:input path=“hours“ /> <button type="submit">Submit</button> </form:form>
  • 18. Demo ✦ Working forms ✦ Bean validation ✦ Error messages appear in browser automagically
  • 19. Bean Validation (JSR-303) ✦ Constraints are defined by annotations on the actual data entities ✦ Validation is executed automagically by framework ✦ User-friendly errors appear automagically on the view. ✦ Object graphs can be traversed and nested objects are validated (or not, if you wish). @Entity public class Yacht { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; @Size(min = 4, max = 35, message = "Key must be between {min} and {max} characters long.") @NotEmpty(message = "Key is required.") @Pattern(regexp = "[A-Za-z0-9_-]*", message = "Only letters, numbers, underscores and hyphens may be used.") private String key; @Size(min = 4, max = 35, message = "Name must be between {min} and {max} characters long.") @NotEmpty(message = "Name is required.") private String name; @ValidDate private Date acquisitionDate; }
  • 20. Setting Up And Using Bean Validation ✦ As simple as @Valid ✦ Can be applied inside domain to validate child/2nd degree objects ✦ BindingResult for errors ✦ MUST be argument after @Valid argument (quirk) ✦ RuntimeException if not ✦ toString() is your friend. ✦ Validating a large object graph is risky. ✦ Complicates future changes ✦ On the other hand, very hard to merge BindingResults
  • 21. Updated Controller @Controller public class YachtController { @RequestMapping(method = POST) public ModelAndView saveYacht(@Valid Yacht yacht, BindingResult result, ModelAndView mv) { LOG.debug("Attempting to save Yacht: " + yacht.getKey()); if (result.hasErrors()) { LOG.debug("Submission has errors " + result); mv.setViewName(MODIFY_YACHT_VIEW); return mv; } service.store(yacht); FlashMap.setSuccessMessage("Successfully saved Yacht"); return createRedirect(yacht); } }
  • 22. Handling Validation Errors ✦ Ensure that you have a BindingResult.hasErrors() check in @Controller ✦ When returning edit view, ensure all needed model attributes are present ✦ This includes the object being validated if you construct a new Model/ MV ✦ You may need a call to the root-level form:errors in order to capture object- level errors (not field-level). ✦ <form:errors path=“” /> ✦ Be sure you interrupt flow so you don’t persist invalid objects ✦ VALIDATION ERRORS ARE NOT EXCEPTIONS ✦ There is a Hibernate option to validate pre-persist, but this is nuanced ✦ Legacy objects ✦ May be incompatible with Spring-managed dependencies
  • 23. Writing Your Own Constraints ✦ Constraints can be combined and composed ✦ For example, @NotEmpty actually means @NotNull, @Size(min=1) & @ReportAsSingleViolation ✦ Write an annotation class ✦ @Target(ElementType.FIELD) ✦ @Retention(RetentionPolicy.RUNTIME) ✦ @Documented (or not) ✦ @Constraint(validatedBy = YourCustomValidator.class) ✦ Be sure to add a default message ✦ These can be Java properties read from a file (Internationalization/ i18n) ✦ Write a validator ✦ Implement ConstraintValidator<AnnotationType, TargetClass> ✦ Return boolean for isValid(TargetClass object, …) ✦ Statefulness (via initialize() method) ✦ Dependency Injection, Constructors, and Hibernate ORM issue
  • 24. Writing Unit Tests For Validation Magic ✦ A lot of JSR-303 is wizardry and magic beans. ✦ Write unit tests so you ensure code execution is predictable. ✦ Easiest to write using Spring’s JUnit Test Runner ✦ Point to an application context field that contains ✦ <bean id="validator“ class="org.springframework.validation.beanvalidation.LocalVa lidatorFactoryBean" /> ✦ Ensure a JSR-303-compliant validator is on your test classpath ✦ Eg, Hibernate Validator
  • 25. Example Unit Test @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration({ "classpath:your-persistence.xml", "classpath:your-persistence-test.xml" }) public class YachtValidationTest { @Autowired private javax.validation.Validator validator; private Yacht emptyYacht; @Before public void setUpEmptyYacht() { emptyYacht = new Yacht(); } @Test public void theKeyFieldIsRequired() { Set<ConstraintViolation<Yacht>> constraintViolations = validator .validate(emptyYacht); boolean containsYachtKeyViolation = false; for (ConstraintViolation<Yacht> violation : constraintViolations) { if ("key".equals(violation.getPropertyPath().toString()) && violation.getMessageTemplate().contains("required")) { containsYachtKeyViolation = true; } } assertTrue(containsYachtKeyViolation); } }
  • 26. The Guts of Spring MVC ✦ Method Return Types ✦ View Resolvers ✦ Exception Handling ✦ File Uploads ✦ Servlet-level code (if you have to) ✦ URL Rewriting
  • 27. Controller Method Return Types ✦ @Controller methods can return many different types. Often: ✦ Model ✦ ModelAndView (use Model.setView(View) or Model.setViewName (String)) ✦ Distinction between View and View Name ✦ String for the view name to display ✦ Can return void if you’ve drank plenty of convention over configuration koolaid. ✦ Dangerous if you refactor a lot (or the next person does). ✦ Methods can also be annotated with @RequestBody ✦ Used to return a value without going through MVC apparatus ✦ Generally bad form, but good for testing or mock apps. ✦ @ModelAttribute has the same two distinct meanings as @ModelAttribute
  • 28. View Resolvers ✦ What is a ViewResolver and how does this differ from a View Name? ✦ Apache Tiles and TilesViewResolver ✦ InternalResourceViewResolver (default) ✦ ContentNegotiatingViewResolver ✦ JSON ✦ XML (if needed) ✦ RSS/Atom ✦ And many, many others… ViewResolver overload….
  • 29. View options and Apache Tiles ✦ Spring MVC is does not attempt to implement its own view layer ✦ JSTL and JSP/JSPX ✦ Apache Tiles is commonly used for page modularization and templating ✦ org.springframework.web.servlet.view.tiles2.TilesViewResolver ✦ org.springframework.web.servlet.view.tiles2.TilesConfigurer ✦ Similar options are available for Freemarker, Velocity and others ✦ JSON can be rendered easily via MappingJacksonJsonView ✦ Don’t forget ContentNegotiatingViewResolver and ignoreAcceptHeaders (true) ✦ Straight JSPs are possible too ✦ Convention over configuration, but often creates complexity/duplication
  • 30. Handling Exceptions ✦ Implement a HandlerExceptionResolver for application-wide errors public interface HandlerExceptionResolver { ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex); } ✦ @ExceptionHandler can annotate a method for @Controller-specific exceptions, such as an IOException in a particular method. This only applies to the controller in which it is declared. ✦ Consider adding web.xml <error-page> handlers too (if your exception handler throws an exception, or if you think everything may break.) ✦ A separate error @Controller is a good idea, with minimal dependencies
  • 31. File Uploads ✦ Uses Commons File Upload ✦ org.springframework.web.multipart.commons.CommonsMultipartResolver ✦ Three easy steps (plus background Spring magic) ✦ Instantiate CommonsMultipartResolver in app context or @Config ✦ Add enctype=“multipart/form-data” to your <form> tag in your view ✦ Add a MultipartFile to your POST @Controller method argument ✦ Use @ModelAttribute for form submission specificity ✦ MultipartFile is your friend ✦ getBytes()* ✦ getContentType() – don’t forget about mime types! ✦ getOriginalFilename() ✦ transferTo(File dest)* (* but IOException is not)
  • 32. Burrowing Down To The Servlets ✦ Sometimes it is necessary to write output directly to servlets. ✦ Extend AbstractView ✦ In your controller, specify your custom view ✦ ModelAndView.setViewName(String name) ✦ ModelAndView.setView(View view) ✦ This is useful for user data in binary form, such as images. ✦ In general, avoid this approach @Component public class ByteArrayView extends AbstractView { public ByteArrayView() { } @Override protected final void renderMergedOutputModel(Map model, HttpServletRequest request, HttpServletResponse response) throws Exception { byte[] bytes = (byte[]) model.get("data"); String contentType = (String) model.get ("contentType"); response.setContentType(contentType); response.setContentLength(bytes.length); ServletOutputStream out = response.getOutputStream(); FileCopyUtils.copy(bytes, out); } }
  • 33. URL Rewriting ✦ URL rewriting implemented as a servlet-level filter (web.xml): ✦ org.tuckey.web.filters.urlrewrite.UrlRewriteFilter ✦ Uses a urlrewrite.xml file, typically in the WEB-INF: <rule> <from>/sun/*</from> <to>/oracle/$1</to> </rule> ✦ Rules are standard regular expressions (java.util.regex.Pattern). ✦ Used extensively to separate dynamic content requests from static content requests (eg, css, images, javascript). ✦ Can be used to route multiple different request paths to the same DispatcherServlet instance (thereby conserving memory).
  • 34. Demo ✦ Creating a new project from the Maven archetype/template in STS IDE ✦ maven-tomcat-plugin, maven-jetty-plugin ✦ Live coding!
  • 35. References ✦ Spring Docs (3.0.x) Manual: http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/ JavaDocs: http://static.springsource.org/spring/docs/3.0.x/javadoc-api/ ✦ Maven Jetty Plugin (mvn jetty:run) http://docs.codehaus.org/display/JETTY/Maven+Jetty+Plugin ✦ Miscellaneous ✦ Spring Roo Keynote http://www.youtube.com/watch?v=GQHlhIIxCIc