Spring Boot异常、MVC及Java Web应用与Druid监控

本文介绍了Spring Boot如何处理全局异常,包括创建自定义异常控制器和配置error.html页面。接着讲解了Spring Boot的MVC拦截器实现,以及AOP在监控方法执行时间中的应用。此外,还讨论了Spring Boot的静态资源处理和JavaWeb的Servlet、Filter、Listener组件。最后,详细阐述了如何配置阿里Druid连接池进行监控,包括设置权限、数据库SQL统计和过滤规则。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

处理全局异常Spring Boot MVC

提示

Spring Boot默认采用了org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration该类自动配置了org.springframework.boot.web.servlet.error.ErrorController该类,它里面定义了两个error处理方式,一个是json,一个html

可以看一下下图

①Spring Boot自动配置的错误组件ErrorMvcAutoConfiguration

②ErrorMvcAutoConfiguration类中的BasicErrorController(定义了error,分别是json和html的)

③可以看到默认的错误信息

配置全局异常

  1. 编写Controller继承AbstractErrorController或者实现ErrorController接口

    @Controller
    public class GlobalErrorController implements ErrorController{
        
        @RequestMapping("/error")
        public ModelAndView exe(){
            return new ModelAndView("error");
        }
        
        @Override
        public String getErrorPath(){
            return "/error";
        }
        
    }
    

    需要注意,重写的方法返回值请作为自定义ModelAndView组建的名字,并且视图组件添加@RequestMapping注解

  2. 配置error.html错误页面

    我这里使用thymeleaf模板

    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8"/>
        <title>错误页面</title>
    </head>
    <body>
    <h3>服务器坐火箭去太空了~</h3>
    </body>
    </html>
    

配置单个异常前的准备

我这里为了测试编写了一个计算阶乘的Controller

package vip.javer.springbootmvc.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import vip.javer.springbootmvc.entity.Tips;

import java.math.BigInteger;
import java.util.ArrayList;

/**
 * Class Describe:计算Controller,这里是为了测试单个异常
 *
 * @author biuaxia
 * @date 2018/12/13 19:23
 */
@RestController
public class CacController {

    @RequestMapping(value = "cac.do", method = {RequestMethod.GET, RequestMethod.POST})
    /**
     * TestUrl:/cac.do?no=123
     */
    public Tips cac(int no) {
        Tips tips = new Tips();
        BigInteger integer;
        Integer maximumNumberOfAfferents = 300;
        if (no > maximumNumberOfAfferents) {
            tips.setStatusCode(400);
            tips.setMsg("error");
            tips.setData("您传入的数字大于300,对服务器性能消耗过大,请调小数字");
            return tips;
        }
        try {
            integer = bigNumber(no);
        } catch (Exception e) {
            tips.setStatusCode(400);
            tips.setMsg("error");
            tips.setData("计算异常");
            return tips;
        }
        tips.setStatusCode(200);
        tips.setMsg("success");
        tips.setData(integer);
        return tips;
    }

    /**
     * 阶乘算法
     * 利用BigInteger类计算阶乘
     *
     * @param num
     * @return
     */
    private static synchronized BigInteger bigNumber(int num) {
        //创建集合数组
        ArrayList list = new ArrayList();
        //往数组里添加一个数值
        list.add(BigInteger.valueOf(1));
        for (int i = list.size(); i <= num; i++) {
            //获得第一个元素
            BigInteger lastfact = (BigInteger) list.get(i - 1);
            //获得下一个数组
            BigInteger nextfact = lastfact.multiply(BigInteger.valueOf(i));
            list.add(nextfact);
        }
        //返回数组中的下标为num的值
        return (BigInteger) list.get(num);
    }

}

代码写好了,如果说我们传入的参数没有或者其他情况则会触发我们的全局异常,那么如何自定义这里的异常?

配置单个异常

在之前的Controller再追加代码

@ExceptionHandler
public Tips error(Exception e) {
    Tips tips = new Tips();
    tips.setStatusCode(413);
    tips.setMsg("waring");
    tips.setData("出异常啦\t" + e.getCause());
    return tips;
}

