Tomcat和Servlet学习记录
Tomcat和Servlet入门
1.Tomcat
1.1什么是Tomcat
简单来说,Tomcat是Web服务器
1.2 目录结构
bin目录: 可执行文件,主要有两大类,一类是以.sh结尾的(linux命令)另一类是以.bat结尾的(windows命令)。
startup 用来启动tomcat。shutdown 用来关闭tomcat。
conf目录: 配置文件。server.xml该文件用于配置server相关的信息,比如tomcat启动的端口号。tomcat-user.xml配置用户名密码和相关权限。
lib目录: 主要用来存放tomcat运行需要加载的jar包。
logs目录: 用来存放tomcat在运行过程中产生的日志文件。windows环境中,控制台的输出日志catalina.xxxx-xx-xx.log文件中 。linux环境中,控制台的输出日志在catalina.out文件中。
temp目录: 用户存放tomcat在运行过程中产生的临时文件。
work目录: 用来存放tomcat在运行时的编译后文件,清空work目录后重启tomcat,可以达到清除缓存的作用。
webapps目录: 项目部署目录,当tomcat启动时会去加载webapps目录下的所有应用程序。在浏览器中可以根据自己的需求访问不同的应用程序。
应用程序一般会打包成归档格式(.war),然后放到Tomcat的应用程序部署目录。而webapp有特定的组织格式,是一种层次型目录结构,通常包含了servlet代码文件、HTML/jsp页面文件、类文件、部署描述符文件等等,相关说明如下:
/:web应用程序的根目录,可以存放HTML/JSP页面以及其他客户端浏览器必须可见的其他文件(如js/css/图像文件)。在较大的应用程序中,还可以选择将这些文件划分为子目录层次结构。
/WEB-INF:此webapp的所有私有资源目录,用户浏览器不可能访问到的,通常web.xml和context.xml均放置于此目录。
/WEB-INF/web.xml:此webapp的私有的部署描述符,描述组成应用程序的servlet和其他组件(如filter),以及相关初始化参数和容器管理的安全性约束。
/WEB-INF/classes:此webapp自有的Java程序类文件(.class)及相关资源存放目录。
/WEB-INF/lib:此目录存放webapp自有的JAR文件,其中包含应用程序所需的Java类文件(及相关资源),例如第三方类库或JDBC驱动程序。
1.3 IDEA中配置Tomcat
2.Servlet
2.1 什么是Servlet
Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。使用 Servlet可以收集来自网页表单的用户输入,呈现来自数据库或者其他源的记录,还可以动态创建网页。
2.2 使用Servlet获取参数
功能:前端输入相应的参数,使用post请求发送给后端并打印获取到的参数。
//addServlet.java 获取前端传来的数据并解析
//同时,后端给前端返回接受成功的文本信息
public class addServlet extends HttpServlet {
@Override
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8"); //设置编码格式 防止中文乱码
String name = req.getParameter("name");
int price =Integer.parseInt(req.getParameter("price"));
int count = Integer.parseInt(req.getParameter("count"));
String remark = req.getParameter("remark");
System.out.println("name :"+ name);
System.out.println("price :"+ price);
System.out.println("count :"+ count);
System.out.println("remark :"+remark);
// 设置响应的内容类型
resp.setContentType("text/plain");
// 获取输出流
PrintWriter out = resp.getWriter();
// 向浏览器发送响应数据
out.println("Data received successfully!");
out.close(); // 关闭输出流
}
}
<!--add.html-->
<body>
<form action="addInformation" method="post">
名称:<input type="text" name="name"><br/>
价格:<input type="text" name="price"><br/>
库存:<input type="text" name="count"><br/>
备注:<input type="text" name="remark"><br/>
<input type="submit" value="提交"/>
</form>
</body>
<!-- web.xml-->
<servlet>
<servlet-name>AddServlet</servlet-name> <!-- 3-->
<servlet-class>addServlet</servlet-class><!-- 4-->
</servlet>
<servlet-mapping>
<servlet-name>AddServlet</servlet-name> <!-- 2-->
<url-pattern>/addInformation</url-pattern> <!-- 1-->
</servlet-mapping>
执行顺序是:
- 前端访问add.html界面(即前端向后端请求add.html页面)。后端返回页面给前端。
- 前端点击添加,触发"addInformation"的动作,会使用“post”向后端的某个组件发送表单。后端会需要有对应的组件处理。
- web.xml配置:即如何确定action对应的是后端的哪个组件。(也可以直接在addServlet添加注解“/addInformation”表示这个动作与addServlet对应起来。)
- servlet-name可以随意命名,url-pattern是html中的action,servlet-class要和具体的实现类对应起来
2.3 Servlet生命周期
Servlet接口的定义如下
public interface Servlet {
void init(ServletConfig var1) throws ServletException;
ServletConfig getServletConfig();
void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
String getServletInfo();
void destroy();
}
-
init方法: 当Servlet第一次被请求时,Servlet容器会开始调用这个方法初始化一个Servlet对象,并且这个方法只会在第一次请求时才会被调用,在后续请求中不会在被Servlet容器调用。
-
service方法: 每当请求Servlet时,Servlet容器就会调用这个方法。第一次请求时,Servlet容器会先调用init( )方法初始化一个Servlet对象出来,然后会调用它的service( )方法进行工作,但在后续的请求中,Servlet容器只会调用service方法了。
-
destory方法: 卸载应用程序或者关闭Servlet容器时,Servlet容器就会调用这个方法,一般在这个方法中会写一些清除代码。
//注:HttpSrvlet中并没有init和destory方法,重写的是GenericServlet类中的init和destory方法,GenericServlet类实现了Servlet接口
public class LifeServlet extends HttpServlet {
@Override
public void init() throws ServletException {
System.out.println("正在初始化...");
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("正在服务...");
}
@Override
public void destroy() {
System.out.println("正在销毁....");
}
}
//打开浏览器,多次刷新,最后终止程序,输出如下
//正在初始化...
//正在服务...
//正在服务...
//正在服务...
//正在销毁...
2.4 Servlet.http.HttpServlet
一般自定义的Servlet类需要继承HttpServlet类,虽然HttpServlet是抽象类,但是内部仍然实现了许多方法,如:Service方法等
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = req.getMethod(); //获取要使用的方法
long lastModified;
if (method.equals("GET")) {
lastModified = this.getLastModified(req);
if (lastModified == -1L) {
this.doGet(req, resp);
} else {
long ifModifiedSince;
try {
ifModifiedSince = req.getDateHeader("If-Modified-Since");
} catch (IllegalArgumentException var9) {
ifModifiedSince = -1L;
}
if (ifModifiedSince < lastModified / 1000L * 1000L) {
this.maybeSetLastModified(resp, lastModified);
this.doGet(req, resp);
} else {
resp.setStatus(304);
}
}
} else if (method.equals("HEAD")) {
lastModified = this.getLastModified(req);
this.maybeSetLastModified(resp, lastModified);
this.doHead(req, resp);
} else if (method.equals("POST")) {
this.doPost(req, resp);
} else if (method.equals("PUT")) {
this.doPut(req, resp);
} else if (method.equals("DELETE")) {
this.doDelete(req, resp);
} else if (method.equals("OPTIONS")) {
this.doOptions(req, resp);
} else if (method.equals("TRACE")) {
this.doTrace(req, resp);
} else {
String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[]{method};
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(501, errMsg);
}
}
调用Service方法时先解析HttpServletRequest中的方法参数,并调用以下方法之一:doGet,doPost,doHead,doPut,doTrace,doOptions,doDelete。因此在我们自定义的Servlet中如果我们需要实现具体的服务逻辑,不再需要重写service方法了,只需要覆盖doGet或者doPost或者其他do方法即可。
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String protocol = req.getProtocol();
String msg = lStrings.getString("http.method_post_not_supported");
if (protocol.endsWith("1.1")) {
resp.sendError(405, msg);
} else {
resp.sendError(400, msg);
}
}
以上述HttpServlet中的doPost方法为例,一般情况下我们自定义的Servlet类会继承HttpServlet类然后重写对应的方法,但是如果没有重写直接调用对应的方法,会报错:405
3.Http协议
HTTP协议详解——请求消息、响应消息、请求方法、响应状态码
在上述的add.html例子中,使用的是POST请求,客户端点击提交按钮后,向服务器端发送请求,可以在如下图的Headers中的Request Headers中查看请求行、请求头,在Payload中查看请求体(POST有但是GET没有)。服务器端接收到数据后会打印输出"Data received successfully",在Response中可以查看到响应体,在Headers的Reponse Headers中查看响应行和响应头。
补充:响应头说明
4.Session 和Cookie
4.1 Session
- 为什么引入session?
HTTP 是无状态的,即服务器无法判断多个请求时由单个还是多个客户端发起的。以购物车为例,如果有用户A和B,A先发送请求将某物品加入购物车然后退出。B的购物车已经加入了某物品,发送请求对该物品结账,如果服务器无法判断是对A还是B的物品结账,可能会带来混乱。
因此会话技术(session)诞生,解决了Http无状态的问题。 - 什么是session?
服务器为了保存用户状态而创建的一个特殊的对象。 - session 的实现
每个session由JSESSIONID唯一标识,JSESSIONID是由服务器端生成的。http在请求的时候会携带 JSESSIONID(如果存在),如果JSESSIONID不存在则表明是客户端第一次请求,此时服务器端会生成唯一的 session并将JSESSIONID返回给客户端,客户端将JSESSIONID保存为cookie,下次请求的时候可以继续携带。
(1)客户端第一次发起请求
此时客户端没有JSESSIONID,因此不携带。服务器端收到请求后使用getSession判断这是客户端第一次请求,于是创建session并以cookie的形式将JSESSIONID返回给客户端。客户端收到响应后将JSESSIONID作为cookie保存下来。
(2)客户端非第一次发起请求
此时客户端已经有JSESSIONID,因此请求时直接携带。服务器端收到请求后使用getSession判断客户端的session已经被保存了,直接将JSESSIONID对应的session返回给客户端。
- session常用API
request.getSession() -> 获取当前的会话,没有则创建一个新的会话
request.getSession(true) -> 效果和不带参数相同
request.getSession(false) -> 获取当前会话,没有则返回null,不会创建新的
session.getId() -> 获取sessionID
session.isNew() -> 判断当前session是否是新的
session.getMaxInactiveInterval() -> session的非激活间隔时长,默认1800秒
session.setMaxInactiveInterval()
session.invalidate() -> 强制性让会话立即失效
- session抓包实验
多次发起请求,服务器端打印sessionID,客户端查看请求和响应。
参考抓包实验部分
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session = req.getSession();
String id = session.getId();
System.out.println(id);
}
//多次请求发现id是一致的
//92F0B4E22926ED64726E1158547E4E11 22:31:34
//92F0B4E22926ED64726E1158547E4E11 22:31:52
4.2 Cookie
彻底搞懂cookie
session和cookie的区别
- cookie保存在客户端,session保存在服务端
- cookie作用于他所表示的path中(url中要包含path),范围较小。session代表客户端和服务器的一次会话过程,web页面跳转时也可以共享数据,范围是本次会话,客户端关闭也不会消失。会持续到我们设置的session生命周期结束(默认30min)
- 我们使用session需要cookie的配合。cookie用来携带JSESSIONID
- cookie存放的数据量较小,session可以存储更多的信息。
- cookie由于存放在客服端,相对于session更不安全
- 由于session是存放于服务器的,当有很多客户端访问时,肯定会产生大量的session,这些session会对服务端的性能造成影响。
5.服务器端内部转发和客户端重定向
上图分别是服务器内部转发和客户端重定向的示意图。
- 服务器内部转发:客户端给服务器端发送请求后,服务器端将请求转发给其他服务器处理,最终响应给客户端。对于客户端而言,内部经过了多少次转发,客户端是不知道的并且地址栏没有变化。
- 客户端重定向:客户端向服务器端发送请求后,服务器会响应给服务器重定向到其他服务器,此时客户端会自动重新给新的服务器发送请求。对于客户端而言是知道具体是哪个服务器响应的,URL会有变化。
6.保存作用域(request、session、application)
(1)request保存作用域
一次请求范围内有效:即只有当次请求才有效,二次请求会无效。例如服务器内部转发,request有效。但是客户端重定向request无效,因为客户端重定向发生了2次请求。
//客户端重定向
//Area1中设置request的值,重定向到Area2.在Area2中获取request的值发现为null
@WebServlet("/RequestSaveArea1")
public class RequestSaveArea1 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setAttribute("num",10);
resp.sendRedirect("RequestSaveArea2");
}
}
@WebServlet("/RequestSaveArea2")
public class RequestSaveArea2 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Object num = req.getAttribute("num");
System.out.println(num); //null
}
}
//服务器内部转发
//Area1中设置request的值,转发到Area2.在Area2中可以获取到request的
@WebServlet("/RequestSaveArea3")
public class RequestSaveArea3 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setAttribute("num",10);
req.getRequestDispatcher("RequestSaveArea4").forward(req,resp); //重定向
}
}
@WebServlet("/RequestSaveArea4")
public class RequestSaveArea4 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Object num = req.getAttribute("num");
System.out.println(num); //10
}
}
(2)session保存作用域
会话期内有效:session创建后,保存的资源一直有效,直到session终止。session终止的方法:调用了session.invalidate()方法、session过期(Tomcat默认30分钟)、服务器重新启动
(3)application保存作用域
一次应用程序范围有效:即只要服务器不重启,保存的资源都有效。其他客户端也可以访问该资源。
@WebServlet("/ApplicationSaveArea1")
public class ApplicationSaveArea1 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext application = req.getServletContext();//获取上下文
application.setAttribute("num",10);//保存值
resp.sendRedirect("ApplicationSaveArea2");//重定向
}
}
@WebServlet("/ApplicationSaveArea2")
public class ApplicationSaveArea2 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext application = req.getServletContext();
Object num = application.getAttribute("num");
System.out.println(num);//10
}
}
原文地址:https://blog.csdn.net/weixin_43956248/article/details/134349838
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!