Äú¿ÉÒÔ¾èÖú£¬Ö§³ÖÎÒÃǵĹ«ÒæÊÂÒµ¡£

1Ôª 10Ôª 50Ôª





ÈÏÖ¤Â룺  ÑéÖ¤Âë,¿´²»Çå³þ?Çëµã»÷Ë¢ÐÂÑéÖ¤Âë ±ØÌî



  ÇóÖª ÎÄÕ ÎÄ¿â Lib ÊÓÆµ iPerson ¿Î³Ì ÈÏÖ¤ ×Éѯ ¹¤¾ß ½²×ù Modeler   Code  
»áÔ±   
 
   
 
 
     
   
 ¶©ÔÄ
  ¾èÖú
×Ô¼º±àдJava Web¿ò¼Ü£ºTakes¿ò¼ÜµÄWeb App¼Ü¹¹
 
ÒëÕߣº¹â»ÔÓÂÊ¿ À´Ô´£ºNetty project ·¢²¼ÓÚ 2015-7-1
  2619  次浏览      27
 

ÎÒÓùýServlets¡¢JSP¡¢JAX-RS¡¢ Spring¿ò¼Ü¡¢Play¿ò¼Ü¡¢´øFaceletsµÄJSFÒÔ¼°Spark Framework¡£ÔÚÎÒ¿´À´£¬ÕâЩ¿ò¼Ü²¢Ã»ÓкܺõØÊµÏÖÃæÏò¶ÔÏóÉè¼Æ¡£ËüÃdzä³âמ²Ì¬·½·¨¡¢Î´¾­²âÊÔµÄÊý¾Ý½á¹¹ÒÔ¼°²»¹»ÃÀ¹ÛµÄ½â¾ö·½Ê½¡£Òò´ËÒ»¸öÔÂǰÎÒ¾ö¶¨¿ªÊ¼±àд×Ô¼ºµÄJava Web¿ò¼Ü£¬ÎÒÖÆ¶¨ÁËһЩ»ù±¾µÄÐÅÌõ£º1) ûÓÐNULL£¬2) ûÓÐpublic static·½·¨£¬3) ûÓпɱäÀࣨmutable class£©£¬4) ûÓÐÀàÐÍת»»¡¢·´ÉäºÍinstanceof²Ù×÷¡£ÕâËÄÌõ»ù±¾×¼ÔòÓ¦¸Ã×ã¹»±£Ö¤¸É¾»µÄ´úÂëºÍ͸Ã÷µÄ¼Ü¹¹¡£Õâ¾ÍÊÇTakes¿ò¼Üµ®ÉúµÄÔ­Òò¡£ÈÃÎÒÃÇ¿´¿´ÕâÊÇÈçºÎʵÏֵġ£

Java Web¼Ü¹¹¼ò½é

¼òµ¥À´Ëµ£¬Õâ¾ÍÊÇÎÒ¶ÔÒ»¸öWebÓ¦Óüܹ¹ÒÔ¼°Æä×é¼þµÄÀí½â¡£

Ê×ÏÈ£¬Òª´´½¨Ò»¸öWeb·þÎñÆ÷£¬ÎÒÃÇÓ¦¸Ãд´½¨Ò»¸öÍøÂçÌ×½Ó×Ö£¨socket£©£¬Æä½«»áÔÚÌØ¶¨µÄ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·þÎñÆ÷¡£ÏÖÔÚ£¬socketÒѾ­¾ÍÐ÷¼àÌý8080¶Ë¿Ú¡£µ±ÓÐÈËÔÚä¯ÀÀÆ÷´ò¿ª http://localhost:8080 £¬½«»á½¨Á¢Á¬½Ó²¢ÇҵȴýµÄ³ÝÂÖÔÚä¯ÀÀÆ÷Éϲ»Í£µÄÐýת¡£±àÒëÕâЩƬ¶ÎÊÔһϡ£ÎÒÃǸոÕûÓÐʹÓÃÈκοò¼Ü´î½¨ÁËÒ»¸ö¼òµ¥µÄWeb·þÎñÆ÷¡£ÎÒÃDz¢Ã»ÓжԽøÈëµÄÁ¬½Ó×öÈκÎÊÂÇ飬µ«ÊÇҲûÓоܾøËüÃÇ¡£ËùÓеÄÁ¬½Ó¶¼ÕýÔÚ·þÎñÆ÷¶ÔÏóÄÚ²¿ÅŶӡ£ÕâЩÔÚºǫ́Ïß³ÌÖÐÍê³É£¬Õâ¾ÍÊÇΪʲôÐèÒªÔÚ×îºó·ÅÒ»¸ö while(true) µÄÔ­Òò¡£Ã»ÓÐÕâ¸öÎÞÏÞÑ­»·£¬Ó¦Óý«»áÁ¢¼´ÖÕÖ¹²Ù×÷²¢ÇÒ·þÎñÆ÷Ì×½Ó×Ö½«»á¹Ø±Õ¡£

