Servlet:Server Applet,是服务器端的一个程序(代码、功能实现),可交互式的处理客户端发送到服务器端的请求,并完成响应操作,实现前后端的交互。
IDEA2022为例
使用版本为Tomcat 8.5.41
点击右上角启动项目旁边的编辑配置,选中已安装的tomcat,设置可保持默认。
点击部署添加启动时部署
导入Servlet.jar包
可能遇到的问题
tomcat版本过高会出现可能会出现404 NOT FOUND此时可以下降tomcat的版本。
其他问题可上网查找,一般可解决大部分问题。
package lhnservetest;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;
/**
* @BelongsProject: testservlet0630
* @BelongsPackage: lhnservetest
* @Author: LiHaoNan
* @Date: 2022/6/30 9:24
* @Description:
*/
@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("销毁");
}
}
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;
/**
* @BelongsProject: testservlet0630
* @BelongsPackage: lhnservetest
* @Author: LiHaoNan
* @Date: 2022/6/30 9:42
* @Description:
*/
@WebServlet("/demo2")
public class GenricServlet extends GenericServlet {
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("只需重写servlet方法即可");
}
}
HttpServlet是继承GenericServlet,在其基础上对service功能进行了拓展提升。
为符合http的协议的开发规范,对service方法进行了重构,产生了两个新方法:
doGet() 和 doPost()
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;
/**
* @BelongsProject: testservlet0630
* @BelongsPackage: lhnservetest
* @Author: LiHaoNan
* @Date: 2022/6/30 9:50
* @Description:
*/
@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);
}
}
在servlet2.5以前使用
<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>demo1servlet-name>
<servlet-class>lhnservetest.HttpServletservlet-class>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>demo1servlet-name>
<url-pattern>/demoHttpServleturl-pattern>
servlet-mapping>
web-app>
在servlet3.0以后才可用
@WebServlet(name="/demo1",urlPatterns = "/demoHttpServlet",loadOnStartup = 1)
@WebServlet("/demo3")
url-pattern规则
load_on_startup
项目分级
数据库查询操作参照JDBC
package servlet;
import entity.Stu;
import service.impl.StuServiceImpl;
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.List;
/**
* @BelongsProject: testservlet0630
* @BelongsPackage: servlet
* @Author: LiHaoNan
* @Date: 2022/6/30 11:43
* @Description:showAllStuServlet
*/
@WebServlet("/showAllStuServlet")
public class ShowAllStuServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
StuServiceImpl stuService=new StuServiceImpl();
//通过服务获取全部数据
List<Stu>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" +
" ID \n" +
" UserName \n" +
" PassWord \n" +
" Sex \n" +
" \n" +
" \n" +
"\n" +
" ");
for(Stu stu:stus){//拼接获取的数据到表头下
resp.getWriter().append(" \n" +
" "+stu.getId()+" \n" +
" "+stu.getUsername()+" \n" +
" "+stu.getPassword()+" \n" +
" "+stu.getSex()+" \n" +
" ");
}
resp.getWriter().append(" \n" +
"\n" +
"
\n" +
"\n" +
"");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
效果:
- 现有的问题:
- 一个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);
特点
发生在客户端,客户端将请求发送给服务器之后,服务器响应给客户端一个新的请求地址,客户端再次发起一个请求。
resp.sendRedirect("showPageServlet");
数据传递
特点
servlet生命周期的四个阶段
实例化:当用户第一次访问servlet时,由容器调用servlet的构造方法创建一个具体的servlet对象;也可以在容器启动后立即创建实例对象,通过代码设置属性值为1;
注意:只执行一次
初始化:调用init()方法,通过ServletConfig类进行初始化。
服务:调用service方法(例如HttpServlet中的doget()和dopost());
销毁:destory()方法;只执行一次。
流程
客户端发起请求—>容器(tomcat)解析请求—>创建servlet实例—>调用init()方法来进行初始化—>调用service()方法解析请求—>输出响应—>响应请求—>销毁servlet
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;
/**
* @BelongsProject: testservlet0630
* @BelongsPackage: test
* @Author: LiHaoNan
* @Date: 2022/7/1 10:02
* @Description:
*/
@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);
}
}
package 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;
/**
* @BelongsProject: testservlet0630
* @BelongsPackage: test
* @Author: LiHaoNan
* @Date: 2022/7/1 10:11
* @Description:
*/
@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);
}
}
只需保证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;
/**
* @BelongsProject: testservlet0630
* @BelongsPackage: test
* @Author: LiHaoNan
* @Date: 2022/7/1 10:18
* @Description:
*/
@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);
}
}
Session记录用户的状态。session指的是在一段时间内,单个客户端与服务器之间的一连串相互交互的过程。
在一个Session中,客户端可能会发起多次请求,可以访问一个资源,或者多个资源,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;
/**
* @BelongsProject: testservlet0630
* @BelongsPackage: test
* @Author: LiHaoNan
* @Date: 2022/7/1 11:03
* @Description:
*/
@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改变。
<session-config>
<session-timeout>30session-timeout>
session-config>
生成验证码通过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;
/**
* @BelongsProject: testservlet0630
* @BelongsPackage: servlet
* @Author: LiHaoNan
* @Date: 2022/7/1 11:20
* @Description:
*/
@WebServlet("/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页面
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<form action="verifyCodeServlet"method="get">
用户名:<input type="text" name="username"\n>
密码:<input type="text" name="password"\n>
验证码:<input type="text" name="code"\n>
<img src="createCode">
<input type="submit" value="登录">
form>
body>
html>
验证码输入是否正确
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;
/**
* @BelongsProject: testservlet0630
* @BelongsPackage: servlet
* @Author: LiHaoNan
* @Date: 2022/7/1 11:27
* @Description:
*/
@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);
}
}
- 全局对象,拥有作用域,对应Tomcat中的一个web应用。
- 当web服务器启动时,会自动的为每一个web应用分配一个共享的内存空间。
- servletContext 在web服务器启动时创建,服务器关闭时销毁。
- 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());
- 存储数据:servletContext.setAttribute(key,value);
- 获取数据:servletContext.getAttribute(key);
- 移除数据:servletContext.removeAttribute(key);
- 唯一性:一个应用程序只对应一个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;
/**
* @BelongsProject: testservlet0630
* @BelongsPackage: day0702
* @Author: LiHaoNan
* @Date: 2022/7/2 9:10
* @Description:
*/
@WebServlet("/countServlet")
public class CountServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取servletContext对象
ServletContext application =req.getServletContext();
//每次访问此servlet时,作用域中的某个值自增
/*基本数据类型 包装类
* int Integer
* char Character
* byte Byte
* long Long
* double Double
* float Float
* boolen Boolen
* short Short
* */
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
- 概念:是处于客户端和服务器之间的一道过滤技术。
- 作用:执行地位在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;
/**
* @BelongsProject: testservlet0630
* @BelongsPackage: entity.filter
* @Author: LiHaoNan
* @Date: 2022/7/2 9:56
* @Description:
*/
@WebFilter("/*")
public class TestFilter 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 {
}
}
在自定义的Filter类上加一个@WebFilter注解即可
xml
<filter>
<filter-name>demo1filter-name>
<filter-class>entity.filter.TestFilterfilter-class>
filter>
<filter-mapping>
<filter-name>demo1filter-name>
<url-pattern>/countServleturl-pattern>
filter-mapping>
过滤器路径
- 精确过滤匹配:/countServlet /index.jsp
- 后缀过滤匹配:/*.jsp等
- 通配符匹配:/* 拦截所有请求;不能使用/进行匹配。/aaa/bbb/*.jsp,表示aaa文件夹下bbb的所有.jsp文件
客户端对服务器发起一个请求后,服务器调用servlet之前会先执行一组过滤器(多个过滤器),那么这一组过滤器就成为过滤器链。
每个过滤器都有特定的功能,当第一个filter的doFilter()被调用时,web服务器会创建一个代表filter链的filterChain对象传送给dofilter(),如果开发人员调用了filterchain中的dofilter方法,则web服务器会检查filterChain中是否还有filter,如果有,则调用第二个filter,如果没有则调用目标资源。
- 如果都为注解,按照类名全称的字符串顺序决定执行顺序。abc 、abb:abb先执行。
- 如果是web.xml,是按照注册的先后顺序执行。
- web.xml的优先级高于注解。
- 如果同时配置,不会报错,会创建多个过滤器对象,对目标资源过滤多次。
package entity.filter;
import javax.servlet.*;
import java.io.IOException;
/**
* @BelongsProject: testservlet0630
* @BelongsPackage: entity.filter
* @Author: LiHaoNan
* @Date: 2022/7/2 10:21
* @Description: 处理乱码
*/
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);
}
}
登录:验证码、验证是否已经登录。
注册:验证两次输入的密码一致。
展示信息:展示所有用户的信息。