关于Spring、SpringMVC我们前面几篇博客都介绍了很多,但是还不够,这些框架中涉及到的注解、配置非常多,那么我们今天再来介绍一个SpringMVC的基本配置,灵活的使用这些配置,可以让我们在开发中更加灵活的处理业务逻辑。OK,废话不多说,那就开始吧。

SpringMVC基础配置(通过注解配置,非xml配置)这篇文章中我们的案例都会有一个MvcConfig的类用来做一个简单的配置,主要是通过ViewResolver来解决映射路径和实际页面的位置,这个类我们还可以继续扩展,让其解决更多的问题,我列举几个:

  • 静态资源映射
  • 拦截器使用
  • 全局配置问题

等等。这些问题我们可以重新定义一个新的类来解决,也可以扩展MvcConfig来解决。我们来一个个看看。

静态资源映射

我们都知道在SpringMVC中静态资源文件都是直接访问的,而不需要映射,这些静态资源主要包括js文件、css文件、图片文件等,那么这个需要我们单独处理,否则系统会找不到路径。OK,这个问题的解决也很容易,假设我有一张图片放在src/main/resources/assets/img目录下,然后想在jsp页面中将其展示出来,我们先来看看jsp页面:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Hello Sang!</title>
</head>
<body>
<p>Welcome To SpringMVC World!</p>
<p>
    <img src="../assets/img/1.png">
</p>
</body>
</html>

然后我们创建MVCConfig类,作用还是和上文一样,不同的是这次我们继承自WebMvcConfigurerAdapter,然后重写WebMvcConfigurerAdapter类中的addResourceHandlers方法来解决这个问题。如下:

@Configuration
@EnableWebMvc
@ComponentScan("org.sang")
public class MVCConfig 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;
    }

    /**
     * /**的意思是所有文件,包括文件夹中的子文件
     * /*是所有文件,不包含子文件
     * /是web项目的根目录
     * @param registry
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        //两个*表示以/assets开始的任意层级的路径都可以访问得到图片,如<img src="../assets/img/1.png">
        //一个*表示只可以访问assets目录下的图片文件
        registry.addResourceHandler("/assets/**").addResourceLocations("classpath:/assets/");
    }
}

OK,这里继承WebMvcConfigureAdapter之后,我们可以重写它里边的很多方法,重写这些方法我们可以对SpringMVC进行配置,addResourceHandler指的是访问路径,addResourceLocations指的是文件放置目录。

拦截器

拦截器在JavaEE开发中还是非常重要的,乱码解决、权限控制等等都会用到,使用Servlet的时候有一个Filter类用来进行过滤,那么SpringMVC也在这方面给我们提供了相应的解决方案。

  1. 定义拦截器

拦截器的定义我们可以通过继承HandlerInterceptorAdapter或者实现HandlerInterceptor接口,我这里以实现接口为例:

public class MyInterceptors implements HandlerInterceptor {
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
        System.out.println("preHandle");
        return true;
    }

    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle");
    }

    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
        System.out.println("afterCompletion");
    }
}

preHandle方法发生在请求发生前执行,postHandle发生在请求发生后执行,afterCompletion在请求完成时执行,实际上执行时机紧挨着postHandle这个方法。然后在MVCConfig类中添加addInterceptors方法注册拦截器,如下:

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(myInterceptors());
    }
    @Bean
    public MyInterceptors myInterceptors() {
        return new MyInterceptors();
    }

这样注册成功之后,我们在浏览器中访问时,打印日志如下:

全局配置

全局资源的配置问题,我们可以通过@ControllerAdvice来把控制器的全局配置放在同一个位置,这样我们可以统一处理下面几个问题:

1 .全局异常处理

2 .预设键值对绑定到Model中

3 .预处理前台请求参数

OK,下面来一个一个看一下。

全局异常处理

全局异常主要是通过@ExceptionHandler这个注解来解决。如下:

@ControllerAdvice
public class ExceptionHandlerAdvice {
    //@ExceptionHandler用来设置拦截条件,这里表示拦截所有的Exception
    @ExceptionHandler(value = Exception.class)
    public ModelAndView exception(Exception e, WebRequest request) {
        ModelAndView modelAndView = new ModelAndView("error");
        modelAndView.addObject("errorMsg", e.getMessage());
        return modelAndView;
    }
}

首先通过@ControllerAdvice声明一个控制器建言,由于这个注解组合了@Component注解,这个这个类会自动注册为Spring容器中的Bean。@ExceptionHandler可以定义全局处理,其中Value属性用来表示过滤拦截条件,Exception.class表示拦截所有的Exception。构造ModelAndView时传入的error表示出错的页面。OK,我们来看一下控制器,我在控制器中添加如下方法:

@RequestMapping("/user")
    public String user(@ModelAttribute("msg") String msg, UserBean userBean) {
        System.out.println("username is :" + userBean.getUsername() + ";and id is :" + userBean.getId());
        throw new IllegalArgumentException("抱歉,参数异常/ 来自@ModelAttribute:" + msg);
    }

当我访问/user这个地址的时候,直接抛一个异常,这个异常会被使用了@ExceptionHandler注解并且满足过滤条件的方法接收并处理,我们这里当然是来到了exception这个方法中,在这个方法中我们又定位到了error.jsp页面。同时这里的参数还使用了@ModelAttribute注解,这个注解我在下一小节再来说。我们再来看看这个error.jsp页面:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>出错啦</title>
</head>
<body>
<p>
    <h1>${errorMsg}</h1>
</p>
</body>
</html>

这个页面很简单,就显示一下错误信息就行了。我们来看看访问结果:

控制台输出的错误信息:

预设键值对绑定到Model中

有的时候我们需要预设键值对到Model中,就像上面那个案例那样,这个时候我们可以在ExceptionHandlerAdvice类中再添加一个方法:

@ModelAttribute
    public void addAttributes(Model model) {
        model.addAttribute("msg", "额外信息");
    }

在这个方法中我们向Model中绑定键值对,绑定完成之后,在任何Controller中我们都可以通过给方法的参数设定@ModelAttribute注解来访问这里存入的值,相当于这里的值是一个全局变量。OK ,这里的访问案例和上文一致,我就不再赘述了。

预处理前台请求参数

OK,还有一种需求,有的时候我们需要预处理前台传来的参数,比如说禁止掉某一个参数,这个也可以统一处理,OK,继续在ExceptionHandlerAdvice方法中添加方法

@InitBinder
    public void initBinder(WebDataBinder webDataBinder) {
        webDataBinder.setDisallowedFields("id");
    }

这个表示将客户端传来的id参数忽略掉,但是注意接收的方式,这里通过对象来接收参数的时候才有效(通过对象接收这个参数的时候才会屏蔽掉id),如果直接提取还是可以提取到的,我们来看一下控制器方法,还是刚才抛异常那个方法,但是在抛异常之前我先打印一下日志:

@RequestMapping("/user")
    public String user(@ModelAttribute("msg") String msg, UserBean userBean) {
        System.out.println("username is :" + userBean.getUsername() + ";and id is :" + userBean.getId());
        throw new IllegalArgumentException("抱歉,参数异常/ 来自@ModelAttribute:" + msg);
    }

我们看看控制台的输出:

OK, id已经被屏蔽掉了。

本案例下载地址:

本案例GitHub地址

以上。

参考资料:

《JavaEE开发的颠覆者 Spring Boot实战》第四章

SpringMVC常用配置的更多相关文章

  1. SpringMVC常用配置(二),最简洁的配置实现文件上传

    Spring.SpringMVC持续介绍中,基础配置前面已经介绍了很多,如果小伙伴们还不熟悉可以参考这几篇文章: 1.Spring基础配置 2.Spring常用配置 3.Spring常用配置(二) 4 ...

  2. SpringMVC常用配置-文件上传-基于Servlet 3.0

    [2] http://www.cnblogs.com/weilu2/p/springmvc_MultipartConfigElement_tomcat_webapps_work.html

  3. SpringMVC常用配置-处理程序异常以及404错误

  4. SpringMVC常用配置-Controller返回格式化数据如JSON、XML的配置方式和机制

  5. SpringMVC常用配置-添加静态资源处理器-针对SpringMVC中静态资源无法访问的问题

  6. SpringMVC常用配置-Controller中的各种配置(基于Java API和注解)

  7. SpringMVC常用配置-配置DispatcherServlet映射请求路径的方式

  8. Spring 和 SpringMVC 常用注解和配置(@Autowired、@Resource、@Component、@Repository、@Service、@Controller的区别)

    Spring 常用注解 总结内容 一.Spring部分 1.声明bean的注解 2.注入bean的注解 3.java配置类相关注解 4.切面(AOP)相关注解 5.事务注解 6.@Bean的属性支持 ...

  9. SpringMVC常用注解實例詳解3:@ResponseBody

    我的開發環境框架:        springmvc+spring+freemarker開發工具: springsource-tool-suite-2.9.0JDK版本: 1.6.0_29tomcat ...

随机推荐

  1. PHP面向对象-看父类调用子类方法

    大部分面向对象编程语言中,父类是不允许调用子类的方法的,但是PHP中可以 1.父类调用子类方法示例 class A { public function testa() { $this->test ...

  2. thinkphp3.2v

    1.thinphp环境搭建 一.将thinkphp文件拿出来,对我们有用的是cof和library,其他对开发都没有作用. 在thinkphp/library/think文件夹中几个重要的文件 1.A ...

  3. [LeetCode] Maximum Length of Pair Chain 链对的最大长度

    You are given n pairs of numbers. In every pair, the first number is always smaller than the second ...

  4. python的变量与赋值

    1.变量的命名规则 变量其实通过一个标记调用内存中的值,而变量名就是这个标记的名称,但是万一这个标记已经被提前占用或者解释器认为这个标记是不合法的,那么就会报错.下面总结了一下变量的命名规则: 1.不 ...

  5. HtmlUnit入门二

    由于在在WebClient中,默认支持对CSS,JavaScript的解析,因此会总是会出现很多错误信息,并且执行速度也很慢. 因此,我们可以选择关闭掉WebClient对CSS,JavaScript ...

  6. 计蒜客NOIP模拟赛4 D2T1 鬼脚图

    鬼脚图,又称画鬼脚,在日本称作阿弥陀签,是一种经典游戏,也是一种简易的决策方法,常常用来抽签或决定分配组合. 下图就是一张鬼脚图,其包含若干条竖线和若干条横线.请注意,横线只能水平连接相邻的两条竖线, ...

  7. bzoj 5286: [Hnoi2018]转盘

    Description Solution 首先注意到一个点不会走两次,只会有停下来等待的情况,把序列倍长 那么如果枚举一个起点\(i\),答案就是 \(min(max(T[j]+n-(j-i)-1)) ...

  8. hdu 5868 Polya计数

    Different Circle Permutation Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 262144/262144 K ...

  9. 【Codeforces Round #430 (Div. 2) A C D三个题】

    ·不论难度,A,C,D自己都有收获! [A. Kirill And The Game] ·全是英文题,述大意:    给出两组区间端点:l,r,x,y和一个k.(都是正整数,保证区间不为空),询问是否 ...

  10. [BZOJ]1059 矩阵游戏(ZJOI2007)

    虽然说是一道水题,但小C觉得还是挺有意思的,所以在这里mark一下. Description 小Q是一个非常聪明的孩子,除了国际象棋,他还很喜欢玩一个电脑益智游戏——矩阵游戏.矩阵游戏在一个N*N黑白 ...