SpringMVC面试题

一、什么是SpringMvc?

Spring MVC(Model-View-Controller)是 Spring 框架的一部分,它是一个基于 Java 的框架,用于构建 Web 应用程序。Spring MVC 提供了一种强大且灵活的方式来开发 Web 应用,它遵循了 MVC 设计模式,将应用程序的业务逻辑、视图和用户输入分离开来,从而使应用程序更易于管理和扩展。

Spring MVC 的核心概念

  1. 模型(Model)

    • 职责:代表应用程序的数据和业务逻辑。
    • 组成:通常包括 Java 对象(POJO)、数据访问层(DAO)和服务层(Service)。
    • 功能:处理业务逻辑和数据访问,与视图层分离。
  2. 视图(View)

    • 职责:负责呈现数据给用户。
    • 组成:视图可以是 JSP(JavaServer Pages)、Thymeleaf、FreeMarker 等模板引擎。
    • 功能:展示模型数据,将用户界面与业务逻辑分开。
  3. 控制器(Controller)

    • 职责:处理用户请求,调用相应的业务逻辑,选择视图来呈现结果。
    • 组成:Spring MVC 中的控制器通常是使用 @Controller 注解的类中的方法。
    • 功能:接收用户请求,调用业务层进行处理,返回模型数据和视图名称。

二、说说SpringMVC的优点?

Spring MVC 作为一个基于 Java 的 Web 框架,具有多种优点,使得它在开发 Web 应用程序时非常受欢迎。以下是 Spring MVC 的主要优点(1,2,3,8一定要答出来):

1. 清晰的分层架构

  • MVC 模式:Spring MVC 实现了 Model-View-Controller(模型-视图-控制器)设计模式,将业务逻辑、视图和用户输入分离,提升了应用的可维护性和扩展性。
  • 松耦合:通过将控制器、模型和视图分离,减少了各层之间的耦合,使得应用程序更容易理解和修改。

2. 灵活性

  • 多视图技术支持:Spring MVC 支持多种视图技术,如 JSP、Thymeleaf、FreeMarker、Velocity 等,开发者可以根据需求选择合适的视图技术。
  • 多种请求处理方式:支持多种请求处理方式,包括传统的基于注解的方式(如 @RequestMapping@GetMapping)和更灵活的配置方式。

3. 强大的数据绑定

  • 表单数据绑定:Spring MVC 提供了强大的数据绑定功能,可以将 HTTP 请求中的参数直接绑定到 Java 对象属性中,简化了表单处理。
  • 数据验证:通过 JSR-303/JSR-380(如 Hibernate Validator)实现数据验证,能够自动校验用户输入的合法性,并提供自定义错误信息。

4. 支持 RESTful 风格

  • RESTful API:Spring MVC 支持创建 RESTful 风格的 Web 服务,提供了 @RestController 和 @RequestMapping 等注解,简化了 RESTful API 的开发。

5. 强大的支持和集成

  • 集成 Spring 生态系统:与 Spring 框架的其他组件(如 Spring Security、Spring Data、Spring Boot)无缝集成,能够利用整个 Spring 生态系统的功能。
  • 支持异步处理:支持异步请求处理,通过 @Async 注解和 Spring WebFlux 等组件处理异步任务,提高应用性能和响应速度。

6. 高度可配置

  • 灵活的配置:支持 XML 配置、注解配置以及 Java 配置等多种方式,开发者可以根据项目需求选择最合适的配置方式。
  • 自定义处理器和拦截器:允许开发者自定义处理器、拦截器和异常处理器,以满足特定的需求。

7. 丰富的开发工具

  • 集成开发环境(IDE)支持:支持主流的 IDE(如 IntelliJ IDEA、Eclipse)中的 Spring 插件,提供了丰富的开发和调试工具。
  • 自动化测试:支持自动化测试,能够与 JUnit 和其他测试框架集成,简化测试过程。

