JavaWeb详解

2年前 (2022) 程序员胖胖胖虎阿
430 0 0

JavaWeb动态Web资源开发

  • 静态Web: 用户看到的数据始终不变;动态Web:各人看到的信息不同
  • 动态Web:1.页面动态展示,淘宝"千人千面";2.和数据库交互

Web应用程序:给浏览器访问的程序 = 静态Web+动态Web

浏览器访问网络资源流程图
JavaWeb详解

  1. 客户端通过网络协议(如Http),请求进入服务器,

  2. WebSeervice收到请求,其中的**WebServerPlugin(服务插件)**判断要访问的文件是静态还是动态的.


  3. 静态直接找到资源文件(FIle System),动态的经过jsp,servlet(web技术)增强后(比如用jdbc连接数据库),

  4. 再通过WebServer(Web服务)找到对应的资源文件,然后以一种编码格式,响应回给客户端.


Http:基于Tcp的超文本传输协议

  • http使用80端口;https使用443端口,s指的是SSL/TLS协议,在HTTP和TCP/IP协议中间

  • http2.0=http/1.1版本,允许客户端与服务器连接后,获得多个资源.1.0是只能获取一个资源

请求行

  • post:参数,大小没有限制,浏览器url栏不显示数据,安全,但get比它更高效

消息头(请求头):告诉服务器怎样响应你这个请求

