跳至主要內容

JSP内置对象

wangdx大约 49 分钟

简介

JavaEE 标准

Java 是一门开源程序语言,所以在 Java 中最重要的设计原则就是标准化,利用接口定义标准,而后不同的厂商依据此标准实现自己的程序逻辑,所以在 JSP 开发中提供有大量的开发接口并且这些接口都被不同厂商所生产的 WEB 容器所实现。

JakartaEE 内置对象

JavaEE 内置对象

<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%
    Class<?> clazz = request.getClass(); // 获取Request对应的类型信息
%>
<h1>Request属性类:<%=clazz%></h1>
<%
    Class<?>[] interfaces = clazz.getInterfaces(); // 获取全部的接口信息
    for (Class<?> temp : interfaces) {
%>
        <h1>父接口:<%=temp%></h1>
<%
    }
%>
</body>
</html>

javaee 官网文档

javaee 官网文档open in new window

JSP 属性范围

在 JSP 程序开发中,一般都会存在有大量的程序页面,并且这些程序页面之间都可能会存在有某些关联,为了保证某一个对象可以实现若干次跨页面的状态保持,在 JSP 中提供了四种属性范围:

  • page 属性范围
  • request 属性范围
  • session 属性范围
  • application 属性范围

page 属性

在每一个 JSP 文件中都可能会根据需要实例化若干个对象,默认情况下这些对象都只能够在当前的页面中进行范围,但是在实际开发中,还有可能通过其他的途径在 Java 程序中进行某些对象的定义,为了方便这些对象的传递与状态保持,所以提供了 page 属性范围


1、
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%  // page属性范围如果要想进行设置,使用的是pageContext内置对象完成的
    pageContext.setAttribute("message", "www.yootk.com"); // 属性名称必须为字符串
    pageContext.setAttribute("score", 150); // 设置的类型不同
%>
<%  // 本页面可以直接获取到page范围的属性内容
    String messageValue = (String) pageContext.getAttribute("message"); // 获取属性
    Integer scoreValue = (Integer) pageContext.getAttribute("score"); // 获取属性
%>
<h1>【获取page属性】message = <%=messageValue%></h1>
<h1>【获取page属性】score = <%=scoreValue%></h1>
</body>
</html>

2、获取不到
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%  // page属性范围如果要想进行设置,使用的是pageContext内置对象完成的
    pageContext.setAttribute("message", "www.yootk.com"); // 属性名称必须为字符串
    pageContext.setAttribute("score", 150); // 设置的类型不同
%>
<jsp:forward page="scope_b.jsp"/>   <%-- 服务端跳转操作 --%>
</body>
</html>

3、 scope_b.jsp
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%  // 本页面可以直接获取到page范围的属性内容
    String messageValue = (String) pageContext.getAttribute("message"); // 获取属性
    Integer scoreValue = (Integer) pageContext.getAttribute("score"); // 获取属性
%>
<h1>【获取page属性】message = <%=messageValue%></h1>
<h1>【获取page属性】score = <%=scoreValue%></h1>
</body>
</html>

4、获取不到
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%  // page属性范围如果要想进行设置,使用的是pageContext内置对象完成的
    pageContext.setAttribute("message", "www.yootk.com"); // 属性名称必须为字符串
    pageContext.setAttribute("score", 150); // 设置的类型不同
%>
<jsp:include page="scope_b.jsp"/>
</body>
</html>

5、可以获取
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%  // page属性范围如果要想进行设置,使用的是pageContext内置对象完成的
    pageContext.setAttribute("message", "www.yootk.com"); // 属性名称必须为字符串
    pageContext.setAttribute("score", 150); // 设置的类型不同
%>
<%@ include file="scope_b.jsp"%>
</body>
</html>

request 属性

request 属性范围是在 JavaWEB 开发中最为常见的一种操作形式,其最大的特点是可以在一次服务器端跳转后依然可以获取所设置的属性内容

1、scope_a.jsp
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%  // 属性设置
    request.setAttribute("message", "www.yootk.com"); // 属性名称必须为字符串
    request.setAttribute("score", 150); // 设置的类型不同
%>
<jsp:forward page="scope_b.jsp"/>   <%-- 服务器端跳转 --%>
</body>
</html>


2、scope_b.jsp
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%  // 本页面可以直接获取到page范围的属性内容
    String messageValue = (String) request.getAttribute("message"); // 获取属性
    Integer scoreValue = (Integer) request.getAttribute("score"); // 获取属性
%>
<h1>【获取request属性】message = <%=messageValue%></h1>
<h1>【获取request属性】score = <%=scoreValue%></h1>
</body>
</html>

3、scope_b.jsp
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%  // 本页面可以直接获取到page范围的属性内容
    String messageValue = (String) request.getAttribute("message"); // 获取属性
    Integer scoreValue = (Integer) request.getAttribute("score"); // 获取属性
%>
<h1>【获取request属性】message = <%=messageValue%></h1>
<h1>【获取request属性】score = <%=scoreValue%></h1>
<h1><a href="scope_c.jsp">属性显示</a></h1>
</body>
</html>

4、scope_c.jsp
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%  // 本页面可以直接获取到page范围的属性内容
    String messageValue = (String) request.getAttribute("message"); // 获取属性
    Integer scoreValue = (Integer) request.getAttribute("score"); // 获取属性
%>
<h1>【获取request属性】message = <%=messageValue%></h1>
<h1>【获取request属性】score = <%=scoreValue%></h1>
</body>
</html>

session 属性范围

在 JSP 中页面的跳转属于常规性的操作,如果现在某些属性希望可以在任意的页面跳转之后还可以继续使用,那么就可以通过 session 属性来完成,session 属性的特点在手,只要设置了属性并且没有关闭页面的情况下,该属性可以持续有效

1、
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%  // 属性设置
    session.setAttribute("message", "www.yootk.com"); // 属性名称必须为字符串
    session.setAttribute("score", 150); // 设置的类型不同
%>
<jsp:forward page="scope_b.jsp"/>   <%-- 服务器端跳转 --%>
</body>
</html>

2、
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%  // 本页面可以直接获取到page范围的属性内容
    String messageValue = (String) session.getAttribute("message"); // 获取属性
    Integer scoreValue = (Integer) session.getAttribute("score"); // 获取属性
%>
<h1>【获取session属性】message = <%=messageValue%></h1>
<h1>【获取session属性】score = <%=scoreValue%></h1>
<h1><a href="scope_c.jsp">属性显示</a></h1>
</body>
</html>

3\
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%
    String messageValue = (String) session.getAttribute("message"); // 获取属性
    Integer scoreValue = (Integer) session.getAttribute("score"); // 获取属性
%>
<h1>【获取session属性】message = <%=messageValue%></h1>
<h1>【获取session属性】score = <%=scoreValue%></h1>
</body>
</html>

application 属性

application 属性可以实现全局属性的配置,即:所有的属性保存在服务器之中,不管用户是否关闭页面,都可以获取到设置的 application 属性,只有在 WEB 容器重启后此属性才会消失

1、
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%  // 属性设置
    application.setAttribute("message", "www.yootk.com"); // 属性名称必须为字符串
    application.setAttribute("score", 150); // 设置的类型不同
%>
</body>
</html>


2、
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%  // 本页面可以直接获取到page范围的属性内容
    String messageValue = (String) application.getAttribute("message"); // 获取属性
    Integer scoreValue = (Integer) application.getAttribute("score"); // 获取属性
%>
<h1>【获取application属性】message = <%=messageValue%></h1>
<h1>【获取application属性】score = <%=scoreValue%></h1>
</body>
</html>


pagecontext 扩展属性

操作方法在 pageContext 类中提供了更加全面的属性操作支持方法,可以实现全部四种属性范围的控制

1、
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%  // 属性设置
    pageContext.setAttribute("message", "www.yootk.com", PageContext.REQUEST_SCOPE); // 属性名称必须为字符串
    pageContext.setAttribute("score", 150, PageContext.SESSION_SCOPE); // 设置的类型不同
%>
<jsp:forward page="scope_b.jsp"/>   <%-- 服务端跳转 --%>
</body>
</html>

2、
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%  // 本页面可以直接获取到page范围的属性内容
    String messageValue = (String) pageContext.getAttribute("message", PageContext.REQUEST_SCOPE); // 获取属性
    Integer scoreValue = (Integer) session.getAttribute("score"); // 获取属性
%>
<h1>【获取request属性】message = <%=messageValue%></h1>
<h1>【获取session属性】score = <%=scoreValue%></h1>
</body>
</html>

request 对象

对象简介

JSP 程序的开发核心为请求(request)与响应(response),用户所需要的所有数据都会封装在 HTTP 请求之中,在服务器端程序如果要想获取这些请求数据,就可以通过 request 内置对象完成,request 对象对应的类型为 javax.servlet.http 包中的 HttpServletRequest 接口

1、
public interface HttpServletRequest
extends ServletRequest

2、
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%
    Class<?> clazz = request.getClass(); // 获取Request对应的类型信息
%>
<h1>Request属性类:<%=clazz%></h1>
</body>
</html>

接收请求参数

