javaweb
1、基本概念
web 开发:
- web 网页的意思,www.baidu.com
- 静态web
- html,css,
- 提供给所有人看的数据始终不会发生变化!
- 动态web
- 提供给所有人看的数据会发生变化,每个人在不同的时间、不同的地点、看到的信息各不相同。
- 淘宝,几乎所有的网站
- 技术栈:Servlet/Jsp、Asp、Php
在java 中,动态web资源开发的技术通常为JavaWeb;
1.2、Web应用程序
web应用程序:可以提供浏览器访问的程序;
- a.html、b.html …多个web资源,这些web资源可以被外界访问,对外界提供服务;
- 访问到的任何一个页面或者资源,都存在于这个世界的某一个角落的计算机上
- URL 统一资源定位符
- 这个统一的web资源会被放在同一文件夹下,web应用程序---->Tomcat 服务器
- 一个web应用由多部分组成(静态web,动态web)
- html,css,js
- Jsp,Servlet
- Java程序
- jar包 别人写好封装 的类 可以使用里面的方法
- 配置文件(Properties)
web应用程序编写完毕后,若想提供给外界访问:需要一个服务器来统一管理;
1.3、静态Web
*.htm, *.html 这些都是网页的后缀,服务器上一直静态存在的
静态web存在的缺点
- Web 页面 无法动态更新,所有用户看到的是同一页面
- 轮播图,点击特性:伪动态
- JavaScript
- VBScript
- 它无法和数据库交互(数据无法持久化,用户无法交互)
1.4、动态web
页面会动态展示:“Web 的页面展示效果因人而异”,千人千面;
缺点:
- 假如服务器的动态web资源出现了错误,我们需要重新编写我们的后台程序
- 停机维护
优点:
- Web 页面 可以动态更新,所有用户看到的都不是同一页面
- 它可以和数据库交互(数据持久化:注册、商品信息)
2、web服务器
服务器封装了HTTP协议(可以和浏览器交互的规范)
可以将web项目部署到服务器中,对外提供网上浏览的功能
2.1技术
1.asp.net
- 在html中嵌入了vb脚本,可以让web页面动态展示 千人千面
- 静态页面和逻辑代码混合到一起,页面混乱,维护成本高
<html>
<body>
<h1>
<%
system.out.print("hello world")
%>
</h1>
</body>
</html>
2.php
- 开发速度快,功能强大,跨平台,代码简单,适合中型项目
- 无法承接访问量大的情况
3.jsp/servlet
B/S C/S
- 是sun公司主推的B/S架构
- 基于Java语言
- 可以承载三高问题
- 语法像asp(早期的市场大部分都是以asp为主,市场占有率高,模仿asp可以便于开发者的使用)
2.2 web服务器
服务器是一种被动的操作,用来处理一些用户的请求和给用户一些响应信息
iis tomcat
3、Tomcat
Tomcat是轻量级的web服务器
Tomcat时Apache软件基金会的核心项目,是一款开源免费轻量级的Web服务器
Tomcat也被称为Web容器,Servlet容器,Servlet需要依赖Tomcat
3.1 tomcat安装
3.2 tomcat目录
3.3.访问测试
http://localhost:8080/
3.配置
配置端口号
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
配置主机的名称
webapps:要发布的网站
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
一个网站是如何访问的
-
输入一个域名,点击回车
-
检查本地的C:\Windows\System32\drivers\etc\hosts 里面有没有这个域名映射,默认的是localhost
-
有 返回ip地址
-
没有 去dns里面找看是否能找到

3.4. 发布一个静态的网站
-
将自己写的静态的网站,放到服务器(tomcat)指定的webapps目录下,就可以访问了
-
网站的固定结构:
-
webapps:
- ROOT
-
-
Honor:
- WEB—INF
- -classes: java程序
- lib: web应用依赖的jar包
- web.xml:网站的配置文件
- index.html
- index.css
- index.js
- WEB—INF
-
url: 王者荣耀官方网站-腾讯游戏
4、HTTP
1 什么是Http
超文本传输协议(Hyper Text Transfer Protocol,HTTP)是一个简单的;请求-响应协议,它通常运行在TCP之上。
- 文本:html,字符串,~
- 超文本:图片,音乐,视频,定位,地图…
- 端口号:80
https:安全的
- 443
2、两个时代
http 1.0
- http/1.0:客户端可以与web服务器连接后,只能获得一个web资源,断开连接

http 2.0
- http/1.1:客户端可以与web服务器连接后,可以获得多个web资源。

3、Http请求
客户端-----发请求(Request)------->服务器
example 访问百度百度:
Request URL: https://www.baidu.com/ --请求地址
Request Method: GET --请求方式
Status Code: 200 OK --状态码
Remote Address: 14.215.177.38:443 --远程地址
3.1.请求行

