Spring-boot(二)WebMvcConfigurerAdapter详解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Suubyy/article/details/84291700

定义

WebMvcConfigurationAdapter是一个配置类,该配置类主要利用@Bean方式来配置,该配置类里的配置主要功能是针对Http请求作统一处理。我们想要使用这样的配置方式,需要自定义一个类取继承这个配置类。

具体的API方法功能

以下的API中WebConfig 类也是我自己定义的,它是继承WebMvcConfigurerAdapter类,并且里边什么也没做。

public void addFormatters(FormatterRegistry registry)

该方法的功能是添加一个实例,这个实例的功能在请求到达之前将数据进行格式化或者转换,以及请求之后对返回给前端的数据进行转换与格式化

@Configuration
public class SysWebConfig extends WebConfig {

    /**
     * 全局处理http请求,主要用于用于对象与字符串之间的转换
     *
     * @param registry
     */
    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addFormatter(new TestForamtter());
    }
}


/**
 * 该类是线程安全的,类似于PropertyEditer功能,用于对象与字符串之间的转换
 *
 */

public class TestForamtter implements Formatter<Test> {

    /**
     * 将请求中的字符串转换成对象
     * Test实体是自己瞎定义的对象,用于测试,这里就不贴了
     * @param s
     * @param locale
     * @return
     * @throws ParseException
     */
    @Override
    public Test parse(String s, Locale locale) throws ParseException {
        Test test = new Test();
        test.setA("i am  is a");
        test.setB("i am is b ");
        return test;
    }

    /**
     * 将请求中的对象转换成字符串类
     *
     * @param test
     * @param locale
     * @return
     */
    @Override
    public String print(Test test, Locale locale) {
        return "this is test!";
    }
}

public void addInterceptors(InterceptorRegistry registry)

该方法功能是添加拦截器实例,这个实例需要实现HandlerInterceptor接口

/**
 * WEB配置类
 */
@Configuration
public class SysWebConfig extends WebConfig {
    /**
     * 添加拦截器实例。该实例需要实现HandlerInterceptor
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
    	 //注册一个拦截器,addPathPatterns指定拦截的RUl,默认除了/login之外的对所有请求进行拦截
        registry.addInterceptor(new TestInterceptor()).addPathPatterns("/**").excludePathPatterns("/login");
        super.addInterceptors(registry);
    }
}


/**
 * 这是一个拦截器,用于处理请求
 */

public class TestInterceptor implements HandlerInterceptor {

    /**
     * 这个方法是在请求controller之前执行的
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws
            Exception {
        String token = request.getHeader("Authorization");
        System.err.println("请求controller之前获取Token:" + token);
        return true;
    }

    /**
     * 这个方法只在请求controller之后,还未熏染视图执行的
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView
            modelAndView) throws Exception {
        System.err.println("请求controller之后");
    }

    /**
     * 这个方法是在渲染视图之后执行的
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception
            ex) throws Exception {
    }
}

public void configurePathMatch(PathMatchConfigurer configurer)

该个方法的功能是设置匹配路由请求规则


/**
 * WEB配置类
 */
@Configuration
public class SysWebConfig extends WebConfig {

    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        // 系统对外暴露的 URL 不会识别和匹配 .* 后缀,例如你请求的是/user.*,那么系统
        //不会匹配到/user.html
        configurer.setUseSuffixPatternMatch(false) 
                .setUseTrailingSlashMatch(true); // 系统不区分 URL 的最后一个字符是否是斜杠 /
    }
}

public void addCorsMappings(CorsRegistry registry)

该方法的功能是配置哪些请求可以跨域请求,以及哪些机器可以访问跨域请求。所谓的跨域大部分是针对前后端分离的项目,并且前端跟后端没有部署在同一台服务器上


/**
 * WEB配置类
 */
@Configuration
public class SysWebConfig extends WebConfig {

