Jetty,Java和OAuth入门

使用Okta的身份管理平台轻松部署您的应用程序 使用Okta的API在几分钟之内即可对任何应用程序中的用户进行身份验证,管理和保护。 今天尝试Okta。

Jetty是一个小型,高度可扩展的基于Java的Web服务器和servlet引擎。 它支持HTTP / 2,WebSockets和许多其他协议。 它为大型和小型网站和框架(例如Google AppEngine)提供支持。 因为它是一个Eclipse项目,所以其开源项目称为Eclipse Jetty。 它符合标准,是开源的,并且可以商业使用。 当托管Java应用程序时,它是Tomcat的主要替代方法。 就像使用Tomcat一样,您可以同时使用嵌入式和独立的Jetty。

默认情况下,Spring Boot使用嵌入式Web服务器创建应用程序,这意味着该服务器是嵌入在应用程序代码本身中的,因此您不必运行单独的Web服务器即可发布Java Web应用程序。 但是,只需进行一些配置,您还可以将WAR文件发布到单独的Jetty或Tomcat Servlet容器(老式的应用程序服务器样式)。 Spring默认情况下也使用Tomcat,但是您可以轻松地更改它,如您所见。

在本教程中,您将构建一个嵌入了Jetty的简单Web服务。 之后,您将在Spring Boot和Jetty中构建相同的Web服务。 最后,您将使用方法级安全性(以Okta作为OAuth / OIDC提供者)将JWT(JSON Web令牌)身份验证和授权添加到Web服务。

安装项目依赖项

开始之前,您需要先安装一些东西。

Java 11 :该项目使用Java11。如果没有Java 11,则可以安装OpenJDK 。 您也可以使用Homebrew安装OpenJDK。 SDKMAN是用于安装和管理Java SDK的另一个不错的选择。

HTTPie :这是用于发出HTTP请求的简单命令行实用程序。 您将使用它来测试REST应用程序。 在其网站上查看安装说明 。

Okta开发人员帐户 :您将Okta用作OAuth / OIDC提供程序,以向应用程序添加JWT身份验证和授权。 如果尚未登录,请访问他们的网站并注册他们的免费开发者帐户之一。

Gradle :这是可选安装。 如果您从仓库中下载了本教程的项目,则可以使用Gradle包装器运行该项目,而无需安装Gradle。 。 如果您想从头开始构建项目,则需要安装Gradle 。

使用Java和Jetty构建简单的Web服务

本教程的第一步是使用Java和Gradle构建一个简单的Web服务。 为此,您将使用Gradle的Gretty插件 。 Gretty使使用Gradle在嵌入式servlet容器上运行Web应用程序变得超级容易,并支持Tomcat和Jetty。

如果您选择从GitHub存储库下载本教程的项目 ,请遵循以下几个步骤,同时我将介绍如何从头开始构建项目。

git clone https://github.com/oktadeveloper/okta-spring-boot-jetty-example.git

首先,打开一个shell并导航到您想要项目驻留的适当目录(或创建一个目录)。 使用Gradle CLI初始化项目。

mkdir jetty
cd jetty
gradle init --type=basic --dsl=groovy --project-name=JettyEmbedded

编辑项目根目录中的build.gradle文件:

plugins {  id 'java'  id 'war'  id 'org.gretty' version '2.3.1'  
}  repositories {  jcenter()  
}  dependencies {  providedCompile 'javax.servlet:javax.servlet-api:3.1.0'  
}  gretty {  contextPath = '/'  
}

我想在这里指出一些事情。 注意plugins块中的org.gretty插件。 此外,注意javax.servlet:javax.servlet-api您添加依赖使用providedCompile 。 这会将其添加到编译类路径中,但不会将其添加到打包的war文件中,因为这将由servlet容器在部署时提供。 最后,请注意,嵌入式servlet容器的上下文路径已设置为gretty块中的gretty

现在,为Java文件创建根目录( src/main/java是标准Java根文件夹,加上com.okta.jettyembedded包):

mkdir -p src/main/java/com/okta/jettyembedded

创建一个简单的servlet:

src/main/java/com/okta/jettyembedded/Hello.java
package com.okta.jettyembedded;  import javax.servlet.ServletException;  
import javax.servlet.annotation.WebServlet;  
import javax.servlet.http.HttpServlet;  
import javax.servlet.http.HttpServletRequest;  
import javax.servlet.http.HttpServletResponse;  
import java.io.IOException;  @WebServlet(name = "HelloServlet", urlPatterns = {"hello"}, loadOnStartup = 1)  
public class Hello extends HttpServlet {  protected void doGet(HttpServletRequest request, HttpServletResponse response)  throws ServletException, IOException {  response.getWriter().print("Howdy");  }  }

