Home | 简体中文 | 繁体中文 | 杂文 | 打赏(Donations) | ITEYE 博客 | OSChina 博客 | Facebook | Linkedin | 知乎专栏 | Search | Email

第 6 章 Spring MVC

目录

6.1. @Controller
6.1.1. @RequestMapping
6.1.1.1. @RequestMapping("/")
6.1.1.2. 映射多个URL
6.1.1.3. headers
6.1.2. @ResponseBody
6.1.2.1. 直接返回HTML
6.1.3. RequestMapping with Path Variables - @PathVariable
6.1.3.1. URL 参数传递
6.1.3.2. URL 传递 Date 类型
6.1.3.3. 处理特殊字符
6.1.3.4. @PathVariable 注意事项
6.1.4. RequestMapping with Request Parameters - @RequestParam
6.1.4.1. HTTP GET
6.1.4.2. HTTP POST
6.1.4.3. @RequestParam 传递特殊字符串
6.1.4.4. 传递日期参数
6.1.5. @ModelAttribute
6.1.6. ModelAndView
6.1.6.1. 变量传递
6.1.6.2. ModelMap 传递多个变量
6.1.6.3. redirect
6.1.6.4. ArrayList
6.1.6.5. HashMap
6.1.6.6. 传递对象
6.1.6.7.
6.1.7. @Scheduled
6.1.8. @CrossOrigin
6.1.9. @SessionAttributes
6.1.10. HttpServletRequest / HttpServletResponse
6.1.10.1. 用于方法参数
6.1.10.2. 注入方式
6.2. @RestController
6.2.1. 返回实体
6.2.2. JSON
6.2.3. XML
6.2.4. 兼容传统 json 接口
6.3. View
6.3.1. Using Spring’s form tag library
6.3.1.1. css
6.3.1.2. cssClass
6.3.2. Thymeleaf
6.3.2.1. Maven pom.xml
6.3.2.2. Spring 配置
6.3.2.3. controller
6.3.2.4. HTML5 Template
6.3.3. FreeMarker
6.4. Properties
6.4.1. 载入*.properties文件
6.4.2. @Value 注解
6.4.3. @PropertySource 注解
6.5. FAQ
6.5.1. o.s.web.servlet.PageNotFound
6.5.2. HTTP Status 500 - Handler processing failed; nested exception is java.lang.NoClassDefFoundError: javax/servlet/jsp/jstl/core/Config
6.5.3. 同时使用 Thymeleaf 与 JSP
6.5.4. 排除静态内容
6.5.5. HTTP Status 406

Spring MVC 有两种启动模式,一种是传统Tomcat,需要配置很多XML文件。另一种方式是采用 Spring Boot 需要些一个Java程序,不需要写xml文件,这个程序会帮助你处理启动所需的一切,并且采用嵌入方式启动 Tomcat 或者 Jetty.

两种方式各有优缺点,Tomcat 方式配置繁琐,但是可以使用虚拟机,同一个IP地址使用不同域名访问,出现不同的内容。而Spring Boot一个应用一个容器一个端口,比不得不通过端口来区分应用。

6.1. @Controller

package cn.netkiller.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class Welcome {

	@RequestMapping("/welcome")
	public ModelAndView helloWorld() {

		String message = "Helloworld!!!";
		return new ModelAndView("welcome", "message", message);
	}
}
	

6.1.1. @RequestMapping

@RequestMapping("/welcome")
		
@RequestMapping(value = "/list", method = RequestMethod.GET)
		

6.1.1.1. @RequestMapping("/")

			
package com.cf88.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
@RequestMapping("/")
public class HelloController {

	@RequestMapping(value = "/{name}", method = RequestMethod.GET)
	public String getMovie(@PathVariable String name, ModelMap model) {
		model.addAttribute("name", name);
		return "hello";
	}

}		
			
			

6.1.1.2. 映射多个URL

@RequestMapping({ "/news/zh-cn", "/news/zh-tw" })
@ResponseBody
public String getNewsByPath() {
    return "Hello";
}
			

