Java学习笔记-Day53 Servlet、JSP(一)
一、Servlet
1、简介
Servlet是运行在服务器端的组件,能够给客户端返回动态页面。
Servlet是多线程、单实例的。多个客户端同时请求访问一个Servlet,Web应用服务器将为每个客户端的连接启动一个线程来服务。第一次访问Servlet时,服务器将创建一个该Servlet类的对象,并调用doXxx方法生成响应。多个客户端访问同一个Servlet时,不再创建新的对象,而是共用同一个Servlet对象。
Servlet是一个java的类,这个类必须继承于 javax.servlet.http.HttpServlet类 ( 抽象类 ),HttpServlet的父类为GenericServlet抽象类。Servlet也可以继承GenericServlet抽象类。通常在web项目中新建一个名为controller的包来存放servlet文件。
Servlet的实例变量是线程不安全的( 没有被Synchronized关键字修饰 )。
Servlet类使用doXxx方法提供服务,这些方法继承于HttpServlet类。查看API,可见doXxx方法都有两个参数,分别是请求和响应。服务器会创建请求对象和响应对象传递给doXxx方法,doXxx方法中可以直接使用请求和响应对象。
HttpServlet的方法:
方法 | 描述 |
---|---|
protected void doDelete(HttpServletRequest req, HttpServletResponse resp) | 被server调用 (通过service方法) 以允许一个 servlet处理一个 DELETE请求. |
protected void doGet(HttpServletRequest req, HttpServletResponse resp) | 被server调用 (通过service方法) 以允许一个 servlet处理一个 GET请求 . |
protected void doOptions(HttpServletRequest req, HttpServletResponse resp) | 被server调用 (通过service方法) 以允许一个 servlet处理一个OPTIONS 请求 . |
protected void doPost(HttpServletRequest req, HttpServletResponse resp) | 被server调用 (通过service方法) 以允许一个 servlet处理一个 POST请求. |
protected void doPut(HttpServletRequest req, HttpServletResponse resp) | 被server调用 (通过service方法) 以允许一个 servlet处理一个 PUT请求. |
protected void doTrace(HttpServletRequest req, HttpServletResponse resp) | 被server调用 (通过service方法) 以允许一个 servlet处理一个 TRACE请求. |
protected long getLastModified(HttpServletRequest req) | 返回HttpServletRequest对象最后一次被修改的时间,单位是毫秒,自格林威治时间1970年1月1日午夜开始计时。 |
protected void service(HttpServletRequest req, HttpServletResponse resp) | 收到一个标准的来自公有service 方法的HTTP 请求并将其分配到该类中定义的doXXX方法。 |
void service(ServletRequest req, ServletResponse res) | 将客户端请求分配到受保护的 service方法. |
doGet方法:
(1)设置请求编码格式。
// 程序最先做的事情是设置请求编码的格式
request.setCharacterEncoding("utf-8");
(2)获取op的值。
<form action="bs.do" method="post">
<input type="text" name="blogtitle" placeholder="请输入标题" required><br/>
<textarea rows="10" cols="60" name="blogcontent" placeholder="请输入内容" required></textarea>
<!-- 通过隐藏域告诉Servlet这里做的操作是增加 -->
<input type="hidden" name="op" value="add" >
<br/>
<input type="submit" value="添加">
</form>
(3)根据op值的不同执行不同的操作。
request.setCharacterEncoding("utf-8");
String op = "";
if (request.getParameter("op") != null) {
op = request.getParameter("op");
}
if ("login".equals(op)) {
doLogin(request, response);//自定义的方法
} else {
doQuery(request, response);//自定义的方法
}
2、生命周期
Servlet是单例模式,当用户第一次从浏览器请求访问Servlet时,对应的Servlet的生命周期为:
1、 实例化和加载(Tomcat创建)
2、 初始化(init方法,仅执行一次)
3、 Service服务(doXxx方法,执行多次)
4、 销毁(destory方法)
5、 垃圾回收(finalize方法,虚拟机调用,仅执行一次)
具体过程:
(1)Tomcat 调用 Servlet 的构造方法,创建该类的对象。
(2)Tomcat 调用 JavaEE API 中的初始化方法:先调用有参数的init方法,再调用无参的init方法,进行初始化工作。(init方法只执行一次)
(3)初始化成功后,调用服务方法,通过判断请求方式,调用相应的 doXxx 方法,如 doGet、doPost 等方法。(服务方法执行多次)
(4)doXxx 方法正常返回后,即提供服务结束。
(5)Tomcat 根据使用情况,在适当的时机销毁 Servlet 对象,销毁前调用 destroy 方法。
(6)垃圾回收finalize方法(虚拟机调用,只执行一次)。
3、Servlet加载启动选项
默认情况下,只有当第一次访问Servlet时,服务器才会初始化Servlet实例。如果需要在Tomcat启动的时候就能初始化Servlet实例,可以在web.xml或@WebServlet中配置。
(1)在WebContent->WEB-INF->web.xml中配置,使得在启动Tomcat的时候就能对Servlet实例化。<load-on-startup>2</load-on-startup>
中的数字2不是表示个数,而是Servlet启动的顺序。Servlet永远只被实例化一个对象。
<servlet>
<description></description>
<display-name>TestServlet</display-name>
<servlet-name>TestServlet</servlet-name>
<servlet-class>com.etc.train.controller.TestServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
(2)可以在@WebServlet中配置loadOnStartup,loadOnStartup的默认值为-1,值为-1的时候Tomcat启动时不会实例化Servlet。
@WebServlet(urlPatterns = "/TestServlet",loadOnStartup=1)
public class TestServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public TestServlet() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter().append("Served at: ").append(request.getContextPath());
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
4、Servlet的配置访问路径
(1)@WebServlet注解 ( 放在Servlet类前 ):
@WebServlet("/ts.do")
public class TestServlet extends HttpServlet {
}
如果@WebServlet的路径为 /a/b/c/d/ts.do
,而转发或重定向的路径为 index.jsp
,当进行转发或重定向时,转发或重定向的路径则会变为 项目名/a/b/c/d/index.jsp
。可以通过将转发或重定向的路径设置为绝对路径解决这个问题。
- Servlet中:
request.getContextPath()+路径名
,例如request.getContextPath()+"index.jsp"
- JSP中:
${pageContext.request.contextPath}+路径名
,例如${pageContext.request.contextPath}+"index.jsp"
(2)web.xml文件:
<servlet>
<servlet-name>ts</servlet-name>
<servlet-class>com.etc.bs.controller.TestServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ts</servlet-name>
<url-pattern>/ts.do</url-pattern>
</servlet-mapping>
4、配置默认首页
web.xml中可以配置默认首页。当不指定具体访问路径时,默认访问默认首页。将按照顺序访问,如果都不存在则报404错误。当web.xml修改完成后,需要重新启动Tomcat。
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
5、Request请求和Response响应
服务器实现了请求和响应接口,实现类分别是 RequestFacade 以及 ResponseFacade 。每次访问Servlet,服务器都会创建请求对象和响应对象传递给Servlet类的doXxx方法。
5.1、Request请求
通过浏览器提交给服务器端的所有数据,都称为请求数据。Servlet API中,定义了请求接口,用来封装和操作请求数据。
Request的实现类是requestFacade,其实现了HttpServletRequest接口,HttpServletRequest接口继承于ServletRequest接口。
HttpServletRequest接口 :负责处理请求(Tomcat对其进行实例化),javax.servlet.http.HttpServletRequest接口继承于javax.servlet. ServletRequest接口。
5.1.1、ServletRequest接口的方法
(1)public void setAttribute(java.lang.String name, java.lang.Object o)
:将数据保存在请求范围内。在请求的范围内传递数据。name是一个指定变量名字的字符串,o是被存储的对象。name为键,o为值,可以通过name得到o。
request.setAttribute("list",list);
(2)public void removeAttribute(java.lang.String name)
:从请求范围中删除一个属性。name是一个指定需要删除的变量名字的字符串,也可以看成键。
request.removeAttribute("list");
(3)public RequestDispatcher getRequestDispatcher(java.lang.String path)
:返回一个作为位于给定路径的资源的封装器的 RequestDispatcher 对象。RequestDispatcher 对象可以被用于向一个资源转发请求,或者用于在一个响应中包含该资源。该资源可以是动态的也可以是静态的。
- RequestDispatcher 的方法:
public void forward(ServletRequest request, ServletResponse response) throws ServletException, java.io.IOException
:在服务器上将一个请求从一个servlet转到另一个资源 (servlet, JSP文件, 或HTML文件)。该方法允许一个servlet预处理一个请求和用于产生响应的另一个资源。
//转发:从servlet跳转到jsp页面
request.getRequestDispatcher("a.jsp").forward(request, response);
(4)public java.lang.Object getAttribute(java.lang.String name)
:返回在请求范围中对应name(键)的属性,当没有具有所给name的属性时,则返回一个空值。
List<Blog> list = (List<Blog>) request.getAttribute("list");
(5)public java.lang.String getParameter(java.lang.String name)
:返回一个请求参数的字符串值。若该参数不存在,则返回一个空值。
(6)public java.lang.String[] getParameterValues(java.lang.String name)
:返回一个包含所有的给定请求参数的值的字符串对象的向量。若该参数不存在,则返回一个空值。
(7)public java.lang.String getRemoteAddr()
:返回客户端发送请求的IP地址。
注意:
setAttribute方法与getRequestDispatcher方法是一对搭档,需要结合使用。通过setAttribute方法设置数据,通过getAttribute获取数据,此时获取的数据是Object类型。
5.1.2、HttpServletRequest接口的方法
public java.lang.String getHeader(java.lang.String name)
:返回指定的作为字符串请求消息头的值。如果该请求没有指定名称的消息头,该方法将返回null值。
public java.lang.String getRemoteAddr()
:获取客户端的IP地址。
public java.lang.String getLocalAddr()
:获取服务器端的IP地址。
MIME:MIME全名叫多用途互联网邮件扩展(Multipurpose Internet Mail Extensions),浏览器能接受的MIME,最初是为了将纯文本格式的电子邮件扩展到可以支持多种信息格式而定制的。后来被应用到多种协议里,包括我们常用的HTTP协议。MIME的常见形式是一个主类型加一个子类型,用斜线分隔。比如text/html、application/javascript、image/png等。在访问网页时,MIME type帮助浏览器识别一个HTTP请求返回的是什么内容的数据,应该如何打开、如何显示类型。
5.2、Response响应
通过服务器返回给客户端的所有数据,都称为响应数据。Servlet API中,定义了响应接口,用来封装和操作响应数据。
HttpServletResponse接口 :负责处理响应(Tomcat对其进行实例化),javax.servlet.http.HttpServletResponse接口 继承于 javax.servlet. ServletResponse接口。
5.2.1、ServletResponse接口的方法
(1)public java.lang.String getCharacterEncoding()
:返回用于在这个响应消息中被发送的 MIME body的编码的名称。如果没有分配charset ,就隐含地设置成ISO-8859-1 (Latin-1)。
(2)public void setCharacterEncoding(String env) throws UnsupportedEncodingException
:设置用于在这个响应消息中被发送的 MIME body的编码。
request.setCharacterEncoding("utf-8");
(3)public java.io.PrintWriter getWriter() throws java.io.IOException
:返回能够向一个客户机发送字符的 PrintWriter 对象。 如果有必要的话,响应的 MIME 类型可以修改以反映所用的字符编码。 本方法或方法getOutputStream() 两者中的任何一个都可以被调用来写入 body , 但不能同时调用这两者。 返回一个能够向一个客户端返回字符的PrintWriter 对象。
PrintWriter out = response.getWriter();
out.print("<p>Servlet</p>");
(4)public void setContentType(java.lang.String type)
:设置正被发往客户端的响应的内容类型。 内容类型可以包括所用的字符编码类型,例如, text/html; charset=ISO-8859-4。
5.2.2、HttpServletResponse接口的方法
(1)public void sendRedirect(java.lang.String location) throws java.io.IOException
:用指定的重定位URL向客户端发送一个临时重定位响应消息。该方法可以接收相对的 URL。
response.sendRedirect("b.jsp");
二、JSP文件
1、JSP简介
JSP(Java Server Pages)是JavaEE规范中的Web组件,用来编写动态页面。JSP运行在服务器端,本质是Servlet。JSP文件以.jsp为后缀,在Eclipse的工程目录中存在WebContent目录下。JSP文件可以直接在浏览器中访问。JSP文件中的内容就是 HTML+Java代码,静态部分使用HTML和文本即可,动态部分使用Java代码。
Servlet生成动态页面比较繁琐,使用JSP生成动态页面比较便捷,因为其中的静态内容可以使用HTML生成。JSP的执行过程是:翻译-编译-实例化-提供服务。JSP的本质就是Servlet,不过是服务器将JSP进行了翻译和编译;可以说,JSP也是一个Java类。
JSP是包含Java代码的html文件,用来展示数据。虽然servlet和jsp都能展示数据,但是通常不会使用servlet显示数据,而是使用jsp来展示数据。
新建JSP文件:在WebContent目录右键 -> new -> JSP File -> Finish。
在JSP文件总,快捷键 ctrl+shift+o
是无效的,而快捷键 Alt+/
是有效的。
JSP中的语法:
(1)指令:用来导包和做一些文档的设置。语法:<%@指令 %>
<%@page import="com.etc.bs.service.BlogService"%>
<%@page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
(2)小脚本:用来编写Java代码。语法:<% Java代码 %>
<%
System.out.println("小脚本");
System.out.println("Java代码");
%>
(3)表达式:用来做页面输出。语法:<%=表达式%>
<% String s = "this.is jsp"%>
<%=s%>
(4)注释:在JSP中可以使用注释元素,有三种情况:
-
格式为
<%--JSP注释--%>
,JSP的注释只有在源代码中可见,翻译时已经忽略。 -
在JSP中,除了使用JSP注释外,还可以使用HTML注释,
<!--HTML注释-->
,HTML注释会被返回到客户端,但是不显示到页面中。 -
JSP中的Java代码部分,可以使用Java注释,Java注释会翻译到.java文件中,但是编译时忽略。
(5)声明:如果需要在JSP文件中定义类的成员变量或方法,可以使用声明元素,格式为<%! 声明语句%>
JSP中的执行过程:jsp文件通过Tomcat翻译成java文件(servlet),java文件再通过虚拟机编译成class字节码文件。实际上响应给浏览器的是字节码文件,所以有时候第一次加载网页时可能比较慢,而后面再加载网页时速度较快,生成的java文件和字节码文件都在Tomcat根目录的work目录之中。
Jar包的配置:Jar放到WebContent/WEB-INF/lib中,正常会自动加入构建路径。可以在javaResources-> Libraries->Web App Libraries 查看是否构建。
jdbc的DBUtil工具类需要加载驱动 class.forName("com.mysql.cj.jdbc.Driver");
。
Web项目的代码写好之后,需要重新启动Tomcat Service,同时要关注控制台的输出信息。
2、JSP九大内置对象
(1)与输入/输出有关的对象: request、response、out
(2)与属性作用域有关的对象:session、application、pageContext
(3)与Servlet 相关对象:page、config
(4)与错误处理有关的:exception
3、作用域范围
(1)pagecontext(页面上下文):当前页面有效(页面跳转后无效)。
(2)request(请求):同一次请求有效(请求转发后有效,重定向后无效),传递数据给下一个页面。
(3)session(会话):同一次对话有效(同一个浏览器在退出关闭之前都有效)
(4)application(整个页面应用):全局有效(整在服务器一开始执行服务,到服务器关闭为止)。在Servlet中为ServletContext,通过this.getServletContext()。在jsp中为application,可以直接使用。
从小到大顺序:pagecontext < request < session < application
作用域范围都包含 setAttribute方法 (存储数据) 和 getAttribute方法 (获取数据)。