Servlet
Servlet
JavaEE规范之一
是运行在服务端上的一个java小程序,它可以接收客户端发过来的数据请求,并且响应数据给客户端
部署tomcat的时候记得部署工程
Servlet的生命周期
1.浏览器根据地址来发起调用,tomcat容器在接收到请求之后会根据地址栏上的地址进行一个数据的解析
会找到具体的工程,然后再定位到工程下面具体的资源
2.定位到资源以后,首先会创建当前servlet类的实例,所以调用的是无参构造方法
3.会执行初始化init方法,初始化servlet上下文配置对象ServletConfig
4.会去执行service方法,service方法以后我们会用来执行请求的分发处理
5.当容器关闭的时候,会执行销毁方法destroy
使用浏览器去访问项目资源时候,记得在xml文件下注册资源路径,例如将HelloServlet注册路径设置为/hello
<!--资源注册-->
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.os467.servlet.HelloServlet</servlet-class>
</servlet>
<!--资源路径的配置-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
servlet的实例是由容器所创建的
package com.os467.servlet;
import javax.servlet.*;
import java.io.IOException;
public class HelloServlet implements Servlet {
public HelloServlet(){
System.out.println("无参构造方法执行了!");
}
/**
* 初始化的方法
* @param servletConfig
* @throws ServletException
*/
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("init初始化方法执行了!");
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("service方法执行了!");
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
System.out.println("destroy方法执行了!");
}
}
HttpServlet
HttpServlet中的service方法为我们提供了请求分发的处理
创建一个HelloServlet类,继承HttpServlet
先由service方法接收到request对象,与response对象
再根据客户端提交的方式调用不同的方法
package com.os467.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class HelloServlet extends HttpServlet {
/**
* servlet中的service方法实际上就是完成请求的分发处理,会根据客户端不同提交的方式来执行不同的方法
* @param request 请求对象 一般用于请求客户端传递过来的数据或者用于获取浏览器的一些信息
* @param response 响应对象 响应数据给前端
* @throws ServletException
* @throws IOException
*/
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取客户端的提交方式
String method = request.getMethod();
//客户端的提交方式
System.out.println("客户端的提交方式为:"+method);
if (method.equals("GET")){
doGet(request,response);
}else if (method.equals("POST")){
doPost(request,response);
}
}
public void doGet(HttpServletRequest request,HttpServletResponse response){
System.out.println("执行了doGet方法!!!");
}
public void doPost(HttpServletRequest request,HttpServletResponse response){
System.out.println("执行了doPost方法!!!");
}
}
//前端资源
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="http://localhost:8080/servlet/hello" method="post">
<input type="submit" value="提交">
</form>
</body>
</html>
ServletConfig
通过ServletConfig的对象来获取上下文配置信息(即xml文件内配置的信息)
/**
* ServletConfig用于获取上下文配置信息
* @param config
* @throws ServletException
*/
@Override
public void init(ServletConfig config) throws ServletException {
//获取初始化的数据
String mysql_url = config.getInitParameter("mysql_url");
System.out.println(mysql_url);
}
配置文件
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.os467.servlet.HelloServlet</servlet-class>
<init-param>
<param-name>mysql_url</param-name>
<param-value>jdbc:mysql://localhost:3306</param-value>
</init-param>
<init-param>
<param-name>username</param-name>
<param-value>root</param-value>
</init-param>
<init-param>
<param-name>driver</param-name>
<param-value>com.mysql.jdbc.Driver</param-value>
</init-param>
</servlet>
servlet配置对象和servlet域对象都是单例的(从工程启动时,这两个实例就创建成功了,使用的都是同一个对象)
单例模式(提高了系统资源,提高了程序的执行效率)
public void doGet(HttpServletRequest request,HttpServletResponse response){
//获取servlet核心配置对象,打印结果为true
ServletConfig servletConfig01 = getServletConfig();
ServletConfig servletConfig02 = getServletConfig();
System.out.println(servletConfig01 == servletConfig02);
//获取servlet域对象,打印结果为true
//1.
ServletContext servletContext = getServletConfig().getServletContext();
//2.
ServletContext servletContext1 = getServletContext();
System.out.println(servletContext == servletContext1);
}
servlet域对象
ServletConfig 是servlet核心配置对象,而且该对象的生命周期是随着容器的创建而创建,
容器的销毁而销毁,在工程的任意位置去获取该实例的时候,指向的都是同一份内存地址
作用:在servlet实例加载的时候去获取局部的初始化信息
servletContext 是servlet中的一个上下文本对象,而且该对象的生命周期是随着容器的创建而创建,
容器的销毁而销毁,在工程的任意位置去获取该实例的时候,指向的都是同一份内存地址
作用:可以像map一样存放数据,取出数据,而且是在工程的任意位置取出数据,范围是整个web工程,可以去读取全局的初始化信息,可以在工程的任何位置读取
后面会接触到的域对象:
request(也是一个域对象,也可以去存放数据,只不过该对象的取值范围比较小),session(会话对象,会对客户端和服务端进行一个绑定)
public void doGet(HttpServletRequest request,HttpServletResponse response){
//获取servlet核心配置对象
ServletConfig servletConfig0 = getServletConfig();
//获取servlet域对象
ServletContext servletContext = getServletConfig().getServletContext();
//往域中存放数据
servletContext.setAttribute("username","root");
servletContext.setAttribute("password","123456");
//取出域中的数据
System.out.println("username的值为:"+servletContext.getAttribute("username")+
" password的值为:"+servletContext.getAttribute("password"));
}
取出全局的初始化数据
//取出全局的初始化数据
String name = servletContext.getInitParameter("name");
String age = servletContext.getInitParameter("age");
String sex = servletContext.getInitParameter("sex");
System.out.println(name+" "+age+" "+sex);
配置文件(需要写在根标签web-app内部)
</servlet-mapping>
<!--配置全局的初始化数据-->
<context-param>
<param-name>name</param-name>
<param-value>jack</param-value>
</context-param>
<context-param>
<param-name>age</param-name>
<param-value>20</param-value>
</context-param>
<context-param>
<param-name>sex</param-name>
<param-value>男</param-value>
</context-param>
</web-app>
**
**
HTTP协议
所谓HTTP协议,客户端和服务器之间通信时,发送的数据,需要遵循的规则,叫HTTP协议
请求分为GET和POST两种
响应HTTP协议格式
1.响应行
- 响应的协议和版本号
- 响应状态码
- 响应状态描述符
2.响应头key :value不同的请求头,有不同的含义
3.响应体 ===>>>就是回传给客户端的数据
常用响应码说明
- 200表示请求成功
- 302表示请求重定向
- 404表示请求服务器已经收到了,但是你要的数据不存在(请求地址错误)
- 500表示服务器已经收到请求,但是服务器内部错误(代码错误)
GET请求
请求行
1.请求的方式GET
2.请求的资源路径[+?+请求参数]
3.请求的协议的版本号HTTP/1.1
请求头
key : value 组成 不同的键值对,表示不同的含义
无论客户端给服务器传数据,还是服务端给客户端传数据,都是基于http协议来完成数据的互传
客户端
客户端如何访问服务端,如何给服务区发送数据?
1.要知道访问服务端具体的地址
http://localhost:8080/servlet/hello
格式:http://本地IP地址:端口号/工程路径/资源路径
2.如何去传递数据
看一下浏览器端的提交方式是什么,如果是get,则把数据封装在地址后面:资源路径?key1=value1&key2=value2
如果是post提交方式,则数据是被封装在请求体中的
服务端
服务端给客户端响应数据,直接是在当前页面上完成,没有地址的跳转,响应的数据则直接被封装在响应体中
以后在前端框架中,我们会根据后端的响应数据,来完成前端逻辑的判断(比如AJA异步技术)
HttpServletRequest类
每次只要有请求进入Tomcat服务器,Tomcat服务器就会把请求过来的HTTP协议信息解析好封装到Request对象中。然后传递到service方法(doGet和doPost)中给我们使用。我们可以通过HttpServletRequest对象,获取到所有请求的信息
HttpServletRequest类的常用方法
getRequestURI() 获取请求的资源路径
getRequestURL() 获取请求的统一资源定位符(绝对路径)
getRemoteHost() 获取客户端的ip地址iv.getHeader()获取求头
getParameter() 获取请求的参数
getParameterValues() 获取请求的参数(多个值的时候使用)
getMethod() 获取请求的方法GET或POST
setAttribute(key,value) 设置域数据
getAttribute(key) 获取域数据
getRequestDispatcher() 获取请求转发对象
配置资源路径的方式(基于注解)
在类名上注释@WebServlet("/hello05")
GET方法处理:
package com.os467.servlet;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
@WebServlet("/hello05")
public class HelloServlet04 extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取请求的资源路径
String requestURI = request.getRequestURI();
System.out.println("请求的资源路径为:"+requestURI);
//基于浏览器的全路径
StringBuffer requestURL = request.getRequestURL();
//http://localhost:8080/servlet/hello04
System.out.println(requestURL);
//获取客户端的ip
String remoteHost = request.getRemoteHost();
//0:0:0:0:0:0:0:1
System.out.println(remoteHost);
String header = request.getHeader("User-Agent");
System.out.println(header);
//获取请求的参数,获取客户端传递过来的数据
String key1 = request.getParameter("key1");
String key2 = request.getParameter("key2");
String key3 = request.getParameter("key3");
String name = request.getParameter("name");
System.out.println(key1+" "+key2+" "+key3+" "+name);
}
}
Post方法处理:
接收数据的方法:
request.getParameter("key的值")
处理中文乱码的方法:
//处理中文乱码
request.setCharacterEncoding("utf-8");
package com.os467.servlet;
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;
@WebServlet("/hello04")
public class HelloServlet04 extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//处理中文乱码
request.setCharacterEncoding("utf-8");
if (request.getMethod().equals("GET")){
doGet(request,response);
}else if (request.getMethod().equals("POST")){
doPost(request,response);
}
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取客户端传递来的数据
String username = request.getParameter("username");
String password = request.getParameter("password");
String sex = request.getParameter("sex");
String country = request.getParameter("country");
System.out.println(username);
System.out.println(password);
System.out.println(sex);
System.out.println(country);
}
}
前端布局:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="http://localhost:8080/servlet/hello04" method="post">
username:<input type="text" name="username"><br>
password:<input type="text" name="password"><br>
男:<input type="radio" name="sex" value="男"> 女:<input type="radio" name="sex" value="女"><br>
国籍:<select name="country">
<option value="1">----请选择----</option>
<option value="中国">中国</option>
<option value="美国">美国</option>
<option value="日本">日本</option>
<option value="德国">德国</option>
</select><br>
<input type="submit" value="提交">
</form>
</body>
</html>
接收具有多个value值的key的方法
//通过请求对象来接收value有多个的key
String[] hobbies = request.getParameterValues("hobby");
//遍历value
for (String hobby : hobbies) {
System.out.println(hobby);
}
HttpServletResponse类
HttpServletResponse类和HttpServletRequest类一样,每次请求进来,Tomcat服务器都会创建一个Response对象传递给Servlet程序去使用,HttpServletRequest表示请求过来的信息,HttpServletResponse表示所有响应的信息,我们如果需要设置返回给客户端的信息,都可以通过HttpServletResponse对象来进行设置
往客户端回传数据
字节流getOutputStream()
效率高
常用于下载(传递二进制数据)
字符流getWriter()
效率低
常用于回传字符串(常用)
响应中文乱码解决方法,以及设置浏览器可读取文本类型
setContentType("text/html;charset=UTF-8")
package com.os467.servlet;
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;
@WebServlet("/hello06")
public class HelloServlet06 extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//让前后端字符集统一的方法
response.setContentType("text/html;charset=UTF-8");
//向tomcat服务器请求字符流对象
response.getWriter().print("hello servlet");
response.getWriter().print("<br/>");
response.getWriter().print("响应成功!");
response.getWriter().print("<br/>");
response.getWriter().print("<input type='text'>");
}
}
案例:(通过前端访问,后端响应数据库数据给前端)
User用户类
JdbcUtils工具类
package com.os467.servlet;
import com.os467.beans.User;
import com.os467.utils.JdbcUtils;
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.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
public class UserServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//处理中文乱码
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
//获取提交类型
String method = request.getMethod();
if (method.equals("GET")){
doGet(request,response);
}else if (method.equals("POST")){
doPost(request,response);
}
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
//创建集合对象
ArrayList<User> users = new ArrayList<>();
//获取数据库对象
try {
connection = JdbcUtils.getConnection();
//获取数据库操作对象并且预编译sql
preparedStatement = connection.prepareStatement("select * from tb_user");
//执行sql
resultSet = preparedStatement.executeQuery();
//遍历结果集
while (resultSet.next()){
//取出数据
int uid = resultSet.getInt("uid");
String username = resultSet.getString("username");
String password = resultSet.getString("password");
//创建用户对象
User user = new User(uid, username, password);
//将用户对象添加到集合
users.add(user);
}
//将集合对象响应到前端
response.getWriter().print(users);
} catch (Exception throwables) {
throwables.printStackTrace();
}finally {
//关闭资源
JdbcUtils.getClose(resultSet,preparedStatement,connection);
}
}
}
请求的转发
请求转发是指,服务器收到请求后,从一次资源跳转到另一个资源的操作叫做请求转发。(地址不会改变,即浏览器路径不会跳转)
getRequestDispatcher() 获取请求转发对象
package com.os467.servlet;
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 java.io.IOException;
@WebServlet("/hello01")
public class HelloServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//往域中去存放数据
request.setAttribute("username","jack");
request.setAttribute("password","123456");
//获取转发对象 相对路径
RequestDispatcher requestDispatcher = request.getRequestDispatcher("/hello02");
//走向具体的资源
requestDispatcher.forward(request,response);
}
}
request除了可以作为请求对象之外,还可以作为域对象,但是该域对象的取值范围,是一次请求范围之内
request通过setAttribute(key,value)
方法存放数据
通过getAttribute(key)
方法获取数据
请求转发:内部资源的跳转,通过浏览器发起访问,工程中的资源会从一个地址跳转到另外一个地址,浏览器的地址不会发生改变
请求转发集合对象 (使用request域存放数据,要使用请求转发)
package com.os467.servlet;
import com.os467.beans.User;
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.util.ArrayList;
@WebServlet("/hello06")
public class HelloServlet06 extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//创建集合对象
ArrayList<User> users = new ArrayList<>();
//创建用户对象
User user1 = new User(100,"jack001","123");
User user2 = new User(100,"jack002","123");
User user3 = new User(100,"jack003","123");
User user4 = new User(100,"jack004","123");
User user5 = new User(100,"jack005","123");
//将数据添加到集合中去
users.add(user1);
users.add(user2);
users.add(user3);
users.add(user4);
users.add(user5);
//将集合存放到域中
request.setAttribute("users",users);
//执行请求转发
request.getRequestDispatcher("/jsp/test.jsp").forward(request,response);
}
}
渲染后端数据 (使用jsp)
jsp的底层是java
不使用html,html作为一个静态文件,是不能读取动态数据的,需要用jsp去操作
el表达式:
作用:取出后端域中的数据,完成数据的校验和判断
${后端域中的key}
<%--
Created by IntelliJ IDEA.
User: tly20
Date: 2022/7/3
Time: 19:54
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>test</title>
</head>
<body>
<%--
el表达式:
取出后端域中的数据
${后端域中的key}
--%>
${users}
</body>
</html>
使用servletContext域存放数据(可以使用请求重定向)
//获取域对象
ServletContext servletContext = getServletContext();
servletContext.setAttribute("users",users);
response.sendRedirect("http://localhost:8080/servlet/jsp/test.jsp");
请求重定向
请求重定向,是指客户端给服务器发请求,然后服务器告诉客户端去新地址访问,叫做请求重定向
请求重定向:也可以完成内部资源的跳转,而且浏览器的地址是会发生改变的,这种情况下是不能取到request域中的数据的
package com.os467.servlet;
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;
@WebServlet("/hello03")
public class HelloServlet03 extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//存数据
request.setAttribute("key","value");
//请求重定向 绝对路径
response.sendRedirect("http://localhost:8080/servlet/hello04");
}
}
package com.os467.servlet;
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;
@WebServlet("/hello04")
public class HelloServlet04 extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Object key = request.getAttribute("key");
//打印key的值应该为null,因为request域中的数据的作用范围只在一次请求范围内
System.out.println(key);
}
}
注意的点:
重定向和转发使用的域对象有哪些
- 采用重定向的时候: servletContext session
- 采用转发的时候: servletContext request session
JSP
什么是jsp?
JSP(全称Java Server Pages)是由Sun公司专门为了解决动态生成HTML文档的技术
jsp的主要作用是代替Servlet程序回传html页面的数据,因为Servlet程序回传html页面数据是一件非常繁琐的事情,开发成本和维护成本都极高
jsp的运行原理
jsp的本质,其实是一个Servlet程序
可以在<%...%>
内写java代码
通过脚本表达式<%=...%>
取到值
也可以通过el表达式${...}
取到域对象中的值
el表达式可以取到后端中的数据,而且取值的方式比较简单${域的key}
jsp脚本表达式<%=request.getAttribute(“key”)%>
el表达式其实在底层封装的就是对应的jsp脚本表达式,它出现目的就是为了替换脚本表达式,使得我们在开发的时候更高效
el表达式的用法:相关的逻辑判断,判断一个容器是否为空,el表达式取到的数据只能是域中的数据,
<%--
Created by IntelliJ IDEA.
User: tly20
Date: 2022/7/4
Time: 9:53
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>study</title>
</head>
<%
String username = "123456";
request.setAttribute("key1","value1");
ArrayList<String> strings = new ArrayList<>();
strings.add("hello");
strings.add("world");
strings.add("java");
strings.add("c++");
request.setAttribute("strings",strings);
HashMap<String, String> hashMap = new HashMap<>();
hashMap.put("key1","value1");
hashMap.put("key2","value2");
hashMap.put("key3","value3");
hashMap.put("key4","value4");
session.setAttribute("hashMap",hashMap);
%>
<body>
<%=request.getAttribute("key1")%>
<%=username%>
${key1}
<%=strings%><br>
集合中的一个对象:${strings[0]}<br>
集合中的一个对象:${strings[1]}<br>
集合中的一个对象:${strings[2]}<br>
集合中的一个对象:${strings[3]}<br>
map集合对象:${hashMap}<br>
根据下表取到某一个元素:${hashMap.get("key1")}<br>
</body>
</html>
判断一个对象是否为空(指的是对象是否存在,不是说容器长度为0)
${empty strings} 判断是否为空
${not empty strings} 判断是否不为空
引入jstl标签库
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
ForEach标签
items表示遍历集合, var表示遍历集合中每一个对象
<c:forEach items="${empList}" var="emp">
<tr>
<td>${emp.empName}</td>
<td>${emp.age}</td>
<td>${emp.sex == 1? '男' : '女'}</td>
<td>${emp.salary}</td>
<td>${emp.birthday}</td>
<td>
<a href="http://localhost:8080/servlet/emp?flag=showEmpByID&eid=${emp.eid}">修改</a>
<a href="http://localhost:8080/servlet/emp?flag=deleteEmpByID&eid=${emp.eid}">删除</a>
</td>
</tr>
</c:forEach>
If标签
<c:if test="${not empty user}">
代码执行
</c:if>
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以邮件至 1300452403@qq.com