springboot 入门

news2024/11/13 9:37:04

springboot是什么

传统的开发模式下,无论是基于xml注解,都要做许多配置,如果项目中集成越多的其他框架,配置内容也会越多。为了让开发人员以最少的配置去开发应用,springboot诞生了。springboot的原则是约定大于配置能不配就不配)。

springboot还未spring项目提供了很多非功能特性,比如嵌入式tomcat。

创建springboot项目

点击File->New->Project,然后左侧选择Spring Initializr,输入相关项目信息,点击next,然后选择相关依赖,选择Spring Web,点击Create

在这里插入图片描述

springboot配置文件

实际开发中,经常需要用到自定义配置下面是以微信公众号开发时为例)。

/src/main/resources/application.yml

wechat:
 appid: wx123456789asdsad
 token: ca
 appSecret: a123b456c789d147e258f369

读取配置项的方式(一)

/src/main/java/com/asd/config/WeChat.java

@ConfigurationProperties("wechat") // 参数输入前缀。@ConfigurationProperties和@Value注解用于获取配置文件中的属性定义并绑定到Java Bean或属性中
@Component
public class WeChat {
	private String appId;
	private String token;
	private String appSecret;

	...getter setter
}

/src/main/java/com/asd/controller/HellowController.java

@RestController // 等同于@Controller + @ResponseBody
public class HellowController {
	
	// 注入WeChat实体类
	@Autowired
	private WeChat weChat;

	...
	@GetMapping("/getWeChat")
	public WeChat getWeChat() {
		return weChat;
	}
}

重启服务后,访问 localhost:8080/getWeChat :

{"appId":"wx123456789asdsad", "token":"ca", "appSecret":"a123b456c789d147e258f369"}

读取配置项的方式(二)

/src/main/java/com/asd/config/WeChatConfig.java

@Configuration // 标识这是一个配置类
public class WeChatConfig {

	@Bean // 这样的话springboot就自动帮我们注入weChat对象
	@ConfigurationProperties("wechat")
	public WeChat weChat() {
		return new WeChat();
	}
}

读取配置项的方式(三)

/src/main/java/com/asd/controller/HellowController.java

@RestController
public class HellowController {

	@Value("${wechat.appId}")
	private String appId;

	@Value("${wechat.token}")
	private String token;

	@Value("${wechat.appSecret}")
	private String appSecret;

	...
	@GetMapping("/getWeChat")
	public WeChat getWeChat() {
		WeChat weChat = new WeChat();
		weChat.setAppId(appId);
		weChat.setAppSecret(appSecret);
		weChat.setToken(token);
		return weChat;
	}
}
如果属性较少,可以用@Value。如果属性较多,建议用第一种或第二种。

在实际项目开发中,有时需要读取自定义的配置文件。新建自定义配置文件:

/src/main/resources/my.yml

wechat1:
 appid: wx123456789asdsad

/src/main/java/com/asd/config/MyWeChat.java

@PropertySource("my.yml")
@ConfigurationProperties("wechat1")
@Component
public class MyWeChat {
	private String appId;

	...getter setter
}

/src/main/java/com/asd/controller/HellowController.java

@RestController
public class HellowController {

	@Resource
	private MyWeChat myWeChat;

	...
	@GetMapping("/getWeChat2")
	public MyWeChat getWeChat2() {
		return myWeChat;
	}
}

springboot多环境配置

开发项目时,通常需要经历几个阶段。

  • 本地开发接口(本地开发环境,local)
  • 开发完后与前端做接口联调(前后端联调环境,dev)
  • 联调完后提交测试(测试环境,test)
  • 测试完后有些公司会预发布(预发布环境,pre)
  • 部署到线上(生产环境,prod)

不同的开发环境,属性配置一般都不一样。如果不做多环境配置,就得去频繁修改配置文件,这样有一定的安全隐患。比如在本地开发时,不小心连上线上数据库,这样会对线上数据库造成一定的数据污染。

在resources目录下创建各环境的配置文件,springboot在启动的过程中,首先会加载application.yml,其次去加载这N个不同环境配置文件中的某一个。

