рд╕реНрдкреНрд░рд┐рдВрдЧ рдПрдорд╡реАрд╕реА: рд╡реЗрдмрд╕рд╛рдЗрдЯ рдбрд┐рдЬрд╛рдЗрди рдФрд░ рд░реЗрд╕реНрдЯрдлреБрд▓ рд╕рд░реНрд╡рд┐рд╕реЗрдЬ

рд╡реЗрдмрд╕рд╛рдЗрдЯ рдпрд╛ Restful рд╕реЗрд╡рд╛рдУрдВ рдХреЛ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рд╕реНрдкреНрд░рд┐рдВрдЧ MVC рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рддрд░реАрдХреЗ рдХреЛ рд╕рдордЭрдиреЗ рдХреЗ рд▓рд┐рдП рдЖрдк рдЗрд╕ рд▓реЗрдЦ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдФрд░ рд╕реНрдкреНрд░рд┐рдВрдЧ рдПрдорд╡реАрд╕реА рдХреЗ рд╕рдмрд╕реЗ рд╕рд╛рдорд╛рдиреНрдп рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рдХрд╡рд░ рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рдЕрдХреНрд╕рд░ рдкреВрдЫреЗ рдЬрд╛рдиреЗ рд╡рд╛рд▓реЗ рдкреНрд░рд╢реНрдиреЛрдВ рдХрд╛ рдЕрд╡рд▓реЛрдХрди рднреА рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВред


рдиреЛрдЯ: ~ words,релрежреж рд╢рдмреНрджреЛрдВ рдХрд╛ рдПрдХ рд▓реЗрдЦ рд╢рд╛рдпрдж рдореЛрдмрд╛рдЗрд▓ рдбрд┐рд╡рд╛рдЗрд╕ рдкрд░ рдкрдврд╝рдиреЗ рд▓рд╛рдпрдХ рдирд╣реАрдВ рд╣реИред рдЗрд╕реЗ рдмреБрдХрдорд╛рд░реНрдХ рдХрд░реЗрдВ рдФрд░ рдмрд╛рдж рдореЗрдВ рд╡рд╛рдкрд╕ рдЖрдПрдВред


рд╕рд╛рдордЧреНрд░реА



рдкрд░рд┐рдЪрдп


рд╕реНрдкреНрд░рд┐рдВрдЧ рдПрдорд╡реАрд╕реА рдХреНрдпрд╛ рд╣реИ?


Spring MVC тАФ - Spring. - RESTful (, JSON/XML) Spring, , REST Spring Boot .


, ?


, : .


( , Spring Spring Boot, , Spring Framework?)


HttpServlets 101


- Java Spring (MVC/Boot) , :


  1. HTML тЖТ - HTML-, .
  2. JSON/XML тЖТ - RESTful, JSON XML. Javascript - , .
  3. , , .

- ? Java?


- Java HttpServlets. HTML, JSON XML. , 1 - Java (Spring MVC, Wicket, Struts) HttpServlets.


( : HttpServlets, .)


HTML- HttpServlets


HttpServlet, HTML-.


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");
        }
    }
}

.


public class MyServletV1 extends HttpServlet {

Java HttpServlet.


@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {

() GET, doGet () . POST doPost (). HTTP .


if (req.getRequestURI().equals("/")) {

, URL- , . ┬л/┬╗, www.marcobehler.com, www.marcobehler.com/hello.


resp.setContentType("text/html");

ServletResponse, , . HTML.


resp.getWriter().print("<html><head></head><body><h1>Welcome!</h1><p>This is a very cool page!</p></body></html>");

: - тАФ HTML! HTML- ServletResponse. response writer.


, Tomcat Jetty. , , , :


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();
    }
}

.


Tomcat tomcat = new Tomcat();
tomcat.setPort(8080);
tomcat.getConnector();

Tomcat, 8080.


        Context ctx = tomcat.addContext("", null);
        Wrapper servlet = Tomcat.addServlet(ctx, "myServlet", new MyServletV2());

Tomcat. , Tomcat .


