Spring?Boot中使用Spring?MVC的示例解析
1.MVC
MVC 是一種常見(jiàn)的軟件設(shè)計(jì)模式,用于分離應(yīng)用程序的不同部分以實(shí)現(xiàn)松散耦合和高內(nèi)聚性。MVC 模式由三個(gè)核心組件組成:
- 模型(Model):表示應(yīng)用程序的數(shù)據(jù)和業(yè)務(wù)邏輯。模型處理應(yīng)用程序的數(shù)據(jù),并根據(jù)控制器的指令執(zhí)行相應(yīng)的操作。
- 視圖(View):提供模型數(shù)據(jù)的用戶界面。視圖通常是模板、HTML 頁(yè)面、XML 文件或其他格式,可以呈現(xiàn)模型數(shù)據(jù)給用戶。
- 控制器(Controller):處理用戶交互并更新模型和視圖??刂破髫?fù)責(zé)接收來(lái)自視圖的用戶輸入,對(duì)模型進(jìn)行相應(yīng)的操作,并更新視圖以反映更改。
MVC 模式的優(yōu)點(diǎn)是可以將代碼分離成三個(gè)獨(dú)立的組件,使得應(yīng)用程序更易于維護(hù)和擴(kuò)展。例如,如果要更改視圖的外觀,可以修改視圖而不影響模型和控制器;如果要更改數(shù)據(jù)存儲(chǔ)方式,可以修改模型而不影響視圖和控制器。同時(shí),MVC 模式還有助于降低應(yīng)用程序中的耦合度,使得各組件更加獨(dú)立和可重用。
2.Spring MVC
在Spring體系下的MVC架構(gòu)中一次請(qǐng)求處理的流程如下:
請(qǐng)求到控制器(controller),經(jīng)過(guò)業(yè)務(wù)模型(model)處理后返回響應(yīng)給識(shí)圖層。
整個(gè)流程里面Spring MVC干了些啥:
整個(gè)Spring MVC的核心是DispatcherServlet,圍繞DispatcherServlet SpringMVC提供了一套組件配合DispatcherServlet完成整個(gè)工作流程。
DispatcherServlet 首先收到請(qǐng)求,將請(qǐng)求映射到對(duì)應(yīng)的處理器(controller)上,映射到controller的時(shí)候會(huì)觸發(fā)攔截器;處理器處理完后封裝數(shù)據(jù)模型,交給視圖解析器將數(shù)據(jù)模型解析為對(duì)應(yīng)的視圖返回給前端。
當(dāng)然有時(shí)候以上流程不會(huì)全部走完,比如使用@RestController或者@ResponseBody的時(shí)候由于直接返回響應(yīng)了,不會(huì)轉(zhuǎn)跳識(shí)圖,所以不會(huì)走視圖解析器。
3.Spring Boot中使用Spring MVC
3.1.配置
因?yàn)镾pring Boot自動(dòng)裝配機(jī)制的存在,一般來(lái)說(shuō)我們不需要對(duì)Spring MVC進(jìn)行配置,如果要進(jìn)行特別定制化的配置,Spring Boot也支持配置文件或者編寫(xiě)代碼的兩種方式來(lái)進(jìn)行配置。
3.1.1.文件配置
# 啟用Spring MVC
spring.mvc.enabled=true# 配置靜態(tài)資源路徑
spring.mvc.static-path-pattern=/static/**
spring.resources.static-locations=classpath:/static/# 配置視圖解析器
spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp# 配置HTTP緩存
spring.resources.cache.period=3600# 配置文件上傳
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=10MB# 配置JSON序列化
spring.jackson.serialization.indent_output=true
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss# 配置異常處理
server.error.whitelabel.enabled=false# 配置攔截器
spring.mvc.interceptor.exclude-path-patterns=/login,/logout
spring.mvc.interceptor.include-path-patterns=/admin/**# 配置會(huì)話管理
server.session.timeout=1800
server.session.cookie.max-age=1800
3.1.2.代碼配置
@Configuration public class MyWebMvcConfig implements WebMvcConfigurer { // 配置視圖解析器 @Override public void configureViewResolvers(ViewResolverRegistry registry) { InternalResourceViewResolver resolver = new InternalResourceViewResolver(); resolver.setPrefix("/WEB-INF/views/"); resolver.setSuffix(".jsp"); registry.viewResolver(resolver); } // 配置靜態(tài)資源 @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/static/**").addResourceLocations("/static/"); } // 配置攔截器 @Autowired private MyInterceptor myInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(myInterceptor).addPathPatterns("/**"); } // 配置消息轉(zhuǎn)換器 @Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); List<MediaType> supportedMediaTypes = new ArrayList<MediaType>(); supportedMediaTypes.add(MediaType.APPLICATION_JSON); converter.setSupportedMediaTypes(supportedMediaTypes); converters.add(converter); } // 配置異常處理器 @ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(value = Exception.class) public ModelAndView handleException(HttpServletRequest req, Exception e) { ModelAndView mav = new ModelAndView(); mav.addObject("exception", e); mav.addObject("url", req.getRequestURL()); mav.setViewName("error"); return mav; } } // 配置跨域資源共享(CORS) @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/api/**").allowedOrigins("http://localhost:8080"); } // 配置文件上傳 @Bean public MultipartResolver multipartResolver() { CommonsMultipartResolver resolver = new CommonsMultipartResolver(); resolver.setMaxUploadSize(10485760); resolver.setMaxInMemorySize(4096); return resolver; } // 配置請(qǐng)求緩存 @Bean public KeyGenerator keyGenerator() { return new DefaultKeyGenerator(); } @Bean public RequestCache requestCache() { return new HttpSessionRequestCache(); } // 配置視圖控制器 @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/").setViewName("index"); registry.addViewController("/login").setViewName("login"); } }
3.2.使用
3.2.1.映射處理器
這里只介紹@RequestMapping,@GETMapping和@PostMapping類似。
@Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented @Mapping public @interface RequestMapping { String name() default ""; @AliasFor("path") String[] value() default {}; @AliasFor("value") String[] path() default {}; RequestMethod[] method() default {}; String[] params() default {}; String[] headers() default {}; String[] consumes() default {}; String[] produces() default {}; }
各參數(shù)的作用如下:
- value和path:用于指定請(qǐng)求的URL路徑,可以使用占位符和正則表達(dá)式。
- method:指定HTTP請(qǐng)求方法,可以是GET、POST、PUT、DELETE等。
- params:指定請(qǐng)求參數(shù)的條件,支持表達(dá)式、多個(gè)參數(shù)和邏輯運(yùn)算。
- headers:指定請(qǐng)求頭的條件,支持表達(dá)式、多個(gè)頭和邏輯運(yùn)算。
- consumes:指定請(qǐng)求的MIME類型,用于限制請(qǐng)求內(nèi)容類型。
- produces:指定響應(yīng)的MIME類型,用于限制響應(yīng)內(nèi)容類型。
- name:指定請(qǐng)求參數(shù)的名稱,用于自動(dòng)綁定參數(shù)值。
- defaultValue:指定請(qǐng)求參數(shù)的默認(rèn)值。
- pathVariable:用于綁定URL路徑中的占位符。
- required:指定請(qǐng)求參數(shù)是否為必須的。
- value、method、params、headers、consumes和produces屬性都支持?jǐn)?shù)組形式,可以匹配多個(gè)條件。
3.2.2.傳參
1.按參數(shù)名匹配
@Controller @RequestMapping("/user") public class UserController { @RequestMapping("/info") public String getUserInfo(Integer userId, Model model) { // 根據(jù)用戶ID查詢用戶信息并返回 User user = userService.getUserById(userId); model.addAttribute("user", user); return "user_info"; } }
URL:
ip:port/info?userId=1
2.@RequestParam
通過(guò)@RequestParam注解可以指定匹配的參數(shù).
@Controller @RequestMapping("/user") public class UserController { @RequestMapping(value = "/search", method = RequestMethod.GET, params = "keyword") public String searchUser(@RequestParam("keyword") String keyword, Model model) { // 根據(jù)關(guān)鍵詞查詢用戶信息并返回 List<User> userList = userService.searchUser(keyword); model.addAttribute("userList", userList); return "user_list"; } }
3.傳數(shù)組
@RequestMapping("/delete") public String deleteUsers(int[] userIds, Model model) { // 根據(jù)用戶ID數(shù)組刪除多個(gè)用戶,并返回用戶列表頁(yè)面 userService.deleteUsers(userIds); List<User> userList = userService.getUserList(); model.addAttribute("userList", userList); return "user_list"; }
4.傳JSON
傳JSON只能用POST方法,使用@ResponseBody注解參數(shù)列表中的參數(shù),就可以用來(lái)接收J(rèn)SON,如果被注解的參數(shù)是個(gè)對(duì)象那么會(huì)將JSON自動(dòng)轉(zhuǎn)化為改對(duì)象。
@RequestMapping(value = "/save", method = RequestMethod.POST) @ResponseBody public Map<String, Object> saveUser(@RequestBody User user) { // 保存用戶信息,并返回成功的響應(yīng) userService.saveUser(user); return Collections.singletonMap("success", true); }
注意傳參的時(shí)候要將設(shè)置好contentType: "application/json"
5.Restful
@Controller @RequestMapping("/user") public class UserController { @RequestMapping("/info/{id}") public String getUserInfo(@PathVariable("id") Integer userId, Model model) { // 根據(jù)用戶ID查詢用戶信息并返回 User user = userService.getUserById(userId); model.addAttribute("user", user); return "user_info"; } }
前端URL為:
ip:port/info/1
3.2.3.參數(shù)轉(zhuǎn)換
當(dāng)后端接口的參數(shù)列表是對(duì)象類型時(shí),Spring MVC會(huì)自動(dòng)按照參數(shù)名完成參數(shù)的轉(zhuǎn)換和填充,當(dāng)然這種轉(zhuǎn)化規(guī)則也可以由我們自己定義,Spring MVC為我們準(zhǔn)備了轉(zhuǎn)換接口,以下是一個(gè)完整示例:
實(shí)體對(duì)象:
public class User { private Long id; private String name; private Integer age; private String email; // 省略 getter 和 setter 方法 }
參數(shù)轉(zhuǎn)換器:
public class UserConverter implements Converter<String, User> { @Override public User convert(String source) { // 將請(qǐng)求參數(shù)解析為User對(duì)象 String[] values = source.split(","); User user = new User(); user.setId(Long.parseLong(values[0])); user.setName(values[1]); user.setAge(Integer.parseInt(values[2])); user.setEmail(values[3]); return user; } }
注冊(cè)參數(shù)轉(zhuǎn)換器:
@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addFormatters(FormatterRegistry registry) { registry.addConverter(new UserConverter()); } }
以后再傳對(duì)應(yīng)類型的參數(shù)時(shí),會(huì)用我們自定義的轉(zhuǎn)換規(guī)則來(lái)進(jìn)行轉(zhuǎn)換:
@RequestMapping(value = "/save", method = RequestMethod.POST) @ResponseBody public Map<String, Object> saveUser(User user) { // 保存用戶信息,并返回成功的響應(yīng) userService.saveUser(user); return Collections.singletonMap("success", true); }
3.2.4.數(shù)據(jù)校驗(yàn)
有時(shí)候我們希望前端傳過(guò)來(lái)的參數(shù)是滿足一定格式的,Spring MVC也考慮到了這一點(diǎn),為我們提供了基于注解的參數(shù)校驗(yàn)功能。
public class User { @NotNull(message = "id不能為空") private Long id; @NotBlank(message = "name不能為空") private String name; @Min(value = 0, message = "age不能小于0") @Max(value = 150, message = "age不能大于150") private Integer age; @Email(message = "email格式不正確") private String email; // 省略 getter 和 setter 方法 }
只是使用了注解,校驗(yàn)并不會(huì)生效,還需要在想要進(jìn)行校驗(yàn)的地方配上@Validated開(kāi)啟校驗(yàn):
public class User { @NotNull(message = "id不能為空") private Long id; @NotBlank(message = "name不能為空") private String name; @Min(value = 0, message = "age不能小于0") @Max(value = 150, message = "age不能大于150") private Integer age; @Email(message = "email格式不正確") private String email; // 省略 getter 和 setter 方法 }
3.2.5.數(shù)據(jù)模型
Spring MVC 中的數(shù)據(jù)模型用于在處理器方法(Controller)和視圖之間傳遞數(shù),有三種:
- Model
- ModelMap
- ModelAndView
Model:
只能承載參數(shù)
@GetMapping("/hello") public String hello(Model model) { model.addAttribute("message", "Hello, world!"); return "hello"; }
ModelMap:
和Model功能相似。
@GetMapping("/hello") public String hello(ModelMap model) { model.put("message", "Hello, world!"); return "hello"; }
ModelAndView:
既能承載參數(shù)也能承載視圖名。
@GetMapping("/hello") public ModelAndView hello() { ModelAndView mav = new ModelAndView("hello"); mav.addObject("message", "Hello, world!"); return mav; }
3.2.6.視圖和解析器
1.視圖
Spring MVC的視圖可以理解為最終返給前端的東西,分為兩類:
- 邏輯視圖
- 非邏輯視圖
邏輯視圖:
邏輯視圖是指一個(gè)字符串,它代表了一個(gè)視圖的邏輯名稱,與實(shí)際的視圖實(shí)現(xiàn)解耦合,而是通過(guò)視圖解析器將其映射為實(shí)際的視圖。在 Spring MVC 中,處理器方法可以返回邏輯視圖名,由 DispatcherServlet 根據(jù)視圖解析器的配置,將其映射為實(shí)際的視圖。
常用的邏輯視圖包括:
- JSP 視圖:使用 InternalResourceViewResolver 視圖解析器,將邏輯視圖名映射為 JSP 文件名。
- Velocity 視圖:使用 VelocityViewResolver 視圖解析器,將邏輯視圖名映射為 Velocity 模板文件名。
- Thymeleaf 視圖:使用 ThymeleafViewResolver 視圖解析器,將邏輯視圖名映射為 Thymeleaf 模板文件名。
非邏輯視圖:
非邏輯視圖是指一個(gè)具體的視圖實(shí)現(xiàn),通常是一個(gè)視圖類或者一個(gè) RESTful Web Service。在處理器方法中,可以直接返回一個(gè)非邏輯視圖,它會(huì)被直接渲染,而不需要通過(guò)視圖解析器進(jìn)行轉(zhuǎn)換。
常用的非邏輯視圖包括:
- JSON 視圖:使用 MappingJackson2JsonView 視圖實(shí)現(xiàn),將模型數(shù)據(jù)轉(zhuǎn)換為 JSON 格式返回給客戶端。
- XML 視圖:使用 MappingJackson2XmlView 視圖實(shí)現(xiàn),將模型數(shù)據(jù)轉(zhuǎn)換為 XML 格式返回給客戶端。
- PDF 視圖:使用 iText PDF 庫(kù)和 AbstractPdfView 視圖實(shí)現(xiàn),將模型數(shù)據(jù)轉(zhuǎn)換為 PDF 格式返回給客戶端。
需要注意的是,非邏輯視圖通常需要進(jìn)行額外的配置和處理,比如 JSON 視圖需要添加 Jackson 依賴庫(kù),并在 Spring 配置文件中配置 MappingJackson2JsonView 視圖解析器。
2.視圖解析器
視圖解析器決定@Controller的return具體映射到什么類型的視圖上,默認(rèn)是使用InternalResourceViewResolver視圖解析器,也就是JSP視圖解析器,當(dāng)我們配置好前綴、后綴后,它會(huì)自動(dòng)將@Controller的return映射到對(duì)應(yīng)的jsp上去。
spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp
當(dāng)然在Spring Boot中也支持我們切換視圖解析器,以下是切換為JSON視圖解析器的示例,切換為JSON視圖解析器后return會(huì)直接返回JSON給前端:
@Configuration @EnableWebMvc public class AppConfig implements WebMvcConfigurer { @Bean public ViewResolver viewResolver() { InternalResourceViewResolver resolver = new InternalResourceViewResolver(); resolver.setPrefix("/WEB-INF/views/"); resolver.setSuffix(".jsp"); return resolver; } }
3.2.7.攔截器
Spring Boot中使用自定義Spring MVC攔截器鏈的代碼如下:
@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new FirstInterceptor()); registry.addInterceptor(new SecondInterceptor()); } } public class FirstInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 在處理器處理請(qǐng)求之前執(zhí)行 return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { // 在處理器處理請(qǐng)求之后,渲染視圖之前執(zhí)行 } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // 在渲染視圖之后執(zhí)行 } } public class SecondInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 在處理器處理請(qǐng)求之前執(zhí)行 return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { // 在處理器處理請(qǐng)求之后,渲染視圖之前執(zhí)行 } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // 在渲染視圖之后執(zhí)行 } }
到此這篇關(guān)于在Spring Boot中使用Spring MVC的的文章就介紹到這了,更多相關(guān)Spring Boot使用Spring MVC內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解SpringMVC驗(yàn)證框架Validation特殊用法
本篇文章主要介紹了詳解SpringMVC驗(yàn)證框架Validation特殊用法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-02-02SpringBoot使用責(zé)任鏈模式優(yōu)化業(yè)務(wù)邏輯中的if-else代碼
在開(kāi)發(fā)過(guò)程中,我們經(jīng)常會(huì)遇到需要根據(jù)不同的條件執(zhí)行不同的邏輯的情況,我們可以考慮使用責(zé)任鏈模式來(lái)優(yōu)化代碼結(jié)構(gòu),使得代碼更加清晰、可擴(kuò)展和易于維護(hù)2023-06-06java編程創(chuàng)建型設(shè)計(jì)模式單例模式的七種示例
這篇文章主要為大家介紹了java編程中創(chuàng)建型設(shè)計(jì)模式之單例模式的示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助2022-02-02Java并發(fā)編程變量可見(jiàn)性避免指令重排使用詳解
這篇文章主要為大家介紹了Java并發(fā)編程變量可見(jiàn)性避免指令重排使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11java如何實(shí)現(xiàn)socket連接方法封裝
這篇文章主要介紹了java實(shí)現(xiàn)socket連接方法封裝教程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09Java多線程Future松獲取異步任務(wù)結(jié)果輕松實(shí)現(xiàn)
這篇文章主要為大家介紹了Java多線程Future松獲取異步任務(wù)結(jié)果輕松實(shí)現(xiàn)方法,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04