Spring Controller
Spring Controller
基本概念
一個最基本的Spring Controller就是一個類別,首先,會定義package,請養成習慣把controller都放在controller的package裡,並定義所需要import的類別,接下來,會利用java的Annotation:「@」來定義這個類別是個Controller。在類別中,指定home這個方法的RequestMapping (詳參: http://peaceful-developer.blogspot.tw/2014/08/spring-2-requestmapping.html),也就是指定這個Controller的相對URI,以下面的範例,就是告訴web server,當瀏覽器要求"/"時,就呼叫home()。另外,@ResponseBody會將home()的回傳值當做是Response的內容。也就是網頁上會看到「Hello World」。
package com.example.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class SampleController {
@RequestMapping("/")
@ResponseBody
public String home() {
return "Hello World";
}
}
如 果不使用@ResponseBody的話,return值就變成要重導的網頁名稱了。如:
package com.example.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class SampleController {
@RequestMapping("/")
public String home() {
return "index.html";
}
}
傳參數給View
Controller可以跟View互動,我們先介紹如何傳值到View。第一種方式是使用Model,Model提供addAttribute(),第一個參數是傳到view之後,對應變數的名稱,第二個參數是傳過去的內容,下面的範例就是將變數名稱「name」內容為「ben」傳到hello。
package com.example.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.ui.Model;
@Controller
public class HelloController {
@RequestMapping("/hello")
public String home(Model model) {
model.addAttribute("name", "ben");
return "hi";
}
}
第二種方式是使用ModelAndView,在產生ModelAndView時,可以指定hi為呼叫的view。ModelAndView提供addObject(),第一個參數是傳到view之後,對應變數的名稱,第二個參數是傳過去的內容,下面的範例就是將變數名稱「name」內容為「ben」傳到hi。
package com.example.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class HelloController {
@RequestMapping("/hello")
public ModelAndView home() {
ModelAndView model = new ModelAndView("hello");
model.addObject("name", "ben");
return model;
}
}
對應的hello.html (採用Thymeleaf)內容如下:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>Hello!</title>
</head>
<body>
<h2>Hello! <span th:text="${name}">Wu</span></h2>
</body>
</html>
如果是物件的話,是以addObject的第一個參數(如:newcustomer)做為傳遞的對應名稱,而不是使用變數名稱(如:cus)。
@RequestMapping(value = "/customerUpdate", method = RequestMethod.GET)
public ModelAndView openFormUpdate(@RequestParam(value="id", required=false, defaultValue="1") Long id) {
ModelAndView model = new ModelAndView("customerUpdate");
Customer cus = dao.findOne(id);
model.addObject("newcustomer",cus);
return model;
}
對應的view(customerUpdate.html):
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>Update Customer</title>
</head>
<body>
<form action="customerUpdate" th:object="${newcustomer}" method ="post">
name:<input type="text" name="name" th:field="*{name}"/><br/>
address:<input type="text" name = "address" th:field="*{address}"/><br/>
weight:<input type="text" name ="weight" th:field="*{weight}"/><br/>
<input type="hidden" name ="id" th:field="*{id}"/>
<input type="submit" value="Submit"/>
</form>
</body>
</html>
如果controller中的addObject是用物件傳送資料(單一參數),在Thymeleaf中,會以物件的類別名稱(如:Customer)來做為物件的名稱, 不過,會將第一個字母的大寫轉為小寫(如:customer),而不是使用變數名稱(如:cus)
@RequestMapping(value = "/customerUpdate", method = RequestMethod.GET)
public ModelAndView openFormUpdate(@RequestParam(value="id", required=false, defaultValue="1") Long id) {
ModelAndView model = new ModelAndView("customerUpdate");
Customer cus = dao.findOne(id);
model.addObject(cus);
return model;
}
對應的view(customerUpdate.html):
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>Update Customer</title>
</head>
<body>
<form action="customerUpdate" th:object="${customer}" method ="post">
name:<input type="text" name="name" th:field="*{name}"/><br/>
address:<input type="text" name = "address" th:field="*{address}"/><br/>
weight:<input type="text" name ="weight" th:field="*{weight}"/><br/>
<input type="hidden" name ="id" th:field="*{id}"/>
<input type="submit" value="Submit"/>
</form>
</body>
</html>
從View接收參數
接收參數的方法有好幾種,第一種方式是利用HttpServletRequest,利用getParameter來存取對應的變數。
package com.example.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
@Controller
public class HelloController {
@RequestMapping("/helloWithId")
public ModelAndView home(HttpServletRequest request) {
ModelAndView model = new ModelAndView("hi");
String name = request.getParameter("id");
model.addObject("name", name);
return model;
}
}
第二種方式是利用@RequestParam,可以設定這個參數不是必要的,也可以設定當參數不存在時的預設值。這樣程式碼簡潔多了。
package com.example.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class HelloController {
@RequestMapping("/helloWithId")
public ModelAndView home(@RequestParam(value="id", required=false, defaultValue="world") String name) {
ModelAndView model = new ModelAndView("hi");
model.addObject("name", name);
return model;
}
}
第三種方式是利用@ModelAttribute。這樣程式碼簡潔多了。
package com.example.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class HelloController {
@RequestMapping("/helloWithId")
public ModelAndView home(@ModelAttribute("id") String name) {
ModelAndView model = new ModelAndView("hi");
model.addObject("name", name);
return model;
}
}
物件的傳遞
使用@ModelAttribute的另一個好處是可以接受一個物件。
package com.example.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import com.example.demo.entity.Customer;
@Controller
public class CustomerController {
@RequestMapping(value = "/customerCreate", method = RequestMethod.GET)
public ModelAndView openForm() {
ModelAndView model = new ModelAndView("customerCreate");
return model;
}
@RequestMapping(value = "/customerCreate", method = RequestMethod.POST)
public ModelAndView processForm(@ModelAttribute Customer cus) {
ModelAndView model = new ModelAndView("customerDone");
model.addObject("customer",cus);
return model;
}
}
上面的範例在RequestMapping中,除了指定URI之外,還指定了RequestMethod,這樣就可以兩個方法(openForm, processForm)使用同一個URI (細節請參閱後面對於RequestMapping的說明)。
package com.example.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import com.example.demo.entity.Customer;
@Controller
public class CustomerController {
@RequestMapping(value = "/customerCreate", method = RequestMethod.GET)
public ModelAndView openForm() {
ModelAndView model = new ModelAndView("customerCreate");
return model;
}
@RequestMapping(value = "/customerCreate", method = RequestMethod.POST)
public ModelAndView processForm(@ModelAttribute Customer cus) {
ModelAndView model = new ModelAndView("customerDone");
model.addObject("customer",cus);
return model;
}
}
必須配合Customer.java,這樣的類別就屬於Model,其內容如下:
package com.example.demo.entity;
public class Customer {
private String name;
private String address;
private int weight;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
}
以及customerCreate.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>Create New Customer</title>
</head>
<body>
<form action="customerCreate" method ="post">
name:<input type="text" name="name"/><br/>
address:<input type="text" name = "address"/><br/>
weight:<input type="text" name ="weight"/><br/>
<input type="submit" value="Submit"/>
</form>
</body>
</html>
及customerDone.html。
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>Create New Customer</title>
</head>
<body>
name: <span th:text="${customer.name}">Wu</span>
address: <span th:text="${customer.address}">Fu Jen</span>
weight: <span th:text="${customer.weight}">56</span>
</body>
</html>
另外,利用model.addObject時,是利用第一個參數(如:newcustomer)來指定view的接收變數名稱。
package com.example.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import com.example.demo.entity.Customer;
@Controller
public class CustomerController {
@RequestMapping(value = "/customerCreate", method = RequestMethod.GET)
public ModelAndView openForm() {
ModelAndView model = new ModelAndView("customerCreate");
return model;
}
@RequestMapping(value = "/customerCreate", method = RequestMethod.POST)
public ModelAndView processForm(@ModelAttribute Customer cus) {
ModelAndView model = new ModelAndView("customerDone");
model.addObject("newcustomer",cus);
return model;
}
}
對應的view (customerDone.html)。
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>Create New Customer</title>
</head>
<body>
name: <span th:text="${newcustomer.name}">Wu</span>
address: <span th:text="${newcustomer.address}">Fu Jen</span>
weight: <span th:text="${newcustomer.weight}">56</span>
</body>
</html>
另外,如果省略第一個參數,在Thymeleaf中,會以物件的類別名稱(如:Customer)來做為物件的名稱, 不過,會將第一個字母的大寫轉為小寫(如:customer),而不是以變數名稱(如:cus)。
package com.example.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import com.example.demo.entity.Customer;
@Controller
public class CustomerController {
@RequestMapping(value = "/customerCreate", method = RequestMethod.GET)
public ModelAndView openForm() {
ModelAndView model = new ModelAndView("customerCreate");
return model;
}
@RequestMapping(value = "/customerCreate", method = RequestMethod.POST)
public ModelAndView processForm(@ModelAttribute Customer cus) {
ModelAndView model = new ModelAndView("customerDone");
model.addObject(cus);
return model;
}
}
對應的view (customerDone.html)。
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>Create New Customer</title>
</head>
<body>
name: <span th:text="${customer.name}">Wu</span>
address: <span th:text="${customer.address}">Fu Jen</span>
weight: <span th:text="${customer.weight}">56</span>
</body>
</html>
RequestMapping
HTTP Request分為get與post,所以,同一個URI可以對應get及post。以下面的範例而言,呼叫GET時,打開hi.html,hi.html會呼叫POST,並傳送id給controller,controller將id內容存在name,傳回給hello.html。
package com.example.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class HelloController {
@RequestMapping(value = "/helloWithId", method = RequestMethod.GET)
public ModelAndView openForm() {
ModelAndView model = new ModelAndView("hi");
return model;
}
@RequestMapping(value = "/helloWithId", method = RequestMethod.POST)
public ModelAndView processForm(@ModelAttribute("id") String name) {
ModelAndView model = new ModelAndView("hello");
model.addObject("name", name);
return model;
}
}
hi.html
<!DOCTYPE html>
<html>
<body>
<form action="helloWithId" method ="post">
id:<input type="text" name ="id"/><br>
<input type="submit" value="Submit"/>
</form>
</body>
</html>
hello.html (採用Thymeleaf)
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>Hello!</title>
</head>
<body>
<h2>Hello! <span th:text="${name}">Wu</span></h2>
</body>
</html>
同一個方法可以對應多個uri,如:value = {"/helloWithId", "hello2"}。
package com.example.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class HelloController {
@RequestMapping(value = {"/helloWithId", "/hello2"}, method = RequestMethod.GET)
public ModelAndView openForm() {
ModelAndView model = new ModelAndView("hi");
return model;
}
@RequestMapping(value = "/helloWithId", method = RequestMethod.POST)
public ModelAndView processForm(@ModelAttribute("id") String name) {
ModelAndView model = new ModelAndView("hello");
model.addObject("name", name);
return model;
}
}