Accept: */* 你这个请求的数据类型
Accept-Encoding: gzip, deflate, br 编码格式
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6 语言环境
cache-control: max-age=0 缓存控制,最大缓存存活时间
Connection: keep-alive 连接成功后的持久策略,keep-alive始终保持连接
Host: www.dealctr.com 主机信息

响应行(响应头):告诉客户端(浏览器)应该怎样接收数据

reFresh :告诉客户端,多久刷新一次
location :网页是否重新定位

响应状态码

200:请求响应成功

300:请求重定向

404:找不到资源

500:服务器代码错误.502:网关错误

思考:浏览器从输入网址回车,到页面展示回来,经历了什么


Web服务器

服务器是一种被动的操作,处理请求与给用户回复响应

  1. 微软windows自带IIS服务器.

  2. Tomcat是一款先进,稳定,免费的轻量级应用服务器


Tomcat

重新部署项目是重新加载当前一个项目.

  1. java的根加载器在r(runtiem)t.jar包里.

  2. 启动startup.bat后,Tomcat的默认网址是http://localhost:8000/

  3. conf下的server.xml文件是tomcat的配置文件,可以在里面修改初始参数,如端口号

<Connector port="8080" protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="8443" />

一个webapps文件夹,就是一个Web应用

  1. webapps(Web项目)\ROOT下的index.jsp是默认访问的主页面:localhost:8080/index.jsp

浏览器访问网站流程

  1. 输入网址后,先去C:\Windows\System32\drivers\etc\hosts文件中找,有没有网址对应的域名映射(如下面的activate.navicat.com).
  2. 找到后返回对应的ip地址(activate.navicat.com对应的是127.0.0.1)
  3. 这个地址中有我们需要的web程序,找到后直接访问.
  4. 如果没有找到,就去**DNS(运营商根服务器)**上找,找的到就返回,找不到就提示"404(not found)找不到资源"

改变本机ip地址访问前缀:修改C:\Windows\System32\drivers\etc\hosts中的127.0.0.1(本地ip地址)的映射网址.

# 设置本机的ip地址中的,127.0.0.1和LiChangGe127.0.0.1的,映射域名为activate.navicat.com
127.0.0.1       LiChangGe127.0.0.1       activate.navicat.com
127.0.0.1       LiChangGe
# 都可以用
http://activate.navicat.com:8080/
http://lichangge:8080/

如果不可以,就再修改server.xml的host属性

<Host name="LiChangGe"  appBase="webapps" unpackWARs="true" autoDeploy="true"></Host>

Web项目结构

  1. 一个常见的TomcatWeb项目基本结构如下:webapps(项目顶级目录)\ROOT(自己的web项目)+index.jsp\WEB-INFO(web程序配置信息目录)\web.xml(web程序配置文件)

    JavaWeb详解

    JavaWeb详解

  2. Tomcat的examples官方API

JavaWeb详解


Maven项目架构管理工具

  • 核心思想:约定大于配置

idea可以不配置环境变量,自带maven

# 查看maven版本
C:\Users\林木>mvn -version
Apache Maven 3.8.3 (ff8e977a158738155dc465c6a97ffaf31982d739)

# 环境变量配置,你自己的maven安装目录
MAVEN_HOME
D:\Maven\apache-maven-3.8.3

# maven的运行程序bin目录,用idea可以不配置
M2_HOME
D:\Maven\apache-maven-3.8.3\bin

# Path引用maven,必须有
Path
%MAVEN_HOME%\bin
  1. conf\settings.xml配置maven本地仓库目录和镜像

    # 本地仓库,配置后去看看C:\用户\李长歌(这里是你自己的电脑账户)\.m2(默认隐藏的),这是maven默认的本地仓库,可以删掉.
    <localRepository>D:\Maven\apache-maven-3.8.3\mvn_properties</localRepository>
    # 镜像
    <mirrors>
      <!-- 阿里镜像配置 -->
        <mirror>
            <id>aliyunmaven</id>
            <mirrorOf>*</mirrorOf>
            <name>Nexus aliyun</name>
            <url>https://maven.aliyun.com/repository/public</url>
        </mirror>
    </mirrors>
    

idea创建MavenWeb项目

一键直达

JavaWeb详解

用模板创建

JavaWeb详解

JavaWeb详解

maven常用的全局设置

JavaWeb详解

创建新模块时选择Maven构建,实现联动父项目

JavaWeb详解

添加webapp目录

JavaWeb详解

添加框架支持时选择web服务,来添加web目录
JavaWeb详解

一个标准的web子模块

JavaWeb详解

  • 必须配置工件:因为访问一个网站,必须指定一个文件夹

JavaWeb详解

http://localhost:8080/xiaomi

pom.xml(Maven核心配置文件)代码解读

父类和子类模块的maven代码会联动

<groupId>com.changGe.li</groupId>
<artifactId>JavaWeb</artifactId>
<version>1.0-SNAPSHOT</version>

<modules>
  <module>XiaoMi</module>
</modules>

<name>JavaWeb</name>
<packaging>pom</packaging>

# 子类
<groupId>com.changGe.li</groupId>
<artifactId>XiaoMi</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>

<name>XiaoMi Maven Webapp</name>

配置运行时的java版本信息

<properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <maven.compiler.source>1.8</maven.compiler.source>
  <maven.compiler.target>1.8</maven.compiler.target>
</properties>

配置依赖

<!-- 配置依赖:maven会自动导入这个jar包,所需要的其他jar包 -->
<dependencies>

</dependencies> 
  1. maven遇到配置文件,无法导出或使用时 (1条消息) Maven解决配置文件无法导出或者无法生效_ReolPurion的博客-CSDN博客
  2. idea的日志文件,记载了我们的错误
  3. bat是批处理文件,可以在里面写cmd代码

HttpServlet

需要导包

<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>javax.servlet-api</artifactId>
  <version>4.0.1</version>
  <!--注意这里是配置作用域为测试和编译时有效
 			不配置的话,maven打包时会把这个包也打进项目中,
			就会和tomcat本身的servlet-api包冲突,报500错误等
	-->
  <scope>provided</scope>
</dependency>

当存储数据时,其下所有类本质是一个Map集合

继承HttpServlet(javax.servlet.http包下),需要Maven导入依赖

只要是实现了Servlet接口,就叫做Servlet小程序

<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>servlet-api</artifactId>
  <version>2.5</version>
</dependency>

重写方法

package com.changGe.li.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class TestServlet extends HttpServlet {

  @Override
  protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    resp.setCharacterEncoding("utf-8");
    resp.getWriter().print("Hello World");
  }

  @Override
  protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    doGet(req,resp);
  }

}

配置域名映射

<servlet>
  <!--设置名字和要加载的Servlet-->
  <servlet-name>he</servlet-name>
  <servlet-class>com.changGe.li.servlet.TestServlet</servlet-class>
</servlet>

<servlet-mapping>
  <!--对应he下面的Servlet的域名映射是/he,注意,一定要/(代表当前web项目,也就是localhost:8080)-->
  <servlet-name>he</servlet-name>
  <url-pattern>/he</url-pattern>
</servlet-mapping>

tomcat日志文件配置

JavaWeb详解


Servlet原理

  • 如果需要携带数据去到新页面,用request转发.
  • 不携带数据,只是单纯的页面跳转或刷新,就用respons重定向(respons也可以携带参数,后面再说).

浏览器向服务器发送请求,访问的是web容器(可以理解为服务器)

  1. 浏览器访问的是映射,然后返回IP地址


  2. 客户端发送请求,到达web容器.

  3. 如果是第一次的话,web容器直接访问servlet,第二次和以后,就是带着请求,找servlet的对应的service方法(如doGet()和doPost()等).

  4. 同时web容器的respons对象,也会监听接收,来自serivice的响应.监听到数据,web容器响应给客户端

JavaWeb详解

作用到代码上的执行流程

表单提交时携带请求和请求参数

  1. 按下submit提交表单,浏览器向action的值的地方发送请求
  2. 提取表单中所有有name属性的元素,把他们的值作为参数传递:如localhost:8080/Super/jsp/user.do?method=modify&uid=26
<form id="userForm" name="userForm" method="post" action="${pageContext.request.contextPath }/jsp/user.do">
	<input type="hidden" name="method" value="modify">
  
  <input type="text" name="userName" id="userName" value="${user.userName}"> 
  
  <input class="button_box" type="submit" value="保存">
  
</form>
  1. 服务器找到web.xml,看有没有对应的映射
  2. 找到这个映射对应的servlet
<servlet>
  <servlet-name>modifyPassword</servlet-name>
  <servlet-class>com.changGe.li.servlets.ModifyPasswordServlet</servlet-class>
</servlet>
<servlet-mapping>
  <servlet-name>modifyPassword</servlet-name>
  <!--
		/ 代表当前路径,也就是localhost:8080
		其后的路径语法根据表单的请求来写
		
		也可以随便写,如/* 代表项目下所有资源都可以访问,或
		
	-->
  <url-pattern>/jsp/user.do</url-pattern>
</servlet-mapping>

<!--不能这样写,会报错java.lang.IllegalArgumentException: servlet映射中的<url pattern>[/*.do]无效
	 因为/*,是匹配localhost:8080/下所有servlet上,/*.do服务器就认为你要访问所有以.do为后缀的Servlet,找不到
-->
<url-pattern>/*.do</url-pattern>

  1. 优先访问最接近的映射
<a href="${pageContext.request.contextPath}/hello">
<!--优先访问最接近的-->
<url-pattern>/hello</url-pattern>
<!--不访问-->  
<url-pattern>/hello.do</url-pattern>
  1. 调用对应的service(),如上面的表单提交方式是get,就找到doGet();

  2. 执行其中的实现代码

public class ModifyPasswordServlet extends HttpServlet {

  @Override
  protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
   	//重定向发送一个请求且携带参数
    resp.sendRedirect(req.getContextPath()+"/jsp/user.do?method=query");
    
  }

ServletContxet:管理所有Servlet,实现Servlet间共享数据

每个程序都有一个对应的上下文对象(ServletContext)
JavaWeb详解

实现Servlet间共享数据

<servlet>
  <servlet-name>he</servlet-name>
  <servlet-class>com.changGe.li.servlet.TestServlet</servlet-class>
</servlet>

<servlet-mapping>
  <servlet-name>he</servlet-name>
  <url-pattern>/hello</url-pattern>
</servlet-mapping>



<servlet>
  <servlet-name>hello</servlet-name>
  <servlet-class>com.changGe.li.servlet.TestServletOne</servlet-class>
</servlet>

<servlet-mapping>
  <servlet-name>hello</servlet-name>
  <url-pattern>/hello.do</url-pattern>
</servlet-mapping>

public class TestServlet extends HttpServlet {

  @Override
  protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    resp.setCharacterEncoding("utf-8");

    ServletContext servletContext = this.getServletContext();

    servletContext.setAttribute("name","武则天");

  }
}  


public class TestServletOne extends HttpServlet {

  @Override
  protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    resp.setCharacterEncoding("utf-8");

    ServletContext servletContext = this.getServletContext();

    Object name = servletContext.getAttribute("name");

    System.out.println(name);

  }
  
}

servletContext转发

// 一定要写上/代表当前web项目目录下
servletContext.getRequestDispatcher("/info.jsp").forward(req,resp);

配置初始化参数后,其下所有servlet都可以获取

<context-param>
  <param-name>name</param-name>
  <param-value>李长歌</param-value>
</context-param>
ServletContext servletContext = this.getServletContext();

String name = servletContext.getInitParameter("name");
System.out.println(name);//李长歌

项目构建后会被打包,在target/项目/WEB-INF/classes下

classes俗称类路径

JavaWeb详解

如果java目录下的资源没有导入成功,在pom.xml中添加下列代码

然后删除target目录,重新部署或重启tomcat服务器

filtering的作用 (4条消息) maven Filtering true 作用_滕青山YYDS的博客-CSDN博客

<!--构建项目时,控制某些资源可以被导入或导出-->
<build>
  <resources>
    <resource>
      <!-- 导入src/main/java下,所有目录下,
        以.properties和以.xml为后缀名的文件 -->
      <directory>src/main/java</directory>
      <includes>
        <include>**/*.properties</include>
        <include>**/*.xml</include>
      </includes>
      <!--允许我这个文件用一些字符,替换掉导入文件中对应的字符-->
      <filtering>true</filtering>
    </resource>
  </resources>
</build>

读取资源文件

public class TestServlet extends HttpServlet {

  @Override
  protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    resp.setCharacterEncoding("utf-8");

    ServletContext servletContext = this.getServletContext();

    InputStream resourceAsStream = servletContext.getResourceAsStream("/WEB-INF/classes/com/changGe/li/lib/test1.properties");

    Properties properties = new Properties();
    properties.load(resourceAsStream);

    String name = properties.getProperty("name");

    System.out.println(name);

  }
  
}  

Request请求转发:直接请求另一个资源的路径,直接写相对路径就可以

服务器接收到浏览器的请求后,针对这个请求自动创建Request(请求)和Respons(响应)对象

HttpServlet源码中有初始的状态码

public interface HttpServletRequest extends ServletRequest {

    /**
     * String identifier for Basic authentication. Value "BASIC"
     */
    public static final String BASIC_AUTH = "BASIC";

    /**
     * String identifier for Form authentication. Value "FORM"
     */
    public static final String FORM_AUTH = "FORM";

    /**
     * String identifier for Client Certificate authentication. Value "CLIENT_CERT"
     */
    public static final String CLIENT_CERT_AUTH = "CLIENT_CERT";