在application.yml中的属性名可以当做变量,即${}来进行引用。

application-local.yml

server:
 port: 8001

application-dev.yml

server:
 port: 8002

application.yml

wechat:
 appid: wx123456789asdsad
 token: ca
 appSecret: a123b456c789d147e258f369
 port: ${server.port}# 引用属性值,如果是引入local配置文件,其值就会是8001
spring:
 profiles:
  active: local #写你要启动的配置文件的后缀就行

获取参数

比如有实体类Student,他有name、age属性。
1)通过request对象获取参数

2)@RequestParam(针对请求头方式为x-www-form-urlencoded,比如form表单)

@GetMapping("/get")
public Student getById(@RequestParam Integer id,@RequestParam String name) {
	return id;
}
如果请求参数的name是id1,就得写成@RequestParam("id1")

3)@RequestBody(针对请求头方式为application/json)

@PostMapping("/save")
public Student save(@RequestBody Student student) {
	return student;
}

4)@PathVariable(接收url路径参数)

@GetMapping("/get/{id}")
public Student getById(@PathVariable Integer id) {
	return id;
}
若是{id1},与参数名id不一样,得写为@PathVariable("id1")

springboot集成mybatis

pom.xml

<dependency>
	<groupId>org.mybatis.spring.boot</groupId>
	<artifactId>mybatis-spring-boot-starter</artifactId>
	<version>2.1.3</version>
</dependency>

<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
	<version>8.0.13</version>
</dependency>

application-local.yml

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/test?
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: wen
    hikari:
      connection-timeout: 30000
      maximum-pool-size: 30
      minimum-idle: 10
      max-lifetime: 6000
mybatis:
  configuration:
    #配置打印sql日志
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  #设置xml文件扫描路径。把所有配置文件放在resources/mapper下面
  mapper-locations: mapper/**/*.xml
在这个例子中application.yml目前引用的是application-local.yml。下同

最后,启动类要加注解@MapperScan("com.ca.mapper"),即扫描dao包里的接口。或在dao上加@Mapper注解。

springboot访问静态资源

resources/static里可存放静态资源文件,比如放一张图片后,localhost:8080/asd.jpg就能访问。

这是springboot默认存放静态资源的目录

若想访问自定义目录下的静态资源,比如新建resources/images目录,里面放图片。此时,需要对该文件夹做配置。

WebAppConfig.java

@Component
public class WebAppConfig implements WebMvcConfigurer {
	
	@Value("${upload.path}")
	private String uploadPath;// 下面文件上传时用

	@Resource
	private TokenInterceptor tokenInterceptor;// 下面拦截器时用

	@Override
	public void addResourceHandlers(ResourceHandlerRegistry registry) {
		registry.addResourceHandler("/static/**").addResourceLocations("classpath:/images/");

		// 下面文件上传时用,让匹配upload开头的URL,让他去找文件路径。
		registry.addResourceHandler("/upload/**").addResourceLocations("file:" + uploadPath);
	}

	// 配置拦截器,下面拦截器时用
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		// 默认拦截所有url
		// registry.addInterceptor(tokenInterceptor);// 注册拦截器

		// 但实际开发中,要对部分url放行。所以可以针对一些url进行匹配,匹配需要拦截的,即addPathPatterns("/**"),"/**"是所有url 
		// 也可以配置不需要拦截的url,比如对/student/...放行。
		registry.addInterceptor(tokenInterceptor).addPathPatterns("/**").excludePathPatterns("/student/*");
		
	}
}

WebMvcConfigurer配置类其实是Spring内部的一种配置方式,采用JavaBean的形式来代替传统的xml配置文件形式进行针对框架个性化定制,可以自定义一些Handler,Interceptor,ViewResolver,MessageConverter。基于java-based方式的spring mvc配置,需要创建一个配置类并实现WebMvcConfigurer 接口。

访问localhost:8080/static/test.jpg就行。

springboot上传文件

pom.xml

