文章目录
简介
-
Spring MVC是Spring Framework提供的Web组件,全称是Spring Web MVC,是目前主流的实现MVC设计模式的框架,提供前端路由映射、视图解析等功能。
-
SpringMVC是Spring的一个后续产品,是Spring的一个子项目
-
SpringMVC 是 Spring 为表述层开发提供的一整套完备的解决方案。在表述层框架历经 Strust、WebWork、Strust2 等诸多产品的历代更迭之后,目前业界普遍选择了 SpringMVC 作为 Java EE 项目表述层开发的首选方案。
注:三层架构分为表述层(或表示层)、业务逻辑层、数据访问层,表述层表示前台页面和后台
servlet
MVC是什么?
MVC是一种软件架构思想,把软件按照模型,视图,控制器来划分
- M(Model):模型层,指工程中的
JavaBean
,作用是处理数据- JavaBean分为两类:
实体类Bean
:专门存储业务数据的,如 Student、User 等,与数据库对应。业务处理 Bean
:指 Service 或 Dao 对象,专门用于处理业务逻辑和数据访问。
- JavaBean分为两类:
- V(View):视图层,指工程中的
html
或jsp
等页面,作用是与用户进行交互,展示数据 - C(Controller):指工程中的
servlet
,作用是接收请求和响应浏览器
优点
- 可以支持各种视图技术,而不仅仅局限于JSP;
- 与Spring框架集成(如IOC容器、AOP等)
- 清晰的角色分配:前端控制器(
dispatcherServlet
),请求到处理器映射(handlerMapping
),处理器适配器(HandlerAdapter
),视图解析器(ViewResolver
) - 支持各种请求资源的映射策略
。
工作流程
(1)首先浏览器发送请求——>DispatcherServlet: 前端控制器收到请求后自己不进行处理,而是委托给其他的解析器进行处理,作为统一访问点,进行全局的流程控制;
(2)DispatcherServlet——>HandlerMapping: 通过对应的url寻找对应的映射器将会把请求映射为HandlerExecution对象重新发给DispatcherServlet
(3)DispatcherServlet——>HandlerAdapter: HandlerExecution将会寻找到相对应的适配器,就像对应型号的插头寻找对应的接口。
(4)HandlerAdapter——>调用处理器相应功能处理方法: 并返回一个ModelAndView对象(包含模型数据、逻辑视图名);
(5)ModelAndView对象(Model部分是业务对象返回的模型数据,View部分为逻辑视图名)——> ViewResolver: 视图解析器将把逻辑视图名解析为具体的View;
(6)View——>渲染: View会根据传进来的Model模型数据进行渲染,此处的Model实际是一个Map数据结构;
(7)返回控制权给DispatcherServlet,由DispatcherServlet返回响应给用户,到此一个流程结束。
核心组件
名词 | 翻译 | 说明 |
---|---|---|
DispatcherServlet | 前端控制器 | 负责调度其他组件的执行,可以降低不同组件之间的耦合性,是整个Spring MVC的核心模块 |
HandlerMapping | 处理器映射器 | DispatcherServlet 是通过 HandlerMapping 把请求映射到不同的Handler |
Handler | 处理器 | 处理器,完成具体的业务逻辑,相当于Servlet |
HandlerInterceptor | 处理器拦截器 | 是一个接口,如果我们需要进行一些拦截处理,可以通过实现该接口完成 |
HandlerExecutionChain | 处理器执行链 | 包括两部分内容:Handler 和HandlerInterceptor (系统会有一个默认的HandlerInterceptor ,如果有额外拦截处理,可以添加拦截器进行设置) |
HandlerAdapter | 处理器适配器 | Handler 执行业务方法之前,需要进行一系列的操作包括表单的数据验证、数据类型转换、把表单数据封装到POJO 等,这些一系列的操作都是由HandlerAdapter 完成,DispatcherServlet 通过HandlerAdapter 执行不同的Handler |
ModelAndView | 模型与视图 | 封装了模型数据和视图信息,作为Handler 的处理结果,返回给DispatcherServlet |
ViewResolver | 视图解析器 | DispatcherServlet 通过它把逻辑视图解析为物理视图,最终把渲染的结果响应给客户端 |
View | 视图 | 渲染后的视图 |
Spring MVC常用注解
@RequestMapping
- Spring MVC通过
@RequestMapping
注解把URL请求和业务方法进行映射 - 在控制器的类定义处以及方法定义处都可以添加
@RequestMapping
,在类定义处添加相当于多了一层访问路径 - 参数:
value
:指定URL请求的实际地址,是@RequestMapping
的默认值method
:指定请求的method类型,包括GET、POST、PUT、DELETE等consumes
: 指定处理请求的提交内容类型(Content-Type),例如application/json, text/html;produces
: 指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回;params
: 指定request中必须包含某些参数值时,才让该方法处理。headers
: 指定request中必须包含某些指定的header值,才能让该方法处理请求。
@GetMapping
,@PutMapping
,@PostMapping
,@DeleteMapping
与@RequestMapping
用法级效果相同,但无method
参数,因为注解直接表明了请求方式
参数绑定
@RequestParam:普通GET方式传参
- 在业务方法定义时声明参数列表,给参数列表添加
@RequestParam
注解进行绑定
@RequestParam(value = "/test")
public class Test{
@GetMapping(value = "/hello")
public String hello(@RequestParam(value = "name",required=true) String name){
}
}
- 一般使用情况:
GET
、DELETE
- 访问上述接口地址为:
xxx.xxx.xxx.xxx:xxxx/test/hello?name=jack
,请求方法为:GET,参数为:name,是一个必传参数 - 可以存在多个
- 参数:
- value :参数名称
- 设置与
url
对应的参数名称并映射到方法的参数项 value
值可以与方法的参数项不同,但必须与请求的参数名称相同,否则无法映射value
值一般最好与方法中的参数项保持一致
- 设置与
- required :是否必须
- defaultValue:设置默认值后,required就会失效,当请求地址中没有对应参数时就会使用此处设置
- value :参数名称
@PathVariable:RESTful URL风格传参
传统的URL:xxx.xxx.xxx.xxx:xxxx/test/hello?name=jack
RESTful URL:xxx.xxx.xxx.xxx:xxxx/test/hello/jack
@RequestParam(value = "/test")
public class Test{
@GetMapping(value = "/hello/{name}")
public String hello(@PathVariable(value = "name",required=true) String name){
}
}
- 一般使用情况:
GET
、DELETE
- 可以存在多个
- 参数:
- value :参数名称
- 设置与
url
对应的参数名称并映射到方法的参数项 value
值可以与方法的参数项不同,但必须与请求的参数名称相同,否则无法映射value
值不可为空
- 设置与
- required :是否必须
- defaultValue:设置默认值后,required就会失效,当请求地址中没有对应参数时就会使用此处设置
- value :参数名称
@RequestBody:使用实体(对象)传参
实体:也就是对象、POJO
必须有 get
set
方法
@Data //提供get set 方法
@AllArgsConstructor //提供全参构造函数
@NoArgsConstructor //提供无参构造函数
public class Test{
private String name;
private Integer age;
private Integer sex;
}
接口示例
@RequestParam(value = "/test")
public class Test{
@PostMapping("/user")
public String userTest(@RequestBody User user){
System.out.println(user);
return "ok";
}
}
- 一般使用情况:
POST
、PUT
@RequestBody
自动解析请求体json为实体对象- 一个请求,只有一个
RequestBody
(请求体) - 可与
@RequestParam
或@PathVariable
混合使用@RequestBody
只会解析请求体
内的json
@RequestParam
或@PathVariable
还需按照原有方式进行传参,但可以是post请求
@CookieValue:映射Cookie
@RequestMapping("/cookie")
public String getCookie(@CookieValue("JSESSIONID") String sessionId){
System.out.println(sessionId);
return "index";
}
- 一般使用情况:
GET
、DELETE
、POST
、PUT
- 用来获取Cookie中的值
- 参数:
value
:参数名称Cookie
名称
required
:是否必须defaultValue
:默认值
转发和重定向
Spring MVC默认是通过转发的形式响应JSP
- 转发:在返回值前面加"
forward
:",如:“forward:user.do?name=method4
” - 重定向:在返回值前面加"
redirect
:",如:“redirect:http://www.baidu.com
”
示例:常规用法,返回一个View
@RequestMapping("/restful/{id}/{name}")
public String restful(@PathVariable("id") Integer num, @PathVariable("name") String name){
System.out.println(num+"-"+name);
//Spring框架找到对应的View并渲染
return "findex";
}
示例:转发"forward:/…"
@RequestMapping(value="/testa", method=RequestMethod.POST)
public String outputData(HttpServletRequest request){
//转发到 /testb 的Controller方法(即outputDataX)上
return "forward:/testb";
}
@RequestMapping(value="/testb", method=RequestMethod.POST)
public String outputDataX(HttpServletRequest request){
return "testb";
}
示例:重定向"redirect:/…"
@RequestMapping(value="/testa", method=RequestMethod.POST)
public String outputData(HttpServletRequest request){
//重定向到 /testb 的Controller方法(即outputDataX)上
return "redirect:/testb";
}
@RequestMapping(value="/testb", method=RequestMethod.POST)
public String outputDataX(HttpServletRequest request){
return "testb";
}
设置重定向的时候不能写逻辑视图,必须写明资源的物理路径
重定向的三种方式
response.sendRedirect重定向跳转
@RequestMapping(value="/testredirect",method = { RequestMethod.POST, RequestMethod.GET })
public String testredirect(HttpServletResponse response){
response.sendRedirect("/index");
return "ok";
}
ViewResolver直接跳转
不带参数
@RequestMapping(value="/testredirect",method = { RequestMethod.POST, RequestMethod.GET })
public String testredirect(HttpServletResponse response){
return "redirect:/index";
}
带参数
@RequestMapping("/testredirect")
public String testredirect(Model model, RedirectAttributes attr) {
//跳转地址带上test参数
attr.addAttribute("test", "51gjie");
//跳转地址不带上u2参数
attr.addFlashAttribute("u2", "51gjie");
return "redirect:/user/users";
}
- 使用
RedirectAttributes
的addAttribute
方法传递参数会跟随在URL后面,如上代码即为http:/index.action?test=51gjie
- 使用
addFlashAttribute
不会跟随在URL后面,会把该参数值暂时保存于session
,待重定向url获取该参数后从session
中移除,这里的redirect
必须是方法映射路径,jsp无效。你会发现redirect
后的jsp页面
中b
只会出现一次,刷新后b
再也不会出现了,这验证了上面说的,b
被访问后就会从session
中移除。对于重复提交可以使用此来完成 - spring mvc设置下
RequestMappingHandlerAdapter
的ignoreDefaultModelOnRedirect=true
,这样可以提高效率,避免不必要的检索。
ModelAndView重定向
不带参数
@RequestMapping(value="/restredirect",method = { RequestMethod.POST, RequestMethod.GET })
public ModelAndView restredirect(String userName){
ModelAndView model = new ModelAndView("redirect:/main/index");
return model;
}
带参数
@RequestMapping(value="/toredirect",method = { RequestMethod.POST, RequestMethod.GET })
public ModelAndView toredirect(String userName){
ModelAndView model = new ModelAndView("/main/index");
//把userName参数带入到controller的RedirectAttributes
model.addObject("userName", userName);
return model;
}
直接跳转某网页
@RequestMapping(value="/testredirect",method = { RequestMethod.POST, RequestMethod.GET })
public String testredirect(HttpServletResponse response){
HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
httpServletResponse.sendRedirect("http://srip.cpu.edu.cn/#/admins");
return "ok";
}
总结
redirect
重定向可以跳转到任意服务器,可以用在系统间的跳转。- Spring MVC中
redirect
重定向,参数传递可以直接拼接url
也可以使用RedirectAttributes
来处理,由于是不同的请求,重定向传递的参数会在地址栏显示,所以传递时要对中文编码进行处理。
拦截器
过滤器、监听器、拦截器的对比
Servlet:处理Reequest请求和Response响应
- 过滤器(Filter):
- 对
Request
请求起到过滤作用,作用在Servlet
之前, - 配置为\*可以为所有的资源(servlet、js/css静态资源等)进行过滤处理
- 对
- 监听器(Listener):
- 实现了javax.servlet.ServletContextListener接口的服务器端组件,它随Web应用的启动而启动,只初始化一次,然后一直监视,随Web应用的停止而销毁
- 作用一:做初始化工作,web应用中spring容器启动ContextLoaderListener
- 作用二:监听web中的特定事件,比如
HttpSession
,ServletRequest
的创建和销毁;变量的创建、销毁和修改等可以在某些动作前后增加处理,实现监控,比如说统计在线人数,利用HttpSessionListener
等
- 拦截器(Interceptor):
- 是Spring MVC、Struts等表现层框架自己的
- 不会拦截
jsp/html/css/image
等的访问,只会拦截访问的控制器方法(Handler
) - servlet、filter、listener是配置在web.xml中,interceptor是配置在表现层框架自己的配置文件中
- 在Handler业务逻辑执行之前拦截一次
- 在Handler逻辑执行完但是还没有跳转页面之前拦截一次
- 在跳转页面后拦截一次
拦截器基本概念
Spring MVC中的拦截器(Interceptor
)类似于Servlet
中的过滤器(Filter
),用于对处理器进行预处理和后处理。例如通过拦截器可以进行权限验证、记录请求信息的日志、判断用户是否登录等。
将拦截器按一定的顺序联结成一条链,这条链称为拦截器链(InterceptorChain)。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。拦截器也是AOP思想的具体实现。
使用Spring MVC中的拦截器的定义和配置。
通常拦截器类可以通过两种方式来定义。
1.实现HandlerInterceptor
接口
2. 继承HandlerInterceptorAdapter
抽象类
实现HandlerInterceptor接口
- 创建拦截器类实现
HandlerInterceptor
接口public class MyInterceptor1 implements HandlerInterceptor { /** * 访问controller方法之前执行 * 返回为true才会去执行Controller方法,返回false,就被拦截了,原路打回(主要做权限控制,有权限才放行) * 注意:如果preHadle返回true,但是没有找到对应的Controller,是不会执行postHandle方法哦 * @param request * @param response * @param handler * @return true:也许放行。false:不允许放行 * @throws Exception */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("preHandle.........."); String param = request.getParameter("param"); if("yes".equals(param)){ return true; }else { request.getRequestDispatcher("/error.jsp").forward(request, response); return false; } } /** * 在执行controller方法之后, * 执行jsp页面之前执行该方法,可以向作用域中放入数据,影响jsp展示效果,(可以在执行jsp之前做渲染) */ @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { modelAndView.addObject("name","NanMu"); System.out.println("postHandle.........."); } /** * 在jsp页面渲染完成之后执行(全部SpringMVC流程完结之后) * 主要用于记录日志,资源释放 */ @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { //打印 System.out.println("afterCompletion.........."); } }
- 在SpringMVC的配置文件中配置
<!--配置拦截器--> <mvc:interceptors> <mvc:interceptor> <!--/** 代表对所有路径拦截--> <mvc:mapping path="/**"/> <bean class="com.lfs.interceptor.MyInterceptor1"/> </mvc:interceptor> <mvc:interceptor> <!--/test/** 代表对第一个资源节点是test的路径拦截--> <mvc:mapping path="/test/**"/> <bean class="com.lfs.interceptor.MyInterceptor1"/> </mvc:interceptor> </mvc:interceptors>
拦截器拦截器的执行顺序
拦截器中的方法执行顺序是:preHandler
-------目标资源-------postHandle
-------afterCompletion
存在多个拦截器时,拦截器的执行顺序
所有拦截器都通过(都不拦截)执行顺序:
如果拦截器A拦截(拦截器.ApreHandle
返回false
)那么之后拦截器也不执行,直接返回
如果拦截器3拦截,那么也不执行controller方法
总结:
- 当拦截器的
preHandle
方法返回true
则会执行目标资源(Controller
),如果返回false
则不执行 - 当拦截器的
preHandle
方法返回true
则会执行postHandle
,如果返回false
则不执行 - 多个拦截器情况下,配置在前的先执行,配置在后的后执行
其他
SpringMvc和AJAX相互调用
通过Jackson框架把Java里面的对象直接转化成Js可以识别的Json对象。
(1)加入Jackson.jar
(2)在配置文件中配置json
的映射
(3)在接受Ajax方法里面可以直接返回Object
、List
等,但方法前面要加上@ResponseBody
注解。
请求中文乱码
POST请求乱码
- 在web.xml中配置一个
CharacterEncodingFilter
过滤器,设置成utf-8
<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> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
GET请求乱码
- 修改tomcat配置文件添加编码与工程编码一致
<ConnectorURIEncoding="utf-8" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>
- 对参数进行重新编码
ISO8859-1是tomcat默认编码,需要将tomcat编码后的内容按utf-8编码String userName = new String(request.getParamter("userName").getBytes("ISO8859-1"),"utf-8")