上篇博客中我们建立了一个注解类C
和一个使用者类DemoC
,还记得DemoC
类中的helloString()
方法吗?对,你们猜的不错,接下来我们要做的就是访问DemoC
的helloString
方法。
在普通的Servlet中,要请求到服务端,服务端必需做一些Servlet让我们做的工作:编写Servlet子类并注册它。即使Spring/Struts这样的框架也得按套路出牌,因为它们都是对Servlet的封装。当然,我们也不例外。额外说一点的是,Spring在web.xml中注册的是Servlet,而Struts2在web.xml中注册的是Filter。我们采用Servlet方式。
我们新建一个Servlet,名为TransServlet
,按照约定,它应该在包com.billy.jee.framework.servlet
下,即它的全限定名是
com.billy.jee.framework.servlet.TransServlet
它的初始代码如下:
package com.billy.jee.framework.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class TransServlet extends HttpServlet {
/** */
private static final long serialVersionUID = 8719005417117579209L;
@Override
protected void service(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
System.out.print(System.currentTimeMillis());
}
}
需要注意的是,我们并没有重写doGet()
或doPost()
方法而是直接重写了service()
方法,因为一个请求是先到达service()方法,处理后再分发到相应的方法如doGet()、doPost()、doPut()、doHead()、doTrace()等方法。 我们在service()方法里输出当前时间毫秒数,仅此而已。
接着我们就在把这个TransServlet注册到web.xml中,代码如下:
<servlet>
<servlet-name>transServlet</servlet-name>
<servlet-class>com.billy.jee.framework.servlet.TransServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>transServlet</servlet-name>
<url-pattern>*.ts</url-pattern>
</servlet-mapping>
从配置中可以看到,我们注册了TransServlet并将它的servlet-name配置成transServlet,并将请求路径配置成*.ts。
配置完成之后,我们就要访问这个服务端应用了。我们可以使用tomcat或Resin或GlassFish来部署这个web工程,为方便测试与调试,我在此处选择了jetty。
要使用jetty,我们需要在pom.xml中做一些配置。请回顾一下博客四中的pom.xml文件,我们在dependencies
节点下添加了两个依赖dependency
(依赖可以理解成classpath下的jar包),即junit和servlet-api,这里我们添加jetty的依赖,如下(请确保如下代码在dependencies节点下):
<dependency>
<groupId>org.eclipse.jetty.aggregate</groupId>
<artifactId>jetty-all-server</artifactId>
<version>7.6.1.v20120215</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-jsp</artifactId>
<version>7.6.1.v20120215</version>
</dependency>
此处我们要添加一个JettyServerStart工具类,代码较长,如下:
package com.billy.jee.framework.util;
import java.io.File;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.net.DatagramSocket;
import java.net.ServerSocket;
import java.util.ArrayList;
import java.util.List;
import javax.management.MBeanServer;
import org.eclipse.jetty.jmx.MBeanContainer;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.Scanner;
import org.eclipse.jetty.webapp.WebAppContext;
public class JettyServerStart {
private int port;
private String context;
private String webappPath;
private int scanIntervalSeconds;
private boolean jmxEnabled;
private Server server;
private WebAppContext webapp;
public JettyServerStart(String webappPath, int port, String context) {
this(webappPath, port, context, 0, false);
}
public JettyServerStart(String webappPath, int port, String context, int scanIntervalSeconds, boolean jmxEnabled) {
this.webappPath = webappPath;
this.port = port;
this.context = context;
this.scanIntervalSeconds = scanIntervalSeconds;
this.jmxEnabled = jmxEnabled;
validateConfig();
}
private void validateConfig() {
if (port < 0 || port > 65536) {
throw new IllegalArgumentException("Invalid port of web server: " + port);
}
if (context == null) {
throw new IllegalStateException("Invalid context of web server: " + context);
}
if (webappPath == null) {
throw new IllegalStateException("Invalid context of web server: " + webappPath);
}
}
public void start() {
if (server == null || server.isStopped()) {
try {
doStart();
} catch (Throwable e) {
e.printStackTrace();
System.err.println("System.exit() ......");
System.exit(1);
}
} else {
throw new RuntimeException("Jetty Server already started.");
}
}
private void doStart() throws Throwable {
if (!portAvailable(port)) {
throw new IllegalStateException("port: " + port + " already in use!");
}
System.setProperty("org.eclipse.jetty.util.URI.charset", "UTF-8");
System.setProperty("org.eclipse.jetty.util.log.class", "org.eclipse.jetty.util.log.Slf4jLog");
System.setProperty("org.eclipse.jetty.server.Request.maxFormContentSize", "20000000");
server = new Server(port);
server.setHandler(getHandler());
if (jmxEnabled) {
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
MBeanContainer mBeanContainer = new MBeanContainer(mBeanServer);
server.addBean(mBeanContainer);
}
if (scanIntervalSeconds > 0) {
startFileWatchScanner();
}
long ts = System.currentTimeMillis();
server.start();
ts = System.currentTimeMillis() - ts;
System.err.println("Jetty Server started: " + String.format("%.2f sec", ts / 1000d));
server.join();
}
protected Handler getHandler(){
webapp = new WebAppContext(webappPath, context);
return webapp;
}
private void startFileWatchScanner() throws Exception {
List<File> scanList = new ArrayList<File>();
scanList.add(new File(webappPath, "WEB-INF"));
Scanner scanner = new Scanner();
scanner.setReportExistingFilesOnStartup(false);
scanner.setScanInterval(scanIntervalSeconds);
scanner.setScanDirs(scanList);
scanner.addListener(new Scanner.BulkListener() {
@SuppressWarnings("rawtypes")
public void filesChanged(List changes) {
try {
System.err.println("Loading changes ......");
webapp.stop();
webapp.start();
System.err.println("Loading complete.\n");
} catch (Exception e) {
System.err.println("Error reconfiguring/restarting webapp after change in watched files");
e.printStackTrace();
}
}
});
System.err.println("Starting scanner at interval of " + scanIntervalSeconds + " seconds.");
scanner.start();
}
private static boolean portAvailable(int port) {
if (port <= 0) {
throw new IllegalArgumentException("Invalid start port: " + port);
}
ServerSocket ss = null;
DatagramSocket ds = null;
try {
ss = new ServerSocket(port);
ss.setReuseAddress(true);
ds = new DatagramSocket(port);
ds.setReuseAddress(true);
return true;
} catch (IOException e) {
} finally {
if (ds != null) {
ds.close();
}
if (ss != null) try {
ss.close();
} catch (IOException e) {
}
}
return false;
}
public static void main(String[] args) {
String webapp = "D:/haocheng/workspace/com.cheng.spring.mvc.test/src/main/webapp";
new JettyServerStart(webapp, 8080, "/").start();
}
}
工具类有了,接下来就是要调用工具类来让我们使用,与JettyServerStart
相比,JettyStarterTest
就很精简了。代码如下(请注意包名,该类是测试类,在src/test/java目录下,不在src/main/java下):
package test.billy.jee.framework.util.JettyServerStart;
import com.billy.jee.framework.util.JettyServerStart;
public class JettyStarterTest {
public static void main(String[] args) {
String webapp = "src/main/webapp";
int port = 2016;
new JettyServerStart(webapp, port, "/webby").start();
}
}
对!你没有看错,这就是个java程序,右键Run As Java Application就能启动该类,这时候在地址栏里输入http://127.0.0.1:2016/webby
即可访问到该项目。
需要注意的是,若你使用Eclipse或MyEclipse作为ide的话,上面的启动类的代码不用改变,但当你使用idea开发的话,请将webapp变量赋值为"项目名/src/main/webapp"即可。
右键项目Run As Maven install即可将项目安装到本地仓库,接着执行JettyStarterTest类启动服务,然后在地址栏项目名的基础上随便输入一个地址如http://127.0.0.1:2016/webby/aaaa.ts
,可以看到控制台打印出了系统当前时间毫秒数。也说明aaaa.ts是能请求到TransServlet的service()方法中的。
接着我们就要在TransServlet中进行调用DemoC的helloString()方法了。
我们将打印语句注释掉,并在其下添加如下代码:
DemoC demoC = new DemoC();
demoC.helloString("这是DemoC");
重新启动服务,我们同样访问http://127.0.0.1:2016/webby/aaaa.ts
,看到后台的输出了吗?
param hello: 这是DemoC
我们确实调用了DemoC这个类的helloString()方法了。可以也遗留了几个问题:
- 我们把地址http://127.0.0.1:2016/webby/aaaa.ts中的aaaa改成任何字符串都能得到helloString()的输出。
- helloString()的参数是固定的,不能改变。
这两个问题其实也是一个问题,我们最终想要的结果可能是——
我在地址栏输出
http://127.0.0.1:2016/webby/demo/helloString.ts?hello=这是DemoC吗
,系统应该能定位到DemoC类的helloString()方法,并将参数hello传入。
这一个问题,或称两个问题我们下篇博客中会给出解决方案。