Updated on 2017-03-09

https://tomcat.apache.org/index.html

https://tomcat.apache.org/tomcat-9.0-doc/api/allclasses-noframe.html

https://tomcat.apache.org/tomcat-9.0-doc/jspapi/allclasses-noframe.html

https://tomcat.apache.org/tomcat-9.0-doc/servletapi/allclasses-noframe.html

Tomcat

环境变量

变量值变量名
CATALINA_HOMED:\Download\apache-tomcat-9.0.0配置 Tomcat 安装路径
—————————————————————————————————————

默认欢迎页

D:\Download\apache-tomcat-9.0.0\conf\web.xml
<welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
</welcome-file-list>

默认端口号

D:\Download\apache-tomcat-9.0.0\conf\server.xml
<Connector port="8080" protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="8443" />

去掉空白行

全局
----
D:\Download\apache-tomcat-9.0.0\conf\web.xml
<init-param>
    <param-name>trimSpaces</param-name>
    <param-value>true</param-value>
</init-param>

单个页面
----
<%@ page trimDirectiveWhitespaces="true" %>

IDEA Deployment

C:\Users\Administrator\.IntelliJIdea2016.3\system\tomcat\

IDEA Dependence

Project Structure -> Modules -> Dependencies -> Add -> Library -> Tomcat

JSP

指令

page

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="java.util.Arrays" %>
<%@ page import="java.util.HashMap" %>

include

index.jsp
----
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

include 指令:
<%@ include file="date.jsp" %>     声明需要包含的页面

include 动作:
<jsp:include page="date.jsp" flush="false"/>     声明需要包含的页面(flush 是否刷新缓冲区)

</body>
</html>

date.jsp     被包含的页面
----
<%@ page import="java.text.SimpleDateFormat" %>
<%@ page import="java.util.Date" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    String date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
    out.print(date);
%>
include 指令与 include 动作的对比
include 指令include 动作
静态包含动态包含
生成内容文件内容执行结果
生成 Servlet合并独立
编译时间较慢较快(不解析资源)
执行时间较快(不解析资源)较慢
作用时间编译期间请求期间
适用页面变化较少经常变化
—————————————————————————–

taglib

注释

客户端可见注释:

<!-- HTML 注释 -->

客户端不可见注释:

<%-- JSP 注释 --%>

<%
    // Java 单行注释
    /*
    *  Java 多行注释
    * */
%>

声明

<%!     Servlet 中的成员(可声明为 static)
    private String s = "ABC";     属性

    private int add(int x, int y) {     方法
        return x + y;
    }
%>

脚本

<%     Servlet 中的 jspService() 的方法代码
    System.out.println("你好");     输出至控制台
    out.println("你好");     输出至页面(out 是内置对象,是 JspWriter 的实例化对象)
%>

表达式

<%=s%>     调用属性(注意表达式不加分号)
<br>
<%=add(1, 2)%>     调用方法

----
输出:
ABC
3

输出九九乘法表
----
<%!     声明方法
    private String a() {
        DecimalFormat format = new DecimalFormat("00");
        StringBuilder s = new StringBuilder();
        for (int i = 1; i <= 9; i++) {
            for (int j = 1; j <= i; j++) {
                s.append(i).append('*').append(j).append('=').append(format.format(i * j)).append("&nbsp;&nbsp;&nbsp;");     空格
            }
            s.append("<br>");     换行
        }
        return s.toString();
    }
%>

<%=a()%>     调用方法

生命周期

内置对象

out

request

index.jsp
----
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>登录页面</title>
</head>
<body>
<h1>登录页面</h1>
<hr>
<form action="doLogin.jsp" name="loginForm" method="post">
    <table>
        <tr>
            <td>账号:</td>
            <td><input type="text" name="account"></td>
        </tr>
        <tr>
            <td>密码:</td>
            <td><input type="password" name="password"></td>
        </tr>
        <tr>
            <td colspan="2"><input type="submit" value="登录"></td>
        </tr>
    </table>
</form>
</body>
</html>

doLogin.jsp
----
<%@ page contentType="text/html;charset=UTF-8" language="java" %>     指定输出字符集
<html>
<head>
    <title>登录成功</title>
