no5-第四章第一次课:内置容器-springmvc支持

飞一样的编程
飞一样的编程
擅长邻域:Java,MySQL,Linux,nginx,springboot,mongodb,微信小程序,vue

分类: springboot 专栏: springboot学习 标签: 内置容器-springmvc支持

2023-03-17 19:16:09 727浏览

内置容器-springmvc支持

1.内置容器

1.1内置容器配置

SpringBoot内置了Tomcat、Jetty、 Undertow 三种web容器,默认使用Tomcat。

1.2切换容器

pom中剔除Tomcat内置容器并新增jetty内置容器

 <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
      <!--排除默认的Tomcat容器-->
      <exclusions>
          <exclusion>
              <groupId>org.apache.tomcat.embed</groupId>
              <artifactId>tomcat-embed-core</artifactId>
          </exclusion>
      </exclusions>
  </dependency>

  <!--增加jetty starter依赖-->
  <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-jetty</artifactId>
  </dependency>

2.springMVC支持

2.1静态资源

  • springboot默认的静态资源设置类ResourceProperties

优先级分别是:

"classpath:/META-INF/resources/",
"classpath:/resources/", 
"classpath:/static/", 
"classpath:/public/"
  • 静态资源加前缀,防止跟controller层重叠
spring.mvc.static-path-pattern=/aaa/**
  • 固定static下为静态资源存放位置
spring.resources.static-locations=classpath:/static/
  • 配置类的方式给访问静态资源加前缀
@Configuration
public class AppConfig implements WebMvcConfigurer {
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/bbb/**")
                .addResourceLocations("classpath:/static/");
    }
}
  • 自定义静态资源存放目录
spring.resources.static-locations=classpath:/c55/

2.2设置首页

直接在默认的静态资源存放的位置写一个index.html即可。当然自定义的静态资源存放路径下也可以。

2.3网站logo设置

favicon.ico放到静态资源路径下即可

如果遇到访问不到此文件的话,要看是不是配置了拦截器给拦截掉了。

关于网站ico小图标的问题可以看我之前总结的笔记:

此处为语雀内容卡片,点击链接查看:https://www.yuque.com/feiyiyangdebiancheng/ekgbw2/tefp73

3.拦截器

依赖于web框架,本质是aop面向切面编程,只拦截control层。常见的应用场景:

  • 权限检查:例如用户登录
  • 日志记录:记录请求的重要信息,仪表与信息监控、信息统计
  • 性能监控:可以记录某个请求通过拦截器进入处理器的开始时间和结束时间,从而得到该请求的耗时
  • 通用行为:拦截器还可以读取cookie,获取用户信息,并将用户信息存放在请求中
public class MyIntercept implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("MyIntercept preHandle exec ...");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("MyIntercept postHandle exec ...");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("MyIntercept afterCompletion exec ...");
    }
}
@Configuration
public class AppConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyIntercept()).addPathPatterns("/**")
                .excludePathPatterns("/dologin","/reg");
    }

4.三大web组件

4.1servlet

@WebServlet(urlPatterns = "/myServlet",name = "myServlet")
public class MyServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        PrintWriter out = resp.getWriter();
        out.write("<h1>my servlet</h1>");
        out.flush();
        out.close();

    }

}

使其生效

@SpringBootApplication
@ServletComponentScan("com.bdqn.c55.web")
public class AppCh4Web {

4.1过滤器

通过过滤器对web的资源静态html文件,静态图片 jsp servlet等进行拦截,比如:设置url的访问权限、过滤敏感词汇、压缩响应信息等,过滤器还适用于对用户请求和响应对象进行检查和修改。

filter的生命周期大致分为三个阶段:实例化,初始化,销毁。

@WebFilter(filterName = "MyFilter",urlPatterns = "/test")
public class MyFilter implements Filter {
    public void destroy() {
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {

        System.out.println("MyFilter doFilter exec ... ");
        chain.doFilter(req, resp);//放行
    }

    public void init(FilterConfig config) throws ServletException {

    }

}

使其生效

@SpringBootApplication
@ServletComponentScan("com.bdqn.c55.web")
public class AppCh4Web {

4.3监听器

监听web中的一些特定事件,主要的应用场景:监听session会话获取当前系统在线人数,监听客户端请求的ServletRequest来获取用户的一些访问信息

1.监听servletContext对象

主要用于初始化一些不经常改变的数据,比如网站首页的一些菜单信息,用户账号相关信息等,将这些数据存进application作用域中,在一定程度上会起到缓存的作用,页面上使用数据的时候直接从application作用域获取,而不是每次获取数据都要从数据库中获取

1.自定义ServletContext的监听器

@Component
public class ServletContextListener implements ApplicationListener<ContextRefreshedEvent> {


    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {

        //获取application上下文信息
        ApplicationContext applicationContext=contextRefreshedEvent.getApplicationContext();

        //获取userservice对象
        UserService userService = applicationContext.getBean(UserService.class);

        UserInfo userinfo = userService.getUser();

        ServletContext servletContext =applicationContext.getBean(ServletContext.class);

        servletContext.setAttribute("user",userinfo);
    }
}
  1. controller层从application作用域中获取初始化的user信息
@RestController
public class UserController  {

    @GetMapping("/user")
    public UserInfo getuser(HttpServletRequest request){
        ServletContext servletContext=request.getServletContext();
        UserInfo  user = (UserInfo) servletContext.getAttribute("user");
        return user;
    }

}

2.监听HTTP会话session对象

监听session对象,以统计当前web应用在线用户总数量。

  1. 自定义session会话监听器
@Component
public class SessionListener implements HttpSessionListener {
    //用于记录在线用户数量
    public static Integer count = 0;

    @Override
    public void sessionCreated(HttpSessionEvent se) {
        System.out.println("新用户上线");
        count++;
        se.getSession().getServletContext().setAttribute("count",count);
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        System.out.println("用户下线");
        count--;
        se.getSession().getServletContext().setAttribute("count",count);
    }
}
  1. controller测试该监听器
 @GetMapping("/countOnlineUser")
    public String getOnlineUserCount(HttpServletRequest request, HttpServletResponse response){
        Cookie cookie;
        try {
            //将sessionId记录到浏览器中,防止在服务器找不到原有的用户信息,重新创建session
            cookie = new Cookie("JSSIONID", URLEncoder.encode(request.getSession().getId(), "utf-8"));
            cookie.setPath("/");
            //设置cookie有效期为1天
            cookie.setMaxAge(24*60*60);
            response.addCookie(cookie);
        }catch (Exception e){
            e.printStackTrace();
        }
        Integer count = (Integer)request.getSession().getServletContext().getAttribute("count");
        return "total user online:"+count;
    }

3.监听servletRequest对象

监听客户端请求,主要是为了获取用户的一些请求信息。

  • 监听request的类
@Component
public class RequestListener implements ServletRequestListener {

    @Override
    public void requestInitialized(ServletRequestEvent sre) {
        System.out.println("此次请求开始");
        HttpServletRequest request = (HttpServletRequest)sre.getServletRequest();
        System.out.println("sessionId:"+request.getRequestedSessionId()+"; url:"+request.getRequestURL());
        String username = (String)request.getAttribute("username");
        if (username == null){
            request.setAttribute("username","tudoudou");
        }
    }

    @Override
    public void requestDestroyed(ServletRequestEvent sre) {
        System.out.println("此次请求结束");
        HttpServletRequest request = (HttpServletRequest) sre.getServletRequest();
        String username = (String)request.getAttribute("username");
        System.out.println("requestScope中username为:"+username);
    }
}

补充:可以监控客户的ip

  @Override
    public void requestInitialized(ServletRequestEvent sre) {
        System.out.println("创建request对象");
        HttpServletRequest request = (HttpServletRequest) sre.getServletRequest();
        //请求的地址
        System.out.println("getRequestURL:" + request.getRequestURL());
        System.out.println("getRequestURI:" + request.getRequestURI());
        System.out.println("getLocalAddr:" + request.getLocalAddr());//获取访客ip
    }
  • 测试类control
 @GetMapping("/testRequest")
    public String testRequest(HttpServletRequest request){
        String username = (String)request.getAttribute("username");
        System.out.println("init requestScope username:"+username);
        return "success";
    }

4.自定义监听器

实现自定义监听器需要三步:

1自定义事件,即监听器用来监听的事件,该事件需要继承applicationEvent对象,

/**
 * 自定义监听事件
 */
