Day50

Spring AOP

概念

AOP全称为Aspect Oriented Programming,表示面向切面编程。切面指的是将那些与业务无关,但业务模块都需要使用的功能封装起来的技术。

AOP基本术语

**连接点(Joinpoint):**连接点就是被拦截到的程序执行点,因为Spring只支持方法类型的连接点,所以在Spring中连接点就是被拦截到的方法。连接点由两个信息确定:

  • 方法( 表示程序执行点,即在哪个目标方法)
  • 相对点(表示方位,即目标方法的什么位置,比如调用前,后等)

切入点(Pointcut): 一般认为,所有的方法都可以认为是连接点,但是我们并不希望在所有的方法上都添加通知,而切入点的作用就是提供一组规则来匹配连接点,给满足规则的连接点添加通知。

**通知、增强(Advice) : **可以为切入点添加额外功能,分为:前置通知、后置通知、异常通知、环绕通知、最终通知等。

**目标对象(Target)**目标对象指将要被增强的对象,即包含主业务逻辑的类对象。或者说是被一个或者多个切面所通知的对象。

**织入(Weaving):**织入是将切面和业务逻辑对象连接起来, 并创建通知代理的过程。织入可以在编译时,类加载时和运行时完成。在编译时进行织入就是静态代理,而在运行时进行织入则是动态代理。

**代理(Proxy):**被AOP织入通知后,产生的结果类。

**切面(Aspect):*切面是一个横切关注点的模块化,一个切面能够包含同一个类型的不同增强方法,比如说事务处理和日志处理可以理解为两个切面。切面由切入点和通知组成。Spring AOP就是负责实施切面的框架,它将切面所定义的横切逻辑织入到切面所指定的连接点中。

应用

配置pom文件:

<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.11</version>
</dependency>
<!-- 切面相关的包 -->
<dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.8.9</version>
</dependency>

编写业务层:

接口:

public interface UserService {int saveUser(Map<String,Object> params);
}

实现类:

public class UserServiceImpl implements UserService{@Overridepublic int saveUser(Map<String, Object> params) {System.out.println("保存用户信息" + params);return 0;}
}

配置业务层:

spring-aop.xml:

<!--业务层对象--><bean id="userService" class="com.qf.aop.service.UserServiceImpl"/>

编写通知类:
通知分为前置通知、后置通知、异常抛出通知、环绕通知、最终通知(没什么用这里不实现)。

前置通知:

接口为MethodBeforeAdvice,其底层实现如下:

public interface MethodBeforeAdvice extends BeforeAdvice {/*** Callback before a given method is invoked.*/void before(Method method, Object[] args, @Nullable Object target) throws Throwable;
}

使用前置通知需要实现这个接口:

public class BeforeAdvice implements MethodBeforeAdvice{@Overridepublic void before(Method method, Object[] args, Object target) throws Throwable {String methodName = method.getName();String className = method.getDeclaringClass().getName();System.out.println("准备执行方法:" + className + "." + methodName + "参数:" + Arrays.toString(args));}
}

写完通知类后需要配置通知:

spring-aop.xml:

<!--业务层对象-->
<bean id="userService" class="com.qf.aop.service.UserServiceImpl"/><!--配置通知对象-->
<bean id="before" class="com.qf.aop.advice.BeforeAdvice"/>

当通知对象和业务层对象都纳入IOC容器管理之后,需要将通知对象作用在业务层对象上。Spring提供了aop标签来完成这一功能。

<!--aop配置--><aop:config><!--pointcut表示切点,也就是通知会在哪些位置触发expression表示切点表达式,切点表达式必须是execution(), execution()方法中的参数必须配置到方法上比如 * com.qf.spring.aop.service..*(..)第一个 * 表示任意访问修饰符com.qf.spring.aop.service.. 最后的两个..表示service包下面的所有子包中的类*(..) 表示任意方法, 如果()中没有..,则表示不带参数的方法;有,就表示带任意参数--><!--切入点配置--><aop:pointcut id="pc" expression="execution(* com.qf.aop.service..*(..))"/><!--通知配置--><aop:advisor advice-ref="before" pointcut-ref="pc"/></aop:config>
</beans>

