天天看点

Spring Boot 2.X 表单处理(GET、POST)类注解方法注解参数注解案例实战

类注解

RestController

@RestController 是spring4.x新引入的一个注解,定义在类前面,相当于@Controller和@ResponseBody的一个结合,使该类中的方法直接返回字符串或者json数据给浏览器,而不是返回视图页面。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController { }
           

Controller

@Controller用于标记在一个类上,使用它标记的类就是一个SpringMvc Controller对象,分发处理器会扫描使用该注解的类的方法,并检测方法是否使用了@RequestMapping注解。

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller { } 
           

Component

@Component 泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。常见的组件有:@Controller 控制层,@Service 业务逻辑层,@Repository DAO层/数据访问层。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface Component { }
           

方法注解

RequestMapping

@RequestMapping 用来标注请求的方法类型

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping { }
           

请求方法一共有 8 种(最常用的只有 GET 和 POST):

public enum RequestMethod {
	GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE
}
           

GetMapping

@GetMapping 是对类型为 GET 的 RequestMapping 的封装

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RequestMapping(method = RequestMethod.GET)
public @interface GetMapping { }
           

PostMapping

@PostMapping 是对类型为 POST 的 RequestMapping 的封装

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RequestMapping(method = RequestMethod.POST)
public @interface PostMapping { }
           

ResponseBody

@PostMapping 将方法的返回值以特定的格式写入到response的body区域,进而将数据返回给客户端。如果返回的是字符串,则直接写入到body中;如果是对象,则转化为 json,然后写入body中。

但是注意:如果是返回对象,默认会按 UTF-8 编码;如果返回的是String,默认会按 iso8859-1 编码,因此页面可能会出现乱码。我们可以通过:@RequestMapping(value=“test”, produces=“text/html;charset=utf-8”),前面是请求的路径,后面是编码格式。

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ResponseBody { }
           

参数注解

RequestBody

表单格式使用的是默认的 ContentType 类型 application/x-www-form-urlencoded 或者 multipart/form-data,格式为key1=value1&key2=value2 提交到后台 ,不需要加 @RequestBody。

如果请求的 ContentType 为 application/json,数据类型为 json 时,如 {“aaa”:“111”,“bbb”:“222”},必须要加 @RequestBody,这样注解的属性才能映射到值。

RequestParam

GET和POST请求传的参数会自动转换赋值到 @RequestParam 所注解的变量上。

例如:

//https://127.0.0.1/person?name=bob&age=28
@GetMapping("/person")
public PersonModel person(@RequestParam(value="name", defaultValue="unknown") String name, @RequestParam(value="age") String age) {
	return new PersonModel(name, age);
}
           

PathVariable

@PathVariable 可以将 URL 中占位符参数,绑定到控制器处理方法的输入参数中。

例如:

//http://127.0.0.1:8080/blog/bob/123
@GetMapping("/blog/{name}/{pageId}")
public BlogModel blog(@PathVariable String name, @PathVariable String pageId) {
	return new BlogModel (name, pageId);
}
           

带占位符的URL 是Spring3.0 新增的功能,该功能在SpringMVC 向REST目标挺进发展过程中具有里程碑的意义。

ModelAttribute

@ModelAttribute 用来将请求参数整合到一个类内部,这样,一来可以避免表单参数过多每个都要写注解的麻烦,二来也可以更好的面向对象进行封装抽象。

@ModelAttribute 可以整合 @RequestParam,@PathVariable,@MultipartFile 的参数。

特别注意:model 需要有 getter / setter 的方法才能被赋值,否则无法正确赋值。

例如:

//https://127.0.0.1/person?name=bob&age=28
@GetMapping("/person")
public PersonModel person(@ModelAttribute PersonModel model) {
	return model;
}

//http://127.0.0.1:8080/blog/bob/123
@GetMapping("/blog/{name}/{pageId}")
public BlogModel blog(@ModelAttribute BlogModel model) {
	return model;
}
           

MultipartFile

@MultipartFile 用于在 enctype=“multipart/form-data” 的 form 中上传文件数据。

public interface MultipartFile extends InputStreamSource {
	//表单中的name值
	String getName();
	//文件的真实名称
 	String getOriginalFilename();
 	//获取文件的MIME类型(比如:image/png)
	String getContentType();
	//文件是否为空
	boolean isEmpty();
	//获取文件大小
	long getSize();
	//获取文件内容
	byte[] getBytes() throws IOException;
	//获取文件输入流
	InputStream getInputStream() throws IOException;
	//获取文件描述符
	default Resource getResource() {
		return new MultipartFileResource(this);
	}
	//将文件内容写入到指定文件
	void transferTo(File dest) throws IOException, IllegalStateException;
	//将文件内容写入到指定路径
	default void transferTo(Path dest) throws IOException, IllegalStateException {
		FileCopyUtils.copy(getInputStream(), Files.newOutputStream(dest));
	}
}
           

案例实战

首先,创建一个spring boot starter项目,勾选 “ Web Starter ” 选项。

在 “src/main/resources/static/” 静态目录下,新建一个测试网页,比如 test.html

<!DOCTYPE HTML>
<html>
<head>
<title>Hello Static Page</title>
<meta charset="utf8">
<style>
#form1 input, textarea, button {
	display: block;
	margin-bottom: .5rem;
}
input[type=image], input[type=file] {
	display: block;
}
</style>
</head>
<body>
<form id="form1" method="post" action="http://127.0.0.1:8080/form1">