请求转发时,可以携带参数

req.setAttribute("name","李长歌");
req.getRequestDispatcher("info.jsp").forward(req,resp);

获取复选框中数据

<form action="${pageContext.request.contextPath}/hello">

  <input type="checkbox" name="check" value="篮球">
  <input type="checkbox" name="check" value="足球">
  <input type="checkbox" name="check" value="排球">

  <input type="submit" value="点我一下看看"/>
</form>
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

  //获取所有的值,返回数组
  String[] names = req.getParameterValues("check");
  for (String name : names) {
    System.out.println(name);
  }

}

Respons响应重定向:从你现在的路径去到一个新的路径,url栏会发生变化,要写绝对路径

//req.getContextPath() = 当前项目目录路径:localhost:8080
resp.sendRedirect(req.getContextPath()+"/info.jsp");

重写向时不会传递参数

响应数据

//把集合响应回去,ajax用做函数的data
resp.setContentType("application/json");
resp.setCharacterEncoding("utf-8");
try {
  PrintWriter writer = resp.getWriter();

  //将集合变成json对象输出
  writer.write(JSON.toJSONString(result));

  writer.flush();
  writer.close();

} catch (IOException e) {
  e.printStackTrace();
}

下载文件:respons负责把读取到的数据,响应回给浏览器

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

  //以utf-8解析请求
  resp.setCharacterEncoding("utf-8");
  //让浏览器以utf-8模式解析响应
  resp.setHeader("Content-type", "text/html;charset=UTF-8");
  
  String imgUrl = "E:\\JAVA\\JavaWeb\\XiaoMi\\src\\main\\resources\\test.properties";

  //从最后一个/开始截取,获得文件名
  String fileName = imgUrl.substring(imgUrl.lastIndexOf("\\") + 1);

  //输入流
  FileInputStream fileInputStream = new FileInputStream(imgUrl);  //设置响应头:内容类型,附件;文件名字=
  resp.setHeader("Content-Disposition","attachment;filename="+ URLEncoder.encode(fileName,"utf-8"));

  //获取响应的文件输出流
  ServletOutputStream outputStream = resp.getOutputStream();

  byte[] bytes = new byte[10];

  int length = 0;

  while ((length = fileInputStream.read(bytes)) != -1){
    outputStream.write(bytes,0,length);
  }

}

    resp.setCharacterEncoding("utf-8");
    resp.setHeader("Content-type", "text/html;charset=UTF-8");

    String imgUrl = "E:\\JAVA\\JavaWeb\\XiaoMi\\src\\main\\resources\\test.properties";

    //从最后一个/开始截取,获得文件名
    String fileName = imgUrl.substring(imgUrl.lastIndexOf("\\") + 1);

    //输入流
    FileInputStream fileInputStream = new FileInputStream(imgUrl);
    BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
    FileReader fileReader = new FileReader(imgUrl);


    //设置响应头:内容类型,附件;文件名字=
    resp.setHeader("Content-Disposition","attachment;filename="+ URLEncoder.encode(fileName,"utf-8"));

    //获取响应的文件输出流
    ServletOutputStream outputStream = resp.getOutputStream();
    BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream);
   // PrintWriter writer = resp.getWriter();

    byte[] bytes = new byte[10];
    char[] chars = new char[1024];

    int length = 0;