测试:

public class AopTest {@Testpublic void saveUserTest(){ApplicationContext context = new ClassPathXmlApplicationContext("spring-aop.xml");UserService userService = context.getBean("userService", UserService.class);HashMap<String, Object> map = new HashMap<>();map.put("name","爱德华");map.put("sex","男");int i = userService.saveUser(map);}
}

注:利用ClassPathXmlApplicationContext拿到配置文件上下文对象,进而拿到bean对象。

后置通知接口:AfterReturningAdvice.

剩下的流程和前置接口相同,编写通知类,配置通知类对象,配置通知。

<!--配置通知对象--><bean id="before" class="com.qf.aop.advice.BeforeAdvice"/><bean id="after" class="com.qf.aop.advice.AfterAdvice"/><!--aop配置--><aop:config><!--切入点配置--><aop:pointcut id="pc" expression="execution(* com.qf.aop.service..*(..))"/><!--通知配置--><aop:advisor advice-ref="before" pointcut-ref="pc"/><aop:advisor advice-ref="after" pointcut-ref="pc"/></aop:config>
</beans>
异常抛出通知

异常抛出接口为ThrowsAdvice。

注意:异常通知类接口没有要重写的方法,而是自定义。

public class ExceptionAdvice implements ThrowsAdvice {public void afterThrowing(Method method, Object[] args, Object target, Exception ex){String methodName = method.getName();String className = method.getDeclaringClass().getName();System.out.println("执行方法时:" + className + "." + methodName + ",参数:" + Arrays.toString(args) + ",发生了异常:" + ex.getMessage());}
}

配置和前面相同:

<bean id="exception" class="com.qf.aop.advice.ExceptionAdvice" /><aop:advisor advice-ref="exception" pointcut-ref="pc"/>
环绕通知

接口:MethodInterceptor

注意:1.这里重写的方法参数为MethodInvocation invocation,可以通过invocation.getMethod();//获取被拦截的方法。

public class AroundAdvice implements MethodInterceptor {@Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {Method method = invocation.getMethod();//获取被拦截的方法对象Object[] args = invocation.getArguments();//获取方法的参数Object target = invocation.getThis();//获取代理对象String methodName = method.getName();String className = method.getDeclaringClass().getName();System.out.println("准备执行方法:" + className + "." + methodName + ",参数:" + Arrays.toString(args));Object returnVal = method.invoke(target, args);System.out.println("执行完方法:" + className + "." + methodName + ",参数:" + Arrays.toString(args) + ",得到返回值:" + returnVal);return returnVal;}
}

环绕通知可以实现前置通知、后置通知、异常抛出通知的功能,所以配置文件中只需要配置环绕通知即可。

<!--业务层对象-->
<bean id="userService" class="com.qf.aop.service.UserServiceImpl"/><!--配置通知对象--><bean id="around" class="com.qf.aop.advice.AroundAdvice"/><!--aop配置-->
<aop:config><!--切入点配置--><aop:pointcut id="pc" expression="execution(* com.qf.aop.service..*(..))"/><!--通知配置--><aop:advisor advice-ref="around" pointcut-ref="pc"/>
</aop:config>

AspectJ

简介:

AspectJ是一个面向切面的框架,它扩展了Java语言,定义了AOP 语法,能够在编译期提供代码的织入。Spring通过集成AspectJ实现了以注解的方式定义增强类,大大减少了配置文件中的工作量

注解:

  • @Aspect 切面标识
  • @Pointcut 切入点
  • @Before 前置通知
  • @AfterReturning 后置通知
  • @Around 环绕通知
  • @AfterThrowing 异常抛出通知

通知类编写:

package com.qf.aop.advice;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;import java.lang.reflect.Method;
import java.util.Arrays;@Aspect
public class AspectJAdvice {@Before(value = "execution(* com.qf.aop.service..*(..))")public void before(JoinPoint jp){Signature signature = jp.getSignature();//获取签名Object[] args = jp.getArgs();//获取方法参数if(signature instanceof MethodSignature){//如果签名是方法签名Method method = ((MethodSignature) signature).getMethod();//获取方法String methodName = method.getName();String className = method.getDeclaringClass().getName();System.out.println("准备执行方法:" + className + "." + methodName + ",参数:" + Arrays.toString(args));}}@AfterReturning(value = "execution(* com.qf.aop.service..*(..))", returning = "returnValue")public void after(JoinPoint jp, Object returnValue){Object[] args = jp.getArgs(); //获取方法参数Signature signature = jp.getSignature(); //获取签名if(signature instanceof MethodSignature){ //如果签名是方法签名Method method = ((MethodSignature) signature).getMethod(); //获取方法String methodName = method.getName();String className = method.getDeclaringClass().getName();System.out.println("执行完方法:" + className + "." + methodName + ",参数:" + Arrays.toString(args) + ",得到返回值:" + returnValue);}}@AfterThrowing(value = "execution(* com.qf.aop.service..*(..))", throwing = "t")public void exception(JoinPoint jp, Throwable t){Object[] args = jp.getArgs(); //获取方法参数Signature signature = jp.getSignature(); //获取签名if(signature instanceof MethodSignature){ //如果签名是方法签名Method method = ((MethodSignature) signature).getMethod(); //获取方法String methodName = method.getName();String className = method.getDeclaringClass().getName();System.out.println("执行方法时:" + className + "." + methodName + ",参数:" + Arrays.toString(args) + ",发生了异常:" + t.getMessage());}}@Around("execution(* com.qf.aop.service..*(..))")public Object around(ProceedingJoinPoint pjp) throws Throwable {Object[] args = pjp.getArgs();//获取方法的参数Object target = pjp.getTarget(); //获取代理对象Signature signature = pjp.getSignature(); //获取签名if(signature instanceof MethodSignature) { //如果签名是方法签名Method method = ((MethodSignature) signature).getMethod(); //获取被拦截的方法对象String methodName = method.getName();String className = method.getDeclaringClass().getName();try {System.out.println("准备执行方法:" + className + "." + methodName + ",参数:" + Arrays.toString(args));Object returnValue = method.invoke(target, args);System.out.println("执行完方法:" + className + "." + methodName + ",参数:" + Arrays.toString(args) + ",得到返回值:" + returnValue);return returnValue;} catch (Throwable t){System.out.println("执行方法时:" + className + "." + methodName + ",参数:" + Arrays.toString(args) + ",发生了异常:" + t.getMessage());throw t;}}return null;}
}

启用注解支持:

<!--配置通知对象-->
<bean class="com.qf.aop.advice.AspectJAdvice"/> <!--启动AspectJ注解 自动为类生成代理--><aop:aspectj-autoproxy proxy-target-class="true"/>

SpringMVC

简介

1. Spring MVC

SpringMVC是一个Java 开源框架, 是Spring Framework生态中的一个独立模块,它基于 Spring 实现了Web MVC(数据、业务与展现)设计模式的请求驱动类型的轻量级Web框架,为简化日常开发,提供了很大便利。

2. Spring MVC 核心组件

  • DispatcherServlet 前置控制器

    负责接收请求、分发请求

  • Handler 处理器

    处理器包括了拦截器、控制器中的方法等,主要负责处理请求

  • HandlerMapping 处理器映射器

    解析配置文件、扫描注解,将请求与处理器进行匹配

  • HandlerAdpter 处理器适配器

    根据请求来找到匹配的处理器,这个过程称为适配

  • ViewResolver 视图解析器

