前言
这一章将记录使用NetBeans在Tomcat中创建servlet程序。
Servlet(Server Applet)是运行在WEB服务端的小程序,目的是和客户端交互并且生成动态的web内容,它可以接收来自客户端的请求并生成响应。
环境搭建
本篇记录将基于Java环境和Tomcat服务器创建 Servlet 应用程序,关于集成Java环境和NetBeans搭建Tomcat服务器可以看之前的记录:
创建Servlet程序
首先是一个我们必须要新建一个Web项目才能创建servlet应用,打开 Netbeans IDE,选择File -> New Project。
然后选择Java Web -> Web Application创建Java Web项目。
给你的Web项目起一个名字,例如hoyue,我们可以点击browse选择这个项目存储的位置:
然后选择我们之前创建过的Tomcat服务器,path处可以填写不同的映射地址。
对于Frameworks则不需要选择其他的框架,直接点击Finish。至此Java Web项目已经创建完成。
要创建 Servlet,请打开Source Package,右键单击<default packages> -> New -> Servlet。
接下来为你的Servlet类文件命名,同时也建议自定义Package(包)名。
PS:Servlet类文件没有 main() 方法,它是一个Java类,通过覆盖doGet()、doPost()等方法来处理客户端请求。
接下来,如果在配置部署中勾选了“将信息添加到部署描述符(web.xml)”它会自动将你的servlet应用注册到web.xml中,让web程序能自动识别到你的应用。
我们可以修改URL Pattern(URL模式),用于定义访问我们的servlet应用URL。
当然还可以通过@WebServlet注解来解决,之后也会讲解。如果选择添加@WebServlet注解这里请不要勾选。
至此就已经创建好了servlet应用。
运行Servlet应用
以一个ServletHello作为一个测试应用,让它输出hello world。例如下面的这个程序:
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
/**
* Hello World! servlet
*/
public class ServletHello extends HttpServlet
{
/**
* Respond to any HTTP GET request with an
* HTML Hello World! page.
* @param request
* @param response
* @throws javax.servlet.ServletException
* @throws java.io.IOException
*/
@Override
public void doGet (HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException
{
// Set the HTTP content type in response header
response.setContentType("text/html; charset=\"UTF-8\"");
// Create the body of the response
try ( // Obtain a PrintWriter object for creating the body
// of the response
PrintWriter servletOut = response.getWriter()) {
// Create the body of the response
servletOut.println(
"<!DOCTYPE html \n" +
" PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \n" +
" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\"> \n" +
"<html xmlns='http://www.w3.org/1999/xhtml'> \n" +
" <head> \n" +
" <title> \n" +
" ServletHello.java \n" +
" </title> \n" +
" </head> \n" +
" <body> \n" +
" <p> \n" +
" Hello World! \n" +
" </p> \n" +
" </body> \n" +
"</html> ");
servletOut.close();
}
}
}
我们可以将这些代码添加到刚才创建好的文件中,替换到Package之下(如果你设定了Package的名字):
(下面添加内容仅为没有勾选添加到web.xml的用户需要的操作)
我们需要引用一个javax.servlet.annotation.WebServlet
库和@WebServlet
注解。
import javax.servlet.annotation.WebServlet;
@WebServlet(name = "ServletHello", urlPatterns = { "/ServletHello" })
//Class 定义之前
我们使用 @WebServlet
注解来定义一个 servlet,并使用 urlPatterns
属性将 HTTP GET 请求映射到 /ServletHello
路径上。当客户端访问这个路径时,将会执行 doGet
方法并将 "Hello, World!" 字符串写入 HTTP 响应中。
然后我们就可以通过这个地址运行访问我们的应用了。选择左侧该Servlet应用,点击Run。
接下来设置URL模式,这里因为我们这个例子中没有参数,那就直接点击OK即可。
然后等待NetBeans的部署,完成后就可以在浏览器中查看结果了。我这个例子的地址为:http://localhost:8084/hoyue/ServletHello
一般你的地址为:http://hostname:[port]/project_name/servlet_name
成功结果如图:
动态响应案例
上面的hello例子没有体现出servlet根据Get与Post动态反馈内容的能力,下面是一个简单的动态响应案例。
一个博客有一个登录页面和一个评论页面。如果我们正确填写了账号密码就会跳转到评论页面,反之则没有。
博客文件将会被放在项目的MOBFiles文件夹下,登录页面为login.html,addentry.html表示一个评论页面,servlet类文件为Login.java
我们先创建servlet类文件并命名为Login,在Package之后写下如下代码:
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class Login extends HttpServlet {
/**
* Processes requests for both HTTP <code>GET</code> and <code>POST</code>
* methods.
*
* @param request servlet request
* @param response servlet response
* @throws ServletException if a servlet-specific error occurs
* @throws IOException if an I/O error occurs
*/
@Override
protected void doGet (HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException
{
response.sendRedirect("./MOBFiles/login.html");
}
@Override
protected void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException
{
String username = request.getParameter("username");
String password = request.getParameter("pwd");
if (username != null && password != null &&
username.equals("nice") &&
password.equals("try")) {
HttpSession session = request.getSession();
session.setAttribute("loggedIn", true);
response.sendRedirect("./MOBFiles/addentry.html");
}
else {
response.sendRedirect("./MOBFiles/login.html");
}
}
代码的意思是:
- 在
doGet
方法中,servlet发送一个重定向响应到URL“./MOBFiles/login.html
”。这意味着当用户使用HTTP GET请求访问servlet时,他们将被重定向到登录页面。 - 在
doPost
方法中,servlet处理POST请求,使用getParameter()
方法从请求中检索“username”和“pwd”参数的值。然后,它检查用户名和密码是否都不为null,并匹配正确值“nice”和“try”,如果是这样,它将使用getSession()
方法创建一个新会话,并将一个名为“loggedIn”的属性设置为true。最后,它发送一个重定向响应到URL“./MOBFiles/addentry.html
”,这意味着用户将被重定向到“addentry”页面。 - 如果用户名和密码不匹配或未提供,则servlet将发送一个重定向响应到原本登录页面。
接下来就是两个简单的html页面和它的一些CSS文件,我们把它们放到项目的MOBFiles
文件夹下,即需要把文件夹移到web目录下,如图:
这些文件放到了网盘中可以直接下载:
当然我们需要修改login.html文件中提交的action,以便于将post内容发送给servlet。只需要填写/project_name/Login即可,当然你需要根据你设置的名称改变这个目录。
最后尝试运行这个servlet程序,然后在浏览器中访问它,我设置的地址为http://localhost:8084/hoyue/Login
,一般是http://hostname:[port]/project_name/Login_name
输入地址后会被重定向到登录页面login.html,如图:
我们在servlet程序中设置的账号为nice,密码为try,输入正确后会跳转到评论页面,如图:
如果密码错误则重新返回登录页面:
至此,这个就是一个简单的根据GET与POST做出响应的servlet程序案例了。
Q&A
下面是一些常见问题与解答,如果遇到了其他问题,欢迎在评论区留言,或通过邮箱等方式联系我。
- Q:Class "[classname]" neither has a main method nor is it a servlet specified in web.xml
首先,请注意在左侧文件中右键运行文件,而不是点击上方的运行键。上方的运行键在部署后将需要main()方法,而servlet没有main()方法。
排除上述,这个问题还说明你的Servlet类没有在web.xml文件中被定义为servlet:如果你想将你的类作为 servlet 运行,那么你需要在 web.xml文件中定义它。- 如果你选择在创建servlet的时候就勾选了自动添加,请在Files-web-WEB-INF,找到web.xml文件,检查<servlet-name>和<servlet-class>是否填写正确,如果你修改了文件名,则也需要同步修改这里的配置。它的格式形如:
<servlet> <servlet-name>Servletname</servlet-name> <servlet-class>package_name.Servletname</servlet-class> </servlet> <servlet-mapping> <servlet-name>Servletname</servlet-name> <url-pattern>/url</url-pattern> </servlet-mapping>
其中,
Servletname
为你设置的名字,package_name
为你设置的包名,url
是你设置的映射URL。 - 如果你没有勾选添加到web.xml,那么请检查@WebServlet注解,例如在ServletHello类上添加@WebServlet注解,指定名称为"MyServlet",URL模式为"/hello",则它形如:
@WebServlet(name = "MyServlet", urlPatterns = { "/hello" })
- 如果你选择在创建servlet的时候就勾选了自动添加,请在Files-web-WEB-INF,找到web.xml文件,检查<servlet-name>和<servlet-class>是否填写正确,如果你修改了文件名,则也需要同步修改这里的配置。它的格式形如:
- Q:"HTTP Status 404 – Not Found"错误
这通常是由于servlet的URL映射不正确导致的。确保在web.xml文件中或者在@WebServlet注解里正确地映射了servlet的URL,并且在浏览器中输入的URL与映射匹配。例如我的项目名字为hoyue,映射的URL模式为/ServletHello,那么我应该在浏览器中输入的是http://hostname:[port]/hoyue/ServletHello
. - Q:javax.servlet 不存在
可能是因为没有将 Servlet API 添加到项目的依赖项中。
在 NetBeans 中打开项目,右键单击项目,选择 "Properties",在 "Properties" 窗口中,选择 "Libraries" 选项卡。点击 "Add Library" 按钮,选择 "Java Platform", 选择任何一个新版的 "Java EE API"。确定即可,应该能够在项目中引用 javax.servlet 类。
或者用其他头文件来代替它,把javax
改为jakarta
即可。 - Q:Tomcat部署时报错,出现无法找到类名称:org.apache.catalina.core.StandardWrapperValve.invoke 分配异常的servlet [classname]
java.lang.ClassNotFoundException: [classname]
这通常是由于Tomcat找不到你的servlet类文件导致的。通常情况下,Tomcat的类加载器会根据web.xml定位你的servlet类,你需要确保你的java文件名与web.xml中描述的一致。如果还是不行,你可以将Java文件打成一个 JAR 包,并将该JAR包放置到 Tomcat的lib目录中。这样,Tomcat 的类加载器就可以从 lib 目录加载你的类了。 - Q:Can't import javax.servlet.annotation.WebServlet
请注意当前Tomcat版本后重试几次,可以尝试在web.xml头部添加下面代码声明它的规则:<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
- Q:没用到的import头
可以删除没有影响。 - Q: 头部报错incorrect package
如果你在创建的时候没有给包一个名字,它会默认为一个空的名字(default package),此时不需要package语句声明,但如果你自定义了,你就需要package语句在头部声明位于某个包中,例如:package servlet;
- Q:类名与文件名不匹配
Java编译器会在编译源代码文件时,根据文件名来确定编译后的类的名称。如果文件名与public类的名称不匹配,编译器将无法正确地创建该类。请检查你的public类名是否与文件名一致。
后记
这一章记录了使用NetBeans在Tomcat中创建servlet程序的一些简单细节。
Comments 3 条评论
博主 星夜空
谢谢大佬
博主 Catherine
这是一条私密评论
博主 Hoyue
@Catherine 使用绝对路径可以明确指出该后端请求的路由是从根路径开始的,无论当前文件或代码的位置如何。为了易于理解且方便扩展,在前后端连接中,一般来说后端请求的路由都是放在同一个位置的,都是基于根路径的绝对路径,这是个设计原则吧?可能。