6.1.1.3. headers

			
@RequestMapping(value = "/news/json", method = GET, headers = "Accept=application/json")
@ResponseBody
public String getFoosAsJsonFromBrowser() {
    return "{...}";
}
			
			
curl -H "Accept:application/json,text/html" http://localhost:8080/spring/news/json.html
			

6.1.2. @ResponseBody

import org.springframework.web.bind.annotation.ResponseBody;
		

6.1.2.1. 直接返回HTML

			
package cn.netkiller.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class Pathinfo {

	@RequestMapping(value = "/news/shenzhen/{numericId:[\\d]+}")
	@ResponseBody
	public String getNewsWithPathVariable(@PathVariable final long numericId) {
		return "Get a specific Bar with id=" + numericId;
	}

}

			
			

6.1.3. RequestMapping with Path Variables - @PathVariable

6.1.3.1. URL 参数传递

需求,我们需要通过URL传递参数,所传递的值是分类ID与文章ID,例如 /news/1.html, /news/1/1.html。

			
package cn.netkiller.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class Pathinfo {
	@RequestMapping("/pathinfo/{id}")
	public ModelAndView urlTestId(@PathVariable String id) {

		return new ModelAndView("pathinfo/param", "id", id);
	}

	@RequestMapping("/pathinfo/{cid}/{id}")
	public ModelAndView urlTestId(@PathVariable String cid, @PathVariable String id) {

		ModelMap model = new ModelMap();

		model.addAttribute("cid", cid);
		model.addAttribute("id", id);

		return new ModelAndView("pathinfo/param", model);
	}
}
			
			

jsp测试文件

			
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
${ cid } <br>
${ id } <br>
</body>
</html>
			
			

6.1.3.2. URL 传递 Date 类型

http://localhost:7000/history/2016-09-28%2000:00:00/

			
	@RequestMapping("/history/{datetime}")
	public String history(@PathVariable @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss") Date datetime) throws Exception {

		System.out.println(datetime)

		return null;
	}			
			
			

6.1.3.3. 处理特殊字符

http://www.netkiller.cn/release/1.0.1

@RequestMapping(value = "/release/{version:[a-zA-Z0-9\\.]+}", method = RequestMethod.GET)  
public @ResponseBody  
String release(@PathVariable String version) {  
    log.debug("version: ", version);  
    return version;  
}
			

http://www.netkiller.cn/release/1.0.1/other

@RequestMapping(value="/release/{version:.+}",method=RequestMethod.GET)
public void download(HttpSession session,@PathVariable("version")String version){
	return version;
}
			

6.1.3.4. @PathVariable 注意事项

@PathVariable 参数传统需要注意,参数中不能携带 “/”,斜杠会被视为目录。

			
	@RequestMapping("/PathVariable/{code}.html")
	@ResponseBody
	public String urlTestId(@PathVariable String code) {
		return code;
	}
			
			

6.1.4. RequestMapping with Request Parameters - @RequestParam

import org.springframework.web.bind.annotation.RequestParam;
		

6.1.4.1. HTTP GET

			
	@RequestMapping("/request/param")
	@ResponseBody
	public String getBarBySimplePathWithRequestParam(@RequestParam("id") long id) {
	    return "Get a specific Bar with id=" + id;
	}
			
			

http://localhost:8080/Spring/request/param.html?id=100
			

6.1.4.2. HTTP POST

			
package cn.netkiller.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class Http {

	@RequestMapping("/http/form")
	public ModelAndView createCustomer(){
		ModelMap model = new ModelMap();

		model.addAttribute("email", "netkiller@msn.com");
		model.addAttribute("phone", "13113668890");

	    return new ModelAndView("http/form", model);
	}

	@RequestMapping(value= "/http/post", method = RequestMethod.POST)
	public ModelAndView saveCustomer(HttpServletRequest request,
	        @RequestParam(value="Email", required=false) String email,
	        @RequestParam(value="Password", required=false) String password,
	        @RequestParam(value="Phone", required=false) String phone){

		ModelMap model = new ModelMap();

		model.addAttribute("email", email);
		model.addAttribute("password", password);
		model.addAttribute("phone", phone);

	    return new ModelAndView("http/post", model);
	}

}
			
			

