- Servlet
- 一、概述
- 二、集成Tomcat
- 2.1 创建Web项目
- 2.2 配置tomcat
- 2.3 测试
- 三、Servlet的三种实现方式
- 3.1 实现原生的Servlet接口
- 3.2 继承GenericServlet
- 3.3 继承HttpServlet
- 四、Servlet的两种配置方式
- 4.1 xml配置文件
- 4.2 @webservlet注解的配置方式
- 五、案例:在前端页面展示所有数据
- 六、转发和重定向
- 6.1转发
- 6.2 重定向
- 6.3 get和post的区别
- 七、生命周期
- 八、Cookie和Session
- 8.1 Cookie
- 8.1.1 添加Cookie
- 8.1.2 获取Cookie
- 8.1.3 修改Cookie
- 8.1.4 Cookie优缺点
- 8.2 Session
- 8.2.1 原理
- 8.2.2 Session使用
- 8.2.3 Session和request的区别
- 8.2.4 验证码
- 九、ServletContext
- 9.1 概述
- 9.2 获取对象
- 9.3 作用
- 9.4 特点
- 9.5 案例:记录程序的访问次数
- 十、过滤器
- 10.1 实现
- 10.2 配置
- 10.3 过滤器链和优先级
- 10.3.1 过滤器链
- 10.3.2 优先级
- 10.3.3 实例(处理乱码)
- 10.4 案例
Servlet:Server Applet,是服务器端的一个程序(代码、功能实现),可交互式的处理客户端发送到服务器端的请求,并完成响应操作,实现前后端的交互。
- 动态网页技术:Servlet、Jsp(el, jstl)、第三方框架(SSM,SSH)。
- 静态网页技术:HTML、CSS。
IDEA2022为例
- 首先创建一个新的普通项目
- 右键项目—>添加框架支持—>选中Web项目
(这里已经创建过了所以没有显示)
使用版本为Tomcat 8.5.41
-
点击右上角启动项目旁边的编辑配置,选中已安装的tomcat,设置可保持默认。
-
点击部署添加启动时部署
-
导入Servlet.jar包
在WEB-INF下创建lib包,将apache-tomcat-8.5.41.zip添加到库
-
可能遇到的问题
-
tomcat版本过高会出现可能会出现404 NOT FOUND此时可以下降tomcat的版本。
-
其他问题可上网查找,一般可解决大部分问题。
-
-
- 点击运行,运行成功会弹出网页。
package lhnservetest;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;
@WebServlet("/demo1")
public class ServletTest implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("初始化方法");
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("处理业务核心方法");
}
@Override
public String getServletInfo() {
System.out.println("获取servlet的信息");
return null;
}
@Override
public void destroy() {
System.out.println("销毁");
}
}
3.2 继承GenericServlet
- 使得servlet的编写更加简单,它提供了生命周期的init方法和destory方法的简单实现;如果需要写servlet时,只需重写抽象的service方法即可。
- GenericServlet是Servlet的接口类。
- 缺点:不区分请求类型
package lhnservetest;
import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;
@WebServlet("/demo2")
public class GenricServlet extends GenericServlet {
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("只需重写servlet方法即可");
}
}
3.3 继承HttpServlet
-
HttpServlet是继承GenericServlet,在其基础上对service功能进行了拓展提升。
-
为符合http的协议的开发规范,对service方法进行了重构,产生了两个新方法:
doGet() 和 doPost()
- doGet():支持HTTP的GET请求。
- doPost():支持HTTP的POST请求。
-
HttpServletRequest、HttpServletResponse
package lhnservetest;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name="/demo1",urlPatterns = "/demoHttpServlet",loadOnStartup = -1)
public class HttpServlet extends javax.servlet.http.HttpServlet {
@Override
public void init() throws ServletException {
System.out.println("初始化servlet");
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("统一处理请求");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//不管请求的方式是get还是post,处理请求都在doGet中处理
doGet(req,resp);
}
}
四、Servlet的两种配置方式
4.1 xml配置文件
在servlet2.5以前使用
4.2 @webservlet注解的配置方式demo1 lhnservetest.HttpServlet 1 demo1 /demoHttpServlet
在servlet3.0以后才可用
- 注解常用属性
- name servlet: 名称
- value: 配置servlet的访问路径,可配置多个
- urlPatterns: 配置servlet的访问路径,可配置多个,不可用和value同时使用
- loadOnStartup:优先级
@WebServlet(name="/demo1",urlPatterns = "/demoHttpServlet",loadOnStartup = 1)
@WebServlet("/demo3")
-
url-pattern规则
- 精确匹配:/具体的名称;/demo1 只有在访问路径名完全一样时才会访问到。
- 后缀匹配:
@WebServlet("/showAllStuServlet")
public class ShowAllStuServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
StuServiceImpl stuService=new StuServiceImpl();
//通过服务获取全部数据
List
stus=stuService.showALLStu(); //向前端页面发送数据 //直接展示一个html页面 resp.setContentType("text/html;charset=UTF-8"); resp.getWriter().print("n" + "n" + "n" + " n" + " Title n" + "n" + "n" + "n" + "n" + " n" + "
n" + "n" + ""); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req,resp); } }n" + " n" + " n" + "n" + " "); for(Stu stu:stus){//拼接获取的数据到表头下 resp.getWriter().append("ID n" + "UserName n" + "PassWord n" + "Sex n" + "n" + " "); } resp.getWriter().append(" n" + "n" + ""+stu.getId()+" n" + ""+stu.getUsername()+" n" + ""+stu.getPassword()+" n" + ""+stu.getSex()+" n" + "效果:
六、转发和重定向
6.1转发- 现有的问题:
- 一个servlet既做了数据解析,又做了展示页面的功能,违背了功能单一性。
- 一个servlet只做数据解析和响应。
- 一个servlet只做页面响应。
那么两个servlet之间如何相互访问。
定义:一次请求,经过多次资源访问,跳转了多次,但是地址栏不发生改变。
-
转发发生在服务器端,将请求发送给服务器端的其他资源,以共同完成一次请求的过程。
req.getRequestDispatcher("showPageServlet?username=李浩楠").forward(req,resp);//放的是URL路径,req即为request作用域
数据传递
-
forward:代表一次请求,是服务器内部进行跳转,可以共享request作用域中的所有数据。
-
request作用域:拥有存储数据的空间,在一次请求的过程中的任何位置都可以获取。
-
可以传递任意类型的数据。
-
存数据:
request.setAttribute(key,value);
-
取数据:
req.getAttribute(key,value);
-
特点
- 转发是服务器行为。
- 转发时游览器只发起一次请求。
- 转发游览器地址栏内容不变。
- 转发多次跳转之间传递的数据不会丢失。
- 转发只能将请求发送给同一个web组件中的资源。
-
发生在客户端,客户端将请求发送给服务器之后,服务器响应给客户端一个新的请求地址,客户端再次发起一个请求。
resp.sendRedirect("showPageServlet");
数据传递
- response:没有作用域,两次请求之间的数据无法共享。
- 传递数据:通过URL路径拼接的方式传递数据(“showPageServlet?uername=123&password=123”)
- 获取数据:req.getParameter();
特点
- 重定向是客户端行为。
- 重定向至少发起了两次请求。
- 重定向地址栏发生改变。
- 重定向多次请求之间无法传递数据。
- 重定向可以指向任意资源,包括当前应用程序中的资源,也包括同一站点上的其他资源,以及其他站点的资源。
- get
- get提交的数据会放在URL之后,以?分割,参数之间以&符号连接。
- get以明文方式传递数据,数据量小,不安全。
- 效率高,游览器默认的访问方式为GET。
- 对应的Servlet方法为doGet();
- post
- post方法将提交的数据Http请求中。
- 密文传递数据,进行一次加密(md5等),数据量大,安全。
- 效率相对于GET低。
- 对应的Servlet方法为doPost();
servlet生命周期的四个阶段
-
实例化:当用户第一次访问servlet时,由容器调用servlet的构造方法创建一个具体的servlet对象;也可以在容器启动后立即创建实例对象,通过代码设置属性值为1;
注意:只执行一次
-
初始化:调用init()方法,通过ServletConfig类进行初始化。
-
服务:调用service方法(例如HttpServlet中的doget()和dopost());
-
销毁:destory()方法;只执行一次。
流程
客户端发起请求—>容器(tomcat)解析请求—>创建servlet实例—>调用init()方法来进行初始化—>调用service()方法解析请求—>输出响应—>响应请求—>销毁servlet
八、Cookie和Session 8.1 Cookie- Cookie是在游览器访问web服务器某个资源时,由web服务器在HTTP响应头中附带传送的一小段数据。
- 一旦某个游览器存储了某个Cookie,在之后访问对应的web服务时,都应在HTTP请求头中携带此Cookie,把Cookie回传给服务器。
- 一个Cookie由标识该信息的名称(name)和值(value)组成。
package test; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet("/addCookie") public class CookieTestServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //创建Cookie对象 Cookie cookie=new Cookie("20220701","java实训"); //设置过期时间 三种取值 >0 有效期,单位:秒 ;=0 游览器关闭失效; <0 内存存储,默认-1 cookie.setMaxAge(3600); //设置访问路径 cookie.setPath("/"); resp.addCookie(cookie); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req,resp); } }8.1.2 获取Cookiepackage test; 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; @WebServlet("/getCookie") public class GetCookieServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //获取请求中携带的cookie Cookie[]cookies=req.getCookies(); for(Cookie cookie:cookies){ //检索cookie getName()获取cookie名称, getValue()获取cookie值 if(cookie.getName().equals("20220701")){ System.out.println("20220701:"+cookie.getValue()); break; } } } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req,resp); } }8.1.3 修改Cookie只需保证Cookie的名和路径一致即可
package test; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet("/updateCookie") public class UpdateCookieServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Cookie cookie=new Cookie("20220701","峡~谷~~之~~巅,爱慕未批,mvp~~15.4的鳄鱼"); cookie.setPath("/"); cookie.setMaxAge(-1); resp.addCookie(cookie); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req,resp); } }8.1.4 Cookie优缺点- 优点
- 可以配置到期规则。
- 简单:一个基于文本的轻量型结构,只包含键值对。
- 数据持久性:cookie默认在过期之前一直保存在客户端的游览器上
- 缺点
- 大小受到限制,4K-8k
- 用户可设置成禁用。
- 潜在的安全风险,cookie可以被篡改。
Session记录用户的状态。session指的是在一段时间内,单个客户端与服务器之间的一连串相互交互的过程。
8.2.1 原理在一个Session中,客户端可能会发起多次请求,可以访问一个资源,或者多个资源,session对象不变
8.2.2 Session使用- 服务器会为每一个会话分配一个session对象。
- 同一个游览器不管发起多少此请求,只要游览器没有关闭,都属于同一个会话。
- 首次使用session时,服务器会自动创建session,并创建Cookie保存SessionID发送回客户端。
-
作用域:拥有存储数据的空间,范围是一次会话有效。
-
一次会话是同一个游览器发送的多次请求。一旦游览器关闭,则会话结束。
-
可以将数据存入Session作用域中,在作用域中的任何位置都可以获取。
-
可以传递任意类型的值。
package test; 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("/testsession") public class TestSessionServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //获取Session对象 HttpSession session=req.getSession(); //存值 session.setAttribute("username","李浩楠"); //取值 String username=(String) session.getAttribute("username"); //移除作用域中的值 session.removeAttribute("username"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req,resp); } }
-
-
request是一次请求有效,请求改变,则request改变。
-
session是一次会话有效,游览器改变,则session改变。
- tomcat中可设定session的过期时间
30
生成验证码通过ValidateCode.jar包来实现
package servlet; import cn.dsna.util.images.ValidateCode; 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("/https://blog.csdn.net/MR_lihaonan/article/details/createCode") public class CreateCodeServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //生成验证码的类 ValidateCode validateCode= new ValidateCode(200,30,4,10); //获取生成的验证码 String code=validateCode.getCode(); System.out.println("生成的验证码:"+code); //存入session req.getSession().setAttribute("code",code); //把生成的验证码图片返回给前端,输出到前端 validateCode.write(resp.getOutputStream()); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req,resp); } }html页面
Title 验证码输入是否正确
package servlet; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet("/verifyCodeServlet") public class VerifyCodeServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //前端传递的code String code=req.getParameter("code"); //生成的code码 String mgrcode=(String) req.getSession().getAttribute("code"); //判断验证码是否正确,STRING内容是否相同,不区分大小写 // code.equalsIgnoreCase(mgrcode)不区分大小写的比较方法 // code.isEmpty()判空操作 if(code.equalsIgnoreCase(mgrcode)&&!code.isEmpty()){ System.out.println("验证通过!"); }else { System.out.println("验证失败!"); } } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req,resp); } }
九、ServletContext 9.1 概述效果:
9.2 获取对象- 全局对象,拥有作用域,对应Tomcat中的一个web应用。
- 当web服务器启动时,会自动的为每一个web应用分配一个共享的内存空间。
- servletContext 在web服务器启动时创建,服务器关闭时销毁。
9.3 作用- GenericServlet提供了一个方法getServletContext();(注:推荐使用)
- HttpServlet提供了一个方法getServletContext();(注:推荐使用)
- HttpSession对象提供了一个方法getServletContext();(做了解)
//如何获取tomcat中web应用的真实路径 ServletContext servletContext=req.getServletContext(); String realPath=req.getServletContext().getRealPath("\img"); System.out.println(realPath)//获取应用程序名称 System.out.println(servletContext.getContextPath()); System.out.println(req.getContextPath());
9.4 特点- 存储数据:servletContext.setAttribute(key,value);
- 获取数据:servletContext.getAttribute(key);
- 移除数据:servletContext.removeAttribute(key);
9.5 案例:记录程序的访问次数- 唯一性:一个应用程序只对应一个servletContext。
- 生命周期:只要应用不关闭或者应用不卸载,servletContext对象一直存在。
package day0702; 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("/countServlet") public class CountServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //获取servletContext对象 ServletContext application =req.getServletContext(); //每次访问此servlet时,作用域中的某个值自增 Integer count=( Integer)application.getAttribute("count"); //当第一次访问时,count不存在 if(count==null){ count=1; // application.setAttribute("count",count); } else{ count++; } //返回前端页面 resp.setContentType("text/html;charset=UTF-8"); application.setAttribute("count",count); resp.getWriter().write("servlet的访问次数为:"+count); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }十、过滤器Filter
10.1 实现- 概念:是处于客户端和服务器之间的一道过滤技术。
- 作用:执行地位在servlet之前,客户端发送请求时,会经过filter,再到达目标的servlet,响应时,再次反向执行filer,之后到达客户端。
- 可以解决多个servlet之间代码冗余的问题。例:前端编码设置
- 编写java类实现filter接口
- 在doFilter中写拦截逻辑
package entity.filter; import com.alibaba.druid.proxy.jdbc.DataSourceProxy; import javax.servlet.*; import javax.servlet.annotation.WebServlet; import javax.servlet.annotation.WebFilter; import java.io.IOException; import java.util.logging.LogRecord; @WebFilter(" public class EncodingFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { Filter.super.init(filterConfig); } @Override public void destroy() { Filter.super.destroy(); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { servletRequest.setCharacterEncoding("UTF-8"); servletResponse.setContentType("text/html;charset=UTF-8"); filterChain.doFilter(servletRequest,servletResponse); } }10.4 案例-
登录:验证码、验证是否已经登录。
-
注册:验证两次输入的密码一致。
-
展示信息:展示所有用户的信息。
- 现有的问题:


