JavaWeb基础

IDEA搭建JavaWeb服务器

然后点一下修复就可以了

JSP基本语法

声明

定义JSP程序所需要的变量、方法与类,语法格式为

<%! declaration;[declaration;]...%>

与标记符所在位置无关,声明的变量、方法与类在整个JSP页面都是有效的

表达式

表达式计算结果自动转换为字符串并发送到客户端显示

<%= expression %>

<%= (new java.util.Date()).toLocaleString()%>

脚本小程序

<% scriptlets %>

<%@ page contentType="text/html;charset=UTF-8"%>
<%@ page import="java.util.Date"%>
<%!
    Date date;
%>

<html>
    <head>
        <title>日期和时间</title>
    </head>
    <body>
    <%
        date=new Date();
        out.println("<br>"+date.toLocaleString()+"<br>");
    %>
    </body>
</html>

指令标记

用于告知JSP引擎如何处理JSP界面

<%@ 指令名 属性="值" ... %>

page指令

include指令

静态包含文件

taglib指令

动作标记

param动作标记

用于传参

<jsp:param name="xxx" value="xxx(也可以是<%= %>表达式)"/>

include动作标记

相当于动态加载jsp

forward动作标记

动态跳转页面

<%@ page contentType="text/html;charset=UTF-8"%>
<html>
    <head>
        <title>OddSum</title>
    </head>
    <body>
        <jsp:forward page="OddSumByNumber.jsp">
            <jsp:param name="number" value="100"/>
        </jsp:forward>
    </body>
</html>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>奇数和</title>
</head>
<body>
<%
    String s=request.getParameter("number");
    int n=Integer.parseInt(s);
    int sum=0;
    for (int i=0;i<=n;i++){
        if (i%2!=0)
            sum=sum+i;
    }
%>
从1~<%=n%>的奇数和是:<%=sum%>
</body>
</html>

plugin动作标记

用于加载Java插件

注释方式

html注释,jsp注释,java注释

内置对象

request对象

封装了由客户端生成的HTTP请求的所有细节

可以用setAttributegetAttribute在不同jsp之间传递数据

response对象

用于对客户端的请求进行动态响应,设置cookie等

session对象

JavaBean

Java中的一种可重用组件技术

规范

一个公共类
有一个不带参数的构造函数
属性为private,方法为public
提供多种方法来存取类中的属性
package Bean;

public class UserBean {
    private String username=null;
    private String password=null;
    public UserBean(){
    }
    public void setUsername(String value){
        username=value;
    }
    public String getUsername(){
        return username;
    }
    public void setPassword(String value){
        password=value;
    }
    public String getPassword(){
        return password;
    }
}

使用JSP和JavaBean

通过JSP标签访问

导入JavaBean类

<%@ page import="mypack.CounterBean"%>

声明JavaBean对象

例如<jsp:useBean id="myBean" class="mypack.CounterBean" scope="session"/>

其中scope用来指定该JavaBean的范围

可以通过<jsp:getProperty>标签与<jsp:setProperty>标签访问JavaBean的属性值

<jsp:setProperty name="" property="*"/>可以根据表单传递的所有参数来设置JavaBean的属性

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>JavaBean</title>
  </head>
  <body>
    <jsp:useBean id="user" scope="session" class="Bean.UserBean">
    </jsp:useBean>
  <%
    user.setUsername("AAA");
    user.setPassword("BBB");
    out.println("用户名: "+user.getUsername()+"<br>");
    out.println("密码: "+user.getPassword()+"<br>");
  %>
  <jsp:setProperty name="user" property="username" value="CCC"></jsp:setProperty>
  <jsp:setProperty name="user" property="password" value="DDD"></jsp:setProperty>
  用户名: <jsp:getProperty name="user" property="username"/><br>
  密码: <jsp:getProperty name="user" property="password"/><br>
  </body>
</html>

JavaBean范围

page:页面范围 JavaBean保存在一页的范围中

request:请求范围 JavaBean保存在一个服务器的跳转范围中

session:会话范围 JavaBean保存在一个用户的操作范围中

web:应用范围 在整个服务器上保存

移除JavaBean

*.removeAttribute(name)来移除JavaBean

Servlet

用于处理HTTP请求,来生成动态的Java Web页面

工作原理

当web服务器接收到http请求时,会将请求交给Servlet容器,Servlet容器首先对URL解析,并根据web.xml配置文件找到相应的处理Servlet,同时将Request(HTTPServletRequest)和Response传递给Servlet,处理好后返回Response(HTTPServletResponse)

