Serelet/Jsp学习笔记(一)
Servlet开发
Servlet是Sun公司提供的一门用于开发动态WEB资源的技术
一、Servlet执行过程
二、Servlet的使用
首先需要建立WEB项目(J2EE=J2SE+扩展JAR),创建一个动态的WEB资源(动态生成HTML页面)
- 首先,创建一个普通的Java类,让其去继承HttpServlet
- 再把开发好的Java类部署到WEB服务器中
当一个类继承了HttpServlet类的普通类,约定俗成有一种称呼这样的普通类为:Servlet
约定的命名方式:XXXXServlet
(1)新建一个Servlet
package com.yu.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 Demo01Servlet extends HttpServlet {//Servlet接口
/* doGet方法是处理GET的请求方式 */
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println(req);
System.out.println(resp);
System.out.println("获取的请求方式:"+req.getMethod());
}
/* doPost方法是处理Post的请求方式:表单设置method="post" */
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println(req);
System.out.println(resp);
System.out.println("获取的请求方式:"+req.getMethod());
}
}
备注:因为我们这个Java文件,不能被浏览器直接访问,我们需要通过映射方式完成
(2)Servlet访问URL映射配置
映射建立方式有两种:
一. web.xml中手动配置方案;
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<!--web.xml中是唯一的标识-->
<servlet-name>Demo01Servlet</servlet-name>
<!--访问servlet全路径-->
<servlet-class>com.yu.Servlet.Demo01Servlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Demo01Servlet</servlet-name>
<!--一般都是从"/"开始写-->
<url-pattern>/yue.com</url-pattern>
</servlet-mapping>
</web-app>
二.通过注解进行Servlet映射。
(3)测试Servlet访问
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>测试</title>
</head>
<body>
<a href="yue.com">YUE</a>
<form action="yue.com" method="get">
<button>GET请求方式</button>
</form>
<form action="yue.com" method="post">
<button>POST请求方式</button>
</form>
</body>
</html>
(4)生成动态WEB资源
HttpServletRequest : 处理Http请求信息
HttpServletResponse : 处理Http响应信息
二者都是Tomcat容器自动创建(实例化)
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("获取的请求方式:"+req.getMethod());
//动态生成一个HTML页面,当我访问test01.php请求的时候,响应回去一个HTML页面
//1.告知响应的头信息是一个HTML数据格式
resp.setContentType("text/html;charset=UTF-8");
//2.生成HTML页面
PrintWriter out = resp.getWriter();
//3.需要我们手动拼写HTML页面
String titleName = "动态生HTML页面";
out.write(" <html> ");
out.write(" <head> ");
out.write(" <meta charset='UTF-8'> ");
out.write(" <title>"+titleName+"</title>");
out.write(" </head> ");
out.write("<body>");
out.write("<h3>");
out.write(String.valueOf(Math.random()));
out.write("</h3>");
out.write("</body>");
out.write(" </html> ");
}
三、HttpServletResponse对象
WEB服务器收到客户端Http请求,会针对每一次请求,分别创建一个用于代表的Request请求对象和Response响应对象,如果向获取客户端提交的数据请求对象,向客户端输出数据使用响应对象。
HttpServletResponse对象代表服务器的响应,这个对象中封装了向客户端发送数据、发送响应头、发送响应的状态码等方法
package com.yu.Servlet;
import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
/**
* Created with IntelliJ IDEA.
*
* @Author: 鱼
* @Date: 2021/06/14/10:12
* @Description:
*/
public class ImageServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//响应回去数据类型图片
//resp.setHeader("refresh","5");//设置refresh响应的头控制浏览器每隔五秒刷新
//1.内存中创建一张图片
BufferedImage image = new BufferedImage(80,20,BufferedImage.TYPE_INT_RGB);
//2.得到图片
Graphics2D g = (Graphics2D)image.getGraphics();
g.setColor(Color.WHITE);//设置图片的背景颜色
g.fillRect(0,0,80,20);//充填背景颜色
//3.向图片上写入数据
g.setColor(Color.BLUE);//数据颜色
g.setFont(new Font(null,Font.BOLD,20));//设置字体
String str = String.valueOf(new Random().nextInt(10000) +10000);
g.drawString(str,0,20);//从坐标(0,20)开始写入数据
//4.响应图片
resp.setContentType("image/jpeg");//响应一张图片
resp.setDateHeader("expires",-1);//清除缓存
resp.setHeader("Cache-Control","no-cache");//不要缓存
resp.setHeader("Pragma","no-cache");
//5.将图片写入浏览器
ImageIO.write(image,"jpg",resp.getOutputStream());
}
}
服务端响应回去的常用的数据类型:text/html、图片、application/json、下载(流的操作)
重定向与请求转发
请求重定向:一个WEB资源收到客户端请求后,通知客户端去访问另外一个WEB资源,我们称为重定向
(地址栏的路径发送了改变)
package com.os.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class Demo02Servlet extends HttpServlet {//Servlet
/* doGet方法是处理GET的请求方式 */
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("Demo02Servlet");
//resp.sendRedirect("test01.php");//重定向
//请求转发
req.getRequestDispatcher("/test01.php").forward(req,resp);
}
}
四、Servlet访问URL映射配置
客户端是通过URL地址访问WEB服务器中资源(Servlet),所以Servlet想被外界访问,必须将Servlet映射到一个URL地址上,这个工作由部署描述符web.xml中
<servlet>
和<sevlet-mapping>
元素完成(或者简化注解方式)
-
<servlet>
元素用于注册servlet,他主要包含两个子元素<servlet-name>
和<servlet-class>
-
<sevlet-mapping>
元素用于映射一个已经注册对外访问URL映射 , 他主要包含两个子元素<servlet-name>
和<url-pattern>
- 一个Servlet可以映射多个路径
public class Demo04Servlet extends HttpServlet {//Servlet
/* doGet方法是处理GET的请求方式 */
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("多个映射路径Demo04Servlet");
//响应的是一个空白页面
}
}
<servlet>
<servlet-name>Demo04Servlet</servlet-name>
<servlet-class>com.os.servlet.Demo04Servlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Demo04Servlet</servlet-name>
<url-pattern>/test04.php</url-pattern>
<url-pattern>/test04.asp</url-pattern>
<url-pattern>/test04.html</url-pattern>
<url-pattern>/test04</url-pattern>
</servlet-mapping>
- servlet的映射路径可以使用通配符
*
<servlet>
<servlet-name>Demo06Servlet</servlet-name>
<servlet-class>com.os.servlet.Demo06Servlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Demo06Servlet</servlet-name>
<!-- 如果有后缀名,不能设置斜线开头 -->
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>Demo07Servlet</servlet-name>
<servlet-class>com.os.servlet.Demo07Servlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Demo07Servlet</servlet-name>
<!-- 所有sys开头的路径 -->
<url-pattern>/sys/*</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>Demo05Servlet</servlet-name>
<servlet-class>com.os.servlet.Demo05Servlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Demo05Servlet</servlet-name>
<!-- *任何的,谁描述的更加准确就使用谁 -->
<url-pattern>/*</url-pattern>
</servlet-mapping>
五、HttpServletRequest对象
现在开始,使用注解方式的形式创建Servlet,在传统方式需要我们手动进行配置,这个过程非常的繁琐。
HttpServletRequest 对象代表客户端的请求,当客户端通过HTTP协议访问服务器的时候
Http请求头中的所有信息都封装在这个对象中
通过该对象提供了响应的获取方法,可以获取请求中所有的信息
使用@WebServlet替换传统方式
package com.os.servlet; /**
* Created with IntelliJ IDEA.
*
* @Author: 鱼
* @Date: 2021/06/19/10:53
* @Description:
*/
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
/**
*@WebServlet(name = "Test01Servlet")注解等价于
* <servlet>
* <servlet-class>Test01Servlet</servlet-class>
* <servlet-class>com/os/servlet/Test01Servlet</servlet-class>
* </servlet>
* 需要建立URL映射:urlPatterns = "/test01.php",是一个数组,只有一个映射如下写法,多个映射数组表示
* <servlet-mapping>
* <servlet-name>Test01Servlet</servlet-name>
* <url-parrten> /test01.php</url-parrten>
* </servlet-mapping>
*
*
* value与urlPatterns等价,两者不能共存
* */
@WebServlet(name = "Test01Servlet", urlPatterns = "/test01.php")
public class Test01Servlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
5.1 获取客户端信息
- getRequestURL() :返回客户端请求时候的完整URL
- getRequestURI() :返回请求行中的资源名称部分
- getQueryString() :返回请求行中的参数部分
- getRemoteAddr() :返回客户端请求的IP地址
out.write("<h4>获取的请求路径:"+request.getServletPath()+"</h4>");
out.write("<h4>获取的发布路径:"+request.getContextPath()+"</h4>");
package com.os.servlet; /**
* Created with IntelliJ IDEA.
*
* @Author: 鱼
* @Date: 2021/06/19/10:53
* @Description:
*/
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.io.PrintWriter;
/**
*@WebServlet(name = "Test01Servlet")注解等价于
* <servlet>
* <servlet-class>Test01Servlet</servlet-class>
* <servlet-class>com/os/servlet/Test01Servlet</servlet-class>
* </servlet>
* 需要建立URL映射:urlPatterns = "/test01.php",是一个数组,只有一个映射如下写法,多个映射数组表示
* <servlet-mapping>
* <servlet-name>Test01Servlet</servlet-name>
* <url-parrten> /test01.php</url-parrten>
* </servlet-mapping>
*
*
* value与urlPatterns等价,两者不能共存
* */
@WebServlet(name = "Test01Servlet", value = "/test01.php")
public class Test01Servlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/*1.获取客户端的信息*/
// + **getRequestURL()** :返回客户端请求时候的完整URL
String requestURL = request.getRequestURL().toString();
// + getRequestURI() :返回请求行中的资源名称部分
String requestURI = request.getRequestURI();
// + **getQueryString()** :返回请求行中的参数部分
String queryString = request.getQueryString();
// + **getRemoteAddr()** :返回客户端请求的IP地址
String remoteAddr = request.getRemoteAddr();
String remoteHost = request.getRemoteHost();//客户端传递过来的HOST
int remotePort = request.getRemotePort();//获取端口号
String remoteUser = request.getRemoteUser();//获取用户
String method = request.getMethod();//请求方式
String pathInfo = request.getPathInfo();//路径信息
String localAddr = request.getLocalAddr();//获取服务器的IP地址
String localName = request.getLocalName();//获取服务钱的主机名
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.write("<h3>获取客户端的信息如下:</h3>");
out.write("<h4>请求完整URL地址:"+requestURL+"</h4>");
out.write("<h4>获取的请求路径:"+request.getServletPath()+"</h4>");
out.write("<h4>获取的发布路径:"+request.getContextPath()+"</h4>");
out.write("<h4>请求的资源:"+requestURI+"</h4>");
out.write("<h4>获取传递参数:"+queryString+"</h4>");
out.write("<h4>来访者(客户端)IP地址:"+remoteAddr+"</h4>");
out.write("<h4>来访者(客户端)主机名:"+remoteHost+"</h4>");
out.write("<h4>使用的端口号:"+remotePort+"</h4>");
out.write("<h4>remoteUser:"+remoteUser+"</h4>");
out.write("<h4>请求的方式:"+method+"</h4>");
out.write("<h4>pathInfo:"+pathInfo+"</h4>");
out.write("<h4>localAddr:"+localAddr+"</h4>");
out.write("<h4>localName:"+localName+"</h4>");
out.close();
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
5.2 获取客户端的请求头
- getHeader(String name):String
- getHeaders(String name): 返回 Enumeration
- getHeaderNames()
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
Enumeration<String> requestHeaderInfos = request.getHeaderNames();
out.write("<h3>获取所有的客户端头信息如下:</h3>");
while(requestHeaderInfos.hasMoreElements()){
String headerName = requestHeaderInfos.nextElement();
String headerValue = request.getHeader(headerName);
out.write("<h4>"+headerName+":"+headerValue+"</h4>");
}
out.close();
}
5.3 数据传递
- 一.服务端(Servlet)获取客户端(Html)数据
常用方法:
-
request.getParameter
(“对应传递name属性对应的值”):单个数据,没有返回null -
request.getParameterValues
(对应传递name属性对应的值) -
request.getParameterMap()
:将传递过来的数据全部获取到,常用于框架封装
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>客户端传递数据</title>
</head>
<body>
<h3>客户端传递的数据:单个值、数组、文件</h3>
<h3 style="color:red;">表单传递数据必须设置name属性</h3>
<form action="test02.php" method="get">
用户名:<input type="text" name="user_name"><br/><!-- 单个值 -->
<!-- 只要传递的name名字有重复,就代表是数组,有经典控件 -->
爱好:<!-- 数组 -->
<input type="checkbox" name="hobby" value="basketall">篮球
<input type="checkbox" name="hobby" value="football">足球
<input type="checkbox" name="hobby" value="pingpang">乒乓
<hr/>
<button>提交GET请求方式</button>
</form>
</body>
</html>
package com.os.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(name = "Test02Servlet",urlPatterns = "/test02.php")
public class Test02Servlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/*1.request.getParameter("对应传递name属性对应的值"):单个数据,没有返回null*/
String userName = request.getParameter("user_name");
System.out.println("userName = " + userName);
/*
* 2.request.getParameterValues(对应传递name属性对应的值):
* String[] 数组:如果没有返回null
* */
String[] hobbyArray = request.getParameterValues("hobby");
if(hobbyArray!=null){
for (String s : hobbyArray) {
System.out.println(s);
}
}
/*
3.request.getParameterMap():将传递过来的数据全部获取到,常用于框架封装
*/
Map<String,String[]> parameterMap = request.getParameterMap();
for(Map.Entry<String,String[]> entry : parameterMap.entrySet()){
String key = entry.getKey();
String[] parameterValueArr = entry.getValue();
String pameterValue = "";
for (int i = 0; i < parameterValueArr.length; i++) {
if(i==parameterValueArr.length-1){//单个值
pameterValue += parameterValueArr[i];
}else{
pameterValue+=parameterValueArr[i]+",";
}
}
System.out.println(key+":"+pameterValue);
}
}
}
注意:POST请求的中文乱码问题:request.setCharacterEncoding(“UTF-8”);
@WebServlet(urlPatterns = "/test03.php")
public class Test03Servlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/*解决POST请求的中文乱码问题或者自己使用编码和解码字符串相关方法*/
request.setCharacterEncoding("UTF-8");
String userName = request.getParameter("user_name");
System.out.println(userName);
}
}
- 二.服务端(Servlet)传递数据给服务端(Servlet)数据(响应的页面:传递给了客户端)
- setAttribute:存储数据
- getAttribute : 获取数据,返回的类型Object或者NULL
- removeAttribute:移除响应数据
请求转发时,必须先存储数据,后读取.若直接读取没有存储,返回null
setAttribute存储数据一致存在,请求转发只要路径不断,数据都可以访问
六、HttpSession(当前会话范围有效)
当我们访问网站的时候,需要进行登录,我们不可能在整个访问完整的过程中,一直传递我们用户名和密码,也不可能一直使用请求转发访问网页。使用Session范围存储的数据是在当前会话范围有效
只要存储过一次,我们就可以在会话范围内访问到
HttpSession session = request.getSession();//我们常用于保存登录用户的信息
//session.setAttribute()//存储数据
//session.getAttribute()
数据什么时候消失:
- 关闭浏览器或者关闭服务器
- 超时,当你浏览器不做任何操作的时候,默认30分注销Session
- 手动注销方式
//1.移除特定存储的数据
HttpSession session = request.getSession();
session.removeAttribute("author");
//2.注销所有session范围数据
session.invalidate();
七、ServletContext(当前应用服务器范围有效)
存储的数据,在当前应用的服务器范围有效
package com.os.servlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.Random;
@WebServlet(urlPatterns = "/test06.php")
public class Test06Servlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setAttribute("bookName","西游记");//请求范围有效
HttpSession session = request.getSession();
session.setAttribute("author","吴承恩");//在当前会话访问(浏览器范围)
//ServletContext application = session.getServletContext();
ServletContext application = request.getServletContext();
System.out.println("服务器的绝对路径:"+application.getRealPath(""));
application.setAttribute("price",new Random().nextInt(1000));
}
}
当服务器关闭时候,数据会消失
八、数据传递总结
- 重定向传递数据:需要我们拼接数据,不能传递复杂的数据,重定向传递数据中含有中文需要经过特殊处理
- 请求转发传递数据:HttpServletRequest对象存储和获取数据
- 会话范围存储数据:HttpSession对象存储和获取数据
- session的注销方式
- 应用范围存储数据:ServletContext对象存储和获取数据
注意:
- 能用request解决,就不要用session处理
- 能用session解决,就不要用application处理