ÏÂÒ»²½ÊǽÓÊܽøÈëµÄÁ¬½Ó¡£ÔÚJavaÖУ¬Í¨¹ý¶Ô accept() ·½·¨µÄ×èÈûµ÷ÓÃÀ´Íê³É¡£

final Socket socket = server.accept();

Õâ¸ö·½·¨½«»áÒ»Ö±×èÈûÏ̵߳ȴýÖ±µ½Ò»¸öеÄÁ¬½Óµ½´ï¡£ÐÂÁ¬½ÓÒ»·¢Éú£¬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

¿Í»§¶Ë£¨ÀýÈç¹È¸èµÄChromeä¯ÀÀÆ÷£©°ÑÕâЩÎı¾´«¸øÒѽ¨Á¢µÄÁ¬½Ó¡£ËüÁ¬½Ó±¾µØµÄ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();

»ù±¾ÉÏÓÐÁ½²½¡£µÚÒ»²½´Ótakes´´½¨TakeµÄʵÀý£¬µÚ¶þ²½´Ótakes´´½¨ÏìÓ¦µÄʵÀý¡£ÎªÊ²Ã´²ÉÓÃÕâÖÖ·½Ê½£¿Ö÷ÒªÊÇΪÁË·ÖÀëÔðÈΡ£TakesµÄʵÀý¸ºÔð·Ö·¢ÇëÇó²¢ÇÒ³õʼ»¯ÕýÈ·µÄTake£¬TakeµÄʵÀý¸ºÔð´´½¨ÏìÓ¦¡£
ÓÃTakes´´½¨Ò»¸ö¼òµ¥µÄÓ¦Óã¬ÄãÓ¦¸Ã´´½¨Á½¸öÀà¡£Ê×ÏÈ£¬Ò»¸öʵÏÖTakes½Ó¿ÚµÄÀࣺ

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

ÎÒÃÇ·Ö±ðÓÃTsºÍTkµÄǰ׺´ú±íTakesºÍTake¡£µÚ¶þ¸öÄãÓ¦¸Ã´´½¨µÄÀ࣬һ¸öʵÏÖTake½Ó¿ÚµÄÀࣺ

