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

建筑工程网站哪个好用电脑怎么做网站

建筑工程网站哪个好,用电脑怎么做网站,新闻类网站排版网站建设,班组安全建设 网站一.Spring AOP 1.什么是Spring AOP AOP#xff08;Aspect Oriented Programming#xff09;#xff1a;面向切面编程#xff0c;它是一种思想#xff0c;它是对某一类事情的集中处理。 2.AOP的作用 想象一个场景#xff0c;我们在做后台系统时#xff0c;除了登录…一.Spring AOP  1.什么是Spring AOP  AOPAspect Oriented Programming面向切面编程它是一种思想它是对某一类事情的集中处理。 2.AOP的作用 想象一个场景我们在做后台系统时除了登录和注册等几个功能不需要做用户登录验证之外其他几乎所有页面调用的前端控制器 Controller都需要先验证用户登录的状态那这个时候我们要怎么处 理呢 我们之前的处理方式是每个 Controller 都要写一遍用户登录验证然而当你的功能越来越多那么你要 写的登录验证也越来越多而这些方法又是相同的这么多的方法就会代码修改和维护的成本。那有没 有简单的处理方案呢答案是有的对于这种功能统一且使用的地方较多的功能就可以考虑 AOP 来统一处理了。 除了统一的用户登录判断之外AOP 还可以实现统一日志记录统一方法执行时间统计统一的返回格式设置统一的异常处理事务的开启和提交等AOP是OOP的补充  3.AOP的相关概念 1.切面Aspect 面Aspect由切点Pointcut和通知Advice组成它既包含了横切逻辑的定义也包 括了连接点的定义。 2.连接点 Join Point 应用执行过程中能够插入面的一个点这个点可以是方法调用时抛出异常时甚至修改字段 时。切面代码可以利用这些点插入到应用的正常流程之中并添加新的行为 3.切点Pointcut) Pointcut 是匹配 Join Point 的谓词。 Pointcut 的作用就是提供一组规则使用 AspectJ pointcut expression language 来描述来 匹配 Join Point给满足规则的 Join Point 添加 Advice 4.通知(Advice) 切面也是有目标的 ——它必须完成的工作。在 AOP 术语中切面的工作被称之为通知。 通知定义了切面是什么何时使用其描述了面要完成的工作还解决何时执行这个工作的 问题。 Spring 切面类中可以在方法上使用以下注解会设置方法为通知方法在满足条件后会通知本 方法进行调用 前置通知使用 Before通知方法会在目标方法调用之前执行。后置通知使用 After通知方法会在目标方法返回或者抛出异常后调用。 返回之后通知使用 AfterReturning通知方法会在目标方法返回后调用。抛异常后通知使用 AfterThrowing通知方法会在目标方法抛出异常后调用。环绕通知使用 Around通知包裹了被通知的方法在被通知的方法通知之前和调用之后执行自定义的行为。 4.Spring AOP的实现 1.添加 AOP 框架支持 在 pom.xml 中添加如下配置 dependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter/artifactId/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdoptionaltrue/optional/dependency !-- Springboot test--dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependency !-- Spring AOP 框架--dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-aop/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependency/dependencies 2.定义切面和切点 Component Slf4j Aspect public class LoginAspect {Pointcut(execution(* com.javastudy.springaopdemo5.controller.LoginController.*(..)))public void pointcut() {}}Aspect类注解表示LoginAspect是一个切面类,Pointcut表示定义一个切点,其中的内容表示连接点的规则,也就是包括哪些类或者方法属于这个切点,连接点. 其中 pointcut 方法为空方法它不需要有方法体此方法名就是起到⼀个“标识”的作用标识下面的 通知方法具体指的是哪个切点因为切点可能有很多个) AspectJ 支持三种通配符 * 匹配任意字符只匹配⼀个元素包类或方法方法参数 .. 匹配任意字符可以匹配多个元素 在表示类时必须和 * 联合使用。 表示按照类型匹配指定类的所有类必须跟在类名后面如 com.cad.Car ,表示继承该类的 所有子类包括本身 切点表达式由切点函数组成其中 execution() 是最常用的切点函数用来匹配方法语法为 execution(修饰符返回类型包.类.方法(参数)异常) 修饰符和异常可以省略具体含义如下 上面我们定义的含义为,匹配com.javastudy.springaopdemo5.controller.LoginController类下所有的方法. 3.定义相关通知 先来定义controller层的内容 RestController Slf4j RequestMapping(/user) public class LoginController {RequestMapping(/login)public String login() {log.info(login...);return login...;}RequestMapping(/register)public String register() {log.info(register...);return register...;}RequestMapping(/get)public String get() {log.info(get...);return get...;}}1.前置通知 Before 通知方法会在目标方法调用之前执行。 注意:Before里面的内容表示切点,即在哪些接口中执行这些通知. Component Slf4j Aspect public class LoginAspect {Pointcut(execution(* com.javastudy.springaopdemo5.controller.LoginController.*(..)))public void pointcut() {}//前置通知Before(pointcut())public void doBefore() {log.info(do before....);}}当我们访问任意一个页面的时候,控制台打印如下日志 可以看到都会先执行doBefore通知. 2.后置通知 After 通知方法会在目标方法返回或者抛出异常后调用。 //后置通知After(pointcut())public void doAfter() {log.info(do after...);}模拟异常情况,可以在LoginController中某一个方法加10/0,观察 RequestMapping(/login)public String login() {log.info(login...);int i10/0;return login...;} 可以观察到在方法异常之后, After通知仍然会执行. 3.返回之后通知 AfterReturning 通知方法会在目标方法返回后调用。 // return 之前通知AfterReturning(pointcut())public void doAfterReturning() {log.info(do after returning...);}当我们访问login接口的时候(10/0,有异常),观察是否有输出 此时是没有输出的. 访问其它接口,没有异常的接口 此时AfterReturning通知正常执行 4.抛异常后通知 AfterThrowing 通知方法会在目标方法抛出异常后调用。 //抛出异常之前通知AfterThrowing(pointcut())public void doAfterThrowing() {log.info(do after throwing);} 执行有异常的接口,有日志的打印 执行没有异常的接口,没有日志的打印  5.环绕通知 Around 通知包裹了被通知的方法在被通知的方法通知之前和调用之后执行自定义的行为。 Around(pointcut())public Object doAround(ProceedingJoinPoint joinPoint) {Object oj null;log.info(环绕通知执行之前...);log.info(joinPoint.getSignature().toLongString());try {oj joinPoint.proceed();//调用目标方法} catch (Throwable e) {throw new RuntimeException(e);}log.info(环绕通知执行之后....);return oj;} 执行没有异常的接口: 执行有异常的接口:  接下来我们看看ProceedingJoinPoint 常用方法 toString连接点所在位置的相关信息toShortString连接点所在位置的简短相关信息toLongString连接点所在位置的全部相关信息getThis返回AOP代理对象也就是com.sun.proxy.$Proxy18getTarget返回目标对象(定义方法的接口或类)getArgs()返回被通知方法参数列表getSignature返回当前连接点签名,其getName()方法返回方法的FQN 执行所有的通知,观察环绕通知和前置通知和后置通知的先后顺序 可以观察到,环绕通知先于before,后于after. 如果一个切点只含有一个通知,那么我们可以将切点的规则放在通知上 Component Slf4j Aspect public class LoginAspect {//前置通知Before(execution(* com.javastudy.springaopdemo5.controller.LoginController.*(..)))public void doBefore() {log.info(do before....);}}4.Spring AOP 实现原理 Spring AOP 是构建在动态代理基础上因此 Spring 对 AOP 的支持局限于方法级别的拦截。 Spring AOP 支持 JDK Proxy 和 CGLIB 方式实现动态代理。默认情况下实现了接口的类使 用 AOP 会基于 JDK 生成代理类没有实现接口的类会基于 CGLIB 生成代理类。 代理模式: 1.静态代理 1.定义接口 public interface PayService {void pay(); }2.实现接口 public class AliPayService implements PayService{Overridepublic void pay() {System.out.println(ali pay...);} }3.创建代理类, 并同样实现支付接口 public class StaticProxy implements PayService {private final PayService payService;public StaticProxy(PayService payService) {this.payService payService;}Overridepublic void pay() {System.out.println(before...);payService.pay();System.out.println(after...);} } 4.实际使用 public static void main(String[] args) {PayService service new AliPayService();PayService proxy new StaticProxy(service);proxy.pay();} 静态代理有个很大的缺点,就是当有很多不同的接口的时候,我们需要定义很多个代理类实现不同的接口,当我们代理实现的功能相同的时候,但是有多个接口,此时完成这么多代理类很麻烦,此时需要我们的动态代理. 2.动态代理 1.JDK动态代理 从 JVM 角度来说动态代理是在运行时动态生成类字节码并加载到 JVM 中 的。 就 Java 来说动态代理的实现方式有很多种比如 JDK 动态代理、CGLIB 动态 代理等等。 定义JDK动态代理类 import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method;/*** author Chooker* create 2023-07-27 22:36*/public class JDKInvocationHandler implements InvocationHandler {//⽬标对象即就是被代理对象private Object target;public JDKInvocationHandler(Object target) {this.target target;}//proxy代理对象Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//1.安全检查System.out.println(安全检查);//2.记录⽇志System.out.println(记录⽇志);//3.时间统计开始System.out.println(记录开始时间);//通过反射调⽤被代理类的⽅法Object retVal method.invoke(target, args);//4.时间统计结束System.out.println(记录结束时间);return retVal;} } 创建⼀个代理对象并使用  public static void main(String[] args) {PayService target new AliPayService();//创建⼀个代理类通过被代理类、被代理实现的接⼝、⽅法调⽤处理器来创建PayService proxy (PayService) Proxy.newProxyInstance(target.getClass().getClassLoader(),new Class[]{PayService.class},new JDKInvocationHandler(target));proxy.pay();} 缺点:JDK的动态代理必须有接口 2.CGLIB动态代理 CGLIB 动态代理类使用步骤 1. 定义一个类 2. 自定义 MethodInterceptor 并重写 intercept 方法intercept 用于拦截增强 被代理类的方法和 JDK 动态代理中的 invoke 方法类似 3. 通过 Enhancer 类的 create()创建代理类 添加依赖(如果创建的是一个Spring项目,不需要引入,因为Spring底层已经引入了cglib框架) dependencygroupIdcglib/groupIdartifactIdcglib/artifactIdversion3.3.0/version /dependency 自定义 MethodInterceptor方法拦截器 import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy;import java.lang.reflect.Method;/*** author Chooker* create 2023-07-27 22:48*/ public class CGLIBInterceptor implements MethodInterceptor {//被代理对象private Object target;public CGLIBInterceptor(Object target) {this.target target;}Overridepublic Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {//1.安全检查System.out.println(安全检查);//2.记录⽇志System.out.println(记录⽇志);//3.时间统计开始System.out.println(记录开始时间);//通过cglib的代理⽅法调⽤Object retVal methodProxy.invoke(target, args);//4.时间统计结束System.out.println(记录结束时间);return retVal;}} 1. obj : 被代理的对象需要增强的对象 2. method : 被拦截的方法需要增强的方法 3. args : 方法入参 4. proxy : 用于调用原始方法 创建代理类, 并使用  public static void main(String[] args) {PayService target new AliPayService();PayService proxy (PayService) Enhancer.create(target.getClass(), new CGLIBInterceptor(target));proxy.pay();}JDK 动态代理和 CGLIB 动态代理对比 1. JDK 动态代理只能代理实现了接口的类或者直接代理接口而 CGLIB 可以代 理未实现任何接口的类。 2. CGLIB 动态代理是通过生成⼀个被代理类的子类来拦截被代理类的方法调用因此不能代理声明为 final  性能: 大部分情况都是 JDK 动态代理更优秀随着 JDK 版本的升级这个优势更 加明显。 Spring代理选择 1. proxyTargetClass 为false, 目标实现了接口, 用jdk代理 2. proxyTargetClass 为false, 目标未实现接口, 用cglib代理 3. proxyTargetClass 为true, 用cglib代理 织入Weaving代理的生成时机 织入是把切面应用到目标对象并创建新的代理对象的过程切面在指定的连接点被织入到目标对 象中。 在目标对象的生命周期里有多个点可以进行织入 编译期切面在目标类编译时被织入。这种方式需要特殊的编译器。AspectJ的织入编译器就是以这种方式织入切面的。类加载期切面在目标类加载到JVM时被织入。这种方式需要特殊的类加载器ClassLoader,它可以在目标类被引入应用之前增强该目标类的字节码。AspectJ5的加载时织入load-time weaving. LTW就支持以这种方式织入切面。运行期切面在应用运行的某⼀时刻被织入。⼀般情况下在织入切面时AOP容器会为目标对象动态创建⼀个代理对象。SpringAOP就是以这种方式织入切面的。 上面我们学习的是Spring AOP的原理,是接下来我们学习内容的底层,SpringBoot一些常见的功能进行了封装,底层使用AOP实现的 二.SpringBoot 统一功能处理 需要实现用户的登录权限的校验功能,在Servlet阶段,我们可以通过在Session中保存用户的信息,之后每个页面先通过session中判断是否存在用户的信息,如果存在说明用户已经登录过了,没有就跳转到登录的页面. 1.Spring AOP 用户统一登录验证的问题 我们第一时间想到的就是通过环绕通知来解决这个问题,可以对除了登录和注册的页面采用环绕通知,用来判断用户是否登录过了.但是会出现以下两个问题 1.. 没办法获取到 HttpSession 对象。 2. 我们要对一部分方法进行拦截而另一部分方法不拦截如注册方法和登录方法是不拦截的这样 的话排除方法的规则很难定义甚至没办法定义。 那么该如何解决呢? 2.Spring 拦截器 对于以上问题 Spring 中提供了具体的实现拦截器HandlerInterceptor拦截器的实现分为以下两个步骤 1. 创建自定义拦截器实现 HandlerInterceptor 接口的 preHandle执行具体方法之前的预处理方法。 2. 将自定义拦截器加入 WebMvcConfigurer 的 addInterceptors 方法中 1.自定义拦截器 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;}//没有权限访问response.setStatus(401);return false;} }2.将自定义拦截器加入到系统配置 Configuration public class AppConfig implements WebMvcConfigurer {Autowiredprivate LoginInterceptor loginInterceptor;Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(loginInterceptor).//表示拦截所有的路径addPathPatterns(/**).//不拦截login接口excludePathPatterns(/login).//不拦截register接口excludePathPatterns(/register);} }其中 addPathPatterns表示需要拦截的 URL“**”表示拦截任意方法也就是所有方法。 excludePathPatterns表示需要排除的 URL。 说明以上拦截规则可以拦截此项目中的使用 URL包括静态文件图片文件、JS 和 CSS 等文件。 排除所有的静态资源 // 拦截器Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new LoginInterceptor()).addPathPatterns(/**) // 拦截所有接⼝.excludePathPatterns(/**/*.js).excludePathPatterns(/**/*.css).excludePathPatterns(/**/*.jpg).excludePathPatterns(/login.html).excludePathPatterns(/**/login); // 排除接⼝} 拓展以下,可以在里面添加统一前缀的添加 Configuration public class AppConfig implements WebMvcConfigurer {Autowiredprivate LoginInterceptor loginInterceptor;Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(loginInterceptor).addPathPatterns(/**)// 拦截所有url.excludePathPatterns(/api/user/login).excludePathPatterns(/api/user/reg);}Overridepublic void configurePathMatch(PathMatchConfigurer configurer) {configurer.addPathPrefix(api, c - true);} } 3.controller接口模仿登录 RestController Slf4j RequestMapping(/user) public class LoginController {RequestMapping(/login)public boolean login(HttpServletRequest request, String username, String password) {log.info(login...);if (!StringUtils.hasLength(username) || !StringUtils.hasLength(password)) {return false;}//此时表示账号密码正确if (admin.equals(username) 123456.equals(password)) {HttpSession session request.getSession(true);session.setAttribute(username, username);return true;}return false;}RequestMapping(/register)public String register() {log.info(register...);return register...;}RequestMapping(/get)public String get() {log.info(get...);return get...;}}当我们直接访问get接口的时候:显示的是401,表示没有权限 正常访问login和register接口都是可以实现的 此时我们使用正确的账号密码登录:可以看到此时已经正确登录了 此时我们再次访问get接口:可以看到此时正确访问 3.拦截器的实现原理 正常情况下的调用顺序 然而有了拦截器之后会在调用 Controller 之前进行相应的业务处理执行的流程如下图所示 拦截器是基于AOP的,Spring是基于Servlet的  三.统一异常处理 统一异常处理使用的是 ControllerAdvice ExceptionHandler 来实现的ControllerAdvice 表示控制器通知类ExceptionHandler 是异常处理器两个结合表示当出现异常的时候执行某个通知 也就是执行某个方法事件具体实现代码如下 ControllerAdvice ResponseBody public class ErrorHandler {ExceptionHandler(Exception.class)public Object error(Exception e) {HashMapString, Object map new HashMap();map.put(success, 0);map.put(status, -1);map.put(msg, e.getMessage());return map;}ExceptionHandler(NullPointerException.class)public Object error2(NullPointerException e) {HashMapString, Object result new HashMap();result.put(success, 0);result.put(status, -2);result.put(message, 空指针异常 e.getMessage());return result;}ExceptionHandler(ArithmeticException.class)public Object error2(ArithmeticException e) {HashMapString, Object result new HashMap();result.put(success, 0);result.put(status, -3);result.put(message, 算数异常 e.getMessage());return result;} }controller RestController Slf4j RequestMapping(/error) public class ErrorController {RequestMapping(/test1)public boolean test1() {int i 10 / 0;return true;}RequestMapping(/test2)public boolean test2() {String a null;a.length();return true;}RequestMapping(/test3)public String test3() {throw new RuntimeException(test3手动创建异常);} }当有多个异常通知时匹配顺序为当前类及其子类向上依次匹配 访问test1 访问test2 访问test3 可以观察到当错误异常为子类的时候,匹配顺序为当前类及其子类向上依次匹配 三.统一数据返回格式 1.为什么需要统一返回格式 统一数据返回格式的优点有很多比如以下几个 方便前端程序员更好的接收和解析后端数据接口返回的数据。降低前端程序员和后端程序员的沟通成本按照某个格式实现就行了因为所有接口都是这样返回的。有利于项目统一数据的维护和修改。有利于后端技术部门的统一规范的标准制定不会出现稀奇古怪的返回内容 2.统一数据返回格式的实现 统一的数据返回格式可以使⽤ ControllerAdvice ResponseBodyAdvice 的方式实现具体实现代码如下 ControllerAdvice public class ResponseHandler implements ResponseBodyAdvice {/*** 内容是否需要重写通过此⽅法可以选择性部分控制器和⽅法进⾏重写* 返回 true 表示重写*/Overridepublic boolean supports(MethodParameter returnType, Class converterType) {return true;}/*** ⽅法返回之前调⽤此⽅法*/SneakyThrowsOverridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {// 构造统⼀返回对象HashMapString, Object result new HashMap();result.put(state, 1);result.put(msg, );result.put(data, body);if(body instanceof String){ObjectMapper objectMapper new ObjectMapper();return objectMapper.writeValueAsString(result);}return result;} }假如没有if((body instanceof String)这一段代码,会发生如下的错误 controller: RestController Slf4j RequestMapping(/user) public class LoginController {RequestMapping(/login)public boolean login(HttpServletRequest request, String username, String password) {log.info(login...);if (!StringUtils.hasLength(username) || !StringUtils.hasLength(password)) {return false;}//此时表示账号密码正确if (admin.equals(username) 123456.equals(password)) {HttpSession session request.getSession(true);session.setAttribute(username, username);return true;}return false;}RequestMapping(/register)public String register() {log.info(register...);return register...;}RequestMapping(/get)public String get() {log.info(get...);return get...;}}
http://www.tj-hxxt.cn/news/232061.html

