1.内容回顾
b/s 浏览器、服务器
c/s 客户端 服务器
tomcat 默认端口号是:8080 conf/server.xml
servlet 浏览器servlet
2.学习目标
1、Servlet相关架构图
Servlet接口,ServletConfig接口,GenericServlet抽象类,HttpServlet抽象类
2、Serlvet生命周期
构造,init(初始化),service(请求服务),doGet,doPost,destory(销毁)
3、Servlet工作原理
客户端发送请求(url),通过请求地址找到匹配的servlet进行处理
4、请求和响应
HttpServletRequest:封装了客户端请求的所有信息
HttpServletResponse: 用与向客户端输出信息
5、转发和重定向
服务器端转发:
RequestDispatcher rd = req.getRequestDispatcher(“页面”);
rd.forward(req,resp)
客户端重定向:
response.sendRedirect(“页面”)
3.具体内容
3.1 什么是Servlet
和applet相对应,是运行在服务器端的小程序,用来处理客户端的请求并给予响应的
java类,继承了HttpServlet类。
1、servlet体系结构
2、Servlet接口
Servlet的框架是由两个Java包组成的:javax.servlet与javax.servlet.http。在
javax.servlet包中定义了所有的Servlet类都必须实现或者扩展的通用接口和类。在
javax.servlet.http包中定义了采用Http协议通信的HttpServlet类。Servlet的框架的核心
是javax.servlet.Servlet接口,所有的Servlet都必须实现这个接口
3、Servlet继承关系
4、GenericServlet
编写Servlet需要通过实现Servlet接口来编写Servlet,但是我们每次都必须为Servlet中
的所有方法都提供实现,还需要将ServletConfig对象保存到一个类级别的变量中,
GenericServlet抽象类就是为了为我们省略一些模板代码,实现了Servlet和
ServletConfig
3.2 Servlet访问
无法通过类名直接访问Servlet,需要通过映射的路径去访问:url
1、web.xml中配置路径映射
<servlet>
<!--名字一般跟类名对应,仅在本配置文件内部使用-->
<servlet-name>HelloServlet</servlet-name>
<!-- servlet对应的类:完全限定的类名-->
<servlet-class>com.aaa.servlet.HelloServlet</servlet-class>
<!--servlet饿汉模式,项目启动时就要创建servlet-->
<load-on-startup>1</load-on-startup>
</servlet>
<!-- 配置路径映射-->
<servlet-mapping>
<!--名字要和前面的对应-->
<servlet-name>HelloServlet</servlet-name>
<!-- 映射路径:当访问该路径时,会去加载指定servlet的实例,提供服务--
<url-pattern>/hello</url-pattern><!-- 注意前面的“/”-->
</servlet-mapping>
<!-- 配置路径映射-->
<servlet-mapping><!-- 可以配置多个映射路径-->
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/hello2</url-pattern>
</servlet-mapping>
load-on-start标签的作用:
1.load-on-startup元素标记容器是否在启动的时候就加载这个servlet(实例化并调用其init()方
法)。
2.它的值必须是一个整数,表示servlet应该被载入的顺序。;
3.当值为0或者大于0时,表示容器在启动时就加载并初始化这个servlet。
4.当值小于0或者没有指定时,则表示容器在该Servlet被请求时,才会去加载。
5.正数的值越小,该Servlet的优先级就越高,应用启动时就优先加载。
6.当值相同的时候,容器就会自己选择优先加载。
所以,x中x的取值1,2,3,4,5代表的是优先级,而非
启动延迟时间。
2、测试访问
3.3 Servlet生命周期
1、Servlet工作原理
当Web服务器接收到一个HTTP请求时,它会先判断请求内容——如果是静态网页数
据,Web服务器将会自行处理,然后产生响应信息;如果牵涉到动态数据,Web服务器
会将请求转交给Servlet容器。此时Servlet容器会找到对应的处理该请求的Servlet实例
来处理,结果会送回Web服务器,再由Web服务器传回用户端。
针对同一个Servlet,Servlet容器会在第一次收到http请求时建立一个Servlet实例,然后
启动一个线程(从容器线程池中获取一个)。第二次收到http请求时,Servlet容器无须
建立相同的Servlet实例,而是启动第二个线程来服务客户端请求。所以多线程方式不但
可以提高Web应用程序的执行效率,也可以降低Web服务器的系统负担。
Servlet是单例的。
2、Servlet工作流程(背诵+提问)
1、Web Client 向Servlet容器(Tomcat)发出Http请求
2、Servlet容器接收Web Client的请求
3、Servlet容器创建一个HttpRequest对象,将Web Client请求的信息封装到这个对象
中
4、Servlet容器创建一个HttpResponse对象
5、Servlet容器调用HttpServlet对象的service方法,把HttpRequest对象与
HttpResponse对象作为参数传给 HttpServlet对象
6、HttpServlet调用HttpRequest对象的有关方法,获取Http请求信息
7、HttpServlet调用HttpResponse对象的有关方法,生成响应数据
8、Servlet容器把HttpServlet的响应结果传给Web Client
3、Servlet生命周期
Servlet生命周期,是指Servlet从加载、初始化、处理请求、返回响应、直到销毁的过
程。
Servlet中跟生命周期相关的方法:
init():初始化,在之前先通过构造方法创建对象
service(ServletRequest,ServletResponse):服务方法,用来处理各种请求的方法
destroy():销毁
生命周期过程
1、实例化(创建对象:调用构造方法)(只实例化一次)
2、初始化(数据的赋初值,或者获取配置信息的过程)(只初始化一次)
3、提供服务(doGet,doPost)(多次)
4、销毁(关闭容器时销毁)(一次)
4、实例化:
创建Servlet对象的时机:
- 默认情况下(懒汉模式),在Servlet容器启动后:客户首次向Servlet发出请求,
Servlet容器会判断内存中是否存在指定的Servlet对象,如果没有则创建它,然后根
据客户的请求创建HttpRequest、HttpResponse对象,从而调用Servlet对象的
service方法; - Servlet容器启动时(饿汉模式):当web.xml文件中如果元素中指定了
子元素时,Servlet容器在启动web服务器时,将按照顺序创建
并初始化Servlet对象; - Servlet的类文件被更新后,重新创建Servlet。Servlet容器在启动时自动创建
Servlet,这是由在web.xml文件中为Servlet设置的属性决定
的。从中我们也能看到同一个类型的Servlet对象在Servlet容器中以单例的形式存
在;
销毁Servlet对象的时机:
Servlet容器停止或者重新启动:Servlet容器调用Servlet对象的destroy方法来释放资
源。
@WebServlet(urlPatterns = "/TestServlet",loadOnStartup = 2)
public class TestServlet extends HttpServlet {
// 构造方法
public TestServlet(){
System.out.println("TestServlet 被创建了");
}
// 初始化
@Override
public void init() throws ServletException {
System.out.println("TestServlet init 被调用");
}
// 干活的方法
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
System.out.println("TestServlet service方法被调用");
if(req.getMethod().equals("GET")){
this.doGet(req,resp);
}else{
this.doPost(req,resp);
}
}
// 处理Get请求
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) t
System.out.println("TestServlet doGet 进行具体业务的处理");
}
// 处理Post请求
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
System.out.println("TestServlet doGet 进行具体业务的处理");
}
// 销毁
@Override
public void destroy() {
System.out.println("TestServlet destroy");
}
}
5、初始化*
Servlet在初始化的时候可以加载初始化参数,初始化参数是预先配置在web.xml 文件中
的或者在@WebServlet注解中设定。
5.1:配置初始化参数
将FirstServlet中的@WebServlet注解去掉,在web.xm文件中配置FirstServlet初始化参
数
<?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.
version="4.0">
<servlet>
<servlet-name>first</servlet-name>
<servlet-class>com.aaa.FirstServlet</servlet-class>
<init-param>
<param-name>driver</param-name>
<param-value>com.mysql.cj.jdbc.Driver</param-value>
</init-param>
<init-param>
<param-name>url</param-name>
<param-value>jdbc:mysql://localhost:3306/test?setverTimezone=Asi
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>first</servlet-name>
<url-pattern>/first</url-pattern>
</servlet-mapping>
</web-app>
5.2:获得初始化参数
init()代码:
public void init(){
System.out.println("First.init()执行...");
String driver=this.getInitParameter("driver");
String url=this.getInitParameter("url");
System.out.println("driver="+driver);
System.out.println("url="+url);
}
启动Tomcat并访问FirstServlet,观察控制台
First.init()执行...
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/test?setverTimezone=Asia/Shanghai
你好,这是我的第一个Servlet
5.3、使用注解进行初始化
去掉web.xml中的配置,在FirstServlet中配置初始化参数(有点脱裤放屁的感觉)
@WebServlet(value="/firstServlet",initParams = {
@WebInitParam(name = "IP", value = "192.168.1.18"),
@WebInitParam(name = "encoding", value = "UTF-8")
})
public class FirstServlet extends HttpServlet {
public void service(HttpServletRequest request, HttpServletResponse respo
System.out.println("你好,这是我的第一个Servlet");
response.setContentType("text/html;charset=utf-8");
PrintWriter out=response.getWriter();
out.println("<h1>你好,我的Servlet</h1>");
}
public void init(){
System.out.println("First.init()执行...");
String driver=this.getInitParameter("IP");
String url=this.getInitParameter("encoding");
System.out.println("driver="+driver);
System.out.println("url="+url);
}
public void destroy(){
System.out.println("First.destory()执行...");
}
}
访问FirstServlet观察控制台:
First.init()执行...
driver=192.168.1.18
url=UTF-8
你好,这是我的第一个Servlet
6、service方法处理请求响应
对于每一个HTTP请求,servlet容器会创建一个封装了HTTP请求的ServletRequest实例
传递给servlet的service方法,ServletResponse则表示一个Servlet响应,其隐藏了将响
应发给浏览器的复杂性。
通过ServletRequest的方法你可以获取一些请求相关的参数,而ServletResponse则可
以将设置一些返回参数信息,并且设置返回内容。
6.1、HttpServlet中的service方法:
protected void service(HttpServletRequest req, HttpServletResponse resp) th
获取请求的方式 get /post /head /put /delete
String method = req.getMethod();
long lastModified;
if (method.equals("GET")) {
lastModified = this.getLastModified(req);
if (lastModified == -1L) {
调用doGet方法
this.doGet(req, resp);
} else {
long ifModifiedSince;
try {
ifModifiedSince = req.getDateHeader("If-Modified-Since")
} catch (IllegalArgumentException var9) {
ifModifiedSince = -1L;
}
if (ifModifiedSince < lastModified / 1000L * 1000L) {
this.maybeSetLastModified(resp, lastModified);
this.doGet(req, resp);
} else {
resp.setStatus(304);
}
}
} else if (method.equals("HEAD")) {
lastModified = this.getLastModified(req);
this.maybeSetLastModified(resp, lastModified);
this.doHead(req, resp);
} else if (method.equals("POST")) {
this.doPost(req, resp);
} else if (method.equals("PUT")) {
this.doPut(req, resp);
} else if (method.equals("DELETE")) {
this.doDelete(req, resp);
} else if (method.equals("OPTIONS")) {
this.doOptions(req, resp);
} else if (method.equals("TRACE")) {
this.doTrace(req, resp);
} else {
String errMsg = lStrings.getString("http.method_not_implemented"
Object[] errArgs = new Object[]{method};
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(501, errMsg);
}
}
6.2、HttpServletResquest常用方法******:
getParameter(String); //根据名字获取参数的值:表单中的参数,地址栏中的参数
getParameterValues(String);//根据名字获取一组参数的值(复选框)
getParameterMap()://获得一个Map<String, String[]>对象,所有的参数值都放在字符串数
getAttribute(String);//根据名字获取属性的值
setAttribute(String,Object);//根据属性设置值
getRequestDispatcher(String);//请求转发
setCharactorEncoding(); //设置编码方式
HttpServletResponse常用方法:
sendRirect();//重定向:重新请求指定的地址
setContentType();//设置响应的编码方式;
addCookie(); //添加cookie
6.3、示例:登录验证
用户输入用户名密码登录,提交到CheckUserServlet,正确则径入欢迎页面,错误再回
到登录页面
login.html
<form action="/checkUserServlet" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="pass"><br>
<input type="submit" value="登录">
</form>
2、使用注解的形式配置
@WebServlet(name = "CheckUserServlet",urlPatterns = {"/checkUserServlet","/c
public class CheckUserServlet extends HttpServlet {
}
CheckUserServlet
@WebServlet(value="/checkUserServlet")
public class CheckUserServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse re
String user=request.getParameter("username");//获得请求参数:username
String pass=request.getParameter("pass");
if(user.equals("admin")&&pass.equals("1234")){
request.setAttribute("msg","欢迎你登陆成功");//request存储数据
request.getRequestDispatcher("welcomeServlet").forward(request,r
}else{
response.sendRedirect("login.html");//重定向到login.html
}
}
}
如果用户名有中文,则需要在接收request参数前对request进行重新编码设置
request.setCharacterEncoding("utf-8");
WelcomeServlet
@WebServlet(value = "/welcomeServlet")
public class WelcomeServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse re
this.doGet(request,response);//调用doGet这样两种请求都可以截获
}
protected void doGet(HttpServletRequest request, HttpServletResponse res
String msg = (String) request.getAttribute("msg");//获得CheckUserSer
response.setContentType("text/html;charset=utf-8");//设置响应的内容类型
PrintWriter out=response.getWriter();//获得响应的输出流
out.println("<h1>"+msg+"</h1>");
out.close();
}
}
request.getParameter()
request.setAttribute();
request.getAttribute()
request.getRequestDispatcher().forward()
response.sendRedirect()
7、转发和重定向区别
服务器转发:
1.地址栏不会发生改变,在服务器端完成,效率高。
2.携带数据可以在Servlet,jsp之间进行传递
3.客户端发送一次请求,服务器进行一次跳转
//请求转发,服务器转发
request.setAttribute("msg","欢迎你登陆成功");//request存储数据
request.getRequestDispatcher("/welcomeServlet").forward(request,response);
客户端重定向:
1.地址栏会发生改变。
2.客户端重新发送新的请求,无法用request携带数据。
3.客户端发起两次请求
//客户端重定向
//服务器会向客户端浏览器发送一个响应:url, 客户端会重新请求该URL
request.setAttribute("msg","欢迎你登陆成功");//request存储数据
response.sendRedirect("/login.html");
8、示例:录入和查询
@WebServlet(name = "StudentAddServlet", value = "/StudentAddServlet")
public class StudentAddServlet extends HttpServlet {
IStudentService studentService =new StudentServiceImpl();
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse res
//HttpServletRequest request:客户端所有信息都在这里面存储
// 扩展:百度一下,通过request可以获取客户端的哪些信息
// request.getParameter(元素名字): 获取对应的表单元素数据,返回的数据是字符
// bug:如果名字拼写错误,或者元素的name属性没写,获取null
String name = request.getParameter("name");
String sex = request.getParameter("sex");
String birthday = request.getParameter("birthday");
String tall = request.getParameter("tall");
System.out.println(name);
System.out.println(sex);
System.out.println(birthday);
System.out.println(tall);
// 封装学生对象
Student student = new Student();
student.setName(name);
student.setSex(sex);
student.setBirthday(java.sql.Date.valueOf(birthday));
student.setTall(Double.parseDouble(tall));
// 插入数据
studentService.save(student);
System.out.println("插入成功");
// 服务器转发,在数据插入之后,直接在服务器端跳转查询的处理程序
// 1.获取转发器对象,要给出转发的目标地址(不需要带项目名)
//RequestDispatcher rd = request.getRequestDispatcher("/StudentServl
//2.调用转发的forward完成请求的转发
//rd.forward(request,response);
// 转发的时候,可以通过attrbute属性带数据到转发的目标程序
//request.setAttribute("xxx",1000);
//request.getRequestDispatcher("/StudentServlet").forward(request,re
// 客户端重定向:服务器告诉客户端发起新的请求
//response.sendRedirect("/qy149_web_0302_demo1_war_exploded/StudentS
// getContextPath():获取项目路径 /qy149_web_0302_demo1_war_exploded
request.setAttribute("xxx",2000);
response.sendRedirect(request.getContextPath()+"/StudentServlet");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse re
}
}
@WebServlet(name = "StudentServlet",urlPatterns = {"/aaa","/bbb"}) // 多路径配
public class StudentServlet extends HttpServlet {
// 定义业务层对象
IStudentService studentService = new StudentServiceImpl();
public StudentServlet(){
System.out.println("StudentServlet 被创建");
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) t
// 获取Servlet配置的参数数据
//String aaa = this.getServletConfig().getInitParameter("aaa");
//System.out.println(aaa);
// 如果转发过来的请求,可以通过request.getAttribute获取上个请求存储的数据
Object obj = req.getAttribute("xxx");
System.out.println("获取上一个请求操作带过来的数据:"+obj);
// 调用业务层查询数据
List<Map> studentList = studentService.listAll();
// 在后台打印输出,用于调试
System.out.println(studentList);
// 设置响应对象对象的编码
resp.setContentType("text/html;charset=utf-8");
// 通过响应对象,获取打印输出流对象,将内容输出给浏览器
PrintWriter out = resp.getWriter();
out.print(studentList);
out.flush();
out.close();
}
}
总结
1、描述下servlet的生命周期?
2、servlet工作原理?
3、servlet是单例还是多例?
4、转发和重定向
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/118084.html