Spring_MVC 高级特性详解与实战应用
一、数据绑定与表单处理
在 Web 开发中,数据绑定和表单处理是常见的需求。Spring_MVC 提供了强大的数据绑定功能,可以方便地将请求参数绑定到业务对象。
1. 使用 @ModelAttribute
绑定请求参数到对象
@ModelAttribute
注解用于将请求参数绑定到业务对象的属性上。控制器方法的参数可以是一个业务对象,Spring_MVC 会自动将请求参数绑定到该对象的属性。
@Controller
@RequestMapping("/user")
public class UserFormController {
@RequestMapping(value = "/form", method = RequestMethod.GET)
public String showForm(Model model) {
model.addAttribute("user", new User());
return "userForm";
}
@RequestMapping(value = "/submit", method = RequestMethod.POST)
public String submitForm(@ModelAttribute User user) {
System.out.println("User submitted: " + user.getName());
return "success";
}
}
showForm
方法用于显示表单页面,并向视图传递一个空的User
对象。submitForm
方法用于处理表单提交,@ModelAttribute
将请求参数绑定到User
对象。
2. 使用 @InitBinder
自定义数据绑定逻辑
对于一些特殊的类型转换需求,可以使用 @InitBinder
注解来自定义数据绑定逻辑。通过注册自定义的 PropertyEditor
或 Converter
,可以处理日期、枚举等类型的转换。
@Controller
@RequestMapping("/user")
public class CustomBindingController {
@InitBinder
public void initBinder(WebDataBinder binder) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
}
@RequestMapping(value = "/submitWithDate", method = RequestMethod.POST)
public String handleUserWithDate(@ModelAttribute User user) {
System.out.println("User birth date: " + user.getBirthDate());
return "success";
}
}
initBinder
方法用于注册自定义的日期编辑器。handleUserWithDate
方法处理带有日期字段的用户提交。
二、异常处理
在 Web 应用开发中,异常处理是保证应用稳定性和用户体验的重要环节。Spring_MVC 提供了多种异常处理机制,可以方便地处理各种异常情况。
1. 使用 @ControllerAdvice
和 @ExceptionHandler
全局处理异常
@ControllerAdvice
注解用于定义一个全局异常处理器,@ExceptionHandler
注解用于指定处理特定异常的方法。
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
public String handleResourceNotFound(ResourceNotFoundException ex, HttpServletRequest request) {
request.setAttribute("errMsg", ex.getMessage());
return "error/404";
}
@ExceptionHandler(Exception.class)
public String handleGeneralException(Exception ex, HttpServletRequest request) {
request.setAttribute("errMsg", "系统发生错误,请联系管理员");
return "error/500";
}
}
handleResourceNotFound
方法处理ResourceNotFoundException
异常,并返回 404 页面。handleGeneralException
方法处理其他异常,并返回 500 页面。
2. 使用 @ResponseStatus
指定响应状态码
@ResponseStatus
注解用于指定异常处理方法的 HTTP 响应状态码。
@ResponseStatus(value = HttpStatus.NOT_FOUND, reason = "Resource not found")
public class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException(String message) {
super(message);
}
}
- 当抛出
ResourceNotFoundException
异常时,响应状态码为 404,原因短语为 “Resource not found”。
三、文件上传与下载
文件上传和下载是 Web 应用中常见的功能。Spring_MVC 提供了简单易用的 API 来处理文件上传和下载。
1. 文件上传
@Controller
@RequestMapping("/file")
public class FileUploadController {
@RequestMapping(value = "/upload", method = RequestMethod.POST)
public String handleFileUpload(@RequestParam("file") MultipartFile file) {
if (!file.isEmpty()) {
try {
byte[] bytes = file.getBytes();
// 处理文件保存逻辑,例如保存到服务器文件系统或数据库
System.out.println("File uploaded successfully: " + file.getOriginalFilename());
return "uploadSuccess";
} catch (IOException e) {
e.printStackTrace();
}
}
return "uploadFailure";
}
}
@RequestParam("file")
用于接收上传的文件。MultipartFile
表示上传的文件对象,可以通过其方法获取文件内容、文件名等信息。
2. 文件下载
@Controller
@RequestMapping("/file")
public class FileDownloadController {
@RequestMapping(value = "/download", method = RequestMethod.GET)
public ResponseEntity<Resource> downloadFile() {
FileSystemResource file = new FileSystemResource("path/to/your/file.txt");
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=file.txt")
.body(file);
}
}
ResponseEntity
用于构建 HTTP 响应。Resource
表示资源文件,可以是文件系统中的文件或其他类型的资源。- 通过设置响应头
Content-Disposition
为attachment
,可以提示浏览器下载文件。
四、拦截器(Interceptors)
拦截器是 Spring_MVC 提供的一种 AOP(面向切面编程)机制,可以用于在请求处理的各个阶段执行自定义逻辑,例如日志记录、权限验证等。
1. 创建自定义拦截器
public class LogInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("Request processing started: " + request.getRequestURI());
return true; // 返回 true 继续处理请求,返回 false 中断请求处理
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("Request processing finished: " + request.getRequestURI());
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("Request completed: " + request.getRequestURI());
}
}
preHandle
方法在请求处理之前执行,可以用于权限验证等逻辑。postHandle
方法在请求处理完成后执行,但视图渲染之前,可以用于修改模型数据等。afterCompletion
方法在请求处理完成之后执行,可以用于资源清理等操作。
2. 配置拦截器
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LogInterceptor())
.addPathPatterns("/user/*") // 拦截 /user/ 开头的请求
.excludePathPatterns("/user/login"); // 排除 /user/login 请求
}
}
addInterceptors
方法用于添加自定义拦截器。addPathPatterns
方法用于指定拦截器拦截的请求路径。excludePathPatterns
方法用于指定拦截器不拦截的请求路径。
五、国际化(I18N)
国际化是开发多语言应用的重要功能。Spring_MVC 支持国际化,可以方便地实现多语言切换。
1. 创建消息资源文件
创建不同语言的消息资源文件,例如:
-
messages_en.properties
:greeting=Hello, {0}! welcome=Welcome to our website.
-
messages_zh.properties
:greeting=你好,{0}! welcome=欢迎来到我们的网站。
2. 配置消息源
@Configuration
public class I18nConfig {
@Bean
public LocaleResolver localeResolver() {
SessionLocaleResolver resolver = new SessionLocaleResolver();
resolver.setDefaultLocale(Locale.US); // 默认语言为英文
return resolver;
}
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource source = new ResourceBundleMessageSource();
source.setBasename("messages"); // 消息资源文件的 basename
source.setDefaultEncoding("UTF-8");
return source;
}
}
LocaleResolver
用于解析客户端的语言环境。MessageSource
用于加载消息资源文件。
3. 使用国际化消息
@Controller
@RequestMapping("/i18n")
public class I18nController {
@Autowired
private MessageSource messageSource;
@RequestMapping(value = "/greeting", method = RequestMethod.GET)
public String showGreeting(Model model, Locale locale) {
String greeting = messageSource.getMessage("greeting", new Object[]{"World"}, locale);
model.addAttribute("greeting", greeting);
return "greetingPage";
}
}
MessageSource.getMessage
方法用于获取国际化消息。Locale
参数用于指定当前的语言环境。
<!-- greetingPage.jsp -->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Greeting</title>
</head>
<body>
<h1>${greeting}</h1>
<a href="?lang=zh">中文</a> | <a href="?lang=en">English</a>
</body>
</html>
- 在页面中可以通过
${greeting}
输出国际化消息。 - 通过添加
lang
参数可以切换语言。