http/form.jsp

			
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>

	<form method="POST"
		action="http://localhost:8080/Spring/http/post.html" id="Register"
		name="Register">
		Email: <input class="register" type="text" id="Email" name="Email" value="${email}" /> <br />
		Password: <input class="register" type="password" id="Password" name="Password" value="" /><br />
		Phone: <input class="register" type="text" id="Phone" name="Phone" value="${phone}" /> <br />
		<input type="submit" id="btnRegister" name="btnRegister" value="Register" style="cursor: pointer" />
	</form>

</body>
</html>
			
			

http/post.jsp

			
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	${email}<br>
	${password}	<br>
	${phone} <br>
</body>
</html>
			
			

6.1.4.3. @RequestParam 传递特殊字符串

URL 中 “+” 有特殊意义,表示空格。

如果 @RequestParam 传递参数含有空格可以这样处理。

			
	@RequestMapping("/RequestParam")
	@ResponseBody
	public String query(@RequestParam("code") String code) {

		return code.replace(" ", "+");

	}
			
			

6.1.4.4. 传递日期参数

			
	@RequestMapping("/range")
	public ModelAndView range(@RequestParam("beginDate") @DateTimeFormat(pattern = "yyyy-MM-dd") Date beginDate, @RequestParam("endDate") @DateTimeFormat(pattern = "yyyy-MM-dd") Date endDate) {
		log.info("===== Begin ===== {}", beginDate);

		// 你的逻辑

		log.info("===== End ===== {}", endDate);
		return new ModelAndView("activity/index", "message", "操作成功");
	}
			
			

6.1.5. @ModelAttribute

@ModelAttribute 处理 HTML FORM POST 提交

		
package cn.netkiller.pojo;

import java.util.List;

public class Deploy {

	private String group;
	private String envionment;
	private String project;
	private List<String> arguments;
	public Deploy() {
		// TODO Auto-generated constructor stub
	}
	// Getters & Setters
}
		
		
		
	@RequestMapping(value="/deploy/post",  method = RequestMethod.POST)
	public ModelAndView post(@ModelAttribute("deploy")Deploy deploy, BindingResult result) {
		if (result.hasErrors()) {
			System.out.println(result.toString());
        }
		System.out.println(deploy.toString());
		return new ModelAndView("output").addObject("output", deploy.toString());
	}		
		
		

6.1.6. ModelAndView

6.1.6.1. 变量传递

	@RequestMapping("/testString")
	public ModelAndView helloWorld() {
		String message = "Helloworld!!!";
		return new ModelAndView("welcome", "message", message);
	}
			
	public ModelAndView handleRequestInternal() {

		ModelAndView mav = new ModelAndView("test");// 实例化一个VIew的ModelAndView实例
		mav.addObject("variable", "Hello World!");// 添加一个带名的model对象
		return mav;
	}
			

6.1.6.2. ModelMap 传递多个变量

传递多个字符串

	@RequestMapping("/testModelMap")
	public ModelAndView testModelMap() {
		ModelMap model = new ModelMap();

		model.addAttribute("username", "Neo");
		model.addAttribute("password", "Netkiller");

		return new ModelAndView("test/modelmap", model);
	}
			

推荐使用ModelMap

			
	@RequestMapping("/testMapString")
	public ModelAndView testMapString() {

		Map<String,String> data = new HashMap<String,String>();
		data.put("username","Neo");
		data.put("password","Netkiller");
	    return new ModelAndView("test/modelmap",data);

	}
			
			
			
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
${username}<br>
${password}<br>
</body>
</html>
			
			

6.1.6.3. redirect

			
	@RequestMapping("/testRedirect")
	public ModelAndView testRedirect(){
		   RedirectView view = new RedirectView("testMapString.html");
		   return new ModelAndView(view);
	}
			
			

6.1.6.4. ArrayList

			
	@RequestMapping(value = "testList")
	public ModelAndView testList() {
		ModelAndView mav = new ModelAndView();
		mav.setViewName("/test/list");

		// List
		List<String> list = new ArrayList<String>();
		list.add("java");
		list.add("c++");
		list.add("oracle");
		mav.addObject("bookList", list);

		return mav;
	}
			
			
			
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
	pageEncoding="ISO-8859-1"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
	${bookList}
	<br>

	<c:forEach items="${bookList}" var="node">
		<c:out value="${node}"></c:out><br>
	</c:forEach>

