Web
基本概念
Web,网页的意思。
- 静态web
- html+css
- 提供给所有人看的数据始终不会变化
- 动态web
- 几乎所有的网站
- 提供给不同人看的数据会不同,每个人在不同时间地点看到的内容不同。
- 技术栈:Servlet/JSP,ASP,PHP
在Java中,动态web资源开发的技术统称为JavaWeb。
web应用程序
web应用程序:可以提供浏览器访问的程序。
- Web应用程序是由多个Servlet、JSP页面、HTML文件以及图像文件等组成。
- 能访问到的任何资源都在世界的某台服务器上。
- 这些统一的web资源会被放在同一个文件夹下
- 一个Web应用程序组成部分:
- Html,CSS,JavaScript
- JSP,Servlet
- Java程序
- jar包
- 配置文件(Properties)
web应用程序编写完毕后,若想要提供给外界访问:需要一个服务器。
静态web
缺点:
- 页面无法动态更新,所有用户看到相同界面
- 可以通过JS实现伪动态交互,如轮播图。
- 无法和数据库交互(无法持久化数据)
动态web
web页面展示的效果因人而异,淘宝千人千面。
缺点
- 假如服务器的动态web资源出现异常,需要重新编写后台程序
- 停机维护
Web服务器
技术讲解
- ASP
- 微软:国内最早流行
- 在HTML中嵌入了VB脚本,耦合度极高,维护成本高
- ASP做前台页面,后台使用VB COM+组件对数据进行操作
- 现在基本用C#编写,IIS发布
- PHP
- 开发速度快,功能很强大,跨平台代码简单
- 无法承载大访问量,但是国内基本都是中小型网站,所以目前依旧应用广泛
- JSP/Servlet
- Sun公司主推的B/S架构
- 基于Java语言(所有的大公司,或者一些开源组件都是Java编写的)
- 可以承载高并发、高可用、高性能带来的影响
- 语法像ASP,有利于ASP转JSP,抢占市场
Web服务器
服务器是一种被动操作,用来处理用户请求和相应用户新消息。
- IIS
- 微软windows系统自带
- Tomcat
- Tomcat是Apache 软件基金会的Jakarta 项目中的一个核心项目,最新的Servlet 和JSP 规范总是能在Tomcat 中得到体现。
- 因为Tomcat 技术先进、性能稳定,而且免费,因而深受Java 爱好者的喜爱并得到了部分软件开发商的认可,成为目前比较流行的Web 应用服务器。
- Tomcat 实际上运行JSP 页面和Servlet。
- ...
Tomcat
安装运行
-
下载完后解压
-
新建系统变量
CATALINA_HOME,值为解压后的(上图中的)E:\apache-tomcat-9.0.40 -
加入Path,
%CATALINA_HOME%\bin,%CATALINA_HOME%\lib -
点击
bin\startup.bat,出现控制台,访问http://localhost:8080/ -
退出:Ctrl+C、关闭窗口或点击
bin\shutdown.bat
配置文件
配置文件均在conf文件夹下。
-
server.xml 服务器配置
<!-- 仅放部分配置信息 --> <!-- 配置端口号 主机名:8080--> <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /> <!-- name主机名 localhost:端口号 若改为某个域名 需要修改hosts文件 --> <!-- appBase网站资源存放的目录 自动访问的是webapps/ROOT --> <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"> ... </Host>
面试题
网站是如何进行访问的?
- 浏览器访问域名
- 查看本机host(C:\Windows\System32\drivers\etc)文件中有没有该域名对应的ip
- 有:直接访问该ip
- 没有:去DNS(域名解析服务器)中查找该域名对应的ip并访问,若找不到则访问失败
发布网站
- webapps是存放网站资源的目录,只要把自己的网站文件夹放入webapps中即可
- 通过
http://localhost:8080/网站文件夹名访问,会默认访问你的index.html - 若没有
index.html,则http://localhost:8080/网站文件夹名/自定义.html
- webapps
//默认存在的网站
- ROOT // http://localhost:8080
- docs // http://localhost:8080/docs 以下类推
- examples
- host-manager
- manager
//自己的网站
- mywebsite //http://localhost:8080/mywebsite
- WEB-INF
- classes //java程序
- lib //依赖包
- web.xml //网站配置
- index.html //默认首页
- static //静态资源
- css
- js
- img
HTTP
HTTP是什么
HTTP(HyperText Transfer Protocol,超文本传输协议)是一个简单的请求-响应协议,它通常运行在TCP之上。
- 超文本是用超链接的方法,将各种不同空间的文字信息组织在一起的网状文本。
- 端口:80
HTTPS(Hyper Text Transfer Protocol over SecureSocket Layer,安全超文本传输协议)
-
是以安全为目标的 HTTP 通道,在HTTP的基础上通过传输加密和身份认证保证了传输过程的安全性,HTTPS 在HTTP 的基础下加入SSL 层,HTTPS 的安全基础是 SSL。
-
端口号:443
两个时代
- HTTP/1.0
- 客户端可以与web服务器连接后,只能获得一个web资源就断开
- HTTP/1.1
- 客户端可以与web服务器连接后,可以获得多个web资源
HTTP请求与响应
以访问百度为例,打开浏览器,按F12打开开发者工具,访问百度网址。
综合体
Request URL: https://www.baidu.com/ #请求的URL
Request Method: GET #请求方法
Status Code: 200 OK # 状态码
Remote Address: 127.0.0.1:1080 #远程地址
Referrer Policy: strict-origin-when-cross-origin
GET和POST
| GET | POST | |
|---|---|---|
| 后退/刷新 | 无害 | 数据会被重新提交(浏览器应该告知用户数据会被重新提交)。 |
| 书签 | 可收藏为书签 | 不可收藏为书签 |
| 缓存 | 能被缓存 | 不能缓存 |
| 编码类型 | application/x-www-form-urlencoded | application/x-www-form-urlencoded 或 multipart/form-data。为二进制数据使用多重编码。 |
| 历史 | 参数保留在浏览器历史中。 | 参数不会保存在浏览器历史中。 |
| 对数据长度的限制 | 是的。当发送数据时,GET 方法向 URL 添加数据;URL 的长度是受限制的(URL 的最大长度是 2048 个字符)。 | 无限制。 |
| 对数据类型的限制 | 只允许 ASCII 字符。 | 没有限制。也允许二进制数据。 |
| 安全性 | 与 POST 相比,GET 的安全性较差,因为所发送的数据是 URL 的一部分。在发送密码或其他敏感信息时绝不要使用 GET ! | POST 比 GET 更安全,因为参数不会被保存在浏览器历史或 web 服务器日志中。 |
| 可见性 | 数据在 URL 中对所有人都是可见的。 | 数据不会显示在 URL 中。 |
状态码
- 1XX:信息,服务器收到请求,需要请求者继续执行操作
- 2XX:成功,操作被成功接收并处理
- 3XX:重定向,需要进一步的操作以完成请求
- 4XX:客户端错误,请求包含语法错误或无法完成请求
- 5XX:服务器错误,服务器在处理请求的过程中发生了错误
请求头
#展示部分
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 #接受的数据类型
Accept-Encoding: gzip, deflate, br #告诉服务器 支持的编码
Accept-Language: zh-CN,zh;q=0.9 #告诉服务器 支持的语言
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36
Cache-Control: no-cache # 缓存控制
Connection: keep-alive # 请求完成连接保持
Cookie: #过长省略
Host: www.baidu.com #主机名百度
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36 #客户端信息
响应头
Cache-Control: private
Connection: keep-alive
Content-Type: text/html;charset=utf-8
Date: Wed, 09 Dec 2020 08:47:38 GMT #时间
Expires: Wed, 09 Dec 2020 08:47:37 GMT #过期时间
Maven
在JavaWeb开发中,需要使用大量的jar包,我们手动去导入,Maven可以帮助我们自动导入包。
Maven 是一个项目管理工具,可以对 Java 项目进行构建、依赖管理。
Maven核心思想:约定大于配置
- 有约束,不要去违反
安装运行
-
下载解压
-
环境变量
- MAVEN_HOME:Maven目录
- M2_HOME:Maven目录下的bin目录
- Path中添加
%MAVEN_HOME%\bin也可以直接%M2_HOME%,只要指向的是bin目录即可
-
打开CMD,测试
mvn -version
配置阿里云镜像
Maven的默认仓库是国外的,要么翻墙,要么下载速度很慢,所以将仓库改为阿里云的国内仓库。
-
打开
conf\settings.xml(以下是删除所有注释后的内容) -
在
mirrors标签中插入以下配置
<!-- 阿里云仓库 -->
<mirror>
<id>alimaven</id>
<mirrorOf>central</mirrorOf>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/repositories/central/</url>
</mirror>
<!-- 中央仓库1 -->
<mirror>
<id>repo1</id>
<mirrorOf>central</mirrorOf>
<name>Human Readable Name for this Mirror.</name>
<url>http://repo1.maven.org/maven2/</url>
</mirror>
<!-- 中央仓库2 -->
<mirror>
<id>repo2</id>
<mirrorOf>central</mirrorOf>
<name>Human Readable Name for this Mirror.</name>
<url>http://repo2.maven.org/maven2/</url>
</mirror>
本地仓库
<!-- settings.xml下加入 路径自定义 以后包都会放在这个目录下 -->
<localRepository>E:\apache-maven-3.6.3\maven-repo</localRepository>
settings.xml的最终配置
<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
<localRepository>
E:\apache-maven-3.6.3\maven-repo
</localRepository>
<pluginGroups>
</pluginGroups>
<proxies>
</proxies>
<servers>
</servers>
<mirrors>
<!-- 阿里云仓库 -->
<mirror>
<id>alimaven</id>
<mirrorOf>central</mirrorOf>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/repositories/central/</url>
</mirror>
<!-- 中央仓库1 -->
<mirror>
<id>repo1</id>
<mirrorOf>central</mirrorOf>
<name>Human Readable Name for this Mirror.</name>
<url>http://repo1.maven.org/maven2/</url>
</mirror>
<!-- 中央仓库2 -->
<mirror>
<id>repo2</id>
<mirrorOf>central</mirrorOf>
<name>Human Readable Name for this Mirror.</name>
<url>http://repo2.maven.org/maven2/</url>
</mirror>
</mirrors>
<profiles>
</profiles>
</settings>
在IDEA中使用Maven
使用模板
-
创建Maven项目
-
勾选自动导入包
-
本地仓库的变化
-
创建完后的注意事项,改完后可以在File—Other Settings—Settings for New Projects再设置,一劳永逸
-
使用模板的项目结构
不使用模板
-
不勾选模板
-
组名项目名
-
直接最后一步
-
干净纯粹的maven项目结构(这里可以选择做别的项目了)
-
手动添加web框架,右键项目名
-
勾选Web Application
-
效果
拓展:文件夹标记
文件夹标记会影响右键创建文件类型的选项。
添加Tomcat
pom文件
maven项目结构
-
clean命令的使用
-
Tomcat运行网站后,会生成一个target文件夹,相当于打包好的项目
-
双击clean可以删除target文件夹
-
-
依赖关系图
pom.xml配置解析
<?xml version="1.0" encoding="UTF-8"?>
<!-- xml的命名空间 -->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- 之前配置的 -->
<groupId>com.volcano</groupId>
<artifactId>javaweb-01-maven</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 项目打包方式
1:jar java程序
2:war JavaWeb程序
-->
<packaging>war</packaging>
<!-- 没什么用的东西 -->
<name>javaweb-01-maven Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<!-- 配置 -->
<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>
<!-- 项目依赖 -->
<dependencies>
<!-- 具体依赖项 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
<!-- 构建项目需要用的东西 这里是模板需要的,可以全部删除,所以不推荐使用模板创建maven,建议添加自行需要 -->
<build>
<finalName>javaweb-01-maven</finalName>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<!-- 插件 -->
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
使用
-
在Maven仓库中寻找需要的包
-
复制Maven代码到pom.xml中的
denpencies中 -
Maven会自动下载这个包,Maven的高级之处在于会自动导入该包所依赖的包
可能遇到的问题
-
maven版本和IDEA版本不匹配,使用低版本maven可解决,记得修改上文提及配置和环境变量
-
本文IDEA2018.2.4,Maven3.6.3,遇到此问题,将Maven版本换为3.5.4成功解决
-
-
由于Maven的核心思想:约定大于配置,会遇到的问题之一就是,java写了java代码之外的文件,比如
.properties,.xml等等,这些在项目导出时会被忽略,因为约定java目录只写java文件-
解决方法:修改pom.xml的build配置
<build> <resources> <resource> <!-- 允许src/main/resources包括includes节点中的文件类型 --> <directory>src/main/resources</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> </resources> </build>
-
-
修改web.xml的最佳版本
-
IDEA自动生成的web.xml内容
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app> <display-name>Archetype Created Web Application</display-name> </web-app> -
Tomcat的ROOT的web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0" metadata-complete="true"> <display-name>Welcome to Tomcat</display-name> <description> Welcome to Tomcat </description> </web-app> -
最好与Tomcat的一致,避免出现后续问题
-
-
Tomcat 控制台乱码
Servlet
简介
- Servlet就是Sun公司开发动态web的一门技术
- Sun公司在这些API中提供一个接口叫做Servlet,要开发一个Servlet程序,需要两步
- 编写一个类,实现Servlet接口
- 把开发好的Java类部署到web服务器上
- 实现了Servlet接口的Java程序叫做,Servlet
HelloServlet
前提准备和解释
-
新建一个不使用模板的Maven项目,删除里面的src目录,一个空的Maven项目,我们可以创建不同的module来对应一个子项目,这些项目都共用一个pom.xml中的依赖,不用新建项目再重新各种导入。
-
右键主项目根目录,创建新module,使用webapp的模板,这个module相当于一个子项目,有自己的结构,如下(自行创建java和resources文件夹并标记,修改web.xml结构为最新):
-
在主项目的pom.xml中会有如下变化
<modules> <module>servlet01</module> </modules> -
子项目的pom.xml中的对应结构
<parent> <artifactId>javaweb-02-maven</artifactId> <groupId>com.volcano</groupId> <version>1.0-SNAPSHOT</version> </parent> -
子项目中的包和java程序只能给子项目用,主项目的包和java程序可以给子项目用。
开始编写
-
导入Servlet的两个依赖包
<dependencies> <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency> <!-- https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api --> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>javax.servlet.jsp-api</artifactId> <version>2.3.3</version> <scope>provided</scope> </dependency> </dependencies> -
创建一个类实现HttpServlet接口
- Sun公司有两个默认的Servlet接口:HttpServlet、GenericServlet
- 继承关系为:Servlet—>GenericServlet—>HttpServlet—>自己的类
import javax.servlet.ServletException; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; public class HelloServlet extends HttpServlet { //由于get和post只是请求实现的不同方式,可以互相调用,业务逻辑都一样 @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //响应流 PrintWriter writer = resp.getWriter(); writer.write("Hello Servlet"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } } -
编写Servlet的映射
- 为什么需要映射:我们写的是Java程序,但是要通过浏览器访问,浏览器连接web服务器,所以需要在web服务器中注册写好的Servlet,给他一个浏览器能够访问的路径。
- 映射需要在web.xml中配置。
<!-- 注册Servlet --> <servlet> <servlet-name>hello</servlet-name> <!-- 一个Servlet对应一个Servlet实现类 --> <servlet-class>com.volcano.servlet.HelloServlet</servlet-class> </servlet> <servlet-mapping> <!-- 给一个访问地址 --> <servlet-name>hello</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping> -
配置Tomcat(前文提及),虚拟路径设置为
/servlet01 -
运行测试 http://localhost:8080/servlet01/hello
Servlet原理
-
前文提过,Servlet就是一个接口,那么接口就是定义一个规范。其中只有5个方法
void init(ServletConfig var1) throws ServletException; ServletConfig getServletConfig(); void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException; String getServletInfo(); void destroy(); -
不论是HttpServlet和GenericServlet都只是基于Servlet的规范,进一步完成了初始化、获得信息、配置、处理请求和销毁的具体实现。
-
我们自己的类继承于HttpServlet,HttpServlet基本上帮我们做了除了处理请求之外的所有事情,我们可以专注于业务。
-
Servlet不会和客户端打交道,因为我们没有在使用Servlet的时候监听端口,所以客户端来的请求不能直接到达Servlet,而是通过Tomcat这个web容器。
-
Tomcat直接和客户端打交道,监听了端口,请求过来后,根据url等信息,确定要将请求交给哪个servlet去处理,然后调用那个servlet的service方法,service方法返回一个response对象,tomcat再把这个response返回给客户端。
Mapping
-
一个Servlet可以映射一个或多个url-pattern
<servlet> <servlet-name>hello</servlet-name> <servlet-class>com.volcano.servlet.HelloServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello2</url-pattern> </servlet-mapping> -
Servlet映射url-pattern可以使用通配符
<servlet> <servlet-name>hello</servlet-name> <servlet-class>com.volcano.servlet.HelloServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello/*</url-pattern> <!-- 不建议使用 会覆盖index.jsp的访问路径 --> <!-- <url-pattern>/*</url-pattern> --> </servlet-mapping> -
Servlet映射url-pattern可以使用后缀
<servlet> <servlet-name>hello</servlet-name> <servlet-class>com.volcano.servlet.HelloServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>hello</servlet-name> <!-- *前不能有/ 但是输入的内容中*可以包含/ --> <url-pattern>*.vol</url-pattern> </servlet-mapping> -
优先级
- 明确的url>通配符url
ServletContext
ServletContext,即Servlet上下文,运行一个web程序,就会有一个ServletContext,凌驾于所有Servlet之上,实现各个Servlet之间的数据通信等功能。
数据通信
新建一个servlet02的module,按照之前的操作优化一下结构和内容,记得把Tomcat中的虚拟路径映射改为/servlet02。
由于之前Tomcat打包的内容是servlet01,所以将01移除加入02,仅加入02,如果加其他的会被一起打包,没有必要。
-
目录结构
-
HelloServlet中的内容
package com.volcano.servlet; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; public class HelloServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { PrintWriter writer = resp.getWriter(); writer.write("Hello,Servlet"); //获得ServletContext ServletContext context = this.getServletContext(); //设置属性 context.setAttribute("username","灿大帅"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } } -
HelloServletContext中的内容
package com.volcano.servlet; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; public class HelloServletContext extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setCharacterEncoding("utf8"); resp.setContentType("text/html"); PrintWriter writer = resp.getWriter(); //获得ServletContext ServletContext context = this.getServletContext(); //获得属性 String username = (String) context.getAttribute("username"); //显示 writer.write("<h1>用户名:"+username+"</h1>"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } } -
web.xml,仅放servlet部分
<servlet> <servlet-name>hello</servlet-name> <servlet-class>com.volcano.servlet.HelloServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping> <servlet> <servlet-name>username</servlet-name> <servlet-class>com.volcano.servlet.HelloServletContext</servlet-class> </servlet> <servlet-mapping> <servlet-name>username</servlet-name> <url-pattern>/username</url-pattern> </servlet-mapping> -
注意事项
- 因为在给ServletContext设置属性是在处理/hello中进行的,所以要先访问/hello,再访问/username
- 设置响应头很重要,不然会是乱码或者响应内容会变成文件被下载
-
效果
获得初始化数据
-
配置初始化数据
-
在web.xml中
<context-param> <param-name>url</param-name> <param-value>jdbc:mysql//localhost:3306/jdbcstudy</param-value> </context-param> -
在java代码中
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { PrintWriter writer = resp.getWriter(); //获得ServletContext ServletContext context = this.getServletContext(); //配置初始化数据 context.setInitParameter("url","jdbc:mysql//localhost:3306/jdbcstudy"); }
-
-
得到数据
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { PrintWriter writer = resp.getWriter(); //获得ServletContext ServletContext context = this.getServletContext(); //获取数据 String initParm = context.getInitParameter("url"); //显示 writer.write("<h1>url:"+initParm+"</h1>"); }
转发
-
HelloServletContext中的内容
public class HelloServletContext extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setCharacterEncoding("utf8"); resp.setContentType("text/html"); PrintWriter writer = resp.getWriter(); //获得ServletContext ServletContext context = this.getServletContext(); //一旦访问的请求到这个Servlet就会被 转发到 /disp context.getRequestDispatcher("/disp").forward(req,resp); } -
新建HelloDispatcher类中的内容
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.getWriter().print("I got it"); } -
web.xml
<servlet> <servlet-name>disp</servlet-name> <servlet-class>com.volcano.servlet.HelloDispather</servlet-class> </servlet> <servlet-mapping> <servlet-name>disp</servlet-name> <url-pattern>/disp</url-pattern> </servlet-mapping>
读取资源文件
-
在java和resources目录下新建一个
.properties文件 -
发现打包后,java下的
.properties文件未被导出,而resources下的文件被导出在classes目录下,我们称该路径为classpath
所以要回到Maven—可能遇到的问题。
配置之后,java下的.properties也被打包了。
读取资源要用到打包后的项目相对路径。
-
db.properties
username=root password=123456 -
新建ReadProperties类
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext context = req.getServletContext(); //注意用的是导出后的项目相对路径 InputStream stream = context.getResourceAsStream("/WEB-INF/classes/db.properties"); Properties properties = new Properties(); properties.load(stream); String username = properties.getProperty("username"); String password = properties.getProperty("username"); resp.getWriter().print(username+":"+password); } -
web.xml
<servlet> <servlet-name>getinfo</servlet-name> <servlet-class>com.volcano.servlet.ReadProperties</servlet-class> </servlet> <servlet-mapping> <servlet-name>getinfo</servlet-name> <url-pattern>/getinfo</url-pattern> </servlet-mapping> -
结果
HttpServletResponse
web服务器接收到客户端的http请求,针对这个请求,分别创建一个请求的HttpServletRequest对象,代表相应的一个HttpServletResponse;
- 如果要获取客户端请求过来的参数:找HttpServletRequest
- 如果要给客户端相应一些信息:找HttpServletResponse
分类
-
向浏览器发送数据的方法
ServletOutputStream getOutputStream() throws IOException; PrintWriter getWriter() throws IOException; -
向浏览器发送响应头的方法
void setCharacterEncoding(String var1); void setContentLength(int var1); void setContentLengthLong(long var1); void setContentType(String var1); void setDateHeader(String var1, long var2); void addDateHeader(String var1, long var2); void setHeader(String var1, String var2); void addHeader(String var1, String var2); void setIntHeader(String var1, int var2); void addIntHeader(String var1, int var2); -
状态码常量:状态码详细表
常见应用
-
向浏览器输出信息
-
下载文件(web.xml已配置)
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //1.获取下载文件的真实路径,是打包好后的路径 String realPath = "F:\\云\\Code\\JavaWeb\\javaweb-02-maven\\response\\target\\response\\WEB-INF\\classes\\家教壁纸.jpg"; System.out.println(realPath); //2.获取文件名 String filename = realPath.substring(realPath.lastIndexOf('\\')+1); System.out.println(filename); //3.文件输入流 FileInputStream in = new FileInputStream(realPath); //4.响应文件输出流 ServletOutputStream out = resp.getOutputStream(); //5.设置下载文件的响应头,设置编码,避免中文乱码 resp.setHeader("Content-Disposition","attachment;filename="+ URLEncoder.encode(filename,"utf-8")); //6.输出文件 int len=0; byte[] buffer=new byte[1024]; while((len=in.read(buffer))>0){ out.write(buffer,0,len); } out.close(); in.close(); } -
验证码(web.xml已配置)
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //设置浏览器每3秒刷新一次 resp.setHeader("refresh","3"); //1.在内存画一张图 BufferedImage image = new BufferedImage(80,40,BufferedImage.TYPE_INT_RGB); //2.获取画笔 Graphics2D graphics = (Graphics2D) image.getGraphics(); //3.设置背景 graphics.setColor(Color.WHITE); graphics.fillRect(0,0,80,40); //4.画随机数 graphics.setColor(Color.BLUE); graphics.drawString(createRandom(),20,20); //5.设置响应头 //返回数据类型 jpg 图片 resp.setHeader("Content-Type","image/jpg"); //不缓存 resp.setHeader("expires","-1"); resp.setHeader("Cache-Control","no-cache"); resp.setHeader("Pragma","no-cache"); ImageIO.write(image,"jpg",resp.getOutputStream()); } -
重定向(重要)
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { /* * 重定向本质 * resp.setStatus(302); * resp.setHeader("Location","/response/vercode"); * */ resp.sendRedirect("/response/vercode"); } -
重定向和转发的相同点和区别
- 相同点
- 页面都会跳转
- 不同点
- 转发页面URL不会变,重定向会变
- 转发的url中
/代表当前项目,重定向中需要当前项目的路径 - 转发(307)
- 重定向(302)
- 相同点
HttpServletRequest
HttpServletRequest代表客户端的请求,用户通过Http协议访问服务器,Http请求中的所有信息会被封装到HttpServletRequest,通过HttpServletRequest的方法,获得客户端的所有信息。
常见应用
-
获取Request数据
- 首次开始使用JSP页面,切记已经导入javax.servlet.jsp-api这个包
<%-- index.jsp --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <body> <%-- 在JSP中,${}中可以编写java代码,这里是获取网站的根目录 --%> <form action="${pageContext.request.contextPath}/dealform" method="post"> 用户名:<input type="text" name="username"> <br> 密码:<<input type="password" name="password"> <br> 爱好: <input type="checkbox" name="hobbies" value="篮球">篮球 <input type="checkbox" name="hobbies" value="足球">足球 <input type="checkbox" name="hobbies" value="乒乓球">乒乓球 <br> <input type="submit"> </form> </body> </html><%-- success.jsp --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Success</title> </head> <body> <h2>登录成功</h2> </body> </html>protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //防止中文乱码 req.setCharacterEncoding("utf-8"); resp.setCharacterEncoding("utf-8"); String username = req.getParameter("username"); String password = req.getParameter("password"); String[] hobbies = req.getParameterValues("hobbies"); System.out.println(Arrays.toString(hobbies)); System.out.println(username); System.out.println(password); //转发时, / 就已经代表着当前项目 req.getRequestDispatcher("/success.jsp").forward(req,resp); }
Cookie和Session
- Cookie
- 客户端技术
- 存放键值对,只能是字符串
- 每个浏览器的存放上限不同
- 每个大小4KB左右
- 录取证书,证明我是这里的学生
- Session
- 服务端技术
- 服务端对每个访问它的浏览器一个Session,默认浏览器关闭失效
- Session可以存放对象
- Sessionid一般通过cookie返回
- 学校登记过,证明我是这里的学生
Cookie
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
resp.setContentType("text/html;Charset=utf-8;");
PrintWriter writer = resp.getWriter();
//获取请求中的Cookies
Cookie[] cookies = req.getCookies();
System.out.println(Arrays.toString(cookies));
if(cookies!=null){
writer.write("最近一次访问是在:");
for(Cookie cookie:cookies){
//获得cookie的key
if("lastLoginTime".equals(cookie.getName())){
//获得cookie的value
long timestamp = Long.parseLong(cookie.getValue());
writer.write((new Date(timestamp)).toLocaleString());
}
}
}
//响应添加cookie,cookie只能存字符串
//每次访问都给一个新的Cookie存放这次的访问时间戳
Cookie cookie = new Cookie("lastLoginTime", System.currentTimeMillis() + "");
//设置过期时间,单位 秒
//经测试 -1 或 不设置 浏览器关闭则过期
//0 马上过期(不会有显示的机会)
//cookie.setMaxAge(0);
resp.addCookie(cookie);
}
Session
//getSession
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8;");
//获得session对象
HttpSession session = req.getSession();
//获得sessionid
String sessionId = session.getId();
PrintWriter writer = resp.getWriter();
//获得session中的属性
Person person = (Person) session.getAttribute("Person");
if(person==null){
writer.write("SessionID:"+sessionId);
}else {
writer.write("SessionID:"+sessionId+"<br>"+person.getName());
}
}
//setSession
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session = req.getSession();
Person person = new Person("volcano","男",21);
//设置Session中的属性
session.setAttribute("Person",person);
}
//clearSession
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session = req.getSession();
//另Session失效
session.invalidate();
}
<!-- web.xml -->
<session-config>
<!-- Session自动过期时间 单位分钟 -->
<session-timeout>60</session-timeout>
</session-config>
JSP
JSP是什么
JSP(Java Server Pages),Java服务端页面,属于动态web技术。
特点:HTML中可以嵌入Java代码
JSP原理
-
每当用IDEA中的Tomcat生成一个网站,就会在本机的
C:\Users\当前用户名\.IntelliJIdeaXXXX.x\system\tomcat\Unnamed_项目名中生成一个work目录。 -
\work\Catalina\localhost\ROOT\org\apache\jsp该目录下存在着index_jsp.java -
查看源码后发现:JSP的本质就是一个Servlet,其实不管浏览器向服务器发送什么请,都是访问了某个Servlet
-
继承和实现关系
index_jsp——>HttpJspBase——>HttpServlet -
JSP内置对象都可以在这个Java文件中找到
final javax.servlet.jsp.PageContext pageContext; javax.servlet.http.HttpSession session = null; //session final javax.servlet.ServletContext application; //ServletContext final javax.servlet.ServletConfig config; javax.servlet.jsp.JspWriter out = null; //JspWriter final java.lang.Object page = this; javax.servlet.jsp.JspWriter _jspx_out = null; javax.servlet.jsp.PageContext _jspx_page_context = null; -
在JSP中填写HTML代码其实都是Java代码输出的
response.setContentType("text/html");//熟悉的设置响应头 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; //JSP中显示的HTML标签 out.write("<html>\n"); out.write("<body>\n"); out.write("<h2>Hello World!</h2>\n"); out.write("</body>\n"); out.write("</html>\n"); -
每当重新运行一次Tomcat,work目录都会被销毁,运行完毕之后会重新生成一个work目录,其中的
XXX_jsp.java,会随着页面的访问而增加,不访问不会被转换为Java类
-
JSP基础语法
JSP中除了HTML标签,还有自己独有的语法,支持所有Java代码。
准备
<dependencies>
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet/jstl -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/taglibs/standard -->
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
</dependencies>
语法
-
JSP表达式
<!-- <%= 变量或表达式%> --> <%= new java.util.Date()%> <!-- 等价于 --> <jsp:expression> 表达式 </jsp:expression> <!-- 可以用EL表达式替代 --> <!-- 若值为null则el表达式不会显示,而jsp表达式会显示null --> ${new java.util.Date()} -
JSP脚本片段
<% int sum = 0; for (int i = 0; i < 10 ; i++) { //out 内置对象 out.write(i+"<br>"); } %> -
Java嵌套Html
<% int sum = 0; for (int i = 0; i < 10 ; i++) { %> <p>Hello,World <%=i%></p> <% } %> -
JSP声明
- 上面的几个嵌入的代码都是在
XXX_jsp.java中的public void _jspService()的方法体中,方法体中无法定义方法和定义全局变量
<%! static { System.out.println("进入static"); } int globalint = 10; public void mymethod(){ System.out.println(globalint); } %> <% //调用要在这里 mymethod(); %> - 上面的几个嵌入的代码都是在
-
JSP注释
<%-- JSP注释不会出现JSP源码中 --%> <!-- HTML注释 会出现浏览器源码中 -->
JSP指令
-
page
-
import
<%@page import="java.util.*" %> -
errorPage
<!-- 如果页面报错,则转到404.jsp --> <%@page errorPage="404.jsp" %> -
...
-
-
include
<!-- 抽取页面公共部分 header.jsp和footer.jsp -->
<!-- 本质:将这两个jsp文件的内容 write 在一起 本质是写到一个页面 -->
<%@include file="header.jsp" %>
<h2>
我是主内容
</h2>
<%@include file="footer.jsp" %>
<!-- 类似 注意需要最前面要加/ -->
<!-- 本质:读取了文件 并且拼接,本质还是多个jsp -->
<jsp:include page="/header.jsp"/>
- taglib
九大内置对象
| 对象 | 描述 |
|---|---|
| request | HttpServletRequest类的实例 |
| response | HttpServletResponse类的实例 |
| out | PrintWriter类的实例,用于把结果输出至网页上 |
| session | HttpSession类的实例 |
| application | ServletContext类的实例,与应用上下文有关 |
| config | ServletConfig类的实例 |
| pageContext | PageContext类的实例,提供对JSP页面所有对象以及命名空间的访问 |
| page | 类似于Java类中的this关键字 |
| exception | exception 类的对象,代表发生错误的 JSP 页面中对应的异常对象 |
存储功能、作用域
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%
pageContext.setAttribute("name1","volcano1");//仅在这个页面有效
request.setAttribute("name3","volcano3");//在请求转发中有效
session.setAttribute("name2","volcano2");//在一次会话中有效,默认浏览器关闭前有效
application.setAttribute("name4","volcano4");//在服务器中有效,服务器关闭前有效
%>
<%
//findAttribute 一层一层找pageContext->request->session->application
String name1 = (String) pageContext.findAttribute("name1");
String name2 = (String) pageContext.findAttribute("name2");
String name3 = (String) pageContext.findAttribute("name3");
String name4 = (String) pageContext.findAttribute("name4");
String name5 = (String) pageContext.findAttribute("name5");//null
//转发功能,等价于 request.getRequestDispatcher("/index.jsp").forward(request,response);
pageContext.forward("/index.jsp");
%>
<h2>${name1}</h2>
<h2>${name2}</h2>
<h2>${name3}</h2>
<h2>${name4}</h2>
<%-- 不显示 --%>
<h2>${name5}</h2>
</body>
</html>
JSP行为、JSTL标签、EL表达式
JSP行为
| 语法 | 描述 |
|---|---|
| jsp:include | 用于在当前页面中包含静态或动态资源 |
| jsp:useBean | 寻找和初始化一个JavaBean组件 |
| jsp:setProperty | 设置 JavaBean组件的值 |
| jsp:getProperty | 将 JavaBean组件的值插入到 output中 |
| jsp:forward | 从一个JSP文件向另一个文件传递一个包含用户请求的request对象 |
| jsp:plugin | 用于在生成的HTML页面中包含Applet和JavaBean对象 |
| jsp:element | 动态创建一个XML元素 |
| jsp:attribute | 定义动态创建的XML元素的属性 |
| jsp:body | 定义动态创建的XML元素的主体 |
| jsp:text | 用于封装模板数据 |
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<jsp:forward page="jspforward.jsp">
<%-- 携带request参数 --%>
<jsp:param name="name" value="volcano"/>
<jsp:param name="age" value="21"/>
</jsp:forward>
</body>
</html>
JSTL标签
JSP标准标签库(JSTL)是一个JSP标签集合,它封装了JSP应用的通用核心功能。
使用步骤
-
导入jstl和standard(后两个)
-
JSP页面中引入(核心库)
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> -
若失败了,试着把这两个包也放入Tomcat的lib中
核心库
-
引入
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
| 标签 | 描述 |
|---|---|
| <c:out> | 用于在JSP中显示数据,就像<%= ... > |
| <c:set> | 用于保存数据 |
| <c:remove> | 用于删除数据 |
| <c:catch> | 用来处理产生错误的异常状况,并且将错误信息储存起来 |
| <c:if> | 与我们在一般程序中用的if一样 |
| <c:choose> | 本身只当做<c:when>和<c:otherwise>的父标签 |
| <c:when> | <c:choose>的子标签,用来判断条件是否成立 |
| <c:otherwise> | <c:choose>的子标签,接在<c:when>标签后,当<c:when>标签判断为false时被执行 |
| <c:import> | 检索一个绝对或相对 URL,然后将其内容暴露给页面 |
| <c:forEach> | 基础迭代标签,接受多种集合类型 |
| <c:forTokens> | 根据指定的分隔符来分隔内容并迭代输出 |
| <c:param> | 用来给包含或重定向的页面传递参数 |
| <c:redirect> | 重定向至一个新的URL. |
| <c:url> | 使用可选的查询参数来创造一个URL |
格式化、SQL、XML、JSTL函数
JavaBean
JavaBean就是一个实体类,JavaBean 具有以下特征:
- 提供一个默认的无参构造函数。
- 需要被序列化并且实现了 Serializable 接口。
- 有一系列可读写属性。
- 有一系列的 getter 或 setter 方法。
一般用来和数据库的字段做映射:ORM(Object Relational Mapping,对象关系映射)
- 表 ——>类
- 字段——>属性
- 记录——>对象
数据库有这么一张表People
| id | name | birthday |
|---|---|---|
| 1 | volcano | 1995/5/5 |
| 2 | LLY | 2000/10/24 |
| 3 | ZX | 2005/8/10 |
需要一个实体类进行映射,字段一一对应属性
package com.volcano.entity;
import java.util.Date;
public class People {
private int id;
private String name;
private Date birthday;
public People() {
}
public People(int id, String name, Date birthday) {
this.id = id;
this.name = name;
this.birthday = birthday;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
}
<%@ page import="java.util.Date" %>
<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%
//等价于这些代码
/*
People people = new People();
people.setId(1);
people.getId();
*/
%>
<jsp:useBean id="people" class="com.volcano.entity.People" scope="page"/>
<jsp:setProperty name="people" property="id" value="1"/>
<jsp:setProperty name="people" property="name" value="volcano"/>
<jsp:setProperty name="people" property="birthday" value="<%=new Date(1995,5,5)%>"/>
id:<jsp:getProperty name="people" property="id"/>
<br>
姓名:<jsp:getProperty name="people" property="name"/>
<br>
生日:<jsp:getProperty name="people" property="birthday"/>
</body>
</html>
MVC三层架构
M:Model
V:View
C:Controller
Filter
过滤器,用来过滤网站的数据和请求。
- 处理中文乱码
- 过滤垃圾请求
使用
-
依旧是那四个包
-
目录结构
-
EncodingFilter
package com.volcano.filter; import javax.servlet.*; import java.io.IOException; //这里实现的Filter必须是javax.servlet下的 public class EncodingFilter implements Filter { //服务器启动时就会被初始化 public void init(FilterConfig filterConfig) throws ServletException { System.out.println("过滤器初始化"); } public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { servletRequest.setCharacterEncoding("utf-8"); servletResponse.setCharacterEncoding("utf-8"); servletResponse.setContentType("text/html;charset=utf-8;"); //必须要有这一段代码,把Request和Response对象传递下去 //传递给下一个过滤器或者给处理的Servlet //不写的话,这个过滤器无效 System.out.println("过滤前"); filterChain.doFilter(servletRequest,servletResponse); System.out.println("过滤后"); } //服务器关闭时销毁 public void destroy() { System.out.println("过滤器被销毁"); } } -
FilteredServlet
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.getWriter().write("你好,过滤器"); } -
web.xml
<servlet> <servlet-name>filtered</servlet-name> <servlet-class>com.volcano.servlet.FilteredServlet</servlet-class> </servlet> <!-- 只过滤指定url的Servlet --> <servlet-mapping> <servlet-name>filtered</servlet-name> <url-pattern>/filtered</url-pattern> </servlet-mapping> <!-- 这里的一个Servlet映射了两个路径,一个用来过滤,一个不过滤 --> <servlet-mapping> <servlet-name>filtered</servlet-name> <url-pattern>/unfiltered</url-pattern> </servlet-mapping> <!-- 过滤器设置,和Servlet大同小异 --> <filter> <filter-name>encodingFilter</filter-name> <filter-class>com.volcano.filter.EncodingFilter</filter-class> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <!-- 不仅可以指定url 也可以直接指定具体Servlet --> <!-- <servlet-name>filtered</servlet-name> --> <url-pattern>/filtered</url-pattern> </filter-mapping> -
结果
监听器
监听一些事件的发生,并且采取一些操作。
由于监听器种类过多,这里只说如何用HttpSessionListener实现在线人数统计。
-
目录结构
-
OnlineCountListener
package com.volcano.listener; import javax.servlet.ServletContext; import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; //实现HttpSessionListener接口,是javax.servlet.http下的 public class OnlineCountListener implements HttpSessionListener { //Session被创建时 public synchronized void sessionCreated(HttpSessionEvent se) { //每当一个Session创建时,在ServletContext中设置属性+1 ServletContext context = se.getSession().getServletContext(); System.out.println(se.getSession().getId()+"创建"); Integer onlineCount = (Integer) context.getAttribute("OnlineCount"); if(onlineCount==null){ context.setAttribute("OnlineCount",1); }else{ int count = onlineCount.intValue(); context.setAttribute("OnlineCount",count+1); } } //Session被销毁时 public synchronized void sessionDestroyed(HttpSessionEvent se) { HttpSession session = se.getSession(); ServletContext context = session.getServletContext(); Integer onlineCount = (Integer) context.getAttribute("OnlineCount"); if(onlineCount==null){ context.setAttribute("OnlineCount",0); }else{ int count = onlineCount.intValue(); context.setAttribute("OnlineCount",count-1); } System.out.println("Session销毁"); } } -
web.xml
<!-- listener的注册就这么简单 --> <listener> <listener-class>com.volcano.listener.OnlineCountListener</listener-class> </listener> -
index.jsp
<h2>当前在线人数:<%=request.getServletContext().getAttribute("OnlineCount")%></h2> -
注意:服务器运行后,因为连接浏览器可能会失败,所以会多连接几次,我们看到的都是成功连接的那一次,但其实已经产生多个了Session,所以数字可能会显示大于1。只要Redeploy重新打包一下就好。
-
结果