如果该servlet是第一次访问,那么该引擎会调用init()方法初始化这个Servlet,后面的请求只是新建一个线程,再调用Servlet中的service()方法

常用接口和类

Servlet依靠继承父类和实现接口来实现。使用servlet必须引入javax.servlet和javax.servlet.http前者用于控制Servlet生命周期,后者用于处理HTTP相关操作

HttpServlet类处理GET和POST,HttpSession接口处理客户端和服务器的会话,ServletConfig接口封装了Servlet的配置信息,ServletContext接口向Servlet提供环境信息

获取HTTP头部信息

package Controller;

import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class ServletHeader extends HttpServlet{
    public void doGet(HttpServletRequest request,HttpServletResponse response)throws IOException,ServletException{
        response.setContentType("text/html");
        PrintWriter out=response.getWriter();
        Enumeration enumer= request.getHeaderNames();
        while (enumer.hasMoreElements()){
            String name=(String)enumer.nextElement();
            String value=request.getHeader(name);
            out.println(name+" = "+value+"<br>");
        }
    }
    public void doPost(HttpServletRequest request,HttpServletResponse response)throws IOException,ServletException{
        doGet(request,response);
    }
}
<servlet>
        <servlet-name>header</servlet-name>
        <servlet-class>Controller.ServletHeader</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>header</servlet-name>
        <url-pattern>/ServletHeader</url-pattern>
    </servlet-mapping>

用Servlet实现简易的验证码功能

一开始我的想法是存几张验证码图片在本地,然后把id存在session里然后再读入用户输入并比较

但是再Controller好像不大好读取验证码的答案

看了别人的做法才发现是自己naive了,原来验证码是动态生成的,答案直接存在Session里了

贴个别人的做法

以后再实现吧

过滤器与监听器

过滤器是服务器与客户端请求与响应的中间层组件。过滤器用于在Servlet之外对HttpServletRequest和HttpServletResponse进行修改

监听器是Servlet规范定义中的一种特殊类,其对应观察者模式,当事件发生时会自动触发该事件对应的监听器。比如统计在线人数和在线用户、统计网站访问量、在系统启动时初始化信息

过滤器接口

Filter接口

在实际开发中,每个过滤器对象都要直接或间接地实现Filter接口,当过滤器对象拦截访问请求时,由servlet容器调用Filter接口的doFilter()方法,并且其参数chain调用doFilter()方法将请求和响应传递给下一个过滤器

FilterConfig接口

用于获取过滤器中的配置信息

FilterChain接口

是过滤器的传递工具

创建和配置过滤器

package Filter;

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
import java.io.PrintWriter;

public class MyFilter implements Filter{
    private FilterConfig fc;
    private String ip;
    @Override
    public void init(FilterConfig fc)throws ServletException{
        this.fc=fc;
        ip=fc.getInitParameter("ip");
    }
    @Override
    public void doFilter(ServletRequest request,ServletResponse response,FilterChain chain)throws IOException,ServletException{
        String userIP=request.getRemoteAddr();
        response.setCharacterEncoding("GB2312");
        PrintWriter out=response.getWriter();
        System.out.println(userIP);
        if (userIP.equals(ip)){
            out.println("您的 IP "+ip+"被禁止访问!");
        }
        else{
            chain.doFilter(request,response);
        }
    }
    @Override
    public void destroy(){
    }
}
        <filter>
        <filter-name>MyFilter</filter-name>
        <filter-class>Filter.MyFilter</filter-class>
        <init-param>
            <param-name>ip</param-name>
            <param-value>127.0.0.1</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>MyFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

监听器接口

在Servlet2.5盒JSP2.0中有8个监听器接口和6个Event类,每个接口都有其对应的event类

根据监听对象不同分类:

  1. 根据监听应用程序环境对象不同分为ServletContextListener接口和ServletContextAttributeListener接口
  2. 根据监听用户会话对象不同分为HttpSessionListener接口和HttpSessionAttributeListener接口
  3. 根据监听请求消息对象不同分为ServletRequestListener接口和ServletRequestAttributeListener接口

根据监听事件不同分类:

  1. 监听域对象自身的创建和销毁的事件监听器,有HttpSessionListener接口,ServletContextListener接口,ServletRequestListener接口
  2. 监听域对象中属性的增加和删除的事件监听器,有HttpSessionAttributeListener接口

监听对象的创建和销毁

HttpSessionListener接口

用于监听HTTP会话的创建和销毁

用户需在web.xml中配置session的超时参数

<session-config>
        <session-timeout>5</session-timeout>
</session-config>
ServletContextListener接口

用于监听ServletContext对象的创建和删除。ServletContext是一个全局的储存信息的空间,服务器开始就存在,服务器关闭才释放。ServletContextListener接口主要用于定时器,加载全局属性对象,创建全局数据库连接以及加载缓存信息。在web.xml中配置项目的初始化信息

<context-param>
    <param-name></param-name>
    <param-value></param-value>
</context-param>
ServletRequestListener接口

用于读取request参数,记录访问历史

监听对象的属性

HttpSessionAttributeListener,ServletContextAttributeListener,ServletRequestAttributeListener

顾名思义

监听Session内的对象(???)

HttpSessionBindingListener接口可以监听HTTP会话中对象的绑定信息。

HttpSessionActivationListener接口用于监听Http会话中属性的设置请求

创建和配置监听器

package Listener;

import javax.servlet.*;

public class MyListener implements ServletContextListener{
    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        System.out.println("销毁Application对象");
    }

    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        System.out.println("初始化Application对象");
        String str=servletContextEvent.getServletContext().getInitParameter("count");
        System.out.println("count="+str);
    }
}
    <listener>
        <listener-class>Listener.MyListener</listener-class>
    </listener>
    <context-param>
        <param-name>count</param-name>
        <param-value>10</param-value>
    </context-param>

Servlet3.0特性

注解

比如@WebServlet @WebInitparam @WebFilter @WebListener...

通过 @WebFilter 注解配置的 Filter 过滤器,无法进行排序,若需要对 Filter 过滤器进行排序,建议使用 web.xml 进行配置。

@WebServlet(urlPatterns = "/ServletHeader")

name默认是类的全限定名

@WebFilter(urlPatterns = {"/*"}, filterName = "filterAnno", asyncSupported = true, initParams = {@WebInitParam(name="ip",value = "127.0.0.1")})

异步处理

就是让Servlet在处理费时的请求时不要阻塞,要一部分一部分地显示。

在注解中加上asyncSupport=true

package Controller;

import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;

@WebServlet(urlPatterns = "/async",asyncSupported = true)
public class AsyncServlet extends HttpServlet{
    public void doGet(HttpServletRequest req,HttpServletResponse resp)throws IOException,ServletException {
        resp.setContentType("text/html;charset=UTF-8");
        PrintWriter out=resp.getWriter();
        out.println("启动Servlet: "+new Date() + ".<br>");
        out.flush();
        AsyncContext ac=req.startAsync();
        new Thread(new Async(ac)).start();
        out.println("结束Servlet: "+new Date() + ".<br>");
        out.println("启动子线程: "+new Date() + ".<br>");
        out.flush();
    }
}
package Controller;

import javax.servlet.AsyncContext;
import java.io.PrintWriter;
import java.util.Date;

public class Async implements Runnable{
    private AsyncContext ac=null;
    public Async(AsyncContext ac){
        this.ac=ac;
    }

    @Override
    public void run() {
        try{
            Thread.sleep(10000);
            PrintWriter out=ac.getResponse().getWriter();
            out.println("业务处理完毕: "+ new Date() +".<br>");
            out.flush();
            ac.complete();
        }
        catch (Exception e){
            e.printStackTrace();
        }
    }
}

对多线程还是不懂TwT

上传组件

使用@MultipartConfig注解和Part

<%@ page import="java.util.*" pageEncoding="UTF-8" %>
<html>
<head>
    <title>Upload</title>
</head>
<body>
    <form action="FileServlet" method="post" enctype="multipart/form-data">
        简历: <input type="file" name="resume"/><br /><input type="submit" value="注册"/>
    </form>
</body>
</html>
package Controller;

import javax.servlet.*;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;
import java.io.PrintWriter;

@WebServlet(urlPatterns = "/FileServlet")
@MultipartConfig(maxFileSize = 1024*1024)
public class FileServlet extends HttpServlet{
    public void doPost(HttpServletRequest req,HttpServletResponse resp)throws IOException,ServletException{
        req.setCharacterEncoding("UTF-8");
        Part part=req.getPart("resume");
        PrintWriter out = resp.getWriter();
        out.println("MIME: "+part.getContentType());
        out.println("Bytes: "+part.getSize());
        out.println("Name: "+part.getName());
        out.println("Details: "+part.getHeader("Content-Disposition"));
        part.write("~/aa.txt");
    }
}

JDBC

JDBC相关类与接口

DriverManager类

加载数据库驱动程序:Class.forName("数据库驱动名")

比如:Class.forName("com.mysql.cj.jdbc.Driver")

此时可以通过DriverManager类的getConnection()方法与对应的数据库建立连接

DriverManager.getConnection(String url,String loginName,String password)