<!-- hutool -->
<dependency>
	<groupId>cn.hutool</groupId>
	<artifactId>hutool-all</artifactId>
	<version>5.7.13</version>
</dependency>

application-local.yml

upload:
  path: d:\\uploads\\

UploadController.java

@RestController
public class UploadController {

	// 文件上传的根路径
	@Value("${upload.path}")
	private String uploadPath;

	@PostMapping("/upload")
	public Result upload(MultipartFile file) throws IOException{

		// 获取文件名称
		String fileName = file.getOriginalFilename();
		// 获取文件后缀(通过hutool的FileUtil工具类,需要注意的是,这里没有“.”,比如只有jpg)
		String suffix = FileUtil.getSuffix(fileName);
		// 对文件名进行重命名(文件的子路径)
		// 可以指定文件名策略,比如:时间戳-UUID.文件后缀
		String url = shijianchuo + uuid + "." + suffix;
		// 文件上传的真实路径
		String filePath = uploadPath + url;
		
		// 获取文件的字节流
		InputStream inputStream = file.getInputStream();
		// 把这个字节流写入到保存路径
		FileUtil.writeFromStream(inputStream, filePath);

		// 把文件的子路径返回到前端
		return Result.success(url);
	}	
}

访问刚才上传的文件:localhost:8080/upload/上传的文件路径.jpg

统一异常处理

调用接口过程中,可能会发生各种异常。此时,springboot默认给前端响应500,但即便发生异常,也应该给前端做一个正常的响应,以及告诉前端响应错误的原因。

有人会说用try catch,但如果项目越来越大,每个方法都用try catch,代码就会越来越臃肿。springboot中可以对项目的异常做一个统一的拦截处理。

/exception/BusinessException.java

public class BusinessException extends RuntimeException { // 这是自定义异常类,要继承RuntimeException
	
	// 写一个构造方法,传递Msg
	public BusinessException(String msg) {
		super(msg);
	}
}

/exception/SystemExceptionHandler.java

// 对系统异常做一个统一的处理(全局异常处理器)。
@RestControllerAdvice // 等同于 @ControllerAdvice + @ResponseBody。此注解通过对异常的拦截实现了统一异常返回处理
public class SystemExceptionHandler {
	
	@ExceptionHandler(BusinessException.class) // 指定要拦截的异常类
	public Result handlerException(BusinessException e) {// 也可以当做参数使用
		// 当我们拦截到异常后,直接给前端返回
		return Result.fail(e.getMessage());
	}

	// 也可以拦截Exception
	@ExceptionHandler(Exception.class)
	public Result exception() {
		return Result.fail("系统异常");
	}

	// 在参数校验时使用
	// 在这里拦截MethodArgumentNotValidException异常
	@ExceptionHandler(MethodArgumentNotValidException.class)
	public Result methodArgumentNotValidException(MethodArgumentNotValidException e) {
		// 拿到所有的参数校验失败的提示
		List<String> errorMessage = e.getBindingResult()
			.getAllErrors() //获取所有的错误提示,返回的是集合对象
			.stream() // 对集合对象进行遍历
			.map(DefaultMessageSourceResolvable::getDefaultMessage) // 获取message
			.collect(Collectors.toList()) // 然后返回集合对象
		
		// 可以使用hutool的工具包,判断集合是否为空
		if (CollUtil.isNotEmpty(errorMessage)) {
			// 如果不为空,直接取他的第一个元素,得到错误提示
			String errorMsg = errorMessage.get(0);
			// 把错误提示信息返回到前端
			return Result.fail(errorMsg);
		}
		return Result.fail("系统异常");
	}

}

配置后,出现异常时,就会返回Result这个统一的restful返回信息了。

如果想拦截自定义的BusinessException类,在代码中写throw new BusinessException("错误");即可。

拦截器

拦截器的拦截对象是controller里的方法。
例子:判断客户端发送的请求头中,是否包含token,并且是否值为asd。

/interceptor/TokenInterceptor.java

@Component
public class TokenInterceptor implements HandlerInterceptor{