Spring Boot的MVC拦截器

  1. 编写组件实现HandlerInterceptor

    package vip.javer.springbootmvc.interceptor;
    
    
    import org.springframework.stereotype.Component;
    import org.springframework.ui.ModelMap;
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    /**
     * Class Describe:
     *
     * @author biuaxia
     * @date 2018/12/13 19:45
     */
    @Component
    public class MvcInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
            String param = httpServletRequest.getQueryString();
            System.out.println("之前\t请求了:" + httpServletRequest.getRequestURI() + "\t携带参数为:" + param + "\tURL:" + httpServletRequest.getRequestURL());
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
            System.out.println("已处理\t");
        }
    
        @Override
        public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
            System.out.println("准备返回数据\t");
        }
    }
    

    需要注意的是,这里请加上**@Component**注解,方便后面注入

  2. 新建配置组件继承org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter

    package vip.javer.springbootmvc.interceptor;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
    
    /**
     * Class Describe:
     *
     * @author biuaxia
     * @date 2018/12/13 19:50
     */
    @Configuration
    public class MvcConfiguration extends WebMvcConfigurerAdapter {
    
        /**
         * 通过扫描注入刚才的MvcInterceptor
         */
        private final MvcInterceptor interceptor;
    
        @Autowired
        public MvcConfiguration(MvcInterceptor interceptor) {
            this.interceptor = interceptor;
        }
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(interceptor).addPathPatterns("/*");
        }
    
    }
    

注意

addPathPatterns();方法内可以传入数据,我这里是全拦截了

Spring Boot 使用AOP

使用aop技术监控每个方法执行时间

切面 计算方法执行时间

切入点 所有Controller类的方法

通知 环绕通知@Around

配置AOP的使用

  1. 引入AOP工具包spring-boot-starter-aop

  2. 新建计时类

    package vip.javer.springbootmvc.aspect;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.springframework.stereotype.Component;
    import org.springframework.util.StopWatch;
    
    /**
     * Class Describe:
     * 计时类,配合Aop使用
     *
     * @author biuaxia
     * @date 2018/12/13 20:02
     */
    @Component
    @Aspect
    public class WatchBean {
    
        @Around("within(vip.javer.springbootmvc.controller.*)")
        public Object exe(ProceedingJoinPoint point) throws Throwable {
            StopWatch watch = new StopWatch();
            watch.start();
            Object o = point.proceed();
            watch.stop();
            System.out.println("类" + point.getTarget().getClass().getName() + "\t方法" + point.getSignature().getName() + "\t执行时间TimeSeconds:" + watch.getTotalTimeSeconds() + "\tTimeMillis:" + watch.getTotalTimeMillis());
            return o;
        }
    
    }
    

Spring Boot静态资源

优先级
最高:META-INF/resources
高:resources
中:static
低:public

例如我想要访问java目录下的资源

可以这么做:
如果想要自定义资源,继承WebMvcConfigurerAdapter,然后重写addResourceHandlers方法

package vip.javer.springbootmvc.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

/**
 * Class Describe:
 * 自定义资源文件夹
 *
 * @author biuaxia
 * @date 2018/12/13 20:15
 */
@Configuration
public class CustomResourceFolderConfiguration extends WebMvcConfigurerAdapter {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/java/**").addResourceLocations("classpath:/java/");
    }
}

JavaWeb的应用

JavaWeb三大组件

  1. Servlet
  2. Filter
  3. Listener

Servlet

  1. 新建Servlet类,继承HttpServlet

  2. 添加注解@WebServlet

    name->对应Servlet-name
    urlPatterns->url-pattern
    initParams{}->init-param
    loadOnStartup->load-on-startup
    
  3. 主启动类添加@ServletComponentScan(添加后自动扫描@WebServlet,@WebFilter,@WebListener)

    package vip.javer.springbootmvc.servlet;
    
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.io.PrintWriter;
    
    /**
     * Class Describe:
     *
     * @author biuaxia
     * @date 2018/12/13 20:26
     */
    @WebServlet(name = "helloServlet", urlPatterns = "/hello.do")
    public class HelloServlet extends HttpServlet {
        @Override
        public void service(HttpServletRequest req, HttpServletResponse res) throws IOException {
            res.setContentType("text/html;charset=UTF-8");
            PrintWriter out = res.getWriter();
            out.print("你好世界!");
            out.print("<br/>");
            out.print("HelloWorld");
            out.flush();
            out.close();
        }
    }
    