import org.takes.Take;
import org.takes.Response;
import org.takes.rs.RsText;
public final class TkFoo implements Take {
@Override
public 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ÀàÕýÊÇʵÏÖÁËÉÏÃæ½âÊ͹ýµÄºÍsocketÒ»ÑùµÄ²Ù×÷¡£ËüÔÚ¶Ë¿Ú8080ÉÏÆô¶¯Ò»¸ö·þÎñÆ÷¶ËµÄsocket£¬Í¨¹ý´«¸ø¹¹Ô캯ÊýTsFooʵÀýÀ´·Ö·¢ËùÓнøÈëµÄÁ¬½Ó¡£ËüÔÚÒ»¸öÎÞÏÞÑ­»·ÖÐÍê³É·Ö·¢£¬ÓÃExitʵÀýÿÃë¼ì²éÊÇ·ñÊÇʱºòÍ£Ö¹¡£ÏÔÈ»£¬Exit.NEVER×ÜÊÇ·µ»Ø¡°Ç벻Ҫֹͣ¡±¡£

HTTPÇëÇó

ÏÖÔÚÈÃÎÒÃÇÀ´Á˽âһϵ½´ïTsFooµÄHTTPÇëÇóÄÚ²¿¶¼ÓÐʲô£¬ÎÒÃÇÄÜ´ÓÇëÇóÖеõ½Ê²Ã´¡£ÏÂÃæÊÇÔÚTakesÖж¨ÒåµÄRequest½Ó¿Ú£º

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

ÇëÇó·ÖΪÁ½²¿·Ö£ºÍ·²¿ºÍÕýÎÄ¡£¸ù¾ÝRFC 2616ÖÐHTTP¹æ·¶£¬Í·²¿°üº¬ÓÃÀ´¿ªÊ¼ÕýÎĵĿÕÐÐǰµÄËùÓеÄÐС£¿ò¼ÜÖÐÓкܶàÓÐÓõÄÇëÇó×°ÊÎÆ÷¡£ÀýÈ磬RqMethod¿ÉÒÔ°ïÖú´ÓÍ·²¿µÚÒ»ÐÐÈ¡µ½·½·¨Ãû¡£

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

RqHrefÓÃÀ´°ïÖúÌáÈ¡²éѯ²¿·Ö²¢ÇÒ½øÐнâÎö¡£ÀýÈ磬ÏÂÃæÊÇÒ»¸öÇëÇó£º

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

´úÂ뽫»áÌáÈ¡µÃµ½¡°123¡±£º

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

RqPrint¿ÉÒÔ»ñÈ¡Õû¸öÇëÇó»òÕßÕýÎÄ£¬×÷Ϊ×Ö·û´®´òÓ¡³öÀ´£º

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

ÕâÀïµÄÏë·¨ÊDZ£³ÖÇëÇó½Ó¿Ú¼òµ¥£¬²¢ÇÒÓÃ×°ÊÎÆ÷Ìṩ½âÎöÇëÇóµÄ¹¦ÄÜ¡£Ã¿Ò»¸ö×°ÊÎÆ÷¶¼·Ç³£Ð¡ÇÉÎȶ¨£¬Ö»ÓÃÀ´Íê³ÉÒ»¼þÊ¡£ËùÓÐÕâЩװÊÎÆ÷¶¼ÔÚ¡°org.takes.rq¡±°üÖС£Äã¿ÉÄÜÒѾ­Àí½â£¬¡°Rq¡±Ç°×º´ú±íÇëÇó£¨Request£©¡£

µÚÒ»¸öÕæÕýµÄWebÓ¦ÓÃ

ÈÃÎÒÃÇ´´½¨ÎÒÃǵÚÒ»¸öÕæÕýÒâÒåÉϵÄWebÓ¦Óã¬Ëü½«»á×öһЩÓÐÒâÒåµÄÊÂÇé¡£ÎÒÍÆ¼öÒÔÒ»¸öEntryÀ࿪ʼ¡£¶ÔJavaÀ´Ëµ£¬´ÓÃüÁîÐÐÆô¶¯Ò»¸öÓ¦ÓÃÊDZØÐëµÄ¡£

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£¨·­Òë³É¡°front-end with command line interface¡±¼´¡°´øÃüÁîÐнӿڵÄǰ¶Ë¡±£©´´½¨ÁËFtBasicµÄʵÀý£¬ÓÃһЩÓÐÓõÄ×°ÊÎÆ÷¶ÔËü½øÐаü×°²¢¸ù¾ÝÃüÁîÐвÎÊýÅäÖá£ÀýÈ磬¡°¨Cport=8080¡±½«»áת»»³É8080¶Ë¿ÚºÅ²¢±»µ±×ö FtBasic ¹¹Ô캯ÊýµÄµÚ¶þ¸ö²ÎÊý´«Èë¡£

webÓ¦Óñ¾Éí¼Ì³ÐTsWrap£¬½Ð×öTsApp£º

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¡£ÔÚ²Ö¿âµÄ¸ùĿ¼Ï´´½¨Ò»¸öProfileÎļþ£¬È»ºó°Ñ²Ö¿âÍÆÈëHeroku¡£ÏÂÃæÊÇProfileµÄÄÚÈÝ£º

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

TsFork

TsForkÀà¿´ÉÏÈ¥ÊÇÆäÖÐÒ»¸ö¿ò¼ÜºËÐÄÔªËØ¡£Ëü½«½øÈëµÄHTTPÇëÇó·Óɵ½ÕýÈ·µÄ¡°take¡±¡£ËüµÄÂß¼­·Ç³£µÄ¼òµ¥£¬´úÂëÒ²Ö»ÓÐÉÙÁ¿ÐС£Ëü·â×°ÁË¡°forks¡±µÄÒ»¸ö¼¯ºÏ£¬¡°forks¡±ÊÇFork<Take>½Ó¿ÚµÄʵÀý¡£

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

½öÓÐµÄ route() ·½·¨·µ»Ø¿Õµü´úÆ÷»òÕߺ¬Óе¥¸ötakeµÄµü´úÆ÷¡£TsFork±éÀúËùÓеÄforks£¬µ÷ÓÃËüÃÇµÄ route() ·½·¨Ö±µ½ÆäÖÐÒ»¸ö·µ»Øtake¡£Ò»µ©·¢Éú£¬TsFork»á°ÑÕâ¸ötake·µ»Ø¸øµ÷ÓÃÕߣ¬¼´ FtBasic¡£

ÏÖÔÚÎÒÃÇ×Ô¼ºÀ´´´½¨Ò»¸ö¼òµ¥µÄfork¡£ÀýÈ磬µ±ÇëÇóURL¡°/status¡±Ê±£¬ÎÒÃÇÏëչʾӦÓõÄ״̬¡£ÒÔÏÂÊÇ´úÂëʵÏÖ£º

final class TsApp extends TsWrap {
private static Takes make() {
return new TsFork(
new Fork.AtTake() {
@Override
public 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½«³¢ÊÔÔÚ¼¯ºÏÖÐѰÕÒÁíÒ»¸öÕâÑùµÄfork£¬Ëü¿ÉÒÔ»ñµÃTakeµÄʵÀý´Ó¶ø½øÐÐÏìÓ¦¡£Ë³±ãÌáһϣ¬Èç¹ûʲôҲû·¢ÏÖËùÓеÄforks·µ»Ø¿Õµü´úÆ÷£¬ÄÇôTsFork½«Å׳ö¡°Page not found¡±µÄÒì³£¡£

ÕâÑùµÄÂß¼­Í¨¹ý½Ð×öFkRegexµÄ¿ªÏä¼´ÓÃforkʵÏÖ£¬³¢ÊÔÓÃÌṩµÄͨÓñí´ïʽȥƥÅäÇëÇóµÄ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())
)
)
);
}
}