- 请求行中的请求方式:GET
- 请求方式:GET、POST、HEAD、DELETE、PUT
- get :一次请求能够携带的参数比较少,大小限制,会在浏览器的url 地址栏显示内容,不安全,但高效。
- post:一次请求能够携带的参数没有限制,大小没有限制,不会在浏览器的url 地址栏显示内容,安全,但不高效。
3.2.请求头
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.7 --告诉浏览器它所支持的数据类型
Accept-Encoding: gzip, deflate, br, zstd --告诉浏览器支持哪种编码格式 GBK、UTF-8 、GB2312
Accept-Language: zh-CN,zh;q=0.9 --告诉浏览器,它的语言环境
Cache-Control: max-age=0 --缓存控制
Connection: keep-alive --告诉浏览器,请求完成是断开还是保持连接
Cookie:...
Host: www.baidu.com
Sec-Ch-Ua:"Google Chrome";v="119", "Chromium";v="119", "Not?A_Brand";v="24" ... --主机
User-Agent:
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36
4、Http响应
服务器-----响应(response)----->客户端
Cache-Control: private --缓存控制
Connection: keep-alive --连接
Content-Encoding: gzip --编码
Content-Type: text/html;charset=utf-8 --类型
4.1.响应体
Accept: --告诉浏览器它所支持的数据类型
Accept-Encoding: --告诉浏览器支持哪种编码格式 GBK、UTF-8 、GB2312
Accept-Language: --告诉浏览器,它的语言环境
Cache-Control: --缓存控制
Connection: --告诉浏览器,请求完成是断开还是保持连接
HOST: --主机
Refresh: --告诉客户端,多久刷新一次
Location: --让网页重新定位
4.2.响应状态码
- 200 请求响应成功
- 4xx 找不到资源 404
- 资源不存在
- 3** 请求重定向
- 重定向:你重新到我给你的新位置去
- 5xx 服务器代码错误 500
- 502 网关错误
5、Maven
5.1、简介
Apache Maven是一个项目管理和构建工具,它基于项目对象模型(pom project object model)的概念。
是一个工具 。
目的:是用来自动导入jar包。
思想:约定大于配置: 有约束不要去违反,maven会规定我们如何去编写我们的jav代码。
-
有一套标准的项目结构,可以让所有的ide使用maven后构建的项目结构完全一样。
-
提供了一套 标准化、简单的 的构建流程(编译、测试、打包、发布...)
-
提供了一套依赖管理机制(管理jar包,插件,第三方资源) 自动下载jar包,复制jar包,加入生产环境
插件:管理项目的声明周期
依赖:自动下载jar包,复制jar包,加入生产环境需要的jar.
仓库:
- 本地仓库:自己计算机中的一个目录
- 中央仓库:由maven搭建维护的全球唯一的开源仓库
- 远程仓库(私服):由公司搭建的私有仓库。
5.2、下载和安装
官网下载安装
5.2.1、环境变量配置
在系统的环境变量中配置
- M2_HOME: maven安装目录下的bin目录
- MAVEN_HOME:maven安装目录
- path:%MAVEN_HOME%\bin
测试:
mvn -version # ->测试是否安装配置成功
output:
Apache Maven 3.9.6 (bc0240f3c744dd6b6ec2920b3cd08dcc295161ae)
Maven home: E:\Environment\apache-maven-3.9.6
Java version: 1.8.0_351, vendor: Oracle Corporation, runtime: E:\Environment\jdk8\jre
Default locale: zh_CN, platform encoding: GBK
OS name: "windows 10", version: "10.0", arch: "x86", family: "windows"
5.3、配置阿里云镜像
<mirrors>
<mirror>
<id>alimaven</id>
<mirrorOf>central</mirrorOf>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
</mirrors>
5.4、本地仓库
- 创建仓库
- 配置仓库 setting.xml
<localRepository>D:\environment\apache-maven-3.8.3\meven-repo</localRepository>
5.5、idea配置maven
- 坐标:
- maven中坐标是资源的唯一标识
- 使用坐标来定义或引用项目
- 组成
- groupid : 定义当前maven项目隶属组织名称(通常是域名反写)
- artifactid:定义moven项目的名称(通常是模块名称)
- version:定义当前项目的版本号
- 项目导入
- maven -> "+"项目路径
5.6、依赖管理
根据坐标 自动下载,导入需要的依赖
- 依赖作用范围
- 编译环境:jar包在编译环境有效,java目录下都可以使用
- 测试环境:jar包在测试目录下有效
- 运行环境:放到服务器上
依赖范围 | 编译 | 测试 | 运行 |
---|---|---|---|
compile | Y | Y | Y |
test | - | Y | - |
provided | Y | Y | - |
runtime | - | Y | Y |
System | Y | Y | |
import | 不讲 |
5.7、idea中创建maven项目
- 启动idea
- 创建一个maven项目
idea中的maven设置
经常在idea中出现一个问题,就是项目自动创建完成后, 这个maven home 会使用idea默认的,我们如果发现了这个问题,手动改为本地。
7.创建一个普通的maven项目 不勾选默认的模板
这个只有web的项目才有
8.标记文件夹功能
9.在idea中配置tomcat
解决警告问题
为什么会有这个问题,我们访问一个网站,需要指定一个文件夹的名字
这个过程叫虚拟路径映射
10.pom文件
pom.xml 是maven的 核心配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!--maven 的版本和头文件-->
<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>cn.bloghut</groupId>
<!--项目名-->
<artifactId>demo1</artifactId>
<!--版本-->
<version>1.0-SNAPSHOT</version>
<!--项目的打包方式
jar:java应用
war:javaweb应用
-->
<packaging>war</packaging>
<name>demo1 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.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<!--项目依赖-->
<dependencies>
<!--具体依赖的jar包配置文件-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
<!--项目构建用的东西-->
<build>
<finalName>demo1</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>
解决问题
6、Servlet
6.1 Servlet简介
Servlet 就是sun公司开发动态web的一门技术
把实现了Servlet接口的Java 程序叫做:Servlet
sun 在这些API 中提供了一个接口:Servlet,如果你想开发一个Servlet 程序,只需要完成两个步骤
- 编写一个类,实现Servlet 接口,自定义业务逻辑
- 把开发号好的Java类部署到服务器中,映射
6.2 HelloServlet
provided作用域 只在编译和测试中有效,打war包后不需要,Tomcat中有自带servlet和jsp的jar包,会冲突。
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.0</version
<scope>provided</scope>
</dependency>
1. 自定义一个类
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
PrintWriter writer = resp.getWriter();
writer.print("Hello Servlet");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
2 编写Servlet的映射
为什么需要映射:我们写的Java程序,但是要通过浏览访问,而浏览器需要连接web服务器,所以我们需要在web服务中注册我们写的Servlet,还需要给他一个浏览器能够访问的路径。
<!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 xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<!-- 声明 -->
<servlet>
<!-- 起名 -->
<servlet-name>hello</servlet-name>
<!-- 完整类名 -->
<servlet-class>cn.bloghut.servlet.HelloServlet</servlet-class>
</servlet>
<!-- 赋值 -->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
6.3 Servlet原理
6.3.1 Servlet 继承关系
6.3.2 Servlet 方法的功能
6.3.3 Servlet生命周期
init初始化 --> servlet--> distroy销毁