<textarea name="message" rows="5" cols="15">
This is a long message!
</textarea>

<select name="car">
	<option value="Toyota">丰田卡罗拉</option>
	<option value="BaoJun">宝骏360</option>
	<option value="BMW">宝马</option>
</select>

<input list="browser" name="browser" placeholder="browser">
<datalist id="browser">
	<option value="Internet Explorer">
	<option value="Firefox">
	<option value="Chrome">
	<option value="Opera">
	<option value="Safari">
</datalist>

<fieldset>
<legend>This is fieldset's legend</legend>
<input type="text" name="text" placeholder="text">
<input type="password" name="password" placeholder="password">
<input type="email" name="email" placeholder="email"/>
<input type="url" name="url" placeholder="url"/>
<input type="number" name="number" step="2" placeholder="number"/>
<input type="range" name="range" />
<input type="date" name="date"/>
<input type="search" name="search" placeholder="keyword"/>
</fieldset>

<input type="submit" value="submit">
</form>

<form id="form2" method="post" action="http://127.0.0.1:8080/form2" oninput="x.value=parseInt(a.value)+parseInt(b.value)" enctype="multipart/form-data">

<input type="radio" name="sex" value="male" id="male">
<label for="male">男人</label>
<input type="radio" name="sex" value="female" id="female">
<label for="female">女人</label>
<button onclick="alert('This is button')">Click Me!</button>

I have a 
<input type="checkbox" name="vehicle" value="bike">bike</input>
<input type="checkbox" name="vehicle" value="car">car</input>
<br>

0<input type="range" id="a" value="50">100
+<input type="number" id="b" value="50">
=<output name="x" for="a b"></output>

<br>
<input name="file1" type="file"/> 
<input name="file2" type="file" accept="image/*" multiple/> 

<br>
<input type="submit" value="submit">
</form>
</body>
</html>
           

效果如下,我在这里面做了两个表单

  • output 标签是H5新增的标签,用来实时显示结果输出,oninput 是一个表单输入改变事件,可以在该事件中修改output的输出值。 output 标签的值不会被上送。
  • 如果表单中存在需要上传的文件,需要在 form 上添加 enctype=“multipart/form-data”,意思是指明表单数据由多部分构成,既有文本数据,又有文件等二进制数据;默认的 enctype=“application/x-www-form-urlencoded”,这种情况下只能上传文本数据,不能上传文件。
    Spring Boot 2.X 表单处理(GET、POST)类注解方法注解参数注解案例实战

新建两个对应的实体类

Form1Model.java

public class Form1Model {

	public String message;
	public String car;
	public String browser;
	public String text;
	public String password;
	public String email;
	public String url;
	public String number;
	public String range;
	public String date;
	public String search;
	
	public String getMessage() {
		return message;
	}
	public void setMessage(String message) {
		this.message = message;
	}
	public String getCar() {
		return car;
	}
	public void setCar(String car) {
		this.car = car;
	}
	public String getBrowser() {
		return browser;
	}
	public void setBrowser(String browser) {
		this.browser = browser;
	}
	public String getText() {
		return text;
	}
	public void setText(String text) {
		this.text = text;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public String getEmail() {
		return email;
	}
	public void setEmail(String email) {
		this.email = email;
	}
	public String getUrl() {
		return url;
	}
	public void setUrl(String url) {
		this.url = url;
	}
	public String getNumber() {
		return number;
	}
	public void setNumber(String number) {
		this.number = number;
	}
	public String getRange() {
		return range;
	}
	public void setRange(String range) {
		this.range = range;
	}
	public String getDate() {
		return date;
	}
	public void setDate(String date) {
		this.date = date;
	}
	public String getSearch() {
		return search;
	}
	public void setSearch(String search) {
		this.search = search;
	}
}
           

Form2Model.java

public class Form2Model {
	
	public String sex;
	public String vehicle;
	public String x;
	
	public String getSex() {
		return sex;
	}
	public void setSex(String sex) {
		this.sex = sex;
	}
	public String getVehicle() {
		return vehicle;
	}
	public void setVehicle(String vehicle) {
		this.vehicle = vehicle;
	}
	public String getX() {
		return x;
	}
	public void setX(String x) {
		this.x = x;
	}
}
           

在 “src/main/java” 中新建 “TestController.java”

@PostMapping("/form1")
public Form1Model form1(@ModelAttribute Form1Model model) {
	return model;
}

@PostMapping("/form2")
//这里的 MultipartFile 也可以整合到 ModelAttribute 里面,但是这样就不能直接返回这个model了
public Form2Model form2(@ModelAttribute Form2Model model, @RequestParam("file1") MultipartFile file1, @RequestParam("file2") MultipartFile[] file2) {
	System.out.println("file1:\n" + printFile(file1));
	System.out.println("file2:\n" + file2 != null ? printFile(file2[0]) : null);
	return model;
}

private String printFile(MultipartFile file) {
	if(file == null) return null;
	StringBuilder sb = new StringBuilder();
	sb.append("name: ");
	sb.append(file.getName());
	sb.append("\n");
	sb.append("originalFilename: ");
	sb.append(file.getOriginalFilename());
	sb.append("\n");
	sb.append("contentType: ");
	sb.append(file.getContentType());
	sb.append("\n");
	sb.append("size: ");
	sb.append(file.getSize());
	sb.append("\n");
	return sb.toString();
}
           

最后访问 http://127.0.0.1/test.html 提交表单,就可以测试了。

继续阅读