外网进入学校内局域网建设的网站,wordpress 主题 h5,做app网站制作,国家工程建设信息公示网app访问java web我曾经利用Servlet#xff0c;JSP#xff0c;JAX-RS#xff0c;Spring框架#xff0c;Play框架#xff0c;带有Facelets的JSF和一些Spark框架。 以我的拙见#xff0c;所有这些解决方案都远非面向对象和优雅的。 它们都充满了静态方法#xff0c;不可测试… app访问java web 我曾经利用ServletJSPJAX-RSSpring框架Play框架带有Facelets的JSF和一些Spark框架。 以我的拙见所有这些解决方案都远非面向对象和优雅的。 它们都充满了静态方法不可测试的数据结构和肮脏的骇客。 因此大约一个月前我决定创建自己的Java Web框架。 我将一些基本原则纳入其基础1没有NULL2没有公共静态方法3没有可变的类以及4没有类的转换反射和instanceof运算符。 这四个基本原则应保证干净的代码和透明的体系结构。 这就是Takes框架的诞生方式。 让我们看看创建了什么以及它如何工作。 教父的制作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-age0
Accept: text/html,application/xhtmlxml,application/xml;q0.9,image/webp,*/*;q0.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;q0.8,ru;q0.6,uk;q0.4 客户端例如Google Chrome浏览器将此文本传递到已建立的连接中。 它连接到localhost端口8080一旦连接就绪它将立即将文本发送到其中然后等待响应。 我们的工作是使用在请求中获得的信息来创建HTTP响应。 如果我们的服务器非常原始那么我们基本上可以忽略请求中的所有信息而只需返回“ Helloworld”。 到所有请求为简单起见我使用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// localhost8080 您将看到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.1User-Agent: curl/7.37.1Host: localhost:8080Accept: */*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(); 基本上有两个步骤。 第一个是创建的一个实例Take从takes 而第二个是创建的实例Response从take 。 为什么这样做呢 主要是为了分开职责。 实例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();}
} 我们分别为Takes和Take使用这些Ts和Tk前缀。 您应该创建的第二个类是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 {IterableString head() throws IOException;InputStream body() throws IOException;
} 该请求分为两部分头部和身体。 根据RFC 2616中的 HTTP规范头部包含开始于正文的空行之前的所有行。 框架中有许多有用的装饰器用于Request 。 例如 RqMethod将帮助您从标题的第一行获取方法名称 final String method new RqMethod(request).method(); RqHref将帮助提取查询部分并进行解析。 例如这是请求 GET /user?id123 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的实例将其包装到一些有用的修饰符中并根据命令行参数进行配置。 例如-- --port8080将转换为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 version1.0?
project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersiongroupIdfoo/groupIdartifactIdfoo/artifactIdversion1.0-SNAPSHOT/versiondependenciesdependencygroupIdorg.takes/groupIdartifactIdtakes/artifactIdversion0.9/version !-- check the latest in Maven Central --/dependency/dependenciesbuildfinalNamefoo/finalNamepluginspluginartifactIdmaven-dependency-plugin/artifactIdexecutionsexecutiongoalsgoalcopy-dependencies/goal/goalsconfigurationoutputDirectory${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.encodingUTF-8 -cp ./target/foo.jar:./target/deps/* foo.Entry --port8080 该应用程序已准备就绪您可以将其部署到Heroku。 只需在存储库的根目录中创建一个Procfile文件然后将存储库推送到Heroku。 这是Procfile外观 web: java -Dfile.encodingUTF-8 -cp target/foo.jar:target/deps/* foo.Entry --port${PORT}叉车 这个TsFork类似乎是框架的核心元素之一。 它有助于路线传入的HTTP请求到右收 。 它的逻辑非常简单里面只有几行代码。 它封装了“ forks”的集合它们是ForkTake接口的实例 public interface ForkT {IteratorT 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 IteratorTake route(Request req) {final CollectionTake 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?fxml 则将返回TkStatusXML的实例。 HTTP响应 现在让我们讨论HTTP响应的结构及其面向对象的抽象Response 。 界面外观如下 public interface Response {IterableString 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(htmlHello, world!/html),text/html),200);}
} 在此示例中装饰器RsWithBody创建一个带有主体但没有头的响应。 然后 RsWithType添加标题Content-Type: text/html 。 然后 RsWithStatus确保响应的第一行包含HTTP/1.1 200 OK 。 您可以创建自己的装饰器以重用现有的装饰器。 看看RsPage在RsPage是如何完成的。 模板如何 如我们所见返回简单的“ Helloworld”页面不是什么大问题。 但是诸如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(htmlHello, 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.htmlapp访问java web