/*
    while ((length = fileInputStream.read(bytes)) != -1){
      outputStream.write(bytes,0,length);
    }*/

    while ((length = bufferedInputStream.read(bytes)) != -1){
      bufferedOutputStream.write(bytes,0,length);
      bufferedOutputStream.flush();
    }

    bufferedInputStream.close();
    bufferedOutputStream.close();
    outputStream.close();
    fileInputStream.close();

验证码

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

  //宽高,以8位RGB色彩模式打包出去
  BufferedImage bufferedImage = new BufferedImage(300,300,BufferedImage.TYPE_INT_RGB);

  //得到支笔
  Graphics2D graphics = (Graphics2D) bufferedImage.getGraphics();

  graphics.setBackground(new Color(0xEBA9E7));
  graphics.setColor(new Color(0x00F4E0));
  //实心矩形,x,y,width,height
  graphics.fillRect(400,400,600,600);

  //字体,罗马基线,大小
  graphics.setFont(new Font("方正舒体",Font.ROMAN_BASELINE,50));
  //要写的字符串,x,y
  graphics.drawString(verifyCode(),50,200);


  //让浏览器以图片格式解析
  resp.setContentType("image/png");

  //设置浏览器的3秒刷新一次
  resp.setHeader("refresh","3");
  //多少秒后过期
  resp.setDateHeader("expires",-1);
  //缓存控制不缓存
  resp.setHeader("Cache-Control","no-cache");
  //程序不缓存,作用和上面一样,一般两者一起使用
  resp.setHeader("Program","no-cache");

  //把图片,按照格式,写到一个地方去
  ImageIO.write(bufferedImage,"png",resp.getOutputStream());

}

public String verifyCode(){
  Random random = new Random();

  /**
     * valueOf()的底层:return (obj == null) ? "null" : obj.toString();
     * 它不会报空指针异常,但是如果是null,也会直接变成"null"
     */
  String number = String.valueOf(random.nextInt(10000000));

  StringBuilder stringBuilder = new StringBuilder(number);

  //保证验证码是7个字符
  for (int i = 0; i < 7 - number.length(); i++) {
    stringBuilder.append("x");
  }
  System.out.println(stringBuilder);

  return stringBuilder.toString();

}

请求重定向与请求转发的区别

  1. 请求重定向
    使用responce.sendRedirect(“xx.jsp”)来进行重定向。是客户端的行为:即客户端会访问两次,第一次访问后会立即跳转到第二个重定向页面上,从本质上讲等于两次请求,而前一次的请求封装的request对象不会保存,地址栏的URL地址会改变。

JavaWeb详解

2、请求转发
使用request.getRequestDispatcher(“xx.jsp”).forward(request,response)请求转发。forward(request,response)用于保存内置对象request和response。是服务器的行为服务器会代替客户端去访问转发页面,从本质是一次请求转发后请求对象会保存,地址栏的URL地址不会改变。

JavaWeb详解


Cookie(客户端技术)

有状态会话:会话(客户端和服务器间的一次交流seesion) + 缓存(cookie)

本质是把用户的数据写给浏览器,由浏览器保存

用cookie读取上一次访问时间:刷新一次数据也刷新

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  String format = new SimpleDateFormat("yyyy年MM月dd日:HH时mm分ss秒").format(new Date());
    Cookie lastTime = new Cookie("lastTime", format);

    boolean flag = true;

    Cookie[] cookies = req.getCookies();

    if(cookies != null && cookies.length > 0){
      for (Cookie cookie : cookies) {

        String value = cookie.getName();

        if(value != null && value.equals("lastTime")){
          flag = false;

          //特定格式解析字符串,常用于中文解码
          req.setAttribute("lastTime", URLDecoder.decode(cookie.getValue(),"utf-8"));

          //更新登录时间
          cookie.setValue(format);
          /**
           * 缓存时间0秒,就是删除cookie,
           * 只有用户关闭浏览器才会删除cookie
           */
          cookie.setMaxAge(60 * 60);//单位是秒
          resp.addCookie(lastTime);

          req.getRequestDispatcher("index.jsp").forward(req,resp);
          return;
        }

      }//for

    }

    if(flag){
      resp.addCookie(lastTime);

      req.setAttribute("msg", "这是您第一次登录");
      req.getRequestDispatcher("info.jsp").forward(req,resp);
    }

}

精简版

String format = new SimpleDateFormat("yyyy年MM月dd日:HH时mm分ss秒").format(new Date());

Cookie[] cookies = req.getCookies();

boolean flag = true;

if(cookies != null && cookies.length > 0){
  for (Cookie cookie : cookies) {

    String value = cookie.getName();

    if(value != null && value.equals("lastTime")){
      flag = false;
      req.setAttribute("msg", "您上一次登录时间:"+URLDecoder.decode(cookie.getValue(),"utf-8"));
    }

  }//for

}

if(flag){
  req.setAttribute("msg", "这是您第一次登录");
}

Cookie lastTime = new Cookie("lastTime", format);
resp.addCookie(lastTime);

req.getRequestDispatcher("info.jsp").forward(req,resp);

浏览器的applition里可以看到cookie缓存.,可以删除掉特定的cookie

JavaWeb详解

只有清除了localhost:8080的缓存后,cookie才真正消失,每次浏览器都默认存储了一些cookie

JavaWeb详解

用everything我们可以找到**cookiie的存放位置,**只是我们不能用(没有权限,到AC就看不到了)

JavaWeb详解

浏览器最多发送300个coolie,约是15个网站的,最大共1200kb数据.


Seesion(服务器技术)

服务器会为每个浏览器都创建一个seesion,在服务器上保存用户的数据,全局作用域,直到浏览器关闭.

seesion在浏览器默认存储30分钟

<session-config>
  <!--15分钟自动失效-->
  <session-timeout>15</session-timeout>