	// 当返回true时执行controller里面的代码,但返回false时不执行下面的postHandler afterCompletion方法。
	@Override
	public boolean preHandler(HttpServletRequest request, HttpServletResponse response, Object handler) {
		// 所以在这里面可以对token进行拦截
		String token = request.getHeader("token");// 获取请求头里面的Token 
		if (StrUtil.isBlank(token)) {
			throw new BusinessException("请求头未包含token");
		}
		if (!"asd".equals(token)) {
			throw new BusinessException("请求头参数错误");
		}
		return true;
	}

	// controller方法执行之后,并且视图未渲染之前进行调用。(在前后端分离开发时,没有试图这个概念,所以了解即可)
	@Override
	public void postHandler(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception{
		HandlerInterceptor.super.postHandler(request, response, handler, modelAndView);
	}
	
	// 在整个请求处理完毕之后进行回调,所以在这个方法里可以做一些线程资源的释放
	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
		HandlerInterceptor.super.afterCompletion(request, response, handler, ex)
	}
}

执行顺序是preHandler、controller的方法、postHandler、aferCompletion。

用注解方式

/anotation/NeadToken.java

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)// 设置此注解只能用于方法
public @interface NeedToken {
	
}

@Retention作用是定义被它所注解的注解保留多久,一共有三种策略,定义在RetentionPolicy枚举中.
source:注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃;被编译器忽略
class:注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期
runtime:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在。

修改preHandler方法(当controller的方法加上这个注解时,我们才去判断他的请求头中是否有token。):

@Override
public boolean preHandler(HttpServletRequest request, HttpServletResponse response, Object handler) {

	// 判断handler是不是HandlerMethod	
	if (handler instanceof HandlerMethod) {
		// 转成HandlerMethod对象
		HandlerMethod handlerMethod = (HandlerMethod) handler;
		// 通过handlerMethod可以去获得方法上面的注解
		NeedToken needToken = handlerMethod.getMethod().getAnnotation(NeedToken.class);
		if (needToken != null) {
			// 不为空,说明方法用了这个注解,就去校验token
			String token = request.getHeader("token");// 获取请求头里面的Token 
			if (StrUtil.isBlank(token)) {
				throw new BusinessException("请求头未包含token");
			}
			if (!"asd".equals(token)) {
				throw new BusinessException("请求头参数错误");
			}

		}
	}
	return true;
}

测试时,为了方便,应该去把url匹配部分注释。

registry.addInterceptor(tokenInterceptor)
	//.addPathPatterns("/**")
	//.excludePathPatterns("/student/*");

springboot aop

aop五大通知:

  • 前置通知 before advice:在目标方法执行之前执行
  • 后置通知 after returning advice:在目标方法执行之后执行
  • 异常通知 after throwing advice:目标方法抛出异常后执行
  • 最终通知 after finally advice:在目标方法执行之后都会执行(发生异常时,不执行后置通知,但执行最终通知,这是这两的区别)
  • 环绕通知 around advice:可以在目标方法执行之前执行,也可以在目标方法执行之后执行。

pom.xml

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

/aop/LogAspect.java

@Aspect // 标识这是一个切面类
@Component
public class LogAspect {
	
	// @Pointcut用来标识切点
	// RestfulStudentController.*(),指RestfulStudentController里面的所有方法
	@Pointcut("execution(* com.ca.controller.RestfulStudentController.*())") 
	public void pointcut() {
		
	}	

	// 前置通知
	@Before("pointcut()") // "pointcut":加切点,加上pointcut这个方法
	public void before() {
		logger.info("执行before方法");
	}

	// 最终通知
	@After("pointcut()")
	public void after() {
		logger.info("执行after方法");
	}

	// 后置通知
	@AfterReturning("pointcut()")
	public void afterReturn() {
		logger.info("执行afterReturn方法");
	}

	// 异常通知
	@AfterThrowing("pointcut()")
	public void ex() {
		logger.info("执行ex方法");
	}
}

执行后:
没异常的话,顺序为before、控制器的接口方法、afterReturn、after。
有异常的话,顺序为before、控制器的接口方法、ex、after。

补充

@Pointcut("execution(* com.ca.controller.RestfulStudentController.*(..))") // 所有方法的所有参数.*(..)
public void pointcut() {
		
}

@Before("pointcut()")
public void before(JoinPoint joinPoint) {// 这里可以加参数 JoinPoint joinPoint(@After、@AfterReturning亦是)
	// 通过joinPoint可以获取目标方法的参数
	Object[] args = joinPoint.getArgs();

	// 还可以通过joinPoint获取目标方法
	MethodSignature methodSignature = (MethodSignature)joinPoint.getSignature();
	Method method = methodSignature.getMethod();// 获取目标方法

	logger.info("拦截目标方法:{}", method.getName());
	logger.info("目标方法参数:{}"JSONUtil.toJsonStr(args));// 转换为json后输出。这时候要取pointcut里修改为拦截有参数的方法。
	logger.info("执行before方法");
}

@AfterThrowing(value="pointcut()", throwing="exception")// 然后注解里要写上throwing="exception"
public void ex(Exception exception) {// 这里也可以传递异常对象,就能获取到是什么异常对象了
	// 之后可以打印异常
	logger.error(exception.getMessage(), exception);
	logger.info("执行ex方法");
}

环绕通知

顾名思义,就是对目标方法进行包围。使用环绕通知时,就不用使用其他通知了,可以统统注释掉。

@Around("pointcut()")
public void around(ProceedingJoinPoint proceedingJoinPoint) {// 里面可以传递 ProceedingJoinPoint proceedingJoinPoint 参数
	// 执行目标方法前执行前置通知
	System.out.println("执行前置通知");
	
	Object result;
	try {
		// 通过proceedingJoinPoint也可以参数和目标方法
		Object[] args = proceedingJoinPoint.getArgs();
		MethodSignature methodSignature = (MethodSignature)proceedingJoinPoint.getSignature();
		Method method = methodSignature.getMethod();
		logger.info("拦截目标方法:{}", method.getName());
		logger.info("目标方法参数:{}"JSONUtil.toJsonStr(args));	
	
		result = proceedingJoinPoint.proceed();// 执行目标方法
	}catch(Throwable e) {
		// 还可以捕获异常
		logger.error(e.getMessage(), e);
	}
	
	// 执行目标方法后执行后置通知
	System.out.println("执行后置通知");

	return result;
}

springboot事务

事务指的是多个操作(插入、更新、删除等)同时进行,要么同时成功或同时失败。

需要用到事务的地方,在方法上添加@Transactional

注意事项

1)比如service里有save和save1方法,本来save上有@Transactional。后来把save里面的代码和@Transactional都干到save1上,然后在save里调用save1。这时,若出现异常也不会回滚。因为@Transactional使用了aop,aop首先要拦截的方法是save,而不是save1,所以他并没有获取到事务注解,此时事务就直接交给数据库自动控制了。所以@Transactional得加到save上才行(然后干掉save1上@Transactional)。

2)假如@Transactional加到save,在save中使用try catch,此时就算有异常,也不会回滚。因为aop只看这个方法是否抛出异常,抛出了才回滚。所以在catch里throw ex;即可。

3)目前service里有save,加上了@Transactional。假如有service1,里面有save1。在service的save里调用service1.save1(),而service1的save1加了@Transactional(propagation = Propagation.REQUIRES_NEW),REQUIRES_NEW是表示每次都重新开启一个新的事务。此时,在save中做了三个操作(加管理员,加管理员角色,[刚刚追加的]加角色)能否同时成功或失败?执行后可以发现,save里有异常时前两个失败,但save1成功了,这是因为save1开启了新的事务,所以他自己就提交了。所以,要保证所有的操作都要在同一个事务里面。

4)创建自定义异常类TestException(继承了Exception)。然后在save里throw new TestException();,但发现不回滚。因为@Transactional默认拦截的异常需要继承RuntimeException。但可以通过@Transactional(rollbackFor = Exception.class)来解决。

参数校验

在controller里用传统的if方式校验参数时,若参数多,就会代码冗余。为了解决这个,有必要使用参数校验框架springboot validation。

他允许我们通过注解的方式来定义对象校验规则,把校验和业务逻辑分离。

springboot validation 常用注解如下:

  • @NotBlank(校验字符串不为null,并且不为空字符串)
  • @NotEmpty(校验字符串不为null,允许空字符串)
  • @NotNull(校验对象不为null)
  • @Length(校验字符串长度)
  • @Min(最小值校验)
  • @Max(最大值校验)
  • @Pattern(正则匹配校验),比如邮箱号、手机号时可以使用这个
  • @Valid(当一个对象嵌套另外一个对象时可使用)
    class Student {
    @Valid
    private Admin admin;
    }
    当我们使用学员类去接收参数时,我们也需要去校验Admin里面的参数的时候,就可以使用@Valid去进行校验。

pom.xml

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-validation</artifactId>
</dependency>

Student.java

public class Student {
	@NotBlank(message="姓名不能为空")
	@Length(max = 5, message = "姓名不能超过5个字符")
	private String name;
	
	@NotNull
	@Max(value=100, message="年龄不能大于100岁")
	@Min(value=1, message="年龄不能小于1岁")
	private Integer age;

	@NotNull
	@Min(value = 1)
	@Max(value = 2)
	private Integer sex;
}

StudentController.java

@PostMapping
public Student save(@RequestBody @Valid Student student) {
	
}

也可以使用@Validated,这个是spring里面的注解,@Validjavax里面的注解,这两个是都可以的,但有点区别。

运行后,若参数有问题,就会校验不通过,抛出MethodArgumentNotValidException异常,但不告诉前端是什么问题。

当然,可以用全局异常拦截器来解决这个问题。

校验模式

springboot validation分两种校验模式,全校验快速校验推荐)。

全校验指的是对所有的参数都校验完毕之后进行返回,快速校验是指只要遇到接口参数校验失败就立即返回。

使用快速校验模式时,需要做一个单独的配置,只需要把下面代码复制到项目即可。

BeanConfig.java

@Configuration
public class BeanConfig {
	// 配置快速校验模式
	@Bean
	public Validator validator() {
		ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class)
			.configure()
			.failFast(true)// 配置校验失败就立即停止
			.buildValidatorFactory();
		Validator validator = validatorFactory.getValidator();
		return validator;
	}
}

其他

使用springboot validator时,可能会遇到一个问题,比如save和update时,若都用Student来接收参数的话,save时虽然不需要做id校验,但update时则需要做id校验。此时,可对校验做分组。

比如@NotNull(groups = Update.class)groups = 这里要设置一个类(得是接口),所以先创建两个接口。若设置为groups = Update.class就说明要在修改时才做校验。

/valid/Save.java

public interface Save {

}

/valid/Update.java

public interface Update {

}

Student.java

public class Student {
	@NotNull(groups=Update.class)
	private Integer id;

	@NotBlank(message="姓名不能为空", groups={Save.class, Update.class})// 也可以指定多个分组
	@Length(max = 5, message = "姓名不能超过5个字符", groups=Save.class)
	private String name;
	
	@NotNull
	@Max(value=100, message="年龄不能大于100岁", groups=Save.class)
	@Min(value=1, message="年龄不能小于1岁", groups=Save.class)
	private Integer age;

	@NotNull
	@Min(value = 1, groups=Save.class)
	@Max(value = 2, groups=Save.class)
	private Integer sex;
}

然后还要把controller里的@Valid改为springboot里的@Validated(Save.class),即也指定了分组。

StudentController.java

@PostMapping
public Student save(@RequestBody @Validated(Save.class) Student student) {
	
}

@PutMapping
public Student update(@RequestBody @Validated(Update.class) Student student) {

}

以上内容源于网络。

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

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

相关文章

VSCode中4个Settings(JSON)的区别与联系

