Skip to content

Spring MVC面试题

1. Spring MVC的基本概念

问题:什么是Spring MVC?

答案: Spring MVC是Spring框架中的Web MVC框架,用于开发Web应用程序。它基于Model-View-Controller设计模式,将应用程序分为模型、视图和控制器三个部分。

2. Spring MVC的核心组件

问题:Spring MVC的核心组件有哪些?

答案

  • DispatcherServlet:前端控制器,处理所有的HTTP请求。
  • HandlerMapping:将请求映射到处理器。
  • HandlerAdapter:处理请求的适配器。
  • Controller:处理请求的控制器。
  • ModelAndView:模型和视图的组合。
  • ViewResolver:视图解析器,将逻辑视图名解析为物理视图。

3. Spring MVC的请求处理流程

问题:Spring MVC的请求处理流程是什么?

答案

  1. 请求接收:DispatcherServlet接收HTTP请求。
  2. 请求映射:HandlerMapping将请求映射到处理器。
  3. 处理器适配:HandlerAdapter适配处理器。
  4. 处理器执行:处理器执行并返回ModelAndView。
  5. 视图解析:ViewResolver解析视图。
  6. 视图渲染:渲染视图并返回响应。

4. Spring MVC的注解

问题:Spring MVC中常用的注解有哪些?

答案

  • @Controller:标记一个类为控制器。
  • @RestController:标记一个类为REST控制器,返回JSON或XML响应。
  • @RequestMapping:映射请求路径。
  • @GetMapping:映射GET请求。
  • @PostMapping:映射POST请求。
  • @PutMapping:映射PUT请求。
  • @DeleteMapping:映射DELETE请求。
  • @RequestParam:获取请求参数。
  • @PathVariable:获取路径参数。
  • @RequestBody:获取请求体。
  • @ResponseBody:返回响应体。
  • @ModelAttribute:模型属性。
  • @SessionAttributes:会话属性。

5. Spring MVC的配置

问题:Spring MVC的配置方式有哪些?

答案

  • XML配置:使用XML文件配置Spring MVC。
  • Java配置:使用Java类配置Spring MVC。
  • 注解配置:使用注解配置Spring MVC。

示例

java
// Java配置
@Configuration
@EnableWebMvc
@ComponentScan("com.example.controller")
public class WebConfig implements WebMvcConfigurer {
    @Bean
    public ViewResolver viewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("/WEB-INF/views/");
        resolver.setSuffix(".jsp");
        return resolver;
    }
}

6. Spring MVC的视图解析器

问题:Spring MVC的视图解析器有哪些?

答案

  • InternalResourceViewResolver:解析JSP视图。
  • FreeMarkerViewResolver:解析FreeMarker视图。
  • ThymeleafViewResolver:解析Thymeleaf视图。
  • VelocityViewResolver:解析Velocity视图。

7. Spring MVC的异常处理

问题:Spring MVC的异常处理如何实现?

答案

  • @ExceptionHandler:处理控制器中的异常。
  • @ControllerAdvice:全局异常处理。
  • SimpleMappingExceptionResolver:通过配置映射异常。

示例

java
// 控制器中的异常处理
@Controller
public class UserController {
    @ExceptionHandler(Exception.class)
    public ModelAndView handleException(Exception e) {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("error", e.getMessage());
        modelAndView.setViewName("error");
        return modelAndView;
    }
}

// 全局异常处理
@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public Map<String, Object> handleException(Exception e) {
        Map<String, Object> result = new HashMap<>();
        result.put("error", e.getMessage());
        return result;
    }
}

8. Spring MVC的拦截器

问题:Spring MVC的拦截器如何实现?

答案

  • 实现HandlerInterceptor接口。
  • 配置拦截器。

示例

java
// 自定义拦截器
public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HttpSession session = request.getSession();
        if (session.getAttribute("user") == null) {
            response.sendRedirect("/login");
            return false;
        }
        return true;
    }
    
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // 处理请求后
    }
    
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 完成请求后
    }
}

// 配置拦截器
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor())
            .addPathPatterns("/**")
            .excludePathPatterns("/login", "/register");
    }
}

9. Spring MVC的文件上传

问题:Spring MVC的文件上传如何实现?

答案

  • 配置MultipartResolver。
  • 使用@RequestParam注解获取上传的文件。

示例

java
// 配置MultipartResolver
@Configuration
public class WebConfig {
    @Bean
    public MultipartResolver multipartResolver() {
        CommonsMultipartResolver resolver = new CommonsMultipartResolver();
        resolver.setMaxUploadSize(10485760); // 10MB
        return resolver;
    }
}