</session-config>
  1. seesion存储在cookie中,去浏览器的applition中找到cookie看,或者请求头的cookie里保存的有

    JavaWeb详解

  2. 底层代码相当于response.addcookie(new Cookie(“JSSSIONID”,value));

    //约等于此,不过是服务器内部实现的,我们这样的不行
    resp.addCookie(new Cookie("JSSSIONID", "123"));
    
  3. seesion可以存储对象,能用seesion就不要用context

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

  HttpSession session = req.getSession();
  session.setAttribute("name","李长歌");
  session.setAttribute("age","18");
  session.setAttribute("sex","女");

  //如果是新创建的
  if(session.isNew()){
    Enumeration<String> attributeNames = session.getAttributeNames();

    //sessionId是D6E8AD19A02583A4CB3DA5F36F86EB28
    System.out.println("sessionId是"+session.getId());

    /**
       * 结果:
       * 女
       * 李长歌
       * 18
       * 
       * 页面自动回到浏览器主页了,因为session注销了
       */
    while (attributeNames.hasMoreElements()){
      String name = attributeNames.nextElement();
      System.out.println(session.getAttribute(name));

      //可以用于用户退出时删除用户信息
      session.removeAttribute(name);
    }

    //注销
    session.invalidate();

  }

}

和全文索引的应用场景一样

JavaWeb详解


JSP(Java服务页面JavaServerPages)

本质就是Servlet(小应用服务程序)

  1. PHP语言不能承载大访问量,微软ASP是HTML+VB脚本,用C#语言开发
  2. jsp基于Java的B(browser)S架构,sun公司开发,可以承载三高:高并发,高性能和高可用(数据要高可靠,服务要高可用)

index.jsp源码分析

服务器访问任何资源,本质是访问Servlet. 因为idea的tomcat>work目录下的jsp页面最后变成了.java文件.

JSP源码分析__板蓝根_的博客-CSDN博客_jsp源码

这个博客没有找到,就在这里面找

JavaWeb详解

