当前位置: 首页 > news >正文

商业网站怎么做移动排名提升软件

商业网站怎么做,移动排名提升软件,工程发布平台,企业内部网站建设费用目录 一、用户登录权限验证 1.1 SpringAOP可以进行处理吗? 1.2 创建自定义拦截器 1.3 将自定义拦截器配置到系统配置项中 1.4 拦截器的实现原理 1.4.1 实现原理源码分析 1.5 统一访问前缀添加 二、统一异常处理 2.1 为什么需要使用统一异常处理?…

目录

一、用户登录权限验证

1.1 SpringAOP可以进行处理吗?

1.2 创建自定义拦截器

 1.3 将自定义拦截器配置到系统配置项中

1.4 拦截器的实现原理

1.4.1 实现原理源码分析

1.5 统一访问前缀添加

二、统一异常处理

2.1 为什么需要使用统一异常处理?

2.2 统一异常处理的实现

三、统一数据返回格式

3.1 为什么需要统一数据返回格式?

3.2 统一数据返回格式的实现

 3.3 返回值为String类型时,应该如何处理?

3.3.1 将 StringHttpMessageConverter 去掉。

3.3.2 在统一数据返回的时候,单独处理String类型,让其返回一个String字符串,而非 HashMap

 总结:


前言:

一般Spring Boot统一功能处理模块,也是AOP的实战环节,要实现课程目标有以下3个:

  • 统一用户登录权限验证
  • 统一数据格式
  • 统一异常处理

一、用户登录权限验证

1.1 SpringAOP可以进行处理吗?

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class UserAspect {// 定义切点⽅法 controller 包下、⼦孙包下所有类的所有⽅法@Pointcut("execution(* com.example.demo.controller..*.*(..))")public void pointcut(){ }// 前置⽅法@Before("pointcut()")public void doBefore(){}// 环绕⽅法@Around("pointcut()")public Object doAround(ProceedingJoinPoint joinPoint){Object obj = null;System.out.println("Around ⽅法开始执⾏");try {// 执⾏拦截⽅法obj = joinPoint.proceed();} catch (Throwable throwable) {throwable.printStackTrace();}System.out.println("Around ⽅法结束执⾏");return obj;}
}

我们知道SpringAOP虽然就提供了对用户登录的处理逻辑,但是存在一些问题:

  • 没有办法获取HttpSession对象
  • 如果要对一部分方法拦截,一部分方法不拦截,这种情况很难处理。(比如注册和登录方法在用户登录权限验证中是不能进行拦截的)

拦截器和SpringAOP虽然都是AOP的实现方式,但是这两个其实是完全不同的技术体系。

Spring提供了具体的实现拦截器:HandlerInterceptor,该SpringBoot 拦截器实现分为以下两个步骤:

  1. 自定义拦截器
  2. 将自定义拦截器配置到系统配置项,并且设置合理的拦截规则

1.2 创建自定义拦截器

自定义拦截器继承HandlerInterceptor后,需要重写相对应的方法,这里我们重写 preHandle方法:

 代码如下:

