学习Servlet

一、引言(两种架构)

1.1C/S架构和B/S架构

C/S架构和B/S架构是软件发展过程中出现的两种架构方式

1.2C/S架构(Client/Server客户端/服务器)

特点:必须在客户端安装特定的软件
优点:图形效果显示较好(如3D游戏)
缺点:服务器的软件和功能进行升级,客户端也必须升级,不利于维护
常见的C/S程序:QQ,微信

1.3B/S架构(Browser/Server浏览器/服务器)

特点:无需安装客户端,任何浏览器都可以直接访问
优点:涉及到功能的升级,只需升级服务器端
缺点:图形显示效果不如C/S架构
需要通过HTTP协议访问

二、服务器

2.1概念

2.1.1什么是web

Web(World Wide Web)称为万维网,简单理解就是网站,它用来表示Internet主机上供外界访问的资源。Internet上提供访问资源分为两大类
静态资源:指的是Web页面中供人们浏览的数据始终是不变的(HTML,CSS)
动态资源:指的是Web页面中供人们浏览的数据是由程序产生的,不同时间不同地点,甚至是不同设备访问web页面看到的内容不同(Jsp,Servelt)
在java中,动态web资源开发技术我们统称Java web

2.1.2什么是web服务器

web服务器是运行及发布在web应用的容器,只有将开发的web项目放置到该容器中,才能使网络中的用户通过浏览器进行访问

2.2常见服务器

开源
    OpenSource(开源代码,免费)
    Tomcat(主流web服务器,适合初学者)
    jetty(淘宝,运行效率比Tomcat高)
    resin(新浪,所有开源服务器中,运行效率最高)
收费
    WebLogic(Oracle)
    WebSphere(IBM)
    提供相应的服务和支持,软件大,耗资大

2.3 Tomcat服务器

Tomcat是Apache软件基金会的JacKarte项目中的一个核心项目,免费开源、并支持Servelt和jsp规范.

2.4Tomcat的安装

2.4.1下载

https://tomcat.apache.org/

2.4.2解压安装

将Tomcat解压到一个没有特殊字符的目录下
    不建议放很多磁盘目录下
    不建议方中文路径

2.4.3目录结构

文件夹说明备注
bin该目录下放的是二进制可执行文件start.up启动Tomcat、shutdown停止Tomcat
conf最重要的目录server.xml和web.xmlserver.xml配置整个服务器信息,例如修改端口号,编码格式。web.xml项目部署描述符文件,这个文件中注册了很多MIME类型,即文档类型。
libTomcat的一个类库,里面放的主要是jar包
logs放日志文件,记录了Tomcat启动和关闭的信息,如果启动Tomcat时有错误,异常也会记录在日志文件中
temp临时文件,这个目录在Tomcat停止后删除
webapps存放web项目的目录,其中每个文件夹都是一个项目;其中ROOT是一个特殊的项目,在地址栏中没有给出项目的目录时,对应的就是ROOT项目。
work运行时生成的文件,最终运行文件都在这里当客户端访问一个JSP文件时,Tomcat会通过JSP生成Java文件,然后编译Java文件生成.class文件,生成的.class和Java文件都会放在这个目录下面。

2.5Tomcat的启动和停止

2.5.1启动

进入tomcat安装目录下bin下,双击Start.bat启动程序出现以下界面

2.5.2验证

打开浏览器输入http://localhost:8080
出现以下界面成功

2.5.3停止tomcat

双击shutdown.bat即可关闭Tomcat的启动窗口

2.5.4修改端口号

Tomcat的默认端口号是8080,可以通过conf/server.xml文件修改

<Connector port="8080" protocol="HTTP/1.1"
				ConnectionTimeout="20000"
           		redirectPort="8443">
修改端口号后,重启tomcat的服务

2.6项目部署及静态资源

2.6.1创建项目

在webapps中建立文件夹(项目应用),比如webDemo01
    创建WEB-INF文件夹,用于存放项目的核心内容
        创建classes,用于存放.class文件
        创建lib,用于存放jar文件
        创建web.xml,项目配置文件(到ROOT项目下面)
    把网页hello.html复制到webDemo01文件中,与WEB-INF在同一级下

 

2.6.2URL访问资源

在浏览器中输入URL:http://localhost:8080/webDemo01/login.html
4部分组成:协议、主机、端口、资源路径

2.7常见错误

2.7.1Tomcat闪退

闪退是由于JAVA_HOEM配置导致的

2.7.2 404

访问资源不存在,出现404错误

三、Servlet【重点】

3.1概念

  • Servelt:Server Applet的简称,是服务器端的程序(代码、功能实现),可交互式的处理客户端发送到服务器端的请求,并完成操作响应。
    
  • 动态网页技术
  • JavaWeb程序的开发的基础,Java EE规范(一套接口)的一个组成部分

3.1.2Servelt的作用

接受客户端请求,完成操作
动态生成网页(页面数据可变)
将包含操作结果的动态页面响应给客户端

3.2Servlet的开发步骤

3.2.1搭建开发环境

3.2.2编写servlet

实现java.servlet.Servelt
重写5个方法
在核心的service()方法中编写输出语句,打印访问结果
package com.qf.servlet;
​
import javax.servlet.*;
import java.io.IOException;
​
/**
 * @X-PENG-7 2023/4/12
 * WebProject
 */
public class MyServlet implements Servlet {
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
​
    }
​
    @Override
    public ServletConfig getServletConfig() {
        return null;
    }
​
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("My First web");
    }
​
    @Override
    public String getServletInfo() {
        return null;
    }
​
    @Override
    public void destroy() {
​
    }
}

3.2.3部署Servlet

编译MyServlet后,将生成的.class文件放在WEB-INF/classes文件中

3.2.4配置Servlet

编写WEB-INF下项目配置文件web.xml