目录 &#x1f525; 前言 1. Preferences: Open Default Settings(JSON) 2. Preferences: Open User Settings 3. Preferences: Open Settings(JSON) 4. Preferences: Open Workspace Settings(JSON) &#x1f525; 总结 &#x1f525; 前言 在VSCode中输入快捷键ctrlsh…

读书笔记:梯度法求函数的最小值 gradient_method.py ← 斋藤康毅

● 由多元函数全部变量的偏导数汇总而成的向量称为梯度&#xff08;gradient&#xff09;。梯度指示的方向是各点处的函数值减小最多的方向。● 虽然梯度的方向并不一定指向最小值&#xff0c;但沿着它的方向能够最大限度地减小函数的值。因此&#xff0c;在寻找函数的最小值&a…

一篇五分生信临床模型预测文章代码复现——Figure 8 生存曲线鲁棒性分析

之前讲过临床模型预测的专栏,但那只是基础版本,下面我们以自噬相关基因为例子,模仿一篇五分文章,将图和代码复现出来,学会本专栏课程,可以具备发一篇五分左右文章的水平: 本专栏目录如下: Figure 1:差异表达基因及预后基因筛选(图片仅供参考) Figure 2. 生存分析,…

Linux输入子系统简析

1. 前言 限于作者能力水平&#xff0c;本文可能存在谬误&#xff0c;因此而给读者带来的损失&#xff0c;作者不做任何承诺。 2. 背景 本文基于 Linux 4.14 内核源码进行分析。 3. 简介 Linux 内核输入子系统&#xff0c;负责对系统中的输入设备进行管理。 一方面&#xf…

Spring Cloud_Ribbon负载均衡服务调用

目录一、概述1.是什么2.官网资料3.能干嘛二、Ribbon负载均衡演示1.架构说明2.POM三、Ribbon核心组件Irule1.IRule2.如何替换3.新建package&#xff08;注意&#xff1a;包的位置&#xff09;4.上面包下新建MySelfRule规则类5.主启动类添加RibbonClient6.测试四、Ribbon负载均衡…

Python将JSON格式文件导入 redis,多种方法

在导入前需要先确定你已经安装 Redis&#xff0c;并且可以启动相关服务。 windows 上启动 redis 的命令是 redis-server.exe redis.windows.conf&#xff0c;效果图如下&#xff1a; 文章目录使用 Python 连接 redis安装 redis 与 导入使用代码连接 Redis写入键值操作 JSON 文…

第26章 分布式缓存数据库配置的定义实现