    主启动类

    package vip.javer.springbootmvc;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.web.servlet.ServletComponentScan;
    
    /**
     * @author wlmpr
     */
    @SpringBootApplication
    @ServletComponentScan
    public class SpringbootmvcApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(SpringbootmvcApplication.class, args);
        }
    
    }
    

Filter

编写Filter组件类,实现Filter接口,在doFilter方法定义拦截逻辑

package vip.javer.springbootmvc.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/**
 * Class Describe:
 *
 * @author biuaxia
 * @date 2018/12/13 20:46
 */
@WebFilter(filterName = "helloFilter", urlPatterns = "/hello.do")
public class HelloFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("拦截器初始化");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        String url = request.getRequestURL().toString();
        String param = request.getQueryString();
        System.out.println("拦截到了请求" + url + "\t参数为:" + param);
        System.out.println("放行前");
        filterChain.doFilter(servletRequest, servletResponse);
        System.out.println("放行后");
    }

    @Override
    public void destroy() {
        System.out.println("拦截器销毁");
    }
}

Listener

这里展示的仅仅在Tomcat启动与销毁时执行

package vip.javer.springbootmvc.listener;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

/**
 * Class Describe: 应用监听器
 * 这里会在Tomcat初始化和销毁时执行
 *
 * @author biuaxia
 * @date 2018/12/13 20:53
 */
@WebListener(value = "appListener")
public class ApplicationListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        System.out.println("应用初始化\t" + servletContextEvent.getServletContext().getServerInfo());
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        System.out.println("应用销毁\t" + servletContextEvent.getServletContext().getServletContextName());
    }
}

配置启用阿里Druid连接池监控

  1. 新建Serlvet继承StatviewServlet
  2. 该类添加注解@WebServlet(name = "druidServlet",urlPatterns = "/druid/*")
  3. 设置账号密码
   @WebServlet(name = "druidServlet", urlPatterns = "/druid/*", initParams = {
           @WebInitParam(name = "loginUsername", value = "root"),
           @WebInitParam(name = "loginPassword", value = "1234")
   })
   public class DruidServlet {
   }
  1. 配置数据库SQL统计

    1. 新建一个Filter继承WebStatFilter
    2. 配置排除不统计的URL
     package vip.javer.springbootmvc.filter;
    
     import javax.servlet.annotation.WebFilter;
     import javax.servlet.annotation.WebInitParam;
    
     /**
      * Class Describe:
      *
      * @author biuaxia
      * @date 2018/12/13 21:03
      */
     @WebFilter(filterName = "druidFilter", urlPatterns = "/*", initParams = {
             @WebInitParam(name = "exclusions", value = "*.js, *.css, *.jpg, *.png, *.gif, *.jpeg, /druid/*")
     })
     public class DruidFilter {
     }
    

配置阿里连接池属性

package vip.java.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;
import java.sql.SQLException;

/**
 * Class Describe:
 *
 * @author biuaxia
 * @date 2018/12/12 9:31
 */
@Configuration
public class DruidDataSourceConfig {

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource druid() {
        DruidDataSource dataSource = new DruidDataSource();
        try {
            dataSource.setFilters("stat");
        } catch (SQLException e) {
            e.printStackTrace();
        }
       /* dataSource.setUsername("");
        dataSource.setPassword("");
        dataSource.setDriverClassName("");
        dataSource.setUrl("");*/
        /*
         * 这样也可以创建对应的Druid连接池
         * 其次,在type里面无参则是默认的tomcat-jdbc连接
         */
        //DataSource dataSource = DataSourceBuilder.create().type(DruidDataSource.class).build();
        return dataSource;
    }

}

结束

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值