Tomcat安装和配置
Http 格式
请求消息响应格式
请求行
1.我们先在webpp目录下创建一个html文件,叫as.html(注意不能是Web-INF文件夹内)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<form action="" method="get">
<input name="username">
<input type="submit" value="提交" id="">
</form>
</body>
</html>
之后访问网址看看成功没
http://localhost:8090/aaa/as.html
GET请求的请求参数在请求行中,特点是在url后面不是很安全,同时请求的url长度是有限制
比如我们在上面这个html中输入内容之后,点击提交,在控制台-网络中我们可以发现我们输入的内容在url的后面.(比如我输入了nihao)
POST请求的请求参数在请求体中,我们可以把html的get改成post。请求的url长度没有限制的:
请求头
常见的请求头有
1.Host:表示请求的主机(localhost表示是自己)
2.User-agent:浏览器告诉服务器访问使用的浏览器的版本信息。可以解决浏览器兼容问题.
3.Accept:告诉服务器,我(浏览器)可以接受什么样的数据(了解一下就可以)
4.Accept-Language :可以接受的语言:(了解一下就可以)
5.Accept-Encoding:可以接受的压缩格式:(了解一下就可以)
6.Referer:(很重要)告诉服务器当前请求从哪里来(1.防止盗链2.统计信息)
防止盗链:比如付费的电影,被一些网站解锁后放到自己的网站(自己的超链接指向付费网站的),付费网站可以指定Referer请求(if(referer.equal(‘优酷首页’))),来判断这个请求来自优酷首页。
统计信息:可以看进入这个网站使用的是什么浏览器最多
7.Connection:连接状态
请求正文
用来封装POST请求消息的请求参数体的,GET请求就没有请求体了
请求空行
用来分割POST请求的请求头和请求体的
Request
Request对象和Response对象的原理:
1.tomcat服务器会根据url请求url的资源路径,创建对应的ServletDemo对象。
2.服务器创建Request对象和Response对象。Request对象中封装请求消息数据,tomcat把Response对象和Request对象传递给service方法。
3.程序员可以通过request对象获取请求消息数据,通过response对象来设置响应消息数据。
4.服务器再为浏览器响应之前,会从response对象中拿出程序员设置的响应消息数据。
从前端获取想要的请求行数据(概念)
就是用来获得get请求或者post请求里面是数据。它们卸载doget()
和dopost()
方法内,用来从前端获得以下7种数据。
比如: GET http://localhost:8090/aaa/as.html?username=as
1.获取请求方法比如:GET,使用 string getMethod()方法
2.(重要)获取虚拟目录(应用上下文)比如:/aaa,使用 String getContextPath()
方法
3.获取Servlet路径比如:/as.html,使用 String getServletPath()
方法
4.获取get方式请求参数比如:?username=aa,使用 getQueryString()
方法
5.(重要)获取请求的url比如:aaa/as.html,使用 String getRequestURI()
方法(返回/aaa/as.html)或者
StringBuffer getRequestURL
方法(返回http://localhost:8090/aaa/as.html)。
其中,URI的范围比URL要大(URI是共和国,URL是中华人民共和国)
6.获取协议及版本比如:HTTP/1.1,使用String getProtocol()
7.获取客户机的比如:IP地址,使用 String getRemoteAddr()
方法
返回的大部分都是String类型的值,因此我们可以直接打印它。
从前端获取想要的请求行数据(代码)
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;
import jakarta.servlet.annotation.*;
@WebServlet(urlPatterns = "/demo44")
public class Servlet3 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException {
//获取请求方式
String method = request.getMethod();
System.out.println(method);
//获取虚拟目录
String aa = request.getContextPath();
System.out.println(aa);
//获取Servlet路径
String aa1 = request.getServletPath();
System.out.println(aa1);
//获取get方式请求参数
String aa2 = request.getQueryString();
System.out.println(aa2);
//获取请求url
String aa3 = request.getRequestURI();
StringBuffer aa4 = request.getRequestURL();
System.out.println(aa3); //打印uri
System.out.println(aa4); //打印url
//获取协议和版本
String aa5 = request.getProtocol();
System.out.println(aa5);
//获取客户端IP
String aa6 = request.getRemoteAddr();
System.out.println(aa);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}
运行服务器,输入url:(因为这里没有参数,所以我们在输入url的时候要手动加一个username=as参数)
http://localhost:8090/aaa/demo22?username=as
在控制台中查看返回:
获取请求头数据(概念)
就是用来查看访问来自哪里。
一共有两个方法:
(重要)String getHeader(String name)方法
:通过请求头的名称获取请求头的值。
Enumerationget<String> HeaderNames()方法
:获取所有请求头的名称。(很少用到)
名词解释:Enumerationget<String>
类似迭代器
获取请求头数据(代码)
获得user-agent头
1.获得指定的请求头user-agent,解决浏览器兼容问题(写在doget()方法中)
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;
import jakarta.servlet.annotation.*;
@WebServlet(urlPatterns = "/demo33")
public class Servlet2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException {
//演示获取单个请求头 user-agent
String agent = request.getHeader("user-agent");
//判断浏览器的版本-执行不同操作
if(agent.contains("Chrome")){
//谷歌
System.out.println("使用了谷歌");
}else if(agent.contains("Firefox")){
//火狐
System.out.println("使用了狐");
}else if(agent.contains("Edge")){
System.out.println("使用了Edge");
}else {
System.out.println("使用了其他浏览器");
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}
结果为:(你也可以打印出来看一看)
获得Referer头
2.获得Referer头,直接在doget方法中修改就可以了。
如果直接输入url来进行访问,Referer的值为null。可以修改之前的htmlas.html用它来指向一个超链接
//获得请求头Referer
String a =request.getHeader("referer");
System.out.println(a);
修改html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<form action="" method="get">
<input name="username">
<input type="submit" value="提交" id="">
</form>
<h><a href="demo44">点我进入</a></h>
</body>
</html>
进入url进行验证,结果为:
执行防止盗链的操作
很简单,添加如下代码:
//获得请求头Referer
String a =request.getHeader("referer");
System.out.println(a);
if (a!= null){
if (a.contains("aaa")){
System.out.println("正常访问"); //来自aaa/目录下,可以访问
}else {
System.out.println("非法访问"); //来自其他地方,不能访问
}
}
就可以初级的防止盗链了。如果其他服务器(就是非这个项目)进行盗链操作,就不会成功了
获得所有请求头的数据
3.获取所有的请求头
你可以注释上面的代码,或者再创建一个Java类(这里要写在get方法)
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;
import jakarta.servlet.annotation.*;
@WebServlet(urlPatterns = "/demo223")
public class aaa extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException {
//演示获取请求头的数据
//1.获取所有的请求头名称
Enumeration<String> headerNames = request.getHeaderNames();
//2.遍历
while (headerNames.hasMoreElements()){
//3.根据名称获取请求头的值
String name = headerNames.nextElement();
String value= request.getHeader(name);
System.out.println(name+"-"+value);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}
结果为:我们可以看到请求头的信息了,比如user-agent。
获取请求体数据(概念)
只有post请求才有请求体。它主要是用来获取前端的数据
1.获取流数据:
方法BufferedReader getReader();
,返回的是BufferedReader对象。可以操作字符流,只能操作字符数据。
方法ServletInputStream getInputStream();
返回的是ServletInputStream对象。可以操作输入流,就是可以操作所有数据。
2.从流数据中拿到数据:
这个通过IDEA中的操作完成。
获取请求体数据(代码)
1.先创建一个注册页面的html文件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>注册界面</title>
</head>
<body>
<form action="aaa/" method="post">
<input type="text" placeholder="请输入用户名" name="username"> <br>
<input type="text" placeholder="请输入密码" name="passwoed">
<input type="button" value="注册">
</form>
</body>
</html>
2.创建一个新类:
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
public class Servlet5 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doGet(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取请求消息体
BufferedReader br = req.getReader();
//读取数据
String line = null;
while ( (line = br.readLine()) !=null ){ //通过遍历的方式完成读取, (line = br.readLine()) !=null )逐行读取,如果不是空,就继续读取
System.out.println(line);
}
}
}
3.现在启动服务器进行访问:输入url后我们就可以在控制台看到我们输入的数据了:
从前端获取任何的参数
这些方法可以兼容get请求和post请求。
1.String getParameter(String name)
方法:根据参数名称获得参数值。比如参数为username就会返回username
的值。
2.String[] getParameterValues(String name)
方法:根据参数名称来获取数值(不过它获得的是数组)如:hobby=xx&hobby=game
(常用于复选框,有多个值传入)
3.Enumeration<String> getParameterNames()
方法获取所有请求的参数名称。
4.MAP<String ,String[]>
方法:获取所有参数的map集合
从前端获取任何的参数(代码)
1.复制一份reg.html文件并把它命名为reg2.html。注意修改java类名,同时创建一个新的java类。
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>注册界面</title>
</head>
<body>
<form action="/aaa/demo66" method="post">
<input type="text" placeholder="请输入用户名" name="username"> <br>
<input type="text" placeholder="请输入密码" name="password"><br>
<input type="submit" value="注册">
</form>
</body>
</html>
Java
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(urlPatterns = "/demo66")
public class Servlet6 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//get获取请求参数
String username = req.getParameter("username"); //获取username的值
System.out.println("来自get:"+username);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//post获取请求参数
String username = req.getParameter("username"); //获取username的值
System.out.println("来自post:"+username);
}
}
结果为:(如果来自get就会返回来自get请求)
2.获得多个数据(复选框)
我们再之前的html中加入一个复选框
<input type="checkbox" name="hobby" value="game">游戏
<input type="checkbox" name="hobby" value="study">学习
加入代码(在doget和dopost中都可以)
String[] hobbies =req.getParameterValues("hobby");
for (String hobby :hobbies){
System.out.println(hobby);
}
这样我们点入html后点击"注册"按钮就会返回:(获得了复选框中我们输入的值)
3.获取所有请求的参数
可以在get或post方法下直接加入:
Enumeration<String> par = req.getParameterNames();
while (par.hasMoreElements()){
String name = par.nextElement();
System.out.println(name);
}
之后我们输入以下值:
在IDEA控制台就会返回:
4.获取所有请求数据的集合
就是把请求名称和值同时封装到一个Map对象中去。
在java代码中加入:
Map<String, String[]> par = req.getParameterMap();
//遍历
Set<String> keyset = par.keySet();
for (String name : keyset){
//获取键获取值
String[] values = req.getParameterValues(name); //用数组装,防止有多个值
System.out.println(name); //打印参数名
for (String value : values){
System.out.println(value); //打印参数值
}
System.out.println("----------------------");
}
之后我们在html中输入以下内容:
出现中文乱码问题
Tomcat 8 以上的版本已经把get请求的中文乱码问题解决了。但是post请求有时候会乱码。我们可以设置流的编码来解决post请求的乱码问题。(这个参数为前端的编码,可以写上保险)
req.setCharacterEncoding("utf-8"); //设置流的编码
请求转发
一种在服务器内部资源跳转方式。就是一个Servet处理完,交给另一个Servet处理。有两种处理方法。
1.通过request对象来获取请求转发对象的:
RequestDispatcher getRequestDispatcher(String path)
方法。
2.使用RequestDispatcher对象来进行转发的
forward(ServletRequest request,ServletResponse reponse)
方法。
这种方法的特点是:浏览器地址栏路径没有发生改变。同时只能访问当前服务器内部资源中(就是不能跳转路由)。
假设有两个servlet类,demo77和demo88,我现在想要使用demo77发送给demo88。就是访问demo77同时执行demo88的方法。
demo77:
import jakarta.servlet.RequestDispatcher;
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;
@WebServlet(urlPatterns = "/demo77")
public class Servlet7 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("demo77被访问了");
//转发到demo88
RequestDispatcher reqq = req.getRequestDispatcher("我是/demo88");
//把request对象和response对象传到demo88中去
reqq.forward(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
}
demo88:
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;
@WebServlet(urlPatterns = "/demo88")
public class Servlet8 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("我是demo88");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取请求消息体
}
}
我们在浏览器中输入:
http://localhost:8090/aaa/demo77
在IDEA控制台的结果为:
共享数据
就是请求转发时多个Servlet相互通讯数据。本篇需要请求转发的代码已经完成。
域对象:有作用范围的对象,可以在范围内共享数据。
request域:代表一次请求的范围,一般用来请求妆发的多个资源中共享数据。
setAttribute(String name,Object obj)
方法:存储数据。
Object getAttribute(String name)
方法:通过键获取值。
void removeAttribute(String name)
方法:通过键移除数值对。
我们在上面的demo99的请求转发之前加入如下的代码(输入我是demo99后面):
req.setAttribute("msg","hello"); //共享数据:hello,赋值在msg中
之后再demo88的文件加(我是demo88的前面):
Object msg = req.getAttribute("msg");
System.out.println(msg);
之后运行服务器,输入网址,结果为:
跳转页面
sendRedirect(String path);
转化get和post请求
如果一个方法只想实现post方法(get同理),我们可以把不想要的方法转化为post方法。
@Override //把get请求转化为post请求
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doGet(req, resp);
doPost(req,resp);
}
比较重要的几种方式
String getParameter(String name) 获得前端传来的几个参数。
String[] getParameterValues(String name) 前端传来的一组数据。
reques.setAttribute(“key”,value) 用来存值。
reques.setAttribute(“key”) 取值
req.setAttribute("uname",username); //后端传值给前端
Object uname = req.getAttribute("uname"); //前端获得数据
前后端交互表单数据
jsp文件
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="/demo101" method="post">
username:<input type="text" name="username">
hobby:<input type="checkbox" name="love" value="足球1">足球
<input type="checkbox" name="love" value="排球1">排球
<input type="checkbox" name="love" value="羽毛球1">羽毛球
<input type="submit" value="submit">提交
</form>
</body>
</html>
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;
@WebServlet(urlPatterns = "/demo101")
public class Servlet11 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
String username = req.getParameter("username"); //获得前端传来的数据
System.out.println(username);
req.getRequestDispatcher("welcome.jsp"); //跳转页面-自己创建
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doGet(req, resp);
}
}
Cookies和Session
先把应用上下文设置为空最好:
Session
request中的值只能在单次请求中使用,如果想要每个页面都想要,就需要用到Session。就是一个用户一个会话,一个会话中有这个用户相关的信息。保存在服务器。验证当前用户是否是同一个。
当用户第一次访问服务器的时候就会创建一个session,当浏览器关闭或手动关闭的时候session就会关闭。比如淘宝每个操作都需要获取用户名。还可以设置时间,当用户长时间不操作的时候,session会关闭。
Session的设置和获取
登录的jsp界面:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
session演示
<form action="/demo103" method="post">
<label for="username">Username:</label>
<input type="text" id="username" name="uname" required><br>
<label for="password">Password:</label>
<input type="password" id="password" name="pass" required><br>
<input type="submit" value="Login">
</form>
</body>
</html>
处理的Sevlet:
@WebServlet(urlPatterns = {"/demo103"})
//用来演示session相关操作 jsp4-5
public class Servlet13 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 {
System.out.println("这是post方法");
//接收用户名和密码
String uname = req.getParameter("uname");
String pass = req.getParameter("pass");
if (uname != null && pass!=null){
if (uname.equals("111")&& pass.equals("111")){
//后台存数据
HttpSession session = req.getSession();
//存值
session.setAttribute("username",uname);
resp.sendRedirect("jsp5.jsp"); //重定向到jsp5,会丢失数据
}else {
resp.sendRedirect("err.jsp");
}
}
}
}
登录成功的界面:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录成功</title>
</head>
<body>
//登录成功的显示
<h1>登录成功,欢迎${sessionScope.username}</h1>
//实现退出登录,退出servlet
<a href="/demo104">退出 </a>
</body>
</html>
登录失败的界面:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录失败</title>
</head>
<body>
登录失败
</body>
</html>
Cookies
Cookeis的设置和获取
功能和Session一致,区别是:Session记录在服务端,Cookies记录在客户端。一旦用户登录成功后,下次登录会直接读取Cookies中的值,不用输入用户名和密码就可以登录了。
一开始用户访问的时候,Cookies是不存在的,在登录一次后才会存在,直到cookies有效期过了。
Servlet页面处:
@WebServlet(urlPatterns = "/demo102")
//用来演示Cookies相关操作
public class Servlet12 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req,resp); //把get请求转化为post请求
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("这是post方法");
//设置cookie
Cookie cookie = new Cookie("key","value");
//cookies存在时间
cookie.setMaxAge(60*60);
//把cookies交给客户端
resp.addCookie(cookie);
//页面跳转
resp.sendRedirect("cookies.jsp");
}
}
jsp页面处:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%
//设置全局变量,不然下面访问不到
String value = "";
//获得所有的cookies
Cookie[] cookies= request.getCookies(); //获得cookies
if (cookies != null){ //判断cookies是否为空
for (Cookie cookie :cookies){ //遍历cookie数组
if (cookie != null && cookie.getName().equals("key")){ //如果cookies的变量名为key
value = cookie.getValue(); //获得其值
break;
}
}
}
%>
获得cookies的值,name=key,value= <%=value%>
</body>
</html>
连接数据库
Servlet与数据库博客