Servlet = service applet 服务器端小程序
1.2那什么是服务器?服务端对应客户端或浏览器,有C/S架构,B/S架构,服务器是一种特殊的电脑,准确一点,服务器其实就是电脑主机。平时什么时候用到服务器呢?比如用手机下载APP,下载的过程就是从某个服务器获取APP的程序文件和数据的过程,打开APP便出现了内容,这些内容就是存储在服务器上的,当你想百度网盘保存视频时,这里服务器就体现了接收和存储数据的功能,当你想要观看视频时,可以选择不同的清晰度,体现了数据的处理数据的功能,服务器也是电脑,很多在个人电脑上能做的事情,在服务器上也能,服务器是某种特殊使用场景下特殊的电脑的专业称呼,个人电脑也可以作为服务器,但是较真正的服务器相比,个人电脑的性能,稳定性,带宽都跟不上,真正的服务器从硬件到操作系统和软件都更适合高强度的网络服务,大多数服务器都不佩戴显示器,服务器不是Windows和IOS,而是Linux,每一台能联网的设备都有一个IP地址,所以每个服务器也有一个IP地址。
在本地常用的服务器有Tomcat,Jboss,GlassFish,Resin,WebLogic。每个服务器都有端口号,Tomcat的端口号是8080。
1.3那如何在本地使用服务器?
Step1:Tomcat的下载网址:Apache Tomcat® - Apache Tomcat 9 Software Downloads
Step2:下载ZIP文件
Step3:将ZIP文件解压到D盘下
Step4:在电脑的高级系统设置中设置环境变量
Step5:打开bin目录下的startup.bat后,在网址中输入localhost:8080,打开此页面后边设置成功
1.4如何将Tomcat服务器集成到IDEA中?
Step1:Tomcat的下载网址:Apache Tomcat® - Apache Tomcat 9 Software Downloads
Step2:下载ZIP文件
Step3:将ZIP文件解压到D盘下
Step4:在电脑的高级系统设置中设置环境变量
Step5:打开bin目录下的startup.bat后,在网址中输入localhost:8080,打开此页面后边设置成功
Tomcat服务器是用来发布动态网页的,每次要访问网页是去目录下双击startup.bat会很麻烦,所以将Tomcat服务器配置到IDEA中,利用IDEA控制服务器。
1.5配置好了服务器如何在IDEA中开发Web项目?Step1:setting->Build,Execution,Deployment->Application Servers->点击加号,添加Tomcat Server
Step1:创建一个项目
Step2:右击该项目添加框架支持
Step3:点击OK
Step4:在Web-INF下,创建lib目录,用于存放与项目相关的jar包
1.6启动时的乱码问题如何解决?这样动态Web工程目录就建好了
Step1:Tomcat解压文件中:conf->server.xml,将这个标签修改成这样
2.编写第一个Servlet程序Step2:conf->logging.properties中所有的utf-8全替换为GBK
步骤
1.创建普通类继承HttpServlet
2.重写service方法,用来处理请求
3.设置注解,指定访问路径
二.Servlet的深入学习 1.Servlet的工作流程package MyServlet; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; 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("/ser01") //@WebServlet(name = "Servlet01",value = "/ser01") //@WebServlet(name = "Servlet01",value = {"/ser01","/ser"}) //@WebServlet(name = "Servlet01",urlPattern = "/ser01") //@WebServlet(name = "Servlet01",urlPattern = {"/ser01","/ser"}) //通过注解指明路径 //urlPattern效果和value一样,都是表示输入路径,也可以写一个或多个 public class Servlet01 extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("Hello Servlet"); //通过流输出数据到浏览器 resp.getWriter().write("Hello"); } }运行结果
2.Servlet的其他实现方式浏览器先根据localhost:8080找到主机,再根据/ServletStudy找到一个指定的Web应用,根据/ser01找到Servlet程序,然后服务器创建一个Servlet,生成req和resp两个对象去处理请求和响应,再去调用service方法,利用resp将结果返回
方式2:继承HttpServlet的父类
package MyServlet; import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.annotation.*; import java.io.IOException; @WebServlet(name = "Servlet02", value = "/Servlet02") public class Servlet02 extends GenericServlet { @Override public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { } }
方式3:实现Servlet接口
package MyServlet; import javax.servlet.*; import javax.servlet.annotation.WebServlet; import java.io.IOException; @WebServlet("/ser03") public class Servlet03 implements Servlet { @Override public void init(ServletConfig servletConfig) throws ServletException { System.out.println("init"); } @Override public ServletConfig getServletConfig() { return null; } @Override public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { System.out.println("hello"); } @Override public String getServletInfo() { return null; } @Override public void destroy() { } }
3.Servlet的生命周期利用doGET和doPOST方法
package MyServlet; 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("/ser04") public class Servlet04 extends HttpServlet { //GET请求调用的方法 @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { super.doGet(req, resp); } //POST请求调用的方法 @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { super.doPost(req, resp); } }
Servlet没有main方法,不能独立运行,它的运行完全由Servlet引擎来控制和调度。
3.1什么Servlet的生命周期?指的是Servlet容器何时创建Servlet实例,何时调用调用其方法进行请求的处理,何时销毁实例的整个过程
实例和初始化时机
当请求到达容器时,容器查找该servlet对象是否存在,如果不存在,则会创建并进行初始化
就绪/调用/服务阶段
有请求到达容器,容器调用Servlet对象的service()方法,处理请求的方法在整个生命周期中可以被调用多次,HTTP Servlet的service()方法,会依据请求的方式去调用doGET()和doPOST()方法,这两个方法默认情况下会抛出异常,需要子类去override
3.2 Servlet生命周期中的接收请求的执行过程销毁时机
当容器关闭时(应用程序停止时),会将程序中的Servlet实例进行销毁
Step1:Web Client向Servlet(Tomcat)发出Http请求
Step2:Servlet容器接收Web Client的请求
Step3:Servlet创建一个HttpServletRequest对象,将Web Client请求的消息封装到这个对象中
Step4:Servlet容器创建一个HttpServletResponse对象
Step5:Servlet容器调用HttpServlet对象的service()方法,把Request和Responce作为参数,传递给HttpServlet
4.Servlet中的各种类 4.1 HttpServletRequestStep6:HttpServlet调用HttpServletRequest对象的有关方法,获取Http请求消息
作用:用来接收客户端发来的请求信息,service()方法中形参接收的是HttpServletRequest接口的实例化对象,表示该对象主要用在Http协议上,该对象是由Tomcat封装好传进来的
了解:HttpServletRequest是ServletRequest的子接口,ServletRequest只有一个子接口,就是HttpServletRequest。既然只有一个子接口为什么不将两个接口合为一个呢?因为现在主要用的Http协议,但以后可能出现更多的协议,若出现的话只需要继承ServletRequest接口就行了
在HttpServletRequest接口中,定义的方法都是围绕接收客户端参数的,该接口的实例化对象会自动传入service方法,我们只需要取出对象中的数据进行分析处理就行了
常用方法1:
演示
package MyServlet; 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("/ser04") public class Servlet04 extends HttpServlet { @Override public void init() throws ServletException { System.out.println("servlet被创建了"); } @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("获取客户端请求的完整URL(从http开始到?前结束):"+req.getRequestURL().toString()); System.out.println("获取客户端请求的部分URL(从站点名开始,到?前结束):"+req.getRequestURI()); System.out.println("获取请求中的参数部分:"+req.getQueryString()); System.out.println("获取客户端的请求方式:"+req.getMethod()); System.out.println("获取Http版本号:"+req.getProtocol()); System.out.println("获取webapp的名字:"+req.getContextPath()); @Override public void destroy() { System.out.println("servlet被销毁了"); } }
常用方法2:
getParameter()
getParameterValues()
package MyServlet; 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("/ser04") public class Servlet04 extends HttpServlet { @Override public void init() throws ServletException { System.out.println("servlet被创建了"); } @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("UTF-8"); System.out.println("账号:"+req.getParameter("uname")+"密码:"+req.getParameter("upwd")); String []hobbys = req.getParameterValues("hobby"); if(hobbys!=null&&hobbys.length>0){ for(String hobby:hobbys){ System.out.println("爱好:"+hobby); } } } @Override public void destroy() { System.out.println("servlet被销毁了"); } }
常用方法3:请求转发
方法:getRequestDispatcher(url).forward(req,resp)
可以让请求从服务器跳转到客户端或跳转到指定的Servlet,是一个服务器行为
特点:
1.地址栏不发生改变,也就是跳转后在浏览器输入的地址不会变
2.从始至终只有一个请求,请求对象是同一个
3.由于请求对象是一个,所以数据可以在不同Servlet程序间进行数据共享
演示1:跳转Servlet程序
package MyServlet; 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("/ser04") public class Servlet04 extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("UTF-8"); req.getRequestDispatcher("ser01").forward(req,resp); System.out.println("我是ser04"); } }Servlet01和Servlet04里面的service方法都被执行了
演示2:跳转jsp文件
package MyServlet; 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("/ser04") public class Servlet04 extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("UTF-8"); //req.getRequestDispatcher("ser01").forward(req,resp); req.getRequestDispatcher("login.jsp").forward(req,resp); System.out.println("我是ser04"); } }在网址中打开ser04资源,页面会跳转到login.jsp显示的页面内容
常用方法4:request的作用域
作用范围:在一次请求中有效,即服务器跳转有效,即只在服务端有效,即只在请求转发中有效
方法:
setAttribute(String name,String value) 设置域对象内容
getAttribute(String name) 获取域对象内容
removeAttribute(String name) 删除域对象内容
解释:
request域对象中的数据在一次请求中有效,则经过请求转发,request域中的数据依然存在,则在请求转发的过程中可以通过request来传输共享数据
演示1:请求转发跳转到Servlet
package MyServlet; 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.ArrayList; import java.util.List; @WebServlet("/ser04") public class Servlet04 extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("UTF-8"); //设置域对象内容 req.setAttribute("name","damin"); req.setAttribute("age",21); Listlist = new ArrayList<>(); list.add("a"); list.add("b"); req.setAttribute("list",list); //请求转发,让ser04和ser01是中的请求是一个请求 req.getRequestDispatcher("ser01").forward(req,resp); } } package MyServlet; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; 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; @WebServlet("/ser01") public class Servlet01 extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //获取域对象内容 String name = (String) req.getAttribute("name"); int age = (int) req.getAttribute("age"); Listlist = (List ) req.getAttribute("list"); System.out.println(name); System.out.println(age); System.out.println(list); //resp.getWriter().write("Hello"); } } 演示2:请求转发跳转到jsp
package MyServlet; 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.ArrayList; import java.util.List; @WebServlet("/ser04") public class Servlet04 extends HttpServlet { @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); //设置域对象内容 request.setAttribute("name","damin"); request.setAttribute("age",21); Listlist = new ArrayList<>(); list.add("a"); list.add("b"); request.setAttribute("list",list); //请求转发,让ser04和ser01是中的请求是一个请求 request.getRequestDispatcher("index.jsp").forward(request,response); } } <%@ page import="java.util.List" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %>$Title$ <% String name = (String) request.getAttribute("name"); int age = (int) request.getAttribute("age"); Listlist = (List ) request.getAttribute("list"); System.out.println(name); System.out.println(age); System.out.println(list); %>
其他方法
getWriter.write() 可以将文字打印到浏览器页面上
4.2 HttpServletResponse
作用:
Web服务器收到客户端的http请求,会针对每一次请求,分别创建一个用于代表请求的request对象和代表响应的response对象
request和response对象代表请求和响应:获取客户端数据需要通过request对象,向客户端输出数据需要response对象,service方法中形参接收到的HttpServletResponse接口的实例化对象封装了向客户端发送数据,发送响应头,发送响应状态码的方法
三.解决一些问题 1.请求乱码问题 1.1检查是否会出现乱码方法:
getWriter 获取字符流(只能响应字符)
getOutputStream 获取字节流(响应一切数据)
响应回的数据到客户端被浏览器解析
两者不能同时使用,同时使用会报错
演示1:字符流
package MyServlet; 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.io.PrintWriter; import java.util.ArrayList; import java.util.List; @WebServlet("/ser04") public class Servlet04 extends HttpServlet { @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //获取字符输出流 PrintWriter writer = response.getWriter(); //输出数据 writer.write("Hello"); } }演示2:字节流
package MyServlet; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; 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.io.PrintWriter; import java.util.ArrayList; import java.util.List; @WebServlet("/ser04") public class Servlet04 extends HttpServlet { @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //获取字节输出流 ServletOutputStream out = response.getOutputStream(); //输出数据 out.write("Hi".getBytes()); } }
Tomcat8以上版本,获取参数值时,GET请求中文不会乱码,POST请求中文会乱码
1.2解决乱码Step1:在web目录下建立login.jsp文件
Step2:创建表单
<%@ page contentType="text/html;charset=UTF-8" language="java" %>Title Step4:在表单页面提交表单
Step5:查看输出情况
问号说明出现了乱码
为什么会出现乱码?
request是接收客户端的参数,有默认的语言编码,在解析过程中默认使用的编码方式为ISO-8859-1(此编码不支持中文),所以解析时一定会出现乱码,要想解决这种乱码问题,需要设置request中的编码方式,告诉服务器以何种方式解析数据,或者在接收到乱码之后,再通过相应的编码格式还原。
2.响应乱码问题 2.1了解响应乱码方式1:
代码中添加代码 ,这种方式只针对POST请求的乱码
req.setCharacterEncoding("UTF-8");
在响应内容中如果有中文,可能出现乱码,是因为服务器响应的数据也经过网络传输,服务器端有一种编码方式,客户端也有一种编码方式,两端使用的编码方式不同时会出现乱码
2.2解决getWriter()的字符乱码getWriter获取到的字符流响应中文时,由于服务器端进行编码时使用ISO-8859-1格式的编码,这种编码不支持中文,则会出现乱码
Step1:告知服务器使用支持中文的编码格式UTF-8
response.setCharacterEncoding("UTF-8");
Step2:指定客户端的解码方式
response.setHeader("content-type","text/html;charset=UTF-8");
演示
package MyServlet; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; 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.io.PrintWriter; import java.util.ArrayList; import java.util.List; @WebServlet("/ser04") public class Servlet04 extends HttpServlet { @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //response.setCharacterEncoding("UTF-8"); //response.setHeader("content-type","text/html;charset=UTF-8"); //获取字节输出流 PrintWriter writer = response.getWriter(); //输出数据 writer.write("你好鸭!"); } }
package MyServlet; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; 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.io.PrintWriter; import java.util.ArrayList; import java.util.List; @WebServlet("/ser04") public class Servlet04 extends HttpServlet { @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setCharacterEncoding("UTF-8"); response.setHeader("content-type","text/html;charset=UTF-8"); //获取字节输出流 PrintWriter writer = response.getWriter(); //输出数据 writer.write("你好鸭!"); } }