        servlet.addMapping("/*");

Tomcat, , . /* , (/users, /register, /checkout).


        tomcat.start();

. main(), 8080 - (http://localhost:8080 /), HTML.


, , doGet () doPost (), - . .


JSON HttpServlets


, ( ) HTML- REST API . React AngularJS URL- :


/api/users/{userId}

JSON userId. MyServlet , , - ?


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");
        }
    }
}

.


        } else if (req.getRequestURI().startsWith("/api/users/")) {

if doGet /api/users/.


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

URL. URL тАФ userID, , 5 /api/users/5. , int, !


resp.setContentType("application/json");

JSON .


// User user = dao.findUser(prettyFragileUserId)
// actually: jsonLibrary.toString(user)
resp.getWriter().print("{\n" +
        "  \"id\":" + prettyFragileUserId + ",\n" +
        "  \"age\": 55,\n" +
        "  \"name\" : \"John Doe\"\n" +
        "}");

, JSON тАФ , HTTPServletResponse. , JSON Java- , .


┬л ┬╗


, :


  1. HTTP- , URI , .. : .
  2. , . : , . , .
  3. JSON HTML .

, ? , ? URI , JSON, ?


Spring MVC.


DispatcherServlet


Spring MVC , Model-View-Controller. .


, Spring MVC тАФ , -?


DispatcherServlet.


( , , , )


Spring MVC DispatcherServlet?


, - Java , Spring MVC , HTTP- ( DispatcherServlet -).


HTTP-, ? ┬л ┬╗, HTML .


DispatcherServlet :


  1. URI HTTP . : POST /register?name=john&age33.
  2. (/ ) Java REST ,, .
  3. , .. , , , , .
  4. HTML/JSON/XML.

, , DispatcherServlet .



. ModelAndView ? DispatcherServlet ?


Let's-write-HTML? .


тАФ HTML


, HTML , Spring MVC ( Spring Boot), . .


Spring


(POST/register?name=john&age33) .


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";
    }
}

.


@Controller
public class RegistrationController {

Spring Controller, .


@PostMapping("/register")

DispatcherServlet, , POST /register, (, ?Username=), .


    public String registerUser(@RequestParam(required = false) Integer age, @RequestParam String name, Model model) {

, .
, , URL (?age=10&name=Joe), POST. , name ( age )


age, , Integer ( , Integer)


, , Spring MVC model . , , HTML-, .


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);

┬лuser┬╗. , HTML- , , ┬л${user.name}┬╗. .


return "registration-success";

registration-success. , , .. HTML, , Spring .


Views ()


, (, , ) Spring MVC , .. , , registration-success.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>

HTML-, . , .


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

, th:text=? Spring? - ?


: Spring MVC HTML. HTML- , , .


Thymeleaf, Spring MVC.


Spring MVC


, Spring MVC, : Thymeleaf, Velocity, Freemarker, Mustache JSP ( ).


, , , , HTML- тАФ , .


, , , . , ?


ViewResolver?


, Spring HTML-, .


, , ViewResolver. , , Spring ViewResolvers , . ViewResolvers, .


, Thymeleaf. , ThymeleafViewResolver.


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;
    }
}

.


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

, ThymeleafViewResolver Spring ViewResolver. (: registration-success), ViewResolvers .


        SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();

ThymeleafViewResolver Thymeleaf . SpringResourceTemplateResolver. .


SpringResourceTemplateResolver Thymeleaf


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

, ( Spring Resources): ┬л classpath, /templates┬╗. .html. :


, String, registration-success, ThymeleafViewResolver : classpath:/templates/registration-success.html.


: Spring Boot


: , ViewResolver, Spring Boot. . Spring Boot , , spring-boot-starter-thymeleaf.


ViewResolver , src/main/resources/template.


, Spring Boot Spring MVC . .


: Model-View-Controller


Controller & ViewResolver, Spring Model-View-Controller.


  • (Controller, @PostMapping, @RequestParam) , .
  • ( ), . , .
  • тАФ HTML. , (). HTTP-. HTTP- .

.


, , Spring , HTTP, - .



, Spring MVC HTTP.


  • requestURI, .
  • , , .

, HTTP-.


@GetMapping @RequestMappping


@GetMapping . *@RequestMapping*. :


@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 @RequestMapping(method=XXX). (Spring 4.3+) () URL, , @RequestMapping , Spring.


@RequestParam


HTTP-, URL (?Key=value) , @RequestParam.


, (, HTTP String int), .


@PostMapping("/users")   /* First Param is optional */
public User createUser(@RequestParam(required = false) Integer age, @RequestParam String name) {
   // does not matter
}

, 400 Bad Request , Spring Boot, , :


{"timestamp":"2020-04-26T08:34:34.441+0000","status":400,"error":"Bad Request","message":"Required Integer parameter 'age' is not present","path":"/users"}

, Spring @RequestParams - . " ".


, getter/setter.


@PostMapping("/users")   /* Spring   ,     getters and setters */
public User createUser(UserDto userDto) {
    //
}

@PathVariable


, URI , @PathVariable. , userId=123, URL: GET / users/123


  1. , {} .

, PathVariables .


@GetMapping("/users/{userId}")
   public User getUser(@PathVariable(required = false) String userId) {
       // ...
       return user;
   }

PathVariables, , Java- ( , getter/setter).


@GetMapping("/users/{userId}")
public User getUser(UserDto userDto) {
    // ...
    return user;
}

:


, HTML- Spring MVC :