这是我最终找到的路径:C:\Users\林木\AppData\Local\JetBrains\IntelliJIdea2021.2\tomcat\61c407dd-c490-4564-89ac-71da59dbac6b\work\Catalina\localhost\XiaoMi\org\apache\jsp

  1. 继承自HttpJspBase类,HttpJspBase继承自HttpServlet类

    public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase
    
  2. 初始化,销毁和服务三大方法

    public void _jspInit() {
    }
    
    public void _jspDestroy() {
    }
    
    public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
    
  3. 判断请求类型.method()

    if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method)) {
            response.setHeader("Allow","GET, HEAD, POST, OPTIONS");
            response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSP 只允许 GET、POST 或 HEAD。Jasper 还允许 OPTIONS");
            return;
          }
    
  4. 初始化对象有context(改名application),page = this…

    final javax.servlet.jsp.PageContext pageContext;
    javax.servlet.http.HttpSession session = null;
    final javax.servlet.ServletContext application;
    final javax.servlet.ServletConfig config;
    javax.servlet.jsp.JspWriter out = null;
    final java.lang.Object page = this;
    javax.servlet.jsp.JspWriter _jspx_out = null;
    javax.servlet.jsp.PageContext _jspx_page_context = null;
    
  5. 有个try里面,在输出页面前为一些默认的对象,如pageContext等赋值,我们可以在jsp页面中直接使用

    try {
      response.setContentType("text/html;charset=utf-8");
      pageContext = _jspxFactory.getPageContext(this, request, response,
                                                null, true, 8192, true);
      _jspx_page_context = pageContext;
      application = pageContext.getServletContext();
      config = pageContext.getServletConfig();
      session = pageContext.getSession();
      out = pageContext.getOut();
      _jspx_out = out;
    
      out.write("\n");
      out.write("<html>\n");
      out.write("\n");
      out.write("<body>\n");
    

JavaWeb详解

<%--这是jsp表达式,加"="号专门用来输出--%>
<input type="text" value="名字是:<% String name="李长歌"; %>
                                                  <%= name%>"/>

<!--对应到jsp.java底层->
out.write("        <input type=\"text\" value=\"名字是:");
 String name="李长歌"; 
      out.print( name);

jsp语法

javax-servlet-jsp-api依赖

<dependency>
  <groupId>javax.servlet.jsp</groupId>
  <artifactId>jsp-api</artifactId>
  <version>2.0</version>
</dependency>

html的注释可以在控制台看到,jsp不显示

JavaWeb详解

<%--jsp脚本在_jspService()中--%>
<!--${i}EL表达式-->
<% for(int i = 0 ; i < 5; i++){%>
  <h1>
    hello world<%= i %>
  </h1>
<% } %>

<%--jsp声明在jsp类中--%>
<%! 
  public void test(){}
%>

自定义错误页面

<%@ page pageEncoding="utf-8" %>

<%--jsp标签:写在页面最上面,作为配置.显式声明这是一个错误页面--%>
<%@ page  isErrorPage="true" %>
<%@page errorPage="info.jsp" %>
<html>

<body>
    <% int i = 1 / 0;%>
</body>
</html>

<error-page>
  <!--500错误时跳转页面-->
  <error-code>500</error-code>
  <location>/info.jsp</location>
</error-page>

添加公共页面

<%--是将页面中的代码提出来,然后和现有页面代码拼接在一起--%>
<%@ include file="info.jsp" %>
out.write("<head>\r\n");
out.write("    <title>Info</title>\r\n");
out.write("</head>\r\n");
out.write("<body>\r\n");
out.write("\r\n");
out.write("<h3>info下的h3</h3>\r\n");
out.write("    <img src=\"WEB-INF/images/error.jpg\" width=\"1240\" height=\"800\">\r\n");
out.write("\r\n");
out.write("\r\n");
out.write("</body>\r\n");
out.write("</html>\r\n");
out.write("\n");
out.write("<html>\n");
out.write("\n");
out.write("<body>\n");

<%--第二种方法--%>
<%--这是调用其它页面,不会出现代码冲突的问题--%>
<jsp:include page="info.jsp"/>
out.write("    <h2>22222</h2>\n");
org.apache.jasper.runtime.JspRuntimeLibrary.include(request, response, "info.jsp", out, false);
out.write("\n");

jsp标签

<%--作用域是request--%>
<jsp:forward page="info.jsp">
  <jsp:param name="name" value="李长歌"/>
</jsp:forward>
<h3>name is:${pageContext.request.getParameter("name")}</h3>

static包下一般放前端的资源,如css,img,js和plugins等.

WEB-INF目录对用户不可见


EL表达式

作用域优先级:pageScope > requestScope > sessionScope > pageContext(页面运行时)>applicationScope(服务器)

如果没有给定取值作用域,则默认从pageScope开始查找,找到则返回,没找到则按照上述顺序继续查找,以此类推,知道找到为止。

如果最终没有找到,则返回null


九大对象及作用域

JavaWeb详解

  1. page对象的数据出了页面就消失了;
  2. seesion间可以互相访问,但是当要统计服务器中所有数据时,就要去到更高级的application对象了:
  3. page -> request -> seesion -> pageContext>application
  4. 类似于双亲委派机制,先从应用类加载器找,找不到用扩展类加载器(ext中的jar包),还找不到就最后去根加载器(rt目录下的jar包).
<body>
  <%
  pageContext.setAttribute("name","李长歌");
  session.setAttribute("name1","session");
  request.setAttribute("name2","request");
  application.setAttribute("name3","application");

  //获取值
  String name5 = (String) pageContext.findAttribute("name5");
  %>
  <%--找不到也不报错,el表达式自动过滤null值,不显示在页面中--%>
  <!--name:李长歌 name1:session name2:request name3:application name5:-->
  name:${name}
  name1:${name1}
  name2:${name2}
  name3:${name3}
  name5:${name5}<!--不显示-->
</body>

设置作用域

<%
	//等同于session.setAttribute("key","value");
	pageContext.setAttribute("key","value",pageContext.SESSION_SCOPE);
%>

作用域保存数据的重要性从低到高:request(客户端看完即删,新闻图片等.) < seestion(需要二次使用,但不事关关键业务,如购物车) < application(需要全局作用,事关关键业务,如聊天数据)

<%
	pagecontext.setAttribute("name","李长歌");

	request = pagecontex.getRequest();
	requext.forward("forward.jsp");
%>

<%--页面转发时,会自动将数据也给转发走--%>
<%--info页面下--%>
<%
	String name = (String)pagecontext.getAttribute("name");
	out.print(name);
%>

jstl标签

jstl-api依赖和standrard标签库依赖

如果报错说找不到这个包,可能是因为tomcat中没有这个jar包,直接粘到tomcat的work目录中去

<dependency>
  <groupId>jstl</groupId>
  <artifactId>jstl</artifactId>
  <version>1.2</version>
</dependency>
<dependency>
  <groupId>taglibs</groupId>
  <artifactId>standard</artifactId>
  <version>1.1.2</version>
</dependency>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<%--写在最顶上,导入core标签库,字首(也就是前缀)为c,字首可以随便写--%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<%--如果报错:根据标记文件中的TLD或attribute指令,attribute[items]不接受任何表达式
  是因为和tomcat中的jstl-api.jar包不兼容
  就换成下面这个--%>
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core_rt" %>

switch循环和if判断

<body>
  <%--定义变量sorce,赋值为100--%>
    <c:set var="score" value="100"/>

    <%-- 把test判断的值,赋值给number --%>
    <c:if test="${score > 0 and score <= 100}" var="number">
        <c:out value="${number}"/>
        <%--循环判断--%>
        <c:choose>
            <%--会自动break--%>
            <c:when test="${score >=90 or score <= 100}">

                <c:out value="优秀的成绩"/>

            </c:when>
        </c:choose>
    </c:if>
</body>

增加for

<%
    ArrayList<Object> arrayList = new ArrayList<>();
    arrayList.add(0,0);
    arrayList.add(1,1);
    arrayList.add(2,2);
    arrayList.add(3,3);
    request.setAttribute("list",arrayList);
%>

<%--从1遍历到3,一次i+2,最后只输出1,3--%>
<c:forEach var="item" items="${list}" begin="1" end="3" step="2">
    <%--从list集合中取值,值为item,打印item到页面上--%>
    <c:out value="${item}"/>
</c:forEach>

JavaBean(咖啡豆)

jsp:useBean的用法_远方©的博客-CSDN博客_jsp:usebean

  • 有无参构造+属性私有化,有对应的set,get方法
<form action="index.jsp" method="get">

    <input type="text" name="name" value="李长歌">
    <input type="text" name="age" value="18">
    <input type="submit" value="请提交">
</form>

<%--实例化对象User--%>
<jsp:useBean id="user" class="com.changGe.li.User" scope="page"/>

<%--获取表单中的所有值,并一一赋值给User类,对应的set方法--%>
<jsp:setProperty name="user" property="*"/>

<%--从user对象中取值--%>
<jsp:getProperty name="user" property="name"/><%--李长歌--%>
<jsp:getProperty name="user" property="age"/><%--18--%>
<%=user.getAge()%><%--18--%>
<form action="index.jsp" method="get">

    <input type="text" name="name" value="李长歌">
    <input type="text" name="age" value="18">
    <input type="submit" value="请提交">
</form>

<%--实例化对象User--%>
<jsp:useBean id="user" class="com.changGe.li.User" scope="page"/>

<%--只给setName()赋值--%>
<jsp:setProperty name="user" property="name"/>

<jsp:getProperty name="user" property="name"/><%--李长歌--%>

<%--尽管age的input输入了值,还是为0--%>  
<jsp:getProperty name="user" property="age"/><%--0--%>
<%=user.getAge()%><%--0--%>
<form action="index.jsp" method="get">

    <input type="text" name="name" value="李长歌">
    <input type="text" name="age" value="18">
    <input type="submit" value="请提交">
</form>

<%--实例化对象User--%>
<jsp:useBean id="user" class="com.changGe.li.User" scope="page"/>

<%--给setName()赋值"武则天"--%>
<jsp:setProperty name="user" property="name" value="武则天"/>

<%--最后得到的还是"武则天"--%>
<jsp:getProperty name="user" property="name"/>
<form action="index.jsp?name=李世民" method="get">

    <input type="text" name="name" value="李长歌">
    <input type="text" name="age" value="18">
    <input type="submit" value="请提交">

</form>

<%--实例化对象User--%>
<jsp:useBean id="user" class="com.changGe.li.User" scope="page"/>

<%--从请求的参数取值name,赋值给user对象的setName--%>
<jsp:setProperty name="user" property="name" param="name"/>

<%--最后得到的还是"李长歌"--%>
<jsp:getProperty name="user" property="name"/>
<body>

<%--实例化对象User--%>
<jsp:useBean id="user" class="com.changGe.li.User" scope="page"/>

<%--赋值给user对象的setName--%>
<jsp:setProperty name="user" property="name" value="武则天"/>

<%--"武则天"--%>
<jsp:getProperty name="user" property="name"/>

</body>

MVC(Model view controller模型视图控制器)三层架构

三层架构就是在Model层进行dao(数据持久),service(业务处理)的中间过渡

JavaWeb详解


Filter过滤器:在服务器与资源文件之间过滤数据

mysql-connector-java依赖,一定要用和自己数据库版本一样的jar包(依赖),不同版本的结构不同

<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <version>8.0.27</version>
</dependency>

实现Filter下的方法init初始化,doFIlter业务,destroy销毁,可以只实现doFilter()

@Override
public void init(FilterConfig filterConfig) throws ServletException {
  Filter.super.init(filterConfig);
}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

}
@Override
public void destroy() {
  Filter.super.destroy();
}