</body>
</html>
			
			

6.1.6.5. HashMap

			
	@RequestMapping("/testMap")
	public ModelAndView testMap() {
		ModelAndView mav = new ModelAndView();
		mav.setViewName("test/map"); // 返回的文件名

		// Map
		Map<String, String> map = new HashMap<String, String>();
		map.put("Java", "http://www.netkiller.cn/java");
		map.put("PHP", "http://www.netkiller.cn/php");
		map.put("Home", "http://www.netkiller.cn");
		mav.addObject("channel", map);

		return mav;
	}
			
			
			
<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
	<c:forEach items="${channel}" var="node">
		<a href="<c:out value="${node.value}"></c:out>"><c:out value="${node.key}"></c:out></a>
        <br/>
	</c:forEach>
</body>
</html>
			
			

6.1.6.6. 传递对象

			
	@RequestMapping("/testObject")
	public ModelAndView testObject() {
		ModelMap model = new ModelMap();

		User user = new User("neo", "passw0rd");
		model.addAttribute("user", user);
		return new ModelAndView("test/object", model);

	}
			
			
			
package cn.netkiller;

public class User {
	public String username;
	public String password;
	public User(String username, String password){
		this.username = username;
		this.password = password;
	}
	public String getUsername(){
		return this.username;
	}
	public String getPassword(){
		return this.password;
	}
}
			
			
			
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
Username: ${user.username}<br>
Password: ${user.password}<br>
</body>
</html>
			
			

6.1.6.7. 

			
			
			

6.1.7. @Scheduled

计划任务

		
@Component
@EnableScheduling
public class MyTask {

    @Scheduled(cron="*/3 * * * * *")
    public void myTaskMethod(){
        //do something
    }
}		
		
		

6.1.8. @CrossOrigin

	@CrossOrigin(origins = "http://localhost:9000")
    @GetMapping("/greeting")
    public Greeting greeting(@RequestParam(required=false, defaultValue="World") String name) {
        System.out.println("==== in greeting ====");
        return new Greeting(counter.incrementAndGet(), String.format(template, name));
    }
		

6.1.9. @SessionAttributes

		
@Controller
@SessionAttributes("myRequestObject")
public class MyController {
  ...
}
		
		

6.1.10. HttpServletRequest / HttpServletResponse

6.1.10.1. 用于方法参数

HttpServletResponse 实例

			
package cn.netkiller.api.rest;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import api.util.MatrixToImageWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Hashtable;

@Controller
@RequestMapping("/public/QRCode")
public class QRCodeController {
    private static final Logger log = LoggerFactory.getLogger(QRCodeController.class);
	
    @RequestMapping("/create/{code}" )
    @ResponseBody
    public void create(@PathVariable String code, HttpServletResponse httpServletResponse) throws WriterException, IOException {
        log.info(code);
        if (code != null && !"".equals(code)){
            ServletOutputStream stream = null;
            try {
                String text = code; 	// 二维码内容
                int width = 300; 		// 二维码图片宽度
                int height = 300; 		// 二维码图片高度
                String format = "gif";	// 二维码的图片格式

                Hashtable<EncodeHintType, String> hints = new Hashtable<EncodeHintType, String>();
                hints.put(EncodeHintType.CHARACTER_SET, "utf-8");   // 内容所使用字符集编码

                BitMatrix bitMatrix = new MultiFormatWriter().encode(text, BarcodeFormat.QR_CODE, width, height, hints);
                // 生成二维码
                stream = httpServletResponse.getOutputStream();
                MatrixToImageWriter.writeToStream(bitMatrix, format, stream);

            }catch (WriterException e) {
                e.printStackTrace();
            } finally {
                if (stream != null) {
                    stream.flush();
                    stream.close();
                }
            }
        }
    }

    @RequestMapping("show")
    @ResponseBody
    public ModelAndView show(){

        return new ModelAndView("/qrcode/qrcode");
    }
}		
			
			

6.1.10.2. 注入方式