8. 高性能和可扩展性

  • 缓存支持:可以通过 Spring 的缓存抽象来提升性能,减少数据库查询和计算开销。
  • 扩展性:提供了丰富的扩展点,允许开发者根据需求扩展和定制框架的功能。

9. 社区支持和文档

  • 广泛的社区支持:Spring MVC 拥有一个活跃的开源社区,提供了大量的文档、教程和示例代码,帮助开发者解决问题。
  • 丰富的文档:官方文档详细且易于理解,为开发者提供了全面的参考资料。

三、说说SpringMVC的原理/工作流程?

1)用户发送请求至前端控制器DispatcherServlet。

2)DispatcherServlet 收到请求调用 HandlerMapping 处理器映射器。

3)处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象 及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。

4)DispatcherServlet 调用 HandlerAdapter 处理器适配器。

5)HandlerAdapter 经过适配调用具体的处理器(Controller,也叫后端控制器)。

6)Controller 执行完成返回ModelAndView。

7)HandlerAdapter 将 controller 执行结果 ModelAndView 返回给 DispatcherServlet。

8)DispatcherServlet 将 ModelAndView 传给 ViewReslover 视图解析器。

9)ViewReslover 解析后返回具体View。

10)DispatcherServlet 根据 View 进行渲染视图(即将模型数据填充至视图中)。

11)DispatcherServlet 响应用户。

四、SpringMvc 的控制器是不是单例模式,如果是,有什么问题,怎么解决

是的,Spring MVC 的控制器默认是单例模式。这意味着在整个应用程序生命周期内,Spring 容器只会创建一个控制器实例,并且这个实例会被多个线程共享和使用。这种单例模式可以提高性能,因为控制器的实例化和销毁操作只发生一次。

1.单例模式带来的问题

  1. 线程安全问题:由于单例控制器实例会被多个线程并发访问,如果控制器中包含了非线程安全的成员变量,那么可能会导致线程安全问题。例如,如果控制器中有一个普通字段,它会被所有线程共享,这可能导致数据不一致或竞争条件。

    @Controller
    public class MyController {
        private int counter = 0; // 非线程安全的字段
    
        @RequestMapping("/increment")
        public String increment() {
            counter++; // 多线程下可能导致数据不一致
            return "counterValue";
        }
    }
    
  2. 状态管理:由于控制器是单例的,如果控制器持有状态(如上例中的 counter 变量),这些状态会被所有请求共享,这可能导致意想不到的行为。

2.解决方法

  1. 避免在控制器中使用可变状态

    • 尽量避免在控制器中定义可变的成员变量。如果需要状态,请将状态保存在方法的局部变量中,或者使用线程安全的方式处理。
    @Controller
    public class MyController {
    
        @RequestMapping("/increment")
        public String increment() {
            int counter = 0; // 方法局部变量,不会被共享
            counter++;
            return "counterValue";
        }
    }
    
  2. 使用线程安全的数据结构

    • 如果确实需要在控制器中使用共享状态,请使用线程安全的数据结构,如 ConcurrentHashMapAtomicInteger 等。
    @Controller
    public class MyController {
        private AtomicInteger counter = new AtomicInteger(0); // 线程安全的计数器
    
        @RequestMapping("/increment")
        public String increment() {
            counter.incrementAndGet(); // 线程安全操作
            return "counterValue";
        }
    }
    
  3. 使用 @Scope("prototype") 注解

    • 如果控制器需要使用非线程安全的成员变量,可以将控制器的作用域从默认的单例(singleton)改为原型(prototype),这样每次请求都会创建一个新的控制器实例。不过这种方式会影响性能,因为每次请求都会创建新的实例。
    @Controller
    @Scope("prototype")
    public class MyController {
        private int counter = 0; // 非线程安全的字段,但每次请求都有自己的实例
    
        @RequestMapping("/increment")
        public String increment() {
            counter++;
            return "counterValue";
        }
    }

