2. MVC 上
写在开头,关于MVC,Model - View - Controller模式
- Model(模型) - 代表一个存取数据的对象或 JAVA POJO。它也可以带有逻辑,在数据变化时更新控制器。
- View(视图) - 代表模型包含的数据的可视化。
- Controller(控制器) - 作用于模型和视图上。它控制数据流向模型对象,并在数据变化时更新视图。它使视图与模型分离开。
这里有几个很容易混淆的概念:模式、框架、架构、平台,它们之间究竟是什么关联?
- 模式(设计模式):包括本章讲述的MVC模式,均属于设计模式。设计模式说白了就是:告诉你针对特定问题如何组织类、对象和接口之间的关系,是前人总结的经验。
- 框架:框架是为了解决特定问题而存在的,其它诸如模板框架、缓存框架等。
- 架构:从大的层面来说,架构关注的是技术整合、扩展、可维护性。
- 平台:类似框架,但又结合的架构的考虑,它是更高层面上的“框架”,准确说是一种应用。它是针对企业用户,为解决企业业务需要而形成的产品。
概念比较:设计模式 < 框架 < 架构 < 平台
从复用角度讲:设计模式是代码级复用、框架是模块级复用、架构是系统级复用、平台是企业应用级复用。
在项目中使用最多的就是Spring MVC框架了,Spring Boot已经将这一MVC框架进行了自动集成并实现了自动配置,可谓一步到位。
-
Web项目目录结构及包结构规范
- 项目目录结构
关于web项目,常规情况下采用maven项目构建工具的打包工具生成。有了Spring Boot这一集成框架,在IDEA中通过Spring Initializr可进行快速SpringBoot项目的搭建。
项目根目录:src/main- java
- packageName
- conf
- controller
- entity
- service
- impl
- …
- dao
- …
- Application.java (启动器类)
- packageName
- resources
- static (静态资源默认)
- css
- js
- …
- template (页面模板默认)
- application.properties (配置文件)
- static (静态资源默认)
- java
- 包结构规范:上述项目目录结构为标准
- Spring Boot默认扫描规则是:自动扫描启动器类的同包或者其子包的下的注解。
- 项目目录结构
-
URL映射到方法
- @RequestMapping
- 用于类上的@RequestMapping注解用来标注请求路径
- 用于方法上的@RequestMapping注解用来进一步映射特定的URL到具体的处理方法
- @RequestMapping 的属性
- value :请求的URL路径,支持URL模板、正则表达式
- method:HTTP请求方法 GET、POST、PUT等
- consumes:允许的媒体类型| consumes = “application/json” 对应HTTP请求的Content-type
- produces:响应的媒体类型| produces = “application/json” 对应HTTP请求的Accept字段
- params:请求的参数,params = “action=update”
- headers:请求HTTP头的值,headers = “myHeader=myValue”
- URL 路径匹配
- 属性value用于匹配URL映射,value支持简单的表达式来匹配
例如:@RequestMapping(value = “/get/user.json”) - Ant路径表达式
- Ant 用符号 " * " 来表示匹配任意字符,用 " ** " 来表示统配任意路径,用 " ? " 来匹配单个字符。
- 属性value用于匹配URL映射,value支持简单的表达式来匹配
例子 说明 /user/*.html 匹配 /user/1.html、/user/2.html等 /**/1.html 匹配 /1.html、/user/1.html、/user/add/1.html等 /user/?.html 匹配 /user/1.html,不匹配 /user/11.html -
匹配优先级:如果一个请求有多个 @RequestMapping 能够匹配
- 有通配符的低于没有通配符的,比如 /user/add.json 比 /user/*.json 优先匹配。
- 有 “**” 通配符的低于有 “*” 通配符的。
- 其他URL映射:通过外部配置文件可以进行参数获取
@Value("${paramName}")
private String name; // 将paramName映射到成员变量name属性
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@Value("#{ }") SpEL表达式
通常用来获取bean的属性,或者调用bean的某个方法,也可以表示常量
-
HTTP method 匹配
- @RequestMapping 提供 method 属性来映射HTTP的请求方法。
- 通常对于Web应用,GET和POST是经常使用的method,对于REST接口,则会采用PUT、DELETE等用来从语义上进一步区分操作。
- Spring 提供简化后的 @RequestMapping ,提供了新的注解来表示 HTTP 方法。如:
- @GetMapping
- @PostMapping
- @PutMapping
- @DeleteMapping
- @PatchMapping
- …
-
consumes 和 produces
-
属性 consumes 表示请求的HTTP头的Content-type媒体类型与consumes的value匹配才能调用此方法
@GetMapping(value = "/consumes/test.json", consumes = "application/json") @ResponseBody public User forJson() { return userService.getUserById(1l); }
这里映射指定请求的媒体类型是 application/json 。因此,此方法接收一个如下AJAX请求:
$.ajax({ type: "get", url: "/consumes/test.json", contentType: "application/json", ... });
-
属性 produces 对应HTTP请求的Accept字段,只有匹配成功才能进行方法调用。
@GetMapping(value = "/user/{userId}", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
将通常浏览器都会把 Accept 设置为 *.* ,因此通过浏览器直接访问 “/user/1” ,浏览器总是返回对应信息,并通过 @ResponseBody 转换成JSON格式返回。
-
-
params 和 headers
不同于Servlet规范,在方法中通过 HttpServletRequest 获取请求的URL、HTTP头这些信息再进行处理。Spring在方法签名处提供了很多匹配方式,能进一步规范方法调用,提高代码可阅读性。@GetMapping(value = "/update.json", headers = "action=update") // params 同理
- @RequestMapping
-
方法参数
-
@PathVariable
-
用于从请求URL中获取参数,并映射到方法参数中
@GetMapping(path = "/{userId}.json", produces = "application/json") @ResponseBody public User getUserById(@PathVariable Long userId) { return userService.getUserById(userId); }
符号 {} 中的变量名与方法参数名字对应,若不想对应可以使用:@PathVariable(“userId”) Long id
-
-
Model & ModelAndView
- Model(结构类似Map),可以向视图中添加需要的变量
- Model对象主要方法:
- Model addAttribute(String attributeName, Object attributeValue):向模型中添加一个变量,参数签名列表前者指明变量名称,可以在随后的视图中引用。后者代表变量。
- Model addAttribute(Object attributeValue):向模型中添加一个变量,变量的名字就是类名首字母小写后专为的Java变量。
- Model addAllAttributes(Map attributes):添加多个变量,若变量存在,则覆盖。
- Model mergeAttributes(Map attributes):添加多个变量,若变量存在,则忽略。
- Boolean containsAttribute(String attributeName):判断是否存在变量。
-
如何使用:ModelAndView对象类似Model,但额外提供了一个视图名称的配置。
// Model model model.addAttribute("userInfo", user); // ModelAndView view view.addObject("userInfo", user); view.setViewName("/userInfo.html"); return view
-
JavaBean 接收HTTP参数 @RequestParam
-
通过 @RequestParam 限定HTTP参数
-
name:指明HTTP参数名称
-
required:布尔类型,声明此参数是否必须有,如果该参数没有,抛出400错误
-
defaultValue:字符类型,如果HTTP参数没有提供,可以指定一个默认字符串
String getUser(@RequestParam(name = "name", required = false, defaultValue = "zhangsan") String name){...}
-
-
接收一个参数对象:HTTP参数名字对应POJO属性名
@GetMapping("/getUser") @ResponseBody public String getUser(User user){...}
-
-
@RequestBody 接收JSON
-
方法参数使用 @RequestBody 指定参数类型为JSON数据,且映射的是一个实体POJO类。
-
Spring Boot默认使用Jackson来处理反序列化工作。
@PostMapping("/save.json") @ResponseBody public String saveUser(@RequestBody User user){...}
-
注意,和JavaBean接收HTTP参数(对象)区分开,接收JSON数据是字符串,采用@RequestBody进行字符串向对象的映射对应
-
-
MultipartFile:处理文件上传
-
案例代码
@PostMapping("/form") @ResponseBody public String handleFormUpload(@RequestParam("name") String name, @RequestParam("file") MultipartFile file) throws IOException { if (!file.isEmpty()) { String fileName = file.getOriginalFilename(); InputStream ins = file.getInputStream(); // 处理上传内容 return "success"; } return "failure"; }
-
MultipartFile相关方法
-
方法名 说明 getOriginalFilename 获取上传文件名称 getBytes 获取上传文件内容,转为字节数组 getInputStream 获取一个InputStream isEmpty 文件上传内容为空,或者没有文件上传 getSize 上传文件大小 transferTo(File dest) 保存上传文件到目标文件系统 -
多文件上传:使用MultipartFile数组类来接收多个文件上传
@RequestParam("file") MultipartFile[] files
-
上传文件参数限制:通过配置文件 application.properties 进行配置
-
-
@ModelAttribute
-
该注解通常作用在Controller的某个方法上,此方法会首先被调用,并将结果作为Model的属性。
@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"; }
-
-
@InitBinder
- Spring框架通过WebDataBinder 类实现HTTP参数向JavaBean对象的绑定
- 可以通过@InitBinder声明方法,进行绑定对象的特性拓展