Servlet学习笔记(IDEA版本 3万字详解)

Servlet从入门到精通 千锋教育 8h 2020年略旧 (IDEA版本)

image-20240909220826858

一,引言

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

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

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

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

image-20240909221137427

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

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

image-20240909221343301

二,服务器

2.1 概念

2.1.1什么是Web

Web(World Wide Web)称为万维网,简单理解就是网站,它用来表示Internet主机上供外界访问的资源。

Internet上供外界访问的资源分为两大类

  • 静态资源:指Web页面中供人们浏览的数据始终是不变的。(HTML, CSS)
  • 动态资源:指Web页面中供人们浏览的数据是由程序产生的,不同时间点,甚至不同设备访问Web页面看到的内容各不相同。(JSP/Servlet)
  • 在Java中,动态Web资源开发技术我们统称为Java Web.

2.1.2什么是Web服务器

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

2.2 常见服务器

  • 开源:OpenSource(1, 开放源代码 2,免费)
    • Tomcat(主流Web服务器之一,适合初学者)
    • jetty (淘宝,运行效率比Tomcat高)
    • resin (新浪,所有开源服务器软件中,运行效率是最高的)
    • 三者的用法从代码角度完全相同,只有在开启,关闭服务器软件时对应的命令稍有区别。掌握一个即掌握所有
  • 收费
    • WebLogic(Oracle)
    • WebSphere(IBM)
    • 提供响应的服务与支持,软件大,耗资源

2.3 Tomcat服务器

Tomcat是Apache 软件基金会(Apache software Foundation) 的 Jakarta项目中的一个核心项目,免费开源,并支持Servlet和JSP规范,目前Tomcat最新版为9.0

Tomcat技术先进,性能稳定,深受Java爱好者喜爱并得到了部分软件开发商的认可,成为目前较为流行的Web应用服务器。

2.4 Tomcat安装(推荐看别的博客!!!)

2.4.1下载

​ 略。。。。。

2.4.2 解压安装

将Tomcat解压到一个没有特殊符号的目录中(一般纯英文即可)。

注意

  • 不建议放在中文路径下
  • 不建议将服务器软件放在磁盘层次很多的文件夹

2.4.3 Tomcat目录结构

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

2.5 Tomcat启动和停止

2.5.1启动

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

image-20240909225134845

2.5.2 验证

打开浏览器,输入 http://localhost:8080

如果出现以下界面证明Tomcat启动成功

image-20240909225630616

2.5.3 停止

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

2.5.4 修改端口号

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

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

[!warning]

修改端口号需要重新启动Tomcat才能生效

2.6 项目部署及访问静态资源

Tomcat是Web服务器,我们的项目应用是部署在webapps下,然后通过特定的URL访问

2.6.1创建项目

  • 在webapps中建立文件夹(项目应用),比如: myweb
    • 创建WEB_INF文件夹,用于存放项目的核心内容
      • 创建classes, 用于存放jar文件
      • 存放lib, 用于存放jar文件
      • 创建web.xml,项目配置文件(到root项目下的WEB-INF复制即可)
  • 把网页hello.html复制到myweb文件夹中,与WEB-INF在同级目录

image-20240909230742000

2.6.2 URL访问资源

浏览器地址中输入URL: http://localhost:8080/myweb/hello.html

[!tip]

经验:URL主要有4部分组成:协议,主机,端口,资源路径

image-20240909230937283

2.6.3 Tomcat响应流程图

image-20240909230950332

2.7 常见错误

2.7.1 Tomcat闪退

闪退问题是由于JAVA_HOME配置导致的,检查JAVA_HOME配置是否正确

我的是因为没开管理员权限,因为我把Tomcat装在一个只能读的文件里了。。。

2.7.2 404

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

image-20240909231200967

三,Servlet[重点]

3.1 概念

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

3.1.2 Servlet作用

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

3.2 Servlet开发步骤

3.2.1 搭建开发环境

将Servlet相关jar包(lib\servlet-api.jar)配置到classpath中

3.2.2 编写Servlet

  • 实现javax.servlet.Servlet
  • 重写5个主要方法
  • 在核心的service()方法中编写输出语句,打印访问结果
package com.qf.servlet;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.ServletException;
import java.io.IOException;

public class MyServlet imploement Servlet {
    public void init(ServletConfig config) throws ServletException {
        
    }
    public void service(ServletRequest request, ServletResponse response) throws ServletExcepiton, IOEception {
        System.out.println("My First Servlet!");
    }
    public void destory() {
        
    }
    public ServletConfig getServletConfig() {
        return null;
    }
    public String getServletInfo() {
        
    }
}

3.2.3部署Servlet

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

3.2.4 配置Servlet

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

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/xMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaeehttp://xmlns.jcp.org/xml/ns/javaee/web-app-3_1.xsd" version="3.1">
    
<!--1、添加servlet节点-->
<servlet>
    <servlet-name>MyServlet</servlet-name>
    <servlet-class>com.qf.servlet.MyServlet</servlet-class>
</servlet>
    
<!--2、添加servlet-mapping节点-->
<servlet-mapping>
    <servlet-name>MyServlet</servlet-name>
    <url-pattern>/myservlet</url-pattern>
</servlet-mapping>
    
</web-app>    

[!warning]

注意:url-pattern配置的内容就是浏览器地址栏输入的URL中项目名称后资源的内容