四、IDEA部署web项目

4.1IDEA创建web项目

 

将tomcat里面lib下的servlet-api.jar复制一份粘贴到WEB-INF目录下的创建目录lib里

4.2IDEA开发servlet

4.2.1编写servlet

package com.qf.servlet;
​
import javax.servlet.*;
import java.io.IOException;
​
/**
 * @X-PENG-7 2023/4/12
 * WebProject
 */
public class MyServlet implements Servlet {
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
​
    }
​
    @Override
    public ServletConfig getServletConfig() {
        return null;
    }
​
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("My First web");
    }
​
    @Override
    public String getServletInfo() {
        return null;
    }
​
    @Override
    public void destroy() {
​
    }
}

4.2.2配置web.xml

4.2.3部署web项目

D:\apache-tomcat-8.0.23\webapps\WebProject\WEB-INF\classes\com\qf\servlet
创建WebProject目录复制idea中的WEB-INF和out下的com到创建目录classes

4.3IDEA部署web项目

前面我们是在Tomcat的webapps目录新建应用程序目录myweb,然后把静态资源和Servlet复制到相关目录下,使用IDEA 我们不再复制了。可以通过IDEA继承Tomcat服务器,实现自动部署

4.3.1IDEA继承Tomcat

4.3.2项目部署Tomcat

 

 

4.4其他操作

4.4.1关联第三方jar包

见上方

4.4.2如何导出war包

项目完成后,有时需要打成war方便部署。war包可以直接放入Tomcat的webapps目录中,启动Tomcat后自动解压,即可访问。
步骤

  

五、HTTP协议

5.1什么是HTTP

超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最广泛的一种网络协议,是一个基于请求响应模式的、无状态的、应用层协议,运行在TCP协议的基础上。(三次握手,四次挥手)

5.2HTTP协议的特点

支持客户端(浏览器)/服务器模式
简单快速:客户端只向服务器发送请求方法和路径,服务器即可响应数据,因而通信速度很快。请求方法有GET、POST等
灵活:HTTP允许传输任意类型的数据,传输书类型由Content-Type标识
无连接:无连接指每次TCP连接只处理一个或多个请求,服务器处理完客户的请求后,即断开连接。采用这种方式可以节省传输时间
    HTTP1.0版本是一个请求响应之后,直接断开,称为短连接
    HTTP1.1版本不是响应后直接断开,而是等几秒钟之后有新的请求,那么还是通过之前的连接通道来手法消息,如果过了这几秒,就会断开连接,称为长连接。
无状态:HTTP协议就是无状态协议
    无状态是指协议对于事务的处理没有记忆能力

5.3HTTP协议通信流程

客户与服务器建立连接(三次握手)
客户向服务发送请求。
服务器接受请求,并根据请求返回相应的文件作为应答
客户与服务器关闭连接(四次挥手)

5.4请求报文和响应报文

5.5常见状态码

状态码状态描述说明
200OK客户端请求成功
302Found临时重定向
403Forbidden服务器收到请求,但是拒绝提供服务。服务器通常会在相应正文中给出不提供服务的原因
404Not Found请求资源不存在,例如输入错误的URL
500Internal Server Error服务器发生不可预期的错误,导致无法完成客户端的请求。

六、Servlet详解【重点】

6.1Servlet核心接口和类

在Servlet体系结构中,除了实现Servlet接口,还可以通过继承GenericServlet或HttpServlet类,完成编写

6.1.1Servlet接口

在Servlet API 中最重要的是Servlet接口,所有的Servlet都会直接或者间接的与该接口发生关系,或者直接实现该接口,或间接继承自实现了该接口的类。
该接口包括以下五个方法
init(ServletConfig config)
ServletConfig getServletConfig()
service(ServletRequest req,ServletResponse resz)
String getServletInfo()
destroy()

6.1.2GenericServlet抽象类

GenericServlet使Servlet变得更容易。它提供生命周期方法init和destroy的简单实现,要编写一般的Servlet,只需重写抽象service方法即可

6.1.3HttpServlet类

HttpServlet是继承GenericServlet的基础上进一步的扩展。
提供将要被子类化创建适用于web站点的HTTP servlet的抽象类。HttpServlet的子类必须重写一个方法,该方法通常是以下这些方法之一:
doGet,如果servlet支持HTTP GET请求
doPost,用于HTTP POST请求
doPut,用于HTTP PUT请求
doDelet,用于HTTP DELET请求

6.2Servlet两种创建方式

6.2.1实现接口Servlet

package com.qf.servlet;
​
import javax.servlet.*;
import java.io.IOException;
​
/**
 * @X-PENG-7 2023/4/12
 * WebProject
 */
public class MyServlet implements Servlet {
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
​
    }
​
    @Override
    public ServletConfig getServletConfig() {
        return null;
    }
​
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("My First web");
    }
​
    @Override
    public String getServletInfo() {
        return null;
    }
​
    @Override
    public void destroy() {
​
    }
}

6.2.2继承HttpServlet(推荐)

package com.qf.servlet;
​
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
​
/**
 * @X-PENG-7 2023/4/13
 * WebProject
 */
public class HttpsServlet extends HttpServlet {
//    @Override
//    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//        System.out.println("HttpServlet class");
//    }
​
​
//    @Override
//    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
//        super.service(req, res);
//    }
​
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("这是get请求过来的内容");
    }
​
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("这是post请求过来的内容");
    }
}
​
​

6.2.3常见错误

HTTP Status 404 资源找不到
    第一种情况:地址书写错误
    第二种情况:地址没问题,把IDEA项目中的out目录删除,然后重新运行。
Servlet地址配置重复。both mapped to the url-pattern[/helloservlet] which is not permitted
Servlet地址配置错误。比如没写/Invaild<url-pattern>[helloservlet2] in servlet mapping