1 Core.Configuration.CacheConfig namespace Core.Configuration { /// <summary> /// 【缓存配置--类】 /// <remarks> /// 摘要&#xff1a; /// 通过该类中的属性成员实例对“appsettings.json”文件中的1个指定缓存项(键/值对)在内存或指定分布式软件中…

mysql-installer-community-8.0.22.0安装教程

1. 下载 mysql-installer-community-8.0.22.0安装包 首先去官网&#xff1a;https://dev.mysql.com/downloads/installer/ 下载MySQL。 2. 默认Next 3. 点击Execute 4. 同意安装 5. 点击Next后点Yes 6. 点击Execute 这里出现10个选项是正确的&#xff0c;如果不是&#xff0c;…

C++ vector 容器介绍

C vector 容器介绍 C的vector是标准库中常见的一种容器&#xff0c;使用起来非常方便&#xff0c;可以用来代替c原本的数组。vector是种容器&#xff0c;类似数组一样&#xff0c;但它的size可以动态改变。vector的元素在内存中连续排列&#xff0c;这一点跟数组一样。由于vect…

队列同步器AQS的实现与分析——独占锁模式

AQS独占锁模式源码分析1、tryAcquire()、acquire()方法2、addWaiter()方法3、acquireQueued()方法4、shouldParkAfterFailedAcquire()方法5、tryRelease()、release()方法1、tryAcquire()、acquire()方法 protected boolean tryAcquire(int arg) {throw new UnsupportedOperat…

glassfish任意文件读取漏洞

glassfish任意文件读取漏洞1.简介1.1.漏洞类型1.2.漏洞成因1.3.语法搜索1.4.影响版本2.漏洞复现2.1.POC2.2.访问地址2.3.GlassFish的敏感目录2.3.1.获取数据库密码2.3.2.获取GlassFish的后台密码2.4.POC脚本1.简介 GlassFish是一款强健的商业兼容应用服务器&#xff0c;达到产品…

MyEclipse提示过期,MyEclipse Subscription Expired激活方案

一、错误描述 紧接上文&#xff0c;虽然解决了MyEclipse提示过期问题&#xff0c;但是你会发现出现一行红色提示如下&#xff1a; 1.错误日志 Product activation must be completed within 5 days. 2.错误说明 产品激活必须在5天内完成。 二、解决方案 从错误日志很明显的可…

C++语法复习笔记-2. c++基础句法

文章目录1. 图灵机与三种基本结构1. 顺序结构2. 分支结构自定义结构-枚举结构体与联合体结构体数据对齐问题3. 循环结构三种循环结构反汇编查看三种结构效率实例&#xff1a;输出所有形如aabb的四位数的完全平方数方案1: 构造aabb数&#xff0c;再判断方案2&#xff1a;反向操作…

《网络编程实战》学习笔记 Day10

系列文章目录 这是本周期内系列打卡文章的所有文章的目录 《Go 并发数据结构和算法实践》学习笔记 Day 1《Go 并发数据结构和算法实践》学习笔记 Day 2《说透芯片》学习笔记 Day 3《深入浅出计算机组成原理》学习笔记 Day 4《编程高手必学的内存知识》学习笔记 Day 5NUMA内存知…

自制DAPLink 基于ARM官方源码以及STM32F103C8T6

【本文发布于https://blog.csdn.net/Stack_/article/details/128771308&#xff0c;未经许可禁止转载&#xff0c;转载须注明出处】 一、安装工具并配置环境变量 1、python3 【官网】 【网盘】 链接&#xff1a;https://pan.baidu.com/s/1zW_H_eQlkzX3FkXuClFnTA 提取码&#…

python 操作 json 文件的种种知识点

本篇博客将带你全方位了解 Python 操作 json 文件的技术点 让你碰到 json 格式文件不在发愁 文章目录json 模块读取 JSON写入 JSON读取与写入基本用法如下json 模块进阶用法控制输出格式在 JSON 中存储 Python 特殊类型对数据进行验证和清洗第三方模块json 模块 Python 提供了…

CE自动汇编之AOB注入

目录 一、什么是AOB注入&#xff1f; 二、什么时候使用AOB注入&#xff1f; 三、代码注入 四、全部注入 五、“全部注入”和“AOB注入”的分别 六、代码注入与AOB注入的区别 CE自动汇编的模板中&#xff0c;有三种注入代码的方式&#xff1a; 第一种是代码注入&#xff…

Qt使用数据库模型中的删除详解

以下使用 QSqlTableModel 模型&#xff0c;使用tableView显示内容 以下为界面&#xff1a; 这里主要介绍删除操作&#xff1a; 删除一行为&#xff1a; int rowui->tableView->currentIndex().row();//获取行号model->revertRow(row);//删除该行model->submitAll(…

git 关于分支和仓库的理解

何时需要initgit init//初始化本地仓库.git目录如果初始化就会在当前文件夹中出现.git的目录&#xff0c;该目录默认是隐藏的&#xff0c;需要关闭显示隐藏文件才能看到。执行完git init命令后&#xff0c;当前目录就成为了工作区&#xff08;工作区可以理解为操作本地仓库的车…

MyBatis-Plus知识快速入门

文章目录1.MyBatis-Plus简介2.入门案例2.1开发环境2.2创建测试数据库和表2.3创建SpringBoot工程2.4创建实体类以及lombok的使用2.5添加mapper2.6加入日志功能3.基本的CRUD3.1BaseMapper3.2插入3.3删除3.4修改3.5查询4.通用Service4.1创建Service接口和实现类5.常用注解5.1Table…