Spring MVC: In-Depth Guide
Tags: java, webdev
Published: 2020-05-15 15:56:24

(**Editor’s note**: At ~7,500 words, you probably don’t want to try reading this on a mobile device. Bookmark it and come back later.)

## Introduction

### What is Spring MVC?

[Spring MVC](https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html) is Spring’s web framework. It lets you build web sites or RESTful services (think: JSON/XML) and is nicely integrated into the Spring ecosystem, e.g. it powers the @Controllers and @RestControllers of your Spring Boot applications.

That doesn’t really help, does it?

**Luckily, there’s also a long answer**: The remainder of this document.

(If you are unsure of what Spring or Spring Boot is, you might want to read [What Is Spring Framework?](https://www.marcobehler.com/guides/spring-framework), first.)

## Java Web Basics: HttpServlets

When writing web applications in Java, with or without Spring (MVC/Boot), you are mostly talking about writing applications that return two different data formats:

1.  **HTML** → Your web app creates HTML pages that can be viewed in a browser.

2.  **JSON/XML** → Your web app provides RESTful services, that produce JSON or XML. Javascript-heavy websites or even other web services can then consume the data that these services provide.

3.  (Yes, there’s other data formats and use cases as well, but we’ll ignore them for now.)

How would you write such applications *without* any framework? Just with plain Java?

Answering this question is essential to *really* understanding Spring MVC, so do not just skip ahead because you think it has nothing to do with Spring MVC.

**Answer**

At the lowest level, every Java web application consists of one or more `HttpServlets`. They generate your HTML, JSON, or XML.

In fact, (almost) every single framework of the 1 million available Java web frameworks ([Spring MVC](https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html), [Wicket](https://wicket.apache.org/), [Struts](https://struts.apache.org/)) is built *on top* of HttpServlets.

### How to write HTML pages with HttpServlets

Let’s have a look at a super simple HttpServlet that returns a very simple, static, HTML page.

```java
    package com.marcobehler.springmvcarticle;

    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;

    public class MyServletV1 extends HttpServlet {

        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
            if (req.getRequestURI().equals("/")) {
                resp.setContentType("text/html");
                resp.getWriter().print("<html><head></head><body><h1>Welcome!</h1><p>This is a very cool page!</p></body></html>");
            }
            else {
                throw new IllegalStateException("Help, I don't know what to do with this url");
            }
        }
    }
```

Let’s break this down.

```java
    public class MyServletV1 extends HttpServlet {
```

Your servlet *extends* Java’s HttpServlet class.

```java
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
```
To handle (any) GET request, you need to override the `doGet()` method from the superclass. For POST requests you would override `doPost()`. Similarly, for all other HTTP methods.
```java
    if (req.getRequestURI().equals("/")) {
```
Your servlet needs to make sure that the URL that comes in is a request that it knows how to handle. For now, the servlet *only* handles "/", i.e.: it handles `www.marcobehler.com`, but *NOT* `www.marcobehler.com/hello`.
```java
    resp.setContentType("text/html");
```
You need to set the proper **Content-Type** on the ServletResponse to let the browser know what content you are sending. In this case, it’s HTML.
```java
    resp.getWriter().print("<html><head></head><body><h1>Welcome!</h1><p>This is a very cool page!</p></body></html>");
```
Remember: web sites are just HTML strings! So you need to generate an HTML string, any way you want, and send that back with the ServletResponse. One way of doing that is with the response’s writer.

After writing your servlet, you would register it with a servlet container, like [Tomcat](https://tomcat.apache.org/) or [Jetty](https://www.eclipse.org/jetty/). If you are using an embedded version of either servlet container, all the code needed to *run* your servlet would look like this:
```java
    package com.marcobehler.springmvcarticle;

    import org.apache.catalina.Context;
    import org.apache.catalina.LifecycleException;
    import org.apache.catalina.Wrapper;
    import org.apache.catalina.startup.Tomcat;

    public class TomcatApplicationLauncher {

        public static void main(String[] args) throws LifecycleException {
            Tomcat tomcat = new Tomcat();
            tomcat.setPort(8080);
            tomcat.getConnector();

            Context ctx = tomcat.addContext("", null);
            Wrapper servlet = Tomcat.addServlet(ctx, "myServlet", new MyServletV2());
            servlet.setLoadOnStartup(1);
            servlet.addMapping("/*");

            tomcat.start();
        }
    }
```
Let’s break this down.
```java
    Tomcat tomcat = new Tomcat();
    tomcat.setPort(8080);
    tomcat.getConnector();
```
You configure a new Tomcat server which will start on port 8080.
```java
    Context ctx = tomcat.addContext("", null);
    Wrapper servlet = Tomcat.addServlet(ctx, "myServlet", new MyServletV2());
```
This is how you register your Servlet with Tomcat. This is the first part, where you simply tell Tomcat about your servlet.
```java
    servlet.addMapping("/*");
```
The second part is letting Tomcat know for what requests the servlet is responsible, i.e. the mapping. A mapping of `/*` means it’s responsible for *any* incoming request (`/users`, `/register`, `/checkout`).
```java
    tomcat.start();
```
That’s it. You run your `main()` method now, go to port 8080 in your favorite web browser (<http://localhost:8080/>), and you’ll see a nice HTML page.

So, essentially, as long as you keep extending your `doGet()` and `doPost()` methods, your whole web application could consist of just one servlet. Let’s try that out.

### How to write JSON endpoints with HttpServlets

Imagine that apart from your (pretty empty) HTML index page, you now also want to offer a REST API for your soon-to-be-developed front end. So your React or AngularJS front end would call a URL like this:
```java
`/api/users/{userId}`
```
That endpoint should return data in JSON format for the user with the given userId. How could we enhance our `MyServlet` to do this, again, no frameworks allowed?
```java
    package com.marcobehler.springmvcarticle;

    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;

    public class MyServletV2 extends HttpServlet {

        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
            if (req.getRequestURI().equals("/")) {
                resp.setContentType("text/html");
                resp.getWriter().print("<html><head></head><body><h1>Welcome!</h1><p>This is a very cool page!</p></body></html>");
            } else if (req.getRequestURI().startsWith("/api/users/")) {

                Integer prettyFragileUserId = Integer.valueOf(req.getRequestURI().lastIndexOf("/") + 1);

                resp.setContentType("application/json");

                // User user = dao.findUser(prettyFragileUserId)
                // actually: jsonLibrary.toString(user)
                resp.getWriter().print("{\n" +
                        "  \"id\":" + prettyFragileUserId + ",\n" +
                        "  \"age\": 55,\n" +
                        "  \"name\" : \"John Doe\"\n" +
                        "}");
            } else {
                throw new IllegalStateException("Help, I don't know what to do with this url");
            }
        }
    }
```
Let’s break this down.
```java
    } else if (req.getRequestURI().startsWith("/api/users/")) {
```
We add another `if` to our doGet method, to handle the `/api/users/` calls.
```java
    Integer prettyFragileUserId = Integer.valueOf(req.getRequestURI().lastIndexOf("/") + 1);
```
We do some `extremely` fragile URL parsing. The last part of the URL is the userID, e.g. `5` for `/api/users/5`. We just assume here that the user always passes in a valid int, which you would actually need to validate!
```java
    resp.setContentType("application/json");
```
Writing JSON to the browser means setting the correct content-type.
```java
    // User user = dao.findUser(prettyFragileUserId)
    // actually: jsonLibrary.toString(user)
    resp.getWriter().print("{\n" +
            "  \"id\":" + prettyFragileUserId + ",\n" +
            "  \"age\": 55,\n" +
            "  \"name\" : \"John Doe\"\n" +
            "}");
```
Again, JSON is just text, so we can write that directly to the HTTPServletResponse. you would probably use a JSON library to convert our User Java object to this string, but for the sake of simplicity, I won’t show that here.


### The problem with our One-Servlet-To-Rule-Them-All Approach

While our servlet above works, there are quite a few problems on the horizon:

1.  Your Servlet needs to do a lot of manual HTTP-specific plumbing, checking request URIs, fumbling with strings, etc. In other words: it needs to know `WHAT` the users want to do.

2.  It then also needs to find the data for whatever you want to display. In other words: it needs to know the `HOW`. In our example above, that would be finding the user in a database, which we conveniently commented-out.

3.  It then also needs to convert that data to JSON or to HTML and set the appropriate response types.

Quite a lot of different responsibilities, eh? Wouldn’t it be nicer if you didn’t have to care about all that plumbing? No more request URI and parameter parsing, no more JSON conversions, no more servlet responses?

That’s `exactly` where [Spring MVC](https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html) comes in.

## What is Spring MVC’s DispatcherServlet?

What if I told you that Spring MVC is really just one servlet, like our uber-servlet above? (And yes, that’s of course a bit of a lie)

Meet the `DispatcherServlet`.

Spring MVC’s DispatcherServlet handles `every` incoming HTTP request (that’s it is also called *front controller*). Now, what does *handle* mean, exactly?

### A sample HTTP request flow

Imagine a "register user workflow", where a user fills out a form and submits it to the server to get a nice little success HTML page back.

In that case, your DispatcherServlet needs to do the following things:

1.  It needs to have a look at the incoming HTTP method request URI and any request parameters. E.g.: `POST /register?name=john&age33`.

2.  It needs to potentially convert the incoming data (request parameters/body) to nice little Java objects and forward them to a `@Controller` or `@RestController` class that *you* wrote.

3.  Your `@Controller` method saves a new user to the database, maybe sends out an email, etc. It would highly likely delegate that to another service class, but let’s assume for now this happens inside the controller.

4.  It needs to take whatever the output from your @Controller was and convert it back to `HTML/JSON/XML`.

### DispatcherServlet Overview

The whole process looks like this, with a fair number of intermediary classes neglected because DispatcherServlet doesn’t do all the work itself.

![Dispatcher Servlet](https://www.marcobehler.com/images/dispatcher-servlet1d.png "Dispatcher Servlet")


What’s a ModelAndView in the above graphic? How exactly does the DispatcherServlet convert the data?

It is easiest to understand by looking at a real-life example. For example: How do you write HTML websites with Spring MVC? Let’s find out in the next section.

## How to write HTML with @Controllers

Whenever you want to write HTML to a client like a browser with Spring MVC (and that includes Spring Boot), you’ll want to write a @Controller class. Let’s do that now.

### How to write a @Controller in Spring

For our user registration workflow from above (`POST /register?name=john&age33`), you would write the following class.
```java
    package com.marcobehler.springmvcarticle;

    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestParam;

    @Controller
    public class RegistrationController {

        @PostMapping("/register")
        public String registerUser(@RequestParam(required = false) Integer age, @RequestParam String name, Model model) {
            User user = new User(name, age);

            // TODO save user to database
            // userDao.save(user);

            // TODO send out registration email
            // mailService.sendRegistrationEmail(user);

            model.addAttribute("user", user);
            return "registration-success";
        }
    }
```
Let’s break this down.
```java
    @Controller
    public class RegistrationController {
```
A controller class in Spring is simply annotated with the `@Controller` annotation, it does not need to implement a specific interface or extend from another class.
```java
    @PostMapping("/register")
```
This line tells our DispatcherServlet that whenever a POST request comes in for the path `/register`, *including* any request parameters (e.g. ?username=), it should dispatch the request to this very controller method.
```java
    public String registerUser(@RequestParam(required = false) Integer age, @RequestParam String name, Model model) {
```
**Note** The naming of our method (`registerUser`) does not really matter, it could be called anything.

We do however specify that each request should include two request parameters, which could either be part of the URL (`?age=10&name=Joe`) or be in the POST request body. Furthermore, only the `name` parameter is required (the `age` parameter is optional)

And the `age` parameter, if the user supplies it, is automatically converted to an Integer (an exception is thrown if the supplied value is not a valid Integer)

Last, but not least, Spring MVC automatically injects a `model` parameter into our controller method. That model is a simple map where you need to put all the data that you want to show in your final HTML page, but more on that in a second.
```java
    User user = new User(name, age);

    // TODO save user to database
    // userDao.save(user);

    // TODO send out registration email
    // mailService.sendRegistrationEmail(user);
```
You do whatever you need to do with the incoming request data. Create a user, save it to a database, send out an email. This is *your* business logic.
```java
    model.addAttribute("user", user);
``` 
You add your user to the model, under key "user". Which means, you’ll be able to reference it in your HTML template later on, like "${user.name}". More on that in a second.
```java
    return "registration-success";
```
Your method returns a simple string, with the value `registration-success`. This is not just any string, it is a reference to your view, i.e. the HTML template that you want Spring to render.

### What do views look like?

Let’s ignore for now how (or rather where) Spring MVC will try and find that view, i.e. your template; instead, let’s see what your `registration-success.html` template should look like.
```html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>

    <p th:text="'Hello ' + ${user.name} + '!'"></p>

    </body>
    </html>
```
It’s just a simple HTML page, which contains one *template-y* line. It prints out the name of the user that has just registered.
```html
    <p th:text="'Hello ' + ${user.name} + '!'"></p>
```
The question is, what is this `th:text=` syntax? Is that Spring-specific? Is it something else?

And the answer is that Spring MVC doesn’t really know anything about HTML templates. It needs a 3rd-party templating library to do all HTML templating work and doesn’t necessarily care what library you choose.

In the above case, you are looking at a [Thymeleaf](https://www.thymeleaf.org/) template, which is a very popular choice when working on Spring MVC projects.

### Spring MVC & Templating Libraries

There are several different templating libraries that integrate well with Spring MVC that you can choose from: [Thymeleaf](https://www.thymeleaf.org/), [Velocity](https://velocity.apache.org/), [Freemarker](https://freemarker.apache.org/), [Mustache](https://mustache.github.io/) and even [JSP](https://en.wikipedia.org/wiki/JavaServer_Pages) (even though that is not a templating library).

In fact, you *must* explicitly choose a templating library, because if you do not have such a templating library added to your project and configured correctly, then your @Controller method would not render your HTML page - because it wouldn’t know how to do it.

It also means that you have to learn and understand the syntax of the particular templating library depending on the project you’re, in because they’re all *slightly* different from each other. Fun, right?

### What is a ViewResolver?

For a second, let’s think about where Spring will actually try and find your HTML templates that your @Controller returns.

The class that tries to *find* your template is called a `ViewResolver`. So whenever a request comes into your Controller, Spring will have a look at the configured ViewResolvers and ask them, in order, to find a template with the given name. If you don’t have any ViewResolvers configured, this won’t work.

Imagine you want to integrate with [Thymeleaf](https://www.thymeleaf.org/). Hence you would need a ThymeleafViewResolver.
```java
    package com.marcobehler.springmvcarticle;

    import org.springframework.context.annotation.Bean;
    import org.thymeleaf.spring5.SpringTemplateEngine;
    import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver;
    import org.thymeleaf.spring5.view.ThymeleafViewResolver;

    public class ThymeleafConfig {

        @Bean
        public ThymeleafViewResolver viewResolver() {
            ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();

            SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
            templateResolver.setPrefix("classpath:/templates");
            templateResolver.setSuffix(".html");
            // some other lines neglected...

            SpringTemplateEngine templateEngine = new SpringTemplateEngine();
            templateEngine.setTemplateResolver(templateResolver);
            // some other lines neglected...

            viewResolver.setTemplateEngine(templateEngine);
            return viewResolver;
        }


    }
```
Let’s break this down.
```java
    @Bean
    public ThymeleafViewResolver viewResolver() {
        ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
```
In the end, a ThymeleafViewResolver simply implements Spring’s `ViewResolver` interface. Given a template name (remember: `registration-success`), ViewResolvers can find the actual template.
```java
    SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
```
The ThymeleafViewResolver needs a couple of other Thymeleaf-specific classes to work properly. One of these classes is the `SpringResourceTemplateResolver`. It does the actual work of finding your template.

> **Note**
>
> SpringResourceTemplateResolver is a Thymeleaf class

    templateResolver.setPrefix("classpath:/templates");
    templateResolver.setSuffix(".html");

You are basically saying (with help of the [Spring Resources](https://www.marcobehler.com/guides/spring-framework#spring-resources) syntax): "All my templates are on the classpath, in the `/templates` folder". And, by default, they all end with `.html`. This means:

Whenever our @Controller returns a String like `registration-success`, the ThymeleafViewResolver will look for a template: `classpath:/templates/registration-success.html`.


### Side Note: Spring MVC, Spring Boot & Controllers

You might be thinking: Marco, I’ve never had to configure such a ViewResolver *in my entire life* working on Spring Boot projects. And that is correct. Because Spring Boot automatically *configures one for you*, whenever you add a dependency such as `spring-boot-starter-thymeleaf` to your project.

It also configures the ViewResolver to have a look at your `src/main/resources/template` directory, by default.

So, Spring Boot really just pre-configures Spring MVC for you. Keep that in mind.

### Summary: Model-View-Controller

Having seen a complete @Controller & ViewResolver example makes it much easier to talk about Spring’s **M**odel-**V**iew-**C**ontroller concept.

-   With a couple of annotations (@Controller, @PostMapping, @RequestParam) you can write a `controller` that takes care of receiving request data and processes it accordingly.

-   Your `model` contains all the data (and *just* the data) that you want to render in your view. It is your job to fill that model map.

-   Your `view` is just an HTML template. It does not care about where you got the (model) data from. Or what the current HTTP request is. Or even whether you have an active HTTP Session or not.

It is all about separation of concerns.

While a bit annotation-heavy at first sight, our Spring @Controller class reads a lot better, with a lot less HTTP plumbing involved than our uber-servlet from the beginning.

### More on @Controllers

We already saw a bit of the convenience that Spring MVC gives us when handling HTTP inputs.

-   You do not have to fumble with the requestURI, you can use an annotation instead.

-   You do not have to fumble with request parameter type conversions or if a parameter is optional or required, you can use an annotation instead.

Let’s have a look at the most common annotations that help you process *incoming* HTTP requests.

#### @GetMapping & @RequestMappping

You already saw the `@GetMapping` annotation above. It is equal to the *\`@RequestMapping*\` annotation. Let’s see how:
```java
    @GetMapping("/books")
    public void book() {
            //
    }

    /* these two mappings are identical */

    @RequestMapping(value = "/books", method = RequestMethod.GET)
    public void book2() {

    }
```

`@GetMapping`, `@[Post|Put|Delete|Patch]Mapping` is equivalent to `@RequestMapping(method=XXX)`. It is simply a newer way (Spring 4.3+) of specifying a mapping, so you’ll find the @RequestMapping annotation used a lot in older, legacy Spring projects.

#### @RequestParam

For HTTP request parameters, be that in your URL (`?key=value`) or in a submitted form request body, can be read in via the `@RequestParam` annotation.

You already saw that it does basic type conversion (e.g. from HTTP String parameter to an int) as well as checking for required or optional parameters.
```java
    @PostMapping("/users")   /* First Param is optional */
    public User createUser(@RequestParam(required = false) Integer age, @RequestParam String name) {
       // does not matter
    }
```

If you forget to provide a required parameter with your request, you’ll get a `400 Bad Request` response code and, if using Spring Boot, a default error object that looks like this:
```json
    {"timestamp":"2020-04-26T08:34:34.441+0000","status":400,"error":"Bad Request","message":"Required Integer parameter 'age' is not present","path":"/users"}
```
If you want even more convenience, you can let Spring directly convert all @RequestParams to an object, without any needed annotations. Simply specify your `object` as *\`method parameter*\`.

You just need to make sure your class has corresponding getters/setters.
```java
    @PostMapping("/users")   /* Spring will convert this automatically if you have getters and setters */
    public User createUser(UserDto userDto) {
        //
    }
```
#### @PathVariable

Next to request parameters, another popular way of specifying variables would be directly in the request URI, as a `@PathVariable`. So for getting a user profile with `userId=123`, you would call the following URL:
`GET /users/123`
```java
    @GetMapping("/users/{userId}")  
    public User getUser(@PathVariable String userId) {
        // ...
        return user;
    }
```

1.  You just need to make sure that your parameter value matches the one between the `{}` in your request mapping annotation.

In addition, `PathVariables` can also be required or optional.
```java
    @GetMapping("/users/{userId}")
       public User getUser(@PathVariable(required = false) String userId) {
           // ...
           return user;
       }
```
And PathVariables could, of course, be directly translated to a Java object (provided, the object has matching getters/setters).
```java
    @GetMapping("/users/{userId}")
    public User getUser(UserDto userDto) {
        // ...
        return user;
    }
```
### Summary: @Controllers

In short, when writing HTML pages with Spring MVC you’ll have to do just a few things:

1.  Write your @Controllers, sprinkled with a couple of annotations. Spring will take care to present you the request input (request params, path variables) in a convenient manner.

2.  Execute whatever logic you need to fill your model. You can conveniently inject the model into any controller method.

3.  Let your @Controller know which HTML template you want rendered and return the template’s name as a string.

4.  Whenever a request comes in, Spring will make sure to call your controller method, and take the resulting model and view, render that to an HTML string and return it back to the browser.

5.  (Provided of course, you set up an appropriate templating library, which Spring Boot will automatically do for you, as long as you add the needed dependencies to your project.)

That’s it.

## How to write XML/JSON with @RestControllers

Things are a bit different when you are writing RESTFul services. Your client, be that a browser or another web service, will (usually) create JSON or XML requests. The client sends, say, a JSON request, you process it, and then the sender expects JSON back.

So, a sender might send you this piece of JSON as part of the HTTP request body.

    POST http://localhost:8080/users

    ###
    {"email": "angela@merkel.de"}

But on the Java side (in your Spring MVC program) you do not want to mess with raw JSON strings. Neither when receiving requests like above, nor when sending responses back to the client.

Instead, you’d like to just have Java objects that get converted automatically, by Spring.
```java
    public class UserDto {
        private String email;
        //...
    }
```

This also means that you do *not* need all that model and view processing that you had to do when rendering HTML in your @Controllers. For RESTful services you don’t have a templating library reading in an HTML template and filling it with model data to generate a JSON response for you.

Instead, you want to go directly from HTTP Request → Java object and from Java Object → HTTP response.

As you might have guessed, that’s exactly what Spring MVC allows you to do, by writing `@RestControllers`.

### How to write @RestControllers

The first thing you need to do to output XML/JSON is to write a `@RestController` instead of a @Controller. (Although @RestController *IS* a @Controller, see [FAQ](#difference-controller-restcontroller) for what the exact difference is).

If we were to write a REST Controller for a bank, that returns a user’s transaction list, it could look something like this:
```java
    package com.marcobehler.springmvcarticle;

    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;

    import java.util.Collections;
    import java.util.List;

    @RestController
    public class BankController {

        @GetMapping("/transactions/{userId}")
        public List<Transaction> transactions(String userId) {

            // find transaction by user
            // List<Transaction> = dao.findByUserId(userId);

            List<Transaction> transactions = Collections.emptyList();
            return transactions;
        }
    }
```
Let’s break it down.
```java
    @RestController
    public class BankController {
```

You annotated the BankController class with the `@RestController` annotation, which signals Spring that you do not want to write HTML pages through the usual ModelAndView process.

Instead, you want to write XML/JSON (or some other format) directly into the HTTP response body.
```java
    public List<Transaction> transactions(String userId) {
```
Your controller does not return a String (view) anymore. Instead, it returns a `List<Transaction>`, that you want Spring to convert to an appropriate JSON or XML structure. You basically want your Transaction Java objects to become this (someone was hungry for fast food very early in the morning):
```json
    [
      {
        "occurred": "28.04.2020 03:18",
        "description": "McDonalds - Binging",
        "id": 1,
        "amount": 10
      },
      {
        "occurred": "28.04.2020 06:18",
        "description": "Burger King - Never enough",
        "id": 2,
        "amount": 15
      }
    ]
```
But how would Spring MVC know that your transaction list should get converted to JSON? Why not XML? Or YAML? How does your @RestController method know what the supposed response format should be?

For that, Spring has the concept of `Content Negotiation`.

### How (Response) Content Negotiation works: Accept Header

In short, content negotiation means that the *client* needs to tell your server what response format it wants to get back from your @RestController.

How? By specifying the `Accept` header with the HTTP request.

    GET http://localhost:8080/transactions/{userid}
    Accept: application/json

Spring MVC will have a look at that `Accept` header and know: The client wants JSON (application/json) back, so I need to convert my `List<Transaction>` to JSON. (Quick note: there are other ways to do [content negotiation](https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-config-content-negotiation), but the Accept header is the default way.)

Let’s call this *response* content negotiation, because it is about the data format of the HTTP response that you are sending back to your client.

But content negotiation also works for incoming requests. Let’s see how.

### How Request Content Negotiation works: Content-Type Header

When building RESTful APIs, there’s an extremely high chance that you also want your clients to be able to send in JSON, or XML. Let’s pick up the example from the beginning of the chapter again, where you offer a REST endpoint to register new users:

    POST http://localhost:8080/users

    ###
    {"email": "angela@merkel.de"}

How would Spring know that the request body above contains JSON and not XML or YAML?

You might have guessed right, you’ll need to add another header, this time it’s the `Content-Type` header.

    POST ...

    Content-Type: application/json; charset=UTF-8

    ###
    ...

What would the corresponding @RestController method for that request look like?
```java
    package com.marcobehler.springmvcarticle;

    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RestController;

    @RestController
    public class BookingController {

        @PostMapping("/transactions")
        public Transaction transaction(@RequestBody TransactionDto dto) {
            // do something with the dto..create the booking..convert it to a transaction
            Transaction transaction = null;
            return transaction;
        }
    }
```

Let’s break it down.
```java
    public Transaction transaction(@RequestBody TransactionDto dto) {
```
Similar to @RequestParam or @Pathvariable, you’ll need another annotation, called `@RequestBody`.

@RequestBody in combination with the correct `Content-Type` will signal Spring that it needs to have a look at the HTTP request body and convert it to whatever Content-Type the user specified: JSON in our case.
```java
        // do something with the dto..create the booking..convert it to a transaction
        Transaction transaction = null;
        return transaction;
    }
```

Your method then doesn’t have to care about the raw JSON string anymore, it can simply work with the TransactionDTO, save it to the database, convert it to a Transaction object, anything you want.

That is the power of Spring MVC.


### How does Spring convert data formats?

There’s only one small problem: Spring knows about the Accept and Content-Type headers, but it does not know how to convert between Java Objects and JSON. Or XML. Or YAML.

It needs an appropriate 3rd-party library to do the dirty work (also called `marshalling/unmarshalling` or `serialization/deserialization`.)

And the classes that integrate between Spring MVC and these 3rd-party libaries are called `HttpMessageConverters`.

### What is a HttpMessageConverter?

An HttpMessageConverter is an interface with four methods (note, I simplified the interface a bit for an easier explanation, as it looks a bit more advanced in real life).

1.  **canRead(MediaType)** → Can this converter read (JSON|XML|YAML|etc)? The MediaType passed in here is typically the value from the `Content-Type` request header.

2.  **canWrite(MediaType)** → Can this converter write (JSON|XML|YAML|etc)? The MediaType passed in here is typically the value from the `Accept` request header.

3.  **read(Object, InputStream, MediaType)** → Read my Java object from the (JSON|XML|YAML|etc.) InputStream

4.  **write(Object, OutputStream, MediaType)** → Write my Java object to the OutputStream as (JSON|XML|YAML|etc.)

In short, a MessageConverter needs to know what MediaTypes it supports (think: application/json) and then needs to implement two methods to do the actual reading/writing in that data format.

### Which HttpMessageConverters are there?

Luckily, you don’t need to write these message converters yourself. Spring MVC comes with a class that automatically registers a couple of default HTTPMessageConverters for you - if you have the appropriate 3rd-party libraries on the classpath.

If you don’t know about this, it’ll sound like magic. In any case, have a look at Spring’s `AllEncompassingFormHttpMessageConverter` (I love the name).
```java
    static {
        ClassLoader classLoader = AllEncompassingFormHttpMessageConverter.class.getClassLoader();
        jaxb2Present = ClassUtils.isPresent("javax.xml.bind.Binder", classLoader);
        jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader) &&
                        ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader);
        jackson2XmlPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.xml.XmlMapper", classLoader);
        jackson2SmilePresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.smile.SmileFactory", classLoader);
        gsonPresent = ClassUtils.isPresent("com.google.gson.Gson", classLoader);
        jsonbPresent = ClassUtils.isPresent("javax.json.bind.Jsonb", classLoader);
    }
```

Let’s break this down.
```java
    jaxb2Present = ClassUtils.isPresent("javax.xml.bind.Binder", classLoader);
```
Spring MVC checks if the class `javax.xml.bind.Binder` is present and if so, assumes you have added a needed library to your project to do [JAXB conversions](https://javaee.github.io/jaxb-v2/).
```java
    jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader) &&
                    ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader);
```
Spring MVC checks if two classes `..jackson..ObjectMapper` and `..jackson..JsonGenerator` are present and if so assumes that you have added [Jackson](https://github.com/FasterXML/jackson) to your project in order to do the JSON conversions.
```java
    jackson2XmlPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.xml.XmlMapper", classLoader);
```
Spring MVC checks if the class `..jackson..XmlMapper` is present and if so assumes that you have added [Jackson’s XML support](https://github.com/FasterXML/jackson) to your project in order to do the XML conversions.

And so on. And a couple of lines later, Spring simply adds an HttpMessageConverter for each library it 'detected'.
```java
    if (jaxb2Present && !jackson2XmlPresent) {
        addPartConverter(new Jaxb2RootElementHttpMessageConverter());
    }

    if (jackson2Present) {
        addPartConverter(new MappingJackson2HttpMessageConverter());
    }
    else if (gsonPresent) {
        addPartConverter(new GsonHttpMessageConverter());
    }
```
### Side-Note: Spring MVC, Spring Boot & RestControllers

When building Spring Boot projects, you’ll automatically use Spring MVC under the hood. But Spring Boot also pulls in Jackson by default.

*That* is the reason why you can immediately write JSON endpoints with Spring Boot, because the correct HttpMessageConverts will be added automatically for you.

### Summary: @RestControllers

Compared with the HTML flow, the JSON/XML flow is a bit simpler, as you bypass all that Model and View rendering.

Instead, your @Controllers directly return Java objects, which Spring MVC will conveniently serialize to JSON/XML or any other format that the user requested with the help of HttpMessageConverters.

You need to make sure of two things, however:

1.  Have the appropriate 3rd party libraries on the classpath.

2.  Make sure to send in the correct `Accept` or `Content-Type` headers with every request.

## FAQ

### Did you publish the source code for this article somewhere?

You can find the working source code for most of this article in the following GitHub repository:
<https://github.com/marcobehler/spring-mvc-article>

Simply clone the project and run the `SpringMvcArticleApplication` class to start up the web application.

### What is the difference between Spring MVC and Spring Boot?

In short: There is no *difference*, Spring Boot uses and builds *on top* of Spring MVC.

For a more thorough explanation, you’ll need to read my [What is Spring Framework?](https://www.marcobehler.com/guides/spring-framework) article first.

### What is the fastest way to create a new Spring MVC application?

Unless you want to use Spring MVC without it (quite rare, nowadays), the quickest way will be to create a new Spring Boot project.

1.  Go to <https://start.spring.io/>.

2.  Make sure to select `Spring Web` as a dependency for your new project.

This will let you build web/RESTful applications with Spring MVC.

### What kind of HTTP request input does Spring MVC understand?

Spring MVC understands basically everything that HTTP offers - with the help of third-party libraries.

That means you can throw JSON, XML, or HTTP (Multipart) Fileuploads request bodies at it, and Spring will conveniently convert that input to Java objects.

### What kind of HTTP responses can Spring MVC write?

Spring MVC can write anything that you want into an HttpServletResponse - with the help of 3rd-party libraries.

Be that HTML, JSON, XML or even WebSocket response bodies. Even better, it takes your Java objects and generates those response bodies for you.

### What is the difference between a @Controller and @RestController

1.  `@Controllers`, by default, return HTML to your users with the help of a templating library, unless you add the @ResponseBody annotation to specific methods, which let you return XML/JSON as well.

2.  `@RestController’s` source code shows that it actually *is* a @Controller, with the added @ResponseBody annotation. Which is equivalent to writing @Controllers which have @ResponseBody annotated on *every single method*.
```java
        @Controller
        @ResponseBody
        public @interface RestController {
```
3.  Therefore, @RestControllers, by default, return XML/JSON, instead of HTML.

> **Note**
>
> XML and JSON are simply the most popular data formats you’ll use in a Spring MVC application. Your @Controllers/@RestControllers could, however, return anything else, like YAML for example. You’ll only need to make sure to have the right `HttpMessageConverter` registered in your ApplicationContext.

### Which templating library should I choose?

Over the years I have personally worked with almost all templating libraries and while there is a certain push to use Thymeleaf in Spring projects, I have no strong preference. So, either go with [Thymeleaf](https://www.thymeleaf.org/) (if you don’t have experience with any other framework) or choose the one you are most comfortable with.

### Why does my @Controller output 404? All mappings are correct.

A relatively common mistake is to have a `@Controller` returning objects that you want to get converted to JSON or XML, but you are missing the @ResponseBody annotation.

Spring will return a rather meaningless `404 Not Found` exception in that case.
```java
    package com.marcobehler.springmvcarticle;

    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.ResponseBody;

    @Controller
    public class _404WithMissingResponseBodyController {

        @GetMapping("/users/{id}")   /* This won't work and lead to a 404 */
        public User getUser_404(@PathVariable String id) {
            return new User("Everyone's name is John", id);
        }

        @GetMapping("/users2/{id}")
        @ResponseBody  /* This will work */
        public User getUser_200(@PathVariable String id) {
            return new User("Everyone's name is John", id);
        }
    }
```
**Fix**: Add `@ResponseBody` or turn your `@Controller` into a `@RestController`.

### What happens if you define the same request mapping for two different methods?

If the two methods have different HTTP methods, it won’t be a problem.
```java
    /* this works */

    @PostMapping("/users")
    public void method1() {

    }

    @GetMapping("/users")
    publi void method(2) {

    }
```

If, however, you map the same HTTP methods to the same path, you will get a problem.
```java
    /* this won't work */

    @PostMapping("/users")
    public void method1() {

    }

    @PostMapping("/users")
    public void method(2) {

    }
```

On application startup, this will lead to an `IllegalStateException`, hinting to your ambiguous mapping.
```console
    Caused by: java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'howToPassAndRetrieveRequestParametersController' method
    com.marcobehler.springmvcarticle.HowToPassAndRetrieveRequestParametersController#createUser(User)
    to {POST /users3}: There is already 'howToPassAndRetrieveRequestParametersController' bean method
```

### Do I need to URL encode @RequestParams?

Yes, because Spring *automatically* URL decodes them. A common error:

Imagine your application sends out confirmation emails whenever a new user signs up and a user signs up with a "+" sign in his email address, like <marco+wantsnospam@marcobehler.com>.

```java
    @GetMapping("/confirm")
    public void confirm(@RequestParam String email, @RequestParam String token){
        // confirm user...
    }
```

If you forgot to properly URL encode the + sign in your confirmation mail and send the string as is to your @Controller, which value will the email @RequestParam contain?

It will be "marco\[space\]<wantsnospam@marcobehler.com>", as Spring will replace the + with a space, which is proper [RFC3986](https://tools.ietf.org/html/rfc3986) handling.

**Fix**: Make sure that the URLs you feed to your application are properly encoded: <marco%2Bwantsnospam@marcobehler.com>, as Spring will decode them automatically.

### How to access the user’s current HttpSession?

In your Spring MVC @Controller or @RestController, you can simply specify the HttpSession as a method argument, and Spring will *automatically* inject it (creating one if it doesn’t yet exist)

```java
    @RestController
    public class HttpSessionController {

        @GetMapping("/session")
        public String getSession(HttpSession httpSession) {
            System.out.println("httpSession = " + httpSession);
            return httpSession.getId();
        }
    }
```

You cannot do that with random @Components or @Services, but you are still able to @Autowire the HttpSession into them.

```java
    @Service
    class SomeOtherService {

        @Autowired
        private HttpSession httpSession;

        public HttpSession getHttpSession() {
            return httpSession;
        }
    }
```

### How to access the HttpServletRequest?

In your Spring MVC @Controller or @RestController, you can simply specify the HttpServletRequest as a method argument and Spring will *automatically* inject it (creating one if it doesn’t yet exist)
```java
    @RestController
    public class HttpServletRequestController {

        @Autowired
        private SomeRequestService someRequestService;

        @GetMapping("/request")
        public String getRequest(HttpServletRequest request) {
            System.out.println("request = " + request);
            return request.toString();
        }
    }
```

You cannot do that with random @Components or @Services, but you are still able to @Autowire the HttpServletRequest into them.
```java
    @Service
    class SomeRequestService {

        @Autowired
        private HttpServletRequest httpServletRequest;

        public HttpServletRequest getRequest() {
            return httpServletRequest;
        }
    }
```

### How to read HTTP Headers?

There’s a variety of ways to access the request headers, depending on whether you want just a single one or a map with all of them. In either case you need to annotate them with @RequestHeader.

Whatever version you pick, try to be consistent with your choice.
```java
    package com.marcobehler.springmvcarticle;

    import org.springframework.http.HttpHeaders;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestHeader;

    import java.util.Map;

    @Controller
    public class HttpHeaderController {

        @GetMapping("/headers1")
        public void singleHeader(@RequestHeader("x-forwarded-for") String xForwardedFor) {
           // ...
        }

        @GetMapping("/headers2")
        public void headersAsMap(@RequestHeader Map<String,String> headers) {  // or MultiValueMap<String,String>
            // ...
        }

        @GetMapping("/headers3")
        public void headersAsObject(HttpHeaders headers) {
            // ...
        }


    }
```
### How to read and write cookies?

For reading cookies you can use the `@CookieValue` annotation in your controllers. You’ll have to write cookies directly to the HttpServletResponse.
```java
    package com.marcobehler.springmvcarticle;

    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.CookieValue;
    import org.springframework.web.bind.annotation.GetMapping;

    import javax.servlet.http.Cookie;
    import javax.servlet.http.HttpServletResponse;

    @Controller
    public class CookieController {

        @GetMapping("/cookie")
        public void handle(@CookieValue("JSESSIONID") String cookie, HttpServletResponse response) {

            response.addCookie(new Cookie("SOME_COOKIE_NAME", "This is a crazy new cookie!"));
            //...
        }
    }
```

### How to get the user’s IP address?

This is a trick question. There is a method, called `httpServletRequest.getRemoteAddr()`, which, however, only returns you the IP of the user `or` the last proxy that sent the request, which 99,99% of the case is your Nginx or Apache.

Hence, you’ll need to parse the `X-Forwarded-For` header for the correct IP address. But what happens if your application, in addition, runs behind a CDN, like CloudFront? Then your X-Forwarded-For would look like this:

`X-Forwarded-For: maybeSomeSpoofedIp, realIp, cloudFrontIp`

The problem is, you cannot read the header from left to right, as users could provide and therefore spoof their own X-Forwarded-For header. You always have to go from `right` to left, and `exclude` all known IP addresses. In the case of CloudFront, this means you’ll need to know the CloudFront IP ranges and remove them from the header. Yup!

This leads to quite elaborate IP-resolving code. Guess how many projects get that wrong!
```java
    package com.marcobehler.springmvcarticle;

    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;

    import javax.servlet.http.HttpServletRequest;

    @RestController
    public class IpController {

        private static final String[] HEADERS_TO_TRY = {
                "X-Forwarded-For",
                "Proxy-Client-IP",
                "WL-Proxy-Client-IP",
                "HTTP_X_FORWARDED_FOR",
                "HTTP_X_FORWARDED",
                "HTTP_X_CLUSTER_CLIENT_IP",
                "HTTP_CLIENT_IP",
                "HTTP_FORWARDED_FOR",
                "HTTP_FORWARDED",
                "HTTP_VIA",
                "REMOTE_ADDR"};


        @GetMapping("/ip")
        public String getClientIpAddress(HttpServletRequest request) {
            for (String header : HEADERS_TO_TRY) {
                String ip = request.getHeader(header);
                if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
                    return getRealClientIpAddress(ip);
                }
            }
            return request.getRemoteAddr();
        }

        /**
         * Goes through the supplied ip string (could be one or multiple). Traverses it through the right side...
         * and removes any known ip address ranges
         *
         * @param ipString
         * @return
         */
        public String getRealClientIpAddress(String ipString) {
            String[] manyPossibleIps = ipString.split(",");

            for (int i = manyPossibleIps.length - 1; i >= 0; i--) {
                String rightMostIp = manyPossibleIps[i].trim();
                if (isKnownAddress(rightMostIp)) {
                    continue; // skip this ip as it is trusted
                } else {
                    return rightMostIp;
                }
            }

            return ipString;
        }

        private boolean isKnownAddress(String rightMostIp) {
            // do your check here..for cloudfront you'd need to download their ip address ranges
            // from e.g. http://d7uri8nf7uskq.cloudfront.net/tools/list-cloudfront-ips
            // and compare the current ip against them
            return false;
        }

    }
```
### How can you handle file uploads in a Spring MVC application?

Given that you have the proper HTML file upload form, which reads something like this:
```html
    <form method="POST" enctype="multipart/form-data" action="/upload">
        File to upload:<input type="file" name="file" />
        <input type="submit" value="Upload" />
    </form>
```

You simply need a @Controller with a corresponding @PostMapping and a MultiPartFile parameter, which contains your upload data and convenient methods to store the file on your disk.
```java
    package com.marcobehler.springmvcarticle;

    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.multipart.MultipartFile;


    import java.io.IOException;
    import java.nio.file.Path;
    import java.nio.file.Paths;

    @Controller
    public class FileUploadController {

        @PostMapping("/upload")
        public String handleFileUpload(@RequestParam MultipartFile file) throws IOException {
            // don't generate upload files like this in a real project.
            // give them random names and save their uploaded name as metadata in a database or similar
            final Path uploadDestination = Paths.get("C:\\uploads").resolve(file.getName());

            file.transferTo(uploadDestination);
            return "redirect:/";
        }

    }
```

### How to handle byte (xls, pdf, csv, jpg, zip file) downloads with Spring Controllers?

There’s a variety of ways to get this working, from writing directly to the HttpServletResponse or returning a byte\[\] as a result.

However, the most Spring-y and flexible version is by returning \`*ResponseEntity&lt;Resource&gt;*\`s. Depending on where you stored the file, you would use a different resource.

-   On a disk → FileSystemResource

-   On your project’s classpath → ClassPathResource

-   Stream it from "somewhere" → InputStreamResource

-   Have it available as byte\[\] in memory → ByteArrayResource

All that’s left to do then, is set the appropriate response HTTP headers (filename, content-type, etc).
```java
    package com.marcobehler.springmvcarticle;

    import org.springframework.core.io.ClassPathResource;
    import org.springframework.core.io.Resource;
    import org.springframework.http.HttpHeaders;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.MediaType;
    import org.springframework.http.ResponseEntity;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.server.ResponseStatusException;

    import java.io.IOException;

    @Controller
    public class FileDownloadController {

        @RequestMapping(value = "/download/{jpgName}", method = RequestMethod.GET)
        public ResponseEntity<Resource> downloadJpg(
                @PathVariable String jpgName) throws IOException {

            //  Resource downloadResource = new InputStreamResource(soimeinputStream)
            //  Resource downloadResource = new ByteArrayResource(someByteArray)
            //  Resource downloadResource = new FileSystemResource(someFile)
            final ClassPathResource downloadResource = new ClassPathResource(jpgName);

            if (!downloadResource.exists()) {
                throw new ResponseStatusException(HttpStatus.BAD_REQUEST);
            }

            HttpHeaders headers = new HttpHeaders();

            // 1. set the correct content type
            headers.setContentType(MediaType.IMAGE_JPEG);

            // 2. set the correct content length, maybe stored in a db table
            headers.setContentLength(downloadResource.contentLength());

            // 3. if you want to force downloads, otherwise attachments might be displayed directly in the brwoser
            headers.setContentDispositionFormData("attachment", jpgName);

            return new ResponseEntity<>(downloadResource, headers, HttpStatus.OK);
        }
    }
```

### How can I handle exceptions from my @Controllers globally?

There’s literally a gazillion ways of handling exceptions with Spring MVC, if you don’t want to handle them directly in your @Controller methods, but rather in one central place.

Create a `@ControllerAdvice` or `@RestControllerAdvice` class, in combination with the @ResponseStatus and @ExceptionHandler annotations. A couple of notes:

1.  You might guess the difference between these two by understanding the difference between @Controllers and @RestControllers.

2.  @ResponseStatus lets you define the HTTP Status code that should be returned to the client after handling your exception.

3.  @ExceptionHandler specifies the exception that should trigger your handler method.

4.  Other than that, it’s like writing a normal @Controller or @RestController.

```java

    package com.marcobehler.springmvcarticle;


    import org.springframework.http.HttpStatus;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.ResponseStatus;

    @ControllerAdvice
    public class GlobalControllerExceptionHandler {

        @ResponseStatus(HttpStatus.CONFLICT)  // 409
        @ExceptionHandler(SomeConflictException.class)
        public String handleConflict(SomeConflictException e, Model model) {
            // do something
            model.addAttribute("message", e.getMessage());
            return "new-template";
        }

        @ResponseStatus(HttpStatus.NOT_IMPLEMENTED)  // 409
        @ExceptionHandler(NotYetImplementedExceptoin.class)
        public void handleBandwithLimitExceeded(NotYetImplementedExceptoin e) {
            // do nothing;
        }
    }
```


### How to return any status code (400, 404, etc) from your @Controllers?

Throw a `ResponseStatusException`, with the appropriate status code and possibly a reason.

An alternative would be returning a ResponseEntity object, but the exception is nicer in most cases.
```java
    package com.marcobehler.springmvcarticle;

    import org.springframework.http.HttpStatus;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.server.ResponseStatusException;

    @Controller
    public class HttpStatusCodeController {

        @GetMapping("/somePath")
        public void alwaysThrowsException() {
             //throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Meeepp, not found.");

            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Well, that just wasn't right!");
        }
    }
```

### What about concept XYZ of Spring MVC?

The official Spring MVC’s documentation literally contains hundreds of pages describing how the web framework works.

So, in case you want to know more about Models, Views, ViewHandlers, InitBinders, RootContexts, Filters, Caching, etc., I invite you to check it out. It is simply not in the scope of this guide to cover everything.

## Fin

That was quite a ride. In the end, I hope that you have taken a couple of things away from this article:

-   Spring MVC is a good old MVC framework that lets you, rather easily, write HTML web sites or JSON/XML web services.

-   It integrates nicely with a lot of templating libraries and data conversion libraries, as well as with the rest of the Spring ecosystem, like Spring Boot.

-   It mainly allows you to focus on writing your business logic, without having to worry too much about servlet plumbing code, HTTP request/response parsing, and data conversion.

That’s it for today. Thanks for reading.

## Acknowledgments

A big "thank you" goes out to [Patricio "Pato" Moschcovich](https://www.linkedin.com/in/patomos/), who not only did the proofreading for this article but also provided invaluable feedback!