SpringMVC框架整理
Posted Nothing_doit
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringMVC框架整理相关的知识,希望对你有一定的参考价值。
博客主要对SpringMVC框架的知识点进行整理,该篇介绍了SpringMVC的HelloWorld环境搭建,常用注解的使用,Ant路径风格,RestFul编程风格,最后使用SpringMVC实现一个RestFul编程风格的CRUD。
MVC概述
Model(模型)-View(视图)-Controller(控制器) Model(模型): 业务模型:业务流程和业务逻辑 数据模型:页面显示的数据.数据库保存的数据对应的javaBean View(视图):和用户直接交互的页面、程序界面 Controller(控制器):调度器控制整个网站的转发逻辑SringMVC概述
SpringMVC是基于MVC理念的表现层框架,是目前最主流的MVC框架。 Spring MVC 通过一套 MVC 注解,让 POJO 成为处理请求的控制器,而无须实现任何接口。 支持 REST 风格的 URL 请求 采用了松散耦合可插拔组件结构,比其他 MVC 框架更具扩展性和灵活性SpringMVC运行流程
SpringMVC的运行逻辑:
①客户端请求提交到DispatcherServlet(SpringMVC前端控制器) ②由DispatcherServlet控制器查询一个或多个HandlerMapping,找到处理请求的Controller。 根据 HandlerMapping提供的信息,再去找到能真正解析和调用业务逻辑方法的适配器。 ③DispatcherServlet将请求提交到Controller(也称为Handler),也就是使用适配器去执行目标方法 mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); ④Controller调用业务逻辑处理后,返回ModelAndView ModelAndView包含了要去向视图的信息,以及其他信息 ⑤ DispatcherServlet查询一个或多个ViewResoler视图解析器,找到ModelAndView指定的视图 ViewResoler进行视图解析,调用render.解析出去哪个页面 ⑥视图负责将结果显示到客户端,渲染 RequestDispatcher rd rd.forward(requestToExpose, response); 总结:请求到达-->找到能够执行目标方法的适配器--->执行目标方法--->返回视图信息以及数据信息(MV)--->根据返回信息渲染视图--->展示视图HelloWorld环境搭建
①导入jar包 Spring基础包 com.springsource.net.sf.cglib-2.2.0.jar com.springsource.org.aopalliance-1.0.0.jar com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar commons-logging-1.1.3.jar spring-aop-4.0.0.RELEASE.jar spring-aspects-4.0.0.RELEASE.jar spring-beans-4.0.0.RELEASE.jar spring-context-4.0.0.RELEASE.jar spring-core-4.0.0.RELEASE.jar spring-expression-4.0.0.RELEASE.jar
SpringMVC需要的包 spring-web-4.0.0.RELEASE.jar spring-webmvc-4.0.0.RELEASE.jar
②在web.xml中配置前端控制器 <!--SpringMVC的前端控制器,它是一个真实的Servlet继承于HttpServlet 因此配置和Servlet配置基本一致 --> <!-- The front controller of this Spring Web application, responsible for handling all application requests --> <servlet> <servlet-name>springDispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <!--这个location写SpringMVC配置文件的--> <param-value>location</param-value> </init-param> <!--这个是启动的优先级,数值越小,优先级越高--> <load-on-startup>1</load-on-startup> </servlet> <!--配置拦截那些请求--> <!-- Map all requests to the DispatcherServlet for handling --> <servlet-mapping> <servlet-name>springDispatcherServlet</servlet-name> <!--这里配置成/,可以拦截所有请求同时又覆盖了DefaultServlet的配置,这样所有的请求都由我们的前端控制器拦截 同时也体现了RestFul风格编程 --> <url-pattern>/</url-pattern> </servlet-mapping> ③创建springmvc配置文件,并将配置文件的地址写到location src目录下新建
配置location(classpath表示在类路径下) <param-value>classpath:springmvc.xml</param-value> 这样基础的环境就搭建好了。
④编写一个简单的请求响应流程,测试运行环境 ①index.jsp(请求/hello) <h1 align="center"><a href="$pageContext.request.contextPath /hello">Hello</a></h1> ②编写一个handle处理这个请求 package com.springmvc.handle;
import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; //基于注解注入,需要加入相关注解 @Controller public class MyHandle //映射请求地址 @RequestMapping(" /hello ") public String hello() System.out.println("接收到请求"); return "success"; ③配置SpringMVC框架,让框架帮忙处理请求(springmvc.xml) <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!-- 开启包的自动扫描,将加了controller注解的handle类注入 --> < context:component-scan base-package="com.springmvc.handle"></context:component-scan> <!-- 配置视图解析器,用于渲染mv --> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 给返回地址配置一个前缀 --> <property name="prefix" value="/"></property> <!-- 配置一个后缀 --> <property name="suffix" value=".jsp"></property> <!--/success.jsp(前缀+返回结果+后缀共同构成转发地址)--> </bean>
</beans> ④编写响应页面success.jsp <h1>HelloWorld运行环境配置成功</h1> ⑤运行测试
@RequestMapping
① 在类上标注,表示该类中的所有handle方法都以这个映射地址开始。 相对于 WEB 应用的根目录 ② 在方法上标注,若类上没有@RequestMapping,直接表示请求地址,若类上有,类上映射+方法上映射共同构成请求地址。 相对于标记在类上的URL作用:DispatcherServlet 截获请求后,就通过控制器上@RequestMapping 提供的映射信息确定请求所对应的处理方法。 属性: value:设置请求地址,在类上标注和在方法上标注/表示的含义不同 method:设置某个方法处理什么样的请求,method是个数组表示可以处理多个符合要求的请求。默认可以处理任意请求 params:设置请求参数(可以设置多个请求参数)(支持简单的表达式) 当配置了params时,必须在请求的时候传入配置的参数,不匹配或者不传都会报错404 当设置多个请求参数的时候必须都设置,否则报错404 结论:params设置的请求参数必须精确匹配,否则报错 params = !user 表示请求参数不能设置为user,其他的都可以 params = user!=1 表示请求参数值不能等于1
含有params的代码: /** * 这个请求地址中必须有password,user可以有可以没有,但是若有user的值不能是1,不能有username * 还可以有其他请求 * @return */ @RequestMapping(value="/test5", params="user!=1", "password", "!username") public String test5() System.out.println("接受到请求"); return "success"; headers设置请求头 发送请求的请求头必须包含headers中的内容,不同的浏览器请求头不同,可以用于区分不同的浏览器 /** * headers (设置只有某一浏览器可以访问) * @return */ @RequestMapping(value="/testheader", headers="User-Agent=Mozilla/5.0 (Windows NT 10.0; WOW64; rv:49.0) Gecko/20100101 Firefox/49.0") public String test6() System.out.println("接受到请求"); return "success";
设置@RequestMapping的条件后,在发送请求的时候,必须满足上边的所有规则,否则报错,什么也不写表示默认规则。
return String 转发地址,在springmvc配置文件中配置的视图解析器还会对这个地址进行包装
Ant路径风格
? : 表示匹配任意一个字符 * : 表示匹配任意零个或者多个字符 ** : 表示多层模糊匹配 (要使用**多层模糊匹配要把这两个**包起来)(这样就可以在具体路径之前写多层嵌套路径) 匹配原则:当都是模糊匹配的时候,先精确再模糊,先范围大的再范围小的示例: Ant路径:/user/*/createUser: 匹配/user/aaa/createUser、/user/bbb/createUser等URL /user/**/createUser: 匹配 /user/createUser、/user/aaa/bbb/createUser 等 URL /user/createUser??: 匹配 /user/createUseraa、/user/createUserbb 等 URL
import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping;
@Controller public class AntUrlPathHandle /** * ant路径风格 * ?:表示匹配任意一个字符 * *:表示匹配任意零个或者多个字符 * **:表示多层模糊匹配 (要使用**多层模糊匹配要把这两个**包起来) * * 当都是模糊匹配的时候,先精确在模糊,先范围大的再范围小的 * @return */ @RequestMapping(value="/??ervice") public String test2() System.out.println("接收到请求地址是模糊匹配?的请求"); return "success"; @RequestMapping(value="/*ervice") public String test3() System.out.println("接收到请求地址是模糊匹配*的请求"); return "success"; @RequestMapping(value="/*/*ervice") public String test5() System.out.println("接收到请求地址是模糊匹配一层*的请求"); return "success"; @RequestMapping(value="/**/ervice") public String test4() System.out.println("接收到请求地址是模糊匹配**多层模糊的请求"); return "success";
RestFul编程风格
简介: REST:即 Representational State Transfer。 (资源)表现层状态转化。是目前最流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用 资源(Resources):网络上的一个实体,或者说是网络上的一个具体信息。它可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的存在。可以用一个URI(统一资源定位符)指向它, 每种资源对应一个特定的 URI。要获取这个资源,访问它的URI就可以, 因此 URI 即为每一个资源的独一无二的识别符。 表现层(Representation):把资源具体呈现出来的形式,叫做它的表现层(Representation)。比如,文本可以用 txt 格式表现,也可以用 html 格式、XML 格式、JSON 格式表现,甚至可以采用二进制格式。 状态转化(State Transfer):每发出一个请求,就代表了客户端和服务器的一次交互过程。HTTP协议,是一个无状态协议,即所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务器端发生“状态转化”(State Transfer)。而这种转化是建立在表现层之上的,所以就是 “表现层状态转化”。 具体说,就是 HTTP 协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。它们分别对应四种基本操作:GET 用来获取资源,POST 用来新建资源,PUT 用来更新资源,DELETE 用来删除资源。原生web项目的订单处理的路径 /order/delete?id=1 /order/update?id=1 /order/save /order/get?id=1 RestFul编程风格 order/1 GET 查询1号订单 order/1 DELETE 删除1号订单 order/1 PUT 更新1号订单 order POST 保存一个订单 每一个路径orderHandle只能占一层路径,而且必须有
RestFul本质就是充分利用Http协议中定义了很多请求方式。有了这个支持。地址还是不变。不同的请求方式就代表当前资源不同的状态转化(删除?修改?保存?....)数据都放在请求体中,不放在地址栏后
@PathVariable 映射 URL 绑定的占位符 带占位符的 URL 是 Spring3.0 新增的功能,该功能在 SpringMVC 向 REST 目标挺进发展过程中具有里程碑的意义 通过@PathVariable 可以将 URL中占位符参数绑定到控制器处理方法的入参中:URL 中的 xxx 占位符可以通过 @PathVariable("xxx") 绑定到操作方法的入参中。
这样在@RequestMapping配置的映射地址设置占位符,同时使用@PathVariable注解可以获取到
HiddenHttpMethodFilter:浏览器 form 表单只支持 GET 与 POST 请求,而DELETE、PUT 等 method 并不支持, Spring3.0 添加了一个过滤器,可以将这些请求转换为标准的 http 方法,使得支持 GET、POST、PUT 与 DELETE 请求。 原生的jsp页面无法发送DELETE请求和PUT请求,要想发送需要在web.xml中进行配置 <!-- 配置配置org.springframework.web.filter.HiddenHttpMethodFilter来支持页面发起restful请求 PUT、DELETE --> <filter> <filter-name>HiddenHttpMethodFilter</filter-name> <filter-class>org.springframework.web.filter. HiddenHttpMethodFilter </filter-class> </filter> <filter-mapping> <filter-name>HiddenHttpMethodFilter</filter-name> <servlet-name>springDispatcherServlet</servlet-name> </filter-mapping>
写一个简易的RestFul风格的程序 orderManage.jsp <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <h1>订单管理</h1> <!-- get请求获取订单 --> <a href="/myspringmvc01 /order/1">获取一个订单</a> <br> <!-- post请求添加订单 --> <form action="/myspringmvc01/order" method="post" > <input type="submit" value="新增一个订单"> </form> <br> <!-- PUT请求修改订单 --> <form action="/myspringmvc01/order/1" method="post" > <input type="hidden" name="_method" value="PUT" > <input type="submit" value="修改一个订单"> </form> <br> <!-- DELETE请求删除订单 --> <form action="/myspringmvc01/order/1" method="post" > <input type="hidden" name="_method" value="DELETE" > <input type="submit" value="删除一个订单"> </form> </body> </html>
处理请求的handle方法 import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod;
@Controller public class RestFulPathHandle /** * 订单处理 * order 1 GET 获取订单号为1的订单 * order 1 DELETE 删除订单号为1的订单 * order 1 PUT 更新订单号为1的订单 * order POST 新增订单 * RestFul 利用Http协议中的多种请求方式实现状态转换 * 通过判断提交的请求类型来选择执行不同的处理请求的方法 * 路径,请求参数只能表示一层路径,必须得有 * 利用@PathVariable注解从url中获取值给参数赋值 */ @RequestMapping(value="/order/ id",method=RequestMethod.GET) public String getOrder(@PathVariable(" id")String id) System.out.println("获取订单号为" + id + "的订单"); return "success"; @RequestMapping( value="/order" ,method=RequestMethod.POST) public String saveOrder() System.out.println("新增一个订单"); return "success"; @RequestMapping( value="/order/id" ,method=RequestMethod.PUT) public String updateOrder(@PathVariable( "id" )String id) System.out.println("更新订单号为" + id + "的订单"); return "success"; @RequestMapping( value="/order/id" ,method=RequestMethod.DELETE) public String deleteOrder(@PathVariable( "id" )String id) System.out.println("删除订单号为" + id + "的订单"); return "success";
请求数据传入(请求方法签名处理)
Spring MVC 通过分析处理方法的签名,将 HTTP 请求信息绑定到处理方法的相应人参中。 Spring MVC 对控制器处理方法签名的限制是很宽松的,几乎可以按喜欢的任何方式对方法进行签名。 必要时可以对方法及方法入参标注相应的注解( @PathVariable 、@RequestParam、@RequestHeader 等)、Spring MVC 框架会将 HTTP 请求的信息绑定到相应的方法入参中,并根据方法的返回值类型做出相应的后续处理。在原生web中获取请求参数值的时候 例如: 请求参数:username=admin 其中username相当于请求参数的键,admin相当于请求参数的值 我们在servlet中获取的时候是,request.getParameter("username")拿到admin 在SpringMVC中类似并且更为简单 获取请求参数的方式 ①直接在方法的参数列表处,声明一个(保存请求参数值的)参数(入参) 若不使用@RequestParam注解,参数名就是请求参数的键(相当于getParameter("键")),key=参数名 在发送请求的时候,不传入任何值,或者键不匹配,key(参数名)=null(value=null) 键匹配不传值,值为空串。 可以传入多个键值对。 使用@RequestParam注解(使用注解匹配,注解的value值是键)可以传入多个键值对 属性: value 默认空串(设置键) required 默认true (就是必须传参数与这个键匹配的键值对,不传,或者不匹配都会400) defaultValue 默认没有,用于设置默认值(键的默认值) 设置默认值后,required=false,可以不传这个键值对 当获取多个请求参数键值对,SpringMVC框架可以自动匹配,赋值 注:当不使用注解,参数名就是键,SpringMVC根据参数名获取到对应的值并赋值给这个参数 使用注解,注解的value值是键,根据键获取对应的值,赋值给这个参数 不使用@RequestParam @RequestMapping(value="/testparam") public String testParam(String username) //这样就可以拿到传入的username的值 System.out.println("username=" + username); return "success";
使用@RequestParam @RequestMapping(value="/testrequestparam") public String testParam2(@RequestParam(value="user",defaultValue="default")String username, String password) System.out.println("username=" + username); System.out.println("password=" + password); return "success";
②还可以使用@PathVariable,@RequestHeader,@CookieValue对入参进行修饰 请求头包含了若干个属性,服务器可据此获知客户端的信息,通过 @RequestHeader 即可将请求头中的属性值绑定到处理方法的入参中
@RequestHeader修饰入参(将请求头中的某些值和入参进行绑定) /** * 入参与请求头中的键值对(任意的)进行绑定 * @RequestHeader value=key(将入参(参数列表处设置的参数)和请求头中key对应的值绑定) * 这些注解的属性和@RequestParam注解属性一致,含义一致 */ @RequestMapping(value="/testheader") public String testHeader(@RequestHeader(value="User-Agent")String agent) System.out.println("Agent=" + agent); return "success"; @RequestMapping(value="/testheader2") public String testHeader2(@RequestHeader(value="Accept-Language")String language) System.out.println("Accept-Language=" + language); return "success";
@CookieValue修饰入参(将Cookie值与入参进行绑定) /** * 使用@RequestHeader获取Cookie,在第一次请求的时候会报500错,因为第一次请求时没有Cookie * Missing header 'Cookie' of type [java.lang.String]找不见Cookie * 获取Cookie使用@CookieValue注解获取(设置defaultValue=""就不会出现500错),Cookie值为空串 * 还可以获取JSESSIONID * @param cookie * @return */ @RequestMapping(value="/testcookie") public String testCookie(@CookieValue(value="Cookie", defaultValue="")String cookie) System.out.println("Cookie=" + cookie); return "success"; @RequestMapping(value="/testcookie2") public String testCookie2(@CookieValue(value="JSESSIONID",defaultValue="")String JSESSIONID) System.out.println("JSESSIONID=" + JSESSIONID); return "success"; 使用 POJO 对象绑定请求参数值 使用表单提交数据,Spring MVC 会按请求参数名和 POJO 属性名进行自动匹配,自动为该对象填充属性值。支持级联属性。
测试: POJO类 Employee类 public class Employee
private Integer id; private String name; private Integer age; private Address address; public Employee() super(); public Employee(Integer id, String name, Integer age, Address address) super(); this.id = id; this.name = name; this.age = age; this.address = address; public Integer getId() return id; public void setId(Integer id) this.id = id; public String getName() return name; public void setName(String name) this.name = name; public Integer getAge() return age; public void setAge(Integer age) this.age = age; public Address getAddress() return address; public void setAddress(Address address) this.address = address; @Override public String toString() return "Employee [id=" + id + ", name=" + name + ", age=" + age + ", address=" + address + "]";
Address public class Address private String city; private String street; public Address() super(); public Address(String city, String street) super(); this.city = city; this.street = street; public String getCity() return city; public void setCity(String city) this.city = city; public String getStreet() return street; public void setStreet(String street) this.street = street; @Override public String toString() return "Address [city=" + city + ", street=" + street + "]"; 表单: <form action="/myspringmvc02/testpojo" method="post"> name<input type="text" name="name"><br> age<input type="text" name="age"><br> address.city<input type="text" name="address.city"><br> address.street<input type="text" name="address.street"><br> <input type="submit" value="提交"> </form> 处理请求的方法: /** * SpringMVC框架也可以自动处理POJO(JavaBean对象) * 只需要让表单的属性和POJO属性一一对象,然后在方法参数列表设置一个对象引用保存这个对象, * 入参设置为一个对象SpringMVC框架在处理这个方法的时候会帮你自动封装,级联属性也可以自动封装 * * 根据表单给的属性值,自动封装成对象 */ @RequestMapping(value="/testpojo") public String testPOJO(Employee employee) System.out.println(employee); return "success"; 解决POST中文乱码问题 乱码: 请求乱码: post请求 (原生解决方式)在服务器第一次接收到请求的时候(在filter中设置) request.setCharacterEncoding("utf-8") get请求 服务器的server.xml中设置 URIEncoding="UTF-8" (8080端口号设置的那里,大小写都行) 响应乱码: response响应的时候乱码(将数据从服务器发送到浏览器的时候乱码) response.setContentType("text/html;charset=UTF-8");
SpringMVC框架的乱码问题解决方式: get请求和原生的解决方式一致 post请求
web.xml中配置CharacterEncodingFilter <filter> <filter-name>characterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <!-- 配置编码参数 --> <init-param> <!-- 配置请求编码设置 --> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <!-- 配置响应编码设置 设置的时候根据请求编码的参数设置--> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>characterEncodingFilter</filter-name> <!-- 对所有请求和.jsp进行拦截 --> <url-pattern>/*</url-pattern> </filter-mapping>
注意: 当使用框架提供的响应方式的时候,SpringMVC自动的配置好请求和响应编码 若使用原生的响应,需要配置编码的text/html(utf-8已经帮你设置)
使用原生的ServletAPI作为入参 使用原生的ServletAPI作为入参,这些原生的东西,在想要用的时候,只需要在入参处设置即可,SpringMVC框架会给你准备好 HttpServletRequest HttpServletResponse HttpSession java.security.Principal Locale InputStream OutputStream Reader Writer /** * 响应的编码测试 * 使用SpringMVC框架的一个好处就是在想要用的时候直接声明一个变量保存就好 * 想要使用原生的api只需要在参数列表设置就行 * @param employee * @return */ @RequestMapping(value="/testpon") public void testResponse(HttpServletRequest request, HttpServletResponse response) System.out.println("使用原生的api不需要设置返回值"); System.out.println("param:" + request.getParameter("user")); try /* * 只有使用原生api,CharacterEncodingFilter会出现乱码,原因ÿ
以上是关于SpringMVC框架整理的主要内容,如果未能解决你的问题,请参考以下文章