Controller中参数解析详解

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.propertiesSpringBoot上传文件进行限定

// 是否允许附件上传
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

注意事项

  1. 如果因为上传文件较大失败, 需要检查是否是因为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();    
        }    
    }  
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值