public class MyEvent extends ApplicationEvent {

    private UserInfo user;

    public MyEvent(Object source, UserInfo user) {
        super(source);
        this.user = user;
    }

    public UserInfo getUser() {
        return user;
    }

    public void setUser(UserInfo user) {
        this.user = user;
    }
}

2自定义一个监听器加监听自定义的时间,需要实现applicationListener接口

public class MyListener implements ApplicationListener<MyEvent> {

    @Override
    public void onApplicationEvent(MyEvent myEvent) {
        UserInfo user = myEvent.getUser();
        System.out.println("username:"+user.getUsername());
    }
}

3手动发布事件,发布后监听器才能监听到。

    @Override
    public UserInfo publishMyEvent() {
        UserInfo userInfo = new UserInfo(1,"afan","123456");

        applicationContext.publishEvent(new MyEvent(this,userInfo));
        return userInfo;
    }

测试类

  @GetMapping("/publish")
    public UserInfo publishMyEvent(HttpServletRequest request){
        return userService.publishMyEvent();
    }

4.4过滤器和拦截器的区别

  • 过滤器是基于函数回调的,拦截器是基于servlet容器的
  • 过滤器几乎可以过滤所有的请求,但是拦截器只能拦截controller的接口请求
  • 拦截器可以访问action上下文,值栈里的对象,而过滤器不能访问
  • 在controller的生命周期中,过滤器只能在容器初始化时被调用一次,拦截器可以多次被调用。
  • 拦截器可以获取IOC容器中的各种bean,根据需求进行业务处理,但是过滤器不支持这一点。