五、SpringMVC用什么对象向前台传送数据?

实际上有多个可以向前台传送数据的对象,如果只让答出一个,答ModelMap

1. Model 和 ModelMap

Model 和 ModelMap 是 Spring MVC 提供的两个接口,用于在控制器中传递数据到视图层。它们的使用方式相似,都是通过将数据添加到模型中,然后由视图层进行渲染。

@Controller
public class MyController {

    @RequestMapping("/welcome")
    public String welcome(Model model) {
        model.addAttribute("message", "Welcome to Spring MVC!");
        return "welcomeView"; // 视图名称
    }
}

@Controller
public class MyController {

    @RequestMapping("/welcome")
    public String welcome(ModelMap modelMap) {
        modelMap.addAttribute("message", "Welcome to Spring MVC!");
        return "welcomeView"; // 视图名称
    }
}

2. ModelAndView

ModelAndView 是一个组合对象,既包含模型数据又包含视图名称。通过 ModelAndView,可以同时设置模型数据和视图信息。

@Controller
public class MyController {

    @RequestMapping("/welcome")
    public ModelAndView welcome() {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("welcomeView"); // 视图名称
        modelAndView.addObject("message", "Welcome to Spring MVC!"); // 模型数据
        return modelAndView;
    }
}

3. Map

Spring MVC 允许使用 Map 作为参数来传递数据到视图层。Map 的用法类似于 Model 和 ModelMap,但更加通用。

@Controller
public class MyController {

    @RequestMapping("/welcome")
    public String welcome(Map<String, Object> map) {
        map.put("message", "Welcome to Spring MVC!");
        return "welcomeView"; // 视图名称
    }
}

4. @ModelAttribute

@ModelAttribute 注解用于绑定请求参数到方法参数或将方法返回值添加到模型中。可以用在方法参数上,也可以用在方法上。

@Controller
public class MyController {

    @RequestMapping("/welcome")
    public String welcome(@ModelAttribute("message") String message) {
        return "welcomeView"; // 视图名称
    }

    @ModelAttribute("message")
    public String addMessage() {
        return "Welcome to Spring MVC!";
    }
}

5. @SessionAttributes 和 @RequestAttributes

@SessionAttributes 用于将模型中的属性放入 HttpSession 中,这样它们在多个请求之间可以保持。

@Controller
@SessionAttributes("user")
public class MyController {

    @RequestMapping("/user")
    public String user(Model model) {
        model.addAttribute("user", new User("John", "Doe"));
        return "userView";
    }
}

@RequestAttributes 则是将属性存储在当前请求中,可以在后续的处理过程中使用。

@Controller
public class MyController {

    @RequestMapping("/request")
    public String request(HttpServletRequest request) {
        request.setAttribute("message", "This is a request attribute");
        return "requestView";
    }
}

6. RedirectAttributes

用于重定向时传递参数,特别适合在 Post-Redirect-Get 模式下使用。

@Controller
public class MyController {

    @PostMapping("/submit")
    public String submit(RedirectAttributes redirectAttributes) {
        redirectAttributes.addFlashAttribute("message", "Submission successful!");
        return "redirect:/result";
    }
}

六、SpringMVC中过滤器与拦截器的区别

1. 拦截器是基于java的反射机制,而过滤器是基于函数回调的。

2. 过滤器Filter是在请求进入容器后,但在进入servlet之前进行预处理,请求结束是在servlet处理完以后。

拦截器 Interceptor 是在请求进入servlet后,在进入Controller之前进行预处理的,Controller 中渲染了对应的视图之后请求结束。

3.因为拦截器更接近业务系统,所以拦截器主要用来实现项目中的业务判断的,比如:登录判断、权限判断、日志记录等业务。

过滤器通常是用来实现通用功能过滤的,比如:敏感词过滤、字符集编码设置、响应数据压缩等功能。

  • 17
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值