HttpServletRequest 接囗的核心作用在于接收用户的请求,所有可以接收的用户请求一定都包含有参数名称,而请求参数的来源可以是表单填写或者是通过 URL 地址重写的方式进行传递但是不管如何传递只要是参数接收都采用如下的方法进行统一处理:

public String getParameter(String paramName)

1、
public String getParameter(String name)

2、
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
    <meta charset="UTF-8">
</head>
<body>
<form action="input_do.jsp" method="post">  <!-- 只要是表单定义在99%的情况下使用的都是POST提交模式 -->
    请输入信息:<input type="text" name="msg" value="沐言科技">
    <!--  在HTML元素里面表单中提供有隐藏域,隐藏域的特点是内容为固定的  -->
    <input type="hidden" name="url" value="www.yootk.com">
    <input type="submit" value="发送">
</form>
</body>
</html>

3、
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%
    String msg = request.getParameter("msg"); // 接收请求参数
    String url = request.getParameter("url"); // 接收请求参数
%>
<h1><%=msg%>:<%=url%></h1>
</body>
</html>

4、
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
    <meta charset="UTF-8">
</head>
<body>
<form action="input_do.jsp" method="post">  <!-- 只要是表单定义在99%的情况下使用的都是POST提交模式 -->
    请输入信息:  <input type="text" name="msg" value="MuyanYootk"><br>
    信息等级:   <select name="level">
                    <option value="0">绝密</option>
                    <option value="1">秘密</option>
                    <option value="2">普通</option>
                    <option value="3">公开</option>
                </select><br>
    <!--  在HTML元素里面表单中提供有隐藏域,隐藏域的特点是内容为固定的  -->
    <input type="hidden" name="url" value="www.yootk.com">
    <input type="submit" value="发送">
</form>
</body>
</html>

5、
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%
    String msg = request.getParameter("msg"); // 接收请求参数
    String url = request.getParameter("url"); // 接收请求参数
    int level = Integer.parseInt(request.getParameter("level")); // 接收的参数数据并转型
    String levelContent = null;
    switch(level) {
        case 0:
            levelContent = "绝密";
            break;
        case 1:
            levelContent = "秘密";
            break;
        case 2:
            levelContent = "普通";
            break;
        case 3:
            levelContent = "公开";
            break;
    }
%>
<h1><%=msg%>:<%=url%></h1>
<h1>信息等级:<%=levelContent%></h1>
</body>
</html>

6、
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
    <meta charset="UTF-8">
</head>
<body>
<!-- 只要是表单定义在99%的情况下使用的都是POST提交模式 -->
<form action="input_do.jsp" method="get">
    请输入信息:  <input type="text" name="msg" value="MuyanYootk"><br>
    信息等级:   <select name="level">
                    <option value="0">绝密</option>
                    <option value="1">秘密</option>
                    <option value="2" selected>普通</option>
                    <option value="3">公开</option>
                </select><br>
    <!--  在HTML元素里面表单中提供有隐藏域,隐藏域的特点是内容为固定的  -->
    <input type="hidden" name="url" value="www.yootk.com">
    <input type="submit" value="发送">
</form>
</body>
</html>

7、
http://localhost/input_do.jsp?msg=&level=0&url=edu.yootk.com

8、
http://localhost/input_do.jsp?level=0&url=edu.yootk.com

9、
http://localhost/input_do.jsp?url=edu.yootk.com

10、
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%
    String msg = request.getParameter("msg"); // 接收请求参数
    String url = request.getParameter("url"); // 接收请求参数
    int level = 99; // 设置一个level默认值
    try {
        Integer.parseInt(request.getParameter("level")); // 接收的参数数据并转型
    } catch (Exception e) {} // 这个异常不需要输出了
    String levelContent = null;
    switch(level) {
        case 0:
            levelContent = "绝密";
            break;
        case 1:
            levelContent = "秘密";
            break;
        case 2:
            levelContent = "普通";
            break;
        case 3:
            levelContent = "公开";
            break;
        default:
            levelContent = "未知";
            break;
    }
%>
<h1><%=msg%>:<%=url%></h1>
<h1>信息等级:<%=levelContent%></h1>
</body>
</html>

设置请求编码

在 WEB 请求中,所有的数据都是以二进制的形式进行传输的这样就需要对所发送的数据进行编码与解码处理,但是如果说此时传递的是中文数据,并且编码和解码不同,就有可能造成乱码问题,在实际的开发中一般都会使用“UTF-8”编码,而此时就可以利用 request 对象的如下方法实现请求编码设置>

public void setCharacterEncoding(String env) throwsUnsupportedEncodingException

1、
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
    <meta charset="UTF-8">
</head>
<body>
<!-- 只要是表单定义在99%的情况下使用的都是POST提交模式 -->
<form action="input_do.jsp" method="post">
    请输入信息:  <input type="text" name="msg" value="沐言科技"><br>
    <!--  在HTML元素里面表单中提供有隐藏域,隐藏域的特点是内容为固定的  -->
    <input type="hidden" name="url" value="www.yootk.com">
    <input type="submit" value="发送">
</form>
<h1><a href="input_do.jsp?msg=沐言科技&url=edu.yootk.com">参数显示</a></h1>
</body>
</html>


2、
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%
    String msg = request.getParameter("msg"); // 接收请求参数
    String url = request.getParameter("url"); // 接收请求参数
%>
<h1><%=msg%>:<%=url%></h1>
</body>
</html>

3、
public void setCharacterEncoding(String env) throws UnsupportedEncodingException

4、
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%
    request.setCharacterEncoding("UTF-8"); // 设置请求编码
    response.setCharacterEncoding("UTF-8"); // 设置响应编码
    String msg = request.getParameter("msg"); // 接收请求参数
    String url = request.getParameter("url"); // 接收请求参数
%>
<h1><%=msg%>:<%=url%></h1>
</body>
</html>


5、
package com.yootk.test;

import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.Charset;

public class TestCode {
    public static void main(String[] args) {
        String message = "沐言科技:www.yootk.com";
        String encodeValue = URLEncoder.encode(message, Charset.forName("UTF-8")); // 编码操作
        System.out.println("【编码结果】" + encodeValue);
        String value = URLDecoder.decode(encodeValue, Charset.forName("UTF-8")); // 解码操作
        System.out.println("【解码结果】" + value);
    }
}

http://localhost/input_do.jsp?msg=%E6%B2%90%E8%A8%80%E7%A7%91%E6%8A%80&url=edu.yootk.com

数组参数

请求参数除了可以实现单个参数的接收之外,也可以实现一组参数的接收,此时就要求传递的若干个参数内容采用相同的参数名称,而对于数组参数的接收则可以使用以下方法完成:

public Stringll getParameterValues(String name)

1、
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
    <meta charset="UTF-8">
</head>
<body>
<!-- 只要是表单定义在99%的情况下使用的都是POST提交模式 -->
<form action="input_do.jsp" method="post">
    请输入信息:<input type="text" name="msg" value="沐言科技"><br>
    消息接收者:<input type="checkbox" name="receiver" value="muyan" checked>沐言科技
            <input type="checkbox" name="receiver" value="yootk">沐言优拓
            <input type="checkbox" name="receiver" value="lee" checked>爆可爱的小李<br>
    <input type="submit" value="发送"><input type="reset" value="重置">
</form>
</body>
</html>


2、
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%
    request.setCharacterEncoding("UTF-8"); // 设置请求编码
    response.setCharacterEncoding("UTF-8"); // 设置响应编码
    String msg = request.getParameter("msg"); // 接收请求参数
    String receiver = request.getParameter("receiver"); //
%>
<h1>消息内容:<%=msg%></h1>
<h1>消息用户:<%=receiver%></h1>
</body>
</html>

3、

<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%
    request.setCharacterEncoding("UTF-8"); // 设置请求编码
    response.setCharacterEncoding("UTF-8"); // 设置响应编码
    String [] msg = request.getParameterValues("msg"); // 接收请求参数
    String [] receiver = request.getParameterValues("receiver"); //
%>
<h1>消息内容:<%=java.util.Arrays.toString(msg)%></h1>
<h1>消息用户:<%=java.util.Arrays.toString(receiver)%></h1>
</body>
</html>

动态获取参数

在参数接收中,常规的做法都是需要明确的知道请求参数的名称,而后才可以正常接收,但是如果所发送的参数会被经常性的改变,这样固定的模式就无法满足程序的开发要求,为了解决此类问题,在 request 内置对象中提供了一个动态接收参数的方法:

public Map<String,Stringl]> getParameterMap()

1、
<%@ page import="java.util.Enumeration" %>
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%
    request.setCharacterEncoding("UTF-8"); // 设置请求编码
    response.setCharacterEncoding("UTF-8"); // 设置响应编码
    Enumeration<String> enumeration = request.getParameterNames(); // 实现了全部请求参数的接收
    while (enumeration.hasMoreElements()) { // 直接迭代
        String paramName = enumeration.nextElement(); // 获取参数名称
%>
        <h2><%=paramName%> = <%=java.util.Arrays.toString(request.getParameterValues(paramName))%></h2>
<%
    }
%>
</body>
</html>

