简单了解SpringMVC(五)
SpringMVC概述
- 介绍
-
Spring为展现层提供的基于MVC设计理念的优秀web框架.
- MVC封装了Servlet
- M: 模型层, 指项目中实体类JavaBean, 装载并传输数据.
- V: 视图层.
- C: 控制层: 代表Servlet.
- SpringMVC通过一套MVC注解, 让POJO成为处理请求的控制器, 而无需实现任何接口.
- POJO: 就是最基本的Java对象.
- 支持REST风格的URL请求.
- 采用了松散耦合可插拔组件结构, 比其他MVC更具有扩展性和灵活性.
- SpringMVC是什么
- 轻量级, 基于MVC的web层应用框架, 偏前端而不是基于业务逻辑层, Spring框架的一个后续产品.
- SpringMVC能干什么
- 天生与Spring框架集成, 如(IOC, AOP)
- 进行更简洁的Web层开发.
- 支持灵活的URL到页面控制器的映射.
- 非常容易与其他视图技术集成, 如:Velocity, FreeMarker等.
- 因为数据模型不存在特定的API里, 二十放在一个Model里(Map数据结构实现), 所以很容易i被其他框架使用.
- 非常灵活的数据验证, 格式化和数据绑定机制, 能使用任何对象进行数据绑定, 不用实现特定框架的API
- 更简单, 强大的异常处理.
- 对静态资源的支持.
- 支持灵活的本地化, 主题等解析.
- SpringMVC怎么用
- 将Web层进行了职责解耦, 基于请求 - 响应模型
- 常用组件
- DispatcherServlet: 前端控制器
-
对客户端发送的请求统一管理的.
-
- Controller: 处理器/页面控制器,做的是MVC中的C的事情,但控制逻辑转移到前端控制器了,用于对请求进行处理.
- HandlerMapping: 请求映射到处理器,找谁来处理, 如果映射成功返回一个HandlerExecutionChain对象(包含一个Handler处理器(页面控制器)对象, 多个HandlerInterceptor拦截器对象).
- View Resolver: 视图解析器,找谁来处理返回的页面。把逻辑视图解析为具体的View,进行这种策略模式,很容易更换其他视图技术.
- 如: InternalResourceViewResolver将逻辑视图名映射为JSP视图.
- LocalResolver: 本地化, 国际化
- MultipartResolver: 文件上传解析器.
- HandlerExceptionResolver: 异常处理器.
- DispatcherServlet: 前端控制器
- 案例
- 创建maven的Web工程, 并加入如下依赖
<properties> <spring.version>5.0.8.RELEASE</spring.version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> </dependencies>
-
在web.xml中配置SpringMVC的核心(前端)控制器-DispatcherServlet
- 作用: 加载springMVC的配置文件, 在如下的配置方式下, 核心配置器会自动加载配置文件, 此时的配置文件有默认的位置和名称(和servlet-name)相同. 为WEB-INF/<servlet-name>-servlet.xml
- 当然, 我们也可以手动设置SpringMVC配置文件的位置.
<servlet> <servlet-name>springMVC</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- 配置DispatcherServlet的初始化參數:设置文件的路径和文件名称 --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springMVC</servlet-name> <!-- 路径模型 --> <url-pattern>/</url-pattern> </servlet-mapping>
- 当然, 我们也可以手动设置SpringMVC配置文件的位置.
- 当加载了配置文件, SpringMVC会根据扫描组件找到控制层
<!-- 扫描组件, 将加@Controller注解的类作为SpringMVC的控制层 --> <context:component-scan base-package="test"></context:component-scan> <!-- 配置视图解析器 作用: 将prefix + 视图名称 + suffix确定最终要跳转的页面 /view/xxx.jsp --> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/view/"></property> <property name="suffix" value=".jsp"></property> </bean>
- 作用: 加载springMVC的配置文件, 在如下的配置方式下, 核心配置器会自动加载配置文件, 此时的配置文件有默认的位置和名称(和servlet-name)相同. 为WEB-INF/<servlet-name>-servlet.xml
- 创建一个POJO, 在此类上加上@Controller注解, springMVC就会将此类作为控制层加载, 让其处理请求响应.
- 在控制层中, 需要在方法上设置@RequestMapping(value="href地址"), springMVC就是通过此注解将请求路径与控制层中的方法进行匹配.
- 此时请求路径为localhost:8080/projectName/xxx
index.jsp <body> <a href="hello?username=admin&password=123456">测试SpringMVC</a> </body> /WEB-INF/view/success.jsp <body> SUCCESS </body>
- handler方法
@Controller public class TestController { @GetMapping(value = "hello") public String hello(String username, String password) { System.out.println(username); System.out.println(password); return "success"; } }
处理请求的方法会返回一个字符串, 即视图名称, 最终会通过配置文件配置的视图解析器来实现页面跳转
- 此时请求路径为localhost:8080/projectName/xxx
RequestMapping详解
-
@RequestMapping注解参数
-
@RequestMapping: 设置请求映射, 把请求和控制层中的方法设置映射关系.
-
@RequestMapping可以加在方法上, 也可以加在类上.
-
若类和方法上都有, 应一层一层的访问, 先访问类, 再访问类中的方法.
-
- value属性
-
当请求路径和@RequestMapping的value属性一致时, 则该注解所标注的方法即为处理请求的方法.
-
- method属性
-
method: 用来设置请求方式, 只有客户端发送请求的方式和method的值一致, 才能处理请求.
-
请求方式常用4种
-
RequestMethod.GET: 查询
-
RequestMethod.POST: 添加
-
RequestMethod.PUT: 修改
-
RequestMethod.DELETE: 删除
-
-
-
params: 用来设置客户端传到服务器的数据(请求参数), 支持表达式
-
//value这里, 加斜线是访问项目下, 不加则是访问当前目录下 @PostMapping(value = "/test", params = {"username", "!age"}) public String testPOST() { System.out.println("SUccess: post"); return "success"; }
-
headers: 用来设置请求头信息, 所发送的请求的请求头信息一定要和headers属性中所设置的一致.
-
//此时, 浏览器中request header的language必须以q=0.8,en-us开头, 否则404错误 @PostMapping(value = "/test", headers = {"Acceept-Language:q=0.8,en-US;"})
-
-
@RequestMapping支持Ant路径风格
-
Ant风格资源地址支持3种匹配符
- 如
@GetMapping(value = "/*/ant??/**/testAnt") 匹配 /aa/antBB/CCC/DDD/testAnt
-
SpringMVC支持占位符方式的路径
- @PathVariable
-
带占位符的url是spring3.0新增, 该功能在SpringMVC向REST目标挺进发展过程具有里程碑意义.
-
通过@PathVariable可以将URL中占位符参数绑定到控制器处理方法的入参中.
- 格式: @PathVariable("xxx") 类型 参数名
<a href="testREST/1001/admin">测试</a> //以前: <a href="testREST?id=1001&useranme=admin>测试</a>
@GetMapping("/testREST/{id}/{username}") public String testREST(@PathVariable("id")Integer id, @PathVariable("username")String useranme) { System.out.println(id); System.out.println(useranme); return "success"; }
-
REST介绍
- 什么是REST
-
REST: Representational State Transfer
-
(资源)表观层状态转换, 是目前最流行的互联网软件架构.
- 资源(Resources): 网络上的一个实体, 或一个具体信息.
- 可以用一个URL指向它: 每种资源对应一个特定的URI获取这个资源, 访问它的URI就可以, 因此URI即为每一个资源的独一无二的识别符.
-
表现层(Representation): 把资源具体呈现出的形式, 叫做它的表现层.
-
比如: 文本以txt格式表现, 也可以用html表现, 甚至二进制表示.
-
-
状态转换(State Transfer): 每发出一个请求, 就代表客户端和服务器的一次交互过程.
-
HTTP 协议, 是一个无状态协议, 即所有的状态都保存在服务器端. 因此, 如果客户端想要操作服务器, 必须通过某种手段, 让服务器端发生"状态转化",而这种转化是建立在表现层之上的, 所以就是"表现层状态转化".
-
具体说, 就是HTTP协议里面, 四个表示操作方式的动词: GET, POST,PUT, DEL它们分别对应四种基本操作: GET用来获取资源, POST用来新建资源, PUT用来更新资源, DELETE用来删除资源.
-
-
- URL风格
- 增删改查
- 增删改查
-
HiddenHTTPMethodFilter
-
浏览器只支持GET与POST请求, 而DELETE, PUT等method并不支持, Spring3.0添加了一个过滤器, 可以将这些请求转换为标准的http方法, 使得支持GET, POST,PUT, DELETE请求.
-
由于使用了HiddenHTTPMethodFilter, 所以要在web.xml中配置过滤器
<filter> <filter-name>HiddenHttpMethodFilter</filter-name> <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class> </filter> <filter-mapping> <filter-name>HiddenHttpMethodFilter</filter-name> <!-- 过滤所有 --> <url-pattern>/*</url-pattern> </filter-mapping>
- 分析
-
该类负责解析隐藏的HttpMethod, 用了该Filter后, 可以在页面上POST时指定 _method参数, 该Filter会根据参数指定的值将Request包装为指定的HttpMethod的request.
-
- 代码
- rest.jsp
<!-- 测试Get --> <a href="testREST/1001">测试GET</a> <!-- 测试POST --> <form action="testREST" method="post"> <input type="submit" value="测试POST"> </form> <!-- 测试PUT --> <form action="testREST" method="post"> <input type="hidden" name="_method" value="PUT"> <input type="submit" value="测试PUT"> </form> <!-- 测试DELETE --> <form action="testREST" method="post"> <input type="hidden" name="_method" value="DELETE"> <input type="submit" value="测试DELETE"> </form>
- RESTController.java
@Controller public class TestController { @GetMapping("/testREST/{id}") public String getUserById(@PathVariable("id") Integer id) { System.out.println(id); return "success"; } @PostMapping("/testREST") public String insertUser() { return "success"; } @PutMapping("/testREST") public String updateUser() { return "success"; } @DeleteMapping("/testREST/{id}") public String deleteUserById(@PathVariable("id")Integer id) { System.out.println(id); return "success"; } }
-
但直接这么写, PUT和DELETE会报错, 因为发起的请求是个RESTFul风格的请求, 调用了RESTFul风格的PUT方法, 但是controller里testRestPUT返回的success字符串被映射到success.jsp, 因此spring认为这应该是个JSP接口, 且JSP接口仅仅支持GET方法和POST方法.
-
- 解决方法:
- @ResponseBody, 在两个负责处理Delete请求和put请求的controller头部添加.
- 但只能显示出return的值, 无法转发.
@ResponseBody @PutMapping("/testREST") public String updateUser() { return "success"; }
- 但只能显示出return的值, 无法转发.
- 使用Redirect重定向
@DeleteMapping("/testREST/{id}") public String deleteUserById(@PathVariable("id")Integer id) { System.out.println(id); return "redirect:/tosuccess"; } @GetMapping("/tosuccess") public String toSuccess() { return "success"; }
- @ResponseBody, 在两个负责处理Delete请求和put请求的controller头部添加.
- rest.jsp
处理请求数据
- 请求数据
- 请求参数, Cookie信息, 请求头信息等.
- 在JavaWeb中, HttpServletRequest
-
Request.getParameter(参数名); Request.getParameterMap();
-
Request.getCookies(); Request.getHeader();
-
-
请求处理方法签名
-
SpringMVC通过分析处理方法的签名(方法名+参数列表), Http请求信息绑定到处理方法的相应形参中.
-
SpringMVC对控制器处理方法签名的限制是很宽松的, 几乎可以按喜欢的任何方式对方法进行签名.
-
可对方法及其参数标注相应注解(@PathVariable, @RequestParam, @RequestHeader等)
-
SpringMVC框架会将Http请求的信息绑定到相应的方法入参中, 并根据方法的返回值类型做出相应的后续处理.
-
@RequestParam注解
-
在处理方法入参处使用@RequestParam可以把请求参数传递给请求方法
-
在请求处理的方法中, 加入相对应的形参, 保证形参参数名和传递数据的参数名保持一致, 就可以自动赋值.
-
- 参数
-
value: 当不满足赋值条件时, 可以使用value属性, 指定映射关系.
-
required: 设置形参是否必须被赋值, 默认为true, 必须赋值, 否则报错. 若设置为false, 则不必赋值.
-
defaultValue: 若形参所获得的值为null, 则设置一个默认值, 用在分页和模糊查询等.
-
- 示例
- param.jsp
<form action="param" method="post"> username: <input type="text" name="name"> <br/> password: <input type="password" name="password"> <br/> </form>
- TestController.java
@PostMapping("/param") public String param(@RequestParam(value = "name", required = false, defaultValue = "admin")String username, String password) { System.out.println(username); System.out.println(password); return "success"; }
- param.jsp
- @RequestHeader和CookieValue
- @RequestHeader
-
在处理请求的方法上, 获取请求头信息, 用法和@RequestParam一致.
@PostMapping("/param") public String param(@RequestHeader("Accept-Language")String lan) { System.out.println(lan); return "success"; }
-
- @CookieValue
- 在处理请求方法上, 获取cookie信息, 用法和@RequestParam一致.
@PostMapping("/param") public String param(@CookieValue("JSESSIONID")String JESSIONID) { System.out.println(JESSIONID); return "success"; }
- 在处理请求方法上, 获取cookie信息, 用法和@RequestParam一致.
- 使用POJO作为参数对象
-
可以使用POJO获取客户端数据, 要求实体类对象中的属性名一定要和页面中表单元素的name属性值一致, 且支持级联关系.
- 示例
- Address.java
@NoArgsConstructor @AllArgsConstructor @Data public class Address { private String province; private String city; private String country; }
- param.jsp
<form action="param" method="post"> province: <input type="text" name="province"> <br/> city: <input type="text" name="city"> <br/> country: <input type="text" name="country"/> <input type="submit" value="添加"> </form>
- TestController.java
@PostMapping("/param") public String param(Address address) { System.out.println(address); return "success"; }
- Address.java
- 使用Servlet原生API作为参数
-
MVC的Handler方法可以接受九种ServletAPI类型的参数
- HttpServletRequest
- HttpServletResponse
- HttpSession
- java.security.Principal
- Locale
- InputStream
- OutputStream
- Reader
- Writer
@Autowired private HttpServletRequest request; @PostMapping("/param") public String param() { request.getParameter("country"); return "success"; }
- 记得一定要加servlet依赖
<dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency>
处理响应数据
- JavaWeb中
- request.setAttribute(xxx)
- request.getRequestDispatcher("地址").forward(req, resp)
-
SpringMVC输出模型数据概述
-
两种输出模型数据
-
ModelAndView: 处理方法返回值类型为ModelAndView时, 方法体即可通过该对象添加模型数据.
-
Map或Model, 入参为org.springframework.ui.Model, org.springframework.ui.ModelMap 或 java.uti.Map时, 处理方法返回时, Map中的数据会自动添加到模型中.
-
- ModelAndView
- 介绍
-
控制器处理方法的返回值如果为ModelAndView, 则其既包含视图信息, 也包含模型数据信息.
-
两个重要的成员变量
- private Object view 视图信息
- private ModelMap model 模型数据
- 添加模型数据
-
MoelAndView addObject(String attributeName, Object attributeValue) 往request作用域中放值
-
ModelAndView addAllObject(Map<String, ?> modelMap)
-
- 设置视图
-
void setView(View view) 设置视图对象
-
void setViewName(String viewName) 设置视图名称
-
-
获取模型数据
-
protected Map<String, Object> getModelInternal()
-
public ModelMap getModelMap()
-
-
- 示例
- Controller方法
@PostMapping("/param") public ModelAndView param() { ModelAndView mav = new ModelAndView(); mav.addObject("useranme", "root"); //往request域中放值 mav.setViewName("success"); return mav; }
- success.jsp
<body> SUCCESS ${requestScope.username} </body>
- Controller方法
- Map和Model
- Map介绍
-
SpringMVC 在内部使用了一个org.springframework.ui.Model接口存储模型数据具体使用步骤.
-
SpringMVC 在调用方法前会创建一个隐含的模型对象作为模型数据的存储容器.
-
如果方法的入参为 Map 或 Model 类型, SpringMVC会将隐含模型的引用传递给这些入参.
-
在方法体内, 开发者可以通过这个入参对象访问到模型中的所有数据,也可以向模型中添加新的属性数据.
-
- 代码
@PostMapping("/param") public String param(Map<String, Object> map) { map.put("username", "admin"); return "success"; } @PostMapping("/param1") public String param1(Model model) { model.addAttribute("username", "张三"); return "success"; }