Again, I believe it¡¯s obvious. The instance of FkRegex will ask an encapsulated instance of TsFork to return a take, and it will try to fetch it from one that FkParams encapsulated. If the HTTP query is /status?f=xml, an instance of TkStatusXML will be returned.

ÎÒÏàÐÅÂß¼­ÊǺÜÇåÎúµÄ¡£FkRegexµÄʵÀý½«»áÒªÇóTsForkµÄ·âװʵÀý·µ»ØÒ»¸ötake£¬²¢ÇÒËü»á³¢ÊÔ´ÓFkParams·â×°µÄʵÀýÖлñÈ¡¡£

HTTPÏìÓ¦

ÏÖÔÚÈÃÎÒÃÇÌÖÂÛHTTPÏìÓ¦µÄ½á¹¹ÒÔ¼°ËüµÄÃæÏò¶ÔÏóµÄ³éÏ󡪡ª Response¡£ÒÔÏÂÊǽӿڵ͍Ò壺

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

ºÍRequest¿´ÆðÀ´·Ç³£ÀàËÆ£¬ÊDz»ÊÇ£¿ºÃ°É£¬ËüÊÇÏàͬµÄ¡£ÒòΪHTTPÇëÇóºÍÏìÓ¦µÄ½á¹¹¼¸ºõÊÇÏàͬµÄ£¬Î¨Ò»µÄÇø±ðÖ»ÊǵÚÒ»ÐС£ÓкܶàÓÐÓõÄ×°ÊÎÆ÷°ïÖú¹¹½¨ÏìÓ¦¡£ËûÃÇÊÇ×é¼þ»¯µÄ£¬ÕâʹµÃʹÓÃÆðÀ´·Ç³£·½±ã¡£ÀýÈ磬Èç¹ûÄãÏë¹¹½¨Ò»¸ö°üº¬HTMLÒ³ÃæµÄÏìÓ¦£¬Äã¿ÉÒÔÕâÑù×ö£º