2、
<%@ page pageEncoding="UTF-8" import="java.util.*"%>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%
    request.setCharacterEncoding("UTF-8"); // 设置请求编码
    response.setCharacterEncoding("UTF-8"); // 设置响应编码
    Map<String, String[]> paramMap = request.getParameterMap(); // 获取全部参数和内容
    for (Map.Entry<String, String[]> entry : paramMap.entrySet()){
%>
        <h2><%=entry.getKey()%> = <%=java.util.Arrays.toString(entry.getValue())%></h2>
<%
    }
%>
</body>
</html>

获取上下文路径

资源获取

在 WEB 中如果需要进行某些资源文件(例如:图片 JavaScript 程序等)加载时往往都需要编写大量的相对路径这样一日所需要加载的资源存储路径过深,则会造成路径匹配的繁琐程度,在动态 WEB 中为了解决此类问题,可以直接利用 request 对象中的 getContextPath()方法获取当前上下文路径名称,而后从根路径开始实现资源匹配,

1、public String getContextPath()
1、public String getContextPath()

2、
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<h1>ContextPath = <%=request.getContextPath()%></h1>
</body>
</html>

3、
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<h1>ContextPath = <%=request.getContextPath()%></h1>
<div><img src="images/logo.png"></div>
</body>
</html>

4、
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<h1>ContextPath = <%=request.getContextPath()%></h1>
<div><img src="../../images/logo.png"></div>
</body>
</html>

5、
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<h1>ContextPath = <%=request.getContextPath()%></h1>
<div><img src="<%=request.getContextPath()%>/images/logo.png"></div>
</body>
</html>

base

利用 request 内置对象中的 getContextPath()方法的确可以非常方便的获取对应的上下文路径,但是如果所有的资源都采用此类的方式进行访问,则会非常的繁琐,为了进一步简化资源加载的问题,可以在元素进行统-资源定位项目中通过 HTML 中的"<base>"

1、
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<h1>ContextPath = <%=request.getContextPath()%></h1>
<div><img src="<%=request.getContextPath()%>/images/logo.png"></div>
<div><img src="<%=request.getContextPath()%>/images/logo.png"></div>
<div><img src="<%=request.getContextPath()%>/images/logo.png"></div>
<div><img src="<%=request.getContextPath()%>/images/logo.png"></div>
<div><img src="<%=request.getContextPath()%>/images/logo.png"></div>
<%-- 假装这里面还有50行的代码,此处被注释一笔带略... --%>
<div><img src="<%=request.getContextPath()%>/images/logo.png"></div>
</body>
</html>


2、
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<%
    String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath() + "/";
    out.print(basePath);
%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
    <base href="<%=basePath%>">
</head>
<body>
<div><img src="images/logo.png"></div>
</body>
</html>

获取请求信息

在用户每一次发出请求之后除了所有的数据之外,实际上还会包含有一些附加的信息,包括:请求方法、用户访问地址等内容

Response

用户接收完请求后,需要对客户端进行响应,在 JSP 中所有的响应都是通过 response 内置对象实现的,response 对象对应的接口类型为"javax.servlet.http.HttpServetResponse 该接口继承子"javax.servlet.ServletResponse”父接,而后不同厂商的 WEB 容器都需要实现该接口以实现响应处理

response 响应输出

所有的 JSP 程序在进行响应前都需要经过 WEB 容器进行处理,实际上所有输出到客户端的 HTML 代码都是由 response 响应的结果,在 response 中可以直接通过 IO 流进行输出


1、
<%@ page import="java.io.PrintWriter" %>
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<%
    PrintWriter printWriter = response.getWriter(); // 获取客户端打印流
    printWriter.println("<h1>沐言科技:www.yootk.com</h1>"); // 设置响应内容
    printWriter.close(); // 关闭打印流
%>

2、

<%@ page import="java.io.PrintWriter" %>
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<%
    request.setCharacterEncoding("UTF-8");
    response.setCharacterEncoding("UTF-8");
    PrintWriter printWriter = response.getWriter(); // 获取客户端打印流
    printWriter.println("<h1>沐言科技:www.yootk.com</h1>"); // 设置响应内容
    printWriter.close(); // 关闭打印流
%>

HTTP 头信息

用户在每一次发出请求以及服务器响应时,除了所需要的核心数据之外,还会包含有许多的附加信息,这些附加信息就属于头信息

1、
<%@ page pageEncoding="UTF-8" import="java.util.*" %>    <%-- 设置显示编码 --%>
<%
    Enumeration<String> headerNamesEunm = request.getHeaderNames(); // 获取全部头信息名称
    while (headerNamesEunm.hasMoreElements()) {
        String headerName = headerNamesEunm.nextElement(); // 获得头信息的名称
%>
        <h2><%=headerName%> = <%=request.getHeader(headerName)%></h2>
<%
    }
%>

2、
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<h1>URI信息:<%=request.getRequestURI()%></h1>
<h1>URL信息:<%=request.getRequestURL()%></h1>
<a href="get_headers.jsp">获取请求头信息</a>
</body>
</html>

3、
<%@ page pageEncoding="UTF-8" import="java.util.*" %>    <%-- 设置显示编码 --%>
<%! int num = 1; // 全局变量%>
<%
    response.addHeader("refresh", "1"); // 设置刷新头信息,每秒刷新1次
%>
<h1>num = <%=num ++%></h1>

4、
<%@ page pageEncoding="UTF-8" import="java.util.*" %>    <%-- 设置显示编码 --%>
<%
    response.addHeader("refresh", "2; url=get_headers.jsp"); // 设置定时跳转
%>

HTTP 状态码

HTTP 协议是基于 TCP 协议基础实现的扩展协议,所有的数据在进行传输时都有其固定的处理存储结构,在每次请求过程时,除了基本的数据和头信息之外实际上还会包括有请求模式、请求路径、HTTP 版本号内容,而在响应时除了数据和头信息职位外,也会包含有 HTTP 版本号、响应状态码等内容

<%@ page pageEncoding="UTF-8" import="java.util.*" %>
<%
    response.setStatus(HttpServletResponse.SC_NOT_FOUND); // 404状态码
%>
<h1>沐言科技:www.yootk.com</h1>

请求重定向

在 WEB 开发中页面之间可以通过超链接的方式实现跳转,如果现在希望可以通过程序的方式来实现类似于超链接的跳转操作则可以通过 response 对象中提供的请求重定向方法完成>操作方法:

public void sendRedirect(String location) throws lOException

1、
<%@ page pageEncoding="UTF-8" import="java.util.*" %>
<%
    response.sendRedirect("welcome.jsp"); // 请求重定向
%>

2、
<%@ page pageEncoding="UTF-8" import="java.util.*" %>
<%
    System.out.println("【BEFORE】*****************************");
%>
<%
    response.sendRedirect("welcome.jsp"); // 请求重定向
%>
<%
    System.out.println("【AFTER】*****************************");
%>

3、
<%@ page pageEncoding="UTF-8" import="java.util.*" %>
<%
    System.out.println("【BEFORE】*****************************");
%>
<jsp:forward page="welcome.jsp"/>
<%
    System.out.println("【AFTER】*****************************");
%>

HTTP 属于无状态的网络通讯协议,服务器端为了便于状态保持可以在客户端保存有部分的数据信息,这样的信息在 HTTP 协议中被称为 Cookie(小甜饼干),所有的 Cookie 由服务器端进行设置而在设置后会随着请求头信息发送到服务器之中

Cookie 类

在 JavaWEB 中,Cookie 数据操作被封装在 javax.servlet.http.Cookie 类中。在进行 Cookie 操作时必须通过关键字 new 实例化对象,同时设置 Cookie 的名称(name)以及对应内容(value)

Cooke 存储路径

在进行 Cookie 操作时,必须注意 Cookie 的保存路径,如果一个 Cookie 的保存路径被设置为“/”,则表示该 Cookie 可以在 WEB 中的任意目录下访问,如果一个 Cookie 的保存路径设置为“/pages 则表示只允许“/pages”路径下的所有程序进行访问

1、jakarta.servlet.http.Cookie

2、
public class Cookie
extends Object
implements Cloneable, Serializable

3、
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%
    Cookie cookie = new Cookie("message", "www.yootk.com"); // 实例化了Cookie类对象
    response.addCookie(cookie); // 进行Cookie响应
%>
</body>
</html>

4、public Cookie[] getCookies()

5、
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%
    Cookie [] cookies = request.getCookies(); // 获取全部的客户端发送的Cookie数据
    for (Cookie cookie : cookies) { // foreach循环结构输出
%>
        <%=cookie.getName()%> = <%=cookie.getValue()%>
<%
    }
%>
</body>
</html>

6、
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%
    Cookie [] cookies = request.getCookies(); // 获取全部的客户端发送的Cookie数据
    if (cookies != null) {
        for (Cookie cookie : cookies) { // foreach循环结构输出
%>
            <%=cookie.getName()%> = <%=cookie.getValue()%><br>
<%
        }
    } else {
%>
            <h2>对不起,本次的请求没有任何的Cookie数据!</h2>
<%
        }
%>
</body>
</html>

7、
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%
    Cookie cookieA = new Cookie("message", "www.yootk.com"); // 实例化了Cookie类对象
    Cookie cookieB = new Cookie("information", "edu.yootk.com"); // 实例化了Cookie类对象
    cookieA.setMaxAge(30);
    cookieB.setMaxAge(60);
    response.addCookie(cookieA); // 进行Cookie响应
    response.addCookie(cookieB); // 进行Cookie响应