    /**
     * 增加跨域支持
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")//对哪些请求支持跨域访问
                .allowedOrigins("*")//哪些机器可以跨域访问
                .allowCredentials(true)//是否支持用户凭证
                .allowedMethods("", "", "", "")//支持跨域请求的请求方式
                .maxAge(3600);//准备响应前的缓存持续的最大时间(以秒为单位)。
        super.addCorsMappings(registry);
    }
}

public void addResourceHandlers(ResourceHandlerRegistry registry)

该方法的功能就是添加静态路径,这个方法中的静态路径会覆盖application.yml里的配置

public class SysWebConfig extends WebConfig {
   
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        //请求的地址
        registry.addResourceHandler("/static/**")
                .addResourceLocations("classpath:/static/");//映射的项目中的路径,这个路径也可以是额外路劲,例如E://file路径
        super.addResourceHandlers(registry);
    }
}

public void addViewControllers(ViewControllerRegistry registry)

该方法的功能用于自定义视图控制器

public class SysWebConfig extends WebConfig {
   
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        //对于/hello的请求 重定向到/home
        registry.addRedirectViewController("/test/test", "/test/redirect");
        //对于/loginou请求,响应200状态码
        registry.addStatusController("/loginout", HttpStatus.OK);
        //对于/home请求,返回home视图
        registry.addViewController("/home").setViewName("home");
        super.addViewControllers(registry);
    }
}

public void configureViewResolvers(ViewResolverRegistry registry)

该方法功能是配置视图解析器的

public class SysWebConfig extends WebConfig {
   
    /**
     * 配置视图解析器
     * @param registry
     */
    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        //注册一个Jsp解析器
        registry.jsp("/static/jsp", ".jsp");/
        //视图解析器会根据返回的视图名称在Spring容器中找到视图名字对应的Bean,这个Bean是View.class类型的,如果找到就直接返回
        registry.beanName();
        //用于注册各种各样的视图解析器的包括自己定义的视图解析器
        registry.viewResolver();
        //开启视图解析器裁决功能
        registry.enableContentNegotiation(new MappingJackson2JsonView());
        super.configureViewResolvers(registry);
    }
     @Bean
    public TestViewResolver testViewResolver() {
        return new TestViewResolver(testView());
    }
    @Bean
    public TestView testView() {
        return new TestView();
    }
}


public class TestView  implements View {

    @Override
    public String getContentType() {
        return null;
    }

    @Override
    public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {

    }
}

public class TestViewResolver implements ViewResolver {

    private View view;

    public TestViewResolver(View view) {
        this.view = view;
    }

    @Override
    public View resolveViewName(String viewName, Locale locale) throws Exception {
        return view;
    }
}

public void addResourceHandlers(ResourceHandlerRegistry registry)

该的方法功能是处理静态文件用的,由于DispatcherSevelet对所有请求都进行拦截,当我们请求静态文件的时候,因为后端没有对应的Controller,那么这个请求就会交由DefaultServletHandler去处理。

public class SysWebConfig extends WebConfig {
   
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        //请求的地址
        registry.addResourceHandler("/static/**")
                .addResourceLocations("classpath:/static/");//映射的项目中的路径,这个路径也可以是额外路劲,例如E://file路径
        super.addResourceHandlers(registry);
    }
}

public void configureDefaultServletHandling(final DefaultServletHandlerConfigurer configurer)

该方法的功能用于自定义视图控制器

public class SysWebConfig extends WebConfig {
   
     /**
     * 这个方法的的作用注册一个Handler,当请求静态资源的时候,如果没有找到相应Controller,就会把这个请求交由defaultservlethandler处理,
     * 其实就是对DispatcherServlet的一种增强
     *
     * @param configurer
     */
    @Override
    public void configureDefaultServletHandling(final DefaultServletHandlerConfigurer configurer) {
        // 等价于<mvc:default-servlet-handler />, 对静态资源文件的访问, 将无法 mapping 到 Controller 的 path 交给 default servlet handler 处理
        configurer.enable();
    }
}

public void addArgumentResolvers(List argumentResolvers)

该方法的功能用于注册Controller的参数解析器,并且这个参数可以注册多个参数解析器,将前端传过来的参数根据业务需求进行参数的解析,解析成我们想要的类型或者格式。

public class SysWebConfig extends WebConfig {
   
  /**
     * 添加参数解析器
     * @param argumentResolvers
     */
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        argumentResolvers.add(testArgumentResolver());
        super.addArgumentResolvers(argumentResolvers);
    }

    /**
     * 配置参数解析器的实例
     * @return
     */
    @Bean
    public TestArgumentResolver testArgumentResolver() {
        return new TestArgumentResolver();
    }
}

public class TestArgumentResolver implements HandlerMethodArgumentResolver {

    @Override
    public boolean supportsParameter(MethodParameter methodParameter) {
        //判断Controller上是否存在该注解,如果存在就之下下边的resovleArgument方法进行参数解析
        return methodParameter.hasParameterAnnotation(TestParam.class);
    }