3.3 运行测试

启动Tomcat,在浏览器地址栏中输入http://localhost:8080/myweb/myservlet访问,在Tomcat中打印时间表示成功。

3.4 常见错误

3.4.1 500

服务端异常

image-20240909233926817

四,IDEA创建Web

4.1 IDEA创建Web项目

创建项目窗口(供参考**)可以看其他的博客,(Servlet项目构建**)

4.1.2 Web项目目录结构(IDEA版本较旧,适合看其他人的博客!!!)

image-20240910150335353

4.2 IDEA开发Servlet

4.2.1 编写Servlet

编写一个classs类,见上编写Servlet

4.2.2 配置Web.xml

见上面配置Servlet

  • 在Tomcat的webapps目录下,新建WebProject项目文件夹
    • 创建WEB-INF, 存放核心文件
    • 在WEB-INF下,创建classes文件夹,将编译后的MyServlet.class文件复制至此.

[!note]

每当我们编写了新的Servlet或者重新编译,都需要手工将新的.class部署到Tomcat中,较为麻烦,如何实现自动部署

4.2.3 部署Web项目

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

4.3 IDEA部署Web项目(略。可看(Servlet项目构建))

4.3.1 IDEA集成Tomcat

4.3.2 项目部署Tomcat

见4.1

4.4 其他操作

4.4.1关联第三方jar包

  • Global Library 表示所有工程都可以使用
  • Project Library 表示当前工程中所有模块都可以使用
  • Module Library 表示当前模块可以使用

image-20240910221536308

4.4.2如何导出war包

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

点击项目结构

image-20240910221709115

选择Artifacts, 点击+号

image-20240910221827238

选择Archive—>For…

image-20240910221920116

构建项目

image-20240910222008787

在out\artifacts\目录中,查看生产的war包,把war放入Tomcat的webapps目录,启动Tomcat自动解压即可访问

image-20240910222148721

五,Http协议

5.1 什么是HTTP

