• 【SpringMVC】提问问题汇总


    (1)什么是Spring MVC ?对springMVC的理解?

    Spring MVC是一个基于Java的实现了MVC设计模式的请求驱动类型的轻量级Web框架,通过把Model,View,Controller分离,将web层进行职责解耦,把复杂的web应用分成逻辑清晰的几部分,简化开发,减少出错,方便组内开发人员之间的配合。

    (2)SpringMVC的流程?

    (1)用户发送请求至前端控制器DispatcherServlet;
    (2)DispatcherServlet收到请求后,调用HandlerMapping处理器映射器,请求获取Handler;
    (3)处理器映射器根据请求url找到具体的处理器Handler,生成处理器对象及处理器拦截器(如果有则生成),一并返回给DispatcherServlet;
    (4)DispatcherServlet 调用 HandlerAdapter处理器适配器,请求执行Handler;
    (5)HandlerAdapter 经过适配调用 具体处理器进行处理业务逻辑;
    (6)Handler执行完成返回ModelAndView;
    (7)HandlerAdapter将Handler执行结果ModelAndView返回给DispatcherServlet;
    (8)DispatcherServlet将ModelAndView传给ViewResolver视图解析器进行解析;
    (9)ViewResolver解析后返回具体View;
    (10)DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)
    (11)DispatcherServlet响应用户。

    在这里插入图片描述

    (3)Springmvc的重要组件

    (1)前端控制器 DispatcherServlet:接收请求、响应结果,相当于转发器,有了DispatcherServlet 就减少了其它组件之间的耦合度。其作用是接收用户请求,然后给用户反馈结果。它的作用相当于一个转发器或中央处理器,控制整个流程的执行,对各个组件进行统一调度,以降低组件之间的耦合性,有利于组件之间的拓展。
    (2)处理器映射器 HandlerMapping:根据请求的URL来查找Handler。其作用是根据请求的URL路径,通过注解或者XML配置,寻找匹配的处理器信息。
    (3)处理器适配器 HandlerAdapter:负责执行Handler。其作用是根据映射器处理器找到的处理器信息,按照特定规则执行相关的处理器(Handler)。
    (4)处理器 Handler:处理器,需要程序员开发。其作用是执行相关的请求处理逻辑,并返回相应的数据和视图信息,将其封装至ModelAndView对象中。
    (5)视图解析器 ViewResolver:进行视图的解析,根据视图逻辑名将ModelAndView解析成真正的视图(view)。其作用是进行解析操作,通过ModelAndView对象中的View信息将逻辑视图名解析成真正的视图View(如通过一个JSP路径返回一个真正的JSP页面)。
    (6)视图View:View是一个接口, 它的实现类支持不同的视图类型,如jsp,freemarker,pdf等等

    (3)Springmvc的优点(设计模式)

    (1)可以支持各种视图技术,而不仅仅局限于JSP;
    (2)与Spring框架集成(如IoC容器、AOP等);
    (3)清晰的角色分配:前端控制器(dispatcherServlet) ,请求到处理器映射(handlerMapping),处理器适配器(HandlerAdapter),视图解析器(ViewResolver)。
    (4) 支持各种请求资源的映射策略。

    (4)SpringMVC怎么样设定重定向和转发的?

    (1)转发:在返回值前面加"forward:“,譬如"forward:user.do?name=method4”

    @RequestParam("/login")
    public String redirect(User user){
        if{
            //登录成功...
        }else{
            //登录失败,转发到登录页面
            return "forward:tologin";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    (2)重定向:在返回值前面加"redirect:“,譬如"redirect:http://www.baidu.com”
    例如我们在登录的时候,登录失败会重定向到登录页面。

    @RequestParam("/login")
    public String redirect(User user){
        if{
            //登录成功...
        }else{
            //登录失败,重定向到登录页面
            return "redirect:tologin";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    (5)SpringMVC常用的注解有哪些?

    (1)@RequestMapping:用于处理请求 url 映射的注解,可用于类或方法上。用于类上,则表示类中的所有响应请求的方法都是以该地址作为父路径。
    返回值会通过视图解析器解析为实际的物理视图,对于 InternalResourceViewResolver 视图解析器,通过 prefix + returnValue + suffix 这样的方式得到实际的物理视图,然后做转发操作。

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    bean>
    
    • 1
    • 2
    • 3
    • 4

    RequestMapping注解有六个属性

    value:
    指定请求的实际地址,指定的地址可以是URI Template 模式(后面将会说明);
    method:
    指定请求的method类型, GET、POST、PUT、DELETE等;
    consumes:
    指定处理请求的提交内容类型(Content-Type),例如application/json, text/html;
    produces:
    指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回;
    params:
    指定request中必须包含某些参数值是,才让该方法处理。
    headers:
    指定request中必须包含某些指定的header值,才能让该方法处理请求。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    (2)@RequestBody:注解实现接收http请求的json数据,将json转换为java对象。

    (3)@ResponseBody:注解实现将conreoller方法返回对象转化为json对象响应给客户。
    作用:该注解用于将Controller的方法返回的对象,通过适当的HttpMessageConverter转换为指定格式后,写入到Response对象的body数据区。
    使用时机:返回的数据不是html标签的页面,而是其他某种格式的数据时(如json、xml等)使用;

    (6)@PathVariable和@RequestParam的区别?

    (1)@PathVariable:
    1-@PathVariable用于接收uri地址传过来的参数,Url中可以通过一个或多个{Xxx}占位符映射,通过@PathVariable可以绑定占位符参数到方法参数中,在RestFul接口风格中经常使用。
    2-例如:请求URL:http://localhost/user/21/张三/query
    (Long类型可以根据需求改变为String或int,SpringMVC会自动做转换)

    @RequestMapping("/user/{userId}/{userName}/query")
    public User query(@PathVariable("userId") Long userId, @PathVariable("userName") String userName){
    
    }
    
    • 1
    • 2
    • 3
    • 4

    (2)@RequestParam
    @RequestParam用于将请求参数映射到控制器方法的形参上,有如下三个属性
    1-value:参数名。
    2-required:是否必需,默认为true,表示请求参数中必须包含该参数,如果不包含抛出异常。
    3-defaultValue:默认参数值,如果设置了该值自动将required设置为false,如果参数中没有包含该参数则使用默认值。
    示例:@RequestParam(value = “pageNum”, required = false, defaultValue = “1”)

    (6)SpingMvc中的控制器的注解一般用哪个?有没有别的注解可以替代?

    答:一般用@Controller注解,也可以使用@RestController,@RestController注解相当于@ResponseBody + @Controller,表示是表现层,除此之外,一般不用别的注解代替。

    在Spring MVC 中,控制器Controller 负责处理由DispatcherServlet 分发的请求,它把用户请求的数据经过业务处理层处理之后封装成一个Model ,然后再把该Model 返回给对应的View 进行展示。在Spring MVC 中提供了一个非常简便的定义Controller 的方法,你无需继承特定的类或实现特定的接口,只需使用@Controller 标记一个类是Controller ,然后使用@RequestMapping 和@RequestParam 等一些注解用以定义URL 请求和Controller 方法之间的映射,这样的Controller 就能被外界访问到。此外Controller 不会直接依赖于HttpServletRequest 和HttpServletResponse 等HttpServlet 对象,它们可以通过Controller 的方法参数灵活的获取到。

    @Controller 用于标记在一个类上,使用它标记的类就是一个Spring MVC Controller 对象。分发处理器将会扫描使用了该注解的类的方法,并检测该方法是否使用了@RequestMapping 注解。@Controller 只是定义了一个控制器类,而使用@RequestMapping 注解的方法才是真正处理请求的处理器。单单使用@Controller 标记在一个类上还不能真正意义上的说它就是Spring MVC 的一个控制器类,因为这个时候Spring 还不认识它。那么要如何做Spring 才能认识它呢?这个时候就需要我们把这个控制器类交给Spring 来管理。有两种方式:

    在Spring MVC 的配置文件中定义MyController 的bean 对象。
    在Spring MVC 的配置文件中告诉Spring 该到哪里去找标记为@Controller 的Controller 控制器。
    
    • 1
    • 2

    (7)如何解决POST请求中文乱码问题,GET的又如何处理呢?

    (1)解决post请求乱码问题:在web.xml中配置一个CharacterEncodingFilter过滤器,设置成utf-8;

    <filter>
        <filter-name>CharacterEncodingFilterfilter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
        <init-param>
            <param-name>encodingparam-name>
            <param-value>utf-8param-value>
        init-param>
    filter>
     
    <filter-mapping>
        <filter-name>CharacterEncodingFilterfilter-name>
        <url-pattern>/*url-pattern>
    filter-mapping>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    (2)get请求中文参数出现乱码解决方法有两个:
    ①修改tomcat配置文件添加编码与工程编码一致,如下:

    
    
    • 1

    ②另外一种方法对参数进行重新编码:

    String userName = new String(request.getParamter("userName").getBytes("ISO8859-1"),"utf-8")
    
    • 1

    ISO8859-1是tomcat默认编码,需要将tomcat编码后的内容按utf-8编码。

    (8)SpringMvc里面拦截器是怎么写的

    有两种写法,一种是实现HandlerInterceptor接口,另外一种是继承适配器HandlerInterceptor接口的类,接着在接口方法当中,实现处理逻辑;然后在SpringMvc的配置文件中配置拦截器即可:

    
    <mvc:interceptors>
        
        <bean id="myInterceptor" class="com.zwp.action.MyHandlerInterceptor">bean>
     
        
        <mvc:interceptor>
           <mvc:mapping path="/modelMap.do" />
           <bean class="com.zwp.action.MyHandlerInterceptorAdapter" />
        mvc:interceptor>
    mvc:interceptors>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    自定义拦截器

    public class LoginInterceptor implements HandlerInterceptor {
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {}
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    HandlerInterceptor接口中定义了三个方法,我们就是通过这三个方法来对用户的请求进行拦截处理的。
    (1)preHandle(): 这个方法在Controller处理请求之前被调用,SpringMVC中的Interceptor是链式的调用的,在一个应用中或者说是在一个请求中可以同时存在多个Interceptor 。每个Interceptor的调用会依据它的声明顺序依次执行,而且最先执行的都是Interceptor 中的preHandle方法,所以可以在这个方法中进行一些前置初始化操作或者是对当前请求的一个预处理,也可以在这个方法中进行一些判断来决定请求是否要继续进行下去。该方法的返回值是布尔值Boolean 类型的,当它返回为false 时,表示请求结束,后续的Interceptor和Controller都不会再执行;当返回值为true时就会继续调用下一个Interceptor的preHandle 方法,如果已经是最后一个Interceptor的时候就会是调用当前请求的Controller方法。
    (2)postHandle():这个方法在Controller方法处理当前请求之后执行,但是它会在DispatcherServlet进行视图返回渲染之前被调用,所以我们可以在这个方法中对Controller处理之后的ModelAndView对象进行操作。postHandle方法被调用的方向跟preHandle 是相反的,也就是说先声明的Interceptor的postHandle方法反而会后执行。
    (3)afterCompletion():这个方法也是需要当前对应的Interceptor的preHandle方法的返回值为true时才会执行。顾名思义,该方法将在整个请求结束之后,也就是在DispatcherServlet渲染了对应的视图之后执行。这个方法的主要作用是用于进行资源清理工作的。

    单个拦截器执行流程图
    在这里插入图片描述多个拦截器执行流程图
    在这里插入图片描述

    (9)SpringMvc中函数的返回值是什么?

    返回值可以有很多类型,有String,ModelAndView。ModelAndView类把视图和数据都合并的一起的,但一般用String比较好。

    (1)ModelAndView
    我们在使用SpringMVC的时候,经常返回ModelAndView类型,现在前后端分离后,后端都是返回JSON格式数据为主。
    返回 ModelAndView类型,我们可以在ModelAndView对象中指定视图名称,然后也可以绑定数据,如下面代码:

    @RequestMapping("/userList")
    public ModelAndView getAllUser(ModelAndView mv) {
        List<User> users= userService.getAllUser();
        //添加数据模型到request域中
        mv.addObject("users", users);
        mv.setViewName("userList");//指定视图名
        return mv;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    (2)void
    如果返回值为void的话,并不是真正没有返回值,而是会出现以下几种情况:
    1-如果方法内真的没有返回值,那么SpringMVC默认把deleteUser(映射的URL)当成视图名称来解析,如果存在该视图,就返回给客户端;如果不存在该视图,就会报视图找不到异常。

    @RequestMapping("/deleteUser")
    public void deleteUser() {
    	//删除操作
    }
    
    • 1
    • 2
    • 3
    • 4

    通过加@ResponseBody来修改默认行为,加上该注解表示返回JSON数据,这里返回空JSON数据,而不是把URL当成视图名称来解析

    @RequestMapping("/deleteUser")
    @ResponseBody
    public void deleteUser() {
    	//删除操作
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    (3)String
    当方法的返回值为String的时候,也会出现下面几种情况:
    1-逻辑视图名:返回String最常见的是逻辑视图名,这种时候一般利用默认的参数Model来传递数据

    @RequestMapping("/deleteUser")
    //方法返回JSON数据
    @ResponseBody	
    public String deleteUser(Model model) {
    	model.addAttribute("msg","删除成功");
    	return "userList";
    } 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2-重定向:登录失败的时候重定向到登录页面。

    @RequestParam("/login")
    public String redirect(User user){
        if{
            //登录成功...
        }else{
            //登录失败,重定向到登录页面
            return "redirect:tologin";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    3-请求转发:登录失败的时候请求转发到登录页面。

    @RequestParam("/login")
    public String redirect(User user){
        if{
            //登录成功...
        }else{
            //登录失败,转发到登录页面
            return "forward:tologin";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    4-真的返回String,相当于JSON格式的数据

    @RequestMapping("/deleteUser")
    @ResponseBody
    public String deleteUser() {
    	try{
    		//删除成功
    		return "删除成功";
    	}catch(Exception e){
    		return "删除失败";
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    (4)JSON
    现在前后端分离的情况下,大部分后端只需要返回JSON数据即可,List 集合、Map集合,实体类等都可以返回,这些数据由 HttpMessageConverter自动转为JSON ,如果使用了Jackson或者Gson,不需要额外配置就可以自动返回JSON了,因为框架帮我们提供了对应的HttpMessageConverter ,如果使用了Alibaba的Fastjson的话,则需要自己手动提供一个相应的 HttpMessageConverter的实例,方法的返回值如下面代码:

    @GetMapping("/getUser")
    @ResponseBody
    public User getUser() {
        User user = userService.getUser();
        return user;
    }
    @RequestMapping("/userList")
    @ResponseBody
    public List<User> getAllUser() {
        List<User> users = userService.getAllUser();
        return users;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    (10)SpringMvc用什么对象从后台向前台传递数据的?

    (1)使用Map、Model和ModelMap的方式,这种方式存储的数据是在request域中

    @RequestMapping("/getUser")
    public String getUser(Map<String,Object> map,Model model,ModelMap modelMap){
        //1.放在map里  
        map.put("name", "xq");
        //2.放在model里,一般是使用这个
        model.addAttribute("habbit", "Play");
        //3.放在modelMap中 
        modelMap.addAttribute("city", "gd");
        modelMap.put("gender", "male");
        return "userDetail";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    (2)使用request的方式

    @RequestMapping("/getUser")
    public String getUser(Map<String,Object> map,Model model,ModelMap modelMap,HttpServletRequest request){
        //放在request里  
        request.setAttribute("user", userService.getUser());
        return "userDetail";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    (3)使用ModelAndView

    @RequestMapping("/getUser")  
    public ModelAndView getUser(ModelAndView modelAndView) {
        mav.addObject("user", userService.getUser());  
        mav.setViewName("userDetail");  
        return modelAndView;  
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    (11)SpringMvc注解原理

    注解本质是一个继承了Annotation的特殊接口,其具体实现类是Java运行时生成的动态代理类。我们通过反射获取注解时,返回的是Java运行时生成的动态代理对象。通过代理对象调用自定义注解的方法,会最终调用AnnotationInvocationHandler的invoke方法。该方法会从memberValues这个Map中索引出对应的值。而memberValues的来源是Java常量池。

  • 相关阅读:
    数据仓库dws层,DWS层搭建--商品主题宽表,md,review第1遍,220622,
    办公自动化杂志办公自动化杂志社办公自动化编辑部2022年第16期目录
    springboot项目中使用minio进行对象存储
    JVM面试核心点
    实际经历学来的管理知识(1)
    nn.GRU和nn.GRUCell区别
    两两交换链表中的节点
    图解八道经典指针笔试题
    定期360评估系统优于年度绩效考核
    【JavaEE初阶】 TCP服务器与客户端的搭建
  • 原文地址:https://blog.csdn.net/weixin_44823875/article/details/127980462