Spring MVC 逻辑视图与非逻辑视图详解及示例
一、逻辑视图与非逻辑视图的定义
类型 | 定义 |
---|---|
逻辑视图 | 通过视图解析器(ViewResolver )将逻辑名称(如 success )映射到具体视图实现。 |
非逻辑视图 | 直接返回具体视图对象(如 JsonView ),或通过注解/方法直接生成响应,无需解析器。 |
二、逻辑视图与非逻辑视图的接口类型
类型 | 接口示例 |
---|---|
逻辑视图 | JSP、Thymeleaf、FreeMarker(模板引擎生成HTML) |
非逻辑视图 | JSON(MappingJackson2JsonView )、Excel(ExcelView )、PDF(PdfView )、XML等 |
三、逻辑视图与非逻辑视图的对比
维度 | 逻辑视图 | 非逻辑视图 |
---|---|---|
视图解析 | 需要配置视图解析器(如 ThymeleafViewResolver ) |
无需解析器,直接返回视图对象或通过注解(如 @ResponseBody ) |
响应格式 | HTML(模板引擎渲染) | JSON、Excel、PDF、XML 等特定格式 |
解耦性 | 控制器与视图解耦,通过名称间接关联 | 控制器直接绑定视图实现,耦合度较高 |
配置复杂度 | 需配置解析器和模板引擎 | 简单(如直接使用注解或自定义View类) |
典型场景 | 前端页面渲染(如网页跳转) | API返回数据、文件下载、特殊格式输出 |
四、代码示例
1. 逻辑视图示例
(1)JSP 示例
java
// 配置JSP视图解析器(在Spring配置类中)
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/"); // JSP文件存放路径
resolver.setSuffix(".jsp"); // 文件后缀
return resolver;
}
}
// 控制器方法
@Controller
public class UserController {
@GetMapping("/user/jsp")
public String showUserJsp(Model model) {
model.addAttribute("userName", "John Doe");
return "userProfile"; // 返回逻辑视图名,对应userProfile.jsp
}
}
// userProfile.jsp 文件(存放于 /WEB-INF/views/)
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>User Profile</title></head>
<body>
<h1>User Name: ${userName}</h1>
</body>
</html>
(2)Thymeleaf 示例
java
// 配置Thymeleaf视图解析器(在Spring配置类中)
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.setTemplateResolver(templateResolver());
return engine;
}
@Bean
public SpringResourceTemplateResolver templateResolver() {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setPrefix("classpath:/templates/");
resolver.setSuffix(".html");
return resolver;
}
@Bean
public ThymeleafViewResolver viewResolver() {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(templateEngine());
return resolver;
}
}
// 控制器方法
@Controller
public class UserController {
@GetMapping("/user/thymeleaf")
public String showUserThymeleaf(Model model) {
model.addAttribute("user", new User("John", "Doe"));
return "userProfile"; // 对应userProfile.html模板
}
}
// userProfile.html(存放于 templates/)
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head><title>User Profile</title></head>
<body>
<h1 th:text="${user.firstName} + ' ' + ${user.lastName}"></h1>
</body>
</html>
2. 非逻辑视图示例
(1)JSON 示例
java
// 直接返回JSON(使用@ResponseBody注解)
@RestController
public class UserController {
@GetMapping("/user/json")
public User getUserJson() {
return new User("John", "Doe"); // 自动序列化为JSON
}
}
// 或通过ModelAndView返回JSON视图
@Controller
public class UserController {
@GetMapping("/user/json-view")
public ModelAndView getUserJsonView() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setView(new MappingJackson2JsonView());
modelAndView.addObject("user", new User("John", "Doe"));
return modelAndView;
}
}
(2)Excel 示例(使用Apache POI)
java
// 自定义Excel视图类
public class ExcelView extends AbstractView {
@Override
protected void renderMergedOutputModel(
Map<String, Object> model,
HttpServletRequest request,
HttpServletResponse response
) throws Exception {
response.setContentType("application/vnd.ms-excel");
response.setHeader("Content-Disposition", "attachment; filename=users.xls");
HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = workbook.createSheet("Users");
HSSFRow headerRow = sheet.createRow(0);
headerRow.createCell(0).setCellValue("First Name");
headerRow.createCell(1).setCellValue("Last Name");
List<User> users = (List<User>) model.get("users");
for (int i = 0; i < users.size(); i++) {
HSSFRow row = sheet.createRow(i + 1);
row.createCell(0).setCellValue(users.get(i).getFirstName());
row.createCell(1).setCellValue(users.get(i).getLastName());
}
workbook.write(response.getOutputStream());
workbook.close();
}
}
// 控制器方法
@Controller
public class ExcelController {
@GetMapping("/generate/excel")
public ModelAndView generateExcel() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setView(new ExcelView());
modelAndView.addObject("users", Arrays.asList(
new User("John", "Doe"),
new User("Jane", "Smith")
));
return modelAndView;
}
}
(3)PDF 示例(使用iText)
java
// 自定义PDF视图类
public class PdfView extends AbstractView {
@Override
protected void renderMergedOutputModel(
Map<String, Object> model,
HttpServletRequest request,
HttpServletResponse response
) throws Exception {
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "inline; filename=document.pdf");
Document document = new Document();
PdfWriter.getInstance(document, response.getOutputStream());
document.open();
document.add(new Paragraph("Hello PDF!"));
document.close();
}
}
// 控制器方法
@Controller
public class PdfController {
@GetMapping("/generate/pdf")
public ModelAndView generatePdf() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setView(new PdfView());
return modelAndView;
}
}
五、总结表格
类型 | 接口示例 | 响应格式 | 是否需要解析器 | 配置方式 | 典型场景 |
---|---|---|---|---|---|
逻辑视图 | JSP、Thymeleaf | HTML | 是 | 配置ViewResolver | 前端页面渲染 |
非逻辑视图 | JSON、Excel、PDF | JSON、XLS、PDF | 否 | 直接实例化View或使用注解 | API响应、文件下载、特殊格式 |
关键区别
- 逻辑视图:依赖模板引擎生成HTML,需配置视图解析器,适合前后端分离场景。
- 非逻辑视图:直接返回数据或文件,无需解析器,适合API、文件导出等场景,配置更灵活。