final class TkIndex implements Take {
@Override
public 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¡±¡£

Äã¿ÉÒÔ¸´ÓÃÒÑÓеÄ×°ÊÎÆ÷À´´´½¨×Ô¼ºµÄ×°ÊÎÆ÷¡£¿ÉÒÔ¿´¿´ rultor.com ÉÏ RsPage ÈçºÎ×Ô¶¨Òå×°ÊÎÆ÷¡£

ÈçºÎʹÓÃÄ£°å£¿

ÈçÄãËù¼û£¬·µ»Ø¼òµ¥µÄ¡°Hello, world¡±Ò³Ãæ²¢²»ÊÇÒ»¸ö´óÎÊÌâ¡£µ«ÊÇ·µ»Ø¸ü¸´ÔÓµÄÊä³öÀýÈçHTMLÒ³Ãæ¡¢XMLÎĵµ¡¢JSONÊý¾Ý¼¯£¬ÓÖ¸ÃÔõô°ì£¿ÈÃÎÒÃÇ´ÓÒ»¸ö¼òµ¥µÄÄ£°åÒýÇæ¡°Velocity¡±¿ªÊ¼¡£ºÃ°É£¬ÆäʵËü²¢²»¼òµ¥¡£ËüÏ൱ǿ´ó£¬µ«ÊÇÎÒÖ»½¨ÒéÔÚ¼òµ¥ÇéÐÎÏÂʹÓá£ÏÂÃæÊǹØÓÚËüÈçºÎ¹¤×÷£º

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

RsVelocity ¹¹ÔìÆ÷½ÓÊÜVelocityÄ£°å×÷ΪΨһ²ÎÊý¡£È»ºó£¬Äã¿ÉÒÔµ÷Óá°with()¡±·½·¨£¬ÍùVelocityÉÏÏÂÎÄ×¢ÈëÊý¾Ý¡£µ±µ½äÖȾHTTPÏìÓ¦µÄʱºò£¬RsVelocity ½«»á½«Ä£°åºÍÅäÖõÄÉÏÏÂÎĽøÐС°ÆÀ¹À¡±¡£ÔÙ´ÎÇ¿µ÷£¬ÎÒÖ»ÍÆ¼öÔڷdz£¼òµ¥µÄÊä³öʱʹÓÃÕâÖÖÄ£°å·½Ê½¡£

¶ÔÓÚ¸ü¸´ÔÓµÄHTMLÎĵµ£¬ÎÒ½«ÍƼöÄãʹÓýáºÏXemblyʹÓÃXML/XSLT¡£ÔÚÏÈǰµÄ¼¸Æª²©¿ÍÖÐÎÒ½âÊÍÁËÕâÖÖÏë·¨£¬XML+XSLT in a Browser ºÍRESTful API and a Web Site in the Same URL¡£ÕâÖÖ·½Ê½¼òµ¥Ç¿´ó¡ª¡ªÓÃJavaÉú³ÉXML£¬XSLT ´¦ÀíÆ÷½«Æäת»»³ÉHTMLÎĵµ¡£Õâ¾ÍÊÇÎÒÃÇÈçºÎ·ÖÀë±íʾºÍÊý¾Ý¡£ÔÚMVCÀ´¿´£¬XSLÑùʽ±íÊÇÒ»¸ö¡°ÊÓͼ¡±£¬TkIndex ÊÇÒ»¸ö¡°¿ØÖÆÆ÷¡±¡£

²»¾ÃÎһᵥ¶ÀдһƪÎÄÕÂÀ´½éÉÜʹÓÃXemblyºÍXSLÄ£°åÉú³ÉÒ³Ãæ¡£

ͬʱ£¬ÎÒ»áÔÚTakes¿ò¼ÜÖÐΪ JSF/Facelets ºÍ JSP äÖȾ´´½¨×°ÊÎÆ÷¡£Èç¹ûÄã¶ÔÕⲿ·Ö¹¤×÷¸ÐÐËȤ£¬ÇëforkÕâ¸ö¿ò¼Ü²¢Ìá½»ÄãµÄpullÇëÇó¡£

ÈçºÎ³Ö¾Ã»¯£¿

ÏÖÔÚ£¬Ò»¸öÎÊÌâ¾Í³öÀ´ÁË¡£ÈçºÎ´¦ÀíÖîÈçÊý¾Ý¿â¡¢ÄÚ´æ½á¹¹¡¢ÍøÂçÁ¬½ÓÖ®ÀàµÄ³Ö¾Ã²ãʵÌ壿ÎҵĽ¨ÒéÊÇÔÚEntryÀàÖÐʵÀý»¯ËüÃÇ£¬²¢°ÑËüÃÇ×÷Ϊ²ÎÊý´«ÈëTsAppµÄ¹¹Ô캯ÊýÖС£È»ºó£¬TsApp½«»á°ÑËüÃÇ´«Èë×Ô¶¨ÒåµÄ¡°takes¡±µÄ¹¹Ô캯ÊýÖС£

ÀýÈ磬ÎÒÃÇÓÐÒ»¸ö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µÄ¹¹ÔìÆ÷±ØÐë½ÓÊÜÒ»¸ö¡°java.sql.Source¡±ÀàÐ͵IJÎÊý£º

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ÀàÐ͵IJÎÊý¡£ÎªÁËÈ¡SQL±íÊý¾Ý²¢°ÑËüת»»³ÉHTML£¬ÏàÐÅÄãÖªµÀTkIndexÄÚ²¿ÈçºÎ´¦ÀíµÄ¡£ÕâÀïµÄ¹Ø¼üµãÊÇÔÚÓ¦Óã¨TsAppÀàµÄʵÀý£©³õʼ»¯Ê±±ØÐë×¢ÈëÒÀÀµ¡£ÕâÊÇ´¿´â¸É¾»µÄÒÀÀµ×¢Èë»úÖÆ£¬ÍêÈ«ÎÞÐèÈκÎÈÝÆ÷¡£¸ü¶àÏà¹ØÔĶÁÇë²ÎÔÄ¡°Dependency Injection Containers Are Code Polluters¡±¡£

µ¥Ôª²âÊÔ

ÒòΪÿ¸öÀàÊDz»¿É±äµÄ²¢ÇÒËùÓеÄÒÀÀµ¶¼ÊÇͨ¹ý¹¹Ô캯Êý×¢È룬ËùÒÔµ¥Ôª²âÊԷdz£¼òµ¥¡£±ÈÈçÎÒÃÇÏë²âÊÔ¡°TkStatus¡±£¬¼Ù¶¨Ëü½«»á·µ»ØÒ»¸öHTMLÏìÓ¦£¨ÎÒʹÓÃJUnit 4 ºÍHamcrest£©£º

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

ͬÑù£¬ÎÒÃÇ¿ÉÒÔÔÚÒ»¸ö²âÊÔHTTP·þÎñÆ÷ÖÐÆô¶¯Õû¸öÓ¦ÓûòÕßÈκÎÒ»¸öµ¥¶ÀµÄ¡°take¡±£¬È»ºóͨ¹ýÕæÊµµÄTCPÌ×½Ó×Ö²âÊÔËüµÄÐÐΪ£»ÀýÈ磨ÎÒʹÓÃjcabi-http¹¹ÔìHTTPÇëÇó²¢ÇÒ¼ì²âÊä³ö£©£º

public final class TkIndexTest {
@Test
public void returnsHtmlPage() throws Exception {
new FtRemote(new TsFixed(new TkIndex())).exec(
new FtRemote.Script() {
@Override
public 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¡±¶¼¿ÉÒÔ×÷Ϊһ¸öµ¥¶ÀµÄ×é¼þ±»²âÊÔ£¬¾ø¶Ô¶ÀÁ¢ÓÚ¿ò¼ÜºÍÆäËü¡°takes¡±¡£

Ϊʲô½ÐÕâ¸öÃû×Ö£¿

ÕâÊÇÎÒÌýµ½×îÆµ·±µÄÎÊÌâ¡£Ïë·¨ºÜ¼òµ¥£¬ËüºÍµçÓ°Óйء£µ±ÖÆ×÷Ò»²¿µçӰʱ£¬¹¤×÷ÈËԱΪÁ˲¶×½ÏÖʵ»áÅÄÉãºÜ¶à¾µÍ·È»ºó·ÅÈëµçÓ°ÖС£Ã¿Ò»¸öÅÄÉã³Æ×÷Ò»¸ö¾µÍ·£¨take£©¡£

»»¾ä»°Ëµ£¬Ò»¸ö¾µÍ·¾ÍÏñÏÖʵµÄÒ»¸ö¿ìÕÕ¡£Ã¿Ò»¸ö¾µÍ·ÊµÀý´ú±íÌØ¶¨Ê±¿ÌµÄÒ»¸öÊÂʵ¡£Õâ¸öÊÂʵȻºóÒÔÏìÓ¦µÄÐÎʽ·¢Ë͸øÓû§¡£

ͬÑùµÄµÀÀíÒ²ÊÊÓÃÓÚ¿ò¼Ü¡£Ã¿¸öTakeʵÀý¶¼´ú±í×ÅÌØ¶¨Ä³¸öʱ¿ÌµÄÕæÊµ´æÔÚ¡£Õâ¸öÐÅÏ¢»áÒÔResponseÐÎʽ·¢ËÍ¡£

   
2619 ´Îä¯ÀÀ       27
Ïà¹ØÎÄÕÂ

Java΢·þÎñÐÂÉú´úÖ®Nacos
ÉîÈëÀí½âJavaÖеÄÈÝÆ÷
JavaÈÝÆ÷Ïê½â
Java´úÂëÖÊÁ¿¼ì²é¹¤¾ß¼°Ê¹Óð¸Àý
Ïà¹ØÎĵµ

JavaÐÔÄÜÓÅ»¯
Spring¿ò¼Ü
SSM¿ò¼Ü¼òµ¥¼òÉÜ
´ÓÁ㿪ʼѧjava±à³Ì¾­µä
Ïà¹Ø¿Î³Ì

¸ßÐÔÄÜJava±à³ÌÓëϵͳÐÔÄÜÓÅ»¯
JavaEE¼Ü¹¹¡¢ Éè¼ÆÄ£Ê½¼°ÐÔÄܵ÷ÓÅ
Java±à³Ì»ù´¡µ½Ó¦Óÿª·¢
JAVAÐéÄâ»úÔ­ÀíÆÊÎö
×îл¼Æ»®
DeepSeekÔÚÈí¼þ²âÊÔÓ¦ÓÃʵ¼ù 4-12[ÔÚÏß]
DeepSeek´óÄ£ÐÍÓ¦Óÿª·¢Êµ¼ù 4-19[ÔÚÏß]
UAF¼Ü¹¹ÌåϵÓëʵ¼ù 4-11[±±¾©]
AIÖÇÄÜ»¯Èí¼þ²âÊÔ·½·¨Óëʵ¼ù 5-23[ÉϺ£]
»ùÓÚ UML ºÍEA½øÐзÖÎöÉè¼Æ 4-26[±±¾©]
ÒµÎñ¼Ü¹¹Éè¼ÆÓ뽨ģ 4-18[±±¾©]

Java ÖеÄÖÐÎıàÂëÎÊÌâ
Java»ù´¡ÖªÊ¶µÄÈýÊ®¸ö¾­µäÎÊ´ð
Íæ×ª Java Web Ó¦Óÿª·¢
ʹÓÃSpring¸üºÃµØ´¦ÀíStruts
ÓÃEclipse¿ª·¢iPhone WebÓ¦ÓÃ
²å¼þϵͳ¿ò¼Ü·ÖÎö

Struts+Spring+Hibernate
»ùÓÚJ2EEµÄWeb 2.0Ó¦Óÿª·¢
J2EEÉè¼ÆÄ£Ê½ºÍÐÔÄܵ÷ÓÅ
Java EE 5ÆóÒµ¼¶¼Ü¹¹Éè¼Æ
Javaµ¥Ôª²âÊÔ·½·¨Óë¼¼Êõ
Java±à³Ì·½·¨Óë¼¼Êõ

Struts+Spring+Hibernate/EJB+ÐÔÄÜÓÅ»¯
»ªÏÄ»ù½ð ActiveMQ Ô­ÀíÓë¹ÜÀí
ijÃñº½¹«Ë¾ Java»ù´¡±à³Ìµ½Ó¦Óÿª·¢
ij·çµç¹«Ë¾ Java Ó¦Óÿª·¢Æ½Ì¨ÓëÇ¨ÒÆ
ÈÕÕÕ¸Û J2EEÓ¦Óÿª·¢¼¼Êõ¿ò¼ÜÓëʵ¼ù
ij¿ç¹ú¹«Ë¾ ¹¤×÷Á÷¹ÜÀíJBPM
¶«·½º½¿Õ¹«Ë¾ ¸ß¼¶J2EE¼°ÆäÇ°ÑØ¼¼Êõ