%>
</body>
</html>

8、
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%
    Cookie [] cookies = request.getCookies(); // 获取全部的客户端发送的Cookie数据
    if (cookies != null) {
        for (Cookie cookie : cookies) { // foreach循环结构输出
%>
            <%=cookie.getName()%> = <%=cookie.getValue()%>(<%=cookie.getPath()%>)<br>
<%
        }
    } else {
%>
            <h2>对不起,本次的请求没有任何的Cookie数据!</h2>
<%
        }
%>
</body>
</html>

9、

<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%
    Cookie cookieA = new Cookie("message", "www.yootk.com"); // 实例化了Cookie类对象
    Cookie cookieB = new Cookie("information", "edu.yootk.com"); // 实例化了Cookie类对象
    cookieA.setMaxAge(3600);
    cookieB.setMaxAge(3600);
    cookieA.setPath("/"); // 设置生效路径
    cookieB.setPath("/yootk/message/"); // 生效路径
    response.addCookie(cookieA); // 进行Cookie响应
    response.addCookie(cookieB); // 进行Cookie响应
%>
</body>
</html>

session

在 WEB 容器中为了方便的区分不同的用户,每一个用户都有一个对应的 session(会话)对象,当用户通过浏览器向 WEB 服务器发出访问请求时,服务器会自动对该用户的 session 状态进行维护,不同客户端的访问用户拥有各自的 session 对象,不同的 session 之间彼此隔离,不允许直接访问

session 继承结构

JSP 中为便于用户状态管理提供了 session 内置对象,该对象对应的接口类型为“javax.servlet.http.HttpSession”,由于 session 属于 http 协议定义范畴,所以 HttpSession 是一个独立的接口没有任何的继承关系

<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
RequestClass = <%=request.getClass()%>
ResponseClass = <%=response.getClass()%>
SessionClass = <%=session.getClass()%>
</body>
</html>

session 工作原理

Session 数据存储结构

每一个数据都通过一个 Map 集合的形式表示,其中 Map 的 Key 是一个 SessionID 标志,而 Map 对应的 value 则是另外一个 Map 集合

1、
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
SessionID = <%=session.getId()%>
</body>
</html>

2、
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
SessionID = <%=session.isNew()%>
</body>
</html>

3、
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<h1>【原始】SessionID = <%=session.getId()%></h1>
<h1>【变更】SessionID = <%=request.changeSessionId()%></h1>
</body>
</html>

session 线程池

每一个用户的请求在 WEB 容器中都会通过一个 Session 实例化对象进行描述,这样在服务端就需要同时维护若于个 Session 线程,为了便于 Session 管理,在 Tomcat 内部会默认创建线程池保存所有的可用资源,这样就可以保证在高并发状态下每一个请求的正确处理

1、
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<h1>【SessionID与线程池】<%=session.getId()%> = <%=Thread.currentThread().getName()%></h1>
</body>
</html>

2、
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<h1>【SessionID与线程池】<%=session.getId()%> = <%=Thread.currentThread().getName()%></h1>
<h1>【主机CPU内核数量】<%=Runtime.getRuntime().availableProcessors()%></h1>
</body>
</html>

3、
    <Connector port="80" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443"
			   maxThreads="16" minSpareThreads="16" acceptCount="32"/>

session 登录验证

session 的主要作用是保存用户的操作状态,在实际项目开发中主要是通过 session 实现登录认证处理,现在假设项目中存在有一些重要的页面,并且这些页面必须要求用户登录后才可以访问,那么这样的功能就可以通过 session 的属性操作来实现

代码地址open in new window

1、
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%
    String error = request.getParameter("error"); // 保存错误信息
    if (!(error == null || "".equals(error))) { // 现在有数据
%>
        <h1>登录失败,错误的用户名或密码!</h1>
<%
    }
%>
<form action="check.jsp" method="post">
    用户名:<input type="text" name="uname" value="muyan"><br>
    密码:<input type="password" name="upass" value="yootk"><br>
    <button type="submit">登录</button><button type="reset">重置</button>
</form>
</body>
</html>

2、
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%
    String uname = request.getParameter("uname"); // 获取登录用户名
    String upass = request.getParameter("upass"); // 获取登录密码
    // 当前系统之中的用户认证信息是固定的,用户名为muyan,密码为yootk
    if ("muyan".equals(uname) && "yootk".equals(upass)) {   // 用户登录合法
        response.setHeader("refresh", "2;url=welcome.jsp"); // 2秒后自动跳转到welcome.jsp页面
        // 将当前的用户名保存在session属性范围之中,不管如何跳转,只要不关闭浏览器都可以获取该数据
        session.setAttribute("id", uname);
%>
        <h1>用户登录成功,欢迎您的光临,2秒后跳转到欢迎页!</h1>
<%
    } else {    // 错误的用户名或密码
        response.setHeader("refresh", "2; url=login.jsp?error=yootk.com");
%>
        <h1>用户登录失败,错误的用户名或密码!</h1>
<%
    }
%>
</body>
</html>

3、
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%
    if (session.getAttribute("id") != null) {   // 现在存在有session属性
%>
        <img src="images/logo.png" style="width:200px;">
        <h1>欢迎您的访问,请为自己认真学习编程技术,<a href="logout.jsp">系统注销</a></h1>
<%
    } else {    // 现在没有登录过
        response.setHeader("refresh", "2;url=login.jsp");
%>
        <h1>非法用户,不允许进行程序访问!</h1>
<%
    }
%>
</body>
</html>

4、

<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%
    session.invalidate(); // 系统注销
%>
<h1>您已成功注销,下次再见,<a href="login.jsp">重新登录</a></h1>
</body>
</html>

验证码检测

在项目引入动态的验证码,在每次进行登录验证前先进行验证码的输入校验,如果验证码输入正确,才进行用户名和密码的检验,同时为了保证验证码的安全,往往通过图片的方式进行显示

w15

1、

<%@ page pageEncoding="UTF-8"%> 			<%-- 设置页面编码 --%>
<%@ page contentType="image/jpeg"%>                	<%-- MIME显示风格为图片 --%>
<%@ page import="java.awt.*,java.awt.image.*,java.util.*,javax.imageio.*"%>
<%!Color getRandColor(int fc, int bc) {    		// 获取随机颜色
      Random random = new Random();
      if (fc > 255) { 				// 设置颜色边界
         fc = 255;
      }
      if (bc > 255) { 				// 设置颜色边界
         bc = 255;
      }
      int r = fc + random.nextInt(bc - fc); 	// 随机生成红色数值
      int g = fc + random.nextInt(bc - fc); 	// 随机生成绿色数值
      int b = fc + random.nextInt(bc - fc); 	// 随机生成蓝色数值
      return new Color(r, g, b); 			// 随机返回颜色对象
   }%>
<%
   response.setHeader("Pragma", "No-cache"); 	// 【HTTP1.0】设置页面不缓存
   response.setHeader("Cache-Control", "no-cache");	// 【HTTP1.1】设置页面不缓存
   response.setDateHeader("Expires", 0); 		// 设置缓存失效时间
   int width = 80; 				// 生成图片宽度
   int height = 25; 				// 生成图片高度
   BufferedImage image = new BufferedImage(width, height,
         BufferedImage.TYPE_INT_RGB); 		// 内存中创建图象
   Graphics g = image.getGraphics();		// 获取图形上下文对象
   Random random = new Random();  			// 实例化随机数类
   g.setColor(getRandColor(200, 250));     		// 设定背景色
   g.fillRect(0, 0, width, height); 		// 绘制矩形
   g.setFont(new Font("宋体", Font.PLAIN, 18)); 	// 设定字体
   g.setColor(getRandColor(160, 200)); 		// 获取新的颜色
   for (int i = 0; i < 155; i++) { 		// 产生干扰线
      int x = random.nextInt(width);
      int y = random.nextInt(height);
      int xl = random.nextInt(12);
      int yl = random.nextInt(12);
      g.drawLine(x, y, x + xl, y + yl); 		// 绘制长线
   }
   StringBuffer sRand = new StringBuffer();	// 保存生成的随机数
   // 如果要使用中文,必须定义字库,可以使用数组进行定义,同时必须将中文转换为unicode编码
   String[] str = { "A", "B", "C", "D", "E", "F", "G", "H", "J", "K",
         "L", "M", "N", "P", "Q", "R", "S", "T", "U", "V", "W", "X",
         "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j",
         "k", "m", "n", "p", "s", "t", "u", "v", "w", "x", "y", "z",
         "1", "2", "3", "4", "5", "6", "7", "8", "9" };
   for (int i = 0; i < 4; i++) { 			// 生成4位随机数
      String rand = str[random.nextInt(str.length)];// 获取随机数
      sRand.append(rand); 				// 随机数保存
      g.setColor(new Color(20 + random.nextInt(110), 20 + random.nextInt(110),
             20 + random.nextInt(110))); 		// 将认证码显示到图象中
      g.drawString(rand, 16 * i + 6, 19); 		// 图形绘制
   }
   session.setAttribute("rand", sRand.toString());	// 将认证码存入SESSION
   g.dispose();					// 图象生效
   ImageIO.write(image, "JPEG", response.getOutputStream());// 输出图象到页面
   out.clear();					// 避免输出冲突
   out = pageContext.pushBody();			// 避免输出冲突
