solitaryclown

Java Web

2022-02-10
solitaryclown

1.

1.1. tomcat

运行Java程序的Web服务器

1.2. Servlet

1.2.1. 使用

Servlet是JavaEE定义的一个规范,在代码中的体现是javax.servlet包下的一个接口。
一个servlet是指一个运行在Web服务器上的小程序,它接收和响应来自Web客户端的请求。

Servlet的运行依赖于Web服务器,如tomcat。
要使用Servlet,就要引入java.servlet包,由于这个包也是tomcat的依赖,因此在maven项目中必须在打包时排除这个依赖,否则tomcat会报异常。

<!--servlet-api是Tomcat依赖的jar包,打包时需要排除,否则服务器抛异常-->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.0.1</version>
    <scope>provided</scope>
</dependency>
  1. 创建web项目,在项目中需要包含一个WEB-INF\web.xml文件
  2. 创建一个class实现Servlet接口
  3. 重写Servlet的5个方法,重点是service()
  4. 为class配置访问url。Servlet3.0以前需要在web.xml中配置,3.0以后提供注解配置。使用@WebServlet为class配置url和其他相关参数
  5. 打包放入tomcat并启动(或者使用插件,maven提供tomcat7插件)
  6. 访问

1.2.2. 生命周期

Servlet在tomcat中是单例多线程的,因此不要在Servlet中定义状态可能改变的变量,会引发线程安全问题。

  1. Servlet默认是惰性实例化,在第一次被访问时进行实例化并调用init(ServletConfig servletConfig)方法
  2. 当url被访问,service()被调用
  3. 服务器正常关闭之前,destroy()方法会被调用。

1.2.3. HttpServlet

javax.servlet.http下实现了一个HttpServlet用来支持http服务,它的继承关系如下图: HttpServlet继承关系

使用HttpServlet类能更加方便实现http服务,它是一个abstract class,使用时需要让class继承HttpServlet,然后重写它的方法,比如doGet(HttpServletRequest req, HttpServletResponse resp)doPost(HttpServletRequest req, HttpServletResponse resp)等,最后通过url就可以访问,并且tomcat会根据不同的http请求方式调用对应的方法。

doGet和doPost的参数类型HttpServletRequestHttpServletResponsejavax.servlet.http下的interface,定义了获取http请求相关参数和设置http响应的行为,tomcat在调用doGet之类的方法时会传入实际的对象引用,这个对象的class是tomcat定义的。

1.2.4. 转发与重定向

1.2.4.1. 请求转发

请求转发是指request在服务器内部的资源跳转方式,即request从一个Servlet传递给另一个Servlet,同时,ServletRequest接口提供在Servlet间共享资源的行为:getAttribute(String s)、setAttribute(String s,Object o)和removeAttribute(String s)。

1.2.4.2. 请求重定向

请求重定向不同于请求转发,请求重定向是服务器无法处理当前请求的资源但知道哪里可以处理当前请求,响应重定向状态码(302)和资源路径location。因此对于浏览器访问某个资源,服务器响应重定向,则浏览器会重新发送一个http请求到新的资源路径。

重定向对于客户端是可见的,请求转发对客户端是不可见的(发生在服务器内部)。

HttpServletResponse响应重定向,可以手动设置status为302并设置header的”location”。

/*
        resp.setStatus(302);
        resp.setHeader("location","http://baidu.com");
*/

        resp.sendRedirect("http://www.baidu.com");

1.2.5. cookie和session

cookie的RFC规范:https://www.rfc-editor.org/rfc/rfc6265.html

cookie是在服务器端设置、在客户端(浏览器)存储的状态信息,一个cookie以key-value的形式存储在客户端计算机上。

  1. cookie的key、value、max-age(到期时间)以及其他的状态信息在服务端被指定,所有的cookie被插入到http响应头中,响应头名称为Set-cookie
  2. 当浏览器访问某个服务器,如果发现当前客户端存有这个域名或IP下的cookie,会将所有cookie插入请求头发送给服务器,请求头名称为Cookie。服务器接收到请求会解析请求头并取出cookie。

典型的Set-cookie和Cookie的格式如下:

响应头:
Set-Cookie: USERID="ADJIOYQAEFBASADPIKOMDMFHQL:I"; Version=1; Max-Age=60; Expires=Sat, 12-Feb-2022 05:17:27 GMT
请求头:
Cookie: USERID="ADJIOYQAEFBASADPIKOMDMFHQL:I"
  • max-age<0,当客户端关闭cookie失效,默认。
  • max-age>0,到期则会失效。
  • max-age=0,接收到请求直接失效。

cookie常常被网站用来跟踪访问者,以保存用户名、兴趣、密码记忆选项等用户信息。

1.2.5.2. session

