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

PDF
Overview of the AngularJS framework
PDF
How to Build ToDo App with Vue 3 + TypeScript
PDF
Angularjs practical project experiences with javascript development in a bank
PDF
How to Implement Basic Angular Routing and Nested Routing With Params in Angu...
PDF
AngularJS - Javascript framework for superheroes
PDF
AngularJS Basics and Best Practices - CC FE &UX
PPT
Spring 3.x - Spring MVC
ODP
Angularjs
Overview of the AngularJS framework
How to Build ToDo App with Vue 3 + TypeScript
Angularjs practical project experiences with javascript development in a bank
How to Implement Basic Angular Routing and Nested Routing With Params in Angu...
AngularJS - Javascript framework for superheroes
AngularJS Basics and Best Practices - CC FE &UX
Spring 3.x - Spring MVC
Angularjs

What's hot (20)

PDF
Introduction to Spring MVC
PPTX
PDF
Vaadin & Web Components
KEY
Introduction to ASP.NET MVC
PDF
AngularJS Project Setup step-by- step guide - RapidValue Solutions
PPTX
AngularJs presentation
PDF
Vaadin and Spring at Devoxx UK 2015
PPSX
PDF
Top 7 Angular Best Practices to Organize Your Angular App
PDF
Testdrive AngularJS with Spring 4
PDF
AngularJS - Services
PPTX
Angular Mini-Challenges
PDF
Gdg dev fest hybrid apps your own mini-cordova
PDF
Seven Versions of One Web Application
PPTX
Asp.Net MVC Intro
PDF
Vaadin Components @ Angular U
PPT
Angular App Presentation
PPTX
Introduction to Google Guice
PPTX
Introduction to angular js for .net developers
PPTX
Comparing Angular and React JS for SPAs
Introduction to Spring MVC
Vaadin & Web Components
Introduction to ASP.NET MVC
AngularJS Project Setup step-by- step guide - RapidValue Solutions
AngularJs presentation
Vaadin and Spring at Devoxx UK 2015
Top 7 Angular Best Practices to Organize Your Angular App
Testdrive AngularJS with Spring 4
AngularJS - Services
Angular Mini-Challenges
Gdg dev fest hybrid apps your own mini-cordova
Seven Versions of One Web Application
Asp.Net MVC Intro
Vaadin Components @ Angular U
Angular App Presentation
Introduction to Google Guice
Introduction to angular js for .net developers
Comparing Angular and React JS for SPAs
Ad

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

PDF
Spring 3: What's New
PPTX
3. Spring MVC Intro - PowerPoint Presentation (1).pptx
PPT
Spring MVC Basics
PDF
Spring_Course_Content
PDF
quickguide-einnovator-7-spring-mvc
ODP
Java Spring MVC Framework with AngularJS by Google and HTML5
ODP
springmvc-150923124312-lva1-app6892
PDF
My04_MVC.pdf
PDF
Spring mvc
PDF
Spring MVC
PDF
Spring MVC introduction HVA
PPT
PPTX
Advance java session 13
PPTX
Unit 38 - Spring MVC Introduction.pptx
PPT
Spring Framework
PDF
Multi Client Development with Spring - Josh Long
PDF
MVC 1.0 als alternative Webtechnologie
PPTX
Spring mvc
PPTX
Spring MVC framework features and concepts
PDF
Advance Java Training in Bangalore | Best Java Training Institute
Spring 3: What's New
3. Spring MVC Intro - PowerPoint Presentation (1).pptx
Spring MVC Basics
Spring_Course_Content
quickguide-einnovator-7-spring-mvc
Java Spring MVC Framework with AngularJS by Google and HTML5
springmvc-150923124312-lva1-app6892
My04_MVC.pdf
Spring mvc
Spring MVC
Spring MVC introduction HVA
Advance java session 13
Unit 38 - Spring MVC Introduction.pptx
Spring Framework
Multi Client Development with Spring - Josh Long
MVC 1.0 als alternative Webtechnologie
Spring mvc
Spring MVC framework features and concepts
Advance Java Training in Bangalore | Best Java Training Institute
Ad

Recently uploaded (20)

PDF
A comparative analysis of optical character recognition models for extracting...
PPTX
Spectroscopy.pptx food analysis technology
PDF
Building Integrated photovoltaic BIPV_UPV.pdf
PDF
Machine learning based COVID-19 study performance prediction
PDF
Agricultural_Statistics_at_a_Glance_2022_0.pdf
PDF
Mobile App Security Testing_ A Comprehensive Guide.pdf
PPTX
Cloud computing and distributed systems.
PDF
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
PDF
Spectral efficient network and resource selection model in 5G networks
PDF
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
PPTX
ACSFv1EN-58255 AWS Academy Cloud Security Foundations.pptx
PPTX
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
PPTX
Machine Learning_overview_presentation.pptx
PPT
“AI and Expert System Decision Support & Business Intelligence Systems”
PDF
Unlocking AI with Model Context Protocol (MCP)
PDF
Encapsulation theory and applications.pdf
PDF
Electronic commerce courselecture one. Pdf
PDF
Advanced methodologies resolving dimensionality complications for autism neur...
PDF
Approach and Philosophy of On baking technology
PDF
Assigned Numbers - 2025 - Bluetooth® Document
A comparative analysis of optical character recognition models for extracting...
Spectroscopy.pptx food analysis technology
Building Integrated photovoltaic BIPV_UPV.pdf
Machine learning based COVID-19 study performance prediction
Agricultural_Statistics_at_a_Glance_2022_0.pdf
Mobile App Security Testing_ A Comprehensive Guide.pdf
Cloud computing and distributed systems.
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
Spectral efficient network and resource selection model in 5G networks
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
ACSFv1EN-58255 AWS Academy Cloud Security Foundations.pptx
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
Machine Learning_overview_presentation.pptx
“AI and Expert System Decision Support & Business Intelligence Systems”
Unlocking AI with Model Context Protocol (MCP)
Encapsulation theory and applications.pdf
Electronic commerce courselecture one. Pdf
Advanced methodologies resolving dimensionality complications for autism neur...
Approach and Philosophy of On baking technology
Assigned Numbers - 2025 - Bluetooth® Document

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 / ted@pennin.gs
  • 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