公司网站 仿站什么意思,成都纯手工seo,ios网站开发视频教程,做网站跳转怎么收费目录
1. 用户登录权限校验
1.1 最初用户登录验证
1.2 Spring AOP 用户统一登陆验证
1.3 Spring 拦截器
1.3.1 创建自定义拦截器
1.3.2 将自定义拦截器加入系统配置
1.4 练习#xff1a;登录拦截器
1.5 拦截器实现原理
1.6 统一访问前缀添加
2. 统一异常处理
3. 统…目录
1. 用户登录权限校验
1.1 最初用户登录验证
1.2 Spring AOP 用户统一登陆验证
1.3 Spring 拦截器
1.3.1 创建自定义拦截器
1.3.2 将自定义拦截器加入系统配置
1.4 练习登录拦截器
1.5 拦截器实现原理
1.6 统一访问前缀添加
2. 统一异常处理
3. 统一数据返回格式
3.1 为什么需要统⼀数据返回格式
3.2 统一数据返回格式的实现 学习了 Spring 的框架后接下来我们来学习 Spring Boot 的统一功能处理模块也是 AOP 的实战环节。我们主要学习以下三个部分
统一用户登录验证统一数据格式返回统一异常处理
接下来我们逐一来看。
1. 用户登录权限校验
用户登录权限的发展从之前每个方法中自己验证用户登录权限到现在统⼀的用户登录验证处理它是⼀个逐渐完善和逐渐优化的过程。
1.1 最初用户登录验证
我们先来看一下最初的用户登录验证是如何实现的。
Slf4j
RequestMapping(/user)
RestController
public class UserController {RequestMapping(method1)public Object method1(HttpServletRequest request){// 有session就获取没有session不会创建HttpSession session request.getSession(false);if(session ! null session.getAttribute(userinfo) ! null){// 说明已经登录业务处理return true;}else {// 未登录return false;}}RequestMapping(method2)public Object method2(HttpServletRequest request){// 有session就获取没有session不会创建HttpSession session request.getSession(false);if(session ! null session.getAttribute(userinfo) ! null){// 说明已经登录业务处理return true;}else {// 未登录return false;}}// 其他方法
}运行结果如下 从上述代码可以看出每个方法中都有相同的用户登录验证权限它的缺点是 每个方法中都要单独写用户登录验证的方法即使封装成公共方法也⼀样要传参调用和在方法中进行判断。 添加控制器越多调用用户登录验证的方法也越多这样就增加了后期的修改成本和维护成本。 这些用户登录验证的方法和接下来要实现的业务几乎没有任何关联但每个方法中都要写⼀遍。 因此我们需要提供⼀个公共的 AOP 方法来进行统⼀的用户登录权限验证。 1.2 Spring AOP 用户统一登陆验证
首先我们可以通过 Spring AOP 前置通知或环绕通知来实现
Slf4j
Component
Aspect
public class LoginAspect {Pointcut(execution(* com.example.demo.controller.UserController.* (..)))public void pointcut(){}Before(pointcut())public void doBefore(){log.info(do berore...);}Around(pointcut())public Object doAround(ProceedingJoinPoint joinPoint){Object oj null;log.info(环绕通知执行之前...);try {oj joinPoint.proceed(); // 调用目标方法} catch (Throwable e) {throw new RuntimeException(e);}log.info(环绕通知执行之后...);return oj;}如果要在以上 Spring AOP 的切面中实现用户登录权限效验的功能有以下两个问题 没办法获取到 HttpSession 对象要对⼀部分方法进行拦截而另⼀部分方法不拦截如注册方法和登录方法是不拦截的这样的话排除方法的规则很难定义甚至没办法定义。
1.3 Spring 拦截器 对于以上问题 Spring 中提供了具体的实现拦截器HandlerInterceptor拦截器的实现分为以下两个步骤 创建自定义拦截器实现 HandlerInterceptor 接口的 preHandle执行具体方法之前的预处理方法。 将自定义拦截器加入 WebMvcConfigurer 的 addInterceptors 方法中。
1.3.1 创建自定义拦截器
public class LoginInterceptor implements HandlerInterceptor {Overridepublic 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;}
}
1.3.2 将自定义拦截器加入系统配置
Configuration
public class AppConfig implements WebMvcConfigurer {Autowiredprivate LoginInterceptor loginInterceptor;// 添加拦截器Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new LoginInterceptor()).addPathPatterns(/**)// 拦截所有接口.excludePathPatterns(/login).excludePathPatterns(/reg);// 排除接口}
}
其中 addPathPatterns表示需要拦截的 URL“**”表示拦截任意方法也就是所有方法 excludePathPatterns表示需要排除的 URL
1.4 练习登录拦截器 登录、注册页面不拦截其他页面都拦截。 当登录成功写入 session 之后拦截的页面可正常访问。
/*** 自定义拦截器*/
Component
public class LoginInterceptor implements HandlerInterceptor {Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 判断是否登录HttpSession session request.getSession(false);// 不存在时不创建if(session ! null session.getAttribute(username) ! null){// 通过不进行拦截return true; // 返回 true 表示不拦截继续执行后续代码}response.setStatus(401);return false;}
}/*** 添加拦截器*/
Configuration
public class AppConfig implements WebMvcConfigurer {Autowiredprivate LoginInterceptor loginInterceptor;// 添加拦截器Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(loginInterceptor).addPathPatterns(/**)// 拦截所有接口.excludePathPatterns(/user/login).excludePathPatterns(/user/reg);// 排除接口}
}
Slf4j
RequestMapping(/user)
RestController
public class UserController {// 获取用户信息RequestMapping(/getInfo)public String getInfo(){log.info(get info...);return get info...;}// 注册RequestMapping(/reg)public String reg(){log.info(reg...);return reg...;}// LoginRequestMapping(/login)public boolean login(HttpServletRequest request,String username,String password){// 判断 username password 是否为空if(!StringUtils.hasLength(username) || !StringUtils.hasLength(password)){// 未登录return false;}if(!admin.equals(username) || !admin.equals(password)){return false;}HttpSession session request.getSession(true);// 不存在则创建session.setAttribute(username,username);return true;}
}运行以上代码后可以看到 http://127.0.0.1:8080/user/reg 可以正常访问 http://127.0.0.1:8080/user/info 界面被拦截且状态码为401 http://127.0.0.1:8080/user/login 界面在没有输入用户信息之前返回 true: 在成功写入 session 之后界面返回 true表示成功登录 在成功登录后再访问 http://127.0.0.1:8080/user/info 界面时可以看到能够正常访问了 1.5 拦截器实现原理 1.6 统一访问前缀添加
所有请求地址添加 api 前缀
Configuration
public class AppConfig implements WebMvcConfigurer {Autowiredprivate LoginInterceptor loginInterceptor;// 添加拦截器Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(loginInterceptor).addPathPatterns(/**)// 拦截所有接口.excludePathPatterns(/api/user/login).excludePathPatterns(/api/user/reg);// 排除接口}Overridepublic void configurePathMatch(PathMatchConfigurer configurer) {configurer.addPathPrefix(api,c - true);}
}
此时可以看到没有 api 前缀则无法访问 加上 api 前缀后则可以访问 其中第二个参数是⼀个表达式设置为 true 表示启动前缀。
2. 统一异常处理
将发生的异常进行统一处理。 统一异常处理使用的是 ControllerAdvice ExceptionHandler 来实现的 ControllerAdvice 表示控制器通知类ExceptionHandler 是异常处理器两个结合表示当出现异常的时候执行某个通知 也就是执行某个方法事件具体实现代码如下 RestController
public class ExceptionController {RequestMapping(/test1)public boolean test1(){int a 10/0;return true;}RequestMapping(/test2)public boolean test2(){String str null;System.out.println(str.length());return true;}RequestMapping(/test3)public String test3(){throw new RuntimeException(test3手动创建异常);}
} ControllerAdvice
public class ErrorHandler {ExceptionHandlerpublic Object error(Exception e){HashMapString,Object result new HashMap();result.put(success,0);result.put(code,-1);result.put(msg,内部异常);return result;}
} 运行后可以看到出现错误且状态码均为500 此时我们需要加上注解ResponseBody
ControllerAdvice
public class ErrorHandler {ResponseBodyExceptionHandlerpublic Object error(Exception e){HashMapString,Object result new HashMap();result.put(success,0);result.put(code,-1);result.put(msg,内部异常);return result;}
} 此时我们可以看到均正常返回 还可以将异常信息分的更详细
ControllerAdvice
public class ErrorHandler {ResponseBodyExceptionHandlerpublic Object error(Exception e){HashMapString,Object result new HashMap();result.put(success,0);result.put(code,-1);result.put(msg,内部异常);return result;}ResponseBodyExceptionHandlerpublic Object error(ArithmeticException e){HashMapString,Object result new HashMap();result.put(success,0);result.put(code,-2);result.put(msg,ArithmeticException 异常);return result;}ResponseBodyExceptionHandlerpublic Object error(NullPointerException e){HashMapString,Object result new HashMap();result.put(success,0);result.put(code,-3);result.put(msg,NullPointerException 异常);return result;}
}
运行结果如下 3. 统一数据返回格式
3.1 为什么需要统⼀数据返回格式 统⼀数据返回格式的优点有很多比如以下几个 方便前端程序员更好的接收和解析后端数据接口返回的数据。 降低前端程序员和后端程序员的沟通成本按照某个格式实现就可以因为所有接口都是这样返回的。 有利于项目统一数据的维护和修改。 有利于后端技术部门的统一规范的标准制定不会出现稀奇古怪的返回内容。
3.2 统一数据返回格式的实现
Slf4j
ControllerAdvice
public class ErrorHandler {ResponseBodyExceptionHandlerpublic Object error(Exception e){HashMapString,Object result new HashMap();result.put(success,0);result.put(code,-1);result.put(msg,内部异常);log.info(Exception:,e);return result;}ResponseBodyExceptionHandlerpublic Object error(ArithmeticException e){HashMapString,Object result new HashMap();result.put(success,0);result.put(code,-2);result.put(msg,ArithmeticException 异常);log.info(ArithmeticException:,e);return result;}ResponseBodyExceptionHandlerpublic Object error(NullPointerException e){HashMapString,Object result new HashMap();result.put(success,0);result.put(code,-3);result.put(msg,NullPointerException 异常);log.info(NullPointerException:,e);return result;}
}
ControllerAdvice
public class ResponseHandller implements ResponseBodyAdvice {Overridepublic boolean supports(MethodParameter returnType, Class converterType) {return true; // 允许对结果进行统一处理}Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {// 在向 Body 写之前要进行的操作HashMapString,Object result new HashMap();result.put(success,1);result.put(data,body);result.put(errMsg,);return result;}
}
可以看到在没有进行统一数据返回格式之前运行结果如下图所示 在进行统一数据返回格式之后运行结果如下图所示 但是需要注意的是如果方法返回的结果类型是 String会出现以下错误 java.lang.ClassCastException: java.util.HashMap cannot be cast to java.lang.String 解决方法如下
ControllerAdvice
public class ResponseHandller implements ResponseBodyAdvice {Overridepublic boolean supports(MethodParameter returnType, Class converterType) {return true; // 允许对结果进行统一处理}SneakyThrowsOverridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {// 在向 ResponseBody 写之前要进行的操作HashMapString,Object result new HashMap();result.put(success,1);result.put(data,body);result.put(errMsg,);// 如果返回的数据类型是字符串类型if(body instanceof String){ObjectMapper mapper new ObjectMapper();return mapper.writeValueAsString(result);}return result;}
} 此时我们可以看到运行结果如下 查看 class 文件可以发现SneakyThrows 注解会自动生成 try catch 语句 本介绍了统一用户登录权限的效验使用 WebMvcConfigurer HandlerInterceptor来实现统⼀异常处理使用 ControllerAdvice ExceptionHandler 来实现统一返回值处理使用ControllerAdvice ResponseBodyAdvice 来处理。