url的语法格式可以如下:String url="jdbc:mysql://127.0.0.1:3306/数据库名?xxx"

Connection接口

代表Java程序和数据库的连接,只有在获得该连接对象后才能访问数据库并操作数据表。

Statement接口

用来执行静态的SQL语句,通过Connection接口对象的createStatement()方法创建的

Statement sql=con.createStatement();

PreparedStatement接口

用来动态执行SQL语句,可以利用setXxx()方法为SQL语句中的参数赋值

ResultSet接口

通过该接口的实例可以获得检索结果集

package jdbc;

import java.sql.*;

public class JDBC {
    public static void main(String[] args){
        Connection con=null;
        try{
            Class.forName("com.mysql.cj.jdbc.Driver");
            con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/student?serverTime=UTC","root","root");
            Statement sql=con.createStatement();
            ResultSet res=sql.executeQuery("select * from student;");
            while (res.next()){
                System.out.println(res.getString("s_name"));
            }
            con.close();
        } catch (SQLException e1){
            e1.printStackTrace();
        } catch (ClassNotFoundException e2){
            e2.printStackTrace();
        }
    }
}

表达式语言EL

基本语法

${expression}

禁用EL

使用\${name}

使用page指令<%@ isELIgnored="true"%>

在web.xml中配置<el-ignored>

    <jsp-config>
        <jsp-property-group>
            <url-pattern>*.jsp</url-pattern>
            <el-ignored>true</el-ignored>
        </jsp-property-group>
    </jsp-config>

关键字

EL中有其自己的保留关键字

EL变量

指定范围的方式:${pageScope.name},${requestScope.name},${sessionScope.name}...

EL运算

判断对象是否为空:${empty expression}

通过EL访问数组数据:使用.[]

还有关系运算,逻辑运算,条件运算等

隐含对象

pageContext

主要用来访问页面信息

<%@ page import="java.util.*" pageEncoding="UTF-8" %>
<html>
<head>
    <title>PageContext</title>
</head>
<body>
request对象: ${pageContext.request} <br>
协议: ${pageContext.request.protocol} <br>

response对象: ${pageContext.response} <br>
ContentType: ${pageContext.response.contentType} <br>

session对象: ${pageContext.session} <br>
session有效时间: ${pageContext.session.maxInactiveInterval} <br>

out对象: ${pageContext.out} <br>
缓冲区大小: ${pageContext.out.bufferSize} <br>

exception对象: ${pageContext.exception} <br>
错误信息: ${pageContext.exception.message} <br>

ServletContext对象: ${pageContext.servletContext} <br>
文件路径: ${pageContext.servletContext.contextPath} <br>
</body>
</html>

与范围有关的隐含对象

可以访问JavaBean

param和paramValues

前者用于获取请求单值的参数,后者用于获取请求多值的参数

header与headerValues

获取HTTP请求的header中的多个值

cookie

initParam

XML

是一种可扩展标记语言,用于结构化、传输和储存数据

文档结构

声明、元素、注释、字符引用、处理指令

基本语法

文档声明

出现在第一行,告诉解析器这是个XML文档

<?xml version="1.0" encoding="UTF-8"?>

标签

所有xml标签都必须有关闭标签,且必须有且仅有一个根标签

属性与注释

<?xml version="1.0" encoding="UTF-8" ?>
<!--XML属性的使用-->
<note date="2022-08-17">
    <to>北京</to>
    <from>深圳</from>
</note>

在XML中主要使用的是标签(元素),对它的属性的使用较少

实体引用

< <
> >
& &
&apos; '
" "

XML树结构

很好理解

XML解析器

<%@ page contentType="text/html;charset=UTF-8"%>
<html>
    <head>
        <title>LoadXML</title>
    </head>
    <script type="text/javascript">
        function file(){
            if (window.XMLHttpRequest){
                xmlhttp=new XMLHttpRequest();
            } else {
                xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
            }
            xmlhttp.open("GET","province.xml",false);
            xmlhttp.send();
            xmlDoc=xmlhttp.responseXML;
            document.getElementById("div1").innerHTML=
                xmlDoc.getElementsByTagName("name")[0].childNodes[0].nodeValue;
            document.getElementById("div2").innerHTML=
                xmlDoc.getElementsByTagName("name")[1].childNodes[0].nodeValue;
            document.getElementById("div3").innerHTML=
                xmlDoc.getElementsByTagName("name")[2].childNodes[0].nodeValue;
            document.getElementById("div4").innerHTML=
                xmlDoc.getElementsByTagName("name")[3].childNodes[0].nodeValue;
        }
    </script>
    <body onload="file()">
    <div id="div1"></div>
    <div id="div2"></div>
    <div id="div3"></div>
    <div id="div4"></div>
    </body>