    @Override
    public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer,
                                  NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory)
            throws Exception {

        //获取参数上的对应的主注解
        TestParam testParamAnn = methodParameter.getParameterAnnotation(TestParam.class);
        //获取注解上的参数
        String paramName = testParamAnn.name();
        if (paramName.equals("")) {
            paramName = methodParameter.getParameterName();
        }

        //获取request请求中的参数,
        Object parameter = nativeWebRequest.getNativeRequest(HttpServletRequest.class).getParameter(paramName);

        //可以根据具体的业务在此进行具体的参数转换逻辑。。。。。
        return parameter == null || parameter.equals("") ? testParamAnn.defaultVaule() : parameter;
    }
}

@Target(value = ElementType.PARAMETER)
@Retention(value = RetentionPolicy.RUNTIME)
public @interface TestParam {
    String name() default "";
    String value() default "";
    String defaultVaule() default "";
}

addReturnValueHandlers

该方法的功能是一个注册返回值解析器的,这个返回值解析器可以统一的将数据以一定的格式返回给前端。以下代码中有很多注意的地方,请认真查看,具体的原因我就不一一细说了,百度上有很多这些资料。

@Configuration
public class SysWebConfig extends WebConfig {
	@Override
    public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {
        returnValueHandlers.add(testReturnValueHandler());
        super.addReturnValueHandlers(returnValueHandlers);
    }

    @Bean
    public TestReturnValueHandler testReturnValueHandler() {

        return new TestReturnValueHandler();
    }
}

public class TestReturnValueHandler implements HandlerMethodReturnValueHandler {

    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public boolean supportsReturnType(MethodParameter returnType) {
        //只有带有TestReturnValue的注解参会相应的Controller的返回值进行转换或者封装
        return returnType.hasMethodAnnotation(TestReturnValue.class);
    }

    @Override
    public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer,
                                  NativeWebRequest webRequest) throws Exception {
        //特别注意的是,如果不想返回视图那么这里一定要设置成true,他的作用类似于@ResponseBody的功能
        mavContainer.setRequestHandled(true);
        //统一的返回类型
        ReturnInfo<Object> returnInfo = new ReturnInfo<>();
        returnInfo.OK();
        returnInfo.setT(returnValue);
        HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);

        response.addHeader("Content-type", MediaType.APPLICATION_JSON_UTF8_VALUE);
        response.getWriter().append(objectMapper.writeValueAsString(returnInfo));
    }
}


@Target ( {ElementType.TYPE, ElementType.METHOD})
@Retention(value = RetentionPolicy.RUNTIME)
public @interface TestReturnValue {

}

@Validated
@Controller
@RequestMapping("/test")
public class TestController {

    /**
     * 特别注意的是,这里的Controller方法一定不能返回一个String类型,因为如果返回的是String类型
     * 他默认的就会去找对应的视图,早晨请求404
     * @return
     */
    @RequestMapping(value = "/returnValue")
    @TestReturnValue
    public Object returnValue() {
        return "liyuzhi";
    }
}

configureHandlerExceptionResolver

该方法的功能是注册Controller异常处理器的,其中的异常处理器可以统一处理Controller的异常

@Configuration
public class SysWebConfig extends WebConfig {
	  @Override
    public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
        exceptionResolvers.add(testExceptionHandler());
        super.configureHandlerExceptionResolvers(exceptionResolvers);
    }

    @Bean
    public TestExceptionHandler testExceptionHandler() {
        return new TestExceptionHandler();
    }
}

public class TestExceptionHandler extends AbstractHandlerExceptionResolver {

    //由于spring自带了异常处理器,我们想要执行我们自己的异常处理器
    //那么就需要将我们的异常处理器的处理顺序放在前边,否则该异常处理器不会生效
    @Override
    public int getOrder() {
        return 0;
    }

    @Override
    protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, Object
            handler, Exception ex) {
        ex.printStackTrace();
        //如果Controller遇到异常就会跳转到这个视图
        //具体业务逻辑肯定是很复杂的,可以根据具体的业务来将这一块细化一下
        return new ModelAndView("liyuzhi");
    }
}


@Validated
@Controller
@RequestMapping("/test")
public class TestController {

    /**
     * 特别注意的是,这里的Controller方法一定不能返回一个String类型,因为如果返回的是String类型
     * 他默认的就会去找对应的视图,早晨请求404
     *
     * @return
     */
    @RequestMapping(value = "/returnValue")
    @TestReturnValue
    public Object returnValue() {
        return 1;
    }


    /**
     * 特别注意的是,这里的Controller方法一定不能返回一个String类型,因为如果返回的是String类型
     * 他默认的就会去找对应的视图,早晨请求404
     *
     * @return
     */
    @RequestMapping(value = "/exceptionResult")
    @TestReturnValue
    public Object exceptionResult() {
        throw new RuntimeException("");
    }
}


猜你喜欢

转载自blog.csdn.net/Suubyy/article/details/84291700