6.4 mapping 映射
一个请求(Servlet)可以指定多个映射路径
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>cn.bloghut.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello1</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello2</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello3</url-pattern>
</servlet-mapping>
一个请求(Servlet)可以指定通用映射路径
<!--默认请求路径 可以覆盖掉所有的网站 包括index.jsp-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
指定一些后缀或者前缀等
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
自定义404界面
优先级问题
指定了固有的映射路径优先级最高,如果找不到就会走默认的处理请求;
6.5 HttpServlet
HttpServlet 继承了GenericServlet,GenericServlet实现了Servlet
在HttpServlet ,自动重写了Service方法 ,在Service中,自动判断客户端发送的请求是get/post/... ,因此在编写业务逻辑的时候,只需要继承HttpServlet。 客户端发送什么请求,服务器端就在对应的请求中编写业务代码。
example code path: E:\stu\java\Javaweb\javaweb-02-severlet01\javaweb-02-severlet
form表单
前端页面
<form action="/Servlet02_Form_war/Login" method="post" id="form">
<h1 id="loginMsg">LOGIN IN</h1>
<p>Username:<input id="username" name="username" type="text"></p>
<p>Password:<input id="password" name="password" type="password"></p>
<input type="submit" class="button" value="login up">
</form>
后端servlet
@WebServlet("/Login")
public class Login extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().print("Success");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
6.6 ServletConfig Servlet级别
作用
ServletConfig 这个对象里面封装的内容是web.xml的信息
通过web.xml这个类,可以获取到web.xml中当前Servlet的配置信息
Exmaple Code Path:javaweb-02-severlet\Servlet02-Form\src\main\java\com\bai\ServletConfigTest.java
案例
web.xml
<servlet>
<servlet-name>ServletConfigTest</servlet-name>
<servlet-class>com.bai.ServletConfigTest</servlet-class>
<init-param>
<param-name>Test</param-name>
<param-value>TestInfo</param-value>
</init-param>
<init-param>
<param-name>Version</param-name>
<param-value>1,0</param-value>
</init-param>
</servlet>
Servlet
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletConfig servletConfig = this.getServletConfig();
// 获取当前Servlet的InitParameter,按照名字取
resp.getWriter().print(servletConfig.getInitParameter("Test") + "\n");
// 获取当前Servlet所有的InitParameter
resp.getWriter().print(servletConfig.getInitParameterNames() + "\n");
// 获取当前Servlet的名字
resp.getWriter().print(servletConfig.getServletName());
}
ServletConfig
public interface ServletConfig {
String getServletName();
ServletContext getServletContext();
String getInitParameter(String var1);
Enumeration<String> getInitParameterNames();
}
6.5 ServletContext 整个网站
web容器在启动的时候,它会为每个web程序都创建一个ServletContext对象,它代表了当前的web应用。
所有的servlet都可以获取到ServletContext
1 共享数据
多个Servlet数据的共享
一个web项目的所有共享同一个ServletContext对象
//放数据的Servlet
public class setData extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
ServletContext servletContext = this.getServletContext();
String username = "闲言";//数据
servletContext.setAttribute("username",username);
//将一个数据保存在ServletContext中 key:username value:闲言
}
}
//读取数据的Servlet
public class GetData extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
ServletContext context = this.getServletContext();
String username = (String) context.getAttribute("username");
resp.setCharacterEncoding("utf-8");
resp.setContentType("text/html");
PrintWriter writer = resp.getWriter();
writer.write(username);
}
}
2 获取web.xml配置的初始化参数
web.xml配置参数
<context-param>
<param-name>url</param-name>
<param-value>jdbc:mysql://localhost:3306/school</param-value>
</context-param>
获取参数
public class ServletDemo03 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
//获取上下文对象
ServletContext context = this.getServletContext();
//获取初始参数
String url = context.getInitParameter("url");
System.out.println("url: "+url);
}
}
3 转发
路径不变化
ServletContext context = getServletContext();
context.getRequestDispatcher("路径").forward(req,resp);
4 获取web项目下的资源文件
使用ServletContext 可以获取到web项目的资源文件 例如 db.Properties文件
使用 Properties 可以保存我们的数据库配置信息等等,把数据库的配置信息放在这里,可以方便程序后续的管理
注意路径问题!!!
测试发现,如果我们使用项目的路径来加载流文件,会发现程序无法找到,原因是项目被发布到服务器以后,会被打成一个war包,那么项目的路径和实际开发的路径完全不一样,所以我们需要在tomcat服务器下找到webapps,获取到web项目在服务器下的真实路径。在webapps中,我们发现,java代码和文件都被放到了classes路径下,俗称classpath,也就是说,在访问项目下的文件时,我们需要找到项目的classes路径,才能够正常访问。
exmaple:
path:
javaweb-02-severlet\Servlet02-Form\src\main\java\com\bai\ServletContextRead.java
Properties
username=root
password=123456
Servlet
@WebServlet("/ServletContextRead")
public class ServletContextRead extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext servletContext = req.getServletContext();
InputStream inputStream = servletContext.getResourceAsStream("//WEB-INF//classes//db.properties");
Properties properties = new Properties();
properties.load(inputStream);
String username = properties.getProperty("username");
String password = properties.getProperty("password");
resp.getWriter().print(username + ": " + password );
}
}
maven资源导出失败问题
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</build>
6.6 HttpServletResponse
Servlet最主要的作用就是处理客户端的请求并向客户端做出响应。为此针对Servlet的每次请求,web服务器会在调用Service()方法之前,都会创建两个对象,分别为HttpServletResponse 和 HttpServletRequset对象。Request 用来封装Http的请求信息,Response用来封装Http响应消息。
![]()
设置状态码
200响应成功 302重定向 404请求的资源找不到 500服务器代码异常
void setStatus(int var1);// 设置状态码
void sendError(int var1, String var2) throws IOException;
void sendError(int var1) throws IOException; // 发送错误码
设置响应头
//设置响应头
public void addHeader(String name, String value);
public void setHeader(String name, String value);
resp.setHeader(a, '111');
resp.setHeader(a, '222');
//重定向
resp.setStatus(302); // 设置状态码
resp.setHeader("Location", '/Test/index.html'); //设置条状的页面 地址会改变 /项目名/页面
读写文件(响应体)
ServletOutputStream getOutputStream() throws IOException; //字节流
PrintWriter getWriter() throws IOException; //字符流
设置编码
编码和解码的字符集用的不一样会导致乱码
resp.getOutputStream().print(username);
resp.getOutputStream().write("我爱你".getBytes("utf-8"));
resp.setHeader("Content-Type","text/html;charset=gb2312");
解决方法:
// 1. 推荐
response.setContentType("text/html;charset=utf-8");
// 2.
response.serHeader("Content-Type","text/html;charset=utf-8");
// 3.
response.setCharacterEncoding("utf-8");
重定向
会重新向服务器发送请求
/**
resp.setHeader("Location","/r2/img"); // /项目名/文件名
resp.setStatus(302);
*/
resp.sendRedirect("/r2/img");//重定向
6.7、Request
代表客户端的请求 用户通过http协议访问服务器,http协议会被封装到Request中,可以通过这个对象获取请求的一些参数。
1.获取表单提交的参数
2.获取请求的各种参数
resp.getWriter().print("获取请求提交的方式"+req.getMethod()+"</br>");
resp.getWriter().print("获取请求提交的协议"+req.getProtocol()+"</br>");
resp.getWriter().print("当前项目"+req.getContextPath()+"</br>");
resp.getWriter().print("当前Servlet路径"+req.getServletPath()+"</br>");
resp.getWriter().print("相对地址"+req.getRequestURI()+"</br>");
resp.getWriter().print("绝对地址"+req.getRequestURL()+"</br>");
3.获取请求头的信息
4.获取表单中用户的输入

5.表单提交数据乱码解决
表单服务器向服务器提交数据的时候,默认编码时 ISO-8859-1 编码
解决方案:
先把字符串按照合适的方式解码,在转换成uft-8
get方式提交表单
byte[] username = req.getParameter("username").getBytes("ISO8859-1");
String strUserName = new String(username, "utf-8");
byte[] password = req.getParameter("password").getBytes("ISO8859-1");
String strPassword = new String(password, "utf-8");
byte[] hobby = req.getParameter("hobby").getBytes("ISO8859-1");
String strHobby = new String(hobby, "utf-8");
resp.getWriter().print("</br>");
resp.getWriter().print(strUserName);
resp.getWriter().print(strPassword);
resp.getWriter().print(strHobby);
post提交表单:
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
resp.getWriter().print(req.getParameter("username"));
}
6.信息的传递
使用Request在多个Servlet中进行信息的传递
只有处于同一个请求中的数据才能通过ServletRequest传递信息
Object getAttribute(String var1);
Enumeration<String> getAttributeNames();
void setAttribute(String var1, Object var2);
void removeAttribute(String var1);
7.请求转发
请求转发是在服务器内部的,浏览器的地址栏不变。
始终时一个请求,所以多个Servlet直接可以进行数据传递
forword方式
request.getRequestDispatcher("/success.jsp").forward(request,response); //转发页面
request.getRequestDispatcher("/servletTest").forward(request,response); //转发Servlet
include方式