package com.example.demo.common;import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;/*** 自定义拦截器*/
public class LoginInterceptor implements HandlerInterceptor {/*** 以下方法是调用目标方法之前执行的方法。此方法返回boolean类型的值* 返回true标识验证成功,程序会继续执行后续流程* 返回false, 表示拦截器拦截失败, 验证未通过, 后续的流程和目标方法不再执行。* @param request* @param response* @param handler* @return* @throws Exception*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 用户登录判断业务HttpSession session = request.getSession(false);if (session != null && session.getAttribute("session_userinfo") != null) {// 用户已经登录return true;}return false;}
}

 1.3 将自定义拦截器配置到系统配置项中

 重写addInterceptors方法:

 设置拦截规则,代码如下

package com.example.demo.config;import com.example.demo.common.LoginInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;public class MyConfig implements WebMvcConfigurer {@AutowiredLoginInterceptor loginInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(loginInterceptor).addPathPatterns("/**") //拦截所有的url.excludePathPatterns("user/login") // url为:user/login 不进行拦截 以下同理.excludePathPatterns("user/reg").excludePathPatterns("image/**"); // image夹目录下的所有url都不进行拦截}
}

或者使用Spring方法,通过DI注入的方式,这样可以实现不用new一个实例:

首先需要将拦截器添加到spring中,也就是给其添加一个五大类注解,这里我们就使用@Component。接着就可以使用@Autowired来得到实例。

 其中:

  • addPathPatterns: 表示需要拦截的URL,“**”表示拦截任意方法(也就是所有方法)。
  • excludePathPatterns: 表示需要排除的URL。

 说明:以上拦截规则可以拦截此项目中的URL,包括静态文件(图片文件,JS和CSS等文件)。

1.4 拦截器的实现原理

下面我们先来看一组正常情况下的调用顺序:

然而有了拦截器之后,会在调用Controller之前进行相应的业务处理,执行的流程如下图所示:

1.4.1 实现原理源码分析

所有的Controller执行都会通过一个调度器DispatcherServlet来实现,这一点可以从Spring Boot控制台的打印信息看出,如下图所示:

在IDEA中,通过全局搜索doDispatch,方法代码如下:

    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {HttpServletRequest processedRequest = request;HandlerExecutionChain mappedHandler = null;boolean multipartRequestParsed = false;WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);try {try {ModelAndView mv = null;Object dispatchException = null;try {processedRequest = this.checkMultipart(request);multipartRequestParsed = processedRequest != request;mappedHandler = this.getHandler(processedRequest);if (mappedHandler == null) {this.noHandlerFound(processedRequest, response);return;}HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());String method = request.getMethod();boolean isGet = HttpMethod.GET.matches(method);if (isGet || HttpMethod.HEAD.matches(method)) {long lastModified = ha.getLastModified(request, mappedHandler.getHandler());if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {return;}}if (!mappedHandler.applyPreHandle(processedRequest, response)) {return;}// 实现Controller的业务逻辑mv = ha.handle(processedRequest, response, mappedHandler.getHandler());if (asyncManager.isConcurrentHandlingStarted()) {return;}this.applyDefaultViewName(processedRequest, mv);mappedHandler.applyPostHandle(processedRequest, response, mv);} catch (Exception var20) {dispatchException = var20;} catch (Throwable var21) {dispatchException = new NestedServletException("Handler dispatch failed", var21);}this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);} catch (Exception var22) {this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);} catch (Throwable var23) {this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));}} finally {if (asyncManager.isConcurrentHandlingStarted()) {if (mappedHandler != null) {mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);}} else if (multipartRequestParsed) {this.cleanupMultipart(processedRequest);}}}

观察DispatcherServlet中的某段代码:

我们发现,在执行后续的Controller代码之前,都会先执行这个applyPreHandle方法,于是鼠标双击 applyPreHandle,得到代码如下:

从上述源码可以看出,在applyPreHandle中会获取所有的拦截器HandlerInterceptor并执行拦截器中的preHandle方法,这样就和之前定义的拦截器对应上了,如下图所示:

package com.example.demo.common;import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;/*** 自定义拦截器*/
@Component
public class LoginInterceptor implements HandlerInterceptor {/*** 以下方法是调用目标方法之前执行的方法。此方法返回boolean类型的值* 返回true标识验证成功,程序会继续执行后续流程* 返回false, 表示拦截器拦截失败, 验证未通过, 后续的流程和目标方法不再执行。* @param request* @param response* @param handler* @return* @throws Exception*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 用户登录判断业务HttpSession session = request.getSession(false);if (session != null && session.getAttribute("session_userinfo") != null) {// 用户已经登录return true;}response.setContentType("application/json");response.setCharacterEncoding("utf8");response.getWriter().println("asdasd");return false;}
}

1.5 统一访问前缀添加

所有请求地址添加api前缀:

代码如下:

package com.example.demo.config;import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class AppConfig implements WebMvcConfigurer {@Overridepublic void configurePathMatch(PathMatchConfigurer configurer) {configurer.addPathPrefix("fox", c -> true);}
}

二、统一异常处理

2.1 为什么需要使用统一异常处理?

通俗来讲,统一异常处理的主要目的是为了方便前端,让其更好的处理后端的信息,尽量将逻辑处理这块放置于后端,前端的目的其实主要是为用户服务。

比如:可以跟前端约定出现异常报错时候的状态码是多少,这样方便前端的处理,也方便后续后端在日志文件中将其找到,并修改异常。

2.2 统一异常处理的实现

统一异常处理使用的是@ControllerAdvice + @ExceptionHandler 来实现的,@ControllerAdvice表示控制器通知类, @ExceptionHandler是异常处理器,两个结合表示当出现异常的时候执行某个通知,也就是执行某个方法事件,具体实现代码如下:

以上方法表示,如果出现了异常就返回给前端一个HashMap对象, 其中包含的字段如代码定义那样。

 注意:

方法名和返回值都是可以自定义的,另外 @ExceptionHandler()中的参数是可以选择的,这里是Exception.class:表示的是可以在程序抛出异常的时候执行这里的代码,让其返回数据给前端,如果填入的参数是NullPointerException:那么表示的是当程序出现空指针异常的时候,会执行这里的代码。

这里的实现逻辑和Java中的异常处理是相似的,如果开发者有对Exception和NullPointerException分别进行了处理,那么当程序出现NullPointerException异常的时候,还是会根据我们写的NullPointerException执行逻辑进行处理,并不会直接走Exception的逻辑。

示例如下:

访问页面后效果如下:

总结:当有多个异常通知时,匹配顺序为当前类及其子类向上依次匹配。

三、统一数据返回格式

3.1 为什么需要统一数据返回格式?

统一数据返回格式的优点如下,比如以下几个:

  • 方便前端程序员更好的接受和解析后端数据接口的数据
  • 降低前端程序员和后端程序员的沟通成本
  • 有利于项目统一数据的维护和修改
  • 有利于后端技术部门的统一规范的标准制定,不会出现稀奇古怪的返回内容

3.2 统一数据返回格式的实现

统一的数据返回格式可以使用@ControllerAdvice + ResponseBodyAdvice 的方式实现,具体实现代码如下:

package com.example.demo.common;import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;import java.util.HashMap;/*** 统一数据格式处理*/
@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {/*** 是否执行 beforeBodyWrite 方法, 返回 true 就执行, 返回 false 就不执行* @param returnType* @param converterType* @return*/@Overridepublic boolean supports(MethodParameter returnType, Class converterType) {return true;}/*** 返回数据之前进行数据重写* @param body 原始返回值* @param returnType* @param selectedContentType* @param selectedConverterType* @param request* @param response* @return*/@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {// 这里我们规定统一的数据返回为HashMapif (body instanceof HashMap) {return body;}// 重写返回结果,让其返回一个统一的数据格式HashMap<String, Object> result = new HashMap<>();result.put("code",200);result.put("data",body);result.put("msg","");return result;}
}

 访问user/login1:

经过统一功能处理后代码展现如下:

 3.3 返回值为String类型时,应该如何处理?

 但是如果将返回值改为String类型,按照以上的执行逻辑,那么就无法走上述的正常数据统一处理:

我们发现,当返回类型为String的时候,程序会抛出异常,从而被我们的 统一异常处理模块拦截。

观察异常信息,发现 抛出异常:java.lang.ClassCastException: java.util.HashMap cannot be cast to java.lang.String

可能会感到奇怪,为什么会抛出这个异常呢?

下面我们来看看后端返回前端时候的执行流程:

1.  一开始,前端访问该网址时,方法返回的是 String:

2. 统一数据返回之前会进行处理,将 String 转换为 HashMap:

3. 将HaspMap转换成 application/json 字符串给前端(接口)

这个步骤有两种情况,先判断原Body的类型:

  • 是 String 类型,那么就会使用 StringHttpMessageConverter 进行类型转换
  • 如果不是 String 类型,那么使用 HttpMessageConverter 进行类型转换

以上报错就是因为原始Body是String类型,所以在类型转换时候报错了

解决方案有如下两种:

  • 将 StringHttpMessageConverter 去掉。
  • 在统一数据返回的时候,单独处理String类型,让其返回一个String字符串,而非HashMap

3.3.1 将 StringHttpMessageConverter 去掉。

在配置文件中使用以下代码即可;

package com.example.demo.config;import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;import java.util.List;@Configuration
public class MyConfig implements WebMvcConfigurer {/*** 移除 StringHttpMessageConverter* @param converters*/@Overridepublic void configureMessageConverters(List<HttpMessageConverter<?>> converters) {converters.removeIf(converter -> converter instanceof StringHttpMessageConverter);}
}

 访问地址后显示如下:

3.3.2 在统一数据返回的时候,单独处理String类型,让其返回一个String字符串,而非 HashMap

引入ObjectMapper(ObjectMapper 是Jackson库中的一个类,用于在Java对象(POJO,Plain Old Java Objects)和JSON数据之间进行相互转换):

对Body为String进行单独处理: 

访问页面如下所示:

 总结:

本文主要介绍了统一用户登录权限的效验,使用WebMvcConfigurer + HandlerInterceptor 来实现。统一异常处理使用 @ControllerAdvice + @ExceptionHandler 来实现,统一返回值处理使用@ControllerAdvice + ResponseBodyAdvice来处理。

http://www.yidumall.com/news/3638.html

相关文章:

  • 海口网站制作成都企业seo
  • 移动网站开发基础知识产品网络营销分析
  • 网站建设 在电商的作用seoul是什么品牌
  • 免费做翻页页面的网站榜单优化
  • 小型劳务公司注册条件seo是指搜索引擎营销
  • 电子商务网站建设报告范文win优化大师有用吗
  • 电子商务网站建设与维护实验报告吸引人气的营销方案
  • 高端网站建设苏州seo搜索规则
  • wordpress建站应用武汉网站设计公司
  • 深圳北网站建设平台推广网站
  • 天津网站建设制作免费网站关键词快速优化
  • 注册公司流程 上海潍坊seo按天收费
  • 网站建设的数据所有权站长工具seo查询软件
  • net网站开发学习百度搜索怎么优化
  • 做旅游业务的商业网站惠城网站设计
  • 网站备案需要什么材料百度热搜风云榜
  • 北京住房城乡建设委官方网站什么软件比百度搜索好
  • nginx 网站建设小红书seo是什么
  • 网店推广新技术广东优化疫情防控措施
  • 用电脑做服务器搭建php网站千锋教育和达内哪个好
  • 帮别人起名 做ppt的网站成都网站seo诊断
  • laravel 做中英文网站网站搭建工具
  • 化妆品网站建设可行性分析seo就业前景如何
  • 网红营销优势汕头seo收费
  • 家居企业网站建设公司成人职业培训学校
  • wordpress wpincseo查询 工具
  • 小程序免费制作平台教学汕头seo关键词排名
  • 网购网站系统佛山网站定制
  • 岳阳网站开发网站运营网络营销和网上销售的区别
  • 网站建好了怎么做才赚钱汕头网页搜索排名提升