</head>
<body>
<%
    request.setCharacterEncoding("UTF-8");     指定输入字符集
    request.setAttribute("str", "欢迎!");
%>
<h1>登录成功</h1>
<hr>
账号:<%=request.getParameter("account")%><br>
密码:<%=request.getParameter("password")%><br>
属性:<%=request.getAttribute("str")%><br>
协议类型:<%=request.getProtocol()%><br>
请求类型:<%=request.getContentType()%><br>
请求大小:<%=request.getContentLength()%> 字节<br>
虚拟路径:<%=request.getContextPath()%><br>
请求路径:<%=request.getServletPath()%><br>
真实路径:<%=request.getServletContext().getRealPath("doLogin.jsp")%><br>
主机名称:<%=request.getServerName()%><br>
主机端口:<%=request.getServerPort()%><br>
客户端 IP 地址:<%=request.getRemoteAddr()%><br>
服务端 IP 地址:<%=request.getLocalAddr()%><br>
</body>
</html>

----
输出:
账号:123456
密码:123456
属性:欢迎!
协议类型:HTTP/1.1
请求类型:application/x-www-form-urlencoded
请求大小:30 字节
虚拟路径:
请求路径:/doLogin.jsp
真实路径:C:\Users\Administrator\IdeaProjects\untitled1\out\artifacts\untitled1_war_exploded\doLogin.jsp
主机名称:localhost
主机端口:8080
客户端 IP 地址:0:0:0:0:0:0:0:1
服务端 IP 地址:0:0:0:0:0:0:0:1

Note:
真实路径:<%=request.getServletContext().getRealPath("doLogin.jsp")%><br>
等同于
真实路径:<%=request.getServletContext().getRealPath(request.getServletPath())%><br>
等同于
真实路径:<%=application.getRealPath(request.getServletPath())%><br>

response

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<%
    response.setContentType("text/html;charset=UTF-8");     与 page 指令中的 contentType 属性作用相同
    response.sendRedirect("request.jsp");     请求重定向(response)

    request.getRequestDispatcher("request.jsp").forward(request, response);     请求转发(request)
    等同于
    <jsp:forward page="request.jsp"/>     JSP 动作:forward

    动作 forward 可添加参数:
    <jsp:forward page="a.jsp">
        <jsp:param name="age" value="25"/>     添加参数
        <jsp:param name="sex" value="男"/>
    </jsp:forward>
    转发后的页面接收参数:
    <%=request.getParameter("age")%><br>

%>
</body>
</html>

Note:
请求重定向(客户端行为)(共发起 2 次请求)(游览器地址会改变)(不传递原有请求对象)(response)(302 临时跳转)
请求转发一(服务端行为)(共发起 1 次请求)(游览器地址不改变)(会传递原有请求对象)(request)

session

index.jsp
----
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="java.text.SimpleDateFormat" %>
<%@ page import="java.util.Date" %>
<%@ page import="java.util.Enumeration" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<%
    session.setAttribute("username", "admin");
    session.setAttribute("password", "123456");
    session.setAttribute("age", 20);
    session.setMaxInactiveInterval(3600);     设置生存间隔时间(秒)
%>
Session ID:<%=session.getId()%><br>
Session 一一创建时间:<%=a(session.getCreationTime())%><br>
Session 最近请求时间:<%=a(session.getLastAccessedTime())%><br>
Session 生存间隔时间:<%=session.getMaxInactiveInterval()%> 秒<br>
Session 中保存的属性:<%
    Enumeration<String> attributeNames = session.getAttributeNames();
    StringBuilder s = new StringBuilder();
    while (attributeNames.hasMoreElements()) {
        String k = attributeNames.nextElement();
        Object v = session.getAttribute(k);
        s.append(k).append('=').append(v.toString()).append("&nbsp;&nbsp;&nbsp;&nbsp;");
    }
    out.print(s.toString());
%><br>
</body>
</html>
<%!
    private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    private String a(long i) {
        return dateFormat.format(new Date(i));
    }
%>

----
输出:
Session ID:C9E1EDACE8806D15DA4BE0354BBD75E8
Session 一一创建时间:2017-03-11 20:37:55
Session 最近请求时间:2017-03-11 20:43:09
Session 生存间隔时间:3600 秒
Session 中保存的属性:password=123456    age=20    username=admin

