app访问java web_Java Web App体系结构

app访问java web

我曾经利用Servlet,JSP,JAX-RS,Spring框架,Play框架,带有Facelets的JSF和一些Spark框架。 以我的拙见,所有这些解决方案都远非面向对象和优雅的。 它们都充满了静态方法,不可测试的数据结构和肮脏的骇客。 因此,大约一个月前,我决定创建自己的Java Web框架。 我将一些基本原则纳入其基础:1)没有NULL,2)没有公共静态方法,3)没有可变的类以及4)没有类的转换,反射和instanceof运算符。 这四个基本原则应保证干净的代码和透明的体系结构。 这就是Takes框架的诞生方式。 让我们看看创建了什么以及它如何工作。

教父的制作(1972),弗朗西斯·福特·科波拉

教父的制作(1972),弗朗西斯·福特·科波拉

简而言之,Java Web体系结构

简单来说,这就是我理解Web应用程序体系结构及其组件的方式。

首先,要创建Web服务器,我们应该创建一个新的网络套接字 ,该套接字在某个TCP端口上接受连接。 通常是80,但是我将使用8080进行测试。 这是在Java中使用ServerSocket类完成的:

import java.net.ServerSocket;
public class Foo {public static void main(final String... args) throws Exception {final ServerSocket server = new ServerSocket(8080);while (true);}
}

这足以启动Web服务器。 现在,套接字已准备就绪,正在侦听8080端口。当有人在其浏览器中打开http://localhost:8080时,将建立连接,浏览器将永远旋转其等待轮。 编译此代码段,然后尝试。 我们只是构建了一个简单的Web服务器,而没有使用任何框架。 我们尚未对传入的连接做任何事情,但是我们也不拒绝它们。 所有这些都在该server对象内对齐。 它是在后台线程中完成的。 这就是为什么我们需要将while(true)放在后面。 没有这种无休止的暂停,应用程序将立即完成执行,服务器套接字将关闭。

下一步是接受传入的连接。 在Java中,这是通过对accept()方法的阻塞调用来完成的:

final Socket socket = server.accept();

该方法正在阻塞其线程,并等待新的连接到达。 一旦发生这种情况,它将返回Socket的实例。 为了接受下一个连接,我们应该再次调用accept() 。 因此,基本上,我们的Web服务器应该像这样工作:

public class Foo {public static void main(final String... args) throws Exception {final ServerSocket server = new ServerSocket(8080);while (true) {final Socket socket = server.accept();// 1. Read HTTP request from the socket// 2. Prepare an HTTP response// 3. Send HTTP response to the socket// 4. Close the socket}}
}

这是一个无休止的循环,接受一个新的连接,理解它,创建一个响应,返回响应,然后再次接受一个新的连接。 HTTP协议是无状态的,这意味着服务器不应记住任何先前连接中发生的情况。 它关心的只是此特定连接中的传入HTTP请求。

HTTP请求来自套接字的输入流,看起来像多行文本块。 如果读取套接字的输入流,将看到以下内容:

final BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream())
);
while (true) {final String line = reader.readLine();if (line.isEmpty()) {break;}System.out.println(line);
}

您将看到如下内容:

GET / HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.89 Safari/537.36
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8,ru;q=0.6,uk;q=0.4

客户端(例如Google Chrome浏览器)将此文本传递到已建立的连接中。 它连接到localhost端口8080,一旦连接就绪,它将立即将文本发送到其中,然后等待响应。

我们的工作是使用在请求中获得的信息来创建HTTP响应。 如果我们的服务器非常原始,那么我们基本上可以忽略请求中的所有信息,而只需返回“ Hello,world!”。 到所有请求(为简单起见,我使用IOUtils ):

import java.net.Socket;
import java.net.ServerSocket;
import org.apache.commons.io.IOUtils;
public class Foo {public static void main(final String... args) throws Exception {final ServerSocket server = new ServerSocket(8080);while (true) {try (final Socket socket = server.accept()) {IOUtils.copy(IOUtils.toInputStream("HTTP/1.1 200 OK\r\n\r\nHello, world!"),socket.getOutputStream());}}}
}

而已。 服务器已准备就绪。 尝试编译并运行它。 将浏览器指向http:// localhost:8080 ,您将看到Hello, world!

$ javac -cp commons-io.jar Foo.java
$ java -cp commons-io.jar:. Foo &
$ curl http://localhost:8080 -v
* Rebuilt URL to: http://localhost:8080/
* Connected to localhost (::1) port 8080 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.37.1
> Host: localhost:8080
> Accept: */*
>
< HTTP/1.1 200 OK
* no chunk, no close, no size. Assume close to signal end
<
* Closing connection 0
Hello, world!

这就是构建Web服务器所需的全部。 现在让我们讨论如何使其面向对象和可组合。 让我们尝试看看Takes框架是如何构建的。

路由/调度

最重要的步骤是确定谁负责构建HTTP响应。 每个HTTP请求都有1)查询,2)方法和3)多个标头。 使用这三个参数,我们需要实例化一个将为我们建立响应的对象。 在大多数Web框架中,此过程称为请求分派或路由。 这是我们在Takes中的做法:

final Take take = takes.route(request);
final Response response = take.act();

基本上有两个步骤。 第一个是创建的一个实例Taketakes ,而第二个是创建的实例Responsetake 。 为什么这样做呢? 主要是为了分开职责。 实例Takes负责调度请求和实例右Take ,和实例Take负责创建响应。

要在Takes中创建一个简单的应用程序,您应该创建两个类。 首先,执行Takes

import org.takes.Request;
import org.takes.Take;
import org.takes.Takes;
public final class TsFoo implements Takes {@Overridepublic Take route(final Request request) {return new TkFoo();}
}

我们分别为TakesTake使用这些TsTk前缀。 您应该创建的第二个类是Take的实现:

import org.takes.Take;
import org.takes.Response;
import org.takes.rs.RsText;
public final class TkFoo implements Take {@Overridepublic Response act() {return new RsText("Hello, world!");}
}

现在是时候启动服务器了:

import org.takes.http.Exit;
import org.takes.http.FtBasic;
public class Foo {public static void main(final String... args) throws Exception {new FtBasic(new TsFoo(), 8080).start(Exit.NEVER);}
}

FtBasic类执行与上述完全相同的套接字操作。 它在端口8080上启动服务器套接字,并通过我们提供给其构造函数的TsFoo实例调度所有传入的连接。 它以无休止的周期进行此调度,每秒检查一次是否应该使用Exit实例停止。 显然, Exit.NEVER永远不会回答“请别停下来”。

HTTP请求

现在,让我们看看到达TsFoo的HTTP请求中TsFoo什么以及我们可以从中获得什么。 这是在Takes中定义Request接口的方式:

public interface Request {Iterable<String> head() throws IOException;InputStream body() throws IOException;
}

该请求分为两部分:头部和身体。 根据RFC 2616中的 HTTP规范,头部包含开始于正文的空行之前的所有行。 框架中有许多有用的装饰器用于Request 。 例如, RqMethod将帮助您从标题的第一行获取方法名称:

final String method = new RqMethod(request).method();

RqHref将帮助提取查询部分并进行解析。 例如,这是请求:

GET /user?id=123 HTTP/1.1
Host: www.example.com

此代码将提取123

final int id = Integer.parseInt(new RqHref(request).href().param("id").get(0)
);

RqPrint可以将整个请求或其主体打印为String

final String body = new RqPrint(request).printBody();

这里的想法是使Request接口保持简单,并向其装饰器提供此请求解析功能。 这种方法有助于框架使类保持较小且具有凝聚力。 每个装饰器都非常小巧,坚固,只能做一件事。 所有这些装饰器都在org.takes.rq包中。 您可能已经知道, Rq前缀代表Request

第一个Real Web App

让我们创建第一个真正的Web应用程序,它将做一些有用的事情。 我建议从Entry类开始,这是Java从命令行启动应用程序所必需的:

import org.takes.http.Exit;
import org.takes.http.FtCLI;
public final class Entry {public static void main(final String... args) throws Exception {new FtCLI(new TsApp(), args).start(Exit.NEVER);}
}

此类仅包含一个main()静态方法,当应用程序从命令行启动时,JVM将调用该方法。 如您所见,它将实例化FtCLI ,为其提供类TsApp和命令行参数的实例。 我们稍后将创建TsApp类。 FtCLI (转换为“带有命令行界面的前端”)创建相同FtBasic的实例,将其包装到一些有用的修饰符中,并根据命令行参数进行配置。 例如,-- --port=8080将转换为8080端口号,并作为FtBasic构造函数的第二个参数传递。

该Web应用程序本身称为TsApp并扩展了TsWrap

import org.takes.Take;
import org.takes.Takes;
import org.takes.facets.fork.FkRegex;
import org.takes.facets.fork.TsFork;
import org.takes.ts.TsWrap;
import org.takes.ts.TsClasspath;
final class TsApp extends TsWrap {TsApp() {super(TsApp.make());}private static Takes make() {return new TsFork(new FkRegex("/robots.txt", ""),new FkRegex("/css/.*", new TsClasspath()),new FkRegex("/", new TkIndex()));}
}

我们将在稍后讨论此TsFork课程。

如果您使用的是Maven,则应使用pom.xml开头:

<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>foo</groupId><artifactId>foo</artifactId><version>1.0-SNAPSHOT</version><dependencies><dependency><groupId>org.takes</groupId><artifactId>takes</artifactId><version>0.9</version> <!-- check the latest in Maven Central --></dependency></dependencies><build><finalName>foo</finalName><plugins><plugin><artifactId>maven-dependency-plugin</artifactId><executions><execution><goals><goal>copy-dependencies</goal></goals><configuration><outputDirectory>${project.build.directory}/deps</outputDirectory></configuration></execution></executions></plugin></plugins></build>
</project>

运行mvn clean package应该在target目录中构建foo.jar文件,并在target/deps构建所有JAR依赖项的集合。 现在,您可以从命令行运行该应用程序:

$ mvn clean package
$ java -Dfile.encoding=UTF-8 -cp ./target/foo.jar:./target/deps/* foo.Entry --port=8080

该应用程序已准备就绪,您可以将其部署到Heroku。 只需在存储库的根目录中创建一个Procfile文件,然后将存储库推送到Heroku。 这是Procfile外观:

web: java -Dfile.encoding=UTF-8 -cp target/foo.jar:target/deps/* foo.Entry --port=${PORT}

叉车

这个TsFork类似乎是框架的核心元素之一。 它有助于路线传入的HTTP请求到右 。 它的逻辑非常简单,里面只有几行代码。 它封装了“ forks”的集合,它们是Fork<Take>接口的实例:

public interface Fork<T> {Iterator<T> route(Request req) throws IOException;
}

它唯一的route()方法要么返回一个空的迭代器,要么返回一个具有单个Take的迭代器。 TsFork遍历所有fork,调用它们的route()方法,直到其中一个返回take 。 一旦出现这种情况, TsFork返回此给调用者,这是FtBasic

现在让我们自己创建一个简单的fork。 例如,我们要在请求/status URL时显示应用程序的/status 。 这是代码:

final class TsApp extends TsWrap {private static Takes make() {return new TsFork(new Fork.AtTake() {@Overridepublic Iterator<Take> route(Request req) {final Collection<Take> takes = new ArrayList<>(1);if (new RqHref(req).href().path().equals("/status")) {takes.add(new TkStatus());}return takes.iterator();}});}
}

我相信这里的逻辑很明确。 我们要么返回一个空的迭代器,要么返回一个内部带有TkStatus实例的迭代器。 如果返回一个空的迭代器, TsFork将尝试在集合中找到另一个实际上获取Take实例的fork,以产生Response 。 顺便说一句,如果未找到任何内容,并且所有派生都返回空的迭代器,则TsFork将抛出“找不到页面”异常。

这种确切的逻辑由一个名为FkRegex即用即用的叉子FkRegex ,它尝试将请求URI路径与提供的正则表达式进行匹配:

final class TsApp extends TsWrap {private static Takes make() {return new TsFork(new FkRegex("/status", new TkStatus()));}
}

我们可以组成TsFork类的多层结构。 例如:

final class TsApp extends TsWrap {private static Takes make() {return new TsFork(new FkRegex("/status",new TsFork(new FkParams("f", "json", new TkStatusJSON()),new FkParams("f", "xml", new TkStatusXML()))));}
}

同样,我认为这很明显。 实例FkRegex会问的一个封装实例TsFork返回一个take,它会尝试从一个获取它FkParams封装。 如果HTTP查询为/status?f=xml ,则将返回TkStatusXML的实例。

HTTP响应

现在让我们讨论HTTP响应的结构及其面向对象的抽象Response 。 界面外观如下:

public interface Response {Iterable<String> head() throws IOException;InputStream body() throws IOException;
}

看起来非常类似于Request ,不是吗? 好吧,它是相同的,主要是因为HTTP请求和响应的结构几乎相同。 唯一的区别是第一行。

有很多有用的装饰器,可以帮助您建立响应。 它们是可组合的 ,这使它们非常方便。 例如,如果要构建一个包含HTML页面的响应,则可以这样编写它们:

final class TkIndex implements Take {@Overridepublic Response act() {return new RsWithStatus(new RsWithType(new RsWithBody("<html>Hello, world!</html>"),"text/html"),200);}
}

在此示例中,装饰器RsWithBody创建一个带有主体但没有头的响应。 然后, RsWithType添加标题Content-Type: text/html 。 然后, RsWithStatus确保响应的第一行包含HTTP/1.1 200 OK

您可以创建自己的装饰器,以重用现有的装饰器。 看看RsPageRsPage是如何完成的。

模板如何?

如我们所见,返回简单的“ Hello,world”页面不是什么大问题。 但是,诸如HTML页面,XML文档,JSON数据集等更复杂的输出呢? 有一些方便的Response装饰器可以实现所有这些功能。 让我们从简单的模板引擎Velocity开始。 好吧,这不是那么简单。 它相当强大,但是我建议仅在简单情况下使用它。 下面是它的工作原理:

final class TkIndex implements Take {@Overridepublic Response act() {return new RsVelocity("Hello, ${name}").with("name", "Jeffrey");}
}

RsVelocity构造函数接受必须为Velocity模板的单个参数。 然后,调用with()方法,将数据注入Velocity上下文中。 当需要呈现HTTP响应时, RsVelocity将根据配置的上下文“评估”模板。 同样,我建议您仅对简单输出使用这种模板方法。

对于更复杂HTML文档,我建议您将XML / XSLT与Xembly结合使用。 我在之前的几篇文章中对此想法进行了解释: 浏览器和RESTful API 中的XML + XSLT,以及相同URL中的网站 。 它简单而强大-Java生成XML输出,而XSLT处理器将其转换为HTML文档。 这就是我们将表示形式与数据分开的方式。 就MVC而言,XSL样式表是一个“视图”,而TkIndex是一个“控制器”。

我将很快写另一篇关于Xembly和XSL模板的文章。

同时,我们将在Takes中为JSF / Facelets和JSP渲染创建装饰器。 如果您有兴趣提供帮助,请分叉框架并提交拉取请求。

持久性呢?

现在,出现的一个问题是如何处理持久性实体,例如数据库,内存结构,网络连接等。我的建议是在Entry类内部对其进行初始化,并将其作为参数传递给TsApp构造函数。 然后, TsApp将它们传递到构造函数的定制需要

例如,我们有一个PostgreSQL数据库,其中包含一些需要渲染的表数据。 这是在Entry类中初始化与它的连接的方式(我使用的是BoneCP连接池):

public final class Entry {public static void main(final String... args) throws Exception {new FtCLI(new TsApp(Entry.postgres()), args).start(Exit.NEVER);}private static Source postgres() {final BoneCPDataSource src = new BoneCPDataSource();src.setDriverClass("org.postgresql.Driver");src.setJdbcUrl("jdbc:postgresql://localhost/db");src.setUser("root");src.setPassword("super-secret-password");return src;}
}

现在, TsApp的构造TsApp必须接受类型为java.sql.Source的单个参数:

final class TsApp extends TsWrap {TsApp(final Source source) {super(TsApp.make(source));}private static Takes make(final Source source) {return new TsFork(new FkRegex("/", new TkIndex(source)));}
}

TkIndex类还接受Source类的单个参数。 我相信您知道如何在TkIndex中使用它来获取SQL表数据并将其转换为HTML。 这里的要点是,必须在实例化时将依赖项注入到应用程序中(类TsApp的实例)。 这是一种纯净的依赖注入机制,它绝对没有容器。 在“依赖注入容器是代码污染者”中阅读有关它的更多信息。

单元测试

由于每个类都是不可变的,并且所有依赖项仅通过构造函数注入,因此单元测试非常容易。 假设我们要测试TkStatus ,它应该返回HTML响应(我正在使用JUnit 4和Hamcrest ):

import org.junit.Test;
import org.hamcrest.MatcherAssert;
import org.hamcrest.Matchers;
public final class TkIndexTest {@Testpublic void returnsHtmlPage() throws Exception {MatcherAssert.assertThat(new RsPrint(new TkStatus().act()).printBody(),Matchers.equalsTo("<html>Hello, world!</html>"));}
}

此外,我们可以开始在测试HTTP服务器的整个应用程序或任何个人起飞 ,并通过一个真实的TCP套接字测试它的行为; 例如(我正在使用jcabi-http发出HTTP请求并检查输出):

public final class TkIndexTest {@Testpublic void returnsHtmlPage() throws Exception {new FtRemote(new TsFixed(new TkIndex())).exec(new FtRemote.Script() {@Overridepublic void exec(final URI home) throws IOException {new JdkRequest(home).fetch().as(RestResponse.class).assertStatus(HttpURLConnection.HTTP_OK).assertBody(Matchers.containsString("Hello, world!"));}});}
}

FtRemote在随机的TCP端口启动测试Web服务器,并在提供的FtRemote.Script实例上调用exec()方法。 此方法的第一个参数是刚启动的Web服务器主页的URI。

Takes框架的体系结构非常模块化且可组合。 任何个体可以进行测试作为一个独立的部件,绝对独立于框架和其他需要

为什么叫名字?

这就是我经常听到的问题。 这个想法很简单,它起源于电影业。 当影片制成,剧组芽许多需要以捕捉现实,把它放在电影。 每次捕获称为一次获取

换句话说, 拍摄就像现实的快照。

同样适用于此框架。 Take每个实例在某个特定时刻代表一个现实。 然后,将该现实以Response的形式发送给用户。

翻译自: https://www.javacodegeeks.com/2015/04/java-web-app-architecture-in-takes-framework.html

app访问java web

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

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

相关文章

电路中滤波电容和退耦电容_详解电源滤波电路中的高频滤波电容电路

图2-12所示是电源滤波电路中的高频滤波电路。电路中&#xff0c;一个容量很大的电解电容C1(2200F)与一个容量很小的电容C2(0.01F)并联&#xff0c;C2是高频滤波电容&#xff0c;用来进行高频成分的滤波&#xff0c;这种一大一小两个电容相并联的电路在电源电路中十分常见。1.高…

计算机驱动空间不够,Win8.1系统如何释放驱动器空间解决可用空间不足问题

现在越来越多用户安装升级win8.1系统&#xff0c;在操作使用过程中难免遇到一些奇奇怪怪的问题。相信有很多win8.1系统用户会遇到电脑的可用空间不足的提示&#xff0c;用户感到很疑惑&#xff0c;自己的电脑又没装什么软件怎么会这么提示。有什么办法可以解决此问题&#xff0…

C/C++ 中公认的三个难点

点击蓝字关注我们C语言在嵌入式学习中是必备的知识&#xff0c;审核大部分操作都要围绕C语言进行&#xff0c;而其中有三块“难啃的硬骨头”几乎是公认级别的。0x01 指针指针公认最难理解的概念&#xff0c;也是让很多初学者选择放弃的直接原因。指针之所以难理解&#xff0c;因…

python 字符串分割_如何使用python语言split方法对不同字符串分割

在JavaScript中&#xff0c;可以使用split()将字符串分割成字符串数组&#xff1b;而在python语言中&#xff0c;split()方法也可以将字符串进行分割&#xff0c;分割之后的结果放置在列表中。下面利用几个实例说明split()方法的用法&#xff0c;操作如下&#xff1a;工具/原料…

java 拼图_功能项目拼图将Java 9引入

java 拼图因此&#xff0c;拼图项目...我们已经对此颇为了解&#xff0c;但尚未看到计划如何兑现其承诺的细节。 这篇文章将精确地做到这一点&#xff0c;并介绍项目的核心概念和功能。 系列 这篇文章是正在进行的有关拼图项目系列的一部分。 按照推荐的顺序&#xff08;不同于…

win7 蓝牙4.0 ble驱动_初识物联网无线通信技术之蓝牙4.0BLE协议栈

[本文属原创&#xff0c;转载请附上原文出处链接。]一、需要的软件工具1、BLE协议栈(BLE-CC254x-1.4.0)2、IAR开发软件(IAR Embedded Workbench8.20.2)注&#xff1a;1.4.0协议栈使用8.20.2的iar版本&#xff0c;1.3.2协议栈等使用的是8.10.4的iar版本。二、BLE协议栈安装目录下…

C语言:谈谈指针!

点击蓝字关注我们指针对于C来说太重要。然而&#xff0c;想要全面理解指针&#xff0c;除了要对C语言有熟练的掌握外&#xff0c;还要有计算机硬件以及操作系统等方方面面的基本知识。所以本文尽可能的通过一篇文章完全讲解指针。为什么需要指针&#xff1f;指针解决了一些编程…

C/C++ 中的 #pragma once 作用是什么?

点击蓝字关注我们1、#pragma once有什么作用&#xff1f;为了避免同一个头文件被包含&#xff08;include&#xff09;多次&#xff0c;C/C中有两种宏实现方式&#xff1a;一种是#ifndef方式&#xff1b;另一种是#pragma once方式。在能够支持这两种方式的编译器上&#xff0c;…

python做大数据的框架_Python+大数据计算平台,PyODPS架构手把手教你搭建

原文链接&#xff1a;http://click.aliyun.com/m/13965/ 在2016年10月的云栖社区在线培训上&#xff0c;来自阿里云大数据事业部的秦续业分享了《双剑合壁——Python和大数据计算平台的结合实战》。他主要介绍了数据分析和机器学习的方法、DataFrame整体架构以及基础API、前端、…

武魂觉醒s系列服务器,[多线]星河斗罗——新服开荒丨高程度剧情还原丨3D坐骑丨魂环丨武魂觉醒[1.12.2]...

[服务器介绍]星河斗罗 全新原创开荒斗罗大陆服务器前言&#xff1a;超高还原小说真实性&#xff0c;独特的武魂贴图&#xff0c;魂兽建模&#xff0c;坐骑建模&#xff0c;开放性冒险地图&#xff0c;让您更加体验斗罗大陆的真实性。进服送新手大礼包&#xff1a;装备&#xff…

C++ 的万能头文件,你知道多少?

点击蓝字关注我们C 中万能头文件 bits/stdc.h 的介绍很多小伙伴估计看有的代码会碰见没有多余的其它头文件比如 algorithm、cmath、iostream 而是用了一行 #include<bits/stdc.h> 这样的头文件并感到诧异&#xff0c;想这是什么。其实这是一个包含了 C 所有头文件的一个头…

pytorch dataset读取数据流程_高效 PyTorch :如何消除训练瓶颈

加入极市专业CV交流群&#xff0c;与 10000来自港科大、北大、清华、中科院、CMU、腾讯、百度 等名校名企视觉开发者互动交流&#xff01;同时提供每月大咖直播分享、真实项目需求对接、干货资讯汇总&#xff0c;行业技术交流。关注 极市平台 公众号 &#xff0c;回复 加群&…

APP 文档服务器,app服务器

app服务器 内容精选换一换华为云帮助中心&#xff0c;为用户提供产品简介、价格说明、购买指南、用户指南、API参考、最佳实践、常见问题、视频帮助等技术文档&#xff0c;帮助您快速上手使用华为云服务。调用接口出错后&#xff0c;将不会返回结果数据。调用方可根据每个接口对…

需求最高的8种编程语言

点击蓝字关注我们在过去的 8 个月时间里&#xff08;从 2021 年 10 月到 2022 年 6 月&#xff09;&#xff0c;DevJobsScanner 分析了超过 700 万份开发者工作需求&#xff0c;得出了目前行业需求量最高的 8 种编程语言。需要注意的是&#xff0c;在这 700 万份工作需求中&…

java面包屑实现_在Java中实现过滤器和面包店锁

java面包屑实现为了了解锁的工作原理&#xff0c;实现自定义锁是一种好方法。 这篇文章将展示如何在Java上实现Filter和Bakery锁&#xff08;自旋锁&#xff09;&#xff0c;并将它们的性能与Java的ReentrantLock进行比较。 过滤器锁和面包房锁满足互斥并且也是无饥饿算法&…

postman 怎么调试pos_SpringBoot|第十五章:基于Postman的RESTful接口测试

前言从上一章节开始&#xff0c;接下来的几个章节会讲解一些开发过程中配套工具的使用。俗话说的好&#xff0c;工欲善其事&#xff0c;必先利其器。对于开发人员而言&#xff0c;有个好用的工具&#xff0c;也是一件事半功倍的事&#xff0c;而且开发起来也很爽&#xff0c;效…

这几个C语言关键字你真的得懂(深度解剖)

点击蓝字关注我们1、什么是语句&#xff0c;表达式&#xff1f; 在C语言中 &#xff0c;凡是以分号隔开的就是一条语句&#xff1a;printf("hello world\n");a 1 2; ; (空语句)什么是表达式呢&#xff1f;C语言中&#xff0c;用各种操作符把变量连起来&#xff0c;…

aws sqs_JMS和AWS SQS的更多高级内容

aws sqs如您所知&#xff0c; AWS中的SQS SQS代表“简单队列服务”。 最近&#xff0c;在使用它的同时&#xff0c;我发现了将其称为“简单”的原因之一。 在之前的两篇文章&#xff08; 此处和此处 &#xff09;中&#xff0c;我展示了结合Spring Framework将SQS用作JMS队列提…

python 直方图每个bin中的值_【Python数据分析】四级成绩分布 -matplotlib,xlrd 应用...

标签&#xff1a; 最近获得了一些四级成绩数据&#xff0c;大概500多个&#xff0c;于是突发奇想是否能够看看这些成绩数据是否满足所谓的正态分布呢&#xff1f;说干就干&#xff0c;于是有了这篇文章。 文章顺带介绍了xlrd模块的一些用法和matplotlib画自定义数据的条形图和随…

adf开发_了解ADF生命周期中的ADF绑定

adf开发在这篇文章中&#xff0c;我将重点介绍ADF绑定层&#xff0c;并探讨当最初从浏览器请求带有一些数据的ADF页面时它如何工作。 Oracle ADF提供了自己的JSF生命周期扩展版。 实际上&#xff0c;ADF扩展了标准的JSF生命周期实现类&#xff0c;并提供了ADF阶段侦听器&#…