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

jsp网站建设项目实战 pdf电商推广和网络推广的区别

jsp网站建设项目实战 pdf,电商推广和网络推广的区别,北京网站制作开发公司,宁波模板建站定制网站目录 前言 拦截器 什么是拦截器? 拦截器的使用 自定义拦截器 注册并配置拦截器 拦截器详解 拦截路径 拦截器执行流程 适配器模式 统一数据返回格式 优点 统一异常处理 前言 在前面中,我们已经学习了spring中的一些常用操作,那么…

目录

前言

拦截器

什么是拦截器?

拦截器的使用

自定义拦截器

注册并配置拦截器

拦截器详解

拦截路径

 拦截器执行流程

适配器模式

统一数据返回格式

优点

统一异常处理


前言

在前面中,我们已经学习了spring中的一些常用操作,那么本篇,我们就继续往下深入学习。

我们在做一些小项目的时候,假如我们想要判断用户是否已经登录,按照我们前面的学习,我们就需要用到seesion来进行判断。设想一下,我们有几个界面,而这几个界面都需要在用户登录后才能进行查看的,就想淘宝,如果我们未登录,那么他就跳转到登录界面。

 对于这样的操作,我们的界面不止一个,那么我们对应的在每个页面调用后端的API,其中的方法每次都需要判断用户是否登录,这样会让代码冗余,所以,在Spring中,给我们提供了一种功能,能够让我们将这些重复的代码进行抽取——拦截器。

拦截器

什么是拦截器?

拦截器(Interceptor)是一种在请求处理流程中,对请求和响应进行拦截和预处理的机制。它允许开发者在请求到达目标处理器(如控制器方法)之前或之后执行统一的逻辑,从而实现诸如权限校验、日志记录、性能监控、请求过滤等功能。

拦截器的使用

拦截器的使用步骤分为两步:

  1. 定义拦截器
  2. 注册并配置拦截器 

自定义拦截器

在Spring  MVC框架中,拦截器通过实现 HandlerInterceptor  接口来定义拦截逻辑

package com.example.demo.interceptor;import com.example.demo.Result.Results;
import com.example.demo.constant.Constants;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;/*** 登录拦截器,用于在请求处理前验证用户是否已登录*/
@Slf4j
@Component
public class LoginInterceptor  implements HandlerInterceptor {@Autowiredprivate ObjectMapper objectMapper;/*** 在请求处理之前进行拦截* * @param request  HttpServletRequest对象,用于获取请求信息* @param response HttpServletResponse对象,用于设置响应信息* @param handler  请求处理器,可以是HandlerMethod或RequestMappingHandler等* @return boolean 表示是否继续执行其他拦截器和目标方法。返回true表示继续执行,返回false表示中断执行。* @throws Exception 抛出异常表示拦截器处理出现错误*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {log.info("方法执行前");//进行登录校验HttpSession session= request.getSession(false);if(session!=null&&"true".equals(session.getAttribute(Constants.USER_SESSION_KEY))){// 用户已登录,继续执行请求return true;}// 用户未登录,返回未授权错误信息Results results=Results.unLogin();response.setStatus(HttpStatus.UNAUTHORIZED.value());response.getOutputStream().write(objectMapper.writeValueAsString(results).getBytes());response.setContentType("application/json;charset=UTF-8");response.getOutputStream().close();return false;}/*** 在请求处理之后,视图渲染之前进行拦截* * @param request  HttpServletRequest对象,用于获取请求信息* @param response HttpServletResponse对象,用于设置响应信息* @param handler  请求处理器,可以是HandlerMethod或RequestMappingHandler等* @param modelAndView ModelAndView对象,用于添加模型数据或修改视图* @throws Exception 抛出异常表示拦截器处理出现错误*/@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {log.info("方法执行后");HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);}/*** 在请求完成之后执行的方法* * @param request 传入的HTTP请求对象,包含请求相关数据* @param response 传入的HTTP响应对象,包含响应相关数据* @param handler 处理请求的处理器对象,可以是任何类型的对象* @param ex 请求处理过程中发生的异常,如果没有异常,则为null* @throws Exception 根据具体实现可能会抛出的异常* * 此方法主要用于在请求处理完成后进行一些清理工作,例如关闭数据库连接、释放资源等* 它是在请求处理的最后一步调用的,确保了所有处理逻辑已经执行完毕*/@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {HandlerInterceptor.super.afterCompletion(request, response, handler, ex);}
}
  • preHandler():该方法是在目标方法执行前执行的。若返回true,则继续执行后续的业务逻辑,返回false,则中断后续的操作。
  • postHandler():该方法是在目标方法执行后再执行的。
  • afterCompletion():该方法是在视图渲染之后执行的,在postHandler()方法之后执行,但由于现在前后端分离,所以后端基本上接触不到视图的渲染,这个方法用的少。