%>

2、
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%
    String error = request.getParameter("error"); // 保存错误信息
    if (!(error == null || "".equals(error))) { // 现在有数据
%>
        <h1>登录失败,错误的用户名或密码!</h1>
<%
    }
%>
<form action="check.jsp" method="post">
    用户名:<input type="text" name="uname" value="muyan"><br>
    密码:<input type="password" name="upass" value="yootk"><br>
    验证码:<input type="text" maxlength="4" size="4" name="code"><img src="image.jsp"><br>
    <button type="submit">登录</button><button type="reset">重置</button>
</form>
</body>
</html>

3.
<%@ page pageEncoding="UTF-8" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%
    String code = request.getParameter("code"); // 获取用户输入的验证码
    String rand = session.getAttribute("rand").toString(); // 获取生成的验证码
    if (!rand.equalsIgnoreCase(code)) {  // 验证码不匹配
%>
        <jsp:forward page="login.jsp"/>
<%
    }
%>
<%
    String uname = request.getParameter("uname"); // 获取登录用户名
    String upass = request.getParameter("upass"); // 获取登录密码
    // 当前系统之中的用户认证信息是固定的,用户名为muyan,密码为yootk
    if ("muyan".equals(uname) && "yootk".equals(upass)) {   // 用户登录合法
        response.setHeader("refresh", "2;url=welcome.jsp"); // 2秒后自动跳转到welcome.jsp页面
        // 将当前的用户名保存在session属性范围之中,不管如何跳转,只要不关闭浏览器都可以获取该数据
        session.setAttribute("id", uname);
%>
        <h1>用户登录成功,欢迎您的光临,2秒后跳转到欢迎页!</h1>
<%
    } else {    // 错误的用户名或密码
        response.setHeader("refresh", "2; url=login.jsp?error=yootk.com");
%>
        <h1>用户登录失败,错误的用户名或密码!</h1>
<%
    }
%>
</body>
</html>

application

application 是 javax.servlet.ServletContext 接日实例,明确的描述的是一个 WEB 应用上下文环境,在 Tomcat 中可以同时部署多个 WEB 应用,并且每一个不同的上下文中都存在有各自的 application 内置对象

<%@ page pageEncoding="UTF-8" import="java.util.*"%>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%
    Enumeration<String> enumeration = application.getAttributeNames(); // 获取全部属性的名称
    while(enumeration.hasMoreElements()) {
        String name = enumeration.nextElement(); // 获取属性名称
%>
        <p><%=name%> = <%=application.getAttribute(name)%></p>
<%
    }
%>
</body>
</html>

真实路径

每一个 WEB 应用都对应有一个磁盘的真实存储路径,由于 WEB 开发环境和部署环境往往不同,所以就需要可以在代码中动态的获取项目所在的真实路径,这样的功能就可以通过 ServletContext 接口中的“getRealPath()”方法来获得> public String getRealPath(String path)

1、
<%@ page pageEncoding="UTF-8" import="java.util.*"%>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%  // 任何情况下,每一个WEB应用都一定会存在有一个根路径
    String diskPathA = application.getRealPath("/"); // 获取根路径对应的真实路径
    String diskPathB = application.getRealPath("/uploads/"); // 获取一个子路径
%>
<h1><%=diskPathA%></h1>
<h1><%=diskPathB%></h1>
</body>
</html>

2、
<%@ page pageEncoding="UTF-8" import="java.util.*,java.io.*"%>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%  // 任何情况下,每一个WEB应用都一定会存在有一个根路径
    String diskPathA = application.getRealPath("/"); // 获取根路径对应的真实路径
    String diskPathB = application.getRealPath("/uploads/"); // 获取一个子路径
%>
<h1><%=diskPathA%>、<%=new File(diskPathA).exists()%></h1>
<h1><%=diskPathB%>、<%=new File(diskPathB).exists()%></h1>
</body>
</html>

3、
<%@ page pageEncoding="UTF-8"%>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%  // 任何情况下,每一个WEB应用都一定会存在有一个根路径
    String diskPathA = getServletContext().getRealPath("/"); // 获取根路径对应的真实路径
    String diskPathB = this.getServletContext().getRealPath("/uploads/"); // 获取一个子路径
%>
<h1><%=diskPathA%></h1>
<h1><%=diskPathB%></h1>
</body>
</html>

初始化参数

在 WEB 应用中会存在有大量的属性内容,这些属性一般分为两种。一种是 Tomcat 启动时自动设置的系统属性,另外一种就是用户通过程序设置的应用属性,这些属性被所有的 session 共享。除了系统属性的处理之外,在 application 中还提供了初始化属性的获取操作,而这些初始化的属性必须通过“WEB-INF/web.xm”文件进行配置。

