一、web服务器
1. 常见web服务器
Tomcat:由Apache组织提供的一种Web服务器,提供对jsp和Servlet的支持。它是一种轻量级的javaWeb容器(服务器),也是当前应用最广的JavaWeb服务器(免费)。
Jboss:是一个遵从JavaEE规范的、开放源代码的、纯Java的EJB服务器,它支持所有的JavaEE规范(免费)。
GlassFish: 由Oracle公司开发的一款JavaWeb服务器,是一款强健的商业服务器,达到产品级质量(应用很少,收费)。
Resin:是CAUCHO公司的产品,是一个非常流行的应用服务器 的支持,性能也比较优良,resin自身采用JAVA语言开发(收费,应用比较多)。
WebLogic:是Oracle公司的产品,是目前应用最广泛的Web服务器,支持JavaEE规范,而且不断的完善以适应新的开发要求,适合大型项目(收费,用的不多,适合大公司)。
2. web服务器简介
(1)web服务器 底层是 基于tcp协议封装 http协议实现、springboot框架 底层内嵌入我们的 Tomcat服
(2)web服务器是一个应用程序(软件),对http协议的进行封装,让web开发更加便捷。
手写http服务器框架,底层是基于socket tcp实现。
二、 Apache Tomcat服务器
1. Tomcat服务器简介
(1)tomcat下载地址:Apache Tomcat® - Apache Tomcat 10 Software Downloads
(2)Apache Tomcat最早是由Sun Microsystems开发的一个Servlet容器,在1999年被捐献给ASF(Apache Software Foundation),隶属于Jakarta项目,现在已经独立为一个顶级项目。Tomcat主要实现了Java EE中的Servlet、JSP规范,同时也提供HTTP服务,是市场上非常流行的Java Web容器。
2. Tomcat服务器基本使用
(1)bin(文件夹)例如启动tomcat 或者停止tomcat --------可执行文件
*.bat---运行在windows批处理文件
*.sh-----linux环境中运行文件
startup.bat ----启动tomcat
shutdown.bat---停止tomcat
如果tomcat启动成功之后 tomcat控制台界面 是不会停止的。
如果tomcat启动失败的话,则tomcat控制台界面会闪退。
tomcat 启动之后默认端口号码:8080
tomcat欢迎界面。
(2)conf 存放全局配置文件 修改tomcat启动端口号码
logging.properties
(3)webapps 存放运行程序 部署war包、jar包、静态资源。
http://127.0.0.1:8080/mayikt/ 默认就是查找tomcat webapps 目录中
mayikt文件夹中 index.html
3. Tomcat文件目录介绍
(1)bin:主要存放tomcat的操作命令,根据操作系统可以分为两大类:一是以.bat结尾(Windows);二是以.sh结尾(Linux)。比如可以通过startup启动,shutdown关闭Tomcat。
(2)conf:全局配置文件
一个策略文件:catalina.policy 定义了安全策略。
两个属性文件:catalina.properties 和 logging.properties 。
四个XML配置文件:
server.xml:Tomcat的主要配置文件,配置整个服务器信息,如修改连接器端口号(默认为8080)。不能动态重加载,文件修改之后必须重启服务器才能生效。
web.xml:全局的web应用程序部署描述文件,如可以设置tomcat支持的文件类型。
context.xml:Tomcat的一些特定配置项,针对所有应用程序生效。
tomcat-users.xml:配置Tomcat的用户名、密码,管理身份验证以及访问控制权限。
(3)lib:Tomcat运行依赖的一些Jar文件,比如常见的servlet-api.jar、jsp-api.jar。所有的应用程序可用,可以放置一些公用的Jar文件,如MySQL JDBC驱动(mysql-connector-java-5.1.{xx}-bin.jar)。
(4)logs:运行中产生的日志文件。包含引擎(engine)日志文件 Catalina.{yyyy-mm-dd}.log,主机日志文件localhost.{yyyy-mm-dd}.log,以及一些其他应用日志文件如manager、host-manager。访问日志也保存在此目录下。
(5)temp:临时文件目录,清空不会影响Tomcat运行
(6)webapps:默认的应用程序根目录,Tomcat启动时会自动加载该目录下的应用程序,可以以文件夹、war包、jar包的形式发布(启动时会自动解压成相应的文件夹)。也可以把应用程序放置在其他路径下,需要在文件中配置路径映射。
(7)work:用来存放tomcat在运行时的编译后文件,如JSP编译后的文件。清空work目录,然后重启tomcat,可以达到清除存的作用。
bin:可以执行文件。
conf:tomcat服务器的配置文件
lib:tomcat启动后需要依赖的jar包
logs:tomcat工作之后的日志文件
webapps:是tomcat部署工程的目录。
work:jsp文件在被翻译之后,保存在当前这个目录下,session对象被序列化之后保存的位置
tomcat下载:
📎apache-tomcat-10.0.20-windows-x64.zip
双击启动:startup.bat
访问:http://127.0.0.1:8080/
注意 :tomcat解压安装位置 不要带中文、不要带任何空格路径。纯英文路径下运行tomcat。
4. 启动tomcat常见问题
(1)启动tomcat控制台乱码
双击启动:startup.bat
D:\path\Tomcat\tomcat10\apache-tomcat-10.0.20-windows-x64\apache-tomcat-10.0.20\conf
logging.properties
删除掉,在启动就好了。
(2)启动tomcat闪退问题
启动tomcat直接闪退,注意检查下jdk安装的环境变量
5. 如何关闭Tomcat服务器
第一种:Ctrl+C键 关闭Tomcat服务器
第二种:点击Tomcat窗口的右上角关闭按钮 (暴力停止服务器)
第三种:找到tomcat目录/shutdown.bat文件,双击执行关闭Tomcat。
发生启动tomcat服务器直接闪退----说明jdk环境没有好
6. Tomcat服务器配置
修改端口号码
1.找到tomcat目录/conf/server.xml
2.修改port的值,将port端口的值修改为80
7. Tomcat服务器部署项目
方式1:直接在tomcat webapps 目录创建一个文件夹
方式2:在tomcat目录/conf/server.xml 配置
127.0.0.1:8080/mayikt----D:\mayikt目录中查找info.html
host标签中:
<Context path="/mayikt" docBase="D:\mayikt"/>
<Context path=”浏览器要访问的目录---虚拟目录” docBase=网站所在磁盘目录”/>
方式3:将项目打成war包 放入到tomcat webapps目录中 自动解压
方式4:webapps目录下/ROOT工程的访问
当我们在浏览器中直接输入http://ip地址:端口号 那么 默认访问的是Tomcat目录/webapps/ROOT目录如果webapps下面有一个ROOT的项目。那么在访问的时候,直接可以省略项目的名字/ 表示找到root目录
----tomcat欢迎页面部署 ----webapps root 目录中
8. Tomcat web开发项目结构
(1)idea 先创建一个普通java项目
(2)在将该java项目 变成web项目
(3)整合tomcat
idea创建web项目
(1)选择创建项目
(2)创建java项目
(3)填写项目名称
(4)新增 add framework support
(5)选择web application
(6)多了web-inf文件夹
(7)新增tomcat
(8)点击新增tomcat
(9)选择tomcat server
(10)添加tomcat 路径
(11)添加当前java项目
(12)点击运行项目
(13)自动弹出界面
9. web项目目录结构说明
web项目结构
src------java代码 核心的配置文件(例如 spring配置文件等) servlet
web-----静态资源 或者jsp等
html--html、js、css、images等 静态资源 外部都可以直接访问的。
web-inf ------外界是无法访问的。
web.xml------servlet相关配置
index.jsp
三、servlet
1. 什么是servlet
Servlet定义:Servlet是基于Java技术的Web组件,由容器管理并产生动态的内容。Servlet与客户端通过Servlet容器实现的请求/响应模型进行交互。
springmvc----底层基于Servlet
演示代码:
http://localhost:8081/mayikt_tomcat04_war_exploded/mayikt?userName=mayikt
package com.mayikt.servlet;
import jakarta.servlet.*;
import jakarta.servlet.annotation.WebServlet;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet("/mayikt")
public class IndexServlet 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 {
String userName = servletRequest.getParameter("userName");
servletResponse.setContentType("text/html;charset=utf-8");
PrintWriter writer = servletResponse.getWriter();
if ("mayikt".equals(userName)) {
writer.println("可以访问");
} else {
writer.println("无法访问");
}
writer.close();
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
2. servlet 环境搭建
(1)在我们的项目中创建libs目录存放第三方的jar包
(2)项目中导入servlet-api.jar libs目录中
就在我们tomcat安装的目录 中 lib 目录中
servlet-api.jar 讲完课之后上传到 文档中可以直接下载
(3)创建servlet包 专门存放就是我们的servlet
(4)创建IndexServlet 实现Servlet 重写方法
(5)IndexServlet 类上加上@WebServlet("/mayikt")注解定义 URL访问的路径
(6)重写Servlet 类中service 在service中编写 动态资源
package com.mayikt.servlet;
import jakarta.servlet.*;
import jakarta.servlet.annotation.WebServlet;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet("/mayikt")
public class IndexServlet implements Servlet {
/**
* @param servletConfig
* @throws ServletException
*/
@Override
public void init(ServletConfig servletConfig) throws ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
/**
* tomcat启动完成
* 127.0.0.1:8080/项目名称/mayikt 执行 service 通过service方法获取servletRequest、servletResponse
*
* @param servletRequest
* @param servletResponse
* @throws ServletException
* @throws IOException
*/
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("mayikt644");
// 需要通过servletRequest对象获取到客户端传递参数到服务器端
String userName = servletRequest.getParameter("userName");
PrintWriter writer = servletResponse.getWriter();
if ("mayikt".equals(userName)) {
// 返回数据 ok
writer.println("ok");
} else {
// fail
writer.println("fail");
}
writer.close();// 关闭资源
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
3. servlet debug调试
养成习惯 学会通过 debug模式 运行项目---非常重要
f8---下一步
f9---跳到下一个断点
4. servlet 执行流程
注意:servleturl 映射路径不要重复!
(1)servlet是由我们的 web服务器(tomcat)创建、该方法是由我们的 web服务器(tomcat)调用
断点分析
(2)tomcat服务器执行到servlet中的service方法,是因为我们创建的servlet实现httpservlet接口 重写了service方法
5. servlet 生命周期(重点)
(1)创建servlet
选择创建servlet :
如果是第一次访问servlet 才会创建servlet ---优点
第一次访问到servlet (单例模式) 线程安全问题
先创建servlet
在执行service方法
该servlet 创建好了以后 在jvm内存中只会存在一份。
如果是第二次访问servlet
在执行service方法
提前创建servlet
或者当你第一次访问servlet 创建servlet 对象
提前创建servlet ----优点可以 第一次访问的时候就不需要创建
servlet 对象可以提高效率、但是 项目启动时提前创建servlet
这样就会导致tomcat启动变得比较慢了。 浪费内存---
创建Servlet实例
web容器负责加载Servlet,当web容器启动时或者是在第一次使用这个Servlet时,容器会负责创建Servlet实例,但是用户必须通过部署描述符(web.xml)指定Servlet的位置,或者在类上加上@WebServlet,成功加载后,web容器会通过反射的方式对Servlet进行实例化。
@WebServlet(urlPatterns = "/mayiktmeite",loadOnStartup = 1)
负数---第一次被访问时创建Servlet对象 @WebServlet(urlPatterns = "/mayiktmeite",loadOnStartup = -1)
0或者正数:服务器启动时创建Servlet对象 数字越小优先级越高
MeiteServlet loadOnStartup = 1
YushengjunServlet loadOnStartup = 2
底层会根据loadOnStartup (从0开始)值排序 越小越优先加载创建
(2)执行servlet类中init---初始化方法
当我们的servlet类被创建时,执行servlet类初始化方法init 代码初始化
该方法只会执行一次。
WEB容器调用Servlet的init()方法,对Servlet进行初始化
在Servlet实例化之后,Servlet容器会调用init()方法,来初始化该对象,
主要是为了让Servlet对象在处理客户请求前可以完成一些初始化的工作,
例如,建立数据库的连接,获取配置信息等。对于每一个Servlet实例,init()方法只能被调用一次。
init()方法有一个类型为ServletConfig的参数,Servlet容器通过这个参数向Servlet传递配置信息。
Servlet使用ServletConfig对象从Web应用程序的配置信息中获取以名-值对形式提供的初始化参数。
另外,在Servlet中,还可以通过ServletConfig对象获取描述Servlet运行环境的ServletContext对象,
使用该对象,Servlet可以和它的Servlet容器进行通信。无论有多少客户机访问Servlet,
都不会重复执行init()。
(3)servlet类---service-----执行每次请求
每次客户端发送请求达到服务器端 都会执行到 servlet类service方法
Servlet初始化之后,将一直存在于容器中,service()响应客户端请求
a. 如果客户端发送GET请求,容器调用Servlet的doGet方法处理并响应请求
b. 如果客户端发送POST请求,容器调用Servlet的doPost方法处理并响应请求
c. 或者统一用service()方法处理来响应用户请求
service()是Servlet的核心,负责响应客户的请求。每当一个客户请求一个HttpServlet对象,
该对象的Service()方法就要调用,而且传递给这个方法一个“请求”(ServletRequest)对象和
一个“响应”(ServletResponse)对象作为参数。在HttpServlet中已存在Service()方法。
默认的服务功能是调用与HTTP请求的方法相应的do功能。要注意的是,在service()方法被容器调用之前,
必须确保init()方法正确完成。容器会构造一个表示客户端请求信息的请求对象(类型为ServletRequest)
和一个用于对客户端进行响应的响应对象(类型为ServletResponse)作为参数传递给service()方法。
在service()方法中,Servlet对象通过ServletRequest对象得到客户端的相关信息和请求信息,
在对请求进行处理后,调用ServletResponse对象的方法设置响应信息。
(4)servlet类---destroy---当我们tomcat容器停止时卸载servlet
存放销毁相关代码
WEB容器决定销毁Servlet时,先调用Servlet的destroy()方法,
通常在关闭web应用之前销毁Servlet
destroy()仅执行一次,在服务器端停止且卸载Servlet时执行该方法。
当容器检测到一个Servlet对象应该从服务中被移除的时候,容器会调用该对象的destroy()方法,
以便让Servlet对象可以释放它所使用的资源,保存数据到持久存储设备中,
例如,将内存中的数据保存到数据库中,关闭数据库的连接等。当需要释放内存或者容器关闭时,
容器就会调用Servlet对象的destroy()方法。在Servlet容器调用destroy()方法前,
如果还有其他的线程正在service()方法中执行,容器会等待这些线程执行完毕或等待服务器
设定的超时值到达。
一旦Servlet对象的destroy()方法被调用,容器不会再把其他的请求发送给该对象。
如果需要该Servlet再次为客户端服务,容器将会重新产生一个Servlet对象来处理客户端的请求。
在destroy()方法调用之后,容器会释放这个Servlet对象,在随后的时间内,
该对象会被Java的垃圾收集器所回收。
6. servlet 多线程存在安全问题
servlet 对象默认是单例 在jvm内存中只会存在一份
当多个线程如果共享到同一个全局变量可能会存在线程安全性问题
需求:需要统计 你是第一个人访问网站?
package com.mayikt.servlet;
import jakarta.servlet.*;
import jakarta.servlet.annotation.WebServlet;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet("/count")
public class CountServlet implements Servlet {
private Integer count = 1;
public CountServlet() {
System.out.println("CountServlet 对象被创建");
}
@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 {
servletResponse.setContentType("text/html;charset=utf-8");
PrintWriter writer = servletResponse.getWriter();
writer.println("您是第" + count + "个人访问网站!");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
writer.close();
synchronized (this) {
count++;
}
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
7. servlet 方法介绍
Servlet接口定义了5种方法:
init()
service()
destroy()
getServletConfig()
getServletInfo()
(1)init()
在Servlet实例化后,Servlet容器会调用init()方法来初始化该对象,主要是为了让Servlet对象在处理客户请求前可以完成一些初始化工作,例如:建立数据库的连接,获取配置信息等。对于每一个Servlet实例,init()方法只能被调用一次。init()方法有一个类型为ServletConfig的参数,Servlet容器通过这个参数向Servlet传递配置信息。Servlet使用ServletConfig对象从Web应用程序的配置信息中获取以名-值对形式提供的初始化参数。另外,在Servlet中,还可以通过ServletConfig对象获取描述Servlet运行环境的ServletContext对象,使用该对象,Servlet可以和它的Servlet容器进行通信。
(2)service()
容器调用service()方法来处理客户端的请求。要注意的是,在service()方法被容器调用之前,必须确保init()方法正确完成。容器会构造一个表示客户端请求信息的请求对象(类型为ServletRequest)和一个用于对客户端进行响应的响应对象(类型为ServletResponse)作为参数传递给service()。在service()方法中,Servlet对象通过ServletRequest对象得到客户端的相关信息和请求信息,在对请求进行处理后,调用ServletResponse对象的方法设置响应信息。
(3)destroy
当容器检测到一个Servlet对象应该从服务中被移除的时候,容器会调用该对象的destroy()方法,以便让Servlet对象可以释放它所使用的资源,保存数据到持久存储设备中,例如将内存中的数据保存到数据库中,关闭数据库的连接等。当需要释放内存或者容器关闭时,容器就会调用Servlet对象的destroy()方法,在Servlet容器调用destroy()方法前,如果还有其他的线程正在service()方法中执行容器会等待这些线程执行完毕或者等待服务器设定的超时值到达。一旦Servlet对象的destroy()方法被调用,容器不回再把请求发送给该对象。如果需要改Servlet再次为客户端服务,容器将会重新产生一个Servlet对象来处理客户端的请求。在destroy()方法调用之后,容器会释放这个Servlet对象,在随后的时间内,该对象会被java的垃圾收集器所回收。
(4)getServletInfo()
返回一个String类型的字符串,其中包括了关于Servlet的信息,例如,作者、版本和版权。该方法返回的应该是纯文本字符串,而不是任何类型的标记。
(5)getServletConfig()
该方法返回容器调用init()方法时传递给Servlet对象的ServletConfig对象,ServletConfig对象包含了Servlet的初始化参数。
package com.mayikt.servlet;
import jakarta.servlet.*;
import jakarta.servlet.annotation.WebInitParam;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet(urlPatterns = "/servletConfig", initParams = {@WebInitParam(name = "p1", value = "mayikt")})
public class ServletConfigServlet implements Servlet {
private ServletConfig servletConfig;
@Override
public void init(ServletConfig servletConfig) throws ServletException {
this.servletConfig = servletConfig;
}
@Override
public ServletConfig getServletConfig() {
return servletConfig;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
String value = getServletConfig().getInitParameter("p1");
PrintWriter writer = servletResponse.getWriter();
writer.println(value);
writer.close();
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
8. servlet 体系结构
HttpServlet 对的servlet接口包装 提供 get/post等方法
9. request与response对象
request: 获取客户端发送数据给服务器端
response:返回对应的数据给客户端(浏览器)
http协议基于 请求(request)与响应的模型(response)
package com.mayikt.servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet("/servletDemo05")
public class ServletDemo05 extends HttpServlet {
/**
* 获取到HttpServletRequest、HttpServletResponse对象
*
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// req 获取到客户端发送数据给服务器()
// http://localhost:8081/mayikt_tomcat04_war_exploded/servletDemo05?userName=mayikt&userPwd=123
String userName = req.getParameter("userName");//userName=mayikt
String userPwd = req.getParameter("userPwd");//userPwd=123456
PrintWriter writer = resp.getWriter();
// 判断用户传递的 用户名称和密码 如果是为zhangsan 644064 则 登录成功
if ("zhangsan".equals(userName) && "644064".equals(userPwd)) {
// 服务器端处理完数据之后 返回对应的数据给客户端 告诉给客户端说 响应的是一个 html或者是文本
resp.setHeader("Content-Type", "text/html;charset=UTF-8");
writer.write("<html> <meta charset=\"utf-8\"/><body><h1>恭喜您登录成功,用户名称是:" + userName + "</h1></body></html>");
} else {
writer.write("<html><meta charset=\"utf-8\"/><body><h1>很遗憾密码错误</h1></body></html>");
}
// 关闭资源
writer.close();
}
}
(1)request与response继承模型
ServletRequest ------ 接口 java提供的请求对象根接口
HttpServletRequest ------ 接口(继承ServletRequest) java提供的对http协议封装请求对象接口
org.apache.catalina.connnector.RequestFacade —— 类(Tomcat编写的,实现HttpServletRequest )
(2)request获取请求数据
http://localhost:8080/mayikt-tomcat04/servletDemo06
a. 请求行部分
String getMethod() // 获取请求方式
String getContextPath() // 获取项目访问路径 /mayikt-tomcat04
StringBuffer getRequestURL() // 获取 URL 统一资源定位符 http://localhost:8080/mayikt-tomcat04/servletDemo06
String getRequestURI() // 获取 URI 统一资源标识符 /mayikt-tomcat04/servletDemo06
String getQueryString() // 获取请求参数(Get 方式) username=mayikt&password=123
b.请求头部分
String getHeader(String name) // 根据请求头名称, 获取值
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36
c.请求体部分 (Post 才有)
通过 流读取 来获取 Post请求的参数 userName=mayikt&password=123
ServletInputStream getInputStream() // 字节输入流
BufferedReader getReader() // 字符输入流 readLine();
(3)request获取请求参数
Request对象里封装好了一个 Map集合,Map集合里放的就是所有的参数
Map<String,String[]> getParameterMap() // 返回这个 Map 集合
String[] getParameterValues(String name) // 根据 键名 获取值
String getParameter(String name) // 根据 键名 获取值
?age=18&age=22
Map<String, String[]> map = req.getParameterMap();
for(String key : map.keySet()){
System.out.print(key + ":");
String[] values = map.get(key);
for(String value : values){
System.out.print(value + " ");
}
System.out.println();
}
package com.mayikt.servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.HashMap;
@WebServlet("/httpServletDemo06")
public class HttpServletDemo06 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 判断请求是get还是post请求
String method = req.getMethod();
String parameters = null;
switch (method) {
case "GET":
parameters = req.getQueryString();
break;
case "POST":
BufferedReader reader = req.getReader();
parameters = reader.readLine();
reader.close();
break;
}
HashMap<String, String> parametersMap = new HashMap<>();
String[] sp1 = parameters.split("&");
for (int i = 0; i < sp1.length; i++) {
String[] sp2 = sp1[i].split("=");
String key = sp2[0];
String value = sp2[1];
parametersMap.put(key, value);
}
System.out.println(parametersMap);
}
}
1
(4)request请求转发
请求转发:一种在服务器内部的资源跳转方式
a.通过request对象获取请求转发器对象 :
RequestDispatcher getRequestDispatcher(String path)
b.使用RequestDispatcher对象来进行转发:
forward(ServletRequest request, ServletResponse response)
RequestDispatcher requestDispatcher = request.getRequestDispatcher("/requestDemo6");
requestDispatcher.forward(request,response);
浏览器地址栏路径不发生变化;
只能转发到当前服务器内部资源中;
转发是一次请求;
request.setAttribute("name",value); 数据共享
有效范围是一个请求范围,不发送请求的界面无法获取到value的值,jsp界面获取使用EL表达式${num};
只能在一个request内有效,如果重定向客户端,将取不到值。
request在当次的请求的URL之间有效,比如,你在请求某个servlet,那么你提交的信息,可以使用request.getAttribute()方式获得,而当你再次跳转之后,这些信息将不存在。
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/httpServletDemo09")
public class HttpServletDemo09 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setAttribute("name", "mayikt");
req.getRequestDispatcher("/httpServletDemo10").forward(req, resp);
}
}
package com.mayikt.servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author 余胜军
* @ClassName HttpServletDemo10
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
@WebServlet("/httpServletDemo10")
public class HttpServletDemo10 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String name = (String) req.getAttribute("name");
System.out.println(name);
System.out.println("httpServletDemo10");
}
}
5. response响应数据
response是Servlet.service方法的一个参数,类型为javax.servlet.http.HttpServletResponse。在客户端发出每个请求时,服务器都会创建一个response对象,并传入给Servlet.service()方法。response对象是用来对客户端进行响应的,这说明在service()方法中使用response对象可以完成对客户端的响应工作。
//设置服务端的编码
resp.setCharacterEncoding("UTF-8");
//通过设置响应头设置客户端(浏览器的编码)
resp.setHeader("Content-type","text/html;utf-8");
//这个方法可以同时设置客户端和服务端,因为它会调用setCharacterEncoding方法
resp.setContentType("text/html;charset=utf-8");
resp.setContentType("text/html;charset=utf-8");
响应格式分为3个部分
(1)响应行:响应数据第一行 http协议版本1.1版本
200表示响应状态码 ok为 成功状态
(2)响应头:第二行开始 格式 key value
(3)响应体
response是响应对象,向客户端输出响应正文(响应体)可以使用response的响应流,repsonse一共提供了两个响应流对象:
PrintWriter out = response.getWriter():获取字符流;
ServletOutputStream out = response.getOutputStream():获取字节流;
如果响应正文内容为字符,那么使用response.getWriter(),如果响应内容是字节,
例如下载时,那么可以使用response.getOutputStream()。
//设置错误的响应码
resp.setError(404,"未找到请求的资源!");
//设置正确的响应码
resp.setStatus(200);
HttpServletResponse与ServletResponse
ServletResponse--- 接口 java提供的响应对象根接口
HttpServletResponse --- 接口(继承ServletResponse) java提供的对http协议封装响应对象接口
org.apache.catalina.connnector.ResponseFacade —— 类(Tomcat编写的,实现HttpServletResponse )
6. response重定向
(1)重定向原理
当我们的客户端发送请求达到服务器端,我们的服务器端响应状态码302 ,同时在响应头中
设置重定向地址(resp.setHeader("Location","www.mayikt.com");) ;
客户端(浏览器)收到结果之后,在浏览器解析Location www.mayikt.com 在直接重定向到
www.mayikt.com
首先客户浏览器发送http请求,当web服务器接受后发送302状态码响应及对应新的location给客 户浏览器,客户浏览器发现是302响应,则自动再发送一个新的http请求,请求url是新的location 地址,服务器根据此请求寻找资源并发送给客户。
void sendRedirect(String location) 使用指定的重定向位置URL,向客户端发送临时重定向响应
resp.setStatus(302);
resp.setHeader("Location","www.mayikt.com");
(1)两次请求,重定向之后,浏览器地址栏的URL会发生改变
(2)重定向过程中会将前面Request对象销毁,然后创建一个新的Request对象
(3)重定向的URL可以是其它项目工程
(2)重定向与转发区别
1.转发只能将请求转发给同一个web应用(项目工程)中的其他组件(servlet程序);
重定向可以重定向到任意的地址,网络地址或是文件地址(跨项目文件夹 www.mayikt.com)
2.重定向访问结束后,浏览器地址栏URL发生变化,变成了重定向后的URL;转发则不变
重定向对浏览器的请求直接做出响应,结果就是告诉浏览器去重新发出另一个新的URL访问请求;
请求转发在服务器端内部将请求转发给另一个资源,浏览器不知道服务器程序内部发生了转发过程
3.请求转发调用者与被调用者之间共享相同的请求对象,属于同一个请求和响应过程;
重定向则是不同的请求和响应过程
四、案例:jdbc+servlet登录和注册
初始化数据库表结构
CREATE TABLE `mayikt_users` (
`id` int NOT NULL AUTO_INCREMENT,
`userName` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
`userPwd` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
jdbc+servlet用户注册
1.添加jar包
commons-lang3-3.4----常用工具包
mysql-connector-java-8.0.13.jar ----mysql驱动包
servlet-api.jar ----servlet-api.jar
该jar上传 该位置--- 点击下载jar包
文档:javaweb开发相关资料下载.note
链接:有道云笔记
2. jdbc工具类
package com.mayikt.utils;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class MayiktJdbcUtils {
/**
* 1.需要将我们的构造方法私有化 ---工具类 不需要 new出来 是通过类名称.方法名称访问
*/
private MayiktJdbcUtils() {
}
/**
* 2.定义工具类 需要 声明 变量
*/
private static String driverClass;
private static String url;
private static String user;
private static String password;
/**
*3.使用静态代码快 来给我们声明好 jdbc变量赋值(读取config.properties)
*/
static {
try {
// 1.读取config.properties IO 路径 相对路径
InputStream resourceAsStream = MayiktJdbcUtils.class.getClassLoader().
getResourceAsStream("config.properties");
// 2.赋值给我们声明好的变量
Properties properties = new Properties();
properties.load(resourceAsStream);
driverClass = properties.getProperty("driverClass");
url = properties.getProperty("url");
user = properties.getProperty("user");
password = properties.getProperty("password");
// 3.注册驱动类
Class.forName(driverClass);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 4.封装连接方法
*/
public static Connection getConnection() throws SQLException {
Connection connection = DriverManager.getConnection(url, user, password);
return connection;
}
/**
* 5.封装释放连接方法 (重载)
*/
public static void closeConnection(ResultSet resultSet, Statement statement, Connection connection) {
// 1.查询 释放连接 resultSet statement connection
try {
if (resultSet != null)
resultSet.close();
if (statement != null)
statement.close();
if (connection != null)
connection.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 增删改---释放jdbc资源
*
* @param statement
* @param connection
*/
public static void closeConnection(Statement statement, Connection connection) {
// 1.查询 释放连接 resultSet statement connection
closeConnection(null, statement, connection);
}
/**
* 开启事务
*
* @param connection
* @throws SQLException
*/
public static void beginTransaction(Connection connection) throws SQLException {
connection.setAutoCommit(false);
}
/**
* 提交事务
*
* @param connection
* @throws SQLException
*/
public static void commitTransaction(Connection connection) throws SQLException {
connection.commit();
}
/**
* 回滚事务
*
* @param connection
*/
public static void rollBackTransaction(Connection connection) {
if (connection != null) {
try {
connection.rollback();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/**
* 关闭事务
*
* @param connection
*/
public static void endTransaction(Connection connection) {
if (connection != null) {
try {
connection.setAutoCommit(true);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
拷贝 config.properties
driverClass=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/mayikt?serverTimezone=UTC
user=root
password=root
3.编写注册 servlet
package com.mayikt.servlet;
import com.mayikt.utils.MayiktJdbcUtils;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.PreparedStatement;
/
@WebServlet("/register")
public class RegisterServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
PrintWriter writer = resp.getWriter();
resp.setContentType("text/html;charset=utf-8");
//1.获取参数
String userName = req.getParameter("userName");
if (StringUtils.isEmpty(userName)) {
writer.print("userName不能为空!");
return;
}
String userPwd = req.getParameter("userPwd");
if (StringUtils.isEmpty(userPwd)) {
writer.print("userPwd不能为空!");
return;
}
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
connection = MayiktJdbcUtils.getConnection();
//2.验证用户名称和密码
MayiktJdbcUtils.beginTransaction(connection);// 开启事务
String insertSql = "INSERT INTO `mayikt`.`mayikt_users` (`id`, `userName`, `userPwd`) VALUES (null, ?,?); ";
preparedStatement = connection.prepareStatement(insertSql);
preparedStatement.setString(1, userName);
preparedStatement.setString(2, userPwd);
int insertResult = preparedStatement.executeUpdate();
MayiktJdbcUtils.commitTransaction(connection);
String result = insertResult > 0 ? "注册成功" : "注册失败";
writer.println(result);
} catch (Exception e) {
e.printStackTrace();
writer.println("error");
// 回滚事务
if (connection != null)
MayiktJdbcUtils.rollBackTransaction(connection);
} finally {
if (writer != null) {
writer.close();
}
MayiktJdbcUtils.closeConnection(null, preparedStatement, connection);
}
}
}
4.编写注册html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户注册</title>
</head>
<body>
<h1>用户注册</h1>
<form action="/mayikt_web_login_war_exploded/register" method="post">
<!--name=mayikt&age=12 -->
<span>用户名称:</span> <input type="text" name="userName"> <br>
<span>密 码:</span> <input type="text" name="userPwd" value=""><br>
<input type="submit">
</form>
</body>
</html>
jdbc+servlet用户登录
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户登录</title>
</head>
<body>
<h1>用户登录</h1>
<form action="/mayikt_web_login_war_exploded/login" method="post">
<!--name=mayikt&age=12 -->
<span>名称:</span> <input type="text" name="userName"> <br>
<span>密 码:</span> <input type="text" name="userPwd" value=""><br>
<input type="submit">
</form>
</body>
</html>
package com.mayikt.servlet;
import com.mayikt.utils.MayiktJdbcUtils;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.获取参数
String userName = req.getParameter("userName");
String userPwd = req.getParameter("userPwd");
PrintWriter writer = resp.getWriter();
resp.setContentType("text/html;charset=utf-8");
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
//2.验证用户名称和密码
connection = MayiktJdbcUtils.getConnection();
String loginSql = "SELECT * FROM mayikt_users where userName=? and userPwd=? ";
preparedStatement = connection.prepareStatement(loginSql);
preparedStatement.setString(1, userName);
preparedStatement.setString(2, userPwd);
resultSet = preparedStatement.executeQuery();
if (resultSet.next()) {
String dbUserName = resultSet.getString(1);
writer.println("恭喜" + userName + "登录成功");
} else {
writer.println("登录失败");
}
} catch (Exception e) {
e.printStackTrace();
writer.println("error");
// 回滚事务
if (connection != null)
MayiktJdbcUtils.rollBackTransaction(connection);
} finally {
if (writer != null) {
writer.close();
}
MayiktJdbcUtils.closeConnection(null, preparedStatement, connection);
}
}
}
常见问题
我们在使用tomcat 运行 web项目时 启动项目报错
java.lang.ClassNotFoundException: com.mysql.cj.jdbc.Driver
原因1:没有引入 mysql驱动jar包
原因2:tomcat 在运行过程中 会在lib目录中查找jar包 发现没有 就会报该错误。
但是我们在编译阶段是在项目中lib 查找jar包,编译阶段没有报错。
将该 jar包拷贝到 tomcat -lib 目录中即可