Servlet
一、Servlet简介
- Servlet是Sun公司提供的也可用于开发动态web资源的技术
- Sun公司在其API中提供了一个Servlet接口,用户若想发一个动态web资源,需两个步骤:
- 编写一个Java类,实现Servlet接口
- 八开发好的Java类部署到web服务器中
- 按照一种约定俗称的称呼习惯,通常我们也把实现了Servlet接口的Java程序称之为Servlet
二、Servlet运行过程
- Web浏览器发出HTTP请求给Web容器
- Web容器首次访问创建目标Servlet
- Web容器创建请求(request)和创建响应(response)
- Web容器调用Servlet.service(request,response)
- service(request,response)获取请求信息。并把响应写入响应信息返回给Web容器
- Web容器发出HTTP响应给Web浏览器
- 注意:service() 方法由容器调用,开发人员不用对 service() 方法做任何动作,只需要根据来自客户端的请求类型来重写 doGet() 或 doPost() 即可
三、Servlet实现类
- Servlet接口Sun公司定义了两个默认实现类。分别为GenericServlet、HttpServlet
- HttpServlet是指能够处理Http请求的Servlet,它在原有的Servlet接口上添加了一些与HTTP协议处理方法,它比原有接口功能更强大,因此通常使用该类,由于在实现Servlet接口时覆写了service方法,该方法体内的代码会自动判断用户的请求方法,因此在编写Servlet时,通常只需要覆写doGet和doPost方法,而不需要去覆写service方法
四、doGet和doPost的区别
-
form运行方式
- 当form框里面的method为get时,执行doGet方法
- 当form框里面的method为post时,执行doPost方法
-
生成方式
- doGet有四种:
- 直接在URL地址栏中输入URL
- 网页中的超链接
- form中method为get
- form中method为空时,默认是get提交
- doPost只有一种
- form中method属性为post
- doGet有四种:
-
数据传输方式
- doGet方式:表单数据存放在URL地址后面。所有get方式提交时HTTP中没有消息体
- doPost方式:表单数据存放在HTTP协议的消息体中以实体的方式传送到服务器
-
服务器获取数据方式
- doGet方式:服务器采用request.QueryString来获取变量的值
- doPost方式:服务器采用request.Form来获取数据
-
传送的数据量
- doGet:数据量长度有限制,一般不超过2kb。因为是参数传递,且在地址栏中,故数据量有限制
- doPost:适合大规模的数据传送。因为是以实体的方式传送的。
-
安全性
- doGet:安全性差。因为是直接将数据显示在地址栏中,浏览器有缓冲,可记录用户信息。所以安全性低
- doPost:安全性高。因为post方式提交数据时是采用的HTTP post机制,是将表单中的字段与值放置在HTTP HEADER内一起传送到ACTION所指的URL中,用户是看不见的
在做数据查询时,建议用Get方式;而在做数据添加、修改或删除时,建议用Post方式
五、使用IEDA开发Servlet
- 准备Servlet需要的jar包
- 在IEDA中新建一个Web项目
- 新建一个Servlet
- 编写代码
- 配置web.xml中Servlet的servlet和servlet-mapping
- 启动Tomcat服务器
- 访问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 ServletTest03 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");
response.getWriter().println("<h1>Hello Servlet</h1>");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request,response);
}
}
配置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>
<servlet-name>Test03</servlet-name>
<servlet-class>com.kuang.servlet.ServletTest03</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Test03</servlet-name>
<url-pattern>/aaa</url-pattern>
</servlet-mapping>
</web-app>
启动服务器发布后:
注意:一般情况下一个URL对应一个请求
六、Response——重定向
当文档移动到新的位置,我们需要向客户端发送这个新位置时,我们需要用到网页重定向。重定向请求到另一个网页的最简单的方式是使用 response 对象的 sendRedirect(String s) 方法,参数需传递新的网页URL
注意:
-
使用sendRedirect(String s) 方法时,若想跳转到本服务器下的其他页面,则传入该页面的URL,重定向后地址栏最后的URL值会改变
例如重定向到本服务器的404.jsp时:
response.sendRedirect("404.jap");
-
使用sendRedirect(String s) 方法跳转到其他服务器的页面时,直接传入新页面的完整网址,包括HTTP或HTTPS协议,否则将重定向失败
例如需要重定向到百度首页时:
response.sendRedirect("https://www.baidu.com");
七、Response——ServletContext
Web容器在启动时,它会为每一个Web应用程序创建一个对应的ServletContext对象,它代表当前对象的引用
-
通过ServletContext对象实现数据共享
发送端:
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 java.io.IOException;
@WebServlet(name = "ServletDemo03")
public class ServletDemo03 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//通过Servlet对象可获取一个ServletContext对象
ServletContext servletContext = this.getServletContext();
String name = "华为";
//通过setAttribute方法向ServletContext发送数据
servletContext.setAttribute("name",name);
response.setCharacterEncoding("utf-8");
response.getWriter().print("设置name成功:"+name);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request,response);
}
}
接收端:
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 java.io.IOException;
@WebServlet(name = "ServletDemo04")
public class ServletDemo04 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext servletContext = this.getServletContext();
//通过getAttribute方法向ServletContext接收数据
Object name = servletContext.getAttribute("name");
response.setCharacterEncoding("utf-8");
response.getWriter().println("接收到的name:"+name);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request,response);
}
}
-
通过ServletContext读取网站配置文件
- 新建一个properties文件
driver=com.mysql.jdbc.Driver username=root password=123456 url=jdbc:mysql://localhost:3306/smbms
- 编写Servlet类
import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.FileInputStream; import java.io.IOException; import java.util.Properties; //读取properties配置文件 public class ServletDemo03 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 { //读取配置文件 //1.获得配置文件的路径 String realPath = this.getServletContext().getRealPath("/WEB-INF/classes/resources/database.properties"); System.out.println("取得的路径为:"+realPath); Properties properties = new Properties(); FileInputStream is = new FileInputStream(realPath); properties.load(is);//把文件流加载到配置文件的对象中; String driver = properties.getProperty("driver"); String username = properties.getProperty("username"); String password = properties.getProperty("password"); String url = properties.getProperty("url"); //响应到网页 resp.getWriter().println(driver); resp.getWriter().println(username); resp.getWriter().println(password); resp.getWriter().println(url); } }
- 配置web.xml
- 访问
注意:配置文件路径在src下(在src下新建resources文件夹)!!!
八、简单验证码的实现
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;
//验证码
public class ServletDemo04 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 {
//自动刷新网页:---> refresh 刷新网页, 2时间
resp.setHeader("refresh","2");
//验证码是一个图片 , 我们需要制作一个图片
BufferedImage image = new BufferedImage(100,30,BufferedImage.TYPE_3BYTE_BGR);
//图片写入一些东西
Graphics2D graphics = image.createGraphics();
graphics.setColor(Color.red);
String num = String.valueOf(newRandom());
graphics.drawString(num,10,10);
//想办法让浏览器知道我们给的是一张图片
resp.setContentType("image/jpg");
//让网站去打开图片
ImageIO.write(image,"jpg",resp.getOutputStream());
}
//生成随机数
public int newRandom(){
int num = (int) Math.ceil(Math.random()*10000);
return num;
}
}
九、Request——获取项目信息
-
jsp获取项目路径
${pageContext.request.contextPath}
-
Request对象
Request对象代表客户端的请求,当客户端通过HTTP协议访问服务器时,HTTP请求头中的所有信息都封装在这个对象中,通过这个对象提供的方法,可以获得客户端请求的所有信息。
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 RequestDemo01 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //查看request对象的方式 System.out.println(request.getContextPath()); //获得web项目路径 System.out.println(request.getRequestURI()); //请求的URL路径 //Remote 远程 System.out.println(request.getRemoteUser()); //获得远程的用户名 System.out.println(request.getRequestedSessionId()); //获得SessionId; System.out.println(request.getServletPath()); //请求servlet的url System.out.println(request.getLocalAddr()); //获得本地地址 防火墙 System.out.println(request.getLocalName()); //获得本地名字 System.out.println(request.getLocalPort()); //获得访问的端口号 } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request,response); } }
十、Request——接收前端用户提交的数据&请求转发
-
登录页面jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>登录</title> </head> <body> <h1>登录</h1> <form action="${pageContext.request.contextPath}/a" method="post"> <p>用户名:<input type="text" name="username"></p> <p>密码:<input type="password" name="password"></p> <p> <input type="submit"> <input type="reset"> </p> </form> </body> </html>
-
成功页面jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>登录成功</title> </head> <body> <h1>登录成功</h1> </body> </html>
-
接收前端传递的控件信息:request.getParameter(“控件的name‘);
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 RequestDemo01 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.setCharacterEncoding("utf-8"); resp.setCharacterEncoding("utf-8"); String username = req.getParameter("username"); String password = req.getParameter("password"); if (username.equals("admin") && password.equals("123456")){ System.out.println("登陆成功"); //转发 //转发:服务器把这个请求转向另外一个Servlet去处理; (地址栏不会变) //RequestDispatcher ,需要使用RequestDispatcher来进行处理,我们需要获得这个类,参数为要转发到的页面 req.getRequestDispatcher("/page/success.jsp").forward(req,resp); }else { System.out.println("登陆失败"); } } }
- 转发
- 通过ServletContext的getRequestDispatcher(String path)方法,该方法返回一个RequestDispatcher对象,调用这个对象的forward方法可以实现请求转发。
- 通过request对象提供的getRequestDispatche(String path)方法,该方法返回一个RequestDispatcher对象,调用这个对象的forward方法可以实现请求转发
十一、转发和重定向的区别
- 重定向:服务器告诉客户端去请求另外一个地址,属于客户端行为,地址栏会改变,不能携带参数(302)
- 转发:服务器自己转发到服务器上的另一个请求,属于服务器行为,地址栏不会变,可以携带参数(307)
十二、会话
-
概念
在Web中,会话表示从浏览器打开某个网站,在这个网站中无论操作了什么,直到关闭浏览器,这一个过程,称之为一个会话。
-
怎样算会话结束
- 客户端关闭了
- 服务器销毁了
-
为什么要处理会话
长期保持会话,无论用户关闭多少次浏览器,这个会话都存在(如虎牙的一个月免登录)
-
保存会话的两种机制
-
Cookie:
Cookie是客户端机制,程序把每个用户的数据以cookie的形式写给用户各自的浏览器。当用户使用浏览器再去访问服务器中的web资源时,就会带着各自的数据去。这样,web资源处理的就是用户各自的数据了
好比超市给用户的会员卡,下次带去就知道之前来过
-
Session
Session是服务器端技术,利用这个机制,服务器在运行时可以为每一个用户的浏览器创建一个其独享的session对象,由于session为用户浏览器独享,所以用户在访问服务器的web资源时,可以把各自的数据放在各自的session中,当用户再去访问服务器中的其它web资源时,其它web资源再从用户各自的session中取出数据为用户服务。
好比超市在自己的系统上保存了用户的信息,用户下次去直接说会员名就行
-
十三、Cookie
构造器:
Cookie cookie = new Cookie(String name,String value);
服务器响应Cookie给客户端:
response.addCookie(Cookie);
服务器查看用户带来的请求是否有Cookie
Cookie[] cookies = Request.getCookie();
//可以使用cookie来验证用户是否来过
//判断cookies是否为空,然后遍历即可
Cookie.getName();
Cookie.getValue();
No. | 方法 | 类型 | 描述 |
---|---|---|---|
1 | Cookie(String name, String value) | 构造方法 | 实例化Cookie对象,传入cooke名称和cookie的值 |
2 | public String getName() | 普通方法 | 取得Cookie的名字 |
3 | public String getValue() | 普通方法 | 取得Cookie的值 |
4 | public void setValue(String newValue) | 普通方法 | 设置Cookie的值 |
5 | public void setMaxAge(int expiry) | 普通方法 | 设置Cookie的最大保存时间,即cookie的有效期,当服务器给浏览器回送一个cookie时,如果在服务器端没有调用setMaxAge方法设置cookie的有效期,那么cookie的有效期只在一次会话过程中有效,用户开一个浏览器,点击多个超链接,访问服务器多个web资源,然后关闭浏览器,整个过程称之为一次会话,当用户关闭浏览器,会话就结束了,此时cookie就会失效,如果在服务器端使用setMaxAge方法设置了cookie的有效期,比如设置了30分钟,那么当服务器把cookie发送给浏览器时,此时cookie就会在客户端的硬盘上存储30分钟,在30分钟内,即使浏览器关了,cookie依然存在,在30分钟内,打开浏览器访问服务器时,浏览器都会把cookie一起带上,这样就可以在服务器端获取到客户端浏览器传递过来的cookie里面的信息了,这就是cookie设置maxAge和不设置maxAge的区别,不设置maxAge,那么cookie就只在一次会话中有效,一旦用户关闭了浏览器,那么cookie就没有了,那么浏览器是怎么做到这一点的呢,我们启动一个浏览器,就相当于启动一个应用程序,而服务器回送的cookie首先是存在浏览器的缓存中的,当浏览器关闭时,浏览器的缓存自然就没有了,所以存储在缓存中的cookie自然就被清掉了,而如果设置了cookie的有效期,那么浏览器在关闭时,就会把缓存中的cookie写到硬盘上存储起来,这样cookie就能够一直存在了。 |
6 | public int getMaxAge() | 普通方法 | 获取Cookies的有效期 |
7 | public void setPath(String uri) | 普通方法 | 设置cookie的有效路径,比如把cookie的有效路径设置为"/xdp",那么浏览器访问"xdp"目录下的web资源时,都会带上cookie,再比如把cookie的有效路径设置为"/xdp/gacl",那么浏览器只有在访问"xdp"目录下的"gacl"这个目录里面的web资源时才会带上cookie一起访问,而当访问"xdp"目录下的web资源时,浏览器是不带cookie的 |
8 | public String getPath() | 普通方法 | 获取cookie的有效路径 |
9 | public void setDomain(String pattern) | 普通方法 | 设置cookie的有效域 |
10 | public String getDomain() | 普通方法 | 获取cookie的有效域 |
Cookie测试用户是否来过
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class CookieDemo extends HttpServlet {
Cookie cookie = null;
Boolean flag = false;
@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.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
Cookie[] cookies = req.getCookies();
if (flag){
resp.getWriter().println("上次登录时间为"+ cookie.getValue());
resp.getWriter().println("刷新了Cookie");
}else {
resp.getWriter().println("第一次来没有Cookie");
}
cookie = new Cookie("LastLoginTime",System.currentTimeMillis()+"");
resp.addCookie(cookie);
flag=true;
}
}
十四、Session
- 只要客户端一旦连接上服务器,服务器就会自动产生Session,一个连接对应一个session,session可以在一个会话中传递信息
- 通过setAttribute设置值
- 通过getAttribute获得值
- Session由服务器控制,如果服务器重启了,信息就会丢失
使用Session存入值:
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
public class SessionDemo 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.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
//session由服务器创建
//得到的session对象
HttpSession session = req.getSession();
String id = session.getId();
resp.getWriter().println("获得的sessionId"+id);
String name = "小学生";
session.setAttribute("name",name);
resp.getWriter().println("设置session成功:"+name);
}
}
获取Session存入的值:
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;
@WebServlet(name = "SessionDemo2")
public class SessionDemo2 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
HttpSession session = request.getSession();
String name = (String)session.getAttribute("name");
response.getWriter().println("得到的session信息:"+name);
//销毁session
session.invalidate();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request,response);
}
}
- 会话注销的方式一
session.invalidate();//通过代码注销会话
- 会话注销的方式二
<!--session-config可以设置会话自动过期,时间分钟为单位-->
<session-config>
<session-timeout>1</session-timeout>
</session-config>