1、
    <context-param> <!-- 定义application初始化信息 -->
        <param-name>basePackages</param-name> <!-- 参数名称 -->
        <param-value>com.yootk.service,com.yootk.dao</param-value> <!-- 参数内容 -->
    </context-param>
    <context-param> <!-- 定义application初始化信息 -->
        <param-name>resources</param-name> <!-- 参数名称 -->
        <param-value>/META-INF/config/*.xml</param-value> <!-- 参数内容 -->
    </context-param>

2、
<%@ page pageEncoding="UTF-8" import="java.util.*" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%  // 任何情况下,每一个WEB应用都一定会存在有一个根路径
    Enumeration<String> enumeration = this.getServletContext().getInitParameterNames(); // 获取全部初始化参数名称
    while (enumeration.hasMoreElements()) { // 迭代获取名称
        String name = enumeration.nextElement(); // 获取参数名称
%>
        <%=name%> = <%=application.getInitParameter(name)%><br>
<%
    }
%>
</body>
</html>

WEB 文件操作

在 WEB 开发中,由于 WebContainer 的支持,可以直接实现名类资源的处理,包括:JDBC、网络 10、文件 IO 处理,而要想完成文件的操作,一般的做法是要获取到一个文件的完整路径而后基于 java.io 包提供的类实现文件的存储与读取

1、
<%@ page pageEncoding="UTF-8" import="java.io.*" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%  // 此时所定位到的文件路径有可能是不存在的,包括目录也有可能是不存在的
    String filePath = this.getServletContext().getRealPath("/uploads/muyan.txt");
    File file = new File(filePath); // 创建File对象
    if (!file.getParentFile().exists()) {   // 不存在父路径
        file.getParentFile().mkdirs(); // 创建父路径
    }
    PrintWriter pw = new PrintWriter(file); // 实例化一个打印流对象
    pw.println("沐言科技:www.yootk.com");
    pw.println("沐言科技:www.yootk.com");
    pw.println("沐言讲师:李兴华 —— 江湖人称“小李老师”");
    pw.close();
%>
</body>
</html>

2、
<%@ page pageEncoding="UTF-8" import="java.io.*,java.text.*" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    String filePath = this.getServletContext().getRealPath("/uploads/");
    File file = new File(filePath);
    File result [] = file.listFiles(); // 获取文件列表
%>
<h2>当前访问路径:<%=filePath%></h2>
<table border="1">
    <thead>
        <tr>
            <td style="width: 200px;">文件名称</td>
            <td style="width: 200px;">文件大小</td>
            <td style="width: 200px;">最后一次修改日期</td>
        </tr>
    </thead>
    <tbody>
    <%
        for (int x = 0; x < result.length; x++) {
    %>
        <tr>
            <td><a href="file_load.jsp?fname=<%=result[x].getName()%>"><%=result[x].getName()%></a></td>
            <td><%=result[x].length()%></td>
            <td><%=sdf.format(new java.util.Date(result[x].lastModified()))%></td>
        </tr>
    <%
        }
    %>
    </tbody>
</table>
</body>
</html>

3、
<%@ page pageEncoding="UTF-8" import="java.io.*,java.util.*" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%
    String filePath = this.getServletContext().getRealPath("/uploads/" + request.getParameter("fname"));
    File file = new File(filePath);
    Scanner scanner = new Scanner(file); // 文件读取
    scanner.useDelimiter("\n");
%>
<h2>当前访问路径:<%=filePath%></h2>
<%
    while (scanner.hasNext()) {
        String str = scanner.next();
%>
        <%=str%><br/>
<%
    }
%>
</body>
</html>

http://localhost:8080/w16/file_load.jsp?fname=muyan.txt

网站访问统计

由于 WEB 站点面向的是整个互联网,所以为了方便统计出某一个 WEB 站点的访问数量,可以设计一个访问计数器,同时由于访问计数器中只是保留一个数字,那么可以通过一个具体的文件实现计数的存储

<%@ page pageEncoding="UTF-8" import="java.io.*,java.util.*" %>
<%@ page import="java.math.BigInteger" %>
<%@ page import="java.util.concurrent.locks.*" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%! // 定义一些操作的公共方法
    public BigInteger get(String path) throws Exception {   // 简化起见,抛出异常
        if (this.getServletContext().getAttribute("count") == null) { // 没有属性的时候
            File file = new File(path);
            if (file.exists()) {    // 文件存在
                Scanner scanner = new Scanner(file);
                if (scanner.hasNext()) {
                    BigInteger bi = new BigInteger(scanner.next());
                    // 因为我们必须防止用户有可能无限制刷新,会造成数据的重复读取
                    this.getServletContext().setAttribute("count", bi);
                }
                scanner.close();
            }
        }
        return (BigInteger) this.getServletContext().getAttribute("count");
    }
    public void save(String path, BigInteger num) throws Exception {
        Lock lock = new ReentrantLock(); // 定义互斥锁
        lock.lock(); // 同步锁定
        File file = new File(path);
        PrintWriter out = new PrintWriter(file);
        out.print(num); // 数据输出
        out.close();
        this.getServletContext().setAttribute("count", num);
        lock.unlock();
    }
%>
<%
    String filePath = this.getServletContext().getRealPath("/") + "count.txt";
    BigInteger current = get(filePath); // 获取当前的访问量
    if (session.isNew()) {  // 用户第一次访问
        current = current.add(new BigInteger("1")); // 实现数据自增
        save(filePath, current);
    }
%>
<h2>当前访问量:<%=current%></h2>
</body>
</html>

WEB 映射访问

每一个 WEB 应用程序目录之中都会存在有一个“WEB-INF”文件夹该文件夹在整个 WEB 中的安全级别最高,同时所有的用户都无法直接进行“WEB-INF”目录的访问,由于 JSP 程序本身携带有程序逻辑代码,为了提高程序安全性,就可以考虑将其保存在 WEB-INF 目录下,而远程用户要想访问此页面,就必须修改 web.xml 配置文件,为指定的 JSP 配置映射路径后才可以访问

1、
<%@ page pageEncoding="UTF-8" import="java.util.*" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<h1>沐言科技:www.yootk.com</h1>
</body>
</html>

2、
    <servlet>
        <servlet-name>HelloJSP</servlet-name>
        <jsp-file>/WEB-INF/hello.jsp</jsp-file>
    </servlet>
    <servlet-mapping>
        <servlet-name>HelloJSP</servlet-name>
        <url-pattern>/muyan.yootk</url-pattern>
    </servlet-mapping>

config 内置对象

接收初始化参数通过 web.xm 文件实现的程序映射访问,除了可以获得更加安全的保护之外,也可以实现初始化参数的配置,在 JSP 中所有的初始化参数需要通过 config 内置对象(对应类型为 javax.servlet.ServletConfig”接口)实现接收

1、
    <servlet>
        <servlet-name>HelloJSP</servlet-name>
        <jsp-file>/WEB-INF/hello.jsp</jsp-file>
        <init-param>
            <param-name>databaseName</param-name>
            <param-value>yoootk</param-value>
        </init-param>
        <init-param>
            <param-name>databaseHost</param-name>
            <param-value>www.yootk.com/mysql</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>HelloJSP</servlet-name>
        <url-pattern>/muyan.yootk</url-pattern>
    </servlet-mapping>
2、
<%@ page pageEncoding="UTF-8" import="java.util.*" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<h1>沐言科技:www.yootk.com</h1>
<%
    Enumeration<String> enu = config.getInitParameterNames(); // 获取全部初始化参数名称
    while (enu.hasMoreElements()) { // 枚举迭代
        String name = enu.nextElement(); // 获取参数名称
%>
        <h3><%=name%> = <%=config.getInitParameter(name)%></h3>
<%
    }
%>
</body>
</html>

pageContext 内置对象

在 JavaWEB 开发中每一个 JSP 页面程序都可以直接使用各个内置对象完成相应的处理,同时在每一个 JSP 程序文件中都包含有一个完整的 pageContext 内置对象,表示页面上下文实例

1、
<%@ page pageEncoding="UTF-8" import="java.lang.reflect.*" %>    <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%
    Method method = pageContext.getRequest().getClass().getMethod("getMethod"); // 反射获取调用方法
%>
<h1>请求模式:<%=method.invoke(pageContext.getRequest())%></h1>
</body>
</html>

2、
<%@ page pageEncoding="UTF-8" import="java.lang.reflect.*" %> <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%
    HttpServletRequest req = (HttpServletRequest) pageContext.getRequest();
%>
<h1>请求模式:<%=req.getMethod()%></h1>
</body>
</html>

3、
<%@ page pageEncoding="UTF-8" import="java.lang.reflect.*" %> <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%
    pageContext.getRequest().setAttribute("r-info", "Yootk Request");
    pageContext.getSession().setAttribute("s-info", "Yootk Session");
    pageContext.forward("scope_get.jsp");
%>
</body>
</html>

4、
<%@ page pageEncoding="UTF-8" import="java.lang.reflect.*" %> <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<h1>Request属性:<%=pageContext.getRequest().getAttribute("r-info")%></h1>
<h1>Session属性:<%=pageContext.getSession().getAttribute("s-info")%></h1>
</body>
</html>

文件上传

动态 WEB 程序结构中除了基本的文本型参数传递之外,还可以在表单中通过文件组件实现上传文件的选择,这样在进行表单提交时所传递的内容就不再是简单的文本信息,而是二进制的数据内容

1、
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
    <meta charset="UTF-8">
</head>
<body>
<!-- 如果要选择了上传文件,那么最终所有的表单都会以二进制数据流的形式进行传输 -->
<form action="upload_do.jsp" enctype="multipart/form-data" method="post">
    姓名:<input type="text" name="name"><br>  <!-- 文本数据 -->
    照片:<input type="file" name="photo"><br> <!-- 文件数据 -->
    <button type="submit">提交</button><button type="reset">重置</button>
</form>
</body>
</html>

2、
<%@ page pageEncoding="UTF-8" import="java.lang.reflect.*" %> <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<h1>【参数接收】name = <%=request.getParameter("name")%></h1>
</body>
</html>

上传接收

当表单通过“enctype="multipart/form-data"” 属性封装之后表单所提交的就是一组二进制的数据内容,在 ServletRequest 接口中提供了一个接收输入流的操作方法,此方法定义为:

public ServletinputStream getinputStream() throws lOException

1、
<%@ page pageEncoding="UTF-8" import="java.util.*" %> <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%
    request.setCharacterEncoding("UTF-8");
    response.setCharacterEncoding("UTF-8");
    Scanner scan = new Scanner(request.getInputStream()); // 只是为了输出
    while (scan.hasNext()) {    // 迭代判断与输出
%>
        <%=scan.next()%>
<%
    }
%>
</body>
</html>

2、
<%@ page pageEncoding="UTF-8" import="java.util.*" %> <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<h1>MIME = <%=request.getContentType()%></h1>
</body>
</html>

FileUpload 组件下载

为了便于接收上传数据信息,在实际的项目开发中往往会使用 Apache 推出的 Commons FileUpload 组件,该组件是一个开源组件,开发者可以登录“http://commons.apache.org/下载相应的开发包

1、http://apache.org/

2、commons.apache.org

3、https://github.com/apache/commons-fileupload

FileUpload 接收请求参数

1.input.html
<html>
<head>
  <title>tomcat9上传文件</title>
  <meta charset="UTF-8">
</head>
<body>
<!-- 如果要选择了上传文件,那么最终所有的表单都会以二进制数据流的形式进行传输 -->
<form action="upload_do.jsp" enctype="multipart/form-data" method="post">
  姓名:<input type="text" name="name"><br>  <!-- 文本数据 -->
  角色:<input type="checkbox" name="role" value="admin">管理员
  <input type="checkbox" name="role" value="guest">访客
  <input type="checkbox" name="role" value="anonymous">匿名用户<br>
  照片:<input type="file" name="photo"><br> <!-- 文件数据 -->
  <button type="submit">提交</button><button type="reset">重置</button>
</form>
</body>
</html>
2.input_do.jsp
<%@ page pageEncoding="UTF-8" import="java.util.*,java.io.*,org.apache.commons.fileupload.*" %>
<%@ page import="org.apache.commons.fileupload.disk.DiskFileItemFactory" %>
<%@ page import="org.apache.commons.fileupload.servlet.ServletFileUpload" %>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%! // 对当前的上传操作做一些核心参数定义
    public static final Long MAX_SIZE = 3145728L; // 上传的最大长度为3M数据
    public static final Long FILE_MAX_SIZE = 1048576L; // 上传单个文件的最大值
    public static final String TEMP_DIR = "/temp9/"; // 临时保存目录
    public static final String UPLOAD_DIR = "/upload9/"; // 目标存储路径
    public static final String DEFAULT_ENCODING = "UTF-8"; // 文本编码
%>
<%
    request.setCharacterEncoding(DEFAULT_ENCODING); // 请求编码配置
    DiskFileItemFactory factory = new DiskFileItemFactory(); // 磁盘管理类
    factory.setRepository(new File(TEMP_DIR)); // 临时存储目录
    ServletFileUpload fileUpload = new ServletFileUpload(factory); // 上传处理的核心类
    fileUpload.setSizeMax(MAX_SIZE); // 上传的最大容量
    fileUpload.setFileSizeMax(FILE_MAX_SIZE); // 单个文件的最大容量
    if (fileUpload.isMultipartContent(request)) {   // 当前存在有文件上传
        Map<String, List<FileItem>> map = fileUpload.parseParameterMap(request); // 解析全部的上传文件
        for (Map.Entry<String, List<FileItem>> entry : map.entrySet()) {    // 全部上传项迭代
            String paramName = entry.getKey(); // 请求参数的名称
            List<FileItem> allItems = entry.getValue(); // 不管是单个的参数还是一组参数接收方式相同
%>
<p><%=paramName%> :
<%
    for (FileItem item : allItems) {   // 获取内容
        if (item.isFormField()) {   // 文本数据内容
%>
<%=item.getString(DEFAULT_ENCODING)%>
<%
} else {    // 不属于文本参数
    if (item.getSize() > 0) {   // 文件选择框选中了文件
        // 使用UUID工具类实现一个自动命名的处理
        String fileName = item.getName();
//        String fileName = UUID.randomUUID() + "." + item.getContentType().substring(item.getContentType().lastIndexOf("/") + 1);
        String filePath = application.getRealPath(UPLOAD_DIR) + fileName; // 文件的存储路径配置
        item.write(new File(filePath)); // 文件的保存
        item.delete(); // 清空上传信息
%>
<img src="<%=request.getContextPath()%><%=UPLOAD_DIR%><%=fileName%>" style="width: 150px;">
<%
                    }
                }
            }
        }
    }
%>
</body>
</html>

1.input.html
<html>
<head>
  <title>tomcat10上传文件</title>
  <meta charset="UTF-8">
</head>
<body>
<!-- 如果要选择了上传文件,那么最终所有的表单都会以二进制数据流的形式进行传输 -->
<form action="upload_do.jsp" enctype="multipart/form-data" method="post">
  姓名:<input type="text" name="name"><br>  <!-- 文本数据 -->
  角色:<input type="checkbox" name="role" value="admin">管理员
  <input type="checkbox" name="role" value="guest">访客
  <input type="checkbox" name="role" value="anonymous">匿名用户<br>
  照片:<input type="file" name="photo"><br> <!-- 文件数据 -->
  <button type="submit">提交</button><button type="reset">重置</button>
</form>
</body>
</html>
2.input_do.jsp
<%@ page pageEncoding="UTF-8" import="java.util.*,java.io.*,org.apache.commons.fileupload2.*" %>
<%@ page import="org.apache.commons.fileupload2.disk.DiskFileItemFactory" %>
<%@ page import="org.apache.commons.fileupload2.servlet.ServletFileUpload" %> <%-- 设置显示编码 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%! // 对当前的上传操作做一些核心参数定义
    public static final Long MAX_SIZE = 3145728L; // 上传的最大长度为3M数据
    public static final Long FILE_MAX_SIZE = 1048576L; // 上传单个文件的最大值
    public static final String TEMP_DIR = "/temp/"; // 临时保存目录
    public static final String UPLOAD_DIR = "/upload/"; // 目标存储路径
    public static final String DEFAULT_ENCODING = "UTF-8"; // 文本编码
%>
<%
    request.setCharacterEncoding(DEFAULT_ENCODING); // 请求编码配置
    DiskFileItemFactory factory = new DiskFileItemFactory(); // 磁盘管理类
    factory.setRepository(new File(TEMP_DIR)); // 临时存储目录
    ServletFileUpload fileUpload = new ServletFileUpload(factory); // 上传处理的核心类
    fileUpload.setSizeMax(MAX_SIZE); // 上传的最大容量
    fileUpload.setFileSizeMax(FILE_MAX_SIZE); // 单个文件的最大容量
    if (fileUpload.isMultipartContent(request)) {   // 当前存在有文件上传
        Map<String, List<FileItem>> map = fileUpload.parseParameterMap(request); // 解析全部的上传文件
        for (Map.Entry<String, List<FileItem>> entry : map.entrySet()) {    // 全部上传项迭代
            String paramName = entry.getKey(); // 请求参数的名称
            List<FileItem> allItems = entry.getValue(); // 不管是单个的参数还是一组参数接收方式相同
%>
            <p><%=paramName%>
<%
            for (FileItem item : allItems) {    // 获取内容
                if (item.isFormField()) {   // 文本数据内容
%>
                    <%=item.getString(DEFAULT_ENCODING)%>
<%
                } else {    // 不属于文本参数
                    if (item.getSize() > 0) {   // 文件选择框选中了文件
                        // 使用UUID工具类实现一个自动命名的处理
                        String fileName = UUID.randomUUID() + "." + item.getContentType().substring(item.getContentType().lastIndexOf("/") + 1);
                        String filePath = application.getRealPath(UPLOAD_DIR) + fileName; // 文件的存储路径配置
                        item.write(new File(filePath)); // 文件的保存
                        item.delete(); // 清空上传信息
%>
                        <img src="<%=request.getContextPath()%>/upload/<%=fileName%>" style="width: 150px;">
<%
                    }
                }
            }
        }
    }
%>
</body>
</html>

commons-io-2.15.1.jar 下载open in new windowcommons-fileupload2-2.0-SNAPSHOT.jar 下载open in new windowcommons-fileupload-1.5.jar 下载open in new window

上传工具类

程序包

为了便于程序功能的分类,可以将此工具类保存在"com.yootk.common.util”开发包之中,对于此时的程序包组成规范为:

{(组织名称)com.yootk}+{(模块名称)common}+{(子包名称)util}

依赖导入

在进行程序开发中需要导入大量的程序类,在本次编写的工具类中,除了 FileUpload 工具包中的类之外实际上还需要导入 HttpServletRequest 接口、java.util 包、java.io 包

默认值

在使用 FileUpload 组件包中的工具类进行项目开发中,往往都需要明确的设置总体的上传数量、单个文件的上传数量、临时存储目录、数据保存目录以及接收编码等信息,如果觉得每一次调用组件都重复进行配置会有些繁琐,那么可以在类中定义一些常量,进行一些默认的配置项定义

工具属性

除了所有固定的参数内容之外,也需要充分考虑用户的个性化配置需要例如:FileUpload 一定是对 HttpServletRequest 接口的包装,而 request 内置对象的获取必须由 WEB 容器获取后再传递到 ParameterUtil 类之中,所以就需要在类中进行 request 对象的引用传递

参数属性

通过 ParameterUtil 类进行的 FileUpload 操作封装,本质上还是要接收用户所发送的所有参数(不管表单是否被封装,都采用统一的方式获取参数)所以在类中设计了一个“uploadFlag”属性用于动态决定参数的接收方式由于 FileUpload 组件在每一次获取请求时都需要进行循环的判断,为了简化起见,设计了一个 paramMap 集合,该集合的 key 为参数名称,而 value 为参数内容

package com.yix.common.util;

import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.fileupload2.FileItem;
import org.apache.commons.fileupload2.disk.DiskFileItemFactory;
import org.apache.commons.fileupload2.servlet.ServletFileUpload;

import java.io.*;
import java.util.*;

/**
 * @author wangdx
 */
public class ParameterUtil {
    // 将所有默认的常量的信息全部放在这个工具类之中,目的是为了进行对象构造时使用的默认参数
    public static final Long MAX_SIZE = 3145728L; // 上传的最大长度为3M数据
    public static final Long FILE_MAX_SIZE = 1048576L; // 上传单个文件的最大值
    // 需要注意的是,此时在进行存储目录设置的时候,后面必须要提供有一个“/”作为完结,如果没有路径出错
    public static final String TEMP_DIR = "/temp/"; // 临时保存目录
    public static final String UPLOAD_DIR = "/upload/"; // 目标存储路径
    public static final String DEFAULT_ENCODING = "UTF-8"; // 文本编码
    // 这个程序类是一个与JavaWEB开发紧密耦合的工具类,必须运行在WEB容器之中
    private HttpServletRequest request; // 实现请求的接收
    private String uploadFile; // 【属性】保存上传路径
    private String tempFile; // 【属性】保存临时存储路径
    private String encoding; // 【属性】保存编码的设置
    private long maxSize; // 【属性】上传文件的最大长度
    private long fileMaxSize; // 【属性】保存每个上传文件最大的长度
    // 在进行请求参数接收处理的时候需要考虑表单是否封装情况下的操作
    // 如果不使用这样的标记,在每次进行参数处理的时候都要求自己手工判断是否以“multipart/form-data”开头
    private boolean uploadFlag = false; // 封装处理标记,保存表单是否封装的状态
    private ServletFileUpload fileUpload; // 实现上传的处理
    // 所有上传的文件应该首先保存在临时目录下,所以需要定义一个可以获取所有临时文件名称的集合,文件名称是随机生成的
    // 该集合还有一个最重要的作用:可以实现上传之后的临时目录清空处理
    private List<String> tempFileNames = new ArrayList<>(); // 临时文件名称存储集合
    // 所有的请求处理的时候,在使用FileUpload组件操作中是需要进行循环的,而设置这个类的目的就是为了减少这样的循环
    // 在一次循环的时候就将所有的临时文件保存了,同时把所有的参数也保存在Map集合里面
    private Map<String, String[]> paramMap = new HashMap<>();