  1. , "" . Spring , ( , ) .
  2. , . .
  3. , HTML , .
  4. , , Spring , HTML- .
  5. , , , Spring Boot , .

.


REST тАФ XML/JSON


RESTFul , -. , -, () JSON XML. , , JSON, , JSON.


, JSON HTTP-.


POST http://localhost:8080/users

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

Java ( Spring MVC) JSON . , , . Java, Spring JSON.


public class UserDto {
    private String email;
    //...
}

, , HTML . RESTful , HTML , JSON.


HTTP тЖТ Java Java тЖТ HTTP .


, , Spring MVC REST .


REST


, XML/JSON, @RestController Controller. ( @RestController Controller, . FAQ ).


REST- , , :


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;
    }
}

.


@RestController
public class BankController {

BankController @RestController, Spring, HTML- ModelAndView. XML/JSON ( - ) HTTP.


public List<Transaction> transactions(String userId) {

String (). List, Spring JSON XML. , , Java Transaction (- - ):

[
  {
    "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
  }
]

Spring MVC , JSON? XML? YAML? REST , ?


Spring .


тАФ Accept Header


, , , REST .


? Accept HTTP-.


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

Spring MVC Accept : JSON (application/json), List JSON. ( . , Accept .)

, HTTP, .


. .


тАФ Content-Type Header ( )


RESTful API , JSON XML. , REST :


POST http://localhost:8080/users

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

Spring , JSON, XML YAML? , , , Content-Type.


POST ...

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

###
...

REST ?


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;
    }
}

.


    public Transaction transaction(@RequestBody TransactionDto dto) {

@RequestParam @Pathvariable, , @RequestBody.


@RequestBody Content-Type Spring , HTTP- Content-Type, : JSON .


    // do something with the dto..create the booking..convert it to a transaction
    Transaction transaction = null;
    return transaction;
}

JSON, TransactionDTO, , Transaction, . Spring MVC.


Spring


: Spring Accept Content-Type, , Java JSON. XML. .


( / / .)


, Spring MVC , HttpMessageConverters.


HttpMessageConverter?


HttpMessageConverter тАФ ( , , ).


  1. canRead (MediaType) тЖТ (JSON | XML | YAML | . .)? MediaType Content-Type.
  2. canWrite (MediaType) тЖТ (JSON | XML | YAML | . .)? MediaType, , Accept.
  3. read(Object, InputStream, MediaType) тЖТ Java- (JSON | XML | YAML | . .) InputStream
  4. write(Object, OutputStream, MediaType) тЖТ Java- OutputStream (JSON | XML | YAML | . .)

, MessageConverter , MediaTypes (, application/json), / .


HttpMessageConverters?


, . Spring MVC , HTTPMessageConverters тАФ .


, . , Spring AllEncompassingFormHttpMessageConverter ( ).


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);
}

.


jaxb2Present = ClassUtils.isPresent("javax.xml.bind.Binder", classLoader);

Spring MVC javax.xml.bind.Binder , , , JAXB.


jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader) &&
ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader);

Spring MVC ..jackson..ObjectMapper ..jackson..JsonGenerator , , , Jackson JSON.


jackson2XmlPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.xml.XmlMapper", classLoader);

Spring MVC ..jackson..XmlMapper , , , XML Jackson s XML.


. Spring HttpMessageConverter , ┬л┬╗.


if (jaxb2Present && !jackson2XmlPresent) {
        addPartConverter(new Jaxb2RootElementHttpMessageConverter());
}

if (jackson2Present) {
        addPartConverter(new MappingJackson2HttpMessageConverter());
}
else if (gsonPresent) {
        addPartConverter(new GsonHttpMessageConverter());
}

: Spring Boot


Spring Boot Spring MVC . Spring Boot Jackson .


JSON Spring Boot, HttpMessageConverts .


: REST


HTML JSON / XML , Model View.


Java, Spring MVC JSON / XML , HttpMessageConverters.


, :


  1. .
  2. Accept Content-Type .


- ?


GitHub:
https://github.com/marcobehler/spring-mvc-article


SpringMvcArticleApplication, -.


Spring MVC Spring Boot?


: , Spring Boot Spring MVC.


Spring Framework?.


Spring MVC?


Spring MVC, Spring Boot .


  1. : https://start.spring.io/.
  2. Spring Web .

/ RESTful- Spring MVC.


HTTP- Spring MVC?


Spring MVC , HTTP тАФ .


, JSON, XML HTTP (Multipart) Fileuploads, Spring Java.


HTTP- Spring MVC?


Spring MVC HttpServletResponse тАФ .


HTML, JSON, XML WebSocket. , Java .


REST


  1. HTML , @ResponseBody , XML / JSON.
  2. REST , @ResponseBody. @ResponseBody .

@Controller
@ResponseBody
public @interface RestController {

  1. REST XML / JSON HTML.

. XML JSON тАФ , Spring MVC. / REST - , , YAML. , HttpMessageConverter ApplicationContext.


?


, , Thymeleaf Spring, . , Thymeleaf ( ), , .


404? .


, , JSON XML, @ResponseBody.


Spring 404 Not Found .


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);
    }
}

: @ResponseBody REST .


, ?


HTTP , .


/*   */

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

}

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

}

HTTP , .


/*    */

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

}

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

}

IllegalStateException, .


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

URL @RequestParams?


, Spring URL. :


, , , ┬л+┬╗ , , marco+wantsnospam@marcobehler.com.


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

тАШ+тАЩ URL - , @RequestParam?


┬лmarco[space]wantnospam@marcobehler.com┬╗, Spring + , RFC3986.


: , URL-, , : marco%2Bwantsnospam@marcobehler.com, Spring .


HttpSession ?


Spring MVC REST HttpSession , Spring ( , ).


@RestController
public class HttpSessionController {

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

, HttpSession .


@Service
class SomeOtherService {

    @Autowired
    private HttpSession httpSession;

    public HttpSession getHttpSession() {
        return httpSession;
    }
}

HttpServletRequest?


Spring MVC REST HttpServletRequest , Spring (, )


@RestController
public class HttpServletRequestController {

    @Autowired
    private SomeRequestService someRequestService;

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

, HttpServletRequest .


@Service
class SomeRequestService {

    @Autowired
    private HttpServletRequest httpServletRequest;

    public HttpServletRequest getRequest() {
        return httpServletRequest;
    }
}

HTTP ?


, , . @RequestHeader.


, .


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) {
        // ...
    }
}


cookie @CookieValue . cookie HttpServletResponse.


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!"));
        //...
    }
}

IP- ?


. httpServletRequest.getRemoteAddr(), , , IP- -, , 99,99% Nginx Apache.


, X-Forwarded-For IP-. , , , CDN, CloudFront? X-Forwarded-For :


X-Forwarded-For: MaybeSomeSpoofedIp, realIp, cloudFrontIp

, , , , X-Forwarded-For. IP-. CloudFront , IP- CloudFront . !


, IP. , !


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;
    }
}

Spring MVC?


, HTML-, :


<form method="POST" enctype="multipart/form-data" action="/upload">
    File to upload:<input type="file" name="file" />
    <input type="submit" value="Upload" />
</form>

@PostMapping MultiPartFile, .


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:/";
    }
}

(xls, pdf, csv, jpg, zip) Spring ?


, HttpServletResponse byte[] .


, Spring- 'ResponseEntity '. , , .

  • тЖТ FileSystemResource
  • тЖТ ClassPathResource
  • ┬л-┬╗ тЖТ InputStreamResource
  • byte[] тЖТ ByteArrayResource

, , HTTP- ( , ..).


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);
    }
}

?


Spring MVC , , .


ControllerAdvice RestControllerAdvice @ResponseStatus @ExceptionHandler. :


  1. , REST .
  2. @ResponseStatus HTTP, .
  3. @ExceptionHandler , -.
  4. , REST .

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;
    }
}

(400, 404 ..) ?


ResponseStatusException , , .


ResponseEntity, .


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!");
    }
}

XYZ Spring MVC?


Spring MVC , , -.


, , , ViewHandlers, InitBinders, RootContexts, , .., Spring MVC. , .



. , :


  • Spring MVC тАФ MVC-, - HTML JSON/XML -.
  • , Spring, Spring Boot.
  • -, , HTTP- / .

рдЖрдЬ рдХреЗ рд▓рд┐рдП рдЗрддрдирд╛ рд╣реАред рдкрдврд╝рдиреЗ рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рджред


рд╕реНрд╡реАрдХреГрддрд┐рдпрд╛рдБ


рдкреЗрдЯреНрд░рд┐рдХрд┐рдпреЛ "рдкреЗрдЯреЛ" рдореЛрд╕реНрд╕реНрдХреЛрд╡рд┐рдЪ рдХреЗ рд▓рд┐рдП рдмрд╣реБрдд рдзрдиреНрдпрд╡рд╛рдж , рдЬрд┐рдиреНрд╣реЛрдВрдиреЗ рди рдХреЗрд╡рд▓ рдЗрд╕ рд▓реЗрдЦ рдХреЛ рд╕рд╣реА рдХрд┐рдпрд╛, рдмрд▓реНрдХрд┐ рдЕрдореВрд▓реНрдп рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рднреА рджреА!


All Articles