PathVariable
从请求的URL
获取参数并映射到方法参数中
@Controller
@RequestMapping("/user/{id}")
public class Sample35Controller {
@Autowired UserService userService;
@RequestMapping(patch="/{type}/get.json")
@ResponseBody
public User getUser(@PathVariable Long id, @PathVariable Integer type) {
return userService.getUserById(id);
}
}
符号{}
中变量名和方法名字一一对应, 如果没有对应则需要通过参数来对应@PachVariable("id") Long userId
Model 和 ModelAndView
Model
可以向视图中添加需要的变量, 有下面几个常用方法
class interface Model {
// 向模型中添加一个变量, `attributeName`为变量名
addAttribute(String attributeName, Object attributeValue);
// 向模型添加一个变量, 变量名为类名字母小写后的`Java`变量
addAttribute(Object attributeValue);
// 添加多个变量, 如果已经存在则覆盖
addAllAttritutes(Map attributes);
// 添加多个变量, 如果已经存在则忽略
mergeAttributes(Map attributes);
// 添加多个白娘, 来源于几何元素, 变量名类名字母小写后的`Java`变量
addAllAttributes(Collection<?> attributeValues);
// 判断变量是否存在
containsAttribute(String attributeName);
}
通常不建议使用类名自动为attributeName
的方法(addAttribute(Object attributeValue)
), 重构后会造成不兼容
Model
@GetMapping(path="/{userId}/get.html")
public String getUser(@PathVariable Long userId, Model model) {
User userInfo = userService.getUserById(userId);
model.addAttribute("user", userInfo);
return "/userInfo.html"
}
ModelAndView
ModelAndView
类似于Model
但是它提供了额外的视图名称
@GetMapping(path="/userId/get.html")
public ModelAndView getUser(@PathVariable Long userId, ModelAndView view) {
User userInfo = userService.getUserById(userId);
view.addObject("user", userUserInfo);
view.setViewName("/userInfo.html");
return view;
}
在方法中构造使用
@GetMapping(path="/userId/get.html")
public ModelAndView getUser(@PathVariable Long userId) {
ModelAndView view = new ModelAndView();
...
return view;
}
JavaBean接受HTTP参数
譬如请求/javabean/update2.json?name=abc&id=1
将会调用以下方法
@GetMapping(path="/update2.json")
@ResponseBody
public String getUser(Integer id, String name) {
return "success";
}
可以通过注解@RequestParam
进一步限定HTTP
参数到Controller
的映射关系, RequestParam
支持如下属性
- value: 指明
HTTP
参数的名称 - required:
boolean
类型, 声明此参数是否必须有, 如果HTTP
参数没有, 则会抛出400 - defaultValue: 如果
HTTP
参数没有提供, 则可以指定一个默认字符串
public String getUser(@RequestParm(name="id", required=true) Integer id, String name);
参数和自定义对象映射
<form action="/javabin/saveOrder.json" method="post">
<input name="order.name">
<input name="detail[0].name">
<input name="detail[1].name">
<input type="submit" value="Submit">
</form>
public class OrderPostForm {
private Order order;
private List<OrderDetail> details;
// 忽略 getter 和 setter
}
@PostMapping(path="/saveorder.json")
@ResponseBody
public String saveOrder(OrderPostForm form) {
return "success";
}
RequestBody 接受 JSON
Controller
方法带有@RequestBody
注解参数, 此时HTTP
消息体内容是一个JSON
, 需要转化为注解指定的参数类型, 此外SpringBoot
默认使用Jackson
来处理反序列化操作
@PostMapping(path="/saveJsonOrder.json")
@ResponseBody
public String saveOrderByJson(@RequestBody User user) {
return user.getNmae();
}
curl -XPOST 'http://127.0.0.1:8080/javabean/saveJsonOrder.json'
-H 'Content-Type: application/json'
-d '{"name":"hello","id":1}'
MultipartFile
通过此类来处理上传的文件
@PostMapping("/form")
@ResponseBody
public String handleFormUpload(String name, MultipartFile file) throws IOException {
if(!file.isEmpty()) {
String fileName = file.getOriginalFilename();
InputStram ins = file.getInputStram();
return "success";
}
return "failure";
}
MultipartFile
提供了以下方法来获取上传文件信息
- getOriginalFilename: 获取上传文件名字
- getBoyes: 获取上传文件内容, 转为字节数组
- getInputStram: 获取为一个
InputStream
- isEmpty: 是否为空
- getSize: 获取上传文件大小
- transferTo(File dest): 保存上传文件到目标文件系统
上传多个文件
当上传多个文件时, 可采用数组类来处理
@PostMapping("/form")
@ResponseBody
public String handleFormUpload(String name, MultipartFile[] files) throw IOException {}
此时需要前端页面设置多个名字为files
<form action="filesUpload.html" method="post" enctype="multipart/form-data">
<input type="file" name="files">
<input type="file" name="files">
<input type="file" name="files">
</form>
通过配置文件限制上传个数, 上传大小
可通过配置application.properties
对SpringBoot
上传文件进行限定
// 是否允许附件上传
spring.service.multipart.enabled=true
// 上传文件最大长度超过多少会在本地建立临时文件存储, 设置适当的值可以减少内存压力
spring.service.multipart.file-size-threshold=0
// 临时存放位置, 如果不指定则会提供一个临时目录
spring.service.multipart.location=/static/
// 最大文件长度, 默认1MB
spring.service.multipart.max-file-size=1MB
// 单次请求最大长度, 默认为10MB, 可能包含多个文件和JSON
spring.service.multipart.max-request-size=10MB
// 表示当文件和参数被访问时才被解析为文件
spring.service.multipart.resolve-lazily=false
注意事项
- 如果因为上传文件较大失败, 需要检查是否是因为
SpringBoot
设置的限定大小造成的, 同时如果有代理服务器nginx
,apache
还需要检查代理服务器是否限制最大上传大小
ModelAttribute
注解ModelAttribute
通常作用在Controller
的某个方法上, 此方法会被首先调用, 并将方法的结果作为Model
的属性, 然后在调用对应的Controller
方法
@ModelAttribute
public void findUserById(@PathVariable Long id, Model model) {
model.addAttribute("user", userService.getUserById(id));
}
@GetMapping(path="/{id}/get.json")
@ResponseBody
public String getUser(Model model) {
System.out.println(model.containsAttribute("User"));
return "success";
}
这个请求当中, 会先调用findUserById
, 取得User
, 并添加到模型中, 使用ModelAttribute
来向一个Controller
需要的公共模型添加数据, 如果findUserById
仅仅添加一个对象到Model
, 可以改写如下形式
@ModelAttribute
public User findUserById(@PathVariable Long id) {
return userService.getUserById(id);
}
如果你的方法参数里带有@ModelAttribute
的参数, 参数并自动的转化为java对象 ,在转换的时候先匹配@ModelAttribute生成的model中匹配属性进行java对象转换
@ModelAttribute("MyUser")
public User getUser(){
User user = new User();
user.setName("winclpt");
user.setSex("男");
user.setAge(25);
return user;
}
@RequestMapping("update")
public void update(@ModelAttribute("MyUser") User user){
System.out.println(user.toString());
}
@RequestMapping("index")
public String index(){
return "index";
}
InitBinder
可以在Controller
中注解@InitBinder
声明一个方法,来自以拓展绑定的特性
@Controller
public class MyFormController {
@InitBinder
protected void initBinder(WebDataBinder binder) {
binder.addCustomFormatter(new DateFormatter("yyyy-MM-dd"));
}
@ResponseBody
@RequestMapping("/date")
public void printDate(Date d) {
System.out.println(d);
return;
}
}
可以使用注解@InitBinder来解决类型自动转换问题,SpingMVC
在绑定表单之前,都会先注册这些编辑器。一般会将这些方法些在BaseController
中,需要进行这类转换的控制器只需继承BaseController
即可。其实Spring提供了很多的实现类,如CustomDateEditor
CustomBooleanEditor
CustomNumberEditor
等
public class BaseController {
@InitBinder
protected void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(Date.class, new MyDateEditor());
binder.registerCustomEditor(Double.class, new DoubleEditor());
binder.registerCustomEditor(Integer.class, new IntegerEditor());
}
private class MyDateEditor extends PropertyEditorSupport {
@Override
public void setAsText(String text) throws IllegalArgumentException {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = null;
try {
date = format.parse(text);
} catch (ParseException e) {
format = new SimpleDateFormat("yyyy-MM-dd");
try {
date = format.parse(text);
} catch (ParseException e1) {
}
}
setValue(date);
}
}
public class DoubleEditor extends PropertiesEditor {
@Override
public void setAsText(String text) throws IllegalArgumentException {
if (text == null || text.equals("")) {
text = "0";
}
setValue(Double.parseDouble(text));
}
@Override
public String getAsText() {
return getValue().toString();
}
}
public class IntegerEditor extends PropertiesEditor {
@Override
public void setAsText(String text) throws IllegalArgumentException {
if (text == null || text.equals("")) {
text = "0";
}
setValue(Integer.parseInt(text));
}
@Override
public String getAsText() {
return getValue().toString();
}
}
}