Spring Boot QuickStart (3) - Web & Restful

環境:Spring Boot 1.5.4html

基於 Spring Boot 能夠快速建立一個Web & Restful 應用,在開始應用以前,至少要了解如下用法:web

  • 定義路由,定義 HTTP 方法spring

  • 獲取Header、GET、POST、路徑等參數數組

  • Cookie、Session操做tomcat

  • 應用一個模板引擎,選擇 Thymeleafcookie

  • 獲取表單數據,以及文件上傳數據session

  • 完成一個登錄、登出、註冊流程app

增長如下兩個依賴便可完成構建:框架

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

注意:當前版本默認選擇的 Thymeleaf 是 2.x 版本的,對html 標籤閉合性要求比較高,雖然能夠經過設置 mode,改變解析方式,可是還要引入額外的 nekoHTML,因此很蛋疼。不過能夠切換到 3.x 版本,兼容性未知。spring-boot

<properties>
    <thymeleaf.version>3.0.2.RELEASE</thymeleaf.version>
    <thymeleaf-layout-dialect.version>2.1.1</thymeleaf-layout-dialect.version>
</properties>

註解

一旦添加了 spring-boot-starter-web 依賴 Spring Boot 會判斷這是一個Web 應用,並啓動一個內嵌的Servlet容器(默認是Tomcat)用於處理HTTP請求。

Spring 框架中關於 Web 應用有大量的註解:

@Controller
註解一個 Web 控制器類,框架會將 Servlet 容器裏收到的 HTTP 請求根據路徑分發給對應的 Controller 類進行處理

@RestController
註解一個 Restful 控制器,默認會自動返回 JSON

@RequestMapping
註解一個路由,若是定義在類上,至關於一個路由組,最終路由是類+方法路由,參數有路由規則和 HTTP 方法,同時還有一些簡寫形式如:@GetMapping@PutMapping

@PathVariable
註解路徑參數,如 /user/{id}

@RequestParam
註解請求參數,如 ?user=a 或 post['user'] = a

@RequestBody
註解請求體

@RequestHeader
註解請求header頭

@CookieValue
註解一個Cookie值

@SessionAttribute
註解一個Session值

路由,方法

下面代碼對應了兩個路由:

/ 使用 @ResponseBody 註解,因此返回了文本串
/hello 返回表示模板的字符串,將會使用 resources/templates/hello.html 模板渲染

@Controller
public class IndexController {

    @RequestMapping("/")
    @ResponseBody
    public String index() {
        return "Spring Boot Index";
    }

    @RequestMapping("/hello")
    public String hello(Model model) {
        model.addAttribute("title", "Spring Boot");
        return "hello";
    }
}

這段代碼對應了 /rest/ 路由。注意 @RequestMapping 中空字符串與 "/" 的區別。
使用空,則 /rest 與 /rest/ 均可以訪問,使用 / 則必須經過 /rest 訪問:

@RestController
@RequestMapping("/rest")
public class RestfulController {

    @RequestMapping("")
    public String index() {
        return "Hello Rest";
    }
}

hello.html:

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <title th:text="'Hello, ' + ${title}">title</title>
</head>
<body>
<h1 th:text="'Hello, ' + ${title}">h1</h1>
</body>
</html>

請求參數

單一參數

@RequestParam 能夠用來註解一個請求參數,默認會合並 GET、POST 請求名相同的參數,變成一個數組,因此下面的 text2 會進行數組 -> String 的轉型。

@RequestMapping(value = "/get", method = {RequestMethod.GET, RequestMethod.POST})
@ResponseBody
public String get(@RequestParam("text1") String text1, @RequestParam("text2") String text2) {

   return text1 + "/" + text2;
}

在這裏不使用註解一樣能夠得到數據,那爲何要使用註解呢? 由於 @RequestParam 主要提供了一些額外的功能:
如參數名->變量名的映射,required 檢查等,更嚴謹一些。

@RequestMapping(value = "/getsimple", method = {RequestMethod.GET, RequestMethod.POST})
@ResponseBody
public String getSimple(String text1, String text2) {
   return text1 + "/" + text2;
}

參數列表

除了使用 @RequestParam 註解獲取單個參數意外,還能夠獲取一個參數列表,但這種方式,POST 不會合並 GET 中的同名參數:

@RequestMapping("/getmap")
@ResponseBody
public String getMap(@RequestParam Map<String, Object> gets) {
   return gets.toString();
}

額外參數列表

除了註解獲取數據之外,咱們還能夠經過向 Controller 中的方法,注入 Servlet 相關的類,來獲取一些額外的參數,好比客戶端 IP 地址

@RequestMapping("/request")
@ResponseBody
public String request(HttpServletRequest request) {
   HashMap<String, String> requests = new HashMap<>();

   requests.put("Method", request.getMethod());
   requests.put("QueryString", request.getQueryString());
   requests.put("RequestURI", request.getRequestURI());
   requests.put("getRequestURL", request.getRequestURL().toString());
   requests.put("RemoteAddr", request.getRemoteAddr());

   return requests.toString();
}

Cookie

Cookie 的操做其實和 Spring 沒有太大的關係,不過Spring 提供了一個 @CookieValue 註解用來快速獲取 Cookie 值

經過 HttpServletResponse 設置頁面的 Cookie:

@RequestMapping("/setcookie")
@ResponseBody
public String setCookie(HttpServletResponse response) {
   Cookie cookie1 = new Cookie("cookie1", "value1");
   cookie1.setMaxAge(1800);
   Cookie cookie2 = new Cookie("cookie2", "value2");
   cookie2.setMaxAge(3600);

   response.addCookie(cookie1);
   response.addCookie(cookie2);
   return "cookie set ok";
}