// 控制器方法
@Controller
public class UploadController {
    @PostMapping("/upload")
    public String upload(@RequestParam("file") MultipartFile file) {
        if (!file.isEmpty()) {
            try {
                byte[] bytes = file.getBytes();
                Path path = Paths.get("uploads/" + file.getOriginalFilename());
                Files.write(path, bytes);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return "redirect:/success";
    }
}

10. Spring MVC的表单处理

问题:Spring MVC的表单处理如何实现?

答案

  • 使用@ModelAttribute注解绑定表单数据。
  • 使用form:form标签生成表单。

示例

java
// 控制器方法
@Controller
public class UserController {
    @GetMapping("/register")
    public String showRegisterForm(Model model) {
        model.addAttribute("user", new User());
        return "register";
    }
    
    @PostMapping("/register")
    public String processRegister(@ModelAttribute User user) {
        // 处理注册
        return "redirect:/success";
    }
}

// JSP视图
<form:form method="post" action="/register" modelAttribute="user">
    <form:input path="name" />
    <form:input path="email" />
    <form:input path="password" type="password" />
    <input type="submit" value="Register" />
</form:form>

11. Spring MVC的RESTful API

问题:Spring MVC如何实现RESTful API?

答案

  • 使用@RestController注解。
  • 使用@RequestMapping、@GetMapping、@PostMapping等注解映射请求。
  • 使用@PathVariable获取路径参数。
  • 使用@RequestBody获取请求体。
  • 使用@ResponseBody返回响应体。

示例

java
@RestController
@RequestMapping("/api/users")
public class UserController {
    @Autowired
    private UserService userService;
    
    @GetMapping
    public List<User> getUsers() {
        return userService.findAll();
    }
    
    @GetMapping("/{id}")
    public User getUserById(@PathVariable int id) {
        return userService.findById(id);
    }
    
    @PostMapping
    public User createUser(@RequestBody User user) {
        return userService.save(user);
    }
    
    @PutMapping("/{id}")
    public User updateUser(@PathVariable int id, @RequestBody User user) {
        user.setId(id);
        return userService.update(user);
    }
    
    @DeleteMapping("/{id}")
    public void deleteUser(@PathVariable int id) {
        userService.delete(id);
    }
}

12. Spring MVC的会话管理

问题:Spring MVC的会话管理如何实现?

答案

  • 使用HttpSession。
  • 使用@SessionAttributes注解。

示例

java
// 使用HttpSession
@Controller
public class UserController {
    @PostMapping("/login")
    public String login(HttpServletRequest request, @RequestParam String username, @RequestParam String password) {
        // 验证用户
        User user = userService.findByUsernameAndPassword(username, password);
        if (user != null) {
            HttpSession session = request.getSession();
            session.setAttribute("user", user);
            return "redirect:/home";
        } else {
            return "redirect:/login?error";
        }
    }
}

// 使用@SessionAttributes
@Controller
@SessionAttributes("user")
public class UserController {
    @GetMapping("/profile")
    public String showProfile(Model model) {
        // user已经在会话中
        return "profile";
    }
    
    @PostMapping("/updateProfile")
    public String updateProfile(@ModelAttribute("user") User user) {
        userService.update(user);
        return "redirect:/profile";
    }
}

13. Spring MVC的国际化

问题:Spring MVC的国际化如何实现?

答案

  • 配置MessageSource。
  • 使用spring:message标签或MessageSource获取消息。
  • 配置LocaleResolver。

示例

java
// 配置MessageSource
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Bean
    public MessageSource messageSource() {
        ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
        messageSource.setBasename("messages");
        messageSource.setDefaultEncoding("UTF-8");
        return messageSource;
    }
    
    @Bean
    public LocaleResolver localeResolver() {
        CookieLocaleResolver resolver = new CookieLocaleResolver();
        resolver.setDefaultLocale(Locale.ENGLISH);
        return resolver;
    }
    
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        LocaleChangeInterceptor interceptor = new LocaleChangeInterceptor();
        interceptor.setParamName("lang");
        registry.addInterceptor(interceptor);
    }
}

// JSP视图
<spring:message code="greeting" />

// 控制器中使用
@Autowired
private MessageSource messageSource;

public String getGreeting(Locale locale) {
    return messageSource.getMessage("greeting", null, locale);
}

14. Spring MVC的数据验证

问题:Spring MVC的数据验证如何实现?

答案

  • 使用JSR-303/JSR-349注解。
  • 使用@Valid注解。
  • 处理BindingResult。

示例

java
// 实体类
public class User {
    @NotNull
    @Size(min = 2, max = 30)
    private String name;
    
    @NotNull
    @Email
    private String email;
    
    @NotNull
    @Size(min = 6)
    private String password;
    
    // getters and setters
}

// 控制器方法
@Controller
public class UserController {
    @PostMapping("/register")
    public String processRegister(@Valid @ModelAttribute User user, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            return "register";
        }
        // 处理注册
        return "redirect:/success";
    }
}

// JSP视图
<form:form method="post" action="/register" modelAttribute="user">
    <form:input path="name" />
    <form:errors path="name" />
    <form:input path="email" />
    <form:errors path="email" />
    <form:input path="password" type="password" />
    <form:errors path="password" />
    <input type="submit" value="Register" />
</form:form>

15. Spring MVC的异步处理

问题:Spring MVC的异步处理如何实现?

答案

  • 使用DeferredResult。
  • 使用Callable。
  • 使用WebAsyncTask。

示例

java
// 使用DeferredResult
@Controller
public class AsyncController {
    @GetMapping("/async")
    public DeferredResult<String> async() {
        DeferredResult<String> result = new DeferredResult<>();
        
        // 异步处理
        CompletableFuture.runAsync(() -> {
            try {
                Thread.sleep(1000);
                result.setResult("Async result");
            } catch (InterruptedException e) {
                result.setErrorResult(e);
            }
        });
        
        return result;
    }
    
    // 使用Callable
    @GetMapping("/callable")
    public Callable<String> callable() {
        return () -> {
            Thread.sleep(1000);
            return "Callable result";
        };
    }
}