6.3Servlet两种配置方式

6.3.1使用web.xml(servlet2.5之前使用)

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    <display-name>WEB_DAY11</display-name>
    <!-- Servlet的第二种配置 -->
    <!-- Servlet配置-->
    <servlet>
        <!--名称-->
        <servlet-name>my</servlet-name>
        <!--Servlet的全称类名-->
        <servlet-class>com.qf.servlet.MyServlet</servlet-class>
        <!--启动优先级,数字越小越先起作用-->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <!-- 映射配置-->
    <servlet-mapping>
        <!--名称-->
        <servlet-name>my</servlet-name>
        <!-- 资源的匹配规则,精确匹配-->
        <url-pattern>/myservlet</url-pattern>
    </servlet-mapping>
    <servlet>
        <servlet-name>gs</servlet-name>
        <servlet-class>com.qf.servlet.GenServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>gs</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
    <servlet>
        <servlet-name>hs</servlet-name>
        <servlet-class>com.qf.servlet.HttpsServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>hs</servlet-name>
        <url-pattern>*.action</url-pattern>
    </servlet-mapping>
    <welcome-file-list>
        <welcome-file>login.html</welcome-file>
    </welcome-file-list>
</web-app>
url-pattern 定义匹配规则,取值说明
精确匹配    /具体的名称  只有url路径是具体的名称时候才会触发Servlet
后缀匹配    *.xxx       只要是以xxx结尾的就匹配触发Servlet
通配符匹配   /*          匹配所有的请求,包含服务器的所有资源
通配符匹配   /           匹配所有的请求,包含服务器的所有资源,不包括.jsp
​
load-on-startup
1.元素标记容器是否应该在web应用程序启动的时候就加载这个servlet
2.它的值必须是一个整数,表示servlet被加载的先后顺序
3.如果该元素的值为负数或者没有设置,则容器会当Servlet被请求时再加载
4.如果值为正数或者0时,表示容器在应用启动时就加载并初始化这个servlet,值越小,servlet的优先级越高,就越先被加载,值相同时,容器会自己选择顺序来加载。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    <display-name>WEB_DAY11</display-name>
    <!-- Servlet的第二种配置 -->
    <!-- Servlet配置-->
    <servlet>
        <!--名称-->
        <servlet-name>my</servlet-name>
        <!--Servlet的全称类名-->
        <servlet-class>com.qf.servlet.MyServlet</servlet-class>
        <!--启动优先级,数字越小越先起作用-->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <!-- 映射配置-->
    <servlet-mapping>
        <!--名称-->
        <servlet-name>my</servlet-name>
        <!-- 资源的匹配规则,精确匹配-->
        <url-pattern>/myservlet</url-pattern>
    </servlet-mapping>
    <servlet>
        <servlet-name>gs</servlet-name>
        <servlet-class>com.qf.servlet.GenServlet</servlet-class>
        <load-on-startup>0</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>gs</servlet-name>
        <url-pattern>/gs</url-pattern>
    </servlet-mapping>
    <servlet>
        <servlet-name>hs</servlet-name>
        <servlet-class>com.qf.servlet.HttpsServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>hs</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
    <welcome-file-list>
        <welcome-file>login.html</welcome-file>
    </welcome-file-list>
</web-app>

6.3.2使用注解(servlet3.0后支持,推荐)

package com.qf.servlet2;
​
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
​
/**
 * @X-PENG-7 2023/4/13
 * WebProject
 */
@WebServlet
public class BasicServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("这是get");
    }
​
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("这是post");
    }
}
​
6.3.3@WebServlet注解常用的属性
name:Servlet名字(可选)
value:配置url路径,可以配置多个
urlPattern:配置url路径,作用和url一样,不能同时使用
loadOnStartup:配置Servlet的创建的时机,如果是0或者正数 启动程序时创建,如果时负数,则访问时创建。数越小优先级越高。


package com.qf.servlet2;
​
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
​
/**
 * @X-PENG-7 2023/4/13
 * WebProject
 */
//value = {"/bs","/bss"}
@WebServlet(urlPatterns = {"/bs","/bss"},loadOnStartup = 0)
public class BasicServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("这是get");
    }
​
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("这是post");
    }
}

这个与web.xml中的不冲突,可以同时配置  但是注解更方便

七、Servlet应用【重点】

7.1 request对象

在servlet中用来处理客户端请求需要doGet和doPost方法的request对象

注意:request对象、response对象作为参数传递给doGet和doPost方法

7.1.1 get和post区别

get请求
    get提交的数据会放在URL之后,以?分割URL和传输数据,参数之间以&相连
    get方式是文明传递,数据量小,不安全
    效率高,浏览器默认请求方式为GET请求
    对应的Servlet的方法是doGet
post请求
    post方法是把提交的数据放在HTTP包的Body中
    密文传递数据,数据量大,安全
    效率相对没有GET高
    对应的Servlet的方法是doPost

7.1.2 request主要方法

方法名说明
String getParameter(String name)根据表单组件名称获取提交数据
void setCharacterEncoding(String charset)指定每个请求的编码

7.1.3request应用

HTML页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>注册页面</title>
</head>
<body>
    <form action="/WebProject_war_exploded/rs" method="get">
        用户名:<input type="text" name="username"/><br/>
        密码:<input type="password" name="password"/><br/>
        <input type="submit" value="注册"/>
    </form>
​
</body>
</html>

Servlet代码:

package com.qf.servlet2;
​
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
​
/**
 * @X-PENG-7 2023/4/13
 * WebProject
 */
@WebServlet(value = "/rs")
public class RegisterServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.获取用户请求发送的数据
        String username=req.getParameter("username");
        String password=req.getParameter("password");
​
        System.out.println("提交的数据:"+username+"\t"+password);
    }
}
 