上面提到,cookie放在http报文中在客户端和服务端之间传输,cookie也是一个rfc规范。 session是指存在服务端的一个对象,它里面的内容可以被同一次会话的多个请求共享,最重要的一点,它基于cookie实现。 对于Java服务器来说,当Servlet中getSession()会返回与当前request关联的会话对象,如果不存在,创建一个新的session对象。 每个session对象都会有一个唯一的ID,当Servlet调用了getSession(),最终响应头的cookie会被添加session的id,这个sessionID是一个会话cookie,即会话关闭即失效。等到下一次同一个会话的请求过来,cookie会携带一个sessionID,如果执行getSession(),发现这个sessionID的session对象存在,直接返回这个session对象。

tomcat中,session对象的存活时间为30min,超时对象被销毁。

session对象可以添加数据,意味着同一个会话多个的http请求可以通过session对象共享数据。

不同于cookie存储在客户端的某个文件上(如果设置了存活时间),session只是内存中的对象,但如果服务器对session做了序列化(钝化)写入文件,如果服务器意外关闭当服务器重启后session对象会重新加载到内存。

1.2.5.3. 对比

  1. 存储位置:cookie存在客户端,session存在服务端
  2. 安全性:cookie数据明文传输,不应该存储敏感数据,session存在服务端,较安全。
  3. cookie有存储大小的限制,不同的浏览器不同,一般为最大4KB左右,session依赖于服务器。

把cookie和session对比并不是说明它们是对立的,事实上很多时候要强调session依赖于cookie,甚至你可以理解为session就是一个服务器端简单的对象,它有一个叫id的属性,这个id可以通过cookie的形式在server和client之间传输。

1.3. JSP

JSP是Java Server Page的简写。

JSP代表Java服务器页面,是一种用于构建支持动态内容的web应用程序的技术,它充当Java servlet技术。您可以将它视为servlet的一个不同选项,并且它具有比servlet更多的功能。 JSP被明确用于创建动态web应用程序。与Servlet相比,使用JSP创建的页面更易于管理。JSP页面是servlet的倒数形式,因为servlet在Java代码中包含HTML代码,而JSP通过JSP标记在HTML中包含Java代码。JSP可以做Servlet可以做的所有事情。

1.3.1. 原理

正如上面的概述,jsp文件是html代码中包含Java代码,jsp文件会被服务器的jsp解析引擎解析为一个Servlet类,在访问jsp时,服务器调用这个类的_jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)方法进行响应,最终服务器返回的是html静态文本。

一个典型的jsp文件如下:

<%@ page import="java.util.Date" %><%--
  Created by IntelliJ IDEA.
  User: Administrator
  Date: 2022/2/11
  Time: 0:31
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<%=
"Hello,我是JSP!" + new Date()
%>
</body>
</html>

如果在服务器访问这个jsp文件,最终得到的结果如下图: 访问jsp

1.3.2. JSTL标签库和EL表达式

虽然jsp可以写Java代码,但大部分时候jsp还是不会写过多的Java代码而只是用来展示数据,具体的逻辑仍然在项目的Servlet中编写。JavaEE为支持jsp提供了EL表达式和JSTL标签库使jsp操作数据更加方便。

1.3.2.1. 示例

Student类:

@WebServlet(urlPatterns = "/students")
public class Students extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request,response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        ArrayList<Student> students = new ArrayList<>();
        students.add(new Student(1,"乔峰","1",new Date()));
        students.add(new Student(2,"段誉","1",new Date()));
        students.add(new Student(3,"虚竹","1",new Date()));
        students.add(new Student(4,"王语嫣","0",new Date()));
        students.add(new Student(5,"慕容复","1",new Date()));

        request.setAttribute("students",students);
        request.getRequestDispatcher("/students.jsp").forward(request,response);
    }

}

students.jsp:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@page isELIgnored="false" %>


<html>
<head>
    <title>Title</title>
</head>
<body>

<h1>天龙八部学生表</h1>

<table border="1px">
<c:forEach items="${requestScope.students}" var="student">
    <tr>
        <td>${student.id}</td>
        <td>${student.name}</td>
        <td>
            <c:if test="${student.sex==1}"></c:if>
            <c:if test="${student.sex==0}"></c:if>
        </td>
        <td>
            <fmt:formatDate pattern="yyyy年MM月dd日" value="${student.birthdate}"></fmt:formatDate>
        </td>
    </tr>

</c:forEach>
</table>
</body>
</html>

当浏览器访问/students,服务器调用Student类的get方法,Student模拟后台查询数据库的过程,将数据存到list中并将list存入request域,然后将请求转发到/students.jsp,通过EL表达式可以将request域中的list取出,然后配合jstl实现集合迭代和取值,另外,jstl提供了格式化的标签,方便对日期等数据格式化。


下一篇 Spring

Comments

Content