相关文章:

  • 泰坦科技网站建设科技感网站模板
  • 网站建设对接流程连锁销售公司网站的建设方案
  • win7局域网网站建设wordpress侧边悬浮框
  • 德保网站建设交换友情链接的目的
  • 网站建设设计费用摊销年限西安有做网站的吗
  • 潍坊网站建设wancet搜索关键词优化排名
  • 网站建设的一些原理网站建设外包多少钱
  • 路桥区高质量营销型网站建设wordpress采集软件
  • 网站+做+app中山手机建网站
  • 国外营销型网站如何用网站做招聘
  • 建站宝盒模板网站一定也做数据库吗
  • 广州一起做网店官网网站优化网络公司
  • 长沙有哪些做网站的公司厦门十家较好的网站建设公司
  • 大旺建设局网站学校校园网站建设实施方案
  • 网站建设如何开票本地生活网免费发信息
  • 江山有做网站开发吗南通仿站定制模板建站
  • 郑州做公司网站的公司新闻发布会筹备方案
  • 武昌网站建设的公司上海市城乡建设部网站首页
  • 个人如何建立公司网站佛山短视频拍摄
  • 交流平台网站怎么做不了公司变更说明
  • 企业做网站etp和源程序网站定制兴田德润实力强
  • 网站建设 sql智能网站建设背景
  • 查商家信息有哪些网站商贸公司注册需要多少钱
  • 用公司的信息做网站违法吗房地产开发与管理专业
  • 直播网站建设品牌刚刚传来最新消息
  • 做包装一般看什么网站禁止wordpress评论外链
  • 青岛网站建设方案公司wordpress调用图像描述
  • 支付公司网站建设会计分录东莞专业的单位网站建设
  • 网站产品优化阳江招聘网娱乐业
  • 提供网站制作公司在线代理ip网页