SpringMvc4.x-3(基本配置)
靜態資源配置:
Spring
MVC
的定製配置需要我們的配置類繼承一個WebMvcConfigurerAdapter
類,並在此類使用@EnableWebMvc
註解,來開啟對Spring
MVC
的配置支援,這樣我們就可以重寫這個類的方法,完成我們的常用配置。
我們將前面文章中的MyMvcConfig
配置類繼承WebMvcConfigurerAdapter
,以後如果不做特別說明,則關於配置的相關內容都在MyMvcConfig
裡面編寫。
程式的靜態檔案(js
,css
,圖片)等需要直接訪問,這時我們可以在配置裡重寫addResourceHandlers
方法來實現。
新增靜態資源
在src/main/resources
assets/js
目錄,並複製一個jquery.js
放置在該目錄下
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import org.springframework.web.servlet.view.InternalResourceViewResolver; import org.springframework.web.servlet.view.JstlView; @Configuration @EnableWebMvc// ① @ComponentScan("org.light4j.springMvc4") public class MyMvcConfig extends WebMvcConfigurerAdapter {// ② @Bean public InternalResourceViewResolver viewResolver() { InternalResourceViewResolver viewResolver = new InternalResourceViewResolver(); viewResolver.setPrefix("/WEB-INF/classes/views/"); viewResolver.setSuffix(".jsp"); viewResolver.setViewClass(JstlView.class); return viewResolver; } @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/assets/**").addResourceLocations("classpath:/assets/");// ③ } }
① @EnableWebMvc
開啟SpringMvc
支援,若無此句,重寫WebMvcConfigurerAdapter
的方法無效。
② 繼承WebMvcConfigurerAdapter
類,重寫其方法可對Spring
MVC
進行配置。
③ addResourceLocations
指的是檔案放置的目錄,addResourceHandler
指的是對外暴露的訪問路徑。
攔截器配置:
攔截器(Interceptor
)實現對每一個請求處理前後進行相關的業務處理,類似於Servlet
的Filter
。
可讓普通的Bean
實現HandlerInterceptor
介面或者繼承HandlerInterceptorAdapter
通過重寫WebMvcConfigurerAdapter
的addInterceptors
方法來註冊自定義的攔截器,下面演示一個簡單的攔截器的開發和配置。業務含義為計算每一次請求的處理時間。
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
/**
* ① 繼承HandlerInterceptorAdapter類來實現自定義攔截器。
* ② 重寫preHandle方法,在請求發生前執行。
* ③ 重寫postHandle方法,在請求完成後執行。
*
*/
public class DemoInterceptor extends HandlerInterceptorAdapter {//①
@Override
public boolean preHandle(HttpServletRequest request, //②
HttpServletResponse response, Object handler) throws Exception {
long startTime = System.currentTimeMillis();
request.setAttribute("startTime", startTime);
return true;
}
@Override
public void postHandle(HttpServletRequest request, //③
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
long startTime = (Long) request.getAttribute("startTime");
request.removeAttribute("startTime");
long endTime = System.currentTimeMillis();
System.out.println("本次請求處理時間為:" + new Long(endTime - startTime)+"ms");
request.setAttribute("handlingTime", endTime - startTime);
}
}
配置:
/**
* ① 配置攔截器的Bean
* ② 重寫addInterceptors方法,註冊攔截器。
* @return
*/
@Bean // ①
public DemoInterceptor demoInterceptor() {
return new DemoInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {// ②
registry.addInterceptor(demoInterceptor());
}
@ControllerAdvice註解
通過@ControllerAdvice
。我們可以將對於控制器的全域性配置放置在同一個位置,註解了@ControllerAdvice
的類的方法可以使用@ExceptionHandler
,@InitBinder
,@ModelAttribute
註解到方法上,這對所有註解了@RequestMapping
的控制器內的方法有效。
@ExceptionHandler
:用於全域性處理控制器裡面的異常。@InitBinder
:用來設定WebDataBinder
,WebDataBinder
用來自動繫結前臺請求引數到Model
中。@ModelAttribute
:@ModelAttribute
本來的作用是繫結鍵值對到Model
裡,此處是讓全域性的@RequestMapping
都能獲得在此處設定的鍵值對。
下面將使用@ExceptionHandler
處理全域性異常,將異常資訊更加人性化的輸出給使用者。
import org.springframework.ui.Model;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.ModelAndView;
@ControllerAdvice //①
public class ExceptionHandlerAdvice {
@ExceptionHandler(value = Exception.class)//②
public ModelAndView exception(Exception exception, WebRequest request) {
ModelAndView modelAndView = new ModelAndView("error");// error頁面
modelAndView.addObject("errorMessage", exception.getMessage());
return modelAndView;
}
@ModelAttribute //③
public void addAttributes(Model model) {
model.addAttribute("msg", "額外資訊"); //④
}
@InitBinder //④
public void initBinder(WebDataBinder webDataBinder) {
webDataBinder.setDisallowedFields("id"); //⑤
}
}
① @ControllerAdvice
宣告一個控制器建言,@ControllerAdvice
組合了@Component
註解,所以自動註冊為Spring的Bean
。
② @ExceptionHandler
在此處定義全域性處理,通過@ExceptionHandler
的value
屬性可過濾攔截的條件,在此處可以看出攔截的是所有的Exception
。
③ 此處使用@ModelAttribute
註解將鍵值對新增到全域性,所有註解了@RequestMapping
的方法可獲得此鍵值對。
④ 通過@InitBinder
註解定製WebDataBinder
import org.light4j.springMvc4.domain.DemoObj;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class AdviceController {
@RequestMapping("/advice")
public String getSomething(@ModelAttribute("msg") String msg,DemoObj obj){//①
throw new IllegalArgumentException("非常抱歉,引數有誤/"+"來自@ModelAttribute:"+ msg);
}
}
在src/main/resources/views
下,新建error.jsp
,內容如下:
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page isELIgnored="false" %>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>@ControllerAdvice Demo</title>
</head>
<body>
${errorMessage}
</body>
</html>
此處無任何的業務處理,只是簡單的頁面跳轉,寫了至少三行有效的程式碼,在實際的開發中會涉及大量這樣的頁面轉向,若都這樣寫會特別的麻煩,我們通過在配置類MyMvcConfig
裡通過重寫addViewControllers
來簡化配置:
@RequestMapping("/index")//②
public String hello(){
return "index";
}
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/index").setViewName("/index");
}
Spring
MVC
中,路徑引數如果帶”.”的話,”.”後面的值將被忽略,例如,訪問http://localhost/springMvc4.x/anno/pathvar/xxx.yy
,此時,”.”後面的yy
被忽略;
通過重寫configurePathMatch
方法可實現不忽略”.”後面的引數,在配置類MyMvcConfig
中增加程式碼如下:
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.setUseSuffixPatternMatch(false);
}
更多配置請檢視WebMvcConfigurerAdater
類的API
。因其是WebMvcConfigurerAdater
介面的實現,所以WebMvcConfigurerAdater
的API
內的方法也可以用來配置MVC
。下面列出WebMvcConfigurerAdater
和WebMvcConfigurer
的原始碼供參考。
1. WebMvcConfigurerAdater
public abstract class WebMvcConfigurerAdapter implements WebMvcConfigurer {
/**
* {@inheritDoc}
* <p>This implementation is empty.
*/
@Override
public void addFormatters(FormatterRegistry registry) {
}
/**
* {@inheritDoc}
* <p>This implementation is empty.
*/
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
}
/**
* {@inheritDoc}
* <p>This implementation is empty.
*/
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
}
/**
* {@inheritDoc}
* <p>This implementation returns {@code null}
*/
@Override
public Validator getValidator() {
return null;
}
/**
* {@inheritDoc}
* <p>This implementation is empty.
*/
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
}
/**
* {@inheritDoc}
* <p>This implementation is empty.
*/
@Override
public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
}
/**
* {@inheritDoc}
* <p>This implementation is empty.
*/
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
}
/**
* {@inheritDoc}
* <p>This implementation is empty.
*/
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
}
/**
* {@inheritDoc}
* <p>This implementation is empty.
*/
@Override
public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {
}
/**
* {@inheritDoc}
* <p>This implementation is empty.
*/
@Override
public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
}
/**
* {@inheritDoc}
* <p>This implementation is empty.
*/
@Override
public MessageCodesResolver getMessageCodesResolver() {
return null;
}
/**
* {@inheritDoc}
* <p>This implementation is empty.
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
}
/**
* {@inheritDoc}
* <p>This implementation is empty.
*/
@Override
public void addViewControllers(ViewControllerRegistry registry) {
}
/**
* {@inheritDoc}
* <p>This implementation is empty.
*/
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
}
/**
* {@inheritDoc}
* <p>This implementation is empty.
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
}
/**
* {@inheritDoc}
* <p>This implementation is empty.
*/
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
}
}
WebMvcConfigurer
public interface WebMvcConfigurer {
/**
* Add {@link Converter}s and {@link Formatter}s in addition to the ones
* registered by default.
*/
void addFormatters(FormatterRegistry registry);
/**
* Configure the {@link HttpMessageConverter}s to use for reading or writing
* to the body of the request or response. If no converters are added, a
* default list of converters is registered.
* <p><strong>Note</strong> that adding converters to the list, turns off
* default converter registration. To simply add a converter without impacting
* default registration, consider using the method
* {@link #extendMessageConverters(java.util.List)} instead.
* @param converters initially an empty list of converters
*/
void configureMessageConverters(List<HttpMessageConverter<?>> converters);
/**
* A hook for extending or modifying the list of converters after it has been
* configured. This may be useful for example to allow default converters to
* be registered and then insert a custom converter through this method.
* @param converters the list of configured converters to extend.
* @since 4.1.3
*/
void extendMessageConverters(List<HttpMessageConverter<?>> converters);
/**
* Provide a custom {@link Validator} instead of the one created by default.
* The default implementation, assuming JSR-303 is on the classpath, is:
* {@link org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean}.
* Leave the return value as {@code null} to keep the default.
*/
Validator getValidator();
/**
* Configure content negotiation options.
*/
void configureContentNegotiation(ContentNegotiationConfigurer configurer);
/**
* Configure asynchronous request handling options.
*/
void configureAsyncSupport(AsyncSupportConfigurer configurer);
/**
* Helps with configuring HandlerMappings path matching options such as trailing slash match,
* suffix registration, path matcher and path helper.
* Configured path matcher and path helper instances are shared for:
* <ul>
* <li>RequestMappings</li>
* <li>ViewControllerMappings</li>
* <li>ResourcesMappings</li>
* </ul>
* @since 4.0.3
*/
void configurePathMatch(PathMatchConfigurer configurer);
/**
* Add resolvers to support custom controller method argument types.
* <p>This does not override the built-in support for resolving handler
* method arguments. To customize the built-in support for argument
* resolution, configure {@link RequestMappingHandlerAdapter} directly.
* @param argumentResolvers initially an empty list
*/
void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers);
/**
* Add handlers to support custom controller method return value types.
* <p>Using this option does not override the built-in support for handling
* return values. To customize the built-in support for handling return
* values, configure RequestMappingHandlerAdapter directly.
* @param returnValueHandlers initially an empty list
*/
void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers);
/**
* Configure the {@link HandlerExceptionResolver}s to handle unresolved
* controller exceptions. If no resolvers are added to the list, default
* exception resolvers are added instead.
* @param exceptionResolvers initially an empty list
*/
void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers);
/**
* Add Spring MVC lifecycle interceptors for pre- and post-processing of
* controller method invocations. Interceptors can be registered to apply
* to all requests or be limited to a subset of URL patterns.
* <p><strong>Note</strong> that interceptors registered here only apply to
* controllers and not to resource handler requests. To intercept requests for
* static resources either declare a
* {@link org.springframework.web.servlet.handler.MappedInterceptor MappedInterceptor}
* bean or switch to advanced configuration mode by extending
* {@link org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport
* WebMvcConfigurationSupport} and then override {@code resourceHandlerMapping}.
*/
void addInterceptors(InterceptorRegistry registry);
/**
* Provide a custom {@link MessageCodesResolver} for building message codes
* from data binding and validation error codes. Leave the return value as
* {@code null} to keep the default.
*/
MessageCodesResolver getMessageCodesResolver();
/**
* Configure simple automated controllers pre-configured with the response
* status code and/or a view to render the response body. This is useful in
* cases where there is no need for custom controller logic -- e.g. render a
* home page, perform simple site URL redirects, return a 404 status with
* HTML content, a 204 with no content, and more.
*/
void addViewControllers(ViewControllerRegistry registry);
/**
* Configure view resolvers to translate String-based view names returned from
* controllers into concrete {@link org.springframework.web.servlet.View}
* implementations to perform rendering with.
*/
void configureViewResolvers(ViewResolverRegistry registry);
/**
* Add handlers to serve static resources such as images, js, and, css
* files from specific locations under web application root, the classpath,
* and others.
*/
void addResourceHandlers(ResourceHandlerRegistry registry);
/**
* Configure a handler to delegate unhandled requests by forwarding to the
* Servlet container's "default" servlet. A common use case for this is when
* the {@link DispatcherServlet} is mapped to "/" thus overriding the
* Servlet container's default handling of static resources.
*/
void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer);
}