7.1.4 get请求收参问题

产生乱码是因为服务器和客户端沟通的编码不一致造成的,因此解决的办法是:客户端和服务器之间设置一个统一的编码,之后按照此编码进行数据的传输和接收

7.1.5get中文乱码

在Tomcat7及以下的版本,客户端以UTF-8的编码传输数据到服务器端,而服务器端的request对象使用的是ISO8859-1这个字符来接收数据,服务器和客户端编码不一致才会产生乱码
解决办法:在接收到数据后,先获取request对象以ISO8859-1字符编码接收到原始数据的字节组,然后通过字节组以指定的编码构建字符串,解决乱码的问题。
Tomcat8的版本方式不会出现乱码,因为服务器对url的编码格式可以进行自动转换。

7.1.6post中文乱码

由于客户端是以UTF-8字符编码将表单数据传输到服务器端的,因此服务器也需要设置UTF-8字符编码进行接收。
解决方案:使用ServletRequest接口继承而来的setCharacterEncoding(charset)方法进行统一的编码设置。

7.2 response对象

response对象用于响应客户端请求并向客户端输出信息

7.2.1 response主要方法

方法名称作用
setHeader(name,vaule)设置响应信息头
setContentType(String)设置响应文件类型、响应式的编码格式
setCharestEnconding(String)设置服务器端响应内容的编码格式
getWrite()获取字符输出流

7.2.2解决输出中文乱码

设置服务器端响应的编码格式
设置客户端响应内容的头内容的文件类型及编码格式
response.setCharacterEncoding("UTF-8");//设置响应编码格式为utf-8,服务端
response.setHeader("Content-type","text/html;charset=UTF-8");//不推荐
同时设置服务器的编码格式和客户端响应的文件类型及响应时的编码格式
response.setContentType("text/html;charset=UTF-8");//推荐

7.3综合案例(Servlet+JDBC)

要求:实现登录功能、展示所用用户功能

7.3.1 数据库

CREATE TABLE admin(
    username VARCHAR(20) PRIMARY KEY,
    PASSWORD VARCHAR(20) NOT NULL,
    phone VARCHAR(11) NOT NULL,
    Address VARCHAR(20) NOT NULL
)ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO admin(username,PASSWORD,phone,Address)
VALUES('gavin','123456','12345678901','北京市昌平区');
INSERT INTO admin(username,PASSWORD,phone,Address)
VALUES('aaron','123456','12345678901','北京市昌平区');

1.导入jar包

 

2.创建database.properties

 

7.3.2 DButils

package com.qf.servletProject.utils;
​
import com.alibaba.druid.Constants;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
​
​
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
​
/**
 * @X-PENG-7 2023/4/15
 * WebProject
 */