經過 HttpServletRequest 或 @CookieValue 註解獲取 Cookie:

@RequestMapping("/getcookie")
@ResponseBody
public String getCookie(HttpServletRequest request,
       @CookieValue(value = "cookie1", required = false) String cookie1) {

   HashMap<String, String> map = new HashMap<>();
   Cookie[] cookies = request.getCookies();
   if (cookies != null) {
       for (Cookie cookie : cookies) {
           map.put(cookie.getName(), cookie.getValue());
       }
   }

   logger.info(cookie1);

   return map.toString();
}

清空Cookie,就是從新設置cookie的值與過時時間:

@RequestMapping("/delcookie")
@ResponseBody
public String delCookie(HttpServletRequest request, HttpServletResponse response) {
   Cookie[] cookies = request.getCookies();
   if (cookies != null) {
       for (Cookie cookie : cookies) {
           // setValue只是清空了value,cookie還在
           cookie.setValue(null);
           cookie.setMaxAge(0);
           response.addCookie(cookie);
       }
   }

   return "delete ok";
}

Session

Session的相關操做,經過 HttpSession、HttpServletRequest、@SessionAttribute 來完成。

設置 Session:

@RequestMapping("/setsession")
@ResponseBody
public String setSession(HttpSession session) {
   session.setAttribute("session1", "value1");
   session.setAttribute("session2", "value2");
   return "";
}

獲取Session:

@RequestMapping("/getsession")
@ResponseBody
public String getSession(
       HttpServletRequest request,
       HttpSession httpSession,
       @SessionAttribute(value = "session1", required = false) String session1) {
   HttpSession session = request.getSession();
   String session2 = (String)session.getAttribute("session2");
   String http_session1 = (String)httpSession.getAttribute("session1");

   logger.info(http_session1);
   logger.info(session1);
   logger.info(session2);

   HashMap<String, String> sessionMap = new HashMap<>();
   Enumeration<String> sessions = session.getAttributeNames();
   while(sessions.hasMoreElements()) {
       String key = sessions.nextElement();
       sessionMap.put(key, (String)session.getAttribute(key));
   }

   return sessionMap.toString();
}

刪除Session:

@RequestMapping("/delsession")
@ResponseBody
public String delSession(HttpSession httpSession) {
   httpSession.removeAttribute("session1");
   httpSession.removeAttribute("session2");

   return "delete session ok";
}

模板引擎

在模板引擎以前,要了解怎麼向模板中傳遞數據,因而有這三種姿式:

Map,這是一個Java原生類型
ModelMap,這是一個類
Model,這是一個接口,其實現類爲 ExtendedModelMap,繼承了 ModelMap 類

這三個均可以在方法參數中直接注入使用,暫時不知道這三個有什麼區別,用起來差很少。

@RequestMapping("/model")
public String model(Model model, ModelMap modelMap, Map<String, Object> map) {
   model.addAttribute("title1", "model_title");
   modelMap.addAttribute("title2", "modelMap_title");
   map.put("title2", "map_title");

   User user = new User(1, "test");
   model.addAttribute("user", user);

   return "model";
}

除了上面的用法,還可使用 ModelAndView 手動渲染模板,效果是同樣的:

@RequestMapping("/modelandview")
public ModelAndView modelAndView() {
   ModelAndView modelAndView = new ModelAndView();
   modelAndView.setViewName("model");
   modelAndView.addObject("title1", "title1");
   modelAndView.addObject("title2", "title2");

   User user = new User(1, "test");
   modelAndView.addObject("user", user);

   return modelAndView;
}

最後 SpringBoot 默承認以集成好幾種模板引擎,如今主要使用 thymeleaf。

@ModelAttribute 註解

這個註解有點複雜。能夠註解到方法上,也能夠註解到方法參數上

  1. 註解到方法參數

大概意思是經過模型中獲取,這個模型是什麼呢?大概經過一些途徑(可能來自Session?可能來自請求參數?可能來自控制器註解到方法上的 @ModelAttribute)

完成自動填充,而且自動傳遞到模板中,這是 Spring MVC 數據綁定。

下面是兩個例子:

請求經過 /xxx?id=1&name=張三,可以自動進行映射,而且傳到模板中,而且還能自動進行輸出格式轉換,以下面第一個例子,受 @ResponseBody 影響,直接輸出了 JSON

@RequestMapping("/getmodel")
@ResponseBody
public User getModel(@ModelAttribute User user) {
   return user;
}

@RequestMapping("/modelattribute")
public String modelAttribute(@ModelAttribute User user) {
   return "model";
}
  1. 註解到方法

將這個控制器的方法,變成一個非請求處理的方法,在其它請求方法(RequestMapping)被調用前首先調用該方法,並將返回的數據放到 Model 中

有什麼用呢?

估計是用來生成初始化數據的,好比生成一個帶有一些默認數據的表單?在進入控制器以前對數據進行一些整理和清洗?

經常使用配置

自動 trim 參數

大多數 PHP 框架都有自動 trim GET/POST 參數的功能

在 Spring 裏面,能夠藉助 @InitBinder 註解能夠完成這種事情,咱們定義一個控制器基類,方便接受請求的控制器繼承

public class BaseController {
    @InitBinder
    protected void initBinder(WebDataBinder binder) {
        StringTrimmerEditor stringtrimmer = new StringTrimmerEditor(true);
        binder.registerCustomEditor(String.class, stringtrimmer);
    }
}

server

server.address 綁定地址
server.port 綁定端口
server.compression.enabled 是否開啓壓縮
server.compression.mime-types 壓縮的類型
server.compression.min-response-size 壓縮的閾值

server.tomcat.* access日誌,日誌目錄,線程數等

server.session.cookie.* SessionCookie相關配置

相關文章
相關標籤/搜索