注册并配置拦截器

注册配置拦截器我们需要实现 WebMvcConfiguer 接口,并实现其中的 addInterceptors 方法。

package com.example.demo.config;import com.example.demo.interceptor.LoginInterceptor;
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.WebMvcConfigurer;/*** 配置类用于配置Web相关的设置*/
@Configuration
public class WebConfig implements WebMvcConfigurer {/*** 登录拦截器,用于拦截请求以进行登录验证*/@Autowiredprivate LoginInterceptor loginInterceptor;/*** 添加拦截器以配置请求的预处理和后处理* * @param registry 拦截器注册对象,用于注册自定义拦截器*/@Overridepublic void addInterceptors(InterceptorRegistry registry) {//注册拦截器registry.addInterceptor(loginInterceptor)//拦截以"/book/"开头的所有请求.addPathPatterns("/book/**")//排除"/user/login"请求,使其不被拦截.excludePathPatterns("/user/login");}
}

假如此时我们未登录,调用一下查询功能:

可以看到,会对请求进行拦截。

 知道了拦截器的是如何使用的,那么就来进一步了解拦截器。

拦截器详解

拦截器的使用细节我们讲以下两个部分:

  • 拦截路径配置
  • 拦截器实现原理

拦截路径

拦截路径指的是我们定义的拦截器对哪些请求生效,我们在注册配置拦截器的时候,通过 addPathPatterns() 方法就可以来指定要拦截哪些请求,也可以通过 excludePathPatterns() 方法来指定哪些请求不需要拦截

关于拦截路径设置的规则,有以下几种:

拦截路径含义举例

/*

一级路径

能匹配/user,/book,但不能匹配/book/getList等

/**任意级路径能匹配/user,/user/login,即任意路径都可以匹配
/book/*/book下的一级路径能匹配/book/addBook,不能匹配/book/addBook/get,/book
/book/**/book下的任意级路径能匹配/book,/book/addBook,/book/addBook/2,不能匹配/user/login

上面的这些拦截规则可以拦截项目中的URL,包括静态文件(如图片文件、JS和CSS等文件).

如果我们使用下面这种拦截规则,就会将前端界面的请求也给拦截住。 

 我们可以通过设置前端界面不拦截:

package com.example.demo.config;import com.example.demo.interceptor.LoginInterceptor;
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.WebMvcConfigurer;import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;/*** 配置类用于配置Web相关的设置*/
@Configuration
public class WebConfig implements WebMvcConfigurer {/*** 登录拦截器,用于拦截请求以进行登录验证*/@Autowiredprivate LoginInterceptor loginInterceptor;public List<String> excludePath= Arrays.asList("/user/*","/css/**","/js/**","/img/**","/**/*.html");//放行路径/*** 添加拦截器以配置请求的预处理和后处理** @param registry 拦截器注册对象,用于注册自定义拦截器*/@Overridepublic void addInterceptors(InterceptorRegistry registry) {//注册拦截器registry.addInterceptor(loginInterceptor)//拦截以"/book/"开头的所有请求.addPathPatterns("/**")//排除"/user/login"请求,使其不被拦截.excludePathPatterns(excludePath);}
}

这样,就可以获取到前端界面。

 拦截器执行流程

在没有添加拦截器之前,我们调用顺序是:

在添加拦截器后:

  1. 在添加完拦截器后,执行Controller中的方法之前,请求会先被拦截器拦截住,执行preHandler() 方法,这个方法会返回一个布尔类型的值。如果返回true,说明要放行,继续访问controller中的方法;如果返回false,则不会放行(controller中的方法不会执行).
  2. controller中的方法执行完后,会继续执行 postHandler() 方法以及 afterCompletion() 方法,执行完毕后,最终给浏览器响应数据。

我们通过观察日志,可以看到当Tomcat在启动之后,会有核心的类 DispatcherServlet 来控制程序的执行顺序。

所有的请求都会先进入到DispatcherServlet 中,执行 doDispatch() 调度方法,如果有拦截器,就会先执行拦截器中 preHandle() 方法中的代码,如果 preHandle() 返回true,那么就会继续访问controller中的方法,当controller中的方法执行完毕,就会再回过来执行 postHandle() 和 afterCpmpletion() 方法,返回给DispatcherServlet,最终给浏览器响应数据。

 我们观察 DispatcherServlet 中的源码,就可以看到这三个方法的执行流程:

DispatcherServlet  源码中,我还可以看到使用了适配器模式:

适配器模式

 适配器模式也叫包装器模式。将一个类的接口,转换成客户期望的另有一个接口,适配器让原本接口不兼容的类可以合作无间。

简单来说:就是目标类不能直接使用,通过一个新类进行包装,适配调用方使用,把两个不兼容的接口通过一定的方式使之兼容

 使用适配器来使两个接口兼容:

其实在我们前面学习Spring日志的时候,其中的 slf4j 就使用到了适配器模式,我们想要打印日志的时候,只需要调用slf4j的API,而它会自动去调用底层的 log4j 或者 logback 来打印日志。

示例:

package com.example.demo.config;/*** Slf4j接口定义了打印日志的方法*/
public interface Slf4j {/*** 打印日志信息* @param message 需要打印的日志信息*/void print(String message);
}/*** Log4j类提供了具体的日志打印实现*/
class Log4j{/*** 打印日志信息* @param message 需要打印的日志信息*/void log4jPrint(String message){System.out.println("Log4j: "+message);}
}/*** Slf4jAdapter类是Slf4j接口与Log4j类之间的适配器* 它使得Log4j可以通过Slf4j接口来打印日志*/
class Slf4jAdapter  implements Slf4j{/*** log4j实例用于实际的日志打印*/private Log4j log4j;/*** 构造函数,接收一个Log4j实例* @param log4j Log4j实例,用于实际的日志打印*/public Slf4jAdapter(Log4j log4j) {this.log4j = log4j;}/*** 实现Slf4j接口的print方法,通过Log4j实例来打印日志* @param message 需要打印的日志信息*/@Overridepublic void print(String message) {log4j.log4jPrint(message);}
}/*** Demo类包含主程序,用于演示Slf4jAdapter的使用*/
class Demo{/*** 主函数,创建Log4j实例并通过Slf4jAdapter适配,然后打印日志信息* @param args 命令行参数*/public static void main(String[] args) {Log4j log4j = new Log4j();Slf4j slf4j = new Slf4jAdapter(log4j);slf4j.print("Hello World");}
}

可以看到,我们不需要修改log4j的api,只需要使用适配器,就可以更换日志框架,维护系统。

那么为什么不直接调用Log4j呢? 