    处理器执行后得到的结果可能是一个视图,但这个视图属于逻辑视图(页面中存在逻辑代码,比如循环、判断),需要使用视图解器行处理,这个过程称为渲染视图

Spring MVC工作原理

在这里插入图片描述

mvc工作原理

前端发送的请求由DispatcherServlet接收到,然后根据提供的HandlerMapping来分发过去,在分发请求过程中使用到HandlerAdapter来适配处理器(因为处理的类型无法确定),找到对应的处理器适配器之后就会执行这个处理器,执行会得到一个ModelAndView,然后交给ViewResolver进行解析得到视图位置,然后对视图进行渲染,渲染完成后将渲染好的视图交给DispatcherServlet,然后传回前端展示。

Spring MVC发展演变

1.Bean的名字或ID匹配URL请求

由于版本更新,使用新版本会无法完成过时的功能,但是为了更好地理解演变的过程,这里使用低版本:

<!--低版本-->
<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>4.3.9.RELEASE</version>
</dependency>
<dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>4.3.9.RELEASE</version>
</dependency>
<dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>4.0.1</version><scope>provided</scope>
</dependency>

首先需要再web.xml配置文件中配置DispatcherServlet,包括初始化参数(全局上下文,自己项目的配置文件路径以及使得项目启动时就创建servlet的初始化参数)

<servlet><servlet-name>dispatcherServlet</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:spring-mvc.xml</param-value></init-param><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>dispatcherServlet</servlet-name><url-pattern>/</url-pattern></servlet-mapping>

然后是自己写的spring-mvc.xml配置,这里需要写视图解析器、处理器映射器(处理器适配器采用默认的,在底层mvc框架中会根据处理器类型寻找合适的处理器适配器)。具体的逻辑为前端发送请求->处理器映射方式、配置控制器找到控制器->控制器返回modelandview->视图解析器解析路径找到jsp文件:

 <!--视图解析器--><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/"/><property name="suffix" value=".jsp"/></bean><!--处理器映射的方式:使用bean的名字或者id的值来与请求匹配--><bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/><!--通过id值匹配请求的URL--><bean id="/user" class="com.qf.controller.UserController"/>

处理器映射器给出映射的方式:使用bean的名字或者id,然后DispatcherServlet找到处理器适配器,处理器适配器提供id和处理器的路径。然后底层会根据路径找到处理器。

处理器:

public class UserController extends AbstractController {@Overrideprotected ModelAndView handleRequestInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {return new ModelAndView("user");}
}

处理器返回ModelAndView给适配器,DispatcherServlet根据id拿到返回的ModelAndView,并交给视图解析器进行处理,最终将处理好的路径进行渲染。

但是这样做有一个问题,每一个请求都需要一个控制器与之对应,如果有很多请求,那么就要写很多个控制器。开发效率极为低下,而Spring提供了方法名匹配请求来解决这个问题。

2.Bean方法名匹配请求

方法名解析器:InternalPathMethodNameResolver,将方法名作为匹配URL请求的依据,与控制器关联起来。

这样一来请求就可以直接与控制器中的方法关联,那么控制器中的方法就应该有多个。

多操作控制器:

MultiActionController控制器类,供其他控制器类继承,在其子类中可以编写多个处理请求的方法,然后使用方法名解析器去匹配请求。

控制器:

public class UserMultiController extends MultiActionController {//这个方法匹配/login请求public ModelAndView login(HttpServletRequest request, HttpServletResponse response){return new ModelAndView("login");}//这个方法匹配/register请求public ModelAndView register(HttpServletRequest request,HttpServletResponse response){return new ModelAndView("register");}
}

编写完控制器后需要写相应的控制器映射器(视图解析器不变):

spring-mvc.xml:

<!--方法名解析器,处理映射的方式:使用方法名--><bean id="methodNameResolver" class="org.springframework.web.servlet.mvc.multiaction.InternalPathMethodNameResolver"/><!--/login 请求使用该bean对象处理--><bean id="/login" class="com.qf.controller.UserMultiController"><property name="methodNameResolver" ref="methodNameResolver"/></bean><!--/register 请求使用该bean对象处理--><bean id="/register" class="com.qf.controller.UserMultiController"><property name="methodNameResolver" ref="methodNameResolver"/></bean>

按照这种匹配请求的方式,如果一个控制器要处理多个请求,就会导致此配置文件无限扩展,变得冗杂,后期难以维护,这时如何解决?

Spring提供了SimpleUrlHandlerMapping映射器,该映射器支持一个控制器与多个请求匹配的同时也解决了配置信息繁多的问题。

3.简单URL处理器映射

在Bean方法名匹配请求方式的控制器不变的基础上,只需要改动控制器映射器即可:

spring-mvc.xml:

<!--使用简单URL处理器映射--><bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"><property name="mappings"><props><prop key="/view">userController</prop><prop key="/user/*">userMultiController</prop></props></property></bean><bean id="userController" class="com.qf.controller.UserController"/><bean id="userMultiController" class="com.qf.controller.UserMultiController"/>

随着业务的增加,控制器的数量也为增加,请求的匹配也会增多,xml文件里虽然减少了冗余,但每次增加方法也会增加代码量,如何解决?

-Spring提供了DefaultAnnotationHandlerMapping映射器,支持使用注解来匹配请求,这样就解决了请求匹配导致配置信息繁多的问题,同时还提升了开发效率。

注解匹配请求

控制器中通过@Controller注解说明这是一个处理器,方法中通过@RequestMapping注解注明映射信息。

controller:

@Controller
public class UserAnnotationController {@RequestMapping(value = "/login",method = RequestMethod.GET)public String login(){return "login";}@RequestMapping(value = "register",method = RequestMethod.GET)public String register(){return "register";}
}

注意:这次的controller不需要实现接口或者继承抽象类了,也就意味着可以自定义方法,只需要在方法上加注解就可以达到映射的效果。

写好处理器后需要配置(视图解析器还是不用变,只需要改变处理器映射器就行):
spring-mvc.xml:

<!--类上的注解处理器--><bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/><!--方法上的注解处理器--><bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"><!--扫描包,使得该包下类以及类中定义的方法上所使用的注解生效--><context:component-scan base-package="com.qf.controller" />
新的版本配置
<!--较新的版本使用该标签启动注解支持-->
<mvc:annotation-driven/>
<!--扫描包,使类和类方法注解生效-->
<context:component-scan base-package="com.qf.controller"/>

相当于使用一句话代替了原来对类和方法上注解处理器的声明。


Spring MVC常用注解

@Controller

控制器的标识

@Controller
public class UserController{}

@RequestMapping

该注解用于匹配请求(注明URI)

@Controller
@RequestMapping("/user")
public class UserController{@RequestMapping(value="/login", method=RequestMethod.POST)public int login(){return 1;}
}

@RequestBody

该方法只能用在方法的参数上,用于从请求体中获取数据并注入参数中,并且获取的数据只能是JSON格式的数据。

@Controller
@RequestMapping("/user")
public class UserController{@RequestMapping(value="/login", method=RequestMethod.POST)public int login(@RequestBody User user){return 1;}
}

@ResponseBody

该注解用于向页面传递数据,如果没有该注解,那么controller方法中返回的任何数据都会被认为是一个页面字符串。

@Controller
@RequestMapping("/user")
public class UserController{@RequestMapping(value="/login", method=RequestMethod.POST)@ResponseBodypublic int login(@RequestBody User user){return 1;}
}

@RequestParam

该注解只能用在方法的参数上, 用于从 URL 查询字符串或表单参数中提取参数。

@Controller
@RequestMapping("/user")
public class UserController{@RequestMapping(value="/search", method=RequestMethod.GET)@ResponseBodypublic List<User> searchUsers(@RequestParam(value="name") String name){return new ArrayList<>();}
}

注意:@RequestParam和@PathVariable的区别:

@PathVariable

  • 用于从 URL 路径中提取参数。
  • 例如:提取 http://example.com/user/john 中的 john
  • 用于 RESTful 风格的 URL。

@RequestParam

  • 用于从 URL 查询字符串或表单参数中提取参数。
  • 例如:提取 http://example.com/user/search?name=john 中的 name,或提取表单提交的数据。
  • 适用于查询字符串参数和表单参数。

@PathVariable

该注解只能应用在方法的参数上,用于从请求路径中获取数据并注入至参数中

@Controller
@RequestMapping("/user")
public class UserController{// /user/admin@RequestMapping(value="/{username}", method=RequestMethod.GET)@ResponseBodypublic User queryUser(@PathVariable("username") String username){return new User();}
}

注意: 花括号 {} 用于定义路径变量,表示 URL 中的动态部分,这些部分将被提取并传递给控制器方法的参数。 前端在发送请求时,必须用具体的 username 替换路径变量 。

@RequestHeader

该注解只能应用在方法的参数上,用于从请求头中获取数据

@RequestMapping("/find")  
public void findUsers(@RequestHeader("Content-Type") String contentType) {//从请求头中获取Content-Type的值
}  

@CookieValue

该注解只能应用在方法的参数上,用于从请求中获取cookie的值

@RequestMapping("/find")  
public void findUsers(@CookieValue("JSESSIONID") String jsessionId) {//从请cookie中获取jsessionId的值
}  

@ControllerAdvice

该注解只能应用在类上,表示这个类就是处理异常的控制器

/*** 异常处理的控制器*/
@ControllerAdvice //这个注解就是spring mvc提供出来做全局异常统一处理的
public class ExceptionController {
}

@ExceptionHandler

该注解只能应用在@ControllerAdvice或者@RestControllerAdvice标识的类的方法上用来处理异常

/*** 异常处理的控制器*/
@ControllerAdvice //这个注解就是spring mvc提供出来做全局异常统一处理的
public class ExceptionController {@ExceptionHandler //异常处理器@ResponseBody //响应至页面public String handleException(Exception e){return e.getMessage();}
}

Spring 对 RESTFUL的支持

@RestController

相当于@Controller 和 @ResponseBody 注解的组合。表示该类中的所有方法执行完成后所返回的结果直接向页面输出。

@GetMapping
@PostMapping
@PutMapping
@DeleteMapping

静态资源处理

静态资源无法访问的原因

静态资源包含html、js、css、图片、字体文件等。静态文件没有url-pattern,所以默认是无法访问的。之所以可以访问,是因为tomcat中有一个全局的servlet:org.apache.catalina.servlets.DefaultServlet,它的url-pattern是 “/”, 所以项目中不能匹配的静态资源请求,都由这个Servlet来处理。但在SpringMVC中DispatcherServlet也采用了"/" 作为url-pattern, 那么项目中不会再使用全局的Serlvet,这样就造成了静态资源不能完成访问。

处理方案

方案一:修改DispatcherServlet对应的url-pattern修改为"/"以外的其他匹配样式。

方案二(建议):将所有的静态资源放进一个static包中,如果需要访问,则将defaultServlet的url-pattern的url-mapping改为/static/*

<!-- web.xml -->
<servlet-mapping><servlet-name>default</servlet-name><url-pattern>/static/*</url-pattern></servlet-mapping>

方案三:利用default-servlet-handler 将处理静态资源的请求转发给容器的默认 Servlet ,而不是给DispatcherServlet。

<!-- spring-mvc.xml -->
<!-- 
这个handler就是处理静态资源的,它的处理方式就是将请求转会到tomcat中名为default的Servlet 
-->
<mvc:default-servlet-handler/>
<!-- mapping是访问路径,location是静态资源存放的路径 -->
<mvc:resources mapping="/static/**" location="/static/" />

中文乱码处理

在web.xml中配置字符编码过滤器CharacterEncodingFilter

<filter><filter-name>encodingFilter</filter-name><!--字符编码过滤器--><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class><init-param><!--编码格式--><param-name>encoding</param-name><param-value>UTF-8</param-value></init-param><init-param><!--强制编码--><param-name>forceEncoding</param-name><param-value>true</param-value></init-param></filter><filter-mapping><filter-name>encodingFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/39379.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第三篇——始计篇:诡计,就是引诱对方犯错误

目录 一、背景介绍二、思路&方案三、过程1.思维导图2.文章中经典的句子理解3.学习之后对于投资市场的理解4.通过这篇文章结合我知道的东西我能想到什么&#xff1f; 四、总结五、升华 一、背景介绍 这一篇讲解了诡计&#xff0c;对于诡计的解释和定位&#xff1b;我们更应…

win10下安装PLSQL14连接Oracle数据库

问题背景 在使用Oracle开发过程中&#xff0c;经常会使用工具来连接数据库&#xff0c;方便查询、处理数据。其中有很多工具可以使用&#xff0c;比如dbeaver、plsql等。本文主要介绍在win10环境下&#xff0c;plsql14的安装步骤以及安装过程中遇到的一些问题。 安装步骤及问题…

清爽一夏,羊大师伴你健康运动,引领活力生活!

在这个绚烂多彩的夏日&#xff0c;让我们携手踏上一段清爽与健康并行的旅程。阳光炽热&#xff0c;万物生长&#xff0c;正是释放活力、追求健康的最佳时节。“清爽一夏&#xff0c;健康运动引领活力生活&#xff01;”这不仅是一句口号&#xff0c;更是我们向美好生活发出的诚…

BurpSuite抓IOS设备HTTPS流量

一、简述&#xff1a; Burp 这个工具做过 web 安全的人都应该用过&#xff0c;是个非常强大的抓包工具。在 PC 的浏览器上直接配置代理就行了&#xff0c;本篇文章就来介绍一下如何用 Burp 抓 IOS 设备上的流量&#xff0c;很多文章都介绍过怎么抓包&#xff0c;但是很多坑都没…

试用笔记之-汇通计算机等级考试软件一级Windows

首先下载汇通计算机等级考试软件一级Windows http://www.htsoft.com.cn/download/htwork.rar

昇思25天学习打卡营第9天|FCN图像语义分割

FCN是Fully Convolutional Networks的简称&#xff0c;即全卷积网络。区别于全连接网络&#xff0c;全连接网络每层直接cell全部连接&#xff0c;全卷积网络即每层都进行卷积。全卷积网络不包含全连接层。 卷积说有点像缩放&#xff0c;具体的可以参考其他专门的介绍文章。 之…

pandas数据分析(4)

修改DataFrame数据的最简单的方法是通过loc和iloc属性为某些元素赋值。 首先构造一组数据 通过标签或位置设置值 也可以一次修改多个值&#xff1a; 通过布尔索引设置数据 将所有来自China&#xff0c;或者年龄20以下的人名字设置为匿名&#xff1a; 通过替换值设置数据 如果…

vue2项目的打包以及部署

打包 当我们写好vue2的项目后&#xff0c;可以通过npm build来对项目进行打包 npm build 打包完成后我们可以看到在当面目录下生成了dis目录,src下的文件都会被打包进这个目录里&#xff0c;当然打包后的文件我们不能直接在浏览器打开&#xff0c;需要进行部署 部署 1.新建一个…

RFID技术在粉末涂料配料生产线的精准应用

RFID技术在粉末涂料配料生产线的精准应用 应用背景 随着科技的快速发展&#xff0c;智能化、自动化已经成为现代工业生产的重要趋势。RFID&#xff08;无线射频识别&#xff09;技术以其独特的优势&#xff0c;如非接触式识别、高速读取、大容量数据存储等&#xff0c;在多个…

中国民间网络外交组织(CCND)

中国民间网络外交组织Chinese Civil Network Diplomacy简称(CCDN) 是由中国网民建立起来的一个网络外交组织&#xff0c;深度贯彻党的主张和网民意志的统一&#xff0c;为保护中国中华优秀传统文化&#xff0c;民族自信&#xff0c;国家安全&#xff0c;民族利益&#xff0c;社…

DICOM灰度图像、彩色图像的窗宽、窗位与像素的最大最小值的换算关系?

图像可以调整窗宽、窗位 dicom图像中灰度图像可以调整窗宽、窗位&#xff0c;RGB图像调整亮度或对比度&#xff1f;_灰度 图 调节窗宽-CSDN博客 窗宽、窗位与像素的最大最小值的换算关系? 换算公式 max-minWindowWidth; (maxmin)/2WindowCenter; 详细解释 窗宽&#xff0…

Michael.W基于Foundry精读Openzeppelin第61期——ERC1967Upgrade.sol

Michael.W基于Foundry精读Openzeppelin第61期——ERC1967Upgrade.sol 0. 版本0.1 ERC1967Upgrade.sol 1. 目标合约2. 代码精读2.1 _getImplementation() internal && _upgradeTo(address newImplementation) internal2.2 _upgradeToAndCall(address newImplementation,…

校园兼职小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;商家管理&#xff0c;管理员管理&#xff0c;用户管理&#xff0c;兼职管理&#xff0c;论坛管理&#xff0c;公告管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;公告&#xff0c;兼职&…

Docker 一篇到位

目录 01. Docker使用导航 02. Build Share Run 样例 03. 理解容器 04. 安装 Docker 05. Docker 样例&#xff08;常见命令使用&#xff09; 下载镜像 启动容器 修改页面 保存镜像 docker commit docker save docker load 分享社区 docker login docker tag do…

数字化转型过程中企业会遇到哪些挑战?该如何应对?

你是否与我一样&#xff0c;也曾有过类似的疑惑&#xff1a; 企业数字化转型过程中会遇到哪些挑战&#xff1f;其中苦难&#xff0c;我们又该如何应对&#xff1f;有什么可借鉴的方法&#xff1f; 有了这些疑问&#xff0c;你肯定想知道答案。 为了解决你的心头之患&#xf…

rocketmq实现多数据源配置

rocketmq实现多数据源配置 背景&#xff1a;一 添加ExtRocketMQTemplateConfiguration配置类二 添加非标mq的配置参数三 非标准RocketMQTemplate 背景&#xff1a; 在实际项目中我们可能会遇到在springboot项目中使用多个mq数据源&#xff0c;那我们该如何配置呢&#xff1f; …

基于若依(ruoyi-vue)的周报管理系统

喂wangyinlon 填报人页面 审批人 审批不通过,填报人需要重新填写.

自动编码器简单理解及简单使用描述

1. 什么是自动编码器&#xff1f; 自动编码器分为编码器和解码器&#xff0c;其中解码器只在训练阶段用到。具体过程就是&#xff1a; 首先&#xff0c;输入训练样本&#xff0c;编码器对输入样本进行编码&#xff0c;对其进行降维&#xff0c;直到到达某个瓶颈层&#xff1b…

2024年江西省研究生数学建模竞赛B题投标中的竞争策略问题论文和代码分析

2024年江西省研究生数学建模竞赛B题投标中的竞争策略问题论文和代码已完成&#xff0c;代码为B题全部问题的代码&#xff0c;论文包括摘要、问题重述、问题分析、模型假设、符号说明、模型的建立和求解&#xff08;问题1模型的建立和求解、问题2模型的建立和求解、问题3模型的建…

oracle体系结构详解(实例+数据文件)

提示&#xff1a;主要总结oracle数据库&#xff1a;物理结构&#xff0c;逻辑结构&#xff0c;内存结构以及oracle进程 文章目录 Oracle服务器由&#xff08;实例和数据库文件组成&#xff09;1、实例2、数据文件1.oracle物理体系结构2.oracle数据库逻辑结构3oracle数据库内存结…