4.5采用配置类的方式注入组件

场景:假设我们要用的servlet等组件是第三方的,我们没办法在jar包里添加注解。这个时候就需要采用配置类的方式

//装配servlet
    @Bean
    ServletRegistrationBean servletRegistrationBean(){
        ServletRegistrationBean servletRegistrationBean= new ServletRegistrationBean(new MyServlet(),"/myservlet");
        return servletRegistrationBean;
    }

 //装配filter
    @Bean
    FilterRegistrationBean filterRegistrationBean(){
        FilterRegistrationBean filterRegistrationBean= new FilterRegistrationBean(new MyFilter());
        filterRegistrationBean.setUrlPatterns(Arrays.asList("/test"));

        return filterRegistrationBean;
    }

 //装配监听器
    @Bean
    ServletListenerRegistrationBean servletListenerRegistrationBean(){
        ServletListenerRegistrationBean registrationBean= new ServletListenerRegistrationBean(new MyListener());
        return registrationBean;
    }

4.6实用小例子——图形验证码

 <!--用于生成图形验证码-->
        <dependency>
            <groupId>com.github.penggle</groupId>
            <artifactId>kaptcha</artifactId>
            <version>2.3.2</version>
        </dependency>
 <!--以jar包的方式引入jQuery-->
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>jquery</artifactId>
            <version>3.4.1</version>
        </dependency>
    @Bean
    ServletRegistrationBean kaptchaServletBean(){
        ServletRegistrationBean servletRegistrationBean= new ServletRegistrationBean(new KaptchaServlet(),"/code");
        return servletRegistrationBean;
    }

前端页面

<body>
<form action="/dologin" method="post">
    用户名:<input type="text" name="username"><br>
    密码:<input type="password" name="pass"><br>
    验证码:<input type="text" name="code"> <img src="code" alt="获取验证码">
    <br>
    <input type="submit" value="登录">
</form>

  
<script src="webjars/jquery/3.4.1/jquery.js"></script>
<script>
    $(function () {
        $("#codeImg").click(function () {
            $("#codeImg").attr("src","/code")
        })
    })
</script>
</body>

好博客就要一起分享哦!分享海报

此处可发布评论

评论(1展开评论

蓝色妖姬 能力:10

2023-03-23 17:01:01

刘鸡宇到此一游
点击查看更多评论

展开评论

您可能感兴趣的博客

客服QQ 1913284695