使用include方式转发,会把处理的结果返回给Servelet1,通过Servlet1返回给客户端,类似于方法的调用
request.getRequestDispatcher("/servletTest").include(request,response); //转发Servlet
7.会话及其会话技术
每一个用户服务器都会给用户一个Cookie和Sesson。
web应用中的会话过程类似于生活中的打电话,它指的是客户端和服务器之间连续发生的一系列请求和响应过程,例如用户在购物网站完成一次购物就是一个会话。
在会话的期间,通话的双方会产生通话内容,同样,在浏览器和服务器交互的过程中,也会产生一些数据。会话技术就是用来保存这些数据的
浏览器关闭了,会话就中断。

网站如何标记你是否访问过?
- 给一个信物 一个cookie,下次访问带上cookie。
- 在服务端登记,下次你再来,我去匹配你。
有状态会话与无状态会话最大区别就是,它可以在交互的同时,保持住状态。
7.1客户端会话跟踪技术cookie
cookie的基本使用:
- 发送cookie
Cookie cookie = new Cookit("键","值");
response.addCookie(cookie);
- 获取cookie
//获取cookie 数组
Cookie[] cookies = request.getCookies();
//遍历数组,获取想要的值
for(Cookie item:cookie);
example:
记住上次访问时间
Cookie的原理
第一次访问,服务器给客户端发送一个cookie
发了之后,每次请求都会带上cookie
- Cookie原理的实现是基于HTTP协议的
- 响应头:保存Cookie到浏览器
- 请求头:携带Cookie数据到服务器
Cookie的销毁
- 默认存储在浏览器的内存中,浏览器关闭,内存释放。Cookie被销毁
- Cookie持久化 setMaxAge(int seconds)
- 正数:将Cookie写入浏览器所在电脑的硬盘,持久化存储。到了秒数后自动删除
- 负数:默认值,浏览器关闭,Cookie删除
- 零:销毁Cookie
Cookie存储中文
- Cookie不能直接存储中文
- 可以编码存储URLEncoding.encode("张三",“utf-8”);
- 使用时解码 URLDecoder.decode("张三",“utf-8”);
7.2 服务端会话跟踪技术session
把会话产生的数据都保存在服务器中
但是,在http协议中,服务器无法判断会话是否中止(也就是浏览器是否关闭),所以及时客户端已经关闭了服务器,但服务器还保留了session的信息。这些session信息随着时间越存越多,直到内存资源耗尽。
![]()
所以设设置好一个时间。在web.xml中设置session的超时时间
<session-config> <session-timeout>30</session-timeout> 单位分钟 </session-config>
session的基本使用:
// falses session不存在 创建新session ture session已经存在返回null
HttpSession getSession(boolean var1);
HttpSession getSession();
long getCreationTime();
String getId();
long getLastAccessedTime();
ServletContext getServletContext();
void setMaxInactiveInterval(int var1);
int getMaxInactiveInterval();
/** @deprecated */
HttpSessionContext getSessionContext();
Object getAttribute(String var1);
/** @deprecated */
Object getValue(String var1);
Enumeration<String> getAttributeNames();
/** @deprecated */
String[] getValueNames();
void setAttribute(String var1, Object var2);
/** @deprecated */
void putValue(String var1, Object var2);
void removeAttribute(String var1);
/** @deprecated */
void removeValue(String var1);
void invalidate();
boolean isNew();
Sessoion 原理
服务端设置Session的时候,会向浏览器发出请求 设置一个sessionID到浏览器的Cookie中。
当再次获取Session对象的时候,Tomcat会去浏览器中找是否有sessionID。这样就实现了一次会话多次请求之间的资源共享。
Session 钝化 活化
-
服务器正常的关闭 ,Session数据还在
- 钝化:服务器正常关闭 服务器会把Session放到硬盘的文件中。
- 活化:服务器把Session加载回去,并且删除这个文件。
req.setCharacterEncoding("UTF-8"); resp.setCharacterEncoding("UTF-8"); resp.setContentType("text/html;charset=utf-8");
8.JSP
java servle pages Java服务端页面
JSP = Java代码+html标签 动态脚本
8.1原理
jsp的工作模式是请求/响应模式,客户端发起http请求,jsp受到请求后返回处理结果。
jsp第一次受到请求后,jsp容器把jsp页面转换成一个servlet


