Hello,今天给各位童鞋们分享的是Spring MVC,赶紧拿出小本子记下来吧
Spring MVC 简单概述:
Model1:早期 Java Web 的开发中,统一把显示层、控制层、数据层的操作全部交给 JSP 或者 JavaBean 来进行处理
JSP 和 Java Bean 之间严重耦合,Java 代码和 HTML 代码也耦合在了一起
要求开发者不仅要掌握 Java ,还要有高超的前端水平
前端和后端相互依赖,前端需要等待后端完成,后端也依赖前端完成,才能进行有效的测试
代码难以复用
Model2 时代 :学过 Servlet 并做过相关 Demo 的朋友应该了解“Java Bean(Model)+ JSP(View,)+Servlet(Controller) ”这种开发模式,这就是早期的 JavaWeb MVC 开发模式。Model:系统涉及的数据,也就是 dao 和 bean。View:展示模型中的数据,只是用来展示。Controller:处理用户请求都发送给 ,返回数据给 JSP 并展示给用户。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WLYBiv8k-1624972406397)(./Java工程.assets/model2.png)]
Model2 模式下还存在很多问题,Model2的抽象和封装程度还远远不够,使用Model2进行开发时不可避免地会重复造轮子,这就大大降低了程序的可维护性和复用性。于是很多JavaWeb开发相关的 MVC 框架应运而生比如Struts2,但是 Struts2 比较笨重。随着 Spring 轻量级开发框架的流行,Spring 生态圈出现了 Spring MVC 框架, Spring MVC 是当前最优秀的 MVC 框架。相比于 Struts2 , Spring MVC 使用更加简单和方便,开发效率更高,并且 Spring MVC 运行速度更快。
MVC 是一种设计模式,Spring MVC 是一款很优秀的 MVC 框架。Spring MVC 可以帮助我们进行更简洁的Web层的开发,并且它天生与 Spring 框架集成。Spring MVC 下我们一般把后端项目分为 Service层(处理业务)、Dao层(数据库操作)、Entity层(实体类)、Controller层(控制层,返回数据给前台页面)。
流程说明(重要):
客户端(浏览器)发送请求,直接请求到 DispatcherServlet。
DispatcherServlet 根据请求信息调用 HandlerMapping,解析请求对应的 Handler。
解析到对应的 Handler(也就是我们平常说的 Controller 控制器)后,开始由 HandlerAdapter 适配器处理。
HandlerAdapter 会根据 Handler来调用真正的处理器来处理请求,并处理相应的业务逻辑。
处理器处理完业务后,会返回一个 ModelAndView 对象,Model 是返回的数据对象,View 是个逻辑上的 View。
ViewResolver 会根据逻辑 View 查找实际的 View。
DispaterServlet 把返回的 Model 传给 View(视图渲染)。
把 View 返回给请求者(浏览器)
1、什么是SpringMVC?
SpringMVC是一种基于 Java 的实现MVC设计模型的请求驱动类型的轻量级Web框架,属于Spring框架的一个模块。
它通过一套注解,让一个简单的Java类成为处理请求的控制器,而无须实现任何接口。同时它还支持RESTful编程风格的请求。
2、什么是MVC模式?
MVC的全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,是一种软件设计典范。它是用一种业务逻辑、数据与界面显示分离的方法来组织代码,将众多的业务逻辑聚集到一个部件里面,在需要改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑,达到减少编码的时间。
V即View视图是指用户看到并与之交互的界面。比如由html元素组成的网页界面,或者软件的客户端界面。MVC的好处之一在于它能为应用程序处理很多不同的视图。在视图中其实没有真正的处理发生,它只是作为一种输出数据并允许用户操纵的方式。
M即model模型是指模型表示业务规则。在MVC的三个部件中,模型拥有最多的处理任务。被模型返回的数据是中立的,模型与数据格式无关,这样一个模型能为多个视图提供数据,由于应用于模型的代码只需写一次就可以被多个视图重用,所以减少了代码的重复性。
C即controller控制器是指控制器接受用户的输入并调用模型和视图去完成用户的需求,控制器本身不输出任何东西和做任何处理。它只是接收请求并决定调用哪个模型构件去处理请求,然后再确定用哪个视图来显示返回的数据。
3、SpringMVC的执行流程?
用户点击某个请求路径,发起一个request请求,此请求会被前端控制器处理。
前端控制器请求处理器映射器去查找Handler。可以依据注解或者XML配置去查找。
处理器映射器根据配置找到相应的Handler(可能包含若干个Interceptor拦截器),返回给前端控制器。
前端控制器请求处理器适配器去执行相应的Handler处理器(常称为Controller)。
处理器适配器执行Handler处理器。
Handler处理器执行完毕之后会返回给处理器适配器一个ModelAndView对象(SpringMVC底层对象,包括Model数据模型和View视图信息)。
处理器适配器接收到Handler处理器返回的ModelAndView后,将其返回给前端控制器。
前端控制器接收到ModelAndView后,会请求视图解析器(ViewResolver)对视图进行解析。
视图解析器根据View信息匹配到相应的视图结果,反馈给前端控制器。
前端控制器收到View具体视图后,进行视图渲染,将Model中的模型数据填充到View视图中的request域,生成最终的视图(View)。
前端控制器向用户返回请求结果。
4、SpringMVC有哪些优点?
SpringMVC本身是与Spring框架结合而成的,它同时拥有Spring的优点(例如依赖注入DI和切面编程AOP等)。
SpringMVC提供强大的约定大于配置的契约式编程支持,即提供一种软件设计方式,减少软件开发人员做决定的次数,开发人员仅需规定应用中不符合约定的部分。
支持灵活的URL到页面控制器的映射。
可以方便地与其他视图技术(JSP、FreeMarker等)进行整合。由于SpringMVC的模型数据往往是放置在Map数据结构中的,因此其可以很方便地被其他框架引用。
拥有十分简洁的异常处理机制。
可以十分灵活地实现数据验证、格式化和数据绑定机制,可以使用任意对象进行数据绑定操作。
支持RestFul风格。
5、Spring MVC的主要组件?
前端控制器 DispatcherServlet:
其作用是接收用户请求,然后给用户反馈结果。它的作用相当于一个转发器或中央处理器,控制整个流程的执行,对各个组件进行统一调度,以降低组件之间的耦合性,有利于组件之间的拓展。——处理所有的HTTP请求和响应。
处理器映射器 HandlerMapping:
其作用是根据请求的URL路径,通过注解或者XML配置,寻找匹配的处理器信息。
处理器适配器 HandlerAdapter:
其作用是根据映射器处理器找到的处理器信息,按照特定规则执行相关的处理器(Handler)。
处理器 Handler:
其作用是执行相关的请求处理逻辑,并返回相应的数据和视图信息,将其封装至ModelAndView对象中。
视图解析器 ViewResolver:
其作用是进行视图的解析操作,通过ModelAndView对象中的View信息将逻辑视图名解析成真正的视图View(如通过一个JSP路径返回一个真正的JSP页面)。
视图 View:
View是一个接口,实现类支持不同的View类型(JSP、FreeMarker、Excel等)。
6、SpringMVC和Struts2的区别有哪些?
最大的区别是Struts2相较于SpringMVC更笨重。
SpringMVC的入口是一个Servlet,也就是前端控制器(DispatcherServlet),而Struts2的入口是一个Filter (StrutsPrepareAndExecuteFilter)。
SpringMVC是基于方法开发(一个url对应一个方法),请求参数传递到方法的形参,可以设计为单例或多例(建议单例)。struts2是基于类开发,请求参数传递到类的成员属性,只能设计为多例。
SpringMVC通过参数解析器将request请求内容解析,并给方法形参赋值,将数据和视图封装成ModelAndView对象,最后又将ModelAndView中的模型数据通过reques域传输到页面。Jsp视图解析器默认使用JSTL。Struts2采用值栈存储请求和响应的数据,通过OGNL存取数据。
7、SpringMVC怎么样设定重定向和请求转发?
我们先说说请求转发与重定向的区别:
请求转发与重定向的区别:
请求转发在服务器端完成的;重定向是在客户端完成的。
请求转发的速度快;重定向速度慢。
请求转发的是同一次请求;重定向是两次不同请求。
请求转发不会执行转发后的代码;重定向会执行重定向之后的代码。
请求转发地址栏没有变化;重定向地址栏有变化。
请求转发必须是在同一台服务器下完成;重定向可以在不同的服务器下完成。
SpringMVC设定请求转发:
在返回值前面加”forward:”。
SpringMVC设定重定向:
在返回值前面加”redirect:”。例如我们在登录的时候,登录失败会重定向到登录页面。
8、当一个方法向AJAX返回特殊对象,譬如Object,List等,需要做什么处理?
在方法上加**@ResponseBody注解**,表示该方法的返回值不管是什么类型,都会返回JSON格式的数据。
把原来Controller类上的@Controller注解替换为**@RestController注解**。
@RestController = @Controller + @ResponseBody,表明该Controller类所有的方法都返回JSON格式的数据(没有加@RequestMapping注解的方法除外)。
加入@ResponseBody注解就能返回JSON格式数据的原因是:SpringMVC提供的HttpMessageConverter自动转为JSON ,
如果使用了Jackson或者Gson,不需要额外配置就可以自动返回JSON了,因为框架帮我们提供了对应的HttpMessageConverter ;
加入Jackson.jar
在配置文件中配置json的映射
在接受Ajax方法里面可以直接返回Object、List等,但方法前面要加上@ResponseBody注解。
如果使用了Alibaba的Fastjson的话,则需要自己手动提供一个相应的 HttpMessageConverter的实例。
9、SpringMVC的常用注解:
注解本质是一个继承了Annotation的特殊接口,其具体实现类是JDK动态代理生成的代理类。
我们通过反射获取注解时,返回的也是Java运行时生成的动态代理对象。
通过代理对象调用自定义注解的方法,会最终调用AnnotationInvocationHandler的invoke方法,该方法会从memberValues这个Map中查询出对应的值,而memberValues的来源是Java常量池。
1、@Controller
@Controller用于标记在一个类上,使用它标记的类就是一个SpringMVC Controller对象。处理器适配器将会扫描使用了该注解的类的方法,并检测该方法是否使用了@RequestMapping注解。@Controller 只是定义了一个控制器类,而使用@RequestMapping 注解的方法才是真正处理请求的处理器。
2、@RequsestMapping
@RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。
用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。返回值会通过视图解析器解析为实际的物理视图,对于 InternalResourceViewResolver 视图解析器,通过 prefix + returnValue + suffix 这样的方式得到实际的物理视图,然后做转发操作。
写在方法上:
@RequestMapping(“/req”) 表示不区分请求类型。
@RequestMapping(value = “/req”,method = RequestMethod.POST) 表示这是一个POST请求。
3、@ResponseBody
@ResponseBody把Java对象转化为json对象,这种方式用于Ajax异步请求,返回的不是一个页面而是JSON格式的数据。
@RequestBody:注解实现接收http请求的json数据,将json转换为java对象。
4、@Valid
标志参数被Hibernate-Validator校验框架校验。
5、@PathVariable
@PathVariable用于接收uri地址传过来的参数,Url中可以通过一个或多个{Xxx}占位符映射,通过@PathVariable可以绑定占位符参数到方法参数中,在RestFul接口风格中经常使用。
例如:请求URL:http://localhost/user/21/张三/query
(Long类型可以根据需求改变为String或int,SpringMVC会自动做转换)
6、@RequestParam
@RequestParam用于将请求参数映射到控制器方法的形参上,有如下三个属性:
7、@ControllerAdvice
@ControllerAdvice标识一个类是全局异常处理类。
8、@ExceptionHandler
@ExceptionHandler标识一个方法为全局异常处理的方法。
补充:前端向Controller传递参数的方式:
1、直接把表单的参数写在Controller相应的方法的形参中
public String addUser(String username,String password) {}
2、通过HttpServletRequest接收
public String addUser(HttpServletRequest request) {
3、通过一个bean来接收
public String addUser(UserModel user) {
4、使用**@ModelAttribute注解**获取POST请求的FORM表单数据
@RequestMapping(value=”/addUser”,method=RequestMethod.POST)
public String addUser(@ModelAttribute(“user”) UserModel user) {
5、用注解@RequestParam绑定请求参数到方法入参
当请求参数username不存在时会有异常发生,可以通过设置属性required=false解决,
例如: @RequestParam(value=“username”, required=false)
@RequestMapping(value=”/addUser”,method=RequestMethod.GET)
public String addUser(@RequestParam(“username”) String username,@RequestParam(“password”) String password) {
6、用request.getQueryString() 获取spring MVC get请求的参数,只适用get请求
10、如何解决POST请求中文乱码问题,GET的又如何处理呢?
JavaWeb乱码问题一般是客户端(浏览器)与服务器端字符集不一致产生的,如果两者字符集一致就不会出现乱码问题。
解决post请求乱码:
SpringMVC默认提供一个解决post请求乱码的过滤器,在web.xml中配置即可
解决get请求乱码:
修改tomcat配置文件添加编码与工程编码一致。
<ConnectorURIEncoding=”utf-8″ connectionTimeout=”20000″ port=”8080″ protocol=”HTTP/1.1″ redirectPort=”8443″/>
2.对请求参数进行重新编码,ISO8859-1是tomcat默认编码,需要将tomcat编码后的内容按utf-8编码。
String userName = new String(request.getParamter(“userName”).getBytes(“ISO8859-1″),”utf-8”);
11、Spring MVC的异常处理?
对于在日常的开发中,遇到的各种可预知、不可预知的异常,在SpringBoot中可以得到解决,可以通过以下3种方式处理:
1、使用@ExceptionHandler注解
前端发送请求给后端,后端处理时发生异常,可以通过三种方式通知前端:1、返回异常页面,不包含错误信息;2、返回ModelAndView,返回视图和异常信息;3、返回JSON格式数据。
缺点:不能实现全局异常处理;进行异常处理的方法必须与出错的方法在同一个Controller里面。
2、实现HandlerExceptionResolver接口
可以实现全局的异常控制,只要在系统运行中发生异常,它都会捕获到。
实现该接口,必须重写resolveException方法,该方法就是异常处理逻辑,只能返回ModelAndView 对象。
3、使用@ControllerAdvice注解 + @ExceptionHandler注解
1、当代码加入了 @ControllerAdvice,则不需要必须在同一个controller中了。
2、@controlleradvice+@ExceptionHandler也可以实现全局的异常捕捉。
3、不同的类型异常由不同的异常处理方法进行处理。
SpringBoot默认不支持捕获404异常,需要添加下面两行配置才能使捕获404异常生效。
12、SpringMVC的控制器是不是单例模式,有什么问题,怎么解决?
Controller是单例模式,在多线程访问的时候可能产生线程安全问题,不要使用同步,会影响程序性能。
解决方案是在控制器里面不能编写可变状态量。
如果需要使用这些可变状态量,可以使用ThreadLocal机制解决,为每个线程单独生成一份副本,独立操作,互不影响。
13、如果在拦截请求中,想拦截get方式提交的方法,怎么配置?
可以在@RequestMapping注解里面加上method=RequestMethod.GET。
可以使用@GetMapping注解。
@GetMapping(value=”/toLogin”)
public ModelAndView toLogin(){}
14、怎样在控制器方法里面得到request或者session?
直接在控制器方法的形参中声明request,session,SpringMvc就会自动把它们注入。
15、如果想在拦截的方法里面得到从前台传入的参数,怎么得到?
直接在控制器方法的形参里面声明这个参数就可以,但名字必须和传过来的参数名称一样,否则参数映射失败。下面方法形参中的userId,就会接收从前端传来参数名称为userId的值。
16、前台传入多个参数,并且这些参数都是一个对象的属性,怎么进行参数绑定?
直接在控制器方法的形参里面声明这个参数就可以,SpringMVC就会自动会请求参数赋值到这个对象的属性中。
下面方法形参中的user用来接收从前端传来的多个参数,参数名称需要和User实体类属性名称一致。
Demo项目中前端带参查询:
Controller:
Service:
ServiceImpl:
Mapper:–【命名参数】:明确指定封装参数——@Param注解
Mapper.xml:
SpringMVC中的参数绑定
SpringMVC默认支持的绑定类型有:
HttpServletReequest对象:通过request对象可以获取参数信息
HttpservletResponse对象:通过response对象可以处理响应信息
HTTPSession对象:获取session中存储的对象
Model/ModelMap:Model是一个接口,ModelMap是一个接口的实现。作用是将模型数据填充到request域。
在参数绑定过程中,如果遇到上面类型就直接进行绑定。也就是说,我们可以在controller的方法的形参中直接定义上面这些类型的参数,springmvc会自动绑定。这里要说明一下的就是Model/ModelMap对象,Model是一个接口,ModelMap是一个接口实现 ,作用是将Model数据填充到request域,跟ModelAndView类似。
TODO:集合类型的绑定等着再看
17、SpringMVC中函数的返回值是什么?
SpringMVC四种返回值类型总结
1、ModelAndView
在SpringMVC中,经常返回ModelAndView类型;前后端分离后,后端以返回JSON格式为主。
ModelAndView类型可以指定视图名称,也可以绑定数据
2、void
1、方法内没有返回值,SpringMVC会默认把该名称当做视图名称解析。存在该视图就返回,不存在就报异常。
还可以通过加上@ResponseBody注解,返回空的JSON数据。
2、请求转发
3、实现重定向
3、String
1、“userList”——返回String最常见的是返回一个逻辑视图名,这时候一般利用默认的参数Model传递数据。
2、“redirect:tologin”——重定向:登录失败时重定向到登录页面。
3、“forward:tologin”——请求转发:登录失败时请求转发到登录页面。
4、“你真棒!”——真的返回String,相当于JSON格式的数据。
4、JSON
现在前后端分离的情况下,大部分后端只需要返回JSON数据即可,List 集合、Map集合,实体类等都可以返回,这些数据由 HttpMessageConverter自动转为JSON ,如果使用了Jackson或者Gson,不需要额外配置就可以自动返回JSON了,因为框架帮我们提供了对应的HttpMessageConverter ,如果使用了Alibaba的Fastjson的话,则需要自己手动提供一个相应的 HttpMessageConverter 的实例。
18、SpringMVC用什么对象从后台向前台传递数据的?
1、使用Map、Model和ModelMap的方式,这种方式存储的数据是在request域中
2、使用request的方式
3、使用ModelAndView
19、SpringMVC中有个类把视图和数据都合并的一起的,叫什么?
就是ModelAndView。
使用ModelAndView类存储处理完后的结果数据,以及显示该数据的视图。从名字上看ModelAndView中的Model代表模型,View代表视图,从名字看就很好地解释了该类的作用。Controller处理器调用模型层处理完用户请求后,把结果数据存储在该类的model属性中,把要返回的视图信息存储在该类的view属性中,然后把ModelAndView返回给前端控制器。前端控制器通过调用配置文件中定义的视图解析器,对该对象进行解析,最后把结果数据显示在指定的页面上。
返回指定页面
ModelAndView构造方法可以指定返回的页面名称。
也可以通过setViewName()方法跳转到指定的页面 。
返回所需数值
使用addObject()设置需要返回的值,addObject()有几个不同参数的方法,可以默认和指定返回对象的名字。
20、怎么样把ModelMap里面的数据放入session里面?
在类上添加@SessionAttributes注解将指定的Model数据存储到session中。
@SessionAttributes
默认情况下Spring MVC将模型中的数据存储到request域中。当一个请求结束后,数据就失效了。
如果要跨页面使用,那么需要使用到session。而**@SessionAttributes注解就可以使得模型中的数据存储一份到session域中。**
@SessionAttributes只能定义在Class,interface enum上,作用是将指定的Model中的键值对添加至session中,方便在一个会话中使用。
@SessionAttributes参数:
names:这是一个字符串数组。里面应写需要存储到session中数据的名称。
types:根据指定参数的类型,将模型中对应类型的参数存储到session中。
value:其实和上面的names是一样的。
在上面代码中,在类上添加@SessionAttributes注解,并指定将names名称的Model数据存储到session域中,以及将Integer类型的Model数据存储到session域中。
21.SpringMVC里面拦截器是怎么写的?
可以使用SpringMVC拦截器进行认证和授权操作,应用场景有:登录认证拦截器(商城),字符过滤拦截器,日志操作拦截器等等。
SpringMVC拦截器的实现一般有两种方式:
自定义的Interceptor类要实现了Spring的HandlerInterceptor接口。
继承实现了HandlerInterceptor接口的类,比如Spring已经提供的实现了HandlerInterceptor接口的抽象类HandlerInterceptorAdapter。
HandlerInterceptor接口中定义了三个方法,我们就是通过这三个方法来对用户的请求进行拦截处理的。
preHandle():
这个方法在Controller处理请求之前被调用,SpringMVC中的Interceptor是链式的调用的,在一个应用中或者说是在一个请求中可以同时存在多个Interceptor 。每个Interceptor的调用会依据它的声明顺序依次执行,而且最先执行的都是Interceptor 中的preHandle方法,所以可以在这个方法中进行一些前置初始化操作或者是对当前请求的一个预处理,也可以在这个方法中进行一些判断来决定请求是否要继续进行下去。
该方法的返回值是布尔值Boolean 类型的,当它返回为false 时,表示请求结束,后续的Interceptor和Controller都不会再执行;当返回值为true时就会继续调用下一个Interceptor的preHandle 方法,如果已经是最后一个Interceptor的时候就会是调用当前请求的Controller方法。
postHandle():
这个方法在Controller方法处理当前请求之后执行,在DispatcherServlet进行视图返回渲染之前被调用,所以可以在这个方法中对Controller处理之后的ModelAndView对象进行操作。——多用于处理返回的视图。
postHandle方法被调用的方向跟preHandle 是相反的,也就是说先声明的Interceptor的postHandle方法反而会后执行。
afterCompletion()
这个方法也是需要当前对应的Interceptor的preHandle方法的返回值为true时才会执行。顾名思义,该方法将在整个请求结束之后,也就是在DispatcherServlet渲染了对应的视图之后执行。——适合进行一些资源清理、记
多个拦截器中方法执行规则:
可以配置多个拦截器,每个拦截器中都有三个方法。下面将总结多个拦截器中的方法执行规律。
preHandle:Controller方法处理请求前执行,根据拦截器定义的顺序,正向执行。
postHandle:Controller方法处理请求后执行,根据拦截器定义的顺序,逆向执行。需要所有的preHandle方法都返回true时才会调用。
afterCompletion:View视图渲染后处理方法:根据拦截器定义的顺序,逆向执行。preHandle返回true就会调用。
我的项目中的拦截器
然后在LoginRequired中定义注解:
具体调用:
@RequestMapping(“checkCart”)
@LoginRequired(loginSuccess = false)
//检查购物车,返回购物车的内嵌页—出一个小的页面, ajax异步+内嵌页—刷新内嵌页
public String checkCart(String isChecked, String skuId, HttpServletRequest request, HttpServletResponse response, HttpSession session, ModelMap modelMap)
好啦,今天的文章就到这里了,希望能够帮助到屏幕前迷茫的你们