Servlet快速入门
- 创建web项目,导入Servlet依赖坐标
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
- 注意:scope:这里的provided设置在本xml中生效,因为tomcat本省就自带就servlet,全局使用会引起冲突
- 创建:定义一个类,实现Servlet接口,并重写接口中所有方法,并在service方法中输入一句话
publicclassServletDemo1implementsServlet {
@Override
publicvoidservice(ServletRequestservletRequest, ServletResponseservletResponse) throwsServletException, IOException {
System.out.println("Servlet hello word");
}
@Override
publicvoidinit(ServletConfigservletConfig) throwsServletException {
}
@Override
publicServletConfiggetServletConfig() {
returnnull;
}
@Override
publicStringgetServletInfo() {
returnnull;
}
@Override
publicvoiddestroy() {
}
}
- 配置:在类上使用@WebServlet注解,配置该Servlet的访问路径
@WebServlet("/demo1")
- 访问:启动Tomcat,浏览器输入URL访问该Servlet
http://localhost:8080/tomcat-demo1/
Servlet执行流程
- 想想问什么我们没有创建servlet对象,也没有执行调用它的方法,它是怎么创建和执行的呢?
其实是由web服务器创建的里面的方法也是被tomcatweb服务器调用的- 那么服务器怎么知道Servlet中一定有servlet方法?
因为我们自定义的servlet,必须是实现servlet接口并复写其方法,而servlet接口中有service方法
Servlet生命周期
- 对象的生命周期指一个对象从被创建到销毁的整个过程
- Servlet运行在Servlet容器(web服务器中)其生命周期由容器来管理,分为4个阶段:
- 加载和实例化:默认情况下,当Servlet第一次被访问时(默认情况下),由容器创建Servlet对象那么在没有默认情况下可以通过
- 初始化:在Servlet实例化之后,容器将调用Servlet的init()方法初始化这个对象,完成一些如:加载配置文件,创建连接等初始化的工作,该方法只调用一次
- 请求处理:每次请求Servlet时,Servlet容器都会调用Servlet的service()方法对请求进行处理
- 服务终止:当需要释放内存或者容器关闭时,容器就会调用Servlet实例的destroy()方法完成资源的释放,在destory()方法调用之后,容器会释放这个Servlet实例,该实例随后会被java的垃圾收集器回收
Servlet体系结构
- Servlet ->体系根接口
- GennericServlet ->Servlet抽象实现类
- HttpServlet -> 对HTTP协议封装的Servlet实现类
- HttpServlet使用步骤
- 继承HttpServlet
- 重写doGet和doPost方法
- 原理就是:获取请求方式,并根据不同的请求方式,调用不同的方法
Servlet urlPattern配置
- Servlet要想被访问,必须配置其访问路径(urlPattern)
- 一个Servlet,可以配置多个urlPattern
@WebServlet(urlPatterns= {"/demo7","/demo8"});
- urlPattern的配置规则
- 精确匹配
- 配置路径:
@WebServlet(urlPatterns="/user/select")
- 访问路径:
http://localhost:8080/tomcat-demo1//user/select
- 目录匹配:上面精确匹配高于目录
- 配置路径:
@WebServlet(urlPatterns="/user/*")
- 访问路径:
http://localhost:8080/tomcat-demo1//user/aaa
- 扩展名匹配
- 配置路径:这里*前面不要加/
@WebServlet(urlPatterns="*.do")
- 访问路径:anyone代表这里填任意都行
http://localhost:8080/tomcat-demo1/anyone.do
- 任意匹配
- 配置路径:
@WebServlet(urlPatterns="/")
@WebServlet(urlPatterns="/*")
这两种都行但是/*优先级更高
- 这/和/*两个的区别:
- 当我们的项目中的Servlet配置了"/",会覆盖掉tomcat中的DefaultServlet,当其他的url-pattern都匹配不上时都会走这个Servlet
- 当我们的项目中配置了"/*",意味着匹配任意访问路径
- 访问路径:
http://localhost:8080/tomcat-demo1/writedowninthereanything
XML配置方式编写Servlet
- Servlet从3.0版本后开始支持使用注解配置,3.0版本前只支持xml配置文件的配置方式
- 步骤:
- 编写Servlet类
- 在web.xml中配置Servlet
<!-- 1Servlet全类名-->
<servlet>
<servlet-name>demo12</servlet-name>
<servlet-class>com.wang.web.ServletDemo12</servlet-class>
</servlet>
<!-- 2Servlet访问路径-->
<servlet-mapping>
<servlet-name>demo12</servlet-name>
<url-pattern>/demo13</url-pattern>
</servlet-mapping>
Request继承体系
- ServletRequest(java提供的请求对象根接口)->HttpServletRequest(java提供的对Http协议封装的请求对象接口)->RequestFacade(Tomcat定义的实现类)
- Tomcat需要解析请求数据,封装为request对象,并且创建request对象传递到service方法中
- 使用request对象,查阅javaEEAPI文档的HttpServletRequest接口
Request获取请求数据
- 请求数据分为3部分:
- 请求行:GET/request-demo/req?username=zhangsan&password=123 HTTTP/1.1
//1String getMethod():获取请求方式:GET
Stringmethod=req.getMethod();
System.out.println(method);
//2String getContexPath():获取虚拟目录(项目访问路径):/request-demo
StringcontextPath=req.getContextPath();
System.out.println(contextPath);
//3StringBuffer getReuestURL():获取URL(统一资源定位符):http://localhost:8080/request-demo/req1
StringBufferurl=req.getRequestURL();
System.out.println(url);
//4String getRequestURI():获取URI(统一资源标识符):/request-demo/req
Stringuri=req.getRequestURI();
System.out.println(uri);
//5String getQueryString():获取请求参数(GET方式):username=zhangsan&password=123
StringqueryString=req.getQueryString();
System.out.println(queryString);
- 请求头:USer-Agent:Mozilla/5.0 Chrome/91.0.4472.106
//获取请求头:user-agent:浏览器的版本信息
Stringagent=req.getHeader("user-agent");
System.out.println(agent);
- 请求体:username=superbaby&passwprd=123
//获取post请求体:请求参数
//1.获取字符输入流
BufferedReaderbr=req.getReader();
//2.读取数据
Stringline=br.readLine();
System.out.println(line);
Request通过方式获取请求参数
- Map<String,String[]> getParameterMap():s获取所有参数Map集合
- Stirng[] getParameterValues(String name):根据名称获取参数值(数组)
- String geParameter(String name):根据名称获取参数值(单个值)
//GET请求逻辑
System.out.println("get...");
//1.获取所有参数的Map集合
Map<String,String[]>map=req.getParameterMap();
for (Stringkey: map.keySet()
) {
System.out.print(key+"");
//获取值
String[] values=map.get(key);
for (Stringvalue: values
) {
System.out.println(value+"");
}
}
System.out.println("--------------------");
//2.根据key获取参数值,数据
String[] hobbies=req.getParameterValues("hobby");
for (Stringhobby:hobbies
) {
System.out.println(hobby);
}
System.out.println("--------------------");
//根据key获取单个参数值
Stringusername=req.getParameter("username");
Stringpassword=req.getParameter("password");
System.out.println(username);
System.out.println(password);
- 使用通用方式获取请求参数后,屏蔽了GET和POST的请求方式代码的不同,则代码可以定义为如下格式:
@Override
protectedvoiddoGet(HttpServletRequestrequest, HttpServletResponseresponse) throwsServletException, IOException {
//2.解决乱码:post,getReader()
request.setCharacterEncoding("UTF-8");
//1.获取username
Stringusername=request.getParameter("username");
System.out.println(username);
}
@Override
protectedvoiddoPost(HttpServletRequestrequest, HttpServletResponseresponse) throwsServletException, IOException {
this.doGet(request,response);
}
- 使用Servlet模板创建Servlet更高效,修改Servlet模板在Setting->Editor->File and code Templates->Other->Web->Servlet Annotated Class.java
解决请求参数中文乱码处理
- 请求参数如果存在中文数据,则会乱码
- 解决方案:
- Post:设置输入流的编码
request.setCharacterEncoding("UTF-8");
- Get:先编码,后解码
//GET获取参数的方式:get
username=newString(username.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
System.out.println(username);
- 张三字符串会通过HTTP协议发送到服务器,而浏览器不支持中文,那么会对中文进行处理,这个处理就是URL编码,将编码发送到Tomcat里去,那么Tomcat会对数据进行解码如果Tomcat用的是UTF-8是不会乱码的,但是Tomcat用的是ISO-8859-1(这里写死了不能更改编码方式)字符集解码
URL编码:1.将字符串安装编码方式转为二进制2.每个字节转为2个16进制并在前边加上% - 小知识点:Tomcat8之后,已将GET请求乱码问题解决,设置默认的解码方式为UTF-8
Request请求转发
- 请求转发:一种在服务器内部的资源跳转方式
- 实现方式:
request.getRequestDispatcher("/req6").forward(request,response);
- 请求转发资源间共享数据:使用Request对象
//存储数据
request.setAttribute("msg","hello");
//获取数据
Objectmsg=request.getAttribute("msg");
//删除数据 request.removeAttribute("msg");
- 特点
- 浏览器地址栏路径不发生变化
- 只能转发到当前服务器的内部资源
- 一次请求,可以在转发的资源间使用request共享数据
Response
- 概念:Request对象用来获取请求数据Response用来设置数据
Response设置响应数据功能介绍
- 响应数据分为3部分
- 响应行:HTTP/1.1 200 OK
voidsetStatus(intsc):设置响应状态码
- 响应头:Content-Type:text/html
voidsetHeader(Stringname,Stringvalue):设置响应头键值对
- 响应体:<html><haed><head><body><body></html>
- PrintWriter getWrite():获取字符输出流
- SevletOutPutSstream getOutputStream():获取字节输出流
Response完成重定向
- 重定向:一种资源跳转方式
- 实现方式:
resp.setStatus(302);
resp.setHeader("location","资源b的路径");\
resp.sendRedirect("资源b路径")
//1设置重定向
//设置响应状态码为302
response.setStatus(302);
//设置响应头:location response.setHeader("Location","/request-demo1/reps2");
//2简化写法
response.sendRedirect("/request-demo1/resp2");
//3动态获取虚拟目录写法
StringcontextPath=request.getContextPath();
response.sendRedirect(contextPath+"/resp2");
- 重定向特点:
- 浏览器地址栏路径发生变化
- 可以重定向到任意位置的资源(服务器内部,外部都可以)
- 两次请求,不能在多个资源使用request共享数据
Response响应字符数据
//获取字符输出流
PrintWriterwriter=response.getWriter();
//写数据
response.setHeader("content-type","text/html");
writer.write("<h1>html</h1>");
//细节:流不要关闭
- text/html是转换成html形式
- 这里存在一个问题输出中文字符的话会乱码所以将setHeader更换成
response.setContentType("text/html;charset=utf-8");
Response响应字节数据
//1.读取文件
FileInputStreamfis=newFileInputStream("路径");
//2.获取response字节输出流
ServletOutputStreamos=response.getOutputStream();
//完成流的拷贝
byte[] buff=newbyte[1024];
intlen=0;
while ((len=fis.read(buff))!=-1){
os.write(buff,0,len);
}
fis.close();
- 更简便的方式工具类
- 在pom.xml导入坐标
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
- 使用
//1.读取文件
FileInputStreamfis=newFileInputStream("C:\\Users\\为了谁\\Desktop\\截图图片\\微信图片_20220406133501.jpg");
//2.获取response字节输出流
ServletOutputStreamos=response.getOutputStream();
//工具类的方法
IOUtils.copy(fis,os);
fis.close();
案例写写
- 流程说明:
- 用户填写用户名密码,提交到LoginServlet
- 在LoginServlet中使用MyBatis查询数据库,验证用户名是否正确
- 如果正确,响应登入成功,如果错误,响应“登入失败”
- 准备环境
- 复制资料中的静态页面到项目的webapp目录下
- 创建db1数据库,创建tb_user表,创建User实体类
- 导入MyBatis坐标,MySql驱动坐标
- 创建mybatis-config.xml核心配置文件,UserMapper.xml映射文件,UserMapper接口