Note:
Session 生命周期
----
1. 创建
首次访问(无 JSESSIONID Cookie):发送 Cookie:JSESSIONID=4619A7A93D0DA9622F3FB06F93E2A328

2. 活动
重置 Session 生存间隔时间。

3. 销毁
主动:session.invalidate()、重启 Tomcat、重启浏览器(JSESSIONID Cookie 失效,导致 Session 过期)。
被动:Session 过期。

设置 Session 超时时间(默认 30 分钟)
----
session.setMaxInactiveInterval(1800);     秒

D:\Download\apache-tomcat-9.0.0\conf\web.xml(全局)
⇳
<session-config>
    <session-timeout>30</session-timeout>     分
</session-config>

application

application 对象类似于 Java 中的 static 成员,属于 Web APP,由所有用户共享,可用于存放全局变量。
application 对象始于服务器,终于服务器。

----

<%
    application.setAttribute("str", "ABC");
    application.getAttribute("str");
    Enumeration<String> attributeNames = application.getAttributeNames();
    while (attributeNames.hasMoreElements()) {
        String k = attributeNames.nextElement();
        Object v = application.getAttribute(k);
        out.print(k + " = " + v + "<br><br>");
    }
%>

<%=application.getRealPath(request.getServletPath())%><br>
<%=application.getServerInfo()%><br>
----
输出:
C:\Users\Administrator\IdeaProjects\untitled\out\artifacts\untitled_war_exploded\index.jsp
Apache Tomcat/9.0.0.M18

page

page 对象类似于 Java 中的 this 指针,指代当前 JSP 页面本身,是 java.lang.Object 的实例。

----

<%=page%>
----
输出:
org.apache.jsp.index_jsp@2445d4f1

pageContext

pageContext 对象提供了对 JSP 页面内所有的命名空间的访问,相当于页面中所有功能的集大成者。

----

pageContext.forward("a.jsp");     请求转发
pageContext.include("a.jsp");     使当前位置包含另一个页面的内容(类似 include 动作,生成独立的 Servlet)

config

<%
    StringBuilder s = new StringBuilder();
    Enumeration<String> initParameterNames = config.getInitParameterNames();
    while (initParameterNames.hasMoreElements()) {
        String k = initParameterNames.nextElement();
        String v = config.getInitParameter(k);
        s.append(k).append(" = ").append(v).append("<br>");
    }
    out.print(s.toString());
%>

----
输出:
fork = false
trimSpaces = true
classdebuginfo = true
xpoweredBy = false

exception

index.jsp
----
<%@ page contentType="text/html;charset=UTF-8" language="java" errorPage="a.jsp" %>     指定异常处理页面
<html>
<head>
    <title>Title</title>
</head>
<body>
<%
    int i = 100 / 0;     将产生运行时异常
%>
</body>
</html>

a.jsp
----
<%@ page contentType="text/html;charset=UTF-8" language="java" isErrorPage="true" %>     设置为异常处理页面(可以使用 exception 对象)
<html>
<head>
    <title>Exception</title>
</head>
<body>
<%=exception.toString()%><br>     输出异常信息
</body>
</html>

index.jsp
----
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>登录页面</title>
</head>
<body>
<h1>登录页面</h1>
<hr>
<form action="doLogin.jsp" name="loginForm" method="post">
    <table>
        <tr>
            <td>账号:</td>
            <td><input type="text" name="account"></td>
        </tr>
        <tr>
            <td>密码:</td>
            <td><input type="password" name="password"></td>
        </tr>
        <tr>
            <td><input type="reset" value="重置"></td>
            <td><input type="submit" value="登录"></td>
        </tr>
    </table>
</form>
</body>
</html>

doLogin.jsp
----
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    request.setCharacterEncoding("UTF-8");     指定输入字符集
    String account = request.getParameter("account");
    String password = request.getParameter("password");
    if ("admin".equals(account) && "123456".equals(password)) {
        request.getRequestDispatcher("login_successful.jsp").forward(request, response);     登录成功:请求转发
    } else {
        response.sendRedirect("login_failed.jsp");     登录失败:请求重定向
    }
%>

