环境:Spring Boot 1.5.4
基于 Spring Boot 可以快速创建一个Web & Restful 应用,在开始应用之前,至少要了解以下用法:
定义路由,定义 HTTP 方法
获取Header、GET、POST、路径等参数
Cookie、Session操作
应用一个模板引擎,选择 Thymeleaf
获取表单数据,以及文件上传数据
完成一个登陆、登出、注册流程
增加以下两个依赖即可完成构建:
<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 版本,兼容性未知。
<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 注解
这个注解有点复杂。可以注解到方法上,也可以注解到方法参数上
注解到方法参数
大概意思是通过模型中获取,这个模型是什么呢?大概通过一些途径(可能来自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";
}
注解到方法
将这个控制器的方法,变成一个非请求处理的方法,在其它请求方法(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相关配置