结论:JSP 文件被tomcat 编译成一个.class文件 实际jsp就是servlet 我们访问.jsp界面时,tomcat会把.Jsp文件转换成.Java文件。这个Java文件其实就是一个servlet界面。
8.2 JSP基础语法和指令
<!-- servlet 依赖-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
<!-- jsp-->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
</dependency>
<!-- 用标签来写语句 -->
<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>
</dependencies>
1.jsp Scriptlet
Java脚本的格式 <% java代码 (变量、方法、表达式) 相当于main%>
example
<body>
<h2>Hello World!</h2>
<%
int b = 10;
for (int i = 0 ; i < b ; i++){
System.out.println(i);
}
%>
</body>
2.jsp 声明语句
定义属性和方法<% %> 相当于类里面,这里可以定义属性和方法,但是不能调用out.print()方法输出
example
<%!
String name = "张三";
String age = "17";
public void introduce(){
System.out.println(name + age);
}
%>
<%
introduce();
%>
3.jsp表达式
<%=%>
<%!
String name = "张三";
String age = "17";
public void introduce(){
System.out.println(name + age);
}
%>
<p>
<%= name + age %>
</p>
8.3公共界面
1.拼接的形式引入页头和页脚
相当于把这两个jsp页面复制了一份到当前页面,所以不可以重复定义变量
<%@include file="CommonPage/Header.jsp"%>
<h1>我是内容</h1>
<%@include file="CommonPage/Footer.jsp"%>
内部实现为:
out.write("<header style=\"width: 200px;background-color: cornflowerblue\">我是头部</header>\r\n");
out.write(" <h1>我是内容</h1>\r\n");
out.write("<footer style=\"width: 200px;background-color: #8398bd\">我是尾部</footer>\r\n");
2.引用的形式引入页头和页脚
在底层实现中,标注了页头的存放位置。在访问时找到位置进行渲染
本质还是几个不同的页面,所以可以重复定义变量
<jsp:include page="/CommonPage/Header.jsp"></jsp:include>
<h1>我是内容</h1>
<jsp:include page="/CommonPage/Footer.jsp"></jsp:include>
底层实现:
org.apache.jasper.runtime.JspRuntimeLibrary.include(request, response, "/CommonPage/Header.jsp", out, false);
out.write("\r\n");--%>
out.write(" <h1>我是内容</h1>\r\n");--%>
out.write(" ");--%>
org.apache.jasper.runtime.JspRuntimeLibrary.include(request, response, "/CommonPage/Footer.jsp", out, false);
8.4 jsp 九大内置对象
在jsp页面转换成servlet时自动创建的九个内置对象
所以在jsp页面中可以直接使用这九个对象,上文中的out.print的out就是内置对象之一哦
final javax.servlet.jsp.JspWriter out = null; //页面输出
final javax.servlet.http.HttpServletRequest request; //请求信息
final javax.servlet.http.HttpServletResponse response; // 响应信息
javax.servlet.http.HttpSession session = null; //客户端保存某个用户的信息
final javax.servlet.ServletContext application; //存储公共数据
final java.lang.Object page = this; //当前页面对象
final javax.servlet.jsp.PageContext pageContext; // 上下文 大家长 当前jsp的所有信息他都知道
final javax.servlet.ServletConfig config; // 配置信息
1. out
javax.servlet.jsp.JspWriter out = resp.getWirter();
//显示的效果是一致的
// 但out对象输出到页面时,会先放到自己的缓冲区,然后在转交给resp对象进行输出
// 所以out输出时会慢一点
<%
out.print("out对象的输出</br>");
response.getWriter().print("resp对象的输出</br>");
%>
输出结果
2.pageContext
- 上下文 大家长 当前jsp的所有信息他都知道
- 通过pageContext可以获取jsp的八大隐式内置对象
- 存储数据 pageContext.setAttribute(key,value,scope); 控制其他对象的取值
<%
// 页面范围
pageContext.setAttribute("username","小白1", PageContext.PAGE_SCOPE);
// 请求范围
pageContext.setAttribute("username","小白2", PageContext.REQUEST_SCOPE);
// 会话范围
pageContext.setAttribute("username","小白3", PageContext.SESSION_SCOPE);
// web应用程序范围
pageContext.setAttribute("username","小白4", PageContext.APPLICATION_SCOPE);
%>
注意:当使用pageContext.findAttribute("username");寻找值的使用,servlet会按照 page,request,session,application这个优先级依次去找,找到一次就返回,找不到就返回null
request.setAttribute(");
保存的数据只在一次请求中有效 ,请求转发会携带这个数据
session.setAttribute();
保存的数据只在一次会话中有效 ,从打开浏览器到关闭服务器
application.setAttribute();
保存的数据只在服务器中有效 ,从打开服务器到关闭服务器
request:客户端向服务器发送请求,产生的数据,用户看完就没用了,比如:新闻,用户看完没用的!
session:客户端想服务器发送请求,产生的数据,用户用完,用户看完一会还有用,比如:购物车
application:客户端想服务器发送请求,产生的数据,一个用户用完,其他用户还能使用。、,比如聊天数据。
3.exception(内置对象)
为状态码指定错误页面
<error-page>
<error-code>404</error-code>
<location>/error/404.jsp</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/error/ComError.jsp</location>
</error-page>
为当前页面指定错误页面
<%@ page errorPage="error/ComError.jsp" %>:表示当前页面可能存在异常,当异常发生的时候条状到errorPage所指定的页面
exmaple
jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" errorPage="err1.jsp" %>
<html>
<body>
<h2>Hello World!</h2>
<% int c;%>
<%=
c = 9 / 0
%>
</body>
</html>
显示错误信息的jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" isErrorPage="true" %>
<html>
<body>
<h1>当前操作有误错误信息如下:</h1>
<p><%= exception.getMessage() %></p>
</body>
</html>
8.5 jsp动作元素
1.引入公共页面
<jsp:include page="common1.jsp" fluse = true/>
<p>我是内容</p>
<jsp:include page="common2.jsp"/>
注意:fluse = true代表,当前页面要等待common1执行完成后才显示
fluse = true代表,当前页面不需要等待common1执行完成后才显示
2.跳转页面
<jsp:forward page=""></jsp:forward>
环境准备
不使用 模板 创建web项目
- pom ->
war 打包为war - 双击 resource ->facets->web resource dir双击添加webapps -> deployment descriptors "+"创建inf文件
- 添加依赖
- 创建文件夹
9.EL表达式 JSTL标签
9.1 java bean
JavaBean是一个遵循特定写法的Java类,它通常具有如下特点:
- 这个Java类必须具有一个无参的构造函数
- 属性必须私有化。
- 私有化的属性必须通过public类型的方法暴露给其它程序,并且方法的命名也必须遵守一定的命名规范。
依赖
<!-- https://mvnrepository.com/artifact/commons-beanutils/commons-beanutils -->
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.4</version>
</dependency>
基本语法
Person person = new Person();
try {
BeanUtils.setProperty(person,"name","小白");
BeanUtils.setProperty(person,"age",10);
BeanUtils.setProperty(person,"sex","男");
BeanUtils.getProperty(person,"name");
BeanUtils.getProperty(person,"age");
BeanUtils.getProperty(person,"sex");
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
e.printStackTrace();
}
一键填充
Person person = new Person();
try {
HashMap<String, String> personInfo = new HashMap<>();
personInfo.put("name","小白");
personInfo.put("age","10");
personInfo.put("sex","男");
BeanUtils.populate(person,personInfo);
System.out.println(BeanUtils.getProperty(person, "age"));
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
e.printStackTrace();
}
进阶用法,一键填充数据到对象中
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Person person = new Person();
try {
BeanUtils.populate(person, req.getParameterMap());
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
}
9.2 EL 表达式
EL(expression language)
是为了让JSP写起来更加方便,他提供了在jsp中简化表达式的方法,让jsp的代码更加简化
方便获取与对象的取值
1.取值
1.拿出隐式内置对象的取值
若存在多个相同名称的值,则按照优先级从小到大的找
依次是:Page -> Request->Session->Application
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>EL表达式</title>
</head>
<body>
<%
pageContext.setAttribute("username","zhangsan");
request.setAttribute("username","lisi");
session.setAttribute("username","wangwu");
application.setAttribute("username","zhaoliu");
%>
<pre>
获取作用域中username: ${username}<br><%-- 默认从小到大的范围中找,找到的第一个返回 --%>
不在作用域中的: ${password}
<%--获取request作用域中的username: ${requestScope.username}
获取session作用域中的username: ${sessionScope.username}
获取application作用域中的username: ${applicationScope.username}--%>
</pre>
</body>
</html>
2.取出集合的值
<%@ page import="java.util.List" %>
<%@ page import="java.util.ArrayList" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>EL表达式</title>
</head>
<body>
<%
List<String> list=new ArrayList<String>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
request.setAttribute("list",list);
%>
<pre>
获取list中指定下标的数据:${list[1]}--${list[2]}
获取集合的长度:${list.size()}
list代表的是存在域对象中的变量名(限域变量名)
</pre>
</body>
</html>
3.javabean
可以使用 . 或者 [] 取值
<%@ page import="com.User.User" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>EL表达式</title>
</head>
<body>
<%
User user=new User();
user.setUsername("zhangsan");
user.setSex(true);
user.setUserId(1);
request.setAttribute("user",user);//设置域对象属性
%>
<pre>
获取JavaBean中的username ${user.username}
获取JavaBean中的userId ${user["userId"]}
获取JavaBean中的sex ${user.sex}
</pre>
</body>
</html>
4.EL的隐式对象(重点)
隐含对象 | 描述 |
---|---|
pageScope | page作用域 |
requestScope | request作用域 |
sessionScope | session作用域 |
applicationScope | application作用域 |
param | Request对象的参数,字符串 |
paramValues | Request对象的参数,字符串集合 |
header | HTTP信息头,字符串 |
headerValues | HTTP信息头,字符串集合 |
initParam | 上下文初始化参数 |
cookie | Cookie值 |
pageContext | 当前页面的pageContext |
5.EL 取文本框的值
与输入相关的隐含对象有两个:param和paramValues,它们是EL中比较特殊的隐含对象。
- 例如我们要取得用户的请求参数时,可以利用下列方法:
- request.getParamster(String name)
- request.getParamsterValues(String name)
- 在EL中则可以使用param和paramValues两者来取得数据。
- $
- $
2.EL表达式的运算符
1.EL表达式运算符有哪些
类别 | 运算符 |
---|---|
算术运算符 | +、-、*、/ 或 div、%或 mod |
关系运算符 | = = 或 eq、!= 或 ne 、< 或 It、>或 gt、<=或le、>= 或 ge |
逻辑运算符 | &&或and、 |
其他运算符 | Empty运算符、条件运算符、()运算符 |
2.EL最常用的表达式
- 为空判断:
${empty param.name}
- 三元运算:
${A?B:C}
- 算法运算:
${A*(B+C)}
3.算数运算
4.关系运算
5.逻辑运算和其他运算
3.EL表达式的自动类型转换
1.自动类型转换
- 在JSP代码块写法中要取得文本框的输入,我们需要做类型转换
- EL会自动类型转换,我们只需要这样写
9.3 JTSL
JavaServer Pages Standard Tag Libary
本章节对于jstl中的Core的标签库进行说明
1.环境准备
1.pom.xml引入依赖坐标
<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>
2.jsp 引入jstl 标签
<%--引入jstl核心标签库 core--%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
2. c 标签的使用
<c:out>
标签 | 描述 |
---|---|
out | 用于在JSP中显示数据,就像<%= ... > |
set | 用于保存数据 |
remove | 用于删除数据 |
catch | 用来处理产生错误的异常状况,并且将错误信息储存起来 |
if | 与我们在一般程序中用的if一样 |
choose | 本身只当做<c:when>和<c:otherwise>的父标签 |
when | <c:choose>的子标签,用来判断条件是否成立 |
otherwise | <c:choose>的子标签,接在<c:when>标签后,当<c:when>标签判断为false时被执行 |
import | 检索一个绝对或相对 URL,然后将其内容暴露给页面 |
forEach | 基础迭代标签,接受多种集合类型 |
forTockens | 根据指定的分隔符来分隔内容并迭代输出 |
param | 用来给包含或重定向的页面传递参数 |
redirect | 重定向至一个新的URL. |
url | 使用可选的查询参数来创造一个URL |
1. out
属性 | 描述 | 是否必要 | 默认值 |
---|---|---|---|
value | 要输出的内容 | 是 | 无 |
default | 输出的默认值 | 否 | 主体中的内容 |
escapeXml | 是否忽略XML特殊字符 | 否 | true |
<c:out value="<要显示的数据对象(未使用转义字符)/>" escapeXml="true" default="默认值"></c:out>
<c:out value="<要显示的数据对象(使用转义字符)/>" escapeXml="false">默认值</c:out>
2.if
属性 | 描述 | 是否必要 | 默认值 |
---|---|---|---|
test | 条件 | 是 | 无 |
var | 用于存储条件结果的变量 | 否 | 无 |
scope | var属性的作用域 | 否 | page |
<c:set var="salary" scope="session" value="${2000*2}"/>
<c:if test="${salary > 2000}">
<p>我的工资为: <c:out value="${salary}"/><p>
</c:if>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<form action="coreif.jsp" method="get">
<%--el表达式获取表单中的数据: ${param.参数名}--%>
<input type="text" name="username" value="${param.username}">
<input type="submit" value="登录">
</form>
<%--判断提交的用户名是管理员,则登录成功--%>
<c:if test="${param.username=='admin'}" var="isAdmin">
<c:out value="管理员欢迎您!"/>
</c:if>
<c:out value="${isAdmin}"/>
</body>
</html>
3.choose
无属性 搭配when 和 otherelse使用 类似于if-else 语法:
<c:set var="salary" scope="session" value="${2000*2}"/>
<p>你的工资为 : <c:out value="${salary}"/></p>
<c:choose>
<c:when test="${salary <= 0}">
欠钱了
</c:when>
<c:when test="${salary > 1000}">
不错的薪水,还能生活。
</c:when>
<c:otherwise>
什么都没有。
</c:otherwise>
</c:choose>
4.foreach
属性 | 描述 | 是否必要 | 默认值 |
---|---|---|---|
items | 要被循环的信息 | 否 | 无 |
begin | 开始的元素(0=第一个元素,1=第二个元素) | 否 | 0 |
end | 最后一个元素(0=第一个元素,1=第二个元素) | 否 | Last element |
step | 每一次迭代的步长 | 否 | 1 |
var | 代表当前条目的变量名称 | 否 | 无 |
varStatus | 代表循环状态的变量名称 | 否 | 无 |
<%
ArrayList<String> people = new ArrayList<>();
people.add("张三");
people.add("李四");
people.add("王五");
people.add("赵六");
people.add("冯七");
request.setAttribute("list",people);
%>
<c:forEach var="people" items="${list}">
<c:out value="${people}"/><br>
</c:forEach>
<c:forEach begin="1" end="3" step="1" var="people" items="${list}" varStatus="itemInfo">
<c:out value="${people}"/> <br>
<c:out value="${itemInfo.index}"/> <span>索引</span><br>
<c:out value="${itemInfo.count}"/> <span>计数</span><br>
<c:out value="${itemInfo.first}"/> <span>是否为第一个</span><br>
<c:out value="${itemInfo.last}"/> <span>是否为最后一个</span><br>
</c:forEach>
5.url
构造一个url
属性 | 描述 | 是否必要 | 默认值 |
---|---|---|---|
value | 基础URL | 是 | 无 |
context | 本地网络应用程序的名称 | 否 | 当前应用程序 |
var | 代表URL的变量名 | 否 | Print to page |
scope | var属性的作用域 | 否 | Page |
<c:url var="myUrl" value="http://www.runoob.com"/>
<c:param name="username" value="tom"></c:param>
<c:param name="password" value="123"></c:param>
</c:url>
<a href="${myUrl}"></a>
10.过滤器filter
10.1 什么是过滤器
和服务器交互过程的中转站,对一些请求进行预处理
类似与过滤器,过滤水中的杂质
过滤器可以创建多个
Filter接口:
方法声明 | 说明 |
---|---|
public default void init(FilterConfig filterConfig) throws ServletException | 过滤器初始化方法,该方法在过滤器初始化时调用。 |
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException | 对请求进行过滤处理。 |
public default void destroy() | 销毁方法,以便释放资源。 |
FilterConfig接口
FilterConfig接口由Servlet容器进行实现,主要用于获取过滤器中的配置信息,其方法声明及说明如下表:
FilterConfig接口的方法声明及说明:
方法声明 | 说明 |
---|---|
public String getFilterName() | 用于获取过滤器的名字。 |
public ServletContext getServletContext() | 获取Servlet上下文。 |
public String getInitParameter(String name) | 获取过滤器的初始化参数值。 |
public Enumeration |
获取过滤器的所有初始化参数。 |
2.1 统计访客数量
package cn.bloghut.filter;
import javax.servlet.*;
import java.io.IOException;
public class CharacterEncodingFilter implements Filter {
//来访数量
private int count;
//web服务器启动的就初始化了
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("初始化");
String param = filterConfig.getInitParameter("count"); // 获取初始化参数
count = Integer.valueOf(param); // 将字符串转换为int类型
}
//过滤处理的方法
@Override
public void doFilter(ServletRequest request,
ServletResponse response, FilterChain chain)
throws IOException, ServletException {
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
count++;
// 将ServletResponse对象转换成HttpServletRequest
HttpServletRequest req = (HttpServletRequest) request;
// 获取ServletContext
ServletContext context = req.getServletContext();
// 将来访数量保存到ServletContext对象中
context.setAttribute("count", count);
System.out.println("CharacterEncodingFilter执行前....");
//让我们的请求继续走,如果不写,程序到这里就会被拦截
chain.doFilter(request,response);
System.out.println("CharacterEncodingFilter执行后....");
}
/**
* 销毁
* web服务器关闭的时候,过滤器会被销毁
*/
@Override
public void destroy() {
System.out.println("destroy");
}
}
在web.xml中配置过滤器
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>cn.bloghut.filter.CharacterEncodingFilter</filter-class>
<!-- 设置初始化参数 -->
<init-param>
<!-- 参数名 -->
<param-name>count</param-name>
<!-- 参数值 -->
<param-value>5000</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<!--只要是 /servlet 的任何请求,会经过这个过滤器-->
<url-pattern>/servlet/ * </url-pattern>
</filter-mapping>
3.1 新特性
1 @WebFilter注释
在Servlet3.0中新增了@WebFilter注释,通过使用该注释就无需在web.xml文件中对过滤器进行配置。@WebFilter注释用于声明过滤器,该注释将会在部署时被容器处理,容器将根据具体的属性配置将相应的类部署为过滤器。
@WebFilter注释主要属性列表:
属性名 | 类型 | 描述 |
---|---|---|
filterName | String | 指定过滤器的name属性,等价于 |
value | String[] | 该属性等价于urlPatterns属性,但是两者不应该同时使用。 |
urlPatterns | String[] | 指定一组过滤器的URL匹配模式,等价于 |
servletNames | String[] | 指定过滤器将应用于哪些Servlet,是@WebServlet中的name属性的取值,或者是web.xml文件中的 |
initParams | WebInitParam[] | 指定一组过滤器初始化参数,等价于 |
asyncSupported | boolean | 声明过滤器是否支持异步操作模式,等价于 |
description | String | 该过滤器的描述信息,等价于 |
displayName | String | 该过滤器的显示名,通常配合工具使用,等价于 |
dispatcherTypes | DispatcherType[] | 指定过滤器的转发模式。具体取值包括:ASYNC、ERROR、FORWARD、INCLUDE 和 REQUEST。 |
2 @WebInitParam注释
@WebInitParam注释等价于web.xml文件中的
@WebInitParam注释主要属性列表:
属性名 | 类型 | 描述 |
---|---|---|
name | String | 指定参数的名字,等价于 |
value | String | 指定参数的值,等价于 |
description | String | 关于参数的描述,等价于 |
//计数器过滤器
@WebFilter(filterName = "CountFilter", urlPatterns = "/index.jsp",
initParams = { @WebInitParam(name = "count", value = "5000") })
public class CountFilter implements Filter
{
...
}
11.监听器Listener
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
/**
* 统计网站在线人数 :统计session
*/
public class OnlineCountListener implements HttpSessionListener {
/**
* 创建session 监听 : 看你的一举一动
* 一旦创建session就会触发一次这个事件!
*
* @param se
*/
@Override
public void sessionCreated(HttpSessionEvent se) {
ServletContext context = se.getSession().getServletContext();
System.out.println(se.getSession().getId());
Integer onLineCount = (Integer) context.getAttribute("onLineCount");
if (onLineCount == null) {
onLineCount = new Integer(1);
} else {
//不为空,在线数量+1
onLineCount++;
}
//更新在线人数
context.setAttribute("onLineCount",onLineCount);
}
/**
* 销毁session 监听
* 一旦session 就会触发一次这个事件!
*
* @param se
*/
@Override
public void sessionDestroyed(HttpSessionEvent se) {
ServletContext context = se.getSession().getServletContext();
Integer onLineCount = (Integer) context.getAttribute("onLineCount");
if (onLineCount == null){
onLineCount = 0;
}else {
onLineCount = onLineCount - 1;
}
context.setAttribute("onLineCount",onLineCount);
}
/**
* session销毁
*
* 1.手动销毁 getSession().invalidate();
* 2.自动销毁
*/
}
12.JDBC
String url jdbc:mysql://localhost:3306/数据库名称?useUnicode=true&characterEncoding=utf8&useSSL=true";
1.对象的作用
1.1DriverManager
加载驱动
//加载驱动
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
Class.forName("com.mysql.jdbc.Driver");
// static {
// try {
// DriverManager.registerDriver(new com.mysql.jdbc.Driver());
// } catch (SQLException var1) {
// throw new RuntimeException("Can't register driver!");
// }
// }
获取连接
//用户信息和url
String url = "jdbc:mysql://localhost:3306/userinfo?useUnicode=true&characterEncoding=utf8&useSSL=true";
String id = "root";
String pwd = "123456";
//连接数据库
Connection connection = DriverManager.getConnection(url, id, pwd);
1.2.Connection
connection.commit(); //设置提交事务
connection.isReadOnly();//是否只读
connection.setAutoCommit(true);//设置事务自动提交
1.3.Statement
(执行SQL的对象) prepareStatement()(执行SQL的对象)
statement.executeQuery(sql);//执行查询,返回一个结果集
statement.execute();//执行任何SQL
statement.executeUpdate();//执行更新操作:插入、修改、删除,返回受影响的行数
1.4ResultSet 查询的结果集:封装了程序结果
--- 在不知道类型的情况下使用getObject类型
resultSet.getObject();
-- 在知道类型的情况下使用对应类型
resultSet.getString();
resultSet.getBigDecimal();
resultSet.getFloat();
resultSet.getDate();
resultSet.getDouble();
resultSet.getInt();
resultSet.getLong();
1.5遍历,指针
resultSet.next();//移动到下一个
resultSet.beforeFirst();//移动到第一个
resultSet.afterLast();//移动到最后面
resultSet.previous();//移动到前一行
resultSet.absolute(row);//移动到指定行
1.6释放资源
resultSet.close();
statement.cancel();
connection.close();
2.Statement 对象详解
jdbc中的statement 用于向数据库发送SQL语句,想要完成对数据库的增、删、改、查,只需要通过这个对象向数据库发送增删改查语句即可
Statement 对象的 executeUpdate方法,用于向数据库 发送增、删、改的SQL语句,executeUpdate执行完后,将会返回一个整数(即增删改语句导致数据库几行数据发生了变化)
Statement. executeQuery()方法用于向数据库发送 查询语句,executeQuery()方法返回代表查询结果的ResultSet对象。
CRUD操作–insert
使用statement.executeUpdate(String sql)方法完成数据添加操作
Statement statement = connection.createStatement();
String sql = "insert into user(...) values(...)"
int num = statement.executeUpdate(sql);
if(num > 0){
System.out.println("插入成功");
}
123456
CRUD操作–delete
加粗样式使用statement.executeUpdate(String sql)方法完成数据删除操作
Statement statement = connection.createStatement();
String sql = "delete from user where id = 1"
int num = statement.executeUpdate(sql);
if(num > 0){
System.out.println("删除成功");
}
CRUD操作–update
使用statement.executeUpdate(String sql)方法完成数据修改操作
Statement statement = connection.createStatement();
String sql = "update user set name='' where id = 1"
int num = statement.executeUpdate(sql);
if(num > 0){
System.out.println("修改成功");
}
CRUD操作–select
使用statement.executeQuery(String sql) 完成查询操作
Statement statement = connection.createStatement();
String sql = "select * from user";
ResultSet rs = statement.executeQuery(sql);
while(rs.next()){
//根据获取列的数据类型,分别调用rs的相应方法映射到java对象中
}
3.提取工具类
package cn.bloghut.lesson02.utils;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
/**
* @author by 闲言
* @classname JdbcUtils
* @description TODO
* @date 2021/9/1 23:03
*/
public class JdbcUtils {
private static String driver;
private static String url;
private static String username;
private static String password;
static {
try {
InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
Properties properties = new Properties();
properties.load(in);
driver = properties.getProperty("driver");
url = properties.getProperty("url");
username = properties.getProperty("username");
password = properties.getProperty("password");
//驱动只加载一次
Class.forName(driver);
} catch (Exception e) {
e.printStackTrace();
}
}
//获取连接
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url, username, password);
}
//释放连接资源
public static void release(Connection connection, Statement statement, ResultSet resultSet) {
if (connection != null) {
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (statement != null) {
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
2.增
package cn.bloghut.lesson02;
import cn.bloghut.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
/**
* @author by 闲言
* @classname TestInstance
* @description TODO
* @date 2021/9/1 23:16
*/
public class TestInsert {
public static void main(String[] args) {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
//1.获取数据库连接
connection = JdbcUtils.getConnection();
//2.创建SQL的执行对象
statement = connection.createStatement();
//3.执行SQL
String sql = "insert into users(id,name,password,email,birthday) values(4,'闲言','123','123@qq.com',null) ";
int num = statement.executeUpdate(sql);
if (num > 0) {
System.out.println("插入成功");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
JdbcUtils.release(connection, statement, resultSet);
}
}
}
3.删
package cn.bloghut.lesson02;
import cn.bloghut.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
/**
* @author by 闲言
* @classname TestInstance
* @description TODO
* @date 2021/9/1 23:16
*/
public class TestDelete {
public static void main(String[] args) {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
//1.获取数据库连接
connection = JdbcUtils.getConnection();
//2.创建SQL的执行对象
statement = connection.createStatement();
//3.执行SQL
String sql = "delete from users where id = 4";
int num = statement.executeUpdate(sql);
if (num > 0) {
System.out.println("删除成功");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
JdbcUtils.release(connection, statement, resultSet);
}
}
}
4.改
package cn.bloghut.lesson02;
import cn.bloghut.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
/**
* @author by 闲言
* @classname TestInstance
* @description TODO
* @date 2021/9/1 23:16
*/
public class TestUpdate {
public static void main(String[] args) {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
//1.获取数据库连接
connection = JdbcUtils.getConnection();
//2.创建SQL的执行对象
statement = connection.createStatement();
//3.执行SQL
String sql = "update users set name='update闲言' where id = 2";
int num = statement.executeUpdate(sql);
if (num > 0) {
System.out.println("修改成功");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
JdbcUtils.release(connection, statement, resultSet);
}
}
}
12345678910111213141516171819202122232425262728293031323334353637383940
5.查
package cn.bloghut.lesson02;
import cn.bloghut.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
/**
* @author by 闲言
* @classname TestInstance
* @description TODO
* @date 2021/9/1 23:16
*/
public class TestQuery {
public static void main(String[] args) {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
//1.获取数据库连接
connection = JdbcUtils.getConnection();
//2.创建SQL的执行对象
statement = connection.createStatement();
//3.执行SQL
String sql = "select * from users";
//4.遍历结果集
resultSet = statement.executeQuery(sql);
while (resultSet.next()) {
System.out.println(resultSet.getString(2));
}
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
JdbcUtils.release(connection, statement, resultSet);
}
}
}
3、 SQL注入问题
4、防止SQL注入
package cn.bloghut.lesson03;
import cn.bloghut.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
/**
* @author by 闲言
* @classname SQLIn
* @description TODO
* @date 2021/9/1 23:39
*/
public class SqlIn {
public static void main(String[] args) {
login("闲言碎语", "123");
// login("'or' 1=1","12133 'or'1=1");
}
//登录业务
public static void login(String username, String password) {
Connection connection = null;
PreparedStatement pst = null;
ResultSet resultSet = null;
try {
connection = JdbcUtils.getConnection();
//preparedStatement 防止sql注入的本质,把传递进来的参数当做字符
//假设其中出现转义字符,就直接忽略了
String sql = "select * from users where name = ? and password = ?";
pst = connection.prepareStatement(sql);
pst.setString(1,username);
pst.setString(2,password);
//预编译的sql
resultSet = pst.executeQuery();
// pst.executeQuery();直接执行
while (resultSet.next()) {
System.out.println(resultSet.getString("name"));
System.out.println(resultSet.getString("password"));
System.out.println("===================");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcUtils.release(connection, pst, resultSet);
}
}
}
依赖坐标
servlet
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
jsp
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
</dependency>
jstl
<!-- 用标签来写语句 -->
<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>
beanutils
<!-- https://mvnrepository.com/artifact/commons-beanutils/commons-beanutils -->
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.4</version>
</dependency>
解决方案
创建干净的项目:
idea中的一个子模块中的pom文件带横线maven为灰色的解决办法
pom依赖 坐标
<dependencies>
<!-- mysql驱动依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.32</version>
</dependency>
<!-- mybatis依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.5</version>
</dependency>
<!-- servlet-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.0</version>
<scope>provided</scope>
</dependency>
<!-- jsp-->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
<scope>provided</scope>
</dependency>
<!-- jstl-->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- if foreach 标准标签库-->
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
</dependencies>
<!-- 服务器插件-->
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat8-maven-plugin</artifactId>
<version>3.0-r1655215</version>
</plugin></plugins>
</build>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)