现在您可以运行该应用程序:

gradlew apprun

要测试它,请打开另一个shell窗口并使用HTTPie:

http :8080/hello
HTTP/1.1 200 OK
Content-Length: 5
Date: Fri, 06 Sep 2019 20:23:40 GMT
Server: Jetty(9.2.26.v20180806)Howdy

您已经构建了一个超级简单的Web servlet。 它还没有做很多,但是(希望)可以工作。 注意Hello.java类中的@WebServlet批注。 在这里,您可以配置一些servlet参数,而不是在web.xml文件中。 将此配置移动到代码中,可以更轻松地构建和维护某些Servlet配置。

接下来,您将看到功能更全的Web Servlet。

通过添加和删除改进Java Servlet

现在,您将创建一个Web应用程序以跟踪远足列表。 它将演示如何支持POST和DELETE操作以及简单的GET和一些简单的错误处理。

创建一个新的Java文件:

src/main/java/com/okta/jettyembedded/HikesTodoServlet.java
package com.okta.jettyembedded;  import java.io.IOException;  
import javax.servlet.annotation.WebServlet;  
import javax.servlet.http.HttpServlet;  
import javax.servlet.http.HttpServletRequest;  
import javax.servlet.http.HttpServletResponse;  
import java.util.ArrayList;  
import java.util.Arrays;
import java.util.List;@WebServlet(name = "HikesTodoServlet", urlPatterns = {"hikes"}, loadOnStartup = 1)  
public class HikesTodoServlet extends HttpServlet {  // Not synchronized  private List<String> hikes = new ArrayList<>(Arrays.asList("Wonderland Trail", "South Maroon Peak", "Tour du Mont Blanc","Teton Crest Trail", "Everest Base Camp via Cho La Pass", "Kesugi Ridge"));protected void doGet(HttpServletRequest request, HttpServletResponse response)  throws IOException {  response.getWriter().print(String.join("\n", this.hikes));  }  protected void doPost(HttpServletRequest request, HttpServletResponse response)  throws IOException {  String hike = request.getParameter("hike");  if (hike == null) {  response.setStatus(400);  response.getWriter().print("Param 'hike' cannot be null.");  }  else if (this.hikes.contains(hike)) {  response.setStatus(400);  response.getWriter().print("The hike '"+hike+"' already exists.");  }  else {  this.hikes.add(hike);  response.getWriter().print(String.join("\n", this.hikes));  }  }  protected void doDelete(HttpServletRequest request, HttpServletResponse response)  throws IOException {  String hike = request.getParameter("hike");  if (hike == null) {  response.setStatus(400);  response.getWriter().print("Param 'hike' cannot be null.");  }  else {  this.hikes.remove(hike);  response.getWriter().print(String.join("\n", this.hikes));  }  }  }

使用Control-C停止服务器,然后使用gradle apprun重启服务器。

获取远足清单:

http :8080/hikes
HTTP/1.1 200 OK
...Wonderland Trail
South Maroon Peak
Tour du Mont Blanc
Teton Crest Trail
Everest Base Camp via Cho La Pass
Kesugi Ridge

发布新的加息:

http -f POST :8080/hikes hike="Pear Lake"
HTTP/1.1 200 OK
...Wonderland Trail
South Maroon Peak
Tour du Mont Blanc
Teton Crest Trail
Everest Base Camp via Cho La Pass
Kesugi Ridge
Pear Lake

删除远足:

http DELETE :8080/hikes hike=="South Maroon Peak"
HTTP/1.1 200 OK
...Wonderland Trail
Tour du Mont Blanc
Teton Crest Trail
Everest Base Camp via Cho La Pass
Kesugi Ridge
Pear Lake

现在,尝试删除不存在的加息,或发送一个空值:

http DELETE :8080/hikes
HTTP/1.1 400 Bad Request
...Param 'hike' cannot be null.

要将其部署到实时服务器,您可以按原样部署项目,使用gradle apprun通过嵌入式Jetty服务器运行应用程序。 您还可以通过使用gradle war构建war文件并将war文件(位于build/libs )复制到服务器上,从而将其部署到外部Jetty服务器。

注意:这是REST服务的非常幼稚的实现。 它使用内存中的ArrayList作为不同步的数据源(因此将在实际的Web servlet中遇到线程问题)。 对于超出本教程范围的任何内容,您都需要实现某种数据库后端。 有关如何执行此操作的帮助,请参阅教程末尾列出的示例博客文章。 通常,您还将添加一个PUT端点,并为每个项目分配一个ID用作索引,以便可以更新数据,但这超出了本教程的范围。

到目前为止,一切进展顺利。 在下一部分中,您将使用Spring Boot重新创建相同的Hikes ToDo应用,并使用Okta作为OAuth / OIDC提供者对应用进行JWT令牌认证。

创建一个OIDC应用程序

现在,让我们前往Okta进行一些实地考察,并为OAuth / OpenID Connect(OIDC)进行设置。 它们一起是用于实施安全授权和身份验证的一组开放标准。 在本教程中,Okta将充当身份提供者,而您的Spring Boot应用将成为客户端。

您应该已经在Okta注册了免费的开发者帐户。 浏览至https://developer.okta.com上的开发人员仪表板。 如果这是您第一次登录,则可能需要单击“ 管理员”按钮。

要配置JWT身份验证和授权,您需要创建一个OIDC应用程序。

在顶部菜单中,单击“ 应用程序”按钮。 单击添加应用程序按钮。

选择应用程序类型Web

单击下一步

为应用命名。 我将其命名为“ Spring Boot Jetty”。

登录重定向URI下 ,添加两个新的URI:

  • https://oidcdebugger.com/debug
  • http://localhost:8080/login/oauth2/code/okta

在“ 允许的授予类型”下 ,选中“ 隐式(混合)”

其余的默认值将起作用。

单击完成

使页面保持打开状态或记下Client ID 。 生成令牌时需要一点时间。

注意:您将使用oidcdebugger.com重定向URI和隐式授予类型创建访问令牌,您可以在命令行中使用HTTPie。 第二个URI是Spring Security在使用OAuth登录功能时用于Okta的默认重定向URI。

使用Jetty创建一个Spring Boot项目

要创建Spring Boot项目,您将使用Spring Initializr 。 查看其GitHub项目以查看其代码。 Initializr有一个不错的Web表单,用于配置和下载Spring Boot入门项目,但是对于该项目,您将使用其REST API。

从外壳执行以下命令,以下载已配置的启动程序项目的zip文件。

http https://start.spring.io/starter.zip \javaVersion==11 \dependencies==web \language==java \type==gradle-project \name==SpringBootJetty \groupId==com.okta.springbootjetty \artifactId==SpringBootJetty \packageName==com.okta.springbootjetty -o SpringBootJetty.zip

解压缩下载的文件,然后在您选择的IDE中打开目录。

首先,修改build.gradle文件,以便项目使用Jetty嵌入式容器,而不是默认的Tomcat。 添加spring-boot-starter-jetty依赖关系,并排除spring-boot-starter-tomcat依赖关系。

更改build.gradle文件以匹配以下内容:

plugins {id 'org.springframework.boot' version '2.2.0.RELEASE'id 'io.spring.dependency-management' version '1.0.8.RELEASE'id 'java'
}group = 'com.okta.springbootjetty'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'repositories {mavenCentral()
}dependencies {implementation 'org.springframework.boot:spring-boot-starter-web'implementation 'org.springframework.boot:spring-boot-starter-jetty' testImplementation('org.springframework.boot:spring-boot-starter-test') {exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'}
}test {useJUnitPlatform()
}configurations {  compile.exclude module: "spring-boot-starter-tomcat"  
}

现在添加一个WebController.java文件。

src/main/java/com/okta/springbootjetty/WebController.java
package com.okta.springbootjetty;  import org.springframework.stereotype.Controller;  
import org.springframework.web.bind.annotation.*;  import javax.servlet.http.HttpServletResponse;  
import java.util.ArrayList;  
import java.util.Arrays;
import java.util.List;@Controller  
public class WebController {  private List<String> hikes = new ArrayList<>(Arrays.asList("Wonderland Trail", "South Maroon Peak", "Tour du Mont Blanc","Teton Crest Trail", "Everest Base Camp via Cho La Pass", "Kesugi Ridge"));@GetMapping("/")  @ResponseBody  public String indexGet() {  return String.join("\n", this.hikes);  }  @PostMapping("/")  @ResponseBody  public String indexPost(@RequestParam String hike, HttpServletResponse response) {  if (hike == null) {  response.setStatus(400);  return "Param 'hike' cannot be null.";  }  else if (this.hikes.contains(hike)) {  response.setStatus(400);  return "The hike '"+hike+"' already exists.";  }  else {  this.hikes.add(hike);  return String.join("\n", this.hikes);  }  }  @DeleteMapping("/")  @ResponseBody  public String indexDelete(@RequestParam String hike, HttpServletResponse response) {  if (hike == null) {  response.setStatus(400);  return "Param 'hike' cannot be null.";  }  else {  this.hikes.remove(hike);  return String.join("\n", this.hikes);  }  }  }

该控制器重新创建在第一个Jetty Hikes ToDo应用程序中发现的相同功能,但现在使用Spring Boot。 您会注意到Spring简化了一些语法。 @ResponseBody注释告诉Spring Boot控制器正在直接返回响应主体(与返回模板名称相反)。 另外,请注意,代码使用依赖注入来获取HttpServletResponse以及请求参数。

运行Spring Boot REST服务(确保您的其他服务已停止,否则您将收到端口冲突错误):

gradle bootRun

在第二个Shell窗口中,获取远足列表(注意,下面没有/hikes路径)。

http :8080

另外,尝试添加和删除新的加息。

发布新的加息:

http -f POST :8080 hike="Pear Lake"

删除远足:

http DELETE :8080 hike=="South Maroon Peak"

部署Spring Boot项目

现在,您有了一个在嵌入式Jetty容器上运行的Spring Boot应用程序。 要将其部署到生产服务器,请使用gradle bootJar构建可执行的jar文件,将该jar文件复制到服务器,然后使用java -jar <your jar file name>.jar运行它。 无需单独的Web服务器,因为此jar包含嵌入式Jetty Web服务器。

注意:对于在同一服务器上具有多个单独应用程序的应用程序服务器,如果要进行更老式的部署,则需要构建war文件。 有关如何执行此操作的Spring文档非常有用。 从本质上讲,你需要做两件事情:1)添加war插件到项目的依赖,以及2)改变码头或Tomcat依赖于providedRuntime所以它不是在打包的战争包括在内。 然后,您构建一个war文件并将其部署到服务器上的servlet Web应用程序路径。

将OAuth / OIDC登录名添加到Spring Boot App

您注册了Okta并创建了OIDC应用程序。 现在是时候配置Spring Boot应用程序以使用OAuth / OIDC进行身份验证和授权了。

首先,将您的Issuer URI添加到src/main/resources/application.properties文件。 您需要用实际的Okta URL替换{yourOktaUrl} 。 如果您访问https://developer.okta.com并导航至API授权服务器 ,则会看到default授权服务器的Issuer URI。

okta.oauth2.issuer=https://{yourOktaUrl}/oauth2/default

在该文件中时,从您先前创建的“ Spring Boot Jetty”应用程序中添加客户端ID和客户端密钥。

okta.oauth2.clientId={clientId}
okta.oauth2.clientSecret={clientSecret}

接下来,您需要在dependencies {}块中的build.gradle文件中添加以下依赖。

implementation 'com.okta.spring:okta-spring-boot-starter:1.3.0'

其中包括Okta Spring Boot Starter,这是一个很好的项目,可简化Spring Boot对Okta身份验证和授权的使用。 查看项目页面以获取更多信息 。

您还需要更新SpringBootJettyApplication类以匹配以下内容:

package com.okta.springbootjetty;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;@SpringBootApplication
public class SpringBootJettyApplication extends WebSecurityConfigurerAdapter {public static void main(String[] args) {SpringApplication.run(SpringBootJettyApplication.class, args);}@Overridepublic void configure(HttpSecurity http) throws Exception {http.authorizeRequests().anyRequest().permitAll().and().oauth2Login().and().oauth2ResourceServer().jwt();}}

保护您的DELETE和POST端点

configure(HttpSecurity http)方法将具有OAuth 2.0登录名的Spring Boot应用配置为OAuth 2.0资源服务器,并默认允许所有请求。 您将通过@PreAuthorize批注使用方法级别的安全性来保护下面的DELETE和POST端点。

最后,将@PreAuthorize("isAuthenticated")批注添加到WebController类的indexPost()indexDelete()方法中。

package com.okta.springbootjetty;  import org.springframework.security.access.prepost.PreAuthorize;  
import org.springframework.stereotype.Controller;  
import org.springframework.web.bind.annotation.*;  import javax.servlet.http.HttpServletResponse;  
import java.util.ArrayList;  
import java.util.Arrays;
import java.util.List;  @Controller  
public class WebController {  private List<String> hikes = new ArrayList<>(Arrays.asList("Wonderland Trail", "South Maroon Peak", "Tour du Mont Blanc","Teton Crest Trail", "Everest Base Camp via Cho La Pass", "Kesugi Ridge"));@GetMapping("/")  @ResponseBody  public String indexGet() {  return String.join("\n", this.hikes);  }  @PreAuthorize("isAuthenticated")  // <- ***ADDED***@PostMapping("/")  @ResponseBody  public String indexPost(@RequestParam String hike, HttpServletResponse response) {  if (hike == null) {  response.setStatus(400);  return "Param 'hike' cannot be null.";  }  else if (this.hikes.contains(hike)) {  response.setStatus(400);  return "The hike '"+hike+"' already exists.";  }  else {  this.hikes.add(hike);  return String.join("\n", this.hikes);  }  }  @PreAuthorize("isAuthenticated")  // <- ***ADDED***@DeleteMapping("/")  @ResponseBody  public String indexDelete(@RequestParam String hike, HttpServletResponse response) {  if (hike == null) {  response.setStatus(400);  return "Param 'hike' cannot be null.";  }  else {  this.hikes.remove(hike);  return String.join("\n", this.hikes);  }  }  }

您现在有了受保护的Web服务。 您可以发出GET请求,但无法发布或删除。 重新启动服务器,并使用以下HTTPie命令对此进行验证。

http :8080
HTTP/1.1 200 OK
...Wonderland Trail
South Maroon Peak
Tour du Mont Blanc
Teton Crest Trail
Everest Base Camp via Cho La Pass
Kesugi Ridge
http -f POST :8080 hike="Pear Lake"
HTTP/1.1 403 Forbidden
...{"error": "Forbidden","message": "Forbidden","path": "/","status": 403,"timestamp": "2019-09-07T16:13:59.474+0000"
}

使用OIDC调试器生成JWT

要访问受保护的端点,您需要生成一个JWT。 为此,您可以使用OIDC调试器 。 您将需要先前创建的OIDC应用程序中的客户端ID,以及基本Okta URI(与Issuer URI中的基本URI相同)。

打开OIDC调试器 。

授权URI更新为: https://{yourOktaUri}/oauth2/default/v1/authorize

从OIDC应用程序将客户端ID更新为客户端ID。

在“ 状态”字段中放置一些内容。 就本教程而言,这可以是任何东西。 此值用于帮助防止跨站点伪造请求。

向下滚动并单击发送请求

将令牌复制到剪贴板,并将其存储在用于发出请求的shell窗口中的shell变量中。

TOKEN=eyJraWQiOiJIb05xb01mNE9jREltWnBGRnBINjZGTkFOM0J...

现在尝试发布新的加息,然后将其删除。

http -f POST :8080 hike="Pear Lake" "Authorization: Bearer $TOKEN"
HTTP/1.1 200 OK
...Wonderland Trail
South Maroon Peak
Tour du Mont Blanc
Teton Crest Trail
Everest Base Camp via Cho La Pass
Kesugi Ridge
Pear Lake
http DELETE :8080 hike=="South Maroon Peak" "Authorization: Bearer $TOKEN"
HTTP/1.1 200 OK
...Wonderland Trail
Tour du Mont Blanc
Teton Crest Trail
Everest Base Camp via Cho La Pass
Kesugi Ridge
Pear Lake

您还配置了此应用程序以使用Spring Security的oauth2Login() 。 这意味着您可以转到http://localhost:8080/login ,单击发行者URL,然后也以这种方式登录。

了解有关Java,Spring Boot和Spring Security的更多信息

就是这样。 在本教程中,您了解了如何制作一个简单的Java servlet服务并使用Jetty运行它。 您还了解了如何在Spring Boot中重新创建相同的服务,如何将其配置为使用Jetty,以及简化Java代码。 最后,您了解了如何使用Okta提供的免费开发者帐户向您的Spring Boot应用程序添加OAuth / OIDC安全性。

您可以在oktadeveloper / okta-spring-boot-jetty-example上的GitHub上找到本教程的代码。

以下是一些相关的博客文章:

  • Java应用程序的简单令牌认证
  • 在15分钟内使用Spring Boot和Spring Security构建一个Web应用程序
  • 创建一个安全的Spring REST API
  • 使用Spring Boot和Vue.js构建一个简单的CRUD应用

如果您对此帖子有任何疑问,请在下面添加评论。 有关更多精彩内容, 请在Twitter上关注@oktadev , 在Facebook上关注我们,或订阅我们的YouTube频道 。

使用Okta的身份管理平台轻松部署您的应用程序 使用Okta的API在几分钟之内即可对任何应用程序中的用户进行身份验证,管理和保护。 今天尝试Okta。


翻译自: https://www.javacodegeeks.com/2019/12/get-started-with-jetty-java-and-oauth.html

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

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

相关文章

vscode 设置 sublime 的主题

vscode 怎么设置 sublime 的主题&#xff1f; VsCode中提供多种主题样式&#xff0c;供使用者选择。 由于习惯于Sublime默认主题&#xff0c;因此将VsCode主题更换为Sublime默认主题。 首先点击编辑器顶部导航菜单中的【文件】&#xff1b; 然后点击【首选项】下【颜色主题】…

spring预加载与懒加载_通过Spring将继承树加载到List中

spring预加载与懒加载我注意到有趣的Spring功能。 我的一位同事使用它将Spring Bean的整个继承树加载到列表中。 在学习Spring文档时错过了这一点。 让我们来看看Spring bean的继承树&#xff1a; 下面的代码片段是通过构造函数注入将此豆树加载到列表中的&#xff1a; Comp…

VsCode连接远程服务器并修改文件代码

一 插件安装配置 1. 安装远程开发插件Remote Development&#xff0c;在商店中搜索Remote Development并安装。 2、选择SSH Targets 安装完成后&#xff0c;vscode左侧多出了一个菜单栏&#xff0c;我们点击配置按钮配置远程服务器的地址。选择SSH Targets。 二 远程服务器配…

VsCode打开终端的方法

方法1&#xff1a;打开终端的常规方法 打开VScode后&#xff0c;鼠标左键单击窗口顶部的【查看】&#xff08;如下图红圈标注&#xff09;&#xff0c; 在下拉列表中找到【终端】&#xff08;如下图红框标注&#xff09; 鼠标左键点击【终端】即可打开终端子窗口&#xff0c;如…

Ubuntu下VScode配置ssh免密远程登录

一 实现步骤 1.在本机与远程服务器上&#xff0c; 输入ssh-keygen -t rsa&#xff0c;然后连续回车直到结束 2.在本机上执行命令 ssh-copy-id 命令 &#xff08;1&#xff09;.命令介绍 ssh-copy-id命令可以把本地的ssh公钥文件安装到远程主机对应的账户下。 达到的功能&am…

VSCode隐藏左边活动栏

用sublime时间较长&#xff0c;VsCode左边的活动栏看上去有些多余。查询隐藏活动栏的快捷键&#xff0c;但没有找到。通过vscode怎么隐藏左边栏&#xff1f; - 知乎有快捷键可以隐藏左边栏么&#xff1f;https://www.zhihu.com/question/48285162 问题&#xff0c;找到相关处理…

Typora设置标题自动标号

Typora由于默认标题无法自动标号&#xff0c;每次编辑时需要手动处理。为实现标题自动编号&#xff0c;需要进行相关操作。 一 官方说明 To achieve this, add the following to your base.user.css or [theme].user.css in the theme folder. /** initialize css counter */ …

捕获Java堆转储的7个选项

堆转储是诊断与内存相关的问题的重要工件&#xff0c;例如内存泄漏缓慢&#xff0c;垃圾回收问题和java.lang.OutOfMemoryError。它们也是优化内存消耗的重要工件。 有很多很棒的工具&#xff0c;例如Eclipse MAT和Heap Hero&#xff0c;可以分析堆转储。 但是&#xff0c;您需…

第一章 基础算法(一)

文章目录排序快速排序--分治归并排序二分整数二分浮点数二分整体框架排序 快速排序–分治 785题目&#xff1a; 给定你一个长度为 n 的整数数列。请你使用快速排序对这个数列按照从小到大进行排序。并将排好序的数列按顺序输出。输入格式 输入共两行&#xff0c;第一行包含整数…

java8hashmap_Java 8中的HashMap性能改进

java8hashmapHashMap<K, V>是每个Java程序中快速&#xff0c;通用且无处不在的数据结构。 首先是一些基础知识。 您可能知道&#xff0c;它使用键的hashCode()和equals()方法在存储桶之间拆分值。 存储桶&#xff08;箱&#xff09;的数量应略高于映射中的条目数&#xf…

装前必看施工干货,贴瓷砖的5大步骤。福州中宅装饰,福州装修

亲爱的朋友们&#xff0c;你们是否曾经在装修房屋时遇到过贴砖的难题呢&#xff1f;贴砖可是装修工程中一项重要的工艺&#xff0c;它直接影响到整个装修的效果和质量。今天&#xff0c;我就来跟大家分享一下贴砖的几个重要要点&#xff0c;希望对你们有所帮助。 1️⃣ 选材是关…

Typora+Node.js+PicGo搭建图床

目录 一 问题背景 二 具体步骤 2.1 picgo的安装 1. 下载picgo 2. 安装 3. 效果 2.2 Node.js的安装 (1)下载链接 &#xff08;2&#xff09;安装步骤 2.3 Gitee设置 2.3.1在gitee上面创建一个仓库 2.4 整体配置 2.4.1 picgo软件配置 2.4.2 图床设置 2.4.3 Typora配…

JMetro版本11.6和8.6发布

再次返回另一个JMetro版本。 这是一个重要的里程碑&#xff0c;此版本中增加了样式&#xff0c;JavaFX库中的所有JavaFX控件现在都具有JMetro样式。 除此之外&#xff0c;还有用于ControlsFX StatusBar的新JMetro样式&#xff0c;对现有样式的样式调整&#xff0c;错误修复等。…

第一章 基础算法(二)

文章目录高精度高精度加法高精度减法高精度乘法高精度除法前缀和一维前缀和二维前缀和--求子矩阵中一部分和差分一维差分二维差分高精度 高精度加法 791 给定两个正整数&#xff08;不含前导 0&#xff09;&#xff0c;计算它们的和。输入格式 共两行&#xff0c;每行包含一个…

第一章 基础算法(三)

文章目录双指针算法双指针算法分类双指针算法模板性质&#xff1a;总结例1例2位运算二进制的第k位lowbit 返回x的最后一位1实现计算机中编码知识做题思路离散化区间合并双指针算法 双指针算法分类 双指针算法模板 性质&#xff1a; 总结 为什么双指针算法可以起到优化的作用&a…

第二章 数据结构(二)

文章目录Trie树存储并查集常规例题并查集维护多余信息堆性质存储基础操作downup操作例题Trie树 Tire&#xff1a;高效地存储和查找字符串集合的数据结构 存储 如果没有就创建。 对单词结尾进行标记&#xff0c;表示以当前节点结尾的地方存在一个单词 维护一个字符串集合&am…

Apache Camel 3只有2个月的路程

骆驼队正忙于为 Apache Camel3 。今天&#xff0c;第二个候选版本已构建并发布在暂存库中&#xff0c;供早期的适配器尝试 。 当我自己很忙的时候&#xff0c;我只想写一篇简短的博客文章&#xff0c;以使社区了解Apache Camel 3即将发布&#xff0c;我们希望它在今年年底&am…

第二章 数据结构(三)

文章目录哈希表存储结构拉链法&#xff1a;插入查询题目注意开放寻址法查找质数代码字符串哈希方式STL相关知识哈希表存储结构 整体结构 0~109->0~105 方法&#xff1a; x mod 105处理冲突 开放寻址法拉链法 拉链法&#xff1a; 思想&#xff1a;每个槽上拉一条链&…

Vaadin 10+作为CUBA UI的未来

从一开始&#xff0c;Vaadin就成为CUBA平台用户界面的基石和重要组成部分。 由于其创新的方法&#xff0c;它帮助CUBA将企业用户界面开发带到了一个非常有希望的&#xff08;如今是默认&#xff09;的WEB领域。 Vaadin最令人兴奋的部分之一是整个开发都是同构的&#xff0c;并且…

第二章 数据结构(一)

文章目录整体结构为什么用数组链表与邻接表单链表存储插入插入至头结点将x插入到下标为k的点后面删除遍历双链表初始化插入删除邻接表栈和队列栈队列单调栈单调队列KMP整体结构 链表与邻接表&#xff08;用数组模拟&#xff09;栈与队列&#xff08;用数组模拟&#xff09;kmp…