login_successful.jsp
----
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>登录成功</title>
</head>
<body>
<h1>登录成功</h1>
<hr>
欢迎用户:<%=request.getParameter("account")%>
</body>
</html>

login_failed.jsp
----
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>登录失败</title>
</head>
<body>
<h1>登录失败</h1>
<hr>
<a href="index.jsp">返回登录页面</a>
</body>
</html>

JavaBean

符合某种设计规范的类,用于封装业务数据和业务逻辑,减少代码冗余,提高代码的可维护性。

UserBean

package a;

public class User {     公有类
    private String username;     私有属性
    private String password;

    public User() {     公有的无参构造方法
    }

    public String getUsername() {     公有 get/set
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

JSP 动作:useBean、set(get)Property

<%@ page import="a.User" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

普通方式
----
<%
    User a = new User();
    a.setUsername("admin");
    a.setPassword("123456");
%>
账户:<%=a.getUsername()%><br>
密码:<%=a.getPassword()%><br>

使用 JSP 动作
----
useBean
<jsp:useBean id="b" class="a.User" scope="page"/>     在指定范围内实例化 JavaBean(默认范围为 page)

setProperty
<jsp:setProperty name="b" property="*"/>     根据表单自动匹配所有属性(跟表单关联)

<jsp:setProperty name="b" property="username"/>     根据表单手动匹配部分属性(跟表单关联)
<jsp:setProperty name="b" property="password"/>

<jsp:setProperty name="b" property="username" value="admin"/>     手动设置属性值
<jsp:setProperty name="b" property="password" value="123456"/>

<jsp:setProperty name="b" property="username" param="abc"/>     根据 URL 参数给属性赋值
<jsp:setProperty name="b" property="password" param="def"/>
<!--http://localhost:8080/index.jsp?abc=123&def=456-->

getProperty
账户:<jsp:getProperty name="b" property="username"/><br>
密码:<jsp:getProperty name="b" property="password"/><br>

</body>
</html>

useBean 作用域范围
----
作用于单个页面的生命周期:page
作用于单个请求的生命周期:request
作用于整个会话的生命周期:session
作用于整个应用的生命周期:application

https://tomcat.apache.org/tomcat-9.0-doc/jspapi/javax/servlet/jsp/PageContext.html#PAGE_SCOPE
https://tomcat.apache.org/tomcat-9.0-doc/jspapi/javax/servlet/jsp/JspContext.html#setAttribute-java.lang.String-java.lang.Object-int-

User.java     用封装业务数据
----
package a;

public class User {
    private String username;
    private String password;

    public User() {
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

UserDAO.java     用于封装业务逻辑
----
package a;

public class UserDAO {
    public boolean userLogin(User user) {
        return "admin".equals(user.getUsername()) && "123456".equals(user.getPassword());
    }
}

index.jsp
----
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>登录页面</title>
</head>
<body>
<h1>登录页面</h1>
<hr>
<form action="doLogin.jsp" name="loginForm" method="post">
    <table>
        <tr>
            <td>账号:</td>
            <td><input type="text" name="username"></td>
        </tr>
        <tr>
            <td>密码:</td>
            <td><input type="password" name="password"></td>
        </tr>
        <tr>
            <td><input type="reset" value="重置"></td>
            <td><input type="submit" value="登录"></td>
        </tr>
    </table>
</form>
</body>
</html>

doLogin.jsp
----
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<jsp:useBean id="userDAO" class="a.UserDAO"/>     默认生命周期为 page
<jsp:useBean id="loginUser" class="a.User" scope="session"/>     指定生命周期为 session
<jsp:setProperty name="loginUser" property="*"/>     根据表单自动匹配所有属性
<%
    request.setCharacterEncoding("UTF-8");     指定输入字符集
    if (userDAO.userLogin(loginUser)) {
        request.getRequestDispatcher("login_successful.jsp").forward(request, response);     登录成功:请求转发
    } else {
        response.sendRedirect("login_failed.jsp");     登录失败:请求重定向
    }
%>

login_successful.jsp
----
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<jsp:useBean id="loginUser" class="a.User" scope="session"/>     在整个 Session 中只有同一个 loginUser
<html>
<head>
    <title>登录成功</title>
</head>
<body>
<h1>登录成功</h1>
<hr>
欢迎用户:<%=loginUser.getUsername()%>
</body>
</html>

login_failed.jsp
----
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>登录失败</title>
</head>
<body>
<h1>登录失败</h1>
<hr>
<a href="/">返回登录页面</a>
</body>
</html>
index.jsp
----
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    String username = "";
    String password = "";
    Cookie[] cookies = request.getCookies();
    if (cookies != null && cookies.length > 0) {
        for (Cookie c : cookies) {
            if (c.getName().equals("username")) {
                username = c.getValue();
            }
            if (c.getName().equals("password")) {
                password = c.getValue();
            }
        }
    }
%>
<html>
<head>
    <title>登录页面</title>
</head>
<body>
<h1>登录页面</h1>
<hr>
<form action="doLogin.jsp" name="loginForm" method="post">
    <table>
        <tr>
            <td>账号:</td>
            <td><input type="text" name="username" value="<%=username%>"></td>
        </tr>
        <tr>
            <td>密码:</td>
            <td><input type="password" name="password" value="<%=password%>"></td>
        </tr>
        <tr>
            <td colspan="2"><input type="checkbox" name="isUseCookie" checked>记住登录状态</td>
        </tr>
        <tr>
            <td><input type="reset" value="重置"></td>
            <td><input type="submit" value="登录"></td>
        </tr>
    </table>
</form>
</body>
</html>

doLogin.jsp
----
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<jsp:useBean id="userDAO" class="a.UserDAO"/>
<jsp:useBean id="loginUser" class="a.User" scope="session"/>
<jsp:setProperty name="loginUser" property="*"/>
<%
    request.setCharacterEncoding("UTF-8");
    if (userDAO.userLogin(loginUser)) {
        request.getRequestDispatcher("login_successful.jsp").forward(request, response);
    } else {
        response.sendRedirect("login_failed.jsp");
    }
%>

login_successful.jsp
----
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<jsp:useBean id="loginUser" class="a.User" scope="session"/>
<%
    String isUseCookie = request.getParameter("isUseCookie");
    if (isUseCookie != null) {
        Cookie username = new Cookie("username", loginUser.getUsername());     创建
        Cookie password = new Cookie("password", loginUser.getPassword());
        username.setMaxAge(86400);     设置 Cookie 有效期为 1 天(单位:秒)(若未设置,默认为浏览会话结束时过期)
        password.setMaxAge(86400);
        response.addCookie(username);     写入
        response.addCookie(password);
    } else {
        Cookie[] cookies = request.getCookies();     读取
        if (cookies != null && cookies.length > 0) {
            for (Cookie c : cookies) {
                if (c.getName().equals("username") || c.getName().equals("password")) {
                    c.setMaxAge(0);     设置 Cookie 立即过期
                    response.addCookie(c);     写入
                }
            }
        }
    }
%>
<html>
<head>
    <title>登录成功</title>
</head>
<body>
<h1>登录成功</h1>
<hr>
<a href="user.jsp">查看用户信息</a>
</body>
</html>

login_failed.jsp
----
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    Cookie[] cookies = request.getCookies();
    if (cookies != null && cookies.length > 0) {
        for (Cookie c : cookies) {
            if (c.getName().equals("username") || c.getName().equals("password")) {
                c.setMaxAge(0);
                response.addCookie(c);
            }
        }
    }
%>
<html>
<head>
    <title>登录失败</title>
</head>
<body>
<h1>登录失败</h1>
<hr>
<a href="/">返回登录页面</a>
</body>
</html>

user.jsp
----
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    String username = "";
    String password = "";
    Cookie[] cookies = request.getCookies();
    if (cookies != null && cookies.length > 0) {
        for (Cookie c : cookies) {
            if (c.getName().equals("username")) {
                username = c.getValue();
            }
            if (c.getName().equals("password")) {
                password = c.getValue();
            }
        }
    }
%>
<html>
<head>
    <title>用户信息</title>
</head>
<body>
<h1>用户信息</h1>
<hr>
账户:<%=username%><br>
密码:<%=password%><br>
</body>
</html>
SessionCookie
保存位置服务端客户端
保存类型Object 类String 类
保存数据保存 重要 的数据保存 不重要 的数据
保存时间会话结束 而结束可以 长期 保存至客户端
—————————————–——————————–