 适配器模式其实可以看做一种“补偿模式”,用来补救设计上的缺陷,使用这种模式是无奈之举。如果在设计初期,能够规避接口不兼容的问题,那么就不需要使用适配器模式了。

统一数据返回格式

我们在做项目的时候,如果前端调用后端返回的数据格式都不同,后序如果修改起来,就显得有点杂乱,所以我们可以对返回的数据格式进行统一——统一数据返回格式

在SpringBoot,如果我们想要在返回数据响应之前对数据进行一些逻辑操作,那么我们就需要使用到注解 @ControllerAdvice ResponseBodyAdvice 接口的实现。

定义下存常量的类:

package com.example.demo.constant;public class Constants {public static final String USER_SESSION_KEY = "user";public static final Integer SUCCESS_CODE = 200;//成功public static final Integer FAIL_CODE = -2;//失败public static final Integer UNLOGIN_CODE = -1;//未登录}

统一返回数据格式:

package com.example.demo.Result;import com.example.demo.constant.Constants;import lombok.Data;@Data
public class Results<T> {private Integer code;//200成功,-1未登录,-2程序异常private String msg;private  T data;public static <T> Results success(T data){Results results=new Results();results.setCode(Constants.SUCCESS_CODE);results.setMsg("");results.setData(data);return results;}public static  Results unLogin(){Results results=new Results();results.setCode(Constants.UNLOGIN_CODE);results.setMsg("用户未登录");return results;}public static <T> Results fail(String msg){Results results=new Results();results.setCode(Constants.FAIL_CODE);results.setMsg(msg);return results;}public static <T> Results fail(){Results results=new Results();results.setCode(Constants.FAIL_CODE);results.setMsg("程序出现异常");return results;}
}

响应处理:

package com.example.demo.config;import com.example.demo.Result.Results;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
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;/*** 全局响应处理,统一处理所有响应* 该类实现了ResponseBodyAdvice接口,用于自定义响应体*/
@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {@Autowiredprivate ObjectMapper objectMapper;/*** 判断是否支持当前的返回类型和转换器类型* 该方法始终返回true,表示支持所有类型的响应处理*/@Overridepublic boolean supports(MethodParameter returnType, Class converterType) {return true;}/*** 在写入响应体前处理数据* 该方法根据返回的数据类型,进行相应的处理和封装* 如果返回类型是String,则将其作为成功消息封装进Results对象* 如果返回类型已经是Results,则直接返回* 否则,将返回值作为成功数据封装进Results对象*/@SneakyThrows@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {if(body instanceof String){return  objectMapper.writeValueAsString(Results.success(body));}if(body instanceof Results){return body;}return Results.success(body);}
}

调用一下看看:

可以看到,这样的话,如果前端想要获取到我们后端的数据,以及后续修改操作等,就更加清晰容易操作了。

我们再来看一处地方:

这里为什么要这样写呢?

 SpringMVC默认会注册一些自导的HttpMessageConverter(从先后顺序排序分别为ByteArrayHttpMessageConverter、StringHttpMessageConverter、SourceHttpMessageConverte、SourceHttpMessageConverterr、AllEncompassingFormHttpMessageConverter)

而其中的 AllEncompassingFormHttpMessageConverter  会根据项目依赖情况添加对应的HttpMessageConverter。

在依赖中引⼊jackson包后,容器会把 MappingJackson2HttpMessageConverter ⾃动注册到
messageConverters 链的末尾。Spring会根据返回的数据类型,从 messageConverters 链选择合适的 HttpMessageConverter。当返回的数据是⾮字符串时,使⽤的MappingJackson2HttpMessageConverter 写⼊返回对象当返回的数据是字符串时, StringHttpMessageConverter 会先被遍历到,这时会认为
StringHttpMessageConverter 可以使用

可以看到子类StringHttpMessageConverter中的addDefaultHeaders()方法接收的参数为String,但我们需要返回的类型为Results类型,所以这里我们就需要利用SpringBoot内置提供的Jackson来实现信息的序列化。即:

  • @SneakyThrows 是 Lombok 提供的一个注解,用于简化 Java 中的异常处理。它允许开发者在方法中抛出受检异常(checked exceptions),而无需在方法签名中显式声明 throws,也不需要使用 try-catch 块。

优点

  • ⽅便前端程序员更好的接收和解析后端数据接口返回的数据
  • 降低前端程序员和后端程序员的沟通成本,按照某个格式实现就可以了,因为所有接口都是这样返回的
  • 有利于项目统⼀数据的维护和修改
  • 有利于后端技术部⻔的统⼀规范的标准制定,不会出现稀奇古怪的返回内容

统一异常处理

 当我们的程序出现异常时,我们也可以对这些异常进行统一处理。

统一异常处理使用的是 @ControllerAdvice@ExceptionHandler 来实现的。

  • @ControllerAdvice 表⽰控制器通知类
  • @ExceptionHandler 是异常处理器,两个结合表示当出现异常的时候执行某个通知,也就是执⾏某个⽅法事件
package com.example.demo.config;import cn.hutool.core.io.resource.NoResourceException;
import com.example.demo.Result.Results;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.servlet.resource.NoResourceFoundException;/*** 全局异常处理类* 用于统一处理项目中的异常,提高代码的健壮性和用户体验*/
@ControllerAdvice
@Slf4j
@ResponseBody
public class ErrorAdviceHandler {/*** 处理通用异常* @param e 异常对象* @return 返回处理结果*/@ExceptionHandlerpublic Object handler(Exception e){log.error("异常信息:{}",e.getMessage());return Results.fail(e.getMessage());}/*** 处理数组越界异常* @param e 异常对象* @return 返回处理结果*/@ExceptionHandlerpublic Object handler(ArrayIndexOutOfBoundsException e){log.error("异常信息:{}",e.getMessage());return Results.fail(e.getMessage());}/*** 处理空指针异常* @param e 异常对象* @return 返回处理结果*/@ResponseStatus@ExceptionHandlerpublic Object handler(NullPointerException e){log.error("异常信息:{}",e.getMessage());return Results.fail(e.getMessage());}/*** 处理算数异常* @param e 异常对象* @return 返回处理结果*/@ExceptionHandlerpublic Object handler(ArithmeticException e){log.error("异常信息:{}",e.getMessage());return Results.fail(e.getMessage());}/*** 处理资源未找到异常* @param e 异常对象* @return 返回处理结果*/@ResponseStatus(HttpStatus.NOT_FOUND)@ExceptionHandlerpublic Object handler(NoResourceFoundException e){log.error("异常信息:{}  path:{}",e.getDetailMessageCode(),e.getResourcePath());return Results.fail(e.getMessage());}
}

 测试案例:

package com.example.demo.Controller;import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** Demo控制器类,用于处理演示项目的HTTP请求*/
@RestController
@RequestMapping("/demo")
public class DemoController {/*** 处理/t1请求的方法* 该方法演示了未处理的除零异常,用于教学或测试目的* * @return 成功信息字符串,但在执行中将引发除零异常*/@RequestMapping("/t1")public String t1(){// 该行代码将产生除零异常int a=1/0;return "success";}/*** 处理/t2请求的方法* 该方法演示了未处理的空指针异常,用于教学或测试目的* * @return 成功信息字符串,但在执行中将引发空指针异常*/@RequestMapping("/t2")public String t2(){// 该行代码将产生空指针异常String str=null;str.length();return "success";}/*** 处理/t3请求的方法* 该方法演示了未处理的数组越界异常,用于教学或测试目的* * @return 成功信息字符串,但在执行中将引发数组越界异常*/@RequestMapping("/t3")public String t3(){// 初始化一个包含三个元素的数组int[] arr={1,2,3};// 该行代码将产生数组越界异常arr[3]=4;return "success";}
}

此外,如果发生空指针异常或者其他异常,异常处理中有Exception和NullPointerException的话,优先执行具体的异常,即执行NullPointerException异常。

具体异常优先于通用异常


以上就是本篇所有内容~

若有不足,欢迎指正~ 

http://www.dtcms.com/wzjs/233275.html

相关文章:

  • 门户网站建设与管理广告竞价
  • 蚌埠市做网站谷歌seo视频教程
  • 江西响应式网站建设旺道seo推广系统怎么收费
  • 新闻单位网站建设的意义郑州网络推广
  • 制作wordpress模板教程赣州seo公司
  • 推广比较好的网站下拉关键词排名
  • 网站怎么做微博链接企业建站模板
  • 动态网站建设流程百度网站优化公司
  • 发布信息的网站广州疫情最新消息
  • 做外贸网站需要注册公司吗宁波的网络营销服务公司
  • 以net结尾的网站百度网盘怎么找片
  • 网站建设合同的要素seo优化推广流程
  • 做免费外贸网站册域名网上推广产品哪个网好
  • 做校园网站哪有恶意点击软件买的
  • 上海网站开发方案怎么样在百度上免费推广
  • 通过对网站seo操作一级消防工程师考试
  • 企业网站建设的策略如何制作一个个人网站
  • wordpress csdn主题兰州网站seo
  • 建设银行网站卡死免费发广告的网站大全
  • 哈尔滨虚拟web网站设计公司产品网络推广方式
  • 福州网站制作公司名字爱战网关键词挖掘查询工具
  • 建设工程备案网站国内企业网站模板
  • 网站的设计 更新网页设计培训教程
  • dedecms 做的医院网站地推拉新接单平台
  • 做短视频网站重庆营销型网站建设公司
  • 有人用wordpress默认主题东莞seo托管
  • 网站开发web服务器控件实验报告企业课程培训
  • 东莞专业网站建设公司下载百度 安装
  • 四川学校网站建设公网站标题优化排名
  • 做网站代理去拉人国家市场监督管理总局