用filter实现登录验证

  1. 用户提交表单后,找到对应的servlet
<h1 class="title">欢迎登录</h1>
<form action="${pageContext.request.contextPath}/login" method="get">
  <input class="input_box" type="text"  name="userCode" value="hanlubiao" placeholder="用户名">
  <input class="input_box" type="password"  name="password" value="0000000" placeholder="密码">
  <input class="button_box" type="submit" value="登录">
  <span>${error}${param.get("error")}</span>
</form>
<servlet>
  <servlet-name>login</servlet-name>
  <servlet-class>com.changGe.li.servlets.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
  <servlet-name>login</servlet-name>
  <url-pattern>/login</url-pattern>
</servlet-mapping>
  1. 这里面取值用户的信息,判断是否成功.

成功了就跳转主页,失败是失败页面.

public class LoginServlet extends HttpServlet {

  //数据库工具类
  private UserService userService = new UserServiceImpl();

  @Override
  protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

    String userCode = req.getParameter("userCode");
    String password = req.getParameter("password");

		//根据用户名和密码找到User对象
    User user = userService.getUser(userCode,password);

    //不为空就保存到session中
    if(user != null){
      req.getSession().setAttribute("user",user);

      resp.sendRedirect(req.getContextPath()+"/jsp/frame.jsp");
    }else {
      //失败就重定向
      req.setAttribute("error","用户名或密码错误");

      req.getRequestDispatcher("login.jsp").forward(req,resp);
    }


  }
}
  1. 注销就是让用户对应的seesion删除掉:req.getSession().removeAttribute(“user”);

注销后回到登录页面.

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  User user = (User)req.getSession().getAttribute("user");

  if(user != null){
    req.getSession().removeAttribute("user");
    resp.sendRedirect(req.getContextPath()+"/login.jsp");
  }else {
    //为空,代表已经被删除了
    req.getRequestDispatcher("error.jsp").forward(req,resp);
  }

}
  1. 有个过滤器每次有新请求时,都判断用户的seesion是否为空
<!-- 初始过滤:强制登录,管理系统不需要让游客看到首页 -->
<filter>
  <filter-name>forcoLogin</filter-name>
  <filter-class>com.changGe.li.filters.ForcoLoginFilter</filter-class>
