SpringBoot自定义配置以及拦截器配置

在进行 SpringBoot 项目开发的过程中,对于 SpringBoot 自带的默认配置我们难免有自己不喜欢的地方。或者你认为更合理更想要的处理方式,这种时候你就可以选择配置自己的处理逻辑。

如果Spring Boot提供的Sping MVC不符合要求,则可以通过一个配置类(注解有@Configuration的类)加上@EnableWebMvc注解来实现完全自己控制的MVC配置。

@EnableWebMvc
@Configuration
public class TestMvc {
    ···
}

通常情况下,Spring Boot的自动配置是符合我们大多数需求的。在你既需要保留Spring Boot提供的便利,有需要增加自己的额外的配置的时候,可以定义一个配置类并继承WebMvcConfigurerAdapter,无需使用@EnableWebMvc注解。

@Configuration
public class TestMvc extends WebMvcConfigurerAdapter{
    ···
}

这里我们提到这个WebMvcConfigurerAdapter这个类,重写这个类中的方法可以让我们增加额外的配置,常用的有如下几个。


自定义资源映射 addResourceHandlers

如果想自定义静态资源映射目录的话,只需重写WebMvcConfigurerAdapter类的addResourceHandlers方法即可。

/**
* {@inheritDoc}
* <p>This implementation is empty.
*
* @param registry
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/illuos1ion/**").addResourceLocations("classpath:/illuos1ion/");
        super.addResourceHandlers(registry);
 }

/ ========================================================================================= /
  
// WebMvcAutoConfiguration 
public void addResourceHandlers(ResourceHandlerRegistry registry) {
       if(!this.resourceProperties.isAddMappings()) {
                logger.debug("Default resource handling disabled");
            } else {
                Integer cachePeriod = this.resourceProperties.getCachePeriod();
                if(!registry.hasMappingForPattern("/webjars/**")) {
                    this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{"/webjars/**"}).addResourceLocations(new String[]{"classpath:/META-INF/resources/webjars/"}).setCachePeriod(cachePeriod));
                }

                String staticPathPattern = this.mvcProperties.getStaticPathPattern();
                if(!registry.hasMappingForPattern(staticPathPattern)) {
                    this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{staticPathPattern}).addResourceLocations(this.resourceProperties.getStaticLocations()).setCachePeriod(cachePeriod));
                }

       }
}
  • 通过addResourceHandler添加映射路径,然后通过addResourceLocations来指定资源文件路径。
  • 访问自定义illuos1ion文件夹中的 item-video.png 图片的地址为 http://localhost:8080/illuos1ion/item-video.png

如果想指定外部的文件目录也很简单,直接通过addResourceLocations方法指定即可:

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/my/**").addResourceLocations("file:E:/illuos1ion/");
    super.addResourceHandlers(registry);
}
  • addResourceLocations 指的是文件放置的目录,addResoureHandler 指的是对外暴露的访问路径

页面跳转 addViewControllers

重写 WebMvcConfigurerAdapter 中的 addViewControllers 方法即可达到你想要的处理效果:

/**
     * 过去要访问一个页面需要先创建个Controller控制类,再写方法跳转到页面
     * 在这里配置后就不需要那么麻烦了,直接访问http://localhost:8080/toLogin就跳转到login.jsp页面了
     * @param registry
     */
@Override
public void addViewControllers(ViewControllerRegistry registry) {
    registry.addViewController("/toLogin").setViewName("login");
    super.addViewControllers(registry);
}

需要注意的是,在这里重写addViewControllers方法,并不会覆盖WebMvcAutoConfiguration中的addViewControllers(在此方法中,Spring Boot将“/”映射至index.html),这也就意味着我们自己的配置和Spring Boot的自动配置同时有效。


拦截器addInterceptors

拦截器在项目中经常使用的,这里介绍下最简单的判断是否登录的使用。
要实现拦截器功能需要完成2个步骤:

  • 创建自己的拦截器类并实现 HandlerInterceptor 接口
  • 重写WebMvcConfigurerAdapter类中的addInterceptors方法把自定义的拦截器类添加进来即可

拦截器代码:

@Component
public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        boolean flag;
        User user = (User) request.getSession().getAttribute("user");
        if (user == null) {
            response.sendRedirect("/login");
            flag = false;
        } else {
            flag = true;
        }
        return flag;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}
  1. 这里简单实现了根据session中是否有User对象来判断是否登录,为空就跳转到登录页,不为空就通过。
  2. 接着,重写WebMvcConfigurerAdapter类中的addInterceptors方法:

Web配置代码:

@Configuration
public class WebMvcConfiguration extends WebMvcConfigurerAdapter{

    @Autowired
    LoginInterceptor loginInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // addPathPatterns 用于添加拦截规则
        // excludePathPatterns 用户排除拦截
        // 映射为 user 的控制器下的所有映射
 registry.addInterceptor(loginInterceptor).addPathPatterns("/login/home").excludePathPatterns("/index", "/");
        super.addInterceptors(registry);
    }
}

拦截器执行流程参考:http://www.jianshu.com/p/f14ed6ca4e56

addPathPatterns("/login/home")/login/home请求拦截,但是排除了/index/请求的拦截。


Html登录代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <title>Login</title>
    <link rel="stylesheet" href="/webjars/bootstrap/3.3.7-1/css/bootstrap.min.css"/>
    <script type="text/javascript" src="/webjars/jquery/3.2.1/jquery.min.js"></script>
</head>
<body>
<form class="form-horizontal" role="form" method="post" action="/login/process">
    <div class="form-group">
        <!--<span class="input-group-addon">用户名</span>-->
        <label class="control-label col-sm-2" for="username">用户名:</label>
        <div class="col-sm-10">
            <input type="text" id="username" name="username" class="form-control" placeholder="Username"/>
        </div>
    </div>

    <div class="form-group">
        <!--<span class="input-group-addon">密码</span>-->
        <label class="control-label col-sm-2" for="password">密  码:</label>
        <div class="col-sm-10">
            <input type="text" id="password" name="password" class="form-control" placeholder="Password"/>
        </div>
    </div>

    <div class="form-group">
        <div class="col-sm-offset-2 col-sm-10">
            <button type="submit" class="btn btn-info">登 录</button>
            <button type="submit" class="btn btn-info">注 册</button>
        </div>
    </div>

</form>
</body>
</html>

控制器代码:

@Controller
@RequestMapping(path = "/login")
public class LoginController {

    @RequestMapping(path = "/process", method = RequestMethod.POST)
    public String login(@RequestParam String username,
                        @RequestParam String password,
                        HttpServletRequest request) {
        if (username.equals("admin") && password.equals("admin")) {
            User user = new User(username, password, "http://www.jiyongguang.xin");
            request.getSession().setAttribute("user", user);
            return "redirect:/login/home";
        }
        return "redirect:/";
    }

    @RequestMapping(path = "/home", method = RequestMethod.GET)
    public String home(Model model) {
        List<User> userList = new ArrayList<User>();
        User user = new User("jyg", "jyg", "http://www.jiyongguang.xin");
        userList.add(user);

        user = new User("lyn", "lyn", "http://www.jiyongguang.xin");
        userList.add(user);
        model.addAttribute("userList", userList);
        return "home";
    }
}

或者可以通过Jquery封装好的AJAX方法来执行一套请求。效果是一样的

$(document).ready(function () {
        $("#login").click(function () {
            $.ajax({
                type: "POST",
                url: "/login/process",
                data: {
                    username: $("#username").val(),
                    password: $("#password").val()
                },
                dataType: "json",
                success: function (data) {
                    if (data.code == 1)
                        <!-- 当前页面打开URL页面 -->
                        window.location.href = "/login/home";
                    else
                        alert("账号密码不能为空!");
                }
            });
        });
});

控制器代码:

@RequestMapping(value = "/process", method = RequestMethod.POST)
@ResponseBody
public String index(@RequestParam String username,
                    @RequestParam String password,
                    HttpServletRequest request) {
        Map<String, Object> map = new HashMap<String, Object>();
        if (username.equals("admin") && password.equals("admin")) {
            User user = new User(username, password, "http://www.jiyongguang.xin");
            request.getSession().setAttribute("user", user);
            return JsonUtil.getJsonString(JsonUtil.REQUEST_SUCCESS);
        } else {
            return JsonUtil.getJsonString(JsonUtil.REQUEST_Fail, "用户名或密码错误");
        }
}

这样访问/login/home的时候,如果未登录就会跳转到login.html页面(注意缓存),而访问http://localhost:8080/indexhttp://localhost:8080不会被拦截。

更多配置可以查看WebMvcConfigurerAdapter的类的API。因其是WebMvcConfigurer接口的实现,所以WebMvcConfigurer的API方法也可以用来配置MVC。只是实现这个接口的话,要实现所有的方法,这个就比较麻烦了。所以还是推荐使用继承WebMvcConfigurerAdapter类来处理。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342

推荐阅读更多精彩内容