javaweb

javaweb

1、基本概念

web 开发:

  • web 网页的意思,www.baidu.com
  • 静态web
    • html,css,
    • 提供给所有人看的数据始终不会发生变化!
  • 动态web
    • 提供给所有人看的数据会发生变化,每个人在不同的时间、不同的地点、看到的信息各不相同。
    • 淘宝,几乎所有的网站
    • 技术栈:Servlet/Jsp、Asp、Php

在java 中,动态web资源开发的技术通常为JavaWeb;

1.2、Web应用程序

web应用程序:可以提供浏览器访问的程序;

  1. a.html、b.html …多个web资源,这些web资源可以被外界访问,对外界提供服务;
  2. 访问到的任何一个页面或者资源,都存在于这个世界的某一个角落的计算机上
  3. URL 统一资源定位符
  4. 这个统一的web资源会被放在同一文件夹下,web应用程序---->Tomcat 服务器
  5. 一个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资源出现了错误,我们需要重新编写我们的后台程序
    • 停机维护

优点:

  1. Web 页面 可以动态更新,所有用户看到的都不是同一页面
  2. 它可以和数据库交互(数据持久化:注册、商品信息)

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安装

Apache Tomcat® - Welcome!

3.2 tomcat目录

image-20211207124420263

3.3.访问测试

http://localhost:8080/

3.配置

image-20240518151626178

配置端口号
<Connector port="8080" protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="8443" />
配置主机的名称

webapps:要发布的网站

<Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true">
一个网站是如何访问的
  1. 输入一个域名,点击回车

  2. 检查本地的C:\Windows\System32\drivers\etc\hosts 里面有没有这个域名映射,默认的是localhost

    image-20240518151854579

  3. 有 返回ip地址

  4. 没有 去dns里面找看是否能找到

image-20240518152037694

3.4. 发布一个静态的网站

  • 将自己写的静态的网站,放到服务器(tomcat)指定的webapps目录下,就可以访问了

  • 网站的固定结构:

    • webapps:

      • ROOT
  • Honor:

    • WEB—INF
      • -classes: java程序
      • lib: web应用依赖的jar包
        • web.xml:网站的配置文件
    • index.html
      • index.css
    • index.js
  • url: 王者荣耀官方网站-腾讯游戏

4、HTTP

1 什么是Http

超文本传输协议(Hyper Text Transfer Protocol,HTTP)是一个简单的;请求-响应协议,它通常运行在TCP之上。

  • 文本:html,字符串,~
  • 超文本:图片,音乐,视频,定位,地图…
  • 端口号:80

https:安全的

  • 443

2、两个时代

http 1.0

  • http/1.0:客户端可以与web服务器连接后,只能获得一个web资源,断开连接
image-20240517163844610

http 2.0

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

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.请求行

image-20240518174523940
  • 请求行中的请求方式: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代码。

  1. 有一套标准的项目结构,可以让所有的ide使用maven后构建的项目结构完全一样。

  2. 提供了一套 标准化、简单的 的构建流程(编译、测试、打包、发布...)

  3. 提供了一套依赖管理机制(管理jar包,插件,第三方资源) 自动下载jar包,复制jar包,加入生产环境

插件:管理项目的声明周期

依赖:自动下载jar包,复制jar包,加入生产环境需要的jar.

仓库:

  • 本地仓库:自己计算机中的一个目录
  • 中央仓库:由maven搭建维护的全球唯一的开源仓库
  • 远程仓库(私服):由公司搭建的私有仓库。

5.2、下载和安装

官网下载安装

Maven – Download Apache Maven

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、配置阿里云镜像

image-20240519135624197

  <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、本地仓库

image-20240519154455898

  1. 创建仓库

image-20240519135944871

  1. 配置仓库 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>

解决问题

image-20220110124707734

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 继承关系

implements
implements
implements
«interface»
Servlet
+init(ServletConfig var1)
+getServletConfig() : ServletConfig
+service(ServletRequest var1, ServletResponse var2)
+getServletInfo() : String
+destroy()
GenericServlet
HttpServlet
重写了service方法 对于不同的请求有不同的处理
自己的类
重写访问改Servlet的方法
doGet(HttpServletRequest req, HttpServletResponse resp)
doPost(HttpServletRequest req, HttpServletResponse resp)

6.3.2 Servlet 方法的功能

image-202405201658474676.3.3 Servlet生命周期

init初始化 --> servlet--> distroy销毁

image-20240522171751456

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界面

image-20211208161519829

优先级问题
  指定了固有的映射路径优先级最高,如果找不到就会走默认的处理请求;

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对象

111

//放数据的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响应消息。

image-20240524142427942

设置状态码

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.获取表单提交的参数

image-20240524151603229

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>");

image-20240530160012973

3.获取请求头的信息

image-20240524193116203

4.获取表单中用户的输入

image-20240524193404459

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应用中的会话过程类似于生活中的打电话,它指的是客户端和服务器之间连续发生的一系列请求和响应过程,例如用户在购物网站完成一次购物就是一个会话。

在会话的期间,通话的双方会产生通话内容,同样,在浏览器和服务器交互的过程中,也会产生一些数据。会话技术就是用来保存这些数据的

浏览器关闭了,会话就中断。

image-20240527205425301

网站如何标记你是否访问过?

  1. 给一个信物 一个cookie,下次访问带上cookie。
  2. 在服务端登记,下次你再来,我去匹配你。

有状态会话与无状态会话最大区别就是,它可以在交互的同时,保持住状态。

7.1客户端会话跟踪技术cookie

cookie的基本使用:

  1. 发送cookie
Cookie cookie = new Cookit("键","值");
response.addCookie(cookie);
  1. 获取cookie
//获取cookie 数组
Cookie[] cookies = request.getCookies();

//遍历数组,获取想要的值
for(Cookie item:cookie);

example:

记住上次访问时间

image-20240527212849369

image-20240527212933522

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信息随着时间越存越多,直到内存资源耗尽。

image-20240529164419849

所以设设置好一个时间。在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();

image-20240529163531693

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 原理

image-20220103102807348

服务端设置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

image-20240531145235030

image-20240531151829216

image-20220103133126933

image-20220103133500239

image-20220103133542301

结论: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>");
%>

image-20240531163901643 输出结果

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项目

  1. pom -> war 打包为war
  2. 双击 resource ->facets->web resource dir双击添加webapps -> deployment descriptors "+"创建inf文件
  3. 添加依赖
  4. 创建文件夹

image-20211206100815262

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的标签库进行说明

image-20240603150844337

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 什么是过滤器

和服务器交互过程的中转站,对一些请求进行预处理

类似与过滤器,过滤水中的杂质

过滤器可以创建多个

image-20240604182224024

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 getInitParameterNames() 获取过滤器的所有初始化参数。

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文件中的子标签,该注释通常不单独使用,而是配合@WebServlet或者@WebFilter使用。

@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

image-20220106173755001

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>

解决方案

image-20220114141549476

创建干净的项目:

image-20220105200847422 image-20220105200915593

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>
posted on   吃可乐的陈伽  阅读(6)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示