public class Dbutils {
    private static DruidDataSource ds;
    private static final ThreadLocal<Constants> THREAD_LOCAL = new ThreadLocal<>();
​
    //初始内容
    static {
        Properties properties = new Properties();
        InputStream inputStream = Dbutils.class.getResourceAsStream("/database.properties");
        try {
            properties.load(inputStream);
            ds = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
​
    public static Connection getConnection() {
        Connection connection = (Connection) THREAD_LOCAL.get();
        try {
            if (connection == null) {
                connection = ds.getConnection();
                THREAD_LOCAL.set((Constants) connection);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return connection;
    }
​
    public static void begin() {
        Connection connection = null;
        connection = getConnection();
        try {
            connection.setAutoCommit(false);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
​
    public static void commit() {
        Connection connection = null;
       
        try {
            connection = getConnection();
            connection.commit();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            closeAll(connection, null, null);
        }
    }
​
    public static void rollback() {
        Connection connection = null;
        try {
            connection = getConnection();
            connection.rollback();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            closeAll(connection, null, null);
        }
    }
​
    public static void closeAll(Connection connection, Statement statement, ResultSet resultSet) {
        try {
            if (resultSet != null) {
                resultSet.close();
            }
            if (statement != null) {
                statement.close();
            }
            if (connection != null) {
                connection.close();
                THREAD_LOCAL.remove();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
​
    }
}
​

7.3.3 DaoImpl

package com.qf.servletProject.dao;
​
import com.qf.servletProject.entity.Admin;
​
import java.util.List;
​
/**
 * @X-PENG-7 2023/4/16
 * WebProject
 */
public interface AdminDao {
    public int insert(Admin admin);
    public int delete(String username);
    public int update(Admin admin);
    public Admin select(String username);
    public List<Admin> selectAll();
}
​


package com.qf.servletProject.dao.impl;
​
import com.qf.servletProject.dao.AdminDao;
import com.qf.servletProject.entity.Admin;
import com.qf.servletProject.utils.Dbutils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
​
import java.sql.SQLException;
import java.util.List;
​
/**
 * @X-PENG-7 2023/4/16
 * WebProject
 */
public class AdminDaoImpl implements AdminDao {
    private QueryRunner queryRunner = new QueryRunner();
​
    @Override
    public int insert(Admin admin) {
        return 0;
    }
​
    @Override
    public int delete(String username) {
        return 0;
    }
​
    @Override
    public int update(Admin admin) {
        return 0;
    }
​
    @Override
    public Admin select(String username) {
        try {
            Admin admin = queryRunner.query(Dbutils.getConnection(), "select * from admin where username=?;", new BeanHandler<Admin>(Admin.class), username);
            return admin;
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }
​
    @Override
    public List<Admin> selectAll() {
        try {
            List<Admin> admins = queryRunner.query(Dbutils.getConnection(), "select * from admin", new BeanListHandler<Admin>(Admin.class));
            return admins;
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }
}
​

7.3.4 SereviceImpl

package com.qf.servletProject.service;
​
import com.qf.servletProject.entity.Admin;
​
import java.util.List;
​
/**
 * @X-PENG-7 2023/4/16
 * WebProject
 */
public interface AdminService {
    public Admin login (String username, String password);
    public List<Admin> showAllAdmin();
}
​
package com.qf.servletProject.service.impl;
​
import com.qf.servletProject.dao.AdminDao;
import com.qf.servletProject.dao.impl.AdminDaoImpl;
import com.qf.servletProject.entity.Admin;
import com.qf.servletProject.service.AdminService;
import com.qf.servletProject.utils.Dbutils;
​
import java.util.List;
​
/**
 * @X-PENG-7 2023/4/16
 * WebProject
 */
public class AdminServiceImpl implements AdminService {
    private AdminDao adminDao = new AdminDaoImpl();
​
    @Override
    public Admin login(String username, String password) {
        Admin result = null;
        try {
            Dbutils.begin();
            Admin admin = adminDao.select(username);
            if (admin != null) {
                if (admin.getPassword().equals(password)) {
                    result = admin;
                }
            }
            Dbutils.commit();
        } catch (Exception e) {
            Dbutils.rollback();
            e.printStackTrace();
        }
        return result;
    }
​
    @Override
    public List<Admin> showAllAdmin() {
        return null;
    }
}
​

7.3.5 HTML页面代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录页面</title>
</head>
<body>
<form action="/WebProject_war_exploded/login" method="post">
    用户名:<input type="text" name="username"/><br/>
    密码:<input type="password" name="password"><br/>
    <input type="submit" value="登录"/>
</form>
​
</body>
</html>

7.3.6 LoginServlet

package com.qf.servletProject.servlet;
​
import com.qf.servletProject.entity.Admin;
import com.qf.servletProject.service.AdminService;
import com.qf.servletProject.service.impl.AdminServiceImpl;
​
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
​
/**
 * @X-PENG-7 2023/4/16
 * WebProject
 */
@WebServlet(value = "/login")
public class LoginServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        resp.setContentType("text/html;charset=UTF-8");
        //1.收参
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        //2.调用业务逻辑
        AdminService adminService=new AdminServiceImpl();
        Admin admin=adminService.login(username,password);
        //3.处理结果
        PrintWriter printWriter = resp.getWriter();
        if (admin!=null){
            //响应给客户一个登录成功的页面
            printWriter.println("<html>");
            printWriter.println("<head>");
            printWriter.println("<meta charset='UTF-8'>");
            printWriter.println("<title>结果页面</title>");
            printWriter.println("</head>");
            printWriter.println("<body>");
            printWriter.println("<h1>登录成功</h1>");
            printWriter.println("</body>");
            printWriter.println("</html>");
        }else {
            //响应给客户端一个登录失败
            printWriter.println("<html>");
            printWriter.println("<head>");
            printWriter.println("<meta charset='UTF-8'>");
            printWriter.println("<title>结果页面</title>");
            printWriter.println("</head>");
            printWriter.println("<body>");
            printWriter.println("<h1>登录失败</h1>");
            printWriter.println("</body>");
            printWriter.println("</html>");
        }
    }
​
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
​

7.3.7 ShowAllAdminServlet

package com.qf.servletProject.servlet;
​
import com.qf.servletProject.entity.Admin;
import com.qf.servletProject.service.AdminService;
import com.qf.servletProject.service.impl.AdminServiceImpl;
​
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
​
@WebServlet(value = "/showall")
public class ShowAllAdminServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=utf-8");
        AdminService adminService = new AdminServiceImpl();
​
        List<Admin> adminList = adminService.showAllAdmin();
​
        PrintWriter printWriter = resp.getWriter();
​
        if(adminList!=null){
            printWriter.println("<html>");
            printWriter.println("<head>");
            printWriter.println("<meta charset='UTF-8'>");
            printWriter.println("<title>显示所有</title>");
            printWriter.println("</head>");
            printWriter.println("<body>");
            printWriter.println("<table border='1'>");
            printWriter.println("   <tr>");
            printWriter.println("       <td>username</td>");
            printWriter.println("       <td>password</td>");
            printWriter.println("       <td>phone</td>");
            printWriter.println("       <td>address</td>");
            printWriter.println("   </tr>");
            for(Admin admin : adminList){
                printWriter.println("   <tr>");
                printWriter.println("       <td>"+admin.getUsername()+"</td>");
                printWriter.println("       <td>"+admin.getPassword()+"</td>");
                printWriter.println("       <td>"+admin.getPhone()+"</td>");
                printWriter.println("       <td>"+admin.getAddress()+"</td>");
                printWriter.println("   </tr>");
            }
            printWriter.println("</table>");
            printWriter.println("</body>");
            printWriter.println("</html>");
        }else{
            printWriter.println("<html>");
            printWriter.println("<head>");
            printWriter.println("<meta charset='UTF-8'>");
            printWriter.println("<title>显示所有</title>");
            printWriter.println("</head>");
            printWriter.println("<body>");
            printWriter.println("<h3>当前没有用户!</h3>");
            printWriter.println("</body>");
            printWriter.println("</html>");
        }
    }
​
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}

八、转发重定向

8.1 现有问题

在之前的案例中,调用业务逻辑和显示结果页面都在同一个Servlet里,就会产生设计问题
    不符合单一职能原则、各司其职的思想
    不利于后续的维护
应该将业务和逻辑显示结果分开

8.1.1 业务、显示分离

问题:业务逻辑和显示结分离后,如何跳转到显示结果的Servlet?
业务逻辑得到的数据如何传递给显示结果的Servlet

8.2转发

跳转的作用在服务器端,将请求发送给服务器上的其他资源,以共同完成一次请求的处理

8.2.1 页面跳转

在调用业务逻辑的Servlet中,编写以下的代码
    request.getRequestDispather("/目标URL-pattern").forward(request,response);
使用forward跳转时,是在服务器内部跳转,地址栏不发生变化,属于同一次请求

8.2.2 数据传递

forward表示一次请求,是在服务器内部跳转,可以共享同一次request作用域中的数据
    request作用域:拥有存储数据的空间,作用范围是一次请求有效(一次请求可以经过多次转发)
        可以将数据存入request后,在一次请求过程中的任何位置进行获取
        可传递任何数据(基本数据类型、对象、数组、集合等)
    存数据:request.setAttribute(key,value);
        以键值对的形式存储在request作用域中。key为String类型,value为Object类型
    获取数据:request.getAttribute(key);
        通过String类型的key访问Object类型的value

8.2.3 转发特点

转发是服务器行为
转发是浏览器只做了一次访问请求
转发浏览器地址不变
转发两次跳转之间传输的信息不会丢失,可以通过request进行数据的传递
转发只能将请求转发给同一个web应用中的组件

8.3 重定向

重定向作用在客户端,客户端将请求发送给服务器后,服务器响应给客户端一个新的请求地址,客户端重新发送请求。

8.3.1页面跳转

在调用业务逻辑的Servlet中,编写以下代码
    response.sendRedirect("目标URL");

8.3.2数据传递

sendRedirect跳转时,地址栏改变,代表客户端重新发送的请求。属于两次请求
    response没有作用域,两次request请求中的数据无法共享
    数据传递:通过URL的拼接进行数据传递("/")
    获取数据:request.getParameter("username");

8.3.3 重定向特点

重定向是客户端行为
重定向是浏览器做了至少两次的访问请求
重定向浏览器地址改变
重定向两次跳转之间传输的信息会丢失(request范围)
重定向可以指向任何的资源,包括当前应用程序中的其他资源、同一个站点上的其他应用程序中的资源、其他站点的资源。

8.4 转发、重定向总结

当两个Servlet需要传递数据时,选择forward转发。不建议使用sendRedirect进行传递

九、Servlet生命周期

9.1生命周期的四个阶段

9.1.1实例化

当用户第一次访问Servlet时,由容器调用Servlet的构造器创建具体的Servlet对象,也可以在容器启动之后立刻创建实例。用如下代码可以设置Servlet是否在服务器时就创建。
<load-on-startup>1</load-on-startup>
注意:只执行1次

9.1.2 初始化

在初始化阶段,init()方法会被调用。这个方法在javax.servlet.Servlet接口中定义。其中,方法以一个ServletConfig类型的对象作为参数。
注意:init方法只执行一次

9.1.3服务

当客户端有一个请求时,容器就会将请求ServletRequest与响应ServletResponse对象转给Servlet,以参数的形式传给service方法
注意:此方法可以执行多次

9.1.4 销毁

当Servlet容器停止或者重新启动都会引起销毁Servlet对象并调用destroy方法
注意:此方法执行一次​

十、Servlet特性

10.1 线程安全问题

Servlet在访问之后,会执行实例化操作,创建一个servlet对象,而我们Tomcat容器可以同时多个线程并发访问同一个Servlet,如果在方法中对成员变量修改操作,就会有线程安全问题。

10.2 如何保证线程安全

synchronized
    将存在线程安全问题的代码放到同步代码块中
实现SingleThreadModel接口
    servlet实现singleThreadModel接口后,每个线程都会创建servlet实例,这样每个客户端请求就不存在共享     资源的问题,但是servlet响应客户端请求的效率太低,所以已经淘汰。
尽可能使用局部变量
package com.qf.servlet3;
​
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
​
/**
 * @X-PENG-7 2023/4/16
 * WebProject
 */
public class SafeServlet extends HttpServlet {
​
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //使用局部变量
        String message = "";
        //假设1、接收参数
        //2.调用业务逻辑 得到登录结果
        message = "登录成功";
        PrintWriter printWriter = resp.getWriter();
        printWriter.println(message);
​
​
    }
​
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

十一、状态管理

11.1 现有问题

HTTP协议是无状态的,不能保存每次提交的信息
如果用户发来一个新的请求,服务器无法知道它是否与上次的请求有联系
对于那些需要多次提交数据才能完成的Web操作,比如登录来说,就成问题了。

11.2概念

将浏览器与Web服务器之间多次交互当作一个整体来处理,并且将福哦此交互涉及的数据(即状态)保存下来。

11.3 状态管理分类

客户端状态管理技术:将状态保存在客户端。代表性的是Cookie技术
服务器状态管理技术:将状态保存在服务器端。代表性的是session技术(服务器传递sessionID时需要使用Cookie的方式)和application

十二、Cookie的使用

12.1 什么是cookie

cookie是在浏览器访问web服务器的某个资源时,由web服务器在HTTP响应消息头中附带传送给浏览器的一小段数据。
一旦web浏览器保存了某个cookie,那么在它以后每次访问该服务器的时,都应在HTTP请求头中将这个cookie回传给    web服务器。
一个cookie主要由标识该信息的名称(name)和值(value) 组成。

cookie原理

 

12.2 创建cookie

//创建cookie
Cookie ck=new Cookie("code",code);
ck.setPath("/webs");//设置Cookie的路径
ck.setMaxAge(-1);//内存存储,取值有三种:>0有效期,单位秒;=0浏览器关闭;<0内存存储,默认-1
response.addCookie(ck);//添加response对象中,响应时发送给客户端
//注意:有效路径:当前访问资源的上一级目录,不带主机名

12.3获取cookie

//获取所有的cookie
Cookie [] cks =request.getCookies();
    //遍历Cookie
    for(Cookie ck :cks){
        //检索出自己的Cookie值
        if(ck.getName().equals("code"))
        {
            //记录Cookie的值
            code=ck.getValue();
            break;
        }
    }

12.4 修改cookie

只需保证cookie的名和路径一致即可修改
//创建cookie
Cookie ck=new Cookie("code",code);
ck.setPath("/webs");//设置cookie的路径
ck.getMaxAge(-1);//内存存储,取值有三种,>0有效期,=0失效,<0内存存储
response.addCookie(ck);//让浏览器添加cookie
注意:如果改变cookie的name和有效路径会新建cookie,而改变cookie值,有效期会覆盖原有的cookie

12.5Cookie编码与解码

Cookie默认不支持中文,只能包含ASCII字符,所以cookie需要对Unicode字符进行编码,否则会出现乱码。
    编码可以使用java.net.URLEncoder类的encodes(String str,String encoding)方法
    解码使用java.net.URLDecoder类的decode(String str,string encoding)方法

12.5.1创建带中文的cookie

//使用中文的Cookie,name与value都使用UTF-8编码
Cookie cookie=new Cookie(
    URLEncoder.encode("姓名","UTF-8"),
    URLEncoder.encode("姓名","UTF-8"));
//发送到客户端
response.addCookie(cookie);

12.6Cookie的优点和缺点

优点

1.可以配置到期规则
2.简单性:Cookie是一种基于文本的轻量级结构,包含简单的键值对
3.数据持久性:Cookie默认在过期之前是可以一直存在客户端浏览器上的。

缺点

1.大小受到限制:大多数浏览器对于cookie的大小有4k,8k字节的限制
2.用户配置为禁用:有些客户禁用了了浏览器或客户端接收cookie的能力,因此限制了这一功能。
3.潜在安全风险:cookie可能会被篡改。会对安全性造成潜在风险或者导致依赖cookie的应用程序失败。

十三、Session对象【重点】

13.1Session概述

session用于记录用户的状态。session指的是在一段时间内,单个客户端与web服务器的一连串相关的交互过程。
在一个session中,客户可能会多次访问同一个资源,也有可能请求访问不同的服务器资源。

13.2Session原理

服务器会为每一次会话分配一个session对象
同一个浏览器发起的多次请求,同属于一次会话(Session)
首次使用到Session时,服务器会自动创建Session,并创建Cookie存储SessionId发送会客户端
注意:session是由服务端创建的。

13.3 Session使用

Session作用域:拥有存储数据的空间,作用范围是一次会话有效
    一次会话是使用同一个浏览器发送的多次请求,一旦浏览器关闭,则会话结束
    可以将数据存入Session中,在一次会话的任意位置进行获取
    可以传递任何数据(基本数据类型、对象、集合、数组)

13.3.1获取session

//获取Session对象
HttpSession session =request.getSession();
System.out.println("Id"+session.getId());//唯一标记

13.3.2 Session保存数据

setAttribute(属性,Object)保存数据到session中
session.setAttibute("key",value);//以键值对形式存储在session作用域中。

13.3.3Session获取数据

getArribute(属性);获取session中数据

getArrtibute("key");//通过String类型的key访问Object类型的value

13.3.4 Session移除数据

removeAttribute(属性名);从session中删除数据
session.removeAttribute("key");//通过键移除session作用域中的值

13.4Session和Request应用的区别

request是一次请求,请求改变,则request改变
session是一次会话有效,浏览器改变,则session改变

13.5 Session的生命周期

开始:第一次使用到Session的请求产生很,则创建Session
结束:
    浏览器关闭,则失效
    Session超时,则失效
        session.setMaxInactiveInterval(seconds);//设置最大有效时间(单位:秒)
    手工销毁,则失效
        session.invalidate();//deng'l

13.5.1 Session失效

session.setMaxInactiveInterval(60*60);//设置session的最大有效期
session.invalidate();//手工销毁

13.6 浏览器禁用Cookie解决方案【了解】

13.6.1浏览器禁用cookie的后果

服务器在默认的情况下,会使用Cookie的方式将seeionID发送给浏览器,如果用户禁用cookie,则sessionID不会被浏览器保存,此时,服务器可以使用URL重写的方式来发送sessionID。

13.6.2 URL重写

response.encodeRedirectURL(String url)生成重写的URL。
HttpSession session =request.getSession();
//重写URL追加SessionID
String newUrl=response.encodeRedirectURL("/WebProject_war_exploded/rs");
System.out.printIn(newUrl);
response.sendRedirect(newUrl2);

十四、ServletContext对象【重点】

14.1 ServletContext概述

全局对象,也拥有作用域,对应一个Tomcat中的web应用
当Web服务器启动时,会为每一个web应用程序创建一块共享区域(ServletContext)。
ServletContext在web服务器启动时创建,服务器关闭的时销毁。

14.2 获取ServletContext对象

GenericServlet提供了getServletContext()方法。(推荐) this.getServletContext();
HttpServletRequest提供了getServletContext()方法。(推荐)
HttpSession提供了getServletContext()方法

14.3 ServletContext作用

14.3.1 获取项目真实路径

获取当前项目在服务器发布的真实路径
String realpath =servletContext.getRealPath("/");

14.3.2 获取项目上下文路径

获取当前项目上下文路径(应用程序名称)
System.out.printIn(servletContext.getContextPath());//上下文路径(应用程序名称)
System.out.printIn(request.getContexPath());

14.3.3全局容器

ServletContext拥有作用域,可以存储数据到全局容器中
    存储数据:servletContext.setAttribute("name",value);
    获取数据:servletContext.getAttribute("name");
    移除数据:servletContext.removeAttribute("name");

14.4 ServletContext特点

唯一性:一个应用对应一个ServletContext
生命周期:只有容器不关闭或者应用不卸载,ServletContext就一直在。

14.5 ServletContext应用场景

ServletContext统计当前项目访问次数
package com.qf.counter;
​
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
​
/**
 * @X-PENG-7 2023/4/21
 * WebProject
 */
@WebServlet(name = "CounterController", value = "/counterController")
public class CounterController extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.获取ServletContext对象
        ServletContext servletContext = req.getServletContext();
        //2.获取计数器
        Integer counter = (Integer) servletContext.getAttribute("counter");
        if (counter == null) {
            counter = 1;
            servletContext.setAttribute("counter", counter);
        } else {
            counter++;
            servletContext.setAttribute("counter", counter);
        }
        System.out.println("counter" + counter);
    }
​
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }
}

14.6 作用域总结

HttpServletRequest:一次请求,请求响应之前有效
HttpSession:一次会话开始,浏览器不关闭或不超时之前有效
ServletContext: 服务器启动开始,服务器停止之前有效

十五、过滤器【重点】

15.1 现有问题

在以往的Servlet中,没有冗余的代码,多个Servlet都要进行编写。

15.2 概念

过滤器(Filter)是处于客户端与服务器目标资源之间的一道过滤技术。

15.3 过滤器作用

执行地位在Servlet之前,客户端发送请求时,会先经过Filter,再到达目标Servlet中,响应时,会根据执行流程再次  反向执行Filter
可以解决多个Servlet共享代码事务冗余问题(例如:乱码处理,登录验证)

15.4 编写过滤器

Servlet API中提供一个Filter接口,开发人员编写一个Java类实现了这个接口即可,这个Java类称为过滤器(Filter)

15.4.1实现过程

1.编写Java类实现Filter接口
2.在doFilter方法中编写拦截逻辑
3.设置拦截路径

15.5 过滤器配置

15.5.1注解配置

在自定义的Filter类上使用注解@WebFilter(value="/过滤目标资源")

15.5.2 xml配置

  
  <!--过滤器的xml配置-->
    <filter>
        <!--名称-->
        <filter-name>sf</filter-name>
        <!--过滤器全称-->
        <filter-class>com.qf.filter.MyFilter</filter-class>
    </filter>
    <!--映射路径配置-->
    <filter-mapping>
        <!--名称-->
        <filter-name>sf</filter-name>
        <!--过滤的url匹配规则和Servlet类似-->
        <url-pattern>/*</url-pattern>
    </filter-mapping>

15.5.3 过滤器路径

过滤器的过滤路径通常有三种形式:
精确过滤匹配,比如/index.jsp   /myservlet
后缀过滤匹配, 比如*.jsp、*.html、*.jpg
通配符过滤匹配/*,表示拦截所有。注意过滤器不能使用/匹配。
  /aaa/bbb/* 允许

15.6过滤器链和优先级

15.6.1过滤链

客户端对服务器请求之后,服务器调用Servlet之前会执行一组过滤器(多个过滤器),那么这组过滤器就称一条过滤器链。
每个过滤器实现某个特定的功能,当第一个Filter的doFilter方法被调用,Web服务器会创建一个代表Filter链的FilterChain对象传递给该方法。在doFilter方法中,开发人员如果调用了FilterChain对象的doFilter方法,则Web服务器会检查FilterChain对象中是否还有Filter,如果有,则调用第2个filter,如果没有,则调用目标资源。

 

15.6.2 过滤器优先级

在一个Web应用中,可以开发编写多个Filter,这些Filter组合称之为一个Filter链。优先级:
    如果为注解的话,是按照类全名称的字符串顺序决定作用顺序
    如果web.xml,按照filter-mapping注册顺序,从上往下
    web.xml配置高于注解方式
    如果注解和web.xml同时配置,会创建多个过滤器对象,造成过滤多次。

15.7 过滤器典型应用

15.7.1 过滤器解决编码

package com.qf.filter;
​
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
​
/**
 * @X-PENG-7 2023/4/21
 * WebProject
 */
@WebFilter(value = "/*")
public class EncodingFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
​
    }
​
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //统一请求和响应的乱码
        servletRequest.setCharacterEncoding("UTF-8");
        servletResponse.setContentType("text/html;charset=utf-8");
​
        filterChain.doFilter(servletRequest, servletResponse);
    }
​
    @Override
    public void destroy() {
​
    }
}
​

15.7.2 权限验证

ShowAllAdminController
package com.qf.servletProject.servlet.controller;

import com.qf.servletProject.entity.Admin;
import com.qf.servletProject.entity.Manager;
import com.qf.servletProject.service.AdminService;
import com.qf.servletProject.service.impl.AdminServiceImpl;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.List;

@WebServlet(value = "/showallcontroller")
public class ShowAllAdminController extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//        //通过HttpSession完成权限控制
//        HttpSession session = req.getSession();
//        Manager mgr  =(Manager)session.getAttribute("mgr");
//        if(mgr !=null){
            //只负责调用业务逻辑功能
            AdminService adminService = new AdminServiceImpl();

            List<Admin> adminList = adminService.showAllAdmin();

            //request作用域存储数据
            req.setAttribute("admins",adminList);
            //通过转发 跳转到显示结果servlet
            req.getRequestDispatcher("/showalljsp").forward(req,resp);
//        }else{
//            resp.sendRedirect("/WebProject_war_exploded/loginMgr.html");
//        }

    }

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

CheckFilter
package com.qf.servletProject.filter;

import com.qf.servletProject.entity.Manager;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@WebFilter(value = "/showallcontroller")
public class CheckFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //权限验证   验证管理员是否登录!
        //向下转型  拆箱
        HttpServletRequest request = (HttpServletRequest)servletRequest;
        HttpServletResponse response = (HttpServletResponse)servletResponse;
        HttpSession session =request.getSession();
        Manager mgr = (Manager) session.getAttribute("mgr");
        if(mgr!=null){//登录过!
            filterChain.doFilter(request,response);
        }else{
            response.sendRedirect(request.getContextPath()+"/loginMgr.html");
        }

    }

    @Override
    public void destroy() {

    }
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值