</filter>
<filter-mapping>
  <filter-name>forcoLogin</filter-name>
  <url-pattern>/jsp/*</url-pattern>
</filter-mapping>
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

  HttpServletRequest req = (HttpServletRequest) request;
  HttpServletResponse resq = (HttpServletResponse) response;

  //从session中获取user对象
  User user = (User)req.getSession().getAttribute("user");

  if(user == null){
    request.setAttribute("error","请先登录,谢谢");

    resq.sendRedirect(req.getContextPath()+"/login.jsp?error="+ URLEncoder.encode("请先登录,谢谢","utf-8"));

  }else{
    //找到之后直接进入主页.不用登录
    //必须让请求和响应 链接 起来后,程序才会继续进行,不然就卡住
    chain.doFilter(req, resq);
  }

}
  1. user的session经常用到,可以提取成静态常量
public static final String USER_SEESION = "user";

用这个思想,实现一个判断用户vip等级的demo.

主要是过滤器根据username获取到的seesion,进而获取对象,然后判断等级

<form action="hello" method="get">

  等级:<input type="text" name="grade" value="2">
  <input type="submit" value="提交">

</form>

info.jsp

<body>
    <h2>您的等级是:${grade}</h2>
</body>

web.xml

<filter>
  <filter-name>verify</filter-name>
  <filter-class>com.changGe.li.FilterTest</filter-class>
</filter>
<filter-mapping>
  <filter-name>verify</filter-name>

  <!--监听名为he的servlet的动作-->
  <servlet-name>he</servlet-name>
  <!--两者可以同时存在,不存在优先级这一说-->
  <url-pattern>/*</url-pattern>
</filter-mapping>

<servlet>
  <servlet-name>he</servlet-name>
  <servlet-class>com.changGe.li.servlet.TestServlet</servlet-class>
</servlet>
<servlet-mapping>
  <servlet-name>he</servlet-name>
  <url-pattern>/hello</url-pattern>
</servlet-mapping>

TestServlet

public class TestServlet extends HttpServlet {

  @Override
  protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    String grade = req.getParameter("grade");
    req.getSession().setAttribute("grade",grade);

    req.getRequestDispatcher("info.jsp").forward(req,resp);
  }

  @Override
  protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    doGet(req,resp);
  }

}

FilterTest

public class FilterTest implements Filter {

  @Override
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

    HttpServletRequest req = (HttpServletRequest) request;
    HttpServletResponse resq = (HttpServletResponse) response;

    String grade = req.getParameter("grade");
    if(grade == null || grade.equals("")){

      //从session中获取user对象
      grade = String.valueOf(req.getSession().getAttribute("grade"));

    }

    if(grade != null && !grade.equals("")){
      System.out.println("if中的"+grade);

      switch (grade){
        case "1":
          req.setAttribute("grade","1");
          break;
        case "2":
          req.setAttribute("grade","2");
          break;
        default:
          req.setAttribute("grade","3");
      }
      chain.doFilter(req, resq);
    }else{
      resq.getWriter().write("等级为空");
    }

  }

}

Listener监听器

各种类型的监听器都可以实现,如HttpSestionListener,始终监听session域

index.jsp

<form action="hello" method="get">

  <input type="submit" value="提交">

</form>
<!--web.xml配置监听器-->
<listener>
    <listener-class>com.changGe.li.ListenerTest</listener-class>
</listener>

监听到有session被创建时,就创建一个sess的session,赋值

有session被销毁时,得到资源

public class ListenerTest implements HttpSessionListener {
  //有session被创建时
  @Override
  public void sessionCreated(HttpSessionEvent se) {
    //创建session
    se.getSession().setAttribute("sess", URLEncoder.encode("监听到session被创建了"));
  }

  //有session被销毁时
  @Override
  public void sessionDestroyed(HttpSessionEvent se) {
    Object source = se.getSource();
		//输出结果org.apache.catalina.session.StandardSessionFacade@8539a6f
    System.out.println("监听到的资源是:"+source.toString());
  }

}

servlet中先创建一个session,触发sessionCreated()

然后得到sessionCreated()创建的session打印出去

最后删除自己创建的session

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

  //创建session
  req.getSession().setAttribute("name","李长歌");

  //写去session
  resp.getWriter().write(String.valueOf(req.getSession().getAttribute("sess")));

  //删除session
  req.getSession().invalidate();

}

实现统计在线人数

只要有个session被创建后,在线人数就+1;销毁时在线人数-1

servlet

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

  //一秒刷新一次
  resp.setHeader("refresh","1");

  //一定要从ServletContext中取值,ServletContext监控所有session
  String online = String.valueOf(req.getServletContext().getAttribute("online"));

  req.setAttribute("online",online);

  req.getRequestDispatcher("info.jsp").forward(req,resp);

}
public class ListenerTest implements HttpSessionListener {

  //有session被创建时
  @Override
  public void sessionCreated(HttpSessionEvent se) {

    //在最高的作用域servletContext操作session
    ServletContext servletContext = se.getSession().getServletContext();

    Integer online = (Integer) servletContext.getAttribute("online");

    if(online == null || online <= 0){
      online = 1;
    }else {
      online ++;
    }

    servletContext.setAttribute("online",online);

  }

  //有session被销毁时
  @Override
  public void sessionDestroyed(HttpSessionEvent se) {
    ServletContext servletContext = se.getSession().getServletContext();

    Integer online = (Integer)servletContext.getAttribute("online");

    if(online == null || online < 0){
      online = 0;
    }else {
      online --;
    }

    servletContext.setAttribute("online",online);

  }

}

info.jsp

<body>
  <h2>在线人数是:${online}</h2>
</body>

web.xml

<session-config>
  <!-- 超时(过期)时间为1分钟 写成0或负数就代表永远不超时-->
  <session-timeout>1</session-timeout>
</session-config>

实现GUI窗口关闭,实现它的子类,用的是适配器模式

public static void main(String[] args) {
  JFrame jFrame = new JFrame();

  //适配器模式,windowAdapter实现了WindowListener
  jFrame.addWindowListener(new WindowAdapter() {
    @Override
    public void windowClosed(WindowEvent e) {
      super.windowClosed(e);
    }
  });

}

WindowAdapter实现了WindowListener

public abstract class WindowAdapter
    implements WindowListener, WindowStateListener, WindowFocusListener
{

juit单元测试依赖

<!--可以直接用@test写在方法上,不用main方法,就能直接运行了-->
<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.13.2</version>
  <scope>test</scope>
</dependency>

q.setAttribute(“online”,online);

req.getRequestDispatcher(“info.jsp”).forward(req,resp);

}


```java
public class ListenerTest implements HttpSessionListener {

  //有session被创建时
  @Override
  public void sessionCreated(HttpSessionEvent se) {

    //在最高的作用域servletContext操作session
    ServletContext servletContext = se.getSession().getServletContext();

    Integer online = (Integer) servletContext.getAttribute("online");

    if(online == null || online <= 0){
      online = 1;
    }else {
      online ++;
    }

    servletContext.setAttribute("online",online);

  }

  //有session被销毁时
  @Override
  public void sessionDestroyed(HttpSessionEvent se) {
    ServletContext servletContext = se.getSession().getServletContext();

    Integer online = (Integer)servletContext.getAttribute("online");

    if(online == null || online < 0){
      online = 0;
    }else {
      online --;
    }

    servletContext.setAttribute("online",online);

  }

}

info.jsp

<body>
  <h2>在线人数是:${online}</h2>
</body>

web.xml

<session-config>
  <!-- 超时(过期)时间为1分钟 写成0或负数就代表永远不超时-->
  <session-timeout>1</session-timeout>
</session-config>

实现GUI窗口关闭,实现它的子类,用的是适配器模式

public static void main(String[] args) {
  JFrame jFrame = new JFrame();

  //适配器模式,windowAdapter实现了WindowListener
  jFrame.addWindowListener(new WindowAdapter() {
    @Override
    public void windowClosed(WindowEvent e) {
      super.windowClosed(e);
    }
  });

}

WindowAdapter实现了WindowListener

public abstract class WindowAdapter
    implements WindowListener, WindowStateListener, WindowFocusListener
{

juit单元测试依赖

<!--可以直接用@test写在方法上,不用main方法,就能直接运行了-->
<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.13.2</version>
  <scope>test</scope>
</dependency>

ORM对象关系映射 :就是实体类和数据库字段互相对应

版权声明:程序员胖胖胖虎阿 发表于 2022年11月7日 下午10:00。
转载请注明:JavaWeb详解 | 胖虎的工具箱-编程导航

相关文章

暂无评论

暂无评论...