超文本传输协议(HTTP, HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议,是一个基于请求与响应模式的,无状态的,应用层的协议,运行于TCP协议基础之上.

5.2 Http协议特点

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

5.3 Http协议通信流程

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

image-20240910224401640

5.4 请求报文和响应报文[了解]

http请求报文

当浏览器向Web服务器发出请求时,它向服务器传递了一个数据块,也就是请求信息(请求报文),Http请求信息由4部分组成:

  1. 请求行,请求方法/地址 URL协议/版本

  2. 请求头(Request Header)

  3. 空行

  4. 请求正文

eg:

image-20240910232247011

5.5 状态码

image-20240910232327791

六,Servlet详解[重点]

6.1 Servlet核心接口和类

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

6.1.1 Servlet接口

在Servlet API中最重要的是Servlet接口,所有Servlet都会直接或间接的与该接口发生联系,或是直接实现该接口,或间接继承自实现了该接口的类。

该接口包括以下5个方法:

init(ServletConfig config)
ServletConfig getServletConfig()
service(ServletReauest req.ServletResponse res)
String getServletInfo()
destory()
6.1.2 GenericServlet抽象类

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

image-20240910235918236

6.1.3 HttpServlet类(推荐该种方法,支持协议)

HttpServlet是继承GenericServlet的基础上进一步的扩展

提供将要被子类化以创建适用于Web站点的Http servlet的抽象类。HttpServlet的子类至少必须重写一个方法,该方法通常是以下这些方法之一:

/*
doGet, 如果servlet支持Http get请求
doPost 用于Htup Post请求
doPut 用于Http put请求
doDelete 用于http Delete请求
*/

image-20240910235826206

6.2 Servlet两种创建方式

6.2.1 实现接口
/*
Servlet创建的第一种方式:实现接口Servlet
*/
public class HelloServlet2 implements Servlet {
    
    @Override
    publicvoid destroy(){
    	//ToDo Auto-generated method stub
    }
                       
    @0verride
    public ServletConfig getServletconfig() {
    	//ToDo Auto-generated method stub
    	return null;
    }
    
    @0verride
    public String getServletInfo() {
        //ToDo Auto-generated method stub
        return null;
    }
    
    @0verride
    publicvoid init(ServletConfig argθ) throws ServletException {
    	//ToDo	Auto-generated	method	stub
    }
    
    @0verride
    public void service(ServletRequest request,ServletResponse response)throws
    ServletException,I0Exception {
        //ToDo Auto-generated method stub
        System.out.println("ok");
        response.getwriter().println("welcome use servlet")
    }
}

[!warning]

该方式比较麻烦,需要实现接口中所有方法

6.2.2 继承HttpServlet(推荐)
/**
*Servletimplementation class HelloServlet
*Servlet的第二种创建方式,继承HttpServlet.也是开发中推荐的
*/
public classHelloServletextendsHttpServlet{
    private static final long serialversionuID = 1L;
    
    /**
    * @see HttpServlet#doGet(HttpServletRequest request,HttpServletResponse response)
    */
    
    protected void doGet(HtltpServletRequest request,HttpServletResponse response) throws
    ServletException,I0Exception{
        
   		response.getwriter().print("welcome use servlet");
    }
    /**
    * @see	HttpServlet#doPost(HttpServletRequest request,HttpServletResponse response)
    */
    protected void doPost(HttpServletRequest request,HttpServletResponse response)throws
    ServletExceptionI0Exception{
    	//ToDo	Auto-generated	method	stub
   		doGet(request,response);
    }
}
6.2.3 常见错误

Http Status 404资源找不到.

  • 第一种情况: 地址书写错误
  • 第二种情况: 地址没有问题,把IDEA项目中out目录删除,然后重新运行.
  • Serlvet地址配置重复. both mapped to the url-pattern [/helloservlet] which is not permitted.
  • Serlvet地址配置错误。比如没有写/ Invalid [helloservlet2] in servlet mapping.

6.3 Servlet两种配置方式

6.3.1 使用web.xml (Servlet2.5之前使用)
<?xml version="1.0" encoding="UTF-8"?>
<web-appxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
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>hello2</servlet-name>
    <!--Servlet的全称类名-->
    <servlet-class>com.qf.web.servlet.HelloServlet</servlet-class>
    <!--启动的优先级,数字越小越先起作用-->
    <load-on-startup>1</load-on-startup>
</servlet>
<!--映射配置-->
<servlet-mapping>
<!--名称-->
    <servlet-name>hello2</servlet-name>
    <!--资源的匹配规则:精确匹配T>
    <url-pattern>/hello2</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如果值为正整数或者o时,表示容器在应用启动时就加载并初始化这个servlet,值越小,servlet的优先级越高,就越先被加载。值相同时,容器就会自己选择顺序来加载。
6.3.2 使用注解(Servlet3.0后支持,推荐)
/**
*ServletimplementationclassHelloServlet
*演示Servlet注解式配置
*/
@WebServlet("/hello")
public class HelfoServlet extends HttpServlet {
    private static final long serialversionuID = 1L;
    /**
    *@see HttpServlet#doGet(HttpServletRequest request,HttpServletResponse response)
    */
	protected void doGet(HttpServletRequest request,HttpServletResponse response)throws
ServletException,I0Exception{
    
		response.getWriter().print("oK");
	}
    /*
    *@see HttpServlet#doPost(HttpServletRequest request,HttpServletResponse response)
    */
	protected void doPost(HttpServletRequest request,HttpServletResponse response)throws
ServletExceptionIOException{
        //ToDo	Auto-generated	method stub
        doGet(request,response);
	}
}
6.3.3 @WebServlet注解常用属性
  • name: Serlvet名字(可选)
  • value: 配置url路径,可以配置多个
  • urlPatterns: 配置url路径,和value作用一样,不能同时使用。
  • loadOnStartup: 配置Servlet的创建的时机,如果是0或者正数,如果是0或者正数 启动时程序自动创建,如果是负数,则访问时创建。数字越小优先级越高。

image-20240911095903831

七,Servlet应用[重点]

7.1 request对象

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

image-20240911100000420

7.1.1 get和post区别

get请求

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

post请求

  • get提交的数据会放在URL之后,以?分割URL和传输数据,参数之间以&相连
  • 密文传递数据,数据量大,安全
  • 效率相对没有GET高
  • 对应的Servlet的方法是doPost
7.1.2 request主要方法
String getParameter(String name)根据表单组件名称获取提交数据
void setCharacterEncoding(String charset)指定每个请求的编码
7.1.3 request应用
7.1.3.1 html页面
<!DOCTYPE htm1>
<html>
<head>
<meta charset="UTF-8">
<title>欢迎页面</title>
</head>
<body>
<h1>欢迎你</h1>
<div>
<form action="HelloServlet"method="post">
<label>姓名:</label><input type="text"name="name"><br/>
<label>年龄:</label><inputtype="text"name="age"><br/>
<inputtype="submit”value="提交">
</form>
</div>
</body>
</html>
7.1.3.2 Servlet代码
@WebServlet("/HelloServlet")
public class HelloServlet extends HttpServlet {
	private static final long serialVersionUID=1L;
    
	protected void doGet(HttpServletRequest request,HttpServletResponse response)throws
ServletExcepMionIOException {
    //获取表单提交的姓名
    String name = request.getParameter("name");
    //获取年龄
    String age = request.getParameter("age");
    //服务端输出打印
    System.out.println(request.getRemoteAddr()+"发来信息:姓名:“+name+"---->年龄:"+age);
	protected void doPost(HttpServletRequest request,HttpServletResponse response) throws
ServletException, I0Exception{
		doGet(request,response);
    }
}
7.1.4 get请求收参问题

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

7.1.5get中文乱码

在Tomcat及以下版本,客户端以UTF-8的编码传输数据到服务器,而服务器端的request对象使用的是ISO8859-1这个字符编码来接受数据,服务器和客户端沟通的编码不一致因此才会产生中文乱码的。

解决办法:在接受到数据后,先获取request对象以ISO8859-1字符编码接受到的原始数据的字节数组,然后通过字节数组以指定的编码构建字符串,解决乱码问题。

Tomcat的版本中get方式不会出现乱码了,因为服务器对url的编码格式可以进行自动转换.

解决办法(Tomcat7及以前版本)
/*
* ServletimplementationclassHelloServlet
* 演示Servlet的GET请求,中文乱码的问题
*/
@WebServlet("/GETServlet")
publicclass GetServletextends HttpServlet{
    
	private static final long serialversionuID = 1L;
    
	protectedvoid doGet(Http$ervletRequest request,HttpServletResponse response)throws
ServletException,I0Exception {
        //获取表单提交的姓名
        String name = request.getParameter("name");
        name = new String(name.getBytes("IS08859-1"),"UTF-8");
        //获取年龄
        String age = request.getParameter("age");
        //服务端输出打印
        System.out.println(request.getRemoteAddr()+"发来信息:姓名:"+name+"---->年龄:"+age);
	}
    protected void doPost(HttpServletRequest request,HttpServletResponse response)throws
    ServletExceptionI0Exception{
    	doGet(request,response)
    }
}
7.1.6 post中文乱码

由于客户端是以UTF-8字符编码将表单数据传输到服务器端的,因此服务器也需要设置以UTF-8字符编码进行接受。

解决方案:使用从ServletRequest接口继承而来的setCharacterEncoding(charset)方法进行统一的编码设置。

解决Post中文乱码代码如下
/**
* Servlet implementation class HelloServlet
* 演示Servlet的GET请求,中文乱码的问题
*
*/
@WebServlet("/GETServlet")
public class GetServlet extends HttpServlet {
    
	private static final long serialVersionuID = 1L;
    
    protected void doGet(HttpServletRequest request,HttpServletResponse response)throws
    ServletExceptionI0Exception{
        
    }
    
    protected void doPost(HttpServletRequest request,HttpServletResponse response)throws
    ServletExceptionI0Exception{

        //设置请求参数的编码格式--对GET无效
        request.setCharacterEncoding("UTF-8");

        //获取表单提交的信息
        String name=request.getParameter("msg");

        //服务端输出打印
        System.out.println(request.getRemoteAddr()+"发来信息:"+msg);
    }
}

image-20240911134852491

7.2 response对象

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

7.2.1 response主要方法

setHeader(name, value) 设置响应信息头

setContentType(String) 设置响应文件类型,响应式的编码格式

setCharacterEncoding(String) 设置服务端响应内容编码格式

getWriter() 获取字符输出流

案例:使用response对象向浏览器输出html内容,实现用户登录后,输出Login Success

//获取请求参数代码省略
//获取输出流
PrintWriter out = response.getWriter(;
out.println("<html>");
out.println("<head><title>login</title></head>");
out.println("<body>");
out.println("<h1>Login Success!!!</h1>");
//out.println("<h1>登录成功!!!</h1>");
out.println("</body>");
out.println("</html>";

[!caution]

如果输出内容包含中文,则出现乱码,因为服务器默认采用ISO8859-1编码响应内容

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)(记得try catch finally)

  • 要求:实现登录功能,展示所有用户功能
  • 以下仅仅展示关键代码
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
) charset=utf8;

导入jar包(数据库连接,druid连接池和tomcat)

image-20240911143734292

image-20240911143948314

数据库资源配置

image-20240911144049459

7.3.2 DBUtils

在com.qf下新建servletProject.utils包,新建DbUtils类

image-20240911144222503

image-20240911144517325

connection.commit() 改为connection.rollback()

image-20240911144654909

image-20240911144829328

servletProject 下新建entity包,包下新建Admin类

image-20240911145005072

7.3.3 Daolmpl

servletProject下新建dao包,dao包下新建接口

image-20240911145126078

dao包下新建impl包,包下新建一个类实现AdminDao接口

image-20240911145409711

7.3.4 Servicelmpl

servletProject下新建service包,service包创建AdminService接口

image-20240911145645693

在service包下新建impl包,impl包创建AdminServicelmpl类以实现AdminService接口

image-20240911150010913

7.3.6 LoginServlet

在servletProject中创建新包servlet, 在servlet后新建LoginServlet类(记得打上注解)

image-20240911150422055

image-20240911150727567

7.3.5 HTML页面代码

web包下新建html界面login

image-20240911150924031

7.3.7 ShowAllAdminServlet

在servlet包下新建ShowAllAdminServlet类

image-20240911152149187

八,重定向和转发

8.1现有问题

在之前案例中,调用业务逻辑和显示结果页面都在同一个Servlet里,就会产生设计问题

  • 不符合单一职能原则,各司其职的思想
  • 不利于后续的维护

因该将业务逻辑和显示结果分离开

image-20240911152608947

image-20240911153206912

[!warning]

  • 业务逻辑和显示结果分离后,如何跳转到显示结果的Servlet?

  • 业务逻辑得到的数据结果如何传递给显示结果的Servlet?

8.1.1 业务,显示分离

在servlet创建ShowAllAdminController类

image-20240911153043184

在servlet中创建ShowAllAdminJSP类**(只显示结果)**

8.2 转发

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

8.2.1 页面跳转

在调用业务逻辑的Servlet中,编写以下代码

  • request.getRequestDispatcher("/目标URL-pattern").forward(request, response);

[!caution]

使用forward跳转时,是在服务器内部跳转,地址栏不发生变化,属于同一次请求。

image-20240911193312788

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

[!warning]

URI: 统一资源标识符(Uniform Resource Identifier), 用来表示服务器中定位一个资源,资源在web项目中的路径(/project/source)

image-20240911195519952

8.3.2 数据传递

sendRedirect跳转时,地址栏改变,代表客户端重新发送的请求。属于两次请求

  • response没有作用域,两次request请求中的数据无法共享
  • 传递数据:通过uRi的拼接进行数据传递(/WebProject/b?username=tom");
  • 获取数据:request.getParameter(“usermame”);
8.3.3 重定向特点(明文转发,不安全)
  • 重定向是客户端行为。
  • 重定向是浏览器做了至少两次的访问请求。
  • 重定向浏览器地址改变。
  • 重定向两次跳转之间传输的信息会丢失(request范围)。
  • 重定向可以指向任何的资源,包括当前应用程序中的其他资源、同一个站点上的其他应用程序中的资源、
    其他站点的资源。

8.4 转发重定向特点

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

九,Servlet生命周期

9.1 生命周期四个阶段

9.1.1 实例化

当用户第一次访问Servlet时,由容器调用Servlet的构造器创建具体的Servlet对象。也可以在容器启动之后立刻创建实例。使用如下代码可以设置Servlet是否在服务器启动时就创建。
1

  • 注意:只执行一次

9.1.2 初始化

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

  • 注意:init方法只被执行一次

9.1.3 服务

当客户端有一个请求时,容器就会将请求ServletRequest与响应ServletResponse对象转给Servlet,以参数的形式传给service方法。

  • 此方法会执行多次

9.1.4 销毁

当Servlet容器停止或者重新启动都会引起销毁Servlet对象并调用destroy方法。

  • destroy方法执行一次

image-20240911201218278

Servlet代码
/**
* Servlet implementation class LifeServlet
* 演示Servlet的生命周期,
* 1、实例化
* 2、init: 初始化
* 3、service: 服务
* 4、destory:销毁
*/

@WebServlet("/lifeservlet")
public class LifeServlet extends HttpServle t{
    
	private static final 1ong serialVersionuID = 1L;
    
    /**
	* @see HttpServlet#HttpServlet()
	*/
    
	public LifeServlet() {
        super();
        System.out.println("1、完成了实例化";
		//ToDo Auto-generated constructor stub
    }
    
	@0verride
    public void init() throws ServletException {
        // ToDo Auto-generated method stub
        super.init();
        System.out.println("2、完成了初始化");
    }
}

十, Servlet特性

10.1 线程安全问题

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

10.2 如何保证线程安全

  • synchronized
    • 将存在线程安全问题的代码放到同步代码块中
  • 实现SingleThreadModel接口
    • servlet实现SingleThreadModel接口后,每个线程都会创建servlet实例,这样每个客户端请求就不存在共享资源的问题,但是servlet响应客户端请求的效率太低,所以已经淘汰。
  • 尽可能使用局部变量

十一,状态管理

11.1 现有问题

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

11.2 概念

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

11.3 状态管理分类

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

十二,Cookie的使用

12.1 什么是Cookie

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

image-20240911204809073

image-20240911205703360

12.2 创建Cookie

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

chrome浏览器查看cookie信息:chrome://settings/content/cookies

12.3 获取Cookie

创建cookies包,新建cookieServlet类

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

12.4 修改Cookie

只需要保证Cookie的名和路径一致即可修改

// 创建Cookie
Cookie ck = new Cookie("code", code);
ck.setPath("/webs"); // 设置Cookie的路径
ck.setMaxAge(-1); // 内存存储,取值有三种: >0有效期,单位秒:=0失效;<0内存存储
response.addCookie(ck);
  • 注意:如果改变cookie的name和有效路径会新建cookie,而改变cookie值,有效期会覆盖原有cookie

12.5 Cookie编码与解码

Cookie中时不需要出现中文的,只能包含ASCII字符,所以Cookie需要对Unicode字符进行编码,否则会出现乱码。

  • 编码可以使用java.net.URLEncoder类的encode(String str, String encoding)方法
  • 解码使用java.net.URLDecoder类的decode(String str, String encoding)方法
12.5.1 创建带中文Cookie
// 使用中文的Cookie.name与value都使用UTF-8编码.
Cookie cookie = new CookieURLEncoder.encode ("姓名”,"UTF-8"),
	URLEncoder.encode ("老邢",“UTF-8"));
	// 发送到客户端
	response.addCookie(cookie);
12.5.2 读取带中文Cookie
if (request.getCookies() != null) {
	for(Cookie cc:request.getCookies()) {
        String cookieName = URLDecoder.decode(cc.getName(),"UTF-8");
        String cookieValu e= URLDecoder.decode(cc.getValue()"UTF-8");
        out.println(cookieName+"=";
        out.println(cookieValue+";<br/>");
    else{
   	 	out.println("Cookie已经写入客户端.请刷新页面.");
    }

12.6 Cookie优点和缺点

优点

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

缺点

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

十三,Session对象[重点]

13.1 Session概述

[!note]

创建sessions包,包下新建SessionServlet类

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

13.2 Session原理(是由服务端创建的)

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

13.3 Session使用

  • Session作用域:拥有存储数据的空间,作用范围是一次会话有效
    • 一次会话是使用同一浏览器发送的多次请求。一旦浏览器关闭,则结束会话
    • 可以将数据存入Session中,在一次会话的任意位置进行获取
    • 可传递任何数据(基本数据类型、对象、集合、数组)
13.3.1 获取Session
//获取Session对象
HttpSession sessionrequest.getSession();
System.out.println("Id: " + session.getId());//唯一标记,
13.3.2 Session保存数据

setAttribute(属性名, Object)保存数据到session中

session.setAttribute("key", value); // 以键值对形式存储在session作用域中。
13.3.3 Session获取数据

getAttribute(属性名);获取session中数据

session.getAttribute("key");// 通过String类型的key访问Object类型的value
13.3.4 Session移除数据

removeAttribute(属性名);从session中删除数据

session.removeAttribute("key"); // 通过键移除session作用域中的值
13.4 Session与Request应用区别
  • request是一次请求有效,请求改变,则request改变
  • session是一次会话有效,浏览器改变,则session改变
@WebServlet(name = "GetValueServlet", value="/getValue")

public class GetValueServlet extends HttpServlet {
    
    protected void doPost(HttpServletRequest request, HeepServletResponse response) throws ServletException {
        
        // 1.通过request获取session对象
        HttpSession session = request.getSession();
        String s = (String) session.getAttribute("username"));
        
        System.out.println("从session中获得了:" + s);
        System.out.println("从reqeust中获得了:" + password);
    }
    
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}
13.3.5 Session的生命周期
  • 开始:第一次使用到Session的请求产生,则创建Session

  • 结束:

    • 浏览器关闭,则失效
    • Session超时,则失效
      • session.setMaxInactiveInterval(seconds); // 设置最大有效时间(单位:秒)
    • 手工销毁,则失效
      • session.invalidate(); //登录退出,注销
13.3.6 Session失效
session.setMaxInactiveInterval(60 * 60); // 设置sesson最大有效期为一小时

session.invalidate(); // 手工注销

13.4 浏览器禁用Cookie解决方案[了解]

13.4.1 浏览器禁用Cookie的后果

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

13.4.2 URL重写

浏览器在访问服务器上的某个地址时, 不再使用原来的那个地址,而是使用经过改写的地址(即在原来的地址后面加上了sessionID)。

13.4.3 实现URL重写

response.encodeRedirectURL(String url)生成重写的URL。

	HttpSession session = request.getSession();
	// 重写URL追加SessionID
	String newUrl = response.encodeRedirectURL("/WebProject_war_exploder/cd");
	System.out.println(newUrl);

	response.sendRedirect(newUr12);

13.5 Session实战权限验证

image-20240911222747146

13.6 Session实战保存验证码

13.6.1 创建验证码(ValidateCode.jar)
  • 导入ValidateCode.jar

  • 创建生成验证码的Servlet

13.6.2 登录页面
	@WebServlet (name = "CreateCodeController",value = "/createCode")
	public class CreateCodeController extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException {
            
        //1.创建验证码图片
        ValidateCode code = new ValidateCode( width: 200, height: 30, codeCount: 4, lineCount: 20) ;
        String codes = code.getCode();
        HttpSession session = request. getSessionO;
        session. setAttribute( s: "codes", codes);
            
        //2.验证码图片响应给客户端
         code. write (response. getOutputStream ());
    }
        
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}
13.6.3 LoginMgrController

Controller包下新建LoginMgrController类


@WebServlet (name = "LoginMgrController", value = "/loginMgr")

public class LoginMgrController extends HttpServlet {
	protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException
    //1.处理乱码
    request. setCharacterEncoding("UTF-8");
    response. setContentType("text/html;charset=utf-8");
    
    //2.收参
    String username = request. getParameter(s: "username");
     String password = request. getParameter( s: "password");
    String inputVcode = request. getParameter(s: "inputVcode");
    
    String codes = (String) request.getSession().getAttribute("codes");
    if (!inputVcode.isEmpty() && inputVcode.equalsIgnoreCase(code)) {
        
        //3.调用业务方法
        ManagerService managerService = new ManagerServiceImpl();
        Manager mgr = managerService.login(username, password) ;

        //4.处理结果,流程跳转
        if(mgr != nul1){
            //登录成功
            //将管理员信息存储在Session里
            HttpSession session = request. getSession() ;
            session. setAttribute( s:"mgr",mgr);
            // 跳转 目标、方式
            response.sendRedirect("/WebProject_war_exploded/showallcontroller");
        else {
            // 登录失败
            response.sendRedirect("/WebProject_war_exploded/loginMgr.html");
        } else {
            // 登录失败
            response.sendRedirect("/WebProject_war_exploded/loginMgr.html");
        }
    }
    

十四,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.println(servletContext.getContextPath()); //上下文路径(应用程序名称)
System.out.println(request.getContextPath());
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.servlet;

import java.io.IoException;
import java.io.PrintWriter;

import javax.servlet.ServletContext;
importjavax.servlet.ServletException;
importjavax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
*Servlet implementation class Servlet3
*/

@WebServlet (name = "CounterController",value"/counterController")
public class CounterController extends HttpServlet {
        protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException {

        //1.获取ServletContext对象
        ServletContext servletContext = request.getServletContext();

        //2.获取计数器
        Integer counter = (Integer) servletContext.getAttribute(s:"counter");

        if(counter == null) {
            counter = 1;
            servletContext. setAttribute( s: "counter", counter);
        } else {
            counter++;
            servletContext.setAttribute("counter", +counter);
        }
        System.out.println("counter:");                   
    }                   
                           
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException {
        doPost (request, response);
    }
}

@WebServlet (name = "showController",value"/showController")
public class CounterController extends HttpServlet {
        protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException {

        //1.获取ServletContext对象
        ServletContext servletContext = request.getServletContext();

        //2.获取计数器
        Integer counter = (Integer) servletContext.getAttribute(s:"counter");

        if(counter == null) {
            counter = 1;
            servletContext. setAttribute( s: "counter", counter);
        } else {
            counter++;
            servletContext.setAttribute("counter", counter);
        }
        System.out.println("show:" +counter);                   
    }                   
                           
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException {
        doPost (request, response);
    }
}

14.6 作用域总结

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

十五,过滤器[重点]

15.1 现有问题

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

15.2 概念

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

image-20240911235021804

15.3 过滤器作用

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

15.4 如何编写过滤器

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

15.4.1 实现过程
  • 编写Java类实现Filter接口
  • 在doFilter方法中编写拦截逻辑
  • 设置拦截路径
package com.qf.web.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.I0Exception;

/**
*@author wgy2018/11/289:23
*@version 1.0
*/

@WebFilter"/myservlet1")// 过滤路径
public class MyFilter1 implements Filter {
    
    //初始化过滤器
    @Override
    public void init(FilterConfig filterConfig)throws ServletException{
    	System.out.println("过滤器初始化了....init..."+filterConfig);
    }
                     
    //执行过滤
    @Override
    public void doFilter(ServletRequest request,ServletResponse response,FilterChain chain) throws IoException, ServletException {
        System.out.println ("过滤前.doFilter ");
        //放行
        chain.doFilter(request,response);

        System.out.println("过滤后.doFilter");
    }
    
    // 销毁
    @Override
    public void destory() {
        
    }
}

15.5 过滤器配置

15.5.1 注解配置

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

15.5.2 xml配置

在web.xml中进行过滤器的配置

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

15.5.3 关于拦截路径

过滤器的拦截路径通常有三种形式:

精确拦截匹配,比如/index.jsp /myservlet1
后缀拦截匹配,比如*.jsp、*.html、*.jpg
通配符拦截匹配/*,表示拦截所有。注意过滤器不能使用/匹配。
	/aaa/bbb/* 允许

15.6 过滤器链和优先级

15.6.1 过滤器链

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

image-20240912001711215

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.I0Exception;

@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);
    }
                     
    @0verride
    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);
    }
                     
    @0verride
    public void destroy() {
        
    }
}

15.7.2 权限验证

login.jsp页面

<%@ page contentType="text/html;charset=UTF-8"language="java"%>
<html>
<head>
	<title>用户登录</title>
</head>
<body>
	<h2>用户登录</h2>
	<form action="/login"method="post">
	用户名:<input type="text" name="username"><br/>
	密码:<input type="password" name="pwd"><br/>
<inputtype type ="submit" value="登录"> <input type="checkbox" name="auto">自动登录
	</form>
</body>
</html>  

十六, 综合案例(EMS)

16.1 数据库环境搭建

该样例是EMS员工管理系统。使用了两张表

  • EMP员工信息表
  • EmpManager管理员表
16.1.1 创建数据库
create database EMP;
16.1.2 创建数据表
use emp;

create table emp (
	ID int primary key auto_increment,
    NAME varchar(20) not null,
    SALARY double not null,
    AGE int not null
)charset=UTF8;

insert into emp(NAME, salary, age) values('jack', 2000, 16);
insert into emp(NAME, salary, age) values('jack', 3000, 26);
insert into emp(NAME, salary, age) values('jack', 4000, 36);

create table EmpManager (
	username varchar(20) not null,
    password varchar(20) not null
)charset=UTF8;

insert into empManager(username, Passward) values('gavin', '123456');

16.2 创建Web项目

配置Servlet环境并导入相关jar包(Servlet项目构建)IDEA版

image-20240912090234004

16.3 基础环境搭建

数据库相关配置

image-20240912090324813

创建com.qf.emp包,在com.qf.emp包下新建utils(数据库连接工具包),entity(实体包),dao(数据访问层),service(业务逻辑层),controller(业务逻辑),jsp(显示页面)

image-20240912090841664

1.编写数据库连接类(在utils包下新建DbUtils类)

import java.io.InputStream;
import java.sql.Connection;
import java.util.Properties;

public class DbUtils {
    
    private static DruidDataSource ds;
    private static final ThreadLocal<Connection> THREAD_LOCAL = new ThreadLocal<>();
    
    static {
        
    Properties properties = new Properties();
    InputStream is = DbUtils.class.getResourceAsStream(name: "/database.properties");
        
    try {
        properties.load(is);
        ds = (DruidDataSource)) DruidDataSourceFactory.createDataSource(properties); // 强转       
        } catch (IOException e){
       		e.printStackTrace();
   		} catch (Exception e) {
        	e.printStackTrace();
    	}
    }
    
    public static Connection getConnection() {
        Connection connection = THREAD_LOCAL.get();
        try {
        	if(connection == null) {
        		connection = ds.getConnection();
                THREAD_LOCAL.set(connection);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return connection;
    }
        
    public static void begin() {
		Connection connection = null;
		try {
            connection = getConnection();
            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) {
         
		try {
            if(resultSet != null) {
            	resultSet.close();
            }
            if(statement != null) {
                statement.close();
            }
            
            if(connection != null) {
                connection.close();
                THREAD_LOCAL.remove();
            }
        } catch (SQLException e) {
            	e.printStackTrace();
            }
     }              
}

entity实体包下新建EmpManager类

image-20240912093234178

dao数据访问层新建接口(EmpManagerDao)

image-20240912093347073

dao包新建EmpManagerDaolmpl类实现EmpManagerDao接口

package com.qf.emp.dao.impl;

import com.qf.emp.dao.EmpManagerDao;
import com.qf.emp.entity.EmpManager;
import org.apache.commons.dbutils.QueryRunner;

public class EmpManagerDaoImpl implements EmpManagerDao {
    
    private QueryRunner queryRunner = new QueryRunner();
    
    @Override
    public EmpManager select(String username) {
        try {
        	EmpNanager empManager = queryRunner.query(DbUtilsgetConnection(), "select * from empmanager where username = ?", new BeanHandle<EmpManager>(EmpManager.class), username); 
            return empManager;
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }
}

service(业务逻辑层)新建接口

image-20240912094029257

service(业务逻辑层)新建impl包,impl包下新建EmpManagerServicelmpl类

image-20240912094228303

controller包下新建EmpManagerLoginController类


@WebServlet (name = "EmpManagerLoginController",value="/manager/EmpManagerLoginController")
public class EmpManagerLoginController extends HttpServlet {
	protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException {
        // 1.收参
        String username = request.getParameter( s:"username");
        String password = request.getParameter(s:"password");
        String inputVcode = request.getParameter(s:"inputVcode");
        
        // 校验验证码
        String codes = (String) request.getSession().getAttribute(s: "codes") 
        if(!inputVcode.isEmpty() && inputVcode.equalsIgnoreCase(codes)){
       		//调用业务逻辑实现登录
            EmpManagerService empManagerService = new EmpManagerServiceImpl();
            EmpManager empManager = empManagerService.login(username,password);
        	if (empManager != null) {
                
                //登录成功
                //存储在session作用域
                HttpSession session = request.getSession() ;
                Session.setAttribute("empManager",empManager) ;
                
                //跳转到查询所有的controller
                response.sendRedirect(request.getContextPath()+"//showAllEmpController") ;
            } else {
                response.sendRedirect(request.getContextPath()+"/login.html");
            } else {
                //验证码输入错误,跳转到登录页面
                response.sendRedirect( S: request.getContextPath() +"/login.html");
            }
    }
    
	protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException {
        doPost(request, response);
    }
}

controller包下新建CreateCodeController,使用验证码登录


@WebServlet(name = "CreateCodeController",value = "/createCode")
public class CreateCodeController extends HttpServlet {
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException {
        ValidateCode validateCode = new ValidateCode(200, 30, 4, 20);
        String codes = validateCode.getCode();
        HttpSession session = request.getSession();
        session.setAttribute("codes", codes);
    }
    
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException {
        doPost(request, response);
    }
}

controller包下新建ShowAllEmpController类

@WebServlet (name = "ShowAllEmpController", value = "/manager/safe/showAllEmpController")
public class ShowAllEmpController extends HttpServlet {
    
    protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException {
        
        EmpService empService = new EmpServiceImpl();
        List<Emp> empss = empService.showAllEmp() ;

        request.setAttribute("emps", emps) ;
        request.getRequestDispatcher(s: "/manager/safe/showAllEmpJSP").forward(request,response);
    }
    
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException {
        doPost(request, response);
    }
    
}

web包下新建html(登录页面)

image-20240912100255429

entity实体类下新建Emp类

image-20240912100432881

dao下新建接口EmpDao

public interface EmpDao {
    public List<Emp> selectAll();
}

impl下新建EmpDaoImpl类实现EmpDao接口

import com.qf.emp.dao.EmpDao;
import com.qf.emp.entity.Emp;
import com.qf.emp.utils.DbUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;

import java.sql.SQLException;
import java.util.List;

public class EmpDaoImpl implements EmpDao {
    private QueryRunner queryRunner = new QueryRunner();
    @Override
    public List<Emp> selectAll() {
        try {
        	List<Emp>emps = queryRunner.query(DbUtils.getConnection(), "select * from emp ;",new BeanListHandler<Emp> (Emp.class));
        	return emps;
        } catch (SQLException e) {
        	e.printStackTrace();
        	return null;
        }
    }
}                                

service创建一个接口EmpService

public interface EmpService {
    public List<Emp> showAllEmp();
}

service(业务逻辑层)imp下,新建EmpServicelmpl类实现那EmpService接口

public class EmpServiceImpl implements EmpService {
    private EmpDao empDao = new EmpDaoImpl();
    @Override
    public List<Emp> showAllEmp() {
        List<Emp> emps = new ArrayList<>();
        try {
            DbUtils.begin();
            List<Emp> temps = empDao.selectAll();
            if(temps != null) {
            	emps = temps;
            }
            DbUtils.commit();
    	} catch (Exception e) {
        	DbUtils.rollback();
    		e.printStackTrace();
		}
    
    	return emps;
    }
    
}

新建包filter, filter包下新建CheckFilter类

image-20240912102346828

jsp下新建ShowAllEmpController类

image-20240912102657465

image-20240912104721226

filter下新建EncodingFilter类

image-20240912102609399

后面的内容建议实操,不然的话写出来就太乱了!!!预估完全消化得花3-4小时,小提一句这个小案例老师讲的非常棒!!。

共勉!!!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值