</html>

JSTL

基于JSP界面且提前定义好的一组标签来实现Java代码,是EL表达式的扩展

核心标签库

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

分为表达式控制标签,流程控制标签,循环标签,URL操作标签

格式化标签库

用来格式化并输出文本、日期、时间和数字

<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>

SQL标签库

与关系型数据库交互

<%@ taglib uri="http://java.sun.com/jsp/jstl/sql" prefix="sql"%>

XML标签库

<%@ taglib uri="http://java.sun.com/jsp/jstl/xml" prefix="x"%>

函数标签库

<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>

Ajax

异步的JavaScript和XML

相当于在用户和服务器之间加了一个中间层,改变了同步交互的过程,也就是说并不是所有的用户请求都提交给服务器

技术组成

XMLHttpRequest对象

XML

JS

CSS

DOM

用于展现Web页面的结构,通过脚本修改DOM,Ajax应用程序可以在运行时改变用户界面,或者高效地重绘页面中的某个部分

XMLHttpRequest对象的使用

初始化该对象需要考虑IE浏览器与非IE浏览器的情况

var xmlhttp;
if (window.XMLHttpRequest){
    xmlhttp=new XMLHttpRequest();
} else {
  //IE
        xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}

一些相关属性:

readyState:0~4

onreadystatechange:指定状态改变时所触发的事件处理器的属性

responsetext:获取服务器的字符串响应的属性

responseXML:获取服务器的XML响应的属性

status:返回服务器的状态码

statusText:状态码文本

XMLHttpRequest对象的方法

创建新请求的open方法

xmlhttp.open("method","URL"[,asyncFlag[,userName[,password]]])

停止或放弃当前异步请求

abort()

向服务器发送请求

send(content)

设置请求的头部信息

setRequestHeader("header","value")

获取指定的Http头信息

getResponseHeader("Headerlabel")

getAllResponseHeaders()

Ajax异步交互的应用

异步交互就是客户端和服务端进行交互时,如果只更新客户端的一部分数据,那么就把这部分数据与服务器交互

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>异步连接服务器</title>
    <script type="text/javascript">
        var xmlhttp;
        function createXMLHttpRequest(){
            if (window.XMLHttpRequest)
                xmlhttp=new XMLHttpRequest();
            else
                xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
        }
        function test(){
            createXMLHttpRequest();
            xmlhttp.open("GET","/Servlet_Demo_war_exploded/ServletHeader?name=aa",true);
            xmlhttp.send(null);
            xmlhttp.onreadystatechange=function () {
                if (xmlhttp.readyState==4&&xmlhttp.status==200){
                    alert("服务器返回的结果是: "+xmlhttp.responseText);
                }
            }
        }
    </script>
</head>
<body>
<input type="button" value="测试是否连接成功" onclick="test()"/>
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>异步连接服务器</title>
    <script type="text/javascript">
        var xmlhttp;
        function createXMLHttpRequest(){
            if (window.XMLHttpRequest)
                xmlhttp=new XMLHttpRequest();
            else
                xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
        }
        function test(){
            createXMLHttpRequest();
            xmlhttp.open("POST","/Servlet_Demo_war_exploded/ServletHeader",true);
            xmlhttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
            var query=encodeURI("name=aa");
            xmlhttp.send(query);
            xmlhttp.onreadystatechange=function () {
                if (xmlhttp.readyState==4&&xmlhttp.status==200){
                    alert("服务器返回的结果是: "+xmlhttp.responseText);
                }
            }
        }
    </script>
</head>
<body>
<input type="button" value="测试是否连接成功" onclick="test()"/>
</body>
</html>
package Controller;

import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;

@WebServlet(urlPatterns = "/ServletHeader")
public class ServletHeader extends HttpServlet{
    public void doGet(HttpServletRequest request,HttpServletResponse response)throws IOException,ServletException{
        response.setContentType("text/html;charset=utf-8");
        response.getWriter().write("name: "+request.getParameter("name"));
        System.out.println("OK");
    }
    public void doPost(HttpServletRequest request,HttpServletResponse response)throws IOException,ServletException{
        response.setContentType("text/html;charset=utf-8");
        System.out.println(request.getContentLength());
        response.getWriter().write("POST: name="+request.getParameter("name"));
        System.out.println("OK");
    }
}

注意POST时要加xmlhttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded");

为了处理多个异步请求,一般把xmlhttp对象设为局部变量