    public ParameterUtil(HttpServletRequest request) {    // 构造方法
        this(request, UPLOAD_DIR, TEMP_DIR, DEFAULT_ENCODING, MAX_SIZE, FILE_MAX_SIZE);
    }

    public ParameterUtil(HttpServletRequest request, String uploadFile) {
        this(request, uploadFile, TEMP_DIR, DEFAULT_ENCODING, MAX_SIZE, FILE_MAX_SIZE);
    }

    public ParameterUtil(HttpServletRequest request, String uploadFile, String tempFile, String encoding, long maxSize, long fileMaxSize) {
        this.request = request;
        if (uploadFile.endsWith("/")) { // 传递进来的路径存在有“/”
            this.uploadFile = uploadFile;
        } else {
            this.uploadFile = uploadFile + "/"; // 设置一个处理后的路径
        }
        if (tempFile.endsWith("/")) {
            this.tempFile = tempFile;
        } else {
            this.tempFile = tempFile + "/";
        }
        this.encoding = encoding;
        this.maxSize = maxSize;
        this.fileMaxSize = fileMaxSize;
        this.handleParameter(); // 在构造的时候同时实现请求参数的处理操作
        System.out.println(this.paramMap);
    }

    private void handleParameter() {    // 对请求的参数进行处理
        // 针对于表单是否封装,请求参数的获取机制是完全不一样的,所以应该考虑对当前的请求状态做出判断
        if ((this.uploadFlag = this.request.getContentType() != null &&
                this.request.getContentType().startsWith("multipart/form-data"))) { // 进行表单封装处理
            // 一旦表单进行了封装处理操作,那么在整个的代码之中就必须考虑到通过FileUpload组件进行处理
            DiskFileItemFactory factory = new DiskFileItemFactory(); // 磁盘管理类
            factory.setRepository(new File(this.tempFile)); // 临时存储目录
            this.fileUpload = new ServletFileUpload(factory); // 上传处理的核心类
            fileUpload.setSizeMax(this.maxSize); // 上传的最大容量
            fileUpload.setFileSizeMax(this.fileMaxSize); // 单个文件的最大容量
            if (fileUpload.isMultipartContent(request)) {   // 当前存在有文件上传
                try {
                    // 此时所得到的全部的数据内容实际上都保存在了FileItem集合里面
                    Map<String, List<FileItem>> map = this.fileUpload.parseParameterMap(request); // 对当前请求进行参数的分析
                    for (Map.Entry<String, List<FileItem>> entry : map.entrySet()) {    // Map集合迭代
                        String paramName = entry.getKey(); // 获取提交的参数名称
                        List<FileItem> allItems = entry.getValue(); // 获取请求的参数内容
                        // 如果现在发现是普通的文本数据,则直接保存在paramMap集合里面,如果是上传文件,则生成一个新的文件名称,保存的是文件名称
                        String[] values = new String[allItems.size()]; // 根据提交参数的个数来确定字符串数组的大小
                        int foot = 0; // 实现字符串数组的索引控制
                        for (FileItem item : allItems) {    // 循环参数内容
                            if (item.isFormField()) {   // 是一个普通的文本参数
                                String value = item.getString(this.encoding); // 直接获取参数内容
                                values[foot++] = value; // 把数据保存在数组之中
                            } else {    // 是二进制文件
                                //  需要创建新的文件名称,同时还要将文件保存在临时目录之中
                                String fileName = this.saveTempFile(item); // 保存临时文件
                                this.tempFileNames.add(fileName); // 保存临时文件名称
                                values[foot++] = fileName; // 二进制文件保存的是临时文件名称
                            }
                        }
                        // 最终能够实现数据信息查询的是ParamMap集合,将所有的数据保存在ParamMap集合里
                        this.paramMap.put(paramName, values);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    // 通过FileItem可以获得原始文件的名称以及MIME类型,因为最终生成的随机文件名称是需要原始文件后缀的
    private String saveTempFile(FileItem item) throws Exception {    // 实现临时文件的存储,并且可以返回临时文件的名称
        if (item.getSize() > 0) {   // 有上传文件存在
            String fileName = "temp." + this.getUUIDName(item); // 获取了一个临时文件的存储名称
            String filePath = this.request.getServletContext().getRealPath(this.tempFile) + fileName; // 临时存储路径
            item.write(new File(filePath)); // 实现文件保存
            item.delete(); // 删除已有的数据
            return fileName;
        }
        return null;
    }

    public String getUUIDName(FileItem item) {  // 实现文件名称的随机创建
        return UUID.randomUUID() + "." + item.getContentType().substring(item.getContentType().lastIndexOf("/") + 1);
    }

    public String getParameter(String paramName) {  // 根据参数名称获取参数内容
        if (this.uploadFlag) {  // 判断当前是否有文件上传
            if (this.paramMap.containsKey(paramName)) { // 当前的参数内容存在
                return this.paramMap.get(paramName)[0]; // 返回第一个内容
            }
            return null;
        }
        return this.request.getParameter(paramName); // 表单未封装,直接使用HttpServletRequest方法处理
    }

    public String[] getParameterValues(String paramName) {  // 根据参数名称获取一组参数内容
        if (this.uploadFlag) {  // 有文件上传
            if (this.paramMap.containsKey(paramName)) { // 存在有指定的key信息
                return this.paramMap.get(paramName); // 最终参数解析获取到的就是一个字符串数组
            }
            return null;
        }
        return this.request.getParameterValues(paramName); // 通过原始方式获取请求参数
    }

    public Set<String> getParameterNames() {    // 获取全部的参数名称
        if (this.uploadFlag) {
            return this.paramMap.keySet(); // 获得包装后的所有参数的名称集合
        }
        return this.request.getParameterMap().keySet(); // 原始方式获取参数的名称集合
    }

    public Map<String, String[]> getParameterMap() {
        if (this.uploadFlag) {
            return this.paramMap;
        }
        return this.request.getParameterMap();
    }

    // 获取指定参数的临时文件的保存名称,同时生成新的目标文件的保存名称
    public List<String> getUUIDName(String paramName) throws Exception {
        List<String> uuidNames = new ArrayList<>(); // 保存最终生成的目标文件的名称
        String fileNames[] = this.paramMap.get(paramName); // 获取临时文件的名称集合
        for (String fileName : fileNames) { // 数组迭代
            uuidNames.add("yootk." + UUID.randomUUID() + "." + fileName.substring(fileName.lastIndexOf(".") + 1));
        }
        return uuidNames; // 返回目标存储的文件名称
    }

    // 文件的保存,而uploadFileNames就是getUUIDName()方法所生成的文件名称
    public void saveUploadFile(String paramName, List<String> uploadFileNames) throws Exception {
        String fileNames[] = this.paramMap.get(paramName); // 获取临时文件名称
        for (int x = 0; x < fileNames.length; x++) {
            File srcFile = new File(this.request.getServletContext().getRealPath(this.tempFile) + fileNames[x]);
            File destFile = new File(this.request.getServletContext().getRealPath(this.uploadFile) + uploadFileNames.get(x));
            InputStream input = new FileInputStream(srcFile); // 临时文件输入流
            OutputStream output = new FileOutputStream(destFile);  // 临时文件输出流
            input.transferTo(output); // 文件的转存
            input.close();
            output.close();
        }
    }

    // 现在目标文件都已经保存在了upload目录下了,那么就需要清除temp目录下的内容
    public void clean() {
        if (this.tempFileNames != null && this.tempFileNames.size() > 0) {
            for (String fileName : this.tempFileNames) {
                String filePath = this.request.getServletContext().getRealPath(this.tempFile) + fileName;
                File file = new File(filePath);
                if (file.exists()) {
                    file.delete();
                }
            }
        }
    }

    public List<String> getTempFileNames() {    // 获取所有临时目录下的文件名称
        return tempFileNames;
    }
}

<%@ page pageEncoding="UTF-8" import="java.util.*" %>
<%@ page import="com.yootk.common.util.ParameterUtil" %>    <%-- 导入自定义的工具类 --%>
<html>
<head>
    <title>沐言科技:www.yootk.com</title>
</head>
<body>
<%
    request.setCharacterEncoding("UTF-8"); // 请求编码配置
    ParameterUtil pu = new ParameterUtil(request); // 通过HttpServletRequest实现上传处理
    List<String> fileNames = pu.getUUIDName("photo"); // 生成最终存储的文件名称集合
    pu.saveUploadFile("photo", fileNames); // 文件存储
    pu.clean();// 清空临时目录中的保存文件内容
%>
<h1>姓名:<%=pu.getParameter("name")%></h1>
<h1>角色:<%=Arrays.toString(pu.getParameterValues("role"))%></h1>
<%
    for (String fileName : fileNames) {
%>
        <img src="<%=request.getContextPath()%>/upload/<%=fileName%>">
<%
    }
%>
</body>
</html>

大幅广告框案例说明

广告展示管理项目案例

JSP 程序开发全部是围绕着内置对象展开的,为了便于读者对内置对象的理解,下面将通过一个完整的项目进行实战讲解分析,在很多的网站首页都会存在有大幅广告条,利用特定的组件可以实现图片信息的滚动显示,为了便于这些图片的管理,可以直接通过数据库实现所有广告数据存储

代码地址open in new window

上次编辑于: