SpringBoot 统一功能处理

在我们写SpringBoot项目的时候,有些功能模块几乎每个项目都是一样,这些功能模块有:

1.统一用户登录权限验证;

2.统一数据格式返回;

3.统一异常处理;

统一用户登录权限验证

在我们利用Spring AOP来做统一登录验证的时候会遇到两个问题:

1.没有办法获取到HTTPSession对象;

2.很难做到只对某一部分拦截,对某一部分不拦截;

Spring拦截器 

对于上面的问题可以使用Spring拦截器来解决,Spring拦截器HandlerInterceptor的实现分为一下两个步骤:

1. 创建自定义拦截器(判断用户是否登陆):该拦截器必须实现HandlerInterceptor并重写preHandle(执行具体方法之前的预处理)方法。

/*
* 登录拦截器
* */
public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler) throws Exception {
        HttpSession session = request.getSession(false);
        if(session!=null&&session.getAttribute("userinfo")!=null){
            //说明已经登录
            return true;
        }
        response.setStatus(401);
        return false;
    }
}

SpringBoot 统一功能处理_第1张图片

2.配置拦截器和拦截规则

/*
* 全局配置文件
* */
@Configuration
public class AppConfig implements WebMvcConfigurer {
    //配置拦截器和拦截规则

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor())
                .addPathPatterns("/**")//拦截所有请求
                .excludePathPatterns("/**/*.html")//排除所有的html文件
                .excludePathPatterns("/**/*.css")//排除所有的css文件
                .excludePathPatterns("/**/*.js")//排除所有的js文件
                .excludePathPatterns("/user/login");//排除登录接口
    }
}

结果:

SpringBoot 统一功能处理_第2张图片

因为拦截了.jpg文件,随意页面中的图片加载不出来,下面是我排除.jpg文件的接口以后的效果:

下面看一个具体的用户登录权限验证的操作:

首先用户是通过输入网址到达某个页面,这个页面可能是系统内部的某个页面(不是登录页面),这个时候因为没有登陆,所以就不能访问:

一:创建两个前端页面

  • index.html 



    
    
    
    Document


index 页面

  •  login.html



    
    
    
    Document


登录页面

二:写一个拦截器,拦截index页面,不拦截login页面

public class LoginIntercept implements HandlerInterceptor {
    /*
    * 返回true表示拦截判断通过,可以访问后面的接口
    * 如果返回false表示拦截未通过,直接返回结果给前端
    * */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //1.得到HttpSession对象
        HttpSession session = request.getSession(false);
        if(session!=null&&session.getAttribute("userinfo")!=null){
            //表示已经登录
            return true;
        }
        //执行到此行代码表示未登录,未登录就跳转到登录页面
        return false;
    }
}
@Configuration
public class AppConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginIntercept())
                .addPathPatterns("/**")//拦截所有的url
                .excludePathPatterns("/user/login")//不拦截登录接口
                .excludePathPatterns("/user/reg")//不拦截注册接口
                .excludePathPatterns("/login.html")//不拦截登录页面
                .excludePathPatterns("/reg.html")//不拦截注册页面
                .excludePathPatterns("/**/*.js")//不拦截所有的js信息
                .excludePathPatterns("/**/*.css")//不拦截所有的css信息
                .excludePathPatterns("/**/*.jpg");//不拦截所有的图片信息
    }
}

三:验证

SpringBoot 统一功能处理_第3张图片

SpringBoot 统一功能处理_第4张图片  

四:让未登录的用户跳转到登录页面 

SpringBoot 统一功能处理_第5张图片  

输入http://localhost:8080/index.html以后因为没有登陆,它会自动的跳转到登录页面:

SpringBoot 统一功能处理_第6张图片

五:在url中输入session信息(输入以后相当于就登录了)

没有输入session信息之前的状态(访问):

我在浏览器输入框中输入localhost:8080/user/index,如果是登录状态,它就会显示Hello,index,但是现在我是未登录状态(也就是浏览器中没有我的登录信息——session) ,因为之前重定向到了登录页面,所以它会让我先登录:

SpringBoot 统一功能处理_第7张图片

在这个页面中,会让我输入登录信息,验证通过后浏览器就会自动的保存我的session,然后我就可以访问其他页面了 ,下面是我没有输入正确session的状态:

SpringBoot 统一功能处理_第8张图片

下面是我输入正确session之后的状态:

SpringBoot 统一功能处理_第9张图片

然后我在访问其他页面:

SpringBoot 统一功能处理_第10张图片

SpringBoot 统一功能处理_第11张图片

当我的登录信息正确以后,拦截器就不拦了,上面整个过程就是用户统一登录的验证。

Spring拦截器的原理 

之前我们没有设置拦截器的时候,用户请求数据的流程是下面这样的:

SpringBoot 统一功能处理_第12张图片

添加拦截器以后,用户请求数据的流程:

SpringBoot 统一功能处理_第13张图片

 也就是说在我们请求数据的时候,所有的请求否要通过拦截器这个关卡,如果拦截器返回false,请求就不能通过,返回true才能访问到要访问的数据。

关于统一访问前缀的添加 

在我们使用拦截器拦截目标文件的时候,可以在相应的url地址前面加上前缀:

    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        //在所有的请求地址前面加上api前缀
        configurer.addPathPrefix("api",c->true);
    }

代码里面的c表示所有的controller 

例如:在所有的请求地址前面加上api前缀 

没加之前:

SpringBoot 统一功能处理_第14张图片

加了之后:

SpringBoot 统一功能处理_第15张图片

统一的异常处理 

在我们写程序的时候,难免会遇到异常,这个异常可能是我们自己导致的也有可能是用户提交的数据导致的,虽然异常还可以try-catch一下处理一下,但是异常多了以后不可能每一个地方都去处理,而且在Spring事务中try-catch会导致事务不能回滚。为了解决这一普遍现象造成的问题,这里就可以Spring里面用统一异常处理机制来处理。

统一异常处理机制:

1.给异常处理类加上@controllerAdervice注解或者@RestControllerAdervice注解,@controllerAdervice注解这个注解表示控制器通知类,而@RestControllerAdervice是一个组合注解,它相当于@controllerAdervice+@ResponseBody,使用了这个注解以后,可以不再类上面加@ResponseBody注解。

@RestControllerAdvice//当前针对controller的通知类
public class MyExceptionAdervice {
    
}

2.在方法上面加上@ExceptionHandler(XXX.class),添加异常返回的业务逻辑。

SpringBoot 统一功能处理_第16张图片

SpringBoot 统一功能处理_第17张图片

在controller里面写一个错误逻辑:

SpringBoot 统一功能处理_第18张图片

执行结果:

 SpringBoot 统一功能处理_第19张图片

返回统一的数据格式 

返回统一数据格式的好处:

  • 方便前端程序员更好的接收和解析后端端口返回的数据;
  • 有利于项目统一数据的维护和修改;
  • 能够降低前后端程序员之间的沟通成本; 

返回统一数据格式的实现也是分为两步:

1.在返回统一数据格式的类上面加上@ControllerAdvice注解;

2.让这个类实现ResponseBodyAdvice接口,并重写它里面的两个方法 

@ControllerAdvice
public class MyResponseAdvice implements ResponseBodyAdvice {

    /*
    * 返回一个boolean值,true表示返回数据之前对数据进行重写,也就是会进入beforeBodyWrite方法,再返回
    * 如果返回false表示对结果不进行任何处理,直接返回
    * */
    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, 
                                  Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        HashMap result = new HashMap<>();
        result.put("state",1);
        result.put("data",body);
        result.put("msg","");
        return result;
    }
}

结果:

SpringBoot 统一功能处理_第20张图片

SpringBoot 统一功能处理_第21张图片 